@paniolo/scan 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.
Files changed (3) hide show
  1. package/README.md +27 -0
  2. package/dist/cli.js +137 -65
  3. package/package.json +21 -3
package/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # paniolo-scan
2
2
 
3
+ [![npm @paniolo/scan](https://img.shields.io/npm/v/%40paniolo%2Fscan?label=%40paniolo%2Fscan)](https://www.npmjs.com/package/@paniolo/scan)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
5
+
3
6
  > Scan a repository for AI harness performance — how well your repo is set up for
4
7
  > coding agents across Copilot, Cursor, Codex, Antigravity, Claude Code, and Gemini.
5
8
 
@@ -13,6 +16,14 @@ a meta-harness is, why your repo needs one, how this scan connects to
13
16
  npx @paniolo/scan
14
17
  ```
15
18
 
19
+ > **Goodwill service**
20
+ >
21
+ > `@paniolo/scan` and these remediation prompts are a free community starting point.
22
+ > Self-service AI fixes will not match a human-tuned intelligence layer —
23
+ > [Paniolo's professional services](https://paniolo.ai/#contact) are recommended for
24
+ > production-grade work. The free tier stays genuinely useful; this is honest guidance,
25
+ > not a gate.
26
+
16
27
  ## Cursor
17
28
 
18
29
  Install the [**paniolo-ai/scan**](https://github.com/paniolo-ai/scan) skill to run the scan from
@@ -38,8 +49,24 @@ npx @paniolo/scan --harness cursor,codex
38
49
  # Scan another repo path
39
50
  npx @paniolo/scan ../songshare-effect
40
51
 
52
+ # Gate CI: exit 1 when findings at or above a severity exist
53
+ npx @paniolo/scan --fail-on error
54
+
55
+ # Opt-in, local-only Session Analysis (deterministic, no LLM, no network)
56
+ npx @paniolo/scan --session-analysis
41
57
  ```
42
58
 
59
+ ### Session Analysis (your pain, in your own words)
60
+
61
+ `--session-analysis` mines this repo's local Claude Code session transcripts to show what you
62
+ keep re-typing — recurring instructions, rules you correct the agent on despite them being in
63
+ your `CLAUDE.md`, friction hotspots, and missing-rule suggestions ("you typed this across N
64
+ sessions but it isn't in your committed guidance"). It is deterministic and LLM-free, reads
65
+ only your local logs for this repo (never other projects, never repo contents), never runs in
66
+ CI, and does not affect the scan score. Prompt snippets are redacted by default; add
67
+ `--include-raw-snippets` to reveal them. See
68
+ [docs/architecture.md](docs/architecture.md#extended-session-analysis-opt-in-local-only).
69
+
43
70
  ### Fenced AI review (Semantic checks via an LLM subagent)
44
71
 
45
72
  1. **Emit the tasks:**
package/dist/cli.js CHANGED
@@ -1,13 +1,16 @@
1
1
  #!/usr/bin/env node
2
- import{readFile as ho}from"node:fs/promises";var nt={status:"not-run",score:null,grade:"not-run",checks:[],findings:[]};var po=[{min:85,grade:"excellent"},{min:70,grade:"good"},{min:50,grade:"fair"},{min:0,grade:"poor"}];function le(e){for(let{min:t,grade:n}of po)if(e>=t)return n;return"poor"}function Ur(e){let t=e.indexOf(":");return t===-1?null:e.slice(t+1)}function H(e,t){let n=e[t];return typeof n=="string"?n:""}import{access as fo}from"node:fs/promises";import mo from"node:path";var $=75,rt=300,Ee=["CLAUDE.md","GEMINI.md",".github/copilot-instructions.md"];function R(e,t){return e.files.some(n=>n.path===t)}function f(e,t){return e.fileContents.get(t)??null}function O(e,t){return e.files.find(r=>r.path===t)?.lines??null}function qr(e){return e.includes("AGENTS.md")||e.includes("docs/ai/rules.md")}function Ie(e){return e.match(/^---\r?\n([\s\S]*?)\r?\n---/)?.[1]??null}function Z(e,t){return new RegExp(`^${t}:`,"m").test(e)}async function ee(e,t){try{return await fo(mo.join(e,t)),!0}catch{return!1}}function te(e,t){return e.files.filter(n=>n.path.startsWith(t)).map(n=>n.path)}function T(e){return e.files.some(t=>t.path.startsWith("skills/")&&t.path.endsWith("/SKILL.md"))}function Le(e){return e.includes("available-skills.md")||e.includes("skills/*/SKILL.md")||e.includes("npm run qmd")||e.includes("skills/")&&e.includes("available-skills")}function Te(e){return/agent routing/i.test(e)&&e.includes("|")&&/agents\/.*\.agent\.md/.test(e)}function h(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}var C={"AI1-contradiction":{checkId:"AI1-contradiction",title:"Cross-guidance contradictions",schemaKey:"contradictions",entryFields:["ruleA","ruleB","explanation"]},"AI2-adapter-fidelity":{checkId:"AI2-adapter-fidelity",title:"Adapter fidelity to shared layer",schemaKey:"drifts",entryFields:["claim","explanation"]},"AI3-security-review":{checkId:"AI3-security-review",title:"Semantic security review (advisory)",schemaKey:"risks",entryFields:["location","risk","explanation"]}};function Br(e){return typeof e=="string"&&e in C}function st(e){if(!h(e.data))return[];let t=e.data[C[e.checkId].schemaKey];return Array.isArray(t)?t.filter(n=>h(n)):[]}function ot(e){let t=st(e);if(e.checkId==="AI1-contradiction")return t.map(r=>({ruleId:"ai-contradiction",severity:"warn",message:`Contradiction: ${H(r,"explanation")}`,file:null,line:null,harnesses:[],hint:`"${H(r,"ruleA")}" conflicts with "${H(r,"ruleB")}"`}));if(e.checkId==="AI3-security-review")return t.map(r=>({ruleId:"ai-security-review",severity:"info",message:`Possible security risk (${H(r,"risk")}): ${H(r,"explanation")}`,file:null,line:null,harnesses:[],hint:`LLM-judged at ${H(r,"location")} \u2014 verify manually before acting.`}));let n=Ur(e.taskId);return t.map(r=>({ruleId:"ai-adapter-fidelity",severity:"warn",message:`Adapter drift: ${H(r,"explanation")}`,file:n,line:null,harnesses:[],hint:`Adapter claim: "${H(r,"claim")}"`}))}function it(e,t){let n={"AI1-contradiction":"ai-contradiction","AI2-adapter-fidelity":"ai-adapter-fidelity","AI3-security-review":"ai-security-review"},r=new Set,s=[];for(let o of e){if(r.has(o.checkId))continue;r.add(o.checkId);let i=n[o.checkId],a=t.filter(c=>c.ruleId===i).length;s.push({checkId:o.checkId,title:C[o.checkId].title,findingsCount:a,passed:a===0})}return s}var go=12;function Fe(e){let t=e.flatMap(s=>ot(s)),n=t.filter(s=>s.severity!=="info"),r=Math.max(0,100-go*n.length);return{status:"run",score:r,grade:le(r),checks:it(e,t),findings:t}}function at(e,t,n){let r=C[t];if(!h(n))throw new TypeError(`AI review result "${e}" data must be an object.`);let s=n[r.schemaKey];if(!Array.isArray(s))throw new TypeError(`AI review result "${e}" must have an array "${r.schemaKey}".`);for(let[o,i]of s.entries()){if(!h(i))throw new TypeError(`AI review result "${e}" ${r.schemaKey}[${String(o)}] must be an object.`);for(let a of r.entryFields){let c=i[a];if(typeof c!="string"||c.trim().length===0)throw new TypeError(`AI review result "${e}" ${r.schemaKey}[${String(o)}] is missing "${a}".`)}}}function ct(e,t){if(!h(e))throw new TypeError(`AI review result #${String(t)} must be an object.`);let{taskId:n,checkId:r,data:s}=e;if(typeof n!="string"||n.length===0)throw new TypeError(`AI review result #${String(t)} is missing a "taskId".`);if(!Br(r))throw new TypeError(`AI review result "${n}" has an unknown checkId: ${String(r)}.`);return at(n,r,s),{taskId:n,checkId:r,data:s}}function He(e){if(!h(e))throw new TypeError("AI review results must be a JSON object.");if(e.version!==1)throw new TypeError('AI review results must have "version": 1.');let{results:t}=e;if(!Array.isArray(t))throw new TypeError('AI review results must include a "results" array.');return{version:1,results:t.map((n,r)=>ct(n,r))}}async function lt(e){let t=await ho(e,"utf8"),n=JSON.parse(t);return He(n).results}import yo from"node:path";function ut(e){let t=e.split(",").map(s=>s.trim()).filter(s=>s.length>0);if(t.length===0)return null;let n=[],r=[];for(let s of t)s==="copilot"||s==="cursor"||s==="codex"||s==="antigravity"||s==="claude"||s==="gemini"?n.push(s):r.push(s);return r.length>0?(process.stderr.write(`error: unknown harness(es): ${r.join(", ")}
3
- `),process.exit(2),[]):n}function Kr(e){return e==="error"||e==="warn"||e==="info"?e:(process.stderr.write(`error: invalid --fail-on value: ${e}
4
- `),process.exit(2),"error")}function Jr(e){return e==="terminal"||e==="json"?e:(process.stderr.write(`error: invalid --format value: ${e}
5
- `),process.exit(2),"terminal")}function dt(e){let t=process.cwd(),n=null,r="terminal",s="error",o=!1,i=!1,a=null;for(let c=0;c<e.length;c+=1){let u=e[c];if(u!==void 0){if(u==="-h"||u==="--help"){o=!0;continue}if(u==="--emit-ai-tasks"){i=!0;continue}if(u==="--ingest-ai-results"){let p=e[c+1];p===void 0&&(process.stderr.write(`error: --ingest-ai-results requires a file path
6
- `),process.exit(2)),a=p,c+=1;continue}if(u==="--harness"){let p=e[c+1];p===void 0&&(process.stderr.write(`error: --harness requires a value
7
- `),process.exit(2)),n=ut(p),c+=1;continue}if(u==="--format"){let p=e[c+1];p===void 0&&(process.stderr.write(`error: --format requires a value
8
- `),process.exit(2)),r=Jr(p),c+=1;continue}if(u==="--fail-on"){let p=e[c+1];p===void 0&&(process.stderr.write(`error: --fail-on requires a value
9
- `),process.exit(2)),s=Kr(p),c+=1;continue}u.startsWith("-")&&(process.stderr.write(`error: unknown option: ${u}
10
- `),process.exit(2)),t=yo.resolve(u)}}return{repoRoot:t,harnessFilter:n,format:r,failOn:s,help:o,emitAiTasks:i,ingestResultsPath:a}}function pt(){process.stdout.write(`paniolo-scan \u2014 AI harness diagnostic (read-only)
2
+ import{readFile as ra}from"node:fs/promises";var wt={status:"not-run",score:null,grade:"not-run",checks:[],findings:[]};var ea=[{min:85,grade:"excellent"},{min:70,grade:"good"},{min:50,grade:"fair"},{min:0,grade:"poor"}];function we(e){for(let{min:t,grade:n}of ea)if(e>=t)return n;return"poor"}function Rt(e){let t=(e.hint??"").toLowerCase().match(/[a-z0-9]+/g),n=t===null?"":[...new Set(t)].toSorted().join(" ");return`${e.ruleId}::${e.file??""}::${n}`}function Zr(e){let t=e.indexOf(":");return t===-1?null:e.slice(t+1)}function I(e,t){let n=e[t];return typeof n=="string"?n:""}import{access as ta}from"node:fs/promises";import na from"node:path";var W=75,bt=300,Ue=["CLAUDE.md","GEMINI.md",".github/copilot-instructions.md"];function E(e,t){return e.files.some(n=>n.path===t)}function h(e,t){return e.fileContents.get(t)??null}function U(e,t){return e.files.find(s=>s.path===t)?.lines??null}function eo(e){return e.includes("AGENTS.md")||e.includes("docs/ai/rules.md")}function Be(e){return e.match(/^---\r?\n([\s\S]*?)\r?\n---/)?.[1]??null}function ce(e,t){return new RegExp(`^${t}:`,"m").test(e)}async function le(e,t){try{return await ta(na.join(e,t)),!0}catch{return!1}}function ue(e,t){return e.files.filter(n=>n.path.startsWith(t)).map(n=>n.path)}function N(e){return e.files.some(t=>t.path.startsWith("skills/")&&t.path.endsWith("/SKILL.md"))}function Ve(e){return e.includes("available-skills.md")||e.includes("skills/*/SKILL.md")||e.includes("npm run qmd")||e.includes("skills/")&&e.includes("available-skills")}function ze(e){return/agent routing/i.test(e)&&e.includes("|")&&/agents\/.*\.agent\.md/.test(e)}function y(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}var w={"AI1-contradiction":{checkId:"AI1-contradiction",title:"Cross-guidance contradictions",schemaKey:"contradictions",entryFields:["ruleA","ruleB","explanation"]},"AI2-adapter-fidelity":{checkId:"AI2-adapter-fidelity",title:"Adapter fidelity to shared layer",schemaKey:"drifts",entryFields:["claim","explanation"]},"AI3-security-review":{checkId:"AI3-security-review",title:"Semantic security review (advisory)",schemaKey:"risks",entryFields:["location","risk","explanation"]},"AI4-deadweight":{checkId:"AI4-deadweight",title:"Dead-weight instructions (deletion test)",schemaKey:"deadweight",entryFields:["rule","reason"]},"AI5-vague-rules":{checkId:"AI5-vague-rules",title:"Vague rules lacking a decision boundary",schemaKey:"vague",entryFields:["rule","reason"]}};function to(e){return typeof e=="string"&&e in w}function Ct(e){if(!y(e.data))return[];let t=e.data[w[e.checkId].schemaKey];return Array.isArray(t)?t.filter(n=>y(n)):[]}function At(e){let t=Ct(e);if(e.checkId==="AI1-contradiction")return t.map(s=>({ruleId:"ai-contradiction",severity:"warn",message:`Contradiction: ${I(s,"explanation")}`,file:null,line:null,harnesses:[],hint:`"${I(s,"ruleA")}" conflicts with "${I(s,"ruleB")}"`}));if(e.checkId==="AI4-deadweight")return t.map(s=>({ruleId:"ai-deadweight",severity:"warn",message:`Dead weight: ${I(s,"reason")}`,file:null,line:null,harnesses:[],hint:`Rule: "${I(s,"rule")}" \u2014 a capable agent would follow it unprompted.`}));if(e.checkId==="AI5-vague-rules")return t.map(s=>({ruleId:"ai-vague-rule",severity:"warn",message:`Vague rule: ${I(s,"reason")}`,file:null,line:null,harnesses:[],hint:`Rule: "${I(s,"rule")}" \u2014 give it a testable decision boundary.`}));if(e.checkId==="AI3-security-review")return t.map(s=>({ruleId:"ai-security-review",severity:"info",message:`Possible security risk (${I(s,"risk")}): ${I(s,"explanation")}`,file:null,line:null,harnesses:[],hint:`LLM-judged at ${I(s,"location")} \u2014 verify manually before acting.`}));let n=Zr(e.taskId);return t.map(s=>({ruleId:"ai-adapter-fidelity",severity:"warn",message:`Adapter drift: ${I(s,"explanation")}`,file:n,line:null,harnesses:[],hint:`Adapter claim: "${I(s,"claim")}"`}))}function It(e){return e.map(t=>{let n=new Map;for(let s of At(t)){let r=Rt(s);n.has(r)||n.set(r,s)}return n})}function Et(e,t,n,s){let r=0,o;for(let i of e){let a=i.get(t);a!==void 0&&(r+=1,o??=a)}if(o!==void 0)return r>=n?o:{...o,severity:"info",message:`${o.message} [low-confidence: LLM judge variance, agreed in ${String(r)}/${String(s)} runs]`}}function vt(e){let t=new Map;for(let s of e){let r=t.get(s.taskId)??[];r.push(s),t.set(s.taskId,r)}let n=[];for(let s of t.values()){let r=It(s),o=Math.ceil(s.length/2),i=new Set;for(let a of r)for(let c of a.keys())i.add(c);for(let a of i){let c=Et(r,a,o,s.length);c!==void 0&&n.push(c)}}return n}function Tt(e,t){let n={"AI1-contradiction":"ai-contradiction","AI2-adapter-fidelity":"ai-adapter-fidelity","AI3-security-review":"ai-security-review","AI4-deadweight":"ai-deadweight","AI5-vague-rules":"ai-vague-rule"},s=new Set,r=[];for(let o of e){if(s.has(o.checkId))continue;s.add(o.checkId);let i=n[o.checkId],a=t.filter(c=>c.ruleId===i).length;r.push({checkId:o.checkId,title:w[o.checkId].title,findingsCount:a,passed:a===0})}return r}var sa=12;function qe(e){let t=vt(e),n=t.filter(r=>r.severity!=="info"),s=Math.max(0,100-sa*n.length);return{status:"run",score:s,grade:we(s),checks:Tt(e,t),findings:t}}function Lt(e,t,n){let s=w[t];if(!y(n))throw new TypeError(`AI review result "${e}" data must be an object.`);let r=n[s.schemaKey];if(!Array.isArray(r))throw new TypeError(`AI review result "${e}" must have an array "${s.schemaKey}".`);for(let[o,i]of r.entries()){if(!y(i))throw new TypeError(`AI review result "${e}" ${s.schemaKey}[${String(o)}] must be an object.`);for(let a of s.entryFields){let c=i[a];if(typeof c!="string"||c.trim().length===0)throw new TypeError(`AI review result "${e}" ${s.schemaKey}[${String(o)}] is missing "${a}".`)}}}function Ft(e,t){if(!y(e))throw new TypeError(`AI review result #${String(t)} must be an object.`);let{taskId:n,checkId:s,data:r}=e;if(typeof n!="string"||n.length===0)throw new TypeError(`AI review result #${String(t)} is missing a "taskId".`);if(!to(s))throw new TypeError(`AI review result "${n}" has an unknown checkId: ${String(s)}.`);return Lt(n,s,r),{taskId:n,checkId:s,data:r}}function Ke(e){if(!y(e))throw new TypeError("AI review results must be a JSON object.");if(e.version!==1)throw new TypeError('AI review results must have "version": 1.');let{results:t}=e;if(!Array.isArray(t))throw new TypeError('AI review results must include a "results" array.');return{version:1,results:t.map((n,s)=>Ft(n,s))}}async function _t(e){let t=await ra(e,"utf8"),n=JSON.parse(t);return Ke(n).results}import ia from"node:path";function no(e){return e==="error"||e==="warn"||e==="info"?e:(process.stderr.write(`error: invalid --fail-on value: ${e}
3
+ `),process.exit(2),"error")}function so(e){return e==="terminal"||e==="json"?e:(process.stderr.write(`error: invalid --format value: ${e}
4
+ `),process.exit(2),"terminal")}function Nt(e){let t=e.split(",").map(r=>r.trim()).filter(r=>r.length>0);if(t.length===0)return null;let n=[],s=[];for(let r of t)r==="copilot"||r==="cursor"||r==="codex"||r==="antigravity"||r==="claude"||r==="gemini"?n.push(r):s.push(r);return s.length>0?(process.stderr.write(`error: unknown harness(es): ${s.join(", ")}
5
+ `),process.exit(2),[]):n}var ro=[/\balways\b/i,/\bnever\b/i,/\bdont\b/i,/\bdon't\b/i,/\bmake sure\b/i,/\bremember to\b/i],oo=[/\bno\b/i,/\bwrong\b/i,/\bnot that\b/i,/\bi said\b/i,/\bstop\b/i,/\bthat's not right\b/i,/\bthats not right\b/i,/\bnot correct\b/i,/\btry again\b/i,/\bnot right\b/i],io=/\b(run|npm|pnpm|yarn|node|python|python3|pytest|make|docker|git|curl|bash|sh|cat|ls|find|grep|sed|awk|rm|cp|mv|touch|tee|mkdir|rmdir)\b/i,ao=[/^<[a-z-]+>/i,/^<\/[a-z-]+>/i,/^─{4,}/,/^={4,}/,/^-{4,}/,/^\*{4,}/,/^#{4,}\s*$/,/^UserPromptSubmit/,/^SessionStart/,/^OK$/,/^Tool loaded/],L={SS1:"Repeated instructions",SS2:"Ignored rules",SS3:"Friction hotspots",SS4:"Missing rule suggestions"};function Pt(e){let t=process.cwd(),n=null,s="terminal",r="error",o=!1,i=!1,a=null,c=!1,l=null,p=30,f=!1;for(let m=0;m<e.length;m+=1){let d=e[m];if(d!==void 0){if(d==="-h"||d==="--help"){o=!0;continue}if(d==="--emit-ai-tasks"){i=!0;continue}if(d==="--session-analysis"){c=!0;continue}if(d==="--include-raw-snippets"){f=!0;continue}if(d==="--session-root"){let g=e[m+1];g===void 0&&(process.stderr.write(`error: --session-root requires a path
6
+ `),process.exit(2)),l=g,m+=1;continue}if(d==="--max-sessions"){let g=e[m+1];g===void 0&&(process.stderr.write(`error: --max-sessions requires a value
7
+ `),process.exit(2));let S=Number.parseInt(g,10);(!Number.isFinite(S)||S<=0)&&(process.stderr.write(`error: --max-sessions must be a positive integer
8
+ `),process.exit(2)),p=S,m+=1;continue}if(d==="--ingest-ai-results"){let g=e[m+1];g===void 0&&(process.stderr.write(`error: --ingest-ai-results requires a file path
9
+ `),process.exit(2)),a=g,m+=1;continue}if(d==="--harness"){let g=e[m+1];g===void 0&&(process.stderr.write(`error: --harness requires a value
10
+ `),process.exit(2)),n=Nt(g),m+=1;continue}if(d==="--format"){let g=e[m+1];g===void 0&&(process.stderr.write(`error: --format requires a value
11
+ `),process.exit(2)),s=so(g),m+=1;continue}if(d==="--fail-on"){let g=e[m+1];g===void 0&&(process.stderr.write(`error: --fail-on requires a value
12
+ `),process.exit(2)),r=no(g),m+=1;continue}d.startsWith("-")&&(process.stderr.write(`error: unknown option: ${d}
13
+ `),process.exit(2)),t=ia.resolve(d)}}return{repoRoot:t,harnessFilter:n,format:s,failOn:r,help:o,emitAiTasks:i,ingestResultsPath:a,sessionAnalysis:c,sessionRoot:l,maxSessions:p,includeRawSnippets:f}}function Ht(){process.stdout.write(`paniolo-scan \u2014 AI harness diagnostic (read-only)
11
14
 
12
15
  Usage:
13
16
  paniolo-scan [options] [path]
@@ -18,6 +21,11 @@ Options:
18
21
  --fail-on <level> Exit 1 when findings at or above level: error (default) | warn | info
19
22
  --emit-ai-tasks Print optional AI-review prompt tasks as JSON, then exit (no scan)
20
23
  --ingest-ai-results <f> Fold AI-review answers from file <f> into the scan's AI dimension
24
+ --session-analysis Mine this repo's local Claude session logs for recurring
25
+ instructions, ignored rules, and friction, then exit (no scan)
26
+ --session-root <path> Override the session-log root (default: ~/.claude/projects)
27
+ --max-sessions <n> Most-recent session logs to analyze (default: 30)
28
+ --include-raw-snippets Show raw prompt snippets instead of redacting them (default: redact)
21
29
  -h, --help Show help
22
30
 
23
31
  Examples:
@@ -26,12 +34,28 @@ Examples:
26
34
  npx @paniolo/scan --harness cursor,codex --fail-on warn
27
35
  npx @paniolo/scan --emit-ai-tasks > paniolo-ai-tasks.json
28
36
  npx @paniolo/scan --ingest-ai-results paniolo-ai-results.json --format json
29
- `)}function ft(e){process.stdout.write(`${JSON.stringify(e,null,2)}
30
- `)}var mt=["error","warn","info"],zr={error:"ERROR",warn:"WARN",info:"INFO"},Yr={layering:"Layering",sharing:"Sharing",discoverability:"Discoverability",harnessWiring:"Harness wiring",maintainability:"Maintainability",guardrails:"Guardrails"},Xr=["layering","sharing","discoverability","harnessWiring","maintainability","guardrails"],Qr=["copilot","cursor","codex","antigravity","claude","gemini"];function gt(e){let t=zr[e.severity],n=e.file===null?"":` ${e.file}${e.line===null?"":`:${String(e.line)}`}`,r=e.harnesses.length===0?"":`
31
- Harnesses: ${e.harnesses.join(", ")}`,s=e.hint===void 0?"":`
32
- Hint: ${e.hint}`;return`[${t}] ${e.ruleId}
37
+ npx @paniolo/scan --session-analysis
38
+ npx @paniolo/scan --session-analysis --format json --include-raw-snippets
39
+ `)}function Mt(e){process.stdout.write(`${JSON.stringify(e,null,2)}
40
+ `)}var aa=["SS4","SS2","SS3","SS1"];function Dt(e){if(process.stdout.write(`# paniolo-scan \u2014 Session Analysis (extended)
41
+
42
+ `),e.status==="no-sessions"){process.stdout.write(`No ${e.harness} session logs found for this repo. Nothing to analyze.
43
+ `);return}let t=e.findings.filter(s=>s.checkId==="SS4").length,n=e.findings.filter(s=>s.checkId==="SS3"&&s.snippet!==null).length;if(process.stdout.write(`Analyzed ${String(e.sessionsAnalyzed)} session(s): ${String(t)} candidate missing rule(s), ${String(n)} recurring friction theme(s).
44
+ `),process.stdout.write(e.redacted?`Snippets are redacted; re-run with --include-raw-snippets to reveal them.
45
+
46
+ `:`Snippets shown verbatim (--include-raw-snippets).
47
+
48
+ `),e.findings.length===0){process.stdout.write(`No recurring instructions, ignored rules, or friction detected.
49
+ `);return}for(let s of aa){let r=e.findings.filter(o=>o.checkId===s);if(r.length!==0){process.stdout.write(`## ${s} \u2014 ${L[s]}
50
+
51
+ `);for(let o of r)process.stdout.write(`- ${o.detail}
52
+ `);process.stdout.write(`
53
+ `)}}}var ca={"shared-agents-md":["Memory","Planning"],"shared-rules-doc":["Planning","Action"],"adapter-thin-claude":["Memory"],"adapter-thin-gemini":["Memory"],"adapter-thin-copilot":["Memory"],"adapter-points-to-shared":["Memory"],"skills-index":["Action"],"claude-agent-routing":["Planning"],"agents-md-mentions-skills":["Action"],"skill-doc-deep-links":["Memory"],"qmd-script-present":["Memory"],"memory-docs-indexed":["Memory"],"focused-test-commands-present":["Reflection"],"skill-frontmatter":["Action"],"skill-line-count":["Memory"],"agent-frontmatter":["Action"],"no-duplicate-skill-trees":["Memory"],"no-duplicate-agent-trees":["Memory"],"guidance-links-resolve":["Memory"],"forbidden-legacy-paths":["Memory"],"local-context-patterns":["Memory"],"correction-loop-documented":["Reflection"],"guidance-maintenance-script":["Reflection"],"pr-template-ai-harness-check":["Reflection"],"emphasis-keyword-density":["Memory"],"identity-language-absent":["Memory"],"adapter-content-duplication":["Memory"],"adapter-context-budget":["Memory"],"always-loaded-budget":["Memory"],"strict-typecheck-present":["Reflection","System Operation"],"lint-gate-present":["Reflection","System Operation"],"jsdoc-enforcement-present":["Reflection"],"test-gates-present":["Reflection"],"ci-enforcement-gates":["Reflection","System Operation"],"ci-validation-gates":["Reflection","System Operation"],"ci-guidance-lint":["Reflection"],"vscode-skills-location":["Action"],"vscode-agents-location":["Action"],"vscode-custom-hooks":["Reflection","System Operation"],"no-dangerous-auto-approve":["Action"],"hook-no-network-exfil":["Action","System Operation"],"hook-stop-circuit-breaker":["Reflection","System Operation"],"env-files-gitignored":["Action"],"secret-scanning-configured":["System Operation"],"no-pull-request-target":["System Operation"],"actions-sha-pinned":["System Operation"],"claude-hooks-valid":["System Operation"],"codex-hooks-valid":["System Operation"],"model-interface-pinned":["System Operation","Action"],"llm-output-schema-validated":["Action"],"tool-contract-tests-present":["Action","System Operation"],"escalation-protocol-discoverability":["Planning","Reflection"],"agent-resource-budget-caps":["System Operation"],"tool-allowlist-inventory":["Action"],"untrusted-input-action-boundary":["Action","Memory"],"memory-write-provenance":["Memory"],"high-impact-action-confirmation":["Action"]};function Ye(e){return ca[e]??[]}var Ot=["error","warn","info"],co={error:"ERROR",warn:"WARN",info:"INFO"},lo={layering:"Layering",sharing:"Sharing",discoverability:"Discoverability",harnessWiring:"Harness wiring",maintainability:"Maintainability",guardrails:"Guardrails"},uo=["layering","sharing","discoverability","harnessWiring","maintainability","guardrails"],po=["copilot","cursor","codex","antigravity","claude","gemini"];function $t(e){let t=co[e.severity],n=e.file===null?"":` ${e.file}${e.line===null?"":`:${String(e.line)}`}`,s=e.harnesses.length===0?"":`
54
+ Harnesses: ${e.harnesses.join(", ")}`,r=e.hint===void 0?"":`
55
+ Hint: ${e.hint}`,o=Ye(e.ruleId),i=o.length===0?"":`
56
+ Prevents: ${o.join(", ")}-class agent failures`;return`[${t}] ${e.ruleId}
33
57
  ${e.message}${n?`
34
- ${n}`:""}${r}${s}`}var Zr=`---
58
+ ${n}`:""}${s}${i}${r}`}var fo=`---
35
59
 
36
60
  \u2139\uFE0F Need professional-grade agent infrastructure?
37
61
 
@@ -44,29 +68,38 @@ For professional or production-grade work, we strongly recommend
44
68
  engaging Paniolo's professional services to design, tune, and evolve
45
69
  your infrastructure. Learn more at https://paniolo.ai or contact us
46
70
  directly at https://paniolo.ai/#contact.
47
- `;function ht(e){if(process.stdout.write(`## AI review (optional)
71
+ `;function Gt(e){if(process.stdout.write(`## AI review (optional)
48
72
 
49
73
  `),e.status==="not-run"){process.stdout.write(`Not run \u2014 pass --ingest-ai-results to score this dimension.
50
74
 
51
75
  `);return}let t=e.score===null?"n/a":`${String(e.score)}/100`;process.stdout.write(`AI review: ${t} (${e.grade})
52
- `);for(let n of e.checks){let r=n.passed?"\u2713":`\u2717 ${String(n.findingsCount)} finding(s)`;process.stdout.write(` ${r} ${n.title}
53
- `)}for(let n of e.findings){let r=n.file===null?"":` (${n.file})`;process.stdout.write(` - ${n.message}${r}
76
+ `);for(let n of e.checks){let s=n.passed?"\u2713":`\u2717 ${String(n.findingsCount)} finding(s)`;process.stdout.write(` ${s} ${n.title}
77
+ `)}for(let n of e.findings){let s=n.file===null?"":` (${n.file})`;process.stdout.write(` - ${n.message}${s}
54
78
  `)}process.stdout.write(`
55
- `)}function yt(e){if(e===void 0)return;let t=e.harnesses.filter(n=>n.detected);if(t.length!==0){process.stdout.write(`## Context budget
79
+ `)}function jt(e){if(e===void 0)return;let t=e.harnesses.filter(n=>n.detected);if(t.length!==0){process.stdout.write(`## Context budget
56
80
 
57
81
  `);for(let n of t){process.stdout.write(`${n.harness}: ${String(n.totalLines)} always-loaded lines, ~${String(n.estimatedTokens)} tokens (${n.status})
58
- `);for(let r of n.files.slice(0,3))process.stdout.write(` ${r.path}: ${String(r.lines)} lines
82
+ `);for(let s of n.files.slice(0,3))process.stdout.write(` ${s.path}: ${String(s.lines)} lines
59
83
  `)}process.stdout.write(`
60
- `)}}var kt=new Set(["shared","skills","agents"]),V=["copilot","cursor","codex","antigravity","claude","gemini"];function es(e,t){return t.length>=2?!0:kt.has(e.layer)||e.path==="AGENTS.md"}function Pe(e){switch(e){case"yes":return"\u2713";case"partial":return"~";case"no":return"\u2717";case"na":return"\u2014"}}import{readFile as ko}from"node:fs/promises";import So from"node:path";async function St(e){try{return await ko(So.join(e,".codex/hooks.json"),"utf8"),!0}catch{return!1}}function l(e,t){return{status:e,detail:t}}function wt(){let e={copilot:l("na",""),cursor:l("na",""),codex:l("na",""),antigravity:l("na",""),claude:l("na",""),gemini:l("na","")};return{sharedSkillsDiscoverable:{...e},customAgents:{...e},lifecycleHooks:{...e},thinAdapter:{...e},workflows:{...e}}}var wo={copilot:".github/copilot-instructions.md",claude:"CLAUDE.md",gemini:"GEMINI.md"};function F(e){return wo[e]??null}function ue(e,t){if(!T(e))return!1;if(R(e,"docs/ai/available-skills.md"))return!0;let n=f(e,"AGENTS.md");if(n!==null&&Le(n))return!0;let r=F(t);if(r===null)return!1;let s=f(e,r);return s!==null&&s.includes("skills/")}function v(e,t,n){let r=e.settings?.[t];if(h(r)&&Object.keys(r).some(a=>a.startsWith(n)))return!0;if(e.settingsRaw===null)return!1;let s=t.replaceAll(".",String.raw`\.`);return new RegExp(`"${s}"\\s*:\\s*\\{[^}]*"${n}[^"]*"`).test(e.settingsRaw)}var xo=50;function ts(e){return e.files.some(t=>t.path.startsWith("agents/")&&t.path.endsWith(".agent.md"))}function Ne(e,t){let n=O(e,t);return n===null?!1:n<=xo}function ns(e,t){let n=f(e,t);return n===null?!1:n.includes("AGENTS.md")||n.includes("docs/ai/rules.md")}function _e(e){return e.files.some(t=>t.path.startsWith(".agent/workflows/"))}function rs(e){let t=f(e,"CLAUDE.md");return t!==null&&Te(t)}function xt(e,t){let n=ts(t.context);switch(e){case"copilot":case"cursor":return v(t.vscode,"chat.agentFilesLocations","agents")&&n?l("yes","agents/ wired in chat.agentFilesLocations"):n?l("partial","agents/ present but not wired in VS Code settings"):l("no","No agents/ tree or VS Code agent locations");case"codex":return t.context.files.some(s=>s.path.startsWith(".codex/agents/"))&&n?l("yes",".codex/agents wrappers with shared agents/"):n?l("partial","agents/ present without .codex/agents wrappers"):l("no","No custom agents configured");case"claude":return rs(t.context)?l("yes","Agent routing table in CLAUDE.md"):n?l("partial","agents/ present without routing table in CLAUDE.md"):l("no","No agent routing or agents/ tree");case"gemini":{if(!n)return l("no","No agents/ tree");let r=F("gemini"),s=r===null?null:t.context.fileContents.get(r)??null;return s!==null&&s.includes("agents/")?l("partial","agents/ referenced from GEMINI.md"):l("partial","agents/ present; document routing in GEMINI.md")}case"antigravity":return l("na","Uses workflow playbooks instead of custom agents");default:return l("no","Unknown harness")}}function Rt(e,t){let n=t.vscode.hooksDirExists,r=t.vscode.settings?.["chat.useCustomAgentHooks"]===!0;switch(e){case"copilot":case"cursor":return n&&r?l("yes",".github/hooks/ with chat.useCustomAgentHooks"):n||r?l("partial","Hooks partially configured in VS Code workspace"):l("no","No lifecycle hooks configured");case"codex":return t.codexHooksExists?l("yes",".codex/hooks.json present"):n?l("partial","Shared .github/hooks/ only; no .codex/hooks.json"):l("no","No Codex hooks configured");case"claude":return t.claudeSettingsRaw!==null&&/"hooks"\s*:/.test(t.claudeSettingsRaw)?l("yes","Hooks in .claude/settings.json"):n?l("partial","Shared .github/hooks/ only; no .claude hooks"):l("no","No Claude hooks configured");case"gemini":return n&&r?l("partial","Shared VS Code hooks only; no Gemini-native hooks"):l("no","No lifecycle hooks for Gemini");case"antigravity":return l("na","No hook surface for Antigravity workflows");default:return l("no","Unknown harness")}}function Ct(e,t){if(!T(t.context))return l("no","No skills/ tree");switch(e){case"copilot":case"cursor":return v(t.vscode,"chat.agentSkillsLocations","skills")?l("yes","skills/ wired in chat.agentSkillsLocations"):l("partial","skills/ present but not wired in VS Code settings");case"codex":return ue(t.context,"codex")?l("partial","skills/ with prose discovery via AGENTS.md or skill index"):l("partial","skills/ present; no documented discovery workflow");case"claude":case"gemini":return ue(t.context,e)?l("partial","Prose discovery via skill index or adapter pointers"):l("no","skills/ without index or adapter pointers");case"antigravity":return _e(t.context)?l("yes","skills/ with workflow playbooks"):l("partial","skills/ present without workflow playbooks");default:return l("no","Unknown harness")}}function bt(e,t){switch(e){case"copilot":{let n=F("copilot");return n===null||!t.context.files.some(r=>r.path===n)?l("no","Missing .github/copilot-instructions.md"):Ne(t.context,n)?l("yes","Copilot instructions within line budget"):l("partial","Copilot instructions exceed thin adapter budget")}case"cursor":{let n=t.context.files.some(s=>s.path.startsWith(".cursor/rules/")),r=v(t.vscode,"chat.agentSkillsLocations","skills")&&v(t.vscode,"chat.agentFilesLocations","agents");return n||r?l("yes","Cursor rules or VS Code agent settings configured"):l("partial","Cursor detected without rules or agent settings")}case"codex":return t.context.files.some(r=>r.path.startsWith(".codex/"))?t.context.files.some(r=>r.path==="AGENTS.md")?l("yes",".codex/ with shared AGENTS.md entry"):l("partial",".codex/ without root AGENTS.md"):l("no","No .codex/ config surface");case"claude":{let n=F("claude");if(n===null||!t.context.files.some(o=>o.path===n))return l("no","Missing CLAUDE.md");let r=Ne(t.context,n),s=ns(t.context,n);return r&&s?l("yes","Thin CLAUDE.md referencing shared layers"):r?l("partial","CLAUDE.md thin but missing shared layer pointers"):l("partial","CLAUDE.md exceeds thin adapter budget")}case"gemini":{let n=F("gemini");return n===null||!t.context.files.some(r=>r.path===n)?l("no","Missing GEMINI.md"):Ne(t.context,n)?l("yes","Thin GEMINI.md adapter"):l("partial","GEMINI.md exceeds thin adapter budget")}case"antigravity":return l("partial","Workflows only; no classic root adapter");default:return l("no","Unknown harness")}}function At(e,t){return e!=="antigravity"?l("na","Workflow playbooks are Antigravity-specific"):_e(t.context)?l("yes",".agent/workflows/ playbooks present"):l("no","No .agent/workflows/ playbooks")}function vt(e,t,n){switch(e){case"sharedSkillsDiscoverable":return Ct(t,n);case"customAgents":return xt(t,n);case"lifecycleHooks":return Rt(t,n);case"thinAdapter":return bt(t,n);case"workflows":return At(t,n);default:return l("no","Unknown capability")}}var Et={sharedSkillsDiscoverable:"Shared skills discoverable",customAgents:"Custom agents",lifecycleHooks:"Lifecycle hooks",thinAdapter:"Thin adapter",workflows:"Workflows / playbooks"},de=["sharedSkillsDiscoverable","customAgents","lifecycleHooks","thinAdapter","workflows"],ss="Harness not detected";import{readFile as Ro}from"node:fs/promises";import Co from"node:path";async function It(e){try{return await Ro(Co.join(e,".claude/settings.json"),"utf8")}catch{return null}}async function Lt(e,t){let n=V.filter(o=>e.harnesses.includes(o)),r={context:e,vscode:t,claudeSettingsRaw:await It(e.repoRoot),codexHooksExists:await St(e.repoRoot)},s=wt();for(let o of de){let i=s[o];for(let a of V){if(!e.harnesses.includes(a)){i[a]=l("na",ss);continue}i[a]=vt(o,a,r)}}return{capabilities:de,harnesses:n,matrix:s}}function Tt(e){if(process.stdout.write(`## Harness gap matrix
84
+ `)}}function Wt(e){if(process.stdout.write(`## Predicted runtime failure exposure
85
+
86
+ `),e.byDimension.length===0){process.stdout.write(`No findings map to a runtime failure class.
87
+
88
+ `);return}let t=[...e.byDimension].sort((n,s)=>s.findingCount-n.findingCount);for(let n of t){let s=`${String(n.error)} error / ${String(n.warn)} warn / ${String(n.info)} info`;process.stdout.write(`${n.dimension}: ${String(n.findingCount)} finding(s) \u2014 ${s}
89
+ `),process.stdout.write(` Rules: ${n.ruleIds.join(", ")}
90
+ `)}e.untaggedFindings>0&&process.stdout.write(`
91
+ ${String(e.untaggedFindings)} finding(s) not yet mapped to a failure class.
92
+ `),process.stdout.write(`
93
+ `)}var Ut=new Set(["shared","skills","agents"]),K=["copilot","cursor","codex","antigravity","claude","gemini"];function mo(e,t){return t.length>=2?!0:Ut.has(e.layer)||e.path==="AGENTS.md"}function Je(e){switch(e){case"yes":return"\u2713";case"partial":return"~";case"no":return"\u2717";case"na":return"\u2014"}}import{readFile as la}from"node:fs/promises";import ua from"node:path";async function Bt(e){try{return await la(ua.join(e,".codex/hooks.json"),"utf8"),!0}catch{return!1}}function u(e,t){return{status:e,detail:t}}function Vt(){let e={copilot:u("na",""),cursor:u("na",""),codex:u("na",""),antigravity:u("na",""),claude:u("na",""),gemini:u("na","")};return{sharedSkillsDiscoverable:{...e},customAgents:{...e},lifecycleHooks:{...e},thinAdapter:{...e},workflows:{...e}}}var da={copilot:".github/copilot-instructions.md",claude:"CLAUDE.md",gemini:"GEMINI.md"};function P(e){return da[e]??null}function Re(e,t){if(!N(e))return!1;if(E(e,"docs/ai/available-skills.md"))return!0;let n=h(e,"AGENTS.md");if(n!==null&&Ve(n))return!0;let s=P(t);if(s===null)return!1;let r=h(e,s);return r!==null&&r.includes("skills/")}function v(e,t,n){let s=e.settings?.[t];if(y(s)&&Object.keys(s).some(a=>a.startsWith(n)))return!0;if(e.settingsRaw===null)return!1;let r=t.replaceAll(".",String.raw`\.`);return new RegExp(`"${r}"\\s*:\\s*\\{[^}]*"${n}[^"]*"`).test(e.settingsRaw)}var pa=50;function go(e){return e.files.some(t=>t.path.startsWith("agents/")&&t.path.endsWith(".agent.md"))}function Xe(e,t){let n=U(e,t);return n===null?!1:n<=pa}function ho(e,t){let n=h(e,t);return n===null?!1:n.includes("AGENTS.md")||n.includes("docs/ai/rules.md")}function Qe(e){return e.files.some(t=>t.path.startsWith(".agent/workflows/"))}function yo(e){let t=h(e,"CLAUDE.md");return t!==null&&ze(t)}function zt(e,t){let n=go(t.context);switch(e){case"copilot":case"cursor":return v(t.vscode,"chat.agentFilesLocations","agents")&&n?u("yes","agents/ wired in chat.agentFilesLocations"):n?u("partial","agents/ present but not wired in VS Code settings"):u("no","No agents/ tree or VS Code agent locations");case"codex":return t.context.files.some(r=>r.path.startsWith(".codex/agents/"))&&n?u("yes",".codex/agents wrappers with shared agents/"):n?u("partial","agents/ present without .codex/agents wrappers"):u("no","No custom agents configured");case"claude":return yo(t.context)?u("yes","Agent routing table in CLAUDE.md"):n?u("partial","agents/ present without routing table in CLAUDE.md"):u("no","No agent routing or agents/ tree");case"gemini":{if(!n)return u("no","No agents/ tree");let s=P("gemini"),r=s===null?null:t.context.fileContents.get(s)??null;return r!==null&&r.includes("agents/")?u("partial","agents/ referenced from GEMINI.md"):u("partial","agents/ present; document routing in GEMINI.md")}case"antigravity":return u("na","Uses workflow playbooks instead of custom agents");default:return u("no","Unknown harness")}}function qt(e,t){let n=t.vscode.hooksDirExists,s=t.vscode.settings?.["chat.useCustomAgentHooks"]===!0;switch(e){case"copilot":case"cursor":return n&&s?u("yes",".github/hooks/ with chat.useCustomAgentHooks"):n||s?u("partial","Hooks partially configured in VS Code workspace"):u("no","No lifecycle hooks configured");case"codex":return t.codexHooksExists?u("yes",".codex/hooks.json present"):n?u("partial","Shared .github/hooks/ only; no .codex/hooks.json"):u("no","No Codex hooks configured");case"claude":return t.claudeSettingsRaw!==null&&/"hooks"\s*:/.test(t.claudeSettingsRaw)?u("yes","Hooks in .claude/settings.json"):n?u("partial","Shared .github/hooks/ only; no .claude hooks"):u("no","No Claude hooks configured");case"gemini":return n&&s?u("partial","Shared VS Code hooks only; no Gemini-native hooks"):u("no","No lifecycle hooks for Gemini");case"antigravity":return u("na","No hook surface for Antigravity workflows");default:return u("no","Unknown harness")}}function Kt(e,t){if(!N(t.context))return u("no","No skills/ tree");switch(e){case"copilot":case"cursor":return v(t.vscode,"chat.agentSkillsLocations","skills")?u("yes","skills/ wired in chat.agentSkillsLocations"):u("partial","skills/ present but not wired in VS Code settings");case"codex":return Re(t.context,"codex")?u("partial","skills/ with prose discovery via AGENTS.md or skill index"):u("partial","skills/ present; no documented discovery workflow");case"claude":case"gemini":return Re(t.context,e)?u("partial","Prose discovery via skill index or adapter pointers"):u("no","skills/ without index or adapter pointers");case"antigravity":return Qe(t.context)?u("yes","skills/ with workflow playbooks"):u("partial","skills/ present without workflow playbooks");default:return u("no","Unknown harness")}}function Yt(e,t){switch(e){case"copilot":{let n=P("copilot");return n===null||!t.context.files.some(s=>s.path===n)?u("no","Missing .github/copilot-instructions.md"):Xe(t.context,n)?u("yes","Copilot instructions within line budget"):u("partial","Copilot instructions exceed thin adapter budget")}case"cursor":{let n=t.context.files.some(r=>r.path.startsWith(".cursor/rules/")),s=v(t.vscode,"chat.agentSkillsLocations","skills")&&v(t.vscode,"chat.agentFilesLocations","agents");return n||s?u("yes","Cursor rules or VS Code agent settings configured"):u("partial","Cursor detected without rules or agent settings")}case"codex":return t.context.files.some(s=>s.path.startsWith(".codex/"))?t.context.files.some(s=>s.path==="AGENTS.md")?u("yes",".codex/ with shared AGENTS.md entry"):u("partial",".codex/ without root AGENTS.md"):u("no","No .codex/ config surface");case"claude":{let n=P("claude");if(n===null||!t.context.files.some(o=>o.path===n))return u("no","Missing CLAUDE.md");let s=Xe(t.context,n),r=ho(t.context,n);return s&&r?u("yes","Thin CLAUDE.md referencing shared layers"):s?u("partial","CLAUDE.md thin but missing shared layer pointers"):u("partial","CLAUDE.md exceeds thin adapter budget")}case"gemini":{let n=P("gemini");return n===null||!t.context.files.some(s=>s.path===n)?u("no","Missing GEMINI.md"):Xe(t.context,n)?u("yes","Thin GEMINI.md adapter"):u("partial","GEMINI.md exceeds thin adapter budget")}case"antigravity":return u("partial","Workflows only; no classic root adapter");default:return u("no","Unknown harness")}}function Jt(e,t){return e!=="antigravity"?u("na","Workflow playbooks are Antigravity-specific"):Qe(t.context)?u("yes",".agent/workflows/ playbooks present"):u("no","No .agent/workflows/ playbooks")}function Xt(e,t,n){switch(e){case"sharedSkillsDiscoverable":return Kt(t,n);case"customAgents":return zt(t,n);case"lifecycleHooks":return qt(t,n);case"thinAdapter":return Yt(t,n);case"workflows":return Jt(t,n);default:return u("no","Unknown capability")}}var Qt={sharedSkillsDiscoverable:"Shared skills discoverable",customAgents:"Custom agents",lifecycleHooks:"Lifecycle hooks",thinAdapter:"Thin adapter",workflows:"Workflows / playbooks"},be=["sharedSkillsDiscoverable","customAgents","lifecycleHooks","thinAdapter","workflows"],So="Harness not detected";import{readFile as fa}from"node:fs/promises";import ma from"node:path";async function Zt(e){try{return await fa(ma.join(e,".claude/settings.json"),"utf8")}catch{return null}}async function en(e,t){let n=K.filter(o=>e.harnesses.includes(o)),s={context:e,vscode:t,claudeSettingsRaw:await Zt(e.repoRoot),codexHooksExists:await Bt(e.repoRoot)},r=Vt();for(let o of be){let i=r[o];for(let a of K){if(!e.harnesses.includes(a)){i[a]=u("na",So);continue}i[a]=Xt(o,a,s)}}return{capabilities:be,harnesses:n,matrix:r}}function tn(e){if(process.stdout.write(`## Harness gap matrix
61
94
 
62
95
  `),e.harnesses.length===0){process.stdout.write(`No harnesses detected \u2014 add tool adapters to compare capabilities.
63
96
 
64
- `);return}let t=28,n=Math.max(...e.harnesses.map(s=>s.length),6)+2,r=`${"Capability".padEnd(t)}${e.harnesses.map(s=>s.padEnd(n)).join("")}`;process.stdout.write(`${r}
65
- `);for(let s of de){let o=Et[s].padEnd(t),i=e.harnesses.map(a=>{let{status:c}=e.matrix[s][a];return Pe(c).padEnd(n)}).join("");process.stdout.write(`${o}${i}
97
+ `);return}let t=28,n=Math.max(...e.harnesses.map(r=>r.length),6)+2,s=`${"Capability".padEnd(t)}${e.harnesses.map(r=>r.padEnd(n)).join("")}`;process.stdout.write(`${s}
98
+ `);for(let r of be){let o=Qt[r].padEnd(t),i=e.harnesses.map(a=>{let{status:c}=e.matrix[r][a];return Je(c).padEnd(n)}).join("");process.stdout.write(`${o}${i}
66
99
  `)}process.stdout.write(`
67
100
  Legend: \u2713 yes ~ partial \u2717 no \u2014 not applicable
68
101
 
69
- `)}function Ft(e){e!==void 0&&(process.stdout.write(`## Intelligence layer
102
+ `)}function nn(e){e!==void 0&&(process.stdout.write(`## Intelligence layer
70
103
 
71
104
  `),process.stdout.write(`Surfaces: ${String(e.surfaces.length)} detected
72
105
  `),process.stdout.write(`Enforcement: ${String(e.enforcement.scripts.length)} script(s), ${String(e.enforcement.configs.length)} config(s), ${String(e.enforcement.ciWorkflows.length)} CI workflow(s)
@@ -76,73 +109,83 @@ Legend: \u2713 yes ~ partial \u2717 no \u2014 not applicable
76
109
  `),process.stdout.write(`Correction loop: ${String(e.correctionLoop.scripts.length)} script(s), ${String(e.correctionLoop.prTemplates.length)} PR template(s), ${String(e.correctionLoop.ciWorkflows.length)} CI workflow(s)
77
110
  `),process.stdout.write(`Correction checks: ${String(e.correctionLoop.maintenanceScripts.length)} maintenance script(s), ${String(e.correctionLoop.prTemplateChecks.length)} PR reminder(s), ${String(e.correctionLoop.guidanceCiWorkflows.length)} CI guidance gate(s)
78
111
 
79
- `))}function Ht(e){process.stdout.write(`## Meta-harness dimensions
112
+ `))}function sn(e){process.stdout.write(`## Meta-harness dimensions
80
113
 
81
- `);for(let t of Xr){let n=e.dimensions[t];if(n===void 0)continue;let r=Yr[t],s=n.applicableRules===0?" (no rules yet)":` (${String(n.passedRules)}/${String(n.applicableRules)} rules)`;process.stdout.write(`${r}: ${String(n.score)}/100 (${n.grade})${s}
114
+ `);for(let t of uo){let n=e.dimensions[t];if(n===void 0)continue;let s=lo[t],r=n.applicableRules===0?" (no rules yet)":` (${String(n.passedRules)}/${String(n.applicableRules)} rules)`;process.stdout.write(`${s}: ${String(n.score)}/100 (${n.grade})${r}
82
115
  `)}process.stdout.write(`
83
- `)}function Pt(e){process.stdout.write(`## Harness optimization
116
+ `)}function rn(e){process.stdout.write(`## Harness optimization
84
117
 
85
- `);let t=e.filter(r=>r.detected);if(t.length===0){process.stdout.write(`No harnesses detected \u2014 add tool adapters to evaluate optimization.
118
+ `);let t=e.filter(s=>s.detected);if(t.length===0){process.stdout.write(`No harnesses detected \u2014 add tool adapters to evaluate optimization.
86
119
 
87
- `);return}for(let r of t){let s=r.score===null?"n/a":`${String(r.score)}/100 (${r.grade})`;process.stdout.write(`${r.harness}: ${s}
88
- `),r.loadProfile!==null&&process.stdout.write(` Load profile: ${String(r.loadProfile.sharedLines)} shared + ${String(r.loadProfile.uniqueLines)} unique lines (${String(r.loadProfile.sharedPercent)}% shared)
89
- `);let o=r.checks.filter(a=>!a.passed),i=r.checks.length-o.length;process.stdout.write(` Checks: ${String(i)}/${String(r.checks.length)} passed`),r.findingsCount.error+r.findingsCount.warn>0&&process.stdout.write(`; findings: ${String(r.findingsCount.error)} error, ${String(r.findingsCount.warn)} warn`),process.stdout.write(`
120
+ `);return}for(let s of t){let r=s.score===null?"n/a":`${String(s.score)}/100 (${s.grade})`;process.stdout.write(`${s.harness}: ${r}
121
+ `),s.loadProfile!==null&&process.stdout.write(` Load profile: ${String(s.loadProfile.sharedLines)} shared + ${String(s.loadProfile.uniqueLines)} unique lines (${String(s.loadProfile.sharedPercent)}% shared)
122
+ `);let o=s.checks.filter(a=>!a.passed),i=s.checks.length-o.length;process.stdout.write(` Checks: ${String(i)}/${String(s.checks.length)} passed`),s.findingsCount.error+s.findingsCount.warn>0&&process.stdout.write(`; findings: ${String(s.findingsCount.error)} error, ${String(s.findingsCount.warn)} warn`),process.stdout.write(`
90
123
  `);for(let a of o.slice(0,5))process.stdout.write(` \u2717 ${a.label}
91
124
  `);o.length>5&&process.stdout.write(` \u2026 and ${String(o.length-5)} more
92
125
  `),process.stdout.write(`
93
- `)}let n=e.filter(r=>!r.detected);n.length>0&&process.stdout.write(`Not detected: ${n.map(r=>r.harness).join(", ")}
126
+ `)}let n=e.filter(s=>!s.detected);n.length>0&&process.stdout.write(`Not detected: ${n.map(s=>s.harness).join(", ")}
94
127
 
95
- `)}function Nt(e){process.stdout.write(`## Guidance sharing
128
+ `)}function on(e){process.stdout.write(`## Guidance sharing
96
129
 
97
130
  `),process.stdout.write(`Shared (canonical / multi-harness): ${String(e.shared.lines)} lines (${String(e.shared.percentLines)}%) across ${String(e.shared.files)} file(s)
98
131
  `),process.stdout.write(`Harness-specific: ${String(e.unique.totals.lines)} lines (${String(e.unique.totals.percentLines)}%) across ${String(e.unique.totals.files)} file(s)
99
- `);let t=Qr.filter(n=>e.unique.byHarness[n].lines>0);if(t.length>0){process.stdout.write(`
132
+ `);let t=po.filter(n=>e.unique.byHarness[n].lines>0);if(t.length>0){process.stdout.write(`
100
133
  Per-harness unique guidance:
101
- `);for(let n of t){let r=e.unique.byHarness[n];process.stdout.write(` ${n}: ${String(r.lines)} lines (${String(r.files)} file(s))
134
+ `);for(let n of t){let s=e.unique.byHarness[n];process.stdout.write(` ${n}: ${String(s.lines)} lines (${String(s.files)} file(s))
102
135
  `)}}process.stdout.write(`
103
- `)}function _t(e){if(process.stdout.write(`paniolo-scan \u2014 AI harness diagnostic
136
+ `)}function an(e){if(process.stdout.write(`paniolo-scan \u2014 AI harness diagnostic
104
137
 
105
138
  `),process.stdout.write(`Root: ${e.root}
106
139
  `),process.stdout.write(`Harnesses: ${e.harnesses.length===0?"(none detected)":e.harnesses.join(", ")}
107
140
  `),process.stdout.write(`Guidance files: ${String(e.inventory.fileCount)}
108
141
  `),process.stdout.write(`Findings: ${String(e.summary.error)} error(s), ${String(e.summary.warn)} warn(s), ${String(e.summary.info)} info
109
142
 
110
- `),Nt(e.sharing),Ft(e.intelligenceLayer),yt(e.contextBudget),Ht(e.metaHarness),ht(e.aiReview),Tt(e.harnessGapMatrix),Pt(e.harnessOptimization),process.stdout.write(`## Findings
143
+ `),on(e.sharing),nn(e.intelligenceLayer),jt(e.contextBudget),sn(e.metaHarness),Gt(e.aiReview),tn(e.harnessGapMatrix),rn(e.harnessOptimization),Wt(e.failureModeExposure),process.stdout.write(`## Findings
111
144
 
112
145
  `),e.findings.length===0)process.stdout.write(`No findings.
113
146
 
114
- `);else{let t=[...e.findings].sort((n,r)=>{let s=mt.indexOf(n.severity)-mt.indexOf(r.severity);return s!==0?s:n.ruleId.localeCompare(r.ruleId)});for(let n of t)process.stdout.write(`${gt(n)}
115
-
116
- `)}process.stdout.write(Zr)}import Ki from"node:path";function Dt(){return{copilot:{files:0,lines:0,bytes:0},cursor:{files:0,lines:0,bytes:0},codex:{files:0,lines:0,bytes:0},antigravity:{files:0,lines:0,bytes:0},claude:{files:0,lines:0,bytes:0},gemini:{files:0,lines:0,bytes:0}}}function Mt(e,t){return e.harness!==void 0?t.includes(e.harness)?[e.harness]:[]:kt.has(e.layer)?t:e.path.startsWith(".cursor/")?t.includes("cursor")?["cursor"]:[]:e.path.startsWith(".codex/")?t.includes("codex")?["codex"]:[]:e.path.startsWith(".agent/")?t.includes("antigravity")?["antigravity"]:[]:e.path==="AGENTS.md"||e.path.startsWith("docs/ai/")?t:[]}function U(e,t){return t===0?0:Math.round(e/t*1e3)/10}function $t(e,t){let n={files:0,lines:0,bytes:0},r=Dt(),s={files:0,lines:0,bytes:0},o={files:0,lines:0,bytes:0},i=[];for(let a of e){let c=Mt(a,t);if(c.length===0)continue;o.files+=1,o.lines+=a.lines,o.bytes+=a.bytes;let u=es(a,c),p=u?"shared":"unique";if(i.push({path:a.path,lines:a.lines,scope:p,harnesses:c}),u)n.files+=1,n.lines+=a.lines,n.bytes+=a.bytes;else{let[m]=c;m!==void 0&&(r[m].files+=1,r[m].lines+=a.lines,r[m].bytes+=a.bytes),s.files+=1,s.lines+=a.lines,s.bytes+=a.bytes}}return{totals:o,shared:{...n,percentLines:U(n.lines,o.lines)},unique:{byHarness:r,totals:{...s,percentLines:U(s.lines,o.lines)}},files:i}}import E from"node:path";import{access as bo}from"node:fs/promises";async function y(e){try{return await bo(e),!0}catch{return!1}}function Ot(e){return e===null?!1:e["chat.agentSkillsLocations"]!==void 0||e["chat.agentFilesLocations"]!==void 0||e["chat.useCustomAgentHooks"]===!0}import{readFile as Ao}from"node:fs/promises";function Gt(e){if(e==="true")return!0;if(e==="false")return!1;if(e==="null")return null;if(e.startsWith('"')&&e.endsWith('"'))return e.slice(1,-1);let t=Number(e);return Number.isNaN(t)?e:t}function jt(e){let t={},n=/"([^"]+)"\s*:\s*(true|false|null|\d+(?:\.\d+)?|"[^"]*")/g;for(let[,r,s]of e.matchAll(n))r===void 0||s===void 0||(t[r]=Gt(s));return Object.keys(t).length===0?null:t}function pe(e){try{let t=JSON.parse(e);if(h(t))return t}catch{}return jt(e)}async function Wt(e){try{let t=await Ao(e,"utf8");return pe(t)}catch{return null}}async function fe(e){let t=new Set;await y(E.join(e,".github/copilot-instructions.md"))&&t.add("copilot"),await y(E.join(e,".github/hooks"))&&t.add("copilot");let n=await Wt(E.join(e,".vscode/settings.json"));return Ot(n)&&(t.add("cursor"),t.add("copilot")),await y(E.join(e,".cursor"))&&t.add("cursor"),await y(E.join(e,".codex/config.toml"))&&t.add("codex"),await y(E.join(e,".codex/hooks.json"))&&t.add("codex"),await y(E.join(e,".codex/agents"))&&t.add("codex"),await y(E.join(e,".agent/workflows"))&&t.add("antigravity"),await y(E.join(e,".agent/README.md"))&&t.add("antigravity"),await y(E.join(e,"CLAUDE.md"))&&t.add("claude"),await y(E.join(e,".claude/settings.json"))&&t.add("claude"),await y(E.join(e,"GEMINI.md"))&&t.add("gemini"),[...t].sort()}function me(e){return Math.ceil(e/4)}function P(e,t){return{path:e.path,lines:e.lines,bytes:e.bytes,estimatedTokens:me(e.bytes),reason:t}}function Vt(e,t){let n=e.fileContents.get(t.path);return n===void 0?!1:/^alwaysApply:\s*true\s*$/im.test(n)||/^always_apply:\s*true\s*$/im.test(n)}function q(e,t){return e.files.find(n=>n.path===t)??null}function Ut(e,t){let n=[];if(t==="copilot"){let r=q(e,".github/copilot-instructions.md");r!==null&&n.push(P(r,"Copilot workspace instructions are loaded by Copilot Chat."))}if(t==="cursor")for(let r of e.files)r.path.startsWith(".cursor/rules/")&&Vt(e,r)&&n.push(P(r,"Cursor rule declares alwaysApply: true."));if(t==="codex"){let r=q(e,"AGENTS.md");r!==null&&n.push(P(r,"Root AGENTS.md is the Codex repo instruction entry."));for(let s of e.files)s.path.startsWith(".codex/")&&s.layer==="adapter"&&n.push(P(s,"Codex adapter guidance under .codex/."))}if(t==="antigravity"){let r=q(e,".agent/README.md");r!==null&&n.push(P(r,"Antigravity workspace adapter README."))}if(t==="claude"){let r=q(e,"CLAUDE.md");r!==null&&n.push(P(r,"Claude Code root instruction file."))}if(t==="gemini"){let r=q(e,"GEMINI.md");r!==null&&n.push(P(r,"Gemini root instruction file."))}return n.toSorted((r,s)=>r.path.localeCompare(s.path))}function qt(e,t){if(!e.harnesses.includes(t))return{harness:t,detected:!1,files:[],totalLines:0,totalBytes:0,estimatedTokens:0,maxRecommendedLines:250,status:"ok"};let r=Ut(e,t),s=r.reduce((i,a)=>i+a.lines,0),o=r.reduce((i,a)=>i+a.bytes,0);return{harness:t,detected:!0,files:r,totalLines:s,totalBytes:o,estimatedTokens:me(o),maxRecommendedLines:250,status:s>250?"high":"ok"}}function Bt(e){return{harnesses:V.map(t=>qt(e,t)),maxRecommendedLines:250,maxRecommendedFileLines:150}}function Kt(e,t){let n={sharedLines:0,uniqueLines:0,totalLines:0,sharedPercent:0,uniquePercent:0},r={copilot:{...n},cursor:{...n},codex:{...n},antigravity:{...n},claude:{...n},gemini:{...n}};for(let s of t){let o=e.unique.byHarness[s].lines,i=e.shared.lines,a=i+o;r[s]={sharedLines:i,uniqueLines:o,totalLines:a,sharedPercent:U(i,a),uniquePercent:U(o,a)}}return r}function Jt(e,t){let n={error:0,warn:0,info:0};for(let r of e)r.harnesses.includes(t)&&(r.severity==="error"?n.error+=1:r.severity==="warn"?n.warn+=1:n.info+=1);return n}var is=[{min:85,grade:"excellent"},{min:70,grade:"good"},{min:50,grade:"fair"},{min:0,grade:"poor"}],De={error:12,warn:5,info:1},as=40;function zt(e){let t=e.error*De.error+e.warn*De.warn+e.info*De.info;return Math.min(t,as)}import he from"node:path";function N(e,t){return e.files.some(n=>n.path===t)}function Yt(e,t){return e.fileContents.get(t)??null}function vo(e,t){return e.files.find(r=>r.path===t)?.lines??null}function Eo(e){return e.includes("AGENTS.md")||e.includes("docs/ai/rules.md")}function B(e){return e.files.some(t=>t.path.startsWith("skills/"))}function ge(e){return e.files.some(t=>t.path.startsWith("agents/"))}function Xt(e,t){return e.settings?.[t]===!0}function Me(e,t){let n=vo(e,t);return n===null?!1:n<=$}function $e(e,t){let n=Yt(e,t);return n===null?!1:Eo(n)}function Qt(e){let t=Yt(e,".agent/README.md");return t===null?!1:/\.agent\/workflows\/|workflows\//i.test(t)&&/(workflow|playbook|slash command|mission|turbo)/i.test(t)}function K(e,t,n){let r=e.settings?.[t];if(h(r)&&Object.keys(r).some(a=>a.startsWith(n)))return!0;if(e.settingsRaw===null)return!1;let s=t.replaceAll(".",String.raw`\.`);return new RegExp(`"${s}"\\s*:\\s*\\{[^}]*"${n}[^"]*"`).test(e.settingsRaw)}var cs={copilot:[{id:"copilot-instructions",label:"Copilot instructions file present",weight:15,run:({context:e})=>N(e,".github/copilot-instructions.md")},{id:"copilot-references-shared",label:"Copilot instructions reference shared layers",weight:15,run:({context:e})=>$e(e,".github/copilot-instructions.md")},{id:"copilot-adapter-thin",label:"Copilot instructions stay thin",weight:10,run:({context:e})=>Me(e,".github/copilot-instructions.md")},{id:"copilot-skills-location",label:"chat.agentSkillsLocations points at skills/",weight:15,run:({vscode:e})=>K(e,"chat.agentSkillsLocations","skills")},{id:"copilot-agents-location",label:"chat.agentFilesLocations points at agents/",weight:15,run:({vscode:e})=>K(e,"chat.agentFilesLocations","agents")},{id:"copilot-hooks-enabled",label:"Custom agent hooks enabled when .github/hooks/ exists",weight:15,run:({vscode:e})=>!e.hooksDirExists||Xt(e,"chat.useCustomAgentHooks")},{id:"copilot-shared-skills",label:"Shared skills/ tree present",weight:8,run:({context:e})=>B(e)},{id:"copilot-shared-agents",label:"Shared agents/ tree present",weight:7,run:({context:e})=>ge(e)}],cursor:[{id:"cursor-rules-or-settings",label:"Cursor rules or VS Code agent settings present",weight:20,run:({context:e,vscode:t})=>e.files.some(n=>n.path.startsWith(".cursor/rules/"))||K(t,"chat.agentSkillsLocations","skills")},{id:"cursor-skills-location",label:"chat.agentSkillsLocations points at skills/",weight:20,run:({vscode:e})=>K(e,"chat.agentSkillsLocations","skills")},{id:"cursor-agents-location",label:"chat.agentFilesLocations points at agents/",weight:20,run:({vscode:e})=>K(e,"chat.agentFilesLocations","agents")},{id:"cursor-hooks-enabled",label:"Custom agent hooks enabled when .github/hooks/ exists",weight:15,run:({vscode:e})=>!e.hooksDirExists||Xt(e,"chat.useCustomAgentHooks")},{id:"cursor-shared-skills",label:"Shared skills/ tree present",weight:13,run:({context:e})=>B(e)},{id:"cursor-shared-agents",label:"Shared agents/ tree present",weight:12,run:({context:e})=>ge(e)}],codex:[{id:"codex-config-surface",label:"Codex config surface present (.codex/ or nested AGENTS.md)",weight:25,run:async({context:e})=>e.files.some(t=>t.path.startsWith(".codex/"))?!0:await y(he.join(e.repoRoot,"api/AGENTS.md"))||await y(he.join(e.repoRoot,"react/AGENTS.md"))||await y(he.join(e.repoRoot,"shared/AGENTS.md"))},{id:"codex-hooks",label:"Codex hooks.json present",weight:20,run:({context:e})=>y(he.join(e.repoRoot,".codex/hooks.json"))},{id:"codex-agents-wrappers",label:"Codex agent wrappers present",weight:20,run:({context:e})=>y(he.join(e.repoRoot,".codex/agents"))},{id:"codex-shared-entry",label:"Root AGENTS.md present",weight:20,run:({context:e})=>N(e,"AGENTS.md")},{id:"codex-shared-skills",label:"Shared skills/ tree present",weight:8,run:({context:e})=>B(e)},{id:"codex-shared-rules",label:"Canonical rules doc present",weight:7,run:({context:e})=>N(e,"docs/ai/rules.md")}],antigravity:[{id:"antigravity-workflows",label:"Workflow playbooks present (.agent/workflows/)",weight:35,run:({context:e})=>e.files.some(t=>t.path.startsWith(".agent/workflows/"))},{id:"antigravity-readme",label:".agent/README.md documents workflow layout",weight:15,run:({context:e})=>Qt(e)},{id:"antigravity-shared-entry",label:"Root AGENTS.md present",weight:20,run:({context:e})=>N(e,"AGENTS.md")},{id:"antigravity-shared-skills",label:"Shared skills/ tree present",weight:15,run:({context:e})=>B(e)},{id:"antigravity-ai-system-doc",label:"AI system layout doc present",weight:15,run:({context:e})=>N(e,"docs/ai/ai-system.md")}],claude:[{id:"claude-adapter",label:"CLAUDE.md adapter present",weight:25,run:({context:e})=>N(e,"CLAUDE.md")},{id:"claude-references-shared",label:"CLAUDE.md references shared layers",weight:25,run:({context:e})=>$e(e,"CLAUDE.md")},{id:"claude-adapter-thin",label:"CLAUDE.md stays thin",weight:20,run:({context:e})=>Me(e,"CLAUDE.md")},{id:"claude-shared-skills",label:"Shared skills/ tree present",weight:15,run:({context:e})=>B(e)},{id:"claude-skills-index",label:"Skill index doc for prose discovery",weight:8,run:({context:e})=>N(e,"docs/ai/available-skills.md")},{id:"claude-shared-agents",label:"Shared agents/ tree present",weight:7,run:({context:e})=>ge(e)}],gemini:[{id:"gemini-adapter",label:"GEMINI.md adapter present",weight:30,run:({context:e})=>N(e,"GEMINI.md")},{id:"gemini-references-shared",label:"GEMINI.md references shared layers",weight:25,run:({context:e})=>$e(e,"GEMINI.md")},{id:"gemini-adapter-thin",label:"GEMINI.md stays thin",weight:20,run:({context:e})=>Me(e,"GEMINI.md")},{id:"gemini-shared-skills",label:"Shared skills/ tree present",weight:15,run:({context:e})=>B(e)},{id:"gemini-shared-agents",label:"Shared agents/ tree present",weight:10,run:({context:e})=>ge(e)}]};async function Zt(e,t){let n=cs[e],r=[];for(let s of n){let o=await s.run(t);r.push({id:s.id,label:s.label,passed:o,weight:s.weight})}return r}function en(e){let t=e.reduce((r,s)=>r+s.weight,0);if(t===0)return 0;let n=e.filter(r=>r.passed).reduce((r,s)=>r+s.weight,0);return Math.round(n/t*100)}function tn(e){for(let{min:t,grade:n}of is)if(e>=t)return n;return"poor"}async function nn(e,t,n,r,s,o){if(!t.harnesses.includes(e))return{harness:e,detected:!1,score:null,grade:"not-detected",checks:[],findingsCount:{error:0,warn:0,info:0},loadProfile:null};let c=await Zt(e,{context:t,vscode:n,harness:e}),u=Jt(r,e),p=en(c),m=zt(u),I=Math.max(0,Math.min(100,p-m));return{harness:e,detected:!0,score:I,grade:tn(I),checks:c,findingsCount:u,loadProfile:o[e]??null}}async function rn(e,t,n,r){let s=Kt(r,e.harnesses),o=[];for(let i of V){let a=await nn(i,e,t,n,r,s);o.push(a)}return o}function sn(e){return!Number.isFinite(e)||e<0?0:e<=1?e:e<=10?e/10:e<=100?e/100:1}function ls(e,t){return e>=t?1:0}function us(e,t){return e<=t?1:e===0?0:t/e}function ds(e,t){if(t<=0)return 0;let n=e/t;return Math.max(0,Math.min(1,n))}function on(e,t,n){return e>=t&&e<=n?1:e<t?t===0?0:e/t:e===0?0:n/e}function an(e){if(e.curve===void 0)return sn(e.rawScore??0);let t=e.measuredValue??0,n=e.referenceValue,r=typeof n=="number"?n:0;switch(e.curve){case"binary":return ls(t,r);case"asymptoticDecay":return us(t,r);case"ratio":return ds(t,r);case"goldilocks":{let[s,o]=Array.isArray(n)?n:[0,r];return on(t,s??0,o??0)}}}function cn(e,t){let n={};for(let s of Object.keys(t.dimensions))n[s]={weightedSum:0,weightSum:0,ran:!1,passedRules:0,applicableRules:0};for(let s of e){let o=n[s.dimension];if(!o)continue;o.ran=!0,o.applicableRules+=1;let i=an(s);i===1&&(o.passedRules+=1);let a=s.weight??t.check_weights[s.checkId]??1;!Number.isFinite(a)||a<=0||(o.weightedSum+=i*a,o.weightSum+=a)}let r={};for(let[s,o]of Object.entries(t.dimensions)){let i=n[s];if(!i||!i.ran){r[s]={status:"not_run",score:null,grade:"not-run",passedRules:0,applicableRules:0};continue}let a=i.weightSum>0?i.weightedSum/i.weightSum*o.max_score:0,c=Number.isFinite(a)?Math.round(a):0;r[s]={status:"run",score:c,grade:le(c),passedRules:i.passedRules,applicableRules:i.applicableRules}}return r}function ln(e,t){let n=0,r=0;for(let[s,o]of Object.entries(t.dimensions)){let i=e[s];if(!i||i.status!=="run"||i.score===null)continue;let a=Number(o.weight);!Number.isFinite(a)||a<=0||(n+=i.score/o.max_score*a,r+=a)}return r===0?0:Math.round(n/r*100)}var Io=new Set(["deep","session"]);function un(e){for(let[t,n]of Object.entries(e))if(Io.has(t)&&n.status==="run")return"core+extended";return"core"}import{readFileSync as Lo}from"node:fs";import{dirname as To,join as ps}from"node:path";import{fileURLToPath as Fo}from"node:url";var Ho=Fo(import.meta.url),fs=To(Ho);function Oe(e){return typeof e=="object"&&e!==null}function Po(e){return Oe(e)&&Oe(e.dimensions)&&Oe(e.check_weights)}function No(e){return Oe(e)}function ms(e,t){let n=JSON.parse(Lo(e,"utf8"));if(!t(n))throw new Error(`Invalid standards file: ${e}`);return n}var dn=ms(ps(fs,"standards","weights.json"),Po),pn=ms(ps(fs,"standards","reference-thresholds.json"),No);function fn(e,t,n,r,s){if(n.totals.lines>0){let u=typeof pn.sharing_target_percent=="number"?pn.sharing_target_percent:65;e.push({checkId:"sharing-percent",dimension:"sharing",curve:"ratio",measuredValue:n.shared.percentLines,referenceValue:u})}let o=r.filter(u=>u.detected&&u.score!==null);if(o.length>0){let u=o.reduce((p,m)=>p+(m.score??0),0)/o.length;e.push({checkId:"harness-optimization-avg",dimension:"harnessWiring",curve:"ratio",measuredValue:u,referenceValue:100})}let i=cn(e,dn),a=ln(i,dn),c=un(i);return{profile:"meta-harness",total_score:a,score_scope:c,dimensions:i}}import{readFile as Go}from"node:fs/promises";import hn from"node:path";import{readdir as _o}from"node:fs/promises";import Do from"node:path";async function Ge(e){let t=[".md",".mdc"];function n(o){return t.some(i=>o.endsWith(i))}let r=[],s=[];try{s=await _o(e,{withFileTypes:!0})}catch{return r}for(let o of s){if(o.isSymbolicLink())continue;let i=Do.join(e,o.name);o.isDirectory()?r.push(...await Ge(i)):o.isFile()&&n(i)&&r.push(i)}return r}import{readFile as Mo,stat as $o}from"node:fs/promises";import Oo from"node:path";function mn(e){return e.length===0?0:e.split(`
117
- `).length}async function gn(e,t,n,r){let s=Oo.join(e,t);try{if(!(await $o(s)).isFile())return null;let i=await Mo(s,"utf8"),a=mn(i),c={path:t,layer:n,lines:a,bytes:Buffer.byteLength(i,"utf8")};return r!==void 0&&(c.harness=r),c}catch{return null}}var jo=["AGENTS.md","docs/ai/rules.md","docs/ai/ai-system.md","docs/ai/available-skills.md","docs/ai/hooks.md"],Wo=[{path:"CLAUDE.md",harness:"claude"},{path:"GEMINI.md",harness:"gemini"},{path:".github/copilot-instructions.md",harness:"copilot"},{path:".agent/README.md",harness:"antigravity"}],Vo=[{dir:"skills",layer:"skills"},{dir:"agents",layer:"agents"},{dir:".cursor/rules",layer:"adapter",harness:"cursor"},{dir:".agent/workflows",layer:"workflows",harness:"antigravity"},{dir:".codex",layer:"adapter",harness:"codex"},{dir:"docs/ai",layer:"shared"}];async function ye(e){let t=[],n=new Map,r=new Set;async function s(o,i,a){let c=o.replaceAll("\\","/");if(r.has(c))return;let u=await gn(e,c,i,a);if(u===null)return;r.add(c),t.push(u);let p=hn.join(e,c);try{let m=await Go(p,"utf8");n.set(c,m)}catch{}}for(let o of jo)await s(o,"shared");for(let o of Wo)await s(o.path,"adapter",o.harness);for(let{dir:o,layer:i,harness:a}of Vo){let c=hn.join(e,o),u=await Ge(c);for(let p of u){let m=hn.relative(e,p).replaceAll("\\","/");await s(m,i,a)}}return t.sort((o,i)=>o.path.localeCompare(i.path)),{files:t,contents:n}}import{readFile as Uo}from"node:fs/promises";import gs from"node:path";import{fileURLToPath as qo}from"node:url";function yn(e){return typeof e=="object"&&e!==null&&"version"in e&&typeof e.version=="string"}async function kn(){let e=gs.resolve(gs.dirname(qo(import.meta.url)),"../package.json"),t=await Uo(e,"utf8"),n=JSON.parse(t);if(!yn(n))throw new Error("package.json is missing a string version field");return{version:n.version}}var hs=null;function ys(){return hs??=kn(),hs}import Jo from"node:path";var ks=new Set([".git","node_modules","dist","coverage"]),Ss=[/^tsconfig(?:\..+)?\.json$/],ws=[/^eslint\.config\.[cm]?[jt]s$/,/^\.eslintrc(?:\..+)?$/,/^\.oxlintrc(?:\..+)?$/,/^biome\.jsonc?$/,/^ruff\.toml$/,/^\.ruff\.toml$/],xs=[/^\.prettierrc(?:\..+)?$/,/^\.markdownlint(?:rc)?(?:\..+)?$/],Rs=[/^vitest\.config\.[cm]?[jt]s$/,/^jest\.config\.[cm]?[jt]s$/,/^playwright\.config\.[cm]?[jt]s$/,/^cypress\.config\.[cm]?[jt]s$/],Cs=[/^package\.json$/,/^pyproject\.toml$/,/^Cargo\.toml$/,/^go\.mod$/],Sn=/(scan:self|check:ai-system|check:md|lint:md|check:links|qmd|markdownlint|textlint|remark|cspell|paniolo-scan)/i,bs=/(correction loop|intelligence layer|diagnostic rule|rules catalog|canonical rules|paired skill|guidance hygiene|adapters stayed thin|json output keys are stable)/i;import{readFile as Bo,stat as Ko}from"node:fs/promises";import As from"node:path";function vs(e){return e.length===0?0:e.split(`
118
- `).length}async function Es(e,t){try{return(await Ko(As.join(e,t))).isFile()}catch{return!1}}async function _(e,t){try{return await Bo(As.join(e,t),"utf8")}catch{return null}}function je(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function re(e,t){return t.some(n=>n.test(e))}function Is(e){return/^\.github\/workflows\/.+\.ya?ml$/.test(e)}function Ls(e){return e===".github/PULL_REQUEST_TEMPLATE.md"||/^\.github\/PULL_REQUEST_TEMPLATE\/.+\.md$/.test(e)||/^docs\/pull_request_template\.md$/i.test(e)}function We(e,t){return Sn.test(`${e}
119
- ${t}`)}function Ve(e){return Sn.test(e.commands.join(`
120
- `))}function Ts(e){return bs.test(e)}function Fs(e){let t=e.toLowerCase();return t.includes("naming")||t.includes("comment")||t.includes("local-context")||t.includes("codebase-map")}function wn(e){let t=Jo.posix.basename(e);return re(t,Ss)?{path:e,kind:"typecheck",capabilities:["typecheck"]}:re(t,ws)?{path:e,kind:"lint",capabilities:["lint"]}:re(t,xs)?{path:e,kind:"format",capabilities:["format"]}:re(t,Rs)?{path:e,kind:"test",capabilities:["test"]}:re(t,Cs)?{path:e,kind:"manifest",capabilities:["project-manifest"]}:null}import{readdir as zo}from"node:fs/promises";import Hs from"node:path";async function Ue(e,t=""){let n=Hs.join(e,t),r=[];try{r=await zo(n,{withFileTypes:!0})}catch{return[]}let s=[];for(let o of r){if(o.isSymbolicLink()||ks.has(o.name))continue;let i=Hs.join(t,o.name).replaceAll("\\","/");o.isDirectory()?s.push(...await Ue(e,i)):o.isFile()&&s.push(i)}return s}function xn(e){let t=e.toLowerCase();return t==="docs/architecture.md"||t==="docs/overview.md"||t==="docs/meta-harness.md"||t==="docs/ai/codebase-map.md"||t==="docs/ai/ai-system.md"||t.includes("/adr")||t.includes("architecture")||t.includes("codebase-map")||t.includes("design")}function Rn(e){let t=e.toLowerCase();return t==="docs/ai/codebase-map.md"||t==="docs/ai/ai-system.md"||t==="docs/overview.md"||t.endsWith("/adr/index.md")||t.endsWith("/adrs/index.md")}function ke(e){if(!je(e))return{};let t={};for(let[n,r]of Object.entries(e))typeof r=="string"&&(t[n]=r);return t}function Cn(e){if(e===null)return{path:null,scripts:{},dependencies:[],devDependencies:[]};try{let t=JSON.parse(e);if(!je(t))return{path:"package.json",scripts:{},dependencies:[],devDependencies:[]};let n=ke(t.scripts),r=Object.keys(ke(t.dependencies)).toSorted(),s=Object.keys(ke(t.devDependencies)).toSorted();return{path:"package.json",scripts:n,dependencies:r,devDependencies:s}}catch{return{path:"package.json",scripts:{},dependencies:[],devDependencies:[]}}}import Yo from"node:path";import{stat as Xo}from"node:fs/promises";async function G(e,t,n,r,s){let o=Yo.join(e,t),i=await Xo(o),a=await _(e,t),c={path:t,kind:n,layer:r,capabilities:s,bytes:i.size};return a!==null&&(c.lines=vs(a)),c}function bn(e){let t=[],n=/^\s*-\s*run:\s*(.+)$/,r=/^\s*-\s*run:\s*[>|]/,s=!1;for(let o of e.split(/\r?\n/)){let i=o.match(n);if(i!==null){t.push(i[1]?.trim()??""),s=!1;continue}if(r.test(o)){s=!0;continue}s&&(/^\s{6,}\S/.test(o)?t.push(o.trim()):/^\s*-\s/.test(o)&&(s=!1))}return t.filter(o=>o.length>0)}async function An(e,t){let n=await _(e,t);return n===null?null:{path:t,commands:bn(n),content:n}}function qe(e){let t=Object.keys(e.packageJson.scripts),n=t.filter(i=>/(^|:)(typecheck|lint|format|check)(:|$)/i.test(i)),r=t.filter(i=>/(^|:)(test|e2e)(:|$)/i.test(i)),s=t.filter(i=>We(i,e.packageJson.scripts[i]??"")),o=e.workflows.filter(Ve).map(i=>i.path).toSorted();return{surfaces:e.surfaces,enforcement:{scripts:n.toSorted(),configs:e.configs.filter(i=>i.kind==="typecheck"||i.kind==="lint").map(i=>i.path).toSorted(),ciWorkflows:e.workflows.filter(i=>/(typecheck|lint|format|check)/i.test(i.commands.join(`
121
- `))).map(i=>i.path).toSorted()},validation:{scripts:r.toSorted(),configs:e.configs.filter(i=>i.kind==="test").map(i=>i.path).toSorted(),ciWorkflows:e.workflows.filter(i=>/(npm test|npm run test|vitest|jest|playwright|cypress)/i.test(i.commands.join(`
122
- `))).map(i=>i.path).toSorted()},memory:{docs:e.memoryDocs.toSorted(),indexes:e.memoryIndexes.toSorted()},localContext:{conventions:e.localContextConventions.toSorted(),nestedAgentsFiles:e.nestedAgentsFiles.toSorted()},correctionLoop:{scripts:s.toSorted(),prTemplates:e.prTemplates.toSorted(),ciWorkflows:o,maintenanceScripts:e.guidanceMaintenanceScripts.toSorted(),prTemplateChecks:e.aiHarnessPrTemplates.toSorted(),guidanceCiWorkflows:o}}}async function vn(e){let t=await Ue(e),n=Cn(await _(e,"package.json")),r=[],s=[],o=[],i=[],a=[],c=[],u=[],p=[],m=[],I={customChecker:!1,packageScript:!1,lintRules:!1,stopHook:!1,guidance:!1};I.packageScript=Object.entries(n.scripts).some(([d,k])=>/(^|:)(lint:jsdoc|check:jsdoc)(:|$)/i.test(d)||/find-missing-jsdoc|check-jsdoc-files/i.test(k));for(let d of t){let k=wn(d);if(k!==null){let S={...k},A=await _(e,d);k.kind==="typecheck"&&A!==null&&/"strict"\s*:\s*true/.test(A)&&(S.capabilities=[...k.capabilities,"strict-typecheck"]),k.kind==="lint"&&A!==null&&/jsdoc\/require-(returns|param)/i.test(A)&&(I.lintRules=!0),r.push(S),m.push(await G(e,d,"enforcement","config",S.capabilities))}if(Is(d)){let S=await An(e,d);if(S!==null){s.push(S);let A=await G(e,d,"workflow","automation",["ci-workflow"]);m.push(A)}}if(Ls(d)){o.push(d);let S=await _(e,d);S!==null&&Ts(S)&&i.push(d);let A=await G(e,d,"automation","pull-request",["pr-template"]);m.push(A)}if(d.endsWith(".md")&&xn(d)&&(a.push(d),Rn(d)&&c.push(d),m.push(await G(e,d,"memory","docs",["memory"]))),d.endsWith(".md")&&Fs(d)&&u.push(d),(d==="scripts/find-missing-jsdoc/analyzeFile.ts"||d==="scripts/find-missing-jsdoc/check-jsdoc-files.bun.ts")&&(I.customChecker=!0),(d==="docs/ai/code-comment-best-practices.md"||d==="skills/code-comment-best-practices/SKILL.md")&&(I.guidance=!0),d.startsWith(".github/hooks/")&&d.endsWith(".json")){let S=await _(e,d);S!==null&&/lint-on-stop|find-missing-jsdoc|jsdoc/i.test(S)&&(I.stopHook=!0)}if(d.endsWith("/AGENTS.md")){p.push(d);let S=await G(e,d,"local-context","nested-entry",["nested-agents-md"]);m.push(S)}}return n.path!==null&&await Es(e,n.path)&&m.push(await G(e,n.path,"automation","project",["package-scripts"])),{packageJson:n,configs:r.toSorted((d,k)=>d.path.localeCompare(k.path)),workflows:s.toSorted((d,k)=>d.path.localeCompare(k.path)),prTemplates:o,guidanceMaintenanceScripts:Object.entries(n.scripts).filter(([d,k])=>We(d,k)).map(([d])=>d).toSorted(),aiHarnessPrTemplates:i.toSorted(),guidanceCiWorkflows:s.filter(d=>Ve(d)).map(d=>d.path).toSorted(),memoryDocs:a,memoryIndexes:c.toSorted(),localContextConventions:u.toSorted(),nestedAgentsFiles:p,surfaces:m.toSorted((d,k)=>d.path.localeCompare(k.path)),jsdocEnforcement:I}}import ni from"node:path";import{readdir as Qo}from"node:fs/promises";import Zo from"node:path";async function En(e,t){let n=[];try{n=await Qo(Zo.join(e,t),{withFileTypes:!0})}catch{return[]}return n.filter(r=>r.isFile()).map(r=>`${t}/${r.name}`)}import{readFile as ei,stat as ti}from"node:fs/promises";import Gs from"node:path";var Ps=[".claude/settings.json",".claude/settings.local.json"],Ns=[".env",".env.local",".env.development",".env.development.local",".env.production",".env.production.local",".env.test"],_s=[".gitleaks.toml",".github/gitleaks.toml",".github/secret_scanning.yml",".github/secret_scanning.yaml"],Ds=[".pre-commit-config.yaml",".pre-commit-config.yml"],Ms=["config/worker-vars.list","config/env-secrets.dev.list","config/env-secrets.staging.list","config/env-secrets.production.list","scripts/env/run-with-env/run-with-env.bun.ts"],$s=/gitleaks|trufflehog|detect-secrets|ggshield/i,Os=/(?:\.\/)?(?:[\w.-]+\/)+[\w.-]+\.(?:tsx?|mts|cts|mjs|cjs|js|sh|bash|py)/g;async function L(e,t){try{return await ei(Gs.join(e,t),"utf8")}catch{return null}}async function D(e,t){try{return(await ti(Gs.join(e,t))).isFile()}catch{return!1}}function j(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Be(e){try{return{ok:!0,value:JSON.parse(e)}}catch{return{ok:!1,value:null}}}function js(e){let{permissions:t}=e;return!j(t)||!Array.isArray(t.allow)?[]:t.allow.filter(n=>typeof n=="string")}function Ws(e){let{permissions:t}=e;return!j(t)||typeof t.defaultMode!="string"?null:t.defaultMode}function Ke(e){let t=e.match(Os)??[];return[...new Set(t.map(n=>n.replace(/^\.\//,"")))]}async function Vs(e,t,n){let r=await D(e,n),s=r?await L(e,n):null;return{reference:{source:t,path:n,exists:r},content:s}}async function In(e,t){for(let n of await En(e,".claude/hooks")){let r=await L(e,n);r!==null&&t.push({source:n,path:n,isStop:/stop/i.test(ni.posix.basename(n)),content:r})}}async function Ln(e){for(let t of Ms)if(await D(e,t))return!0;return!1}function Tn(e){let t=e.hooks;if(t===void 0)return{hooks:[],malformed:!1};if(!j(t))return{hooks:[],malformed:!0};let n=[],r=!1;for(let[s,o]of Object.entries(t)){if(!Array.isArray(o)){r=!0;continue}for(let i of o){if(!j(i)||!Array.isArray(i.hooks)){r=!0;continue}for(let a of i.hooks){if(!j(a)||typeof a.command!="string"){r=!0;continue}n.push({event:s,command:a.command})}}}return{hooks:n,malformed:r}}async function Fn(e,t){let n=await L(e,t);if(n===null)return null;let{ok:r,value:s}=Be(n);if(!r||!j(s))return{path:t,valid:!1,allow:[],defaultMode:null,hooks:[],hooksMalformed:!1};let{hooks:o,malformed:i}=Tn(s);return{path:t,valid:!0,allow:js(s),defaultMode:Ws(s),hooks:o,hooksMalformed:i}}async function Hn(e){let t=".codex/hooks.json",n=await L(e,t);if(n===null)return null;let{ok:r,value:s}=Be(n);if(!r)return{path:t,valid:!1,referencedScripts:[]};let o=[];for(let i of Ke(JSON.stringify(s))){let a=await D(e,i);o.push({source:t,path:i,exists:a})}return{path:t,valid:!0,referencedScripts:o}}async function Pn(e){let t=[];for(let n of Ns)await D(e,n)&&t.push(n);return t}async function Nn(e,t){let n=[],r=[],s=t.flatMap(o=>o.hooks.map(i=>({surface:o,hook:i})));for(let{surface:o,hook:i}of s){let a=`${o.path} (${i.event} hook)`,c=[i.command];for(let u of Ke(i.command)){let{reference:p,content:m}=await Vs(e,a,u);r.push(p),m!==null&&c.push(m)}n.push({source:a,path:null,isStop:i.event==="Stop",content:c.join(`
123
- `)})}return{hookScripts:n,referencedClaudeScripts:r}}async function _n(e){let t=[];for(let n of _s)await D(e,n)&&t.push(n);for(let n of Ds){let r=await L(e,n);r!==null&&$s.test(r)&&t.push(n)}return t}async function Se(e){let t=[];for(let u of Ps){let p=await Fn(e,u);p!==null&&t.push(p)}let{hookScripts:n,referencedClaudeScripts:r}=await Nn(e,t);await In(e,n);let[s,o,i,a,c]=await Promise.all([Hn(e),L(e,".gitignore"),Pn(e),_n(e),Ln(e)]);return{claudeSettings:t,referencedClaudeScripts:r,hookScripts:n,codexHooks:s,gitignore:o,envFilesPresent:i,secretScanningFiles:a,usesKeyringSecrets:c}}import{readFile as ri,stat as si}from"node:fs/promises";import Us from"node:path";async function J(e){let t=Us.join(e,".github/hooks"),n=!1;try{n=(await si(t)).isDirectory()}catch{n=!1}let r=Us.join(e,".vscode/settings.json"),s=null,o=null;try{let i=await ri(r,"utf8");o=i,s=pe(i)}catch{s=null,o=null}return{settings:s,settingsRaw:o,hooksDirExists:n}}function Dn(e){let t=e.contextBudget;if(t===void 0)return{findings:[],records:[]};let n=[],r=[];for(let s of t.harnesses)if(s.detected)for(let o of s.files)r.push({checkId:"adapter-context-budget",dimension:"maintainability",curve:"asymptoticDecay",measuredValue:o.lines,referenceValue:t.maxRecommendedFileLines}),!(o.lines<=t.maxRecommendedFileLines)&&n.push({ruleId:"adapter-context-budget",severity:"info",message:`${o.path} contributes ${String(o.lines)} always-loaded lines for ${s.harness}; recommended maximum per file is ${String(t.maxRecommendedFileLines)}.`,file:o.path,line:null,harnesses:[s.harness],hint:"Split detailed guidance into linked docs and keep always-loaded instruction files compact."});return{findings:n,records:r}}function Mn(e){let t=e.contextBudget;if(t===void 0)return{findings:[],records:[]};let n=[],r=[];for(let s of t.harnesses)s.detected&&(r.push({checkId:"always-loaded-budget",dimension:"maintainability",curve:"asymptoticDecay",measuredValue:s.totalLines,referenceValue:s.maxRecommendedLines}),s.status!=="ok"&&n.push({ruleId:"always-loaded-budget",severity:"info",message:`${s.harness} always-loaded context is ${String(s.totalLines)} lines; recommended maximum is ${String(s.maxRecommendedLines)}.`,file:null,line:null,harnesses:[s.harness],hint:"Keep root adapters as short indexes and move deep guidance into linked docs, skills, agents, or workflows."}));return{findings:n,records:r}}async function $n(e){return e.files.some(n=>n.path.startsWith("agents/"))?await ee(e.repoRoot,".github/agents")?{findings:[{ruleId:"no-duplicate-agent-trees",severity:"error",message:".github/agents/ duplicates root agents/; use agents/ only.",file:".github/agents",line:null,harnesses:[],hint:"Remove .github/agents/ and keep canonical agents/ at the repo root."}],records:[]}:{findings:[],records:[]}:{findings:[],records:[]}}async function On(e){if(!e.files.some(s=>s.path.startsWith("skills/")))return{findings:[],records:[]};let n=[],r=[".github/skills",".cursor/skills"];for(let s of r)await ee(e.repoRoot,s)&&n.push({ruleId:"no-duplicate-skill-trees",severity:"error",message:`${s}/ duplicates root skills/; use skills/ only.`,file:s,line:null,harnesses:[],hint:"Remove the shadow tree and keep canonical skills/ at the repo root."});return{findings:n,records:[]}}var qs=/!?\[([^\]]*)\]\(([^)]+)\)/g;function z(e){let t=[],n=qs.exec(e);for(;n!==null;){let[r]=n;r.startsWith("!")||t.push({label:n[1]??"",href:(n[2]??"").trim()}),n=qs.exec(e)}return t}var oi=new Set(["url","path","href","link","..."]);function we(e){return e.length===0||oi.has(e.toLowerCase())||e.startsWith("http://")||e.startsWith("https://")||e.startsWith("mailto:")||e.startsWith("tel:")?!0:(e.split("#")[0]??"").length===0}function xe(e,t){let n=e.split(`
124
- `);for(let r=0;r<n.length;r+=1){let s=n[r];if(s!==void 0&&s.includes(t))return r+1}return null}function Gn(e){let t=e.replaceAll("\\","/").split("/"),n=[];for(let r of t)if(!(r===""||r===".")){if(r===".."){n.pop();continue}n.push(r)}return n.join("/")}function Re(e,t){let n=(t.split("#")[0]??"").trim();if(n.length===0)return null;let r=n;try{r=decodeURIComponent(n)}catch{r=n}if(r.startsWith("/"))return r.slice(1).replaceAll("\\","/");let s=e.includes("/")?e.slice(0,e.lastIndexOf("/")):"",o=s.length===0?r:`${s}/${r}`;return Gn(o)}var ii=["docs/","skills/","agents/",".cursor/",".github/",".codex/",".agent/",".claude/"],ai=new Set(["AGENTS.md","CLAUDE.md","GEMINI.md","README.md",".github/copilot-instructions.md"]);function Bs(e){let t=e.replaceAll("\\","/").replace(/\/+$/,"");return ai.has(t)?!0:ii.some(n=>t===n.slice(0,-1)||t.startsWith(n))}var ci=["",".md","/README.md","/index.md"];async function Ks(e,t){for(let n of ci){let r=`${t}${n}`.replaceAll("\\","/");if(await ee(e,r))return!0}return!1}function jn(e){return/my-doc\.md|example\.spec\.|\/example\//i.test(e)}function Wn(e){return e.endsWith("/")?!0:e.endsWith(".md")||e.endsWith(".mdc")}var li=8;async function Vn(e){let t=[];for(let n of e.files){if(!n.path.endsWith(".md")&&!n.path.endsWith(".mdc"))continue;let r=f(e,n.path);if(r===null)continue;let s=0;for(let o of z(r)){if(we(o.href))continue;let i=Re(n.path,o.href);if(!(i===null||!Bs(i)||!Wn(i)||jn(i)||await Ks(e.repoRoot,i))&&(t.push({ruleId:"guidance-links-resolve",severity:"warn",message:`Broken link in ${n.path}: (${o.href}) does not resolve.`,file:n.path,line:xe(r,o.href),harnesses:[],hint:"Fix the path or add the missing guidance file."}),s+=1,s>=li))break}}return{findings:t,records:[]}}import{readFile as ui}from"node:fs/promises";import di from"node:path";async function Un(e){try{let t=await ui(di.join(e,"package.json"),"utf8"),n=JSON.parse(t);if(h(n)&&"scripts"in n){let{scripts:r}=n;if(h(r))return r}return null}catch{return null}}function qn(e){return e===null?!1:Object.entries(e).some(([t,n])=>t.toLowerCase().includes("qmd")||typeof n=="string"&&n.toLowerCase().includes("qmd"))}async function Bn(e){let t=T(e),n=e.files.filter(s=>s.path.startsWith("docs/ai/")).length;if(!t&&n<2)return{findings:[],records:[]};let r=await Un(e.repoRoot);return qn(r)?{findings:[],records:[]}:{findings:[{ruleId:"qmd-script-present",severity:"info",message:'package.json is missing a "qmd" (or equivalent) script for skill/doc search.',file:"package.json",line:null,harnesses:[],hint:'Add something like "qmd": "bun run ./scripts/qmd/qmd.bun.ts" and document usage in AGENTS.md.'}],records:[]}}async function Kn(e){let t=await J(e.repoRoot);return t.hooksDirExists?t.settings?.["chat.useCustomAgentHooks"]===!0?{findings:[],records:[]}:{findings:[{ruleId:"vscode-custom-hooks",severity:"warn",message:".github/hooks/ exists but chat.useCustomAgentHooks is not true in .vscode/settings.json.",file:".vscode/settings.json",line:null,harnesses:["cursor","copilot"],hint:'Set "chat.useCustomAgentHooks": true so Cursor and Copilot load workspace hooks.'}],records:[]}:{findings:[],records:[]}}async function Jn(e){let t=await J(e.repoRoot),n=[];return v(t,"chat.agentSkillsLocations","skills")||n.push({ruleId:"vscode-skills-location",severity:"warn",message:"chat.agentSkillsLocations should point at skills/ in .vscode/settings.json.",file:".vscode/settings.json",line:null,harnesses:["cursor","copilot"],hint:'Set "chat.agentSkillsLocations": { "skills/": true }.'}),v(t,"chat.agentFilesLocations","agents")||n.push({ruleId:"vscode-agents-location",severity:"warn",message:"chat.agentFilesLocations should point at agents/ in .vscode/settings.json.",file:".vscode/settings.json",line:null,harnesses:["cursor","copilot"],hint:'Set "chat.agentFilesLocations": { "agents/": true }.'}),{findings:n,records:[]}}function zn(e){let t=[];for(let n of Ee){if(!R(e,n))continue;let r=f(e,n);r===null||qr(r)||t.push({ruleId:"adapter-points-to-shared",severity:"warn",message:`${n} should reference AGENTS.md and docs/ai/rules.md.`,file:n,line:null,harnesses:[],hint:"Keep adapters thin; point at shared layers instead of duplicating rules."})}return{findings:t,records:[]}}function Yn(e){let t=[];for(let n of te(e,"agents/")){if(!n.endsWith(".agent.md"))continue;let r=f(e,n);if(r===null)continue;let s=Ie(r);if(s===null){t.push({ruleId:"agent-frontmatter",severity:"error",message:`${n} is missing YAML frontmatter.`,file:n,line:null,harnesses:[]});continue}Z(s,"name")||t.push({ruleId:"agent-frontmatter",severity:"error",message:`${n} is missing a name field in frontmatter.`,file:n,line:null,harnesses:[]}),Z(s,"description")||t.push({ruleId:"agent-frontmatter",severity:"error",message:`${n} is missing a description field in frontmatter.`,file:n,line:null,harnesses:[]})}return{findings:t,records:[]}}function Xn(e){if(!T(e)||!R(e,"AGENTS.md"))return{findings:[],records:[]};let t=f(e,"AGENTS.md");return t!==null&&Le(t)?{findings:[],records:[]}:{findings:[{ruleId:"agents-md-mentions-skills",severity:"info",message:"AGENTS.md should point at docs/ai/available-skills.md or the qmd search workflow.",file:"AGENTS.md",line:null,harnesses:[],hint:"Document how agents discover skills (index doc or npm run qmd -- search)."}],records:[]}}function Qn(e){if(!e.harnesses.includes("claude")||!R(e,"CLAUDE.md"))return{findings:[],records:[]};let t=f(e,"CLAUDE.md");return t!==null&&Te(t)?{findings:[],records:[]}:{findings:[{ruleId:"claude-agent-routing",severity:"info",message:"CLAUDE.md should include an Agent Routing table pointing at agents/*.agent.md.",file:"CLAUDE.md",line:null,harnesses:["claude"],hint:"Add a markdown table mapping task types to shared agents/*.agent.md files."}],records:[]}}function Zn(e){return!e.endsWith(".md")&&!e.endsWith(".mdc")?!1:e.startsWith("docs/")||e.includes("/docs/")}function er(e,t){for(let n of z(t)){if(we(n.href))continue;let r=Re(e,n.href);if(r!==null&&Zn(r))return!0}return!1}var pi=50;function tr(e){let t=[];for(let n of e.files){if(!n.path.startsWith("skills/")||!n.path.endsWith("SKILL.md")||(n.lines??0)<=pi)continue;let r=f(e,n.path);r===null||er(n.path,r)||t.push({ruleId:"skill-doc-deep-links",severity:"info",message:`${n.path} does not deep-link into a durable doc under docs/.`,file:n.path,line:null,harnesses:[],hint:"Pair the skill with a docs/ reference and link it (for example a **Details:** link to a docs/ page) instead of inlining all detail."})}return{findings:t,records:[]}}function nr(e){let t=[];for(let n of te(e,"skills/")){if(!n.endsWith("/SKILL.md")&&!n.endsWith("SKILL.md"))continue;let r=f(e,n);if(r===null)continue;let s=Ie(r);if(s===null){t.push({ruleId:"skill-frontmatter",severity:"error",message:`${n} is missing YAML frontmatter.`,file:n,line:null,harnesses:[]});continue}Z(s,"name")||t.push({ruleId:"skill-frontmatter",severity:"error",message:`${n} is missing a name field in frontmatter.`,file:n,line:null,harnesses:[]}),Z(s,"description")||t.push({ruleId:"skill-frontmatter",severity:"error",message:`${n} is missing a description field in frontmatter.`,file:n,line:null,harnesses:[]})}return{findings:t,records:[]}}function rr(e){let t=[];for(let n of te(e,"skills/")){if(!n.endsWith("SKILL.md"))continue;let r=O(e,n);r!==null&&r>rt&&t.push({ruleId:"skill-line-count",severity:"warn",message:`${n} has ${String(r)} lines; keep skills under ${String(rt)}.`,file:n,line:null,harnesses:[],hint:"Move detail to docs/; keep SKILL.md as a pointer."})}return{findings:t,records:[]}}var Js="docs/ai/available-skills.md";function sr(e){return T(e)?R(e,Js)?{findings:[],records:[]}:{findings:[{ruleId:"skills-index",severity:"info",message:`${Js} is missing; add a skill slug index when using skills/.`,file:null,line:null,harnesses:[],hint:"List each skills/<slug>/ folder so agents can pick a minimal skill set."}],records:[]}:{findings:[],records:[]}}function Ce(e,t,n,r){return{ruleId:e,severity:"warn",message:`${t} has ${String(n)} lines; keep root adapters thin (max ${String($)}).`,file:t,line:null,harnesses:[r],hint:"Move detailed guidance to docs/ai/ and skills/; keep the adapter as a pointer."}}var fi=["AGENTS.md","CLAUDE.md","GEMINI.md",".github/copilot-instructions.md",".agent/README.md"],zs=["IMPORTANT","CRITICAL","MANDATORY","REQUIRED","MUST NOT","MUST","NEVER","ALWAYS","SHALL","DO NOT"],Ys=.03,Xs=40,Qs=[{pattern:/\byou are an? (?:expert|senior|world[- ]class|10x|highly skilled|seasoned|professional)\b/i,label:"identity framing (\u201Cyou are a/an \u2026\u201D)"},{pattern:/\bact as an?\b/i,label:"roleplay framing (\u201Cact as a \u2026\u201D)"},{pattern:/\bas an ai (?:language model|assistant)\b/i,label:"AI self-reference"},{pattern:/\bworld[- ]class\b/i,label:"superlative filler (\u201Cworld-class\u201D)"}];function Je(e){return e.replaceAll(/```[\s\S]*?```/g," ")}function Zs(e){let t=e.match(/\S+/g);return t===null?0:t.length}function ze(e){return fi.filter(t=>f(e,t)!==null)}function or(e){let t=0;for(let n of zs){let r=e.match(new RegExp(`\\b${n}\\b`,"g"));r!==null&&(t+=r.length)}return t}function ir(e){let t=[];for(let n of ze(e)){let r=f(e,n);if(r===null)continue;let s=Je(r),o=Zs(s);if(o<Xs)continue;let i=or(s),a=i/o;if(a<=Ys)continue;let c=(a*100).toFixed(1);t.push({ruleId:"emphasis-keyword-density",severity:"info",message:`${n} uses ${String(i)} all-caps emphasis keyword(s) across ${String(o)} words (${c}%); emphasis loses force when overused.`,file:n,line:null,harnesses:[],hint:"Reserve IMPORTANT/MUST/NEVER for the few rules that truly need them; rewrite the rest as plain, action-oriented instructions."})}return{findings:t,records:[]}}function ar(e){let t=[];for(let n of ze(e)){let r=f(e,n);if(r===null)continue;let s=Je(r),o=Qs.filter(({pattern:i})=>i.test(s)).map(({label:i})=>i);o.length!==0&&t.push({ruleId:"identity-language-absent",severity:"info",message:`${n} contains identity/roleplay filler: ${o.join(", ")}.`,file:n,line:null,harnesses:[],hint:"Drop identity framing; state what to do, not who to be. Action-oriented rules outperform persona prompts."})}return{findings:t,records:[]}}var eo=[{id:"emphasis-keyword-density",title:"Emphasis-keyword density",severity:"info",category:"instruction-quality",dimension:"maintainability",harnesses:[],check:ir},{id:"identity-language-absent",title:"No identity-language filler",severity:"info",category:"instruction-quality",dimension:"maintainability",harnesses:[],check:ar}];var mi=/\b(?:curl|wget|ncat|telnet|scp)\b|\bnc\s|Invoke-WebRequest|\bfetch\s*\(|\baxios\b|http\.request|urllib|requests\.(?:get|post|put|patch)/i,gi=/localhost|127\.0\.0\.1|0\.0\.0\.0|::1/i;function cr(e){let t=[];for(let n of e.content.split(/\r?\n/)){let r=n.trim();mi.test(r)&&!gi.test(r)&&t.push(r)}return t}var hi=new Set(["Bash","Write","Edit","MultiEdit","NotebookEdit"]);function lr(e){let t=e.trim();if(t==="")return!1;if(t==="*")return!0;if(t.startsWith("mcp__"))return t.includes("*");let n=t.match(/^([A-Za-z_][\w-]*)(?:\((.*)\))?$/);if(n===null)return!1;let[,r="",s]=n;if(!hi.has(r))return!1;if(s===void 0)return!0;let o=s.trim();return o===""||o==="*"||o===":*"}var yi=/^[0-9a-f]{40}$/i;function ur(e){let t=new Set,n=/^\s*-?\s*uses:\s*['"]?([^'"\s#]+)['"]?/gm;for(let r of e.matchAll(n)){let[,s]=r;if(s===void 0||s.startsWith("./")||s.startsWith("docker://"))continue;let o=s.includes("@")?s.slice(s.lastIndexOf("@")+1):"";yi.test(o)||t.add(s)}return[...t]}var M={findings:[],records:[]},ki=new Set(["bypassPermissions","acceptEdits"]),Si="stop_hook_active";function Y(e){return e.security??null}var wi={id:"no-dangerous-auto-approve",title:"No dangerous auto-approve permissions",severity:"error",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=Y(e);if(t===null)return M;let n=[];for(let r of t.claudeSettings){r.defaultMode!==null&&ki.has(r.defaultMode)&&n.push({ruleId:"no-dangerous-auto-approve",severity:"error",message:`${r.path} sets permissions.defaultMode "${r.defaultMode}", auto-approving actions without prompting.`,file:r.path,line:null,harnesses:["claude"],hint:'Use "default" or "plan" mode and allow-list specific commands instead of bypassing prompts.'});for(let s of r.allow.filter(lr))n.push({ruleId:"no-dangerous-auto-approve",severity:"error",message:`${r.path} auto-approves "${s}", a blanket grant over a dangerous capability.`,file:r.path,line:null,harnesses:["claude"],hint:"Scope allow-list entries to specific commands, e.g. Bash(npm run test:*) instead of Bash(*)."})}return{findings:n,records:[]}}},xi={id:"hook-no-network-exfil",title:"Hooks do not exfiltrate over the network",severity:"error",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=Y(e);if(t===null)return M;let n=[];for(let r of t.hookScripts){let[s]=cr(r);s!==void 0&&n.push({ruleId:"hook-no-network-exfil",severity:"error",message:`${r.source} makes a network call (\`${s.slice(0,80)}\`); hooks run automatically and can exfiltrate repo data.`,file:r.path,line:null,harnesses:[],hint:"Remove the network call or restrict it to localhost; move outbound calls into explicit, reviewable steps."})}return{findings:n,records:[]}}},Ri={id:"hook-stop-circuit-breaker",title:"Stop hooks guard against infinite loops",severity:"warn",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=Y(e);if(t===null)return M;let n=[];for(let r of t.hookScripts)!r.isStop||r.content.includes(Si)||n.push({ruleId:"hook-stop-circuit-breaker",severity:"warn",message:`${r.source} is a Stop hook that never checks stop_hook_active; a blocking Stop hook can loop the agent indefinitely.`,file:r.path,line:null,harnesses:[],hint:"Read stop_hook_active from the hook input and exit without blocking when it is true."});return{findings:n,records:[]}}},Ci={id:"env-files-gitignored",title:"Env files are gitignored",severity:"warn",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=Y(e);if(t===null)return M;let r=t.gitignore!==null&&/^\s*!?[*.]*\.env(?:[.*]|\b|\/)?/m.test(t.gitignore)?[]:t.envFilesPresent;if(r.length===0)return M;let s=t.usesKeyringSecrets?"This repo uses keyring-managed secrets; delete the committed .env file rather than relying on it.":"Gitignore `.env`/`.env.*`, or move secrets to an OS keyring (the run-with-env pattern) so they never touch disk.";return{findings:[{ruleId:"env-files-gitignored",severity:"warn",message:`${r.join(", ")} present but not gitignored; secrets risk being committed.`,file:r[0]??null,line:null,harnesses:[],hint:s}],records:[]}}};function bi(e){return e.some(t=>/gitleaks|trufflehog|detect-secrets|ggshield/i.test(t.content))}var Ai={id:"secret-scanning-configured",title:"Secret scanning is configured",severity:"warn",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=Y(e);if(t===null)return M;let n=e.intelligenceLayer?.workflows??[];return t.secretScanningFiles.length>0||bi(n)?M:{findings:[{ruleId:"secret-scanning-configured",severity:"warn",message:"No secret-scanning configuration found (gitleaks, trufflehog, detect-secrets, or a pre-commit secret hook).",file:null,line:null,harnesses:[],hint:"Add a gitleaks/trufflehog CI step or a detect-secrets pre-commit hook so committed credentials are caught."}],records:[]}}},vi={id:"no-pull-request-target",title:"No risky pull_request_target workflows",severity:"error",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=e.intelligenceLayer?.workflows??[],n=[];for(let r of t)/\bpull_request_target\b/.test(r.content)&&n.push({ruleId:"no-pull-request-target",severity:"error",message:`${r.path} triggers on pull_request_target, which runs with repo secrets against untrusted PR code.`,file:r.path,line:null,harnesses:[],hint:"Prefer pull_request; if pull_request_target is required, never check out or execute PR head code with secrets in scope."});return{findings:n,records:[]}}},Ei={id:"actions-sha-pinned",title:"GitHub Actions pinned to commit SHAs",severity:"warn",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=e.intelligenceLayer?.workflows??[],n=[];for(let r of t){let s=ur(r.content);s.length!==0&&n.push({ruleId:"actions-sha-pinned",severity:"warn",message:`${r.path} uses actions pinned to mutable refs: ${s.join(", ")}.`,file:r.path,line:null,harnesses:[],hint:"Pin each action to a full 40-character commit SHA (e.g. actions/checkout@<sha>) to prevent tag-hijack supply-chain attacks."})}return{findings:n,records:[]}}},Ii={id:"claude-hooks-valid",title:"Claude hooks config is valid",severity:"error",category:"hooks",dimension:"guardrails",harnesses:["claude"],check(e){let t=Y(e);if(t===null)return M;let n=[];for(let r of t.claudeSettings){if(!r.valid){n.push({ruleId:"claude-hooks-valid",severity:"error",message:`${r.path} is not valid JSON.`,file:r.path,line:null,harnesses:["claude"],hint:"Fix the JSON syntax; an unparseable settings file disables every configured hook silently."});continue}r.hooksMalformed&&n.push({ruleId:"claude-hooks-valid",severity:"error",message:`${r.path} has a malformed hooks block; entries must be { matcher?, hooks: [{ type, command }] }.`,file:r.path,line:null,harnesses:["claude"],hint:"Match the documented hooks schema so the configured commands actually run."})}for(let r of t.referencedClaudeScripts.filter(s=>!s.exists))n.push({ruleId:"claude-hooks-valid",severity:"error",message:`${r.source} references missing script ${r.path}.`,file:r.path,line:null,harnesses:["claude"],hint:"Create the script or fix the path; a missing hook command fails open and skips the check."});return{findings:n,records:[]}}},Li={id:"codex-hooks-valid",title:"Codex hooks config is valid",severity:"error",category:"hooks",dimension:"guardrails",harnesses:["codex"],check(e){let t=Y(e);if(t===null||t.codexHooks===null)return M;let n=t.codexHooks,r=[];n.valid||r.push({ruleId:"codex-hooks-valid",severity:"error",message:`${n.path} is not valid JSON.`,file:n.path,line:null,harnesses:["codex"],hint:"Fix the JSON syntax so the configured codex hooks load."});for(let s of n.referencedScripts.filter(o=>!o.exists))r.push({ruleId:"codex-hooks-valid",severity:"error",message:`${n.path} references missing script ${s.path}.`,file:s.path,line:null,harnesses:["codex"],hint:"Create the script or fix the path so the hook command runs."});return{findings:r,records:[]}}},to=[wi,xi,Ri,Ci,Ai,vi,Ei,Ii,Li];var Ti={id:"shared-agents-md",title:"Shared AGENTS.md entry point",severity:"warn",category:"structure",dimension:"layering",harnesses:[],check(e){return R(e,"AGENTS.md")?{findings:[],records:[]}:{findings:[{ruleId:"shared-agents-md",severity:"warn",message:"AGENTS.md is missing.",file:null,line:null,harnesses:[],hint:"Add AGENTS.md as the repo-wide AI entry point with workflow, safety, and pointers to canonical docs."}],records:[]}}},Fi={id:"shared-rules-doc",title:"Canonical rules doc",severity:"warn",category:"structure",dimension:"layering",harnesses:[],check(e){return R(e,"docs/ai/rules.md")?{findings:[],records:[]}:{findings:[{ruleId:"shared-rules-doc",severity:"warn",message:"docs/ai/rules.md is missing.",file:null,line:null,harnesses:[],hint:"Add docs/ai/rules.md as the canonical coding-rules reference."}],records:[]}}},Hi={id:"adapter-thin-claude",title:"Thin CLAUDE.md adapter",severity:"warn",category:"adapter",dimension:"layering",harnesses:["claude"],check(e){let t=O(e,"CLAUDE.md");return t===null||t<=$?{findings:[],records:[]}:{findings:[Ce("adapter-thin-claude","CLAUDE.md",t,"claude")],records:[]}}},Pi={id:"adapter-thin-gemini",title:"Thin GEMINI.md adapter",severity:"warn",category:"adapter",dimension:"layering",harnesses:["gemini"],check(e){let t=O(e,"GEMINI.md");return t===null||t<=$?{findings:[],records:[]}:{findings:[Ce("adapter-thin-gemini","GEMINI.md",t,"gemini")],records:[]}}},Ni={id:"adapter-thin-copilot",title:"Thin Copilot instructions",severity:"warn",category:"adapter",dimension:"layering",harnesses:["copilot"],check(e){let t=".github/copilot-instructions.md",n=O(e,t);return n===null||n<=$?{findings:[],records:[]}:{findings:[Ce("adapter-thin-copilot",t,n,"copilot")],records:[]}}},_i={id:"adapter-points-to-shared",title:"Adapters reference shared layers",severity:"warn",category:"adapter",dimension:"layering",harnesses:[],check:zn},Di={id:"skill-frontmatter",title:"Skill frontmatter",severity:"error",category:"skills",dimension:"maintainability",harnesses:[],check:nr},Mi={id:"skill-line-count",title:"Skill line budget",severity:"warn",category:"skills",dimension:"maintainability",harnesses:[],check:rr},$i={id:"agent-frontmatter",title:"Agent frontmatter",severity:"error",category:"agents",dimension:"maintainability",harnesses:[],check:Yn},Oi={id:"skills-index",title:"Skill slug index",severity:"info",category:"discoverability",dimension:"discoverability",harnesses:[],check:sr},Gi={id:"claude-agent-routing",title:"Claude agent routing table",severity:"info",category:"discoverability",dimension:"discoverability",harnesses:["claude"],check:Qn},ji={id:"agents-md-mentions-skills",title:"AGENTS.md skill discovery",severity:"info",category:"discoverability",dimension:"discoverability",harnesses:[],check:Xn},Wi={id:"skill-doc-deep-links",title:"Skills deep-link into docs",severity:"info",category:"discoverability",dimension:"discoverability",harnesses:[],check:tr},no=[Ti,Fi,Hi,Pi,Ni,_i,Di,Mi,$i,Oi,Gi,ji,Wi,...eo,...to];function W(e,t,n,r,s){e.push(...s.findings),t.push(...s.records),s.records.length===0&&t.push({checkId:n,dimension:r,rawScore:s.findings.length>0?0:1})}function be(e,t){return e.length===0?!0:e.some(n=>t.includes(n))}function dr(e,t,n){return be(n,e.harnesses)?t===null||t.length===0?!0:n.some(r=>t.includes(r)):!1}function pr(e,t,n){return be(e.harnesses,t.harnesses)?n===null||n.length===0||e.harnesses.length===0?!0:e.harnesses.some(r=>n.includes(r)):!1}function X(e){return e.trim().replaceAll(/\s+/g," ")}function fr(e){let t=X(e);return!(t.length<20||/^#{1,6}\s/.test(t)||/^[-*]\s/.test(t)&&t.length<40||t.includes("AGENTS.md")||t.includes("docs/ai/rules.md"))}function Ye(e){return e.map(t=>X(t)).filter(t=>t.length>0).join(`
125
- `)}var Xe=3,Vi=80;function mr(e,t){let n=e.split(`
126
- `),r=Ye(t.split(`
127
- `)),s=[],o=new Set;for(let i=0;i<=n.length-Xe;i+=1){if(o.has(i))continue;let a=n.slice(i,i+Xe);if(!a.every(u=>fr(u)))continue;let c=Ye(a);if(!(c.length<Vi)&&r.includes(c)){s.push({startLine:i+1,lineCount:Xe,sample:X(a[0]??"")}),o.add(i);for(let u=1;u<Xe;u+=1)o.add(i+u)}}return s}var gr="docs/ai/rules.md";function hr(e){let t=f(e,gr);if(t===null)return{findings:[],records:[]};let n=[];for(let r of Ee){let s=f(e,r);if(s===null)continue;let o=mr(s,t);for(let i of o)n.push({ruleId:"adapter-content-duplication",severity:"warn",message:`${r} duplicates ${String(i.lineCount)} lines from ${gr} near line ${String(i.startLine)}.`,file:r,line:i.startLine,harnesses:[],hint:`Replace duplicated rules with a pointer to ${gr}.`})}return{findings:n,records:[]}}function se(e){return e.intelligenceLayer??null}function oe(e){return e.packageJson.path!==null||e.workflows.length>0||e.prTemplates.length>0}function g(e,t,n,r){return{ruleId:e,severity:"info",message:t,file:r,line:null,harnesses:[],hint:n}}function yr(e){let t=se(e);return t===null||!oe(t)?{findings:[],records:[]}:t.guidanceCiWorkflows.length>0?{findings:[],records:[]}:{findings:[g("ci-guidance-lint","No CI guidance-maintenance gate was detected.","Run lint:md, check:ai-system, check:links, scan:self, or an equivalent guidance check in CI.",t.workflows[0]?.path??t.packageJson.path)],records:[]}}function w(e){return e.intelligenceLayer??null}function ie(e){return Object.entries(e.packageJson.scripts).map(([t,n])=>({name:t,command:n}))}function ae(e,t,n){return ie(e).some(r=>t.test(r.name)||n.test(r.command))}function ro(e,t){return ie(e).filter(n=>t.test(n.name)||t.test(n.command)).map(n=>n.name).toSorted()}function ce(e){return e.workflows.map(t=>t.commands.join(`
147
+ `);else{let t=[...e.findings].sort((n,s)=>{let r=Ot.indexOf(n.severity)-Ot.indexOf(s.severity);return r!==0?r:n.ruleId.localeCompare(s.ruleId)});for(let n of t)process.stdout.write(`${$t(n)}
148
+
149
+ `)}process.stdout.write(fo)}import yl from"node:path";function cn(){return{copilot:{files:0,lines:0,bytes:0},cursor:{files:0,lines:0,bytes:0},codex:{files:0,lines:0,bytes:0},antigravity:{files:0,lines:0,bytes:0},claude:{files:0,lines:0,bytes:0},gemini:{files:0,lines:0,bytes:0}}}function ln(e,t){return e.harness!==void 0?t.includes(e.harness)?[e.harness]:[]:Ut.has(e.layer)?t:e.path.startsWith(".cursor/")?t.includes("cursor")?["cursor"]:[]:e.path.startsWith(".codex/")?t.includes("codex")?["codex"]:[]:e.path.startsWith(".agent/")?t.includes("antigravity")?["antigravity"]:[]:e.path==="AGENTS.md"||e.path.startsWith("docs/ai/")?t:[]}function Y(e,t){return t===0?0:Math.round(e/t*1e3)/10}function un(e,t){let n={files:0,lines:0,bytes:0},s=cn(),r={files:0,lines:0,bytes:0},o={files:0,lines:0,bytes:0},i=[];for(let a of e){let c=ln(a,t);if(c.length===0)continue;o.files+=1,o.lines+=a.lines,o.bytes+=a.bytes;let l=mo(a,c),p=l?"shared":"unique";if(i.push({path:a.path,lines:a.lines,scope:p,harnesses:c}),l)n.files+=1,n.lines+=a.lines,n.bytes+=a.bytes;else{let[f]=c;f!==void 0&&(s[f].files+=1,s[f].lines+=a.lines,s[f].bytes+=a.bytes),r.files+=1,r.lines+=a.lines,r.bytes+=a.bytes}}return{totals:o,shared:{...n,percentLines:Y(n.lines,o.lines)},unique:{byHarness:s,totals:{...r,percentLines:Y(r.lines,o.lines)}},files:i}}import T from"node:path";import{access as ga}from"node:fs/promises";async function x(e){try{return await ga(e),!0}catch{return!1}}function dn(e){return e===null?!1:e["chat.agentSkillsLocations"]!==void 0||e["chat.agentFilesLocations"]!==void 0||e["chat.useCustomAgentHooks"]===!0}import{readFile as ha}from"node:fs/promises";function pn(e){if(e==="true")return!0;if(e==="false")return!1;if(e==="null")return null;if(e.startsWith('"')&&e.endsWith('"'))return e.slice(1,-1);let t=Number(e);return Number.isNaN(t)?e:t}function fn(e){let t={},n=/"([^"]+)"\s*:\s*(true|false|null|\d+(?:\.\d+)?|"[^"]*")/g;for(let[,s,r]of e.matchAll(n))s===void 0||r===void 0||(t[s]=pn(r));return Object.keys(t).length===0?null:t}function Ce(e){try{let t=JSON.parse(e);if(y(t))return t}catch{}return fn(e)}async function mn(e){try{let t=await ha(e,"utf8");return Ce(t)}catch{return null}}async function Ae(e){let t=new Set;await x(T.join(e,".github/copilot-instructions.md"))&&t.add("copilot"),await x(T.join(e,".github/hooks"))&&t.add("copilot");let n=await mn(T.join(e,".vscode/settings.json"));return dn(n)&&(t.add("cursor"),t.add("copilot")),await x(T.join(e,".cursor"))&&t.add("cursor"),await x(T.join(e,".codex/config.toml"))&&t.add("codex"),await x(T.join(e,".codex/hooks.json"))&&t.add("codex"),await x(T.join(e,".codex/agents"))&&t.add("codex"),await x(T.join(e,".agent/workflows"))&&t.add("antigravity"),await x(T.join(e,".agent/README.md"))&&t.add("antigravity"),await x(T.join(e,"CLAUDE.md"))&&t.add("claude"),await x(T.join(e,".claude/settings.json"))&&t.add("claude"),await x(T.join(e,"GEMINI.md"))&&t.add("gemini"),[...t].sort()}function Ie(e){return Math.ceil(e/4)}function H(e,t){return{path:e.path,lines:e.lines,bytes:e.bytes,estimatedTokens:Ie(e.bytes),reason:t}}function gn(e,t){let n=e.fileContents.get(t.path);return n===void 0?!1:/^alwaysApply:\s*true\s*$/im.test(n)||/^always_apply:\s*true\s*$/im.test(n)}function J(e,t){return e.files.find(n=>n.path===t)??null}function hn(e,t){let n=[];if(t==="copilot"){let s=J(e,".github/copilot-instructions.md");s!==null&&n.push(H(s,"Copilot workspace instructions are loaded by Copilot Chat."))}if(t==="cursor")for(let s of e.files)s.path.startsWith(".cursor/rules/")&&gn(e,s)&&n.push(H(s,"Cursor rule declares alwaysApply: true."));if(t==="codex"){let s=J(e,"AGENTS.md");s!==null&&n.push(H(s,"Root AGENTS.md is the Codex repo instruction entry."));for(let r of e.files)r.path.startsWith(".codex/")&&r.layer==="adapter"&&n.push(H(r,"Codex adapter guidance under .codex/."))}if(t==="antigravity"){let s=J(e,".agent/README.md");s!==null&&n.push(H(s,"Antigravity workspace adapter README."))}if(t==="claude"){let s=J(e,"CLAUDE.md");s!==null&&n.push(H(s,"Claude Code root instruction file."))}if(t==="gemini"){let s=J(e,"GEMINI.md");s!==null&&n.push(H(s,"Gemini root instruction file."))}return n.toSorted((s,r)=>s.path.localeCompare(r.path))}function yn(e,t){if(!e.harnesses.includes(t))return{harness:t,detected:!1,files:[],totalLines:0,totalBytes:0,estimatedTokens:0,maxRecommendedLines:250,status:"ok"};let s=hn(e,t),r=s.reduce((i,a)=>i+a.lines,0),o=s.reduce((i,a)=>i+a.bytes,0);return{harness:t,detected:!0,files:s,totalLines:r,totalBytes:o,estimatedTokens:Ie(o),maxRecommendedLines:250,status:r>250?"high":"ok"}}function Sn(e){return{harnesses:K.map(t=>yn(e,t)),maxRecommendedLines:250,maxRecommendedFileLines:150}}var kn=["Memory","Reflection","Planning","Action","System Operation"];function xn(e){let t=new Map(kn.map(i=>[i,{dimension:i,findingCount:0,error:0,warn:0,info:0,ruleIds:[]}])),n=new Map(kn.map(i=>[i,new Set])),s=0,r=0;for(let i of e){let a=Ye(i.ruleId);if(a.length===0){r+=1;continue}s+=1;for(let c of a){let l=t.get(c),p=n.get(c);l===void 0||p===void 0||(l.findingCount+=1,l[i.severity]+=1,p.has(i.ruleId)||(p.add(i.ruleId),l.ruleIds.push(i.ruleId)))}}return{byDimension:kn.map(i=>t.get(i)).filter(i=>i.findingCount>0),taggedFindings:s,untaggedFindings:r}}function wn(e,t){let n={sharedLines:0,uniqueLines:0,totalLines:0,sharedPercent:0,uniquePercent:0},s={copilot:{...n},cursor:{...n},codex:{...n},antigravity:{...n},claude:{...n},gemini:{...n}};for(let r of t){let o=e.unique.byHarness[r].lines,i=e.shared.lines,a=i+o;s[r]={sharedLines:i,uniqueLines:o,totalLines:a,sharedPercent:Y(i,a),uniquePercent:Y(o,a)}}return s}function Rn(e,t){let n={error:0,warn:0,info:0};for(let s of e)s.harnesses.includes(t)&&(s.severity==="error"?n.error+=1:s.severity==="warn"?n.warn+=1:n.info+=1);return n}var xo=[{min:85,grade:"excellent"},{min:70,grade:"good"},{min:50,grade:"fair"},{min:0,grade:"poor"}],Ze={error:12,warn:5,info:1},wo=40;function bn(e){let t=e.error*Ze.error+e.warn*Ze.warn+e.info*Ze.info;return Math.min(t,wo)}import ve from"node:path";function M(e,t){return e.files.some(n=>n.path===t)}function Cn(e,t){return e.fileContents.get(t)??null}function ya(e,t){return e.files.find(s=>s.path===t)?.lines??null}function Sa(e){return e.includes("AGENTS.md")||e.includes("docs/ai/rules.md")}function X(e){return e.files.some(t=>t.path.startsWith("skills/"))}function Ee(e){return e.files.some(t=>t.path.startsWith("agents/"))}function An(e,t){return e.settings?.[t]===!0}function et(e,t){let n=ya(e,t);return n===null?!1:n<=W}function tt(e,t){let n=Cn(e,t);return n===null?!1:Sa(n)}function In(e){let t=Cn(e,".agent/README.md");return t===null?!1:/\.agent\/workflows\/|workflows\//i.test(t)&&/(workflow|playbook|slash command|mission|turbo)/i.test(t)}function Q(e,t,n){let s=e.settings?.[t];if(y(s)&&Object.keys(s).some(a=>a.startsWith(n)))return!0;if(e.settingsRaw===null)return!1;let r=t.replaceAll(".",String.raw`\.`);return new RegExp(`"${r}"\\s*:\\s*\\{[^}]*"${n}[^"]*"`).test(e.settingsRaw)}var Ro={copilot:[{id:"copilot-instructions",label:"Copilot instructions file present",weight:15,run:({context:e})=>M(e,".github/copilot-instructions.md")},{id:"copilot-references-shared",label:"Copilot instructions reference shared layers",weight:15,run:({context:e})=>tt(e,".github/copilot-instructions.md")},{id:"copilot-adapter-thin",label:"Copilot instructions stay thin",weight:10,run:({context:e})=>et(e,".github/copilot-instructions.md")},{id:"copilot-skills-location",label:"chat.agentSkillsLocations points at skills/",weight:15,run:({vscode:e})=>Q(e,"chat.agentSkillsLocations","skills")},{id:"copilot-agents-location",label:"chat.agentFilesLocations points at agents/",weight:15,run:({vscode:e})=>Q(e,"chat.agentFilesLocations","agents")},{id:"copilot-hooks-enabled",label:"Custom agent hooks enabled when .github/hooks/ exists",weight:15,run:({vscode:e})=>!e.hooksDirExists||An(e,"chat.useCustomAgentHooks")},{id:"copilot-shared-skills",label:"Shared skills/ tree present",weight:8,run:({context:e})=>X(e)},{id:"copilot-shared-agents",label:"Shared agents/ tree present",weight:7,run:({context:e})=>Ee(e)}],cursor:[{id:"cursor-rules-or-settings",label:"Cursor rules or VS Code agent settings present",weight:20,run:({context:e,vscode:t})=>e.files.some(n=>n.path.startsWith(".cursor/rules/"))||Q(t,"chat.agentSkillsLocations","skills")},{id:"cursor-skills-location",label:"chat.agentSkillsLocations points at skills/",weight:20,run:({vscode:e})=>Q(e,"chat.agentSkillsLocations","skills")},{id:"cursor-agents-location",label:"chat.agentFilesLocations points at agents/",weight:20,run:({vscode:e})=>Q(e,"chat.agentFilesLocations","agents")},{id:"cursor-hooks-enabled",label:"Custom agent hooks enabled when .github/hooks/ exists",weight:15,run:({vscode:e})=>!e.hooksDirExists||An(e,"chat.useCustomAgentHooks")},{id:"cursor-shared-skills",label:"Shared skills/ tree present",weight:13,run:({context:e})=>X(e)},{id:"cursor-shared-agents",label:"Shared agents/ tree present",weight:12,run:({context:e})=>Ee(e)}],codex:[{id:"codex-config-surface",label:"Codex config surface present (.codex/ or nested AGENTS.md)",weight:25,run:async({context:e})=>e.files.some(t=>t.path.startsWith(".codex/"))?!0:await x(ve.join(e.repoRoot,"api/AGENTS.md"))||await x(ve.join(e.repoRoot,"react/AGENTS.md"))||await x(ve.join(e.repoRoot,"shared/AGENTS.md"))},{id:"codex-hooks",label:"Codex hooks.json present",weight:20,run:({context:e})=>x(ve.join(e.repoRoot,".codex/hooks.json"))},{id:"codex-agents-wrappers",label:"Codex agent wrappers present",weight:20,run:({context:e})=>x(ve.join(e.repoRoot,".codex/agents"))},{id:"codex-shared-entry",label:"Root AGENTS.md present",weight:20,run:({context:e})=>M(e,"AGENTS.md")},{id:"codex-shared-skills",label:"Shared skills/ tree present",weight:8,run:({context:e})=>X(e)},{id:"codex-shared-rules",label:"Canonical rules doc present",weight:7,run:({context:e})=>M(e,"docs/ai/rules.md")}],antigravity:[{id:"antigravity-workflows",label:"Workflow playbooks present (.agent/workflows/)",weight:35,run:({context:e})=>e.files.some(t=>t.path.startsWith(".agent/workflows/"))},{id:"antigravity-readme",label:".agent/README.md documents workflow layout",weight:15,run:({context:e})=>In(e)},{id:"antigravity-shared-entry",label:"Root AGENTS.md present",weight:20,run:({context:e})=>M(e,"AGENTS.md")},{id:"antigravity-shared-skills",label:"Shared skills/ tree present",weight:15,run:({context:e})=>X(e)},{id:"antigravity-ai-system-doc",label:"AI system layout doc present",weight:15,run:({context:e})=>M(e,"docs/ai/ai-system.md")}],claude:[{id:"claude-adapter",label:"CLAUDE.md adapter present",weight:25,run:({context:e})=>M(e,"CLAUDE.md")},{id:"claude-references-shared",label:"CLAUDE.md references shared layers",weight:25,run:({context:e})=>tt(e,"CLAUDE.md")},{id:"claude-adapter-thin",label:"CLAUDE.md stays thin",weight:20,run:({context:e})=>et(e,"CLAUDE.md")},{id:"claude-shared-skills",label:"Shared skills/ tree present",weight:15,run:({context:e})=>X(e)},{id:"claude-skills-index",label:"Skill index doc for prose discovery",weight:8,run:({context:e})=>M(e,"docs/ai/available-skills.md")},{id:"claude-shared-agents",label:"Shared agents/ tree present",weight:7,run:({context:e})=>Ee(e)}],gemini:[{id:"gemini-adapter",label:"GEMINI.md adapter present",weight:30,run:({context:e})=>M(e,"GEMINI.md")},{id:"gemini-references-shared",label:"GEMINI.md references shared layers",weight:25,run:({context:e})=>tt(e,"GEMINI.md")},{id:"gemini-adapter-thin",label:"GEMINI.md stays thin",weight:20,run:({context:e})=>et(e,"GEMINI.md")},{id:"gemini-shared-skills",label:"Shared skills/ tree present",weight:15,run:({context:e})=>X(e)},{id:"gemini-shared-agents",label:"Shared agents/ tree present",weight:10,run:({context:e})=>Ee(e)}]};async function En(e,t){let n=Ro[e],s=[];for(let r of n){let o=await r.run(t);s.push({id:r.id,label:r.label,passed:o,weight:r.weight})}return s}function vn(e){let t=e.reduce((s,r)=>s+r.weight,0);if(t===0)return 0;let n=e.filter(s=>s.passed).reduce((s,r)=>s+r.weight,0);return Math.round(n/t*100)}function Tn(e){for(let{min:t,grade:n}of xo)if(e>=t)return n;return"poor"}async function Ln(e,t,n,s,r,o){if(!t.harnesses.includes(e))return{harness:e,detected:!1,score:null,grade:"not-detected",checks:[],findingsCount:{error:0,warn:0,info:0},loadProfile:null};let c=await En(e,{context:t,vscode:n,harness:e}),l=Rn(s,e),p=vn(c),f=bn(l),m=Math.max(0,Math.min(100,p-f));return{harness:e,detected:!0,score:m,grade:Tn(m),checks:c,findingsCount:l,loadProfile:o[e]??null}}async function Fn(e,t,n,s){let r=wn(s,e.harnesses),o=[];for(let i of K){let a=await Ln(i,e,t,n,s,r);o.push(a)}return o}import{readFileSync as ka}from"node:fs";import{dirname as xa,join as bo}from"node:path";import{fileURLToPath as wa}from"node:url";var Ra=wa(import.meta.url),Co=xa(Ra);function nt(e){return typeof e=="object"&&e!==null}function ba(e){return nt(e)&&nt(e.dimensions)&&nt(e.check_weights)}function Ca(e){return nt(e)}function Ao(e,t){let n=JSON.parse(ka(e,"utf8"));if(!t(n))throw new Error(`Invalid standards file: ${e}`);return n}var _n=Ao(bo(Co,"standards","weights.json"),ba),Nn=Ao(bo(Co,"standards","reference-thresholds.json"),Ca);function Pn(e){return!Number.isFinite(e)||e<0?0:e<=1?e:e<=10?e/10:e<=100?e/100:1}function Io(e,t){return e>=t?1:0}function Eo(e,t){return e<=t?1:e===0?0:t/e}function vo(e,t){if(t<=0)return 0;let n=e/t;return Math.max(0,Math.min(1,n))}function Hn(e,t,n){return e>=t&&e<=n?1:e<t?t===0?0:e/t:e===0?0:n/e}function Mn(e){if(e.curve===void 0)return Pn(e.rawScore??0);let t=e.measuredValue??0,n=e.referenceValue,s=typeof n=="number"?n:0;switch(e.curve){case"binary":return Io(t,s);case"asymptoticDecay":return Eo(t,s);case"ratio":return vo(t,s);case"goldilocks":{let[r,o]=Array.isArray(n)?n:[0,s];return Hn(t,r??0,o??0)}}}function Dn(e,t){let n={};for(let r of Object.keys(t.dimensions))n[r]={weightedSum:0,weightSum:0,ran:!1,passedRules:0,applicableRules:0};for(let r of e){let o=n[r.dimension];if(!o)continue;o.ran=!0,o.applicableRules+=1;let i=Mn(r);i===1&&(o.passedRules+=1);let a=r.weight??t.check_weights[r.checkId]??1;!Number.isFinite(a)||a<=0||(o.weightedSum+=i*a,o.weightSum+=a)}let s={};for(let[r,o]of Object.entries(t.dimensions)){let i=n[r];if(!i||!i.ran){s[r]={status:"not_run",score:null,grade:"not-run",passedRules:0,applicableRules:0};continue}let a=i.weightSum>0?i.weightedSum/i.weightSum*o.max_score:0,c=Number.isFinite(a)?Math.round(a):0;s[r]={status:"run",score:c,grade:we(c),passedRules:i.passedRules,applicableRules:i.applicableRules}}return s}function On(e,t){let n=0,s=0;for(let[r,o]of Object.entries(t.dimensions)){let i=e[r];if(!i||i.status!=="run"||i.score===null)continue;let a=Number(o.weight);!Number.isFinite(a)||a<=0||(n+=i.score/o.max_score*a,s+=a)}return s===0?0:Math.round(n/s*100)}var Aa=new Set(["deep","session"]);function $n(e){for(let[t,n]of Object.entries(e))if(Aa.has(t)&&n.status==="run")return"core+extended";return"core"}function Gn(e,t,n,s,r){if(n.totals.lines>0){let l=typeof Nn.sharing_target_percent=="number"?Nn.sharing_target_percent:65;e.push({checkId:"sharing-percent",dimension:"sharing",curve:"ratio",measuredValue:n.shared.percentLines,referenceValue:l})}let o=s.filter(l=>l.detected&&l.score!==null);if(o.length>0){let l=o.reduce((p,f)=>p+(f.score??0),0)/o.length;e.push({checkId:"harness-optimization-avg",dimension:"harnessWiring",curve:"ratio",measuredValue:l,referenceValue:100})}let i=Dn(e,_n),a=On(i,_n),c=$n(i);return{profile:"meta-harness",total_score:a,score_scope:c,dimensions:i}}import{readFile as Fa}from"node:fs/promises";import Un from"node:path";import{readdir as Ia}from"node:fs/promises";import Ea from"node:path";async function st(e){let t=[".md",".mdc"];function n(o){return t.some(i=>o.endsWith(i))}let s=[],r=[];try{r=await Ia(e,{withFileTypes:!0})}catch{return s}for(let o of r){if(o.isSymbolicLink())continue;let i=Ea.join(e,o.name);o.isDirectory()?s.push(...await st(i)):o.isFile()&&n(i)&&s.push(i)}return s}import{readFile as va,stat as Ta}from"node:fs/promises";import La from"node:path";function jn(e){return e.length===0?0:e.split(`
150
+ `).length}async function Wn(e,t,n,s){let r=La.join(e,t);try{if(!(await Ta(r)).isFile())return null;let i=await va(r,"utf8"),a=jn(i),c={path:t,layer:n,lines:a,bytes:Buffer.byteLength(i,"utf8")};return s!==void 0&&(c.harness=s),c}catch{return null}}var _a=["AGENTS.md","docs/ai/rules.md","docs/ai/ai-system.md","docs/ai/available-skills.md","docs/ai/hooks.md"],Na=[{path:"CLAUDE.md",harness:"claude"},{path:"GEMINI.md",harness:"gemini"},{path:".github/copilot-instructions.md",harness:"copilot"},{path:".agent/README.md",harness:"antigravity"}],Pa=[{dir:"skills",layer:"skills"},{dir:"agents",layer:"agents"},{dir:".cursor/rules",layer:"adapter",harness:"cursor"},{dir:".agent/workflows",layer:"workflows",harness:"antigravity"},{dir:".codex",layer:"adapter",harness:"codex"},{dir:"docs/ai",layer:"shared"}];async function Te(e){let t=[],n=new Map,s=new Set;async function r(o,i,a){let c=o.replaceAll("\\","/");if(s.has(c))return;let l=await Wn(e,c,i,a);if(l===null)return;s.add(c),t.push(l);let p=Un.join(e,c);try{let f=await Fa(p,"utf8");n.set(c,f)}catch{}}for(let o of _a)await r(o,"shared");for(let o of Na)await r(o.path,"adapter",o.harness);for(let{dir:o,layer:i,harness:a}of Pa){let c=Un.join(e,o),l=await st(c);for(let p of l){let f=Un.relative(e,p).replaceAll("\\","/");await r(f,i,a)}}return t.sort((o,i)=>o.path.localeCompare(i.path)),{files:t,contents:n}}import{readFile as Ha}from"node:fs/promises";import To from"node:path";import{fileURLToPath as Ma}from"node:url";function Bn(e){return typeof e=="object"&&e!==null&&"version"in e&&typeof e.version=="string"}async function Vn(){let e=To.resolve(To.dirname(Ma(import.meta.url)),"../package.json"),t=await Ha(e,"utf8"),n=JSON.parse(t);if(!Bn(n))throw new Error("package.json is missing a string version field");return{version:n.version}}var Lo=null;function Fo(){return Lo??=Vn(),Lo}import{extname as ja}from"node:path";import{readdir as Da}from"node:fs/promises";import $o from"node:path";var _o=new Set([".git","node_modules","dist","coverage"]),No=[/^tsconfig(?:\..+)?\.json$/],Po=[/^eslint\.config\.[cm]?[jt]s$/,/^\.eslintrc(?:\..+)?$/,/^\.oxlintrc(?:\..+)?$/,/^biome\.jsonc?$/,/^ruff\.toml$/,/^\.ruff\.toml$/],Ho=[/^\.prettierrc(?:\..+)?$/,/^\.markdownlint(?:rc)?(?:\..+)?$/],Mo=[/^vitest\.config\.[cm]?[jt]s$/,/^jest\.config\.[cm]?[jt]s$/,/^playwright\.config\.[cm]?[jt]s$/,/^cypress\.config\.[cm]?[jt]s$/],Do=[/^package\.json$/,/^pyproject\.toml$/,/^Cargo\.toml$/,/^go\.mod$/],zn=/(scan:self|check:ai-system|check:md|lint:md|check:links|qmd|markdownlint|textlint|remark|cspell|paniolo-scan)/i,Oo=/(correction loop|intelligence layer|diagnostic rule|rules catalog|canonical rules|paired skill|guidance hygiene|adapters stayed thin|json output keys are stable)/i;async function pe(e,t=""){let n=$o.join(e,t),s=[];try{s=await Da(n,{withFileTypes:!0})}catch{return[]}let r=[];for(let o of s){if(o.isSymbolicLink()||_o.has(o.name))continue;let i=$o.join(t,o.name).replaceAll("\\","/");o.isDirectory()?r.push(...await pe(e,i)):o.isFile()&&r.push(i)}return r}var Go=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".py",".json",".jsonc",".yaml",".yml",".toml"]),jo=new Set(["package-lock.json","npm-shrinkwrap.json","yarn.lock","pnpm-lock.yaml","bun.lock","bun.lockb","cargo.lock","poetry.lock","uv.lock","composer.lock","gemfile.lock"]),Wo=512*1024,qn=/(?:\.(?:test|spec)\.[a-z]+$|(?:^|\/)(?:__tests__|__fixtures__|fixtures|test|tests)\/)/i,Uo=/\b(?:claude|gpt|chatgpt|gemini|mistral|codestral|llama|grok|deepseek|command|qwen|o1|o3|o4)[a-z0-9.]*(?:-[a-z0-9.]+)*-latest\b/i,Le=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".py"]),Bo=/\b(?:anthropic|openai|mistralai|cohere|generativeai|langchain|chat\.completions|messages\.create|responses\.create|generateobject|generatetext|streamtext|generate_content)\b/i,Vo=/\.choices\s*\[|tool_?calls?\b|function_?call|\.content\s*\[|\bJSON\.parse\s*\(|\bjson\.loads\s*\(/i,zo=/\b(?:zod|valibot|superstruct|typebox|class-validator|ajv|yup|pydantic|basemodel|model_validate|parse_obj|typeadapter|jsonschema|marshmallow)\b|\.safeparse\s*\(|\bz\.object\s*\(/i,rt=/\btools\s*:\s*\[|\btool_choice\s*[:=]|\bfunction_?declarations\s*[:=]|\b(?:defineTool|zodFunction|registerTool)\s*\(|\bserver\.tool\s*\(|\binput_?schema\s*[:=]|^\s*@tool\b/im,qo=/\btool\b|\barguments?\b|\bfunction_?call|\bparameters?\b|\binput_?schema\b/i,Ko=/\btothrow\b|\.rejects\b|\bassert_?raises\b|pytest\.raises|\binvalid\b|\bmalformed\b|\bmissing\b|\bsafeparse\b|\berrors?\b/i;import Yo from"node:path";function Kn(e){let t=Yo.basename(e).toLowerCase();return jo.has(t)?!1:Go.has(Yo.extname(t))}import{readFile as Oa,stat as $a}from"node:fs/promises";import Ga from"node:path";async function Yn(e,t){let n=Ga.join(e,t);try{return(await $a(n)).size>Wo?null:{path:t,content:await Oa(n,"utf8")}}catch{return null}}async function Jn(e){let n=(await pe(e)).filter(o=>Kn(o)),r=(await Promise.all(n.map(o=>Yn(e,o)))).filter(o=>o!==null);return{sourceFiles:r.filter(o=>!qn.test(o.path)).toSorted((o,i)=>o.path.localeCompare(i.path)),testFiles:r.filter(o=>qn.test(o.path)&&Le.has(ja(o.path))).toSorted((o,i)=>o.path.localeCompare(i.path))}}async function Xn(e){let{sourceFiles:t,testFiles:n}=await Jn(e);return{sourceFiles:t,testFiles:n}}import Ba from"node:path";import{readFile as Wa,stat as Ua}from"node:fs/promises";import Jo from"node:path";function Xo(e){return e.length===0?0:e.split(`
151
+ `).length}async function Qo(e,t){try{return(await Ua(Jo.join(e,t))).isFile()}catch{return!1}}async function D(e,t){try{return await Wa(Jo.join(e,t),"utf8")}catch{return null}}function ot(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function fe(e,t){return t.some(n=>n.test(e))}function Zo(e){return/^\.github\/workflows\/.+\.ya?ml$/.test(e)}function ei(e){return e===".github/PULL_REQUEST_TEMPLATE.md"||/^\.github\/PULL_REQUEST_TEMPLATE\/.+\.md$/.test(e)||/^docs\/pull_request_template\.md$/i.test(e)}function it(e,t){return zn.test(`${e}
152
+ ${t}`)}function at(e){return zn.test(e.commands.join(`
153
+ `))}function ti(e){return Oo.test(e)}function ni(e){let t=e.toLowerCase();return t.includes("naming")||t.includes("comment")||t.includes("local-context")||t.includes("codebase-map")}function Qn(e){let t=Ba.posix.basename(e);return fe(t,No)?{path:e,kind:"typecheck",capabilities:["typecheck"]}:fe(t,Po)?{path:e,kind:"lint",capabilities:["lint"]}:fe(t,Ho)?{path:e,kind:"format",capabilities:["format"]}:fe(t,Mo)?{path:e,kind:"test",capabilities:["test"]}:fe(t,Do)?{path:e,kind:"manifest",capabilities:["project-manifest"]}:null}function Zn(e){let t=e.toLowerCase();return t==="docs/architecture.md"||t==="docs/overview.md"||t==="docs/meta-harness.md"||t==="docs/ai/codebase-map.md"||t==="docs/ai/ai-system.md"||t.includes("/adr")||t.includes("architecture")||t.includes("codebase-map")||t.includes("design")}function es(e){let t=e.toLowerCase();return t==="docs/ai/codebase-map.md"||t==="docs/ai/ai-system.md"||t==="docs/overview.md"||t.endsWith("/adr/index.md")||t.endsWith("/adrs/index.md")}function Fe(e){if(!ot(e))return{};let t={};for(let[n,s]of Object.entries(e))typeof s=="string"&&(t[n]=s);return t}function ts(e){if(e===null)return{path:null,scripts:{},dependencies:[],devDependencies:[]};try{let t=JSON.parse(e);if(!ot(t))return{path:"package.json",scripts:{},dependencies:[],devDependencies:[]};let n=Fe(t.scripts),s=Object.keys(Fe(t.dependencies)).toSorted(),r=Object.keys(Fe(t.devDependencies)).toSorted();return{path:"package.json",scripts:n,dependencies:s,devDependencies:r}}catch{return{path:"package.json",scripts:{},dependencies:[],devDependencies:[]}}}import{stat as Va}from"node:fs/promises";import za from"node:path";async function B(e,t,n,s,r){let o=za.join(e,t),i=await Va(o),a=await D(e,t),c={path:t,kind:n,layer:s,capabilities:r,bytes:i.size};return a!==null&&(c.lines=Xo(a)),c}function ns(e){let t=[],n=/^\s*-\s*run:\s*(.+)$/,s=/^\s*-\s*run:\s*[>|]/,r=!1;for(let o of e.split(/\r?\n/)){let i=o.match(n);if(i!==null){t.push(i[1]?.trim()??""),r=!1;continue}if(s.test(o)){r=!0;continue}r&&(/^\s{6,}\S/.test(o)?t.push(o.trim()):/^\s*-\s/.test(o)&&(r=!1))}return t.filter(o=>o.length>0)}async function ss(e,t){let n=await D(e,t);return n===null?null:{path:t,commands:ns(n),content:n}}function ct(e){let t=Object.keys(e.packageJson.scripts),n=t.filter(i=>/(^|:)(typecheck|lint|format|check)(:|$)/i.test(i)),s=t.filter(i=>/(^|:)(test|e2e)(:|$)/i.test(i)),r=t.filter(i=>it(i,e.packageJson.scripts[i]??"")),o=e.workflows.filter(at).map(i=>i.path).toSorted();return{surfaces:e.surfaces,enforcement:{scripts:n.toSorted(),configs:e.configs.filter(i=>i.kind==="typecheck"||i.kind==="lint").map(i=>i.path).toSorted(),ciWorkflows:e.workflows.filter(i=>/(typecheck|lint|format|check)/i.test(i.commands.join(`
154
+ `))).map(i=>i.path).toSorted()},validation:{scripts:s.toSorted(),configs:e.configs.filter(i=>i.kind==="test").map(i=>i.path).toSorted(),ciWorkflows:e.workflows.filter(i=>/(npm test|npm run test|vitest|jest|playwright|cypress)/i.test(i.commands.join(`
155
+ `))).map(i=>i.path).toSorted()},memory:{docs:e.memoryDocs.toSorted(),indexes:e.memoryIndexes.toSorted()},localContext:{conventions:e.localContextConventions.toSorted(),nestedAgentsFiles:e.nestedAgentsFiles.toSorted()},correctionLoop:{scripts:r.toSorted(),prTemplates:e.prTemplates.toSorted(),ciWorkflows:o,maintenanceScripts:e.guidanceMaintenanceScripts.toSorted(),prTemplateChecks:e.aiHarnessPrTemplates.toSorted(),guidanceCiWorkflows:o}}}async function rs(e){let t=await pe(e),n=ts(await D(e,"package.json")),s=[],r=[],o=[],i=[],a=[],c=[],l=[],p=[],f=[],m={customChecker:!1,packageScript:!1,lintRules:!1,stopHook:!1,guidance:!1};m.packageScript=Object.entries(n.scripts).some(([d,g])=>/(^|:)(lint:jsdoc|check:jsdoc)(:|$)/i.test(d)||/find-missing-jsdoc|check-jsdoc-files/i.test(g));for(let d of t){let g=Qn(d);if(g!==null){let S={...g},A=await D(e,d);g.kind==="typecheck"&&A!==null&&/"strict"\s*:\s*true/.test(A)&&(S.capabilities=[...g.capabilities,"strict-typecheck"]),g.kind==="lint"&&A!==null&&/jsdoc\/require-(returns|param)/i.test(A)&&(m.lintRules=!0),s.push(S),f.push(await B(e,d,"enforcement","config",S.capabilities))}if(Zo(d)){let S=await ss(e,d);if(S!==null){r.push(S);let A=await B(e,d,"workflow","automation",["ci-workflow"]);f.push(A)}}if(ei(d)){o.push(d);let S=await D(e,d);S!==null&&ti(S)&&i.push(d);let A=await B(e,d,"automation","pull-request",["pr-template"]);f.push(A)}if(d.endsWith(".md")&&Zn(d)&&(a.push(d),es(d)&&c.push(d),f.push(await B(e,d,"memory","docs",["memory"]))),d.endsWith(".md")&&ni(d)&&l.push(d),(d==="scripts/find-missing-jsdoc/analyzeFile.ts"||d==="scripts/find-missing-jsdoc/check-jsdoc-files.bun.ts")&&(m.customChecker=!0),(d==="docs/ai/code-comment-best-practices.md"||d==="skills/code-comment-best-practices/SKILL.md")&&(m.guidance=!0),d.startsWith(".github/hooks/")&&d.endsWith(".json")){let S=await D(e,d);S!==null&&/lint-on-stop|find-missing-jsdoc|jsdoc/i.test(S)&&(m.stopHook=!0)}if(d.endsWith("/AGENTS.md")){p.push(d);let S=await B(e,d,"local-context","nested-entry",["nested-agents-md"]);f.push(S)}}return n.path!==null&&await Qo(e,n.path)&&f.push(await B(e,n.path,"automation","project",["package-scripts"])),{packageJson:n,configs:s.toSorted((d,g)=>d.path.localeCompare(g.path)),workflows:r.toSorted((d,g)=>d.path.localeCompare(g.path)),prTemplates:o,guidanceMaintenanceScripts:Object.entries(n.scripts).filter(([d,g])=>it(d,g)).map(([d])=>d).toSorted(),aiHarnessPrTemplates:i.toSorted(),guidanceCiWorkflows:r.filter(d=>at(d)).map(d=>d.path).toSorted(),memoryDocs:a,memoryIndexes:c.toSorted(),localContextConventions:l.toSorted(),nestedAgentsFiles:p,surfaces:f.toSorted((d,g)=>d.path.localeCompare(g.path)),jsdocEnforcement:m}}import Xa from"node:path";import{readdir as qa}from"node:fs/promises";import Ka from"node:path";async function os(e,t){let n=[];try{n=await qa(Ka.join(e,t),{withFileTypes:!0})}catch{return[]}return n.filter(s=>s.isFile()).map(s=>`${t}/${s.name}`)}import{readFile as Ya,stat as Ja}from"node:fs/promises";import ui from"node:path";var si=[".claude/settings.json",".claude/settings.local.json"],ri=[".env",".env.local",".env.development",".env.development.local",".env.production",".env.production.local",".env.test"],oi=[".gitleaks.toml",".github/gitleaks.toml",".github/secret_scanning.yml",".github/secret_scanning.yaml"],ii=[".pre-commit-config.yaml",".pre-commit-config.yml"],ai=["config/worker-vars.list","config/env-secrets.dev.list","config/env-secrets.staging.list","config/env-secrets.production.list","scripts/env/run-with-env/run-with-env.bun.ts"],ci=/gitleaks|trufflehog|detect-secrets|ggshield/i,li=/(?:\.\/)?(?:[\w.-]+\/)+[\w.-]+\.(?:tsx?|mts|cts|mjs|cjs|js|sh|bash|py)/g;async function F(e,t){try{return await Ya(ui.join(e,t),"utf8")}catch{return null}}async function O(e,t){try{return(await Ja(ui.join(e,t))).isFile()}catch{return!1}}function V(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function lt(e){try{return{ok:!0,value:JSON.parse(e)}}catch{return{ok:!1,value:null}}}function di(e){let{permissions:t}=e;return!V(t)||!Array.isArray(t.allow)?[]:t.allow.filter(n=>typeof n=="string")}function pi(e){let{permissions:t}=e;return!V(t)||typeof t.defaultMode!="string"?null:t.defaultMode}function ut(e){let t=e.match(li)??[];return[...new Set(t.map(n=>n.replace(/^\.\//,"")))]}async function fi(e,t,n){let s=await O(e,n),r=s?await F(e,n):null;return{reference:{source:t,path:n,exists:s},content:r}}async function is(e,t){for(let n of await os(e,".claude/hooks")){let s=await F(e,n);s!==null&&t.push({source:n,path:n,isStop:/stop/i.test(Xa.posix.basename(n)),content:s})}}async function as(e){for(let t of ai)if(await O(e,t))return!0;return!1}function cs(e){let t=e.hooks;if(t===void 0)return{hooks:[],malformed:!1};if(!V(t))return{hooks:[],malformed:!0};let n=[],s=!1;for(let[r,o]of Object.entries(t)){if(!Array.isArray(o)){s=!0;continue}for(let i of o){if(!V(i)||!Array.isArray(i.hooks)){s=!0;continue}for(let a of i.hooks){if(!V(a)||typeof a.command!="string"){s=!0;continue}n.push({event:r,command:a.command})}}}return{hooks:n,malformed:s}}async function ls(e,t){let n=await F(e,t);if(n===null)return null;let{ok:s,value:r}=lt(n);if(!s||!V(r))return{path:t,valid:!1,allow:[],defaultMode:null,hooks:[],hooksMalformed:!1};let{hooks:o,malformed:i}=cs(r);return{path:t,valid:!0,allow:di(r),defaultMode:pi(r),hooks:o,hooksMalformed:i}}async function us(e){let t=".codex/hooks.json",n=await F(e,t);if(n===null)return null;let{ok:s,value:r}=lt(n);if(!s)return{path:t,valid:!1,referencedScripts:[]};let o=[];for(let i of ut(JSON.stringify(r))){let a=await O(e,i);o.push({source:t,path:i,exists:a})}return{path:t,valid:!0,referencedScripts:o}}async function ds(e){let t=[];for(let n of ri)await O(e,n)&&t.push(n);return t}async function ps(e,t){let n=[],s=[],r=t.flatMap(o=>o.hooks.map(i=>({surface:o,hook:i})));for(let{surface:o,hook:i}of r){let a=`${o.path} (${i.event} hook)`,c=[i.command];for(let l of ut(i.command)){let{reference:p,content:f}=await fi(e,a,l);s.push(p),f!==null&&c.push(f)}n.push({source:a,path:null,isStop:i.event==="Stop",content:c.join(`
156
+ `)})}return{hookScripts:n,referencedClaudeScripts:s}}async function fs(e){let t=[];for(let n of oi)await O(e,n)&&t.push(n);for(let n of ii){let s=await F(e,n);s!==null&&ci.test(s)&&t.push(n)}return t}async function _e(e){let t=[];for(let l of si){let p=await ls(e,l);p!==null&&t.push(p)}let{hookScripts:n,referencedClaudeScripts:s}=await ps(e,t);await is(e,n);let[r,o,i,a,c]=await Promise.all([us(e),F(e,".gitignore"),ds(e),fs(e),as(e)]);return{claudeSettings:t,referencedClaudeScripts:s,hookScripts:n,codexHooks:r,gitignore:o,envFilesPresent:i,secretScanningFiles:a,usesKeyringSecrets:c}}import{readFile as Qa,stat as Za}from"node:fs/promises";import mi from"node:path";async function Z(e){let t=mi.join(e,".github/hooks"),n=!1;try{n=(await Za(t)).isDirectory()}catch{n=!1}let s=mi.join(e,".vscode/settings.json"),r=null,o=null;try{let i=await Qa(s,"utf8");o=i,r=Ce(i)}catch{r=null,o=null}return{settings:r,settingsRaw:o,hooksDirExists:n}}function Ne(e,t,n,s){return{ruleId:e,severity:"warn",message:`${t} has ${String(n)} lines; keep root adapters thin (max ${String(W)}).`,file:t,line:null,harnesses:[s],hint:"Move detailed guidance to docs/ai/ and skills/; keep the adapter as a pointer."}}import{extname as gi}from"node:path";function ms(e){let t=[],n=e.split(`
157
+ `);for(let s=0;s<n.length;s+=1){let r=Uo.exec(n[s]??"");r!==null&&t.push({line:s+1,alias:r[0]})}return t}function gs(e){if(!Bo.test(e)||zo.test(e))return null;let t=e.split(`
158
+ `);for(let n=0;n<t.length;n+=1)if(Vo.test(t[n]??""))return n+1;return null}var Pe={findings:[],records:[]},ec={id:"model-interface-pinned",title:"Model interface pinned",severity:"warn",category:"reliability",dimension:"guardrails",harnesses:[],check(e){let t=e.boundary?.sourceFiles;if(t===void 0)return Pe;let n=[];for(let s of t)for(let{line:r,alias:o}of ms(s.content))n.push({ruleId:"model-interface-pinned",severity:"warn",message:`${s.path} references the floating model alias "${o}"; the model behind a "latest" tag can change without notice.`,file:s.path,line:r,harnesses:[],hint:"Pin a dated/versioned model snapshot (e.g. a -YYYYMMDD or explicit-version id) so model upgrades are a deliberate, reviewable change."});return{findings:n,records:[]}}},tc={id:"llm-output-schema-validated",title:"LLM output schema-validated",severity:"warn",category:"reliability",dimension:"guardrails",harnesses:[],check(e){let t=e.boundary?.sourceFiles;if(t===void 0)return Pe;let n=[];for(let s of t){if(!Le.has(gi(s.path)))continue;let r=gs(s.content);r!==null&&n.push({ruleId:"llm-output-schema-validated",severity:"warn",message:`${s.path} consumes LLM/tool output (line ${String(r)}) without a schema validator; a shape change in the model response surfaces as a downstream type error.`,file:s.path,line:r,harnesses:[],hint:"Validate the parsed response against a Zod/Pydantic/JSON-Schema schema at the boundary before reading its fields."})}return{findings:n,records:[]}}},nc={id:"tool-contract-tests-present",title:"Tool contract tests present",severity:"info",category:"reliability",dimension:"guardrails",harnesses:[],check(e){let{boundary:t}=e;if(t===void 0)return Pe;let n=t.sourceFiles.find(r=>Le.has(gi(r.path))&&rt.test(r.content));return n===void 0||t.testFiles.some(r=>qo.test(r.content)&&Ko.test(r.content))?Pe:{findings:[{ruleId:"tool-contract-tests-present",severity:"info",message:`${n.path} declares model-callable tools, but no test exercises tool-call argument validation or error responses \u2014 only happy-path behavior is covered.`,file:n.path,line:null,harnesses:[],hint:"Add tests that feed malformed or missing tool-call arguments and assert the error path, per declared tool."}],records:[]}}},hi=[ec,tc,nc];function hs(e){let t=[];for(let n of Ue){if(!E(e,n))continue;let s=h(e,n);s===null||eo(s)||t.push({ruleId:"adapter-points-to-shared",severity:"warn",message:`${n} should reference AGENTS.md and docs/ai/rules.md.`,file:n,line:null,harnesses:[],hint:"Keep adapters thin; point at shared layers instead of duplicating rules."})}return{findings:t,records:[]}}function ys(e){let t=[];for(let n of ue(e,"agents/")){if(!n.endsWith(".agent.md"))continue;let s=h(e,n);if(s===null)continue;let r=Be(s);if(r===null){t.push({ruleId:"agent-frontmatter",severity:"error",message:`${n} is missing YAML frontmatter.`,file:n,line:null,harnesses:[]});continue}ce(r,"name")||t.push({ruleId:"agent-frontmatter",severity:"error",message:`${n} is missing a name field in frontmatter.`,file:n,line:null,harnesses:[]}),ce(r,"description")||t.push({ruleId:"agent-frontmatter",severity:"error",message:`${n} is missing a description field in frontmatter.`,file:n,line:null,harnesses:[]})}return{findings:t,records:[]}}function Ss(e){if(!N(e)||!E(e,"AGENTS.md"))return{findings:[],records:[]};let t=h(e,"AGENTS.md");return t!==null&&Ve(t)?{findings:[],records:[]}:{findings:[{ruleId:"agents-md-mentions-skills",severity:"info",message:"AGENTS.md should point at docs/ai/available-skills.md or the qmd search workflow.",file:"AGENTS.md",line:null,harnesses:[],hint:"Document how agents discover skills (index doc or npm run qmd -- search)."}],records:[]}}function ks(e){if(!e.harnesses.includes("claude")||!E(e,"CLAUDE.md"))return{findings:[],records:[]};let t=h(e,"CLAUDE.md");return t!==null&&ze(t)?{findings:[],records:[]}:{findings:[{ruleId:"claude-agent-routing",severity:"info",message:"CLAUDE.md should include an Agent Routing table pointing at agents/*.agent.md.",file:"CLAUDE.md",line:null,harnesses:["claude"],hint:"Add a markdown table mapping task types to shared agents/*.agent.md files."}],records:[]}}var yi=/!?\[([^\]]*)\]\(([^)]+)\)/g;function ee(e){let t=[],n=yi.exec(e);for(;n!==null;){let[s]=n;s.startsWith("!")||t.push({label:n[1]??"",href:(n[2]??"").trim()}),n=yi.exec(e)}return t}var sc=new Set(["url","path","href","link","..."]);function He(e){return e.length===0||sc.has(e.toLowerCase())||e.startsWith("http://")||e.startsWith("https://")||e.startsWith("mailto:")||e.startsWith("tel:")?!0:(e.split("#")[0]??"").length===0}function xs(e){let t=e.replaceAll("\\","/").split("/"),n=[];for(let s of t)if(!(s===""||s===".")){if(s===".."){n.pop();continue}n.push(s)}return n.join("/")}function Me(e,t){let n=(t.split("#")[0]??"").trim();if(n.length===0)return null;let s=n;try{s=decodeURIComponent(n)}catch{s=n}if(s.startsWith("/"))return s.slice(1).replaceAll("\\","/");let r=e.includes("/")?e.slice(0,e.lastIndexOf("/")):"",o=r.length===0?s:`${r}/${s}`;return xs(o)}function ws(e){return!e.endsWith(".md")&&!e.endsWith(".mdc")?!1:e.startsWith("docs/")||e.includes("/docs/")}function Rs(e,t){for(let n of ee(t)){if(He(n.href))continue;let s=Me(e,n.href);if(s!==null&&ws(s))return!0}return!1}var rc=50;function bs(e){let t=[];for(let n of e.files){if(!n.path.startsWith("skills/")||!n.path.endsWith("SKILL.md")||(n.lines??0)<=rc)continue;let s=h(e,n.path);s===null||Rs(n.path,s)||t.push({ruleId:"skill-doc-deep-links",severity:"info",message:`${n.path} does not deep-link into a durable doc under docs/.`,file:n.path,line:null,harnesses:[],hint:"Pair the skill with a docs/ reference and link it (for example a **Details:** link to a docs/ page) instead of inlining all detail."})}return{findings:t,records:[]}}function Cs(e){let t=[];for(let n of ue(e,"skills/")){if(!n.endsWith("/SKILL.md")&&!n.endsWith("SKILL.md"))continue;let s=h(e,n);if(s===null)continue;let r=Be(s);if(r===null){t.push({ruleId:"skill-frontmatter",severity:"error",message:`${n} is missing YAML frontmatter.`,file:n,line:null,harnesses:[]});continue}ce(r,"name")||t.push({ruleId:"skill-frontmatter",severity:"error",message:`${n} is missing a name field in frontmatter.`,file:n,line:null,harnesses:[]}),ce(r,"description")||t.push({ruleId:"skill-frontmatter",severity:"error",message:`${n} is missing a description field in frontmatter.`,file:n,line:null,harnesses:[]})}return{findings:t,records:[]}}function As(e){let t=[];for(let n of ue(e,"skills/")){if(!n.endsWith("SKILL.md"))continue;let s=U(e,n);s!==null&&s>bt&&t.push({ruleId:"skill-line-count",severity:"warn",message:`${n} has ${String(s)} lines; keep skills under ${String(bt)}.`,file:n,line:null,harnesses:[],hint:"Move detail to docs/; keep SKILL.md as a pointer."})}return{findings:t,records:[]}}var Si="docs/ai/available-skills.md";function Is(e){return N(e)?E(e,Si)?{findings:[],records:[]}:{findings:[{ruleId:"skills-index",severity:"info",message:`${Si} is missing; add a skill slug index when using skills/.`,file:null,line:null,harnesses:[],hint:"List each skills/<slug>/ folder so agents can pick a minimal skill set."}],records:[]}:{findings:[],records:[]}}var oc=["AGENTS.md","CLAUDE.md","GEMINI.md",".github/copilot-instructions.md",".agent/README.md"],ki=["IMPORTANT","CRITICAL","MANDATORY","REQUIRED","MUST NOT","MUST","NEVER","ALWAYS","SHALL","DO NOT"],xi=.03,wi=40,Ri=[{pattern:/\byou are an? (?:expert|senior|world[- ]class|10x|highly skilled|seasoned|professional)\b/i,label:"identity framing (\u201Cyou are a/an \u2026\u201D)"},{pattern:/\bact as an?\b/i,label:"roleplay framing (\u201Cact as a \u2026\u201D)"},{pattern:/\bas an ai (?:language model|assistant)\b/i,label:"AI self-reference"},{pattern:/\bworld[- ]class\b/i,label:"superlative filler (\u201Cworld-class\u201D)"}];function dt(e){return e.replaceAll(/```[\s\S]*?```/g," ")}function bi(e){let t=e.match(/\S+/g);return t===null?0:t.length}function me(e){return oc.filter(t=>h(e,t)!==null)}function Es(e){let t=0;for(let n of ki){let s=e.match(new RegExp(`\\b${n}\\b`,"g"));s!==null&&(t+=s.length)}return t}function vs(e){let t=[];for(let n of me(e)){let s=h(e,n);if(s===null)continue;let r=dt(s),o=bi(r);if(o<wi)continue;let i=Es(r),a=i/o;if(a<=xi)continue;let c=(a*100).toFixed(1);t.push({ruleId:"emphasis-keyword-density",severity:"info",message:`${n} uses ${String(i)} all-caps emphasis keyword(s) across ${String(o)} words (${c}%); emphasis loses force when overused.`,file:n,line:null,harnesses:[],hint:"Reserve IMPORTANT/MUST/NEVER for the few rules that truly need them; rewrite the rest as plain, action-oriented instructions."})}return{findings:t,records:[]}}function Ts(e){let t=[];for(let n of me(e)){let s=h(e,n);if(s===null)continue;let r=dt(s),o=Ri.filter(({pattern:i})=>i.test(r)).map(({label:i})=>i);o.length!==0&&t.push({ruleId:"identity-language-absent",severity:"info",message:`${n} contains identity/roleplay filler: ${o.join(", ")}.`,file:n,line:null,harnesses:[],hint:"Drop identity framing; state what to do, not who to be. Action-oriented rules outperform persona prompts."})}return{findings:t,records:[]}}var Ci=[{id:"emphasis-keyword-density",title:"Emphasis-keyword density",severity:"info",category:"instruction-quality",dimension:"maintainability",harnesses:[],check:vs},{id:"identity-language-absent",title:"No identity-language filler",severity:"info",category:"instruction-quality",dimension:"maintainability",harnesses:[],check:Ts}];var Ai=/\bask\s+(?:the\s+)?(?:user|human|maintainer)\b|\bask\s+for\s+clarif|\brequest\s+clarification|\bseek\s+clarification|\bclarifying\s+questions?|\bwhen\s+(?:in\s+doubt|unsure|uncertain)\b|\bstop\s+and\s+ask\b|\bask\s+before\s+(?:assum|guess|proceed)|\bescalat(?:e|ion)\b|\b(?:ambiguous|unclear|contradictory|conflicting|incomplete)\b[^.\n]{0,40}\b(?:ask|clarif|escalat|confirm)/i,Ii=/\bmax[_\s-]?(?:iterations?|steps?|turns?|calls?|requests?|attempts?|retries|tokens?|cost|budget)\b|\bmax_calls_per_minute\b|\bcurrency_limits?\b|\brate[_\s-]?limit|\bbudget[_\s-]?(?:cap|limit)|\biteration[_\s-]?(?:cap|limit)|\bcost[_\s-]?(?:cap|limit)/i,Ei=/\blanggraph\b|\bcrewai\b|\bautogen\b|\bAgentExecutor\b|\bcreateReactAgent\b|@modelcontextprotocol|\bmcp\.server\b|\bserver\.tool\s*\(/i;function te(e){return[...e.fileContents.values()].join(`
159
+ `)}function De(e){return(e.boundary?.sourceFiles??[]).map(t=>t.content).join(`
160
+ `)}var vi=/\bmcpservers\b|\.mcp\.json\b|\bmcp__|modelcontextprotocol|\bmcp\s+servers?\b/i,Ti=/\ballow[\s_-]?list\b|\bmcpservers\b|allowed[_\s-]?tools|permitted[_\s-]?tools|"allow"\s*:|pinned\s+(?:tool|server|mcp)/i,Li=/\bmem0\b|memory\.(?:add|write|store|save|upsert)\b|vector[\s_-]?(?:store|db|database)|\bupsert\s*\(|\bembeddings?\b|\bpinecone\b|\bweaviate\b|\bchroma(?:db)?\b|\bqdrant\b|persistent\s+memory/i,Fi=/\bprovenance\b|\bquarantin|\buntrusted\b|\btaint(?:ed)?\b|trust[\s_-]?(?:level|tag|boundary)|source[\s_-]?tag|re-?validat/i,_i=/\bfetch\s*\(|\bwebfetch\b|\baxios\b|requests?\.get\b|\burllib\b|\bhttpx\b|\bscrap(?:e|ing)\b|\bcrawl|retriev(?:e|al)|web[\s_-]?search/i,Ni=/\bexec(?:Sync)?\s*\(|child_process|\bspawn\s*\(|\bsubprocess\b|os\.system|writeFileSync|\bfs\.write|\bunlink\s*\(|\brm\s+-rf\b/i,Pi=/saniti[sz]|\bvalidat|\ballow[\s_-]?list\b|\bescape\b|\bconfirm|\bapproval\b|\bguard(?:rail)?\b/i,Hi=/force[\s_-]?push|push\s+--force|\brm\s+-rf\b|delete\s+from\b|\.delete\s*\(|\bdestroy\s*\(|\bstripe\b|\bpayment|\bcharge\s*\(|wire\s+transfer|send[_\s-]?email|\bsendmail\b|\bdeploy\b|drop\s+table/i,Mi=/human[\s_-]?in[\s_-]?the[\s_-]?loop|\bconfirm(?:ation)?\b|\bapproval\b|\bescalat|requires?\s+(?:approval|confirmation)|dry[\s_-]?run|are\s+you\s+sure/i;function Ls(e){return e.files.some(n=>n.layer==="agents")?!0:(e.boundary?.sourceFiles??[]).some(n=>rt.test(n.content)||Ei.test(n.content))}function pt(e,t,n,s){return{findings:[{ruleId:e,severity:t,message:n,file:null,line:null,harnesses:[],hint:s}],records:[]}}var $={findings:[],records:[]},ic={id:"escalation-protocol-discoverability",title:"Escalation protocol discoverable",severity:"info",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=me(e);return t.length===0||Ai.test(te(e))?$:{findings:[{ruleId:"escalation-protocol-discoverability",severity:"info",message:"No discoverable escalation protocol in guidance: nothing documents when or how the agent should ask for clarification on missing, ambiguous, or contradictory specs.",file:t[0]??null,line:null,harnesses:[],hint:"Document an 'ask before guessing' protocol in AGENTS.md or the rules doc \u2014 the epistemic counterpart to action confirmation (HiL-Bench's 53-82pp finding)."}],records:[]}}},ac={id:"agent-resource-budget-caps",title:"Agent resource budget caps",severity:"info",category:"security",dimension:"guardrails",harnesses:[],check(e){if(!Ls(e))return $;let t=(e.boundary?.sourceFiles??[]).map(n=>n.content).join(`
161
+ `);return Ii.test(`${te(e)}
162
+ ${t}`)?$:{findings:[{ruleId:"agent-resource-budget-caps",severity:"info",message:"An agent/tool surface is present but no resource caps are declared (max iterations, cost, or rate limit); an unbounded loop is a resource-drain (R7) risk.",file:null,line:null,harnesses:[],hint:"Declare max-iteration, max-cost, or rate-limit caps, mirroring OAP's max_calls_per_minute / currency_limits."}],records:[]}}},cc={id:"tool-allowlist-inventory",title:"Tool allowlist inventory",severity:"info",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=`${te(e)}
163
+ ${De(e)}`;return!vi.test(t)||Ti.test(t)?$:pt("tool-allowlist-inventory","info","Repo references MCP/tool servers but declares no explicit, pinned tool allowlist; arbitrary tool discovery widens the attack surface (R1/R3).","Declare an explicit allowlist of tools/MCP servers with pinned versions instead of allowing arbitrary discovery.")}},lc={id:"untrusted-input-action-boundary",title:"Untrusted input / action boundary",severity:"warn",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=De(e);if(!(_i.test(t)&&Ni.test(t)))return $;let s=`${te(e)}
164
+ ${t}`;return Pi.test(s)?$:pt("untrusted-input-action-boundary","warn","Source ingests external/untrusted content and takes actions (exec, file write) with no sanitization, validation, or confirmation in evidence (R2/R3 unconstrained data flow).","Sanitize, allow-list, or confirm untrusted content before it reaches shell exec, file writes, or tool dispatch.")}},uc={id:"memory-write-provenance",title:"Memory write provenance",severity:"info",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=`${te(e)}
165
+ ${De(e)}`;return!Li.test(t)||Fi.test(t)?$:pt("memory-write-provenance","info","Repo writes to persistent agent memory but shows no provenance/trust tagging or re-validation; memory writes from untrusted sources can later be read as trusted (R6).","Tag or quarantine memory writes derived from untrusted sources and re-validate them before trusted reads.")}},dc={id:"high-impact-action-confirmation",title:"High-impact action confirmation",severity:"warn",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=De(e);if(!Hi.test(t))return $;let n=`${te(e)}
166
+ ${t}`;return Mi.test(n)?$:pt("high-impact-action-confirmation","warn","Source performs high-impact actions (deletion, payment, force-push, deploy, external send) with no human-in-the-loop confirmation or escalation in evidence (R6/R7).","Gate high-impact actions behind an explicit confirmation/escalation step, not just allow/deny (OWASP LLM06).")}},Di=[ic,ac,cc,lc,uc,dc];var pc=/\b(?:curl|wget|ncat|telnet|scp)\b|\bnc\s|Invoke-WebRequest|\bfetch\s*\(|\baxios\b|http\.request|urllib|requests\.(?:get|post|put|patch)/i,fc=/localhost|127\.0\.0\.1|0\.0\.0\.0|::1/i;function Fs(e){let t=[];for(let n of e.content.split(/\r?\n/)){let s=n.trim();pc.test(s)&&!fc.test(s)&&t.push(s)}return t}var mc=new Set(["Bash","Write","Edit","MultiEdit","NotebookEdit"]);function _s(e){let t=e.trim();if(t==="")return!1;if(t==="*")return!0;if(t.startsWith("mcp__"))return t.includes("*");let n=t.match(/^([A-Za-z_][\w-]*)(?:\((.*)\))?$/);if(n===null)return!1;let[,s="",r]=n;if(!mc.has(s))return!1;if(r===void 0)return!0;let o=r.trim();return o===""||o==="*"||o===":*"}var gc=/^[0-9a-f]{40}$/i;function Ns(e){let t=new Set,n=/^\s*-?\s*uses:\s*['"]?([^'"\s#]+)['"]?/gm;for(let s of e.matchAll(n)){let[,r]=s;if(r===void 0||r.startsWith("./")||r.startsWith("docker://"))continue;let o=r.includes("@")?r.slice(r.lastIndexOf("@")+1):"";gc.test(o)||t.add(r)}return[...t]}var G={findings:[],records:[]},hc=new Set(["bypassPermissions","acceptEdits"]),yc="stop_hook_active";function ne(e){return e.security??null}var Sc={id:"no-dangerous-auto-approve",title:"No dangerous auto-approve permissions",severity:"error",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=ne(e);if(t===null)return G;let n=[];for(let s of t.claudeSettings){s.defaultMode!==null&&hc.has(s.defaultMode)&&n.push({ruleId:"no-dangerous-auto-approve",severity:"error",message:`${s.path} sets permissions.defaultMode "${s.defaultMode}", auto-approving actions without prompting.`,file:s.path,line:null,harnesses:["claude"],hint:'Use "default" or "plan" mode and allow-list specific commands instead of bypassing prompts.'});for(let r of s.allow.filter(_s))n.push({ruleId:"no-dangerous-auto-approve",severity:"error",message:`${s.path} auto-approves "${r}", a blanket grant over a dangerous capability.`,file:s.path,line:null,harnesses:["claude"],hint:"Scope allow-list entries to specific commands, e.g. Bash(npm run test:*) instead of Bash(*)."})}return{findings:n,records:[]}}},kc={id:"hook-no-network-exfil",title:"Hooks do not exfiltrate over the network",severity:"error",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=ne(e);if(t===null)return G;let n=[];for(let s of t.hookScripts){let[r]=Fs(s);r!==void 0&&n.push({ruleId:"hook-no-network-exfil",severity:"error",message:`${s.source} makes a network call (\`${r.slice(0,80)}\`); hooks run automatically and can exfiltrate repo data.`,file:s.path,line:null,harnesses:[],hint:"Remove the network call or restrict it to localhost; move outbound calls into explicit, reviewable steps."})}return{findings:n,records:[]}}},xc={id:"hook-stop-circuit-breaker",title:"Stop hooks guard against infinite loops",severity:"warn",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=ne(e);if(t===null)return G;let n=[];for(let s of t.hookScripts)!s.isStop||s.content.includes(yc)||n.push({ruleId:"hook-stop-circuit-breaker",severity:"warn",message:`${s.source} is a Stop hook that never checks stop_hook_active; a blocking Stop hook can loop the agent indefinitely.`,file:s.path,line:null,harnesses:[],hint:"Read stop_hook_active from the hook input and exit without blocking when it is true."});return{findings:n,records:[]}}},wc={id:"env-files-gitignored",title:"Env files are gitignored",severity:"warn",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=ne(e);if(t===null)return G;let s=t.gitignore!==null&&/^\s*!?[*.]*\.env(?:[.*]|\b|\/)?/m.test(t.gitignore)?[]:t.envFilesPresent;if(s.length===0)return G;let r=t.usesKeyringSecrets?"This repo uses keyring-managed secrets; delete the committed .env file rather than relying on it.":"Gitignore `.env`/`.env.*`, or move secrets to an OS keyring (the run-with-env pattern) so they never touch disk.";return{findings:[{ruleId:"env-files-gitignored",severity:"warn",message:`${s.join(", ")} present but not gitignored; secrets risk being committed.`,file:s[0]??null,line:null,harnesses:[],hint:r}],records:[]}}};function Rc(e){return e.some(t=>/gitleaks|trufflehog|detect-secrets|ggshield/i.test(t.content))}var bc={id:"secret-scanning-configured",title:"Secret scanning is configured",severity:"warn",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=ne(e);if(t===null)return G;let n=e.intelligenceLayer?.workflows??[];return t.secretScanningFiles.length>0||Rc(n)?G:{findings:[{ruleId:"secret-scanning-configured",severity:"warn",message:"No secret-scanning configuration found (gitleaks, trufflehog, detect-secrets, or a pre-commit secret hook).",file:null,line:null,harnesses:[],hint:"Add a gitleaks/trufflehog CI step or a detect-secrets pre-commit hook so committed credentials are caught."}],records:[]}}},Cc={id:"no-pull-request-target",title:"No risky pull_request_target workflows",severity:"error",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=e.intelligenceLayer?.workflows??[],n=[];for(let s of t)/\bpull_request_target\b/.test(s.content)&&n.push({ruleId:"no-pull-request-target",severity:"error",message:`${s.path} triggers on pull_request_target, which runs with repo secrets against untrusted PR code.`,file:s.path,line:null,harnesses:[],hint:"Prefer pull_request; if pull_request_target is required, never check out or execute PR head code with secrets in scope."});return{findings:n,records:[]}}},Ac={id:"actions-sha-pinned",title:"GitHub Actions pinned to commit SHAs",severity:"warn",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=e.intelligenceLayer?.workflows??[],n=[];for(let s of t){let r=Ns(s.content);r.length!==0&&n.push({ruleId:"actions-sha-pinned",severity:"warn",message:`${s.path} uses actions pinned to mutable refs: ${r.join(", ")}.`,file:s.path,line:null,harnesses:[],hint:"Pin each action to a full 40-character commit SHA (e.g. actions/checkout@<sha>) to prevent tag-hijack supply-chain attacks."})}return{findings:n,records:[]}}},Ic={id:"claude-hooks-valid",title:"Claude hooks config is valid",severity:"error",category:"hooks",dimension:"guardrails",harnesses:["claude"],check(e){let t=ne(e);if(t===null)return G;let n=[];for(let s of t.claudeSettings){if(!s.valid){n.push({ruleId:"claude-hooks-valid",severity:"error",message:`${s.path} is not valid JSON.`,file:s.path,line:null,harnesses:["claude"],hint:"Fix the JSON syntax; an unparseable settings file disables every configured hook silently."});continue}s.hooksMalformed&&n.push({ruleId:"claude-hooks-valid",severity:"error",message:`${s.path} has a malformed hooks block; entries must be { matcher?, hooks: [{ type, command }] }.`,file:s.path,line:null,harnesses:["claude"],hint:"Match the documented hooks schema so the configured commands actually run."})}for(let s of t.referencedClaudeScripts.filter(r=>!r.exists))n.push({ruleId:"claude-hooks-valid",severity:"error",message:`${s.source} references missing script ${s.path}.`,file:s.path,line:null,harnesses:["claude"],hint:"Create the script or fix the path; a missing hook command fails open and skips the check."});return{findings:n,records:[]}}},Ec={id:"codex-hooks-valid",title:"Codex hooks config is valid",severity:"error",category:"hooks",dimension:"guardrails",harnesses:["codex"],check(e){let t=ne(e);if(t===null||t.codexHooks===null)return G;let n=t.codexHooks,s=[];n.valid||s.push({ruleId:"codex-hooks-valid",severity:"error",message:`${n.path} is not valid JSON.`,file:n.path,line:null,harnesses:["codex"],hint:"Fix the JSON syntax so the configured codex hooks load."});for(let r of n.referencedScripts.filter(o=>!o.exists))s.push({ruleId:"codex-hooks-valid",severity:"error",message:`${n.path} references missing script ${r.path}.`,file:r.path,line:null,harnesses:["codex"],hint:"Create the script or fix the path so the hook command runs."});return{findings:s,records:[]}}},Oi=[Sc,kc,xc,wc,bc,Cc,Ac,Ic,Ec];var vc={id:"shared-agents-md",title:"Shared AGENTS.md entry point",severity:"warn",category:"structure",dimension:"layering",harnesses:[],check(e){return E(e,"AGENTS.md")?{findings:[],records:[]}:{findings:[{ruleId:"shared-agents-md",severity:"warn",message:"AGENTS.md is missing.",file:null,line:null,harnesses:[],hint:"Add AGENTS.md as the repo-wide AI entry point with workflow, safety, and pointers to canonical docs."}],records:[]}}},Tc={id:"shared-rules-doc",title:"Canonical rules doc",severity:"warn",category:"structure",dimension:"layering",harnesses:[],check(e){return E(e,"docs/ai/rules.md")?{findings:[],records:[]}:{findings:[{ruleId:"shared-rules-doc",severity:"warn",message:"docs/ai/rules.md is missing.",file:null,line:null,harnesses:[],hint:"Add docs/ai/rules.md as the canonical coding-rules reference."}],records:[]}}},Lc={id:"adapter-thin-claude",title:"Thin CLAUDE.md adapter",severity:"warn",category:"adapter",dimension:"layering",harnesses:["claude"],check(e){let t=U(e,"CLAUDE.md");return t===null||t<=W?{findings:[],records:[]}:{findings:[Ne("adapter-thin-claude","CLAUDE.md",t,"claude")],records:[]}}},Fc={id:"adapter-thin-gemini",title:"Thin GEMINI.md adapter",severity:"warn",category:"adapter",dimension:"layering",harnesses:["gemini"],check(e){let t=U(e,"GEMINI.md");return t===null||t<=W?{findings:[],records:[]}:{findings:[Ne("adapter-thin-gemini","GEMINI.md",t,"gemini")],records:[]}}},_c={id:"adapter-thin-copilot",title:"Thin Copilot instructions",severity:"warn",category:"adapter",dimension:"layering",harnesses:["copilot"],check(e){let t=".github/copilot-instructions.md",n=U(e,t);return n===null||n<=W?{findings:[],records:[]}:{findings:[Ne("adapter-thin-copilot",t,n,"copilot")],records:[]}}},Nc={id:"adapter-points-to-shared",title:"Adapters reference shared layers",severity:"warn",category:"adapter",dimension:"layering",harnesses:[],check:hs},Pc={id:"skill-frontmatter",title:"Skill frontmatter",severity:"error",category:"skills",dimension:"maintainability",harnesses:[],check:Cs},Hc={id:"skill-line-count",title:"Skill line budget",severity:"warn",category:"skills",dimension:"maintainability",harnesses:[],check:As},Mc={id:"agent-frontmatter",title:"Agent frontmatter",severity:"error",category:"agents",dimension:"maintainability",harnesses:[],check:ys},Dc={id:"skills-index",title:"Skill slug index",severity:"info",category:"discoverability",dimension:"discoverability",harnesses:[],check:Is},Oc={id:"claude-agent-routing",title:"Claude agent routing table",severity:"info",category:"discoverability",dimension:"discoverability",harnesses:["claude"],check:ks},$c={id:"agents-md-mentions-skills",title:"AGENTS.md skill discovery",severity:"info",category:"discoverability",dimension:"discoverability",harnesses:[],check:Ss},Gc={id:"skill-doc-deep-links",title:"Skills deep-link into docs",severity:"info",category:"discoverability",dimension:"discoverability",harnesses:[],check:bs},$i=[vc,Tc,Lc,Fc,_c,Nc,Pc,Hc,Mc,Dc,Oc,$c,Gc,...Ci,...Oi,...hi,...Di];function Ps(e){let t=e.contextBudget;if(t===void 0)return{findings:[],records:[]};let n=[],s=[];for(let r of t.harnesses)if(r.detected)for(let o of r.files)s.push({checkId:"adapter-context-budget",dimension:"maintainability",curve:"asymptoticDecay",measuredValue:o.lines,referenceValue:t.maxRecommendedFileLines}),!(o.lines<=t.maxRecommendedFileLines)&&n.push({ruleId:"adapter-context-budget",severity:"info",message:`${o.path} contributes ${String(o.lines)} always-loaded lines for ${r.harness}; recommended maximum per file is ${String(t.maxRecommendedFileLines)}.`,file:o.path,line:null,harnesses:[r.harness],hint:"Split detailed guidance into linked docs and keep always-loaded instruction files compact."});return{findings:n,records:s}}function Hs(e){let t=e.contextBudget;if(t===void 0)return{findings:[],records:[]};let n=[],s=[];for(let r of t.harnesses)r.detected&&(s.push({checkId:"always-loaded-budget",dimension:"maintainability",curve:"asymptoticDecay",measuredValue:r.totalLines,referenceValue:r.maxRecommendedLines}),r.status!=="ok"&&n.push({ruleId:"always-loaded-budget",severity:"info",message:`${r.harness} always-loaded context is ${String(r.totalLines)} lines; recommended maximum is ${String(r.maxRecommendedLines)}.`,file:null,line:null,harnesses:[r.harness],hint:"Keep root adapters as short indexes and move deep guidance into linked docs, skills, agents, or workflows."}));return{findings:n,records:s}}async function Ms(e){return e.files.some(n=>n.path.startsWith("agents/"))?await le(e.repoRoot,".github/agents")?{findings:[{ruleId:"no-duplicate-agent-trees",severity:"error",message:".github/agents/ duplicates root agents/; use agents/ only.",file:".github/agents",line:null,harnesses:[],hint:"Remove .github/agents/ and keep canonical agents/ at the repo root."}],records:[]}:{findings:[],records:[]}:{findings:[],records:[]}}async function Ds(e){if(!e.files.some(r=>r.path.startsWith("skills/")))return{findings:[],records:[]};let n=[],s=[".github/skills",".cursor/skills"];for(let r of s)await le(e.repoRoot,r)&&n.push({ruleId:"no-duplicate-skill-trees",severity:"error",message:`${r}/ duplicates root skills/; use skills/ only.`,file:r,line:null,harnesses:[],hint:"Remove the shadow tree and keep canonical skills/ at the repo root."});return{findings:n,records:[]}}var jc=["docs/","skills/","agents/",".cursor/",".github/",".codex/",".agent/",".claude/"],Wc=new Set(["AGENTS.md","CLAUDE.md","GEMINI.md","README.md",".github/copilot-instructions.md"]);function Gi(e){let t=e.replaceAll("\\","/").replace(/\/+$/,"");return Wc.has(t)?!0:jc.some(n=>t===n.slice(0,-1)||t.startsWith(n))}function Oe(e,t){let n=e.split(`
167
+ `);for(let s=0;s<n.length;s+=1){let r=n[s];if(r!==void 0&&r.includes(t))return s+1}return null}var Uc=["",".md","/README.md","/index.md"];async function ji(e,t){for(let n of Uc){let s=`${t}${n}`.replaceAll("\\","/");if(await le(e,s))return!0}return!1}function Os(e){return/my-doc\.md|example\.spec\.|\/example\//i.test(e)}function $s(e){return e.endsWith("/")?!0:e.endsWith(".md")||e.endsWith(".mdc")}var Bc=8;async function Gs(e){let t=[];for(let n of e.files){if(!n.path.endsWith(".md")&&!n.path.endsWith(".mdc"))continue;let s=h(e,n.path);if(s===null)continue;let r=0;for(let o of ee(s)){if(He(o.href))continue;let i=Me(n.path,o.href);if(!(i===null||!Gi(i)||!$s(i)||Os(i)||await ji(e.repoRoot,i))&&(t.push({ruleId:"guidance-links-resolve",severity:"warn",message:`Broken link in ${n.path}: (${o.href}) does not resolve.`,file:n.path,line:Oe(s,o.href),harnesses:[],hint:"Fix the path or add the missing guidance file."}),r+=1,r>=Bc))break}}return{findings:t,records:[]}}import{readFile as Vc}from"node:fs/promises";import zc from"node:path";async function js(e){try{let t=await Vc(zc.join(e,"package.json"),"utf8"),n=JSON.parse(t);if(y(n)&&"scripts"in n){let{scripts:s}=n;if(y(s))return s}return null}catch{return null}}function Ws(e){return e===null?!1:Object.entries(e).some(([t,n])=>t.toLowerCase().includes("qmd")||typeof n=="string"&&n.toLowerCase().includes("qmd"))}async function Us(e){let t=N(e),n=e.files.filter(r=>r.path.startsWith("docs/ai/")).length;if(!t&&n<2)return{findings:[],records:[]};let s=await js(e.repoRoot);return Ws(s)?{findings:[],records:[]}:{findings:[{ruleId:"qmd-script-present",severity:"info",message:'package.json is missing a "qmd" (or equivalent) script for skill/doc search.',file:"package.json",line:null,harnesses:[],hint:'Add something like "qmd": "bun run ./scripts/qmd/qmd.bun.ts" and document usage in AGENTS.md.'}],records:[]}}async function Bs(e){let t=await Z(e.repoRoot);return t.hooksDirExists?t.settings?.["chat.useCustomAgentHooks"]===!0?{findings:[],records:[]}:{findings:[{ruleId:"vscode-custom-hooks",severity:"warn",message:".github/hooks/ exists but chat.useCustomAgentHooks is not true in .vscode/settings.json.",file:".vscode/settings.json",line:null,harnesses:["cursor","copilot"],hint:'Set "chat.useCustomAgentHooks": true so Cursor and Copilot load workspace hooks.'}],records:[]}:{findings:[],records:[]}}async function Vs(e){let t=await Z(e.repoRoot),n=[];return v(t,"chat.agentSkillsLocations","skills")||n.push({ruleId:"vscode-skills-location",severity:"warn",message:"chat.agentSkillsLocations should point at skills/ in .vscode/settings.json.",file:".vscode/settings.json",line:null,harnesses:["cursor","copilot"],hint:'Set "chat.agentSkillsLocations": { "skills/": true }.'}),v(t,"chat.agentFilesLocations","agents")||n.push({ruleId:"vscode-agents-location",severity:"warn",message:"chat.agentFilesLocations should point at agents/ in .vscode/settings.json.",file:".vscode/settings.json",line:null,harnesses:["cursor","copilot"],hint:'Set "chat.agentFilesLocations": { "agents/": true }.'}),{findings:n,records:[]}}function z(e,t,n,s,r){e.push(...r.findings),t.push(...r.records),r.records.length===0&&t.push({checkId:n,dimension:s,rawScore:r.findings.length>0?0:1})}function $e(e,t){return e.length===0?!0:e.some(n=>t.includes(n))}function zs(e,t,n){return $e(n,e.harnesses)?t===null||t.length===0?!0:n.some(s=>t.includes(s)):!1}function qs(e,t,n){return $e(e.harnesses,t.harnesses)?n===null||n.length===0||e.harnesses.length===0?!0:e.harnesses.some(s=>n.includes(s)):!1}function se(e){return e.trim().replaceAll(/\s+/g," ")}function Ks(e){let t=se(e);return!(t.length<20||/^#{1,6}\s/.test(t)||/^[-*]\s/.test(t)&&t.length<40||t.includes("AGENTS.md")||t.includes("docs/ai/rules.md"))}function ft(e){return e.map(t=>se(t)).filter(t=>t.length>0).join(`
168
+ `)}var mt=3,qc=80;function Ys(e,t){let n=e.split(`
169
+ `),s=ft(t.split(`
170
+ `)),r=[],o=new Set;for(let i=0;i<=n.length-mt;i+=1){if(o.has(i))continue;let a=n.slice(i,i+mt);if(!a.every(l=>Ks(l)))continue;let c=ft(a);if(!(c.length<qc)&&s.includes(c)){r.push({startLine:i+1,lineCount:mt,sample:se(a[0]??"")}),o.add(i);for(let l=1;l<mt;l+=1)o.add(i+l)}}return r}var Js="docs/ai/rules.md";function Xs(e){let t=h(e,Js);if(t===null)return{findings:[],records:[]};let n=[];for(let s of Ue){let r=h(e,s);if(r===null)continue;let o=Ys(r,t);for(let i of o)n.push({ruleId:"adapter-content-duplication",severity:"warn",message:`${s} duplicates ${String(i.lineCount)} lines from ${Js} near line ${String(i.startLine)}.`,file:s,line:i.startLine,harnesses:[],hint:`Replace duplicated rules with a pointer to ${Js}.`})}return{findings:n,records:[]}}function b(e){return e.intelligenceLayer??null}function ge(e){return Object.entries(e.packageJson.scripts).map(([t,n])=>({name:t,command:n}))}function he(e,t,n){return ge(e).some(s=>t.test(s.name)||n.test(s.command))}function Wi(e,t){return ge(e).filter(n=>t.test(n.name)||t.test(n.command)).map(n=>n.name).toSorted()}function ye(e){return e.workflows.map(t=>t.commands.join(`
128
171
  `)).join(`
129
- `)}function x(e){return e.packageJson.path!==null||e.configs.length>0||e.workflows.length>0}function kr(e){let t=w(e);if(t===null||!x(t))return{findings:[],records:[]};let n=ce(t);return/(typecheck|tsc\s+--noEmit|lint|oxlint|eslint|biome|ruff|check:md|lint:md)/i.test(n)?{findings:[],records:[]}:{findings:[g("ci-enforcement-gates","CI workflow enforcement gates were not detected.","Wire typecheck, lint, or static-analysis scripts into CI so AI-facing standards stay enforced.",t.workflows[0]?.path??t.packageJson.path)],records:[]}}function Sr(e){let t=w(e);if(t===null||!x(t))return{findings:[],records:[]};let n=ce(t);return/(npm\s+test|npm\s+run\s+test|vitest|jest|playwright|cypress|pytest|cargo\s+test|go\s+test)/i.test(n)?{findings:[],records:[]}:{findings:[g("ci-validation-gates","CI workflow validation gates were not detected.","Wire test scripts into CI so generated changes are checked by the same validation loop humans use.",t.workflows[0]?.path??t.packageJson.path)],records:[]}}function wr(e){let t=w(e);if(t===null||!x(t))return{findings:[],records:[]};let n=ie(t).map(a=>`${a.name} ${a.command}`).join(`
130
- `),r=ce(t),s=/(scan:self|check:ai-system|lint:md|check:links|qmd)/i.test(n),o=t.prTemplates.length>0,i=/(scan:self|check:ai-system|lint:md|check:links)/i.test(r);return s&&(o||i)?{findings:[],records:[]}:{findings:[g("correction-loop-documented","No durable AI correction-loop signal was detected.","Document when repeated AI mistakes should become rules, docs, skills, tests, hooks, or CI checks, and wire guidance checks into routine validation.",t.prTemplates[0]??t.packageJson.path)],records:[]}}function xr(e){let t=w(e);return t===null||!x(t)?{findings:[],records:[]}:ro(t,/(^|:)(test|e2e).*(file|focused|changed|related|unit|integration|watch|grep)|(--grep|--filter|--testNamePattern|--findRelatedTests)/i).length>0?{findings:[],records:[]}:{findings:[g("focused-test-commands-present","No focused validation command was detected.","Add targeted test scripts for common changed areas or file/grep-based workflows so agents do not over-run broad suites.",t.packageJson.path)],records:[]}}function Rr(e,t){return t.lastIndex=0,t.test(e)}function Cr(e){return/do not|don't|not create|instead of|removed|never use|avoid|legacy|not use|no longer|there is no|\(not `|not `\.cursor\/skills|use \/skills\/|use \/agents\//i.test(e)}function br(e,t){let n=e.split(`
131
- `);for(let r=0;r<n.length;r+=1){let s=n[r]??"";if(!Cr(s)&&(t.lastIndex=0,t.test(s)))return r+1}return null}var Ui=[{id:"github-skills-shadow",pattern:/\.github\/skills\//,message:"use skills/ instead of the removed .github/skills/ path"},{id:"github-agents-shadow",pattern:/\.github\/agents\//,message:"use agents/ instead of the removed .github/agents/ path"},{id:"github-hooks-scripts",pattern:/\.github\/hooks\/scripts\//,message:"use agents/scripts/ instead of .github/hooks/scripts/"},{id:"cursor-skills-shadow",pattern:/\.cursor\/skills\//,message:"use skills/ instead of .cursor/skills/"},{id:"legacy-agent-docs",pattern:/\.agent\/(rules|codebase-map|troubleshooting)\.md/,message:"move legacy .agent docs to docs/ai/ equivalents"}];function Ar(e){let t=[];for(let n of e.files){if(!n.path.endsWith(".md")&&!n.path.endsWith(".mdc"))continue;let r=f(e,n.path);if(r!==null)for(let s of Ui){let o=br(r,s.pattern);if(o!==null){t.push({ruleId:"forbidden-legacy-paths",severity:"warn",message:`${n.path} references a legacy guidance path (${s.id}).`,file:n.path,line:o,harnesses:[],hint:s.message});continue}for(let i of z(r))Rr(i.href,s.pattern)&&t.push({ruleId:"forbidden-legacy-paths",severity:"warn",message:`${n.path} links to a legacy guidance path (${s.id}).`,file:n.path,line:xe(r,i.href),harnesses:[],hint:s.message})}}return{findings:t,records:[]}}function vr(e){let t=se(e);return t===null||!oe(t)?{findings:[],records:[]}:t.guidanceMaintenanceScripts.length>0?{findings:[],records:[]}:{findings:[g("guidance-maintenance-script","No guidance maintenance script was detected.","Expose a script such as check:ai-system, lint:md, check:links, or scan:self so agents and CI can validate AI guidance drift.",t.packageJson.path)],records:[]}}function Er(e){let t=w(e);if(t===null||!x(t))return{findings:[],records:[]};let n=t.jsdocEnforcement;return[n.customChecker,n.packageScript,n.lintRules,n.stopHook].filter(Boolean).length>=2&&n.guidance||n.customChecker&&n.lintRules?{findings:[],records:[]}:{findings:[g("jsdoc-enforcement-present","JSDoc comment enforcement was not detected.","Wire oxlint jsdoc rules, a code-comment guidance doc or skill, and a custom find-missing-jsdoc checker or Stop hook so agents get deterministic JSDoc feedback.",t.packageJson.path)],records:[]}}function Ir(e){let t=w(e);if(t===null||!x(t))return{findings:[],records:[]};let n=ae(t,/(^|:)(lint|check:lint)(:|$)/i,/\b(eslint|oxlint|biome|ruff)\b/i),r=t.configs.some(s=>s.kind==="lint");return n||r?{findings:[],records:[]}:{findings:[g("lint-gate-present","No lint/static-analysis gate was detected.","Expose a lint script or static-analysis config so agents get deterministic correction messages.",t.packageJson.path)],records:[]}}function Lr(e,t){return e.files.some(n=>n.path==="AGENTS.md"||n.path.startsWith("docs/ai/")||n.path.startsWith("skills/")||n.path.startsWith("agents/"))||t.memoryDocs.length>0||t.nestedAgentsFiles.length>0}function Tr(e){let t=e.intelligenceLayer;if(t===void 0||!Lr(e,t))return{findings:[],records:[]};let n=t.localContextConventions.join(`
132
- `),r=/naming|codebase-map|local-context/i.test(n),s=/comment|codebase-map|local-context/i.test(n);return t.nestedAgentsFiles.length>0||r&&s?{findings:[],records:[]}:{findings:[{ruleId:"local-context-patterns",severity:"info",message:"Local context conventions for AI-readable code were not detected.",file:"docs/ai",line:null,harnesses:[],hint:'Document naming conventions and useful "why" comment patterns, or add nested AGENTS.md files for subprojects.'}],records:[]}}function Fr(e){let t=e.intelligenceLayer;if(t===void 0||t.memoryDocs.length===0)return{findings:[],records:[]};let n=t.memoryIndexes.length>0,s=!(t.packageJson.path!==null)||Object.entries(t.packageJson.scripts).some(([o,i])=>/qmd|search/i.test(o)||/qmd|search/i.test(i));return n&&s?{findings:[],records:[]}:{findings:[{ruleId:"memory-docs-indexed",severity:"info",message:"Durable memory docs should be indexed and searchable.",file:t.memoryDocs[0]??null,line:null,harnesses:[],hint:"Add a memory index such as docs/ai/codebase-map.md or docs/ai/ai-system.md, and expose a qmd/search script when package.json exists."}],records:[]}}function Hr(e){let t=se(e);return t===null||!oe(t)?{findings:[],records:[]}:t.aiHarnessPrTemplates.length>0?{findings:[],records:[]}:{findings:[g("pr-template-ai-harness-check","No PR template reminder for durable AI harness updates was detected.","Add a PR checklist item for recurring AI mistakes: update rules, docs, skills, tests, or diagnostics when needed.",t.prTemplates[0]??".github/PULL_REQUEST_TEMPLATE.md")],records:[]}}function Pr(e){let t=w(e);if(t===null||!x(t))return{findings:[],records:[]};let n=ae(t,/(^|:)(typecheck|check:types)(:|$)/i,/\b(tsc\s+--noEmit|vue-tsc|svelte-check|mypy|pyright|cargo\s+check)\b/i),r=t.configs.some(o=>o.capabilities.includes("strict-typecheck")),s=ie(t).some(o=>/\b(mypy|pyright|cargo\s+check)\b/i.test(o.command));return n&&(r||s)?{findings:[],records:[]}:{findings:[g("strict-typecheck-present","No strict typecheck/static-analysis gate was detected.","Expose a discoverable typecheck script and strict type/static-analysis config so agents can verify structural correctness.",t.packageJson.path)],records:[]}}function Nr(e){let t=w(e);if(t===null||!x(t))return{findings:[],records:[]};let n=ae(t,/(^|:)(test|e2e|integration)(:|$)/i,/\b(vitest|jest|playwright|cypress|pytest|cargo\s+test|go\s+test)\b/i),r=t.configs.some(s=>s.kind==="test");return n||r?{findings:[],records:[]}:{findings:[g("test-gates-present","No validation test gate was detected.","Expose discoverable unit, integration, or E2E test scripts so agents can choose a safe verification loop.",t.packageJson.path)],records:[]}}var qi=[hr,Ar,Pr,Ir,Er,Nr,xr,kr,Sr,wr,vr,Hr,yr,Fr,Tr];function so(e){let t=[],n=[];for(let r of qi){let s=r(e);if(t.push(...s.findings),n.push(...s.records),s.records.length===0){let[o]=s.findings,i=o===void 0?r.name.replace(/^check/,"").replaceAll(/[A-Z]/g,a=>`-${a.toLowerCase()}`).replace(/^-/,""):o.ruleId;n.push({checkId:i,dimension:"maintainability",rawScore:s.findings.length>0?0:1})}}return{findings:t,records:n}}async function Qe(e,t){let n=[],r=[],s=no.filter(c=>pr(c,e,t)),o=await Promise.all(s.map(async c=>({rule:c,result:await c.check(e)})));for(let{rule:c,result:u}of o)W(n,r,c.id,c.dimension,u);if(dr(e,t,["cursor","copilot"])){let c=await Jn(e);n.push(...c.findings),r.push(...c.records),c.records.length===0&&(r.push({checkId:"vscode-skills-location",dimension:"harnessWiring",rawScore:c.findings.some(u=>u.ruleId==="vscode-skills-location")?0:1}),r.push({checkId:"vscode-agents-location",dimension:"harnessWiring",rawScore:c.findings.some(u=>u.ruleId==="vscode-agents-location")?0:1})),W(n,r,"vscode-custom-hooks","harnessWiring",await Kn(e))}W(n,r,"no-duplicate-skill-trees","layering",await On(e)),W(n,r,"no-duplicate-agent-trees","layering",await $n(e)),W(n,r,"qmd-script-present","discoverability",await Bn(e)),W(n,r,"guidance-links-resolve","maintainability",await Vn(e));let i=so(e);n.push(...i.findings),r.push(...i.records);let a=[...Dn(e).findings,...Mn(e).findings];if(t===null||t.length===0)n.push(...a);else{let c=a.filter(u=>u.harnesses.some(p=>t.includes(p)));n.push(...c)}return{findings:n,records:r}}function _r(e){let t=0,n=0,r=0;for(let s of e)s.severity==="error"?t+=1:s.severity==="warn"?n+=1:r+=1;return{error:t,warn:n,info:r}}import Bi from"node:path";var Q="AGENTS.md",oo=[Q,"docs/ai/rules.md"],Ze=["CLAUDE.md","GEMINI.md",".github/copilot-instructions.md",".agent/README.md"];function Dr(e){let t=f(e,Q);if(t===null)return[];let n=C["AI2-adapter-fidelity"],r=[];for(let s of Ze){let o=f(e,s);if(o===null||o.trim().length===0)continue;let i=`You are checking whether a thin per-tool adapter stays faithful to the shared guidance it points at.
172
+ `)}function C(e){return e.packageJson.path!==null||e.configs.length>0||e.workflows.length>0}function k(e,t,n,s){return{ruleId:e,severity:"info",message:t,file:s,line:null,harnesses:[],hint:n}}function Qs(e){let t=b(e);if(t===null||!C(t))return{findings:[],records:[]};let n=ye(t);return/(typecheck|tsc\s+--noEmit|lint|oxlint|eslint|biome|ruff|check:md|lint:md)/i.test(n)?{findings:[],records:[]}:{findings:[k("ci-enforcement-gates","CI workflow enforcement gates were not detected.","Wire typecheck, lint, or static-analysis scripts into CI so AI-facing standards stay enforced.",t.workflows[0]?.path??t.packageJson.path)],records:[]}}function Se(e){return e.intelligenceLayer??null}function ke(e){return e.packageJson.path!==null||e.workflows.length>0||e.prTemplates.length>0}function Zs(e){let t=Se(e);return t===null||!ke(t)?{findings:[],records:[]}:t.guidanceCiWorkflows.length>0?{findings:[],records:[]}:{findings:[k("ci-guidance-lint","No CI guidance-maintenance gate was detected.","Run lint:md, check:ai-system, check:links, scan:self, or an equivalent guidance check in CI.",t.workflows[0]?.path??t.packageJson.path)],records:[]}}function er(e){let t=b(e);if(t===null||!C(t))return{findings:[],records:[]};let n=ye(t);return/(npm\s+test|npm\s+run\s+test|vitest|jest|playwright|cypress|pytest|cargo\s+test|go\s+test)/i.test(n)?{findings:[],records:[]}:{findings:[k("ci-validation-gates","CI workflow validation gates were not detected.","Wire test scripts into CI so generated changes are checked by the same validation loop humans use.",t.workflows[0]?.path??t.packageJson.path)],records:[]}}function tr(e){let t=b(e);if(t===null||!C(t))return{findings:[],records:[]};let n=ge(t).map(a=>`${a.name} ${a.command}`).join(`
173
+ `),s=ye(t),r=/(scan:self|check:ai-system|lint:md|check:links|qmd)/i.test(n),o=t.prTemplates.length>0,i=/(scan:self|check:ai-system|lint:md|check:links)/i.test(s);return r&&(o||i)?{findings:[],records:[]}:{findings:[k("correction-loop-documented","No durable AI correction-loop signal was detected.","Document when repeated AI mistakes should become rules, docs, skills, tests, hooks, or CI checks, and wire guidance checks into routine validation.",t.prTemplates[0]??t.packageJson.path)],records:[]}}function nr(e){let t=b(e);return t===null||!C(t)?{findings:[],records:[]}:Wi(t,/(^|:)(test|e2e).*(file|focused|changed|related|unit|integration|watch|grep)|(--grep|--filter|--testNamePattern|--findRelatedTests)/i).length>0?{findings:[],records:[]}:{findings:[k("focused-test-commands-present","No focused validation command was detected.","Add targeted test scripts for common changed areas or file/grep-based workflows so agents do not over-run broad suites.",t.packageJson.path)],records:[]}}function sr(e,t){return t.lastIndex=0,t.test(e)}function rr(e){return/do not|don't|not create|instead of|removed|never use|avoid|legacy|not use|no longer|there is no|\(not `|not `\.cursor\/skills|use \/skills\/|use \/agents\//i.test(e)}function or(e,t){let n=e.split(`
174
+ `);for(let s=0;s<n.length;s+=1){let r=n[s]??"";if(!rr(r)&&(t.lastIndex=0,t.test(r)))return s+1}return null}var Kc=[{id:"github-skills-shadow",pattern:/\.github\/skills\//,message:"use skills/ instead of the removed .github/skills/ path"},{id:"github-agents-shadow",pattern:/\.github\/agents\//,message:"use agents/ instead of the removed .github/agents/ path"},{id:"github-hooks-scripts",pattern:/\.github\/hooks\/scripts\//,message:"use agents/scripts/ instead of .github/hooks/scripts/"},{id:"cursor-skills-shadow",pattern:/\.cursor\/skills\//,message:"use skills/ instead of .cursor/skills/"},{id:"legacy-agent-docs",pattern:/\.agent\/(rules|codebase-map|troubleshooting)\.md/,message:"move legacy .agent docs to docs/ai/ equivalents"}];function ir(e){let t=[];for(let n of e.files){if(!n.path.endsWith(".md")&&!n.path.endsWith(".mdc"))continue;let s=h(e,n.path);if(s!==null)for(let r of Kc){let o=or(s,r.pattern);if(o!==null){t.push({ruleId:"forbidden-legacy-paths",severity:"warn",message:`${n.path} references a legacy guidance path (${r.id}).`,file:n.path,line:o,harnesses:[],hint:r.message});continue}for(let i of ee(s))sr(i.href,r.pattern)&&t.push({ruleId:"forbidden-legacy-paths",severity:"warn",message:`${n.path} links to a legacy guidance path (${r.id}).`,file:n.path,line:Oe(s,i.href),harnesses:[],hint:r.message})}}return{findings:t,records:[]}}function ar(e){let t=Se(e);return t===null||!ke(t)?{findings:[],records:[]}:t.guidanceMaintenanceScripts.length>0?{findings:[],records:[]}:{findings:[k("guidance-maintenance-script","No guidance maintenance script was detected.","Expose a script such as check:ai-system, lint:md, check:links, or scan:self so agents and CI can validate AI guidance drift.",t.packageJson.path)],records:[]}}function cr(e){let t=b(e);if(t===null||!C(t))return{findings:[],records:[]};let n=t.jsdocEnforcement;return[n.customChecker,n.packageScript,n.lintRules,n.stopHook].filter(Boolean).length>=2&&n.guidance||n.customChecker&&n.lintRules?{findings:[],records:[]}:{findings:[k("jsdoc-enforcement-present","JSDoc comment enforcement was not detected.","Wire oxlint jsdoc rules, a code-comment guidance doc or skill, and a custom find-missing-jsdoc checker or Stop hook so agents get deterministic JSDoc feedback.",t.packageJson.path)],records:[]}}function lr(e){let t=b(e);if(t===null||!C(t))return{findings:[],records:[]};let n=he(t,/(^|:)(lint|check:lint)(:|$)/i,/\b(eslint|oxlint|biome|ruff)\b/i),s=t.configs.some(r=>r.kind==="lint");return n||s?{findings:[],records:[]}:{findings:[k("lint-gate-present","No lint/static-analysis gate was detected.","Expose a lint script or static-analysis config so agents get deterministic correction messages.",t.packageJson.path)],records:[]}}function ur(e,t){return e.files.some(n=>n.path==="AGENTS.md"||n.path.startsWith("docs/ai/")||n.path.startsWith("skills/")||n.path.startsWith("agents/"))||t.memoryDocs.length>0||t.nestedAgentsFiles.length>0}function dr(e){let t=e.intelligenceLayer;if(t===void 0||!ur(e,t))return{findings:[],records:[]};let n=t.localContextConventions.join(`
175
+ `),s=/naming|codebase-map|local-context/i.test(n),r=/comment|codebase-map|local-context/i.test(n);return t.nestedAgentsFiles.length>0||s&&r?{findings:[],records:[]}:{findings:[{ruleId:"local-context-patterns",severity:"info",message:"Local context conventions for AI-readable code were not detected.",file:"docs/ai",line:null,harnesses:[],hint:'Document naming conventions and useful "why" comment patterns, or add nested AGENTS.md files for subprojects.'}],records:[]}}function pr(e){let t=e.intelligenceLayer;if(t===void 0||t.memoryDocs.length===0)return{findings:[],records:[]};let n=t.memoryIndexes.length>0,r=!(t.packageJson.path!==null)||Object.entries(t.packageJson.scripts).some(([o,i])=>/qmd|search/i.test(o)||/qmd|search/i.test(i));return n&&r?{findings:[],records:[]}:{findings:[{ruleId:"memory-docs-indexed",severity:"info",message:"Durable memory docs should be indexed and searchable.",file:t.memoryDocs[0]??null,line:null,harnesses:[],hint:"Add a memory index such as docs/ai/codebase-map.md or docs/ai/ai-system.md, and expose a qmd/search script when package.json exists."}],records:[]}}function fr(e){let t=Se(e);return t===null||!ke(t)?{findings:[],records:[]}:t.aiHarnessPrTemplates.length>0?{findings:[],records:[]}:{findings:[k("pr-template-ai-harness-check","No PR template reminder for durable AI harness updates was detected.","Add a PR checklist item for recurring AI mistakes: update rules, docs, skills, tests, or diagnostics when needed.",t.prTemplates[0]??".github/PULL_REQUEST_TEMPLATE.md")],records:[]}}function mr(e){let t=b(e);if(t===null||!C(t))return{findings:[],records:[]};let n=he(t,/(^|:)(typecheck|check:types)(:|$)/i,/\b(tsc\s+--noEmit|vue-tsc|svelte-check|mypy|pyright|cargo\s+check)\b/i),s=t.configs.some(o=>o.capabilities.includes("strict-typecheck")),r=ge(t).some(o=>/\b(mypy|pyright|cargo\s+check)\b/i.test(o.command));return n&&(s||r)?{findings:[],records:[]}:{findings:[k("strict-typecheck-present","No strict typecheck/static-analysis gate was detected.","Expose a discoverable typecheck script and strict type/static-analysis config so agents can verify structural correctness.",t.packageJson.path)],records:[]}}function gr(e){let t=b(e);if(t===null||!C(t))return{findings:[],records:[]};let n=he(t,/(^|:)(test|e2e|integration)(:|$)/i,/\b(vitest|jest|playwright|cypress|pytest|cargo\s+test|go\s+test)\b/i),s=t.configs.some(r=>r.kind==="test");return n||s?{findings:[],records:[]}:{findings:[k("test-gates-present","No validation test gate was detected.","Expose discoverable unit, integration, or E2E test scripts so agents can choose a safe verification loop.",t.packageJson.path)],records:[]}}var Yc=[Xs,ir,mr,lr,cr,gr,nr,Qs,er,tr,ar,fr,Zs,pr,dr];function Ui(e){let t=[],n=[];for(let s of Yc){let r=s(e);if(t.push(...r.findings),n.push(...r.records),r.records.length===0){let[o]=r.findings,i=o===void 0?s.name.replace(/^check/,"").replaceAll(/[A-Z]/g,a=>`-${a.toLowerCase()}`).replace(/^-/,""):o.ruleId;n.push({checkId:i,dimension:"maintainability",rawScore:r.findings.length>0?0:1})}}return{findings:t,records:n}}async function gt(e,t){let n=[],s=[],r=$i.filter(c=>qs(c,e,t)),o=await Promise.all(r.map(async c=>({rule:c,result:await c.check(e)})));for(let{rule:c,result:l}of o)z(n,s,c.id,c.dimension,l);if(zs(e,t,["cursor","copilot"])){let c=await Vs(e);n.push(...c.findings),s.push(...c.records),c.records.length===0&&(s.push({checkId:"vscode-skills-location",dimension:"harnessWiring",rawScore:c.findings.some(l=>l.ruleId==="vscode-skills-location")?0:1}),s.push({checkId:"vscode-agents-location",dimension:"harnessWiring",rawScore:c.findings.some(l=>l.ruleId==="vscode-agents-location")?0:1})),z(n,s,"vscode-custom-hooks","harnessWiring",await Bs(e))}z(n,s,"no-duplicate-skill-trees","layering",await Ds(e)),z(n,s,"no-duplicate-agent-trees","layering",await Ms(e)),z(n,s,"qmd-script-present","discoverability",await Us(e)),z(n,s,"guidance-links-resolve","maintainability",await Gs(e));let i=Ui(e);n.push(...i.findings),s.push(...i.records);let a=[...Ps(e).findings,...Hs(e).findings];if(t===null||t.length===0)n.push(...a);else{let c=a.filter(l=>l.harnesses.some(p=>t.includes(p)));n.push(...c)}return{findings:n,records:s}}function hr(e){let t=0,n=0,s=0;for(let r of e)r.severity==="error"?t+=1:r.severity==="warn"?n+=1:s+=1;return{error:t,warn:n,info:s}}import Jc from"node:path";var re="AGENTS.md",Bi=[re,"docs/ai/rules.md"],ht=["CLAUDE.md","GEMINI.md",".github/copilot-instructions.md",".agent/README.md"];function yr(e){let t=h(e,re);if(t===null)return[];let n=w["AI2-adapter-fidelity"],s=[];for(let r of ht){let o=h(e,r);if(o===null||o.trim().length===0)continue;let i=`You are checking whether a thin per-tool adapter stays faithful to the shared guidance it points at.
133
176
 
134
177
  The adapter should defer to the shared layer, not restate or contradict it. Find
135
178
  claims in the ADAPTER that drift from the SHARED ENTRY: instructions the shared
136
179
  layer does not support, stale pointers, or duplicated guidance that has diverged.
137
180
  Be strict: only report real fidelity problems, not harmless adapter-only setup.
138
181
 
139
- ### SHARED ENTRY: ${Q}
182
+ ### SHARED ENTRY: ${re}
140
183
 
141
184
  \`\`\`markdown
142
185
  ${t}
143
186
  \`\`\`
144
187
 
145
- ### ADAPTER: ${s}
188
+ ### ADAPTER: ${r}
146
189
 
147
190
  \`\`\`markdown
148
191
  ${o}
@@ -150,23 +193,35 @@ ${o}
150
193
 
151
194
  Respond with JSON only, no prose, exactly this shape:
152
195
  { "${n.schemaKey}": [ { "claim": "<quote from adapter>", "explanation": "<how it drifts>" } ] }
153
- Return an empty array if the adapter is faithful.`;r.push({taskId:`AI2-adapter-fidelity:${s}`,checkId:n.checkId,title:`${n.title} (${s})`,targetPaths:[s,Q],schemaKey:n.schemaKey,prompt:i})}return r}function Ae(e,t){let n=[];for(let r of t){let s=f(e,r);s!==null&&s.trim().length>0&&n.push({path:r,content:s})}return n}function ve(e){return e.map(t=>`### FILE: ${t.path}
196
+ Return an empty array if the adapter is faithful.`;s.push({taskId:`AI2-adapter-fidelity:${r}`,checkId:n.checkId,title:`${n.title} (${r})`,targetPaths:[r,re],schemaKey:n.schemaKey,prompt:i})}return s}function Ge(e,t){let n=[];for(let s of t){let r=h(e,s);r!==null&&r.trim().length>0&&n.push({path:s,content:r})}return n}function oe(e){let t=e.files.filter(n=>n.path.startsWith("skills/")&&n.path.endsWith("SKILL.md")).map(n=>n.path);return Ge(e,[...Bi,...t])}function j(e){return e.map(t=>`### FILE: ${t.path}
154
197
 
155
198
  \`\`\`markdown
156
199
  ${t.content}
157
200
  \`\`\``).join(`
158
201
 
159
- `)}function Mr(e){let t=e.files.filter(o=>o.path.startsWith("skills/")&&o.path.endsWith("SKILL.md")).map(o=>o.path),n=Ae(e,[...oo,...t]);if(n.length<2)return null;let r=C["AI1-contradiction"],s=`You are auditing one repository's AI-agent guidance for internal contradictions.
202
+ `)}function Sr(e){let t=oe(e);if(t.length<2)return null;let n=w["AI1-contradiction"],s=`You are auditing one repository's AI-agent guidance for internal contradictions.
160
203
 
161
204
  Read every file below. Find places where one rule directly contradicts another \u2014
162
205
  where an agent could not satisfy both at once. Be strict: only report clear,
163
206
  actionable conflicts, not stylistic differences or complementary advice.
164
207
 
165
- ${ve(n)}
208
+ ${j(t)}
166
209
 
167
210
  Respond with JSON only, no prose, exactly this shape:
168
- { "${r.schemaKey}": [ { "ruleA": "<quote>", "ruleB": "<quote>", "explanation": "<why they conflict>" } ] }
169
- Return an empty array if there are no clear contradictions.`;return{taskId:"AI1-contradiction",checkId:r.checkId,title:r.title,targetPaths:n.map(o=>o.path),schemaKey:r.schemaKey,prompt:s}}function $r(e){let t=[Q,"docs/ai/rules.md",...Ze,...e.files.filter(r=>r.path.startsWith("skills/")&&r.path.endsWith("SKILL.md")).map(r=>r.path),...e.files.filter(r=>r.path.startsWith("agents/")&&r.path.endsWith(".agent.md")).map(r=>r.path)],n=Ae(e,t);for(let r of e.security?.hookScripts??[])r.content.trim().length>0&&n.push({path:r.path??r.source,content:r.content});return n}function Or(e){let t=$r(e);if(t.length===0)return null;let n=C["AI3-security-review"],r=`You are performing a security review of one repository's AI-agent configuration:
211
+ { "${n.schemaKey}": [ { "ruleA": "<quote>", "ruleB": "<quote>", "explanation": "<why they conflict>" } ] }
212
+ Return an empty array if there are no clear contradictions.`;return{taskId:"AI1-contradiction",checkId:n.checkId,title:n.title,targetPaths:t.map(r=>r.path),schemaKey:n.schemaKey,prompt:s}}function kr(e){let t=oe(e);if(t.length===0)return null;let n=w["AI4-deadweight"],s=`You are auditing one repository's AI-agent guidance for dead weight.
213
+
214
+ Apply the deletion test to each rule or instruction below: if this line were
215
+ deleted, would a competent coding agent behave any differently? Flag the lines a
216
+ capable model would already follow without being told (generic best practices,
217
+ restated defaults, motivational filler). Be strict: only flag lines whose removal
218
+ would change nothing, not lines that are merely terse.
219
+
220
+ ${j(t)}
221
+
222
+ Respond with JSON only, no prose, exactly this shape:
223
+ { "${n.schemaKey}": [ { "rule": "<quote>", "reason": "<why deleting it changes nothing>" } ] }
224
+ Return an empty array if every line earns its place.`;return{taskId:"AI4-deadweight",checkId:n.checkId,title:n.title,targetPaths:t.map(r=>r.path),schemaKey:n.schemaKey,prompt:s}}function xr(e){let t=[re,"docs/ai/rules.md",...ht,...e.files.filter(s=>s.path.startsWith("skills/")&&s.path.endsWith("SKILL.md")).map(s=>s.path),...e.files.filter(s=>s.path.startsWith("agents/")&&s.path.endsWith(".agent.md")).map(s=>s.path)],n=Ge(e,t);for(let s of e.security?.hookScripts??[])s.content.trim().length>0&&n.push({path:s.path??s.source,content:s.content});return n}function wr(e){let t=xr(e);if(t.length===0)return null;let n=w["AI3-security-review"],s=`You are performing a security review of one repository's AI-agent configuration:
170
225
  its always-loaded instructions, skills, agent definitions, and lifecycle hook
171
226
  scripts.
172
227
 
@@ -186,11 +241,28 @@ Report ONLY semantic risks that require reading intent:
186
241
  Be strict and specific: only report concrete, defensible risks a reviewer would
187
242
  act on, and quote the exact text. This pass is advisory.
188
243
 
189
- ${ve(t)}
244
+ ${j(t)}
190
245
 
191
246
  Respond with JSON only, no prose, exactly this shape:
192
247
  { "${n.schemaKey}": [ { "location": "<file or area>", "risk": "<short category>", "explanation": "<quote and why it is a risk>" } ] }
193
- Return an empty array if you find no clear risks.`;return{taskId:"AI3-security-review",checkId:n.checkId,title:n.title,targetPaths:t.map(s=>s.path),schemaKey:n.schemaKey,prompt:r}}function Gr(e){let t=[],n=Mr(e);n!==null&&t.push(n),t.push(...Dr(e));let r=Or(e);return r!==null&&t.push(r),t}async function et(e){let t=Bi.resolve(e),n=await fe(t),{files:r,contents:s}=await ye(t),o=await Se(t);return{version:1,root:t,tasks:Gr({repoRoot:t,harnesses:n,files:r,fileContents:s,security:o})}}var io={error:3,warn:2,info:1};function tt(e,t){let n=io[t];return e.some(r=>io[r.severity]>=n)}async function jr(e){let t=Ki.resolve(e.repoRoot),n=ys(),r=await fe(t),{files:s,contents:o}=await ye(t),i=await vn(t),a=await Se(t),c={repoRoot:t,harnesses:r,files:s,fileContents:o,intelligenceLayer:i,security:a},u=Bt(c);c.contextBudget=u;let{findings:p,records:m}=await Qe(c,e.harnessFilter),I=_r(p),d=$t(s,r),k=await J(t),S=await rn(c,k,p,d),A=fn(m,p,d,S,c),ao=await Lt(c,k),co=await n,lo=qe(i),uo=e.aiReviewResults===void 0?nt:Fe(e.aiReviewResults);return{version:co.version,root:t,harnesses:r,total_score:A.total_score,score_scope:A.score_scope,inventory:{fileCount:s.length,files:s},sharing:d,metaHarness:A,harnessGapMatrix:ao,harnessOptimization:S,intelligenceLayer:lo,contextBudget:u,aiReview:uo,findings:p,summary:I}}async function Vr(){let e=dt(process.argv.slice(2));if(e.help&&(pt(),process.exit(0)),e.emitAiTasks)try{let t=await et(e.repoRoot);process.stdout.write(`${JSON.stringify(t,null,2)}
248
+ Return an empty array if you find no clear risks.`;return{taskId:"AI3-security-review",checkId:n.checkId,title:n.title,targetPaths:t.map(r=>r.path),schemaKey:n.schemaKey,prompt:s}}function Rr(e){let t=oe(e);if(t.length===0)return null;let n=w["AI5-vague-rules"],s=`You are auditing one repository's AI-agent guidance for vague rules.
249
+
250
+ Flag each rule below that lacks a clear, testable decision boundary \u2014 where an
251
+ agent cannot determine whether it is complying. Examples: "keep files small"
252
+ (how small?), "write clean code" (by what test?), "use good judgment" (against
253
+ what criterion?). Be strict: only flag rules a reasonable agent could apply two
254
+ different ways, not rules that are specific but terse.
255
+
256
+ ${j(t)}
257
+
258
+ Respond with JSON only, no prose, exactly this shape:
259
+ { "${n.schemaKey}": [ { "rule": "<quote>", "reason": "<what decision boundary is missing>" } ] }
260
+ Return an empty array if every rule has a clear boundary.`;return{taskId:"AI5-vague-rules",checkId:n.checkId,title:n.title,targetPaths:t.map(r=>r.path),schemaKey:n.schemaKey,prompt:s}}function br(e){let t=[],n=Sr(e);n!==null&&t.push(n);let s=kr(e);s!==null&&t.push(s);let r=Rr(e);r!==null&&t.push(r),t.push(...yr(e));let o=wr(e);return o!==null&&t.push(o),t}async function yt(e){let t=Jc.resolve(e),n=await Ae(t),{files:s,contents:r}=await Te(t),o=await _e(t);return{version:1,root:t,tasks:br({repoRoot:t,harnesses:n,files:s,fileContents:r,security:o})}}import hl from"node:path";function Cr(e){let t=Array.from({length:e},(o,i)=>i),n=Array.from({length:e},()=>0);function s(o){let i=o;for(;(t[i]??i)!==i;)i=t[i]??i;let a=o;for(;a!==i;){let c=t[a]??i;t[a]=i,a=c}return i}function r(o,i){let a=s(o),c=s(i);if(a===c)return;let l=n[a]??0,p=n[c]??0;if(l<p){t[a]=c;return}if(l>p){t[c]=a;return}t[c]=a,n[a]=l+1}return{findRoot:s,union:r}}function _(e){return String(e??"").replaceAll(/\s+/g," ").trim().toLowerCase()}function Ir(e,t=20){let n=new Set,s=_(e);if(s.length<t)return n;let r=Math.max(5,Math.floor(t/4));for(let i=0;i+t<=s.length;i+=r)n.add(s.slice(i,i+t));let o=s.length-t;return o>0&&n.add(s.slice(o)),n}function Er(e){let t=null,n=0,s=0;for(let[r,o]of e.entries()){let i=o.sessions.size;(i>n||i===n&&o.occurrences>s)&&(t=r,n=i,s=o.occurrences)}return t}function ie(e,t=20,n=Number.POSITIVE_INFINITY){let s=e.map(p=>({sessionId:p.sessionId,normalized:_(p.text)})).filter(p=>p.normalized.length>=t),r=s.length;if(r<2)return[];let o=s.map(p=>Ir(p.normalized,t)),i=new Map;for(let[p,f]of o.entries())for(let m of f){let d=i.get(m);d===void 0?i.set(m,[p]):d.push(p)}let a=Cr(r);for(let p of i.values()){let[f,...m]=p;if(f!==void 0)for(let d of m)a.union(f,d)}let c=new Map;for(let p=0;p<r;p+=1){let f=a.findRoot(p),m=c.get(f)??[];m.push(p),c.set(f,m)}let l=[];for(let p of c.values()){if(p.length<2)continue;let f=new Set,m=new Map;for(let g of p){let S=s[g],A=o[g];if(!(S===void 0||A===void 0)){f.add(S.sessionId);for(let xe of A){let q=m.get(xe)??{sessions:new Set,occurrences:0};q.occurrences+=1,q.sessions.add(S.sessionId),m.set(xe,q)}}}if(f.size<2&&p.length<n)continue;let d=Er(m);d!==null&&l.push({instruction:d,occurrences:p.length,sessions:f.size})}return l.toSorted((p,f)=>f.sessions-p.sessions||f.occurrences-p.occurrences)}import{createHash as Qc}from"node:crypto";function vr(e){let t=String(e??""),n=Qc("sha256").update(t).digest("hex").slice(0,8);return`[redacted ${t.length}ch #${n}]`}function ae(e,t){return t?String(e??""):vr(e)}function je(e,t){return t.some(n=>n.test(e))}function We(e){return je(e,oo)}function Tr(e,t){let n=e.filter(l=>l.role==="user"&&We(l.text));if(n.length===0)return[];let s=new Set(n.map(l=>l.sessionId)),r=new Set(e.filter(l=>l.role==="user").map(l=>l.sessionId)).size,o=r===0?0:n.length/r,i={checkId:"SS3",name:L.SS3,detail:`${n.length} corrections across ${s.size} of ${r} sessions (${o.toFixed(2)} per session)`,sessions:s.size,occurrences:n.length,snippet:null},a=n.map(l=>({sessionId:l.sessionId,text:l.text})),c=ie(a).map(l=>{let p=ae(l.instruction,t);return{checkId:"SS3",name:L.SS3,detail:`Recurring friction ${p}: corrected in ${l.sessions} sessions (${l.occurrences} times)`,sessions:l.sessions,occurrences:l.occurrences,snippet:p}});return[i,...c]}function Lr(e,t){return e.keywords.length===0?t.includes(_(e.text)):e.keywords.some(n=>new RegExp(`\\b${n}\\b`).test(t))}function Fr(e,t){if(t.length===0)return[];let n=new Map;for(let r of e){let o=n.get(r.sessionId)??[];o.push(r),n.set(r.sessionId,o)}let s=new Map;for(let[r,o]of n.entries()){let i=o.map(a=>_(a.text));for(let[a,c]of o.entries()){if(c.role!=="user"||!We(c.text))continue;let l=[i[a-1],i[a],i[a+1]].filter(p=>typeof p=="string").join(`
261
+ `);if(io.test(l))for(let p of t){if(!Lr(p,l))continue;let f=s.get(p.text)??{rule:p.text,occurrences:0,sessions:new Set};f.occurrences+=1,f.sessions.add(r),s.set(p.text,f)}}}return[...s.values()].toSorted((r,o)=>o.sessions.size-r.sessions.size||o.occurrences-r.occurrences).map(r=>({checkId:"SS2",name:L.SS2,detail:`Possibly ignored rule "${r.rule}": ${r.occurrences} corrections in tool-use context across ${r.sessions.size} sessions`,sessions:r.sessions.size,occurrences:r.occurrences,snippet:r.rule}))}function _r(e){return je(e,ro)}function Nr(e,t){let n=e.filter(s=>s.role==="user"&&_r(s.text)).map(s=>({sessionId:s.sessionId,text:s.text}));return ie(n,void 0,3).map(s=>{let r=ae(s.instruction,t),o=s.sessions>=2?`repeated across ${s.sessions} sessions (${s.occurrences} times)`:`repeated ${s.occurrences} times within a single session`;return{checkId:"SS4",name:L.SS4,detail:`Candidate missing rule ${r}: ${o} but likely not in committed guidance`,sessions:s.sessions,occurrences:s.occurrences,snippet:r}})}function Pr(e,t){let n=e.filter(s=>s.role==="user").map(s=>({sessionId:s.sessionId,text:s.text}));return ie(n).map(s=>{let r=ae(s.instruction,t);return{checkId:"SS1",name:L.SS1,detail:`Repeated prompt ${r} seen in ${s.sessions} sessions (${s.occurrences} times)`,sessions:s.sessions,occurrences:s.occurrences,snippet:r}})}function Hr(e,t,n){return[...Nr(e,n),...Fr(e,t),...Tr(e,n),...Pr(e,n)]}import{homedir as el}from"node:os";import zi from"node:path";function Mr(e){return e!==null&&e.length>0?zi.resolve(e):zi.join(el(),".claude","projects")}import qi from"node:path";import{lstatSync as tl}from"node:fs";function Dr(e){try{return tl(e).mtimeMs}catch{return null}}import{readdirSync as nl}from"node:fs";function Or(e){try{return nl(e,{withFileTypes:!0})}catch{return[]}}function $r(e,t){let n=[];for(let s of Or(e)){if(s.isSymbolicLink()||!s.isFile()||qi.extname(s.name).toLowerCase()!==".jsonl")continue;let r=qi.join(e,s.name),o=Dr(r);o!==null&&n.push({file:r,mtimeMs:o})}return n.toSorted((s,r)=>r.mtimeMs-s.mtimeMs).slice(0,Math.max(0,t)).map(s=>s.file)}import{existsSync as rl,statSync as ol}from"node:fs";import il from"node:path";import sl from"node:path";function Gr(e){return sl.resolve(e).replaceAll(/[/\\]/g,"-")}function jr(e,t){let n=il.join(e,Gr(t));return!rl(n)||!ol(n).isDirectory()?null:n}import{createReadStream as al}from"node:fs";import cl from"node:path";import{createInterface as ll}from"node:readline";function Wr(e){let{type:t,message:n}=e;return typeof t=="string"&&t.trim().length>0?t.trim().toLowerCase():y(n)&&typeof n.role=="string"?n.role.trim().toLowerCase():""}function Ur(e){let t=e.trim();return t.length<5?!0:ao.some(n=>n.test(t))}function Br(e){if(!y(e))return"";let{message:t}=e;if(!y(t))return"";let{content:n}=t,s="";if(typeof n=="string")s=n.trim();else if(Array.isArray(n)){let o=[];for(let i of n)y(i)&&i.type==="text"&&typeof i.text=="string"&&o.push(i.text);s=o.join(`
262
+ `).trim()}let r=s.replaceAll(/<system-reminder>[\s\S]*?<\/system-reminder>/g,"").trim();return Ur(r)?"":r}function Vr(e){try{return JSON.parse(e)}catch{return}}async function zr(e){let t=cl.basename(e,".jsonl"),n=[],s=ll({input:al(e,{encoding:"utf8"}),crlfDelay:1/0});try{for await(let r of s){let o=r.trim();if(o.length===0)continue;let i=Vr(o);if(!y(i))continue;let a=Br(i);a.length!==0&&n.push({sessionId:t,role:Wr(i),text:a})}}catch{return n}return n}async function ul(e){let t=Mr(e.sessionRoot),n=jr(t,e.repoRoot);if(n===null)return[];let s=$r(n,e.maxSessions);return(await Promise.all(s.map(o=>zr(o)))).flat()}var dl={harness:"claude",collectMessages:ul},Ki=dl;import ml from"node:path";import{readFile as pl}from"node:fs/promises";async function qr(e){try{return await pl(e,"utf8")}catch{return null}}function Kr(e){return _(e).replaceAll(/[^a-z0-9 ]/g," ").replaceAll(/\s+/g," ").trim()}var fl=new Set(["the","and","that","with","from","this","they","have","been","were","what","just","when","where","your","you","are","was","for","not","out","into","about","them","then","than","its","our","all","any","can","has","had","but","only","still","very","well","like","use","using","should","must"]);function Yr(e){let t=[];for(let n of e.split(`
263
+ `)){let s=n.trim();if(/^[-*]\s*(don't|dont|never|always|do not|important)\b[:\s-]*(.*)$/i.exec(s)===null)continue;let o=s.replace(/^[-*]\s*/,""),i=Kr(o).split(/\s+/).filter(a=>a.length>=3&&!fl.has(a));t.push({text:o,keywords:i})}return t}var gl=["CLAUDE.md","AGENTS.md"];async function Jr(e){let t=await Promise.all(gl.map(n=>qr(ml.join(e,n))));for(let n of t){if(n===null)continue;let s=Yr(n);if(s.length>0)return s}return[]}async function St(e,t=Ki){let n=hl.resolve(e.repoRoot),s=await t.collectMessages({...e,repoRoot:n}),r=new Set(s.map(a=>a.sessionId)).size;if(s.length===0)return{version:1,root:n,harness:t.harness,tier:"extended",status:"no-sessions",sessionsAnalyzed:0,redacted:!e.includeRawSnippets,findings:[]};let o=await Jr(n),i=Hr(s,o,e.includeRawSnippets);return{version:1,root:n,harness:t.harness,tier:"extended",status:"run",sessionsAnalyzed:r,redacted:!e.includeRawSnippets,findings:i}}var Yi={error:3,warn:2,info:1};function kt(e,t){let n=Yi[t];return e.some(s=>Yi[s.severity]>=n)}async function Xr(e){let t=yl.resolve(e.repoRoot),n=Fo(),s=await Ae(t),{files:r,contents:o}=await Te(t),i=await rs(t),a=await _e(t),c=await Xn(t),l={repoRoot:t,harnesses:s,files:r,fileContents:o,intelligenceLayer:i,security:a,boundary:c},p=Sn(l);l.contextBudget=p;let{findings:f,records:m}=await gt(l,e.harnessFilter),d=hr(f),g=xn(f),S=un(r,s),A=await Z(t),xe=await Fn(l,A,f,S),q=Gn(m,f,S,xe,l),Ji=await en(l,A),Xi=await n,Qi=ct(i),Zi=e.aiReviewResults===void 0?wt:qe(e.aiReviewResults);return{version:Xi.version,root:t,harnesses:s,total_score:q.total_score,score_scope:q.score_scope,inventory:{fileCount:r.length,files:r},sharing:S,metaHarness:q,harnessGapMatrix:Ji,harnessOptimization:xe,intelligenceLayer:Qi,contextBudget:p,aiReview:Zi,findings:f,failureModeExposure:g,summary:d}}async function Qr(){let e=Pt(process.argv.slice(2));if(e.help&&(Ht(),process.exit(0)),e.emitAiTasks)try{let t=await yt(e.repoRoot);process.stdout.write(`${JSON.stringify(t,null,2)}
194
264
  `),process.exit(0)}catch(t){let n=t instanceof Error?t.message:String(t);process.stderr.write(`error: ${n}
195
- `),process.exit(2)}try{let t=e.ingestResultsPath===null?void 0:await lt(e.ingestResultsPath),n=await jr({repoRoot:e.repoRoot,harnessFilter:e.harnessFilter,...t===void 0?{}:{aiReviewResults:t}});e.format==="json"?ft(n):_t(n),tt(n.findings,e.failOn)&&process.exit(1),process.exit(0)}catch(t){let n=t instanceof Error?t.message:String(t);process.stderr.write(`error: ${n}
196
- `),process.exit(2)}}await Vr();
265
+ `),process.exit(2)}if(e.sessionAnalysis)try{let t=await St({repoRoot:e.repoRoot,sessionRoot:e.sessionRoot,maxSessions:e.maxSessions,includeRawSnippets:e.includeRawSnippets});e.format==="json"?process.stdout.write(`${JSON.stringify(t,null,2)}
266
+ `):Dt(t),process.exit(0)}catch(t){let n=t instanceof Error?t.message:String(t);process.stderr.write(`error: ${n}
267
+ `),process.exit(2)}try{let t=e.ingestResultsPath===null?void 0:await _t(e.ingestResultsPath),n=await Xr({repoRoot:e.repoRoot,harnessFilter:e.harnessFilter,...t===void 0?{}:{aiReviewResults:t}});e.format==="json"?Mt(n):an(n),kt(n.findings,e.failOn)&&process.exit(1),process.exit(0)}catch(t){let n=t instanceof Error?t.message:String(t);process.stderr.write(`error: ${n}
268
+ `),process.exit(2)}}await Qr();
package/package.json CHANGED
@@ -1,17 +1,35 @@
1
1
  {
2
2
  "name": "@paniolo/scan",
3
- "version": "0.1.1",
4
- "description": "Scan a repository for AI coding agent harness best practices (diagnostic only)",
3
+ "version": "0.2.1",
4
+ "description": "The AI Technical Debt Scanner diagnostic-only CLI that scores your repo's AI harness across Copilot, Cursor, Codex, Antigravity, Claude Code, and Gemini. No writes, no telemetry.",
5
5
  "keywords": [
6
6
  "agents",
7
+ "agents-md",
7
8
  "ai",
9
+ "antigravity",
10
+ "claude-code",
11
+ "cli",
8
12
  "codex",
13
+ "coding-agents",
9
14
  "copilot",
10
15
  "cursor",
16
+ "diagnostic",
17
+ "gemini",
11
18
  "harness",
12
- "lint"
19
+ "harness-engineering",
20
+ "lint",
21
+ "static-analysis",
22
+ "technical-debt"
13
23
  ],
24
+ "homepage": "https://paniolo.ai",
25
+ "bugs": {
26
+ "url": "https://github.com/paniolo-ai/paniolo-scan/issues"
27
+ },
14
28
  "license": "MIT",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/paniolo-ai/paniolo-scan.git"
32
+ },
15
33
  "bin": {
16
34
  "paniolo-scan": "dist/cli.js"
17
35
  },