@shahmarasy/prodo 0.1.4 → 0.1.5

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.
Files changed (173) hide show
  1. package/README.md +201 -97
  2. package/bin/prodo.cjs +6 -6
  3. package/dist/agents/agent-registry.d.ts +13 -0
  4. package/dist/agents/agent-registry.js +79 -0
  5. package/dist/agents/anthropic/index.d.ts +9 -0
  6. package/dist/agents/anthropic/index.js +55 -0
  7. package/dist/agents/base.d.ts +25 -0
  8. package/dist/agents/base.js +71 -0
  9. package/dist/agents/google/index.d.ts +9 -0
  10. package/dist/agents/google/index.js +53 -0
  11. package/dist/agents/mock/index.d.ts +11 -0
  12. package/dist/agents/mock/index.js +26 -0
  13. package/dist/agents/openai/index.d.ts +9 -0
  14. package/dist/agents/openai/index.js +57 -0
  15. package/dist/agents/system-prompts.d.ts +3 -0
  16. package/dist/agents/system-prompts.js +32 -0
  17. package/dist/cli/agent-command-installer.d.ts +4 -0
  18. package/dist/cli/agent-command-installer.js +148 -0
  19. package/dist/cli/agent-ids.d.ts +15 -0
  20. package/dist/cli/agent-ids.js +49 -0
  21. package/dist/cli/doctor.d.ts +1 -0
  22. package/dist/cli/doctor.js +144 -0
  23. package/dist/cli/fix-tui.d.ts +4 -0
  24. package/dist/cli/fix-tui.js +79 -0
  25. package/dist/cli/index.d.ts +9 -0
  26. package/dist/cli/index.js +465 -0
  27. package/dist/cli/init-tui.d.ts +23 -0
  28. package/dist/cli/init-tui.js +176 -0
  29. package/dist/cli/init.d.ts +11 -0
  30. package/dist/cli/init.js +334 -0
  31. package/dist/cli/normalize-interactive.d.ts +8 -0
  32. package/dist/cli/normalize-interactive.js +167 -0
  33. package/dist/cli/preset-loader.d.ts +4 -0
  34. package/dist/cli/preset-loader.js +210 -0
  35. package/dist/core/artifact-registry.d.ts +11 -0
  36. package/dist/core/artifact-registry.js +49 -0
  37. package/dist/core/artifacts.d.ts +10 -0
  38. package/dist/core/artifacts.js +892 -0
  39. package/dist/core/clean.d.ts +10 -0
  40. package/dist/core/clean.js +74 -0
  41. package/dist/core/consistency.d.ts +8 -0
  42. package/dist/core/consistency.js +328 -0
  43. package/dist/core/constants.d.ts +7 -0
  44. package/dist/core/constants.js +64 -0
  45. package/dist/core/errors.d.ts +3 -0
  46. package/dist/core/errors.js +10 -0
  47. package/dist/core/fix.d.ts +31 -0
  48. package/dist/core/fix.js +188 -0
  49. package/dist/core/hook-executor.d.ts +1 -0
  50. package/dist/core/hook-executor.js +175 -0
  51. package/dist/core/markdown.d.ts +16 -0
  52. package/dist/core/markdown.js +81 -0
  53. package/dist/core/normalize.d.ts +8 -0
  54. package/dist/core/normalize.js +125 -0
  55. package/dist/core/normalized-brief.d.ts +48 -0
  56. package/dist/core/normalized-brief.js +182 -0
  57. package/dist/core/output-index.d.ts +13 -0
  58. package/dist/core/output-index.js +55 -0
  59. package/dist/core/paths.d.ts +17 -0
  60. package/dist/core/paths.js +80 -0
  61. package/dist/core/project-config.d.ts +14 -0
  62. package/dist/core/project-config.js +69 -0
  63. package/dist/core/registry.d.ts +13 -0
  64. package/dist/core/registry.js +115 -0
  65. package/dist/core/settings.d.ts +7 -0
  66. package/dist/core/settings.js +35 -0
  67. package/dist/core/template-engine.d.ts +3 -0
  68. package/dist/core/template-engine.js +43 -0
  69. package/dist/core/template-resolver.d.ts +15 -0
  70. package/dist/core/template-resolver.js +46 -0
  71. package/dist/core/templates.d.ts +33 -0
  72. package/dist/core/templates.js +440 -0
  73. package/dist/core/terminology.d.ts +21 -0
  74. package/dist/core/terminology.js +143 -0
  75. package/dist/core/tracing.d.ts +21 -0
  76. package/dist/core/tracing.js +74 -0
  77. package/dist/core/types.d.ts +35 -0
  78. package/dist/core/types.js +5 -0
  79. package/dist/core/utils.d.ts +7 -0
  80. package/dist/core/utils.js +66 -0
  81. package/dist/core/validate.d.ts +10 -0
  82. package/dist/core/validate.js +226 -0
  83. package/dist/core/validator.d.ts +5 -0
  84. package/dist/core/validator.js +76 -0
  85. package/dist/core/version.d.ts +1 -0
  86. package/dist/core/version.js +30 -0
  87. package/dist/core/workflow-commands.d.ts +7 -0
  88. package/dist/core/workflow-commands.js +29 -0
  89. package/dist/i18n/en.json +45 -0
  90. package/dist/i18n/index.d.ts +5 -0
  91. package/dist/i18n/index.js +63 -0
  92. package/dist/i18n/tr.json +45 -0
  93. package/dist/providers/index.d.ts +2 -1
  94. package/dist/providers/index.js +20 -6
  95. package/dist/providers/mock-provider.d.ts +1 -1
  96. package/dist/providers/mock-provider.js +7 -6
  97. package/dist/providers/openai-provider.d.ts +1 -1
  98. package/dist/providers/openai-provider.js +1 -1
  99. package/dist/skills/engine.d.ts +10 -0
  100. package/dist/skills/engine.js +75 -0
  101. package/dist/skills/fix-skill.d.ts +2 -0
  102. package/dist/skills/fix-skill.js +38 -0
  103. package/dist/skills/generate-artifact-skill.d.ts +2 -0
  104. package/dist/skills/generate-artifact-skill.js +32 -0
  105. package/dist/skills/generate-pipeline-skill.d.ts +2 -0
  106. package/dist/skills/generate-pipeline-skill.js +45 -0
  107. package/dist/skills/normalize-skill.d.ts +2 -0
  108. package/dist/skills/normalize-skill.js +29 -0
  109. package/dist/skills/types.d.ts +28 -0
  110. package/dist/skills/types.js +2 -0
  111. package/dist/skills/validate-skill.d.ts +2 -0
  112. package/dist/skills/validate-skill.js +29 -0
  113. package/package.json +74 -45
  114. package/src/agents/agent-registry.ts +93 -0
  115. package/src/agents/anthropic/index.ts +86 -0
  116. package/src/agents/anthropic/manifest.json +7 -0
  117. package/src/agents/base.ts +77 -0
  118. package/src/agents/google/index.ts +79 -0
  119. package/src/agents/google/manifest.json +7 -0
  120. package/src/agents/mock/index.ts +32 -0
  121. package/src/agents/mock/manifest.json +7 -0
  122. package/src/agents/openai/index.ts +83 -0
  123. package/src/agents/openai/manifest.json +7 -0
  124. package/src/agents/system-prompts.ts +35 -0
  125. package/src/{agent-command-installer.ts → cli/agent-command-installer.ts} +164 -164
  126. package/src/{agents.ts → cli/agent-ids.ts} +58 -58
  127. package/src/{doctor.ts → cli/doctor.ts} +157 -137
  128. package/src/cli/fix-tui.ts +111 -0
  129. package/src/{cli.ts → cli/index.ts} +459 -410
  130. package/src/{init-tui.ts → cli/init-tui.ts} +208 -208
  131. package/src/{init.ts → cli/init.ts} +398 -398
  132. package/src/cli/normalize-interactive.ts +241 -0
  133. package/src/{preset-loader.ts → cli/preset-loader.ts} +237 -237
  134. package/src/{artifact-registry.ts → core/artifact-registry.ts} +69 -69
  135. package/src/{artifacts.ts → core/artifacts.ts} +1081 -1072
  136. package/src/core/clean.ts +88 -0
  137. package/src/{consistency.ts → core/consistency.ts} +374 -303
  138. package/src/{constants.ts → core/constants.ts} +72 -72
  139. package/src/{errors.ts → core/errors.ts} +7 -7
  140. package/src/core/fix.ts +253 -0
  141. package/src/{hook-executor.ts → core/hook-executor.ts} +196 -196
  142. package/src/{markdown.ts → core/markdown.ts} +93 -73
  143. package/src/{normalize.ts → core/normalize.ts} +145 -137
  144. package/src/{normalized-brief.ts → core/normalized-brief.ts} +227 -206
  145. package/src/{output-index.ts → core/output-index.ts} +59 -59
  146. package/src/{paths.ts → core/paths.ts} +75 -71
  147. package/src/{project-config.ts → core/project-config.ts} +78 -78
  148. package/src/{registry.ts → core/registry.ts} +119 -119
  149. package/src/{settings.ts → core/settings.ts} +35 -35
  150. package/src/core/template-engine.ts +45 -0
  151. package/src/{template-resolver.ts → core/template-resolver.ts} +54 -54
  152. package/src/{templates.ts → core/templates.ts} +452 -452
  153. package/src/core/terminology.ts +177 -0
  154. package/src/core/tracing.ts +110 -0
  155. package/src/{types.ts → core/types.ts} +46 -46
  156. package/src/{utils.ts → core/utils.ts} +64 -64
  157. package/src/{validate.ts → core/validate.ts} +252 -246
  158. package/src/{validator.ts → core/validator.ts} +92 -92
  159. package/src/{version.ts → core/version.ts} +24 -24
  160. package/src/{workflow-commands.ts → core/workflow-commands.ts} +32 -32
  161. package/src/i18n/en.json +45 -0
  162. package/src/i18n/index.ts +58 -0
  163. package/src/i18n/tr.json +45 -0
  164. package/src/providers/index.ts +29 -12
  165. package/src/providers/mock-provider.ts +200 -199
  166. package/src/providers/openai-provider.ts +88 -88
  167. package/src/skills/engine.ts +94 -0
  168. package/src/skills/fix-skill.ts +38 -0
  169. package/src/skills/generate-artifact-skill.ts +32 -0
  170. package/src/skills/generate-pipeline-skill.ts +49 -0
  171. package/src/skills/normalize-skill.ts +29 -0
  172. package/src/skills/types.ts +36 -0
  173. package/src/skills/validate-skill.ts +29 -0
package/README.md CHANGED
@@ -1,157 +1,261 @@
1
1
  <div align="center">
2
- <h1>Prodo</h1>
3
- <h3><em>Product Artifact Toolkit</em></h3>
4
- </div>
5
-
6
- <p align="center">
7
- <strong>Build consistent product documentation from a stable brief with a CLI-first workflow.</strong>
8
- </p>
9
2
 
10
- ---
3
+ # Prodo
11
4
 
12
- ## Table of Contents
5
+ **AI-Powered Product Owner for Your Codebase**
13
6
 
14
- - [What is Prodo?](#what-is-prodo)
15
- - [Install](#install)
16
- - [Quick Start](#quick-start)
17
- - [Core Workflow](#core-workflow)
18
- - [Supported Agents](#supported-agents)
19
- - [CLI Reference](#cli-reference)
20
- - [Output Structure](#output-structure)
21
- - [Validation Model](#validation-model)
22
- - [Development](#development)
23
- - [License](#license)
7
+ Turn a short product brief into a complete documentation suite — PRD, workflows, wireframes, user stories, tech spec — validated for cross-artifact consistency.
24
8
 
25
- ## What is Prodo?
9
+ [![npm version](https://img.shields.io/npm/v/@shahmarasy/prodo)](https://www.npmjs.com/package/@shahmarasy/prodo)
10
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D20-brightgreen)](https://nodejs.org/)
11
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
12
+ [![Tests](https://img.shields.io/badge/tests-99%20passing-brightgreen)]()
26
13
 
27
- Prodo is a CLI-first toolkit for product-document pipelines.
14
+ </div>
28
15
 
29
- It helps teams move from a raw brief to structured artifacts such as:
16
+ ---
30
17
 
31
- - PRD
32
- - Workflow (Markdown explanation + Mermaid)
33
- - Wireframe (Markdown explanation + HTML)
34
- - Stories
35
- - Tech Spec
18
+ ## Why Prodo?
36
19
 
37
- Prodo is designed to keep input stable, outputs deterministic, and cross-artifact consistency measurable.
20
+ | Problem | Prodo's Answer |
21
+ |---------|---------------|
22
+ | PRDs drift from implementation | **Input is read-only** — `brief.md` never changes during execution |
23
+ | Docs contradict each other | **7 validation gates** check cross-artifact consistency |
24
+ | Every team reinvents the format | **Strict templates** enforce structure across all artifacts |
25
+ | Tied to one AI tool | **Agent-agnostic** — works with Claude, Codex, Gemini, or any LLM |
26
+ | Manual doc maintenance | **One command** regenerates everything from the brief |
38
27
 
39
- ## Install
28
+ ## Quick Start
40
29
 
41
30
  ```bash
31
+ # Install globally
42
32
  npm i -g @shahmarasy/prodo
33
+
34
+ # Initialize in your project
35
+ prodo init . --ai claude-cli --lang en
36
+
37
+ # Edit your brief
38
+ code brief.md
39
+
40
+ # Generate everything
41
+ prodo generate
42
+
43
+ # Check environment
44
+ prodo doctor
43
45
  ```
44
46
 
45
- ## Quick Start
47
+ **That's it.** Prodo normalizes your brief, generates 5 artifact types, validates them, and writes everything to `product-docs/`.
48
+
49
+ ## What Gets Generated
50
+
51
+ ```
52
+ brief.md # Your input (read-only)
53
+ product-docs/
54
+ prd/ # Product Requirements Document
55
+ workflows/ # Flow descriptions + Mermaid diagrams
56
+ wireframes/ # Screen descriptions + HTML prototypes
57
+ stories/ # User stories with Gherkin scenarios
58
+ techspec/ # Architecture, APIs, data models
59
+ reports/ # Validation report
60
+ ```
61
+
62
+ Every artifact includes:
63
+ - **Contract tags** (`[G1]`, `[F2]`, `[C1]`) linking back to brief requirements
64
+ - **Frontmatter** with version, author, upstream references
65
+ - **Companion files** — workflow gets `.mmd` (Mermaid), wireframe gets `.html`
66
+
67
+ ## CLI Reference
68
+
69
+ ### Primary Commands
70
+
71
+ | Command | Description |
72
+ |---------|-------------|
73
+ | `prodo init [target]` | Bootstrap project with `.prodo/` scaffold and agent commands |
74
+ | `prodo generate` | Full pipeline: normalize → generate all → validate |
75
+ | `prodo doctor` | Check environment, SDKs, and agent availability |
76
+ | `prodo clean` | Remove generated artifacts, keep brief and config |
77
+
78
+ ### Pipeline Commands
79
+
80
+ | Command | Description |
81
+ |---------|-------------|
82
+ | `prodo normalize` | Convert brief.md to structured JSON |
83
+ | `prodo prd` | Generate Product Requirements Document |
84
+ | `prodo workflow` | Generate workflow (Markdown + Mermaid) |
85
+ | `prodo wireframe` | Generate wireframes (Markdown + HTML) |
86
+ | `prodo stories` | Generate user stories |
87
+ | `prodo techspec` | Generate technical specification |
88
+ | `prodo validate` | Run 7-gate cross-artifact validation |
89
+ | `prodo fix` | Auto-repair failing artifacts with backup |
90
+
91
+ ### Global Flags
92
+
93
+ | Flag | Available On | Description |
94
+ |------|-------------|-------------|
95
+ | `--ai <name>` | `init` | Agent: `codex`, `gemini-cli`, `claude-cli` |
96
+ | `--lang <code>` | `init` | Language: `en`, `tr` (extensible) |
97
+ | `--agent <name>` | `generate`, `fix` | Override agent profile |
98
+ | `--dry-run` | `generate`, `normalize`, `fix`, `clean` | Preview without writing |
99
+ | `--strict` | `validate`, `generate`, `fix` | Treat warnings as errors |
100
+ | `--interactive` | `normalize` | Q&A loop for low-confidence fields |
101
+
102
+ ## LLM Providers
103
+
104
+ Prodo supports multiple LLM backends as optional peer dependencies:
46
105
 
47
106
  ```bash
48
- # 1) Initialize in your project
49
- prodo init . --ai codex --lang tr
107
+ # OpenAI
108
+ npm install openai
109
+ export PRODO_AGENT=openai OPENAI_API_KEY=sk-...
50
110
 
51
- # 2) Edit brief
52
- # brief.md
111
+ # Anthropic Claude
112
+ npm install @anthropic-ai/sdk
113
+ export PRODO_AGENT=anthropic ANTHROPIC_API_KEY=sk-ant-...
53
114
 
54
- # 3) Check environment (optional)
55
- prodo doctor
115
+ # Google Gemini
116
+ npm install @google/generative-ai
117
+ export PRODO_AGENT=google GOOGLE_API_KEY=AI...
56
118
  ```
57
119
 
58
- ## Core Workflow
120
+ Install only the SDK you need. `prodo doctor` shows which agents are available.
59
121
 
60
- After initialization, Prodo installs agent-native command files.
122
+ > **Full guide:** [docs/providers.md](docs/providers.md)
61
123
 
62
- Recommended flow inside your AI agent:
124
+ ## Agent Integration
63
125
 
64
- 1. Normalize the brief
65
- 2. Produce artifacts in sequence
66
- 3. Validate consistency
126
+ `prodo init --ai <name>` installs native command files for your AI agent:
67
127
 
68
- Prodo keeps:
128
+ | Agent | Location | Format | Commands |
129
+ |-------|----------|--------|----------|
130
+ | Codex | `.agents/skills/` | SKILL.md | `$prodo-normalize`, `$prodo-prd`, ... |
131
+ | Gemini CLI | `.gemini/commands/` | TOML | `/prodo-normalize`, `/prodo-prd`, ... |
132
+ | Claude CLI | `.claude/commands/` | Markdown | `/prodo-normalize`, `/prodo-prd`, ... |
69
133
 
70
- - `brief.md` as input
71
- - `.prodo/` as internal runtime state
72
- - `product-docs/` as user-facing outputs
134
+ Agent workflow: edit `brief.md` run `/prodo-normalize` → `/prodo-prd` → ... → `/prodo-validate`
73
135
 
74
- ## Supported Agents
136
+ ## Validation Gates
75
137
 
76
- `prodo init --ai <name>` supports:
138
+ `prodo validate` runs 7 sequential checks:
77
139
 
78
- - `codex`
79
- - `gemini-cli`
80
- - `claude-cli`
140
+ | # | Gate | Type | What It Checks |
141
+ |---|------|------|----------------|
142
+ | 1 | **Schema** | Structural | Frontmatter, required headings, content length |
143
+ | 2 | **Tag Coverage** | Structural | Contract IDs present in frontmatter |
144
+ | 3 | **Contract Relevance** | LLM-based | Tagged content matches contract text |
145
+ | 4 | **Semantic Consistency** | LLM-based | No contradictions between artifact pairs |
146
+ | 5 | **Terminology** | Heuristic | Consistent naming across documents |
147
+ | 6 | **Tracing** | Structural | Every brief requirement referenced in artifacts |
148
+ | 7 | **Cross-Reference** | Structural | Inline references point to real sections |
81
149
 
82
- Agent command files are installed to native locations:
150
+ Use `--strict` to promote warnings to errors (recommended for CI).
83
151
 
84
- - Codex: `.agents/skills/`
85
- - Gemini CLI: `.gemini/commands/`
86
- - Claude CLI: `.claude/commands/`
152
+ > **Full guide:** [docs/validation.md](docs/validation.md)
87
153
 
88
- ## Agent Commands
154
+ ## Human-in-the-Loop Fix
89
155
 
90
- Prodo agent command set:
156
+ When validation fails:
91
157
 
92
- - `/prodo-normalize`
93
- - `/prodo-prd`
94
- - `/prodo-workflow`
95
- - `/prodo-wireframe`
96
- - `/prodo-stories`
97
- - `/prodo-techspec`
98
- - `/prodo-validate`
158
+ ```bash
159
+ prodo fix # Shows proposal → asks confirmation → backs up → repairs
160
+ prodo fix --dry-run # Preview what would be regenerated
161
+ ```
99
162
 
100
- Codex skills mode equivalents:
163
+ The fix command:
164
+ 1. Runs validation to identify issues
165
+ 2. Computes affected artifacts + downstream dependencies
166
+ 3. **Shows a proposal** with issue details
167
+ 4. **Asks for confirmation** (auto-proceeds in CI)
168
+ 5. Creates a timestamped backup in `.prodo/state/backups/`
169
+ 6. Regenerates impacted artifacts with version increment
170
+ 7. Re-validates to confirm the fix
101
171
 
102
- - `$prodo-normalize`
103
- - `$prodo-prd`
104
- - `$prodo-workflow`
105
- - `$prodo-wireframe`
106
- - `$prodo-stories`
107
- - `$prodo-techspec`
108
- - `$prodo-validate`
172
+ ## Skill Engine
109
173
 
110
- ## CLI Reference
174
+ Prodo includes a composable skill system:
175
+
176
+ ```bash
177
+ prodo skills list # List all skills
178
+ prodo skills run normalize --input '{"cwd": "."}' # Run a skill
179
+ ```
111
180
 
112
- Primary commands:
181
+ Built-in skills: `normalize`, `validate`, `fix`, `generate-artifact`, `generate-pipeline`
113
182
 
114
- - `prodo init [target] [--ai <name>] [--lang <code>] [--preset <name>]`
115
- - `prodo doctor` (alias: `prodo check`)
183
+ > **Full guide:** [docs/skills.md](docs/skills.md)
116
184
 
117
- Version:
185
+ ## Presets
118
186
 
119
- - `prodo --version`
120
- - `prodo -v`
187
+ Domain-specific presets enrich generation with industry context:
121
188
 
122
- ## Output Structure
189
+ ```bash
190
+ prodo init . --preset saas
191
+ prodo init . --preset fintech
192
+ prodo init . --preset marketplace
193
+ ```
123
194
 
124
- Project-level:
195
+ Presets provide specialized prompt templates, validation rules, and domain vocabulary.
125
196
 
126
- - `brief.md` (input, read-only during execution)
127
- - `product-docs/` (all generated product documents)
128
- - `.prodo/` (internal runtime state: prompts, schemas, templates, index, context)
197
+ ## Internationalization
129
198
 
130
- Paired artifact behavior:
199
+ Prodo supports multiple languages via JSON-based translations:
131
200
 
132
- - Workflow: `*.md` + `*.mmd`
133
- - Wireframe: `*.md` + `*.html`
201
+ ```bash
202
+ prodo init . --lang tr # Turkish
203
+ prodo init . --lang en # English (default)
204
+ ```
134
205
 
135
- ## Validation Model
206
+ Language enforcement prevents mixing — Turkish projects are checked for English leaks and vice versa. Add new languages by creating `src/i18n/<code>.json`.
136
207
 
137
- Validation reports include gate-based checks:
208
+ ## Project Structure
138
209
 
139
- - Schema pass
140
- - Tag coverage pass
141
- - Contract relevance pass
142
- - Semantic consistency pass
210
+ ```
211
+ your-project/
212
+ brief.md # Your product brief (input)
213
+ product-docs/ # Generated artifacts (output)
214
+ .prodo/
215
+ settings.json # Language, author, agent config
216
+ hooks.yml # Lifecycle hooks
217
+ briefs/ # Normalized brief JSON
218
+ templates/ # Artifact templates (customizable)
219
+ schemas/ # Validation schemas
220
+ prompts/ # LLM prompts
221
+ commands/ # Agent command templates
222
+ state/ # Runtime state, backups
223
+ ```
143
224
 
144
- All applicable gates must pass for final success.
225
+ ## Documentation
226
+
227
+ | Guide | Description |
228
+ |-------|-------------|
229
+ | [Provider Setup](docs/providers.md) | Configure OpenAI, Anthropic, Google agents |
230
+ | [Writing Briefs](docs/writing-briefs.md) | Structure your brief for best results |
231
+ | [Validation Gates](docs/validation.md) | Understand all 7 validation checks |
232
+ | [Hook System](docs/hooks.md) | Lifecycle hooks with conditions and retries |
233
+ | [Skill Engine](docs/skills.md) | Built-in skills and custom development |
234
+ | [Local Development](docs/local-development.md) | Dev setup and testing |
235
+ | [Upgrade Guide](docs/upgrade.md) | Migrating between versions |
145
236
 
146
237
  ## Development
147
238
 
148
239
  ```bash
240
+ git clone https://github.com/shahmarasy/prodo.git
241
+ cd prodo
149
242
  npm install
150
243
  npm run build
151
- npm test
152
- npm run verify:release
244
+ npm test # 99 tests
245
+ ```
246
+
247
+ ## Architecture
248
+
249
+ ```
250
+ src/
251
+ core/ # Business logic (artifacts, validation, normalization)
252
+ cli/ # Commander entry points and TUI
253
+ agents/ # LLM plugins (OpenAI, Anthropic, Google, Mock)
254
+ skills/ # Composable skill engine
255
+ i18n/ # Translation system (en, tr)
256
+ providers/ # Backward-compatible provider shim
153
257
  ```
154
258
 
155
259
  ## License
156
260
 
157
- MIT
261
+ MIT &copy; [Shahmarasy](https://github.com/shahmarasy)
package/bin/prodo.cjs CHANGED
@@ -1,6 +1,6 @@
1
- #!/usr/bin/env node
2
- "use strict";
3
- require("../dist/cli").runCli().then((code) => {
4
- process.exitCode = code;
5
- });
6
-
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ require("../dist/cli/index").runCli().then((code) => {
4
+ process.exitCode = code;
5
+ });
6
+
@@ -0,0 +1,13 @@
1
+ import type { AgentPlugin } from "./base";
2
+ import type { LLMProvider } from "../core/types";
3
+ export declare class AgentRegistry {
4
+ private agents;
5
+ register(agent: AgentPlugin): void;
6
+ list(): AgentPlugin[];
7
+ get(name: string): AgentPlugin | undefined;
8
+ resolve(name?: string): Promise<AgentPlugin>;
9
+ private resolveAgentName;
10
+ toProvider(agent: AgentPlugin): LLMProvider;
11
+ }
12
+ export declare function getGlobalRegistry(): AgentRegistry;
13
+ export declare function resetGlobalRegistry(): void;
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AgentRegistry = void 0;
4
+ exports.getGlobalRegistry = getGlobalRegistry;
5
+ exports.resetGlobalRegistry = resetGlobalRegistry;
6
+ const errors_1 = require("../core/errors");
7
+ const mock_1 = require("./mock");
8
+ const openai_1 = require("./openai");
9
+ const anthropic_1 = require("./anthropic");
10
+ const google_1 = require("./google");
11
+ const AGENT_ALIASES = {
12
+ mock: "mock",
13
+ openai: "openai",
14
+ anthropic: "anthropic",
15
+ claude: "anthropic",
16
+ google: "google",
17
+ gemini: "google"
18
+ };
19
+ class AgentRegistry {
20
+ agents = new Map();
21
+ register(agent) {
22
+ this.agents.set(agent.name, agent);
23
+ }
24
+ list() {
25
+ return Array.from(this.agents.values());
26
+ }
27
+ get(name) {
28
+ const normalized = AGENT_ALIASES[name.toLowerCase().trim()] ?? name.toLowerCase().trim();
29
+ return this.agents.get(normalized);
30
+ }
31
+ async resolve(name) {
32
+ const agentName = this.resolveAgentName(name);
33
+ const agent = this.get(agentName);
34
+ if (!agent) {
35
+ const available = this.list().map((a) => a.name).join(", ");
36
+ throw new errors_1.UserError(`Unknown agent: "${agentName}". Available agents: ${available}`);
37
+ }
38
+ return agent;
39
+ }
40
+ resolveAgentName(override) {
41
+ if (override)
42
+ return override;
43
+ const fromEnv = process.env.PRODO_AGENT;
44
+ if (fromEnv)
45
+ return fromEnv;
46
+ const fromLegacy = process.env.PRODO_LLM_PROVIDER;
47
+ if (fromLegacy)
48
+ return fromLegacy;
49
+ const isTest = process.env.NODE_ENV === "test" ||
50
+ process.env.PRODO_TEST === "1";
51
+ if (isTest)
52
+ return "mock";
53
+ return "mock";
54
+ }
55
+ toProvider(agent) {
56
+ return {
57
+ generate: (prompt, inputContext, schemaHint) => agent.generate(prompt, inputContext, schemaHint)
58
+ };
59
+ }
60
+ }
61
+ exports.AgentRegistry = AgentRegistry;
62
+ let globalRegistry = null;
63
+ function createDefaultRegistry() {
64
+ const registry = new AgentRegistry();
65
+ registry.register(new mock_1.MockAgent());
66
+ registry.register(new openai_1.OpenAIAgent());
67
+ registry.register(new anthropic_1.AnthropicAgent());
68
+ registry.register(new google_1.GoogleAgent());
69
+ return registry;
70
+ }
71
+ function getGlobalRegistry() {
72
+ if (!globalRegistry) {
73
+ globalRegistry = createDefaultRegistry();
74
+ }
75
+ return globalRegistry;
76
+ }
77
+ function resetGlobalRegistry() {
78
+ globalRegistry = null;
79
+ }
@@ -0,0 +1,9 @@
1
+ import { BaseAgent, type AgentConfig } from "../base";
2
+ import type { GenerateResult, ProviderSchemaHint } from "../../core/types";
3
+ export declare class AnthropicAgent extends BaseAgent {
4
+ readonly name = "anthropic";
5
+ readonly displayName = "Anthropic Claude";
6
+ readonly sdkRequired = "@anthropic-ai/sdk";
7
+ getConfig(): AgentConfig;
8
+ generate(prompt: string, inputContext: Record<string, unknown>, schemaHint: ProviderSchemaHint): Promise<GenerateResult>;
9
+ }
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AnthropicAgent = void 0;
4
+ const base_1 = require("../base");
5
+ const system_prompts_1 = require("../system-prompts");
6
+ const errors_1 = require("../../core/errors");
7
+ const dynamicImport = new Function("specifier", "return import(specifier)");
8
+ class AnthropicAgent extends base_1.BaseAgent {
9
+ name = "anthropic";
10
+ displayName = "Anthropic Claude";
11
+ sdkRequired = "@anthropic-ai/sdk";
12
+ getConfig() {
13
+ return {
14
+ name: this.name,
15
+ displayName: this.displayName,
16
+ sdkRequired: this.sdkRequired,
17
+ envVars: ["ANTHROPIC_API_KEY"],
18
+ defaultModel: "claude-sonnet-4-20250514"
19
+ };
20
+ }
21
+ async generate(prompt, inputContext, schemaHint) {
22
+ const apiKey = process.env.ANTHROPIC_API_KEY;
23
+ if (!apiKey) {
24
+ throw new errors_1.UserError("ANTHROPIC_API_KEY is not set. Set it to use the Anthropic agent.");
25
+ }
26
+ const model = process.env.PRODO_ANTHROPIC_MODEL ?? "claude-sonnet-4-20250514";
27
+ const outputLanguage = typeof inputContext.outputLanguage === "string" && inputContext.outputLanguage.trim()
28
+ ? inputContext.outputLanguage.trim()
29
+ : "en";
30
+ const system = (0, system_prompts_1.buildSystemPrompt)(schemaHint, outputLanguage);
31
+ const user = (0, system_prompts_1.buildUserMessage)(prompt, inputContext);
32
+ let AnthropicConstructor;
33
+ try {
34
+ const mod = (await dynamicImport("@anthropic-ai/sdk"));
35
+ AnthropicConstructor = mod.default;
36
+ }
37
+ catch {
38
+ throw new errors_1.UserError("Anthropic SDK is not installed. Run: npm install @anthropic-ai/sdk");
39
+ }
40
+ const client = new AnthropicConstructor({ apiKey });
41
+ const response = await client.messages.create({
42
+ model,
43
+ max_tokens: 8192,
44
+ system,
45
+ messages: [{ role: "user", content: user }]
46
+ });
47
+ const textBlock = response.content.find((block) => block.type === "text");
48
+ const content = textBlock?.text?.trim() ?? "";
49
+ if (!content) {
50
+ throw new errors_1.UserError("Anthropic agent returned an empty response.");
51
+ }
52
+ return { body: content };
53
+ }
54
+ }
55
+ exports.AnthropicAgent = AnthropicAgent;
@@ -0,0 +1,25 @@
1
+ import type { GenerateResult, ProviderSchemaHint } from "../core/types";
2
+ export type AgentConfig = {
3
+ name: string;
4
+ displayName: string;
5
+ sdkRequired: string | null;
6
+ envVars: string[];
7
+ defaultModel?: string;
8
+ };
9
+ export interface AgentPlugin {
10
+ readonly name: string;
11
+ readonly displayName: string;
12
+ readonly sdkRequired: string | null;
13
+ generate(prompt: string, inputContext: Record<string, unknown>, schemaHint: ProviderSchemaHint): Promise<GenerateResult>;
14
+ isAvailable(): Promise<boolean>;
15
+ getConfig(): AgentConfig;
16
+ }
17
+ export declare abstract class BaseAgent implements AgentPlugin {
18
+ abstract readonly name: string;
19
+ abstract readonly displayName: string;
20
+ abstract readonly sdkRequired: string | null;
21
+ abstract generate(prompt: string, inputContext: Record<string, unknown>, schemaHint: ProviderSchemaHint): Promise<GenerateResult>;
22
+ abstract getConfig(): AgentConfig;
23
+ isAvailable(): Promise<boolean>;
24
+ availabilityHint(): string;
25
+ }
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.BaseAgent = void 0;
37
+ class BaseAgent {
38
+ async isAvailable() {
39
+ const config = this.getConfig();
40
+ if (config.sdkRequired) {
41
+ try {
42
+ await Promise.resolve(`${config.sdkRequired}`).then(s => __importStar(require(s)));
43
+ }
44
+ catch {
45
+ return false;
46
+ }
47
+ }
48
+ for (const envVar of config.envVars) {
49
+ if (!process.env[envVar]) {
50
+ return false;
51
+ }
52
+ }
53
+ return true;
54
+ }
55
+ availabilityHint() {
56
+ const config = this.getConfig();
57
+ const hints = [];
58
+ if (config.sdkRequired) {
59
+ hints.push(`SDK required: npm install ${config.sdkRequired}`);
60
+ }
61
+ for (const envVar of config.envVars) {
62
+ if (!process.env[envVar]) {
63
+ hints.push(`Set environment variable: ${envVar}`);
64
+ }
65
+ }
66
+ return hints.length > 0
67
+ ? `Agent "${config.displayName}" is not available.\n ${hints.join("\n ")}`
68
+ : `Agent "${config.displayName}" is available.`;
69
+ }
70
+ }
71
+ exports.BaseAgent = BaseAgent;
@@ -0,0 +1,9 @@
1
+ import { BaseAgent, type AgentConfig } from "../base";
2
+ import type { GenerateResult, ProviderSchemaHint } from "../../core/types";
3
+ export declare class GoogleAgent extends BaseAgent {
4
+ readonly name = "google";
5
+ readonly displayName = "Google Gemini";
6
+ readonly sdkRequired = "@google/generative-ai";
7
+ getConfig(): AgentConfig;
8
+ generate(prompt: string, inputContext: Record<string, unknown>, schemaHint: ProviderSchemaHint): Promise<GenerateResult>;
9
+ }