smart-spec-kit-mcp 2.3.0 → 2.3.2

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 (31) hide show
  1. package/README.md +3 -0
  2. package/dist/tools/orchestrationTools.d.ts.map +1 -1
  3. package/dist/tools/orchestrationTools.js +182 -16
  4. package/dist/tools/orchestrationTools.js.map +1 -1
  5. package/dist/utils/constitutionUpdater.d.ts +25 -0
  6. package/dist/utils/constitutionUpdater.d.ts.map +1 -0
  7. package/dist/utils/constitutionUpdater.js +143 -0
  8. package/dist/utils/constitutionUpdater.js.map +1 -0
  9. package/dist/utils/initGuidedFlow.d.ts +21 -0
  10. package/dist/utils/initGuidedFlow.d.ts.map +1 -0
  11. package/dist/utils/initGuidedFlow.js +81 -0
  12. package/dist/utils/initGuidedFlow.js.map +1 -0
  13. package/dist/utils/initGuidedFlow.test.d.ts +5 -0
  14. package/dist/utils/initGuidedFlow.test.d.ts.map +1 -0
  15. package/dist/utils/initGuidedFlow.test.js +34 -0
  16. package/dist/utils/initGuidedFlow.test.js.map +1 -0
  17. package/dist/utils/initGuidedSessionStore.d.ts +34 -0
  18. package/dist/utils/initGuidedSessionStore.d.ts.map +1 -0
  19. package/dist/utils/initGuidedSessionStore.js +90 -0
  20. package/dist/utils/initGuidedSessionStore.js.map +1 -0
  21. package/dist/utils/stackDetector.d.ts +17 -0
  22. package/dist/utils/stackDetector.d.ts.map +1 -0
  23. package/dist/utils/stackDetector.js +256 -0
  24. package/dist/utils/stackDetector.js.map +1 -0
  25. package/dist/utils/stackDetector.test.d.ts +5 -0
  26. package/dist/utils/stackDetector.test.d.ts.map +1 -0
  27. package/dist/utils/stackDetector.test.js +93 -0
  28. package/dist/utils/stackDetector.test.js.map +1 -0
  29. package/docs/DOCUMENTATION.md +35 -0
  30. package/package.json +2 -2
  31. package/starter-kit/github-prompts/speckit.init.prompt.md +36 -0
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Tests for guided init flow utilities.
3
+ */
4
+ import { test } from "node:test";
5
+ import assert from "node:assert/strict";
6
+ import { buildInitQuestions, normalizeGuidedAnswer } from "./initGuidedFlow.js";
7
+ const detection = {
8
+ projectName: "demo-app",
9
+ language: "TypeScript",
10
+ framework: "React",
11
+ database: "PostgreSQL",
12
+ testing: "Vitest",
13
+ codeStyle: "ESLint + Prettier",
14
+ evidence: [],
15
+ };
16
+ test("buildInitQuestions uses detection values", () => {
17
+ const questions = buildInitQuestions("/tmp/demo", detection, "2026-01-31");
18
+ const projectNameQuestion = questions[0];
19
+ assert.ok(projectNameQuestion);
20
+ assert.equal(projectNameQuestion.suggestion, "demo-app");
21
+ const languageQuestion = questions.find(q => q.key === "language");
22
+ assert.equal(languageQuestion?.suggestion, "TypeScript");
23
+ });
24
+ test("normalizeGuidedAnswer respects auto/skip/today", () => {
25
+ const auto = normalizeGuidedAnswer("auto", "React", "2026-01-31");
26
+ assert.equal(auto.value, "React");
27
+ assert.equal(auto.skipped, false);
28
+ const skip = normalizeGuidedAnswer("skip", "React", "2026-01-31");
29
+ assert.equal(skip.value, undefined);
30
+ assert.equal(skip.skipped, true);
31
+ const today = normalizeGuidedAnswer("today", "", "2026-01-31");
32
+ assert.equal(today.value, "2026-01-31");
33
+ });
34
+ //# sourceMappingURL=initGuidedFlow.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"initGuidedFlow.test.js","sourceRoot":"","sources":["../../src/utils/initGuidedFlow.test.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAEhF,MAAM,SAAS,GAAG;IAChB,WAAW,EAAE,UAAU;IACvB,QAAQ,EAAE,YAAY;IACtB,SAAS,EAAE,OAAO;IAClB,QAAQ,EAAE,YAAY;IACtB,OAAO,EAAE,QAAQ;IACjB,SAAS,EAAE,mBAAmB;IAC9B,QAAQ,EAAE,EAAE;CACb,CAAC;AAEF,IAAI,CAAC,0CAA0C,EAAE,GAAG,EAAE;IACpD,MAAM,SAAS,GAAG,kBAAkB,CAAC,WAAW,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;IAC3E,MAAM,mBAAmB,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;IACzC,MAAM,CAAC,EAAE,CAAC,mBAAmB,CAAC,CAAC;IAC/B,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IACzD,MAAM,gBAAgB,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,UAAU,CAAC,CAAC;IACnE,MAAM,CAAC,KAAK,CAAC,gBAAgB,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;AAC3D,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,gDAAgD,EAAE,GAAG,EAAE;IAC1D,MAAM,IAAI,GAAG,qBAAqB,CAAC,MAAM,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC;IAClE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAClC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAElC,MAAM,IAAI,GAAG,qBAAqB,CAAC,MAAM,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC;IAClE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IACpC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAEjC,MAAM,KAAK,GAAG,qBAAqB,CAAC,OAAO,EAAE,EAAE,EAAE,YAAY,CAAC,CAAC;IAC/D,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;AAC1C,CAAC,CAAC,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Guided Init Session Store
3
+ *
4
+ * Tracks multi-step guided init state across tool calls.
5
+ */
6
+ import type { StackDetection } from "./stackDetector.js";
7
+ import type { ConstitutionAnswers } from "./constitutionUpdater.js";
8
+ export interface InitGuidedSession {
9
+ sessionId: string;
10
+ projectPath: string;
11
+ status: "active" | "completed" | "cancelled";
12
+ stepIndex: number;
13
+ answers: ConstitutionAnswers;
14
+ skippedKeys: Array<keyof ConstitutionAnswers>;
15
+ detection: StackDetection;
16
+ createdAt: string;
17
+ updatedAt: string;
18
+ }
19
+ declare class InitGuidedSessionStore {
20
+ private readonly sessions;
21
+ private readonly persistDir;
22
+ constructor();
23
+ init(): Promise<void>;
24
+ generateSessionId(): string;
25
+ create(projectPath: string, detection: StackDetection): Promise<InitGuidedSession>;
26
+ get(sessionId: string): InitGuidedSession | undefined;
27
+ getActiveSession(projectPath: string): InitGuidedSession | undefined;
28
+ update(session: InitGuidedSession): Promise<void>;
29
+ delete(sessionId: string): Promise<void>;
30
+ private persist;
31
+ }
32
+ export declare const initGuidedSessionStore: InitGuidedSessionStore;
33
+ export {};
34
+ //# sourceMappingURL=initGuidedSessionStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"initGuidedSessionStore.d.ts","sourceRoot":"","sources":["../../src/utils/initGuidedSessionStore.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,QAAQ,GAAG,WAAW,GAAG,WAAW,CAAC;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,mBAAmB,CAAC;IAC7B,WAAW,EAAE,KAAK,CAAC,MAAM,mBAAmB,CAAC,CAAC;IAC9C,SAAS,EAAE,cAAc,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,cAAM,sBAAsB;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6C;IACtE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;;IAM9B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB3B,iBAAiB,IAAI,MAAM;IAMrB,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAsBxF,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAIrD,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAY9D,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAMjD,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAUhC,OAAO;CAItB;AAED,eAAO,MAAM,sBAAsB,wBAA+B,CAAC"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Guided Init Session Store
3
+ *
4
+ * Tracks multi-step guided init state across tool calls.
5
+ */
6
+ import * as fs from "node:fs/promises";
7
+ import * as path from "node:path";
8
+ import * as os from "node:os";
9
+ class InitGuidedSessionStore {
10
+ sessions = new Map();
11
+ persistDir;
12
+ constructor() {
13
+ this.persistDir = path.join(os.tmpdir(), "spec-kit-init-sessions");
14
+ }
15
+ async init() {
16
+ try {
17
+ await fs.mkdir(this.persistDir, { recursive: true });
18
+ const files = await fs.readdir(this.persistDir);
19
+ for (const file of files) {
20
+ if (file.endsWith(".json")) {
21
+ const content = await fs.readFile(path.join(this.persistDir, file), "utf-8");
22
+ const session = JSON.parse(content);
23
+ this.sessions.set(session.sessionId, session);
24
+ }
25
+ }
26
+ }
27
+ catch {
28
+ // No persisted sessions
29
+ }
30
+ }
31
+ generateSessionId() {
32
+ const timestamp = Date.now().toString(36);
33
+ const random = Math.random().toString(36).substring(2, 8);
34
+ return `init-${timestamp}-${random}`;
35
+ }
36
+ async create(projectPath, detection) {
37
+ const sessionId = this.generateSessionId();
38
+ const now = new Date().toISOString();
39
+ const session = {
40
+ sessionId,
41
+ projectPath,
42
+ status: "active",
43
+ stepIndex: 0,
44
+ answers: {},
45
+ skippedKeys: [],
46
+ detection,
47
+ createdAt: now,
48
+ updatedAt: now,
49
+ };
50
+ this.sessions.set(sessionId, session);
51
+ await this.persist(session);
52
+ return session;
53
+ }
54
+ get(sessionId) {
55
+ return this.sessions.get(sessionId);
56
+ }
57
+ getActiveSession(projectPath) {
58
+ let latest;
59
+ for (const session of this.sessions.values()) {
60
+ if (session.status === "active" && session.projectPath === projectPath) {
61
+ if (!latest || session.updatedAt > latest.updatedAt) {
62
+ latest = session;
63
+ }
64
+ }
65
+ }
66
+ return latest;
67
+ }
68
+ async update(session) {
69
+ session.updatedAt = new Date().toISOString();
70
+ this.sessions.set(session.sessionId, session);
71
+ await this.persist(session);
72
+ }
73
+ async delete(sessionId) {
74
+ this.sessions.delete(sessionId);
75
+ const filePath = path.join(this.persistDir, `${sessionId}.json`);
76
+ try {
77
+ await fs.unlink(filePath);
78
+ }
79
+ catch {
80
+ // Ignore
81
+ }
82
+ }
83
+ async persist(session) {
84
+ const filePath = path.join(this.persistDir, `${session.sessionId}.json`);
85
+ await fs.writeFile(filePath, JSON.stringify(session, null, 2), "utf-8");
86
+ }
87
+ }
88
+ export const initGuidedSessionStore = new InitGuidedSessionStore();
89
+ await initGuidedSessionStore.init();
90
+ //# sourceMappingURL=initGuidedSessionStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"initGuidedSessionStore.js","sourceRoot":"","sources":["../../src/utils/initGuidedSessionStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Stack Detector
3
+ *
4
+ * Detects project language, framework, database, and testing stack
5
+ * based on common project files and dependencies.
6
+ */
7
+ export interface StackDetection {
8
+ projectName?: string;
9
+ language?: string;
10
+ framework?: string;
11
+ database?: string;
12
+ testing?: string;
13
+ codeStyle?: string;
14
+ evidence: string[];
15
+ }
16
+ export declare function detectStack(projectPath: string): Promise<StackDetection>;
17
+ //# sourceMappingURL=stackDetector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stackDetector.d.ts","sourceRoot":"","sources":["../../src/utils/stackDetector.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,cAAc;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAgQD,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAyB9E"}
@@ -0,0 +1,256 @@
1
+ /**
2
+ * Stack Detector
3
+ *
4
+ * Detects project language, framework, database, and testing stack
5
+ * based on common project files and dependencies.
6
+ */
7
+ import * as fs from "node:fs/promises";
8
+ import * as path from "node:path";
9
+ const EXCLUDED_DIRS = new Set(["node_modules", ".git", "dist", "build", "out", ".next", ".turbo", ".cache"]);
10
+ async function exists(filePath) {
11
+ try {
12
+ await fs.access(filePath);
13
+ return true;
14
+ }
15
+ catch {
16
+ return false;
17
+ }
18
+ }
19
+ async function readJsonFile(filePath) {
20
+ try {
21
+ const raw = await fs.readFile(filePath, "utf-8");
22
+ return JSON.parse(raw);
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ }
28
+ async function readTextFile(filePath) {
29
+ try {
30
+ return await fs.readFile(filePath, "utf-8");
31
+ }
32
+ catch {
33
+ return null;
34
+ }
35
+ }
36
+ async function listFilesRecursive(root, depth, results = []) {
37
+ if (depth < 0)
38
+ return results;
39
+ let entries = [];
40
+ try {
41
+ entries = await fs.readdir(root, { withFileTypes: true });
42
+ }
43
+ catch {
44
+ return results;
45
+ }
46
+ for (const entry of entries) {
47
+ if (entry.isDirectory()) {
48
+ if (EXCLUDED_DIRS.has(entry.name))
49
+ continue;
50
+ await listFilesRecursive(path.join(root, entry.name), depth - 1, results);
51
+ }
52
+ else {
53
+ results.push(path.join(root, entry.name));
54
+ }
55
+ }
56
+ return results;
57
+ }
58
+ function addUnique(list, value) {
59
+ if (!value)
60
+ return;
61
+ if (!list.includes(value))
62
+ list.push(value);
63
+ }
64
+ function joinValues(values) {
65
+ if (values.length === 0)
66
+ return undefined;
67
+ return values.join(" + ");
68
+ }
69
+ function detectFromDependencies(deps) {
70
+ const frameworks = [];
71
+ const testing = [];
72
+ const frameworkMap = [
73
+ ["next", "Next.js"],
74
+ ["react", "React"],
75
+ ["vue", "Vue"],
76
+ ["nuxt", "Nuxt"],
77
+ ["svelte", "Svelte"],
78
+ ["@angular/core", "Angular"],
79
+ ["express", "Express"],
80
+ ["@nestjs/core", "NestJS"],
81
+ ["fastify", "Fastify"],
82
+ ["koa", "Koa"],
83
+ ];
84
+ const testMap = [
85
+ ["vitest", "Vitest"],
86
+ ["jest", "Jest"],
87
+ ["mocha", "Mocha"],
88
+ ["ava", "AVA"],
89
+ ["@playwright/test", "Playwright"],
90
+ ["cypress", "Cypress"],
91
+ ];
92
+ for (const [dep, label] of frameworkMap) {
93
+ if (deps.has(dep))
94
+ addUnique(frameworks, label);
95
+ }
96
+ for (const [dep, label] of testMap) {
97
+ if (deps.has(dep))
98
+ addUnique(testing, label);
99
+ }
100
+ const databaseMap = [
101
+ [["mongoose"], "MongoDB"],
102
+ [["pg", "pg-promise"], "PostgreSQL"],
103
+ [["mysql2", "mysql"], "MySQL"],
104
+ [["sqlite3", "better-sqlite3"], "SQLite"],
105
+ [["prisma"], "Prisma (DB non détectée)"],
106
+ [["typeorm"], "TypeORM (DB non détectée)"],
107
+ [["sequelize"], "Sequelize (DB non détectée)"],
108
+ ];
109
+ let database;
110
+ for (const [depsList, label] of databaseMap) {
111
+ if (depsList.some(dep => deps.has(dep))) {
112
+ database = label;
113
+ break;
114
+ }
115
+ }
116
+ return { frameworks, testing, database };
117
+ }
118
+ function detectCodeStyleFiles(fileList, projectPath) {
119
+ const normalized = fileList.map(file => path.relative(projectPath, file).toLowerCase());
120
+ const hasEslint = normalized.some(file => file.startsWith(".eslintrc") || file === "eslint.config.js" || file === "eslint.config.mjs");
121
+ const hasPrettier = normalized.some(file => file.startsWith(".prettierrc") || file === "prettier.config.js" || file === "prettier.config.cjs");
122
+ const parts = [];
123
+ if (hasEslint)
124
+ parts.push("ESLint");
125
+ if (hasPrettier)
126
+ parts.push("Prettier");
127
+ return joinValues(parts);
128
+ }
129
+ function extractPythonDeps(text) {
130
+ const deps = new Set();
131
+ const lines = text.split("\n").map(line => line.trim());
132
+ for (const line of lines) {
133
+ if (!line || line.startsWith("#"))
134
+ continue;
135
+ const name = line.split(/[<=>\s]/)[0];
136
+ if (name)
137
+ deps.add(name.toLowerCase());
138
+ }
139
+ return deps;
140
+ }
141
+ async function detectNodeStack(projectPath, detection) {
142
+ const packageJsonPath = path.join(projectPath, "package.json");
143
+ const tsconfigPath = path.join(projectPath, "tsconfig.json");
144
+ if (!(await exists(packageJsonPath)))
145
+ return;
146
+ const pkg = await readJsonFile(packageJsonPath);
147
+ if (!pkg)
148
+ return;
149
+ detection.evidence.push("package.json");
150
+ if (pkg.name)
151
+ detection.projectName = pkg.name;
152
+ const depNames = new Set([
153
+ ...Object.keys(pkg.dependencies ?? {}),
154
+ ...Object.keys(pkg.devDependencies ?? {}),
155
+ ]);
156
+ if (depNames.has("typescript") || (await exists(tsconfigPath))) {
157
+ addUnique(detection.languages, "TypeScript");
158
+ }
159
+ else {
160
+ addUnique(detection.languages, "JavaScript");
161
+ }
162
+ const depDetection = detectFromDependencies(depNames);
163
+ for (const fw of depDetection.frameworks)
164
+ addUnique(detection.frameworks, fw);
165
+ for (const test of depDetection.testing)
166
+ addUnique(detection.testing, test);
167
+ if (depDetection.database)
168
+ detection.database = depDetection.database;
169
+ }
170
+ async function detectPythonStack(projectPath, detection) {
171
+ const pyprojectPath = path.join(projectPath, "pyproject.toml");
172
+ const requirementsPath = path.join(projectPath, "requirements.txt");
173
+ const poetryLockPath = path.join(projectPath, "poetry.lock");
174
+ if (!(await exists(pyprojectPath)) && !(await exists(requirementsPath)) && !(await exists(poetryLockPath)))
175
+ return;
176
+ addUnique(detection.languages, "Python");
177
+ detection.evidence.push("python files");
178
+ const pyText = (await readTextFile(pyprojectPath)) ?? (await readTextFile(requirementsPath)) ?? "";
179
+ const pyDeps = extractPythonDeps(pyText);
180
+ if (pyDeps.has("django"))
181
+ addUnique(detection.frameworks, "Django");
182
+ if (pyDeps.has("flask"))
183
+ addUnique(detection.frameworks, "Flask");
184
+ if (pyDeps.has("fastapi"))
185
+ addUnique(detection.frameworks, "FastAPI");
186
+ if (pyDeps.has("pytest"))
187
+ addUnique(detection.testing, "Pytest");
188
+ if (pyDeps.has("sqlalchemy") && !detection.database)
189
+ detection.database = "SQLAlchemy";
190
+ }
191
+ async function detectOtherStacks(projectPath, detection) {
192
+ const goModPath = path.join(projectPath, "go.mod");
193
+ const cargoPath = path.join(projectPath, "Cargo.toml");
194
+ const pomPath = path.join(projectPath, "pom.xml");
195
+ const gradlePath = path.join(projectPath, "build.gradle");
196
+ const gradleKtsPath = path.join(projectPath, "build.gradle.kts");
197
+ const composerPath = path.join(projectPath, "composer.json");
198
+ const gemfilePath = path.join(projectPath, "Gemfile");
199
+ const pubspecPath = path.join(projectPath, "pubspec.yaml");
200
+ if (await exists(goModPath)) {
201
+ addUnique(detection.languages, "Go");
202
+ detection.evidence.push("go.mod");
203
+ }
204
+ if (await exists(cargoPath)) {
205
+ addUnique(detection.languages, "Rust");
206
+ detection.evidence.push("Cargo.toml");
207
+ }
208
+ if (await exists(pomPath) || await exists(gradlePath) || await exists(gradleKtsPath)) {
209
+ addUnique(detection.languages, "Java");
210
+ detection.evidence.push("Java build files");
211
+ }
212
+ if (await exists(composerPath)) {
213
+ addUnique(detection.languages, "PHP");
214
+ detection.evidence.push("composer.json");
215
+ }
216
+ if (await exists(gemfilePath)) {
217
+ addUnique(detection.languages, "Ruby");
218
+ detection.evidence.push("Gemfile");
219
+ }
220
+ if (await exists(pubspecPath)) {
221
+ addUnique(detection.languages, "Dart");
222
+ detection.evidence.push("pubspec.yaml");
223
+ }
224
+ }
225
+ async function detectDotNet(projectPath, detection) {
226
+ const files = await listFilesRecursive(projectPath, 2);
227
+ const csprojFound = files.some(file => file.toLowerCase().endsWith(".csproj"));
228
+ if (csprojFound) {
229
+ addUnique(detection.languages, ".NET");
230
+ detection.evidence.push(".csproj");
231
+ }
232
+ }
233
+ export async function detectStack(projectPath) {
234
+ const detection = {
235
+ languages: [],
236
+ frameworks: [],
237
+ testing: [],
238
+ evidence: [],
239
+ };
240
+ await detectNodeStack(projectPath, detection);
241
+ await detectPythonStack(projectPath, detection);
242
+ await detectOtherStacks(projectPath, detection);
243
+ await detectDotNet(projectPath, detection);
244
+ const files = await listFilesRecursive(projectPath, 2);
245
+ const codeStyle = detectCodeStyleFiles(files, projectPath);
246
+ return {
247
+ projectName: detection.projectName,
248
+ language: joinValues(detection.languages),
249
+ framework: joinValues(detection.frameworks),
250
+ database: detection.database,
251
+ testing: joinValues(detection.testing),
252
+ codeStyle,
253
+ evidence: detection.evidence,
254
+ };
255
+ }
256
+ //# sourceMappingURL=stackDetector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stackDetector.js","sourceRoot":"","sources":["../../src/utils/stackDetector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Tests for stack detection and constitution update.
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=stackDetector.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stackDetector.test.d.ts","sourceRoot":"","sources":["../../src/utils/stackDetector.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Tests for stack detection and constitution update.
3
+ */
4
+ import { test } from "node:test";
5
+ import assert from "node:assert/strict";
6
+ import * as fs from "node:fs/promises";
7
+ import * as path from "node:path";
8
+ import * as os from "node:os";
9
+ import { detectStack } from "./stackDetector.js";
10
+ import { updateConstitution } from "./constitutionUpdater.js";
11
+ async function createTempProject() {
12
+ const dir = await fs.mkdtemp(path.join(os.tmpdir(), "spec-kit-test-"));
13
+ return dir;
14
+ }
15
+ test("detectStack infers TypeScript + React + Jest + PostgreSQL", async () => {
16
+ const projectPath = await createTempProject();
17
+ await fs.writeFile(path.join(projectPath, "package.json"), JSON.stringify({
18
+ name: "demo-app",
19
+ dependencies: {
20
+ react: "18.0.0",
21
+ pg: "8.0.0",
22
+ },
23
+ devDependencies: {
24
+ typescript: "5.0.0",
25
+ jest: "29.0.0",
26
+ },
27
+ }, null, 2), "utf-8");
28
+ await fs.writeFile(path.join(projectPath, "tsconfig.json"), "{}", "utf-8");
29
+ const detection = await detectStack(projectPath);
30
+ assert.equal(detection.projectName, "demo-app");
31
+ assert.equal(detection.language, "TypeScript");
32
+ assert.equal(detection.framework, "React");
33
+ assert.equal(detection.testing, "Jest");
34
+ assert.equal(detection.database, "PostgreSQL");
35
+ });
36
+ test("updateConstitution fills tech stack placeholders", async () => {
37
+ const projectPath = await createTempProject();
38
+ const memoryDir = path.join(projectPath, ".spec-kit", "memory");
39
+ await fs.mkdir(memoryDir, { recursive: true });
40
+ const constitutionTemplate = `# Project Constitution
41
+
42
+ ## Project Information
43
+
44
+ - **Project Name**: [TO FILL: Your project name]
45
+ - **Ratification Date**: [TO FILL: YYYY-MM-DD]
46
+ - **Last Amended**: [TO FILL: YYYY-MM-DD]
47
+ - **Version**: 1.0.0
48
+
49
+ ---
50
+
51
+ ## Tech Stack Guidelines
52
+
53
+ ### Preferred Technologies
54
+ | Category | Technology | Notes |
55
+ |----------|------------|-------|
56
+ | Language | [TO FILL] | |
57
+ | Framework | [TO FILL] | |
58
+ | Database | [TO FILL] | |
59
+ | Testing | [TO FILL] | |
60
+
61
+ ### Code Style
62
+ - [TO FILL: Link to style guide or describe key conventions]
63
+
64
+ ---
65
+
66
+ ## Version History
67
+
68
+ | Version | Date | Changes |
69
+ |---------|------|---------|
70
+ | 1.0.0 | [TO FILL] | Initial constitution |
71
+ `;
72
+ const constitutionPath = path.join(memoryDir, "constitution.md");
73
+ await fs.writeFile(constitutionPath, constitutionTemplate, "utf-8");
74
+ const update = await updateConstitution(projectPath, {
75
+ language: "TypeScript",
76
+ framework: "React",
77
+ database: "PostgreSQL",
78
+ testing: "Vitest",
79
+ evidence: [],
80
+ }, {
81
+ projectName: "SpecKit Demo",
82
+ codeStyle: "ESLint + Prettier",
83
+ });
84
+ assert.equal(update.updated, true);
85
+ const updated = await fs.readFile(constitutionPath, "utf-8");
86
+ assert.match(updated, /\*\*Project Name\*\*: SpecKit Demo/);
87
+ assert.match(updated, /\| Language \|\s*TypeScript\s*\|/);
88
+ assert.match(updated, /\| Framework \|\s*React\s*\|/);
89
+ assert.match(updated, /\| Database \|\s*PostgreSQL\s*\|/);
90
+ assert.match(updated, /\| Testing \|\s*Vitest\s*\|/);
91
+ assert.match(updated, /- ESLint \+ Prettier/);
92
+ });
93
+ //# sourceMappingURL=stackDetector.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stackDetector.test.js","sourceRoot":"","sources":["../../src/utils/stackDetector.test.ts"],"names":[],"mappings":"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"}
@@ -52,6 +52,41 @@ Spec-Kit is an MCP (Model Context Protocol) server that provides **customizable
52
52
 
53
53
  > **Note**: All parameters are optional. Spec-Kit is designed to be conversational - if you don't provide information upfront, Copilot will ask for it.
54
54
 
55
+ ### init
56
+
57
+ **Purpose**: Initialize Spec-Kit in the current project. If `guided` is not specified, Spec-Kit asks you to choose guided vs auto. Guided mode is interactive (Q/A). Auto mode fills the constitution from project detection.
58
+
59
+ **Keyword Triggers**: `speckit: init`, `init`
60
+
61
+ **Parameters** (all optional):
62
+
63
+ - `force`: Overwrite existing Spec-Kit files
64
+ - `guided`: Enable guided setup (detect stack and fill constitution)
65
+ - `session_id`: Session ID for guided mode
66
+ - `answer`: Answer for the current guided question
67
+ - `cancel`: Cancel guided session
68
+ - `answers`: Overrides for constitution fields
69
+ - `projectName`, `ratificationDate`, `lastAmended`
70
+ - `language`, `framework`, `database`, `testing`, `codeStyle`
71
+ - `approvers`
72
+
73
+ **Examples**:
74
+
75
+ ```text
76
+ speckit: init
77
+ speckit: init guided=true
78
+ speckit: init guided=true answer="My Project"
79
+ speckit: init guided=true session_id=init-abc answer="auto"
80
+ speckit: init guided=true answers={"projectName":"Demo","language":"TypeScript","framework":"React"}
81
+ ```
82
+
83
+ **Behavior**:
84
+
85
+ 1. Installs prompts, templates, memory, rules, agents, and specs folders
86
+ 2. If `guided` is enabled, detects the stack from project files
87
+ 3. Updates `.spec-kit/memory/constitution.md` with detected or provided values
88
+ 4. Lists any remaining placeholders to fill
89
+
55
90
  ### speckit_specify
56
91
 
57
92
  **Purpose**: Create a functional specification from requirements.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smart-spec-kit-mcp",
3
- "version": "2.3.0",
3
+ "version": "2.3.2",
4
4
  "description": "AI-driven specification platform using MCP (Model Context Protocol) for VS Code & GitHub Copilot",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -25,7 +25,7 @@
25
25
  "dev": "tsx watch src/index.ts",
26
26
  "start": "node dist/index.js",
27
27
  "setup": "tsx src/utils/vsCodeConfigGenerator.ts",
28
- "test": "tsx src/index.ts",
28
+ "test": "npm run build && node --test dist/**/*.test.js",
29
29
  "prepublishOnly": "npm run build"
30
30
  },
31
31
  "keywords": [