@directive-run/knowledge 1.21.0 → 1.23.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.
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # @directive-run/knowledge
2
2
 
3
- The **source of truth** for all Directive coding knowledge used by Claude Code skills, Cursor / Copilot / Windsurf / Cline / Codex rules files, the website's `/llms.txt` route, and the programmatic API for downstream tooling.
3
+ The **source of truth** for all Directive coding knowledge used by Claude Code skills, Cursor / Copilot / Windsurf / Cline / Codex rules files, the website's `/llms.txt` route, and the programmatic API for downstream tooling.
4
4
 
5
- If you want your AI assistant to write idiomatic Directive code, you do not install this package directly you install one of its consumers below.
5
+ If you want your AI assistant to write idiomatic Directive code, you do not install this package directly you install one of its consumers below.
6
6
 
7
7
  ## Using the knowledge
8
8
 
@@ -15,7 +15,7 @@ Two commands in a Claude Code session:
15
15
  /plugin install directive@directive-plugins
16
16
  ```
17
17
 
18
- Ships 12 skills bundled from this package. Skills are model-invoked Claude reads each skill's description and auto-loads the relevant one when your task matches.
18
+ Ships 12 skills bundled from this package. Skills are model-invoked Claude reads each skill's description and auto-loads the relevant one when your task matches.
19
19
 
20
20
  ### Cursor, Copilot, Windsurf, Cline, OpenAI Codex
21
21
 
@@ -63,7 +63,7 @@ const examples = getAllExamples();
63
63
  clearCache();
64
64
  ```
65
65
 
66
- If you're just trying to write code with AI help, you don't need this install the Claude plugin or run `directive ai-rules` above.
66
+ If you're just trying to write code with AI help, you don't need this install the Claude plugin or run `directive ai-rules` above.
67
67
 
68
68
  ## What's in the package
69
69
 
@@ -156,7 +156,8 @@ seven pieces of work, zero `useEffect` hooks.
156
156
  - [`sources.md`](./sources.md) — the source primitive's full lifecycle
157
157
  and recipes.
158
158
  - [`constraints.md`](./constraints.md) — `when` predicates, requirement
159
- shapes, and the `bind` / `owns` field-scoped CAS contract.
159
+ shapes, and the `abortOn` field-scoped CAS contract (v1; `bind:` is a
160
+ v2 reservation – see RFC 0003 Future Work).
160
161
  - [`resolvers.md`](./resolvers.md) — retry config, batch semantics, and
161
162
  the `ctx.set` write contract.
162
163
  - [`anti-patterns.md`](./anti-patterns.md) — the things to avoid that
package/core/resolvers.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Resolvers
2
2
 
3
- > Covers `@directive-run/core` — resolver definition: retry policies, batching, cancellation, custom dedup keys, `owns` binding.
3
+ > Covers `@directive-run/core` — resolver definition: retry policies, batching, cancellation, custom dedup keys, `abortOn` binding.
4
4
 
5
5
  Resolvers fulfill requirements emitted by constraints. They are the supply side of the constraint-resolver pattern. Resolvers handle async work and mutate state through `context.facts`.
6
6
 
@@ -205,6 +205,31 @@ resolvers: {
205
205
 
206
206
  Failed items from `resolveBatchWithResults` can be individually retried if a retry policy is configured.
207
207
 
208
+ ## `abortOn` binding (constraint-side)
209
+
210
+ Declared on the *constraint*, not the resolver. Lists facts whose values
211
+ must remain unchanged between dispatch and the resolver's writes; if any
212
+ of them changes mid-flight, the resolver's writes are dropped and its
213
+ signal is aborted.
214
+
215
+ ```typescript
216
+ constraints: {
217
+ finalizeKyc: {
218
+ when: (f) => f.kyc.status === "pending",
219
+ require: { type: "FINALIZE_KYC" },
220
+ abortOn: ["kyc.status"], // abort if `kyc.status` changes mid-flight
221
+ },
222
+ },
223
+ ```
224
+
225
+ `abortOn:` does **not** lock or gate other writers. It only protects this
226
+ resolver from clobbering with stale data when its tail write attempts a
227
+ value the world has since moved past. See
228
+ [`/docs/resolver-binding`](https://directive.run/docs/resolver-binding)
229
+ for the full lifecycle, ABA caveats, and the audit event
230
+ (`resolver.write.rejected { reason: "clobbered" }`) that fires on a
231
+ dropped write.
232
+
208
233
  ## Timeout
209
234
 
210
235
  ```typescript
package/dist/index.cjs CHANGED
@@ -1,16 +1,16 @@
1
- 'use strict';var fs=require('fs'),path=require('path'),url=require('url');var _documentCurrentScript=typeof document!=='undefined'?document.currentScript:null;var K=path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)))),A=path.resolve(K,".."),l=null;function L(){let t=[path.join(A,"core","anti-patterns.md"),path.join(A,"..","core","anti-patterns.md")];for(let e of t)if(fs.existsSync(e))return e;return t[0]??""}function k(t){return t.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").replace(/-{2,}/g,"-")}function z(t){let e=t.toLowerCase();return /schema|builder/.test(e)?"schema":/constraint|cross-?module|require/.test(e)?"constraint":/resolver|settle|start/.test(e)?"resolver":/deriv|passthrough/.test(e)?"derivation":/effect/.test(e)?"effect":/usedirective|react|hook/.test(e)?"react":/import|bracket|deep import|name|context|abbreviat/.test(e)?"naming":("module")}function G(t){let e=t.toLowerCase();return /nonexistent|missing|no error|deep import|async logic/.test(e)?"error":"warning"}function U(t){let e=t.split(`
1
+ 'use strict';var fs=require('fs'),path=require('path'),url=require('url');var _documentCurrentScript=typeof document!=='undefined'?document.currentScript:null;var K=path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)))),C=path.resolve(K,".."),l=null;function L(){let t=[path.join(C,"core","anti-patterns.md"),path.join(C,"..","core","anti-patterns.md")];for(let e of t)if(fs.existsSync(e))return e;return t[0]??""}function k(t){return t.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").replace(/-{2,}/g,"-")}function z(t){let e=t.toLowerCase();return /schema|builder/.test(e)?"schema":/constraint|cross-?module|require/.test(e)?"constraint":/resolver|settle|start/.test(e)?"resolver":/deriv|passthrough/.test(e)?"derivation":/effect/.test(e)?"effect":/usedirective|react|hook/.test(e)?"react":/import|bracket|deep import|name|context|abbreviat/.test(e)?"naming":("module")}function G(t){let e=t.toLowerCase();return /nonexistent|missing|no error|deep import|async logic/.test(e)?"error":"warning"}function U(t){let e=t.split(`
2
2
  `),r=[],n=null,o=/^##\s+(\d+)\.\s+(.+?)\s*$/;for(let c of e){let a=o.exec(c);if(a?.[1]&&a?.[2]){n&&r.push(n),n={number:Number(a[1]),title:a[2],body:""};continue}if(n){if(/^##\s+\D/.test(c)){r.push(n),n=null;break}n.body+=`${c}
3
3
  `;}}return n&&r.push(n),r}function $(t){let e=t.match(/```typescript\n([\s\S]*?)```/),r=[];for(let p of t.split(`
4
4
  `)){if(p.startsWith("```"))break;r.push(p);}let n=r.join(`
5
- `).trim();if(!e?.[1])return {explanation:n};let o=e[1],c=o.match(/\/\/\s*WRONG[^\n]*\n([\s\S]*?)(?:\/\/\s*CORRECT|$)/),a=o.match(/\/\/\s*CORRECT[^\n]*\n([\s\S]*)/);return {explanation:n,badExample:c?.[1]?.trim()??void 0,goodExample:a?.[1]?.trim()??void 0}}function C(){if(l)return l;let t=L(),e;try{e=fs.readFileSync(t,"utf-8");}catch{return l=Object.freeze([]),l}let n=U(e).map(o=>{let{explanation:c,badExample:a,goodExample:p}=$(o.body);return {id:k(o.title),number:o.number,title:o.title,severity:G(o.title),category:z(o.title),explanation:c,badExample:a,goodExample:p}});return l=Object.freeze(n),l}function D(){return C()}function B(t){return C().find(e=>e.id===t)}function W(){l=null;}var V=path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)))),S=path.resolve(V,".."),M=["redux","zustand","xstate","mobx","jotai","recoil"],u=null;function Y(){let t=[path.join(S,"migration.json"),path.join(S,"..","migration.json")];for(let e of t)if(fs.existsSync(e))return e;return t[0]??""}function E(){if(u)return u;try{let t=fs.readFileSync(Y(),"utf-8"),e=JSON.parse(t);u=Object.freeze(e.sources??[]);}catch{u=Object.freeze([]);}return u}function Z(){return M}function tt(){return E()}function et(t){return E().find(e=>e.id===t)}function nt(){u=null;}var ct=path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)))),v=path.resolve(ct,".."),g=null;function lt(){let t=[path.join(v,"compositions.json"),path.join(v,"..","compositions.json")];for(let e of t)if(fs.existsSync(e))return e;return t[0]??""}function m(){if(g)return g;try{let t=fs.readFileSync(lt(),"utf-8"),e=JSON.parse(t);g=Object.freeze(e.edges??[]);}catch{g=Object.freeze([]);}return g}function ut(){return m()}function gt(t){return m().filter(e=>e.from===t)}function pt(t){return m().filter(e=>e.to===t)}function ft(){g=null;}var ht=path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)))),w=path.resolve(ht,"..");function f(t){let e=path.join(w,t);if(fs.existsSync(e))return e;let r=path.join(w,"..",t);return fs.existsSync(r)?r:e}var Pt=f("core"),At=f("ai"),Ct=f("examples"),Rt=f("api-skeleton.md"),i=null,s=null;function y(t,e){try{let r=fs.readdirSync(t).filter(n=>n.endsWith(".md")||n.endsWith(".ts"));for(let n of r){let o=n.replace(/\.(md|ts)$/,"");e.set(o,fs.readFileSync(path.join(t,n),"utf-8"));}}catch(r){if(r.code!=="ENOENT")throw r}}function x(){let t=new Map;y(Pt,t),y(At,t);try{t.set("api-skeleton",fs.readFileSync(Rt,"utf-8"));}catch{}return t}function h(){let t=new Map;return y(Ct,t),t}function St(t){return i||(i=x()),i.get(t)??""}function Gt(){return i||(i=x()),i}function Ut(t){return i||(i=x()),i.has(t)}function Mt(t){return s||(s=h()),s.get(t)??""}function $t(t){return s||(s=h()),s.has(t)}function Dt(){return s||(s=h()),s}function Bt(t){return t.map(e=>St(e)).filter(Boolean).join(`
5
+ `).trim();if(!e?.[1])return {explanation:n};let o=e[1],c=o.match(/\/\/\s*WRONG[^\n]*\n([\s\S]*?)(?:\/\/\s*CORRECT|$)/),a=o.match(/\/\/\s*CORRECT[^\n]*\n([\s\S]*)/);return {explanation:n,badExample:c?.[1]?.trim()??void 0,goodExample:a?.[1]?.trim()??void 0}}function S(){if(l)return l;let t=L(),e;try{e=fs.readFileSync(t,"utf-8");}catch{return l=Object.freeze([]),l}let n=U(e).map(o=>{let{explanation:c,badExample:a,goodExample:p}=$(o.body);return {id:k(o.title),number:o.number,title:o.title,severity:G(o.title),category:z(o.title),explanation:c,badExample:a,goodExample:p}});return l=Object.freeze(n),l}function D(){return S()}function B(t){return S().find(e=>e.id===t)}function W(){l=null;}var V=path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)))),E=path.resolve(V,".."),b=["redux","zustand","xstate","mobx","jotai","recoil"],u=null;function Y(){let t=[path.join(E,"migration.json"),path.join(E,"..","migration.json")];for(let e of t)if(fs.existsSync(e))return e;return t[0]??""}function A(){if(u)return u;try{let t=fs.readFileSync(Y(),"utf-8"),e=JSON.parse(t);u=Object.freeze(e.sources??[]);}catch{u=Object.freeze([]);}return u}function Z(){return b}function tt(){return A()}function et(t){return A().find(e=>e.id===t)}function nt(){u=null;}var ct=path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)))),R=path.resolve(ct,".."),g=null;function lt(){let t=[path.join(R,"compositions.json"),path.join(R,"..","compositions.json")];for(let e of t)if(fs.existsSync(e))return e;return t[0]??""}function m(){if(g)return g;try{let t=fs.readFileSync(lt(),"utf-8"),e=JSON.parse(t);g=Object.freeze(e.edges??[]);}catch{g=Object.freeze([]);}return g}function ut(){return m()}function gt(t){return m().filter(e=>e.from===t)}function pt(t){return m().filter(e=>e.to===t)}function ft(){g=null;}var ht=path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)))),w=path.resolve(ht,"..");function f(t){let e=path.join(w,t);if(fs.existsSync(e))return e;let r=path.join(w,"..",t);return fs.existsSync(r)?r:e}var Pt=f("core"),Ct=f("ai"),St=f("examples"),Mt=f("api-skeleton.md"),i=null,s=null;function x(t,e){try{let r=fs.readdirSync(t).filter(n=>n.endsWith(".md")||n.endsWith(".ts"));for(let n of r){let o=n.replace(/\.(md|ts)$/,"");e.set(o,fs.readFileSync(path.join(t,n),"utf-8"));}}catch(r){if(r.code!=="ENOENT")throw r}}function y(){let t=new Map;x(Pt,t),x(Ct,t);try{t.set("api-skeleton",fs.readFileSync(Mt,"utf-8"));}catch{}return t}function h(){let t=new Map;return x(St,t),t}function Et(t){return i||(i=y()),i.get(t)??""}function Gt(){return i||(i=y()),i}function Ut(t){return i||(i=y()),i.has(t)}function bt(t){return s||(s=h()),s.get(t)??""}function $t(t){return s||(s=h()),s.has(t)}function Dt(){return s||(s=h()),s}function Bt(t){return t.map(e=>Et(e)).filter(Boolean).join(`
6
6
 
7
7
  ---
8
8
 
9
- `)}function Wt(t){return t.map(e=>{let r=Mt(e);return r?`### Example: ${e}
9
+ `)}function Wt(t){return t.map(e=>{let r=bt(e);return r?`### Example: ${e}
10
10
 
11
11
  \`\`\`typescript
12
12
  ${r}
13
13
  \`\`\``:""}).filter(Boolean).join(`
14
14
 
15
- `)}function Jt(){i=null,s=null;}exports.MIGRATION_SOURCES=M;exports.clearAntiPatternCache=W;exports.clearCache=Jt;exports.clearCompositionsCache=ft;exports.clearMigrationCache=nt;exports.getAllExamples=Dt;exports.getAllKnowledge=Gt;exports.getAntiPatternById=B;exports.getAntiPatterns=D;exports.getCompositions=ut;exports.getCompositionsFor=gt;exports.getExample=Mt;exports.getExampleFiles=Wt;exports.getKnowledge=St;exports.getKnowledgeFiles=Bt;exports.getMigrationPattern=et;exports.getMigrationPatterns=tt;exports.getMigrationSources=Z;exports.getReverseCompositionsFor=pt;exports.hasExample=$t;exports.hasKnowledge=Ut;//# sourceMappingURL=index.cjs.map
15
+ `)}function Jt(){i=null,s=null;}exports.MIGRATION_SOURCES=b;exports.clearAntiPatternCache=W;exports.clearCache=Jt;exports.clearCompositionsCache=ft;exports.clearMigrationCache=nt;exports.getAllExamples=Dt;exports.getAllKnowledge=Gt;exports.getAntiPatternById=B;exports.getAntiPatterns=D;exports.getCompositions=ut;exports.getCompositionsFor=gt;exports.getExample=bt;exports.getExampleFiles=Wt;exports.getKnowledge=Et;exports.getKnowledgeFiles=Bt;exports.getMigrationPattern=et;exports.getMigrationPatterns=tt;exports.getMigrationSources=Z;exports.getReverseCompositionsFor=pt;exports.hasExample=$t;exports.hasKnowledge=Ut;//# sourceMappingURL=index.cjs.map
16
16
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/parsers/anti-patterns.ts","../src/parsers/migration.ts","../src/parsers/compositions.ts","../src/index.ts"],"names":["__dirname","dirname","fileURLToPath","PKG_ROOT","resolve","cache","resolveSourcePath","candidates","join","c","existsSync","slugify","title","categorize","lower","severityFor","splitSections","md","lines","sections","current","heading","line","match","extractExamples","body","codeBlock","explanationLines","explanation","code","wrongMatch","correctMatch","loadAntiPatterns","sourcePath","readFileSync","out","section","badExample","goodExample","getAntiPatterns","getAntiPatternById","id","ap","clearAntiPatternCache","MIGRATION_SOURCES","load","raw","parsed","getMigrationSources","getMigrationPatterns","getMigrationPattern","source","p","clearMigrationCache","getCompositions","getCompositionsFor","packageName","getReverseCompositionsFor","clearCompositionsCache","resolveAsset","name","fromDist","fromSrc","CORE_DIR","AI_DIR","EXAMPLES_DIR","API_SKELETON_PATH","knowledgeCache","exampleCache","loadDir","dir","map","files","readdirSync","f","file","err","loadAllKnowledge","loadAllExamples","getKnowledge","getAllKnowledge","hasKnowledge","getExample","hasExample","getAllExamples","getKnowledgeFiles","names","getExampleFiles","content","clearCache"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Parser for `packages/knowledge/core/anti-patterns.md` → structured\n * `AntiPattern[]` data. Lazy + cached so the cost is paid once per\n * process at first call.\n *\n * The source markdown is organized as numbered sections (`## N. Title`)\n * each containing a TypeScript code block with `// WRONG` and\n * `// CORRECT` examples. Some sections include prose between the\n * heading and the code block — captured as `explanation`.\n *\n * IDs are kebab-cased slugs derived from the heading text; stable\n * across releases as long as the heading isn't renamed.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst PKG_ROOT = resolve(__dirname, \"..\");\n\nexport type AntiPatternSeverity = \"error\" | \"warning\" | \"info\";\nexport type AntiPatternCategory =\n | \"module\"\n | \"schema\"\n | \"constraint\"\n | \"resolver\"\n | \"derivation\"\n | \"effect\"\n | \"naming\"\n | \"react\"\n | \"composition\";\n\nexport interface AntiPattern {\n /** Stable slug, derived from the heading text. */\n id: string;\n /** Section number in the source markdown (1..N). */\n number: number;\n /** Human-readable title (the heading text minus the number prefix). */\n title: string;\n /** Default severity. Heuristic; tunable per-rule later. */\n severity: AntiPatternSeverity;\n /** Heuristic category from title keywords. */\n category: AntiPatternCategory;\n /** Body prose between heading and the first code block (often empty). */\n explanation: string;\n /** The `// WRONG` example, if present. */\n badExample?: string;\n /** The `// CORRECT` example, if present. */\n goodExample?: string;\n}\n\nlet cache: ReadonlyArray<AntiPattern> | null = null;\n\nfunction resolveSourcePath(): string {\n const candidates = [\n join(PKG_ROOT, \"core\", \"anti-patterns.md\"),\n join(PKG_ROOT, \"..\", \"core\", \"anti-patterns.md\"),\n ];\n for (const c of candidates) {\n if (existsSync(c)) {\n return c;\n }\n }\n return candidates[0] ?? \"\";\n}\n\nfunction slugify(title: string): string {\n return title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .replace(/-{2,}/g, \"-\");\n}\n\nfunction categorize(title: string): AntiPatternCategory {\n const lower = title.toLowerCase();\n if (/schema|builder/.test(lower)) {\n return \"schema\";\n }\n if (/constraint|cross-?module|require/.test(lower)) {\n return \"constraint\";\n }\n if (/resolver|settle|start/.test(lower)) {\n return \"resolver\";\n }\n if (/deriv|passthrough/.test(lower)) {\n return \"derivation\";\n }\n if (/effect/.test(lower)) {\n return \"effect\";\n }\n if (/usedirective|react|hook/.test(lower)) {\n return \"react\";\n }\n if (/import|bracket|deep import|name|context|abbreviat/.test(lower)) {\n return \"naming\";\n }\n if (/init|module|config/.test(lower)) {\n return \"module\";\n }\n return \"module\";\n}\n\nfunction severityFor(title: string): AntiPatternSeverity {\n const lower = title.toLowerCase();\n if (/nonexistent|missing|no error|deep import|async logic/.test(lower)) {\n return \"error\";\n }\n return \"warning\";\n}\n\ninterface Section {\n number: number;\n title: string;\n body: string;\n}\n\nfunction splitSections(md: string): Section[] {\n const lines = md.split(\"\\n\");\n const sections: Section[] = [];\n let current: Section | null = null;\n const heading = /^##\\s+(\\d+)\\.\\s+(.+?)\\s*$/;\n for (const line of lines) {\n const match = heading.exec(line);\n if (match?.[1] && match?.[2]) {\n if (current) {\n sections.push(current);\n }\n current = {\n number: Number(match[1]),\n title: match[2],\n body: \"\",\n };\n continue;\n }\n if (current) {\n // Stop at the first non-numbered ## section (e.g. \"Quick Reference Checklist\")\n if (/^##\\s+\\D/.test(line)) {\n sections.push(current);\n current = null;\n break;\n }\n current.body += `${line}\\n`;\n }\n }\n if (current) {\n sections.push(current);\n }\n return sections;\n}\n\nfunction extractExamples(body: string): {\n explanation: string;\n badExample?: string;\n goodExample?: string;\n} {\n const codeBlock = body.match(/```typescript\\n([\\s\\S]*?)```/);\n const explanationLines: string[] = [];\n for (const line of body.split(\"\\n\")) {\n if (line.startsWith(\"```\")) {\n break;\n }\n explanationLines.push(line);\n }\n const explanation = explanationLines.join(\"\\n\").trim();\n\n if (!codeBlock?.[1]) {\n return { explanation };\n }\n\n const code = codeBlock[1];\n // Split on the WRONG/CORRECT comment markers.\n const wrongMatch = code.match(\n /\\/\\/\\s*WRONG[^\\n]*\\n([\\s\\S]*?)(?:\\/\\/\\s*CORRECT|$)/,\n );\n const correctMatch = code.match(/\\/\\/\\s*CORRECT[^\\n]*\\n([\\s\\S]*)/);\n\n return {\n explanation,\n badExample: wrongMatch?.[1]?.trim() ?? undefined,\n goodExample: correctMatch?.[1]?.trim() ?? undefined,\n };\n}\n\nfunction loadAntiPatterns(): ReadonlyArray<AntiPattern> {\n if (cache) {\n return cache;\n }\n\n const sourcePath = resolveSourcePath();\n let md: string;\n try {\n md = readFileSync(sourcePath, \"utf-8\");\n } catch {\n cache = Object.freeze([]);\n return cache;\n }\n\n const sections = splitSections(md);\n const out: AntiPattern[] = sections.map((section) => {\n const { explanation, badExample, goodExample } = extractExamples(\n section.body,\n );\n return {\n id: slugify(section.title),\n number: section.number,\n title: section.title,\n severity: severityFor(section.title),\n category: categorize(section.title),\n explanation,\n badExample,\n goodExample,\n };\n });\n\n cache = Object.freeze(out);\n return cache;\n}\n\n/** Return every parsed anti-pattern, stable order, frozen. */\nexport function getAntiPatterns(): ReadonlyArray<AntiPattern> {\n return loadAntiPatterns();\n}\n\n/** Look up one anti-pattern by its slug id. */\nexport function getAntiPatternById(id: string): AntiPattern | undefined {\n return loadAntiPatterns().find((ap) => ap.id === id);\n}\n\n/** Clear the in-memory cache. Test / watch-mode helper. */\nexport function clearAntiPatternCache(): void {\n cache = null;\n}\n","/**\n * Loader for `packages/knowledge/migration.json` → structured\n * migration patterns. Lazy + cached.\n *\n * The JSON ships in the published tarball; consumers don't need to\n * parse markdown at runtime.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst PKG_ROOT = resolve(__dirname, \"..\");\n\n/** Supported source-library identifiers. */\nexport const MIGRATION_SOURCES = [\n \"redux\",\n \"zustand\",\n \"xstate\",\n \"mobx\",\n \"jotai\",\n \"recoil\",\n] as const;\nexport type MigrationSourceId = (typeof MIGRATION_SOURCES)[number];\n\nexport interface MigrationConceptRow {\n from: string;\n to: string;\n note: string;\n}\n\nexport interface MigrationPattern {\n id: MigrationSourceId;\n name: string;\n conceptMap: MigrationConceptRow[];\n steps: string[];\n before: string;\n after: string;\n}\n\ninterface MigrationFile {\n version: number;\n sources: MigrationPattern[];\n}\n\nlet cache: ReadonlyArray<MigrationPattern> | null = null;\n\nfunction resolveSourcePath(): string {\n const candidates = [\n join(PKG_ROOT, \"migration.json\"),\n join(PKG_ROOT, \"..\", \"migration.json\"),\n ];\n for (const c of candidates) {\n if (existsSync(c)) {\n return c;\n }\n }\n return candidates[0] ?? \"\";\n}\n\nfunction load(): ReadonlyArray<MigrationPattern> {\n if (cache) {\n return cache;\n }\n try {\n const raw = readFileSync(resolveSourcePath(), \"utf-8\");\n const parsed = JSON.parse(raw) as MigrationFile;\n cache = Object.freeze(parsed.sources ?? []);\n } catch {\n cache = Object.freeze([]);\n }\n return cache;\n}\n\n/** All supported source library IDs. */\nexport function getMigrationSources(): ReadonlyArray<MigrationSourceId> {\n return MIGRATION_SOURCES;\n}\n\n/** All migration patterns, in registry order. */\nexport function getMigrationPatterns(): ReadonlyArray<MigrationPattern> {\n return load();\n}\n\n/** One migration pattern by its source-library id. */\nexport function getMigrationPattern(\n source: string,\n): MigrationPattern | undefined {\n return load().find((p) => p.id === source);\n}\n\n/** Test / watch-mode helper. */\nexport function clearMigrationCache(): void {\n cache = null;\n}\n","/**\n * Loader for `packages/knowledge/compositions.json` → typed\n * composition graph. Lazy + cached.\n *\n * The JSON ships in the published tarball. Adjacency list rather\n * than per-package projections so consumers can answer both\n * \"what does X compose with?\" and \"what composes with X?\" without\n * duplicate data.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n// After bundling, all parsers live in dist/index.js — one level up\n// from dist reaches the package root. In src/ during dev, the file is\n// two levels up; the fallback in `resolveSourcePath` handles that.\nconst PKG_ROOT = resolve(__dirname, \"..\");\n\nexport interface CompositionEdge {\n from: string;\n to: string;\n reason: string;\n}\n\ninterface CompositionsFile {\n version: number;\n edges: CompositionEdge[];\n}\n\nlet cache: ReadonlyArray<CompositionEdge> | null = null;\n\nfunction resolveSourcePath(): string {\n const candidates = [\n join(PKG_ROOT, \"compositions.json\"),\n join(PKG_ROOT, \"..\", \"compositions.json\"),\n ];\n for (const c of candidates) {\n if (existsSync(c)) {\n return c;\n }\n }\n return candidates[0] ?? \"\";\n}\n\nfunction load(): ReadonlyArray<CompositionEdge> {\n if (cache) {\n return cache;\n }\n try {\n const raw = readFileSync(resolveSourcePath(), \"utf-8\");\n const parsed = JSON.parse(raw) as CompositionsFile;\n cache = Object.freeze(parsed.edges ?? []);\n } catch {\n cache = Object.freeze([]);\n }\n return cache;\n}\n\n/** All composition edges as a flat list. */\nexport function getCompositions(): ReadonlyArray<CompositionEdge> {\n return load();\n}\n\n/**\n * All edges originating at the given package. Returns an empty array\n * when the package is unknown or has no outgoing compositions.\n */\nexport function getCompositionsFor(\n packageName: string,\n): ReadonlyArray<CompositionEdge> {\n return load().filter((e) => e.from === packageName);\n}\n\n/**\n * All edges arriving at the given package — \"who composes WITH me?\"\n */\nexport function getReverseCompositionsFor(\n packageName: string,\n): ReadonlyArray<CompositionEdge> {\n return load().filter((e) => e.to === packageName);\n}\n\n/** Test / watch-mode helper. */\nexport function clearCompositionsCache(): void {\n cache = null;\n}\n","import { existsSync, readFileSync, readdirSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n// Resolve package root: works both in src/ (dev) and dist/ (bundled)\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst PKG_ROOT = resolve(__dirname, \"..\");\n\n/**\n * Resolve a path relative to the package root.\n * Tries dist-relative first (bundled), then src-relative (dev).\n */\nfunction resolveAsset(name: string): string {\n const fromDist = join(PKG_ROOT, name);\n if (existsSync(fromDist)) {\n return fromDist;\n }\n\n const fromSrc = join(PKG_ROOT, \"..\", name);\n if (existsSync(fromSrc)) {\n return fromSrc;\n }\n\n return fromDist; // default, will just return empty maps\n}\n\nconst CORE_DIR = resolveAsset(\"core\");\nconst AI_DIR = resolveAsset(\"ai\");\nconst EXAMPLES_DIR = resolveAsset(\"examples\");\nconst API_SKELETON_PATH = resolveAsset(\"api-skeleton.md\");\n\nlet knowledgeCache: Map<string, string> | null = null;\nlet exampleCache: Map<string, string> | null = null;\n\nfunction loadDir(dir: string, map: Map<string, string>): void {\n try {\n const files = readdirSync(dir).filter(\n (f) => f.endsWith(\".md\") || f.endsWith(\".ts\"),\n );\n for (const file of files) {\n const name = file.replace(/\\.(md|ts)$/, \"\");\n map.set(name, readFileSync(join(dir, file), \"utf-8\"));\n }\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw err;\n }\n // directory does not exist — expected during tests or incomplete installs\n }\n}\n\nfunction loadAllKnowledge(): Map<string, string> {\n const map = new Map<string, string>();\n loadDir(CORE_DIR, map);\n loadDir(AI_DIR, map);\n\n // Include api-skeleton\n try {\n map.set(\"api-skeleton\", readFileSync(API_SKELETON_PATH, \"utf-8\"));\n } catch {\n // may not exist yet\n }\n\n return map;\n}\n\nfunction loadAllExamples(): Map<string, string> {\n const map = new Map<string, string>();\n loadDir(EXAMPLES_DIR, map);\n\n return map;\n}\n\n/**\n * Look up a bundled knowledge file by name. Returns the raw markdown\n * string. Returns `\"\"` when the name isn't known — callers driving an\n * LLM should pair this with {@link hasKnowledge} so a typo turns\n * into an actionable error instead of a silently empty prompt.\n *\n * @example\n * ```ts\n * import { getKnowledge, hasKnowledge } from \"@directive-run/knowledge\";\n *\n * if (!hasKnowledge(\"guardrails\")) throw new Error(\"typo\");\n * const md = getKnowledge(\"guardrails\");\n * ```\n */\nexport function getKnowledge(name: string): string {\n if (!knowledgeCache) {\n knowledgeCache = loadAllKnowledge();\n }\n\n return knowledgeCache.get(name) ?? \"\";\n}\n\n/**\n * Return every loaded knowledge file as `name → markdown`. Consumers\n * iterating the corpus (full-text search, embedding builder, RAG\n * index) read this once and key off the returned map.\n */\nexport function getAllKnowledge(): ReadonlyMap<string, string> {\n if (!knowledgeCache) {\n knowledgeCache = loadAllKnowledge();\n }\n\n return knowledgeCache;\n}\n\n/**\n * `true` when a knowledge file with this exact name is bundled.\n * Use this BEFORE {@link getKnowledge} when the name is user / agent\n * input — `getKnowledge` returns `\"\"` on miss, which is\n * indistinguishable from an intentionally empty file.\n *\n * @example\n * ```ts\n * if (!hasKnowledge(userTyped)) {\n * console.error(`unknown knowledge file: ${userTyped}`);\n * console.error(`available: ${[...getAllKnowledge().keys()].join(\", \")}`);\n * return;\n * }\n * ```\n */\nexport function hasKnowledge(name: string): boolean {\n if (!knowledgeCache) {\n knowledgeCache = loadAllKnowledge();\n }\n return knowledgeCache.has(name);\n}\n\n/**\n * Look up a bundled example file by name. Returns the raw source.\n * Returns `\"\"` when the name isn't known — pair with {@link hasExample}\n * when the input is user-controlled.\n */\nexport function getExample(name: string): string {\n if (!exampleCache) {\n exampleCache = loadAllExamples();\n }\n\n return exampleCache.get(name) ?? \"\";\n}\n\n/**\n * `true` when an example file with this exact name is bundled.\n * The miss-vs-empty disambiguator for {@link getExample}.\n */\nexport function hasExample(name: string): boolean {\n if (!exampleCache) {\n exampleCache = loadAllExamples();\n }\n return exampleCache.has(name);\n}\n\nexport function getAllExamples(): ReadonlyMap<string, string> {\n if (!exampleCache) {\n exampleCache = loadAllExamples();\n }\n\n return exampleCache;\n}\n\nexport function getKnowledgeFiles(names: string[]): string {\n return names\n .map((name) => getKnowledge(name))\n .filter(Boolean)\n .join(\"\\n\\n---\\n\\n\");\n}\n\nexport function getExampleFiles(names: string[]): string {\n return names\n .map((name) => {\n const content = getExample(name);\n if (!content) {\n return \"\";\n }\n\n return `### Example: ${name}\\n\\n\\`\\`\\`typescript\\n${content}\\n\\`\\`\\``;\n })\n .filter(Boolean)\n .join(\"\\n\\n\");\n}\n\n/** Clear cached knowledge and examples. Useful for dev/watch mode. */\nexport function clearCache(): void {\n knowledgeCache = null;\n exampleCache = null;\n}\n\n// ---------------------------------------------------------------------------\n// Structured data APIs (v1.16.0 — back the MCP `list_review_rules`,\n// `get_review_rule`, `list_migration_sources`, `get_migration_pattern`,\n// `get_composable_packages` tools).\n// ---------------------------------------------------------------------------\n\nexport {\n type AntiPattern,\n type AntiPatternCategory,\n type AntiPatternSeverity,\n clearAntiPatternCache,\n getAntiPatternById,\n getAntiPatterns,\n} from \"./parsers/anti-patterns.js\";\n\nexport {\n type MigrationConceptRow,\n type MigrationPattern,\n type MigrationSourceId,\n MIGRATION_SOURCES,\n clearMigrationCache,\n getMigrationPattern,\n getMigrationPatterns,\n getMigrationSources,\n} from \"./parsers/migration.js\";\n\nexport {\n type CompositionEdge,\n clearCompositionsCache,\n getCompositions,\n getCompositionsFor,\n getReverseCompositionsFor,\n} from \"./parsers/compositions.js\";\n"]}
1
+ {"version":3,"sources":["../src/parsers/anti-patterns.ts","../src/parsers/migration.ts","../src/parsers/compositions.ts","../src/index.ts"],"names":["__dirname","dirname","fileURLToPath","PKG_ROOT","resolve","cache","resolveSourcePath","candidates","join","c","existsSync","slugify","title","categorize","lower","severityFor","splitSections","md","lines","sections","current","heading","line","match","extractExamples","body","codeBlock","explanationLines","explanation","code","wrongMatch","correctMatch","loadAntiPatterns","sourcePath","readFileSync","out","section","badExample","goodExample","getAntiPatterns","getAntiPatternById","id","ap","clearAntiPatternCache","MIGRATION_SOURCES","load","raw","parsed","getMigrationSources","getMigrationPatterns","getMigrationPattern","source","p","clearMigrationCache","getCompositions","getCompositionsFor","packageName","getReverseCompositionsFor","clearCompositionsCache","resolveAsset","name","fromDist","fromSrc","CORE_DIR","AI_DIR","EXAMPLES_DIR","API_SKELETON_PATH","knowledgeCache","exampleCache","loadDir","dir","map","files","readdirSync","f","file","err","loadAllKnowledge","loadAllExamples","getKnowledge","getAllKnowledge","hasKnowledge","getExample","hasExample","getAllExamples","getKnowledgeFiles","names","getExampleFiles","content","clearCache"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Parser for `packages/knowledge/core/anti-patterns.md` → structured\n * `AntiPattern[]` data. Lazy + cached so the cost is paid once per\n * process at first call.\n *\n * The source markdown is organized as numbered sections (`## N. Title`)\n * each containing a TypeScript code block with `// WRONG` and\n * `// CORRECT` examples. Some sections include prose between the\n * heading and the code block — captured as `explanation`.\n *\n * IDs are kebab-cased slugs derived from the heading text; stable\n * across releases as long as the heading isn't renamed.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst PKG_ROOT = resolve(__dirname, \"..\");\n\nexport type AntiPatternSeverity = \"error\" | \"warning\" | \"info\";\nexport type AntiPatternCategory =\n | \"module\"\n | \"schema\"\n | \"constraint\"\n | \"resolver\"\n | \"derivation\"\n | \"effect\"\n | \"naming\"\n | \"react\"\n | \"composition\";\n\nexport interface AntiPattern {\n /** Stable slug, derived from the heading text. */\n id: string;\n /** Section number in the source markdown (1..N). */\n number: number;\n /** Human-readable title (the heading text minus the number prefix). */\n title: string;\n /** Default severity. Heuristic; tunable per-rule later. */\n severity: AntiPatternSeverity;\n /** Heuristic category from title keywords. */\n category: AntiPatternCategory;\n /** Body prose between heading and the first code block (often empty). */\n explanation: string;\n /** The `// WRONG` example, if present. */\n badExample?: string;\n /** The `// CORRECT` example, if present. */\n goodExample?: string;\n}\n\nlet cache: readonly AntiPattern[] | null = null;\n\nfunction resolveSourcePath(): string {\n const candidates = [\n join(PKG_ROOT, \"core\", \"anti-patterns.md\"),\n join(PKG_ROOT, \"..\", \"core\", \"anti-patterns.md\"),\n ];\n for (const c of candidates) {\n if (existsSync(c)) {\n return c;\n }\n }\n return candidates[0] ?? \"\";\n}\n\nfunction slugify(title: string): string {\n return title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .replace(/-{2,}/g, \"-\");\n}\n\nfunction categorize(title: string): AntiPatternCategory {\n const lower = title.toLowerCase();\n if (/schema|builder/.test(lower)) {\n return \"schema\";\n }\n if (/constraint|cross-?module|require/.test(lower)) {\n return \"constraint\";\n }\n if (/resolver|settle|start/.test(lower)) {\n return \"resolver\";\n }\n if (/deriv|passthrough/.test(lower)) {\n return \"derivation\";\n }\n if (/effect/.test(lower)) {\n return \"effect\";\n }\n if (/usedirective|react|hook/.test(lower)) {\n return \"react\";\n }\n if (/import|bracket|deep import|name|context|abbreviat/.test(lower)) {\n return \"naming\";\n }\n if (/init|module|config/.test(lower)) {\n return \"module\";\n }\n return \"module\";\n}\n\nfunction severityFor(title: string): AntiPatternSeverity {\n const lower = title.toLowerCase();\n if (/nonexistent|missing|no error|deep import|async logic/.test(lower)) {\n return \"error\";\n }\n return \"warning\";\n}\n\ninterface Section {\n number: number;\n title: string;\n body: string;\n}\n\nfunction splitSections(md: string): Section[] {\n const lines = md.split(\"\\n\");\n const sections: Section[] = [];\n let current: Section | null = null;\n const heading = /^##\\s+(\\d+)\\.\\s+(.+?)\\s*$/;\n for (const line of lines) {\n const match = heading.exec(line);\n if (match?.[1] && match?.[2]) {\n if (current) {\n sections.push(current);\n }\n current = {\n number: Number(match[1]),\n title: match[2],\n body: \"\",\n };\n continue;\n }\n if (current) {\n // Stop at the first non-numbered ## section (e.g. \"Quick Reference Checklist\")\n if (/^##\\s+\\D/.test(line)) {\n sections.push(current);\n current = null;\n break;\n }\n current.body += `${line}\\n`;\n }\n }\n if (current) {\n sections.push(current);\n }\n return sections;\n}\n\nfunction extractExamples(body: string): {\n explanation: string;\n badExample?: string;\n goodExample?: string;\n} {\n const codeBlock = body.match(/```typescript\\n([\\s\\S]*?)```/);\n const explanationLines: string[] = [];\n for (const line of body.split(\"\\n\")) {\n if (line.startsWith(\"```\")) {\n break;\n }\n explanationLines.push(line);\n }\n const explanation = explanationLines.join(\"\\n\").trim();\n\n if (!codeBlock?.[1]) {\n return { explanation };\n }\n\n const code = codeBlock[1];\n // Split on the WRONG/CORRECT comment markers.\n const wrongMatch = code.match(\n /\\/\\/\\s*WRONG[^\\n]*\\n([\\s\\S]*?)(?:\\/\\/\\s*CORRECT|$)/,\n );\n const correctMatch = code.match(/\\/\\/\\s*CORRECT[^\\n]*\\n([\\s\\S]*)/);\n\n return {\n explanation,\n badExample: wrongMatch?.[1]?.trim() ?? undefined,\n goodExample: correctMatch?.[1]?.trim() ?? undefined,\n };\n}\n\nfunction loadAntiPatterns(): readonly AntiPattern[] {\n if (cache) {\n return cache;\n }\n\n const sourcePath = resolveSourcePath();\n let md: string;\n try {\n md = readFileSync(sourcePath, \"utf-8\");\n } catch {\n cache = Object.freeze([]);\n return cache;\n }\n\n const sections = splitSections(md);\n const out: AntiPattern[] = sections.map((section) => {\n const { explanation, badExample, goodExample } = extractExamples(\n section.body,\n );\n return {\n id: slugify(section.title),\n number: section.number,\n title: section.title,\n severity: severityFor(section.title),\n category: categorize(section.title),\n explanation,\n badExample,\n goodExample,\n };\n });\n\n cache = Object.freeze(out);\n return cache;\n}\n\n/** Return every parsed anti-pattern, stable order, frozen. */\nexport function getAntiPatterns(): readonly AntiPattern[] {\n return loadAntiPatterns();\n}\n\n/** Look up one anti-pattern by its slug id. */\nexport function getAntiPatternById(id: string): AntiPattern | undefined {\n return loadAntiPatterns().find((ap) => ap.id === id);\n}\n\n/** Clear the in-memory cache. Test / watch-mode helper. */\nexport function clearAntiPatternCache(): void {\n cache = null;\n}\n","/**\n * Loader for `packages/knowledge/migration.json` → structured\n * migration patterns. Lazy + cached.\n *\n * The JSON ships in the published tarball; consumers don't need to\n * parse markdown at runtime.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst PKG_ROOT = resolve(__dirname, \"..\");\n\n/** Supported source-library identifiers. */\nexport const MIGRATION_SOURCES = [\n \"redux\",\n \"zustand\",\n \"xstate\",\n \"mobx\",\n \"jotai\",\n \"recoil\",\n] as const;\nexport type MigrationSourceId = (typeof MIGRATION_SOURCES)[number];\n\nexport interface MigrationConceptRow {\n from: string;\n to: string;\n note: string;\n}\n\nexport interface MigrationPattern {\n id: MigrationSourceId;\n name: string;\n conceptMap: MigrationConceptRow[];\n steps: string[];\n before: string;\n after: string;\n}\n\ninterface MigrationFile {\n version: number;\n sources: MigrationPattern[];\n}\n\nlet cache: readonly MigrationPattern[] | null = null;\n\nfunction resolveSourcePath(): string {\n const candidates = [\n join(PKG_ROOT, \"migration.json\"),\n join(PKG_ROOT, \"..\", \"migration.json\"),\n ];\n for (const c of candidates) {\n if (existsSync(c)) {\n return c;\n }\n }\n return candidates[0] ?? \"\";\n}\n\nfunction load(): readonly MigrationPattern[] {\n if (cache) {\n return cache;\n }\n try {\n const raw = readFileSync(resolveSourcePath(), \"utf-8\");\n const parsed = JSON.parse(raw) as MigrationFile;\n cache = Object.freeze(parsed.sources ?? []);\n } catch {\n cache = Object.freeze([]);\n }\n return cache;\n}\n\n/** All supported source library IDs. */\nexport function getMigrationSources(): readonly MigrationSourceId[] {\n return MIGRATION_SOURCES;\n}\n\n/** All migration patterns, in registry order. */\nexport function getMigrationPatterns(): readonly MigrationPattern[] {\n return load();\n}\n\n/** One migration pattern by its source-library id. */\nexport function getMigrationPattern(\n source: string,\n): MigrationPattern | undefined {\n return load().find((p) => p.id === source);\n}\n\n/** Test / watch-mode helper. */\nexport function clearMigrationCache(): void {\n cache = null;\n}\n","/**\n * Loader for `packages/knowledge/compositions.json` → typed\n * composition graph. Lazy + cached.\n *\n * The JSON ships in the published tarball. Adjacency list rather\n * than per-package projections so consumers can answer both\n * \"what does X compose with?\" and \"what composes with X?\" without\n * duplicate data.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n// After bundling, all parsers live in dist/index.js — one level up\n// from dist reaches the package root. In src/ during dev, the file is\n// two levels up; the fallback in `resolveSourcePath` handles that.\nconst PKG_ROOT = resolve(__dirname, \"..\");\n\nexport interface CompositionEdge {\n from: string;\n to: string;\n reason: string;\n}\n\ninterface CompositionsFile {\n version: number;\n edges: CompositionEdge[];\n}\n\nlet cache: readonly CompositionEdge[] | null = null;\n\nfunction resolveSourcePath(): string {\n const candidates = [\n join(PKG_ROOT, \"compositions.json\"),\n join(PKG_ROOT, \"..\", \"compositions.json\"),\n ];\n for (const c of candidates) {\n if (existsSync(c)) {\n return c;\n }\n }\n return candidates[0] ?? \"\";\n}\n\nfunction load(): readonly CompositionEdge[] {\n if (cache) {\n return cache;\n }\n try {\n const raw = readFileSync(resolveSourcePath(), \"utf-8\");\n const parsed = JSON.parse(raw) as CompositionsFile;\n cache = Object.freeze(parsed.edges ?? []);\n } catch {\n cache = Object.freeze([]);\n }\n return cache;\n}\n\n/** All composition edges as a flat list. */\nexport function getCompositions(): readonly CompositionEdge[] {\n return load();\n}\n\n/**\n * All edges originating at the given package. Returns an empty array\n * when the package is unknown or has no outgoing compositions.\n */\nexport function getCompositionsFor(\n packageName: string,\n): readonly CompositionEdge[] {\n return load().filter((e) => e.from === packageName);\n}\n\n/**\n * All edges arriving at the given package — \"who composes WITH me?\"\n */\nexport function getReverseCompositionsFor(\n packageName: string,\n): readonly CompositionEdge[] {\n return load().filter((e) => e.to === packageName);\n}\n\n/** Test / watch-mode helper. */\nexport function clearCompositionsCache(): void {\n cache = null;\n}\n","import { existsSync, readFileSync, readdirSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n// Resolve package root: works both in src/ (dev) and dist/ (bundled)\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst PKG_ROOT = resolve(__dirname, \"..\");\n\n/**\n * Resolve a path relative to the package root.\n * Tries dist-relative first (bundled), then src-relative (dev).\n */\nfunction resolveAsset(name: string): string {\n const fromDist = join(PKG_ROOT, name);\n if (existsSync(fromDist)) {\n return fromDist;\n }\n\n const fromSrc = join(PKG_ROOT, \"..\", name);\n if (existsSync(fromSrc)) {\n return fromSrc;\n }\n\n return fromDist; // default, will just return empty maps\n}\n\nconst CORE_DIR = resolveAsset(\"core\");\nconst AI_DIR = resolveAsset(\"ai\");\nconst EXAMPLES_DIR = resolveAsset(\"examples\");\nconst API_SKELETON_PATH = resolveAsset(\"api-skeleton.md\");\n\nlet knowledgeCache: Map<string, string> | null = null;\nlet exampleCache: Map<string, string> | null = null;\n\nfunction loadDir(dir: string, map: Map<string, string>): void {\n try {\n const files = readdirSync(dir).filter(\n (f) => f.endsWith(\".md\") || f.endsWith(\".ts\"),\n );\n for (const file of files) {\n const name = file.replace(/\\.(md|ts)$/, \"\");\n map.set(name, readFileSync(join(dir, file), \"utf-8\"));\n }\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw err;\n }\n // directory does not exist — expected during tests or incomplete installs\n }\n}\n\nfunction loadAllKnowledge(): Map<string, string> {\n const map = new Map<string, string>();\n loadDir(CORE_DIR, map);\n loadDir(AI_DIR, map);\n\n // Include api-skeleton\n try {\n map.set(\"api-skeleton\", readFileSync(API_SKELETON_PATH, \"utf-8\"));\n } catch {\n // may not exist yet\n }\n\n return map;\n}\n\nfunction loadAllExamples(): Map<string, string> {\n const map = new Map<string, string>();\n loadDir(EXAMPLES_DIR, map);\n\n return map;\n}\n\n/**\n * Look up a bundled knowledge file by name. Returns the raw markdown\n * string. Returns `\"\"` when the name isn't known — callers driving an\n * LLM should pair this with {@link hasKnowledge} so a typo turns\n * into an actionable error instead of a silently empty prompt.\n *\n * @example\n * ```ts\n * import { getKnowledge, hasKnowledge } from \"@directive-run/knowledge\";\n *\n * if (!hasKnowledge(\"guardrails\")) throw new Error(\"typo\");\n * const md = getKnowledge(\"guardrails\");\n * ```\n */\nexport function getKnowledge(name: string): string {\n if (!knowledgeCache) {\n knowledgeCache = loadAllKnowledge();\n }\n\n return knowledgeCache.get(name) ?? \"\";\n}\n\n/**\n * Return every loaded knowledge file as `name → markdown`. Consumers\n * iterating the corpus (full-text search, embedding builder, RAG\n * index) read this once and key off the returned map.\n */\nexport function getAllKnowledge(): ReadonlyMap<string, string> {\n if (!knowledgeCache) {\n knowledgeCache = loadAllKnowledge();\n }\n\n return knowledgeCache;\n}\n\n/**\n * `true` when a knowledge file with this exact name is bundled.\n * Use this BEFORE {@link getKnowledge} when the name is user / agent\n * input — `getKnowledge` returns `\"\"` on miss, which is\n * indistinguishable from an intentionally empty file.\n *\n * @example\n * ```ts\n * if (!hasKnowledge(userTyped)) {\n * console.error(`unknown knowledge file: ${userTyped}`);\n * console.error(`available: ${[...getAllKnowledge().keys()].join(\", \")}`);\n * return;\n * }\n * ```\n */\nexport function hasKnowledge(name: string): boolean {\n if (!knowledgeCache) {\n knowledgeCache = loadAllKnowledge();\n }\n return knowledgeCache.has(name);\n}\n\n/**\n * Look up a bundled example file by name. Returns the raw source.\n * Returns `\"\"` when the name isn't known — pair with {@link hasExample}\n * when the input is user-controlled.\n */\nexport function getExample(name: string): string {\n if (!exampleCache) {\n exampleCache = loadAllExamples();\n }\n\n return exampleCache.get(name) ?? \"\";\n}\n\n/**\n * `true` when an example file with this exact name is bundled.\n * The miss-vs-empty disambiguator for {@link getExample}.\n */\nexport function hasExample(name: string): boolean {\n if (!exampleCache) {\n exampleCache = loadAllExamples();\n }\n return exampleCache.has(name);\n}\n\nexport function getAllExamples(): ReadonlyMap<string, string> {\n if (!exampleCache) {\n exampleCache = loadAllExamples();\n }\n\n return exampleCache;\n}\n\nexport function getKnowledgeFiles(names: string[]): string {\n return names\n .map((name) => getKnowledge(name))\n .filter(Boolean)\n .join(\"\\n\\n---\\n\\n\");\n}\n\nexport function getExampleFiles(names: string[]): string {\n return names\n .map((name) => {\n const content = getExample(name);\n if (!content) {\n return \"\";\n }\n\n return `### Example: ${name}\\n\\n\\`\\`\\`typescript\\n${content}\\n\\`\\`\\``;\n })\n .filter(Boolean)\n .join(\"\\n\\n\");\n}\n\n/** Clear cached knowledge and examples. Useful for dev/watch mode. */\nexport function clearCache(): void {\n knowledgeCache = null;\n exampleCache = null;\n}\n\n// ---------------------------------------------------------------------------\n// Structured data APIs (v1.16.0 — back the MCP `list_review_rules`,\n// `get_review_rule`, `list_migration_sources`, `get_migration_pattern`,\n// `get_composable_packages` tools).\n// ---------------------------------------------------------------------------\n\nexport {\n type AntiPattern,\n type AntiPatternCategory,\n type AntiPatternSeverity,\n clearAntiPatternCache,\n getAntiPatternById,\n getAntiPatterns,\n} from \"./parsers/anti-patterns.js\";\n\nexport {\n type MigrationConceptRow,\n type MigrationPattern,\n type MigrationSourceId,\n MIGRATION_SOURCES,\n clearMigrationCache,\n getMigrationPattern,\n getMigrationPatterns,\n getMigrationSources,\n} from \"./parsers/migration.js\";\n\nexport {\n type CompositionEdge,\n clearCompositionsCache,\n getCompositions,\n getCompositionsFor,\n getReverseCompositionsFor,\n} from \"./parsers/compositions.js\";\n"]}
package/dist/index.d.cts CHANGED
@@ -32,7 +32,7 @@ interface AntiPattern {
32
32
  goodExample?: string;
33
33
  }
34
34
  /** Return every parsed anti-pattern, stable order, frozen. */
35
- declare function getAntiPatterns(): ReadonlyArray<AntiPattern>;
35
+ declare function getAntiPatterns(): readonly AntiPattern[];
36
36
  /** Look up one anti-pattern by its slug id. */
37
37
  declare function getAntiPatternById(id: string): AntiPattern | undefined;
38
38
  /** Clear the in-memory cache. Test / watch-mode helper. */
@@ -62,9 +62,9 @@ interface MigrationPattern {
62
62
  after: string;
63
63
  }
64
64
  /** All supported source library IDs. */
65
- declare function getMigrationSources(): ReadonlyArray<MigrationSourceId>;
65
+ declare function getMigrationSources(): readonly MigrationSourceId[];
66
66
  /** All migration patterns, in registry order. */
67
- declare function getMigrationPatterns(): ReadonlyArray<MigrationPattern>;
67
+ declare function getMigrationPatterns(): readonly MigrationPattern[];
68
68
  /** One migration pattern by its source-library id. */
69
69
  declare function getMigrationPattern(source: string): MigrationPattern | undefined;
70
70
  /** Test / watch-mode helper. */
@@ -85,16 +85,16 @@ interface CompositionEdge {
85
85
  reason: string;
86
86
  }
87
87
  /** All composition edges as a flat list. */
88
- declare function getCompositions(): ReadonlyArray<CompositionEdge>;
88
+ declare function getCompositions(): readonly CompositionEdge[];
89
89
  /**
90
90
  * All edges originating at the given package. Returns an empty array
91
91
  * when the package is unknown or has no outgoing compositions.
92
92
  */
93
- declare function getCompositionsFor(packageName: string): ReadonlyArray<CompositionEdge>;
93
+ declare function getCompositionsFor(packageName: string): readonly CompositionEdge[];
94
94
  /**
95
95
  * All edges arriving at the given package — "who composes WITH me?"
96
96
  */
97
- declare function getReverseCompositionsFor(packageName: string): ReadonlyArray<CompositionEdge>;
97
+ declare function getReverseCompositionsFor(packageName: string): readonly CompositionEdge[];
98
98
  /** Test / watch-mode helper. */
99
99
  declare function clearCompositionsCache(): void;
100
100
 
package/dist/index.d.ts CHANGED
@@ -32,7 +32,7 @@ interface AntiPattern {
32
32
  goodExample?: string;
33
33
  }
34
34
  /** Return every parsed anti-pattern, stable order, frozen. */
35
- declare function getAntiPatterns(): ReadonlyArray<AntiPattern>;
35
+ declare function getAntiPatterns(): readonly AntiPattern[];
36
36
  /** Look up one anti-pattern by its slug id. */
37
37
  declare function getAntiPatternById(id: string): AntiPattern | undefined;
38
38
  /** Clear the in-memory cache. Test / watch-mode helper. */
@@ -62,9 +62,9 @@ interface MigrationPattern {
62
62
  after: string;
63
63
  }
64
64
  /** All supported source library IDs. */
65
- declare function getMigrationSources(): ReadonlyArray<MigrationSourceId>;
65
+ declare function getMigrationSources(): readonly MigrationSourceId[];
66
66
  /** All migration patterns, in registry order. */
67
- declare function getMigrationPatterns(): ReadonlyArray<MigrationPattern>;
67
+ declare function getMigrationPatterns(): readonly MigrationPattern[];
68
68
  /** One migration pattern by its source-library id. */
69
69
  declare function getMigrationPattern(source: string): MigrationPattern | undefined;
70
70
  /** Test / watch-mode helper. */
@@ -85,16 +85,16 @@ interface CompositionEdge {
85
85
  reason: string;
86
86
  }
87
87
  /** All composition edges as a flat list. */
88
- declare function getCompositions(): ReadonlyArray<CompositionEdge>;
88
+ declare function getCompositions(): readonly CompositionEdge[];
89
89
  /**
90
90
  * All edges originating at the given package. Returns an empty array
91
91
  * when the package is unknown or has no outgoing compositions.
92
92
  */
93
- declare function getCompositionsFor(packageName: string): ReadonlyArray<CompositionEdge>;
93
+ declare function getCompositionsFor(packageName: string): readonly CompositionEdge[];
94
94
  /**
95
95
  * All edges arriving at the given package — "who composes WITH me?"
96
96
  */
97
- declare function getReverseCompositionsFor(packageName: string): ReadonlyArray<CompositionEdge>;
97
+ declare function getReverseCompositionsFor(packageName: string): readonly CompositionEdge[];
98
98
  /** Test / watch-mode helper. */
99
99
  declare function clearCompositionsCache(): void;
100
100
 
package/dist/index.js CHANGED
@@ -1,16 +1,16 @@
1
- import {existsSync,readFileSync,readdirSync}from'fs';import {dirname,resolve,join}from'path';import {fileURLToPath}from'url';var K=dirname(fileURLToPath(import.meta.url)),A=resolve(K,".."),l=null;function L(){let t=[join(A,"core","anti-patterns.md"),join(A,"..","core","anti-patterns.md")];for(let e of t)if(existsSync(e))return e;return t[0]??""}function k(t){return t.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").replace(/-{2,}/g,"-")}function z(t){let e=t.toLowerCase();return /schema|builder/.test(e)?"schema":/constraint|cross-?module|require/.test(e)?"constraint":/resolver|settle|start/.test(e)?"resolver":/deriv|passthrough/.test(e)?"derivation":/effect/.test(e)?"effect":/usedirective|react|hook/.test(e)?"react":/import|bracket|deep import|name|context|abbreviat/.test(e)?"naming":("module")}function G(t){let e=t.toLowerCase();return /nonexistent|missing|no error|deep import|async logic/.test(e)?"error":"warning"}function U(t){let e=t.split(`
1
+ import {existsSync,readFileSync,readdirSync}from'fs';import {dirname,resolve,join}from'path';import {fileURLToPath}from'url';var K=dirname(fileURLToPath(import.meta.url)),C=resolve(K,".."),l=null;function L(){let t=[join(C,"core","anti-patterns.md"),join(C,"..","core","anti-patterns.md")];for(let e of t)if(existsSync(e))return e;return t[0]??""}function k(t){return t.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").replace(/-{2,}/g,"-")}function z(t){let e=t.toLowerCase();return /schema|builder/.test(e)?"schema":/constraint|cross-?module|require/.test(e)?"constraint":/resolver|settle|start/.test(e)?"resolver":/deriv|passthrough/.test(e)?"derivation":/effect/.test(e)?"effect":/usedirective|react|hook/.test(e)?"react":/import|bracket|deep import|name|context|abbreviat/.test(e)?"naming":("module")}function G(t){let e=t.toLowerCase();return /nonexistent|missing|no error|deep import|async logic/.test(e)?"error":"warning"}function U(t){let e=t.split(`
2
2
  `),r=[],n=null,o=/^##\s+(\d+)\.\s+(.+?)\s*$/;for(let c of e){let a=o.exec(c);if(a?.[1]&&a?.[2]){n&&r.push(n),n={number:Number(a[1]),title:a[2],body:""};continue}if(n){if(/^##\s+\D/.test(c)){r.push(n),n=null;break}n.body+=`${c}
3
3
  `;}}return n&&r.push(n),r}function $(t){let e=t.match(/```typescript\n([\s\S]*?)```/),r=[];for(let p of t.split(`
4
4
  `)){if(p.startsWith("```"))break;r.push(p);}let n=r.join(`
5
- `).trim();if(!e?.[1])return {explanation:n};let o=e[1],c=o.match(/\/\/\s*WRONG[^\n]*\n([\s\S]*?)(?:\/\/\s*CORRECT|$)/),a=o.match(/\/\/\s*CORRECT[^\n]*\n([\s\S]*)/);return {explanation:n,badExample:c?.[1]?.trim()??void 0,goodExample:a?.[1]?.trim()??void 0}}function C(){if(l)return l;let t=L(),e;try{e=readFileSync(t,"utf-8");}catch{return l=Object.freeze([]),l}let n=U(e).map(o=>{let{explanation:c,badExample:a,goodExample:p}=$(o.body);return {id:k(o.title),number:o.number,title:o.title,severity:G(o.title),category:z(o.title),explanation:c,badExample:a,goodExample:p}});return l=Object.freeze(n),l}function D(){return C()}function B(t){return C().find(e=>e.id===t)}function W(){l=null;}var V=dirname(fileURLToPath(import.meta.url)),S=resolve(V,".."),M=["redux","zustand","xstate","mobx","jotai","recoil"],u=null;function Y(){let t=[join(S,"migration.json"),join(S,"..","migration.json")];for(let e of t)if(existsSync(e))return e;return t[0]??""}function E(){if(u)return u;try{let t=readFileSync(Y(),"utf-8"),e=JSON.parse(t);u=Object.freeze(e.sources??[]);}catch{u=Object.freeze([]);}return u}function Z(){return M}function tt(){return E()}function et(t){return E().find(e=>e.id===t)}function nt(){u=null;}var ct=dirname(fileURLToPath(import.meta.url)),v=resolve(ct,".."),g=null;function lt(){let t=[join(v,"compositions.json"),join(v,"..","compositions.json")];for(let e of t)if(existsSync(e))return e;return t[0]??""}function m(){if(g)return g;try{let t=readFileSync(lt(),"utf-8"),e=JSON.parse(t);g=Object.freeze(e.edges??[]);}catch{g=Object.freeze([]);}return g}function ut(){return m()}function gt(t){return m().filter(e=>e.from===t)}function pt(t){return m().filter(e=>e.to===t)}function ft(){g=null;}var ht=dirname(fileURLToPath(import.meta.url)),w=resolve(ht,"..");function f(t){let e=join(w,t);if(existsSync(e))return e;let r=join(w,"..",t);return existsSync(r)?r:e}var Pt=f("core"),At=f("ai"),Ct=f("examples"),Rt=f("api-skeleton.md"),i=null,s=null;function y(t,e){try{let r=readdirSync(t).filter(n=>n.endsWith(".md")||n.endsWith(".ts"));for(let n of r){let o=n.replace(/\.(md|ts)$/,"");e.set(o,readFileSync(join(t,n),"utf-8"));}}catch(r){if(r.code!=="ENOENT")throw r}}function x(){let t=new Map;y(Pt,t),y(At,t);try{t.set("api-skeleton",readFileSync(Rt,"utf-8"));}catch{}return t}function h(){let t=new Map;return y(Ct,t),t}function St(t){return i||(i=x()),i.get(t)??""}function Gt(){return i||(i=x()),i}function Ut(t){return i||(i=x()),i.has(t)}function Mt(t){return s||(s=h()),s.get(t)??""}function $t(t){return s||(s=h()),s.has(t)}function Dt(){return s||(s=h()),s}function Bt(t){return t.map(e=>St(e)).filter(Boolean).join(`
5
+ `).trim();if(!e?.[1])return {explanation:n};let o=e[1],c=o.match(/\/\/\s*WRONG[^\n]*\n([\s\S]*?)(?:\/\/\s*CORRECT|$)/),a=o.match(/\/\/\s*CORRECT[^\n]*\n([\s\S]*)/);return {explanation:n,badExample:c?.[1]?.trim()??void 0,goodExample:a?.[1]?.trim()??void 0}}function S(){if(l)return l;let t=L(),e;try{e=readFileSync(t,"utf-8");}catch{return l=Object.freeze([]),l}let n=U(e).map(o=>{let{explanation:c,badExample:a,goodExample:p}=$(o.body);return {id:k(o.title),number:o.number,title:o.title,severity:G(o.title),category:z(o.title),explanation:c,badExample:a,goodExample:p}});return l=Object.freeze(n),l}function D(){return S()}function B(t){return S().find(e=>e.id===t)}function W(){l=null;}var V=dirname(fileURLToPath(import.meta.url)),E=resolve(V,".."),b=["redux","zustand","xstate","mobx","jotai","recoil"],u=null;function Y(){let t=[join(E,"migration.json"),join(E,"..","migration.json")];for(let e of t)if(existsSync(e))return e;return t[0]??""}function A(){if(u)return u;try{let t=readFileSync(Y(),"utf-8"),e=JSON.parse(t);u=Object.freeze(e.sources??[]);}catch{u=Object.freeze([]);}return u}function Z(){return b}function tt(){return A()}function et(t){return A().find(e=>e.id===t)}function nt(){u=null;}var ct=dirname(fileURLToPath(import.meta.url)),R=resolve(ct,".."),g=null;function lt(){let t=[join(R,"compositions.json"),join(R,"..","compositions.json")];for(let e of t)if(existsSync(e))return e;return t[0]??""}function m(){if(g)return g;try{let t=readFileSync(lt(),"utf-8"),e=JSON.parse(t);g=Object.freeze(e.edges??[]);}catch{g=Object.freeze([]);}return g}function ut(){return m()}function gt(t){return m().filter(e=>e.from===t)}function pt(t){return m().filter(e=>e.to===t)}function ft(){g=null;}var ht=dirname(fileURLToPath(import.meta.url)),w=resolve(ht,"..");function f(t){let e=join(w,t);if(existsSync(e))return e;let r=join(w,"..",t);return existsSync(r)?r:e}var Pt=f("core"),Ct=f("ai"),St=f("examples"),Mt=f("api-skeleton.md"),i=null,s=null;function x(t,e){try{let r=readdirSync(t).filter(n=>n.endsWith(".md")||n.endsWith(".ts"));for(let n of r){let o=n.replace(/\.(md|ts)$/,"");e.set(o,readFileSync(join(t,n),"utf-8"));}}catch(r){if(r.code!=="ENOENT")throw r}}function y(){let t=new Map;x(Pt,t),x(Ct,t);try{t.set("api-skeleton",readFileSync(Mt,"utf-8"));}catch{}return t}function h(){let t=new Map;return x(St,t),t}function Et(t){return i||(i=y()),i.get(t)??""}function Gt(){return i||(i=y()),i}function Ut(t){return i||(i=y()),i.has(t)}function bt(t){return s||(s=h()),s.get(t)??""}function $t(t){return s||(s=h()),s.has(t)}function Dt(){return s||(s=h()),s}function Bt(t){return t.map(e=>Et(e)).filter(Boolean).join(`
6
6
 
7
7
  ---
8
8
 
9
- `)}function Wt(t){return t.map(e=>{let r=Mt(e);return r?`### Example: ${e}
9
+ `)}function Wt(t){return t.map(e=>{let r=bt(e);return r?`### Example: ${e}
10
10
 
11
11
  \`\`\`typescript
12
12
  ${r}
13
13
  \`\`\``:""}).filter(Boolean).join(`
14
14
 
15
- `)}function Jt(){i=null,s=null;}export{M as MIGRATION_SOURCES,W as clearAntiPatternCache,Jt as clearCache,ft as clearCompositionsCache,nt as clearMigrationCache,Dt as getAllExamples,Gt as getAllKnowledge,B as getAntiPatternById,D as getAntiPatterns,ut as getCompositions,gt as getCompositionsFor,Mt as getExample,Wt as getExampleFiles,St as getKnowledge,Bt as getKnowledgeFiles,et as getMigrationPattern,tt as getMigrationPatterns,Z as getMigrationSources,pt as getReverseCompositionsFor,$t as hasExample,Ut as hasKnowledge};//# sourceMappingURL=index.js.map
15
+ `)}function Jt(){i=null,s=null;}export{b as MIGRATION_SOURCES,W as clearAntiPatternCache,Jt as clearCache,ft as clearCompositionsCache,nt as clearMigrationCache,Dt as getAllExamples,Gt as getAllKnowledge,B as getAntiPatternById,D as getAntiPatterns,ut as getCompositions,gt as getCompositionsFor,bt as getExample,Wt as getExampleFiles,Et as getKnowledge,Bt as getKnowledgeFiles,et as getMigrationPattern,tt as getMigrationPatterns,Z as getMigrationSources,pt as getReverseCompositionsFor,$t as hasExample,Ut as hasKnowledge};//# sourceMappingURL=index.js.map
16
16
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/parsers/anti-patterns.ts","../src/parsers/migration.ts","../src/parsers/compositions.ts","../src/index.ts"],"names":["__dirname","dirname","fileURLToPath","PKG_ROOT","resolve","cache","resolveSourcePath","candidates","join","c","existsSync","slugify","title","categorize","lower","severityFor","splitSections","md","lines","sections","current","heading","line","match","extractExamples","body","codeBlock","explanationLines","explanation","code","wrongMatch","correctMatch","loadAntiPatterns","sourcePath","readFileSync","out","section","badExample","goodExample","getAntiPatterns","getAntiPatternById","id","ap","clearAntiPatternCache","MIGRATION_SOURCES","load","raw","parsed","getMigrationSources","getMigrationPatterns","getMigrationPattern","source","p","clearMigrationCache","getCompositions","getCompositionsFor","packageName","getReverseCompositionsFor","clearCompositionsCache","resolveAsset","name","fromDist","fromSrc","CORE_DIR","AI_DIR","EXAMPLES_DIR","API_SKELETON_PATH","knowledgeCache","exampleCache","loadDir","dir","map","files","readdirSync","f","file","err","loadAllKnowledge","loadAllExamples","getKnowledge","getAllKnowledge","hasKnowledge","getExample","hasExample","getAllExamples","getKnowledgeFiles","names","getExampleFiles","content","clearCache"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Parser for `packages/knowledge/core/anti-patterns.md` → structured\n * `AntiPattern[]` data. Lazy + cached so the cost is paid once per\n * process at first call.\n *\n * The source markdown is organized as numbered sections (`## N. Title`)\n * each containing a TypeScript code block with `// WRONG` and\n * `// CORRECT` examples. Some sections include prose between the\n * heading and the code block — captured as `explanation`.\n *\n * IDs are kebab-cased slugs derived from the heading text; stable\n * across releases as long as the heading isn't renamed.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst PKG_ROOT = resolve(__dirname, \"..\");\n\nexport type AntiPatternSeverity = \"error\" | \"warning\" | \"info\";\nexport type AntiPatternCategory =\n | \"module\"\n | \"schema\"\n | \"constraint\"\n | \"resolver\"\n | \"derivation\"\n | \"effect\"\n | \"naming\"\n | \"react\"\n | \"composition\";\n\nexport interface AntiPattern {\n /** Stable slug, derived from the heading text. */\n id: string;\n /** Section number in the source markdown (1..N). */\n number: number;\n /** Human-readable title (the heading text minus the number prefix). */\n title: string;\n /** Default severity. Heuristic; tunable per-rule later. */\n severity: AntiPatternSeverity;\n /** Heuristic category from title keywords. */\n category: AntiPatternCategory;\n /** Body prose between heading and the first code block (often empty). */\n explanation: string;\n /** The `// WRONG` example, if present. */\n badExample?: string;\n /** The `// CORRECT` example, if present. */\n goodExample?: string;\n}\n\nlet cache: ReadonlyArray<AntiPattern> | null = null;\n\nfunction resolveSourcePath(): string {\n const candidates = [\n join(PKG_ROOT, \"core\", \"anti-patterns.md\"),\n join(PKG_ROOT, \"..\", \"core\", \"anti-patterns.md\"),\n ];\n for (const c of candidates) {\n if (existsSync(c)) {\n return c;\n }\n }\n return candidates[0] ?? \"\";\n}\n\nfunction slugify(title: string): string {\n return title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .replace(/-{2,}/g, \"-\");\n}\n\nfunction categorize(title: string): AntiPatternCategory {\n const lower = title.toLowerCase();\n if (/schema|builder/.test(lower)) {\n return \"schema\";\n }\n if (/constraint|cross-?module|require/.test(lower)) {\n return \"constraint\";\n }\n if (/resolver|settle|start/.test(lower)) {\n return \"resolver\";\n }\n if (/deriv|passthrough/.test(lower)) {\n return \"derivation\";\n }\n if (/effect/.test(lower)) {\n return \"effect\";\n }\n if (/usedirective|react|hook/.test(lower)) {\n return \"react\";\n }\n if (/import|bracket|deep import|name|context|abbreviat/.test(lower)) {\n return \"naming\";\n }\n if (/init|module|config/.test(lower)) {\n return \"module\";\n }\n return \"module\";\n}\n\nfunction severityFor(title: string): AntiPatternSeverity {\n const lower = title.toLowerCase();\n if (/nonexistent|missing|no error|deep import|async logic/.test(lower)) {\n return \"error\";\n }\n return \"warning\";\n}\n\ninterface Section {\n number: number;\n title: string;\n body: string;\n}\n\nfunction splitSections(md: string): Section[] {\n const lines = md.split(\"\\n\");\n const sections: Section[] = [];\n let current: Section | null = null;\n const heading = /^##\\s+(\\d+)\\.\\s+(.+?)\\s*$/;\n for (const line of lines) {\n const match = heading.exec(line);\n if (match?.[1] && match?.[2]) {\n if (current) {\n sections.push(current);\n }\n current = {\n number: Number(match[1]),\n title: match[2],\n body: \"\",\n };\n continue;\n }\n if (current) {\n // Stop at the first non-numbered ## section (e.g. \"Quick Reference Checklist\")\n if (/^##\\s+\\D/.test(line)) {\n sections.push(current);\n current = null;\n break;\n }\n current.body += `${line}\\n`;\n }\n }\n if (current) {\n sections.push(current);\n }\n return sections;\n}\n\nfunction extractExamples(body: string): {\n explanation: string;\n badExample?: string;\n goodExample?: string;\n} {\n const codeBlock = body.match(/```typescript\\n([\\s\\S]*?)```/);\n const explanationLines: string[] = [];\n for (const line of body.split(\"\\n\")) {\n if (line.startsWith(\"```\")) {\n break;\n }\n explanationLines.push(line);\n }\n const explanation = explanationLines.join(\"\\n\").trim();\n\n if (!codeBlock?.[1]) {\n return { explanation };\n }\n\n const code = codeBlock[1];\n // Split on the WRONG/CORRECT comment markers.\n const wrongMatch = code.match(\n /\\/\\/\\s*WRONG[^\\n]*\\n([\\s\\S]*?)(?:\\/\\/\\s*CORRECT|$)/,\n );\n const correctMatch = code.match(/\\/\\/\\s*CORRECT[^\\n]*\\n([\\s\\S]*)/);\n\n return {\n explanation,\n badExample: wrongMatch?.[1]?.trim() ?? undefined,\n goodExample: correctMatch?.[1]?.trim() ?? undefined,\n };\n}\n\nfunction loadAntiPatterns(): ReadonlyArray<AntiPattern> {\n if (cache) {\n return cache;\n }\n\n const sourcePath = resolveSourcePath();\n let md: string;\n try {\n md = readFileSync(sourcePath, \"utf-8\");\n } catch {\n cache = Object.freeze([]);\n return cache;\n }\n\n const sections = splitSections(md);\n const out: AntiPattern[] = sections.map((section) => {\n const { explanation, badExample, goodExample } = extractExamples(\n section.body,\n );\n return {\n id: slugify(section.title),\n number: section.number,\n title: section.title,\n severity: severityFor(section.title),\n category: categorize(section.title),\n explanation,\n badExample,\n goodExample,\n };\n });\n\n cache = Object.freeze(out);\n return cache;\n}\n\n/** Return every parsed anti-pattern, stable order, frozen. */\nexport function getAntiPatterns(): ReadonlyArray<AntiPattern> {\n return loadAntiPatterns();\n}\n\n/** Look up one anti-pattern by its slug id. */\nexport function getAntiPatternById(id: string): AntiPattern | undefined {\n return loadAntiPatterns().find((ap) => ap.id === id);\n}\n\n/** Clear the in-memory cache. Test / watch-mode helper. */\nexport function clearAntiPatternCache(): void {\n cache = null;\n}\n","/**\n * Loader for `packages/knowledge/migration.json` → structured\n * migration patterns. Lazy + cached.\n *\n * The JSON ships in the published tarball; consumers don't need to\n * parse markdown at runtime.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst PKG_ROOT = resolve(__dirname, \"..\");\n\n/** Supported source-library identifiers. */\nexport const MIGRATION_SOURCES = [\n \"redux\",\n \"zustand\",\n \"xstate\",\n \"mobx\",\n \"jotai\",\n \"recoil\",\n] as const;\nexport type MigrationSourceId = (typeof MIGRATION_SOURCES)[number];\n\nexport interface MigrationConceptRow {\n from: string;\n to: string;\n note: string;\n}\n\nexport interface MigrationPattern {\n id: MigrationSourceId;\n name: string;\n conceptMap: MigrationConceptRow[];\n steps: string[];\n before: string;\n after: string;\n}\n\ninterface MigrationFile {\n version: number;\n sources: MigrationPattern[];\n}\n\nlet cache: ReadonlyArray<MigrationPattern> | null = null;\n\nfunction resolveSourcePath(): string {\n const candidates = [\n join(PKG_ROOT, \"migration.json\"),\n join(PKG_ROOT, \"..\", \"migration.json\"),\n ];\n for (const c of candidates) {\n if (existsSync(c)) {\n return c;\n }\n }\n return candidates[0] ?? \"\";\n}\n\nfunction load(): ReadonlyArray<MigrationPattern> {\n if (cache) {\n return cache;\n }\n try {\n const raw = readFileSync(resolveSourcePath(), \"utf-8\");\n const parsed = JSON.parse(raw) as MigrationFile;\n cache = Object.freeze(parsed.sources ?? []);\n } catch {\n cache = Object.freeze([]);\n }\n return cache;\n}\n\n/** All supported source library IDs. */\nexport function getMigrationSources(): ReadonlyArray<MigrationSourceId> {\n return MIGRATION_SOURCES;\n}\n\n/** All migration patterns, in registry order. */\nexport function getMigrationPatterns(): ReadonlyArray<MigrationPattern> {\n return load();\n}\n\n/** One migration pattern by its source-library id. */\nexport function getMigrationPattern(\n source: string,\n): MigrationPattern | undefined {\n return load().find((p) => p.id === source);\n}\n\n/** Test / watch-mode helper. */\nexport function clearMigrationCache(): void {\n cache = null;\n}\n","/**\n * Loader for `packages/knowledge/compositions.json` → typed\n * composition graph. Lazy + cached.\n *\n * The JSON ships in the published tarball. Adjacency list rather\n * than per-package projections so consumers can answer both\n * \"what does X compose with?\" and \"what composes with X?\" without\n * duplicate data.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n// After bundling, all parsers live in dist/index.js — one level up\n// from dist reaches the package root. In src/ during dev, the file is\n// two levels up; the fallback in `resolveSourcePath` handles that.\nconst PKG_ROOT = resolve(__dirname, \"..\");\n\nexport interface CompositionEdge {\n from: string;\n to: string;\n reason: string;\n}\n\ninterface CompositionsFile {\n version: number;\n edges: CompositionEdge[];\n}\n\nlet cache: ReadonlyArray<CompositionEdge> | null = null;\n\nfunction resolveSourcePath(): string {\n const candidates = [\n join(PKG_ROOT, \"compositions.json\"),\n join(PKG_ROOT, \"..\", \"compositions.json\"),\n ];\n for (const c of candidates) {\n if (existsSync(c)) {\n return c;\n }\n }\n return candidates[0] ?? \"\";\n}\n\nfunction load(): ReadonlyArray<CompositionEdge> {\n if (cache) {\n return cache;\n }\n try {\n const raw = readFileSync(resolveSourcePath(), \"utf-8\");\n const parsed = JSON.parse(raw) as CompositionsFile;\n cache = Object.freeze(parsed.edges ?? []);\n } catch {\n cache = Object.freeze([]);\n }\n return cache;\n}\n\n/** All composition edges as a flat list. */\nexport function getCompositions(): ReadonlyArray<CompositionEdge> {\n return load();\n}\n\n/**\n * All edges originating at the given package. Returns an empty array\n * when the package is unknown or has no outgoing compositions.\n */\nexport function getCompositionsFor(\n packageName: string,\n): ReadonlyArray<CompositionEdge> {\n return load().filter((e) => e.from === packageName);\n}\n\n/**\n * All edges arriving at the given package — \"who composes WITH me?\"\n */\nexport function getReverseCompositionsFor(\n packageName: string,\n): ReadonlyArray<CompositionEdge> {\n return load().filter((e) => e.to === packageName);\n}\n\n/** Test / watch-mode helper. */\nexport function clearCompositionsCache(): void {\n cache = null;\n}\n","import { existsSync, readFileSync, readdirSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n// Resolve package root: works both in src/ (dev) and dist/ (bundled)\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst PKG_ROOT = resolve(__dirname, \"..\");\n\n/**\n * Resolve a path relative to the package root.\n * Tries dist-relative first (bundled), then src-relative (dev).\n */\nfunction resolveAsset(name: string): string {\n const fromDist = join(PKG_ROOT, name);\n if (existsSync(fromDist)) {\n return fromDist;\n }\n\n const fromSrc = join(PKG_ROOT, \"..\", name);\n if (existsSync(fromSrc)) {\n return fromSrc;\n }\n\n return fromDist; // default, will just return empty maps\n}\n\nconst CORE_DIR = resolveAsset(\"core\");\nconst AI_DIR = resolveAsset(\"ai\");\nconst EXAMPLES_DIR = resolveAsset(\"examples\");\nconst API_SKELETON_PATH = resolveAsset(\"api-skeleton.md\");\n\nlet knowledgeCache: Map<string, string> | null = null;\nlet exampleCache: Map<string, string> | null = null;\n\nfunction loadDir(dir: string, map: Map<string, string>): void {\n try {\n const files = readdirSync(dir).filter(\n (f) => f.endsWith(\".md\") || f.endsWith(\".ts\"),\n );\n for (const file of files) {\n const name = file.replace(/\\.(md|ts)$/, \"\");\n map.set(name, readFileSync(join(dir, file), \"utf-8\"));\n }\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw err;\n }\n // directory does not exist — expected during tests or incomplete installs\n }\n}\n\nfunction loadAllKnowledge(): Map<string, string> {\n const map = new Map<string, string>();\n loadDir(CORE_DIR, map);\n loadDir(AI_DIR, map);\n\n // Include api-skeleton\n try {\n map.set(\"api-skeleton\", readFileSync(API_SKELETON_PATH, \"utf-8\"));\n } catch {\n // may not exist yet\n }\n\n return map;\n}\n\nfunction loadAllExamples(): Map<string, string> {\n const map = new Map<string, string>();\n loadDir(EXAMPLES_DIR, map);\n\n return map;\n}\n\n/**\n * Look up a bundled knowledge file by name. Returns the raw markdown\n * string. Returns `\"\"` when the name isn't known — callers driving an\n * LLM should pair this with {@link hasKnowledge} so a typo turns\n * into an actionable error instead of a silently empty prompt.\n *\n * @example\n * ```ts\n * import { getKnowledge, hasKnowledge } from \"@directive-run/knowledge\";\n *\n * if (!hasKnowledge(\"guardrails\")) throw new Error(\"typo\");\n * const md = getKnowledge(\"guardrails\");\n * ```\n */\nexport function getKnowledge(name: string): string {\n if (!knowledgeCache) {\n knowledgeCache = loadAllKnowledge();\n }\n\n return knowledgeCache.get(name) ?? \"\";\n}\n\n/**\n * Return every loaded knowledge file as `name → markdown`. Consumers\n * iterating the corpus (full-text search, embedding builder, RAG\n * index) read this once and key off the returned map.\n */\nexport function getAllKnowledge(): ReadonlyMap<string, string> {\n if (!knowledgeCache) {\n knowledgeCache = loadAllKnowledge();\n }\n\n return knowledgeCache;\n}\n\n/**\n * `true` when a knowledge file with this exact name is bundled.\n * Use this BEFORE {@link getKnowledge} when the name is user / agent\n * input — `getKnowledge` returns `\"\"` on miss, which is\n * indistinguishable from an intentionally empty file.\n *\n * @example\n * ```ts\n * if (!hasKnowledge(userTyped)) {\n * console.error(`unknown knowledge file: ${userTyped}`);\n * console.error(`available: ${[...getAllKnowledge().keys()].join(\", \")}`);\n * return;\n * }\n * ```\n */\nexport function hasKnowledge(name: string): boolean {\n if (!knowledgeCache) {\n knowledgeCache = loadAllKnowledge();\n }\n return knowledgeCache.has(name);\n}\n\n/**\n * Look up a bundled example file by name. Returns the raw source.\n * Returns `\"\"` when the name isn't known — pair with {@link hasExample}\n * when the input is user-controlled.\n */\nexport function getExample(name: string): string {\n if (!exampleCache) {\n exampleCache = loadAllExamples();\n }\n\n return exampleCache.get(name) ?? \"\";\n}\n\n/**\n * `true` when an example file with this exact name is bundled.\n * The miss-vs-empty disambiguator for {@link getExample}.\n */\nexport function hasExample(name: string): boolean {\n if (!exampleCache) {\n exampleCache = loadAllExamples();\n }\n return exampleCache.has(name);\n}\n\nexport function getAllExamples(): ReadonlyMap<string, string> {\n if (!exampleCache) {\n exampleCache = loadAllExamples();\n }\n\n return exampleCache;\n}\n\nexport function getKnowledgeFiles(names: string[]): string {\n return names\n .map((name) => getKnowledge(name))\n .filter(Boolean)\n .join(\"\\n\\n---\\n\\n\");\n}\n\nexport function getExampleFiles(names: string[]): string {\n return names\n .map((name) => {\n const content = getExample(name);\n if (!content) {\n return \"\";\n }\n\n return `### Example: ${name}\\n\\n\\`\\`\\`typescript\\n${content}\\n\\`\\`\\``;\n })\n .filter(Boolean)\n .join(\"\\n\\n\");\n}\n\n/** Clear cached knowledge and examples. Useful for dev/watch mode. */\nexport function clearCache(): void {\n knowledgeCache = null;\n exampleCache = null;\n}\n\n// ---------------------------------------------------------------------------\n// Structured data APIs (v1.16.0 — back the MCP `list_review_rules`,\n// `get_review_rule`, `list_migration_sources`, `get_migration_pattern`,\n// `get_composable_packages` tools).\n// ---------------------------------------------------------------------------\n\nexport {\n type AntiPattern,\n type AntiPatternCategory,\n type AntiPatternSeverity,\n clearAntiPatternCache,\n getAntiPatternById,\n getAntiPatterns,\n} from \"./parsers/anti-patterns.js\";\n\nexport {\n type MigrationConceptRow,\n type MigrationPattern,\n type MigrationSourceId,\n MIGRATION_SOURCES,\n clearMigrationCache,\n getMigrationPattern,\n getMigrationPatterns,\n getMigrationSources,\n} from \"./parsers/migration.js\";\n\nexport {\n type CompositionEdge,\n clearCompositionsCache,\n getCompositions,\n getCompositionsFor,\n getReverseCompositionsFor,\n} from \"./parsers/compositions.js\";\n"]}
1
+ {"version":3,"sources":["../src/parsers/anti-patterns.ts","../src/parsers/migration.ts","../src/parsers/compositions.ts","../src/index.ts"],"names":["__dirname","dirname","fileURLToPath","PKG_ROOT","resolve","cache","resolveSourcePath","candidates","join","c","existsSync","slugify","title","categorize","lower","severityFor","splitSections","md","lines","sections","current","heading","line","match","extractExamples","body","codeBlock","explanationLines","explanation","code","wrongMatch","correctMatch","loadAntiPatterns","sourcePath","readFileSync","out","section","badExample","goodExample","getAntiPatterns","getAntiPatternById","id","ap","clearAntiPatternCache","MIGRATION_SOURCES","load","raw","parsed","getMigrationSources","getMigrationPatterns","getMigrationPattern","source","p","clearMigrationCache","getCompositions","getCompositionsFor","packageName","getReverseCompositionsFor","clearCompositionsCache","resolveAsset","name","fromDist","fromSrc","CORE_DIR","AI_DIR","EXAMPLES_DIR","API_SKELETON_PATH","knowledgeCache","exampleCache","loadDir","dir","map","files","readdirSync","f","file","err","loadAllKnowledge","loadAllExamples","getKnowledge","getAllKnowledge","hasKnowledge","getExample","hasExample","getAllExamples","getKnowledgeFiles","names","getExampleFiles","content","clearCache"],"mappings":"6HAkBA,IAAMA,EAAYC,OAAAA,CAAQC,aAAAA,CAAc,YAAY,GAAG,CAAC,CAAA,CAClDC,CAAAA,CAAWC,QAAQJ,CAAAA,CAAW,IAAI,EAiCpCK,CAAAA,CAAuC,IAAA,CAE3C,SAASC,CAAAA,EAA4B,CACnC,IAAMC,CAAAA,CAAa,CACjBC,KAAKL,CAAAA,CAAU,MAAA,CAAQ,kBAAkB,CAAA,CACzCK,IAAAA,CAAKL,EAAU,IAAA,CAAM,MAAA,CAAQ,kBAAkB,CACjD,EACA,IAAA,IAAWM,CAAAA,IAAKF,EACd,GAAIG,UAAAA,CAAWD,CAAC,CAAA,CACd,OAAOA,EAGX,OAAOF,CAAAA,CAAW,CAAC,CAAA,EAAK,EAC1B,CAEA,SAASI,CAAAA,CAAQC,EAAuB,CACtC,OAAOA,CAAAA,CACJ,WAAA,GACA,OAAA,CAAQ,aAAA,CAAe,GAAG,CAAA,CAC1B,OAAA,CAAQ,WAAY,EAAE,CAAA,CACtB,QAAQ,QAAA,CAAU,GAAG,CAC1B,CAEA,SAASC,EAAWD,CAAAA,CAAoC,CACtD,IAAME,CAAAA,CAAQF,CAAAA,CAAM,WAAA,EAAY,CAChC,OAAI,gBAAA,CAAiB,IAAA,CAAKE,CAAK,CAAA,CACtB,QAAA,CAEL,mCAAmC,IAAA,CAAKA,CAAK,EACxC,YAAA,CAEL,uBAAA,CAAwB,KAAKA,CAAK,CAAA,CAC7B,WAEL,mBAAA,CAAoB,IAAA,CAAKA,CAAK,CAAA,CACzB,YAAA,CAEL,QAAA,CAAS,IAAA,CAAKA,CAAK,CAAA,CACd,QAAA,CAEL,0BAA0B,IAAA,CAAKA,CAAK,EAC/B,OAAA,CAEL,mDAAA,CAAoD,KAAKA,CAAK,CAAA,CACzD,UAGA,QAAA,CAGX,CAEA,SAASC,CAAAA,CAAYH,EAAoC,CACvD,IAAME,EAAQF,CAAAA,CAAM,WAAA,GACpB,OAAI,sDAAA,CAAuD,KAAKE,CAAK,CAAA,CAC5D,QAEF,SACT,CAQA,SAASE,CAAAA,CAAcC,CAAAA,CAAuB,CAC5C,IAAMC,CAAAA,CAAQD,EAAG,KAAA,CAAM;AAAA,CAAI,CAAA,CACrBE,CAAAA,CAAsB,EAAC,CACzBC,EAA0B,IAAA,CACxBC,CAAAA,CAAU,2BAAA,CAChB,IAAA,IAAWC,CAAAA,IAAQJ,CAAAA,CAAO,CACxB,IAAMK,EAAQF,CAAAA,CAAQ,IAAA,CAAKC,CAAI,CAAA,CAC/B,GAAIC,CAAAA,GAAQ,CAAC,CAAA,EAAKA,IAAQ,CAAC,CAAA,CAAG,CACxBH,CAAAA,EACFD,CAAAA,CAAS,IAAA,CAAKC,CAAO,CAAA,CAEvBA,EAAU,CACR,MAAA,CAAQ,MAAA,CAAOG,CAAAA,CAAM,CAAC,CAAC,CAAA,CACvB,KAAA,CAAOA,EAAM,CAAC,CAAA,CACd,IAAA,CAAM,EACR,CAAA,CACA,QACF,CACA,GAAIH,EAAS,CAEX,GAAI,UAAA,CAAW,IAAA,CAAKE,CAAI,CAAA,CAAG,CACzBH,CAAAA,CAAS,KAAKC,CAAO,CAAA,CACrBA,CAAAA,CAAU,IAAA,CACV,KACF,CACAA,CAAAA,CAAQ,IAAA,EAAQ,GAAGE,CAAI;AAAA,EACzB,CACF,CACA,OAAIF,CAAAA,EACFD,CAAAA,CAAS,IAAA,CAAKC,CAAO,CAAA,CAEhBD,CACT,CAEA,SAASK,CAAAA,CAAgBC,CAAAA,CAIvB,CACA,IAAMC,CAAAA,CAAYD,CAAAA,CAAK,KAAA,CAAM,8BAA8B,CAAA,CACrDE,CAAAA,CAA6B,EAAC,CACpC,IAAA,IAAWL,CAAAA,IAAQG,CAAAA,CAAK,KAAA,CAAM;AAAA,CAAI,EAAG,CACnC,GAAIH,CAAAA,CAAK,UAAA,CAAW,KAAK,CAAA,CACvB,MAEFK,CAAAA,CAAiB,IAAA,CAAKL,CAAI,EAC5B,CACA,IAAMM,CAAAA,CAAcD,EAAiB,IAAA,CAAK;AAAA,CAAI,EAAE,IAAA,EAAK,CAErD,GAAI,CAACD,CAAAA,GAAY,CAAC,CAAA,CAChB,OAAO,CAAE,WAAA,CAAAE,CAAY,CAAA,CAGvB,IAAMC,EAAOH,CAAAA,CAAU,CAAC,EAElBI,CAAAA,CAAaD,CAAAA,CAAK,KAAA,CACtB,oDACF,EACME,CAAAA,CAAeF,CAAAA,CAAK,MAAM,iCAAiC,CAAA,CAEjE,OAAO,CACL,WAAA,CAAAD,EACA,UAAA,CAAYE,CAAAA,GAAa,CAAC,CAAA,EAAG,IAAA,IAAU,MAAA,CACvC,WAAA,CAAaC,IAAe,CAAC,CAAA,EAAG,IAAA,EAAK,EAAK,MAC5C,CACF,CAEA,SAASC,CAAAA,EAA2C,CAClD,GAAI3B,CAAAA,CACF,OAAOA,CAAAA,CAGT,IAAM4B,EAAa3B,CAAAA,EAAkB,CACjCW,EACJ,GAAI,CACFA,EAAKiB,YAAAA,CAAaD,CAAAA,CAAY,OAAO,EACvC,MAAQ,CACN,OAAA5B,EAAQ,MAAA,CAAO,MAAA,CAAO,EAAE,CAAA,CACjBA,CACT,CAGA,IAAM8B,EADWnB,CAAAA,CAAcC,CAAE,EACG,GAAA,CAAKmB,CAAAA,EAAY,CACnD,GAAM,CAAE,WAAA,CAAAR,CAAAA,CAAa,WAAAS,CAAAA,CAAY,WAAA,CAAAC,CAAY,CAAA,CAAId,CAAAA,CAC/CY,EAAQ,IACV,CAAA,CACA,OAAO,CACL,GAAIzB,CAAAA,CAAQyB,CAAAA,CAAQ,KAAK,CAAA,CACzB,MAAA,CAAQA,EAAQ,MAAA,CAChB,KAAA,CAAOA,CAAAA,CAAQ,KAAA,CACf,SAAUrB,CAAAA,CAAYqB,CAAAA,CAAQ,KAAK,CAAA,CACnC,QAAA,CAAUvB,EAAWuB,CAAAA,CAAQ,KAAK,EAClC,WAAA,CAAAR,CAAAA,CACA,WAAAS,CAAAA,CACA,WAAA,CAAAC,CACF,CACF,CAAC,EAED,OAAAjC,CAAAA,CAAQ,MAAA,CAAO,MAAA,CAAO8B,CAAG,CAAA,CAClB9B,CACT,CAGO,SAASkC,CAAAA,EAA0C,CACxD,OAAOP,CAAAA,EACT,CAGO,SAASQ,CAAAA,CAAmBC,CAAAA,CAAqC,CACtE,OAAOT,CAAAA,GAAmB,IAAA,CAAMU,CAAAA,EAAOA,CAAAA,CAAG,EAAA,GAAOD,CAAE,CACrD,CAGO,SAASE,CAAAA,EAA8B,CAC5CtC,EAAQ,KACV,CC7NA,IAAML,CAAAA,CAAYC,QAAQC,aAAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAC,EAClDC,CAAAA,CAAWC,OAAAA,CAAQJ,EAAW,IAAI,CAAA,CAG3B4C,EAAoB,CAC/B,OAAA,CACA,SAAA,CACA,QAAA,CACA,OACA,OAAA,CACA,QACF,EAuBIvC,CAAAA,CAA4C,KAEhD,SAASC,CAAAA,EAA4B,CACnC,IAAMC,CAAAA,CAAa,CACjBC,KAAKL,CAAAA,CAAU,gBAAgB,EAC/BK,IAAAA,CAAKL,CAAAA,CAAU,KAAM,gBAAgB,CACvC,CAAA,CACA,IAAA,IAAWM,KAAKF,CAAAA,CACd,GAAIG,WAAWD,CAAC,CAAA,CACd,OAAOA,CAAAA,CAGX,OAAOF,CAAAA,CAAW,CAAC,GAAK,EAC1B,CAEA,SAASsC,CAAAA,EAAoC,CAC3C,GAAIxC,CAAAA,CACF,OAAOA,CAAAA,CAET,GAAI,CACF,IAAMyC,CAAAA,CAAMZ,aAAa5B,CAAAA,EAAkB,CAAG,OAAO,CAAA,CAC/CyC,CAAAA,CAAS,KAAK,KAAA,CAAMD,CAAG,EAC7BzC,CAAAA,CAAQ,MAAA,CAAO,OAAO0C,CAAAA,CAAO,OAAA,EAAW,EAAE,EAC5C,CAAA,KAAQ,CACN1C,EAAQ,MAAA,CAAO,MAAA,CAAO,EAAE,EAC1B,CACA,OAAOA,CACT,CAGO,SAAS2C,GAAoD,CAClE,OAAOJ,CACT,CAGO,SAASK,IAAoD,CAClE,OAAOJ,CAAAA,EACT,CAGO,SAASK,EAAAA,CACdC,EAC8B,CAC9B,OAAON,GAAK,CAAE,IAAA,CAAMO,GAAMA,CAAAA,CAAE,EAAA,GAAOD,CAAM,CAC3C,CAGO,SAASE,EAAAA,EAA4B,CAC1ChD,EAAQ,KACV,CCjFA,IAAML,EAAAA,CAAYC,QAAQC,aAAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAC,EAIlDC,CAAAA,CAAWC,OAAAA,CAAQJ,GAAW,IAAI,CAAA,CAapCK,EAA2C,IAAA,CAE/C,SAASC,IAA4B,CACnC,IAAMC,EAAa,CACjBC,IAAAA,CAAKL,EAAU,mBAAmB,CAAA,CAClCK,KAAKL,CAAAA,CAAU,IAAA,CAAM,mBAAmB,CAC1C,EACA,IAAA,IAAWM,CAAAA,IAAKF,EACd,GAAIG,UAAAA,CAAWD,CAAC,CAAA,CACd,OAAOA,CAAAA,CAGX,OAAOF,EAAW,CAAC,CAAA,EAAK,EAC1B,CAEA,SAASsC,GAAmC,CAC1C,GAAIxC,CAAAA,CACF,OAAOA,EAET,GAAI,CACF,IAAMyC,CAAAA,CAAMZ,YAAAA,CAAa5B,IAAkB,CAAG,OAAO,EAC/CyC,CAAAA,CAAS,IAAA,CAAK,MAAMD,CAAG,CAAA,CAC7BzC,EAAQ,MAAA,CAAO,MAAA,CAAO0C,EAAO,KAAA,EAAS,EAAE,EAC1C,MAAQ,CACN1C,CAAAA,CAAQ,OAAO,MAAA,CAAO,EAAE,EAC1B,CACA,OAAOA,CACT,CAGO,SAASiD,EAAAA,EAA8C,CAC5D,OAAOT,CAAAA,EACT,CAMO,SAASU,EAAAA,CACdC,CAAAA,CAC4B,CAC5B,OAAOX,CAAAA,GAAO,MAAA,CAAQ,CAAA,EAAM,EAAE,IAAA,GAASW,CAAW,CACpD,CAKO,SAASC,GACdD,CAAAA,CAC4B,CAC5B,OAAOX,CAAAA,EAAK,CAAE,OAAQ,CAAA,EAAM,CAAA,CAAE,EAAA,GAAOW,CAAW,CAClD,CAGO,SAASE,IAA+B,CAC7CrD,CAAAA,CAAQ,KACV,CClFA,IAAML,EAAAA,CAAYC,OAAAA,CAAQC,cAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAC,CAAA,CAClDC,CAAAA,CAAWC,QAAQJ,EAAAA,CAAW,IAAI,CAAA,CAMxC,SAAS2D,EAAaC,CAAAA,CAAsB,CAC1C,IAAMC,CAAAA,CAAWrD,IAAAA,CAAKL,EAAUyD,CAAI,CAAA,CACpC,GAAIlD,UAAAA,CAAWmD,CAAQ,EACrB,OAAOA,CAAAA,CAGT,IAAMC,CAAAA,CAAUtD,IAAAA,CAAKL,EAAU,IAAA,CAAMyD,CAAI,CAAA,CACzC,OAAIlD,WAAWoD,CAAO,CAAA,CACbA,EAGFD,CACT,CAEA,IAAME,EAAAA,CAAWJ,CAAAA,CAAa,MAAM,CAAA,CAC9BK,GAASL,CAAAA,CAAa,IAAI,EAC1BM,EAAAA,CAAeN,CAAAA,CAAa,UAAU,CAAA,CACtCO,EAAAA,CAAoBP,CAAAA,CAAa,iBAAiB,EAEpDQ,CAAAA,CAA6C,IAAA,CAC7CC,EAA2C,IAAA,CAE/C,SAASC,EAAQC,CAAAA,CAAaC,CAAAA,CAAgC,CAC5D,GAAI,CACF,IAAMC,CAAAA,CAAQC,WAAAA,CAAYH,CAAG,CAAA,CAAE,MAAA,CAC5BI,GAAMA,CAAAA,CAAE,QAAA,CAAS,KAAK,CAAA,EAAKA,EAAE,QAAA,CAAS,KAAK,CAC9C,CAAA,CACA,IAAA,IAAWC,KAAQH,CAAAA,CAAO,CACxB,IAAMZ,CAAAA,CAAOe,EAAK,OAAA,CAAQ,YAAA,CAAc,EAAE,CAAA,CAC1CJ,CAAAA,CAAI,IAAIX,CAAAA,CAAM1B,YAAAA,CAAa1B,IAAAA,CAAK8D,CAAAA,CAAKK,CAAI,CAAA,CAAG,OAAO,CAAC,EACtD,CACF,OAASC,CAAAA,CAAc,CACrB,GAAKA,CAAAA,CAA8B,IAAA,GAAS,SAC1C,MAAMA,CAGV,CACF,CAEA,SAASC,GAAwC,CAC/C,IAAMN,CAAAA,CAAM,IAAI,IAChBF,CAAAA,CAAQN,EAAAA,CAAUQ,CAAG,CAAA,CACrBF,CAAAA,CAAQL,GAAQO,CAAG,CAAA,CAGnB,GAAI,CACFA,EAAI,GAAA,CAAI,cAAA,CAAgBrC,aAAagC,EAAAA,CAAmB,OAAO,CAAC,EAClE,CAAA,KAAQ,CAER,CAEA,OAAOK,CACT,CAEA,SAASO,CAAAA,EAAuC,CAC9C,IAAMP,CAAAA,CAAM,IAAI,IAChB,OAAAF,CAAAA,CAAQJ,GAAcM,CAAG,CAAA,CAElBA,CACT,CAgBO,SAASQ,GAAanB,CAAAA,CAAsB,CACjD,OAAKO,CAAAA,GACHA,EAAiBU,CAAAA,EAAiB,CAAA,CAG7BV,EAAe,GAAA,CAAIP,CAAI,GAAK,EACrC,CAOO,SAASoB,EAAAA,EAA+C,CAC7D,OAAKb,CAAAA,GACHA,EAAiBU,CAAAA,EAAiB,CAAA,CAG7BV,CACT,CAiBO,SAASc,EAAAA,CAAarB,CAAAA,CAAuB,CAClD,OAAKO,CAAAA,GACHA,EAAiBU,CAAAA,EAAiB,CAAA,CAE7BV,EAAe,GAAA,CAAIP,CAAI,CAChC,CAOO,SAASsB,GAAWtB,CAAAA,CAAsB,CAC/C,OAAKQ,CAAAA,GACHA,CAAAA,CAAeU,GAAgB,CAAA,CAG1BV,CAAAA,CAAa,GAAA,CAAIR,CAAI,GAAK,EACnC,CAMO,SAASuB,EAAAA,CAAWvB,CAAAA,CAAuB,CAChD,OAAKQ,CAAAA,GACHA,EAAeU,CAAAA,EAAgB,CAAA,CAE1BV,EAAa,GAAA,CAAIR,CAAI,CAC9B,CAEO,SAASwB,IAA8C,CAC5D,OAAKhB,CAAAA,GACHA,CAAAA,CAAeU,GAAgB,CAAA,CAG1BV,CACT,CAEO,SAASiB,EAAAA,CAAkBC,EAAyB,CACzD,OAAOA,EACJ,GAAA,CAAK1B,CAAAA,EAASmB,GAAanB,CAAI,CAAC,EAChC,MAAA,CAAO,OAAO,EACd,IAAA,CAAK;;AAAA;;AAAA,CAAa,CACvB,CAEO,SAAS2B,GAAgBD,CAAAA,CAAyB,CACvD,OAAOA,CAAAA,CACJ,GAAA,CAAK1B,GAAS,CACb,IAAM4B,EAAUN,EAAAA,CAAWtB,CAAI,EAC/B,OAAK4B,CAAAA,CAIE,gBAAgB5B,CAAI;;AAAA;AAAA,EAAyB4B,CAAO;AAAA,MAAA,CAAA,CAHlD,EAIX,CAAC,CAAA,CACA,MAAA,CAAO,OAAO,EACd,IAAA,CAAK;;AAAA,CAAM,CAChB,CAGO,SAASC,EAAAA,EAAmB,CACjCtB,CAAAA,CAAiB,IAAA,CACjBC,EAAe,KACjB","file":"index.js","sourcesContent":["/**\n * Parser for `packages/knowledge/core/anti-patterns.md` → structured\n * `AntiPattern[]` data. Lazy + cached so the cost is paid once per\n * process at first call.\n *\n * The source markdown is organized as numbered sections (`## N. Title`)\n * each containing a TypeScript code block with `// WRONG` and\n * `// CORRECT` examples. Some sections include prose between the\n * heading and the code block — captured as `explanation`.\n *\n * IDs are kebab-cased slugs derived from the heading text; stable\n * across releases as long as the heading isn't renamed.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst PKG_ROOT = resolve(__dirname, \"..\");\n\nexport type AntiPatternSeverity = \"error\" | \"warning\" | \"info\";\nexport type AntiPatternCategory =\n | \"module\"\n | \"schema\"\n | \"constraint\"\n | \"resolver\"\n | \"derivation\"\n | \"effect\"\n | \"naming\"\n | \"react\"\n | \"composition\";\n\nexport interface AntiPattern {\n /** Stable slug, derived from the heading text. */\n id: string;\n /** Section number in the source markdown (1..N). */\n number: number;\n /** Human-readable title (the heading text minus the number prefix). */\n title: string;\n /** Default severity. Heuristic; tunable per-rule later. */\n severity: AntiPatternSeverity;\n /** Heuristic category from title keywords. */\n category: AntiPatternCategory;\n /** Body prose between heading and the first code block (often empty). */\n explanation: string;\n /** The `// WRONG` example, if present. */\n badExample?: string;\n /** The `// CORRECT` example, if present. */\n goodExample?: string;\n}\n\nlet cache: readonly AntiPattern[] | null = null;\n\nfunction resolveSourcePath(): string {\n const candidates = [\n join(PKG_ROOT, \"core\", \"anti-patterns.md\"),\n join(PKG_ROOT, \"..\", \"core\", \"anti-patterns.md\"),\n ];\n for (const c of candidates) {\n if (existsSync(c)) {\n return c;\n }\n }\n return candidates[0] ?? \"\";\n}\n\nfunction slugify(title: string): string {\n return title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .replace(/-{2,}/g, \"-\");\n}\n\nfunction categorize(title: string): AntiPatternCategory {\n const lower = title.toLowerCase();\n if (/schema|builder/.test(lower)) {\n return \"schema\";\n }\n if (/constraint|cross-?module|require/.test(lower)) {\n return \"constraint\";\n }\n if (/resolver|settle|start/.test(lower)) {\n return \"resolver\";\n }\n if (/deriv|passthrough/.test(lower)) {\n return \"derivation\";\n }\n if (/effect/.test(lower)) {\n return \"effect\";\n }\n if (/usedirective|react|hook/.test(lower)) {\n return \"react\";\n }\n if (/import|bracket|deep import|name|context|abbreviat/.test(lower)) {\n return \"naming\";\n }\n if (/init|module|config/.test(lower)) {\n return \"module\";\n }\n return \"module\";\n}\n\nfunction severityFor(title: string): AntiPatternSeverity {\n const lower = title.toLowerCase();\n if (/nonexistent|missing|no error|deep import|async logic/.test(lower)) {\n return \"error\";\n }\n return \"warning\";\n}\n\ninterface Section {\n number: number;\n title: string;\n body: string;\n}\n\nfunction splitSections(md: string): Section[] {\n const lines = md.split(\"\\n\");\n const sections: Section[] = [];\n let current: Section | null = null;\n const heading = /^##\\s+(\\d+)\\.\\s+(.+?)\\s*$/;\n for (const line of lines) {\n const match = heading.exec(line);\n if (match?.[1] && match?.[2]) {\n if (current) {\n sections.push(current);\n }\n current = {\n number: Number(match[1]),\n title: match[2],\n body: \"\",\n };\n continue;\n }\n if (current) {\n // Stop at the first non-numbered ## section (e.g. \"Quick Reference Checklist\")\n if (/^##\\s+\\D/.test(line)) {\n sections.push(current);\n current = null;\n break;\n }\n current.body += `${line}\\n`;\n }\n }\n if (current) {\n sections.push(current);\n }\n return sections;\n}\n\nfunction extractExamples(body: string): {\n explanation: string;\n badExample?: string;\n goodExample?: string;\n} {\n const codeBlock = body.match(/```typescript\\n([\\s\\S]*?)```/);\n const explanationLines: string[] = [];\n for (const line of body.split(\"\\n\")) {\n if (line.startsWith(\"```\")) {\n break;\n }\n explanationLines.push(line);\n }\n const explanation = explanationLines.join(\"\\n\").trim();\n\n if (!codeBlock?.[1]) {\n return { explanation };\n }\n\n const code = codeBlock[1];\n // Split on the WRONG/CORRECT comment markers.\n const wrongMatch = code.match(\n /\\/\\/\\s*WRONG[^\\n]*\\n([\\s\\S]*?)(?:\\/\\/\\s*CORRECT|$)/,\n );\n const correctMatch = code.match(/\\/\\/\\s*CORRECT[^\\n]*\\n([\\s\\S]*)/);\n\n return {\n explanation,\n badExample: wrongMatch?.[1]?.trim() ?? undefined,\n goodExample: correctMatch?.[1]?.trim() ?? undefined,\n };\n}\n\nfunction loadAntiPatterns(): readonly AntiPattern[] {\n if (cache) {\n return cache;\n }\n\n const sourcePath = resolveSourcePath();\n let md: string;\n try {\n md = readFileSync(sourcePath, \"utf-8\");\n } catch {\n cache = Object.freeze([]);\n return cache;\n }\n\n const sections = splitSections(md);\n const out: AntiPattern[] = sections.map((section) => {\n const { explanation, badExample, goodExample } = extractExamples(\n section.body,\n );\n return {\n id: slugify(section.title),\n number: section.number,\n title: section.title,\n severity: severityFor(section.title),\n category: categorize(section.title),\n explanation,\n badExample,\n goodExample,\n };\n });\n\n cache = Object.freeze(out);\n return cache;\n}\n\n/** Return every parsed anti-pattern, stable order, frozen. */\nexport function getAntiPatterns(): readonly AntiPattern[] {\n return loadAntiPatterns();\n}\n\n/** Look up one anti-pattern by its slug id. */\nexport function getAntiPatternById(id: string): AntiPattern | undefined {\n return loadAntiPatterns().find((ap) => ap.id === id);\n}\n\n/** Clear the in-memory cache. Test / watch-mode helper. */\nexport function clearAntiPatternCache(): void {\n cache = null;\n}\n","/**\n * Loader for `packages/knowledge/migration.json` → structured\n * migration patterns. Lazy + cached.\n *\n * The JSON ships in the published tarball; consumers don't need to\n * parse markdown at runtime.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst PKG_ROOT = resolve(__dirname, \"..\");\n\n/** Supported source-library identifiers. */\nexport const MIGRATION_SOURCES = [\n \"redux\",\n \"zustand\",\n \"xstate\",\n \"mobx\",\n \"jotai\",\n \"recoil\",\n] as const;\nexport type MigrationSourceId = (typeof MIGRATION_SOURCES)[number];\n\nexport interface MigrationConceptRow {\n from: string;\n to: string;\n note: string;\n}\n\nexport interface MigrationPattern {\n id: MigrationSourceId;\n name: string;\n conceptMap: MigrationConceptRow[];\n steps: string[];\n before: string;\n after: string;\n}\n\ninterface MigrationFile {\n version: number;\n sources: MigrationPattern[];\n}\n\nlet cache: readonly MigrationPattern[] | null = null;\n\nfunction resolveSourcePath(): string {\n const candidates = [\n join(PKG_ROOT, \"migration.json\"),\n join(PKG_ROOT, \"..\", \"migration.json\"),\n ];\n for (const c of candidates) {\n if (existsSync(c)) {\n return c;\n }\n }\n return candidates[0] ?? \"\";\n}\n\nfunction load(): readonly MigrationPattern[] {\n if (cache) {\n return cache;\n }\n try {\n const raw = readFileSync(resolveSourcePath(), \"utf-8\");\n const parsed = JSON.parse(raw) as MigrationFile;\n cache = Object.freeze(parsed.sources ?? []);\n } catch {\n cache = Object.freeze([]);\n }\n return cache;\n}\n\n/** All supported source library IDs. */\nexport function getMigrationSources(): readonly MigrationSourceId[] {\n return MIGRATION_SOURCES;\n}\n\n/** All migration patterns, in registry order. */\nexport function getMigrationPatterns(): readonly MigrationPattern[] {\n return load();\n}\n\n/** One migration pattern by its source-library id. */\nexport function getMigrationPattern(\n source: string,\n): MigrationPattern | undefined {\n return load().find((p) => p.id === source);\n}\n\n/** Test / watch-mode helper. */\nexport function clearMigrationCache(): void {\n cache = null;\n}\n","/**\n * Loader for `packages/knowledge/compositions.json` → typed\n * composition graph. Lazy + cached.\n *\n * The JSON ships in the published tarball. Adjacency list rather\n * than per-package projections so consumers can answer both\n * \"what does X compose with?\" and \"what composes with X?\" without\n * duplicate data.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n// After bundling, all parsers live in dist/index.js — one level up\n// from dist reaches the package root. In src/ during dev, the file is\n// two levels up; the fallback in `resolveSourcePath` handles that.\nconst PKG_ROOT = resolve(__dirname, \"..\");\n\nexport interface CompositionEdge {\n from: string;\n to: string;\n reason: string;\n}\n\ninterface CompositionsFile {\n version: number;\n edges: CompositionEdge[];\n}\n\nlet cache: readonly CompositionEdge[] | null = null;\n\nfunction resolveSourcePath(): string {\n const candidates = [\n join(PKG_ROOT, \"compositions.json\"),\n join(PKG_ROOT, \"..\", \"compositions.json\"),\n ];\n for (const c of candidates) {\n if (existsSync(c)) {\n return c;\n }\n }\n return candidates[0] ?? \"\";\n}\n\nfunction load(): readonly CompositionEdge[] {\n if (cache) {\n return cache;\n }\n try {\n const raw = readFileSync(resolveSourcePath(), \"utf-8\");\n const parsed = JSON.parse(raw) as CompositionsFile;\n cache = Object.freeze(parsed.edges ?? []);\n } catch {\n cache = Object.freeze([]);\n }\n return cache;\n}\n\n/** All composition edges as a flat list. */\nexport function getCompositions(): readonly CompositionEdge[] {\n return load();\n}\n\n/**\n * All edges originating at the given package. Returns an empty array\n * when the package is unknown or has no outgoing compositions.\n */\nexport function getCompositionsFor(\n packageName: string,\n): readonly CompositionEdge[] {\n return load().filter((e) => e.from === packageName);\n}\n\n/**\n * All edges arriving at the given package — \"who composes WITH me?\"\n */\nexport function getReverseCompositionsFor(\n packageName: string,\n): readonly CompositionEdge[] {\n return load().filter((e) => e.to === packageName);\n}\n\n/** Test / watch-mode helper. */\nexport function clearCompositionsCache(): void {\n cache = null;\n}\n","import { existsSync, readFileSync, readdirSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n// Resolve package root: works both in src/ (dev) and dist/ (bundled)\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst PKG_ROOT = resolve(__dirname, \"..\");\n\n/**\n * Resolve a path relative to the package root.\n * Tries dist-relative first (bundled), then src-relative (dev).\n */\nfunction resolveAsset(name: string): string {\n const fromDist = join(PKG_ROOT, name);\n if (existsSync(fromDist)) {\n return fromDist;\n }\n\n const fromSrc = join(PKG_ROOT, \"..\", name);\n if (existsSync(fromSrc)) {\n return fromSrc;\n }\n\n return fromDist; // default, will just return empty maps\n}\n\nconst CORE_DIR = resolveAsset(\"core\");\nconst AI_DIR = resolveAsset(\"ai\");\nconst EXAMPLES_DIR = resolveAsset(\"examples\");\nconst API_SKELETON_PATH = resolveAsset(\"api-skeleton.md\");\n\nlet knowledgeCache: Map<string, string> | null = null;\nlet exampleCache: Map<string, string> | null = null;\n\nfunction loadDir(dir: string, map: Map<string, string>): void {\n try {\n const files = readdirSync(dir).filter(\n (f) => f.endsWith(\".md\") || f.endsWith(\".ts\"),\n );\n for (const file of files) {\n const name = file.replace(/\\.(md|ts)$/, \"\");\n map.set(name, readFileSync(join(dir, file), \"utf-8\"));\n }\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw err;\n }\n // directory does not exist — expected during tests or incomplete installs\n }\n}\n\nfunction loadAllKnowledge(): Map<string, string> {\n const map = new Map<string, string>();\n loadDir(CORE_DIR, map);\n loadDir(AI_DIR, map);\n\n // Include api-skeleton\n try {\n map.set(\"api-skeleton\", readFileSync(API_SKELETON_PATH, \"utf-8\"));\n } catch {\n // may not exist yet\n }\n\n return map;\n}\n\nfunction loadAllExamples(): Map<string, string> {\n const map = new Map<string, string>();\n loadDir(EXAMPLES_DIR, map);\n\n return map;\n}\n\n/**\n * Look up a bundled knowledge file by name. Returns the raw markdown\n * string. Returns `\"\"` when the name isn't known — callers driving an\n * LLM should pair this with {@link hasKnowledge} so a typo turns\n * into an actionable error instead of a silently empty prompt.\n *\n * @example\n * ```ts\n * import { getKnowledge, hasKnowledge } from \"@directive-run/knowledge\";\n *\n * if (!hasKnowledge(\"guardrails\")) throw new Error(\"typo\");\n * const md = getKnowledge(\"guardrails\");\n * ```\n */\nexport function getKnowledge(name: string): string {\n if (!knowledgeCache) {\n knowledgeCache = loadAllKnowledge();\n }\n\n return knowledgeCache.get(name) ?? \"\";\n}\n\n/**\n * Return every loaded knowledge file as `name → markdown`. Consumers\n * iterating the corpus (full-text search, embedding builder, RAG\n * index) read this once and key off the returned map.\n */\nexport function getAllKnowledge(): ReadonlyMap<string, string> {\n if (!knowledgeCache) {\n knowledgeCache = loadAllKnowledge();\n }\n\n return knowledgeCache;\n}\n\n/**\n * `true` when a knowledge file with this exact name is bundled.\n * Use this BEFORE {@link getKnowledge} when the name is user / agent\n * input — `getKnowledge` returns `\"\"` on miss, which is\n * indistinguishable from an intentionally empty file.\n *\n * @example\n * ```ts\n * if (!hasKnowledge(userTyped)) {\n * console.error(`unknown knowledge file: ${userTyped}`);\n * console.error(`available: ${[...getAllKnowledge().keys()].join(\", \")}`);\n * return;\n * }\n * ```\n */\nexport function hasKnowledge(name: string): boolean {\n if (!knowledgeCache) {\n knowledgeCache = loadAllKnowledge();\n }\n return knowledgeCache.has(name);\n}\n\n/**\n * Look up a bundled example file by name. Returns the raw source.\n * Returns `\"\"` when the name isn't known — pair with {@link hasExample}\n * when the input is user-controlled.\n */\nexport function getExample(name: string): string {\n if (!exampleCache) {\n exampleCache = loadAllExamples();\n }\n\n return exampleCache.get(name) ?? \"\";\n}\n\n/**\n * `true` when an example file with this exact name is bundled.\n * The miss-vs-empty disambiguator for {@link getExample}.\n */\nexport function hasExample(name: string): boolean {\n if (!exampleCache) {\n exampleCache = loadAllExamples();\n }\n return exampleCache.has(name);\n}\n\nexport function getAllExamples(): ReadonlyMap<string, string> {\n if (!exampleCache) {\n exampleCache = loadAllExamples();\n }\n\n return exampleCache;\n}\n\nexport function getKnowledgeFiles(names: string[]): string {\n return names\n .map((name) => getKnowledge(name))\n .filter(Boolean)\n .join(\"\\n\\n---\\n\\n\");\n}\n\nexport function getExampleFiles(names: string[]): string {\n return names\n .map((name) => {\n const content = getExample(name);\n if (!content) {\n return \"\";\n }\n\n return `### Example: ${name}\\n\\n\\`\\`\\`typescript\\n${content}\\n\\`\\`\\``;\n })\n .filter(Boolean)\n .join(\"\\n\\n\");\n}\n\n/** Clear cached knowledge and examples. Useful for dev/watch mode. */\nexport function clearCache(): void {\n knowledgeCache = null;\n exampleCache = null;\n}\n\n// ---------------------------------------------------------------------------\n// Structured data APIs (v1.16.0 — back the MCP `list_review_rules`,\n// `get_review_rule`, `list_migration_sources`, `get_migration_pattern`,\n// `get_composable_packages` tools).\n// ---------------------------------------------------------------------------\n\nexport {\n type AntiPattern,\n type AntiPatternCategory,\n type AntiPatternSeverity,\n clearAntiPatternCache,\n getAntiPatternById,\n getAntiPatterns,\n} from \"./parsers/anti-patterns.js\";\n\nexport {\n type MigrationConceptRow,\n type MigrationPattern,\n type MigrationSourceId,\n MIGRATION_SOURCES,\n clearMigrationCache,\n getMigrationPattern,\n getMigrationPatterns,\n getMigrationSources,\n} from \"./parsers/migration.js\";\n\nexport {\n type CompositionEdge,\n clearCompositionsCache,\n getCompositions,\n getCompositionsFor,\n getReverseCompositionsFor,\n} from \"./parsers/compositions.js\";\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@directive-run/knowledge",
3
- "version": "1.21.0",
3
+ "version": "1.23.0",
4
4
  "description": "Knowledge files, examples, and validation for Directive — the constraint-driven TypeScript runtime.",
5
5
  "license": "(MIT OR Apache-2.0)",
6
6
  "author": "Jason Comes",
@@ -53,8 +53,8 @@
53
53
  "tsx": "^4.19.2",
54
54
  "typescript": "^5.7.2",
55
55
  "vitest": "^3.0.0",
56
- "@directive-run/core": "1.21.0",
57
- "@directive-run/ai": "1.21.0"
56
+ "@directive-run/core": "1.23.0",
57
+ "@directive-run/ai": "1.23.0"
58
58
  },
59
59
  "scripts": {
60
60
  "build": "tsx scripts/generate-api-skeleton.ts && tsx scripts/generate-sitemap.ts && tsx scripts/extract-examples.ts && tsup",
package/sitemap.md CHANGED
@@ -12,16 +12,13 @@ Website: https://directive.run
12
12
  - [Why Directive](https://directive.run/docs/why-directive)
13
13
  - [Installation](https://directive.run/docs/installation)
14
14
  - [Core Concepts](https://directive.run/docs/core-concepts)
15
- - [Comparison](https://directive.run/docs/comparison)
16
15
  - [Choosing Primitives](https://directive.run/docs/choosing-primitives)
16
+ - [Comparison](https://directive.run/docs/comparison)
17
17
 
18
- ### AI Tooling
18
+ ### Editor Setup
19
19
  - [IDE Integration](https://directive.run/docs/ide-integration)
20
- - [Claude Code plugin](https://directive.run/docs/ide-integration#claude-code)
21
- - [CLI ai-rules](https://directive.run/docs/ide-integration#cli-ai-rules)
22
- - [Knowledge package](https://directive.run/docs/ide-integration#knowledge-package)
23
20
 
24
- ### Core API
21
+ ### Primitives
25
22
  - [Overview](https://directive.run/docs/core-api)
26
23
  - [Module & System](https://directive.run/docs/module-system)
27
24
  - [Facts](https://directive.run/docs/facts)
@@ -29,8 +26,8 @@ Website: https://directive.run
29
26
  - [Constraints](https://directive.run/docs/constraints)
30
27
  - [Resolvers](https://directive.run/docs/resolvers)
31
28
  - [Effects](https://directive.run/docs/effects)
32
- - [Sources](https://directive.run/docs/sources)
33
29
  - [Events](https://directive.run/docs/events)
30
+ - [Sources](https://directive.run/docs/sources)
34
31
  - [Schema & Types](https://directive.run/docs/schema-overview)
35
32
  - [API Reference](https://directive.run/docs/api/core)
36
33
  - [Type Reference](https://directive.run/docs/api/types)
@@ -63,7 +60,7 @@ Website: https://directive.run
63
60
  ### Advanced Patterns
64
61
  - [Overview](https://directive.run/docs/advanced/overview)
65
62
  - [Data-form Definitions](https://directive.run/docs/data-triggers)
66
- - [Resolver Binding (owns)](https://directive.run/docs/resolver-binding)
63
+ - [Sandbox](https://directive.run/docs/sandbox)
67
64
  - [Multi-Module](https://directive.run/docs/advanced/multi-module)
68
65
  - [Runtime Dynamics](https://directive.run/docs/advanced/runtime)
69
66
  - [History & Snapshots](https://directive.run/docs/advanced/history)
@@ -72,13 +69,13 @@ Website: https://directive.run
72
69
  - [Definition Meta](https://directive.run/docs/advanced/meta)
73
70
 
74
71
  ### Predicate Tools
75
- - [predicateFromIntent (LLM emit)](https://directive.run/docs/predicate-from-intent)
76
- - [describePredicate (prose)](https://directive.run/docs/describe-predicate)
77
- - [Predicate Codegen (SQL/Mongo/PostgREST)](https://directive.run/docs/predicate-codegen)
78
- - [predict()](https://directive.run/docs/predict)
79
- - [doctor.checkAgainst()](https://directive.run/docs/doctor)
80
- - [Predicate Backtest (replay-under)](https://directive.run/docs/replay-under)
81
- - [Parameter Sweep (tune)](https://directive.run/docs/tune)
72
+ - [Predicate from Intent](https://directive.run/docs/predicate-from-intent)
73
+ - [Describe Predicate](https://directive.run/docs/describe-predicate)
74
+ - [Predicate Codegen](https://directive.run/docs/predicate-codegen)
75
+ - [Predict](https://directive.run/docs/predict)
76
+ - [Doctor Check](https://directive.run/docs/doctor)
77
+ - [Predicate Backtest](https://directive.run/docs/replay-under)
78
+ - [Parameter Sweep](https://directive.run/docs/tune)
82
79
  - [Rules Diff](https://directive.run/docs/rules-diff)
83
80
 
84
81
  ### Plugins
@@ -89,17 +86,16 @@ Website: https://directive.run
89
86
  - [Persistence](https://directive.run/docs/plugins/persistence)
90
87
  - [Performance](https://directive.run/docs/plugins/performance)
91
88
  - [Circuit Breaker](https://directive.run/docs/plugins/circuit-breaker)
92
- - [Audit Ledger](https://directive.run/docs/audit-ledger)
93
89
  - [Observability](https://directive.run/docs/plugins/observability)
94
90
  - [Custom Plugins](https://directive.run/docs/plugins/custom)
95
91
 
96
- ### Packages
97
- - [Timeline (test REPL)](https://directive.run/docs/packages/timeline)
98
- - [Mutator (typed mutations)](https://directive.run/docs/packages/mutator)
99
- - [Optimistic (auto-rollback)](https://directive.run/docs/packages/optimistic)
100
- - [Query (data fetching)](https://directive.run/docs/packages/query)
92
+ ### Companion Packages
93
+ - [Timeline](https://directive.run/docs/packages/timeline)
94
+ - [Mutator](https://directive.run/docs/packages/mutator)
95
+ - [Optimistic](https://directive.run/docs/packages/optimistic)
96
+ - [Query](https://directive.run/docs/packages/query)
101
97
  - [Vite Dev Proxy](https://directive.run/docs/packages/vite-dev-proxy)
102
- - [Composing all four](https://directive.run/docs/packages/composing-packages)
98
+ - [Composing All Four](https://directive.run/docs/packages/composing-packages)
103
99
 
104
100
  ### Testing
105
101
  - [Overview](https://directive.run/docs/testing/overview)
@@ -108,6 +104,10 @@ Website: https://directive.run
108
104
  - [Assertions](https://directive.run/docs/testing/assertions)
109
105
  - [Test Async Chains](https://directive.run/docs/guides/test-async-chains)
110
106
 
107
+ ### Security & Compliance
108
+ - [Resolver Binding](https://directive.run/docs/resolver-binding)
109
+ - [Audit Ledger](https://directive.run/docs/audit-ledger)
110
+
111
111
  ### Examples
112
112
  - [Number Match](https://directive.run/docs/examples/counter)
113
113
  - [Auth Flow](https://directive.run/docs/examples/auth-flow)
@@ -134,7 +134,7 @@ Website: https://directive.run
134
134
  - [Role-Based Permissions](https://directive.run/docs/guides/permissions)
135
135
  - [Batch Mutations](https://directive.run/docs/guides/batch-mutations)
136
136
 
137
- ### Integration Guides
137
+ ### Works With
138
138
  - [Overview](https://directive.run/docs/works-with/overview)
139
139
  - [Redux](https://directive.run/docs/works-with/redux)
140
140
  - [Zustand](https://directive.run/docs/works-with/zustand)
@@ -146,17 +146,17 @@ Website: https://directive.run
146
146
 
147
147
  ### Foundations
148
148
  - [Overview](https://directive.run/ai/overview)
149
+ - [Tutorial](https://directive.run/ai/tutorial)
149
150
  - [Running Agents](https://directive.run/ai/running-agents)
150
- - [Resilience & Routing](https://directive.run/ai/resilience-routing)
151
151
  - [Comparison](https://directive.run/ai/comparison)
152
- - [Tutorial](https://directive.run/ai/tutorial)
153
152
  - [Troubleshooting](https://directive.run/ai/troubleshooting)
154
153
 
155
- ### Agent Orchestrator
154
+ ### Single-Agent Orchestrator
156
155
  - [Overview](https://directive.run/ai/orchestrator)
157
156
  - [Guardrails](https://directive.run/ai/guardrails)
158
157
  - [Streaming](https://directive.run/ai/streaming)
159
158
  - [Memory](https://directive.run/ai/memory)
159
+ - [Resilience & Routing](https://directive.run/ai/resilience-routing)
160
160
 
161
161
  ### Multi-Agent Orchestrator
162
162
  - [Overview](https://directive.run/ai/multi-agent)
@@ -168,6 +168,7 @@ Website: https://directive.run
168
168
 
169
169
  ### Infrastructure
170
170
  - [MCP Integration](https://directive.run/ai/mcp)
171
+ - [Sources × Agents](https://directive.run/ai/sources)
171
172
  - [RAG Enricher](https://directive.run/ai/rag)
172
173
  - [SSE Transport](https://directive.run/ai/sse-transport)
173
174
  - [Semantic Cache](https://directive.run/ai/semantic-cache)
@@ -176,6 +177,7 @@ Website: https://directive.run
176
177
  - [Debug Timeline](https://directive.run/ai/debug-timeline)
177
178
  - [Pattern Checkpoints](https://directive.run/ai/checkpoints)
178
179
  - [Breakpoints & Checkpoints](https://directive.run/ai/breakpoints)
180
+ - [Guardrail Events](https://directive.run/ai/guardrail-events)
179
181
  - [DevTools](https://directive.run/ai/devtools)
180
182
 
181
183
  ### Security & Compliance
@@ -195,15 +197,11 @@ Website: https://directive.run
195
197
  - [Data Pipeline](https://directive.run/ai/examples/data-pipeline)
196
198
  - [Code Review](https://directive.run/ai/examples/code-review)
197
199
 
198
- ### Human Approval Workflows
199
- - [Control AI Costs](https://directive.run/ai/guides/control-ai-costs)
200
-
201
- ### Validate Structured Output
200
+ ### Stream Agent Responses
202
201
  - [Handle Agent Errors](https://directive.run/ai/guides/handle-agent-errors)
202
+ - [Control AI Costs](https://directive.run/ai/guides/control-ai-costs)
203
203
 
204
- ### Stream Agent Responses
204
+ ### Pipelines & Apps
205
205
  - [Multi-Step Pipeline](https://directive.run/ai/guides/multi-step-pipeline)
206
-
207
- ### Test Without LLM Calls
208
206
  - [DAG Pipeline](https://directive.run/ai/guides/dag-pipeline)
209
207
  - [Goal Pipeline](https://directive.run/ai/guides/goal-pipeline)