@jawache/flow 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,18 +1,24 @@
1
- function y(n){return n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function $(n){let e=[],t="",r=()=>{t!==""&&e.push({kind:"literal",text:t}),t=""};for(let o=0;o<n.length;o++){let s=n[o];if(s==="*")r(),n[o+1]==="*"?(e.push({kind:"globstar"}),o++,n[o+1]==="/"&&o++):e.push({kind:"star"});else if(s==="?")r(),e.push({kind:"single"});else if(s==="{"){let a=n.indexOf("}",o);if(a===-1){t+=s;continue}r(),e.push({kind:"options",options:n.slice(o+1,a).split(",")}),o=a}else t+=s??""}return r(),e}function v(n){switch(n.kind){case"literal":return y(n.text);case"star":return"[^/]*";case"globstar":return".*";case"single":return"[^/]";case"options":return`(${n.options.map(y).join("|")})`}}function ee(n){return new RegExp(`^${$(n).map(v).join("")}$`)}function ne(n,e){return ee(e).test(n)}function g(n,e){return(e||[]).some(t=>ne(n,t))}function te(n){let e=n.includes("/")?n.slice(0,n.lastIndexOf("/")):".",t=n.slice(n.lastIndexOf("/")+1),r=t.lastIndexOf("."),o=r>0?t.slice(0,r):t,s=e==="."?o:`${e}/${o}`;return{dir:e,base:t,name:o,path:s}}function O(n,e){let t=te(e);return n.replace(/\{(dir|base|name|path)\}/g,(r,o)=>t[o])}var j={write:["edit"],command:["edit","commit"],commit:["commit"],delete:["delete"],"turn-end":["turn"]},re=Object.keys(j),oe=["session","touch","command","turn-end"],se="write",ie="command",ae="commit",de="delete",le="turn-end",ce="session",ue="touch";function fe(n){let e=[];for(let t of n)for(let r of j[t])e.includes(r)||e.push(r);return e}function pe(n){return re.includes(n)}function ge(n){return oe.includes(n)}var M=["write","delete","commit","touch"];function ye(n){return M.includes(n)}var D=[...M,"command"];function me(n,e){return n==="breadcrumb"?D.includes(e):ye(e)}var N=Symbol.for("flow.category");function he(n,e){return{[N]:!0,name:n,classify:e}}function h(n,e){if(!(typeof n!="object"||n===null))return n[e]}function L(n){return h(n,N)===!0}var F=Symbol.for("flow.settings");function f(n){return e=>{let t=n(e);return Object.defineProperty(t,F,{value:e,enumerable:!1,configurable:!0}),t}}function ke(n){return n===void 0?void 0:n[F]}function be(n){return n?(n.pass?.length??0)+(n.block?.length??0)>0:!1}var xe=["at","for","on","ignore","check","message","disabled","test","description"],we=["at","for","on","ignore","text","file","disabled","description"];function x(n,e){let t=r=>x({...n,...r},e);return{...e(n),at:(...r)=>t({at:r}),for:(...r)=>t({for:r}),on:(...r)=>t({on:r}),ignore:(...r)=>t({ignore:r}),check:r=>t({check:r}),message:r=>t({message:r}),text:r=>t({text:r}),file:r=>t({file:r}),disabled:r=>t({disabled:r===void 0?{}:{reason:r}}),test:r=>t({test:r}),description:r=>t({description:r})}}var I=n=>({spec:n});function Se(){return x({kind:"guardrail"},I)}function Re(){return x({kind:"breadcrumb"},I)}function Ce(n){let e=h(h(n,"spec"),"kind");return e==="guardrail"||e==="breadcrumb"}var W=Symbol.for("flow.pack"),K=Symbol.for("flow.ref");function Ee(n,e){let t=typeof e=="function"&&e.length>0;return _(n,[],{name:n,build:o=>typeof e=="function"?e(o):e,takesParams:t})}function _(n,e,t){let r={[K]:{pack:n,id:e.join(".")}};return t&&(r[W]=t),new Proxy(r,{get(o,s){return s in o?o[s]:typeof s=="string"?_(n,[...e,s]):void 0}})}function $e(n){let e=h(n,W);return ve(e)?e:void 0}function ve(n){return typeof n=="object"&&n!==null&&typeof n.name=="string"&&typeof n.build=="function"}function Oe(n){let e=h(n,K),t=h(e,"pack"),r=h(e,"id");return typeof t=="string"&&typeof r=="string"?{pack:t,id:r}:void 0}function Me(n,...e){return{kind:"pack",pack:$e(n),params:e[0],hasParams:e.length>0}}function Pe(n){let e=Oe(n)??{pack:"",id:""};return x({},t=>({binding:{kind:"override",ref:e,spoken:t}}))}function Ae(n,e={}){return{bindings:n.map(t=>"binding"in t?t.binding:t),settings:e}}function T(n,e,t){let r={};for(let o of Object.keys(n))r[o]=t?.[o]??"pack";for(let o of Object.keys(e))r[o]="override";return{spec:{...n,...e},source:r}}var Be=["not-a-pack","missing-parameter","unknown-entry","unknown-key","unknown-moment","missing-mandatory","undeclared-category","no-cases","duplicate-id","dead-scope"];function w(n){return[`flow: the config will not load \u2014 ${n.length} refusal${n.length===1?"":"s"}.`,...n.map(e=>` ${e.code}: ${e.detail}`)].join(`
2
- `)}function Ge(n){let e=[],t=[],r=new Map;for(let o of n.bindings){if(o.kind!=="pack")continue;if(!o.pack||o.pack.name===""){e.push({code:"not-a-pack",entry:"",detail:"A `pack(\u2026)` line was given a value that no `definePack` ever made. Import the pack's default export, not one of its entries."});continue}let{name:s,build:a,takesParams:i}=o.pack;if(i&&!o.hasParams){e.push({code:"missing-parameter",entry:s,detail:`The pack \`${s}\` declares parameters and was bound without any \u2014 write \`pack(${s}, { \u2026 })\`. Which fields it needs is stated by its factory's type.`});continue}for(let{key:d,spec:c}of q(a(o.params))){let l={id:`${s}.${d}`,pack:s,key:d,...T(c,{})};if(r.get(l.id)){e.push({code:"duplicate-id",entry:l.id,detail:`Two entries claim the id \`${l.id}\`. An id is its property name inside its pack, so this is one pack bound twice, or two packs sharing a name.`});continue}r.set(l.id,l),t.push(l)}}for(let o of n.bindings){if(o.kind!=="override")continue;let s=`${o.ref.pack}.${o.ref.id}`,a=r.get(s);if(!a){e.push({code:"unknown-entry",entry:s,detail:`\`override(${s})\` names an entry no bound pack has. Bind the pack it lives in, or correct the reference.`});continue}let i=T(a.spec,o.spoken,a.source);a.spec=i.spec,a.source=i.source}for(let o of t)e.push(...Te(o));return e.length>0?{ok:!1,refusals:e}:{ok:!0,entries:t.map(o=>({id:o.id,pack:o.pack,key:o.key,spec:o.spec,source:o.source,categories:(o.spec.for??[]).map(s=>s.name),phases:o.spec.kind==="guardrail"?fe(o.spec.at??[]):[],settings:o.spec.kind==="guardrail"?ke(o.spec.check):void 0}))}}function q(n,e=[]){let t=[];for(let[r,o]of Object.entries(n))Ce(o)?t.push({key:[...e,r].join("."),spec:o.spec}):typeof o=="object"&&o!==null&&t.push(...q(o,[...e,r]));return t}function Te(n){let{id:e,spec:t}=n,r=[],o=(u,X)=>r.push({code:u,entry:e,detail:X}),s=t.kind==="guardrail"?xe:we,a=Object.keys(t).filter(u=>u!=="kind"&&!s.includes(u));a.length>0&&o("unknown-key",`\`${e}\` carries ${a.map(u=>`\`${u}\``).join(", ")}, which the ${t.kind} grammar does not have. It is closed: ${s.join(" \xB7 ")}.`);let i=t.at??[],d=t.kind==="guardrail"?pe:ge,c=i.filter(u=>!d(u));if(c.length>0&&o("unknown-moment",`\`${e}\` fires at ${c.map(u=>`\`${u}\``).join(", ")}, which is not a moment a ${t.kind} has a rail for.`),(t.for??[]).some(u=>!L(u))&&o("undeclared-category",`\`${e}\` is scoped with \`.for(\u2026)\` to something \`defineCategory\` never made. A category is a value with its recognizer aboard \u2014 import the one you mean.`),t.disabled)return r;let p=[];return i.length===0&&p.push(".at(\u2026)"),t.kind==="guardrail"?(t.check||p.push(".check(\u2026)"),t.message===void 0&&p.push(".message(\u2026)")):t.text===void 0&&t.file===void 0&&p.push(".text(\u2026) or .file(\u2026)"),p.length>0&&o("missing-mandatory",`\`${e}\` never said ${p.join(" and ")}. Nothing in this grammar defaults \u2014 an absent key is absent, not a fallback.`),((t.on?.length??0)>0||(t.ignore?.length??0)>0)&&i.length>0&&!i.some(u=>me(t.kind,u))&&o("dead-scope",`\`${e}\` narrows by path but fires only at ${i.map(u=>`\`${u}\``).join(", ")}, which name no subject to narrow \u2014 its \`on\`/\`ignore\` would be read by nothing. Drop the scope, or add a moment that carries one (${(t.kind==="breadcrumb"?D:M).join(" \xB7 ")}).`),t.kind==="guardrail"&&!be(t.test)&&o("no-cases",`\`${e}\` carries no cases. A rule declares what must pass it and what it must block (\`.test({ pass, block })\`) \u2014 a fence whose block-case was never written is a fence nothing proves is alive.`),r}function m(n,e,t=" \xB7 "){return e.length===0?n.ok():n.fail(e.join(t))}function k(n){return n.file??{path:"",content:""}}function Le(n,e){let t=n.split(`
3
- `),r=[];for(let o of e){let s=new RegExp(o);t.forEach((a,i)=>{s.test(a)&&r.push({pattern:o,line:i+1})})}return r}var Fe=f(n=>e=>{let t=Le(k(e).content,n.ban);return m(e,t.map(r=>`line ${r.line}: matches /${r.pattern}/`))}),Ie=f(n=>e=>{let t=e.command??"",r=n.ban.filter(o=>new RegExp(o).test(t));return m(e,r.map(o=>`matches banned /${o}/`))});function We(n){return`(?:${n.join("|")})[^"\`]*(?:"(?:(?!<<-?')[^"])*"[^"\`]*)*"(?:(?!<<-?')[^"])*\``}var Ke=["You are recording prose through a shell command, and a backtick inside a DOUBLE-quoted argument is not Markdown \u2014 the shell RUNS it and splices its output into your text before the command ever sees it.","On an append-only record there is no undo: no amend, no redact. And once the binary has argv the splice has already happened, so this is the only moment it can be caught.","Fix: SINGLE-quote the argument (backticks are literal there), or feed the prose on stdin with a QUOTED heredoc \u2014 `git commit -F -` plus `<<'EOF'`, which this rule treats as safe.","ALREADY single-quoted and still blocked? Then your PROSE carries an unbalanced double quote before the backtick, and the matcher cannot tell that quote from a real open argument. Nothing would splice \u2014 this one is the rule's cost, not your mistake. Balance the quote, drop it, or use the heredoc; do not go back to double quotes to make it pass."].join(`
4
- `),_e=f(n=>async e=>{let{path:t}=k(e);return n.existingOnly===!0?e.moment!=="delete"&&!await e.fs.exists(t)?e.ok():e.fail(`'${t}' is append-only \u2014 an existing file here is history and may not be edited or deleted (adding a new one is fine)`):e.fail(`'${t}' is a protected path (do not edit directly)`)}),qe=f(n=>async e=>{let t=O(n.sibling,k(e).path);return await e.fs.exists(t)?e.ok():e.fail(`required sibling missing: ${t}`)}),Ue=/\.(ts|tsx|mts|cts|js|mjs|cjs|jsx)$/;function Ve(n,e){let t=n.replace(/\\/g,"/"),r=e.root.replace(/^\/+|\/+$/g,"")+"/",o=t.indexOf(r);if(o===-1)return{ok:!0};let s=t.slice(o+r.length);if(e.folders?.length){let l=s.split("/")[0]??"",p=l.replace(/\.[^.]+$/,"");if(l!==""&&!e.folders.includes(l)&&!e.folders.includes(p))return{ok:!1,tier:"folder",found:l}}if(!e.allow.length)return{ok:!0};let a=Ue.exec(t);if(!a)return{ok:!0};if(t.endsWith(".d.ts"))return{ok:!0};if(!s.includes("/"))return{ok:!0};let d=s.slice(s.lastIndexOf("/")+1).slice(0,-a[0].length);return(d.endsWith(".test")?d.slice(0,-5)!==(e.thinking??""):!e.allow.includes(d))?{ok:!1,tier:"filename"}:{ok:!0}}function He(n,e,t){return n.ok?"":n.tier==="folder"?`'${n.found}' is not one of the names ${t.root}/ may hold: ${t.folders?.join(" \xB7 ")??""} (found ${e})`:`non-canonical file in a ${t.root} feature folder: ${e} (allowed: ${t.allow.join(" \xB7 ")}${t.thinking===void 0?"":` \u2014 only ${t.thinking} may carry a .test sibling`})`}var Je=f(n=>e=>{let{path:t}=k(e),r=Ve(t,n);return r.ok?e.ok():e.fail(He(r,t,n))});function Ye(n,e){let t=n;for(let r of(e??"").split(".").filter(Boolean)){if(t==null||typeof t!="object"||!(r in t))return{found:!1};t=t[r]}return{found:!0,value:t}}function ze(n,e){let t=[],{path:r}=e,o=Ye(n,r);if(!o.found)return e.required===!0&&t.push(`"${r}" is missing (required)`),t;let s=o.value;if(e.keysPrefixedWith!==void 0){if(!s||typeof s!="object")return t;for(let a of Object.keys(s))a.startsWith(e.keysPrefixedWith)||t.push(`"${r}.${a}" must be prefixed "${e.keysPrefixedWith}"`)}return"equals"in e&&JSON.stringify(s)!==JSON.stringify(e.equals)&&t.push(`"${r}" must equal ${JSON.stringify(e.equals)} (is ${JSON.stringify(s)})`),e.matches!==void 0&&!new RegExp(e.matches).test(String(s))&&t.push(`"${r}" (${JSON.stringify(s)}) must match /${e.matches}/`),t}function Qe(n,e){let t;try{t=JSON.parse(n)}catch{return[]}return e.flatMap(r=>ze(t,r))}var Ze=f(n=>e=>m(e,Qe(k(e).content,n.assert)));function Xe(n,e){return n.filter(t=>!new RegExp(`\\b${y(t)}\\b`).test(e))}async function en(n){let{parse:e,Lang:t}=await import("@ast-grep/napi"),r=e(t.Tsx,n).root(),o=new Set;for(let s of["export function $N($$$) { $$$ }","export class $N { $$$ }","export const $N = $V"])for(let a of r.findAll(s)){let i=a.getMatch("N");i&&o.add(i.text())}return[...o]}var nn=f(n=>async e=>{let{path:t,content:r}=k(e),o=O(n.sibling,t);if(!await e.fs.exists(o))return e.fail(`sibling test not found: ${o}`);let s=await e.fs.read(o),a=Xe(await en(r),s);return m(e,a.map(i=>`exported '${i}' is never referenced in ${o}`))});async function H(n){return n.staged?n.staged:n.git.stagedFiles()}function tn(n,e){let t=[];for(let r of e)n.some(o=>g(o,r.if))&&(n.some(o=>g(o,r.thenAny))||t.push(`${r.if.join(", ")} changed but none of [${r.thenAny.join(", ")}] did in the same commit`));return t}var rn=f(n=>async e=>m(e,tn(await H(e),n.groups))),C=new Set([";","&&","||","|","&","|&",`
5
- `]),on=new Set(["-C","-c","--git-dir","--work-tree","--namespace","--exec-path","--config-env"]);function sn(n,e){for(let t=e;t<n.length;t++){if(n[t]==="\\"){t++;continue}if(n[t]==='"')return t}return-1}function B(n){let e=n,t=[],r="",o=!1,s=0,a=()=>{o&&t.push(r),r="",o=!1};for(;s<e.length;){let i=e[s];if(i==="'"||i==='"'){let d=i==="'"?e.indexOf("'",s+1):sn(e,s+1);if(d===-1)return null;r+=i==='"'?e.slice(s+1,d).replace(/\\(["\\$`])/g,"$1"):e.slice(s+1,d),o=!0,s=d+1}else if(i==="\\"&&s+1<e.length)r+=e[s+1],o=!0,s+=2;else if(i===`
1
+ function y(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function K(e){return e.startsWith("^")||e.includes("(?")||e.includes("|")||e.endsWith("$")}function M(e){let n=[],t="",o=()=>{t!==""&&n.push({kind:"literal",text:t}),t=""};for(let r=0;r<e.length;r++){let s=e[r];if(s==="*")o(),e[r+1]==="*"?(n.push({kind:"globstar"}),r++,e[r+1]==="/"&&r++):n.push({kind:"star"});else if(s==="?")o(),n.push({kind:"single"});else if(s==="{"){let a=e.indexOf("}",r);if(a===-1){t+=s;continue}o(),n.push({kind:"options",options:e.slice(r+1,a).split(",")}),r=a}else t+=s??""}return o(),n}function P(e){switch(e.kind){case"literal":return y(e.text);case"star":return"[^/]*";case"globstar":return".*";case"single":return"[^/]";case"options":return`(${e.options.map(y).join("|")})`}}function ge(e){return new RegExp(`^${M(e).map(P).join("")}$`)}function ye(e,n){return ge(n).test(e)}function g(e,n){return(n||[]).some(t=>ye(e,t))}function me(e){let n=e.includes("/")?e.slice(0,e.lastIndexOf("/")):".",t=e.slice(e.lastIndexOf("/")+1),o=t.lastIndexOf("."),r=o>0?t.slice(0,o):t,s=n==="."?r:`${n}/${r}`;return{dir:n,base:t,name:r,path:s}}function B(e,n){let t=me(n);return e.replace(/\{(dir|base|name|path)\}/g,(o,r)=>t[r])}var H={write:["edit"],command:["edit","commit"],commit:["commit"],delete:["delete"],"turn-end":["turn"]},he=Object.keys(H),ke=["session","touch","command","turn-end"],be="write",xe="command",we="commit",Se="delete",Re="turn-end",Ce="session",Ee="touch";function $e(e){let n=[];for(let t of e)for(let o of H[t])n.includes(o)||n.push(o);return n}function Oe(e){return he.includes(e)}function ve(e){return ke.includes(e)}var G=["write","delete","commit","touch"];function Ae(e){return G.includes(e)}var q=[...G,"command"];function Me(e,n){return e==="breadcrumb"?q.includes(n):Ae(n)}var U=Symbol.for("flow.category");function Pe(e,n){return{[U]:!0,name:e,classify:n}}function h(e,n){if(!(typeof e!="object"||e===null))return e[n]}function V(e){return h(e,U)===!0}var J=Symbol.for("flow.settings"),Y=Symbol.for("flow.faults");function w(e,n){return n.length>0&&Object.defineProperty(e,Y,{value:n,enumerable:!1,configurable:!0}),e}function z(e){if(e===void 0)return[];let n=e[Y];return Array.isArray(n)?n:[]}function p(e){return n=>{let t=e(n);return Object.defineProperty(t,J,{value:n,enumerable:!1,configurable:!0}),t}}function Be(e){return e===void 0?void 0:e[J]}function Ge(e){return e?(e.pass?.length??0)+(e.block?.length??0)>0:!1}var Te=["at","for","on","ignore","check","message","disabled","test","description"],je=["at","for","on","ignore","text","file","disabled","description"];function S(e,n){let t=o=>S({...e,...o},n);return{...n(e),at:(...o)=>t({at:o}),for:(...o)=>t({for:o}),on:(...o)=>t({on:o}),ignore:(...o)=>t({ignore:o}),check:o=>t({check:o}),message:o=>t({message:o}),text:o=>t({text:o}),file:o=>t({file:o}),disabled:o=>t({disabled:o===void 0?{}:{reason:o}}),test:o=>t({test:o}),description:o=>t({description:o})}}var Q=e=>({spec:e});function De(){return S({kind:"guardrail"},Q)}function Ne(){return S({kind:"breadcrumb"},Q)}function Le(e){let n=h(h(e,"spec"),"kind");return n==="guardrail"||n==="breadcrumb"}var Z=Symbol.for("flow.pack"),X=Symbol.for("flow.ref");function We(e,n){let t=typeof n=="function"&&n.length>0;return ee(e,[],{name:e,build:r=>typeof n=="function"?n(r):n,takesParams:t})}function ee(e,n,t){let o={[X]:{pack:e,id:n.join(".")}};return t&&(o[Z]=t),new Proxy(o,{get(r,s){return s in r?r[s]:typeof s=="string"?ee(e,[...n,s]):void 0}})}function Fe(e){let n=h(e,Z);return Ie(n)?n:void 0}function Ie(e){return typeof e=="object"&&e!==null&&typeof e.name=="string"&&typeof e.build=="function"}function Ke(e){let n=h(e,X),t=h(n,"pack"),o=h(n,"id");return typeof t=="string"&&typeof o=="string"?{pack:t,id:o}:void 0}function _e(e,...n){return{kind:"pack",pack:Fe(e),params:n[0],hasParams:n.length>0}}function He(e){let n=Ke(e)??{pack:"",id:""};return S({},t=>({binding:{kind:"override",ref:n,spoken:t}}))}function qe(e,n={}){return{bindings:e.map(t=>"binding"in t?t.binding:t),settings:n}}function _(e,n,t){let o={};for(let r of Object.keys(e))o[r]=t?.[r]??"pack";for(let r of Object.keys(n))o[r]="override";return{spec:{...e,...n},source:o}}var Ue=["not-a-pack","missing-parameter","unknown-entry","unknown-key","unknown-moment","missing-mandatory","undeclared-category","no-cases","duplicate-id","dead-scope","bad-check-options"];function R(e){return[`flow: the config will not load \u2014 ${e.length} refusal${e.length===1?"":"s"}.`,...e.map(n=>` ${n.code}: ${n.detail}`)].join(`
2
+ `)}function Ve(e){let n=[],t=[],o=new Map;for(let r of e.bindings){if(r.kind!=="pack")continue;if(!r.pack||r.pack.name===""){n.push({code:"not-a-pack",entry:"",detail:"A `pack(\u2026)` line was given a value that no `definePack` ever made. Import the pack's default export, not one of its entries."});continue}let{name:s,build:a,takesParams:i}=r.pack;if(i&&!r.hasParams){n.push({code:"missing-parameter",entry:s,detail:`The pack \`${s}\` declares parameters and was bound without any \u2014 write \`pack(${s}, { \u2026 })\`. Which fields it needs is stated by its factory's type.`});continue}for(let{key:l,spec:d}of ne(a(r.params))){let c={id:`${s}.${l}`,pack:s,key:l,..._(d,{})};if(o.get(c.id)){n.push({code:"duplicate-id",entry:c.id,detail:`Two entries claim the id \`${c.id}\`. An id is its property name inside its pack, so this is one pack bound twice, or two packs sharing a name.`});continue}o.set(c.id,c),t.push(c)}}for(let r of e.bindings){if(r.kind!=="override")continue;let s=`${r.ref.pack}.${r.ref.id}`,a=o.get(s);if(!a){n.push({code:"unknown-entry",entry:s,detail:`\`override(${s})\` names an entry no bound pack has. Bind the pack it lives in, or correct the reference.`});continue}let i=_(a.spec,r.spoken,a.source);a.spec=i.spec,a.source=i.source}for(let r of t)n.push(...Je(r));return n.length>0?{ok:!1,refusals:n}:{ok:!0,entries:t.map(r=>({id:r.id,pack:r.pack,key:r.key,spec:r.spec,source:r.source,categories:(r.spec.for??[]).map(s=>s.name),phases:r.spec.kind==="guardrail"?$e(r.spec.at??[]):[],settings:r.spec.kind==="guardrail"?Be(r.spec.check):void 0}))}}function ne(e,n=[]){let t=[];for(let[o,r]of Object.entries(e))Le(r)?t.push({key:[...n,o].join("."),spec:r.spec}):typeof r=="object"&&r!==null&&t.push(...ne(r,[...n,o]));return t}function Je(e){let{id:n,spec:t}=e,o=[],r=(u,pe)=>o.push({code:u,entry:n,detail:pe}),s=t.kind==="guardrail"?Te:je,a=Object.keys(t).filter(u=>u!=="kind"&&!s.includes(u));a.length>0&&r("unknown-key",`\`${n}\` carries ${a.map(u=>`\`${u}\``).join(", ")}, which the ${t.kind} grammar does not have. It is closed: ${s.join(" \xB7 ")}.`);let i=t.at??[],l=t.kind==="guardrail"?Oe:ve,d=i.filter(u=>!l(u));if(d.length>0&&r("unknown-moment",`\`${n}\` fires at ${d.map(u=>`\`${u}\``).join(", ")}, which is not a moment a ${t.kind} has a rail for.`),(t.for??[]).some(u=>!V(u))&&r("undeclared-category",`\`${n}\` is scoped with \`.for(\u2026)\` to something \`defineCategory\` never made. A category is a value with its recognizer aboard \u2014 import the one you mean.`),t.disabled)return o;let f=[];i.length===0&&f.push(".at(\u2026)"),t.kind==="guardrail"?(t.check||f.push(".check(\u2026)"),t.message===void 0&&f.push(".message(\u2026)")):t.text===void 0&&t.file===void 0&&f.push(".text(\u2026) or .file(\u2026)"),f.length>0&&r("missing-mandatory",`\`${n}\` never said ${f.join(" and ")}. Nothing in this grammar defaults \u2014 an absent key is absent, not a fallback.`),((t.on?.length??0)>0||(t.ignore?.length??0)>0)&&i.length>0&&!i.some(u=>Me(t.kind,u))&&r("dead-scope",`\`${n}\` narrows by path but fires only at ${i.map(u=>`\`${u}\``).join(", ")}, which name no subject to narrow \u2014 its \`on\`/\`ignore\` would be read by nothing. Drop the scope, or add a moment that carries one (${(t.kind==="breadcrumb"?q:G).join(" \xB7 ")}).`),t.kind==="guardrail"&&!Ge(t.test)&&r("no-cases",`\`${n}\` carries no cases. A rule declares what must pass it and what it must block (\`.test({ pass, block })\`) \u2014 a fence whose block-case was never written is a fence nothing proves is alive.`);for(let u of z(t.kind==="guardrail"?t.check:void 0))r("bad-check-options",`\`${n}\` ${u}`);return o}function m(e,n,t=" \xB7 "){return n.length===0?e.ok():e.fail(n.join(t))}function k(e){return e.file??{path:"",content:""}}function Ze(e,n){let t=e.split(`
3
+ `),o=[];for(let r of n){let s=new RegExp(r);t.forEach((a,i)=>{s.test(a)&&o.push({pattern:r,line:i+1})})}return o}var Xe=p(e=>n=>{let t=Ze(k(n).content,e.ban);return m(n,t.map(o=>`line ${o.line}: matches /${o.pattern}/`))}),en=p(e=>n=>{let t=e.matchHeredocs===!0?n.command??"":On(n.command??""),o=e.ban.filter(r=>new RegExp(r).test(t));return m(n,o.map(r=>`matches banned /${r}/`))});function nn(e){return`(?:${e.join("|")})[^"\`]*(?:"(?:(?!<<-?')[^"])*"[^"\`]*)*"(?:(?!<<-?')[^"])*\``}var tn=["You are recording prose through a shell command, and a backtick inside a DOUBLE-quoted argument is not Markdown \u2014 the shell RUNS it and splices its output into your text before the command ever sees it.","On an append-only record there is no undo: no amend, no redact. And once the binary has argv the splice has already happened, so this is the only moment it can be caught.","Fix: SINGLE-quote the argument (backticks are literal there), or feed the prose on stdin with a QUOTED heredoc \u2014 `git commit -F -` plus `<<'EOF'`, which this rule treats as safe.","ALREADY single-quoted and still blocked? Then your PROSE carries an unbalanced double quote before the backtick, and the matcher cannot tell that quote from a real open argument. Nothing would splice \u2014 this one is the rule's cost, not your mistake. Balance the quote, drop it, or use the heredoc; do not go back to double quotes to make it pass."].join(`
4
+ `),rn=p(e=>async n=>{let{path:t}=k(n);return e.existingOnly===!0?n.moment!=="delete"&&!await n.fs.exists(t)?n.ok():n.fail(`'${t}' is append-only \u2014 an existing file here is history and may not be edited or deleted (adding a new one is fine)`):n.fail(`'${t}' is a protected path (do not edit directly)`)}),on=p(e=>w(n=>{if(n.actor.some(r=>e.writers.includes(r)))return n.ok();let t=n.actor.length===0?"an actor with no category":`an actor wearing ${n.actor.join(", ")}`,o=n.moment==="delete"?"deleted":"written";return n.fail(`${n.file?.path??"a file"} was ${o} by ${t} \u2014 only ${e.writers.join(" or ")} may change files here`)},e.writers.length===0?["lists no `writers`, so it would refuse every change by every actor. Name the categories allowed to write."]:[])),sn=p(e=>async n=>{let t=B(e.sibling,k(n).path);return await n.fs.exists(t)?n.ok():n.fail(`required sibling missing: ${t}`)}),an=/\.(ts|tsx|mts|cts|js|mjs|cjs|jsx)$/;function dn(e,n){let t=e.replace(/\\/g,"/"),o=n.root.replace(/^\/+|\/+$/g,"")+"/",r=t.indexOf(o);if(r===-1)return{ok:!0};let s=t.slice(r+o.length);if(n.folders?.length){let c=s.split("/")[0]??"",f=c.replace(/\.[^.]+$/,"");if(c!==""&&!n.folders.includes(c)&&!n.folders.includes(f))return{ok:!1,tier:"folder",found:c}}if(!n.allow.length)return{ok:!0};let a=an.exec(t);if(!a)return{ok:!0};if(t.endsWith(".d.ts"))return{ok:!0};if(!s.includes("/"))return{ok:!0};let l=s.slice(s.lastIndexOf("/")+1).slice(0,-a[0].length);return(l.endsWith(".test")?l.slice(0,-5)!==(n.thinking??""):!n.allow.includes(l))?{ok:!1,tier:"filename"}:{ok:!0}}function ln(e,n,t){return e.ok?"":e.tier==="folder"?`'${e.found}' is not one of the names ${t.root}/ may hold: ${t.folders?.join(" \xB7 ")??""} (found ${n})`:`non-canonical file in a ${t.root} feature folder: ${n} (allowed: ${t.allow.join(" \xB7 ")}${t.thinking===void 0?"":` \u2014 only ${t.thinking} may carry a .test sibling`})`}var cn=p(e=>n=>{let{path:t}=k(n),o=dn(t,e);return o.ok?n.ok():n.fail(ln(o,t,e))});function un(e,n){let t=e;for(let o of(n??"").split(".").filter(Boolean)){if(t==null||typeof t!="object"||!(o in t))return{found:!1};t=t[o]}return{found:!0,value:t}}function fn(e,n){let t=[],{path:o}=n,r=un(e,o);if(!r.found)return n.required===!0&&t.push(`"${o}" is missing (required)`),t;let s=r.value;if(n.keysPrefixedWith!==void 0){if(!s||typeof s!="object")return t;for(let a of Object.keys(s))a.startsWith(n.keysPrefixedWith)||t.push(`"${o}.${a}" must be prefixed "${n.keysPrefixedWith}"`)}return"equals"in n&&JSON.stringify(s)!==JSON.stringify(n.equals)&&t.push(`"${o}" must equal ${JSON.stringify(n.equals)} (is ${JSON.stringify(s)})`),n.matches!==void 0&&!new RegExp(n.matches).test(String(s))&&t.push(`"${o}" (${JSON.stringify(s)}) must match /${n.matches}/`),t}function pn(e,n){let t;try{t=JSON.parse(e)}catch{return[]}return n.flatMap(o=>fn(t,o))}var gn=p(e=>n=>m(n,pn(k(n).content,e.assert)));function yn(e,n){return e.filter(t=>!new RegExp(`\\b${y(t)}\\b`).test(n))}async function mn(e){let{parse:n,Lang:t}=await import("@ast-grep/napi"),o=n(t.Tsx,e).root(),r=new Set;for(let s of["export function $N($$$) { $$$ }","export class $N { $$$ }","export const $N = $V"])for(let a of o.findAll(s)){let i=a.getMatch("N");i&&r.add(i.text())}return[...r]}var hn=p(e=>async n=>{let{path:t,content:o}=k(n),r=B(e.sibling,t);if(!await n.fs.exists(r))return n.fail(`sibling test not found: ${r}`);let s=await n.fs.read(r),a=yn(await mn(o),s);return m(n,a.map(i=>`exported '${i}' is never referenced in ${r}`))});async function ie(e){return e.staged?e.staged:e.git.stagedFiles()}function kn(e,n){let t=[];for(let o of n)e.some(r=>g(r,o.if))&&(e.some(r=>g(r,o.thenAny))||t.push(`${o.if.join(", ")} changed but none of [${o.thenAny.join(", ")}] did in the same commit`));return t}var bn=p(e=>async n=>m(n,kn(await ie(n),e.groups))),$=new Set([";","&&","||","|","&","|&",`
5
+ `]),xn=new Set(["-C","-c","--git-dir","--work-tree","--namespace","--exec-path","--config-env"]),te=/(?:'([^'\n]*)'|"([^"\n]*)"|\\?([^\s'";&|<>()`]+))/y;function D(e,n){if(!e.startsWith("<<",n)||e[n+2]==="<")return null;let t=e[n+2]==="-",o=n+(t?3:2);for(;e[o]===" "||e[o]===" ";)o++;te.lastIndex=o;let r=te.exec(e),s=r?.[1]??r?.[2]??r?.[3]??"";return r===null||s===""?null:{delim:s,tabs:t,end:o+r[0].length}}function wn(e){for(let n=e.indexOf("<<");n!==-1;){let t=D(e,n);if(t!==null)return t;for(;e[n]==="<";)n++;n=e.indexOf("<<",n)}return null}function N(e,n,t){let o=n;for(;o<e.length;){let r=o,s=e.indexOf(`
6
+ `,o),a=e.slice(o,s===-1?e.length:s);if(o=s===-1?e.length:s+1,(t.tabs?a.replace(/^\t+/,""):a)===t.delim)return{body:r,end:o}}return{body:o,end:o}}function O(e,n){let t=1,o=[];for(let r=n;r<e.length;r++){let s=e[r];if(s==="\\")r++;else if(s==="'"||s==='"'){let a=s==="'"?e.indexOf("'",r+1):L(e,r+1);if(a===-1)return-1;r=a}else if(e.startsWith("$((",r)){let a=e.indexOf("))",r+3);if(a===-1)return-1;r=a+1}else if(e.startsWith("<<<",r))r+=2;else if(s==="<"){let a=D(e,r);a!==null&&(o.push(a),r=a.end-1)}else if(s===`
7
+ `)for(let a of o.splice(0))r=N(e,r+1,a).end-1;else if(s==="(")t++;else if(s===")"&&--t===0)return r}return-1}function L(e,n){for(let t=n;t<e.length;t++)if(e[t]==="\\")t++;else if(e[t]==="$"&&e[t+1]==="("){let o=O(e,t+2);if(o===-1)return-1;t=o}else if(e[t]==='"')return t;return-1}var Sn=new Set(["bash","sh","zsh","dash","ksh","eval"]),Rn=new Set(["sudo","env","exec","command","builtin","nohup","nice","time","if","then","else","elif","while","until","do","!","{"]),Cn=new Set([" "," ",`
8
+ `,";","&","|","(",")","<",">"]);function x(e,n,t,o){for(let[r,s]of ae(e.slice(n,t)))o.push([r+n,s+n])}function En(e,n,t,o){for(let r=n;r<t;r++)if(e[r]==="\\")r++;else if(e.startsWith("$(",r)){let s=O(e,r+2);e[r+2]!=="("&&x(e,r+2,s,o),r=s}else if(e[r]==="`"){let s=e.indexOf("`",r+1);if(s===-1||s>t)return;x(e,r+1,s,o),r=s}}function $n(e,n,t){let o="",r=n;for(;r<e.length&&!Cn.has(e[r]);){let s=e[r],a;if(s==="\\"){e[r+1]!==`
9
+ `&&(o+=e[r+1]??""),r+=2;continue}else if(s==="'")a=e.indexOf("'",r+1),a!==-1&&(o+=e.slice(r+1,a));else if(s==='"')a=L(e,r+1),a!==-1&&(o+=e.slice(r+1,a),En(e,r+1,a,t));else if(e.startsWith("$((",r))a=e.indexOf("))",r+3),a=a===-1?-1:a+1,o+="\0";else if(e.startsWith("$(",r))a=O(e,r+2),a!==-1&&x(e,r+2,a,t),o+="\0";else if(s==="`")a=e.indexOf("`",r+1),a!==-1&&x(e,r+1,a,t),o+="\0";else{o+=s,r++;continue}if(a===-1)return null;r=a+1}return{end:r,text:o}}function ae(e){let n=[],t={shell:!1},o=[],r=!0,s=!1,a=!1,i=0;for(;i<e.length;){let l=e[i];if(l===`
10
+ `){i++;for(let{doc:d,pipeline:c}of o){let{body:f,end:I}=N(e,i,d);c.shell||n.push([i,f]),i=I}o=[],t={shell:!1},r=!0,s=!1}else if(l===" "||l===" ")i++;else if(e.startsWith(`\\
11
+ `,i))i+=2;else if(l==="#"){let d=e.indexOf(`
12
+ `,i);i=d===-1?e.length:d}else if(e.startsWith("<(",i)||e.startsWith(">(",i)){let d=O(e,i+2);if(d===-1)break;x(e,i+2,d,n),i=d+1,r=!1}else if(l==="<"||l===">"||e.startsWith("&>",i)){let d=D(e,i);d!==null?(o.push({doc:d,pipeline:t}),i=d.end):(i+=(/^(?:&>>|&>|<<<|<<-|<<|<>|<&|>>|>\||>&|<|>)/.exec(e.slice(i))?.[0]??l).length,a=!0)}else if(l===";"||l==="&"||l==="|"||l==="("||l===")"){let d=e.slice(i,i+2),c=["&&","||","|&",";;"].includes(d)?d:l;i+=c.length,c!=="|"&&c!=="|&"&&(t={shell:!1}),r=!0,s=!1}else{let d=$n(e,i,n);if(d===null)break;if(i=d.end,a)a=!1;else if(r){let c=d.text.slice(d.text.lastIndexOf("/")+1);Rn.has(c)?s=!0:!/^[A-Za-z_]\w*=/.test(d.text)&&!(s&&d.text.startsWith("-"))&&(Sn.has(c)&&(t.shell=!0),r=!1)}}}return n.sort((l,d)=>l[0]-d[0])}function On(e){let n="",t=0;for(let[o,r]of ae(e))n+=e.slice(t,o),t=r;return n+e.slice(t)}function W(e){let n=e,t=[],o="",r=!1,s=0,a=()=>{r&&t.push(o),o="",r=!1};for(;s<n.length;){let i=n[s];if(i==="'"||i==='"'){let l=i==="'"?n.indexOf("'",s+1):L(n,s+1);if(l===-1)return null;o+=i==='"'?n.slice(s+1,l).replace(/\\(["\\$`])/g,"$1"):n.slice(s+1,l),r=!0,s=l+1}else if(i==="\\"&&s+1<n.length)o+=n[s+1],r=!0,s+=2;else if(i===`
6
13
  `)a(),t.push(`
7
- `),s++;else if(/\s/.test(i))a(),s++;else if(i===";"||i==="|"||i==="&"){a();let d=e.slice(s,s+2);d==="&&"||d==="||"||d==="|&"?(t.push(d),s+=2):(t.push(i),s++)}else r+=i,o=!0,s++}return a(),t}function G(n){let e=B(n);if(!e)return null;let t=[],r=0,o=!0;for(;r<e.length;){let s=e[r];if(C.has(s)){o=!0,r++;continue}if(o&&s==="git"){let a=[],i=r+1;for(;i<e.length&&!C.has(e[i]);)a.push(e[i++]);let d=0;for(;d<a.length;){let c=a[d];if(on.has(c))d+=2;else if(c.startsWith("-"))d+=1;else break}t.push({globals:a.slice(0,d),subcommand:a[d]??null,args:a.slice(d+1)}),r=i,o=!1;continue}o=!1,r++}return t}function an(n){let e=/<<-?\s*(['"]?)([A-Za-z_][A-Za-z0-9_]*)\1/.exec(n);if(!e)return null;let t=e[2],o=n.slice(e.index+e[0].length).split(`
8
- `).slice(1),s=o.findIndex(i=>i.trim()===t);if(s===-1)return null;let a=o.slice(0,s).join(`
9
- `).trim();return a===""?null:a}function J(n){let e=G(n);if(!e)return null;let t=e.find(o=>o.subcommand==="commit");if(!t)return null;let r=[];for(let o=0;o<t.args.length;o++){let s=t.args[o];if(s==="-m"||s==="--message"){let a=t.args[o+1];if(a===void 0)break;r.push(a),o++;continue}s.startsWith("-m")&&s!=="-m"?r.push(s.slice(2)):s.startsWith("--message=")&&r.push(s.slice(10))}return r.length?r.join(`
14
+ `),s++;else if(/\s/.test(i))a(),s++;else if(i===";"||i==="|"||i==="&"){a();let l=n.slice(s,s+2);l==="&&"||l==="||"||l==="|&"?(t.push(l),s+=2):(t.push(i),s++)}else o+=i,r=!0,s++}return a(),t}function F(e){let n=W(e);if(!n)return null;let t=[],o=0,r=!0;for(;o<n.length;){let s=n[o];if($.has(s)){r=!0,o++;continue}if(r&&s==="git"){let a=[],i=o+1;for(;i<n.length&&!$.has(n[i]);)a.push(n[i++]);let l=0;for(;l<a.length;){let d=a[l];if(xn.has(d))l+=2;else if(d.startsWith("-"))l+=1;else break}t.push({globals:a.slice(0,l),subcommand:a[l]??null,args:a.slice(l+1)}),o=i,r=!1;continue}r=!1,o++}return t}function de(e){let n=F(e);if(!n)return null;let t=n.find(d=>d.subcommand==="commit");if(!t)return null;let o=[];for(let d=0;d<t.args.length;d++){let c=t.args[d];if(c==="-m"||c==="--message"){let f=t.args[d+1];if(f===void 0)break;o.push(f),d++;continue}c.startsWith("-m")&&c!=="-m"?o.push(c.slice(2)):c.startsWith("--message=")&&o.push(c.slice(10))}if(o.length)return o.join(`
10
15
 
11
- `):an(n)}function b(n){return`'${n.replace(/'/g,"'\\''")}'`}function Y(n){let e=[],t=B(n),r=t?.[1];t?.[0]==="cd"&&r!==void 0&&!r.startsWith("-")&&!C.has(r)&&C.has(t[2]??"")&&e.push("-C",b(r));let o=G(n)?.[0];if(!o)return e.join(" ");for(let s=0;s<o.globals.length-1;s++)o.globals[s]==="-C"&&e.push("-C",b(o.globals[s+1]));return e.join(" ")}function z(n,e){return new RegExp(`^[ \\t]*${y(e)}[ \\t]*:`,"im").test(n)}function dn(n,e,t=[]){let r=new Set(t),o=new Set;for(let s of n.split(`
12
- `)){if(!s.startsWith("+")||s.startsWith("+++"))continue;let a=s.slice(1);for(let i of e){let d=new RegExp(i,"g"),c;for(;(c=d.exec(a))!==null;)c[1]!==void 0&&!r.has(c[1])&&o.add(c[1]),c[0]===""&&d.lastIndex++}}return[...o]}function ln(n){let{message:e,state:t,whenChanged:r,whenAdded:o,except:s,namesAdded:a,token:i}=n,d=new Set(t.added),c=[];for(let l of t.changed)s&&g(l,s)||(d.has(l)&&o&&g(l,o)?c.push(`\`${l}\` (new)`):r&&g(l,r)&&c.push(`\`${l}\` (changed)`));for(let{name:l,file:p}of a??[])c.push(`\`${l}\` (added in ${p})`);return c.length?z(e,i)?[]:[`${c.join(" \xB7 ")} \u2014 and this commit's message records no reason. Put \`${i}: <why>\` on a line of its own in the message; the act is fine, doing it silently is not.`]:[]}function P(n){return n.split(`
13
- `).map(e=>e.trim()).filter(Boolean)}var cn=f(n=>async e=>{let t=J(e.command??"");if(t==null)return e.ok();let r=`git ${Y(e.command??"")}`.trimEnd(),o={changed:[],added:[]};if(n.whenChanged||n.whenAdded){let[i,d,c]=await Promise.all([e.exec(`${r} diff HEAD --name-only`),e.exec(`${r} diff HEAD --name-only --diff-filter=A`),e.exec(`${r} ls-files --others --exclude-standard`)]);if(i.code!==0||d.code!==0||c.code!==0)return e.ok();let l=P(c.stdout);o={changed:[...new Set([...P(i.stdout),...l])],added:[...P(d.stdout),...l]}}let s=[];for(let i of n.diffAdds??[]){let d=await e.exec(`${r} diff HEAD -- ${b(i.file)}`);if(d.code!==0)return e.ok();for(let c of dn(d.stdout,i.patterns,i.known??[]))s.push({name:c,file:i.file})}let a=ln({message:t,state:o,whenChanged:n.whenChanged,whenAdded:n.whenAdded,except:n.except,namesAdded:s,token:n.token});return m(e,a)});function un(n,e,t){if(t===""||e.length===0)return!1;let r=-1,o=-1;return n.forEach((s,a)=>{s.did==="edit"&&g(s.path,e)&&(r=a),s.did==="run"&&s.command.includes(t)&&(o=a)}),r>=0&&r>o}var fn=f(n=>e=>e.turn&&un(e.turn,n.edited,n.mustRun)?e.fail(`edited ${n.edited.join(", ")} this turn but never ran \`${n.mustRun}\` afterwards`):e.ok());function pn(n,e){let t=e??[];return!t.length||!n.length?!1:!n.some(r=>g(r,t))}function Q(n,e=8){let t=n.trim().split(`
14
- `).filter(Boolean),r=t.filter(o=>/\b(fail|failed|error|not ok|assert|expected|cannot|undefined)\b/i.test(o)||/[✖✗✘]/.test(o));return(r.length?r:t.slice(-6)).slice(0,e).join(`
15
- `)}var gn=f(n=>async e=>{let t=await H(e);if(pn(t,n.changed))return e.ok();let r=n.run.includes("{files}");if(r&&t.length===0)return e.ok();let o=r?n.run.replace("{files}",t.map(b).join(" ")):n.run,s=await e.exec(o);return s.code===0?e.ok():e.fail(`\`${o}\` failed (exit ${s.code}):
16
- ${Q(s.stderr||s.stdout)}`)});function R(n){let e=$(n),t=e[e.length-1]?.kind==="globstar";return`^${(t?e.slice(0,-1):e).map(v).join("")}${t?"":"$"}`}function yn(n){return n==="node:*"?{core:!0}:n.startsWith("node:")?{path:`^${y(n)}$`}:n.includes("/")||n.includes("*")||n.includes(".")?{path:R(n)}:{path:`node_modules/${y(n)}(/|$)`}}function S(n,e){let t=[],r=!1;for(let s of n)for(let a of e[s]??[]){let i=yn(a);i.core?r=!0:i.path&&t.push(i.path)}let o={};return t.length&&(o.path=t),r&&(o.dependencyTypes=["core"]),o}function mn(n){let e=n.layers,t=[],r=[],o=(n.except??[]).includes("type-only"),s=i=>o?{...i,dependencyTypesNot:["type-only"]}:i;for(let[i,d]of Object.entries(n.only??{})){let l={pathNot:S(d,e).path??[]};t.push({name:`${i}-only`,severity:"error",comment:`${i} may import only: ${d.join(", ")} \u2014 an unlisted import blocks here (add it to a layer, or keep it out).`,from:S([i],e),to:s(l)})}for(let i of n.forbid??[])if(i==="circular")t.push({name:"no-circular",severity:"error",comment:"no dependency cycles",from:{pathNot:"node_modules"},to:{circular:!0}});else if(i==="orphans")t.push({name:"no-orphans",severity:"warn",comment:"unreferenced module",from:{orphan:!0,pathNot:"node_modules|\\.d\\.ts$"},to:{}});else if(i.cyclesBetween!==void 0){let d=i.cyclesBetween,c=(e[d]??[])[0]??"",l=R(c).replace(/\$$/,"").replace(/\[\^\/\]\*$/,"([^/]+)");t.push({name:`no-cycles-between-${d}`,severity:"error",comment:i.why??`${d} must not import sideways`,from:{path:`${l}/`},to:s({path:`${l.replace(/\(\[\^\/\]\+\)/,"[^/]+")}/`,pathNot:"$1/"})})}else if(i.from!==void 0&&i.to!==void 0){let d={...S([i.to],e)};i.transitive===!0&&(d.reachable=!0),t.push({name:`no-${i.from}-to-${i.to}${i.transitive===!0?"-transitive":""}`,severity:"error",comment:i.why??`${i.from} must not import ${i.to}`,from:S([i.from],e),to:s(d)})}for(let i of n.require??[])r.push({name:`must-import-${i.import}`,severity:"error",comment:i.why??`modules in ${i.in} must import ${i.import}`,module:{path:R(i.in)},to:{path:R(i.import)}});for(let i of n.warn??[])i==="sdp"&&t.push({name:"sdp",severity:"warn",comment:"depends on a more-unstable module (Stable Dependencies Principle)",from:{},to:{moreUnstable:!0}});let a={enhancedResolveOptions:{extensions:[".js",".jsx",".ts",".tsx",".mjs",".cjs",".json"]},doNotFollow:{path:"node_modules"},tsPreCompilationDeps:!1,...n.options??{}};return{forbidden:t,required:r,options:a}}var U="FLOW_DEPCRUISE_CONFIG";function hn(n){let e=JSON.stringify(mn(n));return["d=$(mktemp -d)",`cat > "$d/dc.json" <<'${U}'`,e,U,`npx --no-install depcruise --config "$d/dc.json" --output-type json ${b(n.scan)}`,"rc=$?",'rm -rf "$d"',"exit $rc"].join(`
17
- `)}function kn(n){let e;try{e=JSON.parse(n.stdout||"")}catch{return n.code===0?[]:[`depcruise failed (exit ${n.code}): ${Q(n.stderr||n.stdout,3)}`]}return(e.summary?.violations??[]).map(t=>{let r=t.rule?.name??"fence",o=t.comment??t.rule?.comment??"";return`${r}: ${t.from} \u2192 ${t.to}${o?` \u2014 ${o}`:""}`})}var bn=f(n=>async e=>m(e,kn(await e.exec(hn(n))),`
18
- `)),Z={html:"Html",css:"Css",javascript:"JavaScript",js:"JavaScript",typescript:"TypeScript",ts:"TypeScript",tsx:"Tsx",jsx:"Tsx"},xn=Object.keys(Z),A=new Set,V=Symbol.for("flow.grammars");function wn(){let n=globalThis,e=n[V];if(e!==void 0)return e;let t={declared:[],present:()=>!1};return n[V]=t,t}function Sn(n,e){return`\`${n}\`: no library at ${e}. A grammar is a BUILD ARTEFACT \u2014 machine-specific, never committed \u2014 so this is the ordinary state of a fresh clone. Build it (the repo that declares a grammar carries the recipe that builds it), or every ast-grep rule on that language refuses rather than passing quietly.`}async function Rn(n){let{Lang:e,registerDynamicLanguage:t}=await import("@ast-grep/napi"),r=Z[n];if(r!==void 0)return{ok:!0,lang:e[r]};if(A.has(n))return{ok:!0,lang:n};let{declared:o,present:s}=wn(),a=o.find(i=>i.name===n);if(a!==void 0)return s(a.libraryPath)?(t({[n]:{libraryPath:a.libraryPath,extensions:[...a.extensions],...a.languageSymbol===void 0?{}:{languageSymbol:a.languageSymbol}}}),A.add(n),{ok:!0,lang:n}):{ok:!1,detail:Sn(n,a.libraryPath)};try{let i=await import(`@ast-grep/lang-${n}`);return t({[n]:i.default??i}),A.add(n),{ok:!0,lang:n}}catch{return{ok:!1,detail:`unknown ast-grep grammar: '${n}'. Built in: ${xn.join(", ")}. Anything else is either a published package \u2014 \`npm i -D @ast-grep/lang-${n}\` \u2014 or a grammar you build yourself and declare in flow.config.ts's \`grammars\` setting.`}}}async function Cn(n,e,t){let r=await Rn(t);if(!r.ok)return r;let{parse:o}=await import("@ast-grep/napi");return{ok:!0,hits:o(r.lang,n).root().findAll({rule:e}).map(a=>`${a.range().start.line+1}: ${a.text()}`)}}var En=f(n=>async e=>{let t=await Cn(k(e).content,n.rule,n.language);return t.ok?m(e,t.hits):e.fail(t.detail)});function $n(n){return e=>{let t=e.agentType;return n.parent===!0?!e.subagent&&t===void 0:t===void 0?!1:(n.types??[]).includes(t)?!0:(n.generic??[]).includes(t)?(n.brief??[]).some(r=>e.head.includes(r)):!1}}var Nn=14400*1e3;var E=class extends Error{refusals;constructor(e){super(w(e)),this.name="FlowConfigError",this.refusals=e}};function vn(n){if(n.ok)return n.entries;throw new E(n.refusals)}export{E as FlowConfigError,Be as REFUSAL_CODES,Ke as SUBSTITUTION_MESSAGE,En as astGrep,Ie as banCommands,Re as breadcrumb,Je as canonicalFiles,rn as changeTogether,ie as command,ae as commit,J as commitMessage,cn as commitReason,he as defineCategory,f as defineCheck,Ae as defineConfig,Ee as definePack,de as deletion,bn as depcruise,vn as entriesOrThrow,y as escapeRe,gn as execPasses,Y as gitDirPrefix,G as gitInvocations,z as givesReason,Se as guardrail,Ze as jsonInvariant,Ge as loadConfig,Pe as override,Me as pack,_e as protectedPath,b as quoteArg,fn as ranSinceEdit,w as refusalText,ce as session,qe as siblingExists,$n as spawnedAs,We as substitutionInProse,nn as symbolsInSibling,Fe as textBan,B as tokenizeCommand,ue as touch,le as turnEnd,se as write};
16
+ `);if(!t.args.some((d,c)=>(d==="-F"||d==="--file")&&t.args[c+1]==="-"||d==="-F-"||d==="--file=-"))return null;let s=wn(e),a=s===null?-1:e.indexOf(`
17
+ `,s.end)+1;if(s===null||a===0)return null;let{body:i,end:l}=N(e,a,s);return i===l?null:e.slice(a,i).trim()||null}function b(e){return`'${e.replace(/'/g,"'\\''")}'`}function le(e){let n=[],t=W(e),o=t?.[1];t?.[0]==="cd"&&o!==void 0&&!o.startsWith("-")&&!$.has(o)&&$.has(t[2]??"")&&n.push("-C",b(o));let r=F(e)?.[0];if(!r)return n.join(" ");for(let s=0;s<r.globals.length-1;s++)r.globals[s]==="-C"&&n.push("-C",b(r.globals[s+1]));return n.join(" ")}function ce(e,n){return new RegExp(`^[ \\t]*${y(n)}[ \\t]*:`,"im").test(e)}function vn(e,n,t=[]){let o=new Set(t),r=new Set;for(let s of e.split(`
18
+ `)){if(!s.startsWith("+")||s.startsWith("+++"))continue;let a=s.slice(1);for(let i of n){let l=new RegExp(i,"g"),d;for(;(d=l.exec(a))!==null;)d[1]!==void 0&&!o.has(d[1])&&r.add(d[1]),d[0]===""&&l.lastIndex++}}return[...r]}function An(e){let{message:n,state:t,whenChanged:o,whenAdded:r,except:s,namesAdded:a,token:i}=e,l=new Set(t.added),d=[];for(let c of t.changed)s&&g(c,s)||(l.has(c)&&r&&g(c,r)?d.push(`\`${c}\` (new)`):o&&g(c,o)&&d.push(`\`${c}\` (changed)`));for(let{name:c,file:f}of a??[])d.push(`\`${c}\` (added in ${f})`);return d.length?ce(n,i)?[]:[`${d.join(" \xB7 ")} \u2014 and this commit's message records no reason. Put \`${i}: <why>\` on a line of its own in the message; the act is fine, doing it silently is not.`]:[]}function T(e){return e.split(`
19
+ `).map(n=>n.trim()).filter(Boolean)}var Mn=p(e=>async n=>{let t=de(n.command??"");if(t==null)return n.ok();let o=`git ${le(n.command??"")}`.trimEnd(),r={changed:[],added:[]};if(e.whenChanged||e.whenAdded){let[i,l,d]=await Promise.all([n.exec(`${o} diff HEAD --name-only`),n.exec(`${o} diff HEAD --name-only --diff-filter=A`),n.exec(`${o} ls-files --others --exclude-standard`)]);if(i.code!==0||l.code!==0||d.code!==0)return n.ok();let c=T(d.stdout);r={changed:[...new Set([...T(i.stdout),...c])],added:[...T(l.stdout),...c]}}let s=[];for(let i of e.diffAdds??[]){let l=await n.exec(`${o} diff HEAD -- ${b(i.file)}`);if(l.code!==0)return n.ok();for(let d of vn(l.stdout,i.patterns,i.known??[]))s.push({name:d,file:i.file})}let a=An({message:t,state:r,whenChanged:e.whenChanged,whenAdded:e.whenAdded,except:e.except,namesAdded:s,token:e.token});return m(n,a)});function Pn(e,n,t){if(t===""||n.length===0)return!1;let o=-1,r=-1;return e.forEach((s,a)=>{s.did==="edit"&&g(s.path,n)&&(o=a),s.did==="run"&&s.command.includes(t)&&(r=a)}),o>=0&&o>r}var Bn=p(e=>n=>n.turn&&Pn(n.turn,e.edited,e.mustRun)?n.fail(`edited ${e.edited.join(", ")} this turn but never ran \`${e.mustRun}\` afterwards`):n.ok());function Gn(e,n){let t=n??[];return!t.length||!e.length?!1:!e.some(o=>g(o,t))}function ue(e,n=8){let t=e.trim().split(`
20
+ `).filter(Boolean),o=t.filter(r=>/\b(fail|failed|error|not ok|assert|expected|cannot|undefined)\b/i.test(r)||/[✖✗✘]/.test(r));return(o.length?o:t.slice(-6)).slice(0,n).join(`
21
+ `)}var Tn=p(e=>async n=>{let t=await ie(n);if(Gn(t,e.changed))return n.ok();let o=e.run.includes("{files}");if(o&&t.length===0)return n.ok();let r=o?e.run.replace("{files}",t.map(b).join(" ")):e.run,s=await n.exec(r);return s.code===0?n.ok():n.fail(`\`${r}\` failed (exit ${s.code}):
22
+ ${ue(s.stderr||s.stdout)}`)});function E(e){let n=M(e),t=n[n.length-1]?.kind==="globstar";return`^${(t?n.slice(0,-1):n).map(P).join("")}${t?"":"$"}`}function re(e){return e==="node:*"?{core:!0}:e.startsWith("node:")?{path:`^${y(e)}$`}:e.includes("/")||e.includes("*")||e.includes(".")?{path:E(e)}:{path:`node_modules/${y(e)}(/|$)`}}function v(e){return e===void 0?{path:[],not:[]}:Array.isArray(e)?{path:e,not:[]}:{path:e.path,not:e.not??[]}}function C(e,n){let t=[],o=[],r=!1;for(let a of e){let{path:i,not:l}=v(n[a]);for(let d of i){let c=re(d);c.core?r=!0:c.path&&t.push(c.path)}for(let d of l){let c=re(d);c.path&&o.push(c.path)}}let s={};return t.length&&(s.path=t),o.length&&(s.pathNot=o),r&&(s.dependencyTypes=["core"]),s}function jn(e){let n=e.layers,t=[],o=[],r=(e.except??[]).includes("type-only"),s=i=>r?{...i,dependencyTypesNot:["type-only"]}:i;for(let[i,l]of Object.entries(e.only??{})){let c={pathNot:C(l,n).path??[]};t.push({name:`${i}-only`,severity:"error",comment:`${i} may import only: ${l.join(", ")} \u2014 an unlisted import blocks here (add it to a layer, or keep it out).`,from:C([i],n),to:s(c)})}for(let i of e.forbid??[])if(i==="circular")t.push({name:"no-circular",severity:"error",comment:"no dependency cycles",from:{pathNot:"node_modules"},to:{circular:!0}});else if(i==="orphans")t.push({name:"no-orphans",severity:"warn",comment:"unreferenced module",from:{orphan:!0,pathNot:"node_modules|\\.d\\.ts$"},to:{}});else if(i.cyclesBetween!==void 0){let l=i.cyclesBetween,d=v(n[l]).path[0]??"",c=E(d).replace(/\$$/,"").replace(/\[\^\/\]\*$/,"([^/]+)");t.push({name:`no-cycles-between-${l}`,severity:"error",comment:i.why??`${l} must not import sideways`,from:{path:`${c}/`},to:s({path:`${c.replace(/\(\[\^\/\]\+\)/,"[^/]+")}/`,pathNot:"$1/"})})}else if(i.from!==void 0&&i.to!==void 0){let l={...C([i.to],n)};i.transitive===!0&&(l.reachable=!0),t.push({name:`no-${i.from}-to-${i.to}${i.transitive===!0?"-transitive":""}`,severity:"error",comment:i.why??`${i.from} must not import ${i.to}`,from:C([i.from],n),to:s(l)})}for(let i of e.require??[])o.push({name:`must-import-${i.import}`,severity:"error",comment:i.why??`modules in ${i.in} must import ${i.import}`,module:{path:E(i.in)},to:{path:E(i.import)}});for(let i of e.warn??[])i==="sdp"&&t.push({name:"sdp",severity:"warn",comment:"depends on a more-unstable module (Stable Dependencies Principle)",from:{},to:{moreUnstable:!0}});let a={enhancedResolveOptions:{extensions:[".js",".jsx",".ts",".tsx",".mjs",".cjs",".json"]},doNotFollow:{path:"node_modules"},tsPreCompilationDeps:!1,...e.options??{}};return{forbidden:t,required:o,options:a}}var oe="FLOW_DEPCRUISE_CONFIG";function Dn(e){let n=JSON.stringify(jn(e));return["d=$(mktemp -d)",`cat > "$d/dc.json" <<'${oe}'`,n,oe,`npx --no-install depcruise --config "$d/dc.json" --output-type json ${b(e.scan)}`,"rc=$?",'rm -rf "$d"',"exit $rc"].join(`
23
+ `)}function Nn(e){let n;try{n=JSON.parse(e.stdout||"")}catch{return e.code===0?[]:[`depcruise failed (exit ${e.code}): ${ue(e.stderr||e.stdout,3)}`]}return(n.summary?.violations??[]).map(t=>{let o=t.rule?.name??"fence",r=t.comment??t.rule?.comment??"";return`${o}: ${t.from} \u2192 ${t.to}${r?` \u2014 ${r}`:""}`})}function Ln(e){let n=[];for(let[t,o]of Object.entries(e)){let{path:r,not:s}=v(o);s.includes("node:*")&&n.push(`binds a depcruise layer \`${t}\` whose \`not\` list excludes \`node:*\`. A builtin is matched as a dependency TYPE, not a path, and the only exclusion available says "not a core module at all" \u2014 wider than this layer means. Say the layer's globs without it, or forbid the edge you actually mean.`);for(let a of[...r,...s])K(a)&&n.push(`binds a depcruise layer \`${t}\` whose entry is a regular expression, not a glob: \`${a}\`. Layers are GLOBS here \u2014 \`src/pages/**\`, \`src/lib/auth/**\` \u2014 and a regex is escaped into a literal, so the fence would load, report armed and match nothing. For a layer with holes in it, say \`{ path: ["src/pages/**"], not: ["src/pages/api/**"] }\` rather than a lookahead.`)}return n}function Wn(e){let n=[];for(let[t,o]of Object.entries(e.only??{}))for(let r of o)v(e.layers[r]).not.length>0&&n.push(`binds a depcruise \`only\` for \`${t}\` naming the layer \`${r}\`, which has a \`not\` list. An allowlist is compiled by inverting the layers it names, and that inversion reads \`path\` alone \u2014 so \`${r}\`'s exclusions would be silently dropped and the allowlist would be wider than it reads. Give \`${r}\` plain globs, or say the exclusion as a \`forbid\` edge.`);return n}var Fn=p(e=>w(async t=>m(t,Nn(await t.exec(Dn(e))),`
24
+ `),[...Ln(e.layers),...Wn(e)])),fe={html:"Html",css:"Css",javascript:"JavaScript",js:"JavaScript",typescript:"TypeScript",ts:"TypeScript",tsx:"Tsx",jsx:"Tsx"},In=Object.keys(fe),j=new Set,se=Symbol.for("flow.grammars");function Kn(){let e=globalThis,n=e[se];if(n!==void 0)return n;let t={declared:[],present:()=>!1};return e[se]=t,t}function _n(e,n){return`\`${e}\`: no library at ${n}. A grammar is a BUILD ARTEFACT \u2014 machine-specific, never committed \u2014 so this is the ordinary state of a fresh clone. Build it (the repo that declares a grammar carries the recipe that builds it), or every ast-grep rule on that language refuses rather than passing quietly.`}async function Hn(e){let{Lang:n,registerDynamicLanguage:t}=await import("@ast-grep/napi"),o=fe[e];if(o!==void 0)return{ok:!0,lang:n[o]};if(j.has(e))return{ok:!0,lang:e};let{declared:r,present:s}=Kn(),a=r.find(i=>i.name===e);if(a!==void 0)return s(a.libraryPath)?(t({[e]:{libraryPath:a.libraryPath,extensions:[...a.extensions],...a.languageSymbol===void 0?{}:{languageSymbol:a.languageSymbol}}}),j.add(e),{ok:!0,lang:e}):{ok:!1,detail:_n(e,a.libraryPath)};try{let i=await import(`@ast-grep/lang-${e}`);return t({[e]:i.default??i}),j.add(e),{ok:!0,lang:e}}catch{return{ok:!1,detail:`unknown ast-grep grammar: '${e}'. Built in: ${In.join(", ")}. Anything else is either a published package \u2014 \`npm i -D @ast-grep/lang-${e}\` \u2014 or a grammar you build yourself and declare in flow.config.ts's \`grammars\` setting.`}}}async function qn(e,n,t){let o=await Hn(t);if(!o.ok)return o;let{parse:r}=await import("@ast-grep/napi");return{ok:!0,hits:r(o.lang,e).root().findAll({rule:n}).map(a=>`${a.range().start.line+1}: ${a.text()}`)}}var Un=p(e=>async n=>{let t=await qn(k(n).content,e.rule,e.language);return t.ok?m(n,t.hits):n.fail(t.detail)});function Vn(e){return n=>{let t=n.agentType;return e.parent===!0?!n.subagent&&t===void 0:t===void 0?!1:(e.types??[]).includes(t)?!0:(e.generic??[]).includes(t)?(e.brief??[]).some(o=>n.head.includes(o)):!1}}var rt=14400*1e3;var A=class extends Error{refusals;constructor(n){super(R(n)),this.name="FlowConfigError",this.refusals=n}};function Jn(e){if(e.ok)return e.entries;throw new A(e.refusals)}export{A as FlowConfigError,Ue as REFUSAL_CODES,tn as SUBSTITUTION_MESSAGE,Un as astGrep,en as banCommands,Ne as breadcrumb,cn as canonicalFiles,bn as changeTogether,xe as command,we as commit,de as commitMessage,Mn as commitReason,Pe as defineCategory,p as defineCheck,qe as defineConfig,We as definePack,Se as deletion,Fn as depcruise,Jn as entriesOrThrow,y as escapeRe,Tn as execPasses,z as faultsOf,le as gitDirPrefix,F as gitInvocations,ce as givesReason,De as guardrail,gn as jsonInvariant,Ve as loadConfig,on as oneWriter,He as override,_e as pack,rn as protectedPath,b as quoteArg,Bn as ranSinceEdit,R as refusalText,Ce as session,sn as siblingExists,Vn as spawnedAs,nn as substitutionInProse,hn as symbolsInSibling,Xe as textBan,W as tokenizeCommand,Ee as touch,Re as turnEnd,w as withFaults,be as write};