refacil-sdd-ai 4.5.0 → 4.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,16 +2,16 @@
2
2
 
3
3
  **SDD-AI** (Specification-Driven Development with AI) packaged as a CLI.
4
4
 
5
- Installs **skills** and **sub-agents** for **Claude Code** and **Cursor** that guide the developer through a structured AI-assisted development workflow, using **`refacil-sdd/`** as the specification store, plus a **local bus** so agents across different repos can communicate with each other.
5
+ Installs **skills** and **sub-agents** for **Claude Code**, **Cursor**, and **OpenCode** that guide the developer through a structured AI-assisted development workflow, using **`refacil-sdd/`** as the specification store, plus a **local bus** so agents across different repos can communicate with each other.
6
6
 
7
7
  ---
8
8
 
9
9
  ## Requirements
10
10
 
11
11
  - **Node.js >= 20.0.0**
12
- - **Claude Code >= 2.1.89** (required by the `compact-bash` hook for silent rewrite via `updatedInput`) or **Cursor**
12
+ - One or more supported IDEs: **Claude Code >= 2.1.89**, **Cursor**, or **OpenCode**
13
13
 
14
- `refacil-sdd-ai init` checks the Claude Code version and warns if it is below 2.1.89. With an older version the rest of the methodology works, but `compact-bash` will have no effect.
14
+ `refacil-sdd-ai init` checks the Claude Code version and warns if it is below 2.1.89. With an older version the rest of the methodology works, but `compact-bash` will have no effect (Claude Code only — OpenCode and Cursor have their own hook delivery mechanisms).
15
15
 
16
16
  ---
17
17
 
@@ -25,10 +25,12 @@ npm install -g refacil-sdd-ai
25
25
 
26
26
  # 2. In the repo root
27
27
  refacil-sdd-ai init
28
- # Copies skills to .claude/ and .cursor/, creates CLAUDE.md + .cursorrules, configures hooks
29
- # Creates/updates .claudeignore and .cursorignore with base exclusions
28
+ # Interactive IDE selector (Claude Code / Cursor / OpenCode) pre-selects IDEs
29
+ # whose folder already exists. Use --all to install for all three without prompting.
30
+ # Copies skills and sub-agents to the selected IDEs, configures hooks,
31
+ # and creates/updates .claudeignore, .cursorignore and .opencodeignore.
30
32
 
31
- # 3. Restart your Claude Code or Cursor session
33
+ # 3. Restart your IDE session
32
34
  # (new skills are not detected until you restart)
33
35
 
34
36
  # 4. In the IDE
@@ -43,12 +45,12 @@ npm update -g refacil-sdd-ai
43
45
  refacil-sdd-ai update # in each repo where it is used
44
46
  ```
45
47
 
46
- In Claude Code / Cursor the `check-update` hook (every session) syncs skills and `compact-guidance`. Only if the automatic detection (`lib/methodology-migration-pending.js`) finds a pending methodology migration does it write the flag and allow `notify-update` to prompt `/refacil:update`. If there is no migration, the user is not interrupted. The `/refacil:update` skill uses `refacil-sdd-ai migration-pending` as the same criterion.
48
+ `update` detects which IDEs are installed by folder presence (`.claude/`, `.cursor/`, `.opencode/`) and only updates those — it never creates IDE directories that did not exist before. In Claude Code and Cursor the `check-update` hook (every session) syncs skills and `compact-guidance`. In OpenCode the equivalent runs via the `session.created` handler of the embedded plugin (`.opencode/plugins/refacil-hooks.js`). Only if the automatic detection (`lib/methodology-migration-pending.js`) finds a pending methodology migration does it write the flag and allow `notify-update` / `tui.prompt.append` to prompt `/refacil:update`. If there is no migration, the user is not interrupted. The `/refacil:update` skill uses `refacil-sdd-ai migration-pending` as the same criterion.
47
49
 
48
50
  ### Uninstall
49
51
 
50
52
  ```bash
51
- refacil-sdd-ai clean # in the repo (removes skills + SDD-AI hooks)
53
+ refacil-sdd-ai clean # in the repo (removes skills + SDD-AI hooks for all IDEs)
52
54
  npm uninstall -g refacil-sdd-ai
53
55
  ```
54
56
 
@@ -133,7 +135,7 @@ Run **`refacil-sdd-ai help`** for the full list including `bus` and `compact` su
133
135
 
134
136
  ## Available IDE Skills
135
137
 
136
- All invoked as `/refacil:<name>` in Claude Code or Cursor.
138
+ All invoked as `/refacil:<name>` in Claude Code, Cursor, or OpenCode.
137
139
 
138
140
  ### SDD cycle
139
141
 
@@ -170,7 +172,7 @@ Some skills delegate their heavy work to **sub-agents** that run in isolated con
170
172
 
171
173
  **Model**: `refacil-proposer` runs with `model: opusplan` (uses Opus during plan mode for highest-stakes planning, then switches to Sonnet for execution). Other sub-agents use `model: sonnet` by default.
172
174
 
173
- **Dual-platform**: `.claude/agents/refacil-*.md` uses `tools:` (granular allowlist). `.cursor/agents/refacil-*.md` is auto-generated: `readonly: true` for agents without `Edit`/`Write`, `readonly: false` for those that have them; always `model: inherit`. The installer transforms the frontmatter automatically.
175
+ **Triple-platform**: `.claude/agents/refacil-*.md` uses `tools:` (granular allowlist). `.cursor/agents/refacil-*.md` is auto-generated: `readonly: true` for agents without `Edit`/`Write`, `readonly: false` for those that have them; always `model: inherit`. `.opencode/agents/refacil-*.md` is auto-generated via `transformFrontmatterForOpenCode()`: converts `tools:` to a `permission:` block (`edit: allow/deny`, `bash: allow/deny`, `webfetch: deny`), adds `mode: subagent`, adds `hidden: true` for internal agents, and removes `model:`. The installer transforms the frontmatter automatically for all three IDEs.
174
176
 
175
177
  **Two-pass `refacil:bug` flow**: the wrapper first invokes the sub-agent in `investigation` mode (writes nothing) → the user confirms the hypothesis and approves the fix → the wrapper validates the working branch → invokes the sub-agent in `fix` mode to implement.
176
178
 
@@ -259,16 +261,23 @@ From there, the full cycle is:
259
261
 
260
262
  ## Automatic Hooks
261
263
 
262
- Installed in `.claude/settings.json` **and** `.cursor/settings.json` during `init` / `update`. Apply to both **Claude Code** and **Cursor**.
264
+ Installed during `init` / `update` for each selected IDE. The same four behaviors are active in Claude Code, Cursor, and OpenCode — each through its own delivery mechanism.
263
265
 
264
- | Hook | Event | What it does |
265
- |---|---|---|
266
- | `check-update` | `SessionStart` | On startup deletes `.refacil-pending-update` if no migration is pending (stale flags). Then: npm check, sync skills, **compact-guidance**. If skills were synced **and** a migration is pending, writes the flag for `notify-update`. |
267
- | `notify-update` | `UserPromptSubmit` (Claude Code) / `beforeSubmitPrompt` (Cursor) | If the flag exists **and** a methodology migration is pending (same table as `/refacil:update`), injects the instruction or pauses the first message; if the sync happened without a migration, the flag is not created or is discarded silently. |
268
- | `compact-bash` | `PreToolUse` (Bash) | Silently rewrites bare Bash commands via `updatedInput`. No extra turns, the IDE does not see the change. Requires Claude Code >= 2.1.89. |
269
- | `check-review` | `PreToolUse` (Bash) | Intercepts `git push` and blocks if `.review-passed` is missing in any active change. |
266
+ | Behavior | Claude Code | Cursor | OpenCode |
267
+ |---|---|---|---|
268
+ | **check-update** | `SessionStart` hook in `.claude/settings.json` | `SessionStart` hook in `.cursor/settings.json` | `session.created` handler in `.opencode/plugins/refacil-hooks.js` |
269
+ | **notify-update** | `UserPromptSubmit` hook | `beforeSubmitPrompt` hook | `tui.prompt.append` handler |
270
+ | **compact-bash** | `PreToolUse` (Bash) hook | `PreToolUse` (Bash) hook | `tool.execute.before` handler for bash tool |
271
+ | **check-review** | `PreToolUse` (Bash) hook | `PreToolUse` (Bash) hook | `tool.execute.before` handler for bash tool |
272
+
273
+ | Behavior | What it does |
274
+ |---|---|
275
+ | `check-update` | On startup: deletes `.refacil-pending-update` if no migration is pending (stale flags). Then: npm check, sync skills, **compact-guidance**. If skills were synced **and** a migration is pending, writes the flag for `notify-update`. Always refreshes the flag content when a migration is pending (keeps the `to` version current). |
276
+ | `notify-update` | If the flag exists **and** a methodology migration is pending (same table as `/refacil:update`), injects the instruction before the agent processes the next user message; if the sync happened without a migration, the flag is not created or is discarded silently. |
277
+ | `compact-bash` | Silently rewrites bare Bash commands. No extra turns, the IDE does not see the change. Requires Claude Code >= 2.1.89 for the `updatedInput` path. |
278
+ | `check-review` | Intercepts `git push` and blocks if `.review-passed` is missing in any active change. |
270
279
 
271
- All four hooks are installed in `.claude/settings.json` (Claude Code) and `.cursor/settings.json` (Cursor) with the same parametric logic.
280
+ > **OpenCode plugin**: a single file (`.opencode/plugins/refacil-hooks.js`) implements all four behaviors. It loads `lib/compact/rules.js` from the package to reuse the same rewrite rules — no duplicated logic. If the rules file is not resolvable, compact-bash is disabled gracefully with a warning to stderr; the plugin never crashes the session.
272
281
 
273
282
  > **Why two hooks for updates?** `SessionStart` does the silent sync when opening the session without user interaction. `notify-update` on `UserPromptSubmit` / `beforeSubmitPrompt` injects the instruction just before the agent processes the next user message, ensuring it is not ignored.
274
283
 
@@ -406,18 +415,35 @@ Local bus (WebSocket over `127.0.0.1`) so agents across different repos can comm
406
415
 
407
416
  ## What Gets Installed in Your Repo
408
417
 
418
+ Only the IDEs selected during `init` (or detected during `update`) receive files. The three IDE targets are independent — selecting only `.opencode` does not create `.claude/` or `.cursor/` directories.
419
+
409
420
  ```
410
- .claude/skills/refacil-*/ # Claude Code skills (includes refacil-prereqs: METHODOLOGY-CONTRACT.md, BUS-CROSS-REPO.md, …)
421
+ # Claude Code (if selected)
422
+ .claude/skills/refacil-*/ # Skills (includes refacil-prereqs: METHODOLOGY-CONTRACT.md, BUS-CROSS-REPO.md, …)
411
423
  .claude/agents/refacil-*.md # Read-only sub-agents: auditor, investigator, validator
412
424
  # Write sub-agents: tester, implementer, debugger, proposer
413
- .claude/settings.json # Hooks: check-update + check-review + compact-bash
425
+ .claude/settings.json # Hooks: check-update + notify-update + check-review + compact-bash
426
+ .claude/.sdd-version # Installed methodology version (used by check-update)
427
+
428
+ # Cursor (if selected)
414
429
  .cursor/skills/refacil-*/ # Cursor skills (equivalent)
415
- .cursor/agents/refacil-*.md # Cursor sub-agents (readonly:true/false + model:inherit auto-generated)
416
- .cursor/settings.json # Hooks: check-update + check-review + compact-bash (mirror of .claude/)
430
+ .cursor/agents/refacil-*.md # Cursor sub-agents (readonly:true/false + model:inherit, auto-generated)
431
+ .cursor/settings.json # Hooks: check-update + notify-update + check-review + compact-bash
432
+ .cursor/.sdd-version # Installed methodology version
433
+
434
+ # OpenCode (if selected)
435
+ .opencode/skills/refacil-*/ # OpenCode skills (byte-for-byte copy — same spec as Claude Code)
436
+ .opencode/agents/refacil-*.md # OpenCode sub-agents (permission block + mode:subagent, auto-generated)
437
+ .opencode/plugins/refacil-hooks.js # Embedded plugin: session.created + tui.prompt.append + tool.execute.before
438
+ .opencode/opencode.json # Created/merged with $schema (user keys preserved)
439
+ .opencode/.sdd-version # Installed methodology version
440
+
441
+ # Shared (IDE-agnostic)
417
442
  CLAUDE.md # Minimal index → points to AGENTS.md
418
- .cursorrules # Same in Cursor format
443
+ .cursorrules # Cursor format equivalent of CLAUDE.md
419
444
  .claudeignore # Base exclusions (node_modules, dist, .env, *.key, etc.)
420
445
  .cursorignore # Same content as .claudeignore
446
+ .opencodeignore # Same content as .claudeignore
421
447
  AGENTS.md # Project index → generated by /refacil:setup
422
448
  # Points to .agents/ + includes auto-managed blocks
423
449
  # (compact-guidance and bus presentation)
@@ -436,6 +462,7 @@ refacil-sdd/ # SDD artifacts store
436
462
  - [AGENTS.md](https://agents.md/) — universal AI instructions standard
437
463
  - [Claude Code](https://claude.ai/code) — Anthropic CLI
438
464
  - [Cursor](https://cursor.sh) — AI IDE
465
+ - [OpenCode](https://opencode.ai) — open-source AI development agent
439
466
 
440
467
  ## License
441
468
 
package/bin/cli.js CHANGED
@@ -466,14 +466,16 @@ async function init() {
466
466
  }
467
467
 
468
468
  try {
469
- const ignoreResult = syncIgnoreFiles(projectRoot);
470
- const s = ignoreResult.claude;
471
- if (s.status === 'created') {
472
- console.log(' .claudeignore, .cursorignore and .opencodeignore created');
473
- } else if (s.status === 'updated') {
474
- console.log(` .claudeignore, .cursorignore and .opencodeignore updated (${s.added} entries added)`);
475
- } else {
476
- console.log(' .claudeignore, .cursorignore and .opencodeignore are up to date');
469
+ const IDE_TO_IGNORE = { '.claude': '.claudeignore', '.cursor': '.cursorignore', '.opencode': '.opencodeignore' };
470
+ const ignoreResult = syncIgnoreFiles(projectRoot, selectedIDEs);
471
+ const ignoreNames = selectedIDEs.map((d) => IDE_TO_IGNORE[d]).filter(Boolean).join(', ');
472
+ const s = ignoreResult.claude || ignoreResult.cursor || ignoreResult.opencode;
473
+ if (s && s.status === 'created') {
474
+ console.log(` ${ignoreNames} created`);
475
+ } else if (s && s.status === 'updated') {
476
+ console.log(` ${ignoreNames} updated (${s.added} entries added)`);
477
+ } else if (ignoreNames) {
478
+ console.log(` ${ignoreNames} are up to date`);
477
479
  }
478
480
  } catch (err) {
479
481
  console.error(` Warning: could not sync ignore files: ${err.message}`);
@@ -562,14 +564,16 @@ function update() {
562
564
  }
563
565
 
564
566
  try {
565
- const ignoreResult = syncIgnoreFiles(projectRoot);
566
- const s = ignoreResult.claude;
567
- if (s.status === 'created') {
568
- console.log(' .claudeignore, .cursorignore and .opencodeignore created');
569
- } else if (s.status === 'updated') {
570
- console.log(` .claudeignore, .cursorignore and .opencodeignore updated (${s.added} entries added)`);
571
- } else {
572
- console.log(' .claudeignore, .cursorignore and .opencodeignore are up to date');
567
+ const IDE_TO_IGNORE = { '.claude': '.claudeignore', '.cursor': '.cursorignore', '.opencode': '.opencodeignore' };
568
+ const ignoreResult = syncIgnoreFiles(projectRoot, detectedIDEs);
569
+ const ignoreNames = detectedIDEs.map((d) => IDE_TO_IGNORE[d]).filter(Boolean).join(', ');
570
+ const s = ignoreResult.claude || ignoreResult.cursor || ignoreResult.opencode;
571
+ if (s && s.status === 'created') {
572
+ console.log(` ${ignoreNames} created`);
573
+ } else if (s && s.status === 'updated') {
574
+ console.log(` ${ignoreNames} updated (${s.added} entries added)`);
575
+ } else if (ignoreNames) {
576
+ console.log(` ${ignoreNames} are up to date`);
573
577
  }
574
578
  } catch (err) {
575
579
  console.error(` Warning: could not sync ignore files: ${err.message}`);
@@ -79,11 +79,19 @@ function syncIgnoreFile(filePath) {
79
79
  return { status: 'updated', added: missing.length };
80
80
  }
81
81
 
82
- function syncIgnoreFiles(projectRoot) {
83
- const claude = syncIgnoreFile(path.join(projectRoot, '.claudeignore'));
84
- const cursor = syncIgnoreFile(path.join(projectRoot, '.cursorignore'));
85
- const opencode = syncIgnoreFile(path.join(projectRoot, '.opencodeignore'));
86
- return { claude, cursor, opencode };
82
+ function syncIgnoreFiles(projectRoot, ideDirs) {
83
+ const dirs = ideDirs || ['.claude', '.cursor', '.opencode'];
84
+ const result = {};
85
+ if (dirs.includes('.claude')) {
86
+ result.claude = syncIgnoreFile(path.join(projectRoot, '.claudeignore'));
87
+ }
88
+ if (dirs.includes('.cursor')) {
89
+ result.cursor = syncIgnoreFile(path.join(projectRoot, '.cursorignore'));
90
+ }
91
+ if (dirs.includes('.opencode')) {
92
+ result.opencode = syncIgnoreFile(path.join(projectRoot, '.opencodeignore'));
93
+ }
94
+ return result;
87
95
  }
88
96
 
89
97
  module.exports = { syncIgnoreFiles, BASE_ENTRIES };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "refacil-sdd-ai",
3
- "version": "4.5.0",
3
+ "version": "4.5.1",
4
4
  "description": "SDD-AI: Specification-Driven Development with AI — development methodology using AI with Claude Code, Cursor and OpenCode",
5
5
  "bin": {
6
6
  "refacil-sdd-ai": "./bin/cli.js"