@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,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spec Writer for Spec-Kit Integration
|
|
3
|
+
*
|
|
4
|
+
* Updates spec.md and plan.md content while preserving document structure.
|
|
5
|
+
* Handles title updates in headers and status line updates.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Updates to apply to a spec file
|
|
9
|
+
*/
|
|
10
|
+
export interface SpecUpdates {
|
|
11
|
+
/** New title (will update # header) */
|
|
12
|
+
title?: string;
|
|
13
|
+
/** New status (will update **Status**: line) */
|
|
14
|
+
status?: string;
|
|
15
|
+
/** New content (will replace everything after frontmatter/header) */
|
|
16
|
+
content?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Result of a spec update operation
|
|
20
|
+
*/
|
|
21
|
+
export interface SpecUpdateResult {
|
|
22
|
+
success: boolean;
|
|
23
|
+
error?: string;
|
|
24
|
+
changes: {
|
|
25
|
+
title?: {
|
|
26
|
+
from: string;
|
|
27
|
+
to: string;
|
|
28
|
+
};
|
|
29
|
+
status?: {
|
|
30
|
+
from: string;
|
|
31
|
+
to: string;
|
|
32
|
+
};
|
|
33
|
+
content?: boolean;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Update spec content while preserving document structure
|
|
38
|
+
*
|
|
39
|
+
* @param specFilePath - Absolute path to the spec.md or plan.md file
|
|
40
|
+
* @param updates - Updates to apply (title, status, content)
|
|
41
|
+
* @returns Result of the update operation
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* // Update just the status
|
|
45
|
+
* updateSpecContent("/project/.specify/specs/001-auth/spec.md", {
|
|
46
|
+
* status: "In Progress"
|
|
47
|
+
* });
|
|
48
|
+
*
|
|
49
|
+
* // Update title and status
|
|
50
|
+
* updateSpecContent("/project/.specify/specs/001-auth/spec.md", {
|
|
51
|
+
* title: "Authentication System",
|
|
52
|
+
* status: "Complete"
|
|
53
|
+
* });
|
|
54
|
+
*/
|
|
55
|
+
export declare function updateSpecContent(specFilePath: string, updates: SpecUpdates): SpecUpdateResult;
|
|
56
|
+
/**
|
|
57
|
+
* Get the current title from a spec file
|
|
58
|
+
*
|
|
59
|
+
* @param specFilePath - Absolute path to the spec file
|
|
60
|
+
* @returns The title or null if not found
|
|
61
|
+
*/
|
|
62
|
+
export declare function getSpecTitle(specFilePath: string): string | null;
|
|
63
|
+
/**
|
|
64
|
+
* Get the current status from a spec file
|
|
65
|
+
*
|
|
66
|
+
* @param specFilePath - Absolute path to the spec file
|
|
67
|
+
* @returns The status or null if not found
|
|
68
|
+
*/
|
|
69
|
+
export declare function getSpecStatus(specFilePath: string): string | null;
|
|
70
|
+
//# sourceMappingURL=spec-writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec-writer.d.ts","sourceRoot":"","sources":["../../src/writer/spec-writer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE;QACP,KAAK,CAAC,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QACrC,MAAM,CAAC,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QACtC,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,CAAC;CACH;AA6BD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,WAAW,GACnB,gBAAgB,CAsGlB;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAWhE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAWjE"}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spec Writer for Spec-Kit Integration
|
|
3
|
+
*
|
|
4
|
+
* Updates spec.md and plan.md content while preserving document structure.
|
|
5
|
+
* Handles title updates in headers and status line updates.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, writeFileSync, existsSync, renameSync } from "fs";
|
|
8
|
+
import { dirname } from "path";
|
|
9
|
+
import { mkdirSync } from "fs";
|
|
10
|
+
/**
|
|
11
|
+
* Regex patterns for spec-kit markdown structure
|
|
12
|
+
*/
|
|
13
|
+
const TITLE_REGEX = /^#\s+(.+)$/;
|
|
14
|
+
const STATUS_REGEX = /^\*\*Status\*\*:\s*(.*)$/i;
|
|
15
|
+
const METADATA_LINE_REGEX = /^\*\*[^*]+\*\*:/;
|
|
16
|
+
/**
|
|
17
|
+
* Update spec content while preserving document structure
|
|
18
|
+
*
|
|
19
|
+
* @param specFilePath - Absolute path to the spec.md or plan.md file
|
|
20
|
+
* @param updates - Updates to apply (title, status, content)
|
|
21
|
+
* @returns Result of the update operation
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* // Update just the status
|
|
25
|
+
* updateSpecContent("/project/.specify/specs/001-auth/spec.md", {
|
|
26
|
+
* status: "In Progress"
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* // Update title and status
|
|
30
|
+
* updateSpecContent("/project/.specify/specs/001-auth/spec.md", {
|
|
31
|
+
* title: "Authentication System",
|
|
32
|
+
* status: "Complete"
|
|
33
|
+
* });
|
|
34
|
+
*/
|
|
35
|
+
export function updateSpecContent(specFilePath, updates) {
|
|
36
|
+
const result = {
|
|
37
|
+
success: false,
|
|
38
|
+
changes: {},
|
|
39
|
+
};
|
|
40
|
+
// Validate inputs
|
|
41
|
+
if (!specFilePath) {
|
|
42
|
+
result.error = "Spec file path is required";
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
if (!updates.title && !updates.status && updates.content === undefined) {
|
|
46
|
+
result.error = "At least one update (title, status, or content) is required";
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
// Check if file exists
|
|
50
|
+
if (!existsSync(specFilePath)) {
|
|
51
|
+
result.error = `Spec file not found: ${specFilePath}`;
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
// Parse the file
|
|
56
|
+
const parsed = parseSpecFile(specFilePath);
|
|
57
|
+
const lines = [...parsed.lines];
|
|
58
|
+
// Apply title update
|
|
59
|
+
if (updates.title !== undefined && updates.title !== parsed.currentTitle) {
|
|
60
|
+
if (parsed.titleLineIndex !== null) {
|
|
61
|
+
lines[parsed.titleLineIndex] = `# ${updates.title}`;
|
|
62
|
+
result.changes.title = {
|
|
63
|
+
from: parsed.currentTitle || "",
|
|
64
|
+
to: updates.title,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
// No title found, prepend one
|
|
69
|
+
lines.unshift(`# ${updates.title}`, "");
|
|
70
|
+
result.changes.title = {
|
|
71
|
+
from: "",
|
|
72
|
+
to: updates.title,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Apply status update
|
|
77
|
+
if (updates.status !== undefined && updates.status !== parsed.currentStatus) {
|
|
78
|
+
if (parsed.statusLineIndex !== null) {
|
|
79
|
+
lines[parsed.statusLineIndex] = `**Status**: ${updates.status}`;
|
|
80
|
+
result.changes.status = {
|
|
81
|
+
from: parsed.currentStatus || "",
|
|
82
|
+
to: updates.status,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// No status found, insert after title or at start
|
|
87
|
+
const insertIndex = parsed.titleLineIndex !== null ? parsed.titleLineIndex + 1 : 0;
|
|
88
|
+
// Make sure there's a blank line before status if inserting after title
|
|
89
|
+
if (parsed.titleLineIndex !== null && lines[insertIndex]?.trim() !== "") {
|
|
90
|
+
lines.splice(insertIndex, 0, "");
|
|
91
|
+
}
|
|
92
|
+
lines.splice(insertIndex + 1, 0, `**Status**: ${updates.status}`);
|
|
93
|
+
result.changes.status = {
|
|
94
|
+
from: "",
|
|
95
|
+
to: updates.status,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Apply content update
|
|
100
|
+
if (updates.content !== undefined) {
|
|
101
|
+
// Recalculate content start after possible line shifts
|
|
102
|
+
const recalculated = recalculateContentStart(lines);
|
|
103
|
+
// Remove everything from content start
|
|
104
|
+
lines.splice(recalculated.contentStartIndex);
|
|
105
|
+
// Add new content with proper spacing
|
|
106
|
+
if (recalculated.contentStartIndex > 0 && !lines[lines.length - 1]?.trim()) {
|
|
107
|
+
// Already has blank line
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
lines.push("");
|
|
111
|
+
}
|
|
112
|
+
// Add the new content
|
|
113
|
+
lines.push(updates.content);
|
|
114
|
+
result.changes.content = true;
|
|
115
|
+
}
|
|
116
|
+
// Write the updated content atomically
|
|
117
|
+
const updatedContent = lines.join("\n");
|
|
118
|
+
writeFileAtomic(specFilePath, updatedContent);
|
|
119
|
+
result.success = true;
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
result.error = `Failed to update spec: ${error instanceof Error ? error.message : String(error)}`;
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get the current title from a spec file
|
|
129
|
+
*
|
|
130
|
+
* @param specFilePath - Absolute path to the spec file
|
|
131
|
+
* @returns The title or null if not found
|
|
132
|
+
*/
|
|
133
|
+
export function getSpecTitle(specFilePath) {
|
|
134
|
+
if (!existsSync(specFilePath)) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
const parsed = parseSpecFile(specFilePath);
|
|
139
|
+
return parsed.currentTitle;
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Get the current status from a spec file
|
|
147
|
+
*
|
|
148
|
+
* @param specFilePath - Absolute path to the spec file
|
|
149
|
+
* @returns The status or null if not found
|
|
150
|
+
*/
|
|
151
|
+
export function getSpecStatus(specFilePath) {
|
|
152
|
+
if (!existsSync(specFilePath)) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
try {
|
|
156
|
+
const parsed = parseSpecFile(specFilePath);
|
|
157
|
+
return parsed.currentStatus;
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Parse a spec-kit markdown file to extract structure
|
|
165
|
+
*/
|
|
166
|
+
function parseSpecFile(filePath) {
|
|
167
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
168
|
+
const lines = raw.split("\n");
|
|
169
|
+
let titleLineIndex = null;
|
|
170
|
+
let currentTitle = null;
|
|
171
|
+
let statusLineIndex = null;
|
|
172
|
+
let currentStatus = null;
|
|
173
|
+
let contentStartIndex = 0;
|
|
174
|
+
let foundFirstContent = false;
|
|
175
|
+
for (let i = 0; i < lines.length; i++) {
|
|
176
|
+
const line = lines[i];
|
|
177
|
+
// Look for title (# header)
|
|
178
|
+
if (titleLineIndex === null) {
|
|
179
|
+
const titleMatch = line.match(TITLE_REGEX);
|
|
180
|
+
if (titleMatch) {
|
|
181
|
+
titleLineIndex = i;
|
|
182
|
+
currentTitle = titleMatch[1].trim();
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// Look for status line
|
|
187
|
+
if (statusLineIndex === null) {
|
|
188
|
+
const statusMatch = line.match(STATUS_REGEX);
|
|
189
|
+
if (statusMatch) {
|
|
190
|
+
statusLineIndex = i;
|
|
191
|
+
currentStatus = statusMatch[1].trim();
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Track metadata section (lines starting with **Key**:)
|
|
196
|
+
if (METADATA_LINE_REGEX.test(line)) {
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
// Track where content starts (first non-empty, non-metadata line after title)
|
|
200
|
+
if (!foundFirstContent && titleLineIndex !== null && line.trim() !== "") {
|
|
201
|
+
// Skip if this is still in metadata section
|
|
202
|
+
if (!METADATA_LINE_REGEX.test(line)) {
|
|
203
|
+
contentStartIndex = i;
|
|
204
|
+
foundFirstContent = true;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// If no content found, start after metadata
|
|
209
|
+
if (!foundFirstContent) {
|
|
210
|
+
contentStartIndex = lines.length;
|
|
211
|
+
}
|
|
212
|
+
return {
|
|
213
|
+
raw,
|
|
214
|
+
lines,
|
|
215
|
+
titleLineIndex,
|
|
216
|
+
currentTitle,
|
|
217
|
+
statusLineIndex,
|
|
218
|
+
currentStatus,
|
|
219
|
+
contentStartIndex,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Recalculate content start index after modifications
|
|
224
|
+
*/
|
|
225
|
+
function recalculateContentStart(lines) {
|
|
226
|
+
let titleLineIndex = null;
|
|
227
|
+
let lastMetadataIndex = -1;
|
|
228
|
+
for (let i = 0; i < lines.length; i++) {
|
|
229
|
+
const line = lines[i];
|
|
230
|
+
// Find title
|
|
231
|
+
if (titleLineIndex === null && TITLE_REGEX.test(line)) {
|
|
232
|
+
titleLineIndex = i;
|
|
233
|
+
}
|
|
234
|
+
// Track metadata lines
|
|
235
|
+
if (METADATA_LINE_REGEX.test(line)) {
|
|
236
|
+
lastMetadataIndex = i;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// Content starts after the last metadata line (or after title if no metadata)
|
|
240
|
+
// Skip any blank lines too
|
|
241
|
+
let contentStartIndex = Math.max(titleLineIndex !== null ? titleLineIndex + 1 : 0, lastMetadataIndex + 1);
|
|
242
|
+
// Skip blank lines after metadata
|
|
243
|
+
while (contentStartIndex < lines.length && lines[contentStartIndex]?.trim() === "") {
|
|
244
|
+
contentStartIndex++;
|
|
245
|
+
}
|
|
246
|
+
return { contentStartIndex };
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Write file atomically using temp file + rename pattern
|
|
250
|
+
*/
|
|
251
|
+
function writeFileAtomic(filePath, content) {
|
|
252
|
+
const dir = dirname(filePath);
|
|
253
|
+
if (!existsSync(dir)) {
|
|
254
|
+
mkdirSync(dir, { recursive: true });
|
|
255
|
+
}
|
|
256
|
+
const tempPath = `${filePath}.tmp.${Date.now()}`;
|
|
257
|
+
writeFileSync(tempPath, content, "utf-8");
|
|
258
|
+
// Rename is atomic on most file systems
|
|
259
|
+
renameSync(tempPath, filePath);
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=spec-writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec-writer.js","sourceRoot":"","sources":["../../src/writer/spec-writer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tasks Writer for Spec-Kit Integration
|
|
3
|
+
*
|
|
4
|
+
* Updates task checkbox status in tasks.md files.
|
|
5
|
+
* Tasks are formatted as: `- [ ] T001: Task description` or `- [x] T001: Task description`
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Result of a task status update operation
|
|
9
|
+
*/
|
|
10
|
+
export interface TaskUpdateResult {
|
|
11
|
+
success: boolean;
|
|
12
|
+
error?: string;
|
|
13
|
+
previousStatus?: boolean;
|
|
14
|
+
newStatus?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Update a task's checkbox status in a tasks.md file
|
|
18
|
+
*
|
|
19
|
+
* @param tasksFilePath - Absolute path to the tasks.md file
|
|
20
|
+
* @param taskId - Task identifier (e.g., "T001")
|
|
21
|
+
* @param completed - Whether the task should be marked as completed
|
|
22
|
+
* @returns Result of the update operation
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* updateTaskStatus("/project/.specify/specs/001-auth/tasks.md", "T001", true);
|
|
26
|
+
* // Changes `- [ ] T001: Setup auth` to `- [x] T001: Setup auth`
|
|
27
|
+
*
|
|
28
|
+
* updateTaskStatus("/project/.specify/specs/001-auth/tasks.md", "T001", false);
|
|
29
|
+
* // Changes `- [x] T001: Setup auth` to `- [ ] T001: Setup auth`
|
|
30
|
+
*/
|
|
31
|
+
export declare function updateTaskStatus(tasksFilePath: string, taskId: string, completed: boolean): TaskUpdateResult;
|
|
32
|
+
/**
|
|
33
|
+
* Get the current status of a task
|
|
34
|
+
*
|
|
35
|
+
* @param tasksFilePath - Absolute path to the tasks.md file
|
|
36
|
+
* @param taskId - Task identifier (e.g., "T001")
|
|
37
|
+
* @returns The task's completion status, or null if not found
|
|
38
|
+
*/
|
|
39
|
+
export declare function getTaskStatus(tasksFilePath: string, taskId: string): boolean | null;
|
|
40
|
+
/**
|
|
41
|
+
* Get all tasks and their statuses from a tasks.md file
|
|
42
|
+
*
|
|
43
|
+
* @param tasksFilePath - Absolute path to the tasks.md file
|
|
44
|
+
* @returns Map of task IDs to their completion status
|
|
45
|
+
*/
|
|
46
|
+
export declare function getAllTaskStatuses(tasksFilePath: string): Map<string, boolean>;
|
|
47
|
+
//# sourceMappingURL=tasks-writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tasks-writer.d.ts","sourceRoot":"","sources":["../../src/writer/tasks-writer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAaD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAC9B,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,OAAO,GACjB,gBAAgB,CAiElB;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,GAAG,IAAI,CAoBhB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,MAAM,GACpB,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAwBtB"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tasks Writer for Spec-Kit Integration
|
|
3
|
+
*
|
|
4
|
+
* Updates task checkbox status in tasks.md files.
|
|
5
|
+
* Tasks are formatted as: `- [ ] T001: Task description` or `- [x] T001: Task description`
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, writeFileSync, existsSync, renameSync } from "fs";
|
|
8
|
+
import { dirname } from "path";
|
|
9
|
+
import { mkdirSync } from "fs";
|
|
10
|
+
/**
|
|
11
|
+
* Regex pattern to match task lines in tasks.md
|
|
12
|
+
* Matches: `- [ ] T001: description` or `- [x] T001: description`
|
|
13
|
+
* Captures:
|
|
14
|
+
* - Group 1: Leading whitespace and bullet
|
|
15
|
+
* - Group 2: Checkbox state (space or x)
|
|
16
|
+
* - Group 3: Task ID (e.g., T001)
|
|
17
|
+
* - Group 4: Rest of line (description)
|
|
18
|
+
*/
|
|
19
|
+
const TASK_LINE_REGEX = /^(\s*-\s*)\[([ xX])\]\s*(T\d+)(.*)$/;
|
|
20
|
+
/**
|
|
21
|
+
* Update a task's checkbox status in a tasks.md file
|
|
22
|
+
*
|
|
23
|
+
* @param tasksFilePath - Absolute path to the tasks.md file
|
|
24
|
+
* @param taskId - Task identifier (e.g., "T001")
|
|
25
|
+
* @param completed - Whether the task should be marked as completed
|
|
26
|
+
* @returns Result of the update operation
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* updateTaskStatus("/project/.specify/specs/001-auth/tasks.md", "T001", true);
|
|
30
|
+
* // Changes `- [ ] T001: Setup auth` to `- [x] T001: Setup auth`
|
|
31
|
+
*
|
|
32
|
+
* updateTaskStatus("/project/.specify/specs/001-auth/tasks.md", "T001", false);
|
|
33
|
+
* // Changes `- [x] T001: Setup auth` to `- [ ] T001: Setup auth`
|
|
34
|
+
*/
|
|
35
|
+
export function updateTaskStatus(tasksFilePath, taskId, completed) {
|
|
36
|
+
// Validate inputs
|
|
37
|
+
if (!tasksFilePath) {
|
|
38
|
+
return { success: false, error: "Tasks file path is required" };
|
|
39
|
+
}
|
|
40
|
+
if (!taskId || !/^T\d+$/.test(taskId)) {
|
|
41
|
+
return {
|
|
42
|
+
success: false,
|
|
43
|
+
error: `Invalid task ID format: ${taskId}. Expected format: T001, T002, etc.`,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
// Check if file exists
|
|
47
|
+
if (!existsSync(tasksFilePath)) {
|
|
48
|
+
return { success: false, error: `Tasks file not found: ${tasksFilePath}` };
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
// Read the file
|
|
52
|
+
const content = readFileSync(tasksFilePath, "utf-8");
|
|
53
|
+
const lines = content.split("\n");
|
|
54
|
+
let taskFound = false;
|
|
55
|
+
let previousStatus;
|
|
56
|
+
const newCheckbox = completed ? "x" : " ";
|
|
57
|
+
// Process each line
|
|
58
|
+
const updatedLines = lines.map((line) => {
|
|
59
|
+
const match = line.match(TASK_LINE_REGEX);
|
|
60
|
+
if (match && match[3] === taskId) {
|
|
61
|
+
taskFound = true;
|
|
62
|
+
const [, prefix, currentCheckbox, id, rest] = match;
|
|
63
|
+
previousStatus = currentCheckbox.toLowerCase() === "x";
|
|
64
|
+
// Return updated line with new checkbox state
|
|
65
|
+
return `${prefix}[${newCheckbox}] ${id}${rest}`;
|
|
66
|
+
}
|
|
67
|
+
return line;
|
|
68
|
+
});
|
|
69
|
+
if (!taskFound) {
|
|
70
|
+
return {
|
|
71
|
+
success: false,
|
|
72
|
+
error: `Task ${taskId} not found in ${tasksFilePath}`,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
// Write the updated content atomically
|
|
76
|
+
const updatedContent = updatedLines.join("\n");
|
|
77
|
+
writeFileAtomic(tasksFilePath, updatedContent);
|
|
78
|
+
return {
|
|
79
|
+
success: true,
|
|
80
|
+
previousStatus,
|
|
81
|
+
newStatus: completed,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
return {
|
|
86
|
+
success: false,
|
|
87
|
+
error: `Failed to update task status: ${error instanceof Error ? error.message : String(error)}`,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get the current status of a task
|
|
93
|
+
*
|
|
94
|
+
* @param tasksFilePath - Absolute path to the tasks.md file
|
|
95
|
+
* @param taskId - Task identifier (e.g., "T001")
|
|
96
|
+
* @returns The task's completion status, or null if not found
|
|
97
|
+
*/
|
|
98
|
+
export function getTaskStatus(tasksFilePath, taskId) {
|
|
99
|
+
if (!existsSync(tasksFilePath)) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
const content = readFileSync(tasksFilePath, "utf-8");
|
|
104
|
+
const lines = content.split("\n");
|
|
105
|
+
for (const line of lines) {
|
|
106
|
+
const match = line.match(TASK_LINE_REGEX);
|
|
107
|
+
if (match && match[3] === taskId) {
|
|
108
|
+
return match[2].toLowerCase() === "x";
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Get all tasks and their statuses from a tasks.md file
|
|
119
|
+
*
|
|
120
|
+
* @param tasksFilePath - Absolute path to the tasks.md file
|
|
121
|
+
* @returns Map of task IDs to their completion status
|
|
122
|
+
*/
|
|
123
|
+
export function getAllTaskStatuses(tasksFilePath) {
|
|
124
|
+
const statuses = new Map();
|
|
125
|
+
if (!existsSync(tasksFilePath)) {
|
|
126
|
+
return statuses;
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
const content = readFileSync(tasksFilePath, "utf-8");
|
|
130
|
+
const lines = content.split("\n");
|
|
131
|
+
for (const line of lines) {
|
|
132
|
+
const match = line.match(TASK_LINE_REGEX);
|
|
133
|
+
if (match) {
|
|
134
|
+
const taskId = match[3];
|
|
135
|
+
const isCompleted = match[2].toLowerCase() === "x";
|
|
136
|
+
statuses.set(taskId, isCompleted);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
// Return empty map on error
|
|
142
|
+
}
|
|
143
|
+
return statuses;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Write file atomically using temp file + rename pattern
|
|
147
|
+
*
|
|
148
|
+
* @param filePath - Target file path
|
|
149
|
+
* @param content - Content to write
|
|
150
|
+
*/
|
|
151
|
+
function writeFileAtomic(filePath, content) {
|
|
152
|
+
const dir = dirname(filePath);
|
|
153
|
+
if (!existsSync(dir)) {
|
|
154
|
+
mkdirSync(dir, { recursive: true });
|
|
155
|
+
}
|
|
156
|
+
const tempPath = `${filePath}.tmp.${Date.now()}`;
|
|
157
|
+
writeFileSync(tempPath, content, "utf-8");
|
|
158
|
+
// Rename is atomic on most file systems
|
|
159
|
+
renameSync(tempPath, filePath);
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=tasks-writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tasks-writer.js","sourceRoot":"","sources":["../../src/writer/tasks-writer.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sudocode-ai/integration-speckit",
|
|
3
|
+
"version": "0.1.14",
|
|
4
|
+
"description": "Spec-kit integration plugin for sudocode",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"test": "vitest --run",
|
|
20
|
+
"clean": "rm -rf dist"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"sudocode",
|
|
24
|
+
"integration",
|
|
25
|
+
"spec-kit",
|
|
26
|
+
"plugin"
|
|
27
|
+
],
|
|
28
|
+
"author": "sudocode-ai",
|
|
29
|
+
"license": "Apache-2.0",
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"chokidar": "^4.0.3"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@sudocode-ai/types": "^0.1.14"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@sudocode-ai/types": "*",
|
|
38
|
+
"@types/node": "^22.10.2",
|
|
39
|
+
"typescript": "^5.8.3",
|
|
40
|
+
"vitest": "^3.2.4"
|
|
41
|
+
}
|
|
42
|
+
}
|