r2pde-ai 0.1.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 +25 -0
- package/LICENSE +21 -0
- package/README.md +373 -0
- package/dist/cli.js +97 -0
- package/dist/commands/config-lang.js +32 -0
- package/dist/commands/config-set.js +38 -0
- package/dist/commands/contract-create.js +101 -0
- package/dist/commands/contract-delete.js +45 -0
- package/dist/commands/doctor.js +112 -0
- package/dist/commands/init.js +190 -0
- package/dist/commands/logs.js +35 -0
- package/dist/commands/manifesto-create.js +93 -0
- package/dist/commands/manifesto-delete.js +45 -0
- package/dist/commands/requirement-create.js +100 -0
- package/dist/commands/requirement-delete.js +46 -0
- package/dist/commands/reset.js +33 -0
- package/dist/commands/score-config.js +31 -0
- package/dist/commands/score.js +43 -0
- package/dist/commands/wave-prompt.js +130 -0
- package/dist/core/ai/adapter-factory.js +9 -0
- package/dist/core/ai/ai-adapter.js +1 -0
- package/dist/core/ai/api-adapter.js +38 -0
- package/dist/core/ai/mock-adapter.js +28 -0
- package/dist/core/config.js +61 -0
- package/dist/core/git.js +20 -0
- package/dist/core/logger.js +22 -0
- package/dist/core/paths.js +17 -0
- package/dist/core/scorer.js +135 -0
- package/dist/index.js +1 -0
- package/dist/templates/contract.template.md +14 -0
- package/dist/templates/manifesto.template.md +15 -0
- package/dist/templates/requirement.template.md +17 -0
- package/package.json +50 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
This project adheres to [Semantic Versioning](https://semver.org).
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
## [0.1.1] - 2026-05-14
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- Refactored `wave:prompt` to clarify that the AI API only generates optimized prompts for Copilot, never code.
|
|
11
|
+
- Updated all documentation (README, GUIDE, doctor, CLI help) to explain the new prompt optimization flow and Copilot's role.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
- `init` command — interactive project initialization with full .r2pde-ai structure
|
|
15
|
+
- `doctor` command — environment health check
|
|
16
|
+
- `manifesto:create` / `manifesto:delete` — manifesto artifact management
|
|
17
|
+
- `contract:create` / `contract:delete` — contract artifact management
|
|
18
|
+
- `requirement:create` / `requirement:delete` — requirement artifact management
|
|
19
|
+
- `score` / `score:config` — quality score engine with traffic light system
|
|
20
|
+
- `wave:prompt` — consolidated AI copilot prompt generation per wave
|
|
21
|
+
- `config:set` / `config:lang` — configuration management
|
|
22
|
+
- `reset` — prompts folder cleanup
|
|
23
|
+
- `logs` / `logs --clear` — audit log management
|
|
24
|
+
- Automated tests with Vitest (14 tests, 100% pass)
|
|
25
|
+
- Enhanced --help with examples and documentation
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 r2pde-ai contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
# r2pde-ai
|
|
2
|
+
|
|
3
|
+
> **Pilot Driven Engineering** — A CLI framework that bridges the gap between architectural intent and AI-generated code.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/r2pde-ai)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://nodejs.org)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## What is r2pde-ai?
|
|
12
|
+
|
|
13
|
+
`r2pde-ai` is a CLI framework for solo developers working with AI copilots (GitHub Copilot, Claude, etc.) inside VS Code. It structures your project's architectural decisions — manifestos, contracts, and specifications — into versioned markdown artifacts that guide the AI with precision, reducing ambiguity, token waste, and code drift.
|
|
14
|
+
|
|
15
|
+
The result: less programming, more engineering. Less guessing, more intent.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## How it works
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
Developer defines → CLI structures → AI receives context → AI delivers code
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
1. Install the package globally
|
|
26
|
+
2. Run `r2pde-ai init` inside your project folder
|
|
27
|
+
3. Use CLI commands to generate manifestos, contracts, and specifications
|
|
28
|
+
4. Use the generated prompts with your AI copilot
|
|
29
|
+
5. Everything is versioned, logged, and git-tracked
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install -g r2pde-ai
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Requirements**
|
|
40
|
+
- Node.js >= 20.0.0 (LTS)
|
|
41
|
+
- npm >= 10
|
|
42
|
+
- Git initialized in your project
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Quick Start
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Create and navigate to your project folder
|
|
50
|
+
mkdir my-project && cd my-project
|
|
51
|
+
|
|
52
|
+
# Initialize git
|
|
53
|
+
git init
|
|
54
|
+
|
|
55
|
+
# Initialize r2pde-ai
|
|
56
|
+
r2pde-ai init
|
|
57
|
+
|
|
58
|
+
# Check environment health
|
|
59
|
+
r2pde-ai doctor
|
|
60
|
+
|
|
61
|
+
# Read the user guide to understand artifacts
|
|
62
|
+
# See .r2pde-ai/GUIDE.md
|
|
63
|
+
|
|
64
|
+
# Create your first manifesto
|
|
65
|
+
r2pde-ai manifesto:create
|
|
66
|
+
|
|
67
|
+
# Evaluate quality score
|
|
68
|
+
r2pde-ai score
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Project Structure
|
|
74
|
+
|
|
75
|
+
After `init`, the following structure is created inside your project:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
.r2pde-ai/
|
|
79
|
+
├── pde.index.md # Master index — always paste this into your AI copilot first
|
|
80
|
+
├── pde.config.json # Central configuration file
|
|
81
|
+
├── GUIDE.md # Human-readable guide — artifact types, structure, examples
|
|
82
|
+
├── templates/
|
|
83
|
+
│ ├── manifesto.template.md # Template used by CLI when generating manifestos
|
|
84
|
+
│ ├── contract.template.md # Template used by CLI when generating contracts
|
|
85
|
+
│ └── requirement.template.md # Template used by CLI when generating requirements
|
|
86
|
+
├── manifestos/ # Guiding principles (UI, UX, code philosophy)
|
|
87
|
+
├── contracts/ # Rigid rules (architecture, TDD, DDD, security, routes)
|
|
88
|
+
├── requirements/ # Application specification (goals, flows, domains)
|
|
89
|
+
├── waves/ # Implementation waves and progress tracking
|
|
90
|
+
├── prompts/ # Generated prompts for AI copilot (manually deletable)
|
|
91
|
+
└── logs/ # Audit log of all CLI commands executed
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### About Templates
|
|
95
|
+
|
|
96
|
+
Templates live in `.r2pde-ai/templates/` and serve two purposes:
|
|
97
|
+
|
|
98
|
+
- **For the CLI** — used as the base structure when generating new artifacts via commands
|
|
99
|
+
- **For the developer** — reference models showing what each artifact should contain and how it should be structured
|
|
100
|
+
|
|
101
|
+
Templates can be customized. Once edited, the CLI will use your version as the base for all future artifact generation in that project — making every artifact consistent with your project's specific style and conventions.
|
|
102
|
+
|
|
103
|
+
### About GUIDE.md
|
|
104
|
+
|
|
105
|
+
`GUIDE.md` is generated by `init` and serves as the human-readable reference for the framework. It explains each artifact type, its purpose, its structure, and includes annotated examples. Consult it whenever you need to understand what to put in a manifesto, contract, or requirement.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Core Concepts
|
|
110
|
+
|
|
111
|
+
### Manifestos
|
|
112
|
+
Flexible guiding principles covering UI, UX, code philosophy, and development culture.
|
|
113
|
+
|
|
114
|
+
### Contracts
|
|
115
|
+
Rigid, non-negotiable rules covering architecture, TDD, DDD, security, permissions, routing, tests, and commit conventions.
|
|
116
|
+
|
|
117
|
+
### Requirements
|
|
118
|
+
Full application specification: objectives, functional and non-functional requirements, business rules, use cases, flows, domains, and acceptance criteria.
|
|
119
|
+
|
|
120
|
+
### Waves
|
|
121
|
+
Incremental implementation phases:
|
|
122
|
+
1. Framework → 2. Architecture → 3. Conceptual environment → 4. Core (errors, logs, security) → 5. Authentication → 6. Users → 7. UI/UX → 8. Tests → 9. Documentation
|
|
123
|
+
|
|
124
|
+
### Quality Score
|
|
125
|
+
Before generating any prompt, the CLI evaluates all artifacts from the current wave forward and returns a traffic-light score:
|
|
126
|
+
- 🟢 **Green** — consistent, proceed
|
|
127
|
+
- 🟡 **Yellow** — gaps or ambiguities detected, proceed with awareness
|
|
128
|
+
- 🔴 **Red** — critical conflicts or broken dependencies, strongly advised to resolve first
|
|
129
|
+
|
|
130
|
+
The score is contextual — it evaluates from the current wave forward, not the entire project. Thresholds are configurable.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## CLI Commands
|
|
135
|
+
|
|
136
|
+
| Command | Description |
|
|
137
|
+
|---|---|
|
|
138
|
+
| `r2pde-ai init` | Initialize framework in current directory |
|
|
139
|
+
| `r2pde-ai doctor` | Check environment health |
|
|
140
|
+
| `r2pde-ai manifesto:create` | Create a new manifesto |
|
|
141
|
+
| `r2pde-ai manifesto:delete` | Delete a manifesto |
|
|
142
|
+
| `r2pde-ai contract:create` | Create a new contract |
|
|
143
|
+
| `r2pde-ai contract:delete` | Delete a contract |
|
|
144
|
+
| `r2pde-ai requirement:create` | Create a new requirement |
|
|
145
|
+
| `r2pde-ai requirement:delete` | Delete a requirement |
|
|
146
|
+
| `r2pde-ai score` | Evaluate quality score from current context |
|
|
147
|
+
| `r2pde-ai score:config` | Configure score thresholds |
|
|
148
|
+
| `r2pde-ai wave:prompt` | Generate consolidated prompt for current wave |
|
|
149
|
+
| `r2pde-ai config:set` | Update configuration values |
|
|
150
|
+
| `r2pde-ai config:lang` | Set language for messages and artifacts |
|
|
151
|
+
| `r2pde-ai reset` | Reset prompts folder (with confirmation) |
|
|
152
|
+
| `r2pde-ai logs` | View audit log |
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Configuration
|
|
157
|
+
|
|
158
|
+
The `pde.config.json` file controls all framework behavior. Every setting has a sensible default and can be changed via commands.
|
|
159
|
+
|
|
160
|
+
```json
|
|
161
|
+
{
|
|
162
|
+
"version": "1.0.0",
|
|
163
|
+
"language": "en",
|
|
164
|
+
"artifactsLanguage": "en",
|
|
165
|
+
"git": {
|
|
166
|
+
"autoCommit": false,
|
|
167
|
+
"commitMessagePrefix": "pde:"
|
|
168
|
+
},
|
|
169
|
+
"score": {
|
|
170
|
+
"green": { "max": 30 },
|
|
171
|
+
"yellow": { "max": 70 },
|
|
172
|
+
"red": { "max": 100 }
|
|
173
|
+
},
|
|
174
|
+
"ai": {
|
|
175
|
+
"apiUrl": "",
|
|
176
|
+
"apiKey": "",
|
|
177
|
+
"model": ""
|
|
178
|
+
},
|
|
179
|
+
"project": {
|
|
180
|
+
"type": "",
|
|
181
|
+
"architecture": "",
|
|
182
|
+
"maturity": "",
|
|
183
|
+
"hasAuth": false,
|
|
184
|
+
"hasPayment": false,
|
|
185
|
+
"hasIntegrations": false,
|
|
186
|
+
"audience": "",
|
|
187
|
+
"stack": ""
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Core Design Principle
|
|
193
|
+
|
|
194
|
+
> *Every behavior has a default. Every default is configurable. Every configuration has a command.*
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
## AI API Integration (Advanced Mode)
|
|
200
|
+
|
|
201
|
+
r2pde-ai works in two modes:
|
|
202
|
+
|
|
203
|
+
**Offline mode (default)** — The CLI generates structured prompts that you copy and paste into GitHub Copilot. No external AI required.
|
|
204
|
+
|
|
205
|
+
**API mode** — When an external AI API is configured, the CLI sends your project context to the AI, which generates an optimized, more precise prompt for GitHub Copilot. You still copy and paste into Copilot — but the prompt is significantly better.
|
|
206
|
+
|
|
207
|
+
**Important:** The AI API never generates code directly. It generates better prompts for Copilot. Copilot is always responsible for generating the code.
|
|
208
|
+
|
|
209
|
+
To enable API mode:
|
|
210
|
+
```bash
|
|
211
|
+
r2pde-ai config:set ai.apiUrl https://api.anthropic.com
|
|
212
|
+
r2pde-ai config:set ai.apiKey your-api-key
|
|
213
|
+
r2pde-ai config:set ai.model claude-sonnet-4-20250514
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Supported: any API following the Anthropic messages format. OpenAI-compatible APIs may require adapter configuration in future versions.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Git Integration
|
|
221
|
+
|
|
222
|
+
`r2pde-ai` is designed to live inside a git repository. Every artifact is a markdown file — versionable, diffable, and auditable.
|
|
223
|
+
|
|
224
|
+
Auto-commit (optional):
|
|
225
|
+
```bash
|
|
226
|
+
r2pde-ai config:set git.autoCommit true
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
When enabled, every CLI command that creates or modifies an artifact automatically stages and commits the change with a standardized message.
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Internationalization
|
|
234
|
+
|
|
235
|
+
Default language is English for both CLI messages and artifact structure. To change:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
r2pde-ai config:lang --messages pt
|
|
239
|
+
r2pde-ai config:lang --artifacts pt
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Contributing
|
|
245
|
+
|
|
246
|
+
We welcome contributions of all kinds — bug reports, feature requests, documentation improvements, and code.
|
|
247
|
+
|
|
248
|
+
### Before You Start
|
|
249
|
+
|
|
250
|
+
1. Read this README fully
|
|
251
|
+
2. Check [open issues](../../issues) — your idea may already be in progress
|
|
252
|
+
3. For significant changes, open an issue first to discuss the approach
|
|
253
|
+
4. Keep changes focused — one concern per pull request
|
|
254
|
+
|
|
255
|
+
### Development Setup
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
# Fork and clone the repository
|
|
259
|
+
git clone https://github.com/your-username/r2pde-ai.git
|
|
260
|
+
cd r2pde-ai
|
|
261
|
+
|
|
262
|
+
# Install dependencies
|
|
263
|
+
npm install
|
|
264
|
+
|
|
265
|
+
# Build
|
|
266
|
+
npm run build
|
|
267
|
+
|
|
268
|
+
# Link locally for testing
|
|
269
|
+
npm link
|
|
270
|
+
|
|
271
|
+
# Run tests
|
|
272
|
+
npm test
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Branching Convention
|
|
276
|
+
|
|
277
|
+
| Branch | Purpose |
|
|
278
|
+
|---|---|
|
|
279
|
+
| `main` | Stable, released code |
|
|
280
|
+
| `dev` | Active development |
|
|
281
|
+
| `feature/short-description` | New features |
|
|
282
|
+
| `fix/short-description` | Bug fixes |
|
|
283
|
+
| `docs/short-description` | Documentation only |
|
|
284
|
+
|
|
285
|
+
All pull requests target `dev`. Never submit directly to `main`.
|
|
286
|
+
|
|
287
|
+
### Commit Convention
|
|
288
|
+
|
|
289
|
+
We follow [Conventional Commits](https://www.conventionalcommits.org):
|
|
290
|
+
|
|
291
|
+
```
|
|
292
|
+
feat: add score:config command
|
|
293
|
+
fix: resolve wave detection on nested folders
|
|
294
|
+
docs: update contributing guide
|
|
295
|
+
chore: bump dependencies
|
|
296
|
+
refactor: simplify artifact loader
|
|
297
|
+
test: add score threshold validation
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Pull Request Process
|
|
301
|
+
|
|
302
|
+
1. Branch from `dev`
|
|
303
|
+
2. Write or update tests for your change
|
|
304
|
+
3. Ensure `npm test` passes with no failures
|
|
305
|
+
4. Update documentation if the change affects behavior or commands
|
|
306
|
+
5. Open a PR against `dev` with a clear title and description
|
|
307
|
+
6. Reference any related issue with `Closes #number`
|
|
308
|
+
7. Wait for review — we aim to respond within 72 hours
|
|
309
|
+
|
|
310
|
+
### Code Standards
|
|
311
|
+
|
|
312
|
+
- TypeScript strict mode — no `any`
|
|
313
|
+
- All public functions documented with JSDoc
|
|
314
|
+
- File names in `kebab-case`
|
|
315
|
+
- Classes and components in `PascalCase`
|
|
316
|
+
- Methods and properties in `camelCase`
|
|
317
|
+
- Constants in `UPPER_SNAKE_CASE`
|
|
318
|
+
- Custom errors in `PascalCase` + `Error` suffix
|
|
319
|
+
|
|
320
|
+
### Reporting Bugs
|
|
321
|
+
|
|
322
|
+
Open an issue with:
|
|
323
|
+
- Node.js version (`node --version`)
|
|
324
|
+
- r2pde-ai version (`r2pde-ai --version`)
|
|
325
|
+
- Operating system
|
|
326
|
+
- Command that triggered the issue
|
|
327
|
+
- Expected vs actual behavior
|
|
328
|
+
- Minimal reproduction steps
|
|
329
|
+
|
|
330
|
+
### Requesting Features
|
|
331
|
+
|
|
332
|
+
Open an issue with:
|
|
333
|
+
- Problem you are trying to solve
|
|
334
|
+
- How you currently work around it
|
|
335
|
+
- Proposed solution or command
|
|
336
|
+
- Any alternative approaches considered
|
|
337
|
+
|
|
338
|
+
### Code of Conduct
|
|
339
|
+
|
|
340
|
+
Be direct, be respectful, be constructive. We value clarity over ceremony. Discussions should focus on ideas, not individuals. Maintainers reserve the right to close unconstructive threads.
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## Versioning
|
|
345
|
+
|
|
346
|
+
This project follows [Semantic Versioning](https://semver.org):
|
|
347
|
+
|
|
348
|
+
- `MAJOR` — breaking changes to CLI commands or artifact structure
|
|
349
|
+
- `MINOR` — new commands or backward-compatible features
|
|
350
|
+
- `PATCH` — bug fixes and internal improvements
|
|
351
|
+
|
|
352
|
+
Changelogs are maintained in [CHANGELOG.md](./CHANGELOG.md).
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## License
|
|
357
|
+
|
|
358
|
+
MIT © r2pde-ai contributors
|
|
359
|
+
|
|
360
|
+
See [LICENSE](./LICENSE) for full terms.
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
## Roadmap
|
|
365
|
+
|
|
366
|
+
- [ ] `init` interactive mode with project type and architecture selection
|
|
367
|
+
- [ ] Template customization per project
|
|
368
|
+
- [ ] API mode with full AI integration
|
|
369
|
+
- [ ] Quality score engine
|
|
370
|
+
- [ ] Wave prompt consolidation
|
|
371
|
+
- [ ] VS Code extension for inline command execution
|
|
372
|
+
- [ ] Multi-language artifact support
|
|
373
|
+
- [ ] Plugin system for custom contracts and manifestos
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { resetCommand } from './commands/reset.js';
|
|
2
|
+
import { logsCommand } from './commands/logs.js';
|
|
3
|
+
import { requirementCreateCommand } from './commands/requirement-create.js';
|
|
4
|
+
import { requirementDeleteCommand } from './commands/requirement-delete.js';
|
|
5
|
+
import { scoreCommand } from './commands/score.js';
|
|
6
|
+
import { scoreConfigCommand } from './commands/score-config.js';
|
|
7
|
+
import { wavePromptCommand } from './commands/wave-prompt.js';
|
|
8
|
+
import { configSetCommand } from './commands/config-set.js';
|
|
9
|
+
import { configLangCommand } from './commands/config-lang.js';
|
|
10
|
+
import { Command } from 'commander';
|
|
11
|
+
import { initCommand } from './commands/init.js';
|
|
12
|
+
import { doctorCommand } from './commands/doctor.js';
|
|
13
|
+
import { manifestoCreateCommand } from './commands/manifesto-create.js';
|
|
14
|
+
import { manifestoDeleteCommand } from './commands/manifesto-delete.js';
|
|
15
|
+
import { contractCreateCommand } from './commands/contract-create.js';
|
|
16
|
+
import { contractDeleteCommand } from './commands/contract-delete.js';
|
|
17
|
+
const program = new Command();
|
|
18
|
+
program.addHelpText('after', `
|
|
19
|
+
Examples:
|
|
20
|
+
$ r2pde-ai init
|
|
21
|
+
$ r2pde-ai doctor
|
|
22
|
+
$ r2pde-ai manifesto:create
|
|
23
|
+
$ r2pde-ai contract:create
|
|
24
|
+
$ r2pde-ai requirement:create
|
|
25
|
+
$ r2pde-ai score
|
|
26
|
+
$ r2pde-ai score --from contracts
|
|
27
|
+
$ r2pde-ai wave:prompt
|
|
28
|
+
$ r2pde-ai config:set git.autoCommit true
|
|
29
|
+
$ r2pde-ai config:lang
|
|
30
|
+
$ r2pde-ai logs
|
|
31
|
+
$ r2pde-ai logs --clear
|
|
32
|
+
$ r2pde-ai reset
|
|
33
|
+
|
|
34
|
+
Documentation:
|
|
35
|
+
After init, read .r2pde-ai/GUIDE.md for full artifact reference.
|
|
36
|
+
Always paste .r2pde-ai/pde.index.md into your AI copilot before any prompt.
|
|
37
|
+
`);
|
|
38
|
+
program.addCommand(resetCommand);
|
|
39
|
+
program.addCommand(logsCommand);
|
|
40
|
+
program
|
|
41
|
+
.command('requirement:create')
|
|
42
|
+
.description('Create a new requirement')
|
|
43
|
+
.action(() => {
|
|
44
|
+
void requirementCreateCommand();
|
|
45
|
+
});
|
|
46
|
+
program
|
|
47
|
+
.command('requirement:delete')
|
|
48
|
+
.description('Delete an existing requirement')
|
|
49
|
+
.action(() => {
|
|
50
|
+
void requirementDeleteCommand();
|
|
51
|
+
});
|
|
52
|
+
program
|
|
53
|
+
.command('contract:create')
|
|
54
|
+
.description('Create a new contract')
|
|
55
|
+
.action(() => {
|
|
56
|
+
void contractCreateCommand();
|
|
57
|
+
});
|
|
58
|
+
program
|
|
59
|
+
.command('contract:delete')
|
|
60
|
+
.description('Delete an existing contract')
|
|
61
|
+
.action(() => {
|
|
62
|
+
void contractDeleteCommand();
|
|
63
|
+
});
|
|
64
|
+
program
|
|
65
|
+
.command('manifesto:create')
|
|
66
|
+
.description('Create a new manifesto')
|
|
67
|
+
.action(() => {
|
|
68
|
+
void manifestoCreateCommand();
|
|
69
|
+
});
|
|
70
|
+
program
|
|
71
|
+
.command('manifesto:delete')
|
|
72
|
+
.description('Delete an existing manifesto')
|
|
73
|
+
.action(() => {
|
|
74
|
+
void manifestoDeleteCommand();
|
|
75
|
+
});
|
|
76
|
+
program.addCommand(scoreCommand);
|
|
77
|
+
program.addCommand(scoreConfigCommand);
|
|
78
|
+
program.addCommand(wavePromptCommand);
|
|
79
|
+
program.addCommand(configSetCommand);
|
|
80
|
+
program.addCommand(configLangCommand);
|
|
81
|
+
program
|
|
82
|
+
.name('r2pde-ai')
|
|
83
|
+
.description('Pilot Driven Engineering A CLI framework that bridges the gap between architectural intent and AI-generated code.')
|
|
84
|
+
.version('0.1.0');
|
|
85
|
+
program
|
|
86
|
+
.command('init')
|
|
87
|
+
.description('Initialize r2pde-ai in the current project')
|
|
88
|
+
.action(() => {
|
|
89
|
+
void initCommand();
|
|
90
|
+
});
|
|
91
|
+
program
|
|
92
|
+
.command('doctor')
|
|
93
|
+
.description('Check the health of the r2pde-ai environment')
|
|
94
|
+
.action(() => {
|
|
95
|
+
void doctorCommand();
|
|
96
|
+
});
|
|
97
|
+
program.parse();
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { select } from '@inquirer/prompts';
|
|
3
|
+
import { loadConfig, saveConfig } from '../core/config.js';
|
|
4
|
+
import { logInfo, logSuccess } from '../core/logger.js';
|
|
5
|
+
export const configLangCommand = new Command('config:lang')
|
|
6
|
+
.description('Set language for messages and artifacts')
|
|
7
|
+
.action(async () => {
|
|
8
|
+
const cwd = process.cwd();
|
|
9
|
+
const config = loadConfig(cwd);
|
|
10
|
+
logInfo('The language for all CLI output messages.');
|
|
11
|
+
const language = await select({
|
|
12
|
+
message: 'Language for CLI messages:',
|
|
13
|
+
choices: [
|
|
14
|
+
{ name: 'English', value: 'en' },
|
|
15
|
+
{ name: 'Português', value: 'pt' }
|
|
16
|
+
],
|
|
17
|
+
default: config.language || 'en',
|
|
18
|
+
});
|
|
19
|
+
logInfo('The language used when generating markdown artifact files.');
|
|
20
|
+
const artifactsLanguage = await select({
|
|
21
|
+
message: 'Language for artifacts:',
|
|
22
|
+
choices: [
|
|
23
|
+
{ name: 'English', value: 'en' },
|
|
24
|
+
{ name: 'Português', value: 'pt' }
|
|
25
|
+
],
|
|
26
|
+
default: config.artifactsLanguage || 'en',
|
|
27
|
+
});
|
|
28
|
+
config.language = language;
|
|
29
|
+
config.artifactsLanguage = artifactsLanguage;
|
|
30
|
+
saveConfig(cwd, config);
|
|
31
|
+
logSuccess('Language settings updated.');
|
|
32
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { loadConfig, saveConfig } from '../core/config.js';
|
|
3
|
+
import { logSuccess, logWarn } from '../core/logger.js';
|
|
4
|
+
function setByDot(obj, path, value) {
|
|
5
|
+
const keys = path.split('.');
|
|
6
|
+
let cur = obj;
|
|
7
|
+
for (let i = 0; i < keys.length - 1; ++i) {
|
|
8
|
+
if (!(keys[i] in cur))
|
|
9
|
+
return false;
|
|
10
|
+
cur = cur[keys[i]];
|
|
11
|
+
}
|
|
12
|
+
const last = keys[keys.length - 1];
|
|
13
|
+
if (!(last in cur))
|
|
14
|
+
return false;
|
|
15
|
+
cur[last] = value;
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
export const configSetCommand = new Command('config:set')
|
|
19
|
+
.description('Set a configuration value')
|
|
20
|
+
.argument('<key>', 'Config key (dot notation)')
|
|
21
|
+
.argument('<value>', 'Value to set')
|
|
22
|
+
.action((key, value) => {
|
|
23
|
+
const cwd = process.cwd();
|
|
24
|
+
const config = loadConfig(cwd);
|
|
25
|
+
let v = value;
|
|
26
|
+
if (value === 'true')
|
|
27
|
+
v = true;
|
|
28
|
+
else if (value === 'false')
|
|
29
|
+
v = false;
|
|
30
|
+
else if (!isNaN(Number(value)))
|
|
31
|
+
v = Number(value);
|
|
32
|
+
const ok = setByDot(config, key, v);
|
|
33
|
+
if (!ok) {
|
|
34
|
+
logWarn(`Key does not exist in config: ${key}`);
|
|
35
|
+
}
|
|
36
|
+
saveConfig(cwd, config);
|
|
37
|
+
logSuccess(`Config updated: ${key} = ${v}`);
|
|
38
|
+
});
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { input, select, confirm } from '@inquirer/prompts';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { getPaths } from '../core/paths.js';
|
|
5
|
+
import { logError, logWarn, logInfo, logSuccess } from '../core/logger.js';
|
|
6
|
+
import { gitAddAndCommit } from '../core/git.js';
|
|
7
|
+
import { loadConfig } from '../core/config.js';
|
|
8
|
+
function toKebabCase(str) {
|
|
9
|
+
return str
|
|
10
|
+
.normalize('NFD')
|
|
11
|
+
.replace(/[^\w\s-]/g, '')
|
|
12
|
+
.trim()
|
|
13
|
+
.toLowerCase()
|
|
14
|
+
.replace(/\s+/g, '-')
|
|
15
|
+
.replace(/-+/g, '-');
|
|
16
|
+
}
|
|
17
|
+
export async function contractCreateCommand() {
|
|
18
|
+
const cwd = process.cwd();
|
|
19
|
+
const paths = getPaths(cwd);
|
|
20
|
+
if (!fs.existsSync(paths.root)) {
|
|
21
|
+
logError('r2pde-ai not initialized. Run r2pde-ai init first.');
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
// Step 2 — Interactive prompts
|
|
25
|
+
logInfo('The name of this contract. Should reflect what rule it enforces (e.g. API Security, Commit Convention).');
|
|
26
|
+
const name = await input({ message: 'Contract name:', validate: (inputVal) => inputVal.trim() !== '' || 'Name is required' });
|
|
27
|
+
logInfo('The category this contract belongs to. Used for organization and score evaluation.');
|
|
28
|
+
const type = await select({ message: 'Type:', choices: [
|
|
29
|
+
{ name: 'Architecture', value: 'architecture' },
|
|
30
|
+
{ name: 'TDD', value: 'tdd' },
|
|
31
|
+
{ name: 'DDD', value: 'ddd' },
|
|
32
|
+
{ name: 'Security', value: 'security' },
|
|
33
|
+
{ name: 'Permissions', value: 'permissions' },
|
|
34
|
+
{ name: 'Routing', value: 'routing' },
|
|
35
|
+
{ name: 'Tests', value: 'tests' },
|
|
36
|
+
{ name: 'Commits', value: 'commits' },
|
|
37
|
+
{ name: 'Other', value: 'other' }
|
|
38
|
+
] });
|
|
39
|
+
logInfo('Mandatory contracts are evaluated strictly. Recommended contracts generate warnings only.');
|
|
40
|
+
const enforcement = await select({ message: 'Enforcement level:', choices: [
|
|
41
|
+
{ name: 'Mandatory', value: 'mandatory' },
|
|
42
|
+
{ name: 'Recommended', value: 'recommended' }
|
|
43
|
+
] });
|
|
44
|
+
logInfo('A brief summary of what this contract enforces and the consequences of violation.');
|
|
45
|
+
const description = await input({ message: 'Brief description:', validate: (inputVal) => inputVal.trim() !== '' || 'Description is required' });
|
|
46
|
+
const kebabName = toKebabCase(name);
|
|
47
|
+
const filename = `${kebabName}.md`;
|
|
48
|
+
const filePath = path.join(paths.contracts, filename);
|
|
49
|
+
// Step 3 — Check for duplicates
|
|
50
|
+
if (fs.existsSync(filePath)) {
|
|
51
|
+
logWarn('Contract already exists.');
|
|
52
|
+
logInfo('Select Yes to overwrite the existing contract file.');
|
|
53
|
+
const overwrite = await confirm({ message: 'Contract already exists. Overwrite?', default: false });
|
|
54
|
+
if (!overwrite) {
|
|
55
|
+
logInfo('Operation cancelled.');
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Step 4 — Generate contract file
|
|
60
|
+
const templatePath = path.join(paths.templates, 'contract.template.md');
|
|
61
|
+
if (!fs.existsSync(templatePath)) {
|
|
62
|
+
logError('Contract template not found.');
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
let template = fs.readFileSync(templatePath, { encoding: 'utf8' });
|
|
66
|
+
template = template.replace('[Name]', name);
|
|
67
|
+
const meta = `---\nname: ${name}\ntype: ${type}\nenforcement: ${enforcement}\ndescription: ${description}\ncreatedAt: ${new Date().toISOString()}\n---\n\n`;
|
|
68
|
+
const content = meta + template;
|
|
69
|
+
fs.writeFileSync(filePath, content, { encoding: 'utf8' });
|
|
70
|
+
// Step 5 — Update pde.index.md
|
|
71
|
+
if (fs.existsSync(paths.index)) {
|
|
72
|
+
let indexContent = fs.readFileSync(paths.index, { encoding: 'utf8' });
|
|
73
|
+
const contractsSection = '- Contracts: .r2pde-ai/contracts/';
|
|
74
|
+
const newLine = ` - ${name}: .r2pde-ai/contracts/${filename}`;
|
|
75
|
+
if (indexContent.includes(contractsSection)) {
|
|
76
|
+
const lines = indexContent.split('\n');
|
|
77
|
+
const idx = lines.findIndex(l => l.trim() === contractsSection);
|
|
78
|
+
if (idx !== -1) {
|
|
79
|
+
let insertAt = idx + 1;
|
|
80
|
+
while (insertAt < lines.length && (lines[insertAt].startsWith(' - ') || lines[insertAt].trim() === ''))
|
|
81
|
+
insertAt++;
|
|
82
|
+
lines.splice(insertAt, 0, newLine);
|
|
83
|
+
indexContent = lines.join('\n');
|
|
84
|
+
fs.writeFileSync(paths.index, indexContent, { encoding: 'utf8' });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
logWarn('pde.index.md not found. Skipping index update.');
|
|
90
|
+
}
|
|
91
|
+
// Step 6 — Log entry
|
|
92
|
+
const logPath = path.join(paths.logs, 'pde.log.md');
|
|
93
|
+
const logLine = `- ${new Date().toISOString()} | contract:create | ${filename} | created\n`;
|
|
94
|
+
fs.ensureFileSync(logPath);
|
|
95
|
+
fs.appendFileSync(logPath, logLine, { encoding: 'utf8' });
|
|
96
|
+
// Step 7 — Git commit if enabled
|
|
97
|
+
const config = loadConfig(cwd);
|
|
98
|
+
gitAddAndCommit(cwd, `feat(contract): add ${name}`, config);
|
|
99
|
+
// Step 8 — Final output
|
|
100
|
+
logSuccess(`Contract '${name}' created at .r2pde-ai/contracts/${filename}`);
|
|
101
|
+
}
|