@jazpiper/rules-doctor 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/README.md +141 -39
- package/dist/adapters/claude.js +31 -0
- package/dist/adapters/codex.js +14 -0
- package/dist/adapters/common.js +54 -0
- package/dist/adapters/copilot.js +15 -0
- package/dist/adapters/cursor.js +19 -0
- package/dist/adapters/gemini.js +12 -0
- package/dist/adapters/index.js +14 -0
- package/dist/adapters/opencode.js +14 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1146 -242
- package/package.json +13 -5
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## 0.3.0 - 2026-02-25
|
|
6
|
+
|
|
7
|
+
- Added `copilot` adapter support for `.github/copilot-instructions.md`.
|
|
8
|
+
- Switched Copilot output to marker-managed mode to preserve user-authored content.
|
|
9
|
+
- Added target presets for `init` (`all`, `core`, `copilot`).
|
|
10
|
+
- Added `preset apply` command for applying presets to existing `.agentrules/rules.yaml`.
|
|
11
|
+
- Added CI workflow template for drift detection via `rules-doctor check`.
|
|
12
|
+
- Expanded tests for shared `AGENTS.md`, Copilot marker re-sync, and `--import` + preset behavior.
|
|
13
|
+
- Improved README with troubleshooting and CI examples.
|
|
14
|
+
|
|
15
|
+
## 0.2.0 - 2026-02-25
|
|
16
|
+
|
|
17
|
+
- Added multi-target adapters for `claude`, `codex`, `cursor`, `gemini`, and `opencode`.
|
|
18
|
+
- Added `init --import`, dry-run default for `sync`, drift `check`, and structural `doctor`.
|
package/README.md
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
# @jazpiper/rules-doctor
|
|
2
2
|
|
|
3
|
-
`rules-doctor`
|
|
3
|
+
`rules-doctor` keeps coding-rule files in sync across multiple agent CLIs from one source of truth: `.agentrules/rules.yaml`.
|
|
4
|
+
|
|
5
|
+
It is optimized for real project adoption:
|
|
6
|
+
- import existing docs (`init --import`)
|
|
7
|
+
- target presets (`init --preset all|core|copilot`)
|
|
8
|
+
- safe previews by default (`sync` is dry-run unless `--write`)
|
|
9
|
+
- drift detection for CI (`check`)
|
|
10
|
+
|
|
11
|
+
All paths are resolved from project root (`.git` ancestor), not current subdirectory.
|
|
4
12
|
|
|
5
13
|
## Install
|
|
6
14
|
|
|
@@ -8,75 +16,169 @@
|
|
|
8
16
|
npm install -D @jazpiper/rules-doctor
|
|
9
17
|
```
|
|
10
18
|
|
|
11
|
-
|
|
19
|
+
Run with:
|
|
12
20
|
|
|
13
21
|
```bash
|
|
14
|
-
npx
|
|
22
|
+
npx rules-doctor --help
|
|
15
23
|
```
|
|
16
24
|
|
|
17
|
-
##
|
|
25
|
+
## Quick Start
|
|
18
26
|
|
|
19
|
-
### 1) Initialize
|
|
27
|
+
### 1) Initialize (recommended with import)
|
|
20
28
|
|
|
21
29
|
```bash
|
|
22
|
-
rules-doctor init
|
|
30
|
+
npx rules-doctor init --import
|
|
23
31
|
```
|
|
24
32
|
|
|
25
|
-
Creates `.agentrules/rules.yaml`
|
|
33
|
+
- Creates `.agentrules/rules.yaml`
|
|
34
|
+
- Reads existing docs when found (`CLAUDE.md`, `AGENTS.md`, `GEMINI.md`, `.cursor/rules/*.mdc`, `.github/copilot-instructions.md`)
|
|
35
|
+
- Writes `.agentrules/import-report.md`
|
|
36
|
+
|
|
37
|
+
Preset example (Copilot only):
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx rules-doctor init --preset copilot
|
|
41
|
+
```
|
|
26
42
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
- Missing scripts are created as TODO placeholders.
|
|
43
|
+
Preset meanings:
|
|
44
|
+
- `all`: all built-in targets enabled
|
|
45
|
+
- `core`: `claude`, `codex`, `opencode`, `cursor`, `gemini`
|
|
46
|
+
- `copilot`: only `copilot` enabled
|
|
32
47
|
|
|
33
|
-
|
|
48
|
+
Apply preset to an existing `.agentrules/rules.yaml`:
|
|
34
49
|
|
|
35
50
|
```bash
|
|
36
|
-
rules-doctor
|
|
37
|
-
rules-doctor sync --target claude
|
|
38
|
-
rules-doctor sync --target codex
|
|
51
|
+
npx rules-doctor preset apply copilot --write
|
|
39
52
|
```
|
|
40
53
|
|
|
41
|
-
|
|
42
|
-
- `CLAUDE.md` (fully managed)
|
|
43
|
-
- `AGENTS.md` (only content inside markers is managed)
|
|
54
|
+
### 2) Preview changes safely
|
|
44
55
|
|
|
45
|
-
|
|
56
|
+
```bash
|
|
57
|
+
npx rules-doctor sync --diff
|
|
58
|
+
```
|
|
46
59
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
60
|
+
`sync` is dry-run by default. Nothing is written yet.
|
|
61
|
+
|
|
62
|
+
### 3) Apply changes
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npx rules-doctor sync --write
|
|
51
66
|
```
|
|
52
67
|
|
|
53
|
-
|
|
68
|
+
Optional backups:
|
|
54
69
|
|
|
55
|
-
|
|
70
|
+
```bash
|
|
71
|
+
npx rules-doctor sync --write --backup
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 4) Verify drift in CI/local
|
|
56
75
|
|
|
57
76
|
```bash
|
|
58
|
-
rules-doctor
|
|
77
|
+
npx rules-doctor check
|
|
59
78
|
```
|
|
60
79
|
|
|
61
|
-
|
|
62
|
-
- missing markers
|
|
63
|
-
- missing verify commands (`lint`/`test`/`build`)
|
|
64
|
-
- obvious contradictions (simple heuristics)
|
|
80
|
+
Returns non-zero when generated targets are out of sync.
|
|
65
81
|
|
|
66
|
-
##
|
|
82
|
+
## Supported Targets
|
|
67
83
|
|
|
68
84
|
```bash
|
|
69
|
-
|
|
70
|
-
npm run build
|
|
85
|
+
npx rules-doctor targets list
|
|
71
86
|
```
|
|
72
87
|
|
|
73
|
-
|
|
88
|
+
Built-in adapters:
|
|
89
|
+
- `claude` -> `CLAUDE.md` (full-managed)
|
|
90
|
+
- `codex` -> `AGENTS.md` (marker-managed)
|
|
91
|
+
- `copilot` -> `.github/copilot-instructions.md` (marker-managed, preserves existing text outside managed block)
|
|
92
|
+
- `opencode` -> `AGENTS.md` (marker-managed)
|
|
93
|
+
- `cursor` -> `.cursor/rules/rules-doctor.mdc` (full-managed)
|
|
94
|
+
- `gemini` -> `GEMINI.md` (full-managed)
|
|
74
95
|
|
|
75
|
-
|
|
96
|
+
## Command Reference
|
|
97
|
+
|
|
98
|
+
### `init`
|
|
76
99
|
|
|
100
|
+
```bash
|
|
101
|
+
npx rules-doctor init [--import]
|
|
102
|
+
npx rules-doctor init [--import] [--preset all|core|copilot]
|
|
103
|
+
```
|
|
77
104
|
|
|
78
|
-
|
|
105
|
+
### `preset apply`
|
|
79
106
|
|
|
80
|
-
|
|
107
|
+
```bash
|
|
108
|
+
npx rules-doctor preset apply <all|core|copilot> [--diff] [--write]
|
|
109
|
+
```
|
|
81
110
|
|
|
82
|
-
|
|
111
|
+
### `sync`
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
npx rules-doctor sync [--target all|claude,codex,...] [--diff] [--write] [--backup]
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### `check`
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
npx rules-doctor check [--target all|claude,codex,...] [--diff]
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### `analyze`
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
npx rules-doctor analyze [--strict]
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### `doctor`
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
npx rules-doctor doctor [--strict]
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## CI Template
|
|
136
|
+
|
|
137
|
+
Copy [docs/workflows/rules-doctor-check.yml](docs/workflows/rules-doctor-check.yml) to your repository as `.github/workflows/rules-doctor-check.yml`.
|
|
138
|
+
It runs `npx rules-doctor check` on push and pull requests.
|
|
139
|
+
|
|
140
|
+
Inline workflow example:
|
|
141
|
+
|
|
142
|
+
```yaml
|
|
143
|
+
name: Rules Doctor Check
|
|
144
|
+
|
|
145
|
+
on:
|
|
146
|
+
push:
|
|
147
|
+
pull_request:
|
|
148
|
+
|
|
149
|
+
jobs:
|
|
150
|
+
rules-doctor:
|
|
151
|
+
runs-on: ubuntu-latest
|
|
152
|
+
steps:
|
|
153
|
+
- uses: actions/checkout@v4
|
|
154
|
+
- uses: actions/setup-node@v4
|
|
155
|
+
with:
|
|
156
|
+
node-version: "20"
|
|
157
|
+
cache: npm
|
|
158
|
+
- run: npm ci
|
|
159
|
+
- run: npx rules-doctor check
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Troubleshooting
|
|
163
|
+
|
|
164
|
+
- `rules-doctor: command not found` after `npm install -D @jazpiper/rules-doctor`:
|
|
165
|
+
- Use `npx rules-doctor ...` (recommended for local dev dependency).
|
|
166
|
+
- Or add an npm script in your project: `"rules:check": "rules-doctor check"`, then run `npm run rules:check`.
|
|
167
|
+
- Global install (`npm i -g @jazpiper/rules-doctor`) works, but local + `npx` is safer for version consistency.
|
|
168
|
+
- `init` says `rules.yaml already exists`:
|
|
169
|
+
- Use `npx rules-doctor preset apply <preset> --write` to change target defaults on an existing project.
|
|
170
|
+
|
|
171
|
+
## Rules Schema (v2 Draft)
|
|
172
|
+
|
|
173
|
+
See [docs/rules-v2-draft.yaml](docs/rules-v2-draft.yaml).
|
|
174
|
+
|
|
175
|
+
## Development
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
npm ci
|
|
179
|
+
npm test
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## License
|
|
183
|
+
|
|
184
|
+
MIT
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const { formatCommands, formatList } = require("./common");
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
id: "claude",
|
|
5
|
+
name: "Claude Code",
|
|
6
|
+
description: "Generate CLAUDE.md from rules.yaml.",
|
|
7
|
+
defaultPath: "CLAUDE.md",
|
|
8
|
+
management: "full",
|
|
9
|
+
render(rules) {
|
|
10
|
+
return [
|
|
11
|
+
"# CLAUDE.md",
|
|
12
|
+
"",
|
|
13
|
+
"## Mission",
|
|
14
|
+
rules.mission,
|
|
15
|
+
"",
|
|
16
|
+
"## Workflow",
|
|
17
|
+
formatList(rules.workflow),
|
|
18
|
+
"",
|
|
19
|
+
"## Commands",
|
|
20
|
+
formatCommands(rules.commands),
|
|
21
|
+
"",
|
|
22
|
+
"## Done",
|
|
23
|
+
formatList(rules.done),
|
|
24
|
+
"",
|
|
25
|
+
"## Approvals",
|
|
26
|
+
`- Mode: \`${rules.approvals.mode}\``,
|
|
27
|
+
...rules.approvals.notes.map((note) => `- ${note}`),
|
|
28
|
+
"",
|
|
29
|
+
].join("\n");
|
|
30
|
+
},
|
|
31
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const { renderManagedRulesBody } = require("./common");
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
id: "codex",
|
|
5
|
+
name: "Codex CLI",
|
|
6
|
+
description: "Manage AGENTS.md via marker-managed section.",
|
|
7
|
+
defaultPath: "AGENTS.md",
|
|
8
|
+
management: "marker",
|
|
9
|
+
markerBegin: "<!-- RULES_DOCTOR:BEGIN -->",
|
|
10
|
+
markerEnd: "<!-- RULES_DOCTOR:END -->",
|
|
11
|
+
render(rules) {
|
|
12
|
+
return renderManagedRulesBody(rules);
|
|
13
|
+
},
|
|
14
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
function formatList(items) {
|
|
2
|
+
if (!Array.isArray(items) || items.length === 0) {
|
|
3
|
+
return "- (none)";
|
|
4
|
+
}
|
|
5
|
+
return items.map((item) => `- ${item}`).join("\n");
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function formatCommands(commands) {
|
|
9
|
+
if (!commands || typeof commands !== "object") {
|
|
10
|
+
return "- (none)";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const preferredOrder = ["lint", "test", "build"];
|
|
14
|
+
const names = [
|
|
15
|
+
...preferredOrder.filter((name) => Object.prototype.hasOwnProperty.call(commands, name)),
|
|
16
|
+
...Object.keys(commands).filter((name) => !preferredOrder.includes(name)),
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
if (names.length === 0) {
|
|
20
|
+
return "- (none)";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return names.map((name) => `- ${name}: \`${commands[name]}\``).join("\n");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function renderManagedRulesBody(rules) {
|
|
27
|
+
return [
|
|
28
|
+
"## rules-doctor Managed Rules",
|
|
29
|
+
"Generated from `.agentrules/rules.yaml`. Edit that file, then run `rules-doctor sync`.",
|
|
30
|
+
"",
|
|
31
|
+
"### Mission",
|
|
32
|
+
rules.mission,
|
|
33
|
+
"",
|
|
34
|
+
"### Workflow",
|
|
35
|
+
formatList(rules.workflow),
|
|
36
|
+
"",
|
|
37
|
+
"### Commands",
|
|
38
|
+
formatCommands(rules.commands),
|
|
39
|
+
"",
|
|
40
|
+
"### Done",
|
|
41
|
+
formatList(rules.done),
|
|
42
|
+
"",
|
|
43
|
+
"### Approvals",
|
|
44
|
+
`- Policy: \`${rules.approvals.mode}\``,
|
|
45
|
+
...rules.approvals.notes.map((note) => `- ${note}`),
|
|
46
|
+
"",
|
|
47
|
+
].join("\n");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = {
|
|
51
|
+
formatCommands,
|
|
52
|
+
formatList,
|
|
53
|
+
renderManagedRulesBody,
|
|
54
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const { renderManagedRulesBody } = require("./common");
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
id: "copilot",
|
|
5
|
+
name: "GitHub Copilot",
|
|
6
|
+
description:
|
|
7
|
+
"Manage .github/copilot-instructions.md via marker-managed section to preserve user content.",
|
|
8
|
+
defaultPath: ".github/copilot-instructions.md",
|
|
9
|
+
management: "marker",
|
|
10
|
+
markerBegin: "<!-- RULES_DOCTOR:COPILOT:BEGIN -->",
|
|
11
|
+
markerEnd: "<!-- RULES_DOCTOR:COPILOT:END -->",
|
|
12
|
+
render(rules) {
|
|
13
|
+
return ["# Copilot Instructions", "", renderManagedRulesBody(rules)].join("\n");
|
|
14
|
+
},
|
|
15
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const { renderManagedRulesBody } = require("./common");
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
id: "cursor",
|
|
5
|
+
name: "Cursor",
|
|
6
|
+
description: "Manage .cursor/rules/rules-doctor.mdc as an always-applied project rule.",
|
|
7
|
+
defaultPath: ".cursor/rules/rules-doctor.mdc",
|
|
8
|
+
management: "full",
|
|
9
|
+
render(rules) {
|
|
10
|
+
return [
|
|
11
|
+
"---",
|
|
12
|
+
"description: rules-doctor managed coding rules",
|
|
13
|
+
"alwaysApply: true",
|
|
14
|
+
"---",
|
|
15
|
+
"",
|
|
16
|
+
renderManagedRulesBody(rules),
|
|
17
|
+
].join("\n");
|
|
18
|
+
},
|
|
19
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const { renderManagedRulesBody } = require("./common");
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
id: "gemini",
|
|
5
|
+
name: "Gemini CLI",
|
|
6
|
+
description: "Generate GEMINI.md managed instruction file.",
|
|
7
|
+
defaultPath: "GEMINI.md",
|
|
8
|
+
management: "full",
|
|
9
|
+
render(rules) {
|
|
10
|
+
return ["# GEMINI.md", "", renderManagedRulesBody(rules)].join("\n");
|
|
11
|
+
},
|
|
12
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const claude = require("./claude");
|
|
2
|
+
const codex = require("./codex");
|
|
3
|
+
const copilot = require("./copilot");
|
|
4
|
+
const cursor = require("./cursor");
|
|
5
|
+
const gemini = require("./gemini");
|
|
6
|
+
const opencode = require("./opencode");
|
|
7
|
+
|
|
8
|
+
const ADAPTERS = [claude, codex, copilot, cursor, gemini, opencode];
|
|
9
|
+
const ADAPTERS_BY_ID = Object.fromEntries(ADAPTERS.map((adapter) => [adapter.id, adapter]));
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
ADAPTERS,
|
|
13
|
+
ADAPTERS_BY_ID,
|
|
14
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const { renderManagedRulesBody } = require("./common");
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
id: "opencode",
|
|
5
|
+
name: "OpenCode CLI",
|
|
6
|
+
description: "Manage AGENTS.md via marker-managed section (OpenCode rules).",
|
|
7
|
+
defaultPath: "AGENTS.md",
|
|
8
|
+
management: "marker",
|
|
9
|
+
markerBegin: "<!-- RULES_DOCTOR:BEGIN -->",
|
|
10
|
+
markerEnd: "<!-- RULES_DOCTOR:END -->",
|
|
11
|
+
render(rules) {
|
|
12
|
+
return renderManagedRulesBody(rules);
|
|
13
|
+
},
|
|
14
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|