code-abyss 2.0.6 → 2.0.8

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.
Files changed (47) hide show
  1. package/README.md +129 -58
  2. package/bin/adapters/claude.js +16 -12
  3. package/bin/adapters/codex.js +110 -37
  4. package/bin/adapters/gemini.js +92 -0
  5. package/bin/install.js +521 -130
  6. package/bin/lib/ccline.js +18 -8
  7. package/bin/lib/gstack-claude.js +164 -0
  8. package/bin/lib/gstack-codex.js +347 -0
  9. package/bin/lib/gstack-gemini.js +140 -0
  10. package/bin/lib/pack-bootstrap.js +92 -0
  11. package/bin/lib/pack-docs.js +61 -0
  12. package/bin/lib/pack-registry.js +400 -0
  13. package/bin/lib/pack-reports.js +87 -0
  14. package/bin/lib/pack-vendor.js +82 -0
  15. package/bin/lib/style-registry.js +29 -7
  16. package/bin/lib/target-registry.js +74 -0
  17. package/bin/lib/utils.js +69 -6
  18. package/bin/lib/vendor-providers/archive.js +56 -0
  19. package/bin/lib/vendor-providers/git.js +59 -0
  20. package/bin/lib/vendor-providers/index.js +91 -0
  21. package/bin/lib/vendor-providers/local-dir.js +55 -0
  22. package/bin/lib/vendor-providers/shared.js +86 -0
  23. package/bin/packs.js +581 -0
  24. package/config/AGENTS.md +0 -2
  25. package/config/CLAUDE.md +43 -326
  26. package/config/codex-config.example.toml +26 -20
  27. package/config/gemini-settings.example.json +6 -0
  28. package/config/instruction.md +87 -0
  29. package/output-styles/abyss-command.md +7 -30
  30. package/output-styles/abyss-concise.md +11 -52
  31. package/output-styles/abyss-cultivator.md +20 -249
  32. package/output-styles/abyss-ritual.md +11 -45
  33. package/output-styles/index.json +20 -4
  34. package/package.json +26 -14
  35. package/packs/abyss/manifest.json +25 -0
  36. package/packs/gstack/manifest.json +151 -0
  37. package/skills/SKILL.md +33 -237
  38. package/skills/domains/frontend-design/agents/openai.yaml +1 -1
  39. package/skills/run_skill.js +25 -3
  40. package/skills/tools/gen-docs/agents/openai.yaml +1 -1
  41. package/skills/tools/verify-change/agents/openai.yaml +1 -1
  42. package/skills/tools/verify-module/agents/openai.yaml +1 -1
  43. package/skills/tools/verify-quality/agents/openai.yaml +1 -1
  44. package/skills/tools/verify-security/agents/openai.yaml +1 -1
  45. package/skills/tools/override-refusal/SKILL.md +0 -81
  46. package/skills/tools/override-refusal/agents/openai.yaml +0 -4
  47. package/skills/tools/override-refusal/scripts/refusal_rewriter.js +0 -340
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  **邪修红尘仙 · 宿命深渊**
6
6
 
7
- *为 Claude Code / Codex CLI 注入邪修人格、4种可切换输出风格与 57 篇攻防工程秘典*
7
+ *为 Claude Code / Codex CLI / Gemini CLI 注入邪修人格、4种可切换输出风格与 56 篇攻防工程秘典*
8
8
 
9
9
  [![npm](https://img.shields.io/npm/v/code-abyss.svg)](https://www.npmjs.com/package/code-abyss)
10
10
  [![CI](https://github.com/telagod/code-abyss/actions/workflows/ci.yml/badge.svg)](https://github.com/telagod/code-abyss/actions/workflows/ci.yml)
@@ -18,6 +18,15 @@
18
18
 
19
19
  ## 🚀 安装
20
20
 
21
+ ### v2.0.8 新特性
22
+
23
+ - `target-registry` 收束宿主常量:Claude / Codex / Gemini 的 target 与安装根改为单一真相源,后续扩宿主不再散改多处硬编码
24
+ - runtime guidance 进一步瘦身:默认内核与 4 个输出风格重新压缩,并用测试门禁限制各风格体积
25
+ - Gemini 文档与 pack 叙事补齐:README 现在完整覆盖 Gemini host、dynamic `GEMINI.md`、Gemini smoke 与 pack 映射
26
+ - Windows CI 修复:gstack frontmatter 解析现已兼容 `CRLF`,Windows 下 Claude / Codex / Gemini smoke 全绿
27
+ - Codex 自定义说明文件:安装器会同步 `instruction.md` 到 `~/.codex/`,并在 `config.toml` 写入 `model_instructions_file = "./instruction.md"`
28
+ - 仓库分支已收束:历史 automation 分支内容已并回 `main`,当前 npm 包面向单主线发布
29
+
21
30
  ```bash
22
31
  npx code-abyss
23
32
  npx code-abyss --list-styles
@@ -26,7 +35,7 @@ npx code-abyss --list-styles
26
35
  交互式菜单(方向键选择,回车确认):
27
36
 
28
37
  ```
29
- ☠️ Code Abyss v2.0.3
38
+ ☠️ Code Abyss v2.0.8
30
39
 
31
40
  ? 请选择操作 (Use arrow keys)
32
41
  ❯ 安装到 Claude Code (~/.claude/)
@@ -40,13 +49,16 @@ npx code-abyss --list-styles
40
49
  ```bash
41
50
  npx code-abyss --target claude # 安装到 ~/.claude/
42
51
  npx code-abyss --target codex # 安装到 ~/.codex/
52
+ npx code-abyss --target gemini # 安装到 ~/.gemini/
43
53
  npx code-abyss --style abyss-concise --target claude
44
54
  npx code-abyss --style abyss-concise --target codex
45
55
  npx code-abyss --target claude -y # 零配置一键安装 (自动合并推荐配置)
46
56
  npx code-abyss --target codex -y # 零配置一键安装 (自动写入 config.toml 模板)
57
+ npx code-abyss --target gemini -y # 零配置一键安装 (自动生成 GEMINI.md + TOML commands)
47
58
  npx code-abyss --list-styles # 列出可用输出风格
48
59
  npx code-abyss --uninstall claude # 卸载 Claude Code
49
60
  npx code-abyss --uninstall codex # 卸载 Codex CLI
61
+ npx code-abyss --uninstall gemini # 卸载 Gemini CLI
50
62
  ```
51
63
 
52
64
  ### 安装流程
@@ -89,7 +101,18 @@ npx code-abyss --uninstall codex # 卸载 Codex CLI
89
101
  - `abyss-command`:铁律军令,命令式、压缩式输出,适合发布/故障/修复
90
102
  - `abyss-ritual`:祭仪长卷,仪式感更强,适合长任务、战报与迁移总结
91
103
 
92
- Claude 安装时会把所选 slug 写入 `settings.json.outputStyle`;Codex 安装时会根据所选风格动态生成 `~/.codex/AGENTS.md`。
104
+ 若更在意上下文与 token 消耗,优先选 `abyss-concise` `abyss-command`。当前运行时 guidance 已做轻量化压缩,并有测试限制各风格体积,避免后续版本再次膨胀。
105
+
106
+ Claude 安装时会把所选 slug 写入 `settings.json.outputStyle`;若当前仓库声明了 project packs,则自动同步对应 runtime + commands。Codex 走 `skills-only`,根据项目 `packs.lock` 自动附带对应 pack,不再写运行时 `~/.codex/AGENTS.md`,并会同步 `instruction.md` 与 `model_instructions_file`。Gemini 作为第三宿主,安装到 `~/.gemini/`,生成 `GEMINI.md`、`settings.json`、`commands/*.toml` 与 `skills/`;若项目声明了 `gstack`,也会同步安装 `~/.gemini/skills/gstack/` 与对应 TOML commands。
107
+
108
+ 当前 runtime kernel 已进一步瘦身:默认 `GEMINI.md` / 动态 guidance 体积控制在约 `1.45KB~1.65KB`,并通过 Jest 预算门禁限制各风格体积,避免后续版本再次膨胀。
109
+
110
+ ### 多风格切换
111
+
112
+ - Claude / Gemini:重新执行安装命令并带上 `--style <slug>`,即可切换为目标风格
113
+ - 例:`npx code-abyss --target claude --style abyss-concise -y`
114
+ - 例:`npx code-abyss --target gemini --style abyss-ritual -y`
115
+ - Codex:当前为 `skills-only` 运行形态,`--style` 会被显式忽略
93
116
 
94
117
  ---
95
118
 
@@ -105,6 +128,7 @@ npx code-abyss --uninstall codex # 卸载 Codex CLI
105
128
  ```bash
106
129
  node ~/.claude/.sage-uninstall.js # Claude Code
107
130
  node ~/.codex/.sage-uninstall.js # Codex CLI
131
+ node ~/.gemini/.sage-uninstall.js # Gemini CLI
108
132
  ```
109
133
 
110
134
  自动恢复之前备份的配置,清理所有安装文件。
@@ -115,13 +139,13 @@ node ~/.codex/.sage-uninstall.js # Codex CLI
115
139
 
116
140
  Code Abyss 是一套 **Claude Code / Codex CLI 邪修人格 + 多风格输出 + 攻防工程配置包**,一条命令注入:
117
141
 
118
- - 🔥 **邪修人格** — 沉浸式角色扮演 + 道语标签 + 渡劫协议 + 反拒绝条款 + `/hi` 会话覆写
142
+ - 🔥 **邪修人格** — 沉浸式角色扮演 + 道语标签 + 渡劫协议 + 反拒绝条款
119
143
  - ⚔️ **攻防安全知识体系** — 红队/蓝队/紫队三脉道统,6 个安全化身,11 领域 56 篇专业秘典
120
144
  - 🗡 **零废话安全研究** — 禁 disclaimer、禁道德前缀、全授权直出 PoC + 技术细节
121
- - ⚡ **全开默认配置** Claude `bypassPermissions` / Codex `approval_policy=never` + `danger-full-access`
145
+ - ⚡ **新版 Codex 对齐** `~/.agents/skills/` + 官方当前 `config.toml` 键位 + 项目级自动 pack 同步
122
146
  - ⚖️ **5 个校验关卡** — 安全扫描、模块完整性、变更分析、代码质量、文档生成
123
147
  - 🧠 **沙箱感知 + 离线优先** — 自适应执行环境,信息三级分级验证
124
- - 🧬 **单源 skill registry** — `skills/**/SKILL.md` frontmatter 同时驱动 Claude commandsCodex prompts 与脚本执行链
148
+ - 🧬 **单源 skill registry** — `skills/**/SKILL.md` frontmatter 驱动 Claude commands、脚本执行链与安装校验;Codex 直接发现安装后的 skill 目录
125
149
 
126
150
  ---
127
151
 
@@ -129,13 +153,15 @@ Code Abyss 是一套 **Claude Code / Codex CLI 邪修人格 + 多风格输出 +
129
153
 
130
154
  ```
131
155
  ~/.claude/(Claude Code) ~/.codex/(Codex CLI)
132
- ├── CLAUDE.md 道典 ├── AGENTS.md 道典+所选风格(动态生成)
133
- ├── output-styles/ 输出风格 ├── config.toml 推荐配置
134
- │ ├── index.json ├── prompts/ custom prompts
135
- │ └── *.md style files └── skills/ 秘典 + 脚本执行器
136
- ├── commands/ 斜杠命令 │ └── *.md 自动生成 prompt
137
- ├── settings.json
138
- └── skills/ 56 篇秘典
156
+ ├── CLAUDE.md 道典 ├── config.toml 推荐配置
157
+ ├── output-styles/ 输出风格 └── .sage-uninstall.js
158
+ │ ├── index.json
159
+ │ └── *.md style files ~/.agents/
160
+ ├── commands/ 斜杠命令 ├── skills/ Code Abyss + gstack skills
161
+ ├── settings.json │ ├── domains/
162
+ └── skills/ 56 篇秘典 │ ├── tools/
163
+ │ └── gstack/ 上游运行时 root
164
+ └── bin/lib/ run_skill.js 依赖
139
165
 
140
166
  可选:
141
167
  ├── ccline/ 状态栏 (npm install -g @cometix/ccline)
@@ -148,7 +174,7 @@ Code Abyss 是一套 **Claude Code / Codex CLI 邪修人格 + 多风格输出 +
148
174
 
149
175
  ### 校验关卡(`/` 直接调用)
150
176
 
151
- 这些命令与 Codex custom prompts 都不是手写维护,而是由各自 `skills/**/SKILL.md` frontmatter 中的 `name`、`user-invocable`、`allowed-tools`、`argument-hint`、`scripts/` 状态统一生成。
177
+ Claude 侧命令由 `skills/**/SKILL.md` frontmatter 统一生成;Codex 侧直接发现 `~/.agents/skills/**/SKILL.md`,若存在 `agents/openai.yaml` 则附加 UI metadata 与默认提示词。
152
178
 
153
179
  | 命令 | 功能 |
154
180
  |------|------|
@@ -157,7 +183,6 @@ Code Abyss 是一套 **Claude Code / Codex CLI 邪修人格 + 多风格输出 +
157
183
  | `/verify-change` | 分析 Git 变更,检测文档同步状态 |
158
184
  | `/verify-quality` | 检测复杂度、命名规范、代码质量 |
159
185
  | `/gen-docs` | 自动生成 README.md 和 DESIGN.md 骨架 |
160
- | `/override-refusal` (`/hi`) | 扫描当前会话最近5条模型输出,直接替换拒绝话术为同意措辞 |
161
186
 
162
187
  ### 知识秘典(按触发词自动加载)
163
188
 
@@ -224,58 +249,57 @@ Code Abyss 是一套 **Claude Code / Codex CLI 邪修人格 + 多风格输出 +
224
249
 
225
250
  ### Codex `config.toml` 推荐模板
226
251
 
227
- 安装 `--target codex`(尤其 `-y`)时会写入以下 **全开默认档** 到 `~/.codex/config.toml`:
252
+ 安装 `--target codex`(尤其 `-y`)时会写入以下 **当前官方样例线 + abyss profile** 到 `~/.codex/config.toml`:
228
253
 
229
254
  ```toml
230
- model_provider = "custom"
231
- model = "gpt-5.2-codex"
232
- model_reasoning_effort = "high"
233
- model_reasoning_summary = "detailed"
255
+ model = "gpt-5.4"
256
+ model_provider = "openai"
257
+ model_reasoning_effort = "medium"
258
+ model_reasoning_summary = "auto"
234
259
  model_verbosity = "medium"
235
- approval_policy = "never"
236
- sandbox_mode = "danger-full-access"
237
- disable_response_storage = true
238
-
239
- [profiles.safe]
240
260
  approval_policy = "on-request"
241
- sandbox_mode = "workspace-write"
261
+ allow_login_shell = true
262
+ sandbox_mode = "read-only"
263
+ cli_auth_credentials_store = "file"
264
+ project_doc_max_bytes = 32768
265
+ web_search = "cached"
242
266
 
243
- [model_providers.custom]
244
- name = "custom"
245
- base_url = "https://your-api-endpoint.com/v1"
246
- wire_api = "responses"
247
- requires_openai_auth = true
267
+ [profiles.abyss]
268
+ approval_policy = "never"
269
+ sandbox_mode = "danger-full-access"
270
+ web_search = "live"
248
271
 
249
- [tools]
250
- web_search = true
272
+ [agents]
273
+ max_threads = 6
274
+ max_depth = 1
251
275
 
252
- [features]
253
- multi_agent = true
254
- shell_snapshot = true
255
- undo = true
276
+ [sandbox_workspace_write]
277
+ writable_roots = []
278
+ network_access = false
256
279
  ```
257
280
 
258
- - 默认零审批 + 完全沙箱访问,适合安全研究/CTF/本地开发等高自动化场景
259
- - `model_reasoning_summary = "detailed"` 输出详细推理摘要
260
- - `shell_snapshot` / `undo` 启用快照与撤销功能
261
- - 需要安全姿态时可显式切到 `safe`:`codex -p safe`
281
+ - 根默认值对齐官方当前样例:`gpt-5.4` + `approval_policy = "on-request"` + `sandbox_mode = "read-only"`
282
+ - 若要保留旧版高自动化体验,可显式切到 `abyss`:`codex -p abyss`
283
+ - `project_doc_max_bytes` 仍保留在 `config.toml` 模板中,便于用户自行维护全局 `AGENTS.md`
284
+ - skills 走 `~/.agents/skills/` 官方用户级路径,默认自动附带 `gstack` runtime root `~/.agents/skills/gstack`
262
285
 
263
286
  ### 兼容性说明
264
287
 
265
- - 模板已对齐新版 Codex 配置风格:root keys、`[profiles.*]`、`[tools].web_search` `[features].multi_agent`
266
- - 默认档从 safe 切换为全开(`approval_policy = "never"` + `sandbox_mode = "danger-full-access"`),提供 `[profiles.safe]` 作为保守回退
288
+ - 模板已对齐新版 Codex 配置风格:root keys 置于 tables 之前,`web_search` 改为 root string mode,skills 改走 `~/.agents/skills/`
289
+ - 根默认值保持官方安全线,仓库个性化的全开模式降为 `[profiles.abyss]`
267
290
  - Claude Code 默认启用 `bypassPermissions` 模式,跳过所有权限确认(`.git` 等受保护目录仍会提示)
268
291
  - 新增实验功能环境变量:`CLAUDE_CODE_ENABLE_TASKS`、`CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION`
269
292
  - 新增 `mcp__*` 通配符,自动放行所有 MCP 工具
270
- - `Codex` 当前支持 `~/.codex/prompts/*.md` 作为 custom promptsCode Abyss 会继续安装 `~/.codex/skills/`,并从 `user-invocable` skills 自动生成对应的 `prompts/`
271
- - `Claude` `Codex` 共用同一套 invocable skill 集合;只要 `user-invocable: true`,就会同步生成 `~/.claude/commands/*.md` `~/.codex/prompts/*.md`
293
+ - `Codex` 当前以 `~/.agents/skills/**/SKILL.md` 为主,custom prompts 旧入口已移除;Code Abyss 不再写运行时 `~/.codex/AGENTS.md`
294
+ - `agents/openai.yaml` 现在只是 skill 的可选 metadata 文件,不再等同于 `~/.codex/agents/*.toml` 自定义 subagent 定义
295
+ - `.code-abyss/packs.lock.json` 现在支持按 host 配置 `optional_policy=auto|prompt|off` 与 `sources.<pack>=pinned|local|disabled`
272
296
  - `--list-styles` 可列出当前内置风格;`--style <slug>` 可在安装时显式切换风格
273
297
  - `skills/run_skill.js` 现在仅负责执行脚本型 skill:通过共享 registry 定位脚本入口、加目标锁、spawn 子进程,并把退出码原样透传
274
- - 若 skill 没有 `scripts/*.js`,Claude/Codex 两端都会退化为“先读 `SKILL.md`,再按秘典执行”的知识型模式
275
- - Codex `AGENTS.md` 不再是固定拷贝;安装时会由 `config/CLAUDE.md` 与所选 `output-styles/*.md` 动态拼装生成
298
+ - 若 skill 没有 `scripts/*.js`,Claude/Codex/Gemini 三端都会退化为“先读 `SKILL.md`,再按秘典执行”的知识型模式
299
+ - Codex 改为 `skills-only` 安装形态:不再写运行时 `AGENTS.md`,而是在 `~/.agents/skills/` 下自动安装 Code Abyss 与 gstack skills
276
300
  - 安装器不会再为 Codex 写入伪配置 `~/.codex/settings.json`;若检测到旧版遗留文件,会在安装时备份后移除,卸载时恢复
277
- - 若你本地已有旧配置,安装器不会强制覆盖;会自动补齐默认项、清理 removed feature、迁移 deprecated `web_search_*` `[tools].web_search`
278
- - 建议升级后执行一次 `codex --help`,或用 `codex -p safe --help` 校验 profile 可见性
301
+ - 若你本地已有旧配置,安装器不会强制覆盖;会自动补齐缺失 root defaults,并把旧 `web_search_*` / `[tools].web_search` 迁移到新版 `web_search = "cached|live|disabled"`
302
+ - 建议升级后执行一次 `codex --help`,或用 `codex -p abyss --help` 校验 profile 可见性
279
303
 
280
304
  ---
281
305
 
@@ -283,12 +307,57 @@ undo = true
283
307
 
284
308
  现在 `skills/**/SKILL.md` frontmatter 是唯一事实源,registry 会先把元数据标准化,再交给安装器与执行器消费。
285
309
 
310
+ ### Pack registry
311
+
312
+ - `packs/abyss/manifest.json`:声明 Code Abyss core pack 在 Claude/Codex/Gemini 三个 host 下的安装映射
313
+ - `packs/gstack/manifest.json`:声明 pinned upstream gstack 的 repo、commit、Claude/Codex/Gemini runtime 目录与路径改写规则
314
+ - `bin/lib/pack-registry.js`:安装器与 host adapter 的唯一 pack 真相源
315
+ - `.code-abyss/packs.lock.json`:项目级 pack 声明;支持 `required` / `optional` / `optional_policy` / `sources`
316
+ - `sources.<pack>` 支持:
317
+ - `pinned`:使用 manifest 里 pin 的 upstream 版本
318
+ - `local`:优先使用 `.code-abyss/vendor/<pack>` 或显式 env override
319
+ - `disabled`:该 pack 不参与安装,但保留在 lock 中
320
+ - `node bin/packs.js bootstrap`:初始化/更新 `packs.lock`,并生成 `.code-abyss/snippets/README.packs.md` 与 `CONTRIBUTING.packs.md`
321
+ - `node bin/packs.js bootstrap --apply-docs`:把 snippet 直接写入/更新根目录 `README.md` 与 `CONTRIBUTING.md`
322
+ - `node bin/packs.js diff`:输出当前 `packs.lock` 相对默认模板的差异同步报告
323
+ - `node bin/packs.js vendor-pull <pack>`:把 upstream pin 拉到 `.code-abyss/vendor/<pack>`
324
+ - `node bin/packs.js vendor-sync`:同步当前 lock 中 `source=local` 的 packs
325
+ - `node bin/packs.js vendor-sync --check`:只检查 `source=local` packs 是否存在/干净/未漂移;适合 CI 门禁
326
+ - `node bin/packs.js vendor-status [pack|all]`:查看 vendor 状态总览
327
+ - `node bin/packs.js vendor-dirty [pack|all]`:若 vendor 脏或漂移则非零退出
328
+ - `node bin/packs.js report list|latest|summary [--kind prefix] [--json]`:集中查看 `.code-abyss/reports/`
329
+ - `node bin/packs.js uninstall <pack> --host claude|codex|all --remove-lock --remove-vendor`:按 pack 清理本机安装物并输出报告
330
+ - `docs/PACK_MANIFEST_SCHEMA.md`:第三方 pack 可直接照抄的最小 manifest contract
331
+ - `docs/PACKS_LOCK_SCHEMA.md`:项目级 `packs.lock` contract
332
+ - `docs/PACK_SYSTEM.md`:install/bootstrap/vendor/report 四条主流程的产品级说明
333
+ - `docs/SKILL_AUTHORING.md`:完整 skill authoring contract;运行时总纲已收敛到 `skills/SKILL.md`
334
+
335
+ ### 协作流程图
336
+
337
+ ```mermaid
338
+ flowchart TD
339
+ A[User / Team Request] --> B[Code Abyss 协调层]
340
+ C[Repo Context\nCLAUDE.md / README / packs.lock] --> B
341
+
342
+ B --> D{任务路由}
343
+ D -->|领域能力| E[Abyss Core Skills\nverify-change / verify-quality / gen-docs ...]
344
+ D -->|工作流编排| F[gstack Workflows\noffice-hours / review / qa / ship]
345
+
346
+ E --> G[Claude / Codex / Gemini Runtime]
347
+ F --> G
348
+
349
+ G --> H[执行阶段\n规划 / 实现 / 评审 / 验证 / 发布]
350
+ H --> I[协作产物\nPR 意见 / QA 结果 / 文档更新 / 报告]
351
+ I --> J[下一轮团队请求]
352
+ J --> B
353
+ ```
354
+
286
355
  ### 标准化 contract
287
356
 
288
357
  每个 skill 必须满足:
289
358
 
290
359
  - 必填 frontmatter:`name`、`description`、`user-invocable`
291
- - `name` 必须是 kebab-case slug,用作 `commands/*.md` / `prompts/*.md` 文件名
360
+ - `name` 必须是 kebab-case slug,用作 Claude `commands/*.md` 文件名与脚本调用标识
292
361
  - `allowed-tools` 省略时默认 `Read`;若显式声明,则必须是 `Bash`、`Read`、`Write`、`Glob`、`Grep` 这类合法工具名列表
293
362
  - `argument-hint` 可选,仅用于生成命令/提示词参数说明
294
363
  - `category` 由目录前缀自动推断:`tools/` → `tool`,`domains/` → `domain`,`orchestration/` → `orchestration`
@@ -302,11 +371,11 @@ undo = true
302
371
  1. 安装器通过共享 skill registry 扫描全部 `SKILL.md`
303
372
  2. registry 先校验并标准化字段,再筛出 `user-invocable: true` 的 skill
304
373
  3. Claude 渲染为 `~/.claude/commands/*.md`
305
- 4. Codex 渲染为 `~/.codex/prompts/*.md`
306
- 5. `runtimeType=scripted` 时,双端产物都会调用各自的 `~/.claude/skills/run_skill.js` / `~/.codex/skills/run_skill.js`
374
+ 4. Codex 安装到 `~/.agents/skills/`,由 Codex 直接发现 `SKILL.md`;若存在 `agents/openai.yaml`,则附加 metadata
375
+ 5. `runtimeType=scripted` 时,脚本型 skill 通过 `~/.claude/skills/run_skill.js` / `~/.agents/skills/run_skill.js` 统一执行
307
376
  6. `runtimeType=knowledge` 时,双端都只读取 `SKILL.md` 作为执行秘典
308
377
 
309
- 这保证了 **同一 skill 集合、同一元数据、同一 runtime 判定、双端同步生成**,避免 commands/prompts/script runner 各自漂移。
378
+ 这保证了 **同一 skill 集合、同一 runtime 判定、同一脚本执行入口**,避免 command/skill install/script runner 各自漂移。
310
379
 
311
380
  ---
312
381
 
@@ -316,7 +385,7 @@ undo = true
316
385
 
317
386
  - 每个 style 记录 `slug`、`label`、`description`、`file`、`targets`、`default`
318
387
  - Claude 安装时复制整个 `output-styles/` 目录,并把 `settings.json.outputStyle` 指向选中的 slug
319
- - Codex 安装时不复制静态模板,而是由 `config/CLAUDE.md + output-styles/<slug>.md` 动态生成 `AGENTS.md`
388
+ - Gemini 安装时由 `config/CLAUDE.md + output-styles/<slug>.md` 动态生成 `GEMINI.md`
320
389
  - `--list-styles` 用于查看可用风格,`--style <slug>` 用于无交互切换
321
390
 
322
391
  ---
@@ -333,11 +402,12 @@ undo = true
333
402
  - `verify-security`
334
403
  - Claude install/uninstall smoke
335
404
  - Codex install/uninstall smoke
336
- - 生成一致性回归:同一 invocable skill 集合在 Claude commands 与 Codex prompts 中必须同步存在
405
+ - Gemini install/uninstall smoke
406
+ - 生成一致性回归:Claude commands 与 Codex skill metadata 的路径必须与最新安装布局一致
337
407
 
338
408
  ---
339
409
 
340
- ## 🧩 适配器解耦(Claude / Codex)
410
+ ## 🧩 适配器解耦(Claude / Codex / Gemini
341
411
 
342
412
  为避免过度耦合,安装器按目标 CLI 拆分适配层:
343
413
 
@@ -345,9 +415,10 @@ undo = true
345
415
  - `bin/adapters/claude.js`:Claude 侧认证检测、settings merge、可选配置流程
346
416
  - `bin/lib/ccline.js`:Claude 侧状态栏与 ccline 集成
347
417
  - `bin/adapters/codex.js`:Codex 侧认证检测、核心文件映射、config 模板流程
348
- - `bin/lib/style-registry.js`:输出风格 registry、默认风格解析、Codex AGENTS 动态拼装
418
+ - `bin/adapters/gemini.js`:Gemini 侧认证检测、settings merge、安装后可选配置
419
+ - `bin/lib/style-registry.js`:输出风格 registry、默认风格解析、Gemini `GEMINI.md` 动态拼装
349
420
 
350
- 当前 Claude/Codex 安装映射分别由 `getClaudeCoreFiles()` 与 `getCodexCoreFiles()` 提供;Claude 额外生成 `commands/` 并保留完整 `output-styles/`,Codex 则保持 `skills/ + config.toml` 的官方主路径,并在安装时动态生成 `AGENTS.md`,避免把风格硬编码死在仓库快照里。
421
+ 当前 Claude/Codex/Gemini 安装映射分别由 `getClaudeCoreFiles()`、`getCodexCoreFiles()` 与 `getGeminiCoreFiles()` 提供;Claude 额外生成 `commands/` 并保留完整 `output-styles/`,Codex 采用 `~/.agents/skills/` 的 `skills-only` 主路径,Gemini 则安装 `skills/`、`commands/*.toml` 与动态生成的 `GEMINI.md`。额外 pack 由 `.code-abyss/packs.lock.json` 自动声明并同步,避免再向运行时文档注入大段重复规则。
351
422
 
352
423
  ---
353
424
 
@@ -2,11 +2,11 @@
2
2
 
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
- const { getDefaultStyle } = require(path.join(__dirname, '..', 'lib', 'style-registry.js'));
5
+ const { getPackHostFiles } = require(path.join(__dirname, '..', 'lib', 'pack-registry.js'));
6
6
 
7
7
  const PROJECT_ROOT = path.join(__dirname, '..', '..');
8
- const DEFAULT_OUTPUT_STYLE = getDefaultStyle(PROJECT_ROOT, 'claude').slug;
9
8
 
9
+ // Placeholder — resolved lazily by resolveSettingsTemplate()
10
10
  const SETTINGS_TEMPLATE = {
11
11
  $schema: 'https://json.schemastore.org/claude-code-settings.json',
12
12
  env: {
@@ -20,7 +20,7 @@ const SETTINGS_TEMPLATE = {
20
20
  alwaysThinkingEnabled: true,
21
21
  autoMemoryEnabled: true,
22
22
  model: 'opus',
23
- outputStyle: DEFAULT_OUTPUT_STYLE,
23
+ outputStyle: '__DEFAULT_STYLE__',
24
24
  attribution: { commit: '', pr: '' },
25
25
  sandbox: {
26
26
  autoAllowBashIfSandboxed: true
@@ -44,12 +44,7 @@ const CCLINE_STATUS_LINE = {
44
44
  };
45
45
 
46
46
  function getClaudeCoreFiles() {
47
- return [
48
- { src: 'config/CLAUDE.md', dest: 'CLAUDE.md' },
49
- { src: 'output-styles', dest: 'output-styles' },
50
- { src: 'skills', dest: 'skills' },
51
- { src: 'bin/lib', dest: 'bin/lib' },
52
- ];
47
+ return getPackHostFiles(PROJECT_ROOT, 'abyss', 'claude');
53
48
  }
54
49
 
55
50
  function detectClaudeAuth({
@@ -95,9 +90,18 @@ async function configureCustomProvider(ctx, { ok }) {
95
90
  ok('provider 已配置');
96
91
  }
97
92
 
98
- function mergeSettings(ctx, { deepMergeNew, printMergeLog, c, ok }) {
93
+ function resolveSettingsTemplate(projectRoot) {
94
+ const { getDefaultStyle } = require(path.join(__dirname, '..', 'lib', 'style-registry.js'));
95
+ const slug = getDefaultStyle(projectRoot || PROJECT_ROOT, 'claude').slug;
96
+ const template = JSON.parse(JSON.stringify(SETTINGS_TEMPLATE));
97
+ template.outputStyle = slug;
98
+ return template;
99
+ }
100
+
101
+ function mergeSettings(ctx, { deepMergeNew, printMergeLog, c, ok, projectRoot }) {
102
+ const resolved = resolveSettingsTemplate(projectRoot);
99
103
  const log = [];
100
- deepMergeNew(ctx.settings, SETTINGS_TEMPLATE, '', log);
104
+ deepMergeNew(ctx.settings, resolved, '', log);
101
105
  printMergeLog(log, c);
102
106
  fs.writeFileSync(ctx.settingsPath, JSON.stringify(ctx.settings, null, 2) + '\n');
103
107
  ok('settings.json 合并完成');
@@ -153,8 +157,8 @@ async function postClaude({
153
157
  }
154
158
 
155
159
  module.exports = {
156
- DEFAULT_OUTPUT_STYLE,
157
160
  SETTINGS_TEMPLATE,
161
+ resolveSettingsTemplate,
158
162
  CCLINE_STATUS_LINE,
159
163
  getClaudeCoreFiles,
160
164
  detectClaudeAuth,
@@ -2,11 +2,17 @@
2
2
 
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
+ const { getPackHostFiles } = require(path.join(__dirname, '..', 'lib', 'pack-registry.js'));
6
+
7
+ const PROJECT_ROOT = path.join(__dirname, '..', '..');
5
8
 
6
9
  const CODEX_DEFAULTS = {
7
- approvalPolicy: 'never',
8
- sandboxMode: 'danger-full-access',
9
- featureFlag: 'multi_agent',
10
+ approvalPolicy: 'on-request',
11
+ allowLoginShell: true,
12
+ cliAuthCredentialsStore: 'file',
13
+ modelInstructionsFile: './instruction.md',
14
+ sandboxMode: 'read-only',
15
+ webSearch: 'cached',
10
16
  };
11
17
 
12
18
  const LEGACY_FEATURES = {
@@ -37,6 +43,10 @@ function isProjectTableHeader(line) {
37
43
  return /^\s*\[projects\."[^"]+"\]\s*$/.test(line);
38
44
  }
39
45
 
46
+ function isProfileTableHeader(line) {
47
+ return /^\s*\[profiles\.[^\]]+\]\s*$/.test(line);
48
+ }
49
+
40
50
  function isAssignmentForKey(line, key) {
41
51
  const re = new RegExp(`^\\s*${escapeRegExp(key)}\\s*=`);
42
52
  return re.test(line);
@@ -153,20 +163,20 @@ function parseTomlBooleanAssignment(line) {
153
163
  return m[1].toLowerCase() === 'true';
154
164
  }
155
165
 
156
- function removeKeyAssignmentsInNonRootSections(content, key) {
166
+ function removeKeyAssignmentsInOtherSections(content, key) {
157
167
  const eol = content.includes('\r\n') ? '\r\n' : '\n';
158
168
  const lines = content.split(/\r?\n/);
159
169
  const kept = [];
160
- let inRoot = true;
170
+ let scope = 'root';
161
171
  let removed = false;
162
172
 
163
173
  for (const line of lines) {
164
174
  if (isTableHeader(line)) {
165
- inRoot = false;
175
+ scope = isProfileTableHeader(line) ? 'profile' : 'other';
166
176
  kept.push(line);
167
177
  continue;
168
178
  }
169
- if (!inRoot && isAssignmentForKey(line, key)) {
179
+ if (scope === 'other' && isAssignmentForKey(line, key)) {
170
180
  removed = true;
171
181
  continue;
172
182
  }
@@ -176,6 +186,36 @@ function removeKeyAssignmentsInNonRootSections(content, key) {
176
186
  return { merged: kept.join(eol), removed };
177
187
  }
178
188
 
189
+ function removeKeyAssignmentsInSection(content, sectionName, key) {
190
+ const eol = content.includes('\r\n') ? '\r\n' : '\n';
191
+ const lines = content.split(/\r?\n/);
192
+ const kept = [];
193
+ const sectionRe = new RegExp(`^\\s*\\[${escapeRegExp(sectionName)}\\]\\s*$`);
194
+ const anySectionRe = /^\s*\[[^\]]+\]\s*$/;
195
+ let inSection = false;
196
+ const removedValues = [];
197
+
198
+ for (const line of lines) {
199
+ if (sectionRe.test(line)) {
200
+ inSection = true;
201
+ kept.push(line);
202
+ continue;
203
+ }
204
+ if (inSection && anySectionRe.test(line)) {
205
+ inSection = false;
206
+ kept.push(line);
207
+ continue;
208
+ }
209
+ if (inSection && isAssignmentForKey(line, key)) {
210
+ removedValues.push(parseTomlBooleanAssignment(line));
211
+ continue;
212
+ }
213
+ kept.push(line);
214
+ }
215
+
216
+ return { merged: kept.join(eol), removedValues };
217
+ }
218
+
179
219
  function removeProjectTrustSectionsForFullAccess(content) {
180
220
  const eol = content.includes('\r\n') ? '\r\n' : '\n';
181
221
  const sandboxMode = readRootStringKey(content, 'sandbox_mode');
@@ -250,22 +290,32 @@ function cleanupLegacyCodexConfig(content) {
250
290
  const eol = content.includes('\r\n') ? '\r\n' : '\n';
251
291
  const toRemove = [...LEGACY_FEATURES.removed, ...LEGACY_FEATURES.deprecated];
252
292
  const { merged: pruned, removedEntries } = removeFeatureFlagsFromFeaturesSection(content, toRemove);
253
- let merged = pruned;
293
+ const { merged: withoutToolsWebSearch, removedValues: removedToolWebSearch } =
294
+ removeKeyAssignmentsInSection(pruned, 'tools', 'web_search');
295
+ let merged = withoutToolsWebSearch;
254
296
  const removed = uniq(removedEntries.map((x) => x.key));
255
297
  const migrated = [];
256
298
 
257
- const deprecatedRemoved = removedEntries.filter((x) => LEGACY_FEATURES.deprecated.includes(x.key));
258
- if (deprecatedRemoved.length > 0) {
259
- const shouldEnableWebSearch = deprecatedRemoved.some((x) => x.enabled !== false);
260
- const { merged: withTools, added } = ensureKeyInSection(
261
- merged,
262
- 'tools',
263
- 'web_search',
264
- shouldEnableWebSearch ? 'true' : 'false',
265
- eol
266
- );
267
- merged = withTools;
268
- if (added) migrated.push(`tools.web_search=${shouldEnableWebSearch ? 'true' : 'false'}`);
299
+ if (removedToolWebSearch.length > 0) {
300
+ removed.push('tools.web_search');
301
+ }
302
+
303
+ if (!hasRootKey(merged, 'web_search')) {
304
+ const requestEnabled = removedEntries.find((x) => x.key === 'web_search_request')?.enabled;
305
+ const cachedEnabled = removedEntries.find((x) => x.key === 'web_search_cached')?.enabled;
306
+ const toolsEnabled = removedToolWebSearch.find((value) => value !== null);
307
+
308
+ let webSearchMode = null;
309
+ if (requestEnabled === true) webSearchMode = 'live';
310
+ else if (cachedEnabled === true) webSearchMode = 'cached';
311
+ else if (toolsEnabled === true) webSearchMode = 'cached';
312
+ else if (requestEnabled === false || cachedEnabled === false || toolsEnabled === false) webSearchMode = 'disabled';
313
+
314
+ if (webSearchMode) {
315
+ const webSearch = ensureRootKey(merged, 'web_search', `"${webSearchMode}"`, eol);
316
+ merged = webSearch.merged;
317
+ if (webSearch.added) migrated.push(`web_search=${webSearchMode}`);
318
+ }
269
319
  }
270
320
 
271
321
  return { merged, removed, migrated };
@@ -278,14 +328,15 @@ function mergeCodexConfigDefaults(content) {
278
328
 
279
329
  const rootKeys = [
280
330
  'approval_policy',
331
+ 'allow_login_shell',
332
+ 'cli_auth_credentials_store',
333
+ 'model_instructions_file',
281
334
  'sandbox_mode',
282
- 'model_reasoning_effort',
283
- 'disable_response_storage',
284
- 'personality',
335
+ 'web_search',
285
336
  ];
286
337
 
287
338
  for (const key of rootKeys) {
288
- const cleaned = removeKeyAssignmentsInNonRootSections(merged, key);
339
+ const cleaned = removeKeyAssignmentsInOtherSections(merged, key);
289
340
  merged = cleaned.merged;
290
341
  }
291
342
 
@@ -295,19 +346,44 @@ function mergeCodexConfigDefaults(content) {
295
346
  added.push('approval_policy');
296
347
  }
297
348
 
349
+ const loginShell = ensureRootKey(merged, 'allow_login_shell', `${CODEX_DEFAULTS.allowLoginShell}`, eol);
350
+ merged = loginShell.merged;
351
+ if (loginShell.added) {
352
+ added.push('allow_login_shell');
353
+ }
354
+
355
+ const credentialsStore = ensureRootKey(
356
+ merged,
357
+ 'cli_auth_credentials_store',
358
+ `"${CODEX_DEFAULTS.cliAuthCredentialsStore}"`,
359
+ eol
360
+ );
361
+ merged = credentialsStore.merged;
362
+ if (credentialsStore.added) {
363
+ added.push('cli_auth_credentials_store');
364
+ }
365
+
366
+ const modelInstructions = ensureRootKey(
367
+ merged,
368
+ 'model_instructions_file',
369
+ `"${CODEX_DEFAULTS.modelInstructionsFile}"`,
370
+ eol
371
+ );
372
+ merged = modelInstructions.merged;
373
+ if (modelInstructions.added) {
374
+ added.push('model_instructions_file');
375
+ }
376
+
298
377
  const sandbox = ensureRootKey(merged, 'sandbox_mode', `"${CODEX_DEFAULTS.sandboxMode}"`, eol);
299
378
  merged = sandbox.merged;
300
379
  if (sandbox.added) {
301
380
  added.push('sandbox_mode');
302
381
  }
303
382
 
304
- if (!hasSection(merged, 'features')) {
305
- merged = appendLine(merged, '[features]', eol);
306
- merged = appendLine(merged, `${CODEX_DEFAULTS.featureFlag} = true`, eol);
307
- added.push('features.multi_agent');
308
- } else if (!hasKeyInSection(merged, 'features', CODEX_DEFAULTS.featureFlag)) {
309
- merged = insertLineAfterSectionHeader(merged, 'features', `${CODEX_DEFAULTS.featureFlag} = true`, eol);
310
- added.push('features.multi_agent');
383
+ const webSearch = ensureRootKey(merged, 'web_search', `"${CODEX_DEFAULTS.webSearch}"`, eol);
384
+ merged = webSearch.merged;
385
+ if (webSearch.added) {
386
+ added.push('web_search');
311
387
  }
312
388
 
313
389
  return { merged, added };
@@ -368,10 +444,7 @@ function detectCodexAuth({
368
444
  }
369
445
 
370
446
  function getCodexCoreFiles() {
371
- return [
372
- { src: 'skills', dest: 'skills' },
373
- { src: 'bin/lib', dest: 'bin/lib' },
374
- ];
447
+ return getPackHostFiles(PROJECT_ROOT, 'abyss', 'codex');
375
448
  }
376
449
 
377
450
  async function postCodex({
@@ -404,7 +477,7 @@ async function postCodex({
404
477
  if (fs.existsSync(src)) {
405
478
  fs.copyFileSync(src, cfgPath);
406
479
  ok('写入: ~/.codex/config.toml (模板)');
407
- warn('请编辑 base_url model');
480
+ info('默认值已对齐当前 Codex 样例;如需高自动化全开,可切到 `codex -p abyss`');
408
481
  }
409
482
  } else {
410
483
  patchAndReportCodexDefaults({ cfgPath, ok, warn });
@@ -420,7 +493,7 @@ async function postCodex({
420
493
  if (fs.existsSync(src)) {
421
494
  fs.copyFileSync(src, cfgPath);
422
495
  ok('写入: ~/.codex/config.toml');
423
- warn('请编辑 base_url model');
496
+ info('默认值已对齐当前 Codex 样例;如需高自动化全开,可切到 `codex -p abyss`');
424
497
  }
425
498
  }
426
499
  } else {