@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.
- 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/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 +467 -0
- package/dist/cli/init-tui.d.ts +23 -0
- package/dist/cli/init-tui.js +183 -0
- package/dist/cli/init.d.ts +12 -0
- package/dist/cli/init.js +335 -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/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 +8 -0
- package/dist/core/settings.js +43 -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/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 +12 -11
- package/dist/providers/openai-provider.d.ts +1 -1
- package/dist/providers/openai-provider.js +13 -13
- package/dist/skill-engine/context.d.ts +7 -0
- package/dist/skill-engine/context.js +76 -0
- package/dist/skill-engine/discovery.d.ts +2 -0
- package/dist/skill-engine/discovery.js +52 -0
- package/dist/skill-engine/graph.d.ts +4 -0
- package/dist/skill-engine/graph.js +114 -0
- package/dist/skill-engine/index.d.ts +11 -0
- package/dist/skill-engine/index.js +49 -0
- package/dist/skill-engine/pipeline.d.ts +9 -0
- package/dist/skill-engine/pipeline.js +84 -0
- package/dist/skill-engine/registry.d.ts +12 -0
- package/dist/skill-engine/registry.js +74 -0
- package/dist/skill-engine/types.d.ts +66 -0
- package/dist/skill-engine/types.js +2 -0
- package/dist/skill-engine/validator.d.ts +4 -0
- package/dist/skill-engine/validator.js +90 -0
- 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/fix.d.ts +2 -0
- package/dist/skills/fix.js +41 -0
- package/dist/skills/generate-artifact-skill.d.ts +2 -0
- package/dist/skills/generate-artifact-skill.js +32 -0
- package/dist/skills/generate-artifact.d.ts +2 -0
- package/dist/skills/generate-artifact.js +42 -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/normalize.d.ts +2 -0
- package/dist/skills/normalize.js +29 -0
- package/dist/skills/register-core.d.ts +2 -0
- package/dist/skills/register-core.js +21 -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/skills/validate.d.ts +2 -0
- package/dist/skills/validate.js +37 -0
- package/package.json +72 -45
- 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 -58
- package/src/{doctor.ts → cli/doctor.ts} +157 -137
- package/src/cli/fix-tui.ts +111 -0
- package/src/{cli.ts → cli/index.ts} +463 -410
- package/src/{init-tui.ts → cli/init-tui.ts} +49 -37
- package/src/{init.ts → cli/init.ts} +399 -398
- 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 -1072
- 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/{normalize.ts → core/normalize.ts} +145 -137
- 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} +8 -2
- 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 -452
- 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 -64
- package/src/{validate.ts → core/validate.ts} +252 -246
- package/src/{validator.ts → core/validator.ts} +92 -92
- package/src/{version.ts → core/version.ts} +24 -24
- package/src/{workflow-commands.ts → core/workflow-commands.ts} +32 -32
- 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 -88
- package/src/skill-engine/context.ts +90 -0
- package/src/skill-engine/discovery.ts +57 -0
- package/src/skill-engine/graph.ts +136 -0
- package/src/skill-engine/index.ts +55 -0
- package/src/skill-engine/pipeline.ts +112 -0
- package/src/skill-engine/registry.ts +75 -0
- package/src/skill-engine/types.ts +81 -0
- package/src/skill-engine/validator.ts +135 -0
- package/src/skills/fix.ts +45 -0
- package/src/skills/generate-artifact.ts +48 -0
- package/src/skills/normalize.ts +32 -0
- package/src/skills/register-core.ts +27 -0
- package/src/skills/validate.ts +40 -0
|
@@ -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;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { ValidationIssue } from "../core/types";
|
|
2
|
+
export type SkillInputType = "string" | "path" | "boolean" | "json" | "number";
|
|
3
|
+
export type SkillInput = {
|
|
4
|
+
name: string;
|
|
5
|
+
type: SkillInputType;
|
|
6
|
+
required: boolean;
|
|
7
|
+
description?: string;
|
|
8
|
+
default?: unknown;
|
|
9
|
+
};
|
|
10
|
+
export type SkillOutput = {
|
|
11
|
+
name: string;
|
|
12
|
+
type: SkillInputType;
|
|
13
|
+
description?: string;
|
|
14
|
+
};
|
|
15
|
+
export type SkillManifest = {
|
|
16
|
+
name: string;
|
|
17
|
+
version: string;
|
|
18
|
+
description: string;
|
|
19
|
+
category: "core" | "artifact" | "validation" | "custom";
|
|
20
|
+
depends_on: string[];
|
|
21
|
+
inputs: SkillInput[];
|
|
22
|
+
outputs: SkillOutput[];
|
|
23
|
+
tags?: string[];
|
|
24
|
+
};
|
|
25
|
+
export type PipelineState = {
|
|
26
|
+
cwd: string;
|
|
27
|
+
normalizedBriefPath?: string;
|
|
28
|
+
generatedArtifacts: Map<string, string>;
|
|
29
|
+
validationResult?: {
|
|
30
|
+
pass: boolean;
|
|
31
|
+
reportPath: string;
|
|
32
|
+
issues: ValidationIssue[];
|
|
33
|
+
};
|
|
34
|
+
custom: Record<string, unknown>;
|
|
35
|
+
startedAt: string;
|
|
36
|
+
completedSkills: string[];
|
|
37
|
+
};
|
|
38
|
+
export type ProgressCallback = (step: number, total: number, message: string) => void;
|
|
39
|
+
export type SkillContext = {
|
|
40
|
+
state: PipelineState;
|
|
41
|
+
progress: ProgressCallback;
|
|
42
|
+
log: (message: string) => void;
|
|
43
|
+
agent?: string;
|
|
44
|
+
};
|
|
45
|
+
export type SkillExecuteFn = (context: SkillContext, inputs: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
46
|
+
export type Skill = {
|
|
47
|
+
manifest: SkillManifest;
|
|
48
|
+
execute: SkillExecuteFn;
|
|
49
|
+
};
|
|
50
|
+
export type SkillError = {
|
|
51
|
+
skillName: string;
|
|
52
|
+
phase: "input_validation" | "execution" | "output_validation";
|
|
53
|
+
message: string;
|
|
54
|
+
inputContext?: Record<string, unknown>;
|
|
55
|
+
stack?: string;
|
|
56
|
+
recoveryHints: string[];
|
|
57
|
+
};
|
|
58
|
+
export type ExecutionTier = {
|
|
59
|
+
tier: number;
|
|
60
|
+
skills: string[];
|
|
61
|
+
};
|
|
62
|
+
export type PipelineOptions = {
|
|
63
|
+
log?: (message: string) => void;
|
|
64
|
+
progress?: ProgressCallback;
|
|
65
|
+
agent?: string;
|
|
66
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { SkillError, SkillManifest } from "./types";
|
|
2
|
+
export declare function validateInputs(manifest: SkillManifest, inputs: Record<string, unknown>): SkillError | null;
|
|
3
|
+
export declare function validateInputPaths(manifest: SkillManifest, inputs: Record<string, unknown>): Promise<SkillError | null>;
|
|
4
|
+
export declare function validateOutputs(manifest: SkillManifest, outputs: Record<string, unknown>): SkillError | null;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateInputs = validateInputs;
|
|
4
|
+
exports.validateInputPaths = validateInputPaths;
|
|
5
|
+
exports.validateOutputs = validateOutputs;
|
|
6
|
+
const utils_1 = require("../core/utils");
|
|
7
|
+
function makeError(skillName, phase, message, hints = []) {
|
|
8
|
+
return {
|
|
9
|
+
skillName,
|
|
10
|
+
phase,
|
|
11
|
+
message,
|
|
12
|
+
recoveryHints: hints
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function checkType(value, expectedType, fieldName) {
|
|
16
|
+
switch (expectedType) {
|
|
17
|
+
case "string":
|
|
18
|
+
if (typeof value !== "string")
|
|
19
|
+
return `"${fieldName}" must be a string, got ${typeof value}`;
|
|
20
|
+
return null;
|
|
21
|
+
case "path":
|
|
22
|
+
if (typeof value !== "string")
|
|
23
|
+
return `"${fieldName}" must be a path (string), got ${typeof value}`;
|
|
24
|
+
return null;
|
|
25
|
+
case "boolean":
|
|
26
|
+
if (typeof value !== "boolean")
|
|
27
|
+
return `"${fieldName}" must be a boolean, got ${typeof value}`;
|
|
28
|
+
return null;
|
|
29
|
+
case "number":
|
|
30
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
31
|
+
return `"${fieldName}" must be a finite number, got ${typeof value}`;
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
case "json":
|
|
35
|
+
if (typeof value === "string") {
|
|
36
|
+
try {
|
|
37
|
+
JSON.parse(value);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return `"${fieldName}" must be valid JSON string`;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
default:
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function validateInputs(manifest, inputs) {
|
|
49
|
+
for (const input of manifest.inputs) {
|
|
50
|
+
const value = inputs[input.name];
|
|
51
|
+
if (input.required && (value === undefined || value === null)) {
|
|
52
|
+
if (input.default !== undefined)
|
|
53
|
+
continue;
|
|
54
|
+
return makeError(manifest.name, "input_validation", `Required input "${input.name}" is missing`, [`Provide "${input.name}" (${input.type}): ${input.description ?? ""}`]);
|
|
55
|
+
}
|
|
56
|
+
if (value === undefined || value === null)
|
|
57
|
+
continue;
|
|
58
|
+
const typeError = checkType(value, input.type, input.name);
|
|
59
|
+
if (typeError) {
|
|
60
|
+
return makeError(manifest.name, "input_validation", typeError, [`Expected type: ${input.type}`]);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
async function validateInputPaths(manifest, inputs) {
|
|
66
|
+
for (const input of manifest.inputs) {
|
|
67
|
+
if (input.type !== "path")
|
|
68
|
+
continue;
|
|
69
|
+
const value = inputs[input.name];
|
|
70
|
+
if (typeof value !== "string")
|
|
71
|
+
continue;
|
|
72
|
+
if (input.required && !(await (0, utils_1.fileExists)(value))) {
|
|
73
|
+
return makeError(manifest.name, "input_validation", `Path "${input.name}" does not exist: ${value}`, [`Ensure the file or directory exists: ${value}`]);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
function validateOutputs(manifest, outputs) {
|
|
79
|
+
for (const output of manifest.outputs) {
|
|
80
|
+
const value = outputs[output.name];
|
|
81
|
+
if (value === undefined || value === null) {
|
|
82
|
+
return makeError(manifest.name, "output_validation", `Expected output "${output.name}" was not produced`, [`Skill "${manifest.name}" should return "${output.name}" (${output.type})`]);
|
|
83
|
+
}
|
|
84
|
+
const typeError = checkType(value, output.type, output.name);
|
|
85
|
+
if (typeError) {
|
|
86
|
+
return makeError(manifest.name, "output_validation", typeError, [`Skill "${manifest.name}" returned wrong type for "${output.name}"`]);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
@@ -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,41 @@
|
|
|
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
|
+
version: "2.0.0",
|
|
9
|
+
description: "Auto-regenerate failing artifacts with backup, proposal, and validation",
|
|
10
|
+
category: "validation",
|
|
11
|
+
depends_on: [],
|
|
12
|
+
inputs: [
|
|
13
|
+
{ name: "cwd", type: "path", required: true, description: "Project working directory" }
|
|
14
|
+
],
|
|
15
|
+
outputs: [
|
|
16
|
+
{ name: "validationResult", type: "json", description: "Final validation result after fix" }
|
|
17
|
+
],
|
|
18
|
+
tags: ["fix", "repair", "validation"]
|
|
19
|
+
},
|
|
20
|
+
async execute(context, inputs) {
|
|
21
|
+
const cwd = inputs.cwd ?? context.state.cwd;
|
|
22
|
+
context.progress(1, 3, "Running fix pipeline...");
|
|
23
|
+
const result = await (0, fix_1.runFix)({
|
|
24
|
+
cwd,
|
|
25
|
+
agent: context.agent,
|
|
26
|
+
log: context.log
|
|
27
|
+
});
|
|
28
|
+
context.progress(3, 3, result.finalPass ? "Fix complete." : "Fix applied, issues remain.");
|
|
29
|
+
context.state.validationResult = result.finalPass
|
|
30
|
+
? { pass: true, reportPath: result.reportPath, issues: [] }
|
|
31
|
+
: undefined;
|
|
32
|
+
return {
|
|
33
|
+
validationResult: {
|
|
34
|
+
pass: result.finalPass,
|
|
35
|
+
reportPath: result.reportPath,
|
|
36
|
+
applied: result.applied,
|
|
37
|
+
targetCount: result.proposal.targets.length
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
};
|
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createArtifactSkill = createArtifactSkill;
|
|
4
|
+
const artifacts_1 = require("../core/artifacts");
|
|
5
|
+
const constants_1 = require("../core/constants");
|
|
6
|
+
function createArtifactSkill(artifactType, upstream) {
|
|
7
|
+
const resolvedUpstream = upstream ?? (0, constants_1.defaultUpstreamByArtifact)(artifactType);
|
|
8
|
+
const depends_on = ["normalize", ...resolvedUpstream];
|
|
9
|
+
const manifest = {
|
|
10
|
+
name: artifactType,
|
|
11
|
+
version: "2.0.0",
|
|
12
|
+
description: `Generate ${artifactType} artifact from normalized brief`,
|
|
13
|
+
category: "artifact",
|
|
14
|
+
depends_on,
|
|
15
|
+
inputs: [
|
|
16
|
+
{ name: "cwd", type: "path", required: true, description: "Project working directory" },
|
|
17
|
+
{ name: "normalizedBriefPath", type: "path", required: false, description: "Path to normalized brief" }
|
|
18
|
+
],
|
|
19
|
+
outputs: [
|
|
20
|
+
{ name: "artifactPath", type: "path", description: `Path to generated ${artifactType}` }
|
|
21
|
+
],
|
|
22
|
+
tags: ["artifact", artifactType]
|
|
23
|
+
};
|
|
24
|
+
return {
|
|
25
|
+
manifest,
|
|
26
|
+
async execute(context, inputs) {
|
|
27
|
+
const cwd = inputs.cwd ?? context.state.cwd;
|
|
28
|
+
const normalizedBriefOverride = inputs.normalizedBriefPath ?? context.state.normalizedBriefPath;
|
|
29
|
+
context.progress(1, 2, `Generating ${artifactType}...`);
|
|
30
|
+
const filePath = await (0, artifacts_1.generateArtifact)({
|
|
31
|
+
artifactType,
|
|
32
|
+
cwd,
|
|
33
|
+
normalizedBriefOverride,
|
|
34
|
+
agent: context.agent
|
|
35
|
+
});
|
|
36
|
+
context.progress(2, 2, `${artifactType} generated.`);
|
|
37
|
+
context.log(`${artifactType.toUpperCase()} generated: ${filePath}`);
|
|
38
|
+
context.state.generatedArtifacts.set(artifactType, filePath);
|
|
39
|
+
return { artifactPath: filePath };
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|