@sudocode-ai/integration-speckit 0.1.14
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/dist/id-generator.d.ts +149 -0
- package/dist/id-generator.d.ts.map +1 -0
- package/dist/id-generator.js +197 -0
- package/dist/id-generator.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1017 -0
- package/dist/index.js.map +1 -0
- package/dist/parser/index.d.ts +11 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +16 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/markdown-utils.d.ts +138 -0
- package/dist/parser/markdown-utils.d.ts.map +1 -0
- package/dist/parser/markdown-utils.js +283 -0
- package/dist/parser/markdown-utils.js.map +1 -0
- package/dist/parser/plan-parser.d.ts +97 -0
- package/dist/parser/plan-parser.d.ts.map +1 -0
- package/dist/parser/plan-parser.js +286 -0
- package/dist/parser/plan-parser.js.map +1 -0
- package/dist/parser/spec-parser.d.ts +95 -0
- package/dist/parser/spec-parser.d.ts.map +1 -0
- package/dist/parser/spec-parser.js +250 -0
- package/dist/parser/spec-parser.js.map +1 -0
- package/dist/parser/supporting-docs.d.ts +119 -0
- package/dist/parser/supporting-docs.d.ts.map +1 -0
- package/dist/parser/supporting-docs.js +324 -0
- package/dist/parser/supporting-docs.js.map +1 -0
- package/dist/parser/tasks-parser.d.ts +171 -0
- package/dist/parser/tasks-parser.d.ts.map +1 -0
- package/dist/parser/tasks-parser.js +281 -0
- package/dist/parser/tasks-parser.js.map +1 -0
- package/dist/relationship-mapper.d.ts +165 -0
- package/dist/relationship-mapper.d.ts.map +1 -0
- package/dist/relationship-mapper.js +238 -0
- package/dist/relationship-mapper.js.map +1 -0
- package/dist/watcher.d.ts +137 -0
- package/dist/watcher.d.ts.map +1 -0
- package/dist/watcher.js +599 -0
- package/dist/watcher.js.map +1 -0
- package/dist/writer/index.d.ts +8 -0
- package/dist/writer/index.d.ts.map +1 -0
- package/dist/writer/index.js +10 -0
- package/dist/writer/index.js.map +1 -0
- package/dist/writer/spec-writer.d.ts +70 -0
- package/dist/writer/spec-writer.d.ts.map +1 -0
- package/dist/writer/spec-writer.js +261 -0
- package/dist/writer/spec-writer.js.map +1 -0
- package/dist/writer/tasks-writer.d.ts +47 -0
- package/dist/writer/tasks-writer.d.ts.map +1 -0
- package/dist/writer/tasks-writer.js +161 -0
- package/dist/writer/tasks-writer.js.map +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tasks Parser for Spec-Kit Integration
|
|
3
|
+
*
|
|
4
|
+
* Parses tasks.md files from spec-kit and extracts individual tasks.
|
|
5
|
+
*
|
|
6
|
+
* Expected format:
|
|
7
|
+
* ```markdown
|
|
8
|
+
* # Tasks
|
|
9
|
+
*
|
|
10
|
+
* ## Phase 1: Foundation
|
|
11
|
+
*
|
|
12
|
+
* - [ ] T001 [P] Setup project structure
|
|
13
|
+
* - [ ] T002 [US1] Create user model
|
|
14
|
+
* - [x] T003: Completed task
|
|
15
|
+
*
|
|
16
|
+
* ## Phase 2: Implementation
|
|
17
|
+
*
|
|
18
|
+
* - [ ] T004 [P] [US2] Implement authentication
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* Task format: `- [ ] T001 [P?] [US?] Description`
|
|
22
|
+
* - Checkbox: `[ ]` (incomplete) or `[x]` (complete)
|
|
23
|
+
* - Task ID: T followed by digits (T001, T002, etc.)
|
|
24
|
+
* - Parallelizable: Optional `[P]` marker
|
|
25
|
+
* - User Story: Optional `[US1]`, `[US2]`, etc.
|
|
26
|
+
* - Description: Rest of the line
|
|
27
|
+
*/
|
|
28
|
+
import { readFileSync, existsSync } from "fs";
|
|
29
|
+
import { PATTERNS, extractMetadata, extractTitle, cleanTaskDescription, } from "./markdown-utils.js";
|
|
30
|
+
/**
|
|
31
|
+
* Parse a tasks.md file and extract all tasks
|
|
32
|
+
*
|
|
33
|
+
* @param filePath - Absolute path to the tasks.md file
|
|
34
|
+
* @param options - Parsing options
|
|
35
|
+
* @returns Parsed tasks data or null if file doesn't exist
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* const tasksFile = parseTasks("/project/.specify/specs/001-auth/tasks.md");
|
|
39
|
+
* console.log(tasksFile?.tasks.length); // 10
|
|
40
|
+
* console.log(tasksFile?.stats.completed); // 3
|
|
41
|
+
*/
|
|
42
|
+
export function parseTasks(filePath, options = {}) {
|
|
43
|
+
if (!existsSync(filePath)) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
const content = readFileSync(filePath, "utf-8");
|
|
48
|
+
return parseTasksContent(content, filePath, options);
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
console.error(`[tasks-parser] Failed to parse ${filePath}:`, error);
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Parse tasks content from a string (for testing or in-memory parsing)
|
|
57
|
+
*
|
|
58
|
+
* @param content - Markdown content string
|
|
59
|
+
* @param filePath - Optional file path for reference
|
|
60
|
+
* @param options - Parsing options
|
|
61
|
+
* @returns Parsed tasks data or null
|
|
62
|
+
*/
|
|
63
|
+
export function parseTasksContent(content, filePath = "<string>", options = {}) {
|
|
64
|
+
const lines = content.split("\n");
|
|
65
|
+
const tasks = [];
|
|
66
|
+
const phases = new Map();
|
|
67
|
+
// Extract title and metadata
|
|
68
|
+
const title = extractTitle(lines);
|
|
69
|
+
const metadata = extractMetadata(lines);
|
|
70
|
+
// Track current phase
|
|
71
|
+
let currentPhase = null;
|
|
72
|
+
let currentPhaseName = null;
|
|
73
|
+
// Parse each line
|
|
74
|
+
for (let i = 0; i < lines.length; i++) {
|
|
75
|
+
const line = lines[i];
|
|
76
|
+
const lineNumber = i + 1; // 1-indexed
|
|
77
|
+
// Check for phase header
|
|
78
|
+
const phaseMatch = line.match(PATTERNS.PHASE_HEADER);
|
|
79
|
+
if (phaseMatch) {
|
|
80
|
+
currentPhase = parseInt(phaseMatch[1], 10);
|
|
81
|
+
currentPhaseName = phaseMatch[2]?.trim() || null;
|
|
82
|
+
phases.set(currentPhase, currentPhaseName || `Phase ${currentPhase}`);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
// Check for task line
|
|
86
|
+
const taskMatch = line.match(PATTERNS.TASK_LINE);
|
|
87
|
+
if (taskMatch) {
|
|
88
|
+
const task = parseTaskLine(line, taskMatch, lineNumber, currentPhase, currentPhaseName);
|
|
89
|
+
// Apply filters
|
|
90
|
+
if (shouldIncludeTask(task, options)) {
|
|
91
|
+
tasks.push(task);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Calculate stats
|
|
96
|
+
const stats = {
|
|
97
|
+
total: tasks.length,
|
|
98
|
+
completed: tasks.filter((t) => t.completed).length,
|
|
99
|
+
incomplete: tasks.filter((t) => !t.completed).length,
|
|
100
|
+
parallelizable: tasks.filter((t) => t.parallelizable).length,
|
|
101
|
+
};
|
|
102
|
+
return {
|
|
103
|
+
title,
|
|
104
|
+
metadata,
|
|
105
|
+
tasks,
|
|
106
|
+
phases,
|
|
107
|
+
filePath,
|
|
108
|
+
stats,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Parse a single task line
|
|
113
|
+
*/
|
|
114
|
+
function parseTaskLine(line, match, lineNumber, phase, phaseName) {
|
|
115
|
+
const [, leadingSpace, checkbox, taskId, rest] = match;
|
|
116
|
+
// Calculate indent level (2 spaces = 1 level)
|
|
117
|
+
const indentLevel = Math.floor(leadingSpace.replace("-", "").length / 2);
|
|
118
|
+
// Check for parallelizable marker
|
|
119
|
+
const parallelizable = PATTERNS.PARALLELIZABLE.test(rest);
|
|
120
|
+
// Check for user story marker
|
|
121
|
+
const userStoryMatch = rest.match(PATTERNS.USER_STORY);
|
|
122
|
+
const userStory = userStoryMatch ? userStoryMatch[1] : null;
|
|
123
|
+
// Clean description
|
|
124
|
+
const description = cleanTaskDescription(rest);
|
|
125
|
+
return {
|
|
126
|
+
taskId,
|
|
127
|
+
description,
|
|
128
|
+
completed: checkbox.toLowerCase() === "x",
|
|
129
|
+
parallelizable,
|
|
130
|
+
userStory,
|
|
131
|
+
phase,
|
|
132
|
+
phaseName,
|
|
133
|
+
lineNumber,
|
|
134
|
+
indentLevel,
|
|
135
|
+
rawLine: line,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Check if a task should be included based on filters
|
|
140
|
+
*/
|
|
141
|
+
function shouldIncludeTask(task, options) {
|
|
142
|
+
// Phase filter
|
|
143
|
+
if (options.filterPhases && options.filterPhases.length > 0) {
|
|
144
|
+
if (task.phase === null || !options.filterPhases.includes(task.phase)) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Incomplete only filter
|
|
149
|
+
if (options.incompleteOnly && task.completed) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
// Parallelizable only filter
|
|
153
|
+
if (options.parallelizableOnly && !task.parallelizable) {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Get all tasks from a file as a simple array
|
|
160
|
+
*
|
|
161
|
+
* @param filePath - Path to the tasks file
|
|
162
|
+
* @returns Array of parsed tasks or empty array
|
|
163
|
+
*/
|
|
164
|
+
export function getAllTasks(filePath) {
|
|
165
|
+
const result = parseTasks(filePath);
|
|
166
|
+
return result?.tasks || [];
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Get a specific task by ID
|
|
170
|
+
*
|
|
171
|
+
* @param filePath - Path to the tasks file
|
|
172
|
+
* @param taskId - Task ID to find (e.g., "T001")
|
|
173
|
+
* @returns The task or null if not found
|
|
174
|
+
*/
|
|
175
|
+
export function getTaskById(filePath, taskId) {
|
|
176
|
+
const tasks = getAllTasks(filePath);
|
|
177
|
+
return tasks.find((t) => t.taskId === taskId) || null;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Get incomplete tasks ready for work (not blocked by dependencies)
|
|
181
|
+
*
|
|
182
|
+
* @param filePath - Path to the tasks file
|
|
183
|
+
* @returns Array of incomplete tasks
|
|
184
|
+
*/
|
|
185
|
+
export function getIncompleteTasks(filePath) {
|
|
186
|
+
const result = parseTasks(filePath, { incompleteOnly: true });
|
|
187
|
+
return result?.tasks || [];
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Get tasks that can be worked on in parallel
|
|
191
|
+
*
|
|
192
|
+
* @param filePath - Path to the tasks file
|
|
193
|
+
* @returns Array of parallelizable incomplete tasks
|
|
194
|
+
*/
|
|
195
|
+
export function getParallelizableTasks(filePath) {
|
|
196
|
+
const result = parseTasks(filePath, {
|
|
197
|
+
incompleteOnly: true,
|
|
198
|
+
parallelizableOnly: true,
|
|
199
|
+
});
|
|
200
|
+
return result?.tasks || [];
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Get tasks grouped by phase
|
|
204
|
+
*
|
|
205
|
+
* @param filePath - Path to the tasks file
|
|
206
|
+
* @returns Map of phase number to tasks in that phase
|
|
207
|
+
*/
|
|
208
|
+
export function getTasksByPhase(filePath) {
|
|
209
|
+
const result = parseTasks(filePath);
|
|
210
|
+
const byPhase = new Map();
|
|
211
|
+
if (!result)
|
|
212
|
+
return byPhase;
|
|
213
|
+
for (const task of result.tasks) {
|
|
214
|
+
const phase = task.phase ?? 0; // Default to phase 0 for tasks without phase
|
|
215
|
+
const phaseTasks = byPhase.get(phase) || [];
|
|
216
|
+
phaseTasks.push(task);
|
|
217
|
+
byPhase.set(phase, phaseTasks);
|
|
218
|
+
}
|
|
219
|
+
return byPhase;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Get tasks grouped by user story
|
|
223
|
+
*
|
|
224
|
+
* @param filePath - Path to the tasks file
|
|
225
|
+
* @returns Map of user story ID to tasks
|
|
226
|
+
*/
|
|
227
|
+
export function getTasksByUserStory(filePath) {
|
|
228
|
+
const result = parseTasks(filePath);
|
|
229
|
+
const byUserStory = new Map();
|
|
230
|
+
if (!result)
|
|
231
|
+
return byUserStory;
|
|
232
|
+
for (const task of result.tasks) {
|
|
233
|
+
const storyTasks = byUserStory.get(task.userStory) || [];
|
|
234
|
+
storyTasks.push(task);
|
|
235
|
+
byUserStory.set(task.userStory, storyTasks);
|
|
236
|
+
}
|
|
237
|
+
return byUserStory;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Check if a file appears to be a valid tasks.md file
|
|
241
|
+
*
|
|
242
|
+
* @param filePath - Path to check
|
|
243
|
+
* @returns true if the file looks like a tasks file
|
|
244
|
+
*/
|
|
245
|
+
export function isTasksFile(filePath) {
|
|
246
|
+
if (!existsSync(filePath)) {
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
try {
|
|
250
|
+
const content = readFileSync(filePath, "utf-8");
|
|
251
|
+
const lines = content.split("\n").slice(0, 30); // Check first 30 lines
|
|
252
|
+
// Look for task-like lines
|
|
253
|
+
for (const line of lines) {
|
|
254
|
+
if (PATTERNS.TASK_LINE.test(line)) {
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
catch {
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Get task completion statistics
|
|
266
|
+
*
|
|
267
|
+
* @param filePath - Path to the tasks file
|
|
268
|
+
* @returns Statistics object or null
|
|
269
|
+
*/
|
|
270
|
+
export function getTaskStats(filePath) {
|
|
271
|
+
const result = parseTasks(filePath);
|
|
272
|
+
if (!result)
|
|
273
|
+
return null;
|
|
274
|
+
return {
|
|
275
|
+
...result.stats,
|
|
276
|
+
completionRate: result.stats.total > 0
|
|
277
|
+
? Math.round((result.stats.completed / result.stats.total) * 100)
|
|
278
|
+
: 0,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
//# sourceMappingURL=tasks-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tasks-parser.js","sourceRoot":"","sources":["../../src/parser/tasks-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EACL,QAAQ,EACR,eAAe,EACf,YAAY,EACZ,oBAAoB,GAErB,MAAM,qBAAqB,CAAC;AA+D7B;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,UAAU,CACxB,QAAgB,EAChB,UAA6B,EAAE;IAE/B,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAChD,OAAO,iBAAiB,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACvD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,kCAAkC,QAAQ,GAAG,EAAE,KAAK,CAAC,CAAC;QACpE,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAAe,EACf,WAAmB,UAAU,EAC7B,UAA6B,EAAE;IAE/B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,KAAK,GAAiB,EAAE,CAAC;IAC/B,MAAM,MAAM,GAAwB,IAAI,GAAG,EAAE,CAAC;IAE9C,6BAA6B;IAC7B,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IAExC,sBAAsB;IACtB,IAAI,YAAY,GAAkB,IAAI,CAAC;IACvC,IAAI,gBAAgB,GAAkB,IAAI,CAAC;IAE3C,kBAAkB;IAClB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,UAAU,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY;QAEtC,yBAAyB;QACzB,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QACrD,IAAI,UAAU,EAAE,CAAC;YACf,YAAY,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC3C,gBAAgB,GAAG,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC;YACjD,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,gBAAgB,IAAI,SAAS,YAAY,EAAE,CAAC,CAAC;YACtE,SAAS;QACX,CAAC;QAED,sBAAsB;QACtB,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACjD,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,IAAI,GAAG,aAAa,CACxB,IAAI,EACJ,SAAS,EACT,UAAU,EACV,YAAY,EACZ,gBAAgB,CACjB,CAAC;YAEF,gBAAgB;YAChB,IAAI,iBAAiB,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;gBACrC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;IACH,CAAC;IAED,kBAAkB;IAClB,MAAM,KAAK,GAAG;QACZ,KAAK,EAAE,KAAK,CAAC,MAAM;QACnB,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM;QAClD,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM;QACpD,cAAc,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,MAAM;KAC7D,CAAC;IAEF,OAAO;QACL,KAAK;QACL,QAAQ;QACR,KAAK;QACL,MAAM;QACN,QAAQ;QACR,KAAK;KACN,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,aAAa,CACpB,IAAY,EACZ,KAAuB,EACvB,UAAkB,EAClB,KAAoB,EACpB,SAAwB;IAExB,MAAM,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC;IAEvD,8CAA8C;IAC9C,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAEzE,kCAAkC;IAClC,MAAM,cAAc,GAAG,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE1D,8BAA8B;IAC9B,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAE5D,oBAAoB;IACpB,MAAM,WAAW,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC;IAE/C,OAAO;QACL,MAAM;QACN,WAAW;QACX,SAAS,EAAE,QAAQ,CAAC,WAAW,EAAE,KAAK,GAAG;QACzC,cAAc;QACd,SAAS;QACT,KAAK;QACL,SAAS;QACT,UAAU;QACV,WAAW;QACX,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CACxB,IAAgB,EAChB,OAA0B;IAE1B,eAAe;IACf,IAAI,OAAO,CAAC,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5D,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACtE,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,yBAAyB;IACzB,IAAI,OAAO,CAAC,cAAc,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QAC7C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,6BAA6B;IAC7B,IAAI,OAAO,CAAC,kBAAkB,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;QACvD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IACpC,OAAO,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC;AAC7B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CACzB,QAAgB,EAChB,MAAc;IAEd,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IACpC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC;AACxD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9D,OAAO,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC;AAC7B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,QAAgB;IACrD,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,EAAE;QAClC,cAAc,EAAE,IAAI;QACpB,kBAAkB,EAAE,IAAI;KACzB,CAAC,CAAC;IACH,OAAO,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC;AAC7B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IACpC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAwB,CAAC;IAEhD,IAAI,CAAC,MAAM;QAAE,OAAO,OAAO,CAAC;IAE5B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,6CAA6C;QAC5E,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAC5C,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAAgB;IAEhB,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IACpC,MAAM,WAAW,GAAG,IAAI,GAAG,EAA+B,CAAC;IAE3D,IAAI,CAAC,MAAM;QAAE,OAAO,WAAW,CAAC;IAEhC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAChC,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QACzD,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAChD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,uBAAuB;QAEvE,2BAA2B;QAC3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBAClC,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB;IAO3C,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IACpC,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEzB,OAAO;QACL,GAAG,MAAM,CAAC,KAAK;QACf,cAAc,EACZ,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC;YACpB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC;YACjE,CAAC,CAAC,CAAC;KACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relationship Mapping for Spec-Kit Integration
|
|
3
|
+
*
|
|
4
|
+
* Maps spec-kit file hierarchy to sudocode relationships.
|
|
5
|
+
*
|
|
6
|
+
* Spec-kit hierarchy:
|
|
7
|
+
* ```
|
|
8
|
+
* spec.md (root)
|
|
9
|
+
* └── plan.md (implements spec.md)
|
|
10
|
+
* ├── tasks (implement plan.md)
|
|
11
|
+
* ├── research.md (references plan.md)
|
|
12
|
+
* ├── data-model.md (references plan.md)
|
|
13
|
+
* └── contracts/* (references plan.md)
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* This creates a clear dependency graph:
|
|
17
|
+
* - plan implements spec (spec defines WHAT, plan defines HOW)
|
|
18
|
+
* - tasks implement plan (tasks are actionable work items from the plan)
|
|
19
|
+
* - supporting docs reference plan (research, data models, contracts support the plan)
|
|
20
|
+
*/
|
|
21
|
+
import type { RelationshipType, EntityType } from "@sudocode-ai/types";
|
|
22
|
+
/**
|
|
23
|
+
* A relationship to be created in sudocode
|
|
24
|
+
*/
|
|
25
|
+
export interface MappedRelationship {
|
|
26
|
+
/** Source entity ID */
|
|
27
|
+
fromId: string;
|
|
28
|
+
/** Source entity type */
|
|
29
|
+
fromType: EntityType;
|
|
30
|
+
/** Target entity ID */
|
|
31
|
+
toId: string;
|
|
32
|
+
/** Target entity type */
|
|
33
|
+
toType: EntityType;
|
|
34
|
+
/** Relationship type */
|
|
35
|
+
relationshipType: RelationshipType;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Task information for relationship mapping
|
|
39
|
+
*/
|
|
40
|
+
export interface TaskInfo {
|
|
41
|
+
/** Task ID from tasks.md (e.g., "T001", "T002") */
|
|
42
|
+
taskId: string;
|
|
43
|
+
/** Optional: task dependencies (other task IDs this task depends on) */
|
|
44
|
+
dependsOn?: string[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Supporting document information
|
|
48
|
+
*/
|
|
49
|
+
export interface SupportingDocInfo {
|
|
50
|
+
/** File type identifier (e.g., "research", "data-model", "contract-api-spec") */
|
|
51
|
+
fileType: string;
|
|
52
|
+
/** Entity type in sudocode */
|
|
53
|
+
entityType: EntityType;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Map all relationships for a spec-kit feature
|
|
57
|
+
*
|
|
58
|
+
* Creates the standard relationship hierarchy:
|
|
59
|
+
* 1. plan implements spec
|
|
60
|
+
* 2. each task implements plan
|
|
61
|
+
* 3. supporting docs reference plan
|
|
62
|
+
*
|
|
63
|
+
* @param featureNumber - Feature number (e.g., "001")
|
|
64
|
+
* @param prefix - Spec ID prefix (default: "sk")
|
|
65
|
+
* @param taskPrefix - Task issue ID prefix (default: "skt")
|
|
66
|
+
* @param tasks - Array of task information from tasks.md
|
|
67
|
+
* @param supportingDocs - Optional array of supporting documents to include
|
|
68
|
+
* @returns Array of relationships to create
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* const relationships = mapFeatureRelationships("001", "sk", "skt", [
|
|
72
|
+
* { taskId: "T001" },
|
|
73
|
+
* { taskId: "T002", dependsOn: ["T001"] },
|
|
74
|
+
* ]);
|
|
75
|
+
* // Returns relationships:
|
|
76
|
+
* // - sk-001-plan implements sk-001-spec
|
|
77
|
+
* // - skt-001-T001 implements sk-001-plan
|
|
78
|
+
* // - skt-001-T002 implements sk-001-plan
|
|
79
|
+
* // - skt-001-T002 depends-on skt-001-T001
|
|
80
|
+
*/
|
|
81
|
+
export declare function mapFeatureRelationships(featureNumber: string, prefix?: string, taskPrefix?: string, tasks?: TaskInfo[], supportingDocs?: SupportingDocInfo[]): MappedRelationship[];
|
|
82
|
+
/**
|
|
83
|
+
* Map relationships for task dependencies within a feature
|
|
84
|
+
*
|
|
85
|
+
* @param featureNumber - Feature number (e.g., "001")
|
|
86
|
+
* @param taskPrefix - Task issue ID prefix (default: "skt")
|
|
87
|
+
* @param tasks - Array of tasks with their dependencies
|
|
88
|
+
* @returns Array of depends-on relationships between tasks
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* const deps = mapTaskDependencies("001", "skt", [
|
|
92
|
+
* { taskId: "T001" },
|
|
93
|
+
* { taskId: "T002", dependsOn: ["T001"] },
|
|
94
|
+
* { taskId: "T003", dependsOn: ["T001", "T002"] },
|
|
95
|
+
* ]);
|
|
96
|
+
* // Returns:
|
|
97
|
+
* // - skt-001-T002 depends-on skt-001-T001
|
|
98
|
+
* // - skt-001-T003 depends-on skt-001-T001
|
|
99
|
+
* // - skt-001-T003 depends-on skt-001-T002
|
|
100
|
+
*/
|
|
101
|
+
export declare function mapTaskDependencies(featureNumber: string, taskPrefix: string | undefined, tasks: TaskInfo[]): MappedRelationship[];
|
|
102
|
+
/**
|
|
103
|
+
* Map relationships for supporting documents in a feature
|
|
104
|
+
*
|
|
105
|
+
* @param featureNumber - Feature number (e.g., "001")
|
|
106
|
+
* @param prefix - Spec ID prefix (default: "sk")
|
|
107
|
+
* @param supportingDocs - Array of supporting document information
|
|
108
|
+
* @returns Array of reference relationships to the plan
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* const refs = mapSupportingDocRelationships("001", "sk", [
|
|
112
|
+
* { fileType: "research", entityType: "spec" },
|
|
113
|
+
* { fileType: "data-model", entityType: "spec" },
|
|
114
|
+
* { fileType: "contract-api-spec", entityType: "spec" },
|
|
115
|
+
* ]);
|
|
116
|
+
* // Returns:
|
|
117
|
+
* // - sk-001-research references sk-001-plan
|
|
118
|
+
* // - sk-001-data-model references sk-001-plan
|
|
119
|
+
* // - sk-001-contract-api-spec references sk-001-plan
|
|
120
|
+
*/
|
|
121
|
+
export declare function mapSupportingDocRelationships(featureNumber: string, prefix: string | undefined, supportingDocs: SupportingDocInfo[]): MappedRelationship[];
|
|
122
|
+
/**
|
|
123
|
+
* Map the core spec->plan relationship for a feature
|
|
124
|
+
*
|
|
125
|
+
* @param featureNumber - Feature number (e.g., "001")
|
|
126
|
+
* @param prefix - Spec ID prefix (default: "sk")
|
|
127
|
+
* @returns The implements relationship from plan to spec
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* const rel = mapPlanToSpecRelationship("001");
|
|
131
|
+
* // Returns: sk-001-plan implements sk-001-spec
|
|
132
|
+
*/
|
|
133
|
+
export declare function mapPlanToSpecRelationship(featureNumber: string, prefix?: string): MappedRelationship;
|
|
134
|
+
/**
|
|
135
|
+
* Map a single task's relationship to its plan
|
|
136
|
+
*
|
|
137
|
+
* @param featureNumber - Feature number (e.g., "001")
|
|
138
|
+
* @param taskId - Task ID (e.g., "T001")
|
|
139
|
+
* @param prefix - Spec ID prefix (default: "sk")
|
|
140
|
+
* @param taskPrefix - Task issue ID prefix (default: "skt")
|
|
141
|
+
* @returns The implements relationship from task to plan
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* const rel = mapTaskToPlanRelationship("001", "T001");
|
|
145
|
+
* // Returns: skt-001-T001 implements sk-001-plan
|
|
146
|
+
*/
|
|
147
|
+
export declare function mapTaskToPlanRelationship(featureNumber: string, taskId: string, prefix?: string, taskPrefix?: string): MappedRelationship;
|
|
148
|
+
/**
|
|
149
|
+
* Determine the standard supporting doc types for a feature
|
|
150
|
+
*
|
|
151
|
+
* @returns Array of standard supporting document types
|
|
152
|
+
*/
|
|
153
|
+
export declare function getStandardSupportingDocTypes(): SupportingDocInfo[];
|
|
154
|
+
/**
|
|
155
|
+
* Create a contract document info for relationship mapping
|
|
156
|
+
*
|
|
157
|
+
* @param contractName - Contract file name without extension (e.g., "api-spec")
|
|
158
|
+
* @returns Supporting doc info for the contract
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* createContractDocInfo("api-spec")
|
|
162
|
+
* // Returns: { fileType: "contract-api-spec", entityType: "spec" }
|
|
163
|
+
*/
|
|
164
|
+
export declare function createContractDocInfo(contractName: string): SupportingDocInfo;
|
|
165
|
+
//# sourceMappingURL=relationship-mapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relationship-mapper.d.ts","sourceRoot":"","sources":["../src/relationship-mapper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAOvE;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,QAAQ,EAAE,UAAU,CAAC;IACrB,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,yBAAyB;IACzB,MAAM,EAAE,UAAU,CAAC;IACnB,wBAAwB;IACxB,gBAAgB,EAAE,gBAAgB,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,UAAU,EAAE,UAAU,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,MAAM,EACrB,MAAM,GAAE,MAAa,EACrB,UAAU,GAAE,MAAc,EAC1B,KAAK,GAAE,QAAQ,EAAO,EACtB,cAAc,GAAE,iBAAiB,EAAO,GACvC,kBAAkB,EAAE,CA+DtB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,YAAQ,EAC1B,KAAK,EAAE,QAAQ,EAAE,GAChB,kBAAkB,EAAE,CA6BtB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,6BAA6B,CAC3C,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,YAAO,EACrB,cAAc,EAAE,iBAAiB,EAAE,GAClC,kBAAkB,EAAE,CAgBtB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CACvC,aAAa,EAAE,MAAM,EACrB,MAAM,GAAE,MAAa,GACpB,kBAAkB,CAQpB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,yBAAyB,CACvC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,MAAa,EACrB,UAAU,GAAE,MAAc,GACzB,kBAAkB,CAQpB;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,IAAI,iBAAiB,EAAE,CAKnE;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,iBAAiB,CAK7E"}
|