@directive-run/knowledge 1.22.0 → 1.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ai/ai-security.md +2 -2
- package/dist/index.cjs +4 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/examples/cloudflare-directive-ai.ts +178 -0
- package/package.json +4 -4
- package/sitemap.md +40 -33
package/ai/ai-security.md
CHANGED
|
@@ -388,8 +388,8 @@ source publishes PII into a fact and the agent's prompt template embeds
|
|
|
388
388
|
that fact (`"Hello ${facts.email}..."`), the PII reaches the LLM call
|
|
389
389
|
without hitting the input guardrail chain.
|
|
390
390
|
|
|
391
|
-
This is
|
|
392
|
-
|
|
391
|
+
This is a documented gap in the input-only guardrail chain — the fix
|
|
392
|
+
is a fact-store-boundary guardrail that runs on every fact write:
|
|
393
393
|
|
|
394
394
|
```ts
|
|
395
395
|
import { createSystem, createModule, t } from "@directive-run/core";
|
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)))),
|
|
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
|
|
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=
|
|
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=
|
|
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
|
package/dist/index.cjs.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":"+JAkBA,IAAMA,EAAYC,YAAAA,CAAQC,iBAAAA,CAAc,2PAAe,CAAC,CAAA,CAClDC,CAAAA,CAAWC,aAAQJ,CAAAA,CAAW,IAAI,EAiCpCK,CAAAA,CAA2C,IAAA,CAE/C,SAASC,CAAAA,EAA4B,CACnC,IAAMC,CAAAA,CAAa,CACjBC,UAAKL,CAAAA,CAAU,MAAA,CAAQ,kBAAkB,CAAA,CACzCK,SAAAA,CAAKL,EAAU,IAAA,CAAM,MAAA,CAAQ,kBAAkB,CACjD,EACA,IAAA,IAAWM,CAAAA,IAAKF,EACd,GAAIG,aAAAA,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,EAA+C,CACtD,GAAI3B,CAAAA,CACF,OAAOA,CAAAA,CAGT,IAAM4B,EAAa3B,CAAAA,EAAkB,CACjCW,EACJ,GAAI,CACFA,EAAKiB,eAAAA,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,EAA8C,CAC5D,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,aAAQC,iBAAAA,CAAc,2PAAe,CAAC,EAClDC,CAAAA,CAAWC,YAAAA,CAAQJ,EAAW,IAAI,CAAA,CAG3B4C,EAAoB,CAC/B,OAAA,CACA,SAAA,CACA,QAAA,CACA,OACA,OAAA,CACA,QACF,EAuBIvC,CAAAA,CAAgD,KAEpD,SAASC,CAAAA,EAA4B,CACnC,IAAMC,CAAAA,CAAa,CACjBC,UAAKL,CAAAA,CAAU,gBAAgB,EAC/BK,SAAAA,CAAKL,CAAAA,CAAU,KAAM,gBAAgB,CACvC,CAAA,CACA,IAAA,IAAWM,KAAKF,CAAAA,CACd,GAAIG,cAAWD,CAAC,CAAA,CACd,OAAOA,CAAAA,CAGX,OAAOF,CAAAA,CAAW,CAAC,GAAK,EAC1B,CAEA,SAASsC,CAAAA,EAAwC,CAC/C,GAAIxC,CAAAA,CACF,OAAOA,CAAAA,CAET,GAAI,CACF,IAAMyC,CAAAA,CAAMZ,gBAAa5B,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,GAAwD,CACtE,OAAOJ,CACT,CAGO,SAASK,IAAwD,CACtE,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,aAAQC,iBAAAA,CAAc,2PAAe,CAAC,EAIlDC,CAAAA,CAAWC,YAAAA,CAAQJ,GAAW,IAAI,CAAA,CAapCK,EAA+C,IAAA,CAEnD,SAASC,IAA4B,CACnC,IAAMC,EAAa,CACjBC,SAAAA,CAAKL,EAAU,mBAAmB,CAAA,CAClCK,UAAKL,CAAAA,CAAU,IAAA,CAAM,mBAAmB,CAC1C,EACA,IAAA,IAAWM,CAAAA,IAAKF,EACd,GAAIG,aAAAA,CAAWD,CAAC,CAAA,CACd,OAAOA,CAAAA,CAGX,OAAOF,EAAW,CAAC,CAAA,EAAK,EAC1B,CAEA,SAASsC,GAAuC,CAC9C,GAAIxC,CAAAA,CACF,OAAOA,EAET,GAAI,CACF,IAAMyC,CAAAA,CAAMZ,eAAAA,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,EAAkD,CAChE,OAAOT,CAAAA,EACT,CAMO,SAASU,EAAAA,CACdC,CAAAA,CACgC,CAChC,OAAOX,CAAAA,GAAO,MAAA,CAAQ,CAAA,EAAM,EAAE,IAAA,GAASW,CAAW,CACpD,CAKO,SAASC,GACdD,CAAAA,CACgC,CAChC,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,YAAAA,CAAQC,kBAAc,2PAAe,CAAC,CAAA,CAClDC,CAAAA,CAAWC,aAAQJ,EAAAA,CAAW,IAAI,CAAA,CAMxC,SAAS2D,EAAaC,CAAAA,CAAsB,CAC1C,IAAMC,CAAAA,CAAWrD,SAAAA,CAAKL,EAAUyD,CAAI,CAAA,CACpC,GAAIlD,aAAAA,CAAWmD,CAAQ,EACrB,OAAOA,CAAAA,CAGT,IAAMC,CAAAA,CAAUtD,SAAAA,CAAKL,EAAU,IAAA,CAAMyD,CAAI,CAAA,CACzC,OAAIlD,cAAWoD,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,cAAAA,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,eAAAA,CAAa1B,SAAAA,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,gBAAagC,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.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():
|
|
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():
|
|
65
|
+
declare function getMigrationSources(): readonly MigrationSourceId[];
|
|
66
66
|
/** All migration patterns, in registry order. */
|
|
67
|
-
declare function getMigrationPatterns():
|
|
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():
|
|
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):
|
|
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):
|
|
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():
|
|
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():
|
|
65
|
+
declare function getMigrationSources(): readonly MigrationSourceId[];
|
|
66
66
|
/** All migration patterns, in registry order. */
|
|
67
|
-
declare function getMigrationPatterns():
|
|
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():
|
|
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):
|
|
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):
|
|
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)),
|
|
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
|
|
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=
|
|
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{
|
|
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":"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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: 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"]}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// Example: cloudflare-directive-ai
|
|
2
|
+
// Source: examples/cloudflare-directive-ai/src/module.ts
|
|
3
|
+
// Pure module file — no DOM wiring
|
|
4
|
+
|
|
5
|
+
import { createModule, createSystem } from "@directive-run/core";
|
|
6
|
+
import { sourceFromDOAlarm } from "@directive-run/sources/cloudflare";
|
|
7
|
+
import { schema, type PublishingStatus } from "./schema.js";
|
|
8
|
+
import type { AuditLog, Broadcaster } from "./deps.js";
|
|
9
|
+
import { createPublishingChain, type PublishingChain } from "./agents.js";
|
|
10
|
+
|
|
11
|
+
export interface PublishingDeps {
|
|
12
|
+
auditLog: AuditLog;
|
|
13
|
+
broadcaster: Broadcaster;
|
|
14
|
+
anthropicApiKey: string;
|
|
15
|
+
storage: DurableObjectStorage;
|
|
16
|
+
intervalMs?: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface PublishingModuleHandle {
|
|
20
|
+
alarmTick: () => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function createPublishingSystem(deps: PublishingDeps) {
|
|
24
|
+
const chain = createPublishingChain(deps.anthropicApiKey);
|
|
25
|
+
const handle: PublishingModuleHandle = {
|
|
26
|
+
alarmTick: () => {},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const alarmSource = sourceFromDOAlarm({
|
|
30
|
+
storage: deps.storage,
|
|
31
|
+
intervalMs: deps.intervalMs ?? 5 * 60 * 1000,
|
|
32
|
+
eventName: "tick",
|
|
33
|
+
payload: () => ({}),
|
|
34
|
+
onTickRegistered: (tick) => {
|
|
35
|
+
handle.alarmTick = tick;
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const publishingModule = createModule("publishing", {
|
|
40
|
+
schema,
|
|
41
|
+
|
|
42
|
+
init: (facts) => {
|
|
43
|
+
facts.status = "idle" satisfies PublishingStatus;
|
|
44
|
+
facts.currentArticle = {};
|
|
45
|
+
facts.ingestQueue = [];
|
|
46
|
+
facts.reviewQueue = [];
|
|
47
|
+
facts.errorLog = [];
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
derive: {
|
|
51
|
+
queueDepth: (facts) => facts.ingestQueue.length,
|
|
52
|
+
reviewDepth: (facts) => facts.reviewQueue.length,
|
|
53
|
+
isReadyToAggregate: (facts) =>
|
|
54
|
+
facts.ingestQueue.length >= 3 && facts.status === "idle",
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
events: {
|
|
58
|
+
ingest: (facts, payload) => {
|
|
59
|
+
facts.ingestQueue = [
|
|
60
|
+
...facts.ingestQueue,
|
|
61
|
+
{ url: payload.url, capturedAt: new Date().toISOString() },
|
|
62
|
+
];
|
|
63
|
+
},
|
|
64
|
+
tick: (facts) => {
|
|
65
|
+
if (facts.status === "failed" || facts.status === "published") {
|
|
66
|
+
facts.status = "idle";
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
sources: {
|
|
72
|
+
alarm: alarmSource,
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
constraints: {
|
|
76
|
+
startAggregation: {
|
|
77
|
+
priority: 100,
|
|
78
|
+
when: (facts) =>
|
|
79
|
+
facts.ingestQueue.length >= 3 && facts.status === "idle",
|
|
80
|
+
require: (facts) => ({
|
|
81
|
+
type: "RUN_PUBLISHING_CHAIN",
|
|
82
|
+
sources: facts.ingestQueue.slice(0, 8),
|
|
83
|
+
}),
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
routeArticle: {
|
|
87
|
+
priority: 90,
|
|
88
|
+
when: (facts) => facts.status === "reviewing",
|
|
89
|
+
require: (facts) => ({
|
|
90
|
+
type: "ROUTE_ARTICLE",
|
|
91
|
+
article: facts.currentArticle,
|
|
92
|
+
}),
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
resolvers: {
|
|
97
|
+
runChain: {
|
|
98
|
+
requirement: "RUN_PUBLISHING_CHAIN",
|
|
99
|
+
key: (req) => `chain-${req.sources.map((s) => s.url).join("|")}`,
|
|
100
|
+
resolve: async (req, context) => {
|
|
101
|
+
context.facts.status = "aggregating";
|
|
102
|
+
context.facts.ingestQueue = context.facts.ingestQueue.slice(
|
|
103
|
+
req.sources.length,
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
const result = await chain.run(req.sources, "demo");
|
|
108
|
+
|
|
109
|
+
context.facts.currentArticle = result;
|
|
110
|
+
context.facts.status = "reviewing";
|
|
111
|
+
await deps.auditLog.append({
|
|
112
|
+
event: "chain-completed",
|
|
113
|
+
at: new Date().toISOString(),
|
|
114
|
+
sources: req.sources.length,
|
|
115
|
+
confidence: result.confidence,
|
|
116
|
+
slug: result.slug,
|
|
117
|
+
});
|
|
118
|
+
} catch (err) {
|
|
119
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
120
|
+
context.facts.errorLog = [
|
|
121
|
+
...context.facts.errorLog,
|
|
122
|
+
{
|
|
123
|
+
at: new Date().toISOString(),
|
|
124
|
+
source: "publishing-chain",
|
|
125
|
+
message,
|
|
126
|
+
},
|
|
127
|
+
];
|
|
128
|
+
context.facts.status = "failed";
|
|
129
|
+
await deps.auditLog.append({
|
|
130
|
+
event: "chain-failed",
|
|
131
|
+
at: new Date().toISOString(),
|
|
132
|
+
error: message,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
routeArticle: {
|
|
139
|
+
requirement: "ROUTE_ARTICLE",
|
|
140
|
+
key: (req) => `route-${req.article.slug ?? "unknown"}`,
|
|
141
|
+
resolve: async (req, context) => {
|
|
142
|
+
const confidence = req.article.confidence ?? 0;
|
|
143
|
+
const slug = req.article.slug ?? "unknown";
|
|
144
|
+
|
|
145
|
+
if (confidence >= 0.85) {
|
|
146
|
+
await deps.broadcaster.send(req.article);
|
|
147
|
+
context.facts.status = "published";
|
|
148
|
+
await deps.auditLog.append({
|
|
149
|
+
event: "auto-published",
|
|
150
|
+
at: new Date().toISOString(),
|
|
151
|
+
slug,
|
|
152
|
+
confidence,
|
|
153
|
+
});
|
|
154
|
+
} else {
|
|
155
|
+
context.facts.reviewQueue = [
|
|
156
|
+
...context.facts.reviewQueue,
|
|
157
|
+
{ articleId: slug, confidence },
|
|
158
|
+
];
|
|
159
|
+
context.facts.status = "idle";
|
|
160
|
+
await deps.auditLog.append({
|
|
161
|
+
event: "routed-to-review",
|
|
162
|
+
at: new Date().toISOString(),
|
|
163
|
+
slug,
|
|
164
|
+
confidence,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
const system = createSystem({ module: publishingModule });
|
|
173
|
+
|
|
174
|
+
return { system, handle };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export type PublishingSystem = ReturnType<typeof createPublishingSystem>;
|
|
178
|
+
export type { PublishingChain };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@directive-run/knowledge",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.23.1",
|
|
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",
|
|
@@ -52,9 +52,9 @@
|
|
|
52
52
|
"tsup": "^8.3.5",
|
|
53
53
|
"tsx": "^4.19.2",
|
|
54
54
|
"typescript": "^5.7.2",
|
|
55
|
-
"vitest": "^3.
|
|
56
|
-
"@directive-run/core": "1.
|
|
57
|
-
"@directive-run/ai": "1.
|
|
55
|
+
"vitest": "^3.2.6",
|
|
56
|
+
"@directive-run/core": "1.23.1",
|
|
57
|
+
"@directive-run/ai": "1.23.1"
|
|
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
|
-
###
|
|
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
|
-
###
|
|
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
|
-
- [
|
|
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
|
-
- [
|
|
76
|
-
- [
|
|
77
|
-
- [Predicate Codegen
|
|
78
|
-
- [
|
|
79
|
-
- [
|
|
80
|
-
- [Predicate Backtest
|
|
81
|
-
- [Parameter Sweep
|
|
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,17 @@ 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
|
-
- [
|
|
89
|
+
- [Clobber Loop Detector](https://directive.run/docs/plugins/clobber-loop)
|
|
93
90
|
- [Observability](https://directive.run/docs/plugins/observability)
|
|
94
91
|
- [Custom Plugins](https://directive.run/docs/plugins/custom)
|
|
95
92
|
|
|
96
|
-
### Packages
|
|
97
|
-
- [Timeline
|
|
98
|
-
- [Mutator
|
|
99
|
-
- [Optimistic
|
|
100
|
-
- [Query
|
|
93
|
+
### Companion Packages
|
|
94
|
+
- [Timeline](https://directive.run/docs/packages/timeline)
|
|
95
|
+
- [Mutator](https://directive.run/docs/packages/mutator)
|
|
96
|
+
- [Optimistic](https://directive.run/docs/packages/optimistic)
|
|
97
|
+
- [Query](https://directive.run/docs/packages/query)
|
|
101
98
|
- [Vite Dev Proxy](https://directive.run/docs/packages/vite-dev-proxy)
|
|
102
|
-
- [Composing
|
|
99
|
+
- [Composing All Four](https://directive.run/docs/packages/composing-packages)
|
|
103
100
|
|
|
104
101
|
### Testing
|
|
105
102
|
- [Overview](https://directive.run/docs/testing/overview)
|
|
@@ -108,6 +105,18 @@ Website: https://directive.run
|
|
|
108
105
|
- [Assertions](https://directive.run/docs/testing/assertions)
|
|
109
106
|
- [Test Async Chains](https://directive.run/docs/guides/test-async-chains)
|
|
110
107
|
|
|
108
|
+
### Security & Compliance
|
|
109
|
+
- [Resolver Binding](https://directive.run/docs/resolver-binding)
|
|
110
|
+
- [Audit Ledger](https://directive.run/docs/audit-ledger)
|
|
111
|
+
|
|
112
|
+
### Broadcast
|
|
113
|
+
- [Overview](https://directive.run/docs/broadcast)
|
|
114
|
+
- [GitHub Action](https://directive.run/docs/broadcast/action)
|
|
115
|
+
- [CLI](https://directive.run/docs/broadcast/cli)
|
|
116
|
+
- [Cloudflare Worker](https://directive.run/docs/broadcast/worker)
|
|
117
|
+
- [MCP server](https://directive.run/docs/broadcast/mcp)
|
|
118
|
+
- [README badge](https://directive.run/docs/broadcast/badge)
|
|
119
|
+
|
|
111
120
|
### Examples
|
|
112
121
|
- [Number Match](https://directive.run/docs/examples/counter)
|
|
113
122
|
- [Auth Flow](https://directive.run/docs/examples/auth-flow)
|
|
@@ -134,7 +143,7 @@ Website: https://directive.run
|
|
|
134
143
|
- [Role-Based Permissions](https://directive.run/docs/guides/permissions)
|
|
135
144
|
- [Batch Mutations](https://directive.run/docs/guides/batch-mutations)
|
|
136
145
|
|
|
137
|
-
###
|
|
146
|
+
### Works With
|
|
138
147
|
- [Overview](https://directive.run/docs/works-with/overview)
|
|
139
148
|
- [Redux](https://directive.run/docs/works-with/redux)
|
|
140
149
|
- [Zustand](https://directive.run/docs/works-with/zustand)
|
|
@@ -146,17 +155,17 @@ Website: https://directive.run
|
|
|
146
155
|
|
|
147
156
|
### Foundations
|
|
148
157
|
- [Overview](https://directive.run/ai/overview)
|
|
158
|
+
- [Tutorial](https://directive.run/ai/tutorial)
|
|
149
159
|
- [Running Agents](https://directive.run/ai/running-agents)
|
|
150
|
-
- [Resilience & Routing](https://directive.run/ai/resilience-routing)
|
|
151
160
|
- [Comparison](https://directive.run/ai/comparison)
|
|
152
|
-
- [Tutorial](https://directive.run/ai/tutorial)
|
|
153
161
|
- [Troubleshooting](https://directive.run/ai/troubleshooting)
|
|
154
162
|
|
|
155
|
-
### Agent Orchestrator
|
|
163
|
+
### Single-Agent Orchestrator
|
|
156
164
|
- [Overview](https://directive.run/ai/orchestrator)
|
|
157
165
|
- [Guardrails](https://directive.run/ai/guardrails)
|
|
158
166
|
- [Streaming](https://directive.run/ai/streaming)
|
|
159
167
|
- [Memory](https://directive.run/ai/memory)
|
|
168
|
+
- [Resilience & Routing](https://directive.run/ai/resilience-routing)
|
|
160
169
|
|
|
161
170
|
### Multi-Agent Orchestrator
|
|
162
171
|
- [Overview](https://directive.run/ai/multi-agent)
|
|
@@ -168,6 +177,7 @@ Website: https://directive.run
|
|
|
168
177
|
|
|
169
178
|
### Infrastructure
|
|
170
179
|
- [MCP Integration](https://directive.run/ai/mcp)
|
|
180
|
+
- [Sources × Agents](https://directive.run/ai/sources)
|
|
171
181
|
- [RAG Enricher](https://directive.run/ai/rag)
|
|
172
182
|
- [SSE Transport](https://directive.run/ai/sse-transport)
|
|
173
183
|
- [Semantic Cache](https://directive.run/ai/semantic-cache)
|
|
@@ -176,6 +186,7 @@ Website: https://directive.run
|
|
|
176
186
|
- [Debug Timeline](https://directive.run/ai/debug-timeline)
|
|
177
187
|
- [Pattern Checkpoints](https://directive.run/ai/checkpoints)
|
|
178
188
|
- [Breakpoints & Checkpoints](https://directive.run/ai/breakpoints)
|
|
189
|
+
- [Guardrail Events](https://directive.run/ai/guardrail-events)
|
|
179
190
|
- [DevTools](https://directive.run/ai/devtools)
|
|
180
191
|
|
|
181
192
|
### Security & Compliance
|
|
@@ -195,15 +206,11 @@ Website: https://directive.run
|
|
|
195
206
|
- [Data Pipeline](https://directive.run/ai/examples/data-pipeline)
|
|
196
207
|
- [Code Review](https://directive.run/ai/examples/code-review)
|
|
197
208
|
|
|
198
|
-
###
|
|
199
|
-
- [Control AI Costs](https://directive.run/ai/guides/control-ai-costs)
|
|
200
|
-
|
|
201
|
-
### Validate Structured Output
|
|
209
|
+
### Stream Agent Responses
|
|
202
210
|
- [Handle Agent Errors](https://directive.run/ai/guides/handle-agent-errors)
|
|
211
|
+
- [Control AI Costs](https://directive.run/ai/guides/control-ai-costs)
|
|
203
212
|
|
|
204
|
-
###
|
|
213
|
+
### Pipelines & Apps
|
|
205
214
|
- [Multi-Step Pipeline](https://directive.run/ai/guides/multi-step-pipeline)
|
|
206
|
-
|
|
207
|
-
### Test Without LLM Calls
|
|
208
215
|
- [DAG Pipeline](https://directive.run/ai/guides/dag-pipeline)
|
|
209
216
|
- [Goal Pipeline](https://directive.run/ai/guides/goal-pipeline)
|