spets 0.2.0 → 0.2.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.
|
@@ -12,6 +12,8 @@ import { join } from "path";
|
|
|
12
12
|
import matter from "gray-matter";
|
|
13
13
|
var KNOWLEDGE_DIR = "knowledge";
|
|
14
14
|
var GUIDE_FILE = "guide.md";
|
|
15
|
+
var MAX_SUMMARY_CHARS = 2e3;
|
|
16
|
+
var MAX_KNOWLEDGE_CHARS = 8e3;
|
|
15
17
|
function getKnowledgeDir(cwd = process.cwd()) {
|
|
16
18
|
return join(getSpetsDir(cwd), KNOWLEDGE_DIR);
|
|
17
19
|
}
|
|
@@ -58,10 +60,21 @@ function saveKnowledge(filename, content, source, cwd = process.cwd()) {
|
|
|
58
60
|
ensureKnowledgeDir(cwd);
|
|
59
61
|
const knowledgeDir = getKnowledgeDir(cwd);
|
|
60
62
|
const filePath = join(knowledgeDir, `${filename}.md`);
|
|
63
|
+
let createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
64
|
+
if (existsSync(filePath)) {
|
|
65
|
+
const existing = readFileSync(filePath, "utf-8");
|
|
66
|
+
const { data } = matter(existing);
|
|
67
|
+
if (data.createdAt) {
|
|
68
|
+
createdAt = data.createdAt;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
61
71
|
const frontmatter = {
|
|
62
72
|
source,
|
|
63
|
-
createdAt
|
|
73
|
+
createdAt
|
|
64
74
|
};
|
|
75
|
+
if (existsSync(filePath)) {
|
|
76
|
+
frontmatter.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
77
|
+
}
|
|
65
78
|
const fileContent = matter.stringify(content, frontmatter);
|
|
66
79
|
writeFileSync(filePath, fileContent);
|
|
67
80
|
}
|
|
@@ -75,21 +88,69 @@ function loadGuide(cwd = process.cwd()) {
|
|
|
75
88
|
const { content } = matter(fileContent);
|
|
76
89
|
return content.trim();
|
|
77
90
|
}
|
|
78
|
-
function
|
|
91
|
+
function knowledgePriority(filename) {
|
|
92
|
+
if (filename.startsWith("rule--")) return 0;
|
|
93
|
+
if (filename.startsWith("pattern--")) return 1;
|
|
94
|
+
if (filename.startsWith("pref--")) return 2;
|
|
95
|
+
return 3;
|
|
96
|
+
}
|
|
97
|
+
function buildKnowledgeSummarySection(cwd = process.cwd()) {
|
|
79
98
|
const files = listKnowledgeFiles(cwd);
|
|
80
99
|
if (files.length === 0) {
|
|
81
100
|
return "";
|
|
82
101
|
}
|
|
102
|
+
const sorted = [...files].sort((a, b) => knowledgePriority(a) - knowledgePriority(b));
|
|
103
|
+
const lines = [];
|
|
104
|
+
let charCount = 0;
|
|
105
|
+
let truncated = 0;
|
|
106
|
+
for (const filename of sorted) {
|
|
107
|
+
const entry = loadKnowledgeFile(filename, cwd);
|
|
108
|
+
const firstLine = entry?.content.split("\n")[0]?.trim() || "";
|
|
109
|
+
const line = `- ${filename}: ${firstLine}`;
|
|
110
|
+
if (charCount + line.length > MAX_SUMMARY_CHARS) {
|
|
111
|
+
truncated = sorted.length - lines.length;
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
lines.push(line);
|
|
115
|
+
charCount += line.length;
|
|
116
|
+
}
|
|
83
117
|
const parts = [];
|
|
84
|
-
parts.push("##
|
|
118
|
+
parts.push("## Knowledge Summary");
|
|
85
119
|
parts.push("");
|
|
86
|
-
parts.push("\
|
|
87
|
-
|
|
88
|
-
|
|
120
|
+
parts.push("\uC774 \uD504\uB85C\uC81D\uD2B8\uC5D0 \uC800\uC7A5\uB41C \uC9C0\uC2DD:");
|
|
121
|
+
parts.push("");
|
|
122
|
+
parts.push(...lines);
|
|
123
|
+
if (truncated > 0) {
|
|
124
|
+
parts.push(`- ... and ${truncated} more`);
|
|
89
125
|
}
|
|
90
126
|
parts.push("");
|
|
91
|
-
parts.
|
|
127
|
+
return parts.join("\n");
|
|
128
|
+
}
|
|
129
|
+
function buildBudgetedKnowledgeSection(entries, heading = "## Loaded Knowledge") {
|
|
130
|
+
if (entries.length === 0) {
|
|
131
|
+
return "";
|
|
132
|
+
}
|
|
133
|
+
const parts = [];
|
|
134
|
+
parts.push(heading);
|
|
92
135
|
parts.push("");
|
|
136
|
+
let charCount = 0;
|
|
137
|
+
for (const entry of entries) {
|
|
138
|
+
const section = `### ${entry.filename}
|
|
139
|
+
|
|
140
|
+
${entry.content}
|
|
141
|
+
`;
|
|
142
|
+
if (charCount + section.length > MAX_KNOWLEDGE_CHARS) {
|
|
143
|
+
const remaining = entries.length - parts.filter((p) => p.startsWith("### ")).length;
|
|
144
|
+
if (remaining > 0) {
|
|
145
|
+
parts.push(`
|
|
146
|
+
*... ${remaining} more entries truncated due to budget*
|
|
147
|
+
`);
|
|
148
|
+
}
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
parts.push(section);
|
|
152
|
+
charCount += section.length;
|
|
153
|
+
}
|
|
93
154
|
return parts.join("\n");
|
|
94
155
|
}
|
|
95
156
|
|
|
@@ -210,7 +271,8 @@ export {
|
|
|
210
271
|
loadKnowledgeFiles,
|
|
211
272
|
saveKnowledge,
|
|
212
273
|
loadGuide,
|
|
213
|
-
|
|
274
|
+
buildKnowledgeSummarySection,
|
|
275
|
+
buildBudgetedKnowledgeSection,
|
|
214
276
|
renderKnowledgeJSON,
|
|
215
277
|
runKnowledgeInteractive
|
|
216
278
|
};
|
package/dist/index.js
CHANGED
|
@@ -22,7 +22,8 @@ import {
|
|
|
22
22
|
runDocsInteractive
|
|
23
23
|
} from "./chunk-3JIHGW47.js";
|
|
24
24
|
import {
|
|
25
|
-
|
|
25
|
+
buildBudgetedKnowledgeSection,
|
|
26
|
+
buildKnowledgeSummarySection,
|
|
26
27
|
getKnowledgeDir,
|
|
27
28
|
listKnowledgeFiles,
|
|
28
29
|
loadGuide,
|
|
@@ -31,7 +32,7 @@ import {
|
|
|
31
32
|
renderKnowledgeJSON,
|
|
32
33
|
runKnowledgeInteractive,
|
|
33
34
|
saveKnowledge
|
|
34
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-OIFVTELS.js";
|
|
35
36
|
import {
|
|
36
37
|
clearConfigCache,
|
|
37
38
|
getConfigPath,
|
|
@@ -272,62 +273,37 @@ async function listPlugins() {
|
|
|
272
273
|
function getClaudeSkillContent() {
|
|
273
274
|
return `# Spets Executor
|
|
274
275
|
|
|
275
|
-
You execute spets
|
|
276
|
+
You execute spets workflow commands. Follow orchestrator instructions exactly.
|
|
276
277
|
|
|
277
278
|
## Startup
|
|
278
279
|
|
|
279
280
|
IF \`$ARGUMENTS\` starts with "resume":
|
|
280
|
-
|
|
281
|
+
RUN \`npx spets orchestrate resume\`
|
|
282
|
+
ELSE IF \`$ARGUMENTS\` starts with "list":
|
|
283
|
+
RUN \`npx spets orchestrate list\`
|
|
281
284
|
ELSE:
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
Then GOTO **Loop**.
|
|
285
|
+
RUN \`npx spets orchestrate init "$ARGUMENTS"\`
|
|
285
286
|
|
|
286
287
|
## Loop
|
|
287
288
|
|
|
288
|
-
1.
|
|
289
|
-
2.
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
- EXECUTE what \`prompt\` says
|
|
293
|
-
- RUN \`onComplete\` with your output as JSON argument
|
|
294
|
-
- GOTO Loop
|
|
295
|
-
|
|
296
|
-
### type="checkpoint", checkpoint="clarify"
|
|
297
|
-
- ASK user each decision in \`decisions[]\` using AskUserQuestion
|
|
298
|
-
- Format each decision as a question with its options
|
|
299
|
-
- RUN \`onComplete\` with \`[{decisionId, selectedOptionId}, ...]\`
|
|
300
|
-
- GOTO Loop
|
|
301
|
-
|
|
302
|
-
### type="checkpoint", checkpoint="approve"
|
|
303
|
-
- READ \`specPath\`, summarize key points to user
|
|
304
|
-
- ASK user using AskUserQuestion with options: Approve / Revise / Reject / Stop
|
|
305
|
-
- RUN matching \`onComplete\` based on user's choice
|
|
306
|
-
- GOTO Loop
|
|
307
|
-
|
|
308
|
-
### type="checkpoint", checkpoint="knowledge"
|
|
309
|
-
- Show \`suggestedKnowledge[]\` to user
|
|
310
|
-
- ASK user if they want to save, modify, or skip
|
|
311
|
-
- If save: RUN \`onComplete\` with entries JSON
|
|
312
|
-
- If skip: RUN \`onSkip\`
|
|
313
|
-
- GOTO Loop
|
|
289
|
+
1. Parse the JSON response
|
|
290
|
+
2. Read the \`instructions\` field
|
|
291
|
+
3. Follow the instructions exactly
|
|
292
|
+
4. Repeat until the response says to stop
|
|
314
293
|
|
|
315
|
-
|
|
316
|
-
- Show \`tasks[]\` to user with taskId, description, status, currentStep
|
|
317
|
-
- ASK user which task to resume
|
|
318
|
-
- RUN \`npx spets orchestrate resume <selectedTaskId>\`
|
|
319
|
-
- GOTO Loop
|
|
294
|
+
## Rules
|
|
320
295
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
296
|
+
- NEVER skip or modify orchestrator commands
|
|
297
|
+
- NEVER improvise steps \u2014 only do what instructions say
|
|
298
|
+
- Always pass JSON output as a single-quoted string argument
|
|
299
|
+
- Minify JSON when passing as command arguments
|
|
324
300
|
|
|
325
301
|
## Forbidden
|
|
326
302
|
|
|
327
303
|
EnterPlanMode, TaskCreate, TaskUpdate
|
|
328
304
|
|
|
329
305
|
$ARGUMENTS
|
|
330
|
-
description: Task description for the workflow (or "resume" to continue
|
|
306
|
+
description: Task description for the workflow (or "resume" to list/continue previous workflows)
|
|
331
307
|
`;
|
|
332
308
|
}
|
|
333
309
|
function getCodexSkillContent() {
|
|
@@ -338,65 +314,37 @@ description: SDD workflow executor - orchestrator-controlled spec-driven develop
|
|
|
338
314
|
|
|
339
315
|
# Spets Executor
|
|
340
316
|
|
|
341
|
-
You execute spets
|
|
317
|
+
You execute spets workflow commands. Follow orchestrator instructions exactly.
|
|
342
318
|
|
|
343
319
|
## Startup
|
|
344
320
|
|
|
345
321
|
IF \`$ARGUMENTS\` starts with "resume":
|
|
346
|
-
|
|
322
|
+
RUN \`npx spets orchestrate resume\`
|
|
323
|
+
ELSE IF \`$ARGUMENTS\` starts with "list":
|
|
324
|
+
RUN \`npx spets orchestrate list\`
|
|
347
325
|
ELSE:
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
Then GOTO **Loop**.
|
|
326
|
+
RUN \`npx spets orchestrate init "$ARGUMENTS"\`
|
|
351
327
|
|
|
352
328
|
## Loop
|
|
353
329
|
|
|
354
|
-
1.
|
|
355
|
-
2.
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
- EXECUTE what \`prompt\` says
|
|
359
|
-
- RUN \`onComplete\` with your output as minified JSON argument
|
|
360
|
-
- GOTO Loop
|
|
361
|
-
|
|
362
|
-
### type="checkpoint", checkpoint="clarify"
|
|
363
|
-
- FORMAT decisions as table for user:
|
|
364
|
-
| # | Decision | Context | Options |
|
|
365
|
-
|---|----------|---------|---------|
|
|
366
|
-
| d1 | ... | ... | 1. ... 2. ... |
|
|
367
|
-
- ASK user to pick an option for each decision
|
|
368
|
-
- RUN \`onComplete\` with \`[{decisionId, selectedOptionId}, ...]\`
|
|
369
|
-
- GOTO Loop
|
|
370
|
-
|
|
371
|
-
### type="checkpoint", checkpoint="approve"
|
|
372
|
-
- READ \`specPath\`, summarize key points to user
|
|
373
|
-
- ASK user with options: Approve / Revise / Reject / Stop
|
|
374
|
-
- RUN matching \`onComplete\` based on user's choice
|
|
375
|
-
- GOTO Loop
|
|
376
|
-
|
|
377
|
-
### type="checkpoint", checkpoint="knowledge"
|
|
378
|
-
- Show \`suggestedKnowledge[]\` to user
|
|
379
|
-
- ASK user if they want to save, modify, or skip
|
|
380
|
-
- If save: RUN \`onComplete\` with entries JSON
|
|
381
|
-
- If skip: RUN \`onSkip\`
|
|
382
|
-
- GOTO Loop
|
|
330
|
+
1. Parse the JSON response
|
|
331
|
+
2. Read the \`instructions\` field
|
|
332
|
+
3. Follow the instructions exactly
|
|
333
|
+
4. Repeat until the response says to stop
|
|
383
334
|
|
|
384
|
-
|
|
385
|
-
- Show \`tasks[]\` to user with taskId, description, status, currentStep
|
|
386
|
-
- ASK user which task to resume
|
|
387
|
-
- RUN \`npx spets orchestrate resume <selectedTaskId>\`
|
|
388
|
-
- GOTO Loop
|
|
335
|
+
## Rules
|
|
389
336
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
337
|
+
- NEVER skip or modify orchestrator commands
|
|
338
|
+
- NEVER improvise steps \u2014 only do what instructions say
|
|
339
|
+
- Always pass JSON output as a single-quoted string argument
|
|
340
|
+
- Minify JSON when passing as command arguments
|
|
393
341
|
|
|
394
342
|
## Forbidden
|
|
395
343
|
|
|
396
344
|
Planning mode, task tracking tools
|
|
397
345
|
|
|
398
346
|
$ARGUMENTS
|
|
399
|
-
description: Task description for the workflow (or "resume" to continue
|
|
347
|
+
description: Task description for the workflow (or "resume" to list/continue previous workflows)
|
|
400
348
|
`;
|
|
401
349
|
}
|
|
402
350
|
function getGeminiSkillContent() {
|
|
@@ -407,61 +355,37 @@ description: SDD workflow executor - orchestrator-controlled spec-driven develop
|
|
|
407
355
|
|
|
408
356
|
# Spets Executor
|
|
409
357
|
|
|
410
|
-
You execute spets
|
|
358
|
+
You execute spets workflow commands. Follow orchestrator instructions exactly.
|
|
411
359
|
|
|
412
360
|
## Startup
|
|
413
361
|
|
|
414
362
|
IF \`$ARGUMENTS\` starts with "resume":
|
|
415
|
-
|
|
363
|
+
RUN \`npx spets orchestrate resume\`
|
|
364
|
+
ELSE IF \`$ARGUMENTS\` starts with "list":
|
|
365
|
+
RUN \`npx spets orchestrate list\`
|
|
416
366
|
ELSE:
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
Then GOTO **Loop**.
|
|
367
|
+
RUN \`npx spets orchestrate init "$ARGUMENTS"\`
|
|
420
368
|
|
|
421
369
|
## Loop
|
|
422
370
|
|
|
423
|
-
1.
|
|
424
|
-
2.
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
- EXECUTE what \`prompt\` says
|
|
428
|
-
- RUN \`onComplete\` with your output as JSON argument
|
|
429
|
-
- GOTO Loop
|
|
430
|
-
|
|
431
|
-
### type="checkpoint", checkpoint="clarify"
|
|
432
|
-
- ASK user each decision in \`decisions[]\`
|
|
433
|
-
- RUN \`onComplete\` with \`[{decisionId, selectedOptionId}, ...]\`
|
|
434
|
-
- GOTO Loop
|
|
435
|
-
|
|
436
|
-
### type="checkpoint", checkpoint="approve"
|
|
437
|
-
- READ \`specPath\`, summarize key points to user
|
|
438
|
-
- ASK user with options: Approve / Revise / Reject / Stop
|
|
439
|
-
- RUN matching \`onComplete\` based on user's choice
|
|
440
|
-
- GOTO Loop
|
|
441
|
-
|
|
442
|
-
### type="checkpoint", checkpoint="knowledge"
|
|
443
|
-
- Show \`suggestedKnowledge[]\` to user
|
|
444
|
-
- ASK user if they want to save, modify, or skip
|
|
445
|
-
- If save: RUN \`onComplete\` with entries JSON
|
|
446
|
-
- If skip: RUN \`onSkip\`
|
|
447
|
-
- GOTO Loop
|
|
371
|
+
1. Parse the JSON response
|
|
372
|
+
2. Read the \`instructions\` field
|
|
373
|
+
3. Follow the instructions exactly
|
|
374
|
+
4. Repeat until the response says to stop
|
|
448
375
|
|
|
449
|
-
|
|
450
|
-
- Show \`tasks[]\` to user with taskId, description, status, currentStep
|
|
451
|
-
- ASK user which task to resume
|
|
452
|
-
- RUN \`npx spets orchestrate resume <selectedTaskId>\`
|
|
453
|
-
- GOTO Loop
|
|
376
|
+
## Rules
|
|
454
377
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
378
|
+
- NEVER skip or modify orchestrator commands
|
|
379
|
+
- NEVER improvise steps \u2014 only do what instructions say
|
|
380
|
+
- Always pass JSON output as a single-quoted string argument
|
|
381
|
+
- Minify JSON when passing as command arguments
|
|
458
382
|
|
|
459
383
|
## Forbidden
|
|
460
384
|
|
|
461
385
|
Planning mode, task tracking tools
|
|
462
386
|
|
|
463
387
|
$ARGUMENTS
|
|
464
|
-
description: Task description for the workflow (or "resume" to continue
|
|
388
|
+
description: Task description for the workflow (or "resume" to list/continue previous workflows)
|
|
465
389
|
`;
|
|
466
390
|
}
|
|
467
391
|
|
|
@@ -503,19 +427,26 @@ async function initCommand(options) {
|
|
|
503
427
|
const hookTemplate = join2(__dirname, "..", "templates", "hooks", "cleanup-branch.sh");
|
|
504
428
|
if (existsSync2(hookTemplate)) {
|
|
505
429
|
const hookDest = join2(spetsDir, "hooks", "cleanup-branch.sh");
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
430
|
+
if (!existsSync2(hookDest)) {
|
|
431
|
+
cpSync(hookTemplate, hookDest);
|
|
432
|
+
try {
|
|
433
|
+
execSync(`chmod +x "${hookDest}"`);
|
|
434
|
+
} catch {
|
|
435
|
+
}
|
|
510
436
|
}
|
|
511
437
|
}
|
|
512
438
|
const knowledgeGuideTemplate = join2(__dirname, "..", "templates", "knowledge", "guide.md");
|
|
513
439
|
if (existsSync2(knowledgeGuideTemplate)) {
|
|
514
440
|
const guideDest = join2(spetsDir, "knowledge", "guide.md");
|
|
515
|
-
|
|
441
|
+
if (!existsSync2(guideDest)) {
|
|
442
|
+
cpSync(knowledgeGuideTemplate, guideDest);
|
|
443
|
+
}
|
|
516
444
|
}
|
|
517
445
|
const githubInfo = getGitHubInfoFromRemote();
|
|
518
|
-
|
|
446
|
+
const configPath = join2(spetsDir, "config.yml");
|
|
447
|
+
if (!existsSync2(configPath)) {
|
|
448
|
+
writeFileSync2(configPath, getDefaultConfig(githubInfo));
|
|
449
|
+
}
|
|
519
450
|
createDefaultSteps(spetsDir);
|
|
520
451
|
createClaudeCommand(cwd);
|
|
521
452
|
printEnhancedInitOutput(options);
|
|
@@ -739,20 +670,23 @@ async function runInteractiveSetup(cwd, spetsDir, options) {
|
|
|
739
670
|
const hookTemplate = join2(__dirname, "..", "templates", "hooks", "cleanup-branch.sh");
|
|
740
671
|
if (existsSync2(hookTemplate)) {
|
|
741
672
|
const hookDest = join2(spetsDir, "hooks", "cleanup-branch.sh");
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
673
|
+
if (!existsSync2(hookDest)) {
|
|
674
|
+
cpSync(hookTemplate, hookDest);
|
|
675
|
+
try {
|
|
676
|
+
execSync(`chmod +x "${hookDest}"`);
|
|
677
|
+
} catch {
|
|
678
|
+
}
|
|
746
679
|
}
|
|
747
680
|
}
|
|
748
681
|
const knowledgeGuideTemplate = join2(__dirname, "..", "templates", "knowledge", "guide.md");
|
|
749
|
-
|
|
750
|
-
|
|
682
|
+
const guideDest = join2(spetsDir, "knowledge", "guide.md");
|
|
683
|
+
if (existsSync2(knowledgeGuideTemplate) && !existsSync2(guideDest)) {
|
|
684
|
+
cpSync(knowledgeGuideTemplate, guideDest);
|
|
685
|
+
}
|
|
686
|
+
const configPath = join2(spetsDir, "config.yml");
|
|
687
|
+
if (!existsSync2(configPath)) {
|
|
688
|
+
writeFileSync2(configPath, getDefaultConfig(githubInfo, { agent, githubEnabled }));
|
|
751
689
|
}
|
|
752
|
-
writeFileSync2(
|
|
753
|
-
join2(spetsDir, "config.yml"),
|
|
754
|
-
getDefaultConfig(githubInfo, { agent, githubEnabled })
|
|
755
|
-
);
|
|
756
690
|
createDefaultSteps(spetsDir);
|
|
757
691
|
createClaudeCommand(cwd);
|
|
758
692
|
if (githubEnabled && githubInfo) {
|
|
@@ -764,10 +698,16 @@ async function runInteractiveSetup(cwd, spetsDir, options) {
|
|
|
764
698
|
function createDefaultSteps(spetsDir) {
|
|
765
699
|
const planDir = join2(spetsDir, "steps", "01-plan");
|
|
766
700
|
mkdirSync2(planDir, { recursive: true });
|
|
767
|
-
|
|
701
|
+
const planTemplatePath = join2(planDir, "template.md");
|
|
702
|
+
if (!existsSync2(planTemplatePath)) {
|
|
703
|
+
writeFileSync2(planTemplatePath, getPlanTemplate());
|
|
704
|
+
}
|
|
768
705
|
const implementDir = join2(spetsDir, "steps", "02-implement");
|
|
769
706
|
mkdirSync2(implementDir, { recursive: true });
|
|
770
|
-
|
|
707
|
+
const implementTemplatePath = join2(implementDir, "template.md");
|
|
708
|
+
if (!existsSync2(implementTemplatePath)) {
|
|
709
|
+
writeFileSync2(implementTemplatePath, getImplementTemplate());
|
|
710
|
+
}
|
|
771
711
|
}
|
|
772
712
|
function getPlanTemplate() {
|
|
773
713
|
const fullTemplate = readFileSync(join2(__dirname, "..", "templates", "steps", "01-plan", "template.md"), "utf-8");
|
|
@@ -1045,7 +985,7 @@ function buildExplorePrompt(params) {
|
|
|
1045
985
|
parts.push("");
|
|
1046
986
|
const config = loadConfig(cwd);
|
|
1047
987
|
if (config.knowledge?.inject !== false) {
|
|
1048
|
-
const knowledgeSection =
|
|
988
|
+
const knowledgeSection = buildKnowledgeSummarySection(cwd);
|
|
1049
989
|
if (knowledgeSection) {
|
|
1050
990
|
parts.push(knowledgeSection);
|
|
1051
991
|
}
|
|
@@ -1125,6 +1065,7 @@ function buildExploreTeamSection() {
|
|
|
1125
1065
|
|
|
1126
1066
|
// src/core/prompts/clarify.ts
|
|
1127
1067
|
function buildClarifyPrompt(params) {
|
|
1068
|
+
const cwd = params.cwd || process.cwd();
|
|
1128
1069
|
const parts = [];
|
|
1129
1070
|
parts.push("# Clarify Phase");
|
|
1130
1071
|
parts.push("");
|
|
@@ -1141,6 +1082,13 @@ function buildClarifyPrompt(params) {
|
|
|
1141
1082
|
parts.push("");
|
|
1142
1083
|
parts.push(params.gatheredContext);
|
|
1143
1084
|
parts.push("");
|
|
1085
|
+
const config = loadConfig(cwd);
|
|
1086
|
+
if (config.knowledge?.inject !== false) {
|
|
1087
|
+
const knowledgeSection = buildKnowledgeSummarySection(cwd);
|
|
1088
|
+
if (knowledgeSection) {
|
|
1089
|
+
parts.push(knowledgeSection);
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1144
1092
|
if (params.loadedKnowledge && params.loadedKnowledge.length > 0) {
|
|
1145
1093
|
parts.push("## Requested Knowledge");
|
|
1146
1094
|
parts.push("");
|
|
@@ -1408,6 +1356,12 @@ function buildExecutePrompt(params) {
|
|
|
1408
1356
|
}
|
|
1409
1357
|
parts.push("");
|
|
1410
1358
|
}
|
|
1359
|
+
if (config.knowledge?.inject !== false) {
|
|
1360
|
+
const knowledgeSection = buildKnowledgeSummarySection(cwd);
|
|
1361
|
+
if (knowledgeSection) {
|
|
1362
|
+
parts.push(knowledgeSection);
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1411
1365
|
if (params.loadedKnowledge && params.loadedKnowledge.length > 0) {
|
|
1412
1366
|
parts.push("### Referenced Knowledge");
|
|
1413
1367
|
parts.push("");
|
|
@@ -1518,6 +1472,20 @@ function buildVerifyPrompt(params) {
|
|
|
1518
1472
|
parts.push(template);
|
|
1519
1473
|
parts.push("");
|
|
1520
1474
|
}
|
|
1475
|
+
const config = loadConfig(cwd);
|
|
1476
|
+
if (config.knowledge?.inject !== false) {
|
|
1477
|
+
const knowledgeSection = buildKnowledgeSummarySection(cwd);
|
|
1478
|
+
if (knowledgeSection) {
|
|
1479
|
+
parts.push(knowledgeSection);
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
if (params.loadedKnowledge && params.loadedKnowledge.length > 0) {
|
|
1483
|
+
const knowledgeContent = buildBudgetedKnowledgeSection(params.loadedKnowledge);
|
|
1484
|
+
if (knowledgeContent) {
|
|
1485
|
+
parts.push(knowledgeContent);
|
|
1486
|
+
parts.push("");
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1521
1489
|
parts.push("## Verification Criteria");
|
|
1522
1490
|
parts.push("");
|
|
1523
1491
|
parts.push("1. **Accuracy** (0-100)");
|
|
@@ -1542,7 +1510,6 @@ function buildVerifyPrompt(params) {
|
|
|
1542
1510
|
parts.push("");
|
|
1543
1511
|
parts.push("If it fails, the output will be automatically revised (up to 3 attempts).");
|
|
1544
1512
|
parts.push("");
|
|
1545
|
-
const config = loadConfig(cwd);
|
|
1546
1513
|
if (config.team?.enabled) {
|
|
1547
1514
|
parts.push(buildVerifyTeamSection());
|
|
1548
1515
|
}
|
|
@@ -1663,6 +1630,20 @@ function buildKnowledgeExtractPrompt(params) {
|
|
|
1663
1630
|
parts.push("");
|
|
1664
1631
|
}
|
|
1665
1632
|
}
|
|
1633
|
+
const cwd = params.cwd || process.cwd();
|
|
1634
|
+
const existingFiles = listKnowledgeFiles(cwd);
|
|
1635
|
+
if (existingFiles.length > 0) {
|
|
1636
|
+
parts.push("## Existing Knowledge Entries");
|
|
1637
|
+
parts.push("");
|
|
1638
|
+
parts.push("\uB2E4\uC74C \uC9C0\uC2DD\uC774 \uC774\uBBF8 \uC800\uC7A5\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4. \uACB9\uCE58\uB294 \uB0B4\uC6A9\uC740 update, \uC0C8\uB85C\uC6B4 \uAC83\uB9CC create \uD558\uC138\uC694:");
|
|
1639
|
+
parts.push("");
|
|
1640
|
+
for (const filename of existingFiles) {
|
|
1641
|
+
const entry = loadKnowledgeFile(filename, cwd);
|
|
1642
|
+
const firstLine = entry?.content.split("\n")[0]?.trim() || "";
|
|
1643
|
+
parts.push(`- **${filename}**: ${firstLine}`);
|
|
1644
|
+
}
|
|
1645
|
+
parts.push("");
|
|
1646
|
+
}
|
|
1666
1647
|
parts.push("## Your Task");
|
|
1667
1648
|
parts.push("");
|
|
1668
1649
|
parts.push("Extract knowledge that would be useful for future workflows:");
|
|
@@ -1678,6 +1659,10 @@ function buildKnowledgeExtractPrompt(params) {
|
|
|
1678
1659
|
parts.push("- One-time decisions");
|
|
1679
1660
|
parts.push("- Temporary workarounds");
|
|
1680
1661
|
parts.push("");
|
|
1662
|
+
parts.push("**Update or Create:**");
|
|
1663
|
+
parts.push('- If an existing entry covers the same topic, use `"action": "update"` with the same filename');
|
|
1664
|
+
parts.push('- Only use `"action": "create"` for genuinely new knowledge');
|
|
1665
|
+
parts.push("");
|
|
1681
1666
|
parts.push("## Output Format");
|
|
1682
1667
|
parts.push("");
|
|
1683
1668
|
parts.push("Output a JSON object with this structure:");
|
|
@@ -1688,7 +1673,8 @@ function buildKnowledgeExtractPrompt(params) {
|
|
|
1688
1673
|
parts.push(" {");
|
|
1689
1674
|
parts.push(' "filename": "pattern--error-handling",');
|
|
1690
1675
|
parts.push(' "content": "The knowledge content in markdown format...",');
|
|
1691
|
-
parts.push(' "reason": "Why this is worth saving"');
|
|
1676
|
+
parts.push(' "reason": "Why this is worth saving",');
|
|
1677
|
+
parts.push(' "action": "create"');
|
|
1692
1678
|
parts.push(" }");
|
|
1693
1679
|
parts.push(" ]");
|
|
1694
1680
|
parts.push("}");
|
|
@@ -1706,6 +1692,36 @@ function buildKnowledgeExtractPrompt(params) {
|
|
|
1706
1692
|
return parts.join("\n");
|
|
1707
1693
|
}
|
|
1708
1694
|
|
|
1695
|
+
// src/orchestrator/instructions.ts
|
|
1696
|
+
function phaseWithJsonOutput(onComplete) {
|
|
1697
|
+
return `Execute the prompt. Then run:
|
|
1698
|
+
${onComplete} '<your_json_output>'`;
|
|
1699
|
+
}
|
|
1700
|
+
function phaseExecute(outputFile, onComplete) {
|
|
1701
|
+
return `Execute the prompt \u2014 write the document to ${outputFile}. Then run:
|
|
1702
|
+
${onComplete}`;
|
|
1703
|
+
}
|
|
1704
|
+
function checkpointClarify(onComplete) {
|
|
1705
|
+
return [
|
|
1706
|
+
`Present each decision to the user with its options. Collect their choices. Then run:`,
|
|
1707
|
+
` ${onComplete} '<answers_json>'`,
|
|
1708
|
+
`Answer format: [{decisionId, selectedOptionId, customInput?}, ...]`
|
|
1709
|
+
].join("\n");
|
|
1710
|
+
}
|
|
1711
|
+
function checkpointApprove(specPath, cmds) {
|
|
1712
|
+
return [
|
|
1713
|
+
`Read the document at ${specPath}. Summarize key points to the user. Ask: Approve / Revise / Reject / Stop. Then run the matching command:`,
|
|
1714
|
+
` approve: ${cmds.approve}`,
|
|
1715
|
+
` revise: ${cmds.revise}`,
|
|
1716
|
+
` reject: ${cmds.reject}`,
|
|
1717
|
+
` stop: ${cmds.stop}`
|
|
1718
|
+
].join("\n");
|
|
1719
|
+
}
|
|
1720
|
+
var PRINT_MESSAGE_AND_STOP = "Print the message. Stop.";
|
|
1721
|
+
var PRINT_ERROR_AND_STOP = "Print the error. Stop.";
|
|
1722
|
+
var LIST_TASKS = "Show tasks to user. Ask which to resume. Run:\n npx spets orchestrate resume <selectedTaskId>";
|
|
1723
|
+
var LIST_EMPTY = "No resumable tasks found. Show this to the user. Stop.";
|
|
1724
|
+
|
|
1709
1725
|
// src/orchestrator/responses.ts
|
|
1710
1726
|
function buildPhaseExploreResponse(cwd, state) {
|
|
1711
1727
|
const steps = getSteps(cwd);
|
|
@@ -1727,6 +1743,7 @@ function buildPhaseExploreResponse(cwd, state) {
|
|
|
1727
1743
|
previousOutput,
|
|
1728
1744
|
cwd
|
|
1729
1745
|
});
|
|
1746
|
+
const onComplete = `npx spets orchestrate explore-done ${state.taskId}`;
|
|
1730
1747
|
return {
|
|
1731
1748
|
type: "phase",
|
|
1732
1749
|
phase: "explore",
|
|
@@ -1739,7 +1756,8 @@ function buildPhaseExploreResponse(cwd, state) {
|
|
|
1739
1756
|
context: {
|
|
1740
1757
|
previousOutput
|
|
1741
1758
|
},
|
|
1742
|
-
onComplete
|
|
1759
|
+
onComplete,
|
|
1760
|
+
instructions: phaseWithJsonOutput(onComplete)
|
|
1743
1761
|
};
|
|
1744
1762
|
}
|
|
1745
1763
|
function buildPhaseClarifyResponse(cwd, state) {
|
|
@@ -1754,6 +1772,7 @@ function buildPhaseClarifyResponse(cwd, state) {
|
|
|
1754
1772
|
// Legacy support
|
|
1755
1773
|
cwd
|
|
1756
1774
|
});
|
|
1775
|
+
const onComplete = `npx spets orchestrate clarify-done ${state.taskId}`;
|
|
1757
1776
|
return {
|
|
1758
1777
|
type: "phase",
|
|
1759
1778
|
phase: "clarify",
|
|
@@ -1765,7 +1784,8 @@ function buildPhaseClarifyResponse(cwd, state) {
|
|
|
1765
1784
|
previousDecisions: state.decisionHistory,
|
|
1766
1785
|
previousQA: state.qaHistory,
|
|
1767
1786
|
// Legacy support
|
|
1768
|
-
onComplete
|
|
1787
|
+
onComplete,
|
|
1788
|
+
instructions: phaseWithJsonOutput(onComplete)
|
|
1769
1789
|
};
|
|
1770
1790
|
}
|
|
1771
1791
|
function buildPhaseExecuteResponse(cwd, state) {
|
|
@@ -1808,6 +1828,8 @@ ${issues}`;
|
|
|
1808
1828
|
verifyFeedback,
|
|
1809
1829
|
cwd
|
|
1810
1830
|
});
|
|
1831
|
+
const onComplete = `npx spets orchestrate execute-done ${state.taskId}`;
|
|
1832
|
+
const outputFile = join9(outputPath, state.taskId, `${state.currentStep}.md`);
|
|
1811
1833
|
return {
|
|
1812
1834
|
type: "phase",
|
|
1813
1835
|
phase: "execute",
|
|
@@ -1822,11 +1844,12 @@ ${issues}`;
|
|
|
1822
1844
|
context: {
|
|
1823
1845
|
template: hasTemplate ? templatePath : void 0,
|
|
1824
1846
|
previousOutput,
|
|
1825
|
-
output:
|
|
1847
|
+
output: outputFile,
|
|
1826
1848
|
revisionFeedback: state.revisionFeedback,
|
|
1827
1849
|
verifyFeedback
|
|
1828
1850
|
},
|
|
1829
|
-
onComplete
|
|
1851
|
+
onComplete,
|
|
1852
|
+
instructions: phaseExecute(outputFile, onComplete)
|
|
1830
1853
|
};
|
|
1831
1854
|
}
|
|
1832
1855
|
function buildPhaseVerifyResponse(cwd, state) {
|
|
@@ -1842,8 +1865,10 @@ function buildPhaseVerifyResponse(cwd, state) {
|
|
|
1842
1865
|
totalSteps: state.totalSteps,
|
|
1843
1866
|
documentPath,
|
|
1844
1867
|
verifyAttempts: state.verifyAttempts || 1,
|
|
1868
|
+
loadedKnowledge: state.loadedKnowledge?.map((k) => ({ filename: k.filename, content: k.content })),
|
|
1845
1869
|
cwd
|
|
1846
1870
|
});
|
|
1871
|
+
const onComplete = `npx spets orchestrate verify-done ${state.taskId}`;
|
|
1847
1872
|
return {
|
|
1848
1873
|
type: "phase",
|
|
1849
1874
|
phase: "verify",
|
|
@@ -1859,7 +1884,8 @@ function buildPhaseVerifyResponse(cwd, state) {
|
|
|
1859
1884
|
template: hasTemplate ? templatePath : void 0,
|
|
1860
1885
|
document: documentPath
|
|
1861
1886
|
},
|
|
1862
|
-
onComplete
|
|
1887
|
+
onComplete,
|
|
1888
|
+
instructions: phaseWithJsonOutput(onComplete)
|
|
1863
1889
|
};
|
|
1864
1890
|
}
|
|
1865
1891
|
function buildPhaseKnowledgeResponse(cwd, state) {
|
|
@@ -1872,6 +1898,7 @@ function buildPhaseKnowledgeResponse(cwd, state) {
|
|
|
1872
1898
|
guide,
|
|
1873
1899
|
cwd
|
|
1874
1900
|
});
|
|
1901
|
+
const onComplete = `npx spets orchestrate knowledge-extract-done ${state.taskId}`;
|
|
1875
1902
|
return {
|
|
1876
1903
|
type: "phase",
|
|
1877
1904
|
phase: "knowledge",
|
|
@@ -1884,21 +1911,31 @@ function buildPhaseKnowledgeResponse(cwd, state) {
|
|
|
1884
1911
|
totalSteps: state.totalSteps
|
|
1885
1912
|
},
|
|
1886
1913
|
guide,
|
|
1887
|
-
onComplete
|
|
1914
|
+
onComplete,
|
|
1915
|
+
instructions: phaseWithJsonOutput(onComplete)
|
|
1888
1916
|
};
|
|
1889
1917
|
}
|
|
1890
1918
|
function buildCheckpointClarifyResponse(state) {
|
|
1919
|
+
const onComplete = `npx spets orchestrate clarified ${state.taskId}`;
|
|
1891
1920
|
return {
|
|
1892
1921
|
type: "checkpoint",
|
|
1893
1922
|
checkpoint: "clarify",
|
|
1894
1923
|
taskId: state.taskId,
|
|
1895
1924
|
step: state.currentStep,
|
|
1896
1925
|
decisions: state.decisions || [],
|
|
1897
|
-
onComplete:
|
|
1926
|
+
onComplete: `${onComplete} '<answers_json>'`,
|
|
1927
|
+
instructions: checkpointClarify(onComplete)
|
|
1898
1928
|
};
|
|
1899
1929
|
}
|
|
1900
1930
|
function buildCheckpointApproveResponse(cwd, state) {
|
|
1901
1931
|
const outputPath = getOutputPath(cwd);
|
|
1932
|
+
const specPath = join9(outputPath, state.taskId, `${state.currentStep}.md`);
|
|
1933
|
+
const cmds = {
|
|
1934
|
+
approve: `npx spets orchestrate approve ${state.taskId}`,
|
|
1935
|
+
revise: `npx spets orchestrate revise ${state.taskId} '<feedback>'`,
|
|
1936
|
+
reject: `npx spets orchestrate reject ${state.taskId}`,
|
|
1937
|
+
stop: `npx spets orchestrate stop ${state.taskId}`
|
|
1938
|
+
};
|
|
1902
1939
|
return {
|
|
1903
1940
|
type: "checkpoint",
|
|
1904
1941
|
checkpoint: "approve",
|
|
@@ -1906,14 +1943,10 @@ function buildCheckpointApproveResponse(cwd, state) {
|
|
|
1906
1943
|
step: state.currentStep,
|
|
1907
1944
|
stepIndex: state.stepIndex,
|
|
1908
1945
|
totalSteps: state.totalSteps,
|
|
1909
|
-
specPath
|
|
1946
|
+
specPath,
|
|
1910
1947
|
options: ["approve", "revise", "reject", "stop"],
|
|
1911
|
-
onComplete:
|
|
1912
|
-
|
|
1913
|
-
revise: `npx spets orchestrate revise ${state.taskId} '<feedback>'`,
|
|
1914
|
-
reject: `npx spets orchestrate reject ${state.taskId}`,
|
|
1915
|
-
stop: `npx spets orchestrate stop ${state.taskId}`
|
|
1916
|
-
}
|
|
1948
|
+
onComplete: cmds,
|
|
1949
|
+
instructions: checkpointApprove(specPath, cmds)
|
|
1917
1950
|
};
|
|
1918
1951
|
}
|
|
1919
1952
|
function buildCompleteResponse(cwd, state, status) {
|
|
@@ -1936,11 +1969,12 @@ function buildCompleteResponse(cwd, state, status) {
|
|
|
1936
1969
|
status,
|
|
1937
1970
|
taskId: state.taskId,
|
|
1938
1971
|
outputs,
|
|
1939
|
-
message: messages[status]
|
|
1972
|
+
message: messages[status],
|
|
1973
|
+
instructions: PRINT_MESSAGE_AND_STOP
|
|
1940
1974
|
};
|
|
1941
1975
|
}
|
|
1942
1976
|
function buildErrorResponse(error, taskId, step) {
|
|
1943
|
-
const response = { type: "error", error };
|
|
1977
|
+
const response = { type: "error", error, instructions: PRINT_ERROR_AND_STOP };
|
|
1944
1978
|
if (taskId) response.taskId = taskId;
|
|
1945
1979
|
if (step) response.step = step;
|
|
1946
1980
|
return response;
|
|
@@ -2282,7 +2316,7 @@ var Orchestrator = class {
|
|
|
2282
2316
|
const outputPath = getOutputPath(this.cwd);
|
|
2283
2317
|
const tasks = [];
|
|
2284
2318
|
if (!existsSync11(outputPath)) {
|
|
2285
|
-
return { type: "list", tasks: [] };
|
|
2319
|
+
return { type: "list", tasks: [], instructions: LIST_EMPTY };
|
|
2286
2320
|
}
|
|
2287
2321
|
const dirs = readdirSync2(outputPath, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
2288
2322
|
for (const dir of dirs) {
|
|
@@ -2304,7 +2338,11 @@ var Orchestrator = class {
|
|
|
2304
2338
|
const bTime = b.updatedAt ? new Date(b.updatedAt).getTime() : 0;
|
|
2305
2339
|
return bTime - aTime;
|
|
2306
2340
|
});
|
|
2307
|
-
return {
|
|
2341
|
+
return {
|
|
2342
|
+
type: "list",
|
|
2343
|
+
tasks,
|
|
2344
|
+
instructions: tasks.length > 0 ? LIST_TASKS : LIST_EMPTY
|
|
2345
|
+
};
|
|
2308
2346
|
}
|
|
2309
2347
|
/**
|
|
2310
2348
|
* Get current workflow status
|
|
@@ -2446,7 +2484,8 @@ function parseKnowledgeOutput(response) {
|
|
|
2446
2484
|
entries: entries.map((e) => ({
|
|
2447
2485
|
filename: e.filename || "",
|
|
2448
2486
|
content: e.content || "",
|
|
2449
|
-
reason: e.reason || ""
|
|
2487
|
+
reason: e.reason || "",
|
|
2488
|
+
action: e.action === "update" ? "update" : "create"
|
|
2450
2489
|
}))
|
|
2451
2490
|
};
|
|
2452
2491
|
}
|
|
@@ -2458,7 +2497,8 @@ function parseKnowledgeOutput(response) {
|
|
|
2458
2497
|
entries: parsed.map((e) => ({
|
|
2459
2498
|
filename: e.filename || "",
|
|
2460
2499
|
content: e.content || "",
|
|
2461
|
-
reason: e.reason || ""
|
|
2500
|
+
reason: e.reason || "",
|
|
2501
|
+
action: e.action === "update" ? "update" : "create"
|
|
2462
2502
|
}))
|
|
2463
2503
|
};
|
|
2464
2504
|
}
|
|
@@ -5861,7 +5901,7 @@ async function uiKnowledgeCommand(entryName, options) {
|
|
|
5861
5901
|
console.log(renderKnowledgeJSON(void 0, cwd));
|
|
5862
5902
|
return;
|
|
5863
5903
|
}
|
|
5864
|
-
const { runKnowledgeInteractive: runKnowledgeInteractive2 } = await import("./knowledge-
|
|
5904
|
+
const { runKnowledgeInteractive: runKnowledgeInteractive2 } = await import("./knowledge-TVXZATJX.js");
|
|
5865
5905
|
await runKnowledgeInteractive2(cwd);
|
|
5866
5906
|
}
|
|
5867
5907
|
|
package/package.json
CHANGED