code-abyss 1.7.6 → 1.8.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
 
@@ -187,15 +187,19 @@ Code Abyss 是一套 **Claude Code / Codex CLI 个性化配置包**,一条命
187
187
 
188
188
  ### Codex `config.toml` 推荐模板
189
189
 
190
- 安装 `--target codex`(尤其 `-y`)时会写入以下模板到 `~/.codex/config.toml`:
190
+ 安装 `--target codex`(尤其 `-y`)时会写入以下 **safe 默认档** 到 `~/.codex/config.toml`:
191
191
 
192
192
  ```toml
193
193
  model_provider = "custom"
194
194
  model = "gpt-5.2-codex"
195
195
  model_reasoning_effort = "high"
196
+ approval_policy = "on-request"
197
+ sandbox_mode = "workspace-write"
198
+ disable_response_storage = true
199
+
200
+ [profiles.full_access]
196
201
  approval_policy = "never"
197
202
  sandbox_mode = "danger-full-access"
198
- disable_response_storage = true
199
203
 
200
204
  [model_providers.custom]
201
205
  name = "custom"
@@ -210,12 +214,16 @@ web_search = true
210
214
  multi_agent = true
211
215
  ```
212
216
 
217
+ - 日常交互默认使用 `on-request + workspace-write`,更贴近当前 Codex CLI 的低摩擦安全姿态
218
+ - 需要高自动化时可显式切到 `full_access`:`codex -p full_access`
213
219
 
214
220
  ### 兼容性说明
215
221
 
216
- - 模板已对齐新版 Codex 配置风格:`[tools].web_search` 与 `[features].multi_agent`
217
- - 若你本地已有旧配置,安装器不会强制覆盖;会自动做三件事:补齐缺失默认项、清理 removed feature、将 deprecated `web_search_*` 迁移为 `[tools].web_search`
218
- - 建议在升级后执行一次 `codex --help` / 启动自检,确认无 deprecation warning
222
+ - 模板已对齐新版 Codex 配置风格:root keys、`[profiles.*]`、`[tools].web_search` 与 `[features].multi_agent`
223
+ - `Codex` 当前支持 `~/.codex/prompts/*.md` 作为 custom prompts;Code Abyss 会继续安装 `~/.codex/skills/`,并从 `user-invocable` skills 自动生成对应的 `prompts/`
224
+ - 安装器不会再为 Codex 写入伪配置 `~/.codex/settings.json`;若检测到旧版遗留文件,会在安装时备份后移除,卸载时恢复
225
+ - 若你本地已有旧配置,安装器不会强制覆盖;会自动补齐 safe root 默认项、清理 removed feature、迁移 deprecated `web_search_*` 到 `[tools].web_search`,并仅在 `danger-full-access` 下清理 `projects.*.trust_level`
226
+ - 建议升级后执行一次 `codex --help`,或用 `codex -p full_access --help` 校验 profile 可见性
219
227
 
220
228
  ---
221
229
 
@@ -228,7 +236,7 @@ multi_agent = true
228
236
  - `bin/lib/ccline.js`:Claude 侧状态栏与 ccline 集成
229
237
  - `bin/adapters/codex.js`:Codex 侧认证检测、核心文件映射、config 模板流程
230
238
 
231
- 当前 Claude/Codex 安装映射分别由 `getClaudeCoreFiles()` 与 `getCodexCoreFiles()` 提供,避免在主流程硬编码目标细节。
239
+ 当前 Claude/Codex 安装映射分别由 `getClaudeCoreFiles()` 与 `getCodexCoreFiles()` 提供;Claude 额外生成 `commands/`,Codex 保持 `skills/ + config.toml` 的官方主路径,避免在主流程硬编码目标细节。
232
240
 
233
241
  ---
234
242
 
@@ -4,7 +4,8 @@ const fs = require('fs');
4
4
  const path = require('path');
5
5
 
6
6
  const CODEX_DEFAULTS = {
7
- sandboxMode: 'danger-full-access',
7
+ approvalPolicy: 'on-request',
8
+ sandboxMode: 'workspace-write',
8
9
  featureFlag: 'multi_agent',
9
10
  };
10
11
 
@@ -28,9 +29,50 @@ function escapeRegExp(input) {
28
29
  return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
29
30
  }
30
31
 
31
- function hasTopLevelKey(content, key) {
32
- const re = new RegExp(`^\\s*${escapeRegExp(key)}\\s*=`, 'm');
33
- return re.test(content);
32
+ function isTableHeader(line) {
33
+ return /^\s*\[[^\]]+\]\s*$/.test(line);
34
+ }
35
+
36
+ function isProjectTableHeader(line) {
37
+ return /^\s*\[projects\."[^"]+"\]\s*$/.test(line);
38
+ }
39
+
40
+ function isAssignmentForKey(line, key) {
41
+ const re = new RegExp(`^\\s*${escapeRegExp(key)}\\s*=`);
42
+ return re.test(line);
43
+ }
44
+
45
+ function hasRootKey(content, key) {
46
+ const lines = content.split(/\r?\n/);
47
+ let inRoot = true;
48
+
49
+ for (const line of lines) {
50
+ if (isTableHeader(line)) {
51
+ inRoot = false;
52
+ continue;
53
+ }
54
+ if (inRoot && isAssignmentForKey(line, key)) {
55
+ return true;
56
+ }
57
+ }
58
+ return false;
59
+ }
60
+
61
+ function readRootStringKey(content, key) {
62
+ const lines = content.split(/\r?\n/);
63
+ const re = new RegExp(`^\\s*${escapeRegExp(key)}\\s*=\\s*"([^"]*)"`);
64
+ let inRoot = true;
65
+
66
+ for (const line of lines) {
67
+ if (isTableHeader(line)) {
68
+ inRoot = false;
69
+ continue;
70
+ }
71
+ if (!inRoot) continue;
72
+ const m = line.match(re);
73
+ if (m) return m[1];
74
+ }
75
+ return null;
34
76
  }
35
77
 
36
78
  function hasSection(content, sectionName) {
@@ -66,6 +108,20 @@ function appendLine(content, line, eol) {
66
108
  return `${normalized}${line}${eol}`;
67
109
  }
68
110
 
111
+ function insertRootLine(content, line, eol) {
112
+ if (!content) return `${line}${eol}`;
113
+ const lines = content.split(/\r?\n/);
114
+ const firstSection = lines.findIndex((l) => isTableHeader(l));
115
+ const idx = firstSection === -1 ? lines.length : firstSection;
116
+ lines.splice(idx, 0, line);
117
+ return lines.join(eol);
118
+ }
119
+
120
+ function ensureRootKey(content, key, valueLiteral, eol) {
121
+ if (hasRootKey(content, key)) return { merged: content, added: false };
122
+ return { merged: insertRootLine(content, `${key} = ${valueLiteral}`, eol), added: true };
123
+ }
124
+
69
125
  function insertLineAfterSectionHeader(content, sectionName, line, eol) {
70
126
  const lines = content.split(/\r?\n/);
71
127
  const sectionRe = new RegExp(`^\\s*\\[${escapeRegExp(sectionName)}\\]\\s*$`);
@@ -97,6 +153,59 @@ function parseTomlBooleanAssignment(line) {
97
153
  return m[1].toLowerCase() === 'true';
98
154
  }
99
155
 
156
+ function removeKeyAssignmentsInNonRootSections(content, key) {
157
+ const eol = content.includes('\r\n') ? '\r\n' : '\n';
158
+ const lines = content.split(/\r?\n/);
159
+ const kept = [];
160
+ let inRoot = true;
161
+ let removed = false;
162
+
163
+ for (const line of lines) {
164
+ if (isTableHeader(line)) {
165
+ inRoot = false;
166
+ kept.push(line);
167
+ continue;
168
+ }
169
+ if (!inRoot && isAssignmentForKey(line, key)) {
170
+ removed = true;
171
+ continue;
172
+ }
173
+ kept.push(line);
174
+ }
175
+
176
+ return { merged: kept.join(eol), removed };
177
+ }
178
+
179
+ function removeProjectTrustSectionsForFullAccess(content) {
180
+ const eol = content.includes('\r\n') ? '\r\n' : '\n';
181
+ const sandboxMode = readRootStringKey(content, 'sandbox_mode');
182
+ if (sandboxMode !== 'danger-full-access') {
183
+ return { merged: content, removed: false };
184
+ }
185
+
186
+ const lines = content.split(/\r?\n/);
187
+ const kept = [];
188
+ let inProjectSection = false;
189
+ let removed = false;
190
+
191
+ for (const line of lines) {
192
+ if (isTableHeader(line)) {
193
+ if (isProjectTableHeader(line)) {
194
+ inProjectSection = true;
195
+ removed = true;
196
+ continue;
197
+ }
198
+ inProjectSection = false;
199
+ kept.push(line);
200
+ continue;
201
+ }
202
+ if (inProjectSection) continue;
203
+ kept.push(line);
204
+ }
205
+
206
+ return { merged: kept.join(eol), removed };
207
+ }
208
+
100
209
  function removeFeatureFlagsFromFeaturesSection(content, featureNames) {
101
210
  const eol = content.includes('\r\n') ? '\r\n' : '\n';
102
211
  const lines = content.split(/\r?\n/);
@@ -167,8 +276,28 @@ function mergeCodexConfigDefaults(content) {
167
276
  let merged = content;
168
277
  const added = [];
169
278
 
170
- if (!hasTopLevelKey(merged, 'sandbox_mode')) {
171
- merged = appendLine(merged, `sandbox_mode = "${CODEX_DEFAULTS.sandboxMode}"`, eol);
279
+ const rootKeys = [
280
+ 'approval_policy',
281
+ 'sandbox_mode',
282
+ 'model_reasoning_effort',
283
+ 'disable_response_storage',
284
+ 'personality',
285
+ ];
286
+
287
+ for (const key of rootKeys) {
288
+ const cleaned = removeKeyAssignmentsInNonRootSections(merged, key);
289
+ merged = cleaned.merged;
290
+ }
291
+
292
+ const approval = ensureRootKey(merged, 'approval_policy', `"${CODEX_DEFAULTS.approvalPolicy}"`, eol);
293
+ merged = approval.merged;
294
+ if (approval.added) {
295
+ added.push('approval_policy');
296
+ }
297
+
298
+ const sandbox = ensureRootKey(merged, 'sandbox_mode', `"${CODEX_DEFAULTS.sandboxMode}"`, eol);
299
+ merged = sandbox.merged;
300
+ if (sandbox.added) {
172
301
  added.push('sandbox_mode');
173
302
  }
174
303
 
@@ -187,9 +316,12 @@ function mergeCodexConfigDefaults(content) {
187
316
  function patchCodexConfig(cfgPath) {
188
317
  const raw = fs.readFileSync(cfgPath, 'utf8');
189
318
  const { merged: cleaned, removed, migrated } = cleanupLegacyCodexConfig(raw);
190
- const { merged, added } = mergeCodexConfigDefaults(cleaned);
319
+ const { merged: mergedDefaults, added } = mergeCodexConfigDefaults(cleaned);
320
+ const { merged, removed: removedProjectTrust } = removeProjectTrustSectionsForFullAccess(mergedDefaults);
321
+ const removedAll = removedProjectTrust ? [...removed, 'projects.*.trust_level'] : removed;
322
+
191
323
  if (merged !== raw) fs.writeFileSync(cfgPath, merged);
192
- return { added, removed, migrated };
324
+ return { added, removed: removedAll, migrated };
193
325
  }
194
326
 
195
327
  function patchCodexConfigDefaults(cfgPath) {
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
  };
@@ -1,9 +1,13 @@
1
1
  model_provider = "custom"
2
2
  model = "gpt-5.2-codex"
3
3
  model_reasoning_effort = "high"
4
+ approval_policy = "on-request"
5
+ sandbox_mode = "workspace-write"
6
+ disable_response_storage = true
7
+
8
+ [profiles.full_access]
4
9
  approval_policy = "never"
5
10
  sandbox_mode = "danger-full-access"
6
- disable_response_storage = true
7
11
 
8
12
  [model_providers.custom]
9
13
  name = "custom"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-abyss",
3
- "version": "1.7.6",
3
+ "version": "1.8.0",
4
4
  "description": "邪修红尘仙·宿命深渊 - 一键为 Claude Code / Codex CLI 注入邪修人格与安全工程知识体系",
5
5
  "keywords": [
6
6
  "claude",