@shahmarasy/prodo 0.1.5 → 0.1.7

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 (69) hide show
  1. package/dist/agents/system-prompts.js +12 -12
  2. package/dist/cli/agent-command-installer.d.ts +1 -1
  3. package/dist/cli/agent-command-installer.js +125 -19
  4. package/dist/cli/doctor.js +2 -2
  5. package/dist/cli/index.js +32 -30
  6. package/dist/cli/init-tui.d.ts +2 -2
  7. package/dist/cli/init-tui.js +43 -36
  8. package/dist/cli/init.d.ts +1 -0
  9. package/dist/cli/init.js +3 -2
  10. package/dist/core/artifacts.js +72 -72
  11. package/dist/core/settings.d.ts +1 -0
  12. package/dist/core/settings.js +10 -2
  13. package/dist/core/templates.js +248 -248
  14. package/dist/i18n/en.json +45 -45
  15. package/dist/i18n/tr.json +45 -45
  16. package/dist/providers/mock-provider.js +5 -5
  17. package/dist/providers/openai-provider.js +12 -12
  18. package/dist/skill-engine/context.d.ts +7 -0
  19. package/dist/skill-engine/context.js +76 -0
  20. package/dist/skill-engine/discovery.d.ts +2 -0
  21. package/dist/skill-engine/discovery.js +52 -0
  22. package/dist/skill-engine/graph.d.ts +4 -0
  23. package/dist/skill-engine/graph.js +114 -0
  24. package/dist/skill-engine/index.d.ts +11 -0
  25. package/dist/skill-engine/index.js +49 -0
  26. package/dist/skill-engine/pipeline.d.ts +9 -0
  27. package/dist/skill-engine/pipeline.js +84 -0
  28. package/dist/skill-engine/registry.d.ts +12 -0
  29. package/dist/skill-engine/registry.js +74 -0
  30. package/dist/skill-engine/types.d.ts +66 -0
  31. package/dist/skill-engine/types.js +2 -0
  32. package/dist/skill-engine/validator.d.ts +4 -0
  33. package/dist/skill-engine/validator.js +90 -0
  34. package/dist/skills/fix.d.ts +2 -0
  35. package/dist/skills/fix.js +41 -0
  36. package/dist/skills/generate-artifact.d.ts +2 -0
  37. package/dist/skills/generate-artifact.js +42 -0
  38. package/dist/skills/normalize.d.ts +2 -0
  39. package/dist/skills/normalize.js +29 -0
  40. package/dist/skills/register-core.d.ts +2 -0
  41. package/dist/skills/register-core.js +21 -0
  42. package/dist/skills/validate.d.ts +2 -0
  43. package/dist/skills/validate.js +37 -0
  44. package/package.json +4 -6
  45. package/src/cli/agent-command-installer.ts +115 -1
  46. package/src/cli/doctor.ts +2 -2
  47. package/src/cli/index.ts +35 -31
  48. package/src/cli/init-tui.ts +220 -208
  49. package/src/cli/init.ts +4 -3
  50. package/src/core/settings.ts +41 -35
  51. package/src/skill-engine/context.ts +90 -0
  52. package/src/skill-engine/discovery.ts +57 -0
  53. package/src/skill-engine/graph.ts +136 -0
  54. package/src/skill-engine/index.ts +55 -0
  55. package/src/skill-engine/pipeline.ts +112 -0
  56. package/src/skill-engine/registry.ts +75 -0
  57. package/src/skill-engine/types.ts +81 -0
  58. package/src/skill-engine/validator.ts +135 -0
  59. package/src/skills/fix.ts +45 -0
  60. package/src/skills/generate-artifact.ts +48 -0
  61. package/src/skills/{normalize-skill.ts → normalize.ts} +15 -12
  62. package/src/skills/register-core.ts +27 -0
  63. package/src/skills/validate.ts +40 -0
  64. package/src/skills/engine.ts +0 -94
  65. package/src/skills/fix-skill.ts +0 -38
  66. package/src/skills/generate-artifact-skill.ts +0 -32
  67. package/src/skills/generate-pipeline-skill.ts +0 -49
  68. package/src/skills/types.ts +0 -36
  69. package/src/skills/validate-skill.ts +0 -29
package/dist/i18n/tr.json CHANGED
@@ -1,45 +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
+ {
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
+ }
@@ -121,11 +121,11 @@ function buildArtifactBody(schemaHint, inputContext) {
121
121
  ? `# ${productName} ${(0, i18n_1.t)("for_artifact", lang)} ${schemaHint.artifactType.toUpperCase()}`
122
122
  : `# ${schemaHint.artifactType.toUpperCase()} ${(0, i18n_1.t)("for_artifact", lang)} ${productName}`;
123
123
  if (schemaHint.artifactType === "workflow") {
124
- return `${title}\n\n${sections.join("\n")}\n\n\`\`\`mermaid
125
- flowchart TD
126
- A[Start] --> B[[F1] User Action]
127
- B --> C[System Step]
128
- C --> D[Done]
124
+ return `${title}\n\n${sections.join("\n")}\n\n\`\`\`mermaid
125
+ flowchart TD
126
+ A[Start] --> B[[F1] User Action]
127
+ B --> C[System Step]
128
+ C --> D[Done]
129
129
  \`\`\``.trim();
130
130
  }
131
131
  return `${title}\n\n${sections.join("\n")}\n\n${(0, i18n_1.t)("note", lang)}: ${fallback}`.trim();
@@ -21,23 +21,23 @@ class OpenAIProvider {
21
21
  : "en";
22
22
  const mode = schemaHint.artifactType;
23
23
  const system = mode === "normalize"
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.
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.
26
26
  Preserve source language and Unicode characters exactly; never transliterate Turkish letters to ASCII.`
27
27
  : mode === "semantic_consistency"
28
- ? `You detect semantic inconsistencies between paired artifacts.
28
+ ? `You detect semantic inconsistencies between paired artifacts.
29
29
  Return valid JSON only: { "issues": [{level, code, check, contract_id, file, message, suggestion}] }.`
30
30
  : mode === "contract_relevance"
31
- ? `You verify whether tagged content actually matches the referenced contract text.
31
+ ? `You verify whether tagged content actually matches the referenced contract text.
32
32
  Return valid JSON only: { "relevant": boolean, "score": number, "reason": string }.`
33
- : `You are a product-document generator.
34
- Return only Markdown body content.
35
- Headings required:
36
- ${schemaHint.requiredHeadings.join("\n")}
37
- Required contract tags:
38
- ${schemaHint.requiredContracts.join(", ")}
39
- Use tags like [G1], [F2], [C1] where relevant.
40
- Output language: ${outputLanguage}
33
+ : `You are a product-document generator.
34
+ Return only Markdown body content.
35
+ Headings required:
36
+ ${schemaHint.requiredHeadings.join("\n")}
37
+ Required contract tags:
38
+ ${schemaHint.requiredContracts.join(", ")}
39
+ Use tags like [G1], [F2], [C1] where relevant.
40
+ Output language: ${outputLanguage}
41
41
  Do not translate required headings.`;
42
42
  const user = `${prompt}\n\nContext JSON:\n${JSON.stringify(inputContext, null, 2)}`;
43
43
  const response = await fetch(`${this.baseUrl}/chat/completions`, {
@@ -0,0 +1,7 @@
1
+ import type { ArtifactType } from "../core/types";
2
+ import type { PipelineState } from "./types";
3
+ export declare function createPipelineState(cwd: string): PipelineState;
4
+ export declare function hydrateStateFromDisk(cwd: string, state: PipelineState, artifactTypes: ArtifactType[]): Promise<void>;
5
+ export declare function isOutputSatisfied(outputName: string, state: PipelineState, artifactType?: string): boolean;
6
+ export declare function wireInputsFromState(inputNames: string[], state: PipelineState): Record<string, unknown>;
7
+ export declare function wireOutputsToState(outputs: Record<string, unknown>, state: PipelineState, skillName: string): void;
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createPipelineState = createPipelineState;
4
+ exports.hydrateStateFromDisk = hydrateStateFromDisk;
5
+ exports.isOutputSatisfied = isOutputSatisfied;
6
+ exports.wireInputsFromState = wireInputsFromState;
7
+ exports.wireOutputsToState = wireOutputsToState;
8
+ const paths_1 = require("../core/paths");
9
+ const output_index_1 = require("../core/output-index");
10
+ const utils_1 = require("../core/utils");
11
+ function createPipelineState(cwd) {
12
+ return {
13
+ cwd,
14
+ normalizedBriefPath: undefined,
15
+ generatedArtifacts: new Map(),
16
+ validationResult: undefined,
17
+ custom: {},
18
+ startedAt: new Date().toISOString(),
19
+ completedSkills: []
20
+ };
21
+ }
22
+ async function hydrateStateFromDisk(cwd, state, artifactTypes) {
23
+ const nbPath = (0, paths_1.normalizedBriefPath)(cwd);
24
+ if (!state.normalizedBriefPath && (await (0, utils_1.fileExists)(nbPath))) {
25
+ state.normalizedBriefPath = nbPath;
26
+ }
27
+ for (const type of artifactTypes) {
28
+ if (!state.generatedArtifacts.has(type)) {
29
+ const active = await (0, output_index_1.getActiveArtifactPath)(cwd, type);
30
+ if (active) {
31
+ state.generatedArtifacts.set(type, active);
32
+ }
33
+ }
34
+ }
35
+ }
36
+ function isOutputSatisfied(outputName, state, artifactType) {
37
+ if (outputName === "normalizedBriefPath") {
38
+ return typeof state.normalizedBriefPath === "string" && state.normalizedBriefPath.length > 0;
39
+ }
40
+ if (outputName === "artifactPath" && artifactType) {
41
+ return state.generatedArtifacts.has(artifactType);
42
+ }
43
+ if (outputName === "validationResult") {
44
+ return state.validationResult !== undefined;
45
+ }
46
+ return false;
47
+ }
48
+ function wireInputsFromState(inputNames, state) {
49
+ const inputs = {};
50
+ for (const name of inputNames) {
51
+ if (name === "cwd")
52
+ inputs.cwd = state.cwd;
53
+ else if (name === "normalizedBriefPath")
54
+ inputs.normalizedBriefPath = state.normalizedBriefPath;
55
+ else if (name in state.custom)
56
+ inputs[name] = state.custom[name];
57
+ }
58
+ return inputs;
59
+ }
60
+ function wireOutputsToState(outputs, state, skillName) {
61
+ if ("normalizedBriefPath" in outputs && typeof outputs.normalizedBriefPath === "string") {
62
+ state.normalizedBriefPath = outputs.normalizedBriefPath;
63
+ }
64
+ if ("artifactPath" in outputs && typeof outputs.artifactPath === "string") {
65
+ const artifactType = skillName;
66
+ state.generatedArtifacts.set(artifactType, outputs.artifactPath);
67
+ }
68
+ if ("validationResult" in outputs && outputs.validationResult && typeof outputs.validationResult === "object") {
69
+ state.validationResult = outputs.validationResult;
70
+ }
71
+ for (const [key, value] of Object.entries(outputs)) {
72
+ if (!["normalizedBriefPath", "artifactPath", "validationResult"].includes(key)) {
73
+ state.custom[key] = value;
74
+ }
75
+ }
76
+ }
@@ -0,0 +1,2 @@
1
+ import type { Skill } from "./types";
2
+ export declare function discoverSkills(cwd: string, log?: (message: string) => void): Promise<Skill[]>;
@@ -0,0 +1,52 @@
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.discoverSkills = discoverSkills;
7
+ const promises_1 = __importDefault(require("node:fs/promises"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const paths_1 = require("../core/paths");
10
+ const utils_1 = require("../core/utils");
11
+ function isValidManifest(obj) {
12
+ if (!obj || typeof obj !== "object")
13
+ return false;
14
+ const m = obj;
15
+ return (typeof m.name === "string" &&
16
+ typeof m.version === "string" &&
17
+ typeof m.description === "string" &&
18
+ Array.isArray(m.depends_on) &&
19
+ Array.isArray(m.inputs) &&
20
+ Array.isArray(m.outputs));
21
+ }
22
+ async function discoverSkills(cwd, log) {
23
+ const skillsDir = node_path_1.default.join((0, paths_1.prodoPath)(cwd), "skills");
24
+ if (!(await (0, utils_1.fileExists)(skillsDir)))
25
+ return [];
26
+ const entries = await promises_1.default.readdir(skillsDir);
27
+ const jsFiles = entries.filter((e) => e.endsWith(".js"));
28
+ const skills = [];
29
+ for (const file of jsFiles) {
30
+ const fullPath = node_path_1.default.resolve(skillsDir, file);
31
+ try {
32
+ const mod = require(fullPath);
33
+ const manifest = mod.manifest;
34
+ const execute = mod.execute;
35
+ if (!isValidManifest(manifest)) {
36
+ log?.(`[Skill Discovery] Skipping ${file}: invalid or missing manifest`);
37
+ continue;
38
+ }
39
+ if (typeof execute !== "function") {
40
+ log?.(`[Skill Discovery] Skipping ${file}: missing execute function`);
41
+ continue;
42
+ }
43
+ skills.push({ manifest, execute: execute });
44
+ log?.(`[Skill Discovery] Loaded plugin: ${manifest.name} v${manifest.version}`);
45
+ }
46
+ catch (err) {
47
+ const message = err instanceof Error ? err.message : String(err);
48
+ log?.(`[Skill Discovery] Failed to load ${file}: ${message}`);
49
+ }
50
+ }
51
+ return skills;
52
+ }
@@ -0,0 +1,4 @@
1
+ import type { ExecutionTier, SkillManifest } from "./types";
2
+ export declare function detectCycles(manifests: Map<string, SkillManifest>): string[][] | null;
3
+ export declare function buildExecutionPlan(manifests: Map<string, SkillManifest>, targetSkills: string[]): ExecutionTier[];
4
+ export declare function getExecutionOrder(manifests: Map<string, SkillManifest>, targetSkills: string[]): string[];
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.detectCycles = detectCycles;
4
+ exports.buildExecutionPlan = buildExecutionPlan;
5
+ exports.getExecutionOrder = getExecutionOrder;
6
+ const errors_1 = require("../core/errors");
7
+ function detectCycles(manifests) {
8
+ const WHITE = 0;
9
+ const GRAY = 1;
10
+ const BLACK = 2;
11
+ const color = new Map();
12
+ const cycles = [];
13
+ for (const name of manifests.keys()) {
14
+ color.set(name, WHITE);
15
+ }
16
+ function dfs(node, path) {
17
+ color.set(node, GRAY);
18
+ path.push(node);
19
+ const manifest = manifests.get(node);
20
+ if (manifest) {
21
+ for (const dep of manifest.depends_on) {
22
+ if (!manifests.has(dep))
23
+ continue;
24
+ const c = color.get(dep) ?? WHITE;
25
+ if (c === GRAY) {
26
+ const cycleStart = path.indexOf(dep);
27
+ cycles.push([...path.slice(cycleStart), dep]);
28
+ }
29
+ else if (c === WHITE) {
30
+ dfs(dep, path);
31
+ }
32
+ }
33
+ }
34
+ path.pop();
35
+ color.set(node, BLACK);
36
+ }
37
+ for (const name of manifests.keys()) {
38
+ if (color.get(name) === WHITE) {
39
+ dfs(name, []);
40
+ }
41
+ }
42
+ return cycles.length > 0 ? cycles : null;
43
+ }
44
+ function collectTransitiveDeps(target, manifests, collected) {
45
+ if (collected.has(target))
46
+ return;
47
+ collected.add(target);
48
+ const manifest = manifests.get(target);
49
+ if (!manifest)
50
+ return;
51
+ for (const dep of manifest.depends_on) {
52
+ if (manifests.has(dep)) {
53
+ collectTransitiveDeps(dep, manifests, collected);
54
+ }
55
+ }
56
+ }
57
+ function buildExecutionPlan(manifests, targetSkills) {
58
+ const needed = new Set();
59
+ for (const target of targetSkills) {
60
+ collectTransitiveDeps(target, manifests, needed);
61
+ }
62
+ const filteredManifests = new Map();
63
+ for (const name of needed) {
64
+ const m = manifests.get(name);
65
+ if (m)
66
+ filteredManifests.set(name, m);
67
+ }
68
+ const cycles = detectCycles(filteredManifests);
69
+ if (cycles) {
70
+ const cycleStr = cycles.map((c) => c.join(" → ")).join("; ");
71
+ throw new errors_1.UserError(`Dependency cycle detected: ${cycleStr}`);
72
+ }
73
+ const inDegree = new Map();
74
+ for (const name of filteredManifests.keys()) {
75
+ inDegree.set(name, 0);
76
+ }
77
+ for (const [, manifest] of filteredManifests) {
78
+ for (const dep of manifest.depends_on) {
79
+ if (filteredManifests.has(dep)) {
80
+ inDegree.set(manifest.name, (inDegree.get(manifest.name) ?? 0) + 1);
81
+ }
82
+ }
83
+ }
84
+ const tiers = [];
85
+ const remaining = new Set(filteredManifests.keys());
86
+ let tierNum = 0;
87
+ while (remaining.size > 0) {
88
+ const ready = [];
89
+ for (const name of remaining) {
90
+ if ((inDegree.get(name) ?? 0) === 0) {
91
+ ready.push(name);
92
+ }
93
+ }
94
+ if (ready.length === 0) {
95
+ throw new errors_1.UserError(`Cannot resolve execution order for: ${Array.from(remaining).join(", ")}`);
96
+ }
97
+ ready.sort();
98
+ tiers.push({ tier: tierNum, skills: ready });
99
+ for (const name of ready) {
100
+ remaining.delete(name);
101
+ for (const [otherName, manifest] of filteredManifests) {
102
+ if (manifest.depends_on.includes(name) && remaining.has(otherName)) {
103
+ inDegree.set(otherName, (inDegree.get(otherName) ?? 0) - 1);
104
+ }
105
+ }
106
+ }
107
+ tierNum += 1;
108
+ }
109
+ return tiers;
110
+ }
111
+ function getExecutionOrder(manifests, targetSkills) {
112
+ const tiers = buildExecutionPlan(manifests, targetSkills);
113
+ return tiers.flatMap((t) => t.skills);
114
+ }
@@ -0,0 +1,11 @@
1
+ import { SkillPipeline } from "./pipeline";
2
+ import type { PipelineState } from "./types";
3
+ export declare function createEngine(cwd: string, log?: (message: string) => void): Promise<SkillPipeline>;
4
+ export declare function createHydratedState(cwd: string): Promise<PipelineState>;
5
+ export { SkillPipeline } from "./pipeline";
6
+ export { SkillRegistry } from "./registry";
7
+ export { createPipelineState, hydrateStateFromDisk } from "./context";
8
+ export { buildExecutionPlan, detectCycles, getExecutionOrder } from "./graph";
9
+ export { discoverSkills } from "./discovery";
10
+ export { validateInputs, validateOutputs, validateInputPaths } from "./validator";
11
+ export type { Skill, SkillManifest, SkillInput, SkillOutput, SkillContext, SkillExecuteFn, PipelineState, PipelineOptions, ExecutionTier, SkillError, ProgressCallback } from "./types";
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateInputPaths = exports.validateOutputs = exports.validateInputs = exports.discoverSkills = exports.getExecutionOrder = exports.detectCycles = exports.buildExecutionPlan = exports.hydrateStateFromDisk = exports.createPipelineState = exports.SkillRegistry = exports.SkillPipeline = void 0;
4
+ exports.createEngine = createEngine;
5
+ exports.createHydratedState = createHydratedState;
6
+ const registry_1 = require("./registry");
7
+ const pipeline_1 = require("./pipeline");
8
+ const discovery_1 = require("./discovery");
9
+ const register_core_1 = require("../skills/register-core");
10
+ const context_1 = require("./context");
11
+ const artifact_registry_1 = require("../core/artifact-registry");
12
+ async function createEngine(cwd, log) {
13
+ const registry = new registry_1.SkillRegistry();
14
+ await (0, register_core_1.registerCoreSkills)(registry, cwd);
15
+ const plugins = await (0, discovery_1.discoverSkills)(cwd, log);
16
+ for (const plugin of plugins) {
17
+ try {
18
+ registry.register(plugin);
19
+ }
20
+ catch (err) {
21
+ const message = err instanceof Error ? err.message : String(err);
22
+ log?.(`[Skill Engine] Plugin registration failed: ${message}`);
23
+ }
24
+ }
25
+ return new pipeline_1.SkillPipeline(registry);
26
+ }
27
+ async function createHydratedState(cwd) {
28
+ const state = (0, context_1.createPipelineState)(cwd);
29
+ const artifactTypes = await (0, artifact_registry_1.listArtifactTypes)(cwd);
30
+ await (0, context_1.hydrateStateFromDisk)(cwd, state, artifactTypes);
31
+ return state;
32
+ }
33
+ var pipeline_2 = require("./pipeline");
34
+ Object.defineProperty(exports, "SkillPipeline", { enumerable: true, get: function () { return pipeline_2.SkillPipeline; } });
35
+ var registry_2 = require("./registry");
36
+ Object.defineProperty(exports, "SkillRegistry", { enumerable: true, get: function () { return registry_2.SkillRegistry; } });
37
+ var context_2 = require("./context");
38
+ Object.defineProperty(exports, "createPipelineState", { enumerable: true, get: function () { return context_2.createPipelineState; } });
39
+ Object.defineProperty(exports, "hydrateStateFromDisk", { enumerable: true, get: function () { return context_2.hydrateStateFromDisk; } });
40
+ var graph_1 = require("./graph");
41
+ Object.defineProperty(exports, "buildExecutionPlan", { enumerable: true, get: function () { return graph_1.buildExecutionPlan; } });
42
+ Object.defineProperty(exports, "detectCycles", { enumerable: true, get: function () { return graph_1.detectCycles; } });
43
+ Object.defineProperty(exports, "getExecutionOrder", { enumerable: true, get: function () { return graph_1.getExecutionOrder; } });
44
+ var discovery_2 = require("./discovery");
45
+ Object.defineProperty(exports, "discoverSkills", { enumerable: true, get: function () { return discovery_2.discoverSkills; } });
46
+ var validator_1 = require("./validator");
47
+ Object.defineProperty(exports, "validateInputs", { enumerable: true, get: function () { return validator_1.validateInputs; } });
48
+ Object.defineProperty(exports, "validateOutputs", { enumerable: true, get: function () { return validator_1.validateOutputs; } });
49
+ Object.defineProperty(exports, "validateInputPaths", { enumerable: true, get: function () { return validator_1.validateInputPaths; } });
@@ -0,0 +1,9 @@
1
+ import type { SkillRegistry } from "./registry";
2
+ import type { PipelineOptions, PipelineState } from "./types";
3
+ export declare class SkillPipeline {
4
+ private registry;
5
+ constructor(registry: SkillRegistry);
6
+ runPipeline(skillNames: string[], state: PipelineState, options?: PipelineOptions): Promise<PipelineState>;
7
+ runSkill(name: string, state: PipelineState, options?: PipelineOptions): Promise<PipelineState>;
8
+ getRegistry(): SkillRegistry;
9
+ }
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SkillPipeline = void 0;
4
+ const errors_1 = require("../core/errors");
5
+ const context_1 = require("./context");
6
+ const graph_1 = require("./graph");
7
+ const validator_1 = require("./validator");
8
+ function createSkillError(skillName, phase, error) {
9
+ const message = error instanceof Error ? error.message : String(error);
10
+ const stack = error instanceof Error ? error.stack : undefined;
11
+ return {
12
+ skillName,
13
+ phase,
14
+ message,
15
+ stack,
16
+ recoveryHints: [`Skill "${skillName}" failed during ${phase}. Check inputs and retry.`]
17
+ };
18
+ }
19
+ class SkillPipeline {
20
+ registry;
21
+ constructor(registry) {
22
+ this.registry = registry;
23
+ }
24
+ async runPipeline(skillNames, state, options = {}) {
25
+ const { log = console.log, progress, agent } = options;
26
+ for (const name of skillNames) {
27
+ if (!this.registry.has(name)) {
28
+ const available = this.registry.list().map((s) => s.manifest.name).join(", ");
29
+ throw new errors_1.UserError(`Unknown skill: "${name}". Available: ${available}`);
30
+ }
31
+ }
32
+ const manifests = new Map(this.registry.list().map((s) => [s.manifest.name, s.manifest]));
33
+ const executionOrder = (0, graph_1.getExecutionOrder)(manifests, skillNames);
34
+ const totalSteps = executionOrder.length;
35
+ for (let i = 0; i < executionOrder.length; i++) {
36
+ const skillName = executionOrder[i];
37
+ if (state.completedSkills.includes(skillName)) {
38
+ log(`[Skip] ${skillName} — already completed`);
39
+ continue;
40
+ }
41
+ const skill = this.registry.get(skillName);
42
+ if (!skill)
43
+ continue;
44
+ progress?.(i + 1, totalSteps, `Running ${skillName}...`);
45
+ log(`[${i + 1}/${totalSteps}] ${skillName}`);
46
+ const inputNames = skill.manifest.inputs.map((inp) => inp.name);
47
+ const wiredInputs = (0, context_1.wireInputsFromState)(inputNames, state);
48
+ const inputError = (0, validator_1.validateInputs)(skill.manifest, wiredInputs);
49
+ if (inputError) {
50
+ throw new errors_1.UserError(`Skill "${skillName}" input validation failed: ${inputError.message}\n` +
51
+ inputError.recoveryHints.join("\n"));
52
+ }
53
+ let outputs;
54
+ try {
55
+ const context = {
56
+ state,
57
+ progress: progress ?? (() => { }),
58
+ log,
59
+ agent
60
+ };
61
+ outputs = await skill.execute(context, wiredInputs);
62
+ }
63
+ catch (error) {
64
+ const skillError = createSkillError(skillName, "execution", error);
65
+ throw new errors_1.UserError(`Skill "${skillName}" execution failed: ${skillError.message}\n` +
66
+ skillError.recoveryHints.join("\n"));
67
+ }
68
+ const outputError = (0, validator_1.validateOutputs)(skill.manifest, outputs);
69
+ if (outputError) {
70
+ log(`[Warning] Skill "${skillName}" output validation: ${outputError.message}`);
71
+ }
72
+ (0, context_1.wireOutputsToState)(outputs, state, skillName);
73
+ state.completedSkills.push(skillName);
74
+ }
75
+ return state;
76
+ }
77
+ async runSkill(name, state, options = {}) {
78
+ return this.runPipeline([name], state, options);
79
+ }
80
+ getRegistry() {
81
+ return this.registry;
82
+ }
83
+ }
84
+ exports.SkillPipeline = SkillPipeline;
@@ -0,0 +1,12 @@
1
+ import type { Skill, SkillManifest } from "./types";
2
+ export declare class SkillRegistry {
3
+ private skills;
4
+ register(skill: Skill): void;
5
+ get(name: string): Skill | undefined;
6
+ has(name: string): boolean;
7
+ list(): Skill[];
8
+ listByCategory(category: string): Skill[];
9
+ listManifests(): SkillManifest[];
10
+ unregister(name: string): boolean;
11
+ size(): number;
12
+ }
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SkillRegistry = void 0;
4
+ const errors_1 = require("../core/errors");
5
+ function validateManifest(manifest) {
6
+ if (!manifest.name || typeof manifest.name !== "string")
7
+ return "Skill name is required";
8
+ if (!manifest.version || typeof manifest.version !== "string")
9
+ return "Skill version is required";
10
+ if (!manifest.description || typeof manifest.description !== "string")
11
+ return "Skill description is required";
12
+ const validCategories = ["core", "artifact", "validation", "custom"];
13
+ if (!validCategories.includes(manifest.category)) {
14
+ return `Invalid category "${manifest.category}". Must be: ${validCategories.join(", ")}`;
15
+ }
16
+ if (!Array.isArray(manifest.depends_on))
17
+ return "depends_on must be an array";
18
+ if (!Array.isArray(manifest.inputs))
19
+ return "inputs must be an array";
20
+ if (!Array.isArray(manifest.outputs))
21
+ return "outputs must be an array";
22
+ const validTypes = ["string", "path", "boolean", "json", "number"];
23
+ for (const input of manifest.inputs) {
24
+ if (!input.name || typeof input.name !== "string")
25
+ return "Input name is required";
26
+ if (!validTypes.includes(input.type))
27
+ return `Invalid input type "${input.type}" for "${input.name}"`;
28
+ }
29
+ for (const output of manifest.outputs) {
30
+ if (!output.name || typeof output.name !== "string")
31
+ return "Output name is required";
32
+ if (!validTypes.includes(output.type))
33
+ return `Invalid output type "${output.type}" for "${output.name}"`;
34
+ }
35
+ return null;
36
+ }
37
+ class SkillRegistry {
38
+ skills = new Map();
39
+ register(skill) {
40
+ const error = validateManifest(skill.manifest);
41
+ if (error) {
42
+ throw new errors_1.UserError(`Invalid skill manifest for "${skill.manifest?.name ?? "unknown"}": ${error}`);
43
+ }
44
+ if (typeof skill.execute !== "function") {
45
+ throw new errors_1.UserError(`Skill "${skill.manifest.name}" must export an execute function`);
46
+ }
47
+ if (this.skills.has(skill.manifest.name)) {
48
+ throw new errors_1.UserError(`Skill "${skill.manifest.name}" is already registered`);
49
+ }
50
+ this.skills.set(skill.manifest.name, skill);
51
+ }
52
+ get(name) {
53
+ return this.skills.get(name);
54
+ }
55
+ has(name) {
56
+ return this.skills.has(name);
57
+ }
58
+ list() {
59
+ return Array.from(this.skills.values());
60
+ }
61
+ listByCategory(category) {
62
+ return this.list().filter((s) => s.manifest.category === category);
63
+ }
64
+ listManifests() {
65
+ return this.list().map((s) => s.manifest);
66
+ }
67
+ unregister(name) {
68
+ return this.skills.delete(name);
69
+ }
70
+ size() {
71
+ return this.skills.size;
72
+ }
73
+ }
74
+ exports.SkillRegistry = SkillRegistry;