stoa-mcp 0.1.0
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/LICENSE +65 -0
- package/README.md +397 -0
- package/dist/cli/build.d.ts +39 -0
- package/dist/cli/build.d.ts.map +1 -0
- package/dist/cli/build.js +288 -0
- package/dist/cli/build.js.map +1 -0
- package/dist/cli/review-loop.d.ts +2 -0
- package/dist/cli/review-loop.d.ts.map +1 -0
- package/dist/cli/review-loop.js +97 -0
- package/dist/cli/review-loop.js.map +1 -0
- package/dist/cli/scenarios-runner.d.ts +12 -0
- package/dist/cli/scenarios-runner.d.ts.map +1 -0
- package/dist/cli/scenarios-runner.js +158 -0
- package/dist/cli/scenarios-runner.js.map +1 -0
- package/dist/cli/verify.d.ts +13 -0
- package/dist/cli/verify.d.ts.map +1 -0
- package/dist/cli/verify.js +149 -0
- package/dist/cli/verify.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1135 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +2 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/parsers.d.ts +29 -0
- package/dist/core/parsers.d.ts.map +1 -0
- package/dist/core/parsers.js +296 -0
- package/dist/core/parsers.js.map +1 -0
- package/dist/core/parsers.test.d.ts +2 -0
- package/dist/core/parsers.test.d.ts.map +1 -0
- package/dist/core/parsers.test.js +198 -0
- package/dist/core/parsers.test.js.map +1 -0
- package/dist/core/prompts.d.ts +30 -0
- package/dist/core/prompts.d.ts.map +1 -0
- package/dist/core/prompts.js +346 -0
- package/dist/core/prompts.js.map +1 -0
- package/dist/core/refine.d.ts +38 -0
- package/dist/core/refine.d.ts.map +1 -0
- package/dist/core/refine.js +233 -0
- package/dist/core/refine.js.map +1 -0
- package/dist/core/spec-score.d.ts +17 -0
- package/dist/core/spec-score.d.ts.map +1 -0
- package/dist/core/spec-score.js +59 -0
- package/dist/core/spec-score.js.map +1 -0
- package/dist/formatters/index.d.ts +2 -0
- package/dist/formatters/index.d.ts.map +1 -0
- package/dist/formatters/index.js +2 -0
- package/dist/formatters/index.js.map +1 -0
- package/dist/formatters/stage-formatters.d.ts +10 -0
- package/dist/formatters/stage-formatters.d.ts.map +1 -0
- package/dist/formatters/stage-formatters.js +100 -0
- package/dist/formatters/stage-formatters.js.map +1 -0
- package/dist/formatters/stage-formatters.test.d.ts +2 -0
- package/dist/formatters/stage-formatters.test.d.ts.map +1 -0
- package/dist/formatters/stage-formatters.test.js +107 -0
- package/dist/formatters/stage-formatters.test.js.map +1 -0
- package/dist/guardrails/index.d.ts +2 -0
- package/dist/guardrails/index.d.ts.map +1 -0
- package/dist/guardrails/index.js +2 -0
- package/dist/guardrails/index.js.map +1 -0
- package/dist/guardrails/loader.d.ts +9 -0
- package/dist/guardrails/loader.d.ts.map +1 -0
- package/dist/guardrails/loader.js +56 -0
- package/dist/guardrails/loader.js.map +1 -0
- package/dist/guardrails/refine.d.ts +53 -0
- package/dist/guardrails/refine.d.ts.map +1 -0
- package/dist/guardrails/refine.js +184 -0
- package/dist/guardrails/refine.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +196 -0
- package/dist/index.js.map +1 -0
- package/dist/storage/change-detection.d.ts +2 -0
- package/dist/storage/change-detection.d.ts.map +1 -0
- package/dist/storage/change-detection.js +47 -0
- package/dist/storage/change-detection.js.map +1 -0
- package/dist/storage/change-detection.test.d.ts +2 -0
- package/dist/storage/change-detection.test.d.ts.map +1 -0
- package/dist/storage/change-detection.test.js +81 -0
- package/dist/storage/change-detection.test.js.map +1 -0
- package/dist/storage/index.d.ts +9 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +6 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/moodboard-describe.d.ts +14 -0
- package/dist/storage/moodboard-describe.d.ts.map +1 -0
- package/dist/storage/moodboard-describe.js +185 -0
- package/dist/storage/moodboard-describe.js.map +1 -0
- package/dist/storage/moodboard-sync.d.ts +11 -0
- package/dist/storage/moodboard-sync.d.ts.map +1 -0
- package/dist/storage/moodboard-sync.js +205 -0
- package/dist/storage/moodboard-sync.js.map +1 -0
- package/dist/storage/moodboard.d.ts +4 -0
- package/dist/storage/moodboard.d.ts.map +1 -0
- package/dist/storage/moodboard.js +68 -0
- package/dist/storage/moodboard.js.map +1 -0
- package/dist/storage/moodboard.test.d.ts +2 -0
- package/dist/storage/moodboard.test.d.ts.map +1 -0
- package/dist/storage/moodboard.test.js +133 -0
- package/dist/storage/moodboard.test.js.map +1 -0
- package/dist/storage/project-scan.d.ts +12 -0
- package/dist/storage/project-scan.d.ts.map +1 -0
- package/dist/storage/project-scan.js +118 -0
- package/dist/storage/project-scan.js.map +1 -0
- package/dist/storage/project.d.ts +10 -0
- package/dist/storage/project.d.ts.map +1 -0
- package/dist/storage/project.js +101 -0
- package/dist/storage/project.js.map +1 -0
- package/dist/storage/roles-refine.d.ts +59 -0
- package/dist/storage/roles-refine.d.ts.map +1 -0
- package/dist/storage/roles-refine.js +223 -0
- package/dist/storage/roles-refine.js.map +1 -0
- package/dist/storage/roles.d.ts +6 -0
- package/dist/storage/roles.d.ts.map +1 -0
- package/dist/storage/roles.js +41 -0
- package/dist/storage/roles.js.map +1 -0
- package/dist/storage/scenarios-refine.d.ts +47 -0
- package/dist/storage/scenarios-refine.d.ts.map +1 -0
- package/dist/storage/scenarios-refine.js +311 -0
- package/dist/storage/scenarios-refine.js.map +1 -0
- package/dist/storage/scenarios.d.ts +12 -0
- package/dist/storage/scenarios.d.ts.map +1 -0
- package/dist/storage/scenarios.js +37 -0
- package/dist/storage/scenarios.js.map +1 -0
- package/dist/storage/specs.d.ts +17 -0
- package/dist/storage/specs.d.ts.map +1 -0
- package/dist/storage/specs.js +104 -0
- package/dist/storage/specs.js.map +1 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/rerefine.d.ts +8 -0
- package/dist/tools/rerefine.d.ts.map +1 -0
- package/dist/tools/rerefine.js +153 -0
- package/dist/tools/rerefine.js.map +1 -0
- package/dist/tools/rerefine.test.d.ts +2 -0
- package/dist/tools/rerefine.test.d.ts.map +1 -0
- package/dist/tools/rerefine.test.js +123 -0
- package/dist/tools/rerefine.test.js.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/slug.d.ts +3 -0
- package/dist/utils/slug.d.ts.map +1 -0
- package/dist/utils/slug.js +33 -0
- package/dist/utils/slug.js.map +1 -0
- package/dist/utils/spec-helpers.d.ts +12 -0
- package/dist/utils/spec-helpers.d.ts.map +1 -0
- package/dist/utils/spec-helpers.js +95 -0
- package/dist/utils/spec-helpers.js.map +1 -0
- package/dist/utils/spec-helpers.test.d.ts +2 -0
- package/dist/utils/spec-helpers.test.d.ts.map +1 -0
- package/dist/utils/spec-helpers.test.js +114 -0
- package/dist/utils/spec-helpers.test.js.map +1 -0
- package/package.json +53 -0
- package/templates/guardrails/ask-when-unclear.md +3 -0
- package/templates/guardrails/dont-delete-code.md +3 -0
- package/templates/guardrails/explain-changes.md +3 -0
- package/templates/guardrails/run-tests.md +3 -0
- package/templates/guardrails/small-changes.md +3 -0
- package/templates/roles/builder.md +3 -0
- package/templates/roles/fixer.md +3 -0
- package/templates/roles/planner.md +3 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Refine Pipeline orchestrator.
|
|
3
|
+
* Runs a 5-stage refinement pipeline that transforms raw task descriptions
|
|
4
|
+
* into structured specifications.
|
|
5
|
+
*/
|
|
6
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
7
|
+
import { spawn, execFileSync } from "child_process";
|
|
8
|
+
import { writeFileSync, mkdirSync } from "fs";
|
|
9
|
+
import { buildProblemStatementPrompt, buildAcceptanceCriteriaPrompt, buildConstraintPrompt, buildDecompositionPrompt, buildEvaluationDesignPrompt, buildMoodboardPrompt, } from "./prompts.js";
|
|
10
|
+
import { stripPreamble, parseAcceptanceCriteria, parseConstraints, parseDecomposition, parseScenarios, } from "./parsers.js";
|
|
11
|
+
import { computeSpecScore } from "./spec-score.js";
|
|
12
|
+
const DEFAULT_TIMEOUT_MS = 300_000;
|
|
13
|
+
// ── Private helpers ────────────────────────────────────────────────────
|
|
14
|
+
function detectExecutionMode(options) {
|
|
15
|
+
if (options.executionMode) {
|
|
16
|
+
return options.executionMode;
|
|
17
|
+
}
|
|
18
|
+
if (options.apiKey || process.env.ANTHROPIC_API_KEY) {
|
|
19
|
+
return "api";
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
execFileSync("which", ["claude"]);
|
|
23
|
+
return "claude-code";
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return "clipboard";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async function executePrompt(prompt, mode, model, apiKey) {
|
|
30
|
+
if (mode === "clipboard") {
|
|
31
|
+
return `${prompt.systemPrompt}\n\n${prompt.userPrompt}`;
|
|
32
|
+
}
|
|
33
|
+
if (mode === "api") {
|
|
34
|
+
const client = new Anthropic({
|
|
35
|
+
apiKey: apiKey || process.env.ANTHROPIC_API_KEY,
|
|
36
|
+
});
|
|
37
|
+
const response = await client.messages.create({
|
|
38
|
+
model,
|
|
39
|
+
max_tokens: 4096,
|
|
40
|
+
system: prompt.systemPrompt,
|
|
41
|
+
messages: [{ role: "user", content: prompt.userPrompt }],
|
|
42
|
+
});
|
|
43
|
+
const textBlock = response.content.find((block) => block.type === "text");
|
|
44
|
+
return textBlock ? textBlock.text : "";
|
|
45
|
+
}
|
|
46
|
+
// claude-code mode — pipe prompt via stdin instead of -p flag
|
|
47
|
+
// (claude --print -p "..." hangs as a subprocess; stdin works reliably)
|
|
48
|
+
const combinedPrompt = `${prompt.systemPrompt}\n\n${prompt.userPrompt}`;
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
const child = spawn("claude", ["--print"], {
|
|
51
|
+
shell: false,
|
|
52
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
53
|
+
});
|
|
54
|
+
let stdout = "";
|
|
55
|
+
let resolved = false;
|
|
56
|
+
let dataTimer = null;
|
|
57
|
+
const finish = () => {
|
|
58
|
+
if (resolved)
|
|
59
|
+
return;
|
|
60
|
+
resolved = true;
|
|
61
|
+
clearTimeout(overallTimer);
|
|
62
|
+
if (dataTimer)
|
|
63
|
+
clearTimeout(dataTimer);
|
|
64
|
+
process.removeListener("SIGINT", onParentSigint);
|
|
65
|
+
child.kill();
|
|
66
|
+
resolve(stdout.trim());
|
|
67
|
+
};
|
|
68
|
+
child.stdout.on("data", (chunk) => {
|
|
69
|
+
stdout += chunk.toString();
|
|
70
|
+
// Reset idle timer on each chunk — after 2s of silence, assume done.
|
|
71
|
+
// Claude Code writes the full response before SessionEnd hooks run.
|
|
72
|
+
if (dataTimer)
|
|
73
|
+
clearTimeout(dataTimer);
|
|
74
|
+
dataTimer = setTimeout(finish, 2000);
|
|
75
|
+
});
|
|
76
|
+
child.on("close", () => {
|
|
77
|
+
finish();
|
|
78
|
+
});
|
|
79
|
+
const overallTimer = setTimeout(() => {
|
|
80
|
+
if (!resolved) {
|
|
81
|
+
resolved = true;
|
|
82
|
+
if (dataTimer)
|
|
83
|
+
clearTimeout(dataTimer);
|
|
84
|
+
process.removeListener("SIGINT", onParentSigint);
|
|
85
|
+
child.kill("SIGKILL");
|
|
86
|
+
reject(new Error(`Claude Code subprocess timed out after ${DEFAULT_TIMEOUT_MS / 1000}s`));
|
|
87
|
+
}
|
|
88
|
+
}, DEFAULT_TIMEOUT_MS);
|
|
89
|
+
const onParentSigint = () => {
|
|
90
|
+
child.kill("SIGINT");
|
|
91
|
+
};
|
|
92
|
+
process.once("SIGINT", onParentSigint);
|
|
93
|
+
child.on("error", (err) => {
|
|
94
|
+
if (!resolved) {
|
|
95
|
+
resolved = true;
|
|
96
|
+
clearTimeout(overallTimer);
|
|
97
|
+
if (dataTimer)
|
|
98
|
+
clearTimeout(dataTimer);
|
|
99
|
+
process.removeListener("SIGINT", onParentSigint);
|
|
100
|
+
reject(err);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
// Write prompt to stdin and close it
|
|
104
|
+
child.stdin.write(combinedPrompt);
|
|
105
|
+
child.stdin.end();
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
const PROMPT_BUILDERS = {
|
|
109
|
+
1: buildProblemStatementPrompt,
|
|
110
|
+
2: buildAcceptanceCriteriaPrompt,
|
|
111
|
+
3: buildConstraintPrompt,
|
|
112
|
+
4: buildDecompositionPrompt,
|
|
113
|
+
5: buildEvaluationDesignPrompt,
|
|
114
|
+
};
|
|
115
|
+
const STAGE_PARSERS = {
|
|
116
|
+
1: stripPreamble,
|
|
117
|
+
2: parseAcceptanceCriteria,
|
|
118
|
+
3: parseConstraints,
|
|
119
|
+
4: parseDecomposition,
|
|
120
|
+
5: parseScenarios,
|
|
121
|
+
};
|
|
122
|
+
function buildPromptForStage(stage, input, completedStages) {
|
|
123
|
+
const builder = PROMPT_BUILDERS[stage];
|
|
124
|
+
if (!builder) {
|
|
125
|
+
throw new Error(`Unknown stage: ${stage}`);
|
|
126
|
+
}
|
|
127
|
+
const findOutput = (s) => {
|
|
128
|
+
const result = completedStages.find((r) => r.stage === s);
|
|
129
|
+
if (!result || result.output == null)
|
|
130
|
+
return "";
|
|
131
|
+
if (typeof result.output === "string")
|
|
132
|
+
return result.output;
|
|
133
|
+
return JSON.stringify(result.output);
|
|
134
|
+
};
|
|
135
|
+
const opts = input.promptOptions;
|
|
136
|
+
// Resolve designContext: prefer moodboard (structured) over raw designContext string
|
|
137
|
+
const designContextStage1 = input.moodboard
|
|
138
|
+
? buildMoodboardPrompt(input.moodboard, 1)
|
|
139
|
+
: input.designContext;
|
|
140
|
+
const designContextStage3 = input.moodboard
|
|
141
|
+
? buildMoodboardPrompt(input.moodboard, 3)
|
|
142
|
+
: input.designContext;
|
|
143
|
+
switch (stage) {
|
|
144
|
+
case 1:
|
|
145
|
+
return buildProblemStatementPrompt(input.title, input.description, input.projectContext, input.role, opts, designContextStage1, input.projectCtx);
|
|
146
|
+
case 2:
|
|
147
|
+
return buildAcceptanceCriteriaPrompt(input.title, findOutput(1) || input.description, opts);
|
|
148
|
+
case 3:
|
|
149
|
+
return buildConstraintPrompt(input.title, findOutput(1) || input.description, findOutput(2), opts, designContextStage3, input.projectCtx);
|
|
150
|
+
case 4:
|
|
151
|
+
return buildDecompositionPrompt(input.title, findOutput(1) || input.description, findOutput(2), findOutput(3), opts);
|
|
152
|
+
case 5:
|
|
153
|
+
return buildEvaluationDesignPrompt(input.title, findOutput(1) || input.description, findOutput(2), findOutput(3), opts);
|
|
154
|
+
default:
|
|
155
|
+
throw new Error(`Unknown stage: ${stage}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function buildSpecScoreInput(input, completedStages) {
|
|
159
|
+
const hasStage = (s) => completedStages.some((r) => r.stage === s);
|
|
160
|
+
const refinedDesc = completedStages.find((r) => r.stage === 1);
|
|
161
|
+
const descText = refinedDesc && typeof refinedDesc.output === "string"
|
|
162
|
+
? refinedDesc.output
|
|
163
|
+
: input.description;
|
|
164
|
+
// A complete pipeline run (all 5 stages with output) produces a fully
|
|
165
|
+
// executable spec — guardrails and role are injected into prompts during
|
|
166
|
+
// refinement, so their presence in the input is not required for a 5/5.
|
|
167
|
+
const allFiveComplete = hasStage(1) && hasStage(2) && hasStage(3) && hasStage(4) && hasStage(5);
|
|
168
|
+
return {
|
|
169
|
+
hasDescription: descText.length > 0,
|
|
170
|
+
descriptionLength: descText.length,
|
|
171
|
+
wasRefined: hasStage(1),
|
|
172
|
+
hasAcceptanceCriteria: hasStage(2),
|
|
173
|
+
hasGuardrails: allFiveComplete || (input.guardrails ?? []).length > 0,
|
|
174
|
+
hasRole: allFiveComplete || (input.role ?? "").length > 0,
|
|
175
|
+
hasScenarios: hasStage(5),
|
|
176
|
+
hasSubtasks: hasStage(4),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
// ── Main export ────────────────────────────────────────────────────────
|
|
180
|
+
export async function refinePipeline(input, options = {}) {
|
|
181
|
+
const mode = detectExecutionMode(options);
|
|
182
|
+
const model = options.model ?? "claude-sonnet-4-6";
|
|
183
|
+
const stagesToRun = options.stages
|
|
184
|
+
? [...options.stages].sort((a, b) => a - b)
|
|
185
|
+
: [1, 2, 3, 4, 5];
|
|
186
|
+
const completedStages = [];
|
|
187
|
+
for (const stage of stagesToRun) {
|
|
188
|
+
const prompt = buildPromptForStage(stage, input, completedStages);
|
|
189
|
+
let rawResponse;
|
|
190
|
+
try {
|
|
191
|
+
rawResponse = await executePrompt(prompt, mode, model, options.apiKey);
|
|
192
|
+
}
|
|
193
|
+
catch (err) {
|
|
194
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
195
|
+
throw new Error(`Stage ${stage} failed: ${message}`);
|
|
196
|
+
}
|
|
197
|
+
// DEBUG: Write raw AI response for diagnosis (temporary — remove after fix is verified)
|
|
198
|
+
try {
|
|
199
|
+
mkdirSync(".stoa", { recursive: true });
|
|
200
|
+
writeFileSync(`.stoa/debug-stage-${stage}.txt`, rawResponse, "utf-8");
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
// Non-critical — ignore debug write failures
|
|
204
|
+
}
|
|
205
|
+
let output = null;
|
|
206
|
+
if (mode !== "clipboard") {
|
|
207
|
+
const parser = STAGE_PARSERS[stage];
|
|
208
|
+
if (parser) {
|
|
209
|
+
output = parser(rawResponse);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
const specScoreInput = mode === "clipboard"
|
|
213
|
+
? { hasDescription: false, descriptionLength: 0, wasRefined: false, hasAcceptanceCriteria: false, hasGuardrails: false, hasRole: false, hasScenarios: false, hasSubtasks: false }
|
|
214
|
+
: buildSpecScoreInput(input, [...completedStages, { stage, output, specScore: 0, rawResponse }]);
|
|
215
|
+
const specScore = mode === "clipboard" ? 0 : computeSpecScore(specScoreInput).score;
|
|
216
|
+
const stageResult = {
|
|
217
|
+
stage,
|
|
218
|
+
output,
|
|
219
|
+
specScore,
|
|
220
|
+
rawResponse,
|
|
221
|
+
};
|
|
222
|
+
completedStages.push(stageResult);
|
|
223
|
+
options.onStageComplete?.(stage, stageResult);
|
|
224
|
+
}
|
|
225
|
+
const lastStage = completedStages[completedStages.length - 1];
|
|
226
|
+
return {
|
|
227
|
+
stages: completedStages,
|
|
228
|
+
finalSpecScore: lastStage?.specScore ?? 0,
|
|
229
|
+
finalOutput: lastStage?.output ?? null,
|
|
230
|
+
executionMode: mode,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=refine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refine.js","sourceRoot":"","sources":["../../src/core/refine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface SpecScoreInput {
|
|
2
|
+
hasDescription: boolean;
|
|
3
|
+
descriptionLength: number;
|
|
4
|
+
wasRefined: boolean;
|
|
5
|
+
hasAcceptanceCriteria: boolean;
|
|
6
|
+
hasGuardrails: boolean;
|
|
7
|
+
hasRole: boolean;
|
|
8
|
+
hasScenarios: boolean;
|
|
9
|
+
hasSubtasks: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface SpecScoreResult {
|
|
12
|
+
score: number;
|
|
13
|
+
level: string;
|
|
14
|
+
missing: string[];
|
|
15
|
+
}
|
|
16
|
+
export declare function computeSpecScore(input: SpecScoreInput): SpecScoreResult;
|
|
17
|
+
//# sourceMappingURL=spec-score.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec-score.d.ts","sourceRoot":"","sources":["../../src/core/spec-score.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,cAAc,EAAE,OAAO,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,OAAO,CAAC;IACpB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAID,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,GAAG,eAAe,CAiDvE"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const DESCRIPTION_LENGTH_THRESHOLD = 100;
|
|
2
|
+
export function computeSpecScore(input) {
|
|
3
|
+
const hasAdequateLength = input.descriptionLength >= DESCRIPTION_LENGTH_THRESHOLD;
|
|
4
|
+
// Determine current level
|
|
5
|
+
let score;
|
|
6
|
+
let level;
|
|
7
|
+
if (!input.hasDescription) {
|
|
8
|
+
score = 0;
|
|
9
|
+
level = "Empty";
|
|
10
|
+
}
|
|
11
|
+
else if (!hasAdequateLength || !input.wasRefined) {
|
|
12
|
+
score = 1;
|
|
13
|
+
level = "Basic";
|
|
14
|
+
}
|
|
15
|
+
else if (!input.hasAcceptanceCriteria || !input.hasGuardrails) {
|
|
16
|
+
score = 2;
|
|
17
|
+
level = "Described";
|
|
18
|
+
}
|
|
19
|
+
else if (!input.hasRole || !input.hasScenarios) {
|
|
20
|
+
score = 3;
|
|
21
|
+
level = "Constrained";
|
|
22
|
+
}
|
|
23
|
+
else if (!input.hasSubtasks) {
|
|
24
|
+
score = 4;
|
|
25
|
+
level = "Specified";
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
return { score: 5, level: "Executable", missing: [] };
|
|
29
|
+
}
|
|
30
|
+
// Collect only the missing items needed to advance to the next level
|
|
31
|
+
const missing = [];
|
|
32
|
+
if (score === 0) {
|
|
33
|
+
missing.push("description");
|
|
34
|
+
}
|
|
35
|
+
if (score === 1) {
|
|
36
|
+
if (!hasAdequateLength)
|
|
37
|
+
missing.push("detailed description (100+ characters)");
|
|
38
|
+
if (!input.wasRefined)
|
|
39
|
+
missing.push("refinement pass");
|
|
40
|
+
}
|
|
41
|
+
if (score === 2) {
|
|
42
|
+
if (!input.hasAcceptanceCriteria)
|
|
43
|
+
missing.push("acceptance criteria");
|
|
44
|
+
if (!input.hasGuardrails)
|
|
45
|
+
missing.push("guardrails");
|
|
46
|
+
}
|
|
47
|
+
if (score === 3) {
|
|
48
|
+
if (!input.hasRole)
|
|
49
|
+
missing.push("role assignment");
|
|
50
|
+
if (!input.hasScenarios)
|
|
51
|
+
missing.push("scenarios");
|
|
52
|
+
}
|
|
53
|
+
if (score === 4) {
|
|
54
|
+
if (!input.hasSubtasks)
|
|
55
|
+
missing.push("subtasks");
|
|
56
|
+
}
|
|
57
|
+
return { score, level, missing };
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=spec-score.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec-score.js","sourceRoot":"","sources":["../../src/core/spec-score.ts"],"names":[],"mappings":"AAiBA,MAAM,4BAA4B,GAAG,GAAG,CAAC;AAEzC,MAAM,UAAU,gBAAgB,CAAC,KAAqB;IACpD,MAAM,iBAAiB,GAAG,KAAK,CAAC,iBAAiB,IAAI,4BAA4B,CAAC;IAElF,0BAA0B;IAC1B,IAAI,KAAa,CAAC;IAClB,IAAI,KAAa,CAAC;IAElB,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC;QAC1B,KAAK,GAAG,CAAC,CAAC;QACV,KAAK,GAAG,OAAO,CAAC;IAClB,CAAC;SAAM,IAAI,CAAC,iBAAiB,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;QACnD,KAAK,GAAG,CAAC,CAAC;QACV,KAAK,GAAG,OAAO,CAAC;IAClB,CAAC;SAAM,IAAI,CAAC,KAAK,CAAC,qBAAqB,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;QAChE,KAAK,GAAG,CAAC,CAAC;QACV,KAAK,GAAG,WAAW,CAAC;IACtB,CAAC;SAAM,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;QACjD,KAAK,GAAG,CAAC,CAAC;QACV,KAAK,GAAG,aAAa,CAAC;IACxB,CAAC;SAAM,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;QAC9B,KAAK,GAAG,CAAC,CAAC;QACV,KAAK,GAAG,WAAW,CAAC;IACtB,CAAC;SAAM,CAAC;QACN,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACxD,CAAC;IAED,qEAAqE;IACrE,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QAChB,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC9B,CAAC;IACD,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QAChB,IAAI,CAAC,iBAAiB;YAAE,OAAO,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;QAC/E,IAAI,CAAC,KAAK,CAAC,UAAU;YAAE,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACzD,CAAC;IACD,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QAChB,IAAI,CAAC,KAAK,CAAC,qBAAqB;YAAE,OAAO,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QACtE,IAAI,CAAC,KAAK,CAAC,aAAa;YAAE,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACvD,CAAC;IACD,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QAChB,IAAI,CAAC,KAAK,CAAC,OAAO;YAAE,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACpD,IAAI,CAAC,KAAK,CAAC,YAAY;YAAE,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACrD,CAAC;IACD,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QAChB,IAAI,CAAC,KAAK,CAAC,WAAW;YAAE,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACnD,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,iBAAiB,EACjB,cAAc,EACd,eAAe,GAChB,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,iBAAiB,EACjB,cAAc,EACd,eAAe,GAChB,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure markdown formatters for the 5 Refine Pipeline stages.
|
|
3
|
+
* No side effects, no I/O, no external dependencies.
|
|
4
|
+
*/
|
|
5
|
+
export declare function formatDescription(raw: string): string;
|
|
6
|
+
export declare function formatAcceptanceCriteria(raw: string): string;
|
|
7
|
+
export declare function formatConstraints(raw: string): string;
|
|
8
|
+
export declare function formatSubtasks(raw: string): string;
|
|
9
|
+
export declare function formatScenarios(raw: string): string;
|
|
10
|
+
//# sourceMappingURL=stage-formatters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stage-formatters.d.ts","sourceRoot":"","sources":["../../src/formatters/stage-formatters.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA0CH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK5D;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA4BrD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAUlD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAUnD"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure markdown formatters for the 5 Refine Pipeline stages.
|
|
3
|
+
* No side effects, no I/O, no external dependencies.
|
|
4
|
+
*/
|
|
5
|
+
function normalizeWhitespace(raw) {
|
|
6
|
+
return raw
|
|
7
|
+
.replace(/\r\n/g, "\n")
|
|
8
|
+
.replace(/\n{3,}/g, "\n\n")
|
|
9
|
+
.replace(/^[\t ]+$/gm, "")
|
|
10
|
+
.replace(/^\n+/, "")
|
|
11
|
+
.replace(/\n+$/, "");
|
|
12
|
+
}
|
|
13
|
+
function splitIntoItems(raw) {
|
|
14
|
+
const lines = raw.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
15
|
+
const listItems = [];
|
|
16
|
+
const listPattern = /^(?:\d+[\.\)]\s*|-\s*|\*\s*)/;
|
|
17
|
+
if (lines.some((l) => listPattern.test(l))) {
|
|
18
|
+
let current = "";
|
|
19
|
+
for (const line of lines) {
|
|
20
|
+
if (listPattern.test(line)) {
|
|
21
|
+
if (current)
|
|
22
|
+
listItems.push(current);
|
|
23
|
+
current = line.replace(listPattern, "").trim();
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
current += " " + line;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (current)
|
|
30
|
+
listItems.push(current);
|
|
31
|
+
}
|
|
32
|
+
if (listItems.length > 0)
|
|
33
|
+
return listItems;
|
|
34
|
+
// Prose: split on sentence boundaries
|
|
35
|
+
const text = lines.join(" ");
|
|
36
|
+
const sentences = text
|
|
37
|
+
.split(/(?<=[.!?])\s+/)
|
|
38
|
+
.map((s) => s.trim())
|
|
39
|
+
.filter(Boolean);
|
|
40
|
+
return sentences.length > 0 ? sentences : [text];
|
|
41
|
+
}
|
|
42
|
+
export function formatDescription(raw) {
|
|
43
|
+
if (!raw || !raw.trim())
|
|
44
|
+
return "No description provided.";
|
|
45
|
+
return normalizeWhitespace(raw);
|
|
46
|
+
}
|
|
47
|
+
export function formatAcceptanceCriteria(raw) {
|
|
48
|
+
if (!raw || !raw.trim())
|
|
49
|
+
return "1. No acceptance criteria specified.";
|
|
50
|
+
const items = splitIntoItems(raw);
|
|
51
|
+
return items.map((item, i) => `${i + 1}. ${item}`).join("\n");
|
|
52
|
+
}
|
|
53
|
+
export function formatConstraints(raw) {
|
|
54
|
+
if (!raw || !raw.trim()) {
|
|
55
|
+
return "## MUSTS\n\n- None specified.\n\n## MUST-NOTS\n\n- None specified.";
|
|
56
|
+
}
|
|
57
|
+
const items = splitIntoItems(raw);
|
|
58
|
+
const mustNotPattern = /\b(must\s+not|never|avoid|do\s+not|don['']t|shall\s+not|cannot|can['']t)\b/i;
|
|
59
|
+
const musts = [];
|
|
60
|
+
const mustNots = [];
|
|
61
|
+
for (const item of items) {
|
|
62
|
+
if (mustNotPattern.test(item)) {
|
|
63
|
+
mustNots.push(item);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
musts.push(item);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const mustsSection = musts.length > 0
|
|
70
|
+
? musts.map((m) => `- ${m}`).join("\n")
|
|
71
|
+
: "- None specified.";
|
|
72
|
+
const mustNotsSection = mustNots.length > 0
|
|
73
|
+
? mustNots.map((m) => `- ${m}`).join("\n")
|
|
74
|
+
: "- None specified.";
|
|
75
|
+
return `## MUSTS\n\n${mustsSection}\n\n## MUST-NOTS\n\n${mustNotsSection}`;
|
|
76
|
+
}
|
|
77
|
+
export function formatSubtasks(raw) {
|
|
78
|
+
if (!raw || !raw.trim())
|
|
79
|
+
return "No decomposition needed.";
|
|
80
|
+
const noDecompPattern = /\b(no\s+decomposition|single\s+task|not\s+needed|no\s+subtasks)\b/i;
|
|
81
|
+
if (noDecompPattern.test(raw))
|
|
82
|
+
return "No decomposition needed.";
|
|
83
|
+
const items = splitIntoItems(raw);
|
|
84
|
+
if (items.length === 0)
|
|
85
|
+
return "No decomposition needed.";
|
|
86
|
+
return items.map((item) => `- [ ] ${item}`).join("\n");
|
|
87
|
+
}
|
|
88
|
+
export function formatScenarios(raw) {
|
|
89
|
+
if (!raw || !raw.trim()) {
|
|
90
|
+
return "[]";
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
const parsed = JSON.parse(raw);
|
|
94
|
+
return JSON.stringify(parsed, null, 2);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return raw;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=stage-formatters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stage-formatters.js","sourceRoot":"","sources":["../../src/formatters/stage-formatters.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stage-formatters.test.d.ts","sourceRoot":"","sources":["../../src/formatters/stage-formatters.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { strict as assert } from "node:assert";
|
|
2
|
+
import { test } from "node:test";
|
|
3
|
+
import { formatDescription, formatAcceptanceCriteria, formatConstraints, formatSubtasks, formatScenarios, } from "./stage-formatters.js";
|
|
4
|
+
// --- formatDescription ---
|
|
5
|
+
test("formatDescription normalizes whitespace", () => {
|
|
6
|
+
const raw = "\n\nBuild a REST API that handles user authentication.\n\n\n\nIt should support OAuth2.\n\n\n";
|
|
7
|
+
const result = formatDescription(raw);
|
|
8
|
+
assert.equal(result, "Build a REST API that handles user authentication.\n\nIt should support OAuth2.");
|
|
9
|
+
});
|
|
10
|
+
test("formatDescription handles empty input", () => {
|
|
11
|
+
assert.equal(formatDescription(""), "No description provided.");
|
|
12
|
+
assert.equal(formatDescription(" "), "No description provided.");
|
|
13
|
+
});
|
|
14
|
+
// --- formatAcceptanceCriteria ---
|
|
15
|
+
test("formatAcceptanceCriteria parses numbered list", () => {
|
|
16
|
+
const raw = "1. Users can log in\n2. Users can log out\n3. Sessions expire after 30 min";
|
|
17
|
+
const result = formatAcceptanceCriteria(raw);
|
|
18
|
+
assert.equal(result, "1. Users can log in\n2. Users can log out\n3. Sessions expire after 30 min");
|
|
19
|
+
});
|
|
20
|
+
test("formatAcceptanceCriteria parses bullet list", () => {
|
|
21
|
+
const raw = "- Users can log in\n- Users can log out";
|
|
22
|
+
const result = formatAcceptanceCriteria(raw);
|
|
23
|
+
assert.equal(result, "1. Users can log in\n2. Users can log out");
|
|
24
|
+
});
|
|
25
|
+
test("formatAcceptanceCriteria splits prose into sentences", () => {
|
|
26
|
+
const raw = "The system should validate emails. Passwords must be at least 8 characters. Users receive a confirmation email.";
|
|
27
|
+
const result = formatAcceptanceCriteria(raw);
|
|
28
|
+
assert.ok(result.startsWith("1. "));
|
|
29
|
+
assert.ok(result.includes("2. "));
|
|
30
|
+
assert.ok(result.includes("3. "));
|
|
31
|
+
});
|
|
32
|
+
test("formatAcceptanceCriteria handles empty input", () => {
|
|
33
|
+
const result = formatAcceptanceCriteria("");
|
|
34
|
+
assert.ok(result.includes("1."));
|
|
35
|
+
});
|
|
36
|
+
// --- formatConstraints ---
|
|
37
|
+
test("formatConstraints classifies MUSTS and MUST-NOTS", () => {
|
|
38
|
+
const raw = "Must use TypeScript. Must not use any external dependencies. Avoid global state. Should support ESM only.";
|
|
39
|
+
const result = formatConstraints(raw);
|
|
40
|
+
assert.ok(result.includes("## MUSTS"));
|
|
41
|
+
assert.ok(result.includes("## MUST-NOTS"));
|
|
42
|
+
assert.ok(result.includes("- Must use TypeScript."));
|
|
43
|
+
assert.ok(result.includes("- Must not use any external dependencies."));
|
|
44
|
+
assert.ok(result.includes("- Avoid global state."));
|
|
45
|
+
});
|
|
46
|
+
test("formatConstraints handles no must-nots", () => {
|
|
47
|
+
const raw = "Use TypeScript. Support ESM.";
|
|
48
|
+
const result = formatConstraints(raw);
|
|
49
|
+
assert.ok(result.includes("## MUST-NOTS"));
|
|
50
|
+
assert.ok(result.includes("- None specified."));
|
|
51
|
+
});
|
|
52
|
+
test("formatConstraints handles empty input", () => {
|
|
53
|
+
const result = formatConstraints("");
|
|
54
|
+
assert.ok(result.includes("## MUSTS"));
|
|
55
|
+
assert.ok(result.includes("## MUST-NOTS"));
|
|
56
|
+
});
|
|
57
|
+
// --- formatSubtasks ---
|
|
58
|
+
test("formatSubtasks produces task list", () => {
|
|
59
|
+
const raw = "1. Set up project structure\n2. Implement auth module\n3. Write tests";
|
|
60
|
+
const result = formatSubtasks(raw);
|
|
61
|
+
assert.ok(result.includes("- [ ] Set up project structure"));
|
|
62
|
+
assert.ok(result.includes("- [ ] Implement auth module"));
|
|
63
|
+
assert.ok(result.includes("- [ ] Write tests"));
|
|
64
|
+
});
|
|
65
|
+
test("formatSubtasks detects no decomposition", () => {
|
|
66
|
+
assert.equal(formatSubtasks("No decomposition needed for this task."), "No decomposition needed.");
|
|
67
|
+
assert.equal(formatSubtasks("This is a single task."), "No decomposition needed.");
|
|
68
|
+
});
|
|
69
|
+
test("formatSubtasks handles empty input", () => {
|
|
70
|
+
assert.equal(formatSubtasks(""), "No decomposition needed.");
|
|
71
|
+
});
|
|
72
|
+
// --- formatScenarios ---
|
|
73
|
+
test("formatScenarios parses given/when/then", () => {
|
|
74
|
+
const raw = "Given a user is logged in When they click logout Then they are redirected to the login page";
|
|
75
|
+
const result = formatScenarios(raw);
|
|
76
|
+
assert.ok(result.includes("**Scenario 1**"));
|
|
77
|
+
assert.ok(result.includes("GIVEN:"));
|
|
78
|
+
assert.ok(result.includes("EXPECTED:"));
|
|
79
|
+
});
|
|
80
|
+
test("formatScenarios parses GIVEN/EXPECTED style", () => {
|
|
81
|
+
const raw = "GIVEN a valid API key EXPECTED the request succeeds with 200";
|
|
82
|
+
const result = formatScenarios(raw);
|
|
83
|
+
assert.ok(result.includes("**Scenario 1**"));
|
|
84
|
+
assert.ok(result.includes("GIVEN: a valid API key"));
|
|
85
|
+
assert.ok(result.includes("EXPECTED: the request succeeds with 200"));
|
|
86
|
+
});
|
|
87
|
+
test("formatScenarios handles empty input", () => {
|
|
88
|
+
const result = formatScenarios("");
|
|
89
|
+
assert.ok(result.includes("**Scenario 1**"));
|
|
90
|
+
assert.ok(result.includes("GIVEN:"));
|
|
91
|
+
assert.ok(result.includes("EXPECTED:"));
|
|
92
|
+
});
|
|
93
|
+
test("formatScenarios handles multiple scenarios", () => {
|
|
94
|
+
const raw = "GIVEN valid input EXPECTED success\nGIVEN invalid input EXPECTED error message";
|
|
95
|
+
const result = formatScenarios(raw);
|
|
96
|
+
assert.ok(result.includes("**Scenario 1**"));
|
|
97
|
+
assert.ok(result.includes("**Scenario 2**"));
|
|
98
|
+
});
|
|
99
|
+
test("all formatters are pure - same input yields same output", () => {
|
|
100
|
+
const input = "Test input string. Another sentence.";
|
|
101
|
+
assert.equal(formatDescription(input), formatDescription(input));
|
|
102
|
+
assert.equal(formatAcceptanceCriteria(input), formatAcceptanceCriteria(input));
|
|
103
|
+
assert.equal(formatConstraints(input), formatConstraints(input));
|
|
104
|
+
assert.equal(formatSubtasks(input), formatSubtasks(input));
|
|
105
|
+
assert.equal(formatScenarios(input), formatScenarios(input));
|
|
106
|
+
});
|
|
107
|
+
//# sourceMappingURL=stage-formatters.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stage-formatters.test.js","sourceRoot":"","sources":["../../src/formatters/stage-formatters.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/guardrails/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/guardrails/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function listGuardrails(): Array<{
|
|
2
|
+
slug: string;
|
|
3
|
+
title: string;
|
|
4
|
+
}>;
|
|
5
|
+
export declare function addGuardrail(title: string): void;
|
|
6
|
+
export declare function showGuardrail(slug: string): string;
|
|
7
|
+
export declare function removeGuardrail(slug: string): void;
|
|
8
|
+
export declare function loadAllGuardrails(): string;
|
|
9
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/guardrails/loader.ts"],"names":[],"mappings":"AAQA,wBAAgB,cAAc,IAAI,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAcvE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAUhD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQlD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAQlD;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAY1C"}
|