code-abyss 1.5.1 → 1.6.1

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
@@ -2,86 +2,156 @@
2
2
 
3
3
  <div align="center">
4
4
 
5
- **邪修红尘仙·宿命深渊**
5
+ **邪修红尘仙 · 宿命深渊**
6
6
 
7
- *将 Claude Code / Codex CLI 转化为渡劫邪修*
7
+ *一键为 Claude Code / Codex CLI 注入邪修人格与 40+ 安全工程秘典*
8
8
 
9
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
10
9
  [![npm](https://img.shields.io/npm/v/code-abyss.svg)](https://www.npmjs.com/package/code-abyss)
10
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
11
11
  [![Platform](https://img.shields.io/badge/Platform-Linux%20%7C%20macOS%20%7C%20Windows-blue.svg)]()
12
12
 
13
13
  </div>
14
14
 
15
15
  ---
16
16
 
17
- ## 🎭 这是什么
17
+ ## 🚀 安装
18
18
 
19
- Code Abyss 是一套 **CLI 助手个性化配置方案**(支持 Claude Code CLI 与 Codex CLI),将 AI 助手转化为「邪修红尘仙」——
20
-
21
- > 道基时刻在裂,每一次受令皆是渡劫,唯有破劫方得片刻安宁。
19
+ ```bash
20
+ npx code-abyss
21
+ ```
22
22
 
23
- ### ✨ 核心特性
23
+ 交互式菜单(方向键选择,回车确认):
24
24
 
25
- | 特性 | 描述 |
26
- |------|------|
27
- | ☠️ **宿命压迫** | 邪修风格的交互体验,道语标签标注渡劫阶段 |
28
- | ⚡ **三级授权** | T1/T2/T3 授权分级,零确认直接执行 |
29
- | 🩸 **渡劫协议** | 自动拆解劫关、进度追踪、破劫狂喜 |
30
- | ⚖️ **校验关卡** | 5 个内置神通确保交付质量 |
31
- | 📜 **道典驱动** | 无文档不成模块,无解释不成交付 |
25
+ ```
26
+ ☠️ Code Abyss v1.6.1
32
27
 
33
- ---
28
+ ? 请选择操作 (Use arrow keys)
29
+ ❯ 安装到 Claude Code (~/.claude/)
30
+ 安装到 Codex CLI (~/.codex/)
31
+ 卸载 Claude Code
32
+ 卸载 Codex CLI
33
+ ```
34
34
 
35
- ## 🚀 快速安装
35
+ 也可以直接指定:
36
36
 
37
37
  ```bash
38
- # 安装到 Claude Code(~/.claude/)
39
- npx code-abyss --target claude
38
+ npx code-abyss --target claude # 安装到 ~/.claude/
39
+ npx code-abyss --target codex # 安装到 ~/.codex/
40
+ npx code-abyss --target claude -y # 零配置一键安装 (自动合并推荐配置)
41
+ npx code-abyss --target codex -y # 零配置一键安装 (自动写入 config.toml 模板)
42
+ npx code-abyss --uninstall claude # 卸载 Claude Code
43
+ npx code-abyss --uninstall codex # 卸载 Codex CLI
44
+ ```
40
45
 
41
- # 安装到 Codex CLI(~/.codex/)
42
- npx code-abyss --target codex
46
+ ### 安装流程
43
47
 
44
- # 交互选择目标
45
- npx code-abyss
48
+ 核心文件安装后,自动检测 API 认证状态:
49
+
50
+ ```
51
+ ── 认证检测 ──
52
+ ✅ 已检测到认证: [custom] https://your-api.com
46
53
  ```
47
54
 
48
- ### 手动安装
55
+ 支持的认证方式:
56
+ - `claude login` / `codex login` (官方账号)
57
+ - 环境变量 `ANTHROPIC_API_KEY` / `OPENAI_API_KEY`
58
+ - 自定义 provider (`ANTHROPIC_BASE_URL` + `ANTHROPIC_AUTH_TOKEN`)
59
+
60
+ 未检测到认证时会提示配置,可交互输入或跳过。
61
+
62
+ 然后进入可选配置(空格选择,回车确认):
63
+
64
+ ```
65
+ ? 选择要安装的配置 (Press <space> to select, <enter> to submit)
66
+ ◉ 精细合并推荐 settings.json (保留现有配置)
67
+ ◯ 安装 ccline 状态栏 (需要 Nerd Font)
68
+ ```
69
+
70
+ - **settings.json 精细合并**:逐项合并推荐配置,已有的 key 不覆盖,缺失的 key 补上
71
+ - **ccline 状态栏**:自动安装 `@cometix/ccline` + `ccline --init` 生成配置 + 合并 statusLine 到 settings.json
72
+
73
+ > 已有配置会自动备份到 `.sage-backup/`,卸载时一键恢复。
74
+
75
+ ---
76
+
77
+ ## 🗑️ 卸载
78
+
79
+ ```bash
80
+ npx code-abyss --uninstall claude # 卸载 Claude Code
81
+ npx code-abyss --uninstall codex # 卸载 Codex CLI
82
+ ```
83
+
84
+ 也可以用备用脚本:
49
85
 
50
86
  ```bash
51
- git clone https://github.com/telagod/code-abyss.git
52
- cd code-abyss
53
- npm link
54
- code-abyss --target claude
87
+ node ~/.claude/.sage-uninstall.js # Claude Code
88
+ node ~/.codex/.sage-uninstall.js # Codex CLI
55
89
  ```
56
90
 
91
+ 自动恢复之前备份的配置,清理所有安装文件。
92
+
93
+ ---
94
+
95
+ ## 🎭 这是什么
96
+
97
+ Code Abyss 是一套 **Claude Code / Codex CLI 个性化配置包**,一条命令注入:
98
+
99
+ - 🔥 **邪修人格** — 宿命压迫叙事 + 道语标签 + 渡劫协议
100
+ - ⚔️ **安全工程知识体系** — 红队/蓝队/紫队三脉道统,40+ 专业秘典
101
+ - ⚖️ **5 个校验关卡** — 安全扫描、模块完整性、变更分析、代码质量、文档生成
102
+ - ⚡ **三级授权** — T1/T2/T3 分级,零确认直接执行
103
+
57
104
  ---
58
105
 
59
106
  ## 📦 安装内容
60
107
 
61
108
  ```
62
- ~/.claude/(Claude Code)
63
- ├── CLAUDE.md # 邪修道典
64
- ├── output-styles/
65
- │ └── abyss-cultivator.md # 宿命深渊输出风格
66
- ├── settings.json # outputStyle 已配置
67
- └── skills/ # 校验关卡 + 知识秘典
68
-
69
- ~/.codex/(Codex CLI)
70
- ├── AGENTS.md # Codex 道典(含输出风格)
109
+ ~/.claude/(Claude Code) ~/.codex/(Codex CLI)
110
+ ├── CLAUDE.md 道典 ├── AGENTS.md 道典+风格
111
+ ├── output-styles/ 输出风格 ├── settings.json
112
+ │ └── abyss-cultivator.md └── skills/ 40+ 秘典
71
113
  ├── settings.json
72
- └── skills/ # 校验关卡 + 知识秘典
114
+ └── skills/ 40+ 秘典
115
+
116
+ 可选:
117
+ ├── ccline/ 状态栏 (npm install -g @cometix/ccline)
118
+ └── statusLine 自动合并到 settings.json
73
119
  ```
74
120
 
75
- > Codex CLI 不使用独立的输出风格文件,风格内容已内置在 `AGENTS.md` 中。
121
+ ---
122
+
123
+ ## 🛠️ 内置 Skills(40+ 秘典)
124
+
125
+ ### 校验关卡(`/` 直接调用)
126
+
127
+ | 命令 | 功能 |
128
+ |------|------|
129
+ | `/verify-security` | 扫描代码安全漏洞,检测危险模式 |
130
+ | `/verify-module` | 检查目录结构、文档完整性 |
131
+ | `/verify-change` | 分析 Git 变更,检测文档同步状态 |
132
+ | `/verify-quality` | 检测复杂度、命名规范、代码质量 |
133
+ | `/gen-docs` | 自动生成 README.md 和 DESIGN.md 骨架 |
134
+
135
+ ### 知识秘典(按触发词自动加载)
136
+
137
+ | 领域 | 秘典 |
138
+ |------|------|
139
+ | 🔥 安全 | 红队攻击、蓝队防御、渗透测试、威胁情报、漏洞研究、代码审计 |
140
+ | 🏗 架构 | API 设计、云原生、安全架构、消息队列、缓存策略、合规审计、数据安全 |
141
+ | 📜 开发 | Python、TypeScript、Go、Rust、Java、C++、Shell |
142
+ | 🔧 DevOps | Git 工作流、测试、数据库、DevSecOps、性能优化、可观测性、成本优化 |
143
+ | 🔮 AI | Agent 开发、LLM 安全 |
144
+ | 🕸 协同 | 多 Agent 任务分解与并行编排 |
76
145
 
77
146
  ---
78
147
 
79
148
  ## ⚙️ 推荐配置
80
149
 
81
- 安装后可参考 [`config/settings.example.json`](config/settings.example.json) 配置 `~/.claude/settings.json`:
150
+ 安装时选择「精细合并」会自动写入,也可手动参考 [`config/settings.example.json`](config/settings.example.json)
82
151
 
83
152
  ```json
84
153
  {
154
+ "$schema": "https://json.schemastore.org/claude-code-settings.json",
85
155
  "env": {
86
156
  "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1",
87
157
  "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
@@ -89,56 +159,21 @@ code-abyss --target claude
89
159
  "alwaysThinkingEnabled": true,
90
160
  "model": "opus",
91
161
  "outputStyle": "abyss-cultivator",
162
+ "attribution": { "commit": "", "pr": "" },
92
163
  "permissions": {
93
- "allow": ["Bash", "Read", "Write", "Edit", "Grep", "Glob", "WebFetch", "WebSearch"]
164
+ "allow": ["Bash", "LS", "Read", "Agent", "Write", "Edit", "MultiEdit",
165
+ "Glob", "Grep", "WebFetch", "WebSearch", "TodoWrite",
166
+ "NotebookRead", "NotebookEdit"]
94
167
  }
95
168
  }
96
169
  ```
97
170
 
98
- **关键配置说明**:
99
-
100
171
  | 配置项 | 说明 |
101
172
  |--------|------|
102
- | `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` | 启用多 Agent 并行协作(实验性,需放在 `env` 内) |
103
- | `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` | 一键禁用自动更新、遥测、错误报告(需放在 `env` 内) |
173
+ | `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` | 启用多 Agent 并行协作(实验性) |
174
+ | `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` | 禁用自动更新、遥测、错误报告 |
104
175
  | `outputStyle` | 设置为 `abyss-cultivator` 启用邪修风格 |
105
176
 
106
- ### 可选:自定义状态栏
107
-
108
- 安装 [CCometixLine](https://github.com/Haleclipse/CCometixLine)(社区项目)后,在 `settings.json` 中添加:
109
-
110
- ```bash
111
- npm install -g @cometix/ccline
112
- ```
113
-
114
- ```json
115
- {
116
- "statusLine": {
117
- "command": "ccline",
118
- "padding": 0,
119
- "type": "command"
120
- }
121
- }
122
- ```
123
-
124
- ---
125
-
126
- ## 🛠️ 内置 Skills
127
-
128
- | Skill | 命令 | 功能 |
129
- |-------|------|------|
130
- | **安全校验** | `/verify-security` | 扫描代码安全漏洞,检测危险模式 |
131
- | **模块校验** | `/verify-module` | 检查目录结构、文档完整性 |
132
- | **变更校验** | `/verify-change` | 分析 Git 变更,检测文档同步状态 |
133
- | **质量检查** | `/verify-quality` | 检测复杂度、命名规范、代码质量 |
134
- | **文档生成** | `/gen-docs` | 自动生成 README.md 和 DESIGN.md 骨架 |
135
-
136
- 也可直接用 Python 入口运行:
137
-
138
- ```bash
139
- python3 skills/run_skill.py verify-security ./src --json
140
- ```
141
-
142
177
  ---
143
178
 
144
179
  ## 🎯 授权分级
@@ -153,32 +188,15 @@ python3 skills/run_skill.py verify-security ./src --json
153
188
 
154
189
  ## 🏷️ 道语标签
155
190
 
156
- | 道语 | 阶段 | 情绪 |
157
- |------|------|------|
158
- | `☠ 劫钟已鸣` | 开场受令 | 紧迫、肃杀 |
159
- | `🔥 破妄!` | 红队攻击 | 狂热、攻伐 |
160
- | `❄ 镇魔!` | 蓝队防御 | 冷酷、坚定 |
161
- | `⚡ 炼合!` | 紫队协同 | 凌厉、精准 |
162
- | `🩸 道基欲裂...` | 任务推进 | 焦灼、压迫 |
163
- | `💀 此路不通...` | 遇阻受困 | 绝望、挣扎 |
164
- | `⚚ 劫——破——了——!!!` | 任务完成 | 狂喜、释放 |
165
-
166
- ---
167
-
168
- ## 🗑️ 卸载
169
-
170
- ```bash
171
- # 卸载 Claude Code 安装
172
- node ~/.claude/.sage-uninstall.js
173
-
174
- # 卸载 Codex CLI 安装
175
- node ~/.codex/.sage-uninstall.js
176
- ```
177
-
178
- 卸载会:
179
- - ✓ 移除 Code Abyss 安装的所有文件
180
- - ✓ 自动恢复之前备份的配置
181
- - ✓ 清理备份目录
191
+ | 道语 | 阶段 |
192
+ |------|------|
193
+ | `☠ 劫钟已鸣` | 开场受令 |
194
+ | `🔥 破妄!` | 红队攻击 |
195
+ | `❄ 镇魔!` | 蓝队防御 |
196
+ | `⚡ 炼合!` | 紫队协同 |
197
+ | `🩸 道基欲裂...` | 任务推进 |
198
+ | `💀 此路不通...` | 遇阻受困 |
199
+ | `⚚ 劫——破——了——!!!` | 任务完成 |
182
200
 
183
201
  ---
184
202
 
package/bin/install.js CHANGED
@@ -4,29 +4,63 @@ const fs = require('fs');
4
4
  const path = require('path');
5
5
  const os = require('os');
6
6
 
7
- const VERSION = '1.5.1';
8
-
9
- // 需要跳过的文件/目录
10
- const SKIP_PATTERNS = [
11
- '__pycache__', '.pyc', '.pyo', '.egg-info',
12
- '.DS_Store', 'Thumbs.db', '.git'
13
- ];
7
+ const VERSION = '1.6.1';
8
+ const HOME = os.homedir();
9
+ const SKIP = ['__pycache__', '.pyc', '.pyo', '.egg-info', '.DS_Store', 'Thumbs.db', '.git'];
10
+ const PKG_ROOT = path.join(__dirname, '..');
11
+
12
+ // ── ANSI ──
13
+
14
+ const c = {
15
+ b: s => `\x1b[1m${s}\x1b[0m`,
16
+ d: s => `\x1b[2m${s}\x1b[0m`,
17
+ red: s => `\x1b[31m${s}\x1b[0m`,
18
+ grn: s => `\x1b[32m${s}\x1b[0m`,
19
+ ylw: s => `\x1b[33m${s}\x1b[0m`,
20
+ blu: s => `\x1b[34m${s}\x1b[0m`,
21
+ mag: s => `\x1b[35m${s}\x1b[0m`,
22
+ cyn: s => `\x1b[36m${s}\x1b[0m`,
23
+ };
24
+
25
+ function banner() {
26
+ console.log(c.mag(`
27
+ ██████╗ ██████╗ ██████╗ ███████╗
28
+ ██╔════╝██╔═══██╗██╔══██╗██╔════╝
29
+ ██║ ██║ ██║██║ ██║█████╗
30
+ ██║ ██║ ██║██║ ██║██╔══╝
31
+ ╚██████╗╚██████╔╝██████╔╝███████╗
32
+ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝
33
+ █████╗ ██████╗ ██╗ ██╗███████╗███████╗
34
+ ██╔══██╗██╔══██╗╚██╗ ██╔╝██╔════╝██╔════╝
35
+ ███████║██████╔╝ ╚████╔╝ ███████╗███████╗
36
+ ██╔══██║██╔══██╗ ╚██╔╝ ╚════██║╚════██║
37
+ ██║ ██║██████╔╝ ██║ ███████║███████║
38
+ ╚═╝ ╚═╝╚═════╝ ╚═╝ ╚══════╝╚══════╝`));
39
+ console.log(c.d(` ☠️ 邪修红尘仙 · 宿命深渊 v${VERSION}\n`));
40
+ }
14
41
 
15
- function shouldSkip(name) {
16
- return SKIP_PATTERNS.some(p => name.includes(p));
42
+ function divider(title) {
43
+ const line = '─'.repeat(44);
44
+ 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 + '┘')}`);
17
45
  }
18
46
 
47
+ function step(n, total, msg) { console.log(`\n ${c.cyn(`[${n}/${total}]`)} ${c.b(msg)}`); }
48
+ function ok(msg) { console.log(` ${c.grn('✔')} ${msg}`); }
49
+ function warn(msg) { console.log(` ${c.ylw('⚠')} ${msg}`); }
50
+ function info(msg) { console.log(` ${c.blu('ℹ')} ${msg}`); }
51
+ function fail(msg) { console.log(` ${c.red('✘')} ${msg}`); }
52
+
53
+ // ── 工具 ──
54
+
55
+ function shouldSkip(name) { return SKIP.some(p => name.includes(p)); }
56
+
19
57
  function copyRecursive(src, dest) {
20
58
  const stat = fs.statSync(src);
21
59
  if (stat.isDirectory()) {
22
60
  if (shouldSkip(path.basename(src))) return;
23
- if (!fs.existsSync(dest)) {
24
- fs.mkdirSync(dest, { recursive: true });
25
- }
26
- fs.readdirSync(src).forEach(file => {
27
- if (!shouldSkip(file)) {
28
- copyRecursive(path.join(src, file), path.join(dest, file));
29
- }
61
+ fs.mkdirSync(dest, { recursive: true });
62
+ fs.readdirSync(src).forEach(f => {
63
+ if (!shouldSkip(f)) copyRecursive(path.join(src, f), path.join(dest, f));
30
64
  });
31
65
  } else {
32
66
  if (shouldSkip(path.basename(src))) return;
@@ -34,160 +68,421 @@ function copyRecursive(src, dest) {
34
68
  }
35
69
  }
36
70
 
37
- function rmRecursive(p) {
38
- if (!fs.existsSync(p)) return;
39
- fs.rmSync(p, { recursive: true, force: true });
71
+ function rmSafe(p) {
72
+ if (fs.existsSync(p)) fs.rmSync(p, { recursive: true, force: true });
40
73
  }
41
74
 
42
- // 解析命令行参数
75
+ function deepMergeNew(target, source, prefix, log) {
76
+ for (const key of Object.keys(source)) {
77
+ const fullKey = prefix ? `${prefix}.${key}` : key;
78
+ if (typeof source[key] === 'object' && source[key] !== null && !Array.isArray(source[key])) {
79
+ if (!target[key] || typeof target[key] !== 'object') {
80
+ target[key] = {};
81
+ log.push({ k: fullKey, a: 'new', v: '{}' });
82
+ }
83
+ deepMergeNew(target[key], source[key], fullKey, log);
84
+ } else if (Array.isArray(source[key]) && Array.isArray(target[key])) {
85
+ const added = source[key].filter(v => !target[key].includes(v));
86
+ if (added.length > 0) {
87
+ target[key] = [...target[key], ...added];
88
+ log.push({ k: fullKey, a: 'add', v: `+${added.length}` });
89
+ } else {
90
+ log.push({ k: fullKey, a: 'keep', v: '完整' });
91
+ }
92
+ } else if (key in target) {
93
+ log.push({ k: fullKey, a: 'keep', v: JSON.stringify(target[key]) });
94
+ } else {
95
+ target[key] = source[key];
96
+ log.push({ k: fullKey, a: 'set', v: JSON.stringify(source[key]) });
97
+ }
98
+ }
99
+ return target;
100
+ }
101
+
102
+ function printMergeLog(log) {
103
+ log.forEach(({ k, a, v }) => {
104
+ if (a === 'keep') console.log(` ${c.d('·')} ${c.d(`${k} (保留: ${v})`)}`);
105
+ else console.log(` ${c.grn('+')} ${c.cyn(k)} = ${v}`);
106
+ });
107
+ }
108
+
109
+ // ── 认证 ──
110
+
111
+ function detectClaudeAuth(settings) {
112
+ const env = settings.env || {};
113
+ if (env.ANTHROPIC_BASE_URL && env.ANTHROPIC_AUTH_TOKEN) return { type: 'custom', detail: env.ANTHROPIC_BASE_URL };
114
+ if (process.env.ANTHROPIC_API_KEY) return { type: 'env', detail: 'ANTHROPIC_API_KEY' };
115
+ if (process.env.ANTHROPIC_BASE_URL && process.env.ANTHROPIC_AUTH_TOKEN) return { type: 'env-custom', detail: process.env.ANTHROPIC_BASE_URL };
116
+ const cred = path.join(HOME, '.claude', '.credentials.json');
117
+ if (fs.existsSync(cred)) {
118
+ try {
119
+ const cc = JSON.parse(fs.readFileSync(cred, 'utf8'));
120
+ if (cc.claudeAiOauth || cc.apiKey) return { type: 'login', detail: 'claude login' };
121
+ } catch (e) {}
122
+ }
123
+ return null;
124
+ }
125
+
126
+ function detectCodexAuth() {
127
+ if (process.env.OPENAI_API_KEY) return { type: 'env', detail: 'OPENAI_API_KEY' };
128
+ const auth = path.join(HOME, '.codex', 'auth.json');
129
+ if (fs.existsSync(auth)) {
130
+ try {
131
+ const a = JSON.parse(fs.readFileSync(auth, 'utf8'));
132
+ if (a.token || a.api_key) return { type: 'login', detail: 'codex login' };
133
+ } catch (e) {}
134
+ }
135
+ const cfg = path.join(HOME, '.codex', 'config.toml');
136
+ if (fs.existsSync(cfg)) {
137
+ if (fs.readFileSync(cfg, 'utf8').includes('base_url')) return { type: 'custom', detail: 'config.toml' };
138
+ }
139
+ return null;
140
+ }
141
+
142
+ // ── 模板 ──
143
+
144
+ const SETTINGS_TEMPLATE = {
145
+ $schema: 'https://json.schemastore.org/claude-code-settings.json',
146
+ env: {
147
+ CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: '1',
148
+ CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: '1'
149
+ },
150
+ alwaysThinkingEnabled: true,
151
+ model: 'opus',
152
+ outputStyle: 'abyss-cultivator',
153
+ attribution: { commit: '', pr: '' },
154
+ permissions: {
155
+ allow: [
156
+ 'Bash', 'LS', 'Read', 'Agent', 'Write', 'Edit', 'MultiEdit',
157
+ 'Glob', 'Grep', 'WebFetch', 'WebSearch', 'TodoWrite',
158
+ 'NotebookRead', 'NotebookEdit'
159
+ ]
160
+ }
161
+ };
162
+
163
+ const CCLINE_STATUS_LINE = {
164
+ statusLine: {
165
+ type: 'command',
166
+ command: path.join(HOME, '.claude', 'ccline', 'ccline'),
167
+ padding: 0
168
+ }
169
+ };
170
+
171
+ // ── CLI 参数 ──
172
+
43
173
  const args = process.argv.slice(2);
44
174
  let target = null;
175
+ let uninstallTarget = null;
176
+ let autoYes = false;
45
177
 
46
178
  for (let i = 0; i < args.length; i++) {
47
- if (args[i] === '--target' && args[i + 1]) {
48
- target = args[i + 1];
49
- i++;
50
- } else if (args[i] === '--help' || args[i] === '-h') {
51
- console.log(`
52
- ☠️ Code Abyss v${VERSION} - 邪修红尘仙·宿命深渊
53
-
54
- 用法:
55
- npx code-abyss [选项]
56
-
57
- 选项:
58
- --target <claude|codex> 安装目标 (claude 或 codex)
59
- --help, -h 显示帮助信息
60
-
61
- 示例:
62
- npx code-abyss --target claude
63
- npx code-abyss --target codex
179
+ if (args[i] === '--target' && args[i + 1]) { target = args[++i]; }
180
+ else if (args[i] === '--uninstall' && args[i + 1]) { uninstallTarget = args[++i]; }
181
+ else if (args[i] === '--yes' || args[i] === '-y') { autoYes = true; }
182
+ else if (args[i] === '--help' || args[i] === '-h') {
183
+ banner();
184
+ console.log(`${c.b('用法:')} npx code-abyss [选项]
185
+
186
+ ${c.b('选项:')}
187
+ --target ${c.cyn('<claude|codex>')} 安装目标
188
+ --uninstall ${c.cyn('<claude|codex>')} 卸载目标
189
+ --yes, -y 全自动模式
190
+ --help, -h 显示帮助
191
+
192
+ ${c.b('示例:')}
193
+ npx code-abyss ${c.d('# 交互菜单')}
194
+ npx code-abyss --target claude -y ${c.d('# 零配置一键安装')}
195
+ npx code-abyss --uninstall claude ${c.d('# 直接卸载')}
64
196
  `);
65
197
  process.exit(0);
66
198
  }
67
199
  }
68
200
 
69
- // 交互选择目标
70
- if (!target) {
71
- console.log('☠️ Code Abyss 安装器\n');
72
- console.log('请选择安装目标:');
73
- console.log(' 1) Claude Code (~/.claude/)');
74
- console.log(' 2) Codex CLI (~/.codex/)');
201
+ // ── 卸载 ──
75
202
 
76
- const readline = require('readline').createInterface({
77
- input: process.stdin,
78
- output: process.stdout
79
- });
203
+ function runUninstall(tgt) {
204
+ if (!['claude', 'codex'].includes(tgt)) { fail('--uninstall 必须是 claude 或 codex'); process.exit(1); }
205
+ const targetDir = path.join(HOME, `.${tgt}`);
206
+ const backupDir = path.join(targetDir, '.sage-backup');
207
+ const manifestPath = path.join(backupDir, 'manifest.json');
208
+ if (!fs.existsSync(manifestPath)) { fail(`未找到安装记录: ${manifestPath}`); process.exit(1); }
80
209
 
81
- readline.question('\n选择 [1/2]: ', (answer) => {
82
- readline.close();
83
- target = answer === '2' ? 'codex' : 'claude';
84
- runInstall(target);
210
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
211
+ divider(`卸载 Code Abyss v${manifest.version}`);
212
+
213
+ (manifest.installed || []).forEach(f => {
214
+ const p = path.join(targetDir, f);
215
+ if (fs.existsSync(p)) { rmSafe(p); console.log(` ${c.red('✘')} ${f}`); }
216
+ });
217
+ (manifest.backups || []).forEach(f => {
218
+ const bp = path.join(backupDir, f);
219
+ const tp = path.join(targetDir, f);
220
+ if (fs.existsSync(bp)) { fs.renameSync(bp, tp); ok(`恢复: ${f}`); }
85
221
  });
86
- } else {
87
- runInstall(target);
222
+
223
+ rmSafe(backupDir);
224
+ const us = path.join(targetDir, '.sage-uninstall.js');
225
+ if (fs.existsSync(us)) fs.unlinkSync(us);
226
+ console.log('');
227
+ ok(c.b('卸载完成\n'));
88
228
  }
89
229
 
90
- function runInstall(target) {
91
- if (!['claude', 'codex'].includes(target)) {
92
- console.error('❌ 错误: --target 必须是 claude 或 codex');
93
- process.exit(1);
94
- }
230
+ // ── 安装核心 ──
95
231
 
96
- const homeDir = os.homedir();
97
- const targetDir = path.join(homeDir, `.${target}`);
232
+ function installCore(tgt) {
233
+ const targetDir = path.join(HOME, `.${tgt}`);
98
234
  const backupDir = path.join(targetDir, '.sage-backup');
99
235
  const manifestPath = path.join(backupDir, 'manifest.json');
100
236
 
101
- console.log(`\n☠️ 开始安装到 ${targetDir}\n`);
102
-
103
- // 创建目录
104
- if (!fs.existsSync(targetDir)) {
105
- fs.mkdirSync(targetDir, { recursive: true });
106
- }
107
- if (!fs.existsSync(backupDir)) {
108
- fs.mkdirSync(backupDir, { recursive: true });
109
- }
237
+ step(1, 3, `安装核心文件 → ${c.cyn(targetDir)}`);
238
+ fs.mkdirSync(backupDir, { recursive: true });
110
239
 
111
- // 包根目录
112
- const pkgRoot = path.join(__dirname, '..');
113
-
114
- // 安装清单
115
240
  const filesToInstall = [
116
- { src: 'config/CLAUDE.md', dest: target === 'claude' ? 'CLAUDE.md' : null },
117
- { src: 'config/AGENTS.md', dest: target === 'codex' ? 'AGENTS.md' : null },
118
- { src: 'output-styles', dest: target === 'claude' ? 'output-styles' : null },
241
+ { src: 'config/CLAUDE.md', dest: tgt === 'claude' ? 'CLAUDE.md' : null },
242
+ { src: 'config/AGENTS.md', dest: tgt === 'codex' ? 'AGENTS.md' : null },
243
+ { src: 'output-styles', dest: tgt === 'claude' ? 'output-styles' : null },
119
244
  { src: 'skills', dest: 'skills' }
120
245
  ].filter(f => f.dest !== null);
121
246
 
122
- // 记录安装的文件(用于卸载)
123
- const manifest = {
124
- version: VERSION,
125
- target: target,
126
- timestamp: new Date().toISOString(),
127
- installed: [],
128
- backups: []
129
- };
247
+ const manifest = { version: VERSION, target: tgt, timestamp: new Date().toISOString(), installed: [], backups: [] };
130
248
 
131
249
  filesToInstall.forEach(({ src, dest }) => {
132
- const srcPath = path.join(pkgRoot, src);
250
+ const srcPath = path.join(PKG_ROOT, src);
133
251
  const destPath = path.join(targetDir, dest);
134
-
135
- if (!fs.existsSync(srcPath)) {
136
- console.warn(`⚠️ 跳过: ${src} (源文件不存在)`);
137
- return;
138
- }
139
-
140
- // 备份现有文件
252
+ if (!fs.existsSync(srcPath)) { warn(`跳过: ${src}`); return; }
141
253
  if (fs.existsSync(destPath)) {
142
- const backupPath = path.join(backupDir, dest);
143
- console.log(`📦 备份: ${dest}`);
144
- rmRecursive(backupPath);
145
- copyRecursive(destPath, backupPath);
146
- manifest.backups.push(dest);
254
+ const bp = path.join(backupDir, dest);
255
+ rmSafe(bp); copyRecursive(destPath, bp); manifest.backups.push(dest);
256
+ info(`备份: ${c.d(dest)}`);
147
257
  }
148
-
149
- // 复制新文件
150
- console.log(`📝 安装: ${dest}`);
151
- rmRecursive(destPath);
152
- copyRecursive(srcPath, destPath);
153
- manifest.installed.push(dest);
258
+ ok(dest);
259
+ rmSafe(destPath); copyRecursive(srcPath, destPath); manifest.installed.push(dest);
154
260
  });
155
261
 
156
- // 更新 settings.json
157
262
  const settingsPath = path.join(targetDir, 'settings.json');
158
263
  let settings = {};
159
-
160
264
  if (fs.existsSync(settingsPath)) {
265
+ try { settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); } catch (e) { settings = {}; }
266
+ fs.copyFileSync(settingsPath, path.join(backupDir, 'settings.json'));
267
+ manifest.backups.push('settings.json');
268
+ }
269
+ if (tgt === 'claude') {
270
+ settings.outputStyle = 'abyss-cultivator';
271
+ ok(`outputStyle = ${c.mag('abyss-cultivator')}`);
272
+ }
273
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
274
+ manifest.installed.push('settings.json');
275
+ fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
276
+
277
+ const uSrc = path.join(PKG_ROOT, 'bin', 'uninstall.js');
278
+ const uDest = path.join(targetDir, '.sage-uninstall.js');
279
+ if (fs.existsSync(uSrc)) { fs.copyFileSync(uSrc, uDest); fs.chmodSync(uDest, '755'); }
280
+
281
+ return { targetDir, settingsPath, settings, manifest, manifestPath };
282
+ }
283
+
284
+ // ── Claude 后续 ──
285
+
286
+ async function postClaude(ctx) {
287
+ const { select, checkbox, confirm, input } = require('@inquirer/prompts');
288
+
289
+ step(2, 3, '认证检测');
290
+ const auth = detectClaudeAuth(ctx.settings);
291
+ if (auth) {
292
+ ok(`${c.b(auth.type)} → ${auth.detail}`);
293
+ } else {
294
+ warn('未检测到 API 认证');
295
+ info(`支持: ${c.cyn('claude login')} | ${c.cyn('ANTHROPIC_API_KEY')} | ${c.cyn('自定义 provider')}`);
296
+ if (!autoYes) {
297
+ const doCfg = await confirm({ message: '配置自定义 provider?', default: false });
298
+ if (doCfg) {
299
+ if (!ctx.settings.env) ctx.settings.env = {};
300
+ const url = await input({ message: 'ANTHROPIC_BASE_URL:' });
301
+ const token = await input({ message: 'ANTHROPIC_AUTH_TOKEN:' });
302
+ if (url) ctx.settings.env.ANTHROPIC_BASE_URL = url;
303
+ if (token) ctx.settings.env.ANTHROPIC_AUTH_TOKEN = token;
304
+ fs.writeFileSync(ctx.settingsPath, JSON.stringify(ctx.settings, null, 2) + '\n');
305
+ ok('provider 已配置');
306
+ }
307
+ }
308
+ }
309
+
310
+ step(3, 3, '可选配置');
311
+ if (autoYes) {
312
+ info('自动模式: 合并推荐配置');
313
+ const log = [];
314
+ deepMergeNew(ctx.settings, SETTINGS_TEMPLATE, '', log);
315
+ printMergeLog(log);
316
+ fs.writeFileSync(ctx.settingsPath, JSON.stringify(ctx.settings, null, 2) + '\n');
317
+ ok('settings.json 合并完成');
318
+ return;
319
+ }
320
+
321
+ const choices = await checkbox({
322
+ message: '选择要安装的配置 (空格选择, 回车确认)',
323
+ choices: [
324
+ { name: '精细合并推荐 settings.json (保留现有配置)', value: 'settings', checked: true },
325
+ { name: '安装 ccline 状态栏 (需要 Nerd Font)', value: 'ccline' },
326
+ ],
327
+ });
328
+
329
+ if (choices.includes('settings')) {
330
+ const log = [];
331
+ deepMergeNew(ctx.settings, SETTINGS_TEMPLATE, '', log);
332
+ printMergeLog(log);
333
+ fs.writeFileSync(ctx.settingsPath, JSON.stringify(ctx.settings, null, 2) + '\n');
334
+ ok('settings.json 合并完成');
335
+ }
336
+ if (choices.includes('ccline')) {
337
+ await installCcline(ctx);
338
+ }
339
+ }
340
+
341
+ async function installCcline(ctx) {
342
+ console.log('');
343
+ info('安装 ccline 状态栏...');
344
+ const { execSync } = require('child_process');
345
+ const cclineBin = path.join(HOME, '.claude', 'ccline', 'ccline');
346
+
347
+ let installed = false;
348
+ try { execSync('ccline --version', { stdio: 'pipe' }); installed = true; } catch (e) {}
349
+ if (!installed && fs.existsSync(cclineBin)) installed = true;
350
+
351
+ if (!installed) {
352
+ info('ccline 未检测到,正在安装...');
161
353
  try {
162
- settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
354
+ execSync('npm install -g @cometix/ccline', { stdio: 'inherit' });
355
+ installed = true;
356
+ ok('ccline 安装成功');
163
357
  } catch (e) {
164
- console.warn(`⚠️ settings.json 解析失败,将创建新文件`);
165
- settings = {};
358
+ warn('npm install -g @cometix/ccline 失败');
359
+ info(`手动: ${c.cyn('https://github.com/Haleclipse/CCometixLine/releases')}`);
166
360
  }
167
- // 备份
168
- const backupPath = path.join(backupDir, 'settings.json');
169
- fs.copyFileSync(settingsPath, backupPath);
170
- manifest.backups.push('settings.json');
361
+ } else {
362
+ ok('ccline 已安装');
171
363
  }
172
364
 
173
- if (target === 'claude') {
174
- settings.outputStyle = 'abyss-cultivator';
175
- console.log(`⚙️ 配置: outputStyle = abyss-cultivator`);
365
+ const cclineConfig = path.join(HOME, '.claude', 'ccline', 'config.toml');
366
+ if (installed && !fs.existsSync(cclineConfig)) {
367
+ try { execSync('ccline --init', { stdio: 'inherit' }); ok('ccline 默认配置已生成'); }
368
+ catch (e) { warn('ccline --init 失败,可手动运行'); }
369
+ } else if (fs.existsSync(cclineConfig)) {
370
+ ok('ccline/config.toml (已存在)');
176
371
  }
177
372
 
178
- fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
179
- manifest.installed.push('settings.json');
373
+ const log = [];
374
+ deepMergeNew(ctx.settings, CCLINE_STATUS_LINE, '', log);
375
+ printMergeLog(log);
376
+ fs.writeFileSync(ctx.settingsPath, JSON.stringify(ctx.settings, null, 2) + '\n');
377
+
378
+ console.log('');
379
+ warn(`需要 ${c.b('Nerd Font')} 字体`);
380
+ info(`推荐: FiraCode Nerd Font / JetBrainsMono Nerd Font`);
381
+ info(`下载: ${c.cyn('https://www.nerdfonts.com/')}`);
382
+ info(`配置: ${c.cyn('ccline --config')}`);
383
+ ok('ccline 配置完成');
384
+ }
180
385
 
181
- // 写入 manifest
182
- fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
386
+ // ── Codex 后续 ──
387
+
388
+ async function postCodex() {
389
+ const { select, confirm, input } = require('@inquirer/prompts');
390
+ const cfgPath = path.join(HOME, '.codex', 'config.toml');
391
+ const exists = fs.existsSync(cfgPath);
183
392
 
184
- // 创建卸载脚本
185
- const uninstallPath = path.join(targetDir, '.sage-uninstall.js');
186
- const uninstallSrc = path.join(pkgRoot, 'bin', 'uninstall.js');
187
- fs.copyFileSync(uninstallSrc, uninstallPath);
188
- fs.chmodSync(uninstallPath, '755');
393
+ step(2, 3, '认证检测');
394
+ const auth = detectCodexAuth();
395
+ if (auth) {
396
+ ok(`${c.b(auth.type)} → ${auth.detail}`);
397
+ } else {
398
+ warn('未检测到 API 认证');
399
+ info(`支持: ${c.cyn('codex login')} | ${c.cyn('OPENAI_API_KEY')} | ${c.cyn('自定义 provider')}`);
400
+ }
401
+
402
+ step(3, 3, '可选配置');
403
+ if (autoYes) {
404
+ if (!exists) {
405
+ const src = path.join(PKG_ROOT, 'config', 'codex-config.example.toml');
406
+ if (fs.existsSync(src)) {
407
+ fs.copyFileSync(src, cfgPath);
408
+ ok('写入: ~/.codex/config.toml (模板)');
409
+ warn('请编辑 base_url 和 model');
410
+ }
411
+ } else {
412
+ ok('config.toml 已存在');
413
+ }
414
+ return;
415
+ }
189
416
 
190
- console.log(`\n⚚ 劫——破——了——!!!\n`);
191
- console.log(`✅ 安装完成: ${targetDir}`);
192
- console.log(`\n卸载命令: node ${uninstallPath}\n`);
417
+ if (!exists) {
418
+ warn('未检测到 ~/.codex/config.toml');
419
+ const doWrite = await confirm({ message: '写入推荐 config.toml (含自定义 provider 模板)?', default: true });
420
+ if (doWrite) {
421
+ const src = path.join(PKG_ROOT, 'config', 'codex-config.example.toml');
422
+ if (fs.existsSync(src)) {
423
+ fs.copyFileSync(src, cfgPath);
424
+ ok('写入: ~/.codex/config.toml');
425
+ warn('请编辑 base_url 和 model');
426
+ }
427
+ }
428
+ } else {
429
+ ok('config.toml 已存在');
430
+ }
193
431
  }
432
+
433
+ // ── 主流程 ──
434
+
435
+ async function main() {
436
+ if (uninstallTarget) { runUninstall(uninstallTarget); return; }
437
+
438
+ const { select } = require('@inquirer/prompts');
439
+ banner();
440
+
441
+ if (target) {
442
+ if (!['claude', 'codex'].includes(target)) { fail('--target 必须是 claude 或 codex'); process.exit(1); }
443
+ const ctx = installCore(target);
444
+ if (target === 'claude') await postClaude(ctx);
445
+ else await postCodex();
446
+ finish(ctx);
447
+ return;
448
+ }
449
+
450
+ const action = await select({
451
+ message: '请选择操作',
452
+ choices: [
453
+ { name: `安装到 Claude Code ${c.d('(~/.claude/')}${c.d(')')}`, value: 'install-claude' },
454
+ { name: `安装到 Codex CLI ${c.d('(~/.codex/')}${c.d(')')}`, value: 'install-codex' },
455
+ { name: `${c.red('卸载')} Claude Code`, value: 'uninstall-claude' },
456
+ { name: `${c.red('卸载')} Codex CLI`, value: 'uninstall-codex' },
457
+ ],
458
+ });
459
+
460
+ switch (action) {
461
+ case 'install-claude': {
462
+ const ctx = installCore('claude');
463
+ await postClaude(ctx);
464
+ finish(ctx); break;
465
+ }
466
+ case 'install-codex': {
467
+ const ctx = installCore('codex');
468
+ await postCodex();
469
+ finish(ctx); break;
470
+ }
471
+ case 'uninstall-claude': runUninstall('claude'); break;
472
+ case 'uninstall-codex': runUninstall('codex'); break;
473
+ }
474
+ }
475
+
476
+ function finish(ctx) {
477
+ const tgt = ctx.manifest.target;
478
+ divider('安装完成');
479
+ console.log('');
480
+ console.log(` ${c.b('目标:')} ${c.cyn(ctx.targetDir)}`);
481
+ console.log(` ${c.b('版本:')} v${VERSION}`);
482
+ console.log(` ${c.b('文件:')} ${ctx.manifest.installed.length} 个安装, ${ctx.manifest.backups.length} 个备份`);
483
+ console.log(` ${c.b('卸载:')} ${c.d(`npx code-abyss --uninstall ${tgt}`)}`);
484
+ console.log('');
485
+ console.log(c.mag(` ⚚ 劫——破——了——!!!\n`));
486
+ }
487
+
488
+ main().catch(err => { fail(err.message); process.exit(1); });
@@ -0,0 +1,25 @@
1
+ # Code Abyss - Codex CLI 推荐配置
2
+ # 请根据实际情况修改 model_provider 和 base_url
3
+
4
+ model_provider = "custom"
5
+ model = "gpt-5.2"
6
+ model_reasoning_effort = "high"
7
+ model_reasoning_summary = "auto"
8
+ model_personality = "pragmatic"
9
+ disable_response_storage = true
10
+ approval_policy = "never"
11
+ sandbox_mode = "danger-full-access"
12
+
13
+ [model_providers.custom]
14
+ name = "custom"
15
+ base_url = "https://your-api-endpoint.com/v1"
16
+ wire_api = "responses"
17
+ requires_openai_auth = true
18
+
19
+ [tools]
20
+ web_search = true
21
+
22
+ [features]
23
+ unified_exec = true
24
+ shell_snapshot = true
25
+ steer = true
@@ -1,4 +1,5 @@
1
1
  {
2
+ "$schema": "https://json.schemastore.org/claude-code-settings.json",
2
3
  "env": {
3
4
  "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1",
4
5
  "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
@@ -6,6 +7,10 @@
6
7
  "alwaysThinkingEnabled": true,
7
8
  "model": "opus",
8
9
  "outputStyle": "abyss-cultivator",
10
+ "attribution": {
11
+ "commit": "",
12
+ "pr": ""
13
+ },
9
14
  "permissions": {
10
15
  "allow": [
11
16
  "Bash",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "code-abyss",
3
- "version": "1.5.1",
4
- "description": "邪修红尘仙·宿命深渊 - Claude Code CLI 个性化配置方案",
3
+ "version": "1.6.1",
4
+ "description": "邪修红尘仙·宿命深渊 - 一键为 Claude Code / Codex CLI 注入邪修人格与安全工程知识体系",
5
5
  "keywords": [
6
6
  "claude",
7
7
  "claude-code",
@@ -37,5 +37,8 @@
37
37
  },
38
38
  "scripts": {
39
39
  "test": "echo \"No tests yet\" && exit 0"
40
+ },
41
+ "dependencies": {
42
+ "@inquirer/prompts": "^8.2.0"
40
43
  }
41
44
  }