@shahmarasy/prodo 0.1.6 → 0.1.7
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.
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export declare const AI_ALIASES: Record<string, "codex" | "gemini-cli" | "claude-cli">;
|
|
2
2
|
export type SupportedAi = "codex" | "gemini-cli" | "claude-cli";
|
|
3
3
|
export declare function resolveAi(ai?: string): SupportedAi | undefined;
|
|
4
|
-
export declare function installAgentCommands(projectRoot: string, ai: SupportedAi): Promise<string[]>;
|
|
4
|
+
export declare function installAgentCommands(projectRoot: string, ai: SupportedAi, lang?: string): Promise<string[]>;
|
|
@@ -110,13 +110,119 @@ async function loadCommandTemplateNames(commandTemplatesDir) {
|
|
|
110
110
|
.map((name) => name.replace(/\.md$/, ""))
|
|
111
111
|
.sort();
|
|
112
112
|
}
|
|
113
|
-
|
|
113
|
+
function generateClaudeMd(projectRoot, lang) {
|
|
114
|
+
const projectName = node_path_1.default.basename(projectRoot) || "Product";
|
|
115
|
+
return `# Prodo — Product Artifact Workspace
|
|
116
|
+
|
|
117
|
+
This project uses **Prodo** to generate product documentation from a brief.
|
|
118
|
+
|
|
119
|
+
## Project Structure
|
|
120
|
+
|
|
121
|
+
- \`brief.md\` — Product brief (INPUT — read-only during generation)
|
|
122
|
+
- \`product-docs/\` — Generated artifacts (OUTPUT)
|
|
123
|
+
- \`.prodo/\` — Internal scaffold (templates, schemas, prompts, state)
|
|
124
|
+
|
|
125
|
+
## Workflow
|
|
126
|
+
|
|
127
|
+
Run commands in this sequence:
|
|
128
|
+
|
|
129
|
+
1. \`/prodo-normalize\` — Parse brief into structured JSON
|
|
130
|
+
2. \`/prodo-prd\` — Generate Product Requirements Document
|
|
131
|
+
3. \`/prodo-workflow\` — Generate workflow diagrams (Markdown + Mermaid)
|
|
132
|
+
4. \`/prodo-wireframe\` — Generate wireframes (Markdown + HTML)
|
|
133
|
+
5. \`/prodo-stories\` — Generate user stories with Gherkin scenarios
|
|
134
|
+
6. \`/prodo-techspec\` — Generate technical specification
|
|
135
|
+
7. \`/prodo-validate\` — Cross-artifact validation (7 gates)
|
|
136
|
+
|
|
137
|
+
## Rules
|
|
138
|
+
|
|
139
|
+
- **Never modify \`brief.md\` during command execution** — it is read-only input
|
|
140
|
+
- **All artifacts must include contract tags** like \`[G1]\`, \`[F2]\`, \`[C1]\` for traceability
|
|
141
|
+
- **Output language is \`${lang}\`** — do not mix languages in generated content
|
|
142
|
+
- **Follow templates strictly** — each artifact has a template in \`.prodo/templates/\`
|
|
143
|
+
- **Validate after generation** — run \`/prodo-validate\` to check consistency
|
|
144
|
+
`;
|
|
145
|
+
}
|
|
146
|
+
function generateArtifactRules(lang) {
|
|
147
|
+
return `# Artifact Format Rules
|
|
148
|
+
|
|
149
|
+
## Contract Tags
|
|
150
|
+
Every artifact must reference brief requirements using tags:
|
|
151
|
+
- \`[G1]\`, \`[G2]\` — Goal references
|
|
152
|
+
- \`[F1]\`, \`[F2]\` — Feature references
|
|
153
|
+
- \`[C1]\`, \`[C2]\` — Constraint references
|
|
154
|
+
|
|
155
|
+
Tags must appear inline where the requirement is addressed.
|
|
156
|
+
|
|
157
|
+
## Frontmatter
|
|
158
|
+
Every generated artifact must include YAML frontmatter:
|
|
159
|
+
\`\`\`yaml
|
|
160
|
+
artifact_type: prd | workflow | wireframe | stories | techspec
|
|
161
|
+
version: <timestamp>
|
|
162
|
+
source_brief: <path to normalized-brief.json>
|
|
163
|
+
generated_at: <ISO timestamp>
|
|
164
|
+
status: draft
|
|
165
|
+
contract_coverage:
|
|
166
|
+
goals: [G1, G2]
|
|
167
|
+
core_features: [F1, F2]
|
|
168
|
+
constraints: [C1]
|
|
169
|
+
\`\`\`
|
|
170
|
+
|
|
171
|
+
## Paired Outputs
|
|
172
|
+
- **Workflow**: Produces \`.md\` (narrative) + \`.mmd\` (Mermaid diagram)
|
|
173
|
+
- **Wireframe**: Produces \`.md\` (description) + \`.html\` (low-fidelity prototype)
|
|
174
|
+
|
|
175
|
+
## Language
|
|
176
|
+
Output language: **${lang}**. Do not mix languages. Required heading names stay in English.
|
|
177
|
+
`;
|
|
178
|
+
}
|
|
179
|
+
function generateBriefRules() {
|
|
180
|
+
return `# Brief Writing Rules
|
|
181
|
+
|
|
182
|
+
## Structure
|
|
183
|
+
The brief (\`brief.md\`) should contain these sections:
|
|
184
|
+
|
|
185
|
+
- **Product Name** — Clear, specific product name
|
|
186
|
+
- **Problem** — Core problem the product solves (be specific)
|
|
187
|
+
- **Audience** — Target users (list distinct personas)
|
|
188
|
+
- **Goals** — Measurable objectives (not vague aspirations)
|
|
189
|
+
- **Core Features** — One capability per bullet point
|
|
190
|
+
- **Constraints** — Technical, business, or regulatory limits
|
|
191
|
+
- **Assumptions** — Open questions or working assumptions
|
|
192
|
+
|
|
193
|
+
## Tips
|
|
194
|
+
- Be specific: "Reduce checkout abandonment by 30%" not "Improve UX"
|
|
195
|
+
- Use consistent terminology throughout
|
|
196
|
+
- Each feature should be distinct and independently describable
|
|
197
|
+
- Constraints should be concrete: "Node.js 20+", "GDPR compliant"
|
|
198
|
+
`;
|
|
199
|
+
}
|
|
200
|
+
async function installAgentCommands(projectRoot, ai, lang) {
|
|
114
201
|
const cfg = AGENT_CONFIG[ai];
|
|
115
202
|
const target = node_path_1.default.join(projectRoot, cfg.baseDir);
|
|
116
203
|
const commandTemplatesDir = node_path_1.default.join(projectRoot, ".prodo", "commands");
|
|
117
204
|
const commandNames = await loadCommandTemplateNames(commandTemplatesDir);
|
|
118
205
|
await (0, utils_1.ensureDir)(target);
|
|
119
206
|
const written = [];
|
|
207
|
+
if (ai === "claude-cli") {
|
|
208
|
+
const claudeMdPath = node_path_1.default.join(projectRoot, "CLAUDE.md");
|
|
209
|
+
if (!(await (0, utils_1.fileExists)(claudeMdPath))) {
|
|
210
|
+
await promises_1.default.writeFile(claudeMdPath, generateClaudeMd(projectRoot, lang ?? "en"), "utf8");
|
|
211
|
+
written.push(claudeMdPath);
|
|
212
|
+
}
|
|
213
|
+
const rulesDir = node_path_1.default.join(projectRoot, ".claude", "rules");
|
|
214
|
+
await (0, utils_1.ensureDir)(rulesDir);
|
|
215
|
+
const artifactRulesPath = node_path_1.default.join(rulesDir, "artifact-format.md");
|
|
216
|
+
if (!(await (0, utils_1.fileExists)(artifactRulesPath))) {
|
|
217
|
+
await promises_1.default.writeFile(artifactRulesPath, generateArtifactRules(lang ?? "en"), "utf8");
|
|
218
|
+
written.push(artifactRulesPath);
|
|
219
|
+
}
|
|
220
|
+
const briefRulesPath = node_path_1.default.join(rulesDir, "brief-rules.md");
|
|
221
|
+
if (!(await (0, utils_1.fileExists)(briefRulesPath))) {
|
|
222
|
+
await promises_1.default.writeFile(briefRulesPath, generateBriefRules(), "utf8");
|
|
223
|
+
written.push(briefRulesPath);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
120
226
|
for (const commandName of commandNames) {
|
|
121
227
|
const templatePath = node_path_1.default.join(commandTemplatesDir, `${commandName}.md`);
|
|
122
228
|
if (!(await (0, utils_1.fileExists)(templatePath))) {
|
package/dist/cli/init.js
CHANGED
|
@@ -312,7 +312,7 @@ async function runInit(cwd, options) {
|
|
|
312
312
|
await rollbackFiles(backup);
|
|
313
313
|
throw error;
|
|
314
314
|
}
|
|
315
|
-
const installedAgentFiles = options?.ai ? await (0, agent_command_installer_1.installAgentCommands)(cwd, options.ai) : [];
|
|
315
|
+
const installedAgentFiles = options?.ai ? await (0, agent_command_installer_1.installAgentCommands)(cwd, options.ai, options?.lang) : [];
|
|
316
316
|
const manifest = {
|
|
317
317
|
schema_version: "1.0",
|
|
318
318
|
generated_at: new Date().toISOString(),
|
package/package.json
CHANGED
|
@@ -122,7 +122,97 @@ async function loadCommandTemplateNames(commandTemplatesDir: string): Promise<st
|
|
|
122
122
|
.sort();
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
|
|
125
|
+
function generateClaudeMd(projectRoot: string, lang: string): string {
|
|
126
|
+
const projectName = path.basename(projectRoot) || "Product";
|
|
127
|
+
return `# Prodo — Product Artifact Workspace
|
|
128
|
+
|
|
129
|
+
This project uses **Prodo** to generate product documentation from a brief.
|
|
130
|
+
|
|
131
|
+
## Project Structure
|
|
132
|
+
|
|
133
|
+
- \`brief.md\` — Product brief (INPUT — read-only during generation)
|
|
134
|
+
- \`product-docs/\` — Generated artifacts (OUTPUT)
|
|
135
|
+
- \`.prodo/\` — Internal scaffold (templates, schemas, prompts, state)
|
|
136
|
+
|
|
137
|
+
## Workflow
|
|
138
|
+
|
|
139
|
+
Run commands in this sequence:
|
|
140
|
+
|
|
141
|
+
1. \`/prodo-normalize\` — Parse brief into structured JSON
|
|
142
|
+
2. \`/prodo-prd\` — Generate Product Requirements Document
|
|
143
|
+
3. \`/prodo-workflow\` — Generate workflow diagrams (Markdown + Mermaid)
|
|
144
|
+
4. \`/prodo-wireframe\` — Generate wireframes (Markdown + HTML)
|
|
145
|
+
5. \`/prodo-stories\` — Generate user stories with Gherkin scenarios
|
|
146
|
+
6. \`/prodo-techspec\` — Generate technical specification
|
|
147
|
+
7. \`/prodo-validate\` — Cross-artifact validation (7 gates)
|
|
148
|
+
|
|
149
|
+
## Rules
|
|
150
|
+
|
|
151
|
+
- **Never modify \`brief.md\` during command execution** — it is read-only input
|
|
152
|
+
- **All artifacts must include contract tags** like \`[G1]\`, \`[F2]\`, \`[C1]\` for traceability
|
|
153
|
+
- **Output language is \`${lang}\`** — do not mix languages in generated content
|
|
154
|
+
- **Follow templates strictly** — each artifact has a template in \`.prodo/templates/\`
|
|
155
|
+
- **Validate after generation** — run \`/prodo-validate\` to check consistency
|
|
156
|
+
`;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function generateArtifactRules(lang: string): string {
|
|
160
|
+
return `# Artifact Format Rules
|
|
161
|
+
|
|
162
|
+
## Contract Tags
|
|
163
|
+
Every artifact must reference brief requirements using tags:
|
|
164
|
+
- \`[G1]\`, \`[G2]\` — Goal references
|
|
165
|
+
- \`[F1]\`, \`[F2]\` — Feature references
|
|
166
|
+
- \`[C1]\`, \`[C2]\` — Constraint references
|
|
167
|
+
|
|
168
|
+
Tags must appear inline where the requirement is addressed.
|
|
169
|
+
|
|
170
|
+
## Frontmatter
|
|
171
|
+
Every generated artifact must include YAML frontmatter:
|
|
172
|
+
\`\`\`yaml
|
|
173
|
+
artifact_type: prd | workflow | wireframe | stories | techspec
|
|
174
|
+
version: <timestamp>
|
|
175
|
+
source_brief: <path to normalized-brief.json>
|
|
176
|
+
generated_at: <ISO timestamp>
|
|
177
|
+
status: draft
|
|
178
|
+
contract_coverage:
|
|
179
|
+
goals: [G1, G2]
|
|
180
|
+
core_features: [F1, F2]
|
|
181
|
+
constraints: [C1]
|
|
182
|
+
\`\`\`
|
|
183
|
+
|
|
184
|
+
## Paired Outputs
|
|
185
|
+
- **Workflow**: Produces \`.md\` (narrative) + \`.mmd\` (Mermaid diagram)
|
|
186
|
+
- **Wireframe**: Produces \`.md\` (description) + \`.html\` (low-fidelity prototype)
|
|
187
|
+
|
|
188
|
+
## Language
|
|
189
|
+
Output language: **${lang}**. Do not mix languages. Required heading names stay in English.
|
|
190
|
+
`;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function generateBriefRules(): string {
|
|
194
|
+
return `# Brief Writing Rules
|
|
195
|
+
|
|
196
|
+
## Structure
|
|
197
|
+
The brief (\`brief.md\`) should contain these sections:
|
|
198
|
+
|
|
199
|
+
- **Product Name** — Clear, specific product name
|
|
200
|
+
- **Problem** — Core problem the product solves (be specific)
|
|
201
|
+
- **Audience** — Target users (list distinct personas)
|
|
202
|
+
- **Goals** — Measurable objectives (not vague aspirations)
|
|
203
|
+
- **Core Features** — One capability per bullet point
|
|
204
|
+
- **Constraints** — Technical, business, or regulatory limits
|
|
205
|
+
- **Assumptions** — Open questions or working assumptions
|
|
206
|
+
|
|
207
|
+
## Tips
|
|
208
|
+
- Be specific: "Reduce checkout abandonment by 30%" not "Improve UX"
|
|
209
|
+
- Use consistent terminology throughout
|
|
210
|
+
- Each feature should be distinct and independently describable
|
|
211
|
+
- Constraints should be concrete: "Node.js 20+", "GDPR compliant"
|
|
212
|
+
`;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export async function installAgentCommands(projectRoot: string, ai: SupportedAi, lang?: string): Promise<string[]> {
|
|
126
216
|
const cfg = AGENT_CONFIG[ai];
|
|
127
217
|
const target = path.join(projectRoot, cfg.baseDir);
|
|
128
218
|
const commandTemplatesDir = path.join(projectRoot, ".prodo", "commands");
|
|
@@ -130,6 +220,30 @@ export async function installAgentCommands(projectRoot: string, ai: SupportedAi)
|
|
|
130
220
|
await ensureDir(target);
|
|
131
221
|
|
|
132
222
|
const written: string[] = [];
|
|
223
|
+
|
|
224
|
+
if (ai === "claude-cli") {
|
|
225
|
+
const claudeMdPath = path.join(projectRoot, "CLAUDE.md");
|
|
226
|
+
if (!(await fileExists(claudeMdPath))) {
|
|
227
|
+
await fs.writeFile(claudeMdPath, generateClaudeMd(projectRoot, lang ?? "en"), "utf8");
|
|
228
|
+
written.push(claudeMdPath);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const rulesDir = path.join(projectRoot, ".claude", "rules");
|
|
232
|
+
await ensureDir(rulesDir);
|
|
233
|
+
|
|
234
|
+
const artifactRulesPath = path.join(rulesDir, "artifact-format.md");
|
|
235
|
+
if (!(await fileExists(artifactRulesPath))) {
|
|
236
|
+
await fs.writeFile(artifactRulesPath, generateArtifactRules(lang ?? "en"), "utf8");
|
|
237
|
+
written.push(artifactRulesPath);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const briefRulesPath = path.join(rulesDir, "brief-rules.md");
|
|
241
|
+
if (!(await fileExists(briefRulesPath))) {
|
|
242
|
+
await fs.writeFile(briefRulesPath, generateBriefRules(), "utf8");
|
|
243
|
+
written.push(briefRulesPath);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
133
247
|
for (const commandName of commandNames) {
|
|
134
248
|
const templatePath = path.join(commandTemplatesDir, `${commandName}.md`);
|
|
135
249
|
if (!(await fileExists(templatePath))) {
|
package/src/cli/init.ts
CHANGED
|
@@ -376,7 +376,7 @@ export async function runInit(
|
|
|
376
376
|
throw error;
|
|
377
377
|
}
|
|
378
378
|
|
|
379
|
-
const installedAgentFiles = options?.ai ? await installAgentCommands(cwd, options.ai) : [];
|
|
379
|
+
const installedAgentFiles = options?.ai ? await installAgentCommands(cwd, options.ai, options?.lang) : [];
|
|
380
380
|
const manifest: ScaffoldManifest = {
|
|
381
381
|
schema_version: "1.0",
|
|
382
382
|
generated_at: new Date().toISOString(),
|