@shahmarasy/prodo 0.1.1 → 0.1.2

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.
@@ -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 = ` ${body.toLowerCase().replace(/\s+/g, " ")} `;
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 (!normalized.startsWith("tr"))
64
- return;
65
- if (hasEnglishLeak(body)) {
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
@@ -124,7 +124,6 @@ async function runCli(options = {}) {
124
124
  projectRoot,
125
125
  settingsPath: result.settingsPath,
126
126
  ai: selectedAi,
127
- script: selected.script,
128
127
  lang: selected.lang
129
128
  });
130
129
  return;
@@ -15,7 +15,6 @@ export declare function finishInitInteractive(summary: {
15
15
  projectRoot: string;
16
16
  settingsPath: string;
17
17
  ai?: SupportedAi;
18
- script: "sh" | "ps";
19
18
  lang: "tr" | "en";
20
19
  }): Promise<void>;
21
20
  export {};
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}\nScript: ${summary.script}\nLanguage: ${summary.lang}\nSettings: ${summary.settingsPath}\nNext: edit brief.md`));
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, items, fallback, coverage));
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
@@ -362,6 +362,7 @@ Execution policy:
362
362
  - Execute-first, diagnose-second.
363
363
  - Perform only minimal prerequisite checks before execution.
364
364
  - Do not run shell commands or CLI commands from inside the agent.
365
+ - Never run \`prodo-${command.cliSubcommand}\`, \`prodo ${command.cliSubcommand}\`, or \`prodo ...\` in shell.
365
366
  - Do not inspect hooks or internals unless command execution fails.
366
367
  - Input files are read-only; never modify or rewrite \`brief.md\`.
367
368
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shahmarasy/prodo",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "CLI-first, prompt-powered product artifact kit",
5
5
  "main": "dist/cli.js",
6
6
  "types": "dist/cli.d.ts",
@@ -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 = ` ${body.toLowerCase().replace(/\s+/g, " ")} `;
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 (!normalized.startsWith("tr")) return;
78
- if (hasEnglishLeak(body)) {
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
@@ -141,7 +141,6 @@ export async function runCli(options: RunOptions = {}): Promise<number> {
141
141
  projectRoot,
142
142
  settingsPath: result.settingsPath,
143
143
  ai: selectedAi,
144
- script: selected.script,
145
144
  lang: selected.lang
146
145
  });
147
146
  return;
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}\nScript: ${summary.script}\nLanguage: ${summary.lang}\nSettings: ${summary.settingsPath}\nNext: edit brief.md`
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) => headingBlock(heading, items, fallback, coverage));
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
@@ -372,6 +372,7 @@ Execution policy:
372
372
  - Execute-first, diagnose-second.
373
373
  - Perform only minimal prerequisite checks before execution.
374
374
  - Do not run shell commands or CLI commands from inside the agent.
375
+ - Never run \`prodo-${command.cliSubcommand}\`, \`prodo ${command.cliSubcommand}\`, or \`prodo ...\` in shell.
375
376
  - Do not inspect hooks or internals unless command execution fails.
376
377
  - Input files are read-only; never modify or rewrite \`brief.md\`.
377
378
 
@@ -11,6 +11,7 @@ $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`.
15
16
 
16
17
  ## Execution
@@ -10,7 +10,7 @@ $ARGUMENTS
10
10
 
11
11
  Execution policy:
12
12
  - Execute-first, diagnose-second.
13
- - Do not run shell/CLI commands from inside the agent.
13
+ - Do not run shell/CLI commands from inside the agent.`n- Never run `prodo-prd`, `prodo prd`, or `prodo ...` in shell.
14
14
  - Input files are read-only; never modify or rewrite `brief.md`.
15
15
 
16
16
  ## Execution
@@ -10,7 +10,7 @@ $ARGUMENTS
10
10
 
11
11
  Execution policy:
12
12
  - Execute-first, diagnose-second.
13
- - Do not run shell/CLI commands from inside the agent.
13
+ - Do not run shell/CLI commands from inside the agent.`n- Never run `prodo-stories`, `prodo stories`, or `prodo ...` in shell.
14
14
  - Input files are read-only; never modify or rewrite `brief.md`.
15
15
 
16
16
  ## Execution
@@ -10,7 +10,7 @@ $ARGUMENTS
10
10
 
11
11
  Execution policy:
12
12
  - Execute-first, diagnose-second.
13
- - Do not run shell/CLI commands from inside the agent.
13
+ - Do not run shell/CLI commands from inside the agent.`n- Never run `prodo-techspec`, `prodo techspec`, or `prodo ...` in shell.
14
14
  - Input files are read-only; never modify or rewrite `brief.md`.
15
15
 
16
16
  ## Execution
@@ -10,7 +10,7 @@ $ARGUMENTS
10
10
 
11
11
  Execution policy:
12
12
  - Execute-first, diagnose-second.
13
- - Do not run shell/CLI commands from inside the agent.
13
+ - Do not run shell/CLI commands from inside the agent.`n- Never run `prodo-validate`, `prodo validate`, or `prodo ...` in shell.
14
14
  - Input files are read-only; never modify or rewrite `brief.md`.
15
15
 
16
16
  ## Execution
@@ -10,7 +10,7 @@ $ARGUMENTS
10
10
 
11
11
  Execution policy:
12
12
  - Execute-first, diagnose-second.
13
- - Do not run shell/CLI commands from inside the agent.
13
+ - Do not run shell/CLI commands from inside the agent.`n- Never run `prodo-wireframe`, `prodo wireframe`, or `prodo ...` in shell.
14
14
  - Input files are read-only; never modify or rewrite `brief.md`.
15
15
 
16
16
  ## Execution
@@ -10,7 +10,7 @@ $ARGUMENTS
10
10
 
11
11
  Execution policy:
12
12
  - Execute-first, diagnose-second.
13
- - Do not run shell/CLI commands from inside the agent.
13
+ - Do not run shell/CLI commands from inside the agent.`n- Never run `prodo-workflow`, `prodo workflow`, or `prodo ...` in shell.
14
14
  - Input files are read-only; never modify or rewrite `brief.md`.
15
15
 
16
16
  ## Execution