auriga-cli 1.19.1 → 1.20.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 +14 -22
- package/README.zh-CN.md +12 -21
- package/dist/catalog.json +17 -19
- package/dist/cli.js +13 -1
- package/dist/guide.js +10 -9
- package/dist/help.js +1 -1
- package/dist/hooks.js +6 -1
- package/dist/plugins.js +233 -19
- package/dist/skills.js +0 -3
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +43 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,10 +11,10 @@ This repo itself is a fully configured harness project. You can clone it to see
|
|
|
11
11
|
| Module | Description |
|
|
12
12
|
|---|---|
|
|
13
13
|
| **Workflow** | `CLAUDE.md` auriga workflow: requirement clarification -> TDD -> Review, Harness principles, Subagent usage guide |
|
|
14
|
-
| **Skills** |
|
|
14
|
+
| **Skills** | External development process skills — brainstorming, systematic-debugging, TDD, verification, planning, playwright |
|
|
15
15
|
| **Recommended Skills** | Optional utility skills (e.g. `codex-agent`, `claude-code-agent`) you can add on top of the workflow skills |
|
|
16
|
-
| **Plugins** | Recommended Claude Code and Codex plugins — skill-creator, claude-md-management, codex, auriga-go, auriga-git-guards, session-instructions-loader, deep-review |
|
|
17
|
-
| **Hooks** | Claude Code
|
|
16
|
+
| **Plugins** | Recommended Claude Code and Codex plugins — skill-creator, claude-md-management, codex, auriga-go, auriga-git-guards, auriga-workflow-skills, auriga-notify, session-instructions-loader, deep-review |
|
|
17
|
+
| **Hooks** | Legacy Claude Code hook installer. No repo-owned hooks are currently exposed here; `notify` ships as the `auriga-notify` plugin. |
|
|
18
18
|
|
|
19
19
|
## Quick Start
|
|
20
20
|
|
|
@@ -41,14 +41,14 @@ The leading `-y` belongs to `npx` (it auto-confirms package installation), **not
|
|
|
41
41
|
Non-interactive install commands:
|
|
42
42
|
|
|
43
43
|
```bash
|
|
44
|
-
npx -y auriga-cli install --all # workflow + skills + plugins
|
|
44
|
+
npx -y auriga-cli install --all # workflow + skills + default plugins (atomic)
|
|
45
45
|
npx -y auriga-cli install recommended # opt-in utility skills (not in --all)
|
|
46
46
|
npx -y auriga-cli install plugins --agent codex --plugin session-instructions-loader
|
|
47
47
|
npx -y auriga-cli install <type> [--flags] # one of: workflow | skills | recommended | plugins | hooks
|
|
48
48
|
npx -y auriga-cli --help # full catalog + flags
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
Exit codes: `0` success, `1` fatal (precheck / parse / fetch), `2` partial success — `stderr` lists per-category `[OK]/[FAIL]` and a `Retry:` hint. After install, reload the Claude Code or Codex session so the new `CLAUDE.md` / skills / plugins / hook registrations are picked up.
|
|
51
|
+
Exit codes: `0` success, `1` fatal (precheck / parse / fetch), `2` partial success — `stderr` lists per-category `[OK]/[FAIL]` and a `Retry:` hint. After install, reload the Claude Code or Codex session so the new `CLAUDE.md` / skills / plugins / hook-plugin registrations are picked up.
|
|
52
52
|
|
|
53
53
|
### Web UI (opt-in)
|
|
54
54
|
|
|
@@ -102,9 +102,6 @@ Installs selected skills via `npx skills add`, targeting both Claude Code and Co
|
|
|
102
102
|
| verification-before-completion | [obra/superpowers](https://github.com/obra/superpowers) | Pre-completion verification — evidence before assertions |
|
|
103
103
|
| planning-with-files | [OthmanAdi/planning-with-files](https://github.com/OthmanAdi/planning-with-files) | File-based task planning and progress tracking |
|
|
104
104
|
| playwright-cli | [microsoft/playwright-cli](https://github.com/microsoft/playwright-cli) | Browser automation and testing |
|
|
105
|
-
| test-designer | [Ben2pc/auriga-cli](https://github.com/Ben2pc/auriga-cli) | Independent-Evaluation test designer for TDD red phase |
|
|
106
|
-
| incremental-impl | [Ben2pc/auriga-cli](https://github.com/Ben2pc/auriga-cli) | Decides how to implement a non-trivial change: size, slicing strategy, optional parallel dispatch, per-slice execution discipline |
|
|
107
|
-
| session-compound | [Ben2pc/auriga-cli](https://github.com/Ben2pc/auriga-cli) | Post-merge session compounder — distills the session into an interactive HTML report (timeline + token / cache / tool health + playground for skill installs / AGENTS.md edits / new-skill gaps) |
|
|
108
105
|
|
|
109
106
|
**Recommended Skills (opt-in, not installed by `--all`):**
|
|
110
107
|
|
|
@@ -129,6 +126,8 @@ Examples:
|
|
|
129
126
|
|
|
130
127
|
```bash
|
|
131
128
|
npx -y auriga-cli install plugins --plugin auriga-go
|
|
129
|
+
npx -y auriga-cli install plugins --agent both --plugin auriga-workflow-skills
|
|
130
|
+
npx -y auriga-cli install plugins --plugin auriga-notify
|
|
132
131
|
npx -y auriga-cli install plugins --agent codex --plugin session-instructions-loader
|
|
133
132
|
npx -y auriga-cli install plugins --agent both --plugin auriga-git-guards
|
|
134
133
|
```
|
|
@@ -140,31 +139,24 @@ npx -y auriga-cli install plugins --agent both --plugin auriga-git-guards
|
|
|
140
139
|
| codex | Claude Code | Codex cross-model collaboration |
|
|
141
140
|
| auriga-go | Claude Code / Codex | Workflow autopilot for the auriga workflow. Reminder-based navigation across the `CLAUDE.md` phases. Bundles two skills: `auriga-go` (description-based NL trigger + `/auriga-go`) and `/goalify` (plans an autonomous goal from a spec or work-in-progress and dispatches it via Claude Code's built-in `/goal` command). |
|
|
142
141
|
| auriga-git-guards | Claude Code / Codex | Three git-lifecycle guardrails plus the bundled `git-workflow` skill. Hooks: `commit-reminder` (PostToolUse on `Edit` / `Write` / `MultiEdit` in Claude Code and on `apply_patch` — Codex's canonical file-edit `tool_name` — so it fires in both runtimes → when uncommitted diff vs `HEAD` exceeds 200 lines or 8 files and the last reminder was ≥ 60 s ago, inject a nudge to commit at the next semantic boundary), `pr-create-guard` (PostToolUse on `gh pr create` → fetch the new PR's body via `gh pr view` and inject headings + TODO counts as `additionalContext` so the Agent can self-verify the five-element PR description: scope / acceptance criteria / design decisions / risks / remaining TODOs), and `pr-ready-guard` (PreToolUse on `gh pr ready` → block on stray planning docs at `findings.md` / `progress.md` / `task_plan.md` / `docs/superpowers/specs/*.md`, unfinalized active specs in `docs/specs/*.md`, or unpushed commits; otherwise inject the body snapshot). The two PostToolUse hooks reach full Claude Code / Codex parity; Codex currently fails open on `pr-ready-guard`'s PreToolUse `additionalContext` informational path (block path identical). |
|
|
142
|
+
| auriga-workflow-skills | Claude Code / Codex | Bundles the auriga-owned workflow execution skills: `incremental-impl`, `test-designer`, and `session-compound`. Installed by default through the plugin path instead of `install skills`. |
|
|
143
|
+
| auriga-notify *(opt-in)* | Claude Code | macOS native notification plugin for Claude Code `Notification` events. Focus-aware sound-only mode, click-to-activate, per-project notification grouping, and migrated `config.json` / `icon.png` support. Not installed by `install --all`; install explicitly with `install plugins --plugin auriga-notify`. |
|
|
143
144
|
| session-instructions-loader | Codex | Codex-only SessionStart plugin that injects ancestor `AGENTS.md` files plus repo-configured extra instruction files. |
|
|
144
145
|
| deep-review | Claude Code / Codex | Multi-dimensional PR review orchestrator — dispatches parallel reviewers (spec-conformance, correctness, test-quality, docs-sync, plus conditional robustness/UX/performance/structure/code-quality/skill-plugin-quality) and synthesizes findings into an actionable punch list. Bundles a companion `reviewer-creator` skill for scaffolding project-level custom reviewers under `docs/rules/review/`. Drives the formal-review phase in `CLAUDE.md`. |
|
|
145
146
|
|
|
146
147
|
### Hooks
|
|
147
148
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
| notify *(opt-in)* | Native macOS notification when Claude needs your attention. Shows the brand mark in the small app-icon position; click brings the originating terminal back to focus. **Focus-aware**: when the launching terminal is already frontmost, drops the banner and plays the sound only (toggle via `soundOnlyWhenFocused` in `config.json`). **Per-project group ID**: new notifications cleanly replace older ones in Notification Center, no process accumulation, no cross-project interference. Auto-installs `alerter` via Homebrew (`vjeantet/tap/alerter`). Customize sound and icon by editing `.claude/hooks/notify/config.json` and `.claude/hooks/notify/icon.png`. macOS-only at runtime; silent no-op on other platforms. |
|
|
153
|
-
|
|
154
|
-
Scope choices:
|
|
155
|
-
|
|
156
|
-
- **Project local** (recommended for cross-platform teams): files under `./.claude/hooks/`, registered in `./.claude/settings.local.json` — per-developer, not committed.
|
|
157
|
-
- **Project**: same files, registered in `./.claude/settings.json` — shared with the team via git.
|
|
158
|
-
- **User**: files under `~/.claude/hooks/`, registered in `~/.claude/settings.json` — global across all your projects.
|
|
159
|
-
|
|
160
|
-
Re-running the installer preserves your customized `config.json` and `icon.png`, overwrites the runtime, and never produces duplicate hook entries (idempotent merge by sentinel marker).
|
|
149
|
+
The traditional hook installer remains for compatibility, but this repo no
|
|
150
|
+
longer exposes a repo-owned hook through `install hooks`. New repo-owned hooks
|
|
151
|
+
should be shipped inside plugins. The former `notify` hook is now the
|
|
152
|
+
`auriga-notify` plugin.
|
|
161
153
|
|
|
162
154
|
## Requirements
|
|
163
155
|
|
|
164
156
|
- Node.js >= 18
|
|
165
157
|
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) (required for Claude Code Plugins and Hooks modules)
|
|
166
158
|
- Codex CLI (required only for `install plugins --agent codex|both`)
|
|
167
|
-
- [Homebrew](https://brew.sh) (recommended for the `notify`
|
|
159
|
+
- [Homebrew](https://brew.sh) (recommended for the `auriga-notify` plugin to use `alerter`)
|
|
168
160
|
|
|
169
161
|
## Development
|
|
170
162
|
|
package/README.zh-CN.md
CHANGED
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
| 模块 | 说明 |
|
|
12
12
|
|---|---|
|
|
13
13
|
| **Workflow** | `CLAUDE.md` 里的 auriga 工作流:需求澄清 → TDD → Review,Harness 原则,Subagent 使用指南 |
|
|
14
|
-
| **Skills** |
|
|
14
|
+
| **Skills** | 外部开发流程 skills —— brainstorming、systematic-debugging、TDD、verification、planning、playwright |
|
|
15
15
|
| **Recommended Skills** | 可选的工具类 skills(如 `codex-agent`、`claude-code-agent`),在 workflow skills 之外按需追加 |
|
|
16
|
-
| **Plugins** | 推荐的 Claude Code 和 Codex 插件 —— skill-creator、claude-md-management、codex、auriga-go、auriga-git-guards、session-instructions-loader、deep-review |
|
|
17
|
-
| **Hooks** | Claude Code
|
|
16
|
+
| **Plugins** | 推荐的 Claude Code 和 Codex 插件 —— skill-creator、claude-md-management、codex、auriga-go、auriga-git-guards、auriga-workflow-skills、auriga-notify、session-instructions-loader、deep-review |
|
|
17
|
+
| **Hooks** | 传统 Claude Code hook 安装器。目前没有仓库自维护 hook 暴露在这里;`notify` 已迁移为 `auriga-notify` 插件。 |
|
|
18
18
|
|
|
19
19
|
## 快速开始
|
|
20
20
|
|
|
@@ -41,7 +41,7 @@ npx -y auriga-cli guide
|
|
|
41
41
|
非交互安装命令:
|
|
42
42
|
|
|
43
43
|
```bash
|
|
44
|
-
npx -y auriga-cli install --all # workflow + skills + plugins
|
|
44
|
+
npx -y auriga-cli install --all # workflow + skills + 默认 plugins(原子)
|
|
45
45
|
npx -y auriga-cli install recommended # 可选工具 skills(不在 --all 内)
|
|
46
46
|
npx -y auriga-cli install plugins --agent codex --plugin session-instructions-loader
|
|
47
47
|
npx -y auriga-cli install <type> [--flags] # 单类:workflow | skills | recommended | plugins | hooks
|
|
@@ -102,9 +102,6 @@ npx auriga-cli
|
|
|
102
102
|
| verification-before-completion | [obra/superpowers](https://github.com/obra/superpowers) | 完成前验证,用证据说话 |
|
|
103
103
|
| planning-with-files | [OthmanAdi/planning-with-files](https://github.com/OthmanAdi/planning-with-files) | 文件化任务计划与进度跟踪 |
|
|
104
104
|
| playwright-cli | [microsoft/playwright-cli](https://github.com/microsoft/playwright-cli) | 浏览器自动化与测试 |
|
|
105
|
-
| test-designer | [Ben2pc/auriga-cli](https://github.com/Ben2pc/auriga-cli) | TDD 红灯阶段的 Independent Evaluation 测试设计器 |
|
|
106
|
-
| incremental-impl | [Ben2pc/auriga-cli](https://github.com/Ben2pc/auriga-cli) | 决定如何实现非平凡改动:估算大小、选择切片策略、按需并行派遣、执行片间纪律 |
|
|
107
|
-
| session-compound | [Ben2pc/auriga-cli](https://github.com/Ben2pc/auriga-cli) | PR 合并后的会话复利 skill — 将本次会话沉淀为交互式 HTML 报告(时间线 + token / cache / 工具健康度 + playground:skill 安装 / AGENTS.md 修改 / 新建 skill 缺口) |
|
|
108
105
|
|
|
109
106
|
**Recommended Skills(可选,不在 `--all` 内):**
|
|
110
107
|
|
|
@@ -129,6 +126,8 @@ npx auriga-cli
|
|
|
129
126
|
|
|
130
127
|
```bash
|
|
131
128
|
npx -y auriga-cli install plugins --plugin auriga-go
|
|
129
|
+
npx -y auriga-cli install plugins --agent both --plugin auriga-workflow-skills
|
|
130
|
+
npx -y auriga-cli install plugins --plugin auriga-notify
|
|
132
131
|
npx -y auriga-cli install plugins --agent codex --plugin session-instructions-loader
|
|
133
132
|
npx -y auriga-cli install plugins --agent both --plugin auriga-git-guards
|
|
134
133
|
```
|
|
@@ -140,31 +139,23 @@ npx -y auriga-cli install plugins --agent both --plugin auriga-git-guards
|
|
|
140
139
|
| codex | Claude Code | Codex 跨模型协作 |
|
|
141
140
|
| auriga-go | Claude Code / Codex | auriga 工作流的自动驾驶:按 `CLAUDE.md` 的 phase 做 reminder-based 导航。内置两个 skill:`auriga-go`(按 description 的自然语言触发 + `/auriga-go` slash command)和 `/goalify`(根据 spec 或当前进展 plan 出 goal,并通过 Claude Code 内置的 `/goal` 命令分发执行)。 |
|
|
142
141
|
| auriga-git-guards | Claude Code / Codex | 三个 git-lifecycle guardrail + 内置 `git-workflow` skill。Hooks:`commit-reminder`(Claude Code 下 PostToolUse 匹配 `Edit` / `Write` / `MultiEdit`,Codex 下匹配 `apply_patch`(Codex 文件编辑 canonical `tool_name`),两个 runtime 都触发 —— 未提交 diff 对比 `HEAD` 超过 200 行或 8 个文件,且距上次提醒 ≥ 60 s 时,注入提醒让 Agent 在下一个语义边界 commit)、`pr-create-guard`(`gh pr create` 的 PostToolUse —— 通过 `gh pr view` 拉真实 PR body,扫 `^##` / `^###` headings 并统计 `- [ ]` / `- [x]` 注入 `additionalContext`,让 Agent 对照五要素:scope / acceptance criteria / design decisions / risks / remaining TODOs)、`pr-ready-guard`(`gh pr ready` 的 PreToolUse —— 仅按结构信号拦截:游离 `findings.md` / `progress.md` / `task_plan.md` / `docs/superpowers/specs/*.md`、`docs/specs/*.md` 内未结案的活跃 spec、未 push commits;放行时注入 body 快照)。两个 PostToolUse hook 在 Claude Code / Codex 上完全对齐;Codex 仅对 `pr-ready-guard` 的 PreToolUse `additionalContext` 信息路径 fail-open(block 路径两边一致)。 |
|
|
142
|
+
| auriga-workflow-skills | Claude Code / Codex | 打包 auriga 自维护的工作流执行 skills:`incremental-impl`、`test-designer`、`session-compound`。默认通过插件路径安装,不再通过 `install skills` 作为独立条目安装。 |
|
|
143
|
+
| auriga-notify *(opt-in)* | Claude Code | Claude Code `Notification` 事件的 macOS 原生通知插件。支持焦点感知仅提示音、点击唤起终端、按项目分组通知,并迁移旧 `config.json` / `icon.png`。不随 `install --all` 默认安装,需要显式执行 `install plugins --plugin auriga-notify`。 |
|
|
143
144
|
| session-instructions-loader | Codex | Codex-only SessionStart 插件,注入上层目录的 `AGENTS.md` 和仓库配置的额外 instruction 文件。 |
|
|
144
145
|
| deep-review | Claude Code / Codex | 多维度 PR review 编排器 —— 并行派发各维度 reviewer(spec-conformance、correctness、test-quality、docs-sync,以及条件触发的 robustness/UX/performance/structure/code-quality/skill-plugin-quality),汇总成 punch list。同包内打包了 `reviewer-creator` skill,用于在 `docs/rules/review/` 下生成项目级自定义 reviewer。承担 `CLAUDE.md` 中的正式评审职责。 |
|
|
145
146
|
|
|
146
147
|
### Hooks
|
|
147
148
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|---|---|
|
|
152
|
-
| notify *(opt-in)* | 当 Claude 需要你关注时弹一条原生 macOS 通知。在通知小图标位显示品牌图,点击通知可把发起 Claude 的终端拉回前台。**焦点感知**:发起 Claude 的终端正处于前台时,仅放提示音不弹横幅(通过 `config.json` 的 `soundOnlyWhenFocused` 切换)。**按项目分组**:新通知会干净地替换通知中心里的旧条目,不会进程堆积,也不会跨项目互相覆盖。会自动通过 Homebrew 安装 `alerter`(`vjeantet/tap/alerter`)。改 `.claude/hooks/notify/config.json` 即可换提示音、替换 `.claude/hooks/notify/icon.png` 即可换图标。仅 macOS 运行时生效,其它平台静默 no-op。 |
|
|
153
|
-
|
|
154
|
-
作用域选择:
|
|
155
|
-
|
|
156
|
-
- **Project local**(推荐给跨平台团队):文件落在 `./.claude/hooks/`,注册到 `./.claude/settings.local.json` —— 每个开发者各自安装,不进 git。
|
|
157
|
-
- **Project**:同样的文件,注册到 `./.claude/settings.json` —— 整个团队共享。
|
|
158
|
-
- **User**:文件落在 `~/.claude/hooks/`,注册到 `~/.claude/settings.json` —— 全局生效。
|
|
159
|
-
|
|
160
|
-
重新跑安装器时会保留你修改过的 `config.json` 和 `icon.png`,覆盖运行时本身,并通过 marker 字段幂等去重,绝不会产生重复的 hook 条目。
|
|
149
|
+
传统 hook 安装器仍保留作兼容入口,但本仓库当前不再通过
|
|
150
|
+
`install hooks` 暴露自维护 hook。新的自维护 hook 应随插件分发。原来的
|
|
151
|
+
`notify` hook 已迁移为 `auriga-notify` 插件。
|
|
161
152
|
|
|
162
153
|
## 环境要求
|
|
163
154
|
|
|
164
155
|
- Node.js >= 18
|
|
165
156
|
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code)(Claude Code Plugins 和 Hooks 模块需要)
|
|
166
157
|
- Codex CLI(仅 `install plugins --agent codex|both` 需要)
|
|
167
|
-
- [Homebrew](https://brew.sh)(`notify`
|
|
158
|
+
- [Homebrew](https://brew.sh)(`auriga-notify` 插件使用 `alerter` 时推荐安装)
|
|
168
159
|
|
|
169
160
|
## 开发
|
|
170
161
|
|
package/dist/catalog.json
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generatedAt": "2026-05-
|
|
2
|
+
"generatedAt": "2026-05-13T12:23:25.619Z",
|
|
3
3
|
"workflowSkills": [
|
|
4
4
|
{
|
|
5
5
|
"name": "brainstorming",
|
|
6
6
|
"description": "You MUST use this before any creative work - creating features, building components, adding functionality, or modifying behavior. Explores user intent, requirements and design before implementation."
|
|
7
7
|
},
|
|
8
|
-
{
|
|
9
|
-
"name": "incremental-impl",
|
|
10
|
-
"description": "Plan a non-trivial code change end-to-end — size triage (XS–XL), slicing strategy, optional parallel subagent dispatch, per-slice Implement → Test → Verify → Commit discipline. Use for any multi-file change, refactor across files, executing a planned task from any planning source, cross-cutting modification (analytics sweep / i18n / library migration), or when about to write more than ~100 lines. 也用于增量实现 / 切片落地 / 推进已规划任务 / 跨切面改动。Skip only for trivial XS edits and pure documentation / configuration changes."
|
|
11
|
-
},
|
|
12
8
|
{
|
|
13
9
|
"name": "planning-with-files",
|
|
14
10
|
"description": "Implements Manus-style file-based planning to organize and track progress on complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when asked to plan out, break down, or organize a multi-step project, research task, or any work requiring 5+ tool calls. Supports automatic session recovery after /clear."
|
|
@@ -17,18 +13,10 @@
|
|
|
17
13
|
"name": "playwright-cli",
|
|
18
14
|
"description": "Automate browser interactions, test web pages and work with Playwright tests."
|
|
19
15
|
},
|
|
20
|
-
{
|
|
21
|
-
"name": "session-compound",
|
|
22
|
-
"description": "This skill should be used when the user asks to \"复盘 / 总结 / 沉淀 / wrap up this session\", \"整理一下这次会话\", or \"extract takeaways from this session\". It compounds a single Claude Code or Codex CLI session into a self-contained interactive HTML report (narrative timeline + token / cache / tool health + a playground panel with checkable candidate items for ecosystem-skill installs / AGENTS.md edits / new-skill gaps) so the user can review, tick, and copy back a prompt that lands each item in the right place."
|
|
23
|
-
},
|
|
24
16
|
{
|
|
25
17
|
"name": "systematic-debugging",
|
|
26
18
|
"description": "Use when encountering any bug, test failure, or unexpected behavior, before proposing fixes"
|
|
27
19
|
},
|
|
28
|
-
{
|
|
29
|
-
"name": "test-designer",
|
|
30
|
-
"description": "Design failing tests for complex features using Independent Evaluation — dispatches a context-free agent that sees only the requirement spec and code paths (not the implementation approach), then returns executable failing tests. Use when starting TDD for a non-trivial feature, when the requirement is ambiguous enough that biased tests are a risk, or when the user asks for independent test design."
|
|
31
|
-
},
|
|
32
20
|
{
|
|
33
21
|
"name": "test-driven-development",
|
|
34
22
|
"description": "Use when implementing any feature or bugfix, before writing implementation code"
|
|
@@ -113,6 +101,21 @@
|
|
|
113
101
|
"codex"
|
|
114
102
|
]
|
|
115
103
|
},
|
|
104
|
+
{
|
|
105
|
+
"name": "auriga-workflow-skills",
|
|
106
|
+
"description": "(Claude/Codex) Bundles the auriga-owned workflow execution skills: incremental-impl, test-designer, and session-compound.",
|
|
107
|
+
"agents": [
|
|
108
|
+
"claude",
|
|
109
|
+
"codex"
|
|
110
|
+
]
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"name": "auriga-notify",
|
|
114
|
+
"description": "(opt-in) Opt-in macOS native notification hook for Claude Code Notification events; migrates legacy notify config and icon on install.",
|
|
115
|
+
"agents": [
|
|
116
|
+
"claude"
|
|
117
|
+
]
|
|
118
|
+
},
|
|
116
119
|
{
|
|
117
120
|
"name": "deep-review",
|
|
118
121
|
"description": "(Claude/Codex) Multi-dimensional PR review orchestrator. Dispatches parallel reviewers (spec-conformance, correctness, test-quality, docs-sync, robustness, security, ux, performance, structure, code-quality, skill-plugin-quality) and synthesizes findings into an actionable punch list. Supports project-level custom reviewers via docs/rules/review/ and ships a reviewer-creator skill for scaffolding them.",
|
|
@@ -129,10 +132,5 @@
|
|
|
129
132
|
]
|
|
130
133
|
}
|
|
131
134
|
],
|
|
132
|
-
"hooks": [
|
|
133
|
-
{
|
|
134
|
-
"name": "notify",
|
|
135
|
-
"description": "(opt-in) Native macOS notification when Claude needs your attention (auto-installs alerter via Homebrew)"
|
|
136
|
-
}
|
|
137
|
-
]
|
|
135
|
+
"hooks": []
|
|
138
136
|
}
|
package/dist/cli.js
CHANGED
|
@@ -316,10 +316,22 @@ function validateFilterAgainstCatalog(type, filter) {
|
|
|
316
316
|
const singular = categorySingular(type);
|
|
317
317
|
for (const name of filter) {
|
|
318
318
|
if (!available.includes(name)) {
|
|
319
|
-
|
|
319
|
+
const hint = migratedPluginHint(type, name);
|
|
320
|
+
const hintText = hint ? ` ${hint}` : "";
|
|
321
|
+
parseErr(`unknown ${singular} '${name}';${hintText} available: ${available.join(", ")}`);
|
|
320
322
|
}
|
|
321
323
|
}
|
|
322
324
|
}
|
|
325
|
+
function migratedPluginHint(type, name) {
|
|
326
|
+
if (type === "skills" &&
|
|
327
|
+
["incremental-impl", "test-designer", "session-compound"].includes(name)) {
|
|
328
|
+
return "This skill moved to the auriga-workflow-skills plugin; install it with `install plugins --plugin auriga-workflow-skills`.";
|
|
329
|
+
}
|
|
330
|
+
if (type === "hooks" && name === "notify") {
|
|
331
|
+
return "The notify hook moved to the auriga-notify plugin; install it with `install plugins --plugin auriga-notify`.";
|
|
332
|
+
}
|
|
333
|
+
return undefined;
|
|
334
|
+
}
|
|
323
335
|
function categorySingular(type) {
|
|
324
336
|
return type === "recommended" ? "recommended skill"
|
|
325
337
|
: type === "skills" ? "skill"
|
package/dist/guide.js
CHANGED
|
@@ -20,7 +20,7 @@ export function renderGuide(opts) {
|
|
|
20
20
|
return `${h(`# auriga-cli bootstrap SOP (v${opts.version})`)}
|
|
21
21
|
|
|
22
22
|
This guide walks an Agent through installing the auriga harness
|
|
23
|
-
(CLAUDE.md + skills + plugins
|
|
23
|
+
(CLAUDE.md + skills + plugins, plus any legacy hooks) into the current repository.
|
|
24
24
|
|
|
25
25
|
Run each step in order. If any step fails with exit 1, stop and report.
|
|
26
26
|
If exit 2, see stderr for per-category status and follow the "Retry"
|
|
@@ -62,8 +62,8 @@ Per-type detail (flags + only that category's catalog slice):
|
|
|
62
62
|
|
|
63
63
|
${h("## Step 3 — Install")}
|
|
64
64
|
|
|
65
|
-
Preset — the full default-on set (workflow + skills + plugins
|
|
66
|
-
recommended skills are NOT included):
|
|
65
|
+
Preset — the full default-on set (workflow + skills + default plugins;
|
|
66
|
+
the legacy hooks category is currently empty; recommended skills are NOT included):
|
|
67
67
|
${cmd("npx -y auriga-cli install --all")}
|
|
68
68
|
|
|
69
69
|
Targeted — single category, picking from the catalog surfaced in Step 2:
|
|
@@ -72,10 +72,10 @@ Targeted — single category, picking from the catalog surfaced in Step 2:
|
|
|
72
72
|
${cmd("npx -y auriga-cli install plugins --plugin skill-creator codex --scope user")}
|
|
73
73
|
${cmd("npx -y auriga-cli install plugins --agent codex --plugin session-instructions-loader")}
|
|
74
74
|
|
|
75
|
-
Opt-in
|
|
76
|
-
set because they have side effects
|
|
77
|
-
|
|
78
|
-
${cmd("npx -y auriga-cli install
|
|
75
|
+
Opt-in plugins (\`defaultOn: false\`) are NOT in the default \`install --all\`
|
|
76
|
+
set because they have side effects or platform-specific behavior. For example,
|
|
77
|
+
the macOS notification plugin is explicit opt-in:
|
|
78
|
+
${cmd("npx -y auriga-cli install plugins --plugin auriga-notify")}
|
|
79
79
|
|
|
80
80
|
Opt-in recommended skills (cross-model delegation helpers —
|
|
81
81
|
claude-code-agent, codex-agent):
|
|
@@ -94,7 +94,7 @@ Exit codes:
|
|
|
94
94
|
${h("## Step 4 — Reload session (REQUIRED when installed non-interactively)")}
|
|
95
95
|
|
|
96
96
|
${warn("⚠")} CLAUDE.md, .agents/skills/, .claude/plugins.json, Codex plugin
|
|
97
|
-
config, and hook registrations are loaded at session startup. If you ran
|
|
97
|
+
config, and hook/plugin registrations are loaded at session startup. If you ran
|
|
98
98
|
\`npx -y auriga-cli install\` inside an existing Claude Code or Codex session
|
|
99
99
|
(e.g., \`claude -p\` / \`claude -p --worktree\` / \`codex exec\`), the current session
|
|
100
100
|
will NOT see the new harness.
|
|
@@ -112,7 +112,8 @@ Expected artifacts:
|
|
|
112
112
|
- .agents/skills/<name>/ (one per installed skill)
|
|
113
113
|
- .claude/plugins.json
|
|
114
114
|
- ~/.codex/config.toml (Codex plugin enablement, if Codex plugins selected)
|
|
115
|
-
- .claude/settings.json (updated hook registrations, if
|
|
115
|
+
- .claude/settings.json (updated hook/plugin registrations, if selected)
|
|
116
|
+
- .claude/auriga-notify/ (project notify config, if auriga-notify selected)
|
|
116
117
|
|
|
117
118
|
${h("## Troubleshooting")}
|
|
118
119
|
|
package/dist/help.js
CHANGED
|
@@ -125,7 +125,7 @@ USAGE
|
|
|
125
125
|
|
|
126
126
|
FLAGS
|
|
127
127
|
--plugin <names...> space-separated; '*' = all
|
|
128
|
-
omit → install every plugin
|
|
128
|
+
omit → install every plugin with defaultOn != false
|
|
129
129
|
--agent <...> target runtime: claude, codex, or both
|
|
130
130
|
default claude; codex enablement is user-level
|
|
131
131
|
--scope <project|user> default project
|
package/dist/hooks.js
CHANGED
|
@@ -687,7 +687,12 @@ export async function installHooks(packageRoot, opts) {
|
|
|
687
687
|
const config = loadHooksConfig(packageRoot);
|
|
688
688
|
const compatible = config.hooks.filter((h) => h.runtimePlatforms.includes(process.platform));
|
|
689
689
|
if (compatible.length === 0) {
|
|
690
|
-
|
|
690
|
+
if (config.hooks.length === 0) {
|
|
691
|
+
log.warn("No legacy hooks are defined. The notify hook moved to the opt-in auriga-notify plugin.");
|
|
692
|
+
}
|
|
693
|
+
else {
|
|
694
|
+
log.warn(`No hooks available for your platform (${process.platform}). Skipping.`);
|
|
695
|
+
}
|
|
691
696
|
return;
|
|
692
697
|
}
|
|
693
698
|
// Non-interactive explicit `--hook <name>` has stronger intent than
|
package/dist/plugins.js
CHANGED
|
@@ -3,7 +3,7 @@ import os from "node:os";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { checkbox, select } from "@inquirer/prompts";
|
|
5
5
|
import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
|
|
6
|
-
import { codexManifestPath, validateCodexInstallConfig, validateCodexMarketplace, } from "./codex-plugin-config.js";
|
|
6
|
+
import { codexLocalPluginPath, codexManifestPath, validateCodexInstallConfig, validateCodexMarketplace, } from "./codex-plugin-config.js";
|
|
7
7
|
import { validateMarketplaceField } from "./marketplace.js";
|
|
8
8
|
import { atomicWriteFile, exec, execAsync, fetchExtraContent, log, withEsc } from "./utils.js";
|
|
9
9
|
// Plugin names and plugin-package names end up in `claude plugins ...`
|
|
@@ -15,6 +15,15 @@ import { atomicWriteFile, exec, execAsync, fetchExtraContent, log, withEsc } fro
|
|
|
15
15
|
// `./marketplace.js` so Claude and Codex sides share one validator.
|
|
16
16
|
const PLUGIN_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
17
17
|
const PLUGIN_PACKAGE_RE = /^[A-Za-z0-9][A-Za-z0-9._@/-]{0,255}$/;
|
|
18
|
+
const MIGRATED_WORKFLOW_SKILLS = [
|
|
19
|
+
"incremental-impl",
|
|
20
|
+
"test-designer",
|
|
21
|
+
"session-compound",
|
|
22
|
+
];
|
|
23
|
+
const NOTIFY_PLUGIN_NAME = "auriga-notify";
|
|
24
|
+
const WORKFLOW_SKILLS_PLUGIN_NAME = "auriga-workflow-skills";
|
|
25
|
+
const LEGACY_NOTIFY_MARKER = "auriga:notify";
|
|
26
|
+
const CODEX_PLUGIN_VERSION_RE = /^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/;
|
|
18
27
|
export function validatePluginsConfig(raw) {
|
|
19
28
|
if (!raw || typeof raw !== "object") {
|
|
20
29
|
throw new Error("plugins.json: root must be an object");
|
|
@@ -37,6 +46,9 @@ export function validatePluginsConfig(raw) {
|
|
|
37
46
|
if (plugin.marketplace !== undefined) {
|
|
38
47
|
validateMarketplaceField(`plugins.json: plugins[${i}]`, plugin.marketplace);
|
|
39
48
|
}
|
|
49
|
+
if (plugin.defaultOn !== undefined && typeof plugin.defaultOn !== "boolean") {
|
|
50
|
+
throw new Error(`plugins.json: plugins[${i}].defaultOn must be a boolean`);
|
|
51
|
+
}
|
|
40
52
|
});
|
|
41
53
|
}
|
|
42
54
|
function getInstalledPlugins() {
|
|
@@ -60,12 +72,14 @@ function getInstalledPlugins() {
|
|
|
60
72
|
}
|
|
61
73
|
}
|
|
62
74
|
/**
|
|
63
|
-
* Non-interactive selection resolver for plugins.
|
|
64
|
-
*
|
|
65
|
-
* filter. CLI parser validates names up-front.
|
|
75
|
+
* Non-interactive selection resolver for plugins.
|
|
76
|
+
* `undefined` = default-on set; `["*"]` = full set; explicit names =
|
|
77
|
+
* exact filter. CLI parser validates names up-front.
|
|
66
78
|
*/
|
|
67
79
|
function resolvePluginSelection(all, selected) {
|
|
68
|
-
if (!selected
|
|
80
|
+
if (!selected)
|
|
81
|
+
return all.filter((p) => p.defaultOn !== false);
|
|
82
|
+
if (selected.length === 1 && selected[0] === "*")
|
|
69
83
|
return all;
|
|
70
84
|
const byName = new Map(all.map((p) => [p.name, p]));
|
|
71
85
|
const missing = selected.filter((name) => !byName.has(name));
|
|
@@ -121,6 +135,162 @@ function codexHome() {
|
|
|
121
135
|
function shellQuote(value) {
|
|
122
136
|
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
123
137
|
}
|
|
138
|
+
function installTargetCwd(opts) {
|
|
139
|
+
return path.resolve(opts.cwd ?? process.cwd());
|
|
140
|
+
}
|
|
141
|
+
function emitMigrationLog(opts, line) {
|
|
142
|
+
opts.onLog?.(line, "stdout");
|
|
143
|
+
}
|
|
144
|
+
function runtimeSkillRoot(runtime) {
|
|
145
|
+
return runtime === "claude" ? ".claude" : ".agents";
|
|
146
|
+
}
|
|
147
|
+
function legacySkillDir(opts, runtime, name) {
|
|
148
|
+
const cwd = installTargetCwd(opts);
|
|
149
|
+
const scope = opts.scope ?? "project";
|
|
150
|
+
const baseDir = scope === "user" ? os.homedir() : cwd;
|
|
151
|
+
return path.join(baseDir, runtimeSkillRoot(runtime), "skills", name);
|
|
152
|
+
}
|
|
153
|
+
function isWorkflowPluginDevSymlink(skillPath, cwd, name) {
|
|
154
|
+
const stat = fs.lstatSync(skillPath, { throwIfNoEntry: false });
|
|
155
|
+
if (!stat?.isSymbolicLink())
|
|
156
|
+
return false;
|
|
157
|
+
const target = fs.readlinkSync(skillPath);
|
|
158
|
+
const resolved = path.resolve(path.dirname(skillPath), target);
|
|
159
|
+
const expected = path.resolve(cwd, "plugins", "auriga-workflow-skills", "skills", name);
|
|
160
|
+
return resolved === expected;
|
|
161
|
+
}
|
|
162
|
+
function removeMigratedSkillFromLock(cwd, name, opts) {
|
|
163
|
+
const lockPath = path.join(cwd, "skills-lock.json");
|
|
164
|
+
if (!fs.existsSync(lockPath))
|
|
165
|
+
return;
|
|
166
|
+
const raw = JSON.parse(fs.readFileSync(lockPath, "utf-8"));
|
|
167
|
+
if (!raw.skills || typeof raw.skills !== "object" || !(name in raw.skills))
|
|
168
|
+
return;
|
|
169
|
+
const nextSkills = { ...raw.skills };
|
|
170
|
+
delete nextSkills[name];
|
|
171
|
+
atomicWriteFile(lockPath, JSON.stringify({ ...raw, skills: nextSkills }, null, 2) + "\n");
|
|
172
|
+
emitMigrationLog(opts, `removed ${name} from skills-lock.json`);
|
|
173
|
+
}
|
|
174
|
+
function cleanupMigratedWorkflowSkillInstalls(opts, runtimes) {
|
|
175
|
+
const cwd = installTargetCwd(opts);
|
|
176
|
+
const scope = opts.scope ?? "project";
|
|
177
|
+
for (const name of MIGRATED_WORKFLOW_SKILLS) {
|
|
178
|
+
for (const runtime of runtimes) {
|
|
179
|
+
const dir = legacySkillDir(opts, runtime, name);
|
|
180
|
+
const stat = fs.lstatSync(dir, { throwIfNoEntry: false });
|
|
181
|
+
if (!stat)
|
|
182
|
+
continue;
|
|
183
|
+
if (scope === "project" && isWorkflowPluginDevSymlink(dir, cwd, name)) {
|
|
184
|
+
emitMigrationLog(opts, `preserved ${runtimeSkillRoot(runtime)}/skills/${name} development symlink`);
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
188
|
+
emitMigrationLog(opts, `removed ${runtimeSkillRoot(runtime)}/skills/${name}`);
|
|
189
|
+
}
|
|
190
|
+
if (scope === "project")
|
|
191
|
+
removeMigratedSkillFromLock(cwd, name, opts);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
function copyIfPresentWithoutOverwrite(src, dest) {
|
|
195
|
+
if (!fs.existsSync(src) || fs.existsSync(dest))
|
|
196
|
+
return false;
|
|
197
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
198
|
+
fs.copyFileSync(src, dest);
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
function removeMarkerFromSettings(settings, marker) {
|
|
202
|
+
const next = JSON.parse(JSON.stringify(settings ?? {}));
|
|
203
|
+
if (!next.hooks || typeof next.hooks !== "object" || Array.isArray(next.hooks)) {
|
|
204
|
+
return { settings: next, removed: 0 };
|
|
205
|
+
}
|
|
206
|
+
let removed = 0;
|
|
207
|
+
for (const event of Object.keys(next.hooks)) {
|
|
208
|
+
const groups = next.hooks[event];
|
|
209
|
+
if (!Array.isArray(groups))
|
|
210
|
+
continue;
|
|
211
|
+
const nextGroups = [];
|
|
212
|
+
for (const group of groups) {
|
|
213
|
+
if (!Array.isArray(group.hooks)) {
|
|
214
|
+
nextGroups.push(group);
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
const hooks = group.hooks.filter((action) => {
|
|
218
|
+
if (action?._marker === marker) {
|
|
219
|
+
removed += 1;
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
return true;
|
|
223
|
+
});
|
|
224
|
+
if (hooks.length > 0)
|
|
225
|
+
nextGroups.push({ ...group, hooks });
|
|
226
|
+
}
|
|
227
|
+
if (nextGroups.length > 0)
|
|
228
|
+
next.hooks[event] = nextGroups;
|
|
229
|
+
else
|
|
230
|
+
delete next.hooks[event];
|
|
231
|
+
}
|
|
232
|
+
return { settings: next, removed };
|
|
233
|
+
}
|
|
234
|
+
function cleanLegacyNotifySettings(settingsPaths, opts) {
|
|
235
|
+
let allReadable = true;
|
|
236
|
+
for (const settingsPath of settingsPaths) {
|
|
237
|
+
if (!fs.existsSync(settingsPath))
|
|
238
|
+
continue;
|
|
239
|
+
let parsed;
|
|
240
|
+
try {
|
|
241
|
+
parsed = JSON.parse(fs.readFileSync(settingsPath, "utf-8"));
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
emitMigrationLog(opts, `skipped unreadable legacy notify settings: ${settingsPath}`);
|
|
245
|
+
allReadable = false;
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
const result = removeMarkerFromSettings(parsed, LEGACY_NOTIFY_MARKER);
|
|
249
|
+
if (result.removed === 0)
|
|
250
|
+
continue;
|
|
251
|
+
atomicWriteFile(settingsPath, JSON.stringify(result.settings, null, 2) + "\n");
|
|
252
|
+
emitMigrationLog(opts, `removed ${result.removed} legacy notify settings entries from ${settingsPath}`);
|
|
253
|
+
}
|
|
254
|
+
return allReadable;
|
|
255
|
+
}
|
|
256
|
+
function migrateLegacyNotifyConfig(opts) {
|
|
257
|
+
const scope = opts.scope ?? "project";
|
|
258
|
+
const cwd = installTargetCwd(opts);
|
|
259
|
+
const home = os.homedir();
|
|
260
|
+
const legacyBase = scope === "user" ? home : cwd;
|
|
261
|
+
const legacyDir = path.join(legacyBase, ".claude", "hooks", "notify");
|
|
262
|
+
const destDir = scope === "user"
|
|
263
|
+
? path.join(home, ".config", "auriga-cli", "notify")
|
|
264
|
+
: path.join(cwd, ".claude", "auriga-notify");
|
|
265
|
+
const copiedConfig = copyIfPresentWithoutOverwrite(path.join(legacyDir, "config.json"), path.join(destDir, "config.json"));
|
|
266
|
+
const copiedIcon = copyIfPresentWithoutOverwrite(path.join(legacyDir, "icon.png"), path.join(destDir, "icon.png"));
|
|
267
|
+
if (copiedConfig)
|
|
268
|
+
emitMigrationLog(opts, `migrated legacy notify config to ${path.join(destDir, "config.json")}`);
|
|
269
|
+
if (copiedIcon)
|
|
270
|
+
emitMigrationLog(opts, `migrated legacy notify icon to ${path.join(destDir, "icon.png")}`);
|
|
271
|
+
const settingsPaths = scope === "user"
|
|
272
|
+
? [path.join(home, ".claude", "settings.json")]
|
|
273
|
+
: [
|
|
274
|
+
path.join(cwd, ".claude", "settings.json"),
|
|
275
|
+
path.join(cwd, ".claude", "settings.local.json"),
|
|
276
|
+
];
|
|
277
|
+
const settingsCleaned = cleanLegacyNotifySettings(settingsPaths, opts);
|
|
278
|
+
if (settingsCleaned && fs.existsSync(legacyDir)) {
|
|
279
|
+
fs.rmSync(legacyDir, { recursive: true, force: true });
|
|
280
|
+
emitMigrationLog(opts, `removed legacy notify hook directory ${legacyDir}`);
|
|
281
|
+
}
|
|
282
|
+
else if (!settingsCleaned && fs.existsSync(legacyDir)) {
|
|
283
|
+
emitMigrationLog(opts, `kept legacy notify hook directory because settings cleanup was incomplete: ${legacyDir}`);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
function runPostInstallMigration(pluginName, opts, runtimes) {
|
|
287
|
+
if (pluginName === WORKFLOW_SKILLS_PLUGIN_NAME) {
|
|
288
|
+
cleanupMigratedWorkflowSkillInstalls(opts, runtimes);
|
|
289
|
+
}
|
|
290
|
+
if (pluginName === NOTIFY_PLUGIN_NAME) {
|
|
291
|
+
migrateLegacyNotifyConfig(opts);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
124
294
|
function codexMarketplaceAddCommand(packageRoot) {
|
|
125
295
|
if (process.env.DEV === "1") {
|
|
126
296
|
return `codex plugin marketplace add ${shellQuote(packageRoot)}`;
|
|
@@ -167,6 +337,16 @@ function pluginHasHooks(packageRoot, plugin) {
|
|
|
167
337
|
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
168
338
|
return typeof manifest.hooks === "string" || Array.isArray(manifest.hooks);
|
|
169
339
|
}
|
|
340
|
+
function resolveSelectedCodexMarketplacePlugins(localMarketplace, localSelected) {
|
|
341
|
+
const localMpByName = new Map(localMarketplace.plugins.map((p) => [p.name, p]));
|
|
342
|
+
return localSelected.map((p) => {
|
|
343
|
+
const plugin = localMpByName.get(p.name);
|
|
344
|
+
if (!plugin) {
|
|
345
|
+
throw new Error(`Codex install.json: plugin ${p.name} is not present in marketplace.json`);
|
|
346
|
+
}
|
|
347
|
+
return plugin;
|
|
348
|
+
});
|
|
349
|
+
}
|
|
170
350
|
async function ensureCodexPluginManifests(packageRoot, plugins) {
|
|
171
351
|
for (const plugin of plugins) {
|
|
172
352
|
const manifestPath = codexManifestPath(plugin);
|
|
@@ -178,6 +358,38 @@ async function ensureCodexPluginManifests(packageRoot, plugins) {
|
|
|
178
358
|
await fetchExtraContent(packageRoot, manifestPath);
|
|
179
359
|
}
|
|
180
360
|
}
|
|
361
|
+
function readCodexPluginVersion(packageRoot, plugin) {
|
|
362
|
+
const manifestPath = codexManifestPath(plugin);
|
|
363
|
+
if (!manifestPath) {
|
|
364
|
+
throw new Error(`Codex marketplace.json: plugin ${plugin.name} must use a local source.path`);
|
|
365
|
+
}
|
|
366
|
+
const manifest = JSON.parse(fs.readFileSync(path.join(packageRoot, manifestPath), "utf-8"));
|
|
367
|
+
if (typeof manifest.version !== "string" || !CODEX_PLUGIN_VERSION_RE.test(manifest.version)) {
|
|
368
|
+
throw new Error(`Codex plugin ${plugin.name} manifest must include a safe string version`);
|
|
369
|
+
}
|
|
370
|
+
return manifest.version;
|
|
371
|
+
}
|
|
372
|
+
function materializeLocalCodexPluginCache(packageRoot, marketplaceName, plugins) {
|
|
373
|
+
const cacheRoot = path.join(codexHome(), "plugins", "cache");
|
|
374
|
+
for (const plugin of plugins) {
|
|
375
|
+
const sourcePath = codexLocalPluginPath(plugin);
|
|
376
|
+
if (!sourcePath) {
|
|
377
|
+
throw new Error(`Codex marketplace.json: plugin ${plugin.name} must use a local source.path`);
|
|
378
|
+
}
|
|
379
|
+
const version = readCodexPluginVersion(packageRoot, plugin);
|
|
380
|
+
const sourceDir = path.join(packageRoot, sourcePath);
|
|
381
|
+
const destDir = path.join(cacheRoot, marketplaceName, plugin.name, version);
|
|
382
|
+
const tmpDir = `${destDir}.tmp-${process.pid}-${Date.now()}`;
|
|
383
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
384
|
+
fs.mkdirSync(path.dirname(destDir), { recursive: true });
|
|
385
|
+
fs.cpSync(sourceDir, tmpDir, { recursive: true });
|
|
386
|
+
fs.rmSync(destDir, { recursive: true, force: true });
|
|
387
|
+
fs.renameSync(tmpDir, destDir);
|
|
388
|
+
if (!fs.existsSync(path.join(destDir, ".codex-plugin", "plugin.json"))) {
|
|
389
|
+
throw new Error(`Codex plugin ${plugin.name} cache materialization did not produce plugin.json`);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
181
393
|
function ensureTomlBoolean(content, section, key, value) {
|
|
182
394
|
const line = `${key} = ${value ? "true" : "false"}`;
|
|
183
395
|
const header = `[${section}]`;
|
|
@@ -306,19 +518,10 @@ async function addCodexMarketplaceWithRetry(marketplaceName, addCommand, opts, m
|
|
|
306
518
|
// manifest at install time. Acceptable while no external plugin ships
|
|
307
519
|
// hooks; once one does, prefer fetching the manifest or adding an
|
|
308
520
|
// explicit `requiresPluginHooks: true` field on the install.json entry.
|
|
309
|
-
async function composeCodexPluginKeys(packageRoot, localMarketplace,
|
|
521
|
+
async function composeCodexPluginKeys(packageRoot, localMarketplace, selectedMarketplacePlugins, externalSelected) {
|
|
310
522
|
const pluginKeys = [];
|
|
311
523
|
let needsPluginHooks = false;
|
|
312
524
|
if (localMarketplace) {
|
|
313
|
-
const localMpByName = new Map(localMarketplace.plugins.map((p) => [p.name, p]));
|
|
314
|
-
const selectedMarketplacePlugins = localSelected.map((p) => {
|
|
315
|
-
const plugin = localMpByName.get(p.name);
|
|
316
|
-
if (!plugin) {
|
|
317
|
-
throw new Error(`Codex install.json: plugin ${p.name} is not present in marketplace.json`);
|
|
318
|
-
}
|
|
319
|
-
return plugin;
|
|
320
|
-
});
|
|
321
|
-
await ensureCodexPluginManifests(packageRoot, selectedMarketplacePlugins);
|
|
322
525
|
for (const plugin of selectedMarketplacePlugins) {
|
|
323
526
|
pluginKeys.push(`${plugin.name}@${localMarketplace.name}`);
|
|
324
527
|
if (pluginHasHooks(packageRoot, plugin))
|
|
@@ -397,10 +600,18 @@ async function installCodexPlugins(packageRoot, opts) {
|
|
|
397
600
|
await addCodexMarketplaceWithRetry(mp.name, codexExternalMarketplaceAddCommand(mp.source), opts, marketplaceExecOpts, failures);
|
|
398
601
|
}
|
|
399
602
|
if (failures.length === 0) {
|
|
400
|
-
const
|
|
603
|
+
const selectedMarketplacePlugins = localMarketplace
|
|
604
|
+
? resolveSelectedCodexMarketplacePlugins(localMarketplace, localSelected)
|
|
605
|
+
: [];
|
|
606
|
+
await ensureCodexPluginManifests(packageRoot, selectedMarketplacePlugins);
|
|
607
|
+
if (localMarketplace) {
|
|
608
|
+
materializeLocalCodexPluginCache(packageRoot, localMarketplace.name, selectedMarketplacePlugins);
|
|
609
|
+
}
|
|
610
|
+
const { pluginKeys, needsPluginHooks } = await composeCodexPluginKeys(packageRoot, localMarketplace, selectedMarketplacePlugins, externalSelected);
|
|
401
611
|
enableCodexPluginConfig(path.join(codexHome(), "config.toml"), pluginKeys, needsPluginHooks);
|
|
402
612
|
for (const plugin of [...localSelected, ...externalSelected]) {
|
|
403
613
|
log.ok(`${plugin.name} enabled for Codex`);
|
|
614
|
+
runPostInstallMigration(plugin.name, opts, ["codex"]);
|
|
404
615
|
}
|
|
405
616
|
}
|
|
406
617
|
if (failures.length > 0 && !opts.interactive) {
|
|
@@ -490,10 +701,11 @@ export async function installPlugins(packageRoot, opts) {
|
|
|
490
701
|
choices: config.plugins.map((p) => {
|
|
491
702
|
const scopes = installed.get(p.package);
|
|
492
703
|
const suffix = scopes ? ` (installed: ${scopes.join(", ")})` : "";
|
|
704
|
+
const installedEverywhere = scopes?.includes("user") && scopes?.includes("project");
|
|
493
705
|
return {
|
|
494
706
|
name: `${p.name} — ${p.description}${suffix}`,
|
|
495
707
|
value: p,
|
|
496
|
-
checked:
|
|
708
|
+
checked: p.defaultOn !== false && !installedEverywhere,
|
|
497
709
|
};
|
|
498
710
|
}),
|
|
499
711
|
}))
|
|
@@ -572,14 +784,16 @@ export async function installPlugins(packageRoot, opts) {
|
|
|
572
784
|
console.log(`\nInstalling ${plugin.name}...`);
|
|
573
785
|
try {
|
|
574
786
|
const cmd = `claude plugins install ${plugin.package} --scope ${scope}`;
|
|
787
|
+
const cmdOpts = { cwd: installTargetCwd(opts) };
|
|
575
788
|
if (opts.onLog) {
|
|
576
789
|
opts.onLog(`▸ ${cmd}`, "stdout");
|
|
577
|
-
await execAsync(cmd, { onLine: opts.onLog });
|
|
790
|
+
await execAsync(cmd, { ...cmdOpts, onLine: opts.onLog });
|
|
578
791
|
}
|
|
579
792
|
else {
|
|
580
|
-
exec(cmd, { inherit: true });
|
|
793
|
+
exec(cmd, { ...cmdOpts, inherit: true });
|
|
581
794
|
}
|
|
582
795
|
log.ok(`${plugin.name} installed`);
|
|
796
|
+
runPostInstallMigration(plugin.name, { ...opts, scope }, ["claude"]);
|
|
583
797
|
}
|
|
584
798
|
catch {
|
|
585
799
|
log.error(`Failed to install: ${plugin.name}`);
|
package/dist/skills.js
CHANGED
|
@@ -8,12 +8,9 @@ import { atomicWriteFile, exec, execAsync, log, withEsc } from "./utils.js";
|
|
|
8
8
|
// installRecommendedSkills as an opt-in utility.
|
|
9
9
|
export const WORKFLOW_SKILLS = [
|
|
10
10
|
"brainstorming",
|
|
11
|
-
"incremental-impl",
|
|
12
11
|
"planning-with-files",
|
|
13
12
|
"playwright-cli",
|
|
14
|
-
"session-compound",
|
|
15
13
|
"systematic-debugging",
|
|
16
|
-
"test-designer",
|
|
17
14
|
"test-driven-development",
|
|
18
15
|
"verification-before-completion",
|
|
19
16
|
];
|
package/dist/utils.d.ts
CHANGED
package/dist/utils.js
CHANGED
|
@@ -152,6 +152,49 @@ const CONTENT_FILES = [
|
|
|
152
152
|
".agents/plugins/marketplace.json",
|
|
153
153
|
".agents/plugins/install.json",
|
|
154
154
|
".claude/hooks/hooks.json",
|
|
155
|
+
"plugins/auriga-go/.claude-plugin/plugin.json",
|
|
156
|
+
"plugins/auriga-go/.codex-plugin/plugin.json",
|
|
157
|
+
"plugins/auriga-go/README.md",
|
|
158
|
+
"plugins/auriga-go/skills/auriga-go/SKILL.md",
|
|
159
|
+
"plugins/auriga-go/skills/goalify/SKILL.md",
|
|
160
|
+
"plugins/auriga-git-guards/.claude-plugin/plugin.json",
|
|
161
|
+
"plugins/auriga-git-guards/.codex-plugin/plugin.json",
|
|
162
|
+
"plugins/auriga-git-guards/README.md",
|
|
163
|
+
"plugins/auriga-git-guards/hooks/hooks.json",
|
|
164
|
+
"plugins/auriga-git-guards/scripts/commit-reminder.mjs",
|
|
165
|
+
"plugins/auriga-git-guards/scripts/pr-create-guard.mjs",
|
|
166
|
+
"plugins/auriga-git-guards/scripts/pr-ready-guard.mjs",
|
|
167
|
+
"plugins/auriga-git-guards/skills/git-workflow/SKILL.md",
|
|
168
|
+
"plugins/auriga-workflow-skills/.claude-plugin/plugin.json",
|
|
169
|
+
"plugins/auriga-workflow-skills/.codex-plugin/plugin.json",
|
|
170
|
+
"plugins/auriga-workflow-skills/README.md",
|
|
171
|
+
"plugins/auriga-workflow-skills/skills/incremental-impl/SKILL.md",
|
|
172
|
+
"plugins/auriga-workflow-skills/skills/session-compound/SKILL.md",
|
|
173
|
+
"plugins/auriga-workflow-skills/skills/session-compound/analyzers/claude-code.mjs",
|
|
174
|
+
"plugins/auriga-workflow-skills/skills/session-compound/analyzers/codex.mjs",
|
|
175
|
+
"plugins/auriga-workflow-skills/skills/session-compound/template.html",
|
|
176
|
+
"plugins/auriga-workflow-skills/skills/test-designer/SKILL.md",
|
|
177
|
+
"plugins/session-instructions-loader/.codex-plugin/plugin.json",
|
|
178
|
+
"plugins/session-instructions-loader/README.md",
|
|
179
|
+
"plugins/session-instructions-loader/hooks/hooks.json",
|
|
180
|
+
"plugins/session-instructions-loader/scripts/session-start.mjs",
|
|
181
|
+
"plugins/deep-review/.claude-plugin/plugin.json",
|
|
182
|
+
"plugins/deep-review/.codex-plugin/plugin.json",
|
|
183
|
+
"plugins/deep-review/README.md",
|
|
184
|
+
"plugins/deep-review/skills/deep-review/SKILL.md",
|
|
185
|
+
"plugins/deep-review/skills/deep-review/references/reviewers/code-quality.md",
|
|
186
|
+
"plugins/deep-review/skills/deep-review/references/reviewers/correctness.md",
|
|
187
|
+
"plugins/deep-review/skills/deep-review/references/reviewers/docs-sync.md",
|
|
188
|
+
"plugins/deep-review/skills/deep-review/references/reviewers/performance.md",
|
|
189
|
+
"plugins/deep-review/skills/deep-review/references/reviewers/robustness.md",
|
|
190
|
+
"plugins/deep-review/skills/deep-review/references/reviewers/security.md",
|
|
191
|
+
"plugins/deep-review/skills/deep-review/references/reviewers/skill-plugin-quality.md",
|
|
192
|
+
"plugins/deep-review/skills/deep-review/references/reviewers/spec-conformance.md",
|
|
193
|
+
"plugins/deep-review/skills/deep-review/references/reviewers/structure.md",
|
|
194
|
+
"plugins/deep-review/skills/deep-review/references/reviewers/test-quality.md",
|
|
195
|
+
"plugins/deep-review/skills/deep-review/references/reviewers/ux.md",
|
|
196
|
+
"plugins/deep-review/skills/reviewer-creator/SKILL.md",
|
|
197
|
+
"plugins/deep-review/skills/reviewer-creator/references/template.md",
|
|
155
198
|
];
|
|
156
199
|
async function fetchFile(file) {
|
|
157
200
|
const ref = resolveContentRef();
|
package/package.json
CHANGED