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 +50 -23
- package/bin/cli.js +20 -16
- package/lib/ignore-files.js +13 -5
- package/package.json +1 -1
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 **
|
|
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**
|
|
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
|
-
#
|
|
29
|
-
#
|
|
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
|
|
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
|
|
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
|
|
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
|
-
**
|
|
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
|
|
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
|
-
|
|
|
265
|
-
|
|
266
|
-
|
|
|
267
|
-
|
|
|
268
|
-
|
|
|
269
|
-
|
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 #
|
|
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
|
|
470
|
-
const
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
console.log(`
|
|
475
|
-
} else {
|
|
476
|
-
console.log(
|
|
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
|
|
566
|
-
const
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
console.log(`
|
|
571
|
-
} else {
|
|
572
|
-
console.log(
|
|
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}`);
|
package/lib/ignore-files.js
CHANGED
|
@@ -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
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
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