pcl-mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +122 -0
  3. package/dist/bin/pcl.d.ts +3 -0
  4. package/dist/bin/pcl.d.ts.map +1 -0
  5. package/dist/bin/pcl.js +327 -0
  6. package/dist/bin/pcl.js.map +1 -0
  7. package/dist/src/db.d.ts +38 -0
  8. package/dist/src/db.d.ts.map +1 -0
  9. package/dist/src/db.js +238 -0
  10. package/dist/src/db.js.map +1 -0
  11. package/dist/src/embeddings.d.ts +15 -0
  12. package/dist/src/embeddings.d.ts.map +1 -0
  13. package/dist/src/embeddings.js +82 -0
  14. package/dist/src/embeddings.js.map +1 -0
  15. package/dist/src/indexer.d.ts +19 -0
  16. package/dist/src/indexer.d.ts.map +1 -0
  17. package/dist/src/indexer.js +174 -0
  18. package/dist/src/indexer.js.map +1 -0
  19. package/dist/src/scanner.d.ts +30 -0
  20. package/dist/src/scanner.d.ts.map +1 -0
  21. package/dist/src/scanner.js +290 -0
  22. package/dist/src/scanner.js.map +1 -0
  23. package/dist/src/schemas.d.ts +184 -0
  24. package/dist/src/schemas.d.ts.map +1 -0
  25. package/dist/src/schemas.js +113 -0
  26. package/dist/src/schemas.js.map +1 -0
  27. package/dist/src/search.d.ts +10 -0
  28. package/dist/src/search.d.ts.map +1 -0
  29. package/dist/src/search.js +99 -0
  30. package/dist/src/search.js.map +1 -0
  31. package/dist/src/server.d.ts +3 -0
  32. package/dist/src/server.d.ts.map +1 -0
  33. package/dist/src/server.js +156 -0
  34. package/dist/src/server.js.map +1 -0
  35. package/dist/src/tools.d.ts +111 -0
  36. package/dist/src/tools.d.ts.map +1 -0
  37. package/dist/src/tools.js +190 -0
  38. package/dist/src/tools.js.map +1 -0
  39. package/dist/src/types.d.ts +31 -0
  40. package/dist/src/types.d.ts.map +1 -0
  41. package/dist/src/types.js +3 -0
  42. package/dist/src/types.js.map +1 -0
  43. package/package.json +56 -0
@@ -0,0 +1,290 @@
1
+ // src/scanner.ts
2
+ // Scan repo for existing .md files, classify them by PCL type, and transform into product/ structure.
3
+ import { readdir, readFile, stat, writeFile, access, mkdir } from "node:fs/promises";
4
+ import { join, relative, basename, dirname, extname } from "node:path";
5
+ import { constants } from "node:fs";
6
+ import matter from "gray-matter";
7
+ // ─── Constants ───────────────────────────────────────────────────────────────
8
+ const SKIP_DIRS = new Set([
9
+ "node_modules", "dist", ".git", "product", ".next", ".nuxt",
10
+ ".output", "build", "coverage", "__pycache__", ".cache",
11
+ ]);
12
+ const SKIP_FILES = new Set([
13
+ "CLAUDE.md", "CHANGELOG.md", "LICENSE.md", "LICENSE",
14
+ "CODE_OF_CONDUCT.md", "CONTRIBUTING.md", "SECURITY.md",
15
+ ]);
16
+ const TYPE_PLURAL = {
17
+ product: "",
18
+ persona: "personas",
19
+ journey: "journeys",
20
+ spec: "specs",
21
+ decision: "decisions",
22
+ domain: "domain",
23
+ };
24
+ const RULES = [
25
+ {
26
+ type: "persona",
27
+ dirs: /^(personas?|users?|user-research)$/i,
28
+ files: /^(persona-.*|.*-persona)\.md$/i,
29
+ fmKeys: ["role", "primary_goal", "jobs_to_be_done", "biggest_fear"],
30
+ contentPatterns: [
31
+ /primary goal/i, /jobs to be done/i, /anti[- ]?patterns?/i, /tech level/i,
32
+ ],
33
+ },
34
+ {
35
+ type: "journey",
36
+ dirs: /^(journeys?|user-journeys?|flows?)$/i,
37
+ files: /^(journey-.*|.*-journey|.*-flow)\.md$/i,
38
+ fmKeys: ["trigger", "success_state", "steps", "failure_modes"],
39
+ contentPatterns: [
40
+ /user journey/i, /\btrigger\b/i, /success state/i, /failure mode/i,
41
+ ],
42
+ },
43
+ {
44
+ type: "spec",
45
+ dirs: /^(specs?|specifications?|features?|requirements?)$/i,
46
+ files: /^(spec-.*|.*-spec|feature-.*|.*-feature|.*-requirement)\.md$/i,
47
+ fmKeys: ["acceptance_criteria", "out_of_scope", "design_ref"],
48
+ contentPatterns: [
49
+ /acceptance criteria/i, /out of scope/i, /\brequirement\b/i,
50
+ ],
51
+ },
52
+ {
53
+ type: "decision",
54
+ dirs: /^(decisions?|adrs?|architecture-decisions?)$/i,
55
+ files: /^(adr-.*|.*-adr|decision-.*)\.md$/i,
56
+ fmKeys: ["context", "decision", "consequences"],
57
+ contentPatterns: [
58
+ /architecture decision/i, /alternatives rejected/i, /\bconsequences?\b/i,
59
+ ],
60
+ },
61
+ {
62
+ type: "domain",
63
+ dirs: /^(domain|rules?|business-rules?|policies?)$/i,
64
+ files: /^(rules-.*|.*-rules|policy-.*)\.md$/i,
65
+ fmKeys: ["critical"],
66
+ contentPatterns: [
67
+ /business rule/i, /\binvariant\b/i, /must never/i, /must always/i,
68
+ ],
69
+ },
70
+ {
71
+ type: "product",
72
+ dirs: /(?!)/, // never matches on dir alone
73
+ files: /^(product|product-brief.*|product-overview.*)\.md$/i,
74
+ fmKeys: ["tagline", "problem", "solution", "tech_stack", "primary_persona"],
75
+ contentPatterns: [
76
+ /north star/i, /\bvision\b/i, /what this product is/i,
77
+ ],
78
+ },
79
+ ];
80
+ // ─── 1a. scanRepo — find all .md files ───────────────────────────────────────
81
+ export async function scanRepo(rootDir) {
82
+ const results = [];
83
+ async function walk(dir) {
84
+ const entries = await readdir(dir, { withFileTypes: true });
85
+ for (const entry of entries) {
86
+ const fullPath = join(dir, entry.name);
87
+ if (entry.isDirectory()) {
88
+ if (SKIP_DIRS.has(entry.name) || entry.name.startsWith("."))
89
+ continue;
90
+ await walk(fullPath);
91
+ }
92
+ else if (entry.isFile() && extname(entry.name) === ".md") {
93
+ if (SKIP_FILES.has(entry.name))
94
+ continue;
95
+ results.push({
96
+ path: fullPath,
97
+ relativePath: relative(rootDir, fullPath),
98
+ });
99
+ }
100
+ }
101
+ }
102
+ await walk(rootDir);
103
+ return results;
104
+ }
105
+ // ─── 1b. classifyFile — heuristic classification ─────────────────────────────
106
+ export function classifyFile(filePath, fm, body) {
107
+ const fileName = basename(filePath);
108
+ const dirName = basename(dirname(filePath));
109
+ const fmKeys = Object.keys(fm);
110
+ let bestType = null;
111
+ let bestScore = 0;
112
+ for (const rule of RULES) {
113
+ let score = 0;
114
+ // Directory name match (high weight: 0.4)
115
+ if (rule.dirs.test(dirName)) {
116
+ score += 0.4;
117
+ }
118
+ // Filename match (medium weight: 0.25)
119
+ if (rule.files.test(fileName)) {
120
+ score += 0.25;
121
+ }
122
+ // Frontmatter keys match (high weight: up to 0.4)
123
+ const fmMatches = rule.fmKeys.filter((k) => fmKeys.includes(k)).length;
124
+ if (rule.fmKeys.length > 0 && fmMatches > 0) {
125
+ // Need at least 2 fm key matches for decision type to avoid false positives
126
+ // (many files have a generic "context" or "decision" key)
127
+ const minMatches = rule.type === "decision" ? 2 : 1;
128
+ if (fmMatches >= minMatches) {
129
+ score += 0.4 * (fmMatches / rule.fmKeys.length);
130
+ }
131
+ }
132
+ // Content keyword match (low weight: up to 0.15)
133
+ const contentMatches = rule.contentPatterns.filter((p) => p.test(body)).length;
134
+ if (contentMatches > 0) {
135
+ score += 0.15 * (contentMatches / rule.contentPatterns.length);
136
+ }
137
+ if (score > bestScore) {
138
+ bestScore = score;
139
+ bestType = rule.type;
140
+ }
141
+ }
142
+ // Minimum threshold to classify
143
+ if (bestType === null || bestScore < 0.25)
144
+ return null;
145
+ return { type: bestType, confidence: Math.min(bestScore, 1) };
146
+ }
147
+ // ─── 1c. transformFile — generate PCL frontmatter ────────────────────────────
148
+ function slugify(str) {
149
+ return str
150
+ .toLowerCase()
151
+ .replace(/\.md$/, "")
152
+ .replace(/[^a-z0-9]+/g, "-")
153
+ .replace(/^-|-$/g, "");
154
+ }
155
+ function extractFirstHeading(body) {
156
+ const match = body.match(/^#\s+(.+)$/m);
157
+ return match ? match[1].trim() : null;
158
+ }
159
+ export function transformFile(filePath, fm, body, type, mtime) {
160
+ const fileName = basename(filePath, ".md");
161
+ const slug = slugify(fileName);
162
+ const heading = extractFirstHeading(body);
163
+ const newFm = { ...fm };
164
+ switch (type) {
165
+ case "persona":
166
+ newFm.id ??= slug;
167
+ newFm.name ??= fm.title ?? heading ?? fileName;
168
+ newFm.role ??= "";
169
+ newFm.primary_goal ??= "";
170
+ newFm.jobs_to_be_done ??= [];
171
+ newFm.anti_patterns ??= [];
172
+ newFm.channels ??= [];
173
+ break;
174
+ case "journey":
175
+ newFm.id ??= slug;
176
+ newFm.name ??= fm.title ?? heading ?? fileName;
177
+ newFm.persona ??= "";
178
+ newFm.trigger ??= "";
179
+ newFm.success_state ??= "";
180
+ newFm.failure_modes ??= [];
181
+ newFm.steps ??= [];
182
+ break;
183
+ case "spec":
184
+ newFm.id ??= slug;
185
+ newFm.title ??= fm.name ?? heading ?? fileName;
186
+ newFm.status ??= "draft";
187
+ newFm.acceptance_criteria ??= [];
188
+ newFm.out_of_scope ??= [];
189
+ break;
190
+ case "decision":
191
+ newFm.id ??= slug;
192
+ newFm.title ??= fm.name ?? heading ?? fileName;
193
+ newFm.status ??= "accepted";
194
+ newFm.date ??= mtime.toISOString().slice(0, 10);
195
+ newFm.context ??= "";
196
+ newFm.decision ??= "";
197
+ newFm.consequences ??= [];
198
+ newFm.alternatives_rejected ??= [];
199
+ break;
200
+ case "domain":
201
+ newFm.id ??= slug;
202
+ newFm.critical ??= false;
203
+ newFm.title ??= fm.name ?? heading ?? fileName;
204
+ break;
205
+ case "product":
206
+ newFm.name ??= fm.title ?? heading ?? fileName;
207
+ newFm.tagline ??= "";
208
+ newFm.problem ??= "";
209
+ newFm.solution ??= "";
210
+ newFm.primary_persona ??= "";
211
+ newFm.tech_stack ??= [];
212
+ newFm.stage ??= "prototype";
213
+ break;
214
+ }
215
+ // Determine target path
216
+ const subDir = TYPE_PLURAL[type];
217
+ const targetPath = subDir
218
+ ? join(subDir, `${slug}.md`)
219
+ : "product.md";
220
+ return { frontmatter: newFm, body, targetPath };
221
+ }
222
+ // ─── 1d. runScan — orchestrate ───────────────────────────────────────────────
223
+ export async function runScan(rootDir, productDir) {
224
+ const summary = {
225
+ imported: [],
226
+ skipped: [],
227
+ unclassified: [],
228
+ };
229
+ console.log(`Scanning ${rootDir}...`);
230
+ const files = await scanRepo(rootDir);
231
+ console.log(`Found ${files.length} markdown file${files.length === 1 ? "" : "s"}\n`);
232
+ if (files.length === 0)
233
+ return summary;
234
+ console.log("Classified:");
235
+ for (const file of files) {
236
+ const raw = await readFile(file.path, "utf8");
237
+ const parsed = matter(raw);
238
+ const fm = parsed.data;
239
+ const classification = classifyFile(file.path, fm, parsed.content);
240
+ if (!classification) {
241
+ summary.unclassified.push(file.relativePath);
242
+ continue;
243
+ }
244
+ const { type, confidence } = classification;
245
+ const fileStat = await stat(file.path);
246
+ const transformed = transformFile(file.path, fm, parsed.content, type, fileStat.mtime);
247
+ const destPath = join(productDir, transformed.targetPath);
248
+ const destRelative = relative(rootDir, destPath);
249
+ // Check if target already exists
250
+ try {
251
+ await access(destPath, constants.F_OK);
252
+ console.log(` ↷ ${destRelative} already exists, skipped`);
253
+ summary.skipped.push({
254
+ sourcePath: file.relativePath,
255
+ targetPath: transformed.targetPath,
256
+ type,
257
+ confidence,
258
+ });
259
+ continue;
260
+ }
261
+ catch {
262
+ // File doesn't exist — proceed
263
+ }
264
+ // Ensure target directory exists
265
+ await mkdir(dirname(destPath), { recursive: true });
266
+ // Write the transformed file
267
+ const output = matter.stringify(transformed.body, transformed.frontmatter);
268
+ await writeFile(destPath, output, "utf8");
269
+ console.log(` ✓ ${file.relativePath} → ${destRelative} [${type}, confidence: ${confidence.toFixed(2)}]`);
270
+ summary.imported.push({
271
+ sourcePath: file.relativePath,
272
+ targetPath: transformed.targetPath,
273
+ type,
274
+ confidence,
275
+ });
276
+ }
277
+ // Print unclassified
278
+ if (summary.unclassified.length > 0) {
279
+ console.log("\nSkipped (not classifiable):");
280
+ for (const path of summary.unclassified) {
281
+ console.log(` · ${path}`);
282
+ }
283
+ }
284
+ const skipCount = summary.skipped.length;
285
+ console.log(`\nSummary: ${summary.imported.length} imported, ` +
286
+ `${skipCount} skipped (exists), ` +
287
+ `${summary.unclassified.length} unclassified`);
288
+ return summary;
289
+ }
290
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/scanner.ts"],"names":[],"mappings":"AAAA,iBAAiB;AACjB,sGAAsG;AAEtG,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACrF,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,MAAM,MAAM,aAAa,CAAC;AAkCjC,gFAAgF;AAEhF,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC;IACxB,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO;IAC3D,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,QAAQ;CACxD,CAAC,CAAC;AAEH,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC;IACzB,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,SAAS;IACpD,oBAAoB,EAAE,iBAAiB,EAAE,aAAa;CACvD,CAAC,CAAC;AAEH,MAAM,WAAW,GAA6B;IAC5C,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,UAAU;IACnB,OAAO,EAAE,UAAU;IACnB,IAAI,EAAE,OAAO;IACb,QAAQ,EAAE,WAAW;IACrB,MAAM,EAAE,QAAQ;CACjB,CAAC;AAYF,MAAM,KAAK,GAAyB;IAClC;QACE,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,qCAAqC;QAC3C,KAAK,EAAE,gCAAgC;QACvC,MAAM,EAAE,CAAC,MAAM,EAAE,cAAc,EAAE,iBAAiB,EAAE,cAAc,CAAC;QACnE,eAAe,EAAE;YACf,eAAe,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,aAAa;SAC1E;KACF;IACD;QACE,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,sCAAsC;QAC5C,KAAK,EAAE,wCAAwC;QAC/C,MAAM,EAAE,CAAC,SAAS,EAAE,eAAe,EAAE,OAAO,EAAE,eAAe,CAAC;QAC9D,eAAe,EAAE;YACf,eAAe,EAAE,cAAc,EAAE,gBAAgB,EAAE,eAAe;SACnE;KACF;IACD;QACE,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,qDAAqD;QAC3D,KAAK,EAAE,+DAA+D;QACtE,MAAM,EAAE,CAAC,qBAAqB,EAAE,cAAc,EAAE,YAAY,CAAC;QAC7D,eAAe,EAAE;YACf,sBAAsB,EAAE,eAAe,EAAE,kBAAkB;SAC5D;KACF;IACD;QACE,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,+CAA+C;QACrD,KAAK,EAAE,oCAAoC;QAC3C,MAAM,EAAE,CAAC,SAAS,EAAE,UAAU,EAAE,cAAc,CAAC;QAC/C,eAAe,EAAE;YACf,wBAAwB,EAAE,wBAAwB,EAAE,oBAAoB;SACzE;KACF;IACD;QACE,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,8CAA8C;QACpD,KAAK,EAAE,sCAAsC;QAC7C,MAAM,EAAE,CAAC,UAAU,CAAC;QACpB,eAAe,EAAE;YACf,gBAAgB,EAAE,gBAAgB,EAAE,aAAa,EAAE,cAAc;SAClE;KACF;IACD;QACE,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,MAAM,EAAG,6BAA6B;QAC5C,KAAK,EAAE,qDAAqD;QAC5D,MAAM,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,CAAC;QAC3E,eAAe,EAAE;YACf,aAAa,EAAE,aAAa,EAAE,uBAAuB;SACtD;KACF;CACF,CAAC;AAEF,gFAAgF;AAEhF,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,OAAe;IAC5C,MAAM,OAAO,GAAkB,EAAE,CAAC;IAElC,KAAK,UAAU,IAAI,CAAC,GAAW;QAC7B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACvC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;oBAAE,SAAS;gBACtE,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;YACvB,CAAC;iBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,EAAE,CAAC;gBAC3D,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;oBAAE,SAAS;gBACzC,OAAO,CAAC,IAAI,CAAC;oBACX,IAAI,EAAE,QAAQ;oBACd,YAAY,EAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;iBAC1C,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC;IACpB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,gFAAgF;AAEhF,MAAM,UAAU,YAAY,CAC1B,QAAgB,EAChB,EAA2B,EAC3B,IAAY;IAEZ,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACpC,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAE/B,IAAI,QAAQ,GAAoB,IAAI,CAAC;IACrC,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,KAAK,GAAG,CAAC,CAAC;QAEd,0CAA0C;QAC1C,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,KAAK,IAAI,GAAG,CAAC;QACf,CAAC;QAED,uCAAuC;QACvC,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC9B,KAAK,IAAI,IAAI,CAAC;QAChB,CAAC;QAED,kDAAkD;QAClD,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QACvE,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;YAC5C,4EAA4E;YAC5E,0DAA0D;YAC1D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACpD,IAAI,SAAS,IAAI,UAAU,EAAE,CAAC;gBAC5B,KAAK,IAAI,GAAG,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAClD,CAAC;QACH,CAAC;QAED,iDAAiD;QACjD,MAAM,cAAc,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;QAC/E,IAAI,cAAc,GAAG,CAAC,EAAE,CAAC;YACvB,KAAK,IAAI,IAAI,GAAG,CAAC,cAAc,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QACjE,CAAC;QAED,IAAI,KAAK,GAAG,SAAS,EAAE,CAAC;YACtB,SAAS,GAAG,KAAK,CAAC;YAClB,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC;QACvB,CAAC;IACH,CAAC;IAED,gCAAgC;IAChC,IAAI,QAAQ,KAAK,IAAI,IAAI,SAAS,GAAG,IAAI;QAAE,OAAO,IAAI,CAAC;IAEvD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC;AAChE,CAAC;AAED,gFAAgF;AAEhF,SAAS,OAAO,CAAC,GAAW;IAC1B,OAAO,GAAG;SACP,WAAW,EAAE;SACb,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;SACpB,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,mBAAmB,CAAC,IAAY;IACvC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IACxC,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,QAAgB,EAChB,EAA2B,EAC3B,IAAY,EACZ,IAAc,EACd,KAAW;IAEX,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/B,MAAM,OAAO,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IAE1C,MAAM,KAAK,GAA4B,EAAE,GAAG,EAAE,EAAE,CAAC;IAEjD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,SAAS;YACZ,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC;YAClB,KAAK,CAAC,IAAI,KAAK,EAAE,CAAC,KAAK,IAAI,OAAO,IAAI,QAAQ,CAAC;YAC/C,KAAK,CAAC,IAAI,KAAK,EAAE,CAAC;YAClB,KAAK,CAAC,YAAY,KAAK,EAAE,CAAC;YAC1B,KAAK,CAAC,eAAe,KAAK,EAAE,CAAC;YAC7B,KAAK,CAAC,aAAa,KAAK,EAAE,CAAC;YAC3B,KAAK,CAAC,QAAQ,KAAK,EAAE,CAAC;YACtB,MAAM;QAER,KAAK,SAAS;YACZ,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC;YAClB,KAAK,CAAC,IAAI,KAAK,EAAE,CAAC,KAAK,IAAI,OAAO,IAAI,QAAQ,CAAC;YAC/C,KAAK,CAAC,OAAO,KAAK,EAAE,CAAC;YACrB,KAAK,CAAC,OAAO,KAAK,EAAE,CAAC;YACrB,KAAK,CAAC,aAAa,KAAK,EAAE,CAAC;YAC3B,KAAK,CAAC,aAAa,KAAK,EAAE,CAAC;YAC3B,KAAK,CAAC,KAAK,KAAK,EAAE,CAAC;YACnB,MAAM;QAER,KAAK,MAAM;YACT,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC;YAClB,KAAK,CAAC,KAAK,KAAK,EAAE,CAAC,IAAI,IAAI,OAAO,IAAI,QAAQ,CAAC;YAC/C,KAAK,CAAC,MAAM,KAAK,OAAO,CAAC;YACzB,KAAK,CAAC,mBAAmB,KAAK,EAAE,CAAC;YACjC,KAAK,CAAC,YAAY,KAAK,EAAE,CAAC;YAC1B,MAAM;QAER,KAAK,UAAU;YACb,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC;YAClB,KAAK,CAAC,KAAK,KAAK,EAAE,CAAC,IAAI,IAAI,OAAO,IAAI,QAAQ,CAAC;YAC/C,KAAK,CAAC,MAAM,KAAK,UAAU,CAAC;YAC5B,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAChD,KAAK,CAAC,OAAO,KAAK,EAAE,CAAC;YACrB,KAAK,CAAC,QAAQ,KAAK,EAAE,CAAC;YACtB,KAAK,CAAC,YAAY,KAAK,EAAE,CAAC;YAC1B,KAAK,CAAC,qBAAqB,KAAK,EAAE,CAAC;YACnC,MAAM;QAER,KAAK,QAAQ;YACX,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC;YAClB,KAAK,CAAC,QAAQ,KAAK,KAAK,CAAC;YACzB,KAAK,CAAC,KAAK,KAAK,EAAE,CAAC,IAAI,IAAI,OAAO,IAAI,QAAQ,CAAC;YAC/C,MAAM;QAER,KAAK,SAAS;YACZ,KAAK,CAAC,IAAI,KAAK,EAAE,CAAC,KAAK,IAAI,OAAO,IAAI,QAAQ,CAAC;YAC/C,KAAK,CAAC,OAAO,KAAK,EAAE,CAAC;YACrB,KAAK,CAAC,OAAO,KAAK,EAAE,CAAC;YACrB,KAAK,CAAC,QAAQ,KAAK,EAAE,CAAC;YACtB,KAAK,CAAC,eAAe,KAAK,EAAE,CAAC;YAC7B,KAAK,CAAC,UAAU,KAAK,EAAE,CAAC;YACxB,KAAK,CAAC,KAAK,KAAK,WAAW,CAAC;YAC5B,MAAM;IACV,CAAC;IAED,wBAAwB;IACxB,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,UAAU,GAAG,MAAM;QACvB,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,KAAK,CAAC;QAC5B,CAAC,CAAC,YAAY,CAAC;IAEjB,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;AAClD,CAAC;AAED,gFAAgF;AAEhF,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,OAAe,EACf,UAAkB;IAElB,MAAM,OAAO,GAAgB;QAC3B,QAAQ,EAAE,EAAE;QACZ,OAAO,EAAE,EAAE;QACX,YAAY,EAAE,EAAE;KACjB,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,YAAY,OAAO,KAAK,CAAC,CAAC;IACtC,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC;IACtC,OAAO,CAAC,GAAG,CAAC,SAAS,KAAK,CAAC,MAAM,iBAAiB,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAErF,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IAEvC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAE3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC3B,MAAM,EAAE,GAAG,MAAM,CAAC,IAA+B,CAAC;QAElD,MAAM,cAAc,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;QACnE,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAC7C,SAAS;QACX,CAAC;QAED,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,cAAc,CAAC;QAC5C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvC,MAAM,WAAW,GAAG,aAAa,CAC/B,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,KAAK,CACpD,CAAC;QAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC;QAC1D,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAEjD,iCAAiC;QACjC,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;YACvC,OAAO,CAAC,GAAG,CAAC,OAAO,YAAY,0BAA0B,CAAC,CAAC;YAC3D,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;gBACnB,UAAU,EAAE,IAAI,CAAC,YAAY;gBAC7B,UAAU,EAAE,WAAW,CAAC,UAAU;gBAClC,IAAI;gBACJ,UAAU;aACX,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAAC,MAAM,CAAC;YACP,+BAA+B;QACjC,CAAC;QAED,iCAAiC;QACjC,MAAM,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEpD,6BAA6B;QAC7B,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;QAC3E,MAAM,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAE1C,OAAO,CAAC,GAAG,CACT,OAAO,IAAI,CAAC,YAAY,MAAM,YAAY,KAAK,IAAI,iBAAiB,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAC7F,CAAC;QACF,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;YACpB,UAAU,EAAE,IAAI,CAAC,YAAY;YAC7B,UAAU,EAAE,WAAW,CAAC,UAAU;YAClC,IAAI;YACJ,UAAU;SACX,CAAC,CAAC;IACL,CAAC;IAED,qBAAqB;IACrB,IAAI,OAAO,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;QAC7C,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;YACxC,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC;IACzC,OAAO,CAAC,GAAG,CACT,cAAc,OAAO,CAAC,QAAQ,CAAC,MAAM,aAAa;QAClD,GAAG,SAAS,qBAAqB;QACjC,GAAG,OAAO,CAAC,YAAY,CAAC,MAAM,eAAe,CAC9C,CAAC;IAEF,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,184 @@
1
+ import { z } from "zod";
2
+ import type { FileType } from "./types.js";
3
+ export declare const ProductSchema: z.ZodObject<{
4
+ name: z.ZodString;
5
+ tagline: z.ZodString;
6
+ problem: z.ZodString;
7
+ solution: z.ZodString;
8
+ primary_persona: z.ZodString;
9
+ tech_stack: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
10
+ stage: z.ZodEnum<["idea", "prototype", "early_revenue", "growth", "mature"]>;
11
+ repo: z.ZodOptional<z.ZodString>;
12
+ url: z.ZodOptional<z.ZodString>;
13
+ }, "strip", z.ZodTypeAny, {
14
+ name: string;
15
+ tagline: string;
16
+ problem: string;
17
+ solution: string;
18
+ primary_persona: string;
19
+ tech_stack: string[];
20
+ stage: "idea" | "prototype" | "early_revenue" | "growth" | "mature";
21
+ repo?: string | undefined;
22
+ url?: string | undefined;
23
+ }, {
24
+ name: string;
25
+ tagline: string;
26
+ problem: string;
27
+ solution: string;
28
+ primary_persona: string;
29
+ stage: "idea" | "prototype" | "early_revenue" | "growth" | "mature";
30
+ tech_stack?: string[] | undefined;
31
+ repo?: string | undefined;
32
+ url?: string | undefined;
33
+ }>;
34
+ export declare const PersonaSchema: z.ZodObject<{
35
+ id: z.ZodString;
36
+ name: z.ZodString;
37
+ role: z.ZodString;
38
+ age_range: z.ZodOptional<z.ZodString>;
39
+ tech_level: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
40
+ primary_goal: z.ZodString;
41
+ biggest_fear: z.ZodOptional<z.ZodString>;
42
+ jobs_to_be_done: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
43
+ anti_patterns: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
44
+ channels: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
45
+ }, "strip", z.ZodTypeAny, {
46
+ channels: string[];
47
+ name: string;
48
+ id: string;
49
+ role: string;
50
+ primary_goal: string;
51
+ jobs_to_be_done: string[];
52
+ anti_patterns: string[];
53
+ age_range?: string | undefined;
54
+ tech_level?: "low" | "medium" | "high" | undefined;
55
+ biggest_fear?: string | undefined;
56
+ }, {
57
+ name: string;
58
+ id: string;
59
+ role: string;
60
+ primary_goal: string;
61
+ channels?: string[] | undefined;
62
+ age_range?: string | undefined;
63
+ tech_level?: "low" | "medium" | "high" | undefined;
64
+ biggest_fear?: string | undefined;
65
+ jobs_to_be_done?: string[] | undefined;
66
+ anti_patterns?: string[] | undefined;
67
+ }>;
68
+ export declare const JourneyStepSchema: z.ZodObject<{
69
+ id: z.ZodString;
70
+ goal: z.ZodOptional<z.ZodString>;
71
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
72
+ id: z.ZodString;
73
+ goal: z.ZodOptional<z.ZodString>;
74
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
75
+ id: z.ZodString;
76
+ goal: z.ZodOptional<z.ZodString>;
77
+ }, z.ZodTypeAny, "passthrough">>;
78
+ export declare const JourneySchema: z.ZodObject<{
79
+ id: z.ZodString;
80
+ name: z.ZodOptional<z.ZodString>;
81
+ persona: z.ZodString;
82
+ trigger: z.ZodString;
83
+ success_state: z.ZodString;
84
+ failure_modes: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
85
+ steps: z.ZodArray<z.ZodString, "many">;
86
+ }, "strip", z.ZodTypeAny, {
87
+ persona: string;
88
+ id: string;
89
+ trigger: string;
90
+ success_state: string;
91
+ failure_modes: string[];
92
+ steps: string[];
93
+ name?: string | undefined;
94
+ }, {
95
+ persona: string;
96
+ id: string;
97
+ trigger: string;
98
+ success_state: string;
99
+ steps: string[];
100
+ name?: string | undefined;
101
+ failure_modes?: string[] | undefined;
102
+ }>;
103
+ export declare const SpecSchema: z.ZodObject<{
104
+ id: z.ZodString;
105
+ title: z.ZodString;
106
+ persona: z.ZodOptional<z.ZodString>;
107
+ journey: z.ZodOptional<z.ZodString>;
108
+ status: z.ZodEnum<["draft", "approved", "in-progress", "done", "deprecated"]>;
109
+ acceptance_criteria: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
110
+ out_of_scope: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
111
+ design_ref: z.ZodOptional<z.ZodString>;
112
+ }, "strip", z.ZodTypeAny, {
113
+ status: "draft" | "approved" | "in-progress" | "done" | "deprecated";
114
+ id: string;
115
+ title: string;
116
+ acceptance_criteria: string[];
117
+ out_of_scope: string[];
118
+ persona?: string | undefined;
119
+ journey?: string | undefined;
120
+ design_ref?: string | undefined;
121
+ }, {
122
+ status: "draft" | "approved" | "in-progress" | "done" | "deprecated";
123
+ id: string;
124
+ title: string;
125
+ persona?: string | undefined;
126
+ journey?: string | undefined;
127
+ acceptance_criteria?: string[] | undefined;
128
+ out_of_scope?: string[] | undefined;
129
+ design_ref?: string | undefined;
130
+ }>;
131
+ export declare const DecisionSchema: z.ZodObject<{
132
+ id: z.ZodString;
133
+ title: z.ZodString;
134
+ status: z.ZodEnum<["proposed", "accepted", "deprecated", "superseded"]>;
135
+ date: z.ZodString;
136
+ context: z.ZodString;
137
+ decision: z.ZodString;
138
+ consequences: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
139
+ alternatives_rejected: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
140
+ superseded_by: z.ZodOptional<z.ZodString>;
141
+ }, "strip", z.ZodTypeAny, {
142
+ decision: string;
143
+ status: "deprecated" | "proposed" | "accepted" | "superseded";
144
+ date: string;
145
+ id: string;
146
+ title: string;
147
+ context: string;
148
+ consequences: string[];
149
+ alternatives_rejected: string[];
150
+ superseded_by?: string | undefined;
151
+ }, {
152
+ decision: string;
153
+ status: "deprecated" | "proposed" | "accepted" | "superseded";
154
+ date: string;
155
+ id: string;
156
+ title: string;
157
+ context: string;
158
+ consequences?: string[] | undefined;
159
+ alternatives_rejected?: string[] | undefined;
160
+ superseded_by?: string | undefined;
161
+ }>;
162
+ export declare const DomainSchema: z.ZodObject<{
163
+ id: z.ZodString;
164
+ critical: z.ZodDefault<z.ZodBoolean>;
165
+ title: z.ZodOptional<z.ZodString>;
166
+ }, "strip", z.ZodTypeAny, {
167
+ id: string;
168
+ critical: boolean;
169
+ title?: string | undefined;
170
+ }, {
171
+ id: string;
172
+ title?: string | undefined;
173
+ critical?: boolean | undefined;
174
+ }>;
175
+ export declare const SCHEMAS: Record<FileType, z.ZodObject<z.ZodRawShape>>;
176
+ export declare function validateFrontmatter(type: FileType, data: unknown): {
177
+ success: true;
178
+ data: Record<string, unknown>;
179
+ } | {
180
+ success: false;
181
+ error: string;
182
+ };
183
+ export declare function deriveTitle(type: FileType, fm: Record<string, unknown>): string;
184
+ //# sourceMappingURL=schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/schemas.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAS3C,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUxB,CAAC;AAIH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWxB,CAAC;AAIH,eAAO,MAAM,iBAAiB;;;;;;;;;gCAGd,CAAC;AAEjB,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;EAQxB,CAAC;AAIH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;EASrB,CAAC;AAIH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUzB,CAAC;AAIH,eAAO,MAAM,YAAY;;;;;;;;;;;;EAIvB,CAAC;AAIH,eAAO,MAAM,OAAO,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAOhE,CAAC;AAEF,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,OAAO,GACZ;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAUtF;AAGD,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAQ/E"}
@@ -0,0 +1,113 @@
1
+ // src/schemas.ts
2
+ // Zod schemas for every file type.
3
+ // These are the contracts — agents rely on predictable structure.
4
+ import { z } from "zod";
5
+ // ─── Shared ───────────────────────────────────────────────────────────────────
6
+ const StringList = z.array(z.string()).default([]);
7
+ const OptStr = z.string().optional();
8
+ // ─── product.md ───────────────────────────────────────────────────────────────
9
+ export const ProductSchema = z.object({
10
+ name: z.string(),
11
+ tagline: z.string(),
12
+ problem: z.string(),
13
+ solution: z.string(),
14
+ primary_persona: z.string(),
15
+ tech_stack: StringList,
16
+ stage: z.enum(["idea", "prototype", "early_revenue", "growth", "mature"]),
17
+ repo: OptStr,
18
+ url: OptStr,
19
+ });
20
+ // ─── personas/*.md ────────────────────────────────────────────────────────────
21
+ export const PersonaSchema = z.object({
22
+ id: z.string(),
23
+ name: z.string(),
24
+ role: z.string(),
25
+ age_range: OptStr,
26
+ tech_level: z.enum(["low", "medium", "high"]).optional(),
27
+ primary_goal: z.string(),
28
+ biggest_fear: OptStr,
29
+ jobs_to_be_done: StringList,
30
+ anti_patterns: StringList,
31
+ channels: StringList, // where they hang out
32
+ });
33
+ // ─── journeys/*.md ────────────────────────────────────────────────────────────
34
+ export const JourneyStepSchema = z.object({
35
+ id: z.string(),
36
+ goal: OptStr,
37
+ }).passthrough(); // allow extra step-level keys
38
+ export const JourneySchema = z.object({
39
+ id: z.string(),
40
+ name: z.string().optional(),
41
+ persona: z.string(),
42
+ trigger: z.string(),
43
+ success_state: z.string(),
44
+ failure_modes: StringList,
45
+ steps: z.array(z.string()), // ordered list of step IDs
46
+ });
47
+ // ─── specs/*.md ───────────────────────────────────────────────────────────────
48
+ export const SpecSchema = z.object({
49
+ id: z.string(),
50
+ title: z.string(),
51
+ persona: z.string().optional(),
52
+ journey: z.string().optional(), // links to journey ID
53
+ status: z.enum(["draft", "approved", "in-progress", "done", "deprecated"]),
54
+ acceptance_criteria: StringList,
55
+ out_of_scope: StringList,
56
+ design_ref: OptStr, // Figma URL or local path
57
+ });
58
+ // ─── decisions/*.md ───────────────────────────────────────────────────────────
59
+ export const DecisionSchema = z.object({
60
+ id: z.string(),
61
+ title: z.string(),
62
+ status: z.enum(["proposed", "accepted", "deprecated", "superseded"]),
63
+ date: z.string(), // ISO date string
64
+ context: z.string(),
65
+ decision: z.string(),
66
+ consequences: StringList,
67
+ alternatives_rejected: StringList,
68
+ superseded_by: OptStr,
69
+ });
70
+ // ─── domain/*.md ──────────────────────────────────────────────────────────────
71
+ export const DomainSchema = z.object({
72
+ id: z.string(),
73
+ critical: z.boolean().default(false), // if true, always loaded at session start
74
+ title: z.string().optional(),
75
+ });
76
+ // ─── Schema registry ──────────────────────────────────────────────────────────
77
+ export const SCHEMAS = {
78
+ product: ProductSchema,
79
+ persona: PersonaSchema,
80
+ journey: JourneySchema,
81
+ spec: SpecSchema,
82
+ decision: DecisionSchema,
83
+ domain: DomainSchema,
84
+ };
85
+ export function validateFrontmatter(type, data) {
86
+ const schema = SCHEMAS[type];
87
+ const result = schema.safeParse(data);
88
+ if (result.success)
89
+ return { success: true, data: result.data };
90
+ return {
91
+ success: false,
92
+ error: result.error.issues
93
+ .map((i) => `${i.path.join(".")}: ${i.message}`)
94
+ .join("; "),
95
+ };
96
+ }
97
+ // Derive a display title from frontmatter
98
+ export function deriveTitle(type, fm) {
99
+ if (type === "product")
100
+ return String(fm.name ?? "Untitled product");
101
+ if (type === "persona")
102
+ return String(fm.name ?? fm.id ?? "Unnamed persona");
103
+ if (type === "journey")
104
+ return String(fm.name ?? fm.id ?? "Unnamed journey");
105
+ if (type === "spec")
106
+ return String(fm.title ?? fm.id ?? "Unnamed spec");
107
+ if (type === "decision")
108
+ return String(fm.title ?? fm.id ?? "Unnamed decision");
109
+ if (type === "domain")
110
+ return String(fm.title ?? fm.id ?? "Domain rules");
111
+ return "Unknown";
112
+ }
113
+ //# sourceMappingURL=schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../src/schemas.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type Database from "better-sqlite3";
2
+ import type { SearchResult } from "./types.js";
3
+ export type SearchMode = "hybrid" | "semantic" | "keyword";
4
+ export declare function search(db: Database.Database, query: string, opts?: {
5
+ mode?: SearchMode;
6
+ topK?: number;
7
+ types?: string[];
8
+ }): Promise<SearchResult[]>;
9
+ export declare function findRelated(db: Database.Database, sourceId: string, topK?: number): Promise<SearchResult[]>;
10
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/search.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAe,YAAY,EAAa,MAAM,YAAY,CAAC;AA2CvE,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;AAE3D,wBAAsB,MAAM,CAC1B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,KAAK,EAAE,MAAM,EACb,IAAI,GAAE;IACJ,IAAI,CAAC,EAAK,UAAU,CAAC;IACrB,IAAI,CAAC,EAAK,MAAM,CAAC;IACjB,KAAK,CAAC,EAAI,MAAM,EAAE,CAAC;CACf,GACL,OAAO,CAAC,YAAY,EAAE,CAAC,CAwCzB;AAID,wBAAsB,WAAW,CAC/B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,QAAQ,EAAE,MAAM,EAChB,IAAI,SAAI,GACP,OAAO,CAAC,YAAY,EAAE,CAAC,CA4BzB"}