@shahmarasy/prodo 0.1.4 → 0.1.6

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/cli/agent-command-installer.d.ts +4 -0
  18. package/dist/cli/agent-command-installer.js +148 -0
  19. package/dist/cli/agent-ids.d.ts +15 -0
  20. package/dist/cli/agent-ids.js +49 -0
  21. package/dist/cli/doctor.d.ts +1 -0
  22. package/dist/cli/doctor.js +144 -0
  23. package/dist/cli/fix-tui.d.ts +4 -0
  24. package/dist/cli/fix-tui.js +79 -0
  25. package/dist/cli/index.d.ts +9 -0
  26. package/dist/cli/index.js +467 -0
  27. package/dist/cli/init-tui.d.ts +23 -0
  28. package/dist/cli/init-tui.js +183 -0
  29. package/dist/cli/init.d.ts +12 -0
  30. package/dist/cli/init.js +335 -0
  31. package/dist/cli/normalize-interactive.d.ts +8 -0
  32. package/dist/cli/normalize-interactive.js +167 -0
  33. package/dist/cli/preset-loader.d.ts +4 -0
  34. package/dist/cli/preset-loader.js +210 -0
  35. package/dist/core/artifact-registry.d.ts +11 -0
  36. package/dist/core/artifact-registry.js +49 -0
  37. package/dist/core/artifacts.d.ts +10 -0
  38. package/dist/core/artifacts.js +892 -0
  39. package/dist/core/clean.d.ts +10 -0
  40. package/dist/core/clean.js +74 -0
  41. package/dist/core/consistency.d.ts +8 -0
  42. package/dist/core/consistency.js +328 -0
  43. package/dist/core/constants.d.ts +7 -0
  44. package/dist/core/constants.js +64 -0
  45. package/dist/core/errors.d.ts +3 -0
  46. package/dist/core/errors.js +10 -0
  47. package/dist/core/fix.d.ts +31 -0
  48. package/dist/core/fix.js +188 -0
  49. package/dist/core/hook-executor.d.ts +1 -0
  50. package/dist/core/hook-executor.js +175 -0
  51. package/dist/core/markdown.d.ts +16 -0
  52. package/dist/core/markdown.js +81 -0
  53. package/dist/core/normalize.d.ts +8 -0
  54. package/dist/core/normalize.js +125 -0
  55. package/dist/core/normalized-brief.d.ts +48 -0
  56. package/dist/core/normalized-brief.js +182 -0
  57. package/dist/core/output-index.d.ts +13 -0
  58. package/dist/core/output-index.js +55 -0
  59. package/dist/core/paths.d.ts +17 -0
  60. package/dist/core/paths.js +80 -0
  61. package/dist/core/project-config.d.ts +14 -0
  62. package/dist/core/project-config.js +69 -0
  63. package/dist/core/registry.d.ts +13 -0
  64. package/dist/core/registry.js +115 -0
  65. package/dist/core/settings.d.ts +8 -0
  66. package/dist/core/settings.js +43 -0
  67. package/dist/core/template-engine.d.ts +3 -0
  68. package/dist/core/template-engine.js +43 -0
  69. package/dist/core/template-resolver.d.ts +15 -0
  70. package/dist/core/template-resolver.js +46 -0
  71. package/dist/core/templates.d.ts +33 -0
  72. package/dist/core/templates.js +440 -0
  73. package/dist/core/terminology.d.ts +21 -0
  74. package/dist/core/terminology.js +143 -0
  75. package/dist/core/tracing.d.ts +21 -0
  76. package/dist/core/tracing.js +74 -0
  77. package/dist/core/types.d.ts +35 -0
  78. package/dist/core/types.js +5 -0
  79. package/dist/core/utils.d.ts +7 -0
  80. package/dist/core/utils.js +66 -0
  81. package/dist/core/validate.d.ts +10 -0
  82. package/dist/core/validate.js +226 -0
  83. package/dist/core/validator.d.ts +5 -0
  84. package/dist/core/validator.js +76 -0
  85. package/dist/core/version.d.ts +1 -0
  86. package/dist/core/version.js +30 -0
  87. package/dist/core/workflow-commands.d.ts +7 -0
  88. package/dist/core/workflow-commands.js +29 -0
  89. package/dist/i18n/en.json +45 -0
  90. package/dist/i18n/index.d.ts +5 -0
  91. package/dist/i18n/index.js +63 -0
  92. package/dist/i18n/tr.json +45 -0
  93. package/dist/providers/index.d.ts +2 -1
  94. package/dist/providers/index.js +20 -6
  95. package/dist/providers/mock-provider.d.ts +1 -1
  96. package/dist/providers/mock-provider.js +12 -11
  97. package/dist/providers/openai-provider.d.ts +1 -1
  98. package/dist/providers/openai-provider.js +13 -13
  99. package/dist/skill-engine/context.d.ts +7 -0
  100. package/dist/skill-engine/context.js +76 -0
  101. package/dist/skill-engine/discovery.d.ts +2 -0
  102. package/dist/skill-engine/discovery.js +52 -0
  103. package/dist/skill-engine/graph.d.ts +4 -0
  104. package/dist/skill-engine/graph.js +114 -0
  105. package/dist/skill-engine/index.d.ts +11 -0
  106. package/dist/skill-engine/index.js +49 -0
  107. package/dist/skill-engine/pipeline.d.ts +9 -0
  108. package/dist/skill-engine/pipeline.js +84 -0
  109. package/dist/skill-engine/registry.d.ts +12 -0
  110. package/dist/skill-engine/registry.js +74 -0
  111. package/dist/skill-engine/types.d.ts +66 -0
  112. package/dist/skill-engine/types.js +2 -0
  113. package/dist/skill-engine/validator.d.ts +4 -0
  114. package/dist/skill-engine/validator.js +90 -0
  115. package/dist/skills/engine.d.ts +10 -0
  116. package/dist/skills/engine.js +75 -0
  117. package/dist/skills/fix-skill.d.ts +2 -0
  118. package/dist/skills/fix-skill.js +38 -0
  119. package/dist/skills/fix.d.ts +2 -0
  120. package/dist/skills/fix.js +41 -0
  121. package/dist/skills/generate-artifact-skill.d.ts +2 -0
  122. package/dist/skills/generate-artifact-skill.js +32 -0
  123. package/dist/skills/generate-artifact.d.ts +2 -0
  124. package/dist/skills/generate-artifact.js +42 -0
  125. package/dist/skills/generate-pipeline-skill.d.ts +2 -0
  126. package/dist/skills/generate-pipeline-skill.js +45 -0
  127. package/dist/skills/normalize-skill.d.ts +2 -0
  128. package/dist/skills/normalize-skill.js +29 -0
  129. package/dist/skills/normalize.d.ts +2 -0
  130. package/dist/skills/normalize.js +29 -0
  131. package/dist/skills/register-core.d.ts +2 -0
  132. package/dist/skills/register-core.js +21 -0
  133. package/dist/skills/types.d.ts +28 -0
  134. package/dist/skills/types.js +2 -0
  135. package/dist/skills/validate-skill.d.ts +2 -0
  136. package/dist/skills/validate-skill.js +29 -0
  137. package/dist/skills/validate.d.ts +2 -0
  138. package/dist/skills/validate.js +37 -0
  139. package/package.json +72 -45
  140. package/src/agents/agent-registry.ts +93 -0
  141. package/src/agents/anthropic/index.ts +86 -0
  142. package/src/agents/anthropic/manifest.json +7 -0
  143. package/src/agents/base.ts +77 -0
  144. package/src/agents/google/index.ts +79 -0
  145. package/src/agents/google/manifest.json +7 -0
  146. package/src/agents/mock/index.ts +32 -0
  147. package/src/agents/mock/manifest.json +7 -0
  148. package/src/agents/openai/index.ts +83 -0
  149. package/src/agents/openai/manifest.json +7 -0
  150. package/src/agents/system-prompts.ts +35 -0
  151. package/src/{agent-command-installer.ts → cli/agent-command-installer.ts} +164 -164
  152. package/src/{agents.ts → cli/agent-ids.ts} +58 -58
  153. package/src/{doctor.ts → cli/doctor.ts} +157 -137
  154. package/src/cli/fix-tui.ts +111 -0
  155. package/src/{cli.ts → cli/index.ts} +463 -410
  156. package/src/{init-tui.ts → cli/init-tui.ts} +49 -37
  157. package/src/{init.ts → cli/init.ts} +399 -398
  158. package/src/cli/normalize-interactive.ts +241 -0
  159. package/src/{preset-loader.ts → cli/preset-loader.ts} +237 -237
  160. package/src/{artifact-registry.ts → core/artifact-registry.ts} +69 -69
  161. package/src/{artifacts.ts → core/artifacts.ts} +1081 -1072
  162. package/src/core/clean.ts +88 -0
  163. package/src/{consistency.ts → core/consistency.ts} +374 -303
  164. package/src/{constants.ts → core/constants.ts} +72 -72
  165. package/src/{errors.ts → core/errors.ts} +7 -7
  166. package/src/core/fix.ts +253 -0
  167. package/src/{hook-executor.ts → core/hook-executor.ts} +196 -196
  168. package/src/{markdown.ts → core/markdown.ts} +93 -73
  169. package/src/{normalize.ts → core/normalize.ts} +145 -137
  170. package/src/{normalized-brief.ts → core/normalized-brief.ts} +227 -206
  171. package/src/{output-index.ts → core/output-index.ts} +59 -59
  172. package/src/{paths.ts → core/paths.ts} +75 -71
  173. package/src/{project-config.ts → core/project-config.ts} +78 -78
  174. package/src/{registry.ts → core/registry.ts} +119 -119
  175. package/src/{settings.ts → core/settings.ts} +8 -2
  176. package/src/core/template-engine.ts +45 -0
  177. package/src/{template-resolver.ts → core/template-resolver.ts} +54 -54
  178. package/src/{templates.ts → core/templates.ts} +452 -452
  179. package/src/core/terminology.ts +177 -0
  180. package/src/core/tracing.ts +110 -0
  181. package/src/{types.ts → core/types.ts} +46 -46
  182. package/src/{utils.ts → core/utils.ts} +64 -64
  183. package/src/{validate.ts → core/validate.ts} +252 -246
  184. package/src/{validator.ts → core/validator.ts} +92 -92
  185. package/src/{version.ts → core/version.ts} +24 -24
  186. package/src/{workflow-commands.ts → core/workflow-commands.ts} +32 -32
  187. package/src/i18n/en.json +45 -0
  188. package/src/i18n/index.ts +58 -0
  189. package/src/i18n/tr.json +45 -0
  190. package/src/providers/index.ts +29 -12
  191. package/src/providers/mock-provider.ts +200 -199
  192. package/src/providers/openai-provider.ts +88 -88
  193. package/src/skill-engine/context.ts +90 -0
  194. package/src/skill-engine/discovery.ts +57 -0
  195. package/src/skill-engine/graph.ts +136 -0
  196. package/src/skill-engine/index.ts +55 -0
  197. package/src/skill-engine/pipeline.ts +112 -0
  198. package/src/skill-engine/registry.ts +75 -0
  199. package/src/skill-engine/types.ts +81 -0
  200. package/src/skill-engine/validator.ts +135 -0
  201. package/src/skills/fix.ts +45 -0
  202. package/src/skills/generate-artifact.ts +48 -0
  203. package/src/skills/normalize.ts +32 -0
  204. package/src/skills/register-core.ts +27 -0
  205. package/src/skills/validate.ts +40 -0
@@ -1,137 +1,145 @@
1
- import fs from "node:fs/promises";
2
- import path from "node:path";
3
- import { UserError } from "./errors";
4
- import {
5
- buildContractsFromArrays,
6
- parseNormalizedBriefOrThrow,
7
- requireConfidenceOrThrow
8
- } from "./normalized-brief";
9
- import { briefPath, normalizedBriefPath, prodoPath } from "./paths";
10
- import { createProvider } from "./providers";
11
- import { readSettings } from "./settings";
12
- import { fileExists, isPathInside } from "./utils";
13
-
14
- type NormalizeOptions = {
15
- cwd: string;
16
- brief?: string;
17
- out?: string;
18
- };
19
-
20
- function normalizedKey(value: string): string {
21
- return value
22
- .normalize("NFD")
23
- .replace(/[\u0300-\u036f]/g, "")
24
- .replace(/ı/g, "i")
25
- .replace(/İ/g, "I")
26
- .toLowerCase()
27
- .replace(/[^a-z0-9]+/g, " ")
28
- .trim();
29
- }
30
-
31
- function extractBriefProductName(rawBrief: string): string | undefined {
32
- const lines = rawBrief.split(/\r?\n/);
33
- for (let index = 0; index < lines.length; index += 1) {
34
- const headingMatch = lines[index].match(/^\s*#{1,6}\s+(.+?)\s*$/);
35
- if (!headingMatch) continue;
36
- const headingKey = normalizedKey(headingMatch[1]);
37
- const isProductHeading =
38
- headingKey === "product name" ||
39
- headingKey === "project name" ||
40
- headingKey === "urun adi" ||
41
- headingKey === "urun ismi";
42
- if (!isProductHeading) continue;
43
-
44
- for (let cursor = index + 1; cursor < lines.length; cursor += 1) {
45
- const rawLine = lines[cursor].trim();
46
- if (!rawLine) continue;
47
- if (/^\s*#{1,6}\s+/.test(rawLine)) break;
48
- const cleaned = rawLine.replace(/^\s*[-*]\s*/, "").trim();
49
- if (cleaned.length > 0) return cleaned;
50
- }
51
- }
52
- return undefined;
53
- }
54
-
55
- function preserveOriginalProductName(
56
- parsed: Record<string, unknown>,
57
- rawBrief: string
58
- ): Record<string, unknown> {
59
- const briefProductName = extractBriefProductName(rawBrief);
60
- if (!briefProductName) return parsed;
61
- const generated = typeof parsed.product_name === "string" ? parsed.product_name : "";
62
- if (!generated.trim()) return { ...parsed, product_name: briefProductName };
63
- if (normalizedKey(generated) !== normalizedKey(briefProductName)) return parsed;
64
- return { ...parsed, product_name: briefProductName };
65
- }
66
-
67
- function extractJsonObject(raw: string): Record<string, unknown> {
68
- const trimmed = raw.trim();
69
- const fenced = trimmed.match(/```(?:json)?\s*([\s\S]*?)```/i);
70
- const candidate = fenced ? fenced[1] : trimmed;
71
- try {
72
- return JSON.parse(candidate) as Record<string, unknown>;
73
- } catch {
74
- throw new UserError("Normalizer provider did not return valid JSON.");
75
- }
76
- }
77
-
78
- export async function runNormalize(options: NormalizeOptions): Promise<string> {
79
- const { cwd } = options;
80
- const root = prodoPath(cwd);
81
- if (!(await fileExists(root))) {
82
- throw new UserError("Missing .prodo directory. Run `prodo init .` first.");
83
- }
84
-
85
- const inPath = options.brief ? path.resolve(cwd, options.brief) : briefPath(cwd);
86
- if (!(await fileExists(inPath))) {
87
- throw new UserError(`Brief file not found: ${inPath}`);
88
- }
89
-
90
- const rawBrief = await fs.readFile(inPath, "utf8");
91
- const normalizePromptPath = path.join(root, "prompts", "normalize.md");
92
- const normalizePrompt = await fs.readFile(normalizePromptPath, "utf8");
93
- const settings = await readSettings(cwd);
94
- const provider = createProvider();
95
-
96
- const generated = await provider.generate(
97
- normalizePrompt,
98
- {
99
- briefMarkdown: rawBrief,
100
- sourceBriefPath: inPath,
101
- outputLanguage: settings.lang
102
- },
103
- {
104
- artifactType: "normalize",
105
- requiredHeadings: [],
106
- requiredContracts: []
107
- }
108
- );
109
-
110
- const parsed = extractJsonObject(generated.body);
111
- const preserved = preserveOriginalProductName(parsed, rawBrief);
112
- const withContracts = {
113
- ...preserved,
114
- contracts:
115
- preserved.contracts ??
116
- buildContractsFromArrays({
117
- goals: Array.isArray(preserved.goals) ? preserved.goals.filter((x): x is string => typeof x === "string") : [],
118
- core_features: Array.isArray(preserved.core_features)
119
- ? preserved.core_features.filter((x): x is string => typeof x === "string")
120
- : [],
121
- constraints: Array.isArray(preserved.constraints)
122
- ? preserved.constraints.filter((x): x is string => typeof x === "string")
123
- : []
124
- })
125
- };
126
-
127
- const normalized = parseNormalizedBriefOrThrow(withContracts);
128
- requireConfidenceOrThrow(normalized, ["product_name", "problem", "audience", "goals", "core_features"], 0.7);
129
-
130
- const outPath = options.out ? path.resolve(cwd, options.out) : normalizedBriefPath(cwd);
131
- if (!isPathInside(prodoPath(cwd), outPath)) {
132
- throw new UserError("Normalize output must be inside `.prodo/`.");
133
- }
134
- await fs.mkdir(path.dirname(outPath), { recursive: true });
135
- await fs.writeFile(outPath, `${JSON.stringify(normalized, null, 2)}\n`, "utf8");
136
- return outPath;
137
- }
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { UserError } from "./errors";
4
+ import {
5
+ buildContractsFromArrays,
6
+ parseNormalizedBriefOrThrow,
7
+ requireConfidenceOrThrow
8
+ } from "./normalized-brief";
9
+ import { briefPath, normalizedBriefPath, prodoPath } from "./paths";
10
+ import { createProvider } from "../providers";
11
+ import { readSettings } from "./settings";
12
+ import { fileExists, isPathInside } from "./utils";
13
+
14
+ type NormalizeOptions = {
15
+ cwd: string;
16
+ brief?: string;
17
+ out?: string;
18
+ additionalContext?: Record<string, string>;
19
+ };
20
+
21
+ function normalizedKey(value: string): string {
22
+ return value
23
+ .normalize("NFD")
24
+ .replace(/[\u0300-\u036f]/g, "")
25
+ .replace(/ı/g, "i")
26
+ .replace(/İ/g, "I")
27
+ .toLowerCase()
28
+ .replace(/[^a-z0-9]+/g, " ")
29
+ .trim();
30
+ }
31
+
32
+ function extractBriefProductName(rawBrief: string): string | undefined {
33
+ const lines = rawBrief.split(/\r?\n/);
34
+ for (let index = 0; index < lines.length; index += 1) {
35
+ const headingMatch = lines[index].match(/^\s*#{1,6}\s+(.+?)\s*$/);
36
+ if (!headingMatch) continue;
37
+ const headingKey = normalizedKey(headingMatch[1]);
38
+ const isProductHeading =
39
+ headingKey === "product name" ||
40
+ headingKey === "project name" ||
41
+ headingKey === "urun adi" ||
42
+ headingKey === "urun ismi";
43
+ if (!isProductHeading) continue;
44
+
45
+ for (let cursor = index + 1; cursor < lines.length; cursor += 1) {
46
+ const rawLine = lines[cursor].trim();
47
+ if (!rawLine) continue;
48
+ if (/^\s*#{1,6}\s+/.test(rawLine)) break;
49
+ const cleaned = rawLine.replace(/^\s*[-*]\s*/, "").trim();
50
+ if (cleaned.length > 0) return cleaned;
51
+ }
52
+ }
53
+ return undefined;
54
+ }
55
+
56
+ function preserveOriginalProductName(
57
+ parsed: Record<string, unknown>,
58
+ rawBrief: string
59
+ ): Record<string, unknown> {
60
+ const briefProductName = extractBriefProductName(rawBrief);
61
+ if (!briefProductName) return parsed;
62
+ const generated = typeof parsed.product_name === "string" ? parsed.product_name : "";
63
+ if (!generated.trim()) return { ...parsed, product_name: briefProductName };
64
+ if (normalizedKey(generated) !== normalizedKey(briefProductName)) return parsed;
65
+ return { ...parsed, product_name: briefProductName };
66
+ }
67
+
68
+ function extractJsonObject(raw: string): Record<string, unknown> {
69
+ const trimmed = raw.trim();
70
+ const fenced = trimmed.match(/```(?:json)?\s*([\s\S]*?)```/i);
71
+ const candidate = fenced ? fenced[1] : trimmed;
72
+ try {
73
+ return JSON.parse(candidate) as Record<string, unknown>;
74
+ } catch {
75
+ throw new UserError("Normalizer provider did not return valid JSON.");
76
+ }
77
+ }
78
+
79
+ export async function runNormalize(options: NormalizeOptions): Promise<string> {
80
+ const { cwd } = options;
81
+ const root = prodoPath(cwd);
82
+ if (!(await fileExists(root))) {
83
+ throw new UserError("Missing .prodo directory. Run `prodo init .` first.");
84
+ }
85
+
86
+ const inPath = options.brief ? path.resolve(cwd, options.brief) : briefPath(cwd);
87
+ if (!(await fileExists(inPath))) {
88
+ throw new UserError(`Brief file not found: ${inPath}`);
89
+ }
90
+
91
+ const rawBrief = await fs.readFile(inPath, "utf8");
92
+ const normalizePromptPath = path.join(root, "prompts", "normalize.md");
93
+ const normalizePrompt = await fs.readFile(normalizePromptPath, "utf8");
94
+ const settings = await readSettings(cwd);
95
+ const provider = createProvider();
96
+
97
+ const inputContext: Record<string, unknown> = {
98
+ briefMarkdown: rawBrief,
99
+ sourceBriefPath: inPath,
100
+ outputLanguage: settings.lang
101
+ };
102
+ if (options.additionalContext && Object.keys(options.additionalContext).length > 0) {
103
+ inputContext.userClarifications = options.additionalContext;
104
+ }
105
+
106
+ const generated = await provider.generate(
107
+ normalizePrompt,
108
+ inputContext,
109
+ {
110
+ artifactType: "normalize",
111
+ requiredHeadings: [],
112
+ requiredContracts: []
113
+ }
114
+ );
115
+
116
+ const parsed = extractJsonObject(generated.body);
117
+ const preserved = preserveOriginalProductName(parsed, rawBrief);
118
+ const withContracts = {
119
+ ...preserved,
120
+ contracts:
121
+ preserved.contracts ??
122
+ buildContractsFromArrays({
123
+ goals: Array.isArray(preserved.goals) ? preserved.goals.filter((x): x is string => typeof x === "string") : [],
124
+ core_features: Array.isArray(preserved.core_features)
125
+ ? preserved.core_features.filter((x): x is string => typeof x === "string")
126
+ : [],
127
+ constraints: Array.isArray(preserved.constraints)
128
+ ? preserved.constraints.filter((x): x is string => typeof x === "string")
129
+ : []
130
+ })
131
+ };
132
+
133
+ const normalized = parseNormalizedBriefOrThrow(withContracts);
134
+
135
+ const outPath = options.out ? path.resolve(cwd, options.out) : normalizedBriefPath(cwd);
136
+ if (!isPathInside(prodoPath(cwd), outPath)) {
137
+ throw new UserError("Normalize output must be inside `.prodo/`.");
138
+ }
139
+ await fs.mkdir(path.dirname(outPath), { recursive: true });
140
+ await fs.writeFile(outPath, `${JSON.stringify(normalized, null, 2)}\n`, "utf8");
141
+
142
+ requireConfidenceOrThrow(normalized, ["product_name", "problem", "audience", "goals", "core_features"], 0.7);
143
+
144
+ return outPath;
145
+ }