spets 0.1.99 → 0.2.1

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: (/* @__PURE__ */ new Date()).toISOString()
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 buildAvailableKnowledgeSection(cwd = process.cwd()) {
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("## Available Knowledge");
118
+ parts.push("## Knowledge Summary");
85
119
  parts.push("");
86
- parts.push("\uB2E4\uC74C \uC9C0\uC2DD \uD30C\uC77C\uB4E4\uC774 \uC774 \uD504\uB85C\uC81D\uD2B8\uC5D0 \uC800\uC7A5\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4:");
87
- for (const file of files) {
88
- parts.push(`- ${file}`);
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.push("\uD604\uC7AC \uD0DC\uC2A4\uD06C\uC5D0 \uCC38\uACE0\uD560 \uC9C0\uC2DD\uC774 \uC788\uB2E4\uBA74 JSON \uCD9C\uB825\uC758 `knowledgeRequests` \uD544\uB4DC\uC5D0 \uD30C\uC77C\uBA85\uC744 \uCD94\uAC00\uD558\uC138\uC694.");
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
- buildAvailableKnowledgeSection,
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
- buildAvailableKnowledgeSection,
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-3QH66XVU.js";
35
+ } from "./chunk-OIFVTELS.js";
35
36
  import {
36
37
  clearConfigCache,
37
38
  getConfigPath,
@@ -274,29 +275,51 @@ function getClaudeSkillContent() {
274
275
 
275
276
  You execute spets orchestrator commands. Parse JSON, follow instructions, repeat.
276
277
 
277
- ## Execution
278
+ ## Startup
278
279
 
279
- 1. RUN \`npx spets orchestrate init "$ARGUMENTS"\`
280
- 2. PARSE JSON response
281
- 3. SWITCH on \`type\`:
280
+ IF \`$ARGUMENTS\` starts with "resume":
281
+ 1. RUN \`npx spets orchestrate resume\`
282
+ ELSE:
283
+ 1. RUN \`npx spets orchestrate init "$ARGUMENTS"\`
282
284
 
283
- type="phase":
285
+ Then GOTO **Loop**.
286
+
287
+ ## Loop
288
+
289
+ 1. PARSE JSON response
290
+ 2. SWITCH on \`type\`:
291
+
292
+ ### type="phase"
284
293
  - EXECUTE what \`prompt\` says
285
294
  - RUN \`onComplete\` with your output as JSON argument
286
- - GOTO step 2
295
+ - GOTO Loop
287
296
 
288
- type="checkpoint", checkpoint="clarify":
289
- - ASK user each question in \`questions[]\` using AskUserQuestion
290
- - RUN \`onComplete\` with \`[{questionId, answer}, ...]\`
291
- - GOTO step 2
297
+ ### type="checkpoint", checkpoint="clarify"
298
+ - ASK user each decision in \`decisions[]\` using AskUserQuestion
299
+ - Format each decision as a question with its options
300
+ - RUN \`onComplete\` with \`[{decisionId, selectedOptionId}, ...]\`
301
+ - GOTO Loop
292
302
 
293
- type="checkpoint", checkpoint="approve":
303
+ ### type="checkpoint", checkpoint="approve"
294
304
  - READ \`specPath\`, summarize key points to user
295
305
  - ASK user using AskUserQuestion with options: Approve / Revise / Reject / Stop
296
306
  - RUN matching \`onComplete\` based on user's choice
297
- - GOTO step 2
307
+ - GOTO Loop
298
308
 
299
- type="complete" or "error":
309
+ ### type="checkpoint", checkpoint="knowledge"
310
+ - Show \`suggestedKnowledge[]\` to user
311
+ - ASK user if they want to save, modify, or skip
312
+ - If save: RUN \`onComplete\` with entries JSON
313
+ - If skip: RUN \`onSkip\`
314
+ - GOTO Loop
315
+
316
+ ### type="list"
317
+ - Show \`tasks[]\` to user with taskId, description, status, currentStep
318
+ - ASK user which task to resume
319
+ - RUN \`npx spets orchestrate resume <selectedTaskId>\`
320
+ - GOTO Loop
321
+
322
+ ### type="complete" or "error"
300
323
  - PRINT message
301
324
  - STOP
302
325
 
@@ -305,7 +328,7 @@ type="complete" or "error":
305
328
  EnterPlanMode, TaskCreate, TaskUpdate
306
329
 
307
330
  $ARGUMENTS
308
- description: Task description for the workflow
331
+ description: Task description for the workflow (or "resume" to continue a previous workflow)
309
332
  `;
310
333
  }
311
334
  function getCodexSkillContent() {
@@ -318,33 +341,54 @@ description: SDD workflow executor - orchestrator-controlled spec-driven develop
318
341
 
319
342
  You execute spets orchestrator commands. Parse JSON, follow instructions, repeat.
320
343
 
321
- ## Execution
344
+ ## Startup
345
+
346
+ IF \`$ARGUMENTS\` starts with "resume":
347
+ 1. RUN \`npx spets orchestrate resume\`
348
+ ELSE:
349
+ 1. RUN \`npx spets orchestrate init "$ARGUMENTS"\`
322
350
 
323
- 1. RUN \`npx spets orchestrate init "$ARGUMENTS"\`
324
- 2. PARSE JSON response
325
- 3. SWITCH on \`type\`:
351
+ Then GOTO **Loop**.
326
352
 
327
- type="phase":
353
+ ## Loop
354
+
355
+ 1. PARSE JSON response
356
+ 2. SWITCH on \`type\`:
357
+
358
+ ### type="phase"
328
359
  - EXECUTE what \`prompt\` says
329
360
  - RUN \`onComplete\` with your output as minified JSON argument
330
- - GOTO step 2
361
+ - GOTO Loop
331
362
 
332
- type="checkpoint", checkpoint="clarify":
333
- - FORMAT questions as table for user:
334
- | # | Question | Context | Options |
363
+ ### type="checkpoint", checkpoint="clarify"
364
+ - FORMAT decisions as table for user:
365
+ | # | Decision | Context | Options |
335
366
  |---|----------|---------|---------|
336
- | q1 | ... | ... | 1. ... 2. ... |
337
- - ASK user to answer each question
338
- - RUN \`onComplete\` with \`[{questionId, answer}, ...]\`
339
- - GOTO step 2
367
+ | d1 | ... | ... | 1. ... 2. ... |
368
+ - ASK user to pick an option for each decision
369
+ - RUN \`onComplete\` with \`[{decisionId, selectedOptionId}, ...]\`
370
+ - GOTO Loop
340
371
 
341
- type="checkpoint", checkpoint="approve":
372
+ ### type="checkpoint", checkpoint="approve"
342
373
  - READ \`specPath\`, summarize key points to user
343
- - ASK user using AskUserQuestion with options: Approve / Revise / Reject / Stop
374
+ - ASK user with options: Approve / Revise / Reject / Stop
344
375
  - RUN matching \`onComplete\` based on user's choice
345
- - GOTO step 2
376
+ - GOTO Loop
377
+
378
+ ### type="checkpoint", checkpoint="knowledge"
379
+ - Show \`suggestedKnowledge[]\` to user
380
+ - ASK user if they want to save, modify, or skip
381
+ - If save: RUN \`onComplete\` with entries JSON
382
+ - If skip: RUN \`onSkip\`
383
+ - GOTO Loop
346
384
 
347
- type="complete" or "error":
385
+ ### type="list"
386
+ - Show \`tasks[]\` to user with taskId, description, status, currentStep
387
+ - ASK user which task to resume
388
+ - RUN \`npx spets orchestrate resume <selectedTaskId>\`
389
+ - GOTO Loop
390
+
391
+ ### type="complete" or "error"
348
392
  - PRINT message
349
393
  - STOP
350
394
 
@@ -353,7 +397,7 @@ type="complete" or "error":
353
397
  Planning mode, task tracking tools
354
398
 
355
399
  $ARGUMENTS
356
- description: Task description for the workflow
400
+ description: Task description for the workflow (or "resume" to continue a previous workflow)
357
401
  `;
358
402
  }
359
403
  function getGeminiSkillContent() {
@@ -366,29 +410,50 @@ description: SDD workflow executor - orchestrator-controlled spec-driven develop
366
410
 
367
411
  You execute spets orchestrator commands. Parse JSON, follow instructions, repeat.
368
412
 
369
- ## Execution
413
+ ## Startup
414
+
415
+ IF \`$ARGUMENTS\` starts with "resume":
416
+ 1. RUN \`npx spets orchestrate resume\`
417
+ ELSE:
418
+ 1. RUN \`npx spets orchestrate init "$ARGUMENTS"\`
419
+
420
+ Then GOTO **Loop**.
370
421
 
371
- 1. RUN \`npx spets orchestrate init "$ARGUMENTS"\`
372
- 2. PARSE JSON response
373
- 3. SWITCH on \`type\`:
422
+ ## Loop
374
423
 
375
- type="phase":
424
+ 1. PARSE JSON response
425
+ 2. SWITCH on \`type\`:
426
+
427
+ ### type="phase"
376
428
  - EXECUTE what \`prompt\` says
377
429
  - RUN \`onComplete\` with your output as JSON argument
378
- - GOTO step 2
430
+ - GOTO Loop
379
431
 
380
- type="checkpoint", checkpoint="clarify":
381
- - ASK user each question in \`decisions[]\`
432
+ ### type="checkpoint", checkpoint="clarify"
433
+ - ASK user each decision in \`decisions[]\`
382
434
  - RUN \`onComplete\` with \`[{decisionId, selectedOptionId}, ...]\`
383
- - GOTO step 2
435
+ - GOTO Loop
384
436
 
385
- type="checkpoint", checkpoint="approve":
437
+ ### type="checkpoint", checkpoint="approve"
386
438
  - READ \`specPath\`, summarize key points to user
387
439
  - ASK user with options: Approve / Revise / Reject / Stop
388
440
  - RUN matching \`onComplete\` based on user's choice
389
- - GOTO step 2
441
+ - GOTO Loop
442
+
443
+ ### type="checkpoint", checkpoint="knowledge"
444
+ - Show \`suggestedKnowledge[]\` to user
445
+ - ASK user if they want to save, modify, or skip
446
+ - If save: RUN \`onComplete\` with entries JSON
447
+ - If skip: RUN \`onSkip\`
448
+ - GOTO Loop
449
+
450
+ ### type="list"
451
+ - Show \`tasks[]\` to user with taskId, description, status, currentStep
452
+ - ASK user which task to resume
453
+ - RUN \`npx spets orchestrate resume <selectedTaskId>\`
454
+ - GOTO Loop
390
455
 
391
- type="complete" or "error":
456
+ ### type="complete" or "error"
392
457
  - PRINT message
393
458
  - STOP
394
459
 
@@ -397,7 +462,7 @@ type="complete" or "error":
397
462
  Planning mode, task tracking tools
398
463
 
399
464
  $ARGUMENTS
400
- description: Task description for the workflow
465
+ description: Task description for the workflow (or "resume" to continue a previous workflow)
401
466
  `;
402
467
  }
403
468
 
@@ -981,7 +1046,7 @@ function buildExplorePrompt(params) {
981
1046
  parts.push("");
982
1047
  const config = loadConfig(cwd);
983
1048
  if (config.knowledge?.inject !== false) {
984
- const knowledgeSection = buildAvailableKnowledgeSection(cwd);
1049
+ const knowledgeSection = buildKnowledgeSummarySection(cwd);
985
1050
  if (knowledgeSection) {
986
1051
  parts.push(knowledgeSection);
987
1052
  }
@@ -1061,6 +1126,7 @@ function buildExploreTeamSection() {
1061
1126
 
1062
1127
  // src/core/prompts/clarify.ts
1063
1128
  function buildClarifyPrompt(params) {
1129
+ const cwd = params.cwd || process.cwd();
1064
1130
  const parts = [];
1065
1131
  parts.push("# Clarify Phase");
1066
1132
  parts.push("");
@@ -1077,6 +1143,13 @@ function buildClarifyPrompt(params) {
1077
1143
  parts.push("");
1078
1144
  parts.push(params.gatheredContext);
1079
1145
  parts.push("");
1146
+ const config = loadConfig(cwd);
1147
+ if (config.knowledge?.inject !== false) {
1148
+ const knowledgeSection = buildKnowledgeSummarySection(cwd);
1149
+ if (knowledgeSection) {
1150
+ parts.push(knowledgeSection);
1151
+ }
1152
+ }
1080
1153
  if (params.loadedKnowledge && params.loadedKnowledge.length > 0) {
1081
1154
  parts.push("## Requested Knowledge");
1082
1155
  parts.push("");
@@ -1344,6 +1417,12 @@ function buildExecutePrompt(params) {
1344
1417
  }
1345
1418
  parts.push("");
1346
1419
  }
1420
+ if (config.knowledge?.inject !== false) {
1421
+ const knowledgeSection = buildKnowledgeSummarySection(cwd);
1422
+ if (knowledgeSection) {
1423
+ parts.push(knowledgeSection);
1424
+ }
1425
+ }
1347
1426
  if (params.loadedKnowledge && params.loadedKnowledge.length > 0) {
1348
1427
  parts.push("### Referenced Knowledge");
1349
1428
  parts.push("");
@@ -1454,6 +1533,20 @@ function buildVerifyPrompt(params) {
1454
1533
  parts.push(template);
1455
1534
  parts.push("");
1456
1535
  }
1536
+ const config = loadConfig(cwd);
1537
+ if (config.knowledge?.inject !== false) {
1538
+ const knowledgeSection = buildKnowledgeSummarySection(cwd);
1539
+ if (knowledgeSection) {
1540
+ parts.push(knowledgeSection);
1541
+ }
1542
+ }
1543
+ if (params.loadedKnowledge && params.loadedKnowledge.length > 0) {
1544
+ const knowledgeContent = buildBudgetedKnowledgeSection(params.loadedKnowledge);
1545
+ if (knowledgeContent) {
1546
+ parts.push(knowledgeContent);
1547
+ parts.push("");
1548
+ }
1549
+ }
1457
1550
  parts.push("## Verification Criteria");
1458
1551
  parts.push("");
1459
1552
  parts.push("1. **Accuracy** (0-100)");
@@ -1478,7 +1571,6 @@ function buildVerifyPrompt(params) {
1478
1571
  parts.push("");
1479
1572
  parts.push("If it fails, the output will be automatically revised (up to 3 attempts).");
1480
1573
  parts.push("");
1481
- const config = loadConfig(cwd);
1482
1574
  if (config.team?.enabled) {
1483
1575
  parts.push(buildVerifyTeamSection());
1484
1576
  }
@@ -1599,6 +1691,20 @@ function buildKnowledgeExtractPrompt(params) {
1599
1691
  parts.push("");
1600
1692
  }
1601
1693
  }
1694
+ const cwd = params.cwd || process.cwd();
1695
+ const existingFiles = listKnowledgeFiles(cwd);
1696
+ if (existingFiles.length > 0) {
1697
+ parts.push("## Existing Knowledge Entries");
1698
+ parts.push("");
1699
+ 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:");
1700
+ parts.push("");
1701
+ for (const filename of existingFiles) {
1702
+ const entry = loadKnowledgeFile(filename, cwd);
1703
+ const firstLine = entry?.content.split("\n")[0]?.trim() || "";
1704
+ parts.push(`- **${filename}**: ${firstLine}`);
1705
+ }
1706
+ parts.push("");
1707
+ }
1602
1708
  parts.push("## Your Task");
1603
1709
  parts.push("");
1604
1710
  parts.push("Extract knowledge that would be useful for future workflows:");
@@ -1614,6 +1720,10 @@ function buildKnowledgeExtractPrompt(params) {
1614
1720
  parts.push("- One-time decisions");
1615
1721
  parts.push("- Temporary workarounds");
1616
1722
  parts.push("");
1723
+ parts.push("**Update or Create:**");
1724
+ parts.push('- If an existing entry covers the same topic, use `"action": "update"` with the same filename');
1725
+ parts.push('- Only use `"action": "create"` for genuinely new knowledge');
1726
+ parts.push("");
1617
1727
  parts.push("## Output Format");
1618
1728
  parts.push("");
1619
1729
  parts.push("Output a JSON object with this structure:");
@@ -1624,7 +1734,8 @@ function buildKnowledgeExtractPrompt(params) {
1624
1734
  parts.push(" {");
1625
1735
  parts.push(' "filename": "pattern--error-handling",');
1626
1736
  parts.push(' "content": "The knowledge content in markdown format...",');
1627
- parts.push(' "reason": "Why this is worth saving"');
1737
+ parts.push(' "reason": "Why this is worth saving",');
1738
+ parts.push(' "action": "create"');
1628
1739
  parts.push(" }");
1629
1740
  parts.push(" ]");
1630
1741
  parts.push("}");
@@ -1778,6 +1889,7 @@ function buildPhaseVerifyResponse(cwd, state) {
1778
1889
  totalSteps: state.totalSteps,
1779
1890
  documentPath,
1780
1891
  verifyAttempts: state.verifyAttempts || 1,
1892
+ loadedKnowledge: state.loadedKnowledge?.map((k) => ({ filename: k.filename, content: k.content })),
1781
1893
  cwd
1782
1894
  });
1783
1895
  return {
@@ -2382,7 +2494,8 @@ function parseKnowledgeOutput(response) {
2382
2494
  entries: entries.map((e) => ({
2383
2495
  filename: e.filename || "",
2384
2496
  content: e.content || "",
2385
- reason: e.reason || ""
2497
+ reason: e.reason || "",
2498
+ action: e.action === "update" ? "update" : "create"
2386
2499
  }))
2387
2500
  };
2388
2501
  }
@@ -2394,7 +2507,8 @@ function parseKnowledgeOutput(response) {
2394
2507
  entries: parsed.map((e) => ({
2395
2508
  filename: e.filename || "",
2396
2509
  content: e.content || "",
2397
- reason: e.reason || ""
2510
+ reason: e.reason || "",
2511
+ action: e.action === "update" ? "update" : "create"
2398
2512
  }))
2399
2513
  };
2400
2514
  }
@@ -5797,7 +5911,7 @@ async function uiKnowledgeCommand(entryName, options) {
5797
5911
  console.log(renderKnowledgeJSON(void 0, cwd));
5798
5912
  return;
5799
5913
  }
5800
- const { runKnowledgeInteractive: runKnowledgeInteractive2 } = await import("./knowledge-QC6464NS.js");
5914
+ const { runKnowledgeInteractive: runKnowledgeInteractive2 } = await import("./knowledge-TVXZATJX.js");
5801
5915
  await runKnowledgeInteractive2(cwd);
5802
5916
  }
5803
5917
 
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  renderKnowledgeJSON,
3
3
  runKnowledgeInteractive
4
- } from "./chunk-3QH66XVU.js";
4
+ } from "./chunk-OIFVTELS.js";
5
5
  import "./chunk-2MUV3F53.js";
6
6
  export {
7
7
  renderKnowledgeJSON,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spets",
3
- "version": "0.1.99",
3
+ "version": "0.2.1",
4
4
  "description": "Spec Driven Development Execution Framework",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -27,6 +27,12 @@
27
27
  - `pattern--` : 코드 패턴 (예: `pattern--error-handling`)
28
28
  - prefix 없이 사용해도 무방
29
29
 
30
+ ## Update or Create
31
+
32
+ - 기존 파일과 겹치는 내용이면 `"action": "update"`로 업데이트
33
+ - 새로운 지식이면 `"action": "create"`로 생성
34
+ - 중복 파일이 누적되지 않도록 기존 항목을 확인하세요
35
+
30
36
  ## 예시
31
37
 
32
38
  ```