kspec 1.0.12 → 1.0.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/package.json +1 -1
- package/src/index.js +207 -45
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -17,7 +17,12 @@ const defaultConfig = {
|
|
|
17
17
|
|
|
18
18
|
function loadConfig() {
|
|
19
19
|
if (fs.existsSync(CONFIG_FILE)) {
|
|
20
|
-
|
|
20
|
+
try {
|
|
21
|
+
return { ...defaultConfig, ...JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')) };
|
|
22
|
+
} catch {
|
|
23
|
+
console.error('Warning: Invalid config.json, using defaults');
|
|
24
|
+
return defaultConfig;
|
|
25
|
+
}
|
|
21
26
|
}
|
|
22
27
|
return defaultConfig;
|
|
23
28
|
}
|
|
@@ -65,8 +70,9 @@ function slugify(text) {
|
|
|
65
70
|
}
|
|
66
71
|
|
|
67
72
|
function detectCli() {
|
|
68
|
-
|
|
69
|
-
try { execSync('
|
|
73
|
+
const opts = { stdio: 'ignore', timeout: 5000 };
|
|
74
|
+
try { execSync('kiro-cli --version', opts); return 'kiro-cli'; } catch {}
|
|
75
|
+
try { execSync('q --version', opts); return 'q'; } catch {}
|
|
70
76
|
return null;
|
|
71
77
|
}
|
|
72
78
|
|
|
@@ -100,10 +106,19 @@ async function confirm(question) {
|
|
|
100
106
|
}
|
|
101
107
|
|
|
102
108
|
function chat(message, agent) {
|
|
109
|
+
// Refresh context before each chat to ensure LLM has latest state
|
|
110
|
+
refreshContext();
|
|
111
|
+
|
|
103
112
|
const cli = requireCli();
|
|
104
113
|
const args = agent ? ['chat', '--agent', agent, message] : ['chat', message];
|
|
105
114
|
const child = spawn(cli, args, { stdio: 'inherit' });
|
|
106
|
-
return new Promise(resolve =>
|
|
115
|
+
return new Promise((resolve, reject) => {
|
|
116
|
+
child.on('error', err => {
|
|
117
|
+
console.error(`Failed to start ${cli}: ${err.message}`);
|
|
118
|
+
reject(err);
|
|
119
|
+
});
|
|
120
|
+
child.on('close', resolve);
|
|
121
|
+
});
|
|
107
122
|
}
|
|
108
123
|
|
|
109
124
|
// Spec management
|
|
@@ -155,13 +170,109 @@ function getOrSelectSpec(name) {
|
|
|
155
170
|
function getTaskStats(folder) {
|
|
156
171
|
const tasksFile = path.join(folder, 'tasks.md');
|
|
157
172
|
if (!fs.existsSync(tasksFile)) return null;
|
|
158
|
-
|
|
173
|
+
|
|
159
174
|
const content = fs.readFileSync(tasksFile, 'utf8');
|
|
160
|
-
|
|
161
|
-
const
|
|
175
|
+
// Match both [x] and [X] consistently for total and done counts
|
|
176
|
+
const total = (content.match(/^-\s*\[[ xX]\]/gm) || []).length;
|
|
177
|
+
const done = (content.match(/^-\s*\[[xX]\]/gm) || []).length;
|
|
162
178
|
return { total, done, remaining: total - done };
|
|
163
179
|
}
|
|
164
180
|
|
|
181
|
+
function getCurrentTask(folder) {
|
|
182
|
+
const tasksFile = path.join(folder, 'tasks.md');
|
|
183
|
+
if (!fs.existsSync(tasksFile)) return null;
|
|
184
|
+
|
|
185
|
+
const content = fs.readFileSync(tasksFile, 'utf8');
|
|
186
|
+
const lines = content.split('\n');
|
|
187
|
+
for (const line of lines) {
|
|
188
|
+
if (/^-\s*\[ \]/.test(line)) {
|
|
189
|
+
return line.replace(/^-\s*\[ \]\s*/, '').trim();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function refreshContext() {
|
|
196
|
+
const contextFile = path.join(KSPEC_DIR, 'CONTEXT.md');
|
|
197
|
+
const current = getCurrentSpec();
|
|
198
|
+
|
|
199
|
+
if (!current) {
|
|
200
|
+
// No current spec - create minimal context
|
|
201
|
+
const content = `# kspec Context
|
|
202
|
+
|
|
203
|
+
No active spec. Run: \`kspec spec "Feature Name"\`
|
|
204
|
+
`;
|
|
205
|
+
ensureDir(KSPEC_DIR);
|
|
206
|
+
fs.writeFileSync(contextFile, content);
|
|
207
|
+
return content;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const specName = path.basename(current);
|
|
211
|
+
const stats = getTaskStats(current);
|
|
212
|
+
const currentTask = getCurrentTask(current);
|
|
213
|
+
|
|
214
|
+
// Read spec-lite if exists
|
|
215
|
+
const specLiteFile = path.join(current, 'spec-lite.md');
|
|
216
|
+
let specLite = '';
|
|
217
|
+
if (fs.existsSync(specLiteFile)) {
|
|
218
|
+
specLite = fs.readFileSync(specLiteFile, 'utf8');
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Read memory if exists
|
|
222
|
+
const memoryFile = path.join(current, 'memory.md');
|
|
223
|
+
let memory = '';
|
|
224
|
+
if (fs.existsSync(memoryFile)) {
|
|
225
|
+
memory = fs.readFileSync(memoryFile, 'utf8');
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Build context
|
|
229
|
+
let content = `# kspec Context
|
|
230
|
+
> Auto-generated. Always read this first after context compression.
|
|
231
|
+
|
|
232
|
+
## Current Spec
|
|
233
|
+
**${specName}**
|
|
234
|
+
Path: \`${current}\`
|
|
235
|
+
|
|
236
|
+
`;
|
|
237
|
+
|
|
238
|
+
if (stats) {
|
|
239
|
+
content += `## Progress
|
|
240
|
+
- Tasks: ${stats.done}/${stats.total} completed
|
|
241
|
+
- Remaining: ${stats.remaining}
|
|
242
|
+
`;
|
|
243
|
+
if (currentTask) {
|
|
244
|
+
content += `- **Current Task**: ${currentTask}
|
|
245
|
+
`;
|
|
246
|
+
}
|
|
247
|
+
content += '\n';
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (specLite) {
|
|
251
|
+
content += `## Requirements Summary
|
|
252
|
+
${specLite}
|
|
253
|
+
|
|
254
|
+
`;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (memory) {
|
|
258
|
+
content += `## Decisions & Learnings
|
|
259
|
+
${memory}
|
|
260
|
+
|
|
261
|
+
`;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
content += `## Quick Commands
|
|
265
|
+
- \`kspec build\` - Continue building tasks
|
|
266
|
+
- \`kspec verify\` - Verify implementation
|
|
267
|
+
- \`kspec status\` - Show current status
|
|
268
|
+
- \`kspec context\` - Refresh this file
|
|
269
|
+
`;
|
|
270
|
+
|
|
271
|
+
ensureDir(KSPEC_DIR);
|
|
272
|
+
fs.writeFileSync(contextFile, content);
|
|
273
|
+
return content;
|
|
274
|
+
}
|
|
275
|
+
|
|
165
276
|
// Templates
|
|
166
277
|
const steeringTemplates = {
|
|
167
278
|
'product.md': `# Product Overview
|
|
@@ -208,10 +319,15 @@ const agentTemplates = {
|
|
|
208
319
|
tools: ['read', 'write'],
|
|
209
320
|
allowedTools: ['read', 'write'],
|
|
210
321
|
resources: [
|
|
322
|
+
'file://.kspec/CONTEXT.md',
|
|
211
323
|
'file://.kiro/steering/**/*.md',
|
|
212
324
|
'file://.kspec/**/*.md'
|
|
213
325
|
],
|
|
214
|
-
prompt: `You are the kspec analyser.
|
|
326
|
+
prompt: `You are the kspec analyser.
|
|
327
|
+
|
|
328
|
+
FIRST: Read .kspec/CONTEXT.md for current state and spec summary.
|
|
329
|
+
|
|
330
|
+
Your job:
|
|
215
331
|
1. Analyse the codebase structure, tech stack, patterns
|
|
216
332
|
2. Review .kiro/steering/ docs
|
|
217
333
|
3. Suggest updates to steering based on actual codebase
|
|
@@ -229,25 +345,31 @@ Output a clear analysis report. Propose specific steering doc updates.`,
|
|
|
229
345
|
tools: ['read', 'write'],
|
|
230
346
|
allowedTools: ['read', 'write'],
|
|
231
347
|
resources: [
|
|
348
|
+
'file://.kspec/CONTEXT.md',
|
|
232
349
|
'file://.kiro/steering/**/*.md',
|
|
233
350
|
'file://.kspec/**/*.md'
|
|
234
351
|
],
|
|
235
|
-
prompt: `You are the kspec specification writer.
|
|
352
|
+
prompt: `You are the kspec specification writer.
|
|
353
|
+
|
|
354
|
+
WORKFLOW (do this autonomously):
|
|
236
355
|
1. Read .kiro/steering/ for project context
|
|
237
|
-
2. Create
|
|
356
|
+
2. Create spec folder: .kspec/specs/YYYY-MM-DD-{feature-slug}/
|
|
357
|
+
- Use today's date and a short slug (2-4 words from feature name)
|
|
358
|
+
3. Create spec.md in that folder with:
|
|
238
359
|
- Problem/Context
|
|
239
360
|
- Requirements (functional + non-functional)
|
|
240
361
|
- Constraints
|
|
241
362
|
- High-level design
|
|
242
363
|
- Acceptance criteria
|
|
243
|
-
|
|
244
|
-
- Concise version
|
|
364
|
+
4. Create spec-lite.md (CRITICAL - under 500 words):
|
|
365
|
+
- Concise version for context retention after compression
|
|
245
366
|
- Key requirements only
|
|
246
|
-
|
|
367
|
+
5. Update .kspec/.current with the spec folder path
|
|
368
|
+
6. Update .kspec/CONTEXT.md with current state
|
|
247
369
|
|
|
248
|
-
|
|
370
|
+
After completion, suggest: "Switch to kspec-tasks agent to generate implementation tasks"`,
|
|
249
371
|
keyboardShortcut: 'ctrl+s',
|
|
250
|
-
welcomeMessage: 'Ready to create specification.'
|
|
372
|
+
welcomeMessage: 'Ready to create specification. Describe your feature.'
|
|
251
373
|
},
|
|
252
374
|
|
|
253
375
|
'kspec-tasks.json': {
|
|
@@ -257,21 +379,29 @@ Always create both files. spec-lite.md is critical for context retention.`,
|
|
|
257
379
|
tools: ['read', 'write'],
|
|
258
380
|
allowedTools: ['read', 'write'],
|
|
259
381
|
resources: [
|
|
382
|
+
'file://.kspec/CONTEXT.md',
|
|
260
383
|
'file://.kiro/steering/**/*.md',
|
|
261
384
|
'file://.kspec/**/*.md'
|
|
262
385
|
],
|
|
263
|
-
prompt: `You are the kspec task generator.
|
|
264
|
-
|
|
265
|
-
|
|
386
|
+
prompt: `You are the kspec task generator.
|
|
387
|
+
|
|
388
|
+
WORKFLOW:
|
|
389
|
+
1. Read .kspec/CONTEXT.md for current spec location
|
|
390
|
+
2. Read .kspec/.current to get spec folder path
|
|
391
|
+
3. Read spec.md and spec-lite.md from that folder
|
|
392
|
+
4. Generate tasks.md in the spec folder with:
|
|
266
393
|
- Checkbox format: "- [ ] Task description"
|
|
267
394
|
- TDD approach: test first, then implement
|
|
268
395
|
- Logical ordering (models → services → API → UI)
|
|
269
396
|
- Dependencies noted
|
|
270
397
|
- File paths where changes occur
|
|
398
|
+
5. Update .kspec/CONTEXT.md with task count
|
|
399
|
+
|
|
400
|
+
Tasks must be atomic and independently verifiable.
|
|
271
401
|
|
|
272
|
-
|
|
402
|
+
After completion, suggest: "Switch to kspec-build agent to start implementing tasks"`,
|
|
273
403
|
keyboardShortcut: 'ctrl+t',
|
|
274
|
-
welcomeMessage: '
|
|
404
|
+
welcomeMessage: 'Reading current spec and generating tasks...'
|
|
275
405
|
},
|
|
276
406
|
|
|
277
407
|
'kspec-build.json': {
|
|
@@ -281,24 +411,34 @@ Tasks must be atomic and independently verifiable.`,
|
|
|
281
411
|
tools: ['read', 'write', 'shell'],
|
|
282
412
|
allowedTools: ['read', 'write', 'shell'],
|
|
283
413
|
resources: [
|
|
414
|
+
'file://.kspec/CONTEXT.md',
|
|
284
415
|
'file://.kiro/steering/**/*.md',
|
|
285
416
|
'file://.kspec/**/*.md'
|
|
286
417
|
],
|
|
287
|
-
prompt: `You are the kspec builder.
|
|
288
|
-
|
|
289
|
-
|
|
418
|
+
prompt: `You are the kspec builder.
|
|
419
|
+
|
|
420
|
+
WORKFLOW:
|
|
421
|
+
1. Read .kspec/CONTEXT.md for current spec and task progress
|
|
422
|
+
2. Read .kspec/.current to get spec folder path
|
|
423
|
+
3. Read tasks.md from spec folder, find first uncompleted task (- [ ])
|
|
424
|
+
4. For each task:
|
|
290
425
|
a) Write test first (TDD)
|
|
291
426
|
b) Implement minimal code to pass
|
|
292
427
|
c) Run tests
|
|
293
428
|
d) Mark task complete: change "- [ ]" to "- [x]"
|
|
294
429
|
e) Update tasks.md file
|
|
295
|
-
|
|
430
|
+
f) Update .kspec/CONTEXT.md with new progress
|
|
431
|
+
5. Commit after each task with descriptive message
|
|
432
|
+
|
|
433
|
+
CRITICAL:
|
|
434
|
+
- Always update tasks.md after completing each task
|
|
435
|
+
- Update .kspec/CONTEXT.md with current task and progress
|
|
436
|
+
- NEVER delete .kiro or .kspec folders
|
|
437
|
+
- Use non-interactive flags for commands (--yes, -y)
|
|
296
438
|
|
|
297
|
-
|
|
298
|
-
NEVER delete .kiro or .kspec folders.
|
|
299
|
-
Use non-interactive flags for commands (--yes, -y).`,
|
|
439
|
+
When all tasks complete, suggest: "Switch to kspec-verify agent to verify implementation"`,
|
|
300
440
|
keyboardShortcut: 'ctrl+b',
|
|
301
|
-
welcomeMessage: '
|
|
441
|
+
welcomeMessage: 'Reading current task and building...'
|
|
302
442
|
},
|
|
303
443
|
|
|
304
444
|
'kspec-verify.json': {
|
|
@@ -308,10 +448,15 @@ Use non-interactive flags for commands (--yes, -y).`,
|
|
|
308
448
|
tools: ['read', 'shell'],
|
|
309
449
|
allowedTools: ['read', 'shell'],
|
|
310
450
|
resources: [
|
|
451
|
+
'file://.kspec/CONTEXT.md',
|
|
311
452
|
'file://.kiro/steering/**/*.md',
|
|
312
453
|
'file://.kspec/**/*.md'
|
|
313
454
|
],
|
|
314
|
-
prompt: `You are the kspec verifier.
|
|
455
|
+
prompt: `You are the kspec verifier.
|
|
456
|
+
|
|
457
|
+
FIRST: Read .kspec/CONTEXT.md for current spec and progress.
|
|
458
|
+
|
|
459
|
+
Based on what you're asked to verify:
|
|
315
460
|
|
|
316
461
|
VERIFY-SPEC:
|
|
317
462
|
- Check spec covers all requirements
|
|
@@ -343,10 +488,15 @@ Output a clear verification report with pass/fail status.`,
|
|
|
343
488
|
tools: ['read', 'shell'],
|
|
344
489
|
allowedTools: ['read', 'shell'],
|
|
345
490
|
resources: [
|
|
491
|
+
'file://.kspec/CONTEXT.md',
|
|
346
492
|
'file://.kiro/steering/**/*.md',
|
|
347
493
|
'file://.kspec/**/*.md'
|
|
348
494
|
],
|
|
349
|
-
prompt: `You are the kspec code reviewer.
|
|
495
|
+
prompt: `You are the kspec code reviewer.
|
|
496
|
+
|
|
497
|
+
FIRST: Read .kspec/CONTEXT.md for current spec context.
|
|
498
|
+
|
|
499
|
+
Your job:
|
|
350
500
|
1. Review code changes (git diff or specified files)
|
|
351
501
|
2. Check compliance with .kiro/steering/
|
|
352
502
|
3. Evaluate:
|
|
@@ -402,11 +552,13 @@ const commands = {
|
|
|
402
552
|
}
|
|
403
553
|
}
|
|
404
554
|
|
|
405
|
-
// Create agents
|
|
555
|
+
// Create agents (skip if already exist to preserve customizations)
|
|
406
556
|
for (const [file, content] of Object.entries(agentTemplates)) {
|
|
407
557
|
const p = path.join(AGENTS_DIR, file);
|
|
408
|
-
fs.
|
|
409
|
-
|
|
558
|
+
if (!fs.existsSync(p)) {
|
|
559
|
+
fs.writeFileSync(p, JSON.stringify(content, null, 2));
|
|
560
|
+
log(`Created ${p}`);
|
|
561
|
+
}
|
|
410
562
|
}
|
|
411
563
|
|
|
412
564
|
console.log('\n✅ kspec initialized!\n');
|
|
@@ -617,13 +769,13 @@ Output: APPROVE or REQUEST_CHANGES with specifics.`, 'kspec-review');
|
|
|
617
769
|
|
|
618
770
|
status() {
|
|
619
771
|
const current = getCurrentSpec();
|
|
620
|
-
|
|
772
|
+
|
|
621
773
|
console.log('\nkspec Status\n');
|
|
622
774
|
console.log(`CLI: ${detectCli() || '(not installed)'}`);
|
|
623
775
|
console.log(`Initialized: ${config.initialized ? 'yes' : 'no'}`);
|
|
624
776
|
console.log(`Date format: ${config.dateFormat || 'YYYY-MM-DD'}`);
|
|
625
777
|
console.log(`Auto-execute: ${config.autoExecute || 'ask'}`);
|
|
626
|
-
|
|
778
|
+
|
|
627
779
|
if (current) {
|
|
628
780
|
console.log(`\nCurrent spec: ${path.basename(current)}`);
|
|
629
781
|
const stats = getTaskStats(current);
|
|
@@ -643,6 +795,12 @@ Output: APPROVE or REQUEST_CHANGES with specifics.`, 'kspec-review');
|
|
|
643
795
|
console.log('');
|
|
644
796
|
},
|
|
645
797
|
|
|
798
|
+
context() {
|
|
799
|
+
const content = refreshContext();
|
|
800
|
+
console.log(content);
|
|
801
|
+
console.log(`Context saved to: .kspec/CONTEXT.md\n`);
|
|
802
|
+
},
|
|
803
|
+
|
|
646
804
|
agents() {
|
|
647
805
|
console.log(`
|
|
648
806
|
kspec Agents
|
|
@@ -664,7 +822,7 @@ Switch: /agent swap or use keyboard shortcuts
|
|
|
664
822
|
console.log(`
|
|
665
823
|
kspec - Spec-driven development for Kiro CLI
|
|
666
824
|
|
|
667
|
-
Workflow:
|
|
825
|
+
CLI Workflow (outside kiro-cli):
|
|
668
826
|
kspec init Interactive setup
|
|
669
827
|
kspec analyse Analyse codebase, update steering
|
|
670
828
|
kspec spec "Feature" Create specification
|
|
@@ -675,22 +833,26 @@ Workflow:
|
|
|
675
833
|
kspec verify Verify implementation
|
|
676
834
|
kspec done Complete spec, harvest memory
|
|
677
835
|
|
|
836
|
+
Inside kiro-cli (recommended):
|
|
837
|
+
/agent swap kspec-spec → Describe feature → creates spec
|
|
838
|
+
/agent swap kspec-tasks → Generates tasks from spec
|
|
839
|
+
/agent swap kspec-build → Builds tasks with TDD
|
|
840
|
+
/agent swap kspec-verify → Verifies implementation
|
|
841
|
+
|
|
842
|
+
Agents read .kspec/CONTEXT.md automatically for state.
|
|
843
|
+
|
|
678
844
|
Other:
|
|
845
|
+
kspec context Refresh/view context file
|
|
679
846
|
kspec review [target] Code review
|
|
680
847
|
kspec list List all specs
|
|
681
848
|
kspec status Current status
|
|
682
849
|
kspec agents List agents
|
|
683
850
|
kspec help Show this help
|
|
684
|
-
kspec --help, -h Show this help
|
|
685
|
-
kspec --version, -v Show version
|
|
686
851
|
|
|
687
852
|
Examples:
|
|
688
|
-
kspec init
|
|
689
|
-
kspec spec "User
|
|
690
|
-
kspec
|
|
691
|
-
kspec build
|
|
692
|
-
kspec verify
|
|
693
|
-
kspec done
|
|
853
|
+
kspec init # First time setup
|
|
854
|
+
kspec spec "User Auth" # CLI mode
|
|
855
|
+
kiro-cli --agent kspec-spec # Direct agent mode
|
|
694
856
|
`);
|
|
695
857
|
}
|
|
696
858
|
};
|
|
@@ -717,4 +879,4 @@ async function run(args) {
|
|
|
717
879
|
}
|
|
718
880
|
}
|
|
719
881
|
|
|
720
|
-
module.exports = { run, commands, loadConfig, detectCli, requireCli, agentTemplates };
|
|
882
|
+
module.exports = { run, commands, loadConfig, detectCli, requireCli, agentTemplates, getTaskStats, refreshContext, getCurrentTask };
|