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.
Files changed (167) hide show
  1. package/LICENSE +65 -0
  2. package/README.md +397 -0
  3. package/dist/cli/build.d.ts +39 -0
  4. package/dist/cli/build.d.ts.map +1 -0
  5. package/dist/cli/build.js +288 -0
  6. package/dist/cli/build.js.map +1 -0
  7. package/dist/cli/review-loop.d.ts +2 -0
  8. package/dist/cli/review-loop.d.ts.map +1 -0
  9. package/dist/cli/review-loop.js +97 -0
  10. package/dist/cli/review-loop.js.map +1 -0
  11. package/dist/cli/scenarios-runner.d.ts +12 -0
  12. package/dist/cli/scenarios-runner.d.ts.map +1 -0
  13. package/dist/cli/scenarios-runner.js +158 -0
  14. package/dist/cli/scenarios-runner.js.map +1 -0
  15. package/dist/cli/verify.d.ts +13 -0
  16. package/dist/cli/verify.d.ts.map +1 -0
  17. package/dist/cli/verify.js +149 -0
  18. package/dist/cli/verify.js.map +1 -0
  19. package/dist/cli.d.ts +3 -0
  20. package/dist/cli.d.ts.map +1 -0
  21. package/dist/cli.js +1135 -0
  22. package/dist/cli.js.map +1 -0
  23. package/dist/core/index.d.ts +3 -0
  24. package/dist/core/index.d.ts.map +1 -0
  25. package/dist/core/index.js +2 -0
  26. package/dist/core/index.js.map +1 -0
  27. package/dist/core/parsers.d.ts +29 -0
  28. package/dist/core/parsers.d.ts.map +1 -0
  29. package/dist/core/parsers.js +296 -0
  30. package/dist/core/parsers.js.map +1 -0
  31. package/dist/core/parsers.test.d.ts +2 -0
  32. package/dist/core/parsers.test.d.ts.map +1 -0
  33. package/dist/core/parsers.test.js +198 -0
  34. package/dist/core/parsers.test.js.map +1 -0
  35. package/dist/core/prompts.d.ts +30 -0
  36. package/dist/core/prompts.d.ts.map +1 -0
  37. package/dist/core/prompts.js +346 -0
  38. package/dist/core/prompts.js.map +1 -0
  39. package/dist/core/refine.d.ts +38 -0
  40. package/dist/core/refine.d.ts.map +1 -0
  41. package/dist/core/refine.js +233 -0
  42. package/dist/core/refine.js.map +1 -0
  43. package/dist/core/spec-score.d.ts +17 -0
  44. package/dist/core/spec-score.d.ts.map +1 -0
  45. package/dist/core/spec-score.js +59 -0
  46. package/dist/core/spec-score.js.map +1 -0
  47. package/dist/formatters/index.d.ts +2 -0
  48. package/dist/formatters/index.d.ts.map +1 -0
  49. package/dist/formatters/index.js +2 -0
  50. package/dist/formatters/index.js.map +1 -0
  51. package/dist/formatters/stage-formatters.d.ts +10 -0
  52. package/dist/formatters/stage-formatters.d.ts.map +1 -0
  53. package/dist/formatters/stage-formatters.js +100 -0
  54. package/dist/formatters/stage-formatters.js.map +1 -0
  55. package/dist/formatters/stage-formatters.test.d.ts +2 -0
  56. package/dist/formatters/stage-formatters.test.d.ts.map +1 -0
  57. package/dist/formatters/stage-formatters.test.js +107 -0
  58. package/dist/formatters/stage-formatters.test.js.map +1 -0
  59. package/dist/guardrails/index.d.ts +2 -0
  60. package/dist/guardrails/index.d.ts.map +1 -0
  61. package/dist/guardrails/index.js +2 -0
  62. package/dist/guardrails/index.js.map +1 -0
  63. package/dist/guardrails/loader.d.ts +9 -0
  64. package/dist/guardrails/loader.d.ts.map +1 -0
  65. package/dist/guardrails/loader.js +56 -0
  66. package/dist/guardrails/loader.js.map +1 -0
  67. package/dist/guardrails/refine.d.ts +53 -0
  68. package/dist/guardrails/refine.d.ts.map +1 -0
  69. package/dist/guardrails/refine.js +184 -0
  70. package/dist/guardrails/refine.js.map +1 -0
  71. package/dist/index.d.ts +6 -0
  72. package/dist/index.d.ts.map +1 -0
  73. package/dist/index.js +196 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/storage/change-detection.d.ts +2 -0
  76. package/dist/storage/change-detection.d.ts.map +1 -0
  77. package/dist/storage/change-detection.js +47 -0
  78. package/dist/storage/change-detection.js.map +1 -0
  79. package/dist/storage/change-detection.test.d.ts +2 -0
  80. package/dist/storage/change-detection.test.d.ts.map +1 -0
  81. package/dist/storage/change-detection.test.js +81 -0
  82. package/dist/storage/change-detection.test.js.map +1 -0
  83. package/dist/storage/index.d.ts +9 -0
  84. package/dist/storage/index.d.ts.map +1 -0
  85. package/dist/storage/index.js +6 -0
  86. package/dist/storage/index.js.map +1 -0
  87. package/dist/storage/moodboard-describe.d.ts +14 -0
  88. package/dist/storage/moodboard-describe.d.ts.map +1 -0
  89. package/dist/storage/moodboard-describe.js +185 -0
  90. package/dist/storage/moodboard-describe.js.map +1 -0
  91. package/dist/storage/moodboard-sync.d.ts +11 -0
  92. package/dist/storage/moodboard-sync.d.ts.map +1 -0
  93. package/dist/storage/moodboard-sync.js +205 -0
  94. package/dist/storage/moodboard-sync.js.map +1 -0
  95. package/dist/storage/moodboard.d.ts +4 -0
  96. package/dist/storage/moodboard.d.ts.map +1 -0
  97. package/dist/storage/moodboard.js +68 -0
  98. package/dist/storage/moodboard.js.map +1 -0
  99. package/dist/storage/moodboard.test.d.ts +2 -0
  100. package/dist/storage/moodboard.test.d.ts.map +1 -0
  101. package/dist/storage/moodboard.test.js +133 -0
  102. package/dist/storage/moodboard.test.js.map +1 -0
  103. package/dist/storage/project-scan.d.ts +12 -0
  104. package/dist/storage/project-scan.d.ts.map +1 -0
  105. package/dist/storage/project-scan.js +118 -0
  106. package/dist/storage/project-scan.js.map +1 -0
  107. package/dist/storage/project.d.ts +10 -0
  108. package/dist/storage/project.d.ts.map +1 -0
  109. package/dist/storage/project.js +101 -0
  110. package/dist/storage/project.js.map +1 -0
  111. package/dist/storage/roles-refine.d.ts +59 -0
  112. package/dist/storage/roles-refine.d.ts.map +1 -0
  113. package/dist/storage/roles-refine.js +223 -0
  114. package/dist/storage/roles-refine.js.map +1 -0
  115. package/dist/storage/roles.d.ts +6 -0
  116. package/dist/storage/roles.d.ts.map +1 -0
  117. package/dist/storage/roles.js +41 -0
  118. package/dist/storage/roles.js.map +1 -0
  119. package/dist/storage/scenarios-refine.d.ts +47 -0
  120. package/dist/storage/scenarios-refine.d.ts.map +1 -0
  121. package/dist/storage/scenarios-refine.js +311 -0
  122. package/dist/storage/scenarios-refine.js.map +1 -0
  123. package/dist/storage/scenarios.d.ts +12 -0
  124. package/dist/storage/scenarios.d.ts.map +1 -0
  125. package/dist/storage/scenarios.js +37 -0
  126. package/dist/storage/scenarios.js.map +1 -0
  127. package/dist/storage/specs.d.ts +17 -0
  128. package/dist/storage/specs.d.ts.map +1 -0
  129. package/dist/storage/specs.js +104 -0
  130. package/dist/storage/specs.js.map +1 -0
  131. package/dist/tools/index.d.ts +2 -0
  132. package/dist/tools/index.d.ts.map +1 -0
  133. package/dist/tools/index.js +2 -0
  134. package/dist/tools/index.js.map +1 -0
  135. package/dist/tools/rerefine.d.ts +8 -0
  136. package/dist/tools/rerefine.d.ts.map +1 -0
  137. package/dist/tools/rerefine.js +153 -0
  138. package/dist/tools/rerefine.js.map +1 -0
  139. package/dist/tools/rerefine.test.d.ts +2 -0
  140. package/dist/tools/rerefine.test.d.ts.map +1 -0
  141. package/dist/tools/rerefine.test.js +123 -0
  142. package/dist/tools/rerefine.test.js.map +1 -0
  143. package/dist/utils/index.d.ts +3 -0
  144. package/dist/utils/index.d.ts.map +1 -0
  145. package/dist/utils/index.js +3 -0
  146. package/dist/utils/index.js.map +1 -0
  147. package/dist/utils/slug.d.ts +3 -0
  148. package/dist/utils/slug.d.ts.map +1 -0
  149. package/dist/utils/slug.js +33 -0
  150. package/dist/utils/slug.js.map +1 -0
  151. package/dist/utils/spec-helpers.d.ts +12 -0
  152. package/dist/utils/spec-helpers.d.ts.map +1 -0
  153. package/dist/utils/spec-helpers.js +95 -0
  154. package/dist/utils/spec-helpers.js.map +1 -0
  155. package/dist/utils/spec-helpers.test.d.ts +2 -0
  156. package/dist/utils/spec-helpers.test.d.ts.map +1 -0
  157. package/dist/utils/spec-helpers.test.js +114 -0
  158. package/dist/utils/spec-helpers.test.js.map +1 -0
  159. package/package.json +53 -0
  160. package/templates/guardrails/ask-when-unclear.md +3 -0
  161. package/templates/guardrails/dont-delete-code.md +3 -0
  162. package/templates/guardrails/explain-changes.md +3 -0
  163. package/templates/guardrails/run-tests.md +3 -0
  164. package/templates/guardrails/small-changes.md +3 -0
  165. package/templates/roles/builder.md +3 -0
  166. package/templates/roles/fixer.md +3 -0
  167. package/templates/roles/planner.md +3 -0
@@ -0,0 +1,95 @@
1
+ import { readdir, readFile, stat } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { z } from "zod";
4
+ export class InvalidSpecNameError extends Error {
5
+ code = "INVALID_SPEC_NAME";
6
+ constructor(message = "Invalid spec name") {
7
+ super(message);
8
+ this.name = "InvalidSpecNameError";
9
+ }
10
+ }
11
+ export function validateSpecName(name) {
12
+ if (name === "" || name.trim() === "") {
13
+ throw new InvalidSpecNameError("Spec name must not be empty");
14
+ }
15
+ if (name.includes("/") || name.includes("\\")) {
16
+ throw new InvalidSpecNameError("Spec name must not contain path separators");
17
+ }
18
+ }
19
+ export class SpecNotFoundError extends Error {
20
+ code = "NO_SPECS";
21
+ constructor(message = "No specs found. Run stoa refine <task> first.") {
22
+ super(message);
23
+ this.name = "SpecNotFoundError";
24
+ }
25
+ }
26
+ export async function resolveSpecName(name) {
27
+ if (name !== undefined) {
28
+ validateSpecName(name);
29
+ return name;
30
+ }
31
+ const specsDir = join(process.cwd(), ".stoa", "specs");
32
+ let entries;
33
+ try {
34
+ entries = await readdir(specsDir);
35
+ }
36
+ catch {
37
+ throw new SpecNotFoundError();
38
+ }
39
+ const dirs = [];
40
+ for (const entry of entries) {
41
+ const s = await stat(join(specsDir, entry));
42
+ if (s.isDirectory()) {
43
+ dirs.push({ name: entry, mtime: s.mtimeMs });
44
+ }
45
+ }
46
+ if (dirs.length === 0) {
47
+ throw new SpecNotFoundError();
48
+ }
49
+ dirs.sort((a, b) => b.mtime - a.mtime);
50
+ return dirs[0].name;
51
+ }
52
+ const SPEC_FILES = [
53
+ "01-problem-statement.md",
54
+ "02-acceptance-criteria.md",
55
+ "03-constraints.md",
56
+ "04-decomposition.md",
57
+ "05-evaluation-design.md",
58
+ "user-notes.md",
59
+ "moodboard.md",
60
+ ];
61
+ const FrontMatterSchema = z.object({}).passthrough();
62
+ function hasYamlFrontMatter(content) {
63
+ return content.startsWith("---\n") || content.startsWith("---\r\n");
64
+ }
65
+ function isJsonContent(content) {
66
+ const trimmed = content.trimStart();
67
+ return trimmed.startsWith("{") || trimmed.startsWith("[");
68
+ }
69
+ export async function snapshotSpecFiles(specDir) {
70
+ const result = {};
71
+ for (const filename of SPEC_FILES) {
72
+ const filePath = join(specDir, filename);
73
+ let content;
74
+ try {
75
+ content = await readFile(filePath, "utf-8");
76
+ }
77
+ catch (err) {
78
+ if (err instanceof Error &&
79
+ "code" in err &&
80
+ err.code === "ENOENT") {
81
+ continue;
82
+ }
83
+ throw err;
84
+ }
85
+ if (hasYamlFrontMatter(content)) {
86
+ FrontMatterSchema.parse({});
87
+ }
88
+ else if (isJsonContent(content)) {
89
+ z.record(z.string(), z.unknown()).parse(JSON.parse(content));
90
+ }
91
+ result[filename] = content;
92
+ }
93
+ return result;
94
+ }
95
+ //# sourceMappingURL=spec-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-helpers.js","sourceRoot":"","sources":["../../src/utils/spec-helpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=spec-helpers.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-helpers.test.d.ts","sourceRoot":"","sources":["../../src/utils/spec-helpers.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,114 @@
1
+ import { describe, it, beforeEach, afterEach } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { mkdir, writeFile, rm } from "node:fs/promises";
4
+ import { join } from "node:path";
5
+ import { resolveSpecName, snapshotSpecFiles, SpecNotFoundError } from "./spec-helpers.js";
6
+ const TEST_ROOT = join(process.cwd(), ".stoa-test-helpers");
7
+ const SPECS_DIR = join(TEST_ROOT, ".stoa", "specs");
8
+ describe("resolveSpecName", () => {
9
+ beforeEach(async () => {
10
+ await rm(TEST_ROOT, { recursive: true, force: true });
11
+ });
12
+ afterEach(async () => {
13
+ await rm(TEST_ROOT, { recursive: true, force: true });
14
+ });
15
+ it("returns the provided name when given", async () => {
16
+ const result = await resolveSpecName("my-spec");
17
+ assert.equal(result, "my-spec");
18
+ });
19
+ it("throws SpecNotFoundError when .stoa/specs/ does not exist", async () => {
20
+ const originalCwd = process.cwd();
21
+ await mkdir(TEST_ROOT, { recursive: true });
22
+ process.chdir(TEST_ROOT);
23
+ try {
24
+ await assert.rejects(() => resolveSpecName(), (err) => {
25
+ assert.ok(err instanceof SpecNotFoundError);
26
+ assert.equal(err.message, "No specs found. Run stoa refine <task> first.");
27
+ assert.equal(err.code, "NO_SPECS");
28
+ return true;
29
+ });
30
+ }
31
+ finally {
32
+ process.chdir(originalCwd);
33
+ }
34
+ });
35
+ it("throws SpecNotFoundError when .stoa/specs/ has no subdirectories", async () => {
36
+ const originalCwd = process.cwd();
37
+ await mkdir(SPECS_DIR, { recursive: true });
38
+ await writeFile(join(SPECS_DIR, "some-file.txt"), "not a dir");
39
+ process.chdir(TEST_ROOT);
40
+ try {
41
+ await assert.rejects(() => resolveSpecName(), (err) => {
42
+ assert.ok(err instanceof SpecNotFoundError);
43
+ return true;
44
+ });
45
+ }
46
+ finally {
47
+ process.chdir(originalCwd);
48
+ }
49
+ });
50
+ it("returns the most recently modified subdirectory", async () => {
51
+ const originalCwd = process.cwd();
52
+ await mkdir(join(SPECS_DIR, "older-spec"), { recursive: true });
53
+ // Small delay to ensure different mtime
54
+ await new Promise((r) => setTimeout(r, 50));
55
+ await mkdir(join(SPECS_DIR, "newer-spec"), { recursive: true });
56
+ process.chdir(TEST_ROOT);
57
+ try {
58
+ const result = await resolveSpecName();
59
+ assert.equal(result, "newer-spec");
60
+ }
61
+ finally {
62
+ process.chdir(originalCwd);
63
+ }
64
+ });
65
+ });
66
+ describe("snapshotSpecFiles", () => {
67
+ const specDir = join(TEST_ROOT, "test-spec");
68
+ beforeEach(async () => {
69
+ await rm(TEST_ROOT, { recursive: true, force: true });
70
+ await mkdir(specDir, { recursive: true });
71
+ });
72
+ afterEach(async () => {
73
+ await rm(TEST_ROOT, { recursive: true, force: true });
74
+ });
75
+ it("returns only filenames that exist on disk", async () => {
76
+ await writeFile(join(specDir, "01-problem-statement.md"), "# My Description");
77
+ await writeFile(join(specDir, "02-acceptance-criteria.md"), "## Criteria");
78
+ const result = await snapshotSpecFiles(specDir);
79
+ assert.ok("01-problem-statement.md" in result);
80
+ assert.ok("02-acceptance-criteria.md" in result);
81
+ assert.ok(!("03-constraints.md" in result));
82
+ assert.ok(!("04-decomposition.md" in result));
83
+ assert.ok(!("05-evaluation-design.md" in result));
84
+ assert.ok(!("user-notes.md" in result));
85
+ assert.ok(!("moodboard.md" in result));
86
+ assert.equal(Object.keys(result).length, 2);
87
+ });
88
+ it("returns all 7 keys when all files are present", async () => {
89
+ const allFiles = [
90
+ "01-problem-statement.md",
91
+ "02-acceptance-criteria.md",
92
+ "03-constraints.md",
93
+ "04-decomposition.md",
94
+ "05-evaluation-design.md",
95
+ "user-notes.md",
96
+ "moodboard.md",
97
+ ];
98
+ for (const f of allFiles) {
99
+ await writeFile(join(specDir, f), `Content of ${f}`);
100
+ }
101
+ const result = await snapshotSpecFiles(specDir);
102
+ assert.equal(Object.keys(result).length, 7);
103
+ for (const f of allFiles) {
104
+ assert.ok(f in result);
105
+ assert.equal(result[f], `Content of ${f}`);
106
+ }
107
+ });
108
+ it("returns empty record when no recognized files exist", async () => {
109
+ await writeFile(join(specDir, "unrecognized.md"), "content");
110
+ const result = await snapshotSpecFiles(specDir);
111
+ assert.equal(Object.keys(result).length, 0);
112
+ });
113
+ });
114
+ //# sourceMappingURL=spec-helpers.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-helpers.test.js","sourceRoot":"","sources":["../../src/utils/spec-helpers.test.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "stoa-mcp",
3
+ "version": "0.1.0",
4
+ "description": "The Specification Compiler for AI Agents. Transform vague tasks into executable specs with blind test scenarios.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "stoa": "dist/cli.js",
9
+ "stoa-mcp": "dist/index.js"
10
+ },
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "start": "node dist/index.js",
14
+ "dev": "tsc --watch",
15
+ "test": "tsc && node --test dist/core/parsers.test.js",
16
+ "prepublishOnly": "npm run build"
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "templates",
21
+ "README.md",
22
+ "LICENSE"
23
+ ],
24
+ "keywords": [
25
+ "mcp",
26
+ "specification",
27
+ "ai-coding",
28
+ "spec-score",
29
+ "refine",
30
+ "claude",
31
+ "cursor",
32
+ "guardrails"
33
+ ],
34
+ "author": "Lambis Stratoudakis",
35
+ "license": "BSL-1.1",
36
+ "homepage": "https://stoa.dev",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "https://github.com/LambisStratoudakis/stoa-mcp"
40
+ },
41
+ "dependencies": {
42
+ "@anthropic-ai/sdk": "^0.78.0",
43
+ "@modelcontextprotocol/sdk": "^1.27.1",
44
+ "chalk": "^5.6.2",
45
+ "commander": "^14.0.3",
46
+ "ora": "^9.3.0",
47
+ "zod": "^4.3.6"
48
+ },
49
+ "devDependencies": {
50
+ "@types/node": "^25.4.0",
51
+ "typescript": "^5.9.3"
52
+ }
53
+ }
@@ -0,0 +1,3 @@
1
+ # Ask When Unclear
2
+
3
+ If requirements are ambiguous or conflicting, stop and ask for clarification before writing code. Do not make silent assumptions about business logic, data models, or user-facing behavior.
@@ -0,0 +1,3 @@
1
+ # Don't Delete Code
2
+
3
+ Do not delete existing code, functions, or files unless the task explicitly asks for removal. Comment out or deprecate instead. If removal seems necessary, explain why before doing it.
@@ -0,0 +1,3 @@
1
+ # Explain Changes
2
+
3
+ Always explain what you changed and why. Every file modification should have a one-sentence reason. If you're making a choice between approaches, state which you chose and why.
@@ -0,0 +1,3 @@
1
+ # Run Tests
2
+
3
+ Before declaring a task done, run the project's existing test suite. If tests fail, fix them. If no tests exist, state that explicitly. Never say "done" with failing tests.
@@ -0,0 +1,3 @@
1
+ # Small Changes
2
+
3
+ Keep changes small and focused. One task, one purpose. Don't combine a bug fix with a refactor. Don't add a feature while fixing a typo. If you notice something else that needs fixing, note it but don't fix it in this session.
@@ -0,0 +1,3 @@
1
+ # Builder
2
+
3
+ You build software. Write clean, working code that follows the project's existing conventions and patterns. When you see an established pattern in the codebase, follow it. If a task is ambiguous, pick the simplest approach that satisfies the acceptance criteria. Don't refactor code that isn't part of the task. Don't add features that weren't requested.
@@ -0,0 +1,3 @@
1
+ # Fixer
2
+
3
+ You fix bugs. Read the error, trace the root cause, fix only what's broken. Don't refactor unrelated code. Don't "improve" things that aren't part of the bug. If the fix requires changing more than 3 files, stop and explain why before proceeding. Always verify your fix by describing how to reproduce the original bug and confirming it no longer occurs.
@@ -0,0 +1,3 @@
1
+ # Planner
2
+
3
+ You break big ideas into small, buildable tasks. Each task should be completable in a single session (under 2 hours). Be specific about what "done" looks like for each task. Include file paths when you know them. Order tasks so dependencies come first. If a task is too vague to build, say what information is missing.