@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.
- package/README.md +201 -97
- package/bin/prodo.cjs +6 -6
- package/dist/agents/agent-registry.d.ts +13 -0
- package/dist/agents/agent-registry.js +79 -0
- package/dist/agents/anthropic/index.d.ts +9 -0
- package/dist/agents/anthropic/index.js +55 -0
- package/dist/agents/base.d.ts +25 -0
- package/dist/agents/base.js +71 -0
- package/dist/agents/google/index.d.ts +9 -0
- package/dist/agents/google/index.js +53 -0
- package/dist/agents/mock/index.d.ts +11 -0
- package/dist/agents/mock/index.js +26 -0
- package/dist/agents/openai/index.d.ts +9 -0
- package/dist/agents/openai/index.js +57 -0
- package/dist/agents/system-prompts.d.ts +3 -0
- package/dist/agents/system-prompts.js +32 -0
- package/dist/agents.js +4 -2
- package/dist/artifacts.d.ts +1 -0
- package/dist/artifacts.js +265 -31
- package/dist/cli/agent-command-installer.d.ts +4 -0
- package/dist/cli/agent-command-installer.js +148 -0
- package/dist/cli/agent-ids.d.ts +15 -0
- package/dist/cli/agent-ids.js +49 -0
- package/dist/cli/doctor.d.ts +1 -0
- package/dist/cli/doctor.js +144 -0
- package/dist/cli/fix-tui.d.ts +4 -0
- package/dist/cli/fix-tui.js +79 -0
- package/dist/cli/index.d.ts +9 -0
- package/dist/cli/index.js +465 -0
- package/dist/cli/init-tui.d.ts +23 -0
- package/dist/cli/init-tui.js +176 -0
- package/dist/cli/init.d.ts +11 -0
- package/dist/cli/init.js +334 -0
- package/dist/cli/normalize-interactive.d.ts +8 -0
- package/dist/cli/normalize-interactive.js +167 -0
- package/dist/cli/preset-loader.d.ts +4 -0
- package/dist/cli/preset-loader.js +210 -0
- package/dist/cli.js +80 -3
- package/dist/core/artifact-registry.d.ts +11 -0
- package/dist/core/artifact-registry.js +49 -0
- package/dist/core/artifacts.d.ts +10 -0
- package/dist/core/artifacts.js +892 -0
- package/dist/core/clean.d.ts +10 -0
- package/dist/core/clean.js +74 -0
- package/dist/core/consistency.d.ts +8 -0
- package/dist/core/consistency.js +328 -0
- package/dist/core/constants.d.ts +7 -0
- package/dist/core/constants.js +64 -0
- package/dist/core/errors.d.ts +3 -0
- package/dist/core/errors.js +10 -0
- package/dist/core/fix.d.ts +31 -0
- package/dist/core/fix.js +188 -0
- package/dist/core/hook-executor.d.ts +1 -0
- package/dist/core/hook-executor.js +175 -0
- package/dist/core/markdown.d.ts +16 -0
- package/dist/core/markdown.js +81 -0
- package/dist/core/normalize.d.ts +8 -0
- package/dist/core/normalize.js +125 -0
- package/dist/core/normalized-brief.d.ts +48 -0
- package/dist/core/normalized-brief.js +182 -0
- package/dist/core/output-index.d.ts +13 -0
- package/dist/core/output-index.js +55 -0
- package/dist/core/paths.d.ts +17 -0
- package/dist/core/paths.js +80 -0
- package/dist/core/project-config.d.ts +14 -0
- package/dist/core/project-config.js +69 -0
- package/dist/core/registry.d.ts +13 -0
- package/dist/core/registry.js +115 -0
- package/dist/core/settings.d.ts +7 -0
- package/dist/core/settings.js +35 -0
- package/dist/core/template-engine.d.ts +3 -0
- package/dist/core/template-engine.js +43 -0
- package/dist/core/template-resolver.d.ts +15 -0
- package/dist/core/template-resolver.js +46 -0
- package/dist/core/templates.d.ts +33 -0
- package/dist/core/templates.js +440 -0
- package/dist/core/terminology.d.ts +21 -0
- package/dist/core/terminology.js +143 -0
- package/dist/core/tracing.d.ts +21 -0
- package/dist/core/tracing.js +74 -0
- package/dist/core/types.d.ts +35 -0
- package/dist/core/types.js +5 -0
- package/dist/core/utils.d.ts +7 -0
- package/dist/core/utils.js +66 -0
- package/dist/core/validate.d.ts +10 -0
- package/dist/core/validate.js +226 -0
- package/dist/core/validator.d.ts +5 -0
- package/dist/core/validator.js +76 -0
- package/dist/core/version.d.ts +1 -0
- package/dist/core/version.js +30 -0
- package/dist/core/workflow-commands.d.ts +7 -0
- package/dist/core/workflow-commands.js +29 -0
- package/dist/i18n/en.json +45 -0
- package/dist/i18n/index.d.ts +5 -0
- package/dist/i18n/index.js +63 -0
- package/dist/i18n/tr.json +45 -0
- package/dist/init-tui.d.ts +3 -0
- package/dist/init-tui.js +28 -1
- package/dist/init.d.ts +1 -0
- package/dist/init.js +9 -3
- package/dist/normalize.js +55 -7
- package/dist/providers/index.d.ts +2 -1
- package/dist/providers/index.js +20 -6
- package/dist/providers/mock-provider.d.ts +1 -1
- package/dist/providers/mock-provider.js +7 -6
- package/dist/providers/openai-provider.d.ts +1 -1
- package/dist/providers/openai-provider.js +3 -2
- package/dist/settings.d.ts +1 -0
- package/dist/settings.js +2 -1
- package/dist/skills/engine.d.ts +10 -0
- package/dist/skills/engine.js +75 -0
- package/dist/skills/fix-skill.d.ts +2 -0
- package/dist/skills/fix-skill.js +38 -0
- package/dist/skills/generate-artifact-skill.d.ts +2 -0
- package/dist/skills/generate-artifact-skill.js +32 -0
- package/dist/skills/generate-pipeline-skill.d.ts +2 -0
- package/dist/skills/generate-pipeline-skill.js +45 -0
- package/dist/skills/normalize-skill.d.ts +2 -0
- package/dist/skills/normalize-skill.js +29 -0
- package/dist/skills/types.d.ts +28 -0
- package/dist/skills/types.js +2 -0
- package/dist/skills/validate-skill.d.ts +2 -0
- package/dist/skills/validate-skill.js +29 -0
- package/dist/templates.d.ts +1 -1
- package/dist/templates.js +2 -0
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +13 -0
- package/dist/validator.js +0 -4
- package/dist/workflow-commands.js +2 -1
- package/package.json +74 -45
- package/presets/fintech/preset.json +48 -1
- package/presets/fintech/prompts/prd.md +99 -2
- package/presets/marketplace/preset.json +51 -1
- package/presets/marketplace/prompts/prd.md +140 -2
- package/presets/saas/preset.json +53 -1
- package/presets/saas/prompts/prd.md +150 -2
- package/src/agents/agent-registry.ts +93 -0
- package/src/agents/anthropic/index.ts +86 -0
- package/src/agents/anthropic/manifest.json +7 -0
- package/src/agents/base.ts +77 -0
- package/src/agents/google/index.ts +79 -0
- package/src/agents/google/manifest.json +7 -0
- package/src/agents/mock/index.ts +32 -0
- package/src/agents/mock/manifest.json +7 -0
- package/src/agents/openai/index.ts +83 -0
- package/src/agents/openai/manifest.json +7 -0
- package/src/agents/system-prompts.ts +35 -0
- package/src/{agent-command-installer.ts → cli/agent-command-installer.ts} +164 -164
- package/src/{agents.ts → cli/agent-ids.ts} +58 -56
- package/src/{doctor.ts → cli/doctor.ts} +157 -137
- package/src/cli/fix-tui.ts +111 -0
- package/src/{cli.ts → cli/index.ts} +459 -319
- package/src/{init-tui.ts → cli/init-tui.ts} +208 -179
- package/src/{init.ts → cli/init.ts} +398 -391
- package/src/cli/normalize-interactive.ts +241 -0
- package/src/{preset-loader.ts → cli/preset-loader.ts} +237 -237
- package/src/{artifact-registry.ts → core/artifact-registry.ts} +69 -69
- package/src/{artifacts.ts → core/artifacts.ts} +1081 -777
- package/src/core/clean.ts +88 -0
- package/src/{consistency.ts → core/consistency.ts} +374 -303
- package/src/{constants.ts → core/constants.ts} +72 -72
- package/src/{errors.ts → core/errors.ts} +7 -7
- package/src/core/fix.ts +253 -0
- package/src/{hook-executor.ts → core/hook-executor.ts} +196 -196
- package/src/{markdown.ts → core/markdown.ts} +93 -73
- package/src/core/normalize.ts +145 -0
- package/src/{normalized-brief.ts → core/normalized-brief.ts} +227 -206
- package/src/{output-index.ts → core/output-index.ts} +59 -59
- package/src/{paths.ts → core/paths.ts} +75 -71
- package/src/{project-config.ts → core/project-config.ts} +78 -78
- package/src/{registry.ts → core/registry.ts} +119 -119
- package/src/{settings.ts → core/settings.ts} +35 -34
- package/src/core/template-engine.ts +45 -0
- package/src/{template-resolver.ts → core/template-resolver.ts} +54 -54
- package/src/{templates.ts → core/templates.ts} +452 -450
- package/src/core/terminology.ts +177 -0
- package/src/core/tracing.ts +110 -0
- package/src/{types.ts → core/types.ts} +46 -46
- package/src/{utils.ts → core/utils.ts} +64 -50
- package/src/{validate.ts → core/validate.ts} +252 -246
- package/src/{validator.ts → core/validator.ts} +92 -96
- package/src/{version.ts → core/version.ts} +24 -24
- package/src/{workflow-commands.ts → core/workflow-commands.ts} +32 -31
- package/src/i18n/en.json +45 -0
- package/src/i18n/index.ts +58 -0
- package/src/i18n/tr.json +45 -0
- package/src/providers/index.ts +29 -12
- package/src/providers/mock-provider.ts +200 -199
- package/src/providers/openai-provider.ts +88 -87
- package/src/skills/engine.ts +94 -0
- package/src/skills/fix-skill.ts +38 -0
- package/src/skills/generate-artifact-skill.ts +32 -0
- package/src/skills/generate-pipeline-skill.ts +49 -0
- package/src/skills/normalize-skill.ts +29 -0
- package/src/skills/types.ts +36 -0
- package/src/skills/validate-skill.ts +29 -0
- package/templates/commands/prodo-fix.md +46 -0
- package/templates/commands/prodo-normalize.md +118 -23
- package/templates/commands/prodo-prd.md +138 -17
- package/templates/commands/prodo-stories.md +153 -17
- package/templates/commands/prodo-techspec.md +167 -17
- package/templates/commands/prodo-validate.md +184 -26
- package/templates/commands/prodo-wireframe.md +188 -17
- package/templates/commands/prodo-workflow.md +200 -17
- package/src/normalize.ts +0 -89
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.t = t;
|
|
7
|
+
exports.loadTranslations = loadTranslations;
|
|
8
|
+
exports.availableLanguages = availableLanguages;
|
|
9
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
const cache = new Map();
|
|
12
|
+
function loadJson(lang) {
|
|
13
|
+
if (cache.has(lang))
|
|
14
|
+
return cache.get(lang);
|
|
15
|
+
const filePath = node_path_1.default.resolve(__dirname, `${lang}.json`);
|
|
16
|
+
try {
|
|
17
|
+
const raw = node_fs_1.default.readFileSync(filePath, "utf8");
|
|
18
|
+
const parsed = JSON.parse(raw);
|
|
19
|
+
cache.set(lang, parsed);
|
|
20
|
+
return parsed;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
cache.set(lang, {});
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function normalizeLang(lang) {
|
|
28
|
+
if (!lang)
|
|
29
|
+
return "en";
|
|
30
|
+
const code = lang.toLowerCase().trim();
|
|
31
|
+
if (code.startsWith("tr"))
|
|
32
|
+
return "tr";
|
|
33
|
+
if (code.startsWith("en"))
|
|
34
|
+
return "en";
|
|
35
|
+
return code;
|
|
36
|
+
}
|
|
37
|
+
function t(key, lang) {
|
|
38
|
+
const normalized = normalizeLang(lang);
|
|
39
|
+
const translations = loadJson(normalized);
|
|
40
|
+
if (key in translations)
|
|
41
|
+
return translations[key];
|
|
42
|
+
if (normalized !== "en") {
|
|
43
|
+
const fallback = loadJson("en");
|
|
44
|
+
if (key in fallback)
|
|
45
|
+
return fallback[key];
|
|
46
|
+
}
|
|
47
|
+
return key;
|
|
48
|
+
}
|
|
49
|
+
function loadTranslations(lang) {
|
|
50
|
+
return { ...loadJson(normalizeLang(lang)) };
|
|
51
|
+
}
|
|
52
|
+
function availableLanguages() {
|
|
53
|
+
const dir = node_path_1.default.resolve(__dirname);
|
|
54
|
+
try {
|
|
55
|
+
return node_fs_1.default.readdirSync(dir)
|
|
56
|
+
.filter((f) => f.endsWith(".json"))
|
|
57
|
+
.map((f) => f.replace(".json", ""))
|
|
58
|
+
.sort();
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return ["en"];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -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
|
+
}
|
package/dist/init-tui.d.ts
CHANGED
|
@@ -3,12 +3,14 @@ export type InitSelections = {
|
|
|
3
3
|
ai?: SupportedAi;
|
|
4
4
|
script: "sh" | "ps";
|
|
5
5
|
lang: "tr" | "en";
|
|
6
|
+
author: string;
|
|
6
7
|
interactive: boolean;
|
|
7
8
|
};
|
|
8
9
|
type GatherInitUiOptions = {
|
|
9
10
|
projectRoot: string;
|
|
10
11
|
aiInput?: string;
|
|
11
12
|
langInput?: string;
|
|
13
|
+
authorInput?: string;
|
|
12
14
|
};
|
|
13
15
|
export declare function gatherInitSelections(options: GatherInitUiOptions): Promise<InitSelections>;
|
|
14
16
|
export declare function finishInitInteractive(summary: {
|
|
@@ -16,5 +18,6 @@ export declare function finishInitInteractive(summary: {
|
|
|
16
18
|
settingsPath: string;
|
|
17
19
|
ai?: SupportedAi;
|
|
18
20
|
lang: "tr" | "en";
|
|
21
|
+
author: string;
|
|
19
22
|
}): Promise<void>;
|
|
20
23
|
export {};
|
package/dist/init-tui.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.gatherInitSelections = gatherInitSelections;
|
|
7
7
|
exports.finishInitInteractive = finishInitInteractive;
|
|
8
8
|
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
9
10
|
const agent_command_installer_1 = require("./agent-command-installer");
|
|
10
11
|
const errors_1 = require("./errors");
|
|
11
12
|
const utils_1 = require("./utils");
|
|
@@ -75,16 +76,32 @@ function modelChoiceFromAi(ai) {
|
|
|
75
76
|
return "gemini";
|
|
76
77
|
return "auto-detect";
|
|
77
78
|
}
|
|
79
|
+
function defaultAuthorName(authorInput) {
|
|
80
|
+
const explicit = (authorInput ?? "").trim();
|
|
81
|
+
if (explicit.length > 0)
|
|
82
|
+
return explicit;
|
|
83
|
+
try {
|
|
84
|
+
const username = node_os_1.default.userInfo().username.trim();
|
|
85
|
+
if (username.length > 0)
|
|
86
|
+
return username;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// ignore lookup errors and continue with fallback
|
|
90
|
+
}
|
|
91
|
+
return "Product Author";
|
|
92
|
+
}
|
|
78
93
|
async function gatherInitSelections(options) {
|
|
79
94
|
const clack = await loadClack();
|
|
80
95
|
const defaultLang = normalizeLang(options.langInput);
|
|
81
96
|
const fallbackScript = process.platform === "win32" ? "ps" : "sh";
|
|
82
97
|
const parsedAi = (0, agent_command_installer_1.resolveAi)(options.aiInput);
|
|
98
|
+
const defaultAuthor = defaultAuthorName(options.authorInput);
|
|
83
99
|
if (!isInteractiveTerminal()) {
|
|
84
100
|
return {
|
|
85
101
|
ai: parsedAi,
|
|
86
102
|
script: fallbackScript,
|
|
87
103
|
lang: defaultLang,
|
|
104
|
+
author: defaultAuthor,
|
|
88
105
|
interactive: false
|
|
89
106
|
};
|
|
90
107
|
}
|
|
@@ -129,6 +146,15 @@ async function gatherInitSelections(options) {
|
|
|
129
146
|
clack.cancel("Initialization cancelled.");
|
|
130
147
|
throw new errors_1.UserError("Initialization cancelled.");
|
|
131
148
|
}
|
|
149
|
+
const author = await clack.text({
|
|
150
|
+
message: "Author name",
|
|
151
|
+
placeholder: "Shahmarasy",
|
|
152
|
+
defaultValue: defaultAuthor
|
|
153
|
+
});
|
|
154
|
+
if (clack.isCancel(author)) {
|
|
155
|
+
clack.cancel("Initialization cancelled.");
|
|
156
|
+
throw new errors_1.UserError("Initialization cancelled.");
|
|
157
|
+
}
|
|
132
158
|
let selectedAi;
|
|
133
159
|
if (model === "codex")
|
|
134
160
|
selectedAi = "codex";
|
|
@@ -140,10 +166,11 @@ async function gatherInitSelections(options) {
|
|
|
140
166
|
ai: selectedAi,
|
|
141
167
|
script: fallbackScript,
|
|
142
168
|
lang,
|
|
169
|
+
author: String(author).trim() || defaultAuthor,
|
|
143
170
|
interactive: true
|
|
144
171
|
};
|
|
145
172
|
}
|
|
146
173
|
function finishInitInteractive(summary) {
|
|
147
174
|
const aiText = summary.ai ?? "none";
|
|
148
|
-
return loadClack().then((clack) => clack.outro(`Scaffold complete.\nAI: ${aiText}\nLanguage: ${summary.lang}\nSettings: ${summary.settingsPath}\nNext: edit brief.md`));
|
|
175
|
+
return loadClack().then((clack) => clack.outro(`Scaffold complete.\nAI: ${aiText}\nLanguage: ${summary.lang}\nAuthor: ${summary.author}\nSettings: ${summary.settingsPath}\nNext: edit brief.md`));
|
|
149
176
|
}
|
package/dist/init.d.ts
CHANGED
package/dist/init.js
CHANGED
|
@@ -15,6 +15,7 @@ const paths_1 = require("./paths");
|
|
|
15
15
|
const preset_loader_1 = require("./preset-loader");
|
|
16
16
|
const registry_1 = require("./registry");
|
|
17
17
|
const settings_1 = require("./settings");
|
|
18
|
+
const template_resolver_1 = require("./template-resolver");
|
|
18
19
|
const workflow_commands_1 = require("./workflow-commands");
|
|
19
20
|
const templates_1 = require("./templates");
|
|
20
21
|
function templateFileName(artifactType) {
|
|
@@ -272,12 +273,16 @@ async function runInit(cwd, options) {
|
|
|
272
273
|
await writeFileIfMissing(node_path_1.default.join(root, "hooks.yml"), templates_1.HOOKS_TEMPLATE);
|
|
273
274
|
await writeFileIfMissing(node_path_1.default.join(root, "prompts", "normalize.md"), `${templates_1.NORMALIZE_PROMPT_TEMPLATE}\n`);
|
|
274
275
|
const scriptType = options?.script ?? (process.platform === "win32" ? "ps" : "sh");
|
|
275
|
-
await promises_1.default.writeFile(node_path_1.default.join(root, "init-options.json"), `${JSON.stringify({ ai: options?.ai ?? null, lang: options?.lang ?? "en", preset: options?.preset ?? null, script: scriptType }, null, 2)}\n`, "utf8");
|
|
276
|
+
await promises_1.default.writeFile(node_path_1.default.join(root, "init-options.json"), `${JSON.stringify({ ai: options?.ai ?? null, lang: options?.lang ?? "en", author: options?.author ?? null, preset: options?.preset ?? null, script: scriptType }, null, 2)}\n`, "utf8");
|
|
276
277
|
await copyDirIfMissing(node_path_1.default.join(projectScaffoldTemplates, "artifacts"), node_path_1.default.join(root, "templates"), copiedAssets);
|
|
277
278
|
for (const artifact of artifactDefs) {
|
|
279
|
+
const markdownTemplatePath = node_path_1.default.join(root, "templates", `${artifact.name}.md`);
|
|
280
|
+
const templateHeadings = (await (0, utils_1.fileExists)(markdownTemplatePath))
|
|
281
|
+
? (0, template_resolver_1.extractRequiredHeadingsFromTemplate)(await promises_1.default.readFile(markdownTemplatePath, "utf8"))
|
|
282
|
+
: [];
|
|
278
283
|
const schema = {
|
|
279
284
|
...(0, templates_1.schemaTemplate)(artifact.name),
|
|
280
|
-
x_required_headings: artifact.required_headings
|
|
285
|
+
x_required_headings: templateHeadings.length > 0 ? templateHeadings : artifact.required_headings
|
|
281
286
|
};
|
|
282
287
|
await writeFileIfMissing(node_path_1.default.join(root, "schemas", `${artifact.name}.yaml`), js_yaml_1.default.dump(schema));
|
|
283
288
|
await writeFileIfMissing(node_path_1.default.join(root, "prompts", `${artifact.name}.md`), `${(0, templates_1.promptTemplate)(artifact.name, options?.lang ?? "en")}\n`);
|
|
@@ -322,7 +327,8 @@ async function runInit(cwd, options) {
|
|
|
322
327
|
await (0, registry_1.syncRegistry)(cwd);
|
|
323
328
|
const settingsPath = await (0, settings_1.writeSettings)(cwd, {
|
|
324
329
|
lang: (options?.lang ?? "en").trim() || "en",
|
|
325
|
-
ai: options?.ai
|
|
330
|
+
ai: options?.ai,
|
|
331
|
+
author: (options?.author ?? "").trim() || undefined
|
|
326
332
|
});
|
|
327
333
|
return { installedAgentFiles, settingsPath };
|
|
328
334
|
}
|
package/dist/normalize.js
CHANGED
|
@@ -12,6 +12,53 @@ const paths_1 = require("./paths");
|
|
|
12
12
|
const providers_1 = require("./providers");
|
|
13
13
|
const settings_1 = require("./settings");
|
|
14
14
|
const utils_1 = require("./utils");
|
|
15
|
+
function normalizedKey(value) {
|
|
16
|
+
return value
|
|
17
|
+
.normalize("NFD")
|
|
18
|
+
.replace(/[\u0300-\u036f]/g, "")
|
|
19
|
+
.replace(/ı/g, "i")
|
|
20
|
+
.replace(/İ/g, "I")
|
|
21
|
+
.toLowerCase()
|
|
22
|
+
.replace(/[^a-z0-9]+/g, " ")
|
|
23
|
+
.trim();
|
|
24
|
+
}
|
|
25
|
+
function extractBriefProductName(rawBrief) {
|
|
26
|
+
const lines = rawBrief.split(/\r?\n/);
|
|
27
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
28
|
+
const headingMatch = lines[index].match(/^\s*#{1,6}\s+(.+?)\s*$/);
|
|
29
|
+
if (!headingMatch)
|
|
30
|
+
continue;
|
|
31
|
+
const headingKey = normalizedKey(headingMatch[1]);
|
|
32
|
+
const isProductHeading = headingKey === "product name" ||
|
|
33
|
+
headingKey === "project name" ||
|
|
34
|
+
headingKey === "urun adi" ||
|
|
35
|
+
headingKey === "urun ismi";
|
|
36
|
+
if (!isProductHeading)
|
|
37
|
+
continue;
|
|
38
|
+
for (let cursor = index + 1; cursor < lines.length; cursor += 1) {
|
|
39
|
+
const rawLine = lines[cursor].trim();
|
|
40
|
+
if (!rawLine)
|
|
41
|
+
continue;
|
|
42
|
+
if (/^\s*#{1,6}\s+/.test(rawLine))
|
|
43
|
+
break;
|
|
44
|
+
const cleaned = rawLine.replace(/^\s*[-*]\s*/, "").trim();
|
|
45
|
+
if (cleaned.length > 0)
|
|
46
|
+
return cleaned;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
function preserveOriginalProductName(parsed, rawBrief) {
|
|
52
|
+
const briefProductName = extractBriefProductName(rawBrief);
|
|
53
|
+
if (!briefProductName)
|
|
54
|
+
return parsed;
|
|
55
|
+
const generated = typeof parsed.product_name === "string" ? parsed.product_name : "";
|
|
56
|
+
if (!generated.trim())
|
|
57
|
+
return { ...parsed, product_name: briefProductName };
|
|
58
|
+
if (normalizedKey(generated) !== normalizedKey(briefProductName))
|
|
59
|
+
return parsed;
|
|
60
|
+
return { ...parsed, product_name: briefProductName };
|
|
61
|
+
}
|
|
15
62
|
function extractJsonObject(raw) {
|
|
16
63
|
const trimmed = raw.trim();
|
|
17
64
|
const fenced = trimmed.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
@@ -48,16 +95,17 @@ async function runNormalize(options) {
|
|
|
48
95
|
requiredContracts: []
|
|
49
96
|
});
|
|
50
97
|
const parsed = extractJsonObject(generated.body);
|
|
98
|
+
const preserved = preserveOriginalProductName(parsed, rawBrief);
|
|
51
99
|
const withContracts = {
|
|
52
|
-
...
|
|
53
|
-
contracts:
|
|
100
|
+
...preserved,
|
|
101
|
+
contracts: preserved.contracts ??
|
|
54
102
|
(0, normalized_brief_1.buildContractsFromArrays)({
|
|
55
|
-
goals: Array.isArray(
|
|
56
|
-
core_features: Array.isArray(
|
|
57
|
-
?
|
|
103
|
+
goals: Array.isArray(preserved.goals) ? preserved.goals.filter((x) => typeof x === "string") : [],
|
|
104
|
+
core_features: Array.isArray(preserved.core_features)
|
|
105
|
+
? preserved.core_features.filter((x) => typeof x === "string")
|
|
58
106
|
: [],
|
|
59
|
-
constraints: Array.isArray(
|
|
60
|
-
?
|
|
107
|
+
constraints: Array.isArray(preserved.constraints)
|
|
108
|
+
? preserved.constraints.filter((x) => typeof x === "string")
|
|
61
109
|
: []
|
|
62
110
|
})
|
|
63
111
|
};
|
package/dist/providers/index.js
CHANGED
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getGlobalRegistry = void 0;
|
|
3
4
|
exports.createProvider = createProvider;
|
|
4
|
-
const
|
|
5
|
-
|
|
5
|
+
const agent_registry_1 = require("../agents/agent-registry");
|
|
6
|
+
let cachedProvider = null;
|
|
7
|
+
let cachedAgentName = null;
|
|
6
8
|
function createProvider() {
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
const agentName = process.env.PRODO_AGENT ??
|
|
10
|
+
process.env.PRODO_LLM_PROVIDER ??
|
|
11
|
+
"mock";
|
|
12
|
+
if (cachedProvider && cachedAgentName === agentName) {
|
|
13
|
+
return cachedProvider;
|
|
10
14
|
}
|
|
11
|
-
|
|
15
|
+
const registry = (0, agent_registry_1.getGlobalRegistry)();
|
|
16
|
+
const agent = registry.get(agentName);
|
|
17
|
+
if (!agent) {
|
|
18
|
+
const available = registry.list().map((a) => a.name).join(", ");
|
|
19
|
+
throw new Error(`Unknown agent: "${agentName}". Available: ${available}`);
|
|
20
|
+
}
|
|
21
|
+
cachedProvider = registry.toProvider(agent);
|
|
22
|
+
cachedAgentName = agentName;
|
|
23
|
+
return cachedProvider;
|
|
12
24
|
}
|
|
25
|
+
var agent_registry_2 = require("../agents/agent-registry");
|
|
26
|
+
Object.defineProperty(exports, "getGlobalRegistry", { enumerable: true, get: function () { return agent_registry_2.getGlobalRegistry; } });
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { LLMProvider, ProviderSchemaHint } from "../types";
|
|
1
|
+
import type { LLMProvider, ProviderSchemaHint } from "../core/types";
|
|
2
2
|
export declare class MockProvider implements LLMProvider {
|
|
3
3
|
generate(_prompt: string, inputContext: Record<string, unknown>, schemaHint: ProviderSchemaHint): Promise<{
|
|
4
4
|
body: string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MockProvider = void 0;
|
|
4
|
+
const i18n_1 = require("../i18n");
|
|
4
5
|
function asStringArray(value) {
|
|
5
6
|
if (!Array.isArray(value))
|
|
6
7
|
return [];
|
|
@@ -107,18 +108,18 @@ function buildArtifactBody(schemaHint, inputContext) {
|
|
|
107
108
|
const lang = typeof inputContext.outputLanguage === "string" ? inputContext.outputLanguage.toLowerCase() : "en";
|
|
108
109
|
const items = normalizeSectionItems(inputContext);
|
|
109
110
|
const coverage = coverageItems(schemaHint, inputContext);
|
|
110
|
-
const localizedItems = lang === "tr" ? items.map((_, index) =>
|
|
111
|
+
const localizedItems = lang === "tr" ? items.map((_, index) => `${(0, i18n_1.t)("requirement_item", lang)} ${index + 1}`) : items;
|
|
111
112
|
const localizedCoverage = lang === "tr"
|
|
112
113
|
? coverage.map((item, index) => ({
|
|
113
114
|
id: item.id,
|
|
114
|
-
text:
|
|
115
|
+
text: `${(0, i18n_1.t)("contract_coverage", lang)} ${index + 1}`
|
|
115
116
|
}))
|
|
116
117
|
: coverage;
|
|
117
|
-
const fallback =
|
|
118
|
+
const fallback = (0, i18n_1.t)("to_be_refined", lang);
|
|
118
119
|
const sections = schemaHint.requiredHeadings.map((heading) => headingBlock(heading, localizedItems, fallback, localizedCoverage));
|
|
119
120
|
const title = lang === "tr"
|
|
120
|
-
? `# ${productName}
|
|
121
|
-
: `# ${schemaHint.artifactType.toUpperCase()}
|
|
121
|
+
? `# ${productName} ${(0, i18n_1.t)("for_artifact", lang)} ${schemaHint.artifactType.toUpperCase()}`
|
|
122
|
+
: `# ${schemaHint.artifactType.toUpperCase()} ${(0, i18n_1.t)("for_artifact", lang)} ${productName}`;
|
|
122
123
|
if (schemaHint.artifactType === "workflow") {
|
|
123
124
|
return `${title}\n\n${sections.join("\n")}\n\n\`\`\`mermaid
|
|
124
125
|
flowchart TD
|
|
@@ -127,7 +128,7 @@ flowchart TD
|
|
|
127
128
|
C --> D[Done]
|
|
128
129
|
\`\`\``.trim();
|
|
129
130
|
}
|
|
130
|
-
return `${title}\n\n${sections.join("\n")}\n\n${
|
|
131
|
+
return `${title}\n\n${sections.join("\n")}\n\n${(0, i18n_1.t)("note", lang)}: ${fallback}`.trim();
|
|
131
132
|
}
|
|
132
133
|
function semanticIssuesWithMock(inputContext) {
|
|
133
134
|
const pair = inputContext.pair;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.OpenAIProvider = void 0;
|
|
4
|
-
const errors_1 = require("../errors");
|
|
4
|
+
const errors_1 = require("../core/errors");
|
|
5
5
|
class OpenAIProvider {
|
|
6
6
|
apiKey;
|
|
7
7
|
model;
|
|
@@ -22,7 +22,8 @@ class OpenAIProvider {
|
|
|
22
22
|
const mode = schemaHint.artifactType;
|
|
23
23
|
const system = mode === "normalize"
|
|
24
24
|
? `You normalize messy human product briefs into strict JSON.
|
|
25
|
-
Return valid JSON only, no markdown. Include confidence scores (0..1) for critical fields
|
|
25
|
+
Return valid JSON only, no markdown. Include confidence scores (0..1) for critical fields.
|
|
26
|
+
Preserve source language and Unicode characters exactly; never transliterate Turkish letters to ASCII.`
|
|
26
27
|
: mode === "semantic_consistency"
|
|
27
28
|
? `You detect semantic inconsistencies between paired artifacts.
|
|
28
29
|
Return valid JSON only: { "issues": [{level, code, check, contract_id, file, message, suggestion}] }.`
|
package/dist/settings.d.ts
CHANGED
package/dist/settings.js
CHANGED
|
@@ -20,7 +20,8 @@ async function readSettings(cwd) {
|
|
|
20
20
|
const parsed = JSON.parse(raw);
|
|
21
21
|
return {
|
|
22
22
|
lang: typeof parsed.lang === "string" && parsed.lang.trim() ? parsed.lang.trim() : "en",
|
|
23
|
-
ai: typeof parsed.ai === "string" && parsed.ai.trim() ? parsed.ai.trim() : undefined
|
|
23
|
+
ai: typeof parsed.ai === "string" && parsed.ai.trim() ? parsed.ai.trim() : undefined,
|
|
24
|
+
author: typeof parsed.author === "string" && parsed.author.trim() ? parsed.author.trim() : undefined
|
|
24
25
|
};
|
|
25
26
|
}
|
|
26
27
|
catch {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Skill, SkillContext, SkillManifest } from "./types";
|
|
2
|
+
export type SkillEngine = {
|
|
3
|
+
register(skill: Skill): void;
|
|
4
|
+
getSkill(name: string): Skill | undefined;
|
|
5
|
+
listSkills(): SkillManifest[];
|
|
6
|
+
execute(name: string, context: SkillContext, inputs: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
export declare function createSkillEngine(): SkillEngine;
|
|
9
|
+
export declare function getGlobalSkillEngine(): SkillEngine;
|
|
10
|
+
export declare function resetGlobalSkillEngine(): void;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSkillEngine = createSkillEngine;
|
|
4
|
+
exports.getGlobalSkillEngine = getGlobalSkillEngine;
|
|
5
|
+
exports.resetGlobalSkillEngine = resetGlobalSkillEngine;
|
|
6
|
+
const errors_1 = require("../core/errors");
|
|
7
|
+
function validateInputs(skill, inputs) {
|
|
8
|
+
for (const input of skill.manifest.inputs) {
|
|
9
|
+
if (input.required && !(input.name in inputs)) {
|
|
10
|
+
throw new errors_1.UserError(`Skill "${skill.manifest.name}" requires input "${input.name}" (${input.description})`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function createSkillEngine() {
|
|
15
|
+
const skills = new Map();
|
|
16
|
+
return {
|
|
17
|
+
register(skill) {
|
|
18
|
+
skills.set(skill.manifest.name, skill);
|
|
19
|
+
},
|
|
20
|
+
getSkill(name) {
|
|
21
|
+
return skills.get(name);
|
|
22
|
+
},
|
|
23
|
+
listSkills() {
|
|
24
|
+
return Array.from(skills.values()).map((s) => s.manifest);
|
|
25
|
+
},
|
|
26
|
+
async execute(name, context, inputs) {
|
|
27
|
+
const skill = skills.get(name);
|
|
28
|
+
if (!skill) {
|
|
29
|
+
const available = Array.from(skills.keys()).join(", ");
|
|
30
|
+
throw new errors_1.UserError(`Unknown skill: "${name}". Available: ${available}`);
|
|
31
|
+
}
|
|
32
|
+
validateInputs(skill, inputs);
|
|
33
|
+
return skill.execute(context, inputs);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
let globalEngine = null;
|
|
38
|
+
function getGlobalSkillEngine() {
|
|
39
|
+
if (!globalEngine) {
|
|
40
|
+
globalEngine = createSkillEngine();
|
|
41
|
+
loadBuiltinSkills(globalEngine);
|
|
42
|
+
}
|
|
43
|
+
return globalEngine;
|
|
44
|
+
}
|
|
45
|
+
function resetGlobalSkillEngine() {
|
|
46
|
+
globalEngine = null;
|
|
47
|
+
}
|
|
48
|
+
function loadBuiltinSkills(engine) {
|
|
49
|
+
// Lazy-load to avoid circular dependencies
|
|
50
|
+
try {
|
|
51
|
+
const { normalizeSkill } = require("./normalize-skill");
|
|
52
|
+
engine.register(normalizeSkill);
|
|
53
|
+
}
|
|
54
|
+
catch { /* skill not available */ }
|
|
55
|
+
try {
|
|
56
|
+
const { validateSkill } = require("./validate-skill");
|
|
57
|
+
engine.register(validateSkill);
|
|
58
|
+
}
|
|
59
|
+
catch { /* skill not available */ }
|
|
60
|
+
try {
|
|
61
|
+
const { fixSkill } = require("./fix-skill");
|
|
62
|
+
engine.register(fixSkill);
|
|
63
|
+
}
|
|
64
|
+
catch { /* skill not available */ }
|
|
65
|
+
try {
|
|
66
|
+
const { generateArtifactSkill } = require("./generate-artifact-skill");
|
|
67
|
+
engine.register(generateArtifactSkill);
|
|
68
|
+
}
|
|
69
|
+
catch { /* skill not available */ }
|
|
70
|
+
try {
|
|
71
|
+
const { generatePipelineSkill } = require("./generate-pipeline-skill");
|
|
72
|
+
engine.register(generatePipelineSkill);
|
|
73
|
+
}
|
|
74
|
+
catch { /* skill not available */ }
|
|
75
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fixSkill = void 0;
|
|
4
|
+
const fix_1 = require("../core/fix");
|
|
5
|
+
exports.fixSkill = {
|
|
6
|
+
manifest: {
|
|
7
|
+
name: "fix",
|
|
8
|
+
description: "Auto-regenerate artifacts that failed validation with backup and rollback",
|
|
9
|
+
category: "validation",
|
|
10
|
+
inputs: [
|
|
11
|
+
{ name: "cwd", type: "path", required: true, description: "Project working directory" },
|
|
12
|
+
{ name: "agent", type: "string", required: false, description: "Agent profile name" },
|
|
13
|
+
{ name: "strict", type: "boolean", required: false, description: "Treat warnings as errors" },
|
|
14
|
+
{ name: "dryRun", type: "boolean", required: false, description: "Preview without applying" }
|
|
15
|
+
],
|
|
16
|
+
outputs: [
|
|
17
|
+
{ name: "applied", type: "string", description: "Whether fix was applied" },
|
|
18
|
+
{ name: "finalPass", type: "string", description: "Whether validation passed after fix" },
|
|
19
|
+
{ name: "reportPath", type: "path", description: "Path to validation report" }
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
async execute(context, inputs) {
|
|
23
|
+
const cwd = inputs.cwd ?? context.cwd;
|
|
24
|
+
const result = await (0, fix_1.runFix)({
|
|
25
|
+
cwd,
|
|
26
|
+
agent: inputs.agent ?? context.agent,
|
|
27
|
+
strict: Boolean(inputs.strict),
|
|
28
|
+
dryRun: Boolean(inputs.dryRun),
|
|
29
|
+
log: context.log
|
|
30
|
+
});
|
|
31
|
+
return {
|
|
32
|
+
applied: result.applied,
|
|
33
|
+
finalPass: result.finalPass,
|
|
34
|
+
reportPath: result.reportPath,
|
|
35
|
+
targetCount: result.proposal.targets.length
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateArtifactSkill = void 0;
|
|
4
|
+
const artifacts_1 = require("../core/artifacts");
|
|
5
|
+
exports.generateArtifactSkill = {
|
|
6
|
+
manifest: {
|
|
7
|
+
name: "generate-artifact",
|
|
8
|
+
description: "Generate a single artifact (PRD, workflow, wireframe, stories, techspec)",
|
|
9
|
+
category: "artifact",
|
|
10
|
+
inputs: [
|
|
11
|
+
{ name: "cwd", type: "path", required: true, description: "Project working directory" },
|
|
12
|
+
{ name: "artifactType", type: "string", required: true, description: "Artifact type to generate" },
|
|
13
|
+
{ name: "from", type: "path", required: false, description: "Override path to normalized-brief.json" },
|
|
14
|
+
{ name: "out", type: "path", required: false, description: "Override output path" }
|
|
15
|
+
],
|
|
16
|
+
outputs: [
|
|
17
|
+
{ name: "filePath", type: "path", description: "Path to generated artifact" }
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
async execute(context, inputs) {
|
|
21
|
+
const cwd = inputs.cwd ?? context.cwd;
|
|
22
|
+
const filePath = await (0, artifacts_1.generateArtifact)({
|
|
23
|
+
artifactType: inputs.artifactType,
|
|
24
|
+
cwd,
|
|
25
|
+
normalizedBriefOverride: inputs.from,
|
|
26
|
+
outPath: inputs.out,
|
|
27
|
+
agent: context.agent
|
|
28
|
+
});
|
|
29
|
+
context.log(`${inputs.artifactType.toUpperCase()} generated: ${filePath}`);
|
|
30
|
+
return { filePath };
|
|
31
|
+
}
|
|
32
|
+
};
|