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.
- package/README.md +3 -0
- package/dist/tools/orchestrationTools.d.ts.map +1 -1
- package/dist/tools/orchestrationTools.js +182 -16
- package/dist/tools/orchestrationTools.js.map +1 -1
- package/dist/utils/constitutionUpdater.d.ts +25 -0
- package/dist/utils/constitutionUpdater.d.ts.map +1 -0
- package/dist/utils/constitutionUpdater.js +143 -0
- package/dist/utils/constitutionUpdater.js.map +1 -0
- package/dist/utils/initGuidedFlow.d.ts +21 -0
- package/dist/utils/initGuidedFlow.d.ts.map +1 -0
- package/dist/utils/initGuidedFlow.js +81 -0
- package/dist/utils/initGuidedFlow.js.map +1 -0
- package/dist/utils/initGuidedFlow.test.d.ts +5 -0
- package/dist/utils/initGuidedFlow.test.d.ts.map +1 -0
- package/dist/utils/initGuidedFlow.test.js +34 -0
- package/dist/utils/initGuidedFlow.test.js.map +1 -0
- package/dist/utils/initGuidedSessionStore.d.ts +34 -0
- package/dist/utils/initGuidedSessionStore.d.ts.map +1 -0
- package/dist/utils/initGuidedSessionStore.js +90 -0
- package/dist/utils/initGuidedSessionStore.js.map +1 -0
- package/dist/utils/stackDetector.d.ts +17 -0
- package/dist/utils/stackDetector.d.ts.map +1 -0
- package/dist/utils/stackDetector.js +256 -0
- package/dist/utils/stackDetector.js.map +1 -0
- package/dist/utils/stackDetector.test.d.ts +5 -0
- package/dist/utils/stackDetector.test.d.ts.map +1 -0
- package/dist/utils/stackDetector.test.js +93 -0
- package/dist/utils/stackDetector.test.js.map +1 -0
- package/docs/DOCUMENTATION.md +35 -0
- package/package.json +2 -2
- 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 @@
|
|
|
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":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAE9D,KAAK,UAAU,iBAAiB;IAC9B,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,gBAAgB,CAAC,CAAC,CAAC;IACvE,OAAO,GAAG,CAAC;AACb,CAAC;AAED,IAAI,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;IAC3E,MAAM,WAAW,GAAG,MAAM,iBAAiB,EAAE,CAAC;IAE9C,MAAM,EAAE,CAAC,SAAS,CAChB,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,EACtC,IAAI,CAAC,SAAS,CAAC;QACb,IAAI,EAAE,UAAU;QAChB,YAAY,EAAE;YACZ,KAAK,EAAE,QAAQ;YACf,EAAE,EAAE,OAAO;SACZ;QACD,eAAe,EAAE;YACf,UAAU,EAAE,OAAO;YACnB,IAAI,EAAE,QAAQ;SACf;KACF,EAAE,IAAI,EAAE,CAAC,CAAC,EACX,OAAO,CACR,CAAC;IAEF,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,eAAe,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAE3E,MAAM,SAAS,GAAG,MAAM,WAAW,CAAC,WAAW,CAAC,CAAC;IAEjD,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IAChD,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAC/C,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAC3C,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACxC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;AACjD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;IAClE,MAAM,WAAW,GAAG,MAAM,iBAAiB,EAAE,CAAC;IAC9C,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;IAChE,MAAM,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE/C,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+B9B,CAAC;IAEA,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;IACjE,MAAM,EAAE,CAAC,SAAS,CAAC,gBAAgB,EAAE,oBAAoB,EAAE,OAAO,CAAC,CAAC;IAEpE,MAAM,MAAM,GAAG,MAAM,kBAAkB,CACrC,WAAW,EACX;QACE,QAAQ,EAAE,YAAY;QACtB,SAAS,EAAE,OAAO;QAClB,QAAQ,EAAE,YAAY;QACtB,OAAO,EAAE,QAAQ;QACjB,QAAQ,EAAE,EAAE;KACb,EACD;QACE,WAAW,EAAE,cAAc;QAC3B,SAAS,EAAE,mBAAmB;KAC/B,CACF,CAAC;IAEF,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;IAE7D,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,oCAAoC,CAAC,CAAC;IAC5D,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,kCAAkC,CAAC,CAAC;IAC1D,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,8BAA8B,CAAC,CAAC;IACtD,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,kCAAkC,CAAC,CAAC;IAC1D,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,6BAA6B,CAAC,CAAC;IACrD,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAC;AAChD,CAAC,CAAC,CAAC"}
|
package/docs/DOCUMENTATION.md
CHANGED
|
@@ -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.
|
|
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": "
|
|
28
|
+
"test": "npm run build && node --test dist/**/*.test.js",
|
|
29
29
|
"prepublishOnly": "npm run build"
|
|
30
30
|
},
|
|
31
31
|
"keywords": [
|