@shahmarasy/prodo 0.1.1 → 0.1.3
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/dist/agent-command-installer.js +5 -0
- package/dist/artifacts.js +45 -5
- package/dist/cli.js +0 -1
- package/dist/init-tui.d.ts +0 -1
- package/dist/init-tui.js +2 -14
- package/dist/providers/mock-provider.js +8 -1
- package/dist/templates.js +10 -0
- package/package.json +1 -1
- package/src/agent-command-installer.ts +5 -0
- package/src/artifacts.ts +47 -4
- package/src/cli.ts +0 -1
- package/src/init-tui.ts +2 -16
- package/src/providers/mock-provider.ts +12 -1
- package/src/templates.ts +11 -0
- package/templates/commands/prodo-normalize.md +11 -3
- package/templates/commands/prodo-prd.md +3 -0
- package/templates/commands/prodo-stories.md +3 -0
- package/templates/commands/prodo-techspec.md +3 -0
- package/templates/commands/prodo-validate.md +3 -0
- package/templates/commands/prodo-wireframe.md +3 -0
- package/templates/commands/prodo-workflow.md +3 -0
|
@@ -68,6 +68,11 @@ function toTomlPrompt(body, frontmatter, argsPlaceholder) {
|
|
|
68
68
|
return `description = "${description.replace(/"/g, '\\"')}"
|
|
69
69
|
|
|
70
70
|
prompt = """
|
|
71
|
+
Important execution rule:
|
|
72
|
+
- This is an agent slash command, not a shell command.
|
|
73
|
+
- Do NOT run \`prodo-normalize\`, \`prodo-prd\`, or \`prodo ...\` in shell.
|
|
74
|
+
- Execute the workflow directly using workspace files.
|
|
75
|
+
|
|
71
76
|
${promptBody}
|
|
72
77
|
"""`;
|
|
73
78
|
}
|
package/dist/artifacts.js
CHANGED
|
@@ -53,18 +53,53 @@ async function loadArtifactDoc(filePath) {
|
|
|
53
53
|
body: parsed.content
|
|
54
54
|
};
|
|
55
55
|
}
|
|
56
|
+
function languageProbe(body) {
|
|
57
|
+
const stripped = body
|
|
58
|
+
.replace(/```[\s\S]*?```/g, " ")
|
|
59
|
+
.replace(/^\s*#{1,6}\s+.*$/gm, " ")
|
|
60
|
+
.replace(/<[^>]+>/g, " ")
|
|
61
|
+
.replace(/\|/g, " ")
|
|
62
|
+
.replace(/\s+/g, " ")
|
|
63
|
+
.trim()
|
|
64
|
+
.toLowerCase();
|
|
65
|
+
return ` ${stripped} `;
|
|
66
|
+
}
|
|
56
67
|
function hasEnglishLeak(body) {
|
|
57
|
-
const englishMarkers = [" the ", " and ", " with ", " user ", " should ", " must ", " requirement ", " flow "];
|
|
58
|
-
const normalized =
|
|
68
|
+
const englishMarkers = [" the ", " and ", " with ", " user ", " should ", " must ", " requirement ", " flow ", " error ", " success "];
|
|
69
|
+
const normalized = languageProbe(body);
|
|
59
70
|
return englishMarkers.filter((m) => normalized.includes(m)).length >= 2;
|
|
60
71
|
}
|
|
72
|
+
function hasTurkishLeak(body) {
|
|
73
|
+
const turkishMarkers = [
|
|
74
|
+
" ve ",
|
|
75
|
+
" ile ",
|
|
76
|
+
" kullanici ",
|
|
77
|
+
" kullanıcı ",
|
|
78
|
+
" akis ",
|
|
79
|
+
" akış ",
|
|
80
|
+
" hata ",
|
|
81
|
+
" basari ",
|
|
82
|
+
" başarı ",
|
|
83
|
+
" ekran ",
|
|
84
|
+
" islem ",
|
|
85
|
+
" işlem ",
|
|
86
|
+
" gerekli "
|
|
87
|
+
];
|
|
88
|
+
const normalized = languageProbe(body);
|
|
89
|
+
return turkishMarkers.filter((m) => normalized.includes(m)).length >= 2;
|
|
90
|
+
}
|
|
61
91
|
function enforceLanguage(body, lang, artifactType) {
|
|
62
92
|
const normalized = (lang || "en").toLowerCase();
|
|
63
|
-
if (
|
|
64
|
-
|
|
65
|
-
|
|
93
|
+
if (normalized.startsWith("tr")) {
|
|
94
|
+
if (!hasEnglishLeak(body))
|
|
95
|
+
return;
|
|
66
96
|
throw new errors_1.UserError(`Language enforcement failed for ${artifactType}: output contains English fragments while language is Turkish.`);
|
|
67
97
|
}
|
|
98
|
+
if (normalized.startsWith("en")) {
|
|
99
|
+
if (!hasTurkishLeak(body))
|
|
100
|
+
return;
|
|
101
|
+
throw new errors_1.UserError(`Language enforcement failed for ${artifactType}: output contains Turkish fragments while language is English.`);
|
|
102
|
+
}
|
|
68
103
|
}
|
|
69
104
|
function toSlug(value) {
|
|
70
105
|
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "screen";
|
|
@@ -387,6 +422,7 @@ async function writeWireframeScreens(targetDir, baseName, normalized, coverage,
|
|
|
387
422
|
return "[ LOGO ]";
|
|
388
423
|
return token;
|
|
389
424
|
});
|
|
425
|
+
enforceLanguage(html, lang, "wireframe");
|
|
390
426
|
await promises_1.default.writeFile(htmlPath, html, "utf8");
|
|
391
427
|
const defaultMap = {
|
|
392
428
|
purpose: [`- [${screen.id}] ${screen.text}`],
|
|
@@ -437,6 +473,7 @@ async function writeWireframeScreens(targetDir, baseName, normalized, coverage,
|
|
|
437
473
|
mdLines.push("");
|
|
438
474
|
}
|
|
439
475
|
const mdBody = mdLines.join("\n").trim();
|
|
476
|
+
enforceLanguage(mdBody, lang, "wireframe");
|
|
440
477
|
await promises_1.default.writeFile(mdPath, `${mdBody}\n`, "utf8");
|
|
441
478
|
if (!primaryMdPath)
|
|
442
479
|
primaryMdPath = mdPath;
|
|
@@ -519,6 +556,9 @@ async function generateArtifact(options) {
|
|
|
519
556
|
workflowMermaidBody = renderWorkflowMermaidTemplate(companionTemplate.content, normalizedBrief, contractCoverage, settings.lang).trim();
|
|
520
557
|
}
|
|
521
558
|
enforceLanguage(generatedBody, settings.lang, artifactType);
|
|
559
|
+
if (artifactType === "workflow" && workflowMermaidBody) {
|
|
560
|
+
enforceLanguage(workflowMermaidBody, settings.lang, artifactType);
|
|
561
|
+
}
|
|
522
562
|
const uncovered = missingCoverage(def.required_contracts, normalizedBrief, contractCoverage);
|
|
523
563
|
if (uncovered.length > 0) {
|
|
524
564
|
const lines = uncovered
|
package/dist/cli.js
CHANGED
package/dist/init-tui.d.ts
CHANGED
package/dist/init-tui.js
CHANGED
|
@@ -117,18 +117,6 @@ async function gatherInitSelections(options) {
|
|
|
117
117
|
clack.cancel("Initialization cancelled.");
|
|
118
118
|
throw new errors_1.UserError("Initialization cancelled.");
|
|
119
119
|
}
|
|
120
|
-
const script = await clack.select({
|
|
121
|
-
message: "Select script type",
|
|
122
|
-
initialValue: fallbackScript,
|
|
123
|
-
options: [
|
|
124
|
-
{ value: "sh", label: "sh", hint: "Command profile (metadata)" },
|
|
125
|
-
{ value: "ps", label: "ps", hint: "Command profile (metadata)" }
|
|
126
|
-
]
|
|
127
|
-
});
|
|
128
|
-
if (clack.isCancel(script)) {
|
|
129
|
-
clack.cancel("Initialization cancelled.");
|
|
130
|
-
throw new errors_1.UserError("Initialization cancelled.");
|
|
131
|
-
}
|
|
132
120
|
const lang = await clack.select({
|
|
133
121
|
message: "Select language",
|
|
134
122
|
initialValue: defaultLang,
|
|
@@ -150,12 +138,12 @@ async function gatherInitSelections(options) {
|
|
|
150
138
|
selectedAi = detectedAi;
|
|
151
139
|
return {
|
|
152
140
|
ai: selectedAi,
|
|
153
|
-
script,
|
|
141
|
+
script: fallbackScript,
|
|
154
142
|
lang,
|
|
155
143
|
interactive: true
|
|
156
144
|
};
|
|
157
145
|
}
|
|
158
146
|
function finishInitInteractive(summary) {
|
|
159
147
|
const aiText = summary.ai ?? "none";
|
|
160
|
-
return loadClack().then((clack) => clack.outro(`Scaffold complete.\nAI: ${aiText}\
|
|
148
|
+
return loadClack().then((clack) => clack.outro(`Scaffold complete.\nAI: ${aiText}\nLanguage: ${summary.lang}\nSettings: ${summary.settingsPath}\nNext: edit brief.md`));
|
|
161
149
|
}
|
|
@@ -107,8 +107,15 @@ function buildArtifactBody(schemaHint, inputContext) {
|
|
|
107
107
|
const lang = typeof inputContext.outputLanguage === "string" ? inputContext.outputLanguage.toLowerCase() : "en";
|
|
108
108
|
const items = normalizeSectionItems(inputContext);
|
|
109
109
|
const coverage = coverageItems(schemaHint, inputContext);
|
|
110
|
+
const localizedItems = lang === "tr" ? items.map((_, index) => `Gereksinim maddesi ${index + 1}`) : items;
|
|
111
|
+
const localizedCoverage = lang === "tr"
|
|
112
|
+
? coverage.map((item, index) => ({
|
|
113
|
+
id: item.id,
|
|
114
|
+
text: `Kontrat kapsami ${index + 1}`
|
|
115
|
+
}))
|
|
116
|
+
: coverage;
|
|
110
117
|
const fallback = lang === "tr" ? "Detay daha sonra netlestirilecek." : "To be refined.";
|
|
111
|
-
const sections = schemaHint.requiredHeadings.map((heading) => headingBlock(heading,
|
|
118
|
+
const sections = schemaHint.requiredHeadings.map((heading) => headingBlock(heading, localizedItems, fallback, localizedCoverage));
|
|
112
119
|
const title = lang === "tr"
|
|
113
120
|
? `# ${productName} icin ${schemaHint.artifactType.toUpperCase()}`
|
|
114
121
|
: `# ${schemaHint.artifactType.toUpperCase()} for ${productName}`;
|
package/dist/templates.js
CHANGED
|
@@ -343,6 +343,12 @@ Rules:
|
|
|
343
343
|
- input files are read-only; never modify, summarize, or rewrite \`brief.md\` in-place
|
|
344
344
|
- write normalized output as a new JSON object only`;
|
|
345
345
|
function commandTemplate(command) {
|
|
346
|
+
const normalizeJsonGuard = command.cliSubcommand === "normalize"
|
|
347
|
+
? `
|
|
348
|
+
- Normalize output format check:
|
|
349
|
+
- \`.prodo/briefs/normalized-brief.json\` must be strict JSON object (no markdown fences).
|
|
350
|
+
- If invalid, rewrite file as pure JSON object only.`
|
|
351
|
+
: "";
|
|
346
352
|
return `---
|
|
347
353
|
description: ${command.description}
|
|
348
354
|
handoffs:
|
|
@@ -362,8 +368,11 @@ Execution policy:
|
|
|
362
368
|
- Execute-first, diagnose-second.
|
|
363
369
|
- Perform only minimal prerequisite checks before execution.
|
|
364
370
|
- Do not run shell commands or CLI commands from inside the agent.
|
|
371
|
+
- Never run \`prodo-${command.cliSubcommand}\`, \`prodo ${command.cliSubcommand}\`, or \`prodo ...\` in shell.
|
|
365
372
|
- Do not inspect hooks or internals unless command execution fails.
|
|
366
373
|
- Input files are read-only; never modify or rewrite \`brief.md\`.
|
|
374
|
+
- Never print full artifact content in chat.
|
|
375
|
+
- Write/update files first, then reply with short status + written file path(s).
|
|
367
376
|
|
|
368
377
|
## Execution
|
|
369
378
|
|
|
@@ -381,6 +390,7 @@ Execution policy:
|
|
|
381
390
|
- Confirm command success state (exit code or validation status).
|
|
382
391
|
- Confirm \`brief.md\` hash/content did not change.
|
|
383
392
|
- Do NOT create manual fallback files under \`.prodo/artifact\` or any ad-hoc folder.
|
|
393
|
+
${normalizeJsonGuard}
|
|
384
394
|
|
|
385
395
|
4. Diagnose only on failure:
|
|
386
396
|
- Inspect \`.prodo/hooks.yml\` only after execution failure.
|
package/package.json
CHANGED
|
@@ -77,6 +77,11 @@ function toTomlPrompt(body: string, frontmatter: Record<string, unknown>, argsPl
|
|
|
77
77
|
return `description = "${description.replace(/"/g, '\\"')}"
|
|
78
78
|
|
|
79
79
|
prompt = """
|
|
80
|
+
Important execution rule:
|
|
81
|
+
- This is an agent slash command, not a shell command.
|
|
82
|
+
- Do NOT run \`prodo-normalize\`, \`prodo-prd\`, or \`prodo ...\` in shell.
|
|
83
|
+
- Execute the workflow directly using workspace files.
|
|
84
|
+
|
|
80
85
|
${promptBody}
|
|
81
86
|
"""`;
|
|
82
87
|
}
|
package/src/artifacts.ts
CHANGED
|
@@ -66,20 +66,58 @@ async function loadArtifactDoc(filePath: string): Promise<ArtifactDoc> {
|
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
function languageProbe(body: string): string {
|
|
70
|
+
const stripped = body
|
|
71
|
+
.replace(/```[\s\S]*?```/g, " ")
|
|
72
|
+
.replace(/^\s*#{1,6}\s+.*$/gm, " ")
|
|
73
|
+
.replace(/<[^>]+>/g, " ")
|
|
74
|
+
.replace(/\|/g, " ")
|
|
75
|
+
.replace(/\s+/g, " ")
|
|
76
|
+
.trim()
|
|
77
|
+
.toLowerCase();
|
|
78
|
+
return ` ${stripped} `;
|
|
79
|
+
}
|
|
80
|
+
|
|
69
81
|
function hasEnglishLeak(body: string): boolean {
|
|
70
|
-
const englishMarkers = [" the ", " and ", " with ", " user ", " should ", " must ", " requirement ", " flow "];
|
|
71
|
-
const normalized =
|
|
82
|
+
const englishMarkers = [" the ", " and ", " with ", " user ", " should ", " must ", " requirement ", " flow ", " error ", " success "];
|
|
83
|
+
const normalized = languageProbe(body);
|
|
72
84
|
return englishMarkers.filter((m) => normalized.includes(m)).length >= 2;
|
|
73
85
|
}
|
|
74
86
|
|
|
87
|
+
function hasTurkishLeak(body: string): boolean {
|
|
88
|
+
const turkishMarkers = [
|
|
89
|
+
" ve ",
|
|
90
|
+
" ile ",
|
|
91
|
+
" kullanici ",
|
|
92
|
+
" kullanıcı ",
|
|
93
|
+
" akis ",
|
|
94
|
+
" akış ",
|
|
95
|
+
" hata ",
|
|
96
|
+
" basari ",
|
|
97
|
+
" başarı ",
|
|
98
|
+
" ekran ",
|
|
99
|
+
" islem ",
|
|
100
|
+
" işlem ",
|
|
101
|
+
" gerekli "
|
|
102
|
+
];
|
|
103
|
+
const normalized = languageProbe(body);
|
|
104
|
+
return turkishMarkers.filter((m) => normalized.includes(m)).length >= 2;
|
|
105
|
+
}
|
|
106
|
+
|
|
75
107
|
function enforceLanguage(body: string, lang: string, artifactType: ArtifactType): void {
|
|
76
108
|
const normalized = (lang || "en").toLowerCase();
|
|
77
|
-
if (
|
|
78
|
-
|
|
109
|
+
if (normalized.startsWith("tr")) {
|
|
110
|
+
if (!hasEnglishLeak(body)) return;
|
|
79
111
|
throw new UserError(
|
|
80
112
|
`Language enforcement failed for ${artifactType}: output contains English fragments while language is Turkish.`
|
|
81
113
|
);
|
|
82
114
|
}
|
|
115
|
+
if (normalized.startsWith("en")) {
|
|
116
|
+
if (!hasTurkishLeak(body)) return;
|
|
117
|
+
throw new UserError(
|
|
118
|
+
`Language enforcement failed for ${artifactType}: output contains Turkish fragments while language is English.`
|
|
119
|
+
);
|
|
120
|
+
}
|
|
83
121
|
}
|
|
84
122
|
|
|
85
123
|
function toSlug(value: string): string {
|
|
@@ -473,6 +511,7 @@ async function writeWireframeScreens(
|
|
|
473
511
|
return token;
|
|
474
512
|
}
|
|
475
513
|
);
|
|
514
|
+
enforceLanguage(html, lang, "wireframe");
|
|
476
515
|
await fs.writeFile(htmlPath, html, "utf8");
|
|
477
516
|
const defaultMap = {
|
|
478
517
|
purpose: [`- [${screen.id}] ${screen.text}`],
|
|
@@ -516,6 +555,7 @@ async function writeWireframeScreens(
|
|
|
516
555
|
mdLines.push("");
|
|
517
556
|
}
|
|
518
557
|
const mdBody = mdLines.join("\n").trim();
|
|
558
|
+
enforceLanguage(mdBody, lang, "wireframe");
|
|
519
559
|
await fs.writeFile(mdPath, `${mdBody}\n`, "utf8");
|
|
520
560
|
if (!primaryMdPath) primaryMdPath = mdPath;
|
|
521
561
|
summaryBodies.push(mdBody);
|
|
@@ -630,6 +670,9 @@ export async function generateArtifact(options: GenerateOptions): Promise<string
|
|
|
630
670
|
}
|
|
631
671
|
|
|
632
672
|
enforceLanguage(generatedBody, settings.lang, artifactType);
|
|
673
|
+
if (artifactType === "workflow" && workflowMermaidBody) {
|
|
674
|
+
enforceLanguage(workflowMermaidBody, settings.lang, artifactType);
|
|
675
|
+
}
|
|
633
676
|
const uncovered = missingCoverage(def.required_contracts, normalizedBrief, contractCoverage);
|
|
634
677
|
if (uncovered.length > 0) {
|
|
635
678
|
const lines = uncovered
|
package/src/cli.ts
CHANGED
package/src/init-tui.ts
CHANGED
|
@@ -140,19 +140,6 @@ export async function gatherInitSelections(options: GatherInitUiOptions): Promis
|
|
|
140
140
|
throw new UserError("Initialization cancelled.");
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
const script = await clack.select({
|
|
144
|
-
message: "Select script type",
|
|
145
|
-
initialValue: fallbackScript,
|
|
146
|
-
options: [
|
|
147
|
-
{ value: "sh", label: "sh", hint: "Command profile (metadata)" },
|
|
148
|
-
{ value: "ps", label: "ps", hint: "Command profile (metadata)" }
|
|
149
|
-
]
|
|
150
|
-
});
|
|
151
|
-
if (clack.isCancel(script)) {
|
|
152
|
-
clack.cancel("Initialization cancelled.");
|
|
153
|
-
throw new UserError("Initialization cancelled.");
|
|
154
|
-
}
|
|
155
|
-
|
|
156
143
|
const lang = await clack.select({
|
|
157
144
|
message: "Select language",
|
|
158
145
|
initialValue: defaultLang,
|
|
@@ -173,7 +160,7 @@ export async function gatherInitSelections(options: GatherInitUiOptions): Promis
|
|
|
173
160
|
|
|
174
161
|
return {
|
|
175
162
|
ai: selectedAi,
|
|
176
|
-
script,
|
|
163
|
+
script: fallbackScript,
|
|
177
164
|
lang,
|
|
178
165
|
interactive: true
|
|
179
166
|
};
|
|
@@ -183,11 +170,10 @@ export function finishInitInteractive(summary: {
|
|
|
183
170
|
projectRoot: string;
|
|
184
171
|
settingsPath: string;
|
|
185
172
|
ai?: SupportedAi;
|
|
186
|
-
script: "sh" | "ps";
|
|
187
173
|
lang: "tr" | "en";
|
|
188
174
|
}): Promise<void> {
|
|
189
175
|
const aiText = summary.ai ?? "none";
|
|
190
176
|
return loadClack().then((clack) => clack.outro(
|
|
191
|
-
`Scaffold complete.\nAI: ${aiText}\
|
|
177
|
+
`Scaffold complete.\nAI: ${aiText}\nLanguage: ${summary.lang}\nSettings: ${summary.settingsPath}\nNext: edit brief.md`
|
|
192
178
|
));
|
|
193
179
|
}
|
|
@@ -120,8 +120,19 @@ function buildArtifactBody(schemaHint: ProviderSchemaHint, inputContext: Record<
|
|
|
120
120
|
const lang = typeof inputContext.outputLanguage === "string" ? inputContext.outputLanguage.toLowerCase() : "en";
|
|
121
121
|
const items = normalizeSectionItems(inputContext);
|
|
122
122
|
const coverage = coverageItems(schemaHint, inputContext);
|
|
123
|
+
const localizedItems =
|
|
124
|
+
lang === "tr" ? items.map((_, index) => `Gereksinim maddesi ${index + 1}`) : items;
|
|
125
|
+
const localizedCoverage =
|
|
126
|
+
lang === "tr"
|
|
127
|
+
? coverage.map((item, index) => ({
|
|
128
|
+
id: item.id,
|
|
129
|
+
text: `Kontrat kapsami ${index + 1}`
|
|
130
|
+
}))
|
|
131
|
+
: coverage;
|
|
123
132
|
const fallback = lang === "tr" ? "Detay daha sonra netlestirilecek." : "To be refined.";
|
|
124
|
-
const sections = schemaHint.requiredHeadings.map((heading) =>
|
|
133
|
+
const sections = schemaHint.requiredHeadings.map((heading) =>
|
|
134
|
+
headingBlock(heading, localizedItems, fallback, localizedCoverage)
|
|
135
|
+
);
|
|
125
136
|
const title =
|
|
126
137
|
lang === "tr"
|
|
127
138
|
? `# ${productName} icin ${schemaHint.artifactType.toUpperCase()}`
|
package/src/templates.ts
CHANGED
|
@@ -353,6 +353,13 @@ Rules:
|
|
|
353
353
|
- write normalized output as a new JSON object only`;
|
|
354
354
|
|
|
355
355
|
export function commandTemplate(command: WorkflowCommand): string {
|
|
356
|
+
const normalizeJsonGuard =
|
|
357
|
+
command.cliSubcommand === "normalize"
|
|
358
|
+
? `
|
|
359
|
+
- Normalize output format check:
|
|
360
|
+
- \`.prodo/briefs/normalized-brief.json\` must be strict JSON object (no markdown fences).
|
|
361
|
+
- If invalid, rewrite file as pure JSON object only.`
|
|
362
|
+
: "";
|
|
356
363
|
return `---
|
|
357
364
|
description: ${command.description}
|
|
358
365
|
handoffs:
|
|
@@ -372,8 +379,11 @@ Execution policy:
|
|
|
372
379
|
- Execute-first, diagnose-second.
|
|
373
380
|
- Perform only minimal prerequisite checks before execution.
|
|
374
381
|
- Do not run shell commands or CLI commands from inside the agent.
|
|
382
|
+
- Never run \`prodo-${command.cliSubcommand}\`, \`prodo ${command.cliSubcommand}\`, or \`prodo ...\` in shell.
|
|
375
383
|
- Do not inspect hooks or internals unless command execution fails.
|
|
376
384
|
- Input files are read-only; never modify or rewrite \`brief.md\`.
|
|
385
|
+
- Never print full artifact content in chat.
|
|
386
|
+
- Write/update files first, then reply with short status + written file path(s).
|
|
377
387
|
|
|
378
388
|
## Execution
|
|
379
389
|
|
|
@@ -391,6 +401,7 @@ Execution policy:
|
|
|
391
401
|
- Confirm command success state (exit code or validation status).
|
|
392
402
|
- Confirm \`brief.md\` hash/content did not change.
|
|
393
403
|
- Do NOT create manual fallback files under \`.prodo/artifact\` or any ad-hoc folder.
|
|
404
|
+
${normalizeJsonGuard}
|
|
394
405
|
|
|
395
406
|
4. Diagnose only on failure:
|
|
396
407
|
- Inspect \`.prodo/hooks.yml\` only after execution failure.
|
|
@@ -11,13 +11,21 @@ $ARGUMENTS
|
|
|
11
11
|
Execution policy:
|
|
12
12
|
- Execute-first, diagnose-second.
|
|
13
13
|
- Do not run shell/CLI commands from inside the agent.
|
|
14
|
+
- Never run `prodo-normalize`, `prodo normalize`, or `prodo ...` in shell.
|
|
14
15
|
- Input files are read-only; never modify or rewrite `brief.md`.
|
|
16
|
+
- Never print full normalized JSON in chat.
|
|
17
|
+
- Write `.prodo/briefs/normalized-brief.json`, then reply with short status + file path.
|
|
15
18
|
|
|
16
19
|
## Execution
|
|
17
20
|
|
|
18
21
|
1. Verify minimal prerequisites (`.prodo/`, `brief.md`).
|
|
19
22
|
2. Read only `brief.md` and normalize it into `.prodo/briefs/normalized-brief.json`.
|
|
20
23
|
3. Confirm `.prodo/briefs/normalized-brief.json` exists.
|
|
21
|
-
4.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
4. Verify normalized file is strict JSON only:
|
|
25
|
+
- first non-space char is `{`
|
|
26
|
+
- no markdown fences like ```json or ```
|
|
27
|
+
- JSON parses successfully as an object
|
|
28
|
+
5. If format is not strict JSON, rewrite the same file as pure JSON object only.
|
|
29
|
+
6. Confirm `brief.md` content did not change.
|
|
30
|
+
7. Do not create any manual files under `.prodo/` except expected runtime outputs.
|
|
31
|
+
8. Diagnose internals only if command fails.
|
|
@@ -11,7 +11,10 @@ $ARGUMENTS
|
|
|
11
11
|
Execution policy:
|
|
12
12
|
- Execute-first, diagnose-second.
|
|
13
13
|
- Do not run shell/CLI commands from inside the agent.
|
|
14
|
+
- Never run `prodo-prd`, `prodo prd`, or `prodo ...` in shell.
|
|
14
15
|
- Input files are read-only; never modify or rewrite `brief.md`.
|
|
16
|
+
- Never print full artifact JSON/Markdown in chat.
|
|
17
|
+
- Write outputs to files, then reply with short status + written file path(s).
|
|
15
18
|
|
|
16
19
|
## Execution
|
|
17
20
|
|
|
@@ -11,7 +11,10 @@ $ARGUMENTS
|
|
|
11
11
|
Execution policy:
|
|
12
12
|
- Execute-first, diagnose-second.
|
|
13
13
|
- Do not run shell/CLI commands from inside the agent.
|
|
14
|
+
- Never run `prodo-stories`, `prodo stories`, or `prodo ...` in shell.
|
|
14
15
|
- Input files are read-only; never modify or rewrite `brief.md`.
|
|
16
|
+
- Never print full artifact JSON/Markdown in chat.
|
|
17
|
+
- Write outputs to files, then reply with short status + written file path(s).
|
|
15
18
|
|
|
16
19
|
## Execution
|
|
17
20
|
|
|
@@ -11,7 +11,10 @@ $ARGUMENTS
|
|
|
11
11
|
Execution policy:
|
|
12
12
|
- Execute-first, diagnose-second.
|
|
13
13
|
- Do not run shell/CLI commands from inside the agent.
|
|
14
|
+
- Never run `prodo-techspec`, `prodo techspec`, or `prodo ...` in shell.
|
|
14
15
|
- Input files are read-only; never modify or rewrite `brief.md`.
|
|
16
|
+
- Never print full artifact JSON/Markdown in chat.
|
|
17
|
+
- Write outputs to files, then reply with short status + written file path(s).
|
|
15
18
|
|
|
16
19
|
## Execution
|
|
17
20
|
|
|
@@ -11,7 +11,10 @@ $ARGUMENTS
|
|
|
11
11
|
Execution policy:
|
|
12
12
|
- Execute-first, diagnose-second.
|
|
13
13
|
- Do not run shell/CLI commands from inside the agent.
|
|
14
|
+
- Never run `prodo-validate`, `prodo validate`, or `prodo ...` in shell.
|
|
14
15
|
- Input files are read-only; never modify or rewrite `brief.md`.
|
|
16
|
+
- Never print full validation payload in chat.
|
|
17
|
+
- Write/update validation report file, then reply with short status + report path.
|
|
15
18
|
|
|
16
19
|
## Execution
|
|
17
20
|
|
|
@@ -11,7 +11,10 @@ $ARGUMENTS
|
|
|
11
11
|
Execution policy:
|
|
12
12
|
- Execute-first, diagnose-second.
|
|
13
13
|
- Do not run shell/CLI commands from inside the agent.
|
|
14
|
+
- Never run `prodo-wireframe`, `prodo wireframe`, or `prodo ...` in shell.
|
|
14
15
|
- Input files are read-only; never modify or rewrite `brief.md`.
|
|
16
|
+
- Never print full artifact JSON/Markdown in chat.
|
|
17
|
+
- Write outputs to files, then reply with short status + written file path(s).
|
|
15
18
|
|
|
16
19
|
## Execution
|
|
17
20
|
|
|
@@ -11,7 +11,10 @@ $ARGUMENTS
|
|
|
11
11
|
Execution policy:
|
|
12
12
|
- Execute-first, diagnose-second.
|
|
13
13
|
- Do not run shell/CLI commands from inside the agent.
|
|
14
|
+
- Never run `prodo-workflow`, `prodo workflow`, or `prodo ...` in shell.
|
|
14
15
|
- Input files are read-only; never modify or rewrite `brief.md`.
|
|
16
|
+
- Never print full artifact JSON/Markdown in chat.
|
|
17
|
+
- Write outputs to files, then reply with short status + written file path(s).
|
|
15
18
|
|
|
16
19
|
## Execution
|
|
17
20
|
|