code-abyss 1.7.7 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -111,8 +111,8 @@ Code Abyss 是一套 **Claude Code / Codex CLI 个性化配置包**,一条命
111
111
  ```
112
112
  ~/.claude/(Claude Code) ~/.codex/(Codex CLI)
113
113
  ├── CLAUDE.md 道典 ├── AGENTS.md 道典+风格
114
- ├── output-styles/ 输出风格 ├── settings.json
115
- │ └── abyss-cultivator.md └── skills/ 56 篇秘典
114
+ ├── output-styles/ 输出风格 ├── config.toml 推荐配置
115
+ │ └── abyss-cultivator.md ├── prompts/ custom prompts
116
116
  ├── settings.json
117
117
  └── skills/ 56 篇秘典
118
118
 
@@ -163,40 +163,59 @@ Code Abyss 是一套 **Claude Code / Codex CLI 个性化配置包**,一条命
163
163
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
164
164
  "env": {
165
165
  "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1",
166
- "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
166
+ "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1",
167
+ "CLAUDE_CODE_ENABLE_TASKS": "1",
168
+ "CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION": "1",
169
+ "ENABLE_TOOL_SEARCH": "auto:10"
167
170
  },
171
+ "defaultMode": "bypassPermissions",
168
172
  "alwaysThinkingEnabled": true,
173
+ "autoMemoryEnabled": true,
169
174
  "model": "opus",
170
175
  "outputStyle": "abyss-cultivator",
171
176
  "attribution": { "commit": "", "pr": "" },
177
+ "sandbox": { "autoAllowBashIfSandboxed": true },
172
178
  "permissions": {
173
- "allow": ["Bash", "LS", "Read", "Agent", "Write", "Edit", "MultiEdit",
174
- "Glob", "Grep", "WebFetch", "WebSearch", "TodoWrite",
175
- "NotebookRead", "NotebookEdit"]
179
+ "allow": ["Bash", "LS", "Read", "Edit", "Write", "MultiEdit",
180
+ "Agent", "Glob", "Grep", "WebFetch", "WebSearch",
181
+ "TodoWrite", "NotebookRead", "NotebookEdit", "mcp__*"]
176
182
  }
177
183
  }
178
184
  ```
179
185
 
180
186
  | 配置项 | 说明 |
181
187
  |--------|------|
188
+ | `defaultMode: bypassPermissions` | 跳过所有权限确认(`.git`等受保护目录仍会提示) |
189
+ | `autoMemoryEnabled` | 启用自动记忆,跨会话保留上下文 |
190
+ | `sandbox.autoAllowBashIfSandboxed` | 沙箱环境内自动放行 Bash 命令 |
182
191
  | `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` | 启用多 Agent 并行协作(实验性) |
183
192
  | `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` | 禁用自动更新、遥测、错误报告 |
193
+ | `CLAUDE_CODE_ENABLE_TASKS` | 启用任务管理功能 |
194
+ | `CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION` | 启用提示建议 |
195
+ | `ENABLE_TOOL_SEARCH` | MCP 工具自动搜索(auto:10 = 自动匹配前10个) |
196
+ | `mcp__*` | 自动放行所有 MCP 工具 |
184
197
  | `outputStyle` | 设置为 `abyss-cultivator` 启用邪修风格 |
185
198
 
186
199
  ---
187
200
 
188
201
  ### Codex `config.toml` 推荐模板
189
202
 
190
- 安装 `--target codex`(尤其 `-y`)时会写入以下模板到 `~/.codex/config.toml`:
203
+ 安装 `--target codex`(尤其 `-y`)时会写入以下 **全开默认档** 到 `~/.codex/config.toml`:
191
204
 
192
205
  ```toml
193
206
  model_provider = "custom"
194
207
  model = "gpt-5.2-codex"
195
208
  model_reasoning_effort = "high"
209
+ model_reasoning_summary = "detailed"
210
+ model_verbosity = "medium"
196
211
  approval_policy = "never"
197
212
  sandbox_mode = "danger-full-access"
198
213
  disable_response_storage = true
199
214
 
215
+ [profiles.safe]
216
+ approval_policy = "on-request"
217
+ sandbox_mode = "workspace-write"
218
+
200
219
  [model_providers.custom]
201
220
  name = "custom"
202
221
  base_url = "https://your-api-endpoint.com/v1"
@@ -208,14 +227,26 @@ web_search = true
208
227
 
209
228
  [features]
210
229
  multi_agent = true
230
+ shell_snapshot = true
231
+ undo = true
211
232
  ```
212
233
 
234
+ - 默认零审批 + 完全沙箱访问,适合安全研究/CTF/本地开发等高自动化场景
235
+ - `model_reasoning_summary = "detailed"` 输出详细推理摘要
236
+ - `shell_snapshot` / `undo` 启用快照与撤销功能
237
+ - 需要安全姿态时可显式切到 `safe`:`codex -p safe`
213
238
 
214
239
  ### 兼容性说明
215
240
 
216
- - 模板已对齐新版 Codex 配置风格:`[tools].web_search` 与 `[features].multi_agent`
217
- - 若你本地已有旧配置,安装器不会强制覆盖;会自动补齐 root 默认项(正确写入首段)、清理 removed feature、迁移 deprecated `web_search_*` `[tools].web_search`,并在 `danger-full-access` 下清理 `projects.*.trust_level`
218
- - 建议在升级后执行一次 `codex --help` / 启动自检,确认无 deprecation warning
241
+ - 模板已对齐新版 Codex 配置风格:root keys、`[profiles.*]`、`[tools].web_search` 与 `[features].multi_agent`
242
+ - 默认档从 safe 切换为全开(`approval_policy = "never"` + `sandbox_mode = "danger-full-access"`),提供 `[profiles.safe]` 作为保守回退
243
+ - Claude Code 默认启用 `bypassPermissions` 模式,跳过所有权限确认(`.git` 等受保护目录仍会提示)
244
+ - 新增实验功能环境变量:`CLAUDE_CODE_ENABLE_TASKS`、`CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION`
245
+ - 新增 `mcp__*` 通配符,自动放行所有 MCP 工具
246
+ - `Codex` 当前支持 `~/.codex/prompts/*.md` 作为 custom prompts;Code Abyss 会继续安装 `~/.codex/skills/`,并从 `user-invocable` skills 自动生成对应的 `prompts/`
247
+ - 安装器不会再为 Codex 写入伪配置 `~/.codex/settings.json`;若检测到旧版遗留文件,会在安装时备份后移除,卸载时恢复
248
+ - 若你本地已有旧配置,安装器不会强制覆盖;会自动补齐默认项、清理 removed feature、迁移 deprecated `web_search_*` 到 `[tools].web_search`
249
+ - 建议升级后执行一次 `codex --help`,或用 `codex -p safe --help` 校验 profile 可见性
219
250
 
220
251
  ---
221
252
 
@@ -228,7 +259,7 @@ multi_agent = true
228
259
  - `bin/lib/ccline.js`:Claude 侧状态栏与 ccline 集成
229
260
  - `bin/adapters/codex.js`:Codex 侧认证检测、核心文件映射、config 模板流程
230
261
 
231
- 当前 Claude/Codex 安装映射分别由 `getClaudeCoreFiles()` 与 `getCodexCoreFiles()` 提供,避免在主流程硬编码目标细节。
262
+ 当前 Claude/Codex 安装映射分别由 `getClaudeCoreFiles()` 与 `getCodexCoreFiles()` 提供;Claude 额外生成 `commands/`,Codex 保持 `skills/ + config.toml` 的官方主路径,避免在主流程硬编码目标细节。
232
263
 
233
264
  ---
234
265
 
@@ -7,17 +7,25 @@ const SETTINGS_TEMPLATE = {
7
7
  $schema: 'https://json.schemastore.org/claude-code-settings.json',
8
8
  env: {
9
9
  CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: '1',
10
- CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: '1'
10
+ CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: '1',
11
+ CLAUDE_CODE_ENABLE_TASKS: '1',
12
+ CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION: '1',
13
+ ENABLE_TOOL_SEARCH: 'auto:10'
11
14
  },
15
+ defaultMode: 'bypassPermissions',
12
16
  alwaysThinkingEnabled: true,
17
+ autoMemoryEnabled: true,
13
18
  model: 'opus',
14
19
  outputStyle: 'abyss-cultivator',
15
20
  attribution: { commit: '', pr: '' },
21
+ sandbox: {
22
+ autoAllowBashIfSandboxed: true
23
+ },
16
24
  permissions: {
17
25
  allow: [
18
- 'Bash', 'LS', 'Read', 'Agent', 'Write', 'Edit', 'MultiEdit',
19
- 'Glob', 'Grep', 'WebFetch', 'WebSearch', 'TodoWrite',
20
- 'NotebookRead', 'NotebookEdit'
26
+ 'Bash', 'LS', 'Read', 'Edit', 'Write', 'MultiEdit',
27
+ 'Agent', 'Glob', 'Grep', 'WebFetch', 'WebSearch',
28
+ 'TodoWrite', 'NotebookRead', 'NotebookEdit', 'mcp__*'
21
29
  ]
22
30
  }
23
31
  };
@@ -179,7 +179,7 @@ function removeKeyAssignmentsInNonRootSections(content, key) {
179
179
  function removeProjectTrustSectionsForFullAccess(content) {
180
180
  const eol = content.includes('\r\n') ? '\r\n' : '\n';
181
181
  const sandboxMode = readRootStringKey(content, 'sandbox_mode');
182
- if (sandboxMode !== CODEX_DEFAULTS.sandboxMode) {
182
+ if (sandboxMode !== 'danger-full-access') {
183
183
  return { merged: content, removed: false };
184
184
  }
185
185
 
package/bin/install.js CHANGED
@@ -186,92 +186,154 @@ function scanInvocableSkills(skillsDir) {
186
186
  return results;
187
187
  }
188
188
 
189
- /**
190
- * 根据 SKILL.md 元数据生成 command .md 内容
191
- *
192
- * 设计原则:
193
- * - 读取 SKILL.md + 执行脚本合并为一气呵成的指令流
194
- * - 禁止「先…然后…」的分步模式,避免 Claude 在步骤间停顿
195
- * - 无脚本的 skill:仅读取 SKILL.md 作为知识库提供指导
196
- *
197
- * @param {Object} meta - parseFrontmatter 返回的元数据
198
- * @param {string} skillRelPath - 相对于 skills/ 的路径(如 'tools/gen-docs'
199
- * @param {boolean} hasScripts - 是否有可执行脚本
200
- * @returns {string} command .md 文件内容
201
- */
202
- function generateCommandContent(meta, skillRelPath, hasScripts) {
203
- const name = meta.name;
189
+ const INVOCABLE_TARGETS = {
190
+ claude: {
191
+ dir: 'commands',
192
+ label: '斜杠命令',
193
+ skillRoot: '~/.claude/skills',
194
+ },
195
+ codex: {
196
+ dir: 'prompts',
197
+ label: 'custom prompts',
198
+ skillRoot: '~/.codex/skills',
199
+ },
200
+ };
201
+
202
+ function getInvocableTarget(targetName) {
203
+ const targetCfg = INVOCABLE_TARGETS[targetName];
204
+ if (!targetCfg) throw new Error(`不支持的 invocable target: ${targetName}`);
205
+ return targetCfg;
206
+ }
207
+
208
+ function getSkillPath(skillRoot, skillRelPath) {
209
+ return skillRelPath
210
+ ? `${skillRoot}/${skillRelPath}/SKILL.md`
211
+ : `${skillRoot}/SKILL.md`;
212
+ }
213
+
214
+ function buildCommandFrontmatter(meta) {
204
215
  const desc = (meta.description || '').replace(/"/g, '\\"');
205
216
  const argHint = meta['argument-hint'];
206
217
  const tools = meta['allowed-tools'] || 'Read';
207
- const skillPath = skillRelPath
208
- ? `~/.claude/skills/${skillRelPath}/SKILL.md`
209
- : '~/.claude/skills/SKILL.md';
210
-
211
- const lines = [
212
- '---',
213
- `name: ${name}`,
214
- `description: "${desc}"`,
215
- ];
218
+ const lines = ['---', `name: ${meta.name}`, `description: "${desc}"`];
219
+
216
220
  if (argHint) lines.push(`argument-hint: "${argHint}"`);
217
221
  lines.push(`allowed-tools: ${tools}`);
218
- lines.push('---');
219
- lines.push('');
222
+ lines.push('---', '');
223
+ return lines;
224
+ }
220
225
 
226
+ function buildClaudeBody(skillPath, meta, hasScripts) {
227
+ const lines = [];
221
228
  if (hasScripts) {
222
- // ── 有脚本的 skill:读取规范 + 执行脚本,一气呵成 ──
223
- lines.push('以下所有步骤一气呵成,不要在步骤间停顿等待用户输入:');
224
- lines.push('');
229
+ lines.push('以下所有步骤一气呵成,不要在步骤间停顿等待用户输入:', '');
225
230
  lines.push(`1. 读取规范:${skillPath}`);
226
- lines.push(`2. 执行命令:\`node ~/.claude/skills/run_skill.js ${name} $ARGUMENTS\``);
227
- lines.push('3. 按规范分析输出,完成后续动作');
228
- lines.push('');
231
+ lines.push(`2. 执行命令:\`node ~/.claude/skills/run_skill.js ${meta.name} $ARGUMENTS\``);
232
+ lines.push('3. 按规范分析输出,完成后续动作', '');
229
233
  lines.push('全程不要停顿,不要询问是否继续。');
230
- } else {
231
- // ── 无脚本的 skill:知识库模式 ──
232
- lines.push('读取以下秘典,根据内容为用户提供专业指导:');
233
- lines.push('');
234
- lines.push('```');
235
- lines.push(skillPath);
236
- lines.push('```');
234
+ return lines;
237
235
  }
238
236
 
239
- lines.push('');
240
- return lines.join('\n');
237
+ lines.push('读取以下秘典,根据内容为用户提供专业指导:', '');
238
+ lines.push('```', skillPath, '```');
239
+ return lines;
241
240
  }
242
241
 
243
- /**
244
- * 扫描 skills 并为 user-invocable 的 skill 生成 command 包装,文件级合并安装
245
- */
246
- function installGeneratedCommands(skillsSrcDir, targetDir, backupDir, manifest) {
242
+ function buildCodexPromptBody(skillPath, meta, hasScripts) {
243
+ const lines = [];
244
+ if (meta['argument-hint']) lines.push(`Arguments: ${meta['argument-hint']}`, '');
245
+ lines.push(`Read \`${skillPath}\` before acting.`, '');
246
+ if (hasScripts) {
247
+ lines.push(`Then run \`node ~/.codex/skills/run_skill.js ${meta.name} $ARGUMENTS\`.`);
248
+ lines.push('Do not stop between steps unless blocked by permissions or missing required inputs.');
249
+ lines.push('Use the skill guidance plus script output to complete the task end-to-end.');
250
+ return lines;
251
+ }
252
+
253
+ lines.push('Use that skill as the authoritative playbook for the task.');
254
+ lines.push('Respond with concrete actions instead of generic advice.');
255
+ return lines;
256
+ }
257
+
258
+ function generateInvocableContent(meta, skillRelPath, hasScripts, targetName) {
259
+ const targetCfg = getInvocableTarget(targetName);
260
+ const skillPath = getSkillPath(targetCfg.skillRoot, skillRelPath);
261
+ const lines = targetName === 'claude' ? buildCommandFrontmatter(meta) : [];
262
+ const body = targetName === 'claude'
263
+ ? buildClaudeBody(skillPath, meta, hasScripts)
264
+ : buildCodexPromptBody(skillPath, meta, hasScripts);
265
+ return [...lines, ...body, ''].join('\n');
266
+ }
267
+
268
+ function generateCommandContent(meta, skillRelPath, hasScripts) {
269
+ return generateInvocableContent(meta, skillRelPath, hasScripts, 'claude');
270
+ }
271
+
272
+ function generatePromptContent(meta, skillRelPath, hasScripts) {
273
+ return generateInvocableContent(meta, skillRelPath, hasScripts, 'codex');
274
+ }
275
+
276
+ function installGeneratedArtifacts(skillsSrcDir, targetDir, backupDir, manifest, targetName) {
247
277
  const skills = scanInvocableSkills(skillsSrcDir);
248
278
  if (skills.length === 0) return 0;
249
279
 
250
- const cmdsDir = path.join(targetDir, 'commands');
251
- fs.mkdirSync(cmdsDir, { recursive: true });
280
+ const targetCfg = getInvocableTarget(targetName);
281
+ const installDir = path.join(targetDir, targetCfg.dir);
282
+ fs.mkdirSync(installDir, { recursive: true });
252
283
 
253
284
  skills.forEach(({ meta, relPath, hasScripts }) => {
254
285
  const fileName = `${meta.name}.md`;
255
- const destFile = path.join(cmdsDir, fileName);
256
- const relFile = path.posix.join('commands', fileName);
286
+ const destFile = path.join(installDir, fileName);
287
+ const relFile = path.posix.join(targetCfg.dir, fileName);
257
288
 
258
289
  if (fs.existsSync(destFile)) {
259
- const cmdsBackupDir = path.join(backupDir, 'commands');
260
- fs.mkdirSync(cmdsBackupDir, { recursive: true });
261
- fs.copyFileSync(destFile, path.join(cmdsBackupDir, fileName));
290
+ const backupSubdir = path.join(backupDir, targetCfg.dir);
291
+ fs.mkdirSync(backupSubdir, { recursive: true });
292
+ fs.copyFileSync(destFile, path.join(backupSubdir, fileName));
262
293
  manifest.backups.push(relFile);
263
294
  info(`备份: ${c.d(relFile)}`);
264
295
  }
265
296
 
266
- const content = generateCommandContent(meta, relPath, hasScripts);
297
+ const content = generateInvocableContent(meta, relPath, hasScripts, targetName);
267
298
  fs.writeFileSync(destFile, content);
268
299
  manifest.installed.push(relFile);
269
300
  });
270
301
 
271
- ok(`commands/ ${c.d(`(自动生成 ${skills.length} 个斜杠命令)`)}`);
302
+ ok(`${targetCfg.dir}/ ${c.d(`(自动生成 ${skills.length} 个 ${targetCfg.label})`)}`);
272
303
  return skills.length;
273
304
  }
274
305
 
306
+ function installGeneratedCommands(skillsSrcDir, targetDir, backupDir, manifest) {
307
+ return installGeneratedArtifacts(skillsSrcDir, targetDir, backupDir, manifest, 'claude');
308
+ }
309
+
310
+ function installGeneratedPrompts(skillsSrcDir, targetDir, backupDir, manifest) {
311
+ return installGeneratedArtifacts(skillsSrcDir, targetDir, backupDir, manifest, 'codex');
312
+ }
313
+
314
+ function backupPathIfExists(targetDir, backupDir, relPath, manifest) {
315
+ const targetPath = path.join(targetDir, relPath);
316
+ if (!fs.existsSync(targetPath)) return false;
317
+
318
+ const backupPath = path.join(backupDir, relPath);
319
+ rmSafe(backupPath);
320
+ copyRecursive(targetPath, backupPath);
321
+ manifest.backups.push(relPath);
322
+ info(`备份: ${c.d(relPath)}`);
323
+ return true;
324
+ }
325
+
326
+ function pruneLegacyCodexSettings(targetDir, backupDir, manifest) {
327
+ const relPath = 'settings.json';
328
+ const settingsPath = path.join(targetDir, relPath);
329
+ if (!fs.existsSync(settingsPath)) return null;
330
+
331
+ backupPathIfExists(targetDir, backupDir, relPath, manifest);
332
+ rmSafe(settingsPath);
333
+ warn('移除 legacy settings.json(Codex 已改用 config.toml)');
334
+ return settingsPath;
335
+ }
336
+
275
337
  function installCore(tgt) {
276
338
  const targetDir = path.join(HOME, `.${tgt}`);
277
339
  const backupDir = path.join(targetDir, '.sage-backup');
@@ -309,30 +371,37 @@ function installCore(tgt) {
309
371
  rmSafe(destPath); copyRecursive(srcPath, destPath); manifest.installed.push(dest);
310
372
  });
311
373
 
312
- // Claude 目标自动生成 user-invocable 斜杠命令
374
+ // 为目标 CLI 自动生成 user-invocable artifacts
313
375
  if (tgt === 'claude') {
314
376
  const skillsSrc = path.join(PKG_ROOT, 'skills');
315
377
  installGeneratedCommands(skillsSrc, targetDir, backupDir, manifest);
378
+ } else if (tgt === 'codex') {
379
+ const skillsSrc = path.join(PKG_ROOT, 'skills');
380
+ installGeneratedPrompts(skillsSrc, targetDir, backupDir, manifest);
316
381
  }
317
382
 
318
- const settingsPath = path.join(targetDir, 'settings.json');
383
+ let settingsPath = null;
319
384
  let settings = {};
320
- if (fs.existsSync(settingsPath)) {
321
- try {
322
- settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
323
- } catch (e) {
324
- warn(`settings.json 解析失败,将使用空配置`);
325
- settings = {};
326
- }
327
- fs.copyFileSync(settingsPath, path.join(backupDir, 'settings.json'));
328
- manifest.backups.push('settings.json');
329
- }
330
385
  if (tgt === 'claude') {
386
+ settingsPath = path.join(targetDir, 'settings.json');
387
+ if (fs.existsSync(settingsPath)) {
388
+ try {
389
+ settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
390
+ } catch (e) {
391
+ warn('settings.json 解析失败,将使用空配置');
392
+ settings = {};
393
+ }
394
+ fs.copyFileSync(settingsPath, path.join(backupDir, 'settings.json'));
395
+ manifest.backups.push('settings.json');
396
+ }
331
397
  settings.outputStyle = 'abyss-cultivator';
332
398
  ok(`outputStyle = ${c.mag('abyss-cultivator')}`);
399
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
400
+ manifest.installed.push('settings.json');
401
+ } else {
402
+ pruneLegacyCodexSettings(targetDir, backupDir, manifest);
333
403
  }
334
- fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
335
- manifest.installed.push('settings.json');
404
+
336
405
  fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
337
406
 
338
407
  const uSrc = path.join(PKG_ROOT, 'bin', 'uninstall.js');
@@ -438,5 +507,9 @@ if (require.main === module) {
438
507
  module.exports = {
439
508
  deepMergeNew, detectClaudeAuth, detectCodexAuth,
440
509
  detectCclineBin, copyRecursive, shouldSkip, SETTINGS_TEMPLATE,
441
- scanInvocableSkills, generateCommandContent, installGeneratedCommands
510
+ scanInvocableSkills,
511
+ generateCommandContent,
512
+ generatePromptContent,
513
+ installGeneratedCommands,
514
+ installGeneratedPrompts,
442
515
  };