kiro-spec-engine 1.2.3 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/CHANGELOG.md +135 -0
  2. package/README.md +239 -213
  3. package/README.zh.md +0 -330
  4. package/bin/kiro-spec-engine.js +62 -0
  5. package/docs/README.md +223 -0
  6. package/docs/agent-hooks-analysis.md +815 -0
  7. package/docs/command-reference.md +252 -0
  8. package/docs/cross-tool-guide.md +554 -0
  9. package/docs/examples/add-export-command/design.md +194 -0
  10. package/docs/examples/add-export-command/requirements.md +110 -0
  11. package/docs/examples/add-export-command/tasks.md +88 -0
  12. package/docs/examples/add-rest-api/design.md +855 -0
  13. package/docs/examples/add-rest-api/requirements.md +323 -0
  14. package/docs/examples/add-rest-api/tasks.md +355 -0
  15. package/docs/examples/add-user-dashboard/design.md +192 -0
  16. package/docs/examples/add-user-dashboard/requirements.md +143 -0
  17. package/docs/examples/add-user-dashboard/tasks.md +91 -0
  18. package/docs/faq.md +696 -0
  19. package/docs/integration-modes.md +525 -0
  20. package/docs/integration-philosophy.md +313 -0
  21. package/docs/manual-workflows-guide.md +417 -0
  22. package/docs/quick-start-with-ai-tools.md +374 -0
  23. package/docs/quick-start.md +711 -0
  24. package/docs/spec-workflow.md +453 -0
  25. package/docs/steering-strategy-guide.md +196 -0
  26. package/docs/tools/claude-guide.md +653 -0
  27. package/docs/tools/cursor-guide.md +705 -0
  28. package/docs/tools/generic-guide.md +445 -0
  29. package/docs/tools/kiro-guide.md +308 -0
  30. package/docs/tools/vscode-guide.md +444 -0
  31. package/docs/tools/windsurf-guide.md +390 -0
  32. package/docs/troubleshooting.md +795 -0
  33. package/docs/zh/README.md +275 -0
  34. package/docs/zh/quick-start.md +711 -0
  35. package/docs/zh/tools/claude-guide.md +348 -0
  36. package/docs/zh/tools/cursor-guide.md +280 -0
  37. package/docs/zh/tools/generic-guide.md +498 -0
  38. package/docs/zh/tools/kiro-guide.md +342 -0
  39. package/docs/zh/tools/vscode-guide.md +448 -0
  40. package/docs/zh/tools/windsurf-guide.md +377 -0
  41. package/lib/adoption/detection-engine.js +14 -4
  42. package/lib/commands/adopt.js +117 -3
  43. package/lib/commands/context.js +99 -0
  44. package/lib/commands/prompt.js +105 -0
  45. package/lib/commands/status.js +225 -0
  46. package/lib/commands/task.js +199 -0
  47. package/lib/commands/watch.js +569 -0
  48. package/lib/commands/workflows.js +240 -0
  49. package/lib/commands/workspace.js +189 -0
  50. package/lib/context/context-exporter.js +378 -0
  51. package/lib/context/prompt-generator.js +482 -0
  52. package/lib/steering/adoption-config.js +164 -0
  53. package/lib/steering/steering-manager.js +289 -0
  54. package/lib/task/task-claimer.js +430 -0
  55. package/lib/utils/tool-detector.js +383 -0
  56. package/lib/watch/action-executor.js +458 -0
  57. package/lib/watch/event-debouncer.js +323 -0
  58. package/lib/watch/execution-logger.js +550 -0
  59. package/lib/watch/file-watcher.js +499 -0
  60. package/lib/watch/presets.js +266 -0
  61. package/lib/watch/watch-manager.js +533 -0
  62. package/lib/workspace/workspace-manager.js +370 -0
  63. package/lib/workspace/workspace-sync.js +356 -0
  64. package/package.json +3 -1
  65. package/template/.kiro/tools/backup_manager.py +295 -0
  66. package/template/.kiro/tools/configuration_manager.py +218 -0
  67. package/template/.kiro/tools/document_evaluator.py +550 -0
  68. package/template/.kiro/tools/enhancement_logger.py +168 -0
  69. package/template/.kiro/tools/error_handler.py +335 -0
  70. package/template/.kiro/tools/improvement_identifier.py +444 -0
  71. package/template/.kiro/tools/modification_applicator.py +737 -0
  72. package/template/.kiro/tools/quality_gate_enforcer.py +207 -0
  73. package/template/.kiro/tools/quality_scorer.py +305 -0
  74. package/template/.kiro/tools/report_generator.py +154 -0
  75. package/template/.kiro/tools/ultrawork_enhancer_refactored.py +0 -0
  76. package/template/.kiro/tools/ultrawork_enhancer_v2.py +463 -0
  77. package/template/.kiro/tools/ultrawork_enhancer_v3.py +606 -0
  78. package/template/.kiro/tools/workflow_quality_gate.py +100 -0
@@ -0,0 +1,378 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+
4
+ /**
5
+ * ContextExporter - 上下文导出器
6
+ *
7
+ * 将 Spec 上下文导出为独立的 Markdown 文件,供跨工具使用
8
+ */
9
+ class ContextExporter {
10
+ constructor() {
11
+ this.exportFileName = 'context-export.md';
12
+ }
13
+
14
+ /**
15
+ * 导出 Spec 上下文
16
+ *
17
+ * @param {string} projectPath - 项目根目录路径
18
+ * @param {string} specName - Spec 名称
19
+ * @param {Object} options - 导出选项
20
+ * @returns {Promise<Object>} 导出结果
21
+ */
22
+ async exportContext(projectPath, specName, options = {}) {
23
+ const {
24
+ includeRequirements = true,
25
+ includeDesign = true,
26
+ includeTasks = true,
27
+ includeSteering = false,
28
+ steeringFiles = []
29
+ } = options;
30
+
31
+ try {
32
+ const specPath = path.join(projectPath, '.kiro/specs', specName);
33
+
34
+ // 检查 Spec 是否存在
35
+ const specExists = await fs.pathExists(specPath);
36
+ if (!specExists) {
37
+ return {
38
+ success: false,
39
+ error: `Spec not found: ${specName}`
40
+ };
41
+ }
42
+
43
+ // 构建导出内容
44
+ const sections = [];
45
+
46
+ // 添加头部
47
+ sections.push(this.generateHeader(specName));
48
+
49
+ // 添加 Requirements
50
+ if (includeRequirements) {
51
+ const requirements = await this.readSpecFile(specPath, 'requirements.md');
52
+ if (requirements) {
53
+ sections.push(this.formatSection('Requirements', requirements));
54
+ }
55
+ }
56
+
57
+ // 添加 Design
58
+ if (includeDesign) {
59
+ const design = await this.readSpecFile(specPath, 'design.md');
60
+ if (design) {
61
+ sections.push(this.formatSection('Design', design));
62
+ }
63
+ }
64
+
65
+ // 添加 Tasks
66
+ if (includeTasks) {
67
+ const tasks = await this.readSpecFile(specPath, 'tasks.md');
68
+ if (tasks) {
69
+ sections.push(this.formatSection('Tasks', tasks));
70
+ }
71
+ }
72
+
73
+ // 添加 Steering Rules
74
+ if (includeSteering && steeringFiles.length > 0) {
75
+ const steeringContent = await this.includeSteeringRules(projectPath, steeringFiles);
76
+ if (steeringContent) {
77
+ sections.push(steeringContent);
78
+ }
79
+ }
80
+
81
+ // 添加使用说明
82
+ sections.push(this.generateUsageInstructions());
83
+
84
+ // 组合所有内容
85
+ const exportContent = sections.join('\n\n---\n\n');
86
+
87
+ // 保存导出文件
88
+ const exportPath = path.join(specPath, this.exportFileName);
89
+ await fs.writeFile(exportPath, exportContent, 'utf8');
90
+
91
+ return {
92
+ success: true,
93
+ exportPath,
94
+ specName,
95
+ sections: sections.length,
96
+ size: Buffer.byteLength(exportContent, 'utf8')
97
+ };
98
+ } catch (error) {
99
+ return {
100
+ success: false,
101
+ error: error.message
102
+ };
103
+ }
104
+ }
105
+
106
+ /**
107
+ * 生成导出文件头部
108
+ *
109
+ * @param {string} specName - Spec 名称
110
+ * @returns {string} 头部内容
111
+ */
112
+ generateHeader(specName) {
113
+ const timestamp = new Date().toISOString();
114
+
115
+ return `# Context Export: ${specName}
116
+
117
+ **Exported**: ${timestamp}
118
+ **Format**: Standalone Markdown
119
+ **Purpose**: Cross-tool AI coding assistant usage
120
+
121
+ ---
122
+
123
+ ## 📋 About This Export
124
+
125
+ This file contains the complete context for the **${specName}** specification. It is designed to be used with AI coding assistants like Claude Code, Cursor, Codex, or any other tool that accepts Markdown context.
126
+
127
+ ### What's Included
128
+
129
+ - Requirements document
130
+ - Design document
131
+ - Task list
132
+ - Optional: Steering rules
133
+
134
+ ### How to Use
135
+
136
+ 1. **Copy this entire file** into your AI coding assistant
137
+ 2. **Reference specific sections** when working on tasks
138
+ 3. **Update task status** in the original tasks.md after completion
139
+
140
+ ---`;
141
+ }
142
+
143
+ /**
144
+ * 格式化章节
145
+ *
146
+ * @param {string} title - 章节标题
147
+ * @param {string} content - 章节内容
148
+ * @returns {string} 格式化后的章节
149
+ */
150
+ formatSection(title, content) {
151
+ return `## ${title}
152
+
153
+ ${content}`;
154
+ }
155
+
156
+ /**
157
+ * 读取 Spec 文件
158
+ *
159
+ * @param {string} specPath - Spec 目录路径
160
+ * @param {string} fileName - 文件名
161
+ * @returns {Promise<string|null>} 文件内容或 null
162
+ */
163
+ async readSpecFile(specPath, fileName) {
164
+ const filePath = path.join(specPath, fileName);
165
+
166
+ try {
167
+ const exists = await fs.pathExists(filePath);
168
+ if (!exists) {
169
+ return null;
170
+ }
171
+
172
+ return await fs.readFile(filePath, 'utf8');
173
+ } catch (error) {
174
+ return null;
175
+ }
176
+ }
177
+
178
+ /**
179
+ * 包含 Steering 规则
180
+ *
181
+ * @param {string} projectPath - 项目根目录路径
182
+ * @param {Array<string>} steeringFiles - Steering 文件列表
183
+ * @returns {Promise<string>} Steering 内容
184
+ */
185
+ async includeSteeringRules(projectPath, steeringFiles) {
186
+ const steeringPath = path.join(projectPath, '.kiro/steering');
187
+ const sections = ['## Steering Rules\n'];
188
+
189
+ for (const fileName of steeringFiles) {
190
+ const filePath = path.join(steeringPath, fileName);
191
+
192
+ try {
193
+ const exists = await fs.pathExists(filePath);
194
+ if (!exists) {
195
+ continue;
196
+ }
197
+
198
+ const content = await fs.readFile(filePath, 'utf8');
199
+ sections.push(`### ${fileName}\n\n${content}`);
200
+ } catch (error) {
201
+ // Skip files that can't be read
202
+ continue;
203
+ }
204
+ }
205
+
206
+ return sections.length > 1 ? sections.join('\n\n') : null;
207
+ }
208
+
209
+ /**
210
+ * 生成使用说明
211
+ *
212
+ * @returns {string} 使用说明
213
+ */
214
+ generateUsageInstructions() {
215
+ return `## 💡 Usage Instructions
216
+
217
+ ### For Claude Code / Cursor / Codex
218
+
219
+ 1. **Load this file** as context in your AI coding assistant
220
+ 2. **Reference specific tasks** when implementing features
221
+ 3. **Follow the design** outlined in the Design section
222
+ 4. **Update task status** in the original \`tasks.md\` after completion
223
+
224
+ ### Task Status Updates
225
+
226
+ After completing a task, update the original \`tasks.md\` file:
227
+
228
+ \`\`\`markdown
229
+ - [x] 1.1 Completed task
230
+ - [-] 1.2 In-progress task
231
+ - [ ] 1.3 Not started task
232
+ \`\`\`
233
+
234
+ ### Best Practices
235
+
236
+ - **Read Requirements first** to understand the problem
237
+ - **Review Design** to understand the solution approach
238
+ - **Follow Tasks** to implement incrementally
239
+ - **Test thoroughly** before marking tasks as complete
240
+ - **Document changes** in code comments
241
+
242
+ ### Getting Help
243
+
244
+ If you encounter issues:
245
+ 1. Review the Requirements for clarification
246
+ 2. Check the Design for architectural guidance
247
+ 3. Consult the original project documentation
248
+ 4. Ask the project maintainer for guidance
249
+
250
+ ---
251
+
252
+ **Generated by**: kiro-spec-engine
253
+ **Export Format**: Standalone Markdown
254
+ **Compatible with**: Claude Code, Cursor, Codex, and other AI coding assistants`;
255
+ }
256
+
257
+ /**
258
+ * 生成任务特定上下文
259
+ *
260
+ * @param {string} projectPath - 项目根目录路径
261
+ * @param {string} specName - Spec 名称
262
+ * @param {string} taskId - 任务 ID
263
+ * @returns {Promise<Object>} 任务上下文
264
+ */
265
+ async generateTaskContext(projectPath, specName, taskId) {
266
+ try {
267
+ const specPath = path.join(projectPath, '.kiro/specs', specName);
268
+
269
+ // 读取所有文件
270
+ const requirements = await this.readSpecFile(specPath, 'requirements.md');
271
+ const design = await this.readSpecFile(specPath, 'design.md');
272
+ const tasks = await this.readSpecFile(specPath, 'tasks.md');
273
+
274
+ if (!tasks) {
275
+ return {
276
+ success: false,
277
+ error: 'tasks.md not found'
278
+ };
279
+ }
280
+
281
+ // 提取任务信息
282
+ const taskInfo = this.extractTaskInfo(tasks, taskId);
283
+
284
+ if (!taskInfo) {
285
+ return {
286
+ success: false,
287
+ error: `Task not found: ${taskId}`
288
+ };
289
+ }
290
+
291
+ // 提取相关 Requirements
292
+ const relevantRequirements = this.extractRelevantRequirements(
293
+ requirements,
294
+ taskInfo
295
+ );
296
+
297
+ // 提取相关 Design
298
+ const relevantDesign = this.extractRelevantDesignSections(
299
+ design,
300
+ taskInfo
301
+ );
302
+
303
+ return {
304
+ success: true,
305
+ taskId,
306
+ taskInfo,
307
+ relevantRequirements,
308
+ relevantDesign
309
+ };
310
+ } catch (error) {
311
+ return {
312
+ success: false,
313
+ error: error.message
314
+ };
315
+ }
316
+ }
317
+
318
+ /**
319
+ * 提取任务信息
320
+ *
321
+ * @param {string} tasksContent - tasks.md 内容
322
+ * @param {string} taskId - 任务 ID
323
+ * @returns {Object|null} 任务信息
324
+ */
325
+ extractTaskInfo(tasksContent, taskId) {
326
+ const lines = tasksContent.split('\n');
327
+ const taskPattern = new RegExp(`^-\\s*\\[[\\s\\-x~]\\]\\*?\\s+${taskId}\\s+(.+)$`);
328
+
329
+ for (const line of lines) {
330
+ const match = line.match(taskPattern);
331
+ if (match) {
332
+ return {
333
+ id: taskId,
334
+ title: match[1].replace(/\[@.+\]$/, '').trim(),
335
+ fullLine: line
336
+ };
337
+ }
338
+ }
339
+
340
+ return null;
341
+ }
342
+
343
+ /**
344
+ * 提取相关 Requirements
345
+ *
346
+ * @param {string} requirements - Requirements 内容
347
+ * @param {Object} taskInfo - 任务信息
348
+ * @returns {string} 相关 Requirements
349
+ */
350
+ extractRelevantRequirements(requirements, taskInfo) {
351
+ if (!requirements) {
352
+ return 'No requirements document found.';
353
+ }
354
+
355
+ // 简单实现:返回所有 Requirements
356
+ // 可以根据任务描述中的关键词进行智能过滤
357
+ return requirements;
358
+ }
359
+
360
+ /**
361
+ * 提取相关 Design 章节
362
+ *
363
+ * @param {string} design - Design 内容
364
+ * @param {Object} taskInfo - 任务信息
365
+ * @returns {string} 相关 Design 章节
366
+ */
367
+ extractRelevantDesignSections(design, taskInfo) {
368
+ if (!design) {
369
+ return 'No design document found.';
370
+ }
371
+
372
+ // 简单实现:返回所有 Design
373
+ // 可以根据任务描述中的关键词进行智能过滤
374
+ return design;
375
+ }
376
+ }
377
+
378
+ module.exports = ContextExporter;