@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.
Files changed (205) hide show
  1. package/README.md +201 -97
  2. package/bin/prodo.cjs +6 -6
  3. package/dist/agents/agent-registry.d.ts +13 -0
  4. package/dist/agents/agent-registry.js +79 -0
  5. package/dist/agents/anthropic/index.d.ts +9 -0
  6. package/dist/agents/anthropic/index.js +55 -0
  7. package/dist/agents/base.d.ts +25 -0
  8. package/dist/agents/base.js +71 -0
  9. package/dist/agents/google/index.d.ts +9 -0
  10. package/dist/agents/google/index.js +53 -0
  11. package/dist/agents/mock/index.d.ts +11 -0
  12. package/dist/agents/mock/index.js +26 -0
  13. package/dist/agents/openai/index.d.ts +9 -0
  14. package/dist/agents/openai/index.js +57 -0
  15. package/dist/agents/system-prompts.d.ts +3 -0
  16. package/dist/agents/system-prompts.js +32 -0
  17. package/dist/agents.js +4 -2
  18. package/dist/artifacts.d.ts +1 -0
  19. package/dist/artifacts.js +265 -31
  20. package/dist/cli/agent-command-installer.d.ts +4 -0
  21. package/dist/cli/agent-command-installer.js +148 -0
  22. package/dist/cli/agent-ids.d.ts +15 -0
  23. package/dist/cli/agent-ids.js +49 -0
  24. package/dist/cli/doctor.d.ts +1 -0
  25. package/dist/cli/doctor.js +144 -0
  26. package/dist/cli/fix-tui.d.ts +4 -0
  27. package/dist/cli/fix-tui.js +79 -0
  28. package/dist/cli/index.d.ts +9 -0
  29. package/dist/cli/index.js +465 -0
  30. package/dist/cli/init-tui.d.ts +23 -0
  31. package/dist/cli/init-tui.js +176 -0
  32. package/dist/cli/init.d.ts +11 -0
  33. package/dist/cli/init.js +334 -0
  34. package/dist/cli/normalize-interactive.d.ts +8 -0
  35. package/dist/cli/normalize-interactive.js +167 -0
  36. package/dist/cli/preset-loader.d.ts +4 -0
  37. package/dist/cli/preset-loader.js +210 -0
  38. package/dist/cli.js +80 -3
  39. package/dist/core/artifact-registry.d.ts +11 -0
  40. package/dist/core/artifact-registry.js +49 -0
  41. package/dist/core/artifacts.d.ts +10 -0
  42. package/dist/core/artifacts.js +892 -0
  43. package/dist/core/clean.d.ts +10 -0
  44. package/dist/core/clean.js +74 -0
  45. package/dist/core/consistency.d.ts +8 -0
  46. package/dist/core/consistency.js +328 -0
  47. package/dist/core/constants.d.ts +7 -0
  48. package/dist/core/constants.js +64 -0
  49. package/dist/core/errors.d.ts +3 -0
  50. package/dist/core/errors.js +10 -0
  51. package/dist/core/fix.d.ts +31 -0
  52. package/dist/core/fix.js +188 -0
  53. package/dist/core/hook-executor.d.ts +1 -0
  54. package/dist/core/hook-executor.js +175 -0
  55. package/dist/core/markdown.d.ts +16 -0
  56. package/dist/core/markdown.js +81 -0
  57. package/dist/core/normalize.d.ts +8 -0
  58. package/dist/core/normalize.js +125 -0
  59. package/dist/core/normalized-brief.d.ts +48 -0
  60. package/dist/core/normalized-brief.js +182 -0
  61. package/dist/core/output-index.d.ts +13 -0
  62. package/dist/core/output-index.js +55 -0
  63. package/dist/core/paths.d.ts +17 -0
  64. package/dist/core/paths.js +80 -0
  65. package/dist/core/project-config.d.ts +14 -0
  66. package/dist/core/project-config.js +69 -0
  67. package/dist/core/registry.d.ts +13 -0
  68. package/dist/core/registry.js +115 -0
  69. package/dist/core/settings.d.ts +7 -0
  70. package/dist/core/settings.js +35 -0
  71. package/dist/core/template-engine.d.ts +3 -0
  72. package/dist/core/template-engine.js +43 -0
  73. package/dist/core/template-resolver.d.ts +15 -0
  74. package/dist/core/template-resolver.js +46 -0
  75. package/dist/core/templates.d.ts +33 -0
  76. package/dist/core/templates.js +440 -0
  77. package/dist/core/terminology.d.ts +21 -0
  78. package/dist/core/terminology.js +143 -0
  79. package/dist/core/tracing.d.ts +21 -0
  80. package/dist/core/tracing.js +74 -0
  81. package/dist/core/types.d.ts +35 -0
  82. package/dist/core/types.js +5 -0
  83. package/dist/core/utils.d.ts +7 -0
  84. package/dist/core/utils.js +66 -0
  85. package/dist/core/validate.d.ts +10 -0
  86. package/dist/core/validate.js +226 -0
  87. package/dist/core/validator.d.ts +5 -0
  88. package/dist/core/validator.js +76 -0
  89. package/dist/core/version.d.ts +1 -0
  90. package/dist/core/version.js +30 -0
  91. package/dist/core/workflow-commands.d.ts +7 -0
  92. package/dist/core/workflow-commands.js +29 -0
  93. package/dist/i18n/en.json +45 -0
  94. package/dist/i18n/index.d.ts +5 -0
  95. package/dist/i18n/index.js +63 -0
  96. package/dist/i18n/tr.json +45 -0
  97. package/dist/init-tui.d.ts +3 -0
  98. package/dist/init-tui.js +28 -1
  99. package/dist/init.d.ts +1 -0
  100. package/dist/init.js +9 -3
  101. package/dist/normalize.js +55 -7
  102. package/dist/providers/index.d.ts +2 -1
  103. package/dist/providers/index.js +20 -6
  104. package/dist/providers/mock-provider.d.ts +1 -1
  105. package/dist/providers/mock-provider.js +7 -6
  106. package/dist/providers/openai-provider.d.ts +1 -1
  107. package/dist/providers/openai-provider.js +3 -2
  108. package/dist/settings.d.ts +1 -0
  109. package/dist/settings.js +2 -1
  110. package/dist/skills/engine.d.ts +10 -0
  111. package/dist/skills/engine.js +75 -0
  112. package/dist/skills/fix-skill.d.ts +2 -0
  113. package/dist/skills/fix-skill.js +38 -0
  114. package/dist/skills/generate-artifact-skill.d.ts +2 -0
  115. package/dist/skills/generate-artifact-skill.js +32 -0
  116. package/dist/skills/generate-pipeline-skill.d.ts +2 -0
  117. package/dist/skills/generate-pipeline-skill.js +45 -0
  118. package/dist/skills/normalize-skill.d.ts +2 -0
  119. package/dist/skills/normalize-skill.js +29 -0
  120. package/dist/skills/types.d.ts +28 -0
  121. package/dist/skills/types.js +2 -0
  122. package/dist/skills/validate-skill.d.ts +2 -0
  123. package/dist/skills/validate-skill.js +29 -0
  124. package/dist/templates.d.ts +1 -1
  125. package/dist/templates.js +2 -0
  126. package/dist/utils.d.ts +1 -0
  127. package/dist/utils.js +13 -0
  128. package/dist/validator.js +0 -4
  129. package/dist/workflow-commands.js +2 -1
  130. package/package.json +74 -45
  131. package/presets/fintech/preset.json +48 -1
  132. package/presets/fintech/prompts/prd.md +99 -2
  133. package/presets/marketplace/preset.json +51 -1
  134. package/presets/marketplace/prompts/prd.md +140 -2
  135. package/presets/saas/preset.json +53 -1
  136. package/presets/saas/prompts/prd.md +150 -2
  137. package/src/agents/agent-registry.ts +93 -0
  138. package/src/agents/anthropic/index.ts +86 -0
  139. package/src/agents/anthropic/manifest.json +7 -0
  140. package/src/agents/base.ts +77 -0
  141. package/src/agents/google/index.ts +79 -0
  142. package/src/agents/google/manifest.json +7 -0
  143. package/src/agents/mock/index.ts +32 -0
  144. package/src/agents/mock/manifest.json +7 -0
  145. package/src/agents/openai/index.ts +83 -0
  146. package/src/agents/openai/manifest.json +7 -0
  147. package/src/agents/system-prompts.ts +35 -0
  148. package/src/{agent-command-installer.ts → cli/agent-command-installer.ts} +164 -164
  149. package/src/{agents.ts → cli/agent-ids.ts} +58 -56
  150. package/src/{doctor.ts → cli/doctor.ts} +157 -137
  151. package/src/cli/fix-tui.ts +111 -0
  152. package/src/{cli.ts → cli/index.ts} +459 -319
  153. package/src/{init-tui.ts → cli/init-tui.ts} +208 -179
  154. package/src/{init.ts → cli/init.ts} +398 -391
  155. package/src/cli/normalize-interactive.ts +241 -0
  156. package/src/{preset-loader.ts → cli/preset-loader.ts} +237 -237
  157. package/src/{artifact-registry.ts → core/artifact-registry.ts} +69 -69
  158. package/src/{artifacts.ts → core/artifacts.ts} +1081 -777
  159. package/src/core/clean.ts +88 -0
  160. package/src/{consistency.ts → core/consistency.ts} +374 -303
  161. package/src/{constants.ts → core/constants.ts} +72 -72
  162. package/src/{errors.ts → core/errors.ts} +7 -7
  163. package/src/core/fix.ts +253 -0
  164. package/src/{hook-executor.ts → core/hook-executor.ts} +196 -196
  165. package/src/{markdown.ts → core/markdown.ts} +93 -73
  166. package/src/core/normalize.ts +145 -0
  167. package/src/{normalized-brief.ts → core/normalized-brief.ts} +227 -206
  168. package/src/{output-index.ts → core/output-index.ts} +59 -59
  169. package/src/{paths.ts → core/paths.ts} +75 -71
  170. package/src/{project-config.ts → core/project-config.ts} +78 -78
  171. package/src/{registry.ts → core/registry.ts} +119 -119
  172. package/src/{settings.ts → core/settings.ts} +35 -34
  173. package/src/core/template-engine.ts +45 -0
  174. package/src/{template-resolver.ts → core/template-resolver.ts} +54 -54
  175. package/src/{templates.ts → core/templates.ts} +452 -450
  176. package/src/core/terminology.ts +177 -0
  177. package/src/core/tracing.ts +110 -0
  178. package/src/{types.ts → core/types.ts} +46 -46
  179. package/src/{utils.ts → core/utils.ts} +64 -50
  180. package/src/{validate.ts → core/validate.ts} +252 -246
  181. package/src/{validator.ts → core/validator.ts} +92 -96
  182. package/src/{version.ts → core/version.ts} +24 -24
  183. package/src/{workflow-commands.ts → core/workflow-commands.ts} +32 -31
  184. package/src/i18n/en.json +45 -0
  185. package/src/i18n/index.ts +58 -0
  186. package/src/i18n/tr.json +45 -0
  187. package/src/providers/index.ts +29 -12
  188. package/src/providers/mock-provider.ts +200 -199
  189. package/src/providers/openai-provider.ts +88 -87
  190. package/src/skills/engine.ts +94 -0
  191. package/src/skills/fix-skill.ts +38 -0
  192. package/src/skills/generate-artifact-skill.ts +32 -0
  193. package/src/skills/generate-pipeline-skill.ts +49 -0
  194. package/src/skills/normalize-skill.ts +29 -0
  195. package/src/skills/types.ts +36 -0
  196. package/src/skills/validate-skill.ts +29 -0
  197. package/templates/commands/prodo-fix.md +46 -0
  198. package/templates/commands/prodo-normalize.md +118 -23
  199. package/templates/commands/prodo-prd.md +138 -17
  200. package/templates/commands/prodo-stories.md +153 -17
  201. package/templates/commands/prodo-techspec.md +167 -17
  202. package/templates/commands/prodo-validate.md +184 -26
  203. package/templates/commands/prodo-wireframe.md +188 -17
  204. package/templates/commands/prodo-workflow.md +200 -17
  205. package/src/normalize.ts +0 -89
@@ -1,96 +1,92 @@
1
- import fs from "node:fs/promises";
2
- import Ajv2020 from "ajv/dist/2020";
3
- import addFormats from "ajv-formats";
4
- import yaml from "js-yaml";
5
- import { sectionTextMap } from "./markdown";
6
- import type { ArtifactDoc, ArtifactType, ValidationIssue } from "./types";
7
- import { schemaPath } from "./paths";
8
-
9
- type SchemaWithHeading = Record<string, unknown> & {
10
- x_required_headings?: unknown;
11
- };
12
-
13
- const ajv = new Ajv2020({ allErrors: true, strict: false });
14
- addFormats(ajv);
15
-
16
- async function resolveSchema(
17
- cwd: string,
18
- artifactType: ArtifactType
19
- ): Promise<SchemaWithHeading> {
20
- const raw = await fs.readFile(schemaPath(cwd, artifactType), "utf8");
21
- return yaml.load(raw) as SchemaWithHeading;
22
- }
23
-
24
- function requiredHeadingsFromSchema(schema: SchemaWithHeading): string[] {
25
- if (!Array.isArray(schema.x_required_headings)) return [];
26
- return schema.x_required_headings.filter((item): item is string => typeof item === "string");
27
- }
28
-
29
- export async function validateSchema(
30
- cwd: string,
31
- artifactType: ArtifactType,
32
- doc: ArtifactDoc,
33
- requiredHeadingsOverride?: string[]
34
- ): Promise<{ issues: ValidationIssue[]; requiredHeadings: string[] }> {
35
- const schema = await resolveSchema(cwd, artifactType);
36
- const requiredHeadings =
37
- requiredHeadingsOverride && requiredHeadingsOverride.length > 0
38
- ? requiredHeadingsOverride
39
- : requiredHeadingsFromSchema(schema);
40
- const workingSchema: Record<string, unknown> = { ...schema };
41
- delete workingSchema.x_required_headings;
42
-
43
- const validate = ajv.compile(workingSchema);
44
- const valid = validate(doc);
45
- const issues: ValidationIssue[] = [];
46
-
47
- if (!valid && validate.errors) {
48
- for (const err of validate.errors) {
49
- issues.push({
50
- level: "error",
51
- code: "schema_validation_failed",
52
- check: "schema",
53
- artifactType,
54
- field: err.instancePath || err.schemaPath,
55
- message: `Schema validation error: ${err.message ?? "unknown error"}`,
56
- suggestion: "Adjust the generated content to satisfy schema requirements."
57
- });
58
- }
59
- }
60
-
61
- const sections = sectionTextMap(doc.body);
62
- const trMode = String((doc.frontmatter as Record<string, unknown>).language ?? "").toLowerCase().startsWith("tr");
63
- if (trMode) {
64
- return { issues, requiredHeadings: [] };
65
- }
66
- for (const heading of requiredHeadings) {
67
- if (!doc.body.includes(heading)) {
68
- issues.push({
69
- level: "error",
70
- code: "missing_required_heading",
71
- check: "schema",
72
- artifactType,
73
- field: heading,
74
- message: `Required section missing: ${heading}`,
75
- suggestion: "Regenerate or manually edit the artifact to include all required headings."
76
- });
77
- continue;
78
- }
79
-
80
- const content = sections.get(heading) ?? "";
81
- const isPlaceholder = /(tbd|to be defined|i don't know|unknown|n\/a)/i.test(content);
82
- if (content.trim().length < 20 || isPlaceholder) {
83
- issues.push({
84
- level: "error",
85
- code: "weak_required_heading_content",
86
- check: "schema",
87
- artifactType,
88
- field: heading,
89
- message: `Section has weak or placeholder content: ${heading}`,
90
- suggestion: "Replace placeholders with concrete, actionable details."
91
- });
92
- }
93
- }
94
-
95
- return { issues, requiredHeadings };
96
- }
1
+ import fs from "node:fs/promises";
2
+ import Ajv2020 from "ajv/dist/2020";
3
+ import addFormats from "ajv-formats";
4
+ import yaml from "js-yaml";
5
+ import { sectionTextMap } from "./markdown";
6
+ import type { ArtifactDoc, ArtifactType, ValidationIssue } from "./types";
7
+ import { schemaPath } from "./paths";
8
+
9
+ type SchemaWithHeading = Record<string, unknown> & {
10
+ x_required_headings?: unknown;
11
+ };
12
+
13
+ const ajv = new Ajv2020({ allErrors: true, strict: false });
14
+ addFormats(ajv);
15
+
16
+ async function resolveSchema(
17
+ cwd: string,
18
+ artifactType: ArtifactType
19
+ ): Promise<SchemaWithHeading> {
20
+ const raw = await fs.readFile(schemaPath(cwd, artifactType), "utf8");
21
+ return yaml.load(raw) as SchemaWithHeading;
22
+ }
23
+
24
+ function requiredHeadingsFromSchema(schema: SchemaWithHeading): string[] {
25
+ if (!Array.isArray(schema.x_required_headings)) return [];
26
+ return schema.x_required_headings.filter((item): item is string => typeof item === "string");
27
+ }
28
+
29
+ export async function validateSchema(
30
+ cwd: string,
31
+ artifactType: ArtifactType,
32
+ doc: ArtifactDoc,
33
+ requiredHeadingsOverride?: string[]
34
+ ): Promise<{ issues: ValidationIssue[]; requiredHeadings: string[] }> {
35
+ const schema = await resolveSchema(cwd, artifactType);
36
+ const requiredHeadings =
37
+ requiredHeadingsOverride && requiredHeadingsOverride.length > 0
38
+ ? requiredHeadingsOverride
39
+ : requiredHeadingsFromSchema(schema);
40
+ const workingSchema: Record<string, unknown> = { ...schema };
41
+ delete workingSchema.x_required_headings;
42
+
43
+ const validate = ajv.compile(workingSchema);
44
+ const valid = validate(doc);
45
+ const issues: ValidationIssue[] = [];
46
+
47
+ if (!valid && validate.errors) {
48
+ for (const err of validate.errors) {
49
+ issues.push({
50
+ level: "error",
51
+ code: "schema_validation_failed",
52
+ check: "schema",
53
+ artifactType,
54
+ field: err.instancePath || err.schemaPath,
55
+ message: `Schema validation error: ${err.message ?? "unknown error"}`,
56
+ suggestion: "Adjust the generated content to satisfy schema requirements."
57
+ });
58
+ }
59
+ }
60
+
61
+ const sections = sectionTextMap(doc.body);
62
+ for (const heading of requiredHeadings) {
63
+ if (!doc.body.includes(heading)) {
64
+ issues.push({
65
+ level: "error",
66
+ code: "missing_required_heading",
67
+ check: "schema",
68
+ artifactType,
69
+ field: heading,
70
+ message: `Required section missing: ${heading}`,
71
+ suggestion: "Regenerate or manually edit the artifact to include all required headings."
72
+ });
73
+ continue;
74
+ }
75
+
76
+ const content = sections.get(heading) ?? "";
77
+ const isPlaceholder = /(tbd|to be defined|i don't know|unknown|n\/a)/i.test(content);
78
+ if (content.trim().length < 20 || isPlaceholder) {
79
+ issues.push({
80
+ level: "error",
81
+ code: "weak_required_heading_content",
82
+ check: "schema",
83
+ artifactType,
84
+ field: heading,
85
+ message: `Section has weak or placeholder content: ${heading}`,
86
+ suggestion: "Replace placeholders with concrete, actionable details."
87
+ });
88
+ }
89
+ }
90
+
91
+ return { issues, requiredHeadings };
92
+ }
@@ -1,24 +1,24 @@
1
- import fs from "node:fs/promises";
2
- import path from "node:path";
3
- import { fileExists } from "./utils";
4
-
5
- export async function readCliVersion(cwd: string): Promise<string> {
6
- const candidates = [
7
- path.join(cwd, "package.json"),
8
- path.resolve(__dirname, "..", "package.json")
9
- ];
10
- for (const candidate of candidates) {
11
- if (!(await fileExists(candidate))) continue;
12
- try {
13
- const raw = await fs.readFile(candidate, "utf8");
14
- const parsed = JSON.parse(raw) as { version?: unknown };
15
- if (typeof parsed.version === "string" && parsed.version.trim().length > 0) {
16
- return parsed.version.trim();
17
- }
18
- } catch {
19
- // ignore and continue
20
- }
21
- }
22
- return "0.0.0";
23
- }
24
-
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { fileExists } from "./utils";
4
+
5
+ export async function readCliVersion(cwd: string): Promise<string> {
6
+ const candidates = [
7
+ path.join(cwd, "package.json"),
8
+ path.resolve(__dirname, "..", "..", "package.json")
9
+ ];
10
+ for (const candidate of candidates) {
11
+ if (!(await fileExists(candidate))) continue;
12
+ try {
13
+ const raw = await fs.readFile(candidate, "utf8");
14
+ const parsed = JSON.parse(raw) as { version?: unknown };
15
+ if (typeof parsed.version === "string" && parsed.version.trim().length > 0) {
16
+ return parsed.version.trim();
17
+ }
18
+ } catch {
19
+ // ignore and continue
20
+ }
21
+ }
22
+ return "0.0.0";
23
+ }
24
+
@@ -1,31 +1,32 @@
1
- export type WorkflowCommand = {
2
- name: string;
3
- cliSubcommand: string;
4
- description: string;
5
- };
6
-
7
- const BASE_WORKFLOW_COMMANDS: WorkflowCommand[] = [
8
- { name: "prodo-normalize", cliSubcommand: "normalize", description: "Normalize start brief into normalized brief JSON." },
9
- { name: "prodo-prd", cliSubcommand: "prd", description: "Generate PRD artifact from normalized brief." },
10
- { name: "prodo-workflow", cliSubcommand: "workflow", description: "Generate workflow artifact." },
11
- { name: "prodo-wireframe", cliSubcommand: "wireframe", description: "Generate wireframe artifact." },
12
- { name: "prodo-stories", cliSubcommand: "stories", description: "Generate stories artifact." },
13
- { name: "prodo-techspec", cliSubcommand: "techspec", description: "Generate technical specification artifact." },
14
- { name: "prodo-validate", cliSubcommand: "validate", description: "Run schema and cross-artifact consistency validation." }
15
- ];
16
-
17
- export const WORKFLOW_COMMANDS: WorkflowCommand[] = BASE_WORKFLOW_COMMANDS;
18
-
19
- export function buildWorkflowCommands(artifactTypes: string[]): WorkflowCommand[] {
20
- const commandByName = new Map<string, WorkflowCommand>(BASE_WORKFLOW_COMMANDS.map((item) => [item.name, item]));
21
- for (const type of artifactTypes) {
22
- const name = `prodo-${type}`;
23
- if (commandByName.has(name)) continue;
24
- commandByName.set(name, {
25
- name,
26
- cliSubcommand: type,
27
- description: `Generate ${type} artifact from normalized brief.`
28
- });
29
- }
30
- return Array.from(commandByName.values());
31
- }
1
+ export type WorkflowCommand = {
2
+ name: string;
3
+ cliSubcommand: string;
4
+ description: string;
5
+ };
6
+
7
+ const BASE_WORKFLOW_COMMANDS: WorkflowCommand[] = [
8
+ { name: "prodo-normalize", cliSubcommand: "normalize", description: "Normalize start brief into normalized brief JSON." },
9
+ { name: "prodo-prd", cliSubcommand: "prd", description: "Generate PRD artifact from normalized brief." },
10
+ { name: "prodo-workflow", cliSubcommand: "workflow", description: "Generate workflow artifact." },
11
+ { name: "prodo-wireframe", cliSubcommand: "wireframe", description: "Generate wireframe artifact." },
12
+ { name: "prodo-stories", cliSubcommand: "stories", description: "Generate stories artifact." },
13
+ { name: "prodo-techspec", cliSubcommand: "techspec", description: "Generate technical specification artifact." },
14
+ { name: "prodo-validate", cliSubcommand: "validate", description: "Run schema and cross-artifact consistency validation." },
15
+ { name: "prodo-fix", cliSubcommand: "fix", description: "Auto-fix artifacts based on validation report and brief." }
16
+ ];
17
+
18
+ export const WORKFLOW_COMMANDS: WorkflowCommand[] = BASE_WORKFLOW_COMMANDS;
19
+
20
+ export function buildWorkflowCommands(artifactTypes: string[]): WorkflowCommand[] {
21
+ const commandByName = new Map<string, WorkflowCommand>(BASE_WORKFLOW_COMMANDS.map((item) => [item.name, item]));
22
+ for (const type of artifactTypes) {
23
+ const name = `prodo-${type}`;
24
+ if (commandByName.has(name)) continue;
25
+ commandByName.set(name, {
26
+ name,
27
+ cliSubcommand: type,
28
+ description: `Generate ${type} artifact from normalized brief.`
29
+ });
30
+ }
31
+ return Array.from(commandByName.values());
32
+ }
@@ -0,0 +1,45 @@
1
+ {
2
+ "user_action": "User action",
3
+ "main_flow": "Main Flow",
4
+ "user": "User",
5
+ "success": "Success",
6
+ "error": "Error",
7
+ "flow_focus": "Flow Focus",
8
+ "initial_version": "Initial version",
9
+ "fix_revision": "Post-validation fix revision",
10
+ "primary_user": "Primary user",
11
+ "back": "Back",
12
+ "next": "Next",
13
+ "save": "Save",
14
+ "content": "Content",
15
+ "primary_info_area": "Primary information area",
16
+ "status_indicator": "Status indicator",
17
+ "form": "Form",
18
+ "field": "Field",
19
+ "description": "Description",
20
+ "contract": "Contract",
21
+ "actor": "Actor",
22
+ "detailed_input_area": "Detailed Input Area",
23
+ "upload_area": "Upload Area",
24
+ "low_fidelity_wireframe": "Low-fidelity wireframe.",
25
+ "confirmation_text": "Confirmation text",
26
+ "header_and_navigation": "Header and navigation",
27
+ "content_section": "Content section",
28
+ "form_section": "Form section",
29
+ "text_input": "Text input",
30
+ "to_be_refined": "To be refined.",
31
+ "note": "Note",
32
+ "requirement_item": "Requirement item",
33
+ "contract_coverage": "Contract coverage",
34
+ "screen": "Screen",
35
+ "for_artifact": "for",
36
+ "fix_proposal": "Fix Proposal",
37
+ "fix_complete": "Fix complete — validation passed.",
38
+ "fix_still_failing": "Fix applied but validation still failing.",
39
+ "fix_cancelled": "Fix cancelled.",
40
+ "no_issues": "No blocking issues found. Nothing to fix.",
41
+ "issues_found": "Issues found",
42
+ "artifacts_to_regenerate": "Artifacts to regenerate",
43
+ "general": "General",
44
+ "suggestion_prefix": "→"
45
+ }
@@ -0,0 +1,58 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+
4
+ type TranslationMap = Record<string, string>;
5
+
6
+ const cache = new Map<string, TranslationMap>();
7
+
8
+ function loadJson(lang: string): TranslationMap {
9
+ if (cache.has(lang)) return cache.get(lang)!;
10
+ const filePath = path.resolve(__dirname, `${lang}.json`);
11
+ try {
12
+ const raw = fs.readFileSync(filePath, "utf8");
13
+ const parsed = JSON.parse(raw) as TranslationMap;
14
+ cache.set(lang, parsed);
15
+ return parsed;
16
+ } catch {
17
+ cache.set(lang, {});
18
+ return {};
19
+ }
20
+ }
21
+
22
+ function normalizeLang(lang?: string): string {
23
+ if (!lang) return "en";
24
+ const code = lang.toLowerCase().trim();
25
+ if (code.startsWith("tr")) return "tr";
26
+ if (code.startsWith("en")) return "en";
27
+ return code;
28
+ }
29
+
30
+ export function t(key: string, lang?: string): string {
31
+ const normalized = normalizeLang(lang);
32
+ const translations = loadJson(normalized);
33
+
34
+ if (key in translations) return translations[key];
35
+
36
+ if (normalized !== "en") {
37
+ const fallback = loadJson("en");
38
+ if (key in fallback) return fallback[key];
39
+ }
40
+
41
+ return key;
42
+ }
43
+
44
+ export function loadTranslations(lang: string): TranslationMap {
45
+ return { ...loadJson(normalizeLang(lang)) };
46
+ }
47
+
48
+ export function availableLanguages(): string[] {
49
+ const dir = path.resolve(__dirname);
50
+ try {
51
+ return fs.readdirSync(dir)
52
+ .filter((f) => f.endsWith(".json"))
53
+ .map((f) => f.replace(".json", ""))
54
+ .sort();
55
+ } catch {
56
+ return ["en"];
57
+ }
58
+ }
@@ -0,0 +1,45 @@
1
+ {
2
+ "user_action": "Kullanıcı işlemi",
3
+ "main_flow": "Ana Akış",
4
+ "user": "Kullanıcı",
5
+ "success": "Başarı",
6
+ "error": "Hata",
7
+ "flow_focus": "Akış Odağı",
8
+ "initial_version": "İlk sürüm",
9
+ "fix_revision": "Doğrulama sonrası düzeltme revizyonu",
10
+ "primary_user": "Birincil kullanıcı",
11
+ "back": "Geri",
12
+ "next": "Devam",
13
+ "save": "Kaydet",
14
+ "content": "İçerik",
15
+ "primary_info_area": "Birincil bilgi alanı",
16
+ "status_indicator": "Durum göstergesi",
17
+ "form": "Form",
18
+ "field": "Alan",
19
+ "description": "Açıklama",
20
+ "contract": "Kontrat",
21
+ "actor": "Aktör",
22
+ "detailed_input_area": "Detaylı Giriş Alanı",
23
+ "upload_area": "Dosya Alanı",
24
+ "low_fidelity_wireframe": "Düşük sadakatli wireframe.",
25
+ "confirmation_text": "Onay metni",
26
+ "header_and_navigation": "Başlık ve gezinme",
27
+ "content_section": "İçerik bölümü",
28
+ "form_section": "Form bölümü",
29
+ "text_input": "Metin alanı",
30
+ "to_be_refined": "Detay daha sonra netleştirilecek.",
31
+ "note": "Not",
32
+ "requirement_item": "Gereksinim maddesi",
33
+ "contract_coverage": "Kontrat kapsamı",
34
+ "screen": "Ekran",
35
+ "for_artifact": "için",
36
+ "fix_proposal": "Düzeltme Önerisi",
37
+ "fix_complete": "Düzeltme tamamlandı — doğrulama geçti.",
38
+ "fix_still_failing": "Düzeltme uygulandı ama doğrulama hâlâ başarısız.",
39
+ "fix_cancelled": "Düzeltme iptal edildi.",
40
+ "no_issues": "Engel teşkil eden sorun bulunamadı. Düzeltilecek bir şey yok.",
41
+ "issues_found": "Bulunan sorunlar",
42
+ "artifacts_to_regenerate": "Yeniden oluşturulacak artefaktlar",
43
+ "general": "Genel",
44
+ "suggestion_prefix": "→"
45
+ }
@@ -1,12 +1,29 @@
1
- import type { LLMProvider } from "../types";
2
- import { MockProvider } from "./mock-provider";
3
- import { OpenAIProvider } from "./openai-provider";
4
-
5
- export function createProvider(): LLMProvider {
6
- const provider = (process.env.PRODO_LLM_PROVIDER ?? "mock").toLowerCase();
7
- if (provider === "openai") {
8
- return new OpenAIProvider();
9
- }
10
- return new MockProvider();
11
- }
12
-
1
+ import type { LLMProvider } from "../core/types";
2
+ import { getGlobalRegistry } from "../agents/agent-registry";
3
+
4
+ let cachedProvider: LLMProvider | null = null;
5
+ let cachedAgentName: string | null = null;
6
+
7
+ export function createProvider(): LLMProvider {
8
+ const agentName =
9
+ process.env.PRODO_AGENT ??
10
+ process.env.PRODO_LLM_PROVIDER ??
11
+ "mock";
12
+
13
+ if (cachedProvider && cachedAgentName === agentName) {
14
+ return cachedProvider;
15
+ }
16
+
17
+ const registry = getGlobalRegistry();
18
+ const agent = registry.get(agentName);
19
+ if (!agent) {
20
+ const available = registry.list().map((a) => a.name).join(", ");
21
+ throw new Error(`Unknown agent: "${agentName}". Available: ${available}`);
22
+ }
23
+
24
+ cachedProvider = registry.toProvider(agent);
25
+ cachedAgentName = agentName;
26
+ return cachedProvider;
27
+ }
28
+
29
+ export { getGlobalRegistry } from "../agents/agent-registry";