@shahmarasy/prodo 0.1.3 → 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.
- package/README.md +201 -97
- package/bin/prodo.cjs +6 -6
- package/dist/agents/agent-registry.d.ts +13 -0
- package/dist/agents/agent-registry.js +79 -0
- package/dist/agents/anthropic/index.d.ts +9 -0
- package/dist/agents/anthropic/index.js +55 -0
- package/dist/agents/base.d.ts +25 -0
- package/dist/agents/base.js +71 -0
- package/dist/agents/google/index.d.ts +9 -0
- package/dist/agents/google/index.js +53 -0
- package/dist/agents/mock/index.d.ts +11 -0
- package/dist/agents/mock/index.js +26 -0
- package/dist/agents/openai/index.d.ts +9 -0
- package/dist/agents/openai/index.js +57 -0
- package/dist/agents/system-prompts.d.ts +3 -0
- package/dist/agents/system-prompts.js +32 -0
- package/dist/agents.js +4 -2
- package/dist/artifacts.d.ts +1 -0
- package/dist/artifacts.js +265 -31
- package/dist/cli/agent-command-installer.d.ts +4 -0
- package/dist/cli/agent-command-installer.js +148 -0
- package/dist/cli/agent-ids.d.ts +15 -0
- package/dist/cli/agent-ids.js +49 -0
- package/dist/cli/doctor.d.ts +1 -0
- package/dist/cli/doctor.js +144 -0
- package/dist/cli/fix-tui.d.ts +4 -0
- package/dist/cli/fix-tui.js +79 -0
- package/dist/cli/index.d.ts +9 -0
- package/dist/cli/index.js +465 -0
- package/dist/cli/init-tui.d.ts +23 -0
- package/dist/cli/init-tui.js +176 -0
- package/dist/cli/init.d.ts +11 -0
- package/dist/cli/init.js +334 -0
- package/dist/cli/normalize-interactive.d.ts +8 -0
- package/dist/cli/normalize-interactive.js +167 -0
- package/dist/cli/preset-loader.d.ts +4 -0
- package/dist/cli/preset-loader.js +210 -0
- package/dist/cli.js +80 -3
- package/dist/core/artifact-registry.d.ts +11 -0
- package/dist/core/artifact-registry.js +49 -0
- package/dist/core/artifacts.d.ts +10 -0
- package/dist/core/artifacts.js +892 -0
- package/dist/core/clean.d.ts +10 -0
- package/dist/core/clean.js +74 -0
- package/dist/core/consistency.d.ts +8 -0
- package/dist/core/consistency.js +328 -0
- package/dist/core/constants.d.ts +7 -0
- package/dist/core/constants.js +64 -0
- package/dist/core/errors.d.ts +3 -0
- package/dist/core/errors.js +10 -0
- package/dist/core/fix.d.ts +31 -0
- package/dist/core/fix.js +188 -0
- package/dist/core/hook-executor.d.ts +1 -0
- package/dist/core/hook-executor.js +175 -0
- package/dist/core/markdown.d.ts +16 -0
- package/dist/core/markdown.js +81 -0
- package/dist/core/normalize.d.ts +8 -0
- package/dist/core/normalize.js +125 -0
- package/dist/core/normalized-brief.d.ts +48 -0
- package/dist/core/normalized-brief.js +182 -0
- package/dist/core/output-index.d.ts +13 -0
- package/dist/core/output-index.js +55 -0
- package/dist/core/paths.d.ts +17 -0
- package/dist/core/paths.js +80 -0
- package/dist/core/project-config.d.ts +14 -0
- package/dist/core/project-config.js +69 -0
- package/dist/core/registry.d.ts +13 -0
- package/dist/core/registry.js +115 -0
- package/dist/core/settings.d.ts +7 -0
- package/dist/core/settings.js +35 -0
- package/dist/core/template-engine.d.ts +3 -0
- package/dist/core/template-engine.js +43 -0
- package/dist/core/template-resolver.d.ts +15 -0
- package/dist/core/template-resolver.js +46 -0
- package/dist/core/templates.d.ts +33 -0
- package/dist/core/templates.js +440 -0
- package/dist/core/terminology.d.ts +21 -0
- package/dist/core/terminology.js +143 -0
- package/dist/core/tracing.d.ts +21 -0
- package/dist/core/tracing.js +74 -0
- package/dist/core/types.d.ts +35 -0
- package/dist/core/types.js +5 -0
- package/dist/core/utils.d.ts +7 -0
- package/dist/core/utils.js +66 -0
- package/dist/core/validate.d.ts +10 -0
- package/dist/core/validate.js +226 -0
- package/dist/core/validator.d.ts +5 -0
- package/dist/core/validator.js +76 -0
- package/dist/core/version.d.ts +1 -0
- package/dist/core/version.js +30 -0
- package/dist/core/workflow-commands.d.ts +7 -0
- package/dist/core/workflow-commands.js +29 -0
- package/dist/i18n/en.json +45 -0
- package/dist/i18n/index.d.ts +5 -0
- package/dist/i18n/index.js +63 -0
- package/dist/i18n/tr.json +45 -0
- package/dist/init-tui.d.ts +3 -0
- package/dist/init-tui.js +28 -1
- package/dist/init.d.ts +1 -0
- package/dist/init.js +9 -3
- package/dist/normalize.js +55 -7
- package/dist/providers/index.d.ts +2 -1
- package/dist/providers/index.js +20 -6
- package/dist/providers/mock-provider.d.ts +1 -1
- package/dist/providers/mock-provider.js +7 -6
- package/dist/providers/openai-provider.d.ts +1 -1
- package/dist/providers/openai-provider.js +3 -2
- package/dist/settings.d.ts +1 -0
- package/dist/settings.js +2 -1
- package/dist/skills/engine.d.ts +10 -0
- package/dist/skills/engine.js +75 -0
- package/dist/skills/fix-skill.d.ts +2 -0
- package/dist/skills/fix-skill.js +38 -0
- package/dist/skills/generate-artifact-skill.d.ts +2 -0
- package/dist/skills/generate-artifact-skill.js +32 -0
- package/dist/skills/generate-pipeline-skill.d.ts +2 -0
- package/dist/skills/generate-pipeline-skill.js +45 -0
- package/dist/skills/normalize-skill.d.ts +2 -0
- package/dist/skills/normalize-skill.js +29 -0
- package/dist/skills/types.d.ts +28 -0
- package/dist/skills/types.js +2 -0
- package/dist/skills/validate-skill.d.ts +2 -0
- package/dist/skills/validate-skill.js +29 -0
- package/dist/templates.d.ts +1 -1
- package/dist/templates.js +2 -0
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +13 -0
- package/dist/validator.js +0 -4
- package/dist/workflow-commands.js +2 -1
- package/package.json +74 -45
- package/presets/fintech/preset.json +48 -1
- package/presets/fintech/prompts/prd.md +99 -2
- package/presets/marketplace/preset.json +51 -1
- package/presets/marketplace/prompts/prd.md +140 -2
- package/presets/saas/preset.json +53 -1
- package/presets/saas/prompts/prd.md +150 -2
- package/src/agents/agent-registry.ts +93 -0
- package/src/agents/anthropic/index.ts +86 -0
- package/src/agents/anthropic/manifest.json +7 -0
- package/src/agents/base.ts +77 -0
- package/src/agents/google/index.ts +79 -0
- package/src/agents/google/manifest.json +7 -0
- package/src/agents/mock/index.ts +32 -0
- package/src/agents/mock/manifest.json +7 -0
- package/src/agents/openai/index.ts +83 -0
- package/src/agents/openai/manifest.json +7 -0
- package/src/agents/system-prompts.ts +35 -0
- package/src/{agent-command-installer.ts → cli/agent-command-installer.ts} +164 -164
- package/src/{agents.ts → cli/agent-ids.ts} +58 -56
- package/src/{doctor.ts → cli/doctor.ts} +157 -137
- package/src/cli/fix-tui.ts +111 -0
- package/src/{cli.ts → cli/index.ts} +459 -319
- package/src/{init-tui.ts → cli/init-tui.ts} +208 -179
- package/src/{init.ts → cli/init.ts} +398 -391
- package/src/cli/normalize-interactive.ts +241 -0
- package/src/{preset-loader.ts → cli/preset-loader.ts} +237 -237
- package/src/{artifact-registry.ts → core/artifact-registry.ts} +69 -69
- package/src/{artifacts.ts → core/artifacts.ts} +1081 -777
- package/src/core/clean.ts +88 -0
- package/src/{consistency.ts → core/consistency.ts} +374 -303
- package/src/{constants.ts → core/constants.ts} +72 -72
- package/src/{errors.ts → core/errors.ts} +7 -7
- package/src/core/fix.ts +253 -0
- package/src/{hook-executor.ts → core/hook-executor.ts} +196 -196
- package/src/{markdown.ts → core/markdown.ts} +93 -73
- package/src/core/normalize.ts +145 -0
- package/src/{normalized-brief.ts → core/normalized-brief.ts} +227 -206
- package/src/{output-index.ts → core/output-index.ts} +59 -59
- package/src/{paths.ts → core/paths.ts} +75 -71
- package/src/{project-config.ts → core/project-config.ts} +78 -78
- package/src/{registry.ts → core/registry.ts} +119 -119
- package/src/{settings.ts → core/settings.ts} +35 -34
- package/src/core/template-engine.ts +45 -0
- package/src/{template-resolver.ts → core/template-resolver.ts} +54 -54
- package/src/{templates.ts → core/templates.ts} +452 -450
- package/src/core/terminology.ts +177 -0
- package/src/core/tracing.ts +110 -0
- package/src/{types.ts → core/types.ts} +46 -46
- package/src/{utils.ts → core/utils.ts} +64 -50
- package/src/{validate.ts → core/validate.ts} +252 -246
- package/src/{validator.ts → core/validator.ts} +92 -96
- package/src/{version.ts → core/version.ts} +24 -24
- package/src/{workflow-commands.ts → core/workflow-commands.ts} +32 -31
- package/src/i18n/en.json +45 -0
- package/src/i18n/index.ts +58 -0
- package/src/i18n/tr.json +45 -0
- package/src/providers/index.ts +29 -12
- package/src/providers/mock-provider.ts +200 -199
- package/src/providers/openai-provider.ts +88 -87
- package/src/skills/engine.ts +94 -0
- package/src/skills/fix-skill.ts +38 -0
- package/src/skills/generate-artifact-skill.ts +32 -0
- package/src/skills/generate-pipeline-skill.ts +49 -0
- package/src/skills/normalize-skill.ts +29 -0
- package/src/skills/types.ts +36 -0
- package/src/skills/validate-skill.ts +29 -0
- package/templates/commands/prodo-fix.md +46 -0
- package/templates/commands/prodo-normalize.md +118 -23
- package/templates/commands/prodo-prd.md +138 -17
- package/templates/commands/prodo-stories.md +153 -17
- package/templates/commands/prodo-techspec.md +167 -17
- package/templates/commands/prodo-validate.md +184 -26
- package/templates/commands/prodo-wireframe.md +188 -17
- package/templates/commands/prodo-workflow.md +200 -17
- package/src/normalize.ts +0 -89
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
|
-
|
|
5
|
+
**AI-Powered Product Owner for Your Codebase**
|
|
13
6
|
|
|
14
|
-
|
|
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
|
-
|
|
9
|
+
[](https://www.npmjs.com/package/@shahmarasy/prodo)
|
|
10
|
+
[](https://nodejs.org/)
|
|
11
|
+
[](LICENSE)
|
|
12
|
+
[]()
|
|
26
13
|
|
|
27
|
-
|
|
14
|
+
</div>
|
|
28
15
|
|
|
29
|
-
|
|
16
|
+
---
|
|
30
17
|
|
|
31
|
-
|
|
32
|
-
- Workflow (Markdown explanation + Mermaid)
|
|
33
|
-
- Wireframe (Markdown explanation + HTML)
|
|
34
|
-
- Stories
|
|
35
|
-
- Tech Spec
|
|
18
|
+
## Why Prodo?
|
|
36
19
|
|
|
37
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
#
|
|
49
|
-
|
|
107
|
+
# OpenAI
|
|
108
|
+
npm install openai
|
|
109
|
+
export PRODO_AGENT=openai OPENAI_API_KEY=sk-...
|
|
50
110
|
|
|
51
|
-
#
|
|
52
|
-
|
|
111
|
+
# Anthropic Claude
|
|
112
|
+
npm install @anthropic-ai/sdk
|
|
113
|
+
export PRODO_AGENT=anthropic ANTHROPIC_API_KEY=sk-ant-...
|
|
53
114
|
|
|
54
|
-
#
|
|
55
|
-
|
|
115
|
+
# Google Gemini
|
|
116
|
+
npm install @google/generative-ai
|
|
117
|
+
export PRODO_AGENT=google GOOGLE_API_KEY=AI...
|
|
56
118
|
```
|
|
57
119
|
|
|
58
|
-
|
|
120
|
+
Install only the SDK you need. `prodo doctor` shows which agents are available.
|
|
59
121
|
|
|
60
|
-
|
|
122
|
+
> **Full guide:** [docs/providers.md](docs/providers.md)
|
|
61
123
|
|
|
62
|
-
|
|
124
|
+
## Agent Integration
|
|
63
125
|
|
|
64
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
136
|
+
## Validation Gates
|
|
75
137
|
|
|
76
|
-
`prodo
|
|
138
|
+
`prodo validate` runs 7 sequential checks:
|
|
77
139
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
-
|
|
150
|
+
Use `--strict` to promote warnings to errors (recommended for CI).
|
|
83
151
|
|
|
84
|
-
|
|
85
|
-
- Gemini CLI: `.gemini/commands/`
|
|
86
|
-
- Claude CLI: `.claude/commands/`
|
|
152
|
+
> **Full guide:** [docs/validation.md](docs/validation.md)
|
|
87
153
|
|
|
88
|
-
##
|
|
154
|
+
## Human-in-the-Loop Fix
|
|
89
155
|
|
|
90
|
-
|
|
156
|
+
When validation fails:
|
|
91
157
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
-
|
|
95
|
-
|
|
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
|
-
|
|
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
|
-
|
|
103
|
-
- `$prodo-prd`
|
|
104
|
-
- `$prodo-workflow`
|
|
105
|
-
- `$prodo-wireframe`
|
|
106
|
-
- `$prodo-stories`
|
|
107
|
-
- `$prodo-techspec`
|
|
108
|
-
- `$prodo-validate`
|
|
172
|
+
## Skill Engine
|
|
109
173
|
|
|
110
|
-
|
|
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
|
-
|
|
181
|
+
Built-in skills: `normalize`, `validate`, `fix`, `generate-artifact`, `generate-pipeline`
|
|
113
182
|
|
|
114
|
-
|
|
115
|
-
- `prodo doctor` (alias: `prodo check`)
|
|
183
|
+
> **Full guide:** [docs/skills.md](docs/skills.md)
|
|
116
184
|
|
|
117
|
-
|
|
185
|
+
## Presets
|
|
118
186
|
|
|
119
|
-
-
|
|
120
|
-
- `prodo -v`
|
|
187
|
+
Domain-specific presets enrich generation with industry context:
|
|
121
188
|
|
|
122
|
-
|
|
189
|
+
```bash
|
|
190
|
+
prodo init . --preset saas
|
|
191
|
+
prodo init . --preset fintech
|
|
192
|
+
prodo init . --preset marketplace
|
|
193
|
+
```
|
|
123
194
|
|
|
124
|
-
|
|
195
|
+
Presets provide specialized prompt templates, validation rules, and domain vocabulary.
|
|
125
196
|
|
|
126
|
-
|
|
127
|
-
- `product-docs/` (all generated product documents)
|
|
128
|
-
- `.prodo/` (internal runtime state: prompts, schemas, templates, index, context)
|
|
197
|
+
## Internationalization
|
|
129
198
|
|
|
130
|
-
|
|
199
|
+
Prodo supports multiple languages via JSON-based translations:
|
|
131
200
|
|
|
132
|
-
|
|
133
|
-
|
|
201
|
+
```bash
|
|
202
|
+
prodo init . --lang tr # Turkish
|
|
203
|
+
prodo init . --lang en # English (default)
|
|
204
|
+
```
|
|
134
205
|
|
|
135
|
-
|
|
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
|
-
|
|
208
|
+
## Project Structure
|
|
138
209
|
|
|
139
|
-
|
|
140
|
-
-
|
|
141
|
-
|
|
142
|
-
-
|
|
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
|
-
|
|
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
|
-
|
|
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 © [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
|
+
}
|