wyrm-mcp 6.12.0 → 6.14.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.
Files changed (51) hide show
  1. package/dist/auto-capture.d.ts +32 -0
  2. package/dist/auto-capture.d.ts.map +1 -0
  3. package/dist/auto-capture.js +136 -0
  4. package/dist/auto-capture.js.map +1 -0
  5. package/dist/database.d.ts +61 -3
  6. package/dist/database.d.ts.map +1 -1
  7. package/dist/database.js +155 -9
  8. package/dist/database.js.map +1 -1
  9. package/dist/http-fast.d.ts.map +1 -1
  10. package/dist/http-fast.js +28 -7
  11. package/dist/http-fast.js.map +1 -1
  12. package/dist/http-server.d.ts.map +1 -1
  13. package/dist/http-server.js +9 -5
  14. package/dist/http-server.js.map +1 -1
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +209 -20
  17. package/dist/index.js.map +1 -1
  18. package/dist/indexer.d.ts.map +1 -1
  19. package/dist/indexer.js +6 -0
  20. package/dist/indexer.js.map +1 -1
  21. package/dist/mcp-client.d.ts.map +1 -1
  22. package/dist/mcp-client.js +18 -1
  23. package/dist/mcp-client.js.map +1 -1
  24. package/dist/memory-artifacts.d.ts.map +1 -1
  25. package/dist/memory-artifacts.js +13 -3
  26. package/dist/memory-artifacts.js.map +1 -1
  27. package/dist/migrations.d.ts.map +1 -1
  28. package/dist/migrations.js +50 -0
  29. package/dist/migrations.js.map +1 -1
  30. package/dist/resilience.d.ts.map +1 -1
  31. package/dist/resilience.js +6 -4
  32. package/dist/resilience.js.map +1 -1
  33. package/dist/security.d.ts.map +1 -1
  34. package/dist/security.js +10 -1
  35. package/dist/security.js.map +1 -1
  36. package/dist/spec-kit.d.ts +56 -0
  37. package/dist/spec-kit.d.ts.map +1 -0
  38. package/dist/spec-kit.js +191 -0
  39. package/dist/spec-kit.js.map +1 -0
  40. package/dist/sync.d.ts.map +1 -1
  41. package/dist/sync.js +5 -2
  42. package/dist/sync.js.map +1 -1
  43. package/dist/tool-profiles.d.ts.map +1 -1
  44. package/dist/tool-profiles.js +3 -0
  45. package/dist/tool-profiles.js.map +1 -1
  46. package/dist/vault.d.ts.map +1 -1
  47. package/dist/vault.js +23 -3
  48. package/dist/vault.js.map +1 -1
  49. package/dist/wyrm-cli.js +3 -2
  50. package/dist/wyrm-cli.js.map +1 -1
  51. package/package.json +1 -1
@@ -0,0 +1,32 @@
1
+ import type { ArtifactKind } from './memory-artifacts.js';
2
+ export type CandidateKind = 'truth' | 'failure' | 'decision' | 'pattern' | 'lesson';
3
+ export interface MemoryCandidate {
4
+ kind: CandidateKind;
5
+ text: string;
6
+ confidence: number;
7
+ }
8
+ export interface ExtractResult {
9
+ candidates: MemoryCandidate[];
10
+ method: 'llm' | 'deterministic';
11
+ model?: string;
12
+ }
13
+ /** Robustly pull a candidate array out of an LLM response (small models wrap JSON in prose/markdown). */
14
+ export declare function parseCandidates(raw: string): MemoryCandidate[];
15
+ /** No-LLM extractor: segment into statements, keep durable-looking ones, classify. */
16
+ export declare function extractDeterministic(text: string): MemoryCandidate[];
17
+ /**
18
+ * Extract candidate memories from text. Tries the configured local LLM first
19
+ * (if any), falls back to deterministic. Never throws.
20
+ */
21
+ export declare function extractCandidates(text: string, opts?: {
22
+ model?: string;
23
+ ollamaUrl?: string;
24
+ }): Promise<ExtractResult>;
25
+ /** Map a candidate to its review-queue memory-artifact shape (needs_review=1). */
26
+ export declare function candidateToArtifact(c: MemoryCandidate): {
27
+ kind: ArtifactKind;
28
+ problem: string;
29
+ tags: string[];
30
+ confidence: number;
31
+ };
32
+ //# sourceMappingURL=auto-capture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-capture.d.ts","sourceRoot":"","sources":["../src/auto-capture.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;AACpF,MAAM,WAAW,eAAe;IAAG,IAAI,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;CAAE;AAC3F,MAAM,WAAW,aAAa;IAAG,UAAU,EAAE,eAAe,EAAE,CAAC;IAAC,MAAM,EAAE,KAAK,GAAG,eAAe,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CAAE;AAoBlH,yGAAyG;AACzG,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,EAAE,CAqB9D;AAgBD,sFAAsF;AACtF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,EAAE,CAmBpE;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAChD,OAAO,CAAC,aAAa,CAAC,CAQxB;AAED,kFAAkF;AAClF,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,eAAe,GAAG;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAWnI"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Auto-extraction (bet #2) — turn freeform text (a session, notes, a transcript)
3
+ * into candidate memories that land in the REVIEW QUEUE for operator approval.
4
+ *
5
+ * Closes the "just talk, it remembers" gap WITHOUT an expensive cloud LLM, via a
6
+ * pluggable LOCAL extractor:
7
+ * - LLM: any Ollama model (`WYRM_EXTRACT_MODEL`) — the slot the future DragonSpark
8
+ * nano-LLM drops into. Structured JSON out, robustly parsed.
9
+ * - Deterministic fallback: sentence segmentation + signal markers + classifyCapture,
10
+ * used when no model is configured or the LLM is unreachable.
11
+ * Always produces candidates, never blocks a write, never throws. Candidates are
12
+ * stored with needs_review=1 so the operator vets them (wyrm_review) — nothing
13
+ * auto-trusted, matching Wyrm's distillation-queue discipline.
14
+ *
15
+ * @copyright 2024-2026 Ghost Protocol (Pvt) Ltd.
16
+ * @license AGPL-3.0-or-later — dual-licensed; commercial terms: ghosts.lk@proton.me. See LICENSE.
17
+ */
18
+ import { classifyCapture } from './capture.js';
19
+ const KINDS = ['truth', 'failure', 'decision', 'pattern', 'lesson'];
20
+ const EXTRACT_PROMPT = (text) => `You extract DURABLE, REUSABLE memories from a developer's working notes/transcript.
21
+ Output ONLY a JSON array, no prose. Each item: {"kind": one of ["truth","failure","decision","pattern","lesson"], "text": "<one self-contained sentence>"}.
22
+ - truth: a validated fact/constraint ("X uses Y", "Z is required").
23
+ - failure: an approach that FAILED and why (so it is not repeated).
24
+ - decision: a choice made + the reason ("chose A because B").
25
+ - pattern: a reusable approach that worked.
26
+ - lesson: a general insight learned.
27
+ Skip chit-chat, questions, and ephemeral status. Extract 0-8 items; fewer + higher-quality wins. If nothing durable, output [].
28
+
29
+ NOTES:
30
+ """
31
+ ${text.slice(0, 8000)}
32
+ """
33
+ JSON:`;
34
+ /** Robustly pull a candidate array out of an LLM response (small models wrap JSON in prose/markdown). */
35
+ export function parseCandidates(raw) {
36
+ const m = raw.match(/\[[\s\S]*\]/);
37
+ if (!m)
38
+ return [];
39
+ let arr;
40
+ try {
41
+ arr = JSON.parse(m[0]);
42
+ }
43
+ catch {
44
+ return [];
45
+ }
46
+ if (!Array.isArray(arr))
47
+ return [];
48
+ const out = [];
49
+ const seen = new Set();
50
+ for (const it of arr) {
51
+ if (!it || typeof it !== 'object')
52
+ continue;
53
+ const kind = it.kind;
54
+ const text = it.text;
55
+ if (typeof text !== 'string' || text.trim().length < 8)
56
+ continue;
57
+ const t = text.trim().slice(0, 1000);
58
+ const key = t.toLowerCase().replace(/\s+/g, ' ').slice(0, 80);
59
+ if (seen.has(key))
60
+ continue;
61
+ seen.add(key);
62
+ out.push({ kind: KINDS.includes(kind) ? kind : 'pattern', text: t, confidence: 0.6 });
63
+ if (out.length >= 12)
64
+ break;
65
+ }
66
+ return out;
67
+ }
68
+ async function extractViaLLM(text, model, url) {
69
+ try {
70
+ const res = await fetch(`${url.replace(/\/$/, '')}/api/generate`, {
71
+ method: 'POST',
72
+ headers: { 'Content-Type': 'application/json' },
73
+ body: JSON.stringify({ model, prompt: EXTRACT_PROMPT(text), stream: false, options: { temperature: 0 } }),
74
+ signal: AbortSignal.timeout(120_000),
75
+ });
76
+ if (!res.ok)
77
+ return null;
78
+ const data = await res.json();
79
+ return data.response ? parseCandidates(data.response) : null;
80
+ }
81
+ catch {
82
+ return null;
83
+ }
84
+ }
85
+ /** No-LLM extractor: segment into statements, keep durable-looking ones, classify. */
86
+ export function extractDeterministic(text) {
87
+ const segs = text.split(/(?<=[.!?])\s+|\n+/).map((s) => s.trim()).filter((s) => s.length >= 20 && s.length <= 400);
88
+ const out = [];
89
+ const seen = new Set();
90
+ for (const s of segs) {
91
+ if (!/\b(use[sd]?|decided|because|fail(s|ed)?|error|always|never|must|should|learned|lesson|turned out|prefer|avoid|root cause|fixed|broke|requires?)\b/i.test(s))
92
+ continue;
93
+ const key = s.toLowerCase().replace(/\s+/g, ' ').slice(0, 80);
94
+ if (seen.has(key))
95
+ continue;
96
+ seen.add(key);
97
+ const c = classifyCapture(s);
98
+ const kind = /\b(fail(s|ed)?|error|broke|bug|mistake)\b/i.test(s) ? 'failure'
99
+ : c.type === 'truth' ? 'truth'
100
+ : /\bbecause\b/i.test(s) ? 'decision'
101
+ : c.subtype === 'lesson' ? 'lesson'
102
+ : 'pattern';
103
+ out.push({ kind, text: s, confidence: (c.confidence ?? 60) / 100 });
104
+ if (out.length >= 8)
105
+ break;
106
+ }
107
+ return out;
108
+ }
109
+ /**
110
+ * Extract candidate memories from text. Tries the configured local LLM first
111
+ * (if any), falls back to deterministic. Never throws.
112
+ */
113
+ export async function extractCandidates(text, opts = {}) {
114
+ const url = opts.ollamaUrl || process.env.WYRM_OLLAMA_URL || 'http://localhost:11434';
115
+ const model = opts.model || process.env.WYRM_EXTRACT_MODEL || '';
116
+ if (model) {
117
+ const llm = await extractViaLLM(text, model, url);
118
+ if (llm && llm.length)
119
+ return { candidates: llm, method: 'llm', model };
120
+ }
121
+ return { candidates: extractDeterministic(text), method: 'deterministic' };
122
+ }
123
+ /** Map a candidate to its review-queue memory-artifact shape (needs_review=1). */
124
+ export function candidateToArtifact(c) {
125
+ const map = {
126
+ failure: 'anti_pattern',
127
+ decision: 'reasoning_trace',
128
+ lesson: 'lesson',
129
+ pattern: 'pattern',
130
+ truth: 'heuristic',
131
+ };
132
+ // A stable signature for dedup against re-extraction of the same text.
133
+ const sig = 'ax:' + c.text.toLowerCase().replace(/\s+/g, ' ').trim().slice(0, 64);
134
+ return { kind: map[c.kind], problem: c.text, tags: ['auto-extract', `intent:${c.kind}`, sig], confidence: c.confidence };
135
+ }
136
+ //# sourceMappingURL=auto-capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-capture.js","sourceRoot":"","sources":["../src/auto-capture.ts"],"names":[],"mappings":"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"}
@@ -81,12 +81,41 @@ export interface Skill {
81
81
  author?: string;
82
82
  version?: string;
83
83
  tags?: string;
84
+ /** GOD-SKILL SPEC v2 apex tier: 'atomic' (default) | 'mega' | 'god'. */
85
+ tier: 'atomic' | 'mega' | 'god';
86
+ /** JSON string array of skill names this node governs (routes DOWN to). */
87
+ governs?: string;
88
+ /** JSON string array of skill names this node composes (pulls in laterally). */
89
+ composes?: string;
84
90
  is_active: boolean;
85
91
  usage_count: number;
86
92
  last_used?: string;
87
93
  created_at: string;
88
94
  updated_at: string;
89
95
  }
96
+ /** A registered spec-kit spec directory linked to a project. */
97
+ export interface Spec {
98
+ id: number;
99
+ project_id: number;
100
+ spec_dir: string;
101
+ title?: string;
102
+ summary?: string;
103
+ task_count: number;
104
+ created_at: string;
105
+ updated_at: string;
106
+ }
107
+ /** A node in the skill governance graph (god → mega → atomic). */
108
+ export interface SkillGraphNode {
109
+ name: string;
110
+ tier: 'atomic' | 'mega' | 'god';
111
+ description: string;
112
+ governs: string[];
113
+ composes: string[];
114
+ /** Resolved child nodes (only the governed ones that exist as registered skills). */
115
+ children: SkillGraphNode[];
116
+ /** True when a governs/composes target name is not a registered skill. */
117
+ missing?: string[];
118
+ }
90
119
  export declare class WyrmDB {
91
120
  private db;
92
121
  private readonly BATCH_SIZE;
@@ -163,10 +192,23 @@ export declare class WyrmDB {
163
192
  setGlobalContext(key: string, value: string): void;
164
193
  getGlobalContext(key: string): string | undefined;
165
194
  getAllGlobalContext(): Record<string, string>;
166
- registerSkill(name: string, description: string, skillPath: string, category?: string, author?: string, version?: string, tags?: string): Skill;
195
+ registerSkill(name: string, description: string, skillPath: string, category?: string, author?: string, version?: string, tags?: string, governance?: {
196
+ tier?: 'atomic' | 'mega' | 'god';
197
+ governs?: string[];
198
+ composes?: string[];
199
+ }): Skill;
167
200
  getSkill(name: string): Skill | undefined;
168
- listSkills(active?: boolean, category?: string, search?: string): Skill[];
169
- searchSkills(query: string, limit?: number): Skill[];
201
+ listSkills(active?: boolean, category?: string, search?: string, tier?: 'atomic' | 'mega' | 'god'): Skill[];
202
+ searchSkills(query: string, limit?: number, tier?: 'atomic' | 'mega' | 'god'): Skill[];
203
+ /**
204
+ * Build the GOD-SKILL SPEC v2 governance graph.
205
+ *
206
+ * Walks tier routing edges: a node's `governs` list names the skills it routes
207
+ * DOWN to (god → mega → atomic). Each node also exposes its `composes` list
208
+ * (lateral pull-ins). When `root` is given, returns that single tree; otherwise
209
+ * returns a forest of every 'god' tier skill (the apexes). Cycle-safe.
210
+ */
211
+ getSkillGraph(root?: string): SkillGraphNode[];
170
212
  updateSkill(name: string, updates: Partial<Skill>): Skill | undefined;
171
213
  deleteSkill(name: string): boolean;
172
214
  deactivateSkill(name: string): Skill | undefined;
@@ -176,6 +218,22 @@ export declare class WyrmDB {
176
218
  active: number;
177
219
  byCategory: Record<string, number>;
178
220
  };
221
+ /** Upsert a spec→project link (idempotent by project_id + spec_dir). */
222
+ upsertSpec(projectId: number, specDir: string, title?: string, summary?: string, taskCount?: number): Spec;
223
+ getSpec(projectId: number, specDir: string): Spec | undefined;
224
+ listSpecs(projectId?: number): Spec[];
225
+ /**
226
+ * Find an existing quest for a project carrying a specific spec-task tag
227
+ * signature. Used by wyrm_spec_register to dedupe (update-not-duplicate) on
228
+ * re-run. The signature lives in the quest's comma-separated `tags` column.
229
+ */
230
+ findQuestBySpecSignature(projectId: number, signature: string): Quest | undefined;
231
+ /** Update a quest's title/description/tags in place (used by spec re-registration). */
232
+ updateQuestFields(id: number, fields: {
233
+ title?: string;
234
+ description?: string;
235
+ tags?: string;
236
+ }): Quest | undefined;
179
237
  insertData(projectId: number, category: string, key: string, value: string, metadata?: Record<string, unknown>): DataPoint;
180
238
  /**
181
239
  * Batch insert with resilience - uses checkpointing for large batches
@@ -1 +1 @@
1
- {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"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"}
package/dist/database.js CHANGED
@@ -553,10 +553,15 @@ export class WyrmDB {
553
553
  return result;
554
554
  }
555
555
  // ==================== SKILLS MANAGEMENT ====================
556
- registerSkill(name, description, skillPath, category, author, version, tags) {
556
+ registerSkill(name, description, skillPath, category, author, version, tags, governance) {
557
+ // Normalize governance to safe defaults so existing callers (no 8th arg)
558
+ // keep producing 'atomic' / '[]' / '[]' — fully backward-compatible.
559
+ const tier = governance?.tier ?? 'atomic';
560
+ const governsJson = JSON.stringify(Array.isArray(governance?.governs) ? governance.governs : []);
561
+ const composesJson = JSON.stringify(Array.isArray(governance?.composes) ? governance.composes : []);
557
562
  const result = this.resilience.withRetrySync(() => this.db.prepare(`
558
- INSERT INTO skills (name, description, skill_path, category, author, version, tags, is_active, usage_count)
559
- VALUES (?, ?, ?, ?, ?, ?, ?, 1, 0)
563
+ INSERT INTO skills (name, description, skill_path, category, author, version, tags, tier, governs, composes, is_active, usage_count)
564
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 0)
560
565
  ON CONFLICT(name) DO UPDATE SET
561
566
  description = excluded.description,
562
567
  skill_path = excluded.skill_path,
@@ -564,10 +569,13 @@ export class WyrmDB {
564
569
  author = excluded.author,
565
570
  version = excluded.version,
566
571
  tags = excluded.tags,
572
+ tier = excluded.tier,
573
+ governs = excluded.governs,
574
+ composes = excluded.composes,
567
575
  updated_at = datetime('now'),
568
576
  is_active = 1
569
577
  RETURNING *
570
- `).get(name, description, skillPath, category || null, author || null, version || null, tags || null), 'registerSkill');
578
+ `).get(name, description, skillPath, category || null, author || null, version || null, tags || null, tier, governsJson, composesJson), 'registerSkill');
571
579
  if (!result.success) {
572
580
  throw result.error || new Error('Failed to register skill');
573
581
  }
@@ -581,7 +589,7 @@ export class WyrmDB {
581
589
  }
582
590
  return skill;
583
591
  }
584
- listSkills(active, category, search) {
592
+ listSkills(active, category, search, tier) {
585
593
  let query = 'SELECT * FROM skills WHERE 1=1';
586
594
  const params = [];
587
595
  if (active !== undefined) {
@@ -592,6 +600,10 @@ export class WyrmDB {
592
600
  query += ' AND category = ?';
593
601
  params.push(category);
594
602
  }
603
+ if (tier) {
604
+ query += ' AND tier = ?';
605
+ params.push(tier);
606
+ }
595
607
  if (search) {
596
608
  const match = buildFtsMatchQuery(search);
597
609
  if (match) {
@@ -602,17 +614,90 @@ export class WyrmDB {
602
614
  query += ' ORDER BY updated_at DESC';
603
615
  return this.db.prepare(query).all(...params);
604
616
  }
605
- searchSkills(query, limit = 20) {
617
+ searchSkills(query, limit = 20, tier) {
606
618
  const match = buildFtsMatchQuery(query);
607
619
  if (!match)
608
620
  return [];
609
- return this.db.prepare(`
621
+ // Optional tier filter is applied in SQL so the FTS rank ordering is preserved.
622
+ const tierClause = tier ? ' AND s.tier = ?' : '';
623
+ const stmt = this.db.prepare(`
610
624
  SELECT s.* FROM skills s
611
625
  JOIN skills_fts ON s.id = skills_fts.rowid
612
- WHERE skills_fts MATCH ?
626
+ WHERE skills_fts MATCH ?${tierClause}
613
627
  ORDER BY rank
614
628
  LIMIT ?
615
- `).all(match, limit);
629
+ `);
630
+ return (tier ? stmt.all(match, tier, limit) : stmt.all(match, limit));
631
+ }
632
+ /**
633
+ * Build the GOD-SKILL SPEC v2 governance graph.
634
+ *
635
+ * Walks tier routing edges: a node's `governs` list names the skills it routes
636
+ * DOWN to (god → mega → atomic). Each node also exposes its `composes` list
637
+ * (lateral pull-ins). When `root` is given, returns that single tree; otherwise
638
+ * returns a forest of every 'god' tier skill (the apexes). Cycle-safe.
639
+ */
640
+ getSkillGraph(root) {
641
+ const all = this.db.prepare('SELECT * FROM skills').all();
642
+ const byName = new Map();
643
+ for (const s of all)
644
+ byName.set(s.name, s);
645
+ const parseArr = (v) => {
646
+ if (!v)
647
+ return [];
648
+ try {
649
+ const parsed = JSON.parse(v);
650
+ return Array.isArray(parsed) ? parsed.filter((x) => typeof x === 'string') : [];
651
+ }
652
+ catch {
653
+ return [];
654
+ }
655
+ };
656
+ const build = (name, seen) => {
657
+ const skill = byName.get(name);
658
+ if (!skill)
659
+ return null;
660
+ const governs = parseArr(skill.governs);
661
+ const composes = parseArr(skill.composes);
662
+ const node = {
663
+ name: skill.name,
664
+ tier: skill.tier ?? 'atomic',
665
+ description: skill.description,
666
+ governs,
667
+ composes,
668
+ children: [],
669
+ };
670
+ const missing = [];
671
+ if (!seen.has(name)) {
672
+ const nextSeen = new Set(seen).add(name);
673
+ for (const childName of governs) {
674
+ const child = build(childName, nextSeen);
675
+ if (child)
676
+ node.children.push(child);
677
+ else
678
+ missing.push(childName);
679
+ }
680
+ }
681
+ if (missing.length)
682
+ node.missing = missing;
683
+ return node;
684
+ };
685
+ if (root) {
686
+ const node = build(root, new Set());
687
+ return node ? [node] : [];
688
+ }
689
+ // No root → forest of all god-tier apexes (deterministic by name).
690
+ const gods = all
691
+ .filter((s) => (s.tier ?? 'atomic') === 'god')
692
+ .map((s) => s.name)
693
+ .sort();
694
+ const forest = [];
695
+ for (const g of gods) {
696
+ const node = build(g, new Set());
697
+ if (node)
698
+ forest.push(node);
699
+ }
700
+ return forest;
616
701
  }
617
702
  updateSkill(name, updates) {
618
703
  const setClauses = [];
@@ -672,6 +757,67 @@ export class WyrmDB {
672
757
  }
673
758
  return { total, active, byCategory };
674
759
  }
760
+ // ==================== SPEC-KIT REGISTRY ====================
761
+ /** Upsert a spec→project link (idempotent by project_id + spec_dir). */
762
+ upsertSpec(projectId, specDir, title, summary, taskCount = 0) {
763
+ return this.db.prepare(`
764
+ INSERT INTO specs (project_id, spec_dir, title, summary, task_count)
765
+ VALUES (?, ?, ?, ?, ?)
766
+ ON CONFLICT(project_id, spec_dir) DO UPDATE SET
767
+ title = excluded.title,
768
+ summary = excluded.summary,
769
+ task_count = excluded.task_count,
770
+ updated_at = datetime('now')
771
+ RETURNING *
772
+ `).get(projectId, specDir, title || null, summary || null, taskCount);
773
+ }
774
+ getSpec(projectId, specDir) {
775
+ return this.db.prepare('SELECT * FROM specs WHERE project_id = ? AND spec_dir = ?').get(projectId, specDir);
776
+ }
777
+ listSpecs(projectId) {
778
+ if (projectId !== undefined) {
779
+ return this.db.prepare('SELECT * FROM specs WHERE project_id = ? ORDER BY updated_at DESC').all(projectId);
780
+ }
781
+ return this.db.prepare('SELECT * FROM specs ORDER BY updated_at DESC').all();
782
+ }
783
+ /**
784
+ * Find an existing quest for a project carrying a specific spec-task tag
785
+ * signature. Used by wyrm_spec_register to dedupe (update-not-duplicate) on
786
+ * re-run. The signature lives in the quest's comma-separated `tags` column.
787
+ */
788
+ findQuestBySpecSignature(projectId, signature) {
789
+ return this.db.prepare(`
790
+ SELECT * FROM quests
791
+ WHERE project_id = ?
792
+ AND (tags = ? OR tags LIKE ? OR tags LIKE ? OR tags LIKE ?)
793
+ LIMIT 1
794
+ `).get(projectId, signature, `${signature},%`, `%,${signature}`, `%,${signature},%`);
795
+ }
796
+ /** Update a quest's title/description/tags in place (used by spec re-registration). */
797
+ updateQuestFields(id, fields) {
798
+ const setClauses = [];
799
+ const values = [];
800
+ if (fields.title !== undefined) {
801
+ setClauses.push('title = ?');
802
+ values.push(fields.title);
803
+ }
804
+ if (fields.description !== undefined) {
805
+ setClauses.push('description = ?');
806
+ values.push(fields.description);
807
+ }
808
+ if (fields.tags !== undefined) {
809
+ setClauses.push('tags = ?');
810
+ values.push(fields.tags);
811
+ }
812
+ if (setClauses.length === 0) {
813
+ return this.db.prepare('SELECT * FROM quests WHERE id = ?').get(id);
814
+ }
815
+ values.push(id);
816
+ const quest = this.db.prepare(`UPDATE quests SET ${setClauses.join(', ')} WHERE id = ? RETURNING *`).get(...values);
817
+ if (quest)
818
+ emitEvent(this.db, { projectId: quest.project_id, kind: 'quest', refTable: 'quests', refId: id });
819
+ return quest;
820
+ }
675
821
  // ==================== DATA LAKE ====================
676
822
  insertData(projectId, category, key, value, metadata) {
677
823
  const result = this.resilience.withRetrySync(() => this.db.prepare(`