@shahmarasy/prodo 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/LICENSE +21 -0
- package/README.md +157 -0
- package/bin/prodo.cjs +6 -0
- package/dist/agent-command-installer.d.ts +4 -0
- package/dist/agent-command-installer.js +158 -0
- package/dist/agents.d.ts +15 -0
- package/dist/agents.js +47 -0
- package/dist/artifact-registry.d.ts +11 -0
- package/dist/artifact-registry.js +49 -0
- package/dist/artifacts.d.ts +9 -0
- package/dist/artifacts.js +514 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.js +305 -0
- package/dist/consistency.d.ts +8 -0
- package/dist/consistency.js +268 -0
- package/dist/constants.d.ts +7 -0
- package/dist/constants.js +64 -0
- package/dist/doctor.d.ts +1 -0
- package/dist/doctor.js +123 -0
- package/dist/errors.d.ts +3 -0
- package/dist/errors.js +10 -0
- package/dist/hook-executor.d.ts +1 -0
- package/dist/hook-executor.js +175 -0
- package/dist/init-tui.d.ts +21 -0
- package/dist/init-tui.js +161 -0
- package/dist/init.d.ts +10 -0
- package/dist/init.js +307 -0
- package/dist/markdown.d.ts +11 -0
- package/dist/markdown.js +66 -0
- package/dist/normalize.d.ts +7 -0
- package/dist/normalize.js +73 -0
- package/dist/normalized-brief.d.ts +39 -0
- package/dist/normalized-brief.js +170 -0
- package/dist/output-index.d.ts +13 -0
- package/dist/output-index.js +55 -0
- package/dist/paths.d.ts +16 -0
- package/dist/paths.js +76 -0
- package/dist/preset-loader.d.ts +4 -0
- package/dist/preset-loader.js +210 -0
- package/dist/project-config.d.ts +14 -0
- package/dist/project-config.js +69 -0
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.js +12 -0
- package/dist/providers/mock-provider.d.ts +7 -0
- package/dist/providers/mock-provider.js +168 -0
- package/dist/providers/openai-provider.d.ts +11 -0
- package/dist/providers/openai-provider.js +69 -0
- package/dist/registry.d.ts +13 -0
- package/dist/registry.js +115 -0
- package/dist/settings.d.ts +6 -0
- package/dist/settings.js +34 -0
- package/dist/template-resolver.d.ts +11 -0
- package/dist/template-resolver.js +28 -0
- package/dist/templates.d.ts +33 -0
- package/dist/templates.js +428 -0
- package/dist/types.d.ts +35 -0
- package/dist/types.js +5 -0
- package/dist/utils.d.ts +6 -0
- package/dist/utils.js +53 -0
- package/dist/validate.d.ts +9 -0
- package/dist/validate.js +226 -0
- package/dist/validator.d.ts +5 -0
- package/dist/validator.js +80 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +30 -0
- package/dist/workflow-commands.d.ts +7 -0
- package/dist/workflow-commands.js +28 -0
- package/package.json +45 -0
- package/presets/fintech/preset.json +1 -0
- package/presets/fintech/prompts/prd.md +3 -0
- package/presets/marketplace/preset.json +1 -0
- package/presets/marketplace/prompts/prd.md +3 -0
- package/presets/saas/preset.json +1 -0
- package/presets/saas/prompts/prd.md +3 -0
- package/src/agent-command-installer.ts +174 -0
- package/src/agents.ts +56 -0
- package/src/artifact-registry.ts +69 -0
- package/src/artifacts.ts +606 -0
- package/src/cli.ts +322 -0
- package/src/consistency.ts +303 -0
- package/src/constants.ts +72 -0
- package/src/doctor.ts +137 -0
- package/src/errors.ts +7 -0
- package/src/hook-executor.ts +196 -0
- package/src/init-tui.ts +193 -0
- package/src/init.ts +375 -0
- package/src/markdown.ts +73 -0
- package/src/normalize.ts +89 -0
- package/src/normalized-brief.ts +206 -0
- package/src/output-index.ts +59 -0
- package/src/paths.ts +72 -0
- package/src/preset-loader.ts +237 -0
- package/src/project-config.ts +78 -0
- package/src/providers/index.ts +12 -0
- package/src/providers/mock-provider.ts +188 -0
- package/src/providers/openai-provider.ts +87 -0
- package/src/registry.ts +119 -0
- package/src/settings.ts +34 -0
- package/src/template-resolver.ts +33 -0
- package/src/templates.ts +440 -0
- package/src/types.ts +46 -0
- package/src/utils.ts +50 -0
- package/src/validate.ts +246 -0
- package/src/validator.ts +96 -0
- package/src/version.ts +24 -0
- package/src/workflow-commands.ts +31 -0
- package/templates/artifacts/prd.md +219 -0
- package/templates/artifacts/stories.md +49 -0
- package/templates/artifacts/techspec.md +42 -0
- package/templates/artifacts/wireframe.html +260 -0
- package/templates/artifacts/wireframe.md +22 -0
- package/templates/artifacts/workflow.md +22 -0
- package/templates/artifacts/workflow.mmd +6 -0
- package/templates/commands/prodo-normalize.md +24 -0
- package/templates/commands/prodo-prd.md +24 -0
- package/templates/commands/prodo-stories.md +24 -0
- package/templates/commands/prodo-techspec.md +24 -0
- package/templates/commands/prodo-validate.md +24 -0
- package/templates/commands/prodo-wireframe.md +24 -0
- package/templates/commands/prodo-workflow.md +24 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Bahman Shahmarasy
|
|
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,157 @@
|
|
|
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
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Table of Contents
|
|
13
|
+
|
|
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)
|
|
24
|
+
|
|
25
|
+
## What is Prodo?
|
|
26
|
+
|
|
27
|
+
Prodo is a CLI-first toolkit for product-document pipelines.
|
|
28
|
+
|
|
29
|
+
It helps teams move from a raw brief to structured artifacts such as:
|
|
30
|
+
|
|
31
|
+
- PRD
|
|
32
|
+
- Workflow (Markdown explanation + Mermaid)
|
|
33
|
+
- Wireframe (Markdown explanation + HTML)
|
|
34
|
+
- Stories
|
|
35
|
+
- Tech Spec
|
|
36
|
+
|
|
37
|
+
Prodo is designed to keep input stable, outputs deterministic, and cross-artifact consistency measurable.
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm i -g @shahmarasy/prodo
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Quick Start
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# 1) Initialize in your project
|
|
49
|
+
prodo init . --ai codex --lang tr
|
|
50
|
+
|
|
51
|
+
# 2) Edit brief
|
|
52
|
+
# brief.md
|
|
53
|
+
|
|
54
|
+
# 3) Check environment (optional)
|
|
55
|
+
prodo doctor
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Core Workflow
|
|
59
|
+
|
|
60
|
+
After initialization, Prodo installs agent-native command files.
|
|
61
|
+
|
|
62
|
+
Recommended flow inside your AI agent:
|
|
63
|
+
|
|
64
|
+
1. Normalize the brief
|
|
65
|
+
2. Produce artifacts in sequence
|
|
66
|
+
3. Validate consistency
|
|
67
|
+
|
|
68
|
+
Prodo keeps:
|
|
69
|
+
|
|
70
|
+
- `brief.md` as input
|
|
71
|
+
- `.prodo/` as internal runtime state
|
|
72
|
+
- `product-docs/` as user-facing outputs
|
|
73
|
+
|
|
74
|
+
## Supported Agents
|
|
75
|
+
|
|
76
|
+
`prodo init --ai <name>` supports:
|
|
77
|
+
|
|
78
|
+
- `codex`
|
|
79
|
+
- `gemini-cli`
|
|
80
|
+
- `claude-cli`
|
|
81
|
+
|
|
82
|
+
Agent command files are installed to native locations:
|
|
83
|
+
|
|
84
|
+
- Codex: `.agents/skills/`
|
|
85
|
+
- Gemini CLI: `.gemini/commands/`
|
|
86
|
+
- Claude CLI: `.claude/commands/`
|
|
87
|
+
|
|
88
|
+
## Agent Commands
|
|
89
|
+
|
|
90
|
+
Prodo agent command set:
|
|
91
|
+
|
|
92
|
+
- `/prodo-normalize`
|
|
93
|
+
- `/prodo-prd`
|
|
94
|
+
- `/prodo-workflow`
|
|
95
|
+
- `/prodo-wireframe`
|
|
96
|
+
- `/prodo-stories`
|
|
97
|
+
- `/prodo-techspec`
|
|
98
|
+
- `/prodo-validate`
|
|
99
|
+
|
|
100
|
+
Codex skills mode equivalents:
|
|
101
|
+
|
|
102
|
+
- `$prodo-normalize`
|
|
103
|
+
- `$prodo-prd`
|
|
104
|
+
- `$prodo-workflow`
|
|
105
|
+
- `$prodo-wireframe`
|
|
106
|
+
- `$prodo-stories`
|
|
107
|
+
- `$prodo-techspec`
|
|
108
|
+
- `$prodo-validate`
|
|
109
|
+
|
|
110
|
+
## CLI Reference
|
|
111
|
+
|
|
112
|
+
Primary commands:
|
|
113
|
+
|
|
114
|
+
- `prodo init [target] [--ai <name>] [--lang <code>] [--preset <name>]`
|
|
115
|
+
- `prodo doctor` (alias: `prodo check`)
|
|
116
|
+
|
|
117
|
+
Version:
|
|
118
|
+
|
|
119
|
+
- `prodo --version`
|
|
120
|
+
- `prodo -v`
|
|
121
|
+
|
|
122
|
+
## Output Structure
|
|
123
|
+
|
|
124
|
+
Project-level:
|
|
125
|
+
|
|
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)
|
|
129
|
+
|
|
130
|
+
Paired artifact behavior:
|
|
131
|
+
|
|
132
|
+
- Workflow: `*.md` + `*.mmd`
|
|
133
|
+
- Wireframe: `*.md` + `*.html`
|
|
134
|
+
|
|
135
|
+
## Validation Model
|
|
136
|
+
|
|
137
|
+
Validation reports include gate-based checks:
|
|
138
|
+
|
|
139
|
+
- Schema pass
|
|
140
|
+
- Tag coverage pass
|
|
141
|
+
- Contract relevance pass
|
|
142
|
+
- Semantic consistency pass
|
|
143
|
+
|
|
144
|
+
All applicable gates must pass for final success.
|
|
145
|
+
|
|
146
|
+
## Development
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
npm install
|
|
150
|
+
npm run build
|
|
151
|
+
npm test
|
|
152
|
+
npm run verify:release
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## License
|
|
156
|
+
|
|
157
|
+
MIT
|
package/bin/prodo.cjs
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const AI_ALIASES: Record<string, "codex" | "gemini-cli" | "claude-cli">;
|
|
2
|
+
export type SupportedAi = "codex" | "gemini-cli" | "claude-cli";
|
|
3
|
+
export declare function resolveAi(ai?: string): SupportedAi | undefined;
|
|
4
|
+
export declare function installAgentCommands(projectRoot: string, ai: SupportedAi): Promise<string[]>;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.AI_ALIASES = void 0;
|
|
7
|
+
exports.resolveAi = resolveAi;
|
|
8
|
+
exports.installAgentCommands = installAgentCommands;
|
|
9
|
+
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
const js_yaml_1 = __importDefault(require("js-yaml"));
|
|
12
|
+
const errors_1 = require("./errors");
|
|
13
|
+
const utils_1 = require("./utils");
|
|
14
|
+
exports.AI_ALIASES = {
|
|
15
|
+
codex: "codex",
|
|
16
|
+
gemini: "gemini-cli",
|
|
17
|
+
"gemmini-cli": "gemini-cli",
|
|
18
|
+
"gemmini": "gemini-cli",
|
|
19
|
+
"gemini-cli": "gemini-cli",
|
|
20
|
+
claude: "claude-cli",
|
|
21
|
+
"claude-cli": "claude-cli"
|
|
22
|
+
};
|
|
23
|
+
const AGENT_CONFIG = {
|
|
24
|
+
"claude-cli": {
|
|
25
|
+
baseDir: ".claude/commands",
|
|
26
|
+
format: "markdown",
|
|
27
|
+
extension: ".md",
|
|
28
|
+
argsPlaceholder: "$ARGUMENTS"
|
|
29
|
+
},
|
|
30
|
+
"gemini-cli": {
|
|
31
|
+
baseDir: ".gemini/commands",
|
|
32
|
+
format: "toml",
|
|
33
|
+
extension: ".toml",
|
|
34
|
+
argsPlaceholder: "{{args}}"
|
|
35
|
+
},
|
|
36
|
+
codex: {
|
|
37
|
+
baseDir: ".agents/skills",
|
|
38
|
+
format: "skill",
|
|
39
|
+
extension: "/SKILL.md",
|
|
40
|
+
argsPlaceholder: "$ARGUMENTS"
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
function parseFrontmatter(content) {
|
|
44
|
+
if (!content.startsWith("---"))
|
|
45
|
+
return { frontmatter: {}, body: content };
|
|
46
|
+
const end = content.indexOf("\n---", 4);
|
|
47
|
+
if (end === -1)
|
|
48
|
+
return { frontmatter: {}, body: content };
|
|
49
|
+
const fmRaw = content.slice(3, end).trim();
|
|
50
|
+
const body = content.slice(end + 4).trimStart();
|
|
51
|
+
const frontmatter = js_yaml_1.default.load(fmRaw) ?? {};
|
|
52
|
+
return { frontmatter, body };
|
|
53
|
+
}
|
|
54
|
+
function renderFrontmatter(frontmatter) {
|
|
55
|
+
if (Object.keys(frontmatter).length === 0)
|
|
56
|
+
return "";
|
|
57
|
+
return `---\n${js_yaml_1.default.dump(frontmatter)}---\n`;
|
|
58
|
+
}
|
|
59
|
+
function resolveScriptBlock(frontmatter, argsPlaceholder) {
|
|
60
|
+
const run = frontmatter.run;
|
|
61
|
+
const runAction = typeof run?.action === "string" ? run.action.trim() : "";
|
|
62
|
+
const runMode = typeof run?.mode === "string" ? run.mode.trim() : "";
|
|
63
|
+
if (runAction) {
|
|
64
|
+
const modeSuffix = runMode ? ` (${runMode})` : "";
|
|
65
|
+
return `- Internal action: ${runAction}${modeSuffix}`;
|
|
66
|
+
}
|
|
67
|
+
const runCommand = typeof run?.command === "string" ? run.command.replace("{ARGS}", argsPlaceholder) : "";
|
|
68
|
+
if (runCommand) {
|
|
69
|
+
return `- Command: ${runCommand}`;
|
|
70
|
+
}
|
|
71
|
+
const scripts = frontmatter.scripts;
|
|
72
|
+
const sh = typeof scripts?.sh === "string" ? scripts.sh.replace("{ARGS}", argsPlaceholder) : "";
|
|
73
|
+
const ps = typeof scripts?.ps === "string" ? scripts.ps.replace("{ARGS}", argsPlaceholder) : "";
|
|
74
|
+
return [`- Bash: ${sh}`, `- PowerShell: ${ps}`].filter((line) => line.length > 8).join("\n");
|
|
75
|
+
}
|
|
76
|
+
function toTomlPrompt(body, frontmatter, argsPlaceholder) {
|
|
77
|
+
const description = String(frontmatter.description ?? "Prodo command");
|
|
78
|
+
const scriptsBlock = resolveScriptBlock(frontmatter, argsPlaceholder);
|
|
79
|
+
const promptBody = body.replaceAll("$ARGUMENTS", argsPlaceholder);
|
|
80
|
+
return `description = "${description.replace(/"/g, '\\"')}"
|
|
81
|
+
|
|
82
|
+
prompt = """
|
|
83
|
+
${promptBody}
|
|
84
|
+
|
|
85
|
+
Script options:
|
|
86
|
+
${scriptsBlock}
|
|
87
|
+
"""`;
|
|
88
|
+
}
|
|
89
|
+
function toSkill(name, body, frontmatter) {
|
|
90
|
+
const description = String(frontmatter.description ?? "Prodo workflow command");
|
|
91
|
+
return `---
|
|
92
|
+
name: ${name}
|
|
93
|
+
description: ${description}
|
|
94
|
+
compatibility: Requires Prodo project scaffold (.prodo)
|
|
95
|
+
metadata:
|
|
96
|
+
author: prodo
|
|
97
|
+
source: .prodo/commands/${name}.md
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
${body}`;
|
|
101
|
+
}
|
|
102
|
+
function resolveAi(ai) {
|
|
103
|
+
if (!ai)
|
|
104
|
+
return undefined;
|
|
105
|
+
const normalized = exports.AI_ALIASES[ai.trim().toLowerCase()];
|
|
106
|
+
if (!normalized) {
|
|
107
|
+
throw new errors_1.UserError("Unsupported --ai value. Use: codex | gemini-cli | claude-cli");
|
|
108
|
+
}
|
|
109
|
+
return normalized;
|
|
110
|
+
}
|
|
111
|
+
async function loadCommandTemplateNames(commandTemplatesDir) {
|
|
112
|
+
if (!(await (0, utils_1.fileExists)(commandTemplatesDir))) {
|
|
113
|
+
throw new errors_1.UserError(`Missing command templates directory: ${commandTemplatesDir}`);
|
|
114
|
+
}
|
|
115
|
+
const entries = await promises_1.default.readdir(commandTemplatesDir, { withFileTypes: true });
|
|
116
|
+
return entries
|
|
117
|
+
.filter((entry) => entry.isFile())
|
|
118
|
+
.map((entry) => entry.name)
|
|
119
|
+
.filter((name) => name.endsWith(".md") && name.startsWith("prodo-"))
|
|
120
|
+
.map((name) => name.replace(/\.md$/, ""))
|
|
121
|
+
.sort();
|
|
122
|
+
}
|
|
123
|
+
async function installAgentCommands(projectRoot, ai) {
|
|
124
|
+
const cfg = AGENT_CONFIG[ai];
|
|
125
|
+
const target = node_path_1.default.join(projectRoot, cfg.baseDir);
|
|
126
|
+
const commandTemplatesDir = node_path_1.default.join(projectRoot, ".prodo", "commands");
|
|
127
|
+
const commandNames = await loadCommandTemplateNames(commandTemplatesDir);
|
|
128
|
+
await (0, utils_1.ensureDir)(target);
|
|
129
|
+
const written = [];
|
|
130
|
+
for (const commandName of commandNames) {
|
|
131
|
+
const templatePath = node_path_1.default.join(commandTemplatesDir, `${commandName}.md`);
|
|
132
|
+
if (!(await (0, utils_1.fileExists)(templatePath))) {
|
|
133
|
+
throw new errors_1.UserError(`Missing command template: ${templatePath}`);
|
|
134
|
+
}
|
|
135
|
+
const raw = await promises_1.default.readFile(templatePath, "utf8");
|
|
136
|
+
const parsed = parseFrontmatter(raw);
|
|
137
|
+
if (cfg.format === "skill") {
|
|
138
|
+
const skillDir = node_path_1.default.join(target, commandName);
|
|
139
|
+
await (0, utils_1.ensureDir)(skillDir);
|
|
140
|
+
const outPath = node_path_1.default.join(skillDir, "SKILL.md");
|
|
141
|
+
const content = toSkill(commandName, parsed.body.replaceAll("$ARGUMENTS", cfg.argsPlaceholder), parsed.frontmatter);
|
|
142
|
+
await promises_1.default.writeFile(outPath, content, "utf8");
|
|
143
|
+
written.push(outPath);
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
if (cfg.format === "toml") {
|
|
147
|
+
const outPath = node_path_1.default.join(target, `${commandName}${cfg.extension}`);
|
|
148
|
+
await promises_1.default.writeFile(outPath, toTomlPrompt(parsed.body, parsed.frontmatter, cfg.argsPlaceholder), "utf8");
|
|
149
|
+
written.push(outPath);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
const outPath = node_path_1.default.join(target, `${commandName}${cfg.extension}`);
|
|
153
|
+
const replacedBody = parsed.body.replaceAll("$ARGUMENTS", cfg.argsPlaceholder);
|
|
154
|
+
await promises_1.default.writeFile(outPath, `${renderFrontmatter(parsed.frontmatter)}\n${replacedBody}`, "utf8");
|
|
155
|
+
written.push(outPath);
|
|
156
|
+
}
|
|
157
|
+
return written;
|
|
158
|
+
}
|
package/dist/agents.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const AGENT_IDS: readonly ["codex", "gemini-cli", "claude-cli"];
|
|
2
|
+
export type AgentId = (typeof AGENT_IDS)[number];
|
|
3
|
+
export declare function isSupportedAgent(agent?: string): agent is AgentId;
|
|
4
|
+
export declare function resolveAgent(agent?: string): AgentId | undefined;
|
|
5
|
+
export type CommandSetItem = {
|
|
6
|
+
command: string;
|
|
7
|
+
purpose: string;
|
|
8
|
+
};
|
|
9
|
+
export type AgentCommandSet = {
|
|
10
|
+
agent: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
recommended_sequence?: CommandSetItem[];
|
|
13
|
+
artifact_shortcuts?: Record<string, string>;
|
|
14
|
+
};
|
|
15
|
+
export declare function loadAgentCommandSet(_cwd: string, agent: AgentId): Promise<AgentCommandSet>;
|
package/dist/agents.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AGENT_IDS = void 0;
|
|
4
|
+
exports.isSupportedAgent = isSupportedAgent;
|
|
5
|
+
exports.resolveAgent = resolveAgent;
|
|
6
|
+
exports.loadAgentCommandSet = loadAgentCommandSet;
|
|
7
|
+
const errors_1 = require("./errors");
|
|
8
|
+
exports.AGENT_IDS = ["codex", "gemini-cli", "claude-cli"];
|
|
9
|
+
function isSupportedAgent(agent) {
|
|
10
|
+
if (!agent)
|
|
11
|
+
return false;
|
|
12
|
+
return exports.AGENT_IDS.includes(agent);
|
|
13
|
+
}
|
|
14
|
+
function resolveAgent(agent) {
|
|
15
|
+
if (!agent)
|
|
16
|
+
return undefined;
|
|
17
|
+
if (!isSupportedAgent(agent)) {
|
|
18
|
+
throw new errors_1.UserError(`Unsupported agent: ${agent}. Supported: ${exports.AGENT_IDS.join(", ")}`);
|
|
19
|
+
}
|
|
20
|
+
return agent;
|
|
21
|
+
}
|
|
22
|
+
async function loadAgentCommandSet(_cwd, agent) {
|
|
23
|
+
const prefix = `prodo-${agent}`;
|
|
24
|
+
return {
|
|
25
|
+
agent,
|
|
26
|
+
description: "Agent-specific command set for Prodo artifact pipeline.",
|
|
27
|
+
recommended_sequence: [
|
|
28
|
+
{ command: "prodo init . --ai <agent> --lang <en|tr>", purpose: "Initialize Prodo scaffold and agent commands." },
|
|
29
|
+
{ command: `${prefix} normalize`, purpose: "Normalize start brief into normalized brief JSON." },
|
|
30
|
+
{ command: `${prefix} prd`, purpose: "Generate PRD artifact." },
|
|
31
|
+
{ command: `${prefix} workflow`, purpose: "Generate workflow artifact." },
|
|
32
|
+
{ command: `${prefix} wireframe`, purpose: "Generate wireframe artifact." },
|
|
33
|
+
{ command: `${prefix} stories`, purpose: "Generate stories artifact." },
|
|
34
|
+
{ command: `${prefix} techspec`, purpose: "Generate techspec artifact." },
|
|
35
|
+
{ command: `${prefix} validate`, purpose: "Run validation report." }
|
|
36
|
+
],
|
|
37
|
+
artifact_shortcuts: {
|
|
38
|
+
normalize: `${prefix} normalize`,
|
|
39
|
+
prd: `${prefix} prd`,
|
|
40
|
+
workflow: `${prefix} workflow`,
|
|
41
|
+
wireframe: `${prefix} wireframe`,
|
|
42
|
+
stories: `${prefix} stories`,
|
|
43
|
+
techspec: `${prefix} techspec`,
|
|
44
|
+
validate: `${prefix} validate`
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ArtifactType, ContractCoverage } from "./types";
|
|
2
|
+
export type ArtifactDefinition = {
|
|
3
|
+
name: ArtifactType;
|
|
4
|
+
output_dir: string;
|
|
5
|
+
required_headings: string[];
|
|
6
|
+
upstream: ArtifactType[];
|
|
7
|
+
required_contracts: Array<keyof ContractCoverage>;
|
|
8
|
+
};
|
|
9
|
+
export declare function listArtifactDefinitions(cwd: string): Promise<ArtifactDefinition[]>;
|
|
10
|
+
export declare function listArtifactTypes(cwd: string): Promise<ArtifactType[]>;
|
|
11
|
+
export declare function getArtifactDefinition(cwd: string, artifactType: string): Promise<ArtifactDefinition>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.listArtifactDefinitions = listArtifactDefinitions;
|
|
4
|
+
exports.listArtifactTypes = listArtifactTypes;
|
|
5
|
+
exports.getArtifactDefinition = getArtifactDefinition;
|
|
6
|
+
const constants_1 = require("./constants");
|
|
7
|
+
const project_config_1 = require("./project-config");
|
|
8
|
+
const types_1 = require("./types");
|
|
9
|
+
function normalizeName(name) {
|
|
10
|
+
return name.trim().toLowerCase().replace(/[^a-z0-9_-]/g, "-");
|
|
11
|
+
}
|
|
12
|
+
function toDefinition(partial) {
|
|
13
|
+
const name = normalizeName(partial.name);
|
|
14
|
+
const outputDir = partial.output_dir?.trim() || (0, constants_1.defaultOutputDir)(name);
|
|
15
|
+
const requiredHeadings = partial.required_headings?.length ? partial.required_headings : (0, constants_1.defaultRequiredHeadings)(name);
|
|
16
|
+
const upstream = (partial.upstream?.length ? partial.upstream : (0, constants_1.defaultUpstreamByArtifact)(name)).map(normalizeName);
|
|
17
|
+
const requiredContracts = partial.required_contracts?.length
|
|
18
|
+
? partial.required_contracts
|
|
19
|
+
: (0, constants_1.defaultRequiredContractsByArtifact)(name);
|
|
20
|
+
return {
|
|
21
|
+
name,
|
|
22
|
+
output_dir: outputDir,
|
|
23
|
+
required_headings: requiredHeadings,
|
|
24
|
+
upstream,
|
|
25
|
+
required_contracts: requiredContracts
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
async function listArtifactDefinitions(cwd) {
|
|
29
|
+
const config = await (0, project_config_1.readProjectConfig)(cwd);
|
|
30
|
+
const base = types_1.ARTIFACT_TYPES.map((name) => toDefinition({ name }));
|
|
31
|
+
const byName = new Map(base.map((item) => [item.name, item]));
|
|
32
|
+
for (const extra of config.artifacts ?? []) {
|
|
33
|
+
const merged = toDefinition(extra);
|
|
34
|
+
byName.set(merged.name, merged);
|
|
35
|
+
}
|
|
36
|
+
return Array.from(byName.values());
|
|
37
|
+
}
|
|
38
|
+
async function listArtifactTypes(cwd) {
|
|
39
|
+
const defs = await listArtifactDefinitions(cwd);
|
|
40
|
+
return defs.map((item) => item.name);
|
|
41
|
+
}
|
|
42
|
+
async function getArtifactDefinition(cwd, artifactType) {
|
|
43
|
+
const normalized = normalizeName(artifactType);
|
|
44
|
+
const defs = await listArtifactDefinitions(cwd);
|
|
45
|
+
const found = defs.find((item) => item.name === normalized);
|
|
46
|
+
if (found)
|
|
47
|
+
return found;
|
|
48
|
+
return toDefinition({ name: normalized });
|
|
49
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ArtifactType } from "./types";
|
|
2
|
+
export type GenerateOptions = {
|
|
3
|
+
artifactType: ArtifactType;
|
|
4
|
+
cwd: string;
|
|
5
|
+
normalizedBriefOverride?: string;
|
|
6
|
+
outPath?: string;
|
|
7
|
+
agent?: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function generateArtifact(options: GenerateOptions): Promise<string>;
|