@paniolo/scan 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli.js +65 -65
- package/dist/standards/weights.json +40 -9
- package/package.json +56 -92
package/README.md
CHANGED
|
@@ -105,7 +105,7 @@ CI, and does not affect the scan score. Prompt snippets are redacted by default;
|
|
|
105
105
|
- [npm publishing steps](./docs/npm-publishing-steps.md) — release runbook for publishing
|
|
106
106
|
`npx @paniolo/scan`
|
|
107
107
|
- [npm packaging and privacy](./docs/npm-packaging-privacy.md) — publishing `npx @paniolo/scan`
|
|
108
|
-
without publishing `src/`
|
|
108
|
+
without publishing `packages/scan/src/`
|
|
109
109
|
- [Diagrams](./docs/diagrams.md) — Mermaid conventions for docs
|
|
110
110
|
|
|
111
111
|
## Development
|
package/dist/cli.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{readFile as
|
|
3
|
-
`),process.exit(2),"error")}function
|
|
4
|
-
`),process.exit(2),"terminal")}function
|
|
5
|
-
`),process.exit(2),[]):n}var
|
|
2
|
+
import{readFile as fa}from"node:fs/promises";var vt={status:"not-run",score:null,grade:"not-run",checks:[],findings:[]};var ua=[{min:85,grade:"excellent"},{min:70,grade:"good"},{min:50,grade:"fair"},{min:0,grade:"poor"}];function be(e){for(let{min:t,grade:n}of ua)if(e>=t)return n;return"poor"}function Tt(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 ro(e){let t=e.indexOf(":");return t===-1?null:e.slice(t+1)}function v(e,t){let n=e[t];return typeof n=="string"?n:""}import{access as da}from"node:fs/promises";import pa from"node:path";var W=75,Lt=300,Ke=["CLAUDE.md","GEMINI.md",".github/copilot-instructions.md"];function S(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(r=>r.path===t)?.lines??null}function so(e){return e.includes("AGENTS.md")||e.includes("docs/ai/rules.md")}function Ye(e){return e.match(/^---\r?\n([\s\S]*?)\r?\n---/)?.[1]??null}function me(e,t){return new RegExp(`^${t}:`,"m").test(e)}async function fe(e,t){try{return await da(pa.join(e,t)),!0}catch{return!1}}function ge(e,t){return e.files.filter(n=>n.path.startsWith(t)).map(n=>n.path)}function I(e){return e.files.some(t=>t.path.startsWith("skills/")&&t.path.endsWith("/SKILL.md"))}function Je(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 Xe(e){return/agent routing/i.test(e)&&e.includes("|")&&/agents\/.*\.agent\.md/.test(e)}function x(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"]},"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 oo(e){return typeof e=="string"&&e in C}function _t(e){if(!x(e.data))return[];let t=e.data[C[e.checkId].schemaKey];return Array.isArray(t)?t.filter(n=>x(n)):[]}function Ft(e){let t=_t(e);if(e.checkId==="AI1-contradiction")return t.map(r=>({ruleId:"ai-contradiction",severity:"warn",message:`Contradiction: ${v(r,"explanation")}`,file:null,line:null,harnesses:[],hint:`"${v(r,"ruleA")}" conflicts with "${v(r,"ruleB")}"`}));if(e.checkId==="AI4-deadweight")return t.map(r=>({ruleId:"ai-deadweight",severity:"warn",message:`Dead weight: ${v(r,"reason")}`,file:null,line:null,harnesses:[],hint:`Rule: "${v(r,"rule")}" \u2014 a capable agent would follow it unprompted.`}));if(e.checkId==="AI5-vague-rules")return t.map(r=>({ruleId:"ai-vague-rule",severity:"warn",message:`Vague rule: ${v(r,"reason")}`,file:null,line:null,harnesses:[],hint:`Rule: "${v(r,"rule")}" \u2014 give it a testable decision boundary.`}));if(e.checkId==="AI3-security-review")return t.map(r=>({ruleId:"ai-security-review",severity:"info",message:`Possible security risk (${v(r,"risk")}): ${v(r,"explanation")}`,file:null,line:null,harnesses:[],hint:`LLM-judged at ${v(r,"location")} \u2014 verify manually before acting.`}));let n=ro(e.taskId);return t.map(r=>({ruleId:"ai-adapter-fidelity",severity:"warn",message:`Adapter drift: ${v(r,"explanation")}`,file:n,line:null,harnesses:[],hint:`Adapter claim: "${v(r,"claim")}"`}))}function Nt(e){return e.map(t=>{let n=new Map;for(let r of Ft(t)){let s=Tt(r);n.has(s)||n.set(s,r)}return n})}function Pt(e,t,n,r){let s=0,o;for(let i of e){let a=i.get(t);a!==void 0&&(s+=1,o??=a)}if(o!==void 0)return s>=n?o:{...o,severity:"info",message:`${o.message} [low-confidence: LLM judge variance, agreed in ${String(s)}/${String(r)} runs]`}}function Ht(e){let t=new Map;for(let r of e){let s=t.get(r.taskId)??[];s.push(r),t.set(r.taskId,s)}let n=[];for(let r of t.values()){let s=Nt(r),o=Math.ceil(r.length/2),i=new Set;for(let a of s)for(let c of a.keys())i.add(c);for(let a of i){let c=Pt(s,a,o,r.length);c!==void 0&&n.push(c)}}return n}function Mt(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"},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 ma=12;function Qe(e){let t=Ht(e),n=t.filter(s=>s.severity!=="info"),r=Math.max(0,100-ma*n.length);return{status:"run",score:r,grade:be(r),checks:Mt(e,t),findings:t}}function Dt(e,t,n){let r=C[t];if(!x(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(!x(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 Ot(e,t){if(!x(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(!oo(r))throw new TypeError(`AI review result "${n}" has an unknown checkId: ${String(r)}.`);return Dt(n,r,s),{taskId:n,checkId:r,data:s}}function Ze(e){if(!x(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)=>Ot(n,r))}}async function $t(e){let t=await fa(e,"utf8"),n=JSON.parse(t);return Ze(n).results}import ha from"node:path";function io(e){return e==="error"||e==="warn"||e==="info"?e:(process.stderr.write(`error: invalid --fail-on value: ${e}
|
|
3
|
+
`),process.exit(2),"error")}function ao(e){return e==="terminal"||e==="json"?e:(process.stderr.write(`error: invalid --format value: ${e}
|
|
4
|
+
`),process.exit(2),"terminal")}function Gt(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(", ")}
|
|
5
|
+
`),process.exit(2),[]):n}var co=[/\balways\b/i,/\bnever\b/i,/\bdont\b/i,/\bdon't\b/i,/\bmake sure\b/i,/\bremember to\b/i],lo=[/\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],uo=/\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,_={SS1:"Repeated instructions",SS2:"Ignored rules",SS3:"Friction hotspots",SS4:"Missing rule suggestions"};function jt(e){let t=process.cwd(),n=null,r="terminal",s="error",o=!1,i=!1,a=null,c=!1,l=null,m=30,u=!1;for(let f=0;f<e.length;f+=1){let d=e[f];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"){u=!0;continue}if(d==="--session-root"){let g=e[f+1];g===void 0&&(process.stderr.write(`error: --session-root requires a path
|
|
6
6
|
`),process.exit(2)),l=g,f+=1;continue}if(d==="--max-sessions"){let g=e[f+1];g===void 0&&(process.stderr.write(`error: --max-sessions requires a value
|
|
7
7
|
`),process.exit(2));let y=Number.parseInt(g,10);(!Number.isFinite(y)||y<=0)&&(process.stderr.write(`error: --max-sessions must be a positive integer
|
|
8
8
|
`),process.exit(2)),m=y,f+=1;continue}if(d==="--ingest-ai-results"){let g=e[f+1];g===void 0&&(process.stderr.write(`error: --ingest-ai-results requires a file path
|
|
9
9
|
`),process.exit(2)),a=g,f+=1;continue}if(d==="--harness"){let g=e[f+1];g===void 0&&(process.stderr.write(`error: --harness requires a value
|
|
10
|
-
`),process.exit(2)),n
|
|
11
|
-
`),process.exit(2)),r=
|
|
12
|
-
`),process.exit(2)),s=
|
|
13
|
-
`),process.exit(2)),t=
|
|
10
|
+
`),process.exit(2)),n=Gt(g),f+=1;continue}if(d==="--format"){let g=e[f+1];g===void 0&&(process.stderr.write(`error: --format requires a value
|
|
11
|
+
`),process.exit(2)),r=ao(g),f+=1;continue}if(d==="--fail-on"){let g=e[f+1];g===void 0&&(process.stderr.write(`error: --fail-on requires a value
|
|
12
|
+
`),process.exit(2)),s=io(g),f+=1;continue}d.startsWith("-")&&(process.stderr.write(`error: unknown option: ${d}
|
|
13
|
+
`),process.exit(2)),t=ha.resolve(d)}}return{repoRoot:t,harnessFilter:n,format:r,failOn:s,help:o,emitAiTasks:i,ingestResultsPath:a,sessionAnalysis:c,sessionRoot:l,maxSessions:m,includeRawSnippets:u}}function Wt(){process.stdout.write(`paniolo-scan \u2014 AI harness diagnostic (read-only)
|
|
14
14
|
|
|
15
15
|
Usage:
|
|
16
16
|
paniolo-scan [options] [path]
|
|
@@ -36,8 +36,8 @@ Examples:
|
|
|
36
36
|
npx @paniolo/scan --ingest-ai-results paniolo-ai-results.json --format json
|
|
37
37
|
npx @paniolo/scan --session-analysis
|
|
38
38
|
npx @paniolo/scan --session-analysis --format json --include-raw-snippets
|
|
39
|
-
`)}function
|
|
40
|
-
`)}var
|
|
39
|
+
`)}function Ut(e){process.stdout.write(`${JSON.stringify(e,null,2)}
|
|
40
|
+
`)}var ya=["SS4","SS2","SS3","SS1"];function Bt(e){if(process.stdout.write(`# paniolo-scan \u2014 Session Analysis (extended)
|
|
41
41
|
|
|
42
42
|
`),e.status==="no-sessions"){process.stdout.write(`No ${e.harness} session logs found for this repo. Nothing to analyze.
|
|
43
43
|
`);return}let t=e.findings.filter(r=>r.checkId==="SS4").length,n=e.findings.filter(r=>r.checkId==="SS3"&&r.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).
|
|
@@ -46,16 +46,16 @@ Examples:
|
|
|
46
46
|
`:`Snippets shown verbatim (--include-raw-snippets).
|
|
47
47
|
|
|
48
48
|
`),e.findings.length===0){process.stdout.write(`No recurring instructions, ignored rules, or friction detected.
|
|
49
|
-
`);return}for(let r of
|
|
49
|
+
`);return}for(let r of ya){let s=e.findings.filter(o=>o.checkId===r);if(s.length!==0){process.stdout.write(`## ${r} \u2014 ${_[r]}
|
|
50
50
|
|
|
51
51
|
`);for(let o of s)process.stdout.write(`- ${o.detail}
|
|
52
52
|
`);process.stdout.write(`
|
|
53
|
-
`)}}}var
|
|
53
|
+
`)}}}var Sa={"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 et(e){return Sa[e]??[]}var Vt=["error","warn","info"],po={error:"ERROR",warn:"WARN",info:"INFO"},mo={layering:"Layering",sharing:"Sharing",discoverability:"Discoverability",harnessWiring:"Harness wiring",maintainability:"Maintainability",guardrails:"Guardrails"},fo=["layering","sharing","discoverability","harnessWiring","maintainability","guardrails"],go=["copilot","cursor","codex","antigravity","claude","gemini"];function zt(e){let t=po[e.severity],n=e.file===null?"":` ${e.file}${e.line===null?"":`:${String(e.line)}`}`,r=e.harnesses.length===0?"":`
|
|
54
54
|
Harnesses: ${e.harnesses.join(", ")}`,s=e.hint===void 0?"":`
|
|
55
|
-
Hint: ${e.hint}`,o=
|
|
55
|
+
Hint: ${e.hint}`,o=et(e.ruleId),i=o.length===0?"":`
|
|
56
56
|
Prevents: ${o.join(", ")}-class agent failures`;return`[${t}] ${e.ruleId}
|
|
57
57
|
${e.message}${n?`
|
|
58
|
-
${n}`:""}${r}${i}${s}`}var
|
|
58
|
+
${n}`:""}${r}${i}${s}`}var ho=`---
|
|
59
59
|
|
|
60
60
|
\u2139\uFE0F Need professional-grade agent infrastructure?
|
|
61
61
|
|
|
@@ -68,7 +68,7 @@ For professional or production-grade work, we strongly recommend
|
|
|
68
68
|
engaging Paniolo's professional services to design, tune, and evolve
|
|
69
69
|
your infrastructure. Learn more at https://paniolo.ai or contact us
|
|
70
70
|
directly at https://paniolo.ai/#contact.
|
|
71
|
-
`;function
|
|
71
|
+
`;function qt(e){if(process.stdout.write(`## AI review (optional)
|
|
72
72
|
|
|
73
73
|
`),e.status==="not-run"){process.stdout.write(`Not run \u2014 pass --ingest-ai-results to score this dimension.
|
|
74
74
|
|
|
@@ -76,12 +76,12 @@ directly at https://paniolo.ai/#contact.
|
|
|
76
76
|
`);for(let n of e.checks){let r=n.passed?"\u2713":`\u2717 ${String(n.findingsCount)} finding(s)`;process.stdout.write(` ${r} ${n.title}
|
|
77
77
|
`)}for(let n of e.findings){let r=n.file===null?"":` (${n.file})`;process.stdout.write(` - ${n.message}${r}
|
|
78
78
|
`)}process.stdout.write(`
|
|
79
|
-
`)}function
|
|
79
|
+
`)}function Kt(e){if(e===void 0)return;let t=e.harnesses.filter(n=>n.detected);if(t.length!==0){process.stdout.write(`## Context budget
|
|
80
80
|
|
|
81
81
|
`);for(let n of t){process.stdout.write(`${n.harness}: ${String(n.totalLines)} always-loaded lines, ~${String(n.estimatedTokens)} tokens (${n.status})
|
|
82
82
|
`);for(let r of n.files.slice(0,3))process.stdout.write(` ${r.path}: ${String(r.lines)} lines
|
|
83
83
|
`)}process.stdout.write(`
|
|
84
|
-
`)}}function
|
|
84
|
+
`)}}function Yt(e){if(process.stdout.write(`## Predicted runtime failure exposure
|
|
85
85
|
|
|
86
86
|
`),e.byDimension.length===0){process.stdout.write(`No findings map to a runtime failure class.
|
|
87
87
|
|
|
@@ -90,16 +90,16 @@ directly at https://paniolo.ai/#contact.
|
|
|
90
90
|
`)}e.untaggedFindings>0&&process.stdout.write(`
|
|
91
91
|
${String(e.untaggedFindings)} finding(s) not yet mapped to a failure class.
|
|
92
92
|
`),process.stdout.write(`
|
|
93
|
-
`)}var
|
|
93
|
+
`)}var Jt=new Set(["shared","skills","agents"]),Q=["copilot","cursor","codex","antigravity","claude","gemini"];function yo(e,t){return t.length>=2?!0:Jt.has(e.layer)||e.path==="AGENTS.md"}function tt(e){switch(e){case"yes":return"\u2713";case"partial":return"~";case"no":return"\u2717";case"na":return"\u2014"}}import{readFile as ka}from"node:fs/promises";import xa from"node:path";async function Xt(e){try{return await ka(xa.join(e,".codex/hooks.json"),"utf8"),!0}catch{return!1}}function p(e,t){return{status:e,detail:t}}function Qt(){let e={copilot:p("na",""),cursor:p("na",""),codex:p("na",""),antigravity:p("na",""),claude:p("na",""),gemini:p("na","")};return{sharedSkillsDiscoverable:{...e},customAgents:{...e},lifecycleHooks:{...e},thinAdapter:{...e},workflows:{...e}}}var Ra={copilot:".github/copilot-instructions.md",claude:"CLAUDE.md",gemini:"GEMINI.md"};function P(e){return Ra[e]??null}function Ce(e,t){if(!I(e))return!1;if(S(e,"docs/ai/available-skills.md"))return!0;let n=h(e,"AGENTS.md");if(n!==null&&Je(n))return!0;let r=P(t);if(r===null)return!1;let s=h(e,r);return s!==null&&s.includes("skills/")}function T(e,t,n){let r=e.settings?.[t];if(x(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 wa=50;function So(e){return e.files.some(t=>t.path.startsWith("agents/")&&t.path.endsWith(".agent.md"))}function nt(e,t){let n=U(e,t);return n===null?!1:n<=wa}function ko(e,t){let n=h(e,t);return n===null?!1:n.includes("AGENTS.md")||n.includes("docs/ai/rules.md")}function rt(e){return e.files.some(t=>t.path.startsWith(".agent/workflows/"))}function xo(e){let t=h(e,"CLAUDE.md");return t!==null&&Xe(t)}function Zt(e,t){let n=So(t.context);switch(e){case"copilot":case"cursor":return T(t.vscode,"chat.agentFilesLocations","agents")&&n?p("yes","agents/ wired in chat.agentFilesLocations"):n?p("partial","agents/ present but not wired in VS Code settings"):p("no","No agents/ tree or VS Code agent locations");case"codex":return t.context.files.some(s=>s.path.startsWith(".codex/agents/"))&&n?p("yes",".codex/agents wrappers with shared agents/"):n?p("partial","agents/ present without .codex/agents wrappers"):p("no","No custom agents configured");case"claude":return xo(t.context)?p("yes","Agent routing table in CLAUDE.md"):n?p("partial","agents/ present without routing table in CLAUDE.md"):p("no","No agent routing or agents/ tree");case"gemini":{if(!n)return p("no","No agents/ tree");let r=P("gemini"),s=r===null?null:t.context.fileContents.get(r)??null;return s!==null&&s.includes("agents/")?p("partial","agents/ referenced from GEMINI.md"):p("partial","agents/ present; document routing in GEMINI.md")}case"antigravity":return p("na","Uses workflow playbooks instead of custom agents");default:return p("no","Unknown harness")}}function en(e,t){let n=t.vscode.hooksDirExists,r=t.vscode.settings?.["chat.useCustomAgentHooks"]===!0;switch(e){case"copilot":case"cursor":return n&&r?p("yes",".github/hooks/ with chat.useCustomAgentHooks"):n||r?p("partial","Hooks partially configured in VS Code workspace"):p("no","No lifecycle hooks configured");case"codex":return t.codexHooksExists?p("yes",".codex/hooks.json present"):n?p("partial","Shared .github/hooks/ only; no .codex/hooks.json"):p("no","No Codex hooks configured");case"claude":return t.claudeSettingsRaw!==null&&/"hooks"\s*:/.test(t.claudeSettingsRaw)?p("yes","Hooks in .claude/settings.json"):n?p("partial","Shared .github/hooks/ only; no .claude hooks"):p("no","No Claude hooks configured");case"gemini":return n&&r?p("partial","Shared VS Code hooks only; no Gemini-native hooks"):p("no","No lifecycle hooks for Gemini");case"antigravity":return p("na","No hook surface for Antigravity workflows");default:return p("no","Unknown harness")}}function tn(e,t){if(!I(t.context))return p("no","No skills/ tree");switch(e){case"copilot":case"cursor":return T(t.vscode,"chat.agentSkillsLocations","skills")?p("yes","skills/ wired in chat.agentSkillsLocations"):p("partial","skills/ present but not wired in VS Code settings");case"codex":return Ce(t.context,"codex")?p("partial","skills/ with prose discovery via AGENTS.md or skill index"):p("partial","skills/ present; no documented discovery workflow");case"claude":case"gemini":return Ce(t.context,e)?p("partial","Prose discovery via skill index or adapter pointers"):p("no","skills/ without index or adapter pointers");case"antigravity":return rt(t.context)?p("yes","skills/ with workflow playbooks"):p("partial","skills/ present without workflow playbooks");default:return p("no","Unknown harness")}}function nn(e,t){switch(e){case"copilot":{let n=P("copilot");return n===null||!t.context.files.some(r=>r.path===n)?p("no","Missing .github/copilot-instructions.md"):nt(t.context,n)?p("yes","Copilot instructions within line budget"):p("partial","Copilot instructions exceed thin adapter budget")}case"cursor":{let n=t.context.files.some(s=>s.path.startsWith(".cursor/rules/")),r=T(t.vscode,"chat.agentSkillsLocations","skills")&&T(t.vscode,"chat.agentFilesLocations","agents");return n||r?p("yes","Cursor rules or VS Code agent settings configured"):p("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")?p("yes",".codex/ with shared AGENTS.md entry"):p("partial",".codex/ without root AGENTS.md"):p("no","No .codex/ config surface");case"claude":{let n=P("claude");if(n===null||!t.context.files.some(o=>o.path===n))return p("no","Missing CLAUDE.md");let r=nt(t.context,n),s=ko(t.context,n);return r&&s?p("yes","Thin CLAUDE.md referencing shared layers"):r?p("partial","CLAUDE.md thin but missing shared layer pointers"):p("partial","CLAUDE.md exceeds thin adapter budget")}case"gemini":{let n=P("gemini");return n===null||!t.context.files.some(r=>r.path===n)?p("no","Missing GEMINI.md"):nt(t.context,n)?p("yes","Thin GEMINI.md adapter"):p("partial","GEMINI.md exceeds thin adapter budget")}case"antigravity":return p("partial","Workflows only; no classic root adapter");default:return p("no","Unknown harness")}}function rn(e,t){return e!=="antigravity"?p("na","Workflow playbooks are Antigravity-specific"):rt(t.context)?p("yes",".agent/workflows/ playbooks present"):p("no","No .agent/workflows/ playbooks")}function sn(e,t,n){switch(e){case"sharedSkillsDiscoverable":return tn(t,n);case"customAgents":return Zt(t,n);case"lifecycleHooks":return en(t,n);case"thinAdapter":return nn(t,n);case"workflows":return rn(t,n);default:return p("no","Unknown capability")}}var on={sharedSkillsDiscoverable:"Shared skills discoverable",customAgents:"Custom agents",lifecycleHooks:"Lifecycle hooks",thinAdapter:"Thin adapter",workflows:"Workflows / playbooks"},Ae=["sharedSkillsDiscoverable","customAgents","lifecycleHooks","thinAdapter","workflows"],Ro="Harness not detected";import{readFile as ba}from"node:fs/promises";import Ca from"node:path";async function an(e){try{return await ba(Ca.join(e,".claude/settings.json"),"utf8")}catch{return null}}async function cn(e,t){let n=Q.filter(o=>e.harnesses.includes(o)),r={context:e,vscode:t,claudeSettingsRaw:await an(e.repoRoot),codexHooksExists:await Xt(e.repoRoot)},s=Qt();for(let o of Ae){let i=s[o];for(let a of Q){if(!e.harnesses.includes(a)){i[a]=p("na",Ro);continue}i[a]=sn(o,a,r)}}return{capabilities:Ae,harnesses:n,matrix:s}}function ln(e){if(process.stdout.write(`## Harness gap matrix
|
|
94
94
|
|
|
95
95
|
`),e.harnesses.length===0){process.stdout.write(`No harnesses detected \u2014 add tool adapters to compare capabilities.
|
|
96
96
|
|
|
97
97
|
`);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}
|
|
98
|
-
`);for(let s of Ae){let o=
|
|
98
|
+
`);for(let s of Ae){let o=on[s].padEnd(t),i=e.harnesses.map(a=>{let{status:c}=e.matrix[s][a];return tt(c).padEnd(n)}).join("");process.stdout.write(`${o}${i}
|
|
99
99
|
`)}process.stdout.write(`
|
|
100
100
|
Legend: \u2713 yes ~ partial \u2717 no \u2014 not applicable
|
|
101
101
|
|
|
102
|
-
`)}function
|
|
102
|
+
`)}function un(e){e!==void 0&&(process.stdout.write(`## Intelligence layer
|
|
103
103
|
|
|
104
104
|
`),process.stdout.write(`Surfaces: ${String(e.surfaces.length)} detected
|
|
105
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)
|
|
@@ -109,13 +109,13 @@ Legend: \u2713 yes ~ partial \u2717 no \u2014 not applicable
|
|
|
109
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)
|
|
110
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)
|
|
111
111
|
|
|
112
|
-
`))}function
|
|
112
|
+
`))}function dn(e){process.stdout.write(`## Meta-harness dimensions
|
|
113
113
|
|
|
114
|
-
`);for(let c of
|
|
114
|
+
`);for(let c of fo){let l=e.dimensions[c];if(l===void 0)continue;let m=mo[c],u=l.applicableRules===0?" (no rules yet)":` (${String(l.passedRules)}/${String(l.applicableRules)} rules)`;process.stdout.write(`${m}: ${String(l.score)}/100 (${l.grade})${u}
|
|
115
115
|
`)}let{coverage:t}=e,n=`Total: ${String(e.total_score)}/100 (${e.score_scope}) \u2014 ${String(t.rulesApplied)} rules across ${String(t.dimensionsRun)}/${String(t.dimensionsTotal)} core dimensions`,r=t.level==="partial"?` (partial coverage: ${t.dimensionsNotRun.join(", ")} did not run \u2014 the score reflects evaluated surfaces only)`:"";process.stdout.write(`${n}${r}
|
|
116
116
|
`);let{harnessNet:s}=e,o=s.score>0?"+":"",i=s.repoReadiness===null?"":` \xB7 repo readiness ${String(s.repoReadiness)}/100`,a=s.status==="implicit-only"?" (implicit infrastructure only \u2014 tests, gates, and enforced comments count as harness; no guidance files detected)":` (${String(s.contributions.length)} contributions, ${String(s.liabilities.length)} liabilities)`;process.stdout.write(`Harness net: ${o}${String(s.score)} vs bare-repo baseline 0${a}${i}
|
|
117
117
|
|
|
118
|
-
`)}function
|
|
118
|
+
`)}function pn(e){process.stdout.write(`## Harness optimization
|
|
119
119
|
|
|
120
120
|
`);let t=e.filter(r=>r.detected);if(t.length===0){process.stdout.write(`No harnesses detected \u2014 add tool adapters to evaluate optimization.
|
|
121
121
|
|
|
@@ -127,54 +127,54 @@ Legend: \u2713 yes ~ partial \u2717 no \u2014 not applicable
|
|
|
127
127
|
`),process.stdout.write(`
|
|
128
128
|
`)}let n=e.filter(r=>!r.detected);n.length>0&&process.stdout.write(`Not detected: ${n.map(r=>r.harness).join(", ")}
|
|
129
129
|
|
|
130
|
-
`)}function
|
|
130
|
+
`)}function mn(e){process.stdout.write(`## Guidance sharing
|
|
131
131
|
|
|
132
132
|
`),process.stdout.write(`Shared (canonical / multi-harness): ${String(e.shared.lines)} lines (${String(e.shared.percentLines)}%) across ${String(e.shared.files)} file(s)
|
|
133
133
|
`),process.stdout.write(`Harness-specific: ${String(e.unique.totals.lines)} lines (${String(e.unique.totals.percentLines)}%) across ${String(e.unique.totals.files)} file(s)
|
|
134
|
-
`);let t=
|
|
134
|
+
`);let t=go.filter(n=>e.unique.byHarness[n].lines>0);if(t.length>0){process.stdout.write(`
|
|
135
135
|
Per-harness unique guidance:
|
|
136
136
|
`);for(let n of t){let r=e.unique.byHarness[n];process.stdout.write(` ${n}: ${String(r.lines)} lines (${String(r.files)} file(s))
|
|
137
137
|
`)}}process.stdout.write(`
|
|
138
|
-
`)}function
|
|
138
|
+
`)}function fn(e){if(process.stdout.write(`paniolo-scan \u2014 AI harness diagnostic
|
|
139
139
|
|
|
140
140
|
`),process.stdout.write(`Root: ${e.root}
|
|
141
141
|
`),process.stdout.write(`Harnesses: ${e.harnesses.length===0?"(none detected)":e.harnesses.join(", ")}
|
|
142
142
|
`),process.stdout.write(`Guidance files: ${String(e.inventory.fileCount)}
|
|
143
143
|
`),process.stdout.write(`Findings: ${String(e.summary.error)} error(s), ${String(e.summary.warn)} warn(s), ${String(e.summary.info)} info
|
|
144
144
|
|
|
145
|
-
`),
|
|
145
|
+
`),mn(e.sharing),un(e.intelligenceLayer),Kt(e.contextBudget),dn(e.metaHarness),qt(e.aiReview),ln(e.harnessGapMatrix),pn(e.harnessOptimization),Yt(e.failureModeExposure),process.stdout.write(`## Findings
|
|
146
146
|
|
|
147
147
|
`),e.findings.length===0)process.stdout.write(`No findings.
|
|
148
148
|
|
|
149
|
-
`);else{let t=[...e.findings].sort((n,r)=>{let s=
|
|
149
|
+
`);else{let t=[...e.findings].sort((n,r)=>{let s=Vt.indexOf(n.severity)-Vt.indexOf(r.severity);return s!==0?s:n.ruleId.localeCompare(r.ruleId)});for(let n of t)process.stdout.write(`${zt(n)}
|
|
150
150
|
|
|
151
|
-
`)}process.stdout.write(Eo)}import Bl from"node:path";function fn(){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 gn(e,t){return e.harness!==void 0?t.includes(e.harness)?[e.harness]:[]:Yt.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 Z(e,t){return t===0?0:Math.round(e/t*1e3)/10}function hn(e,t){let n={files:0,lines:0,bytes:0},r=fn(),s={files:0,lines:0,bytes:0},o={files:0,lines:0,bytes:0},i=[];for(let a of e){let c=gn(a,t);if(c.length===0)continue;o.files+=1,o.lines+=a.lines,o.bytes+=a.bytes;let l=vo(a,c),m=l?"shared":"unique";if(i.push({path:a.path,lines:a.lines,scope:m,harnesses:c}),l)n.files+=1,n.lines+=a.lines,n.bytes+=a.bytes;else{let[u]=c;u!==void 0&&(r[u].files+=1,r[u].lines+=a.lines,r[u].bytes+=a.bytes),s.files+=1,s.lines+=a.lines,s.bytes+=a.bytes}}return{totals:o,shared:{...n,percentLines:Z(n.lines,o.lines)},unique:{byHarness:r,totals:{...s,percentLines:Z(s.lines,o.lines)}},files:i}}import L from"node:path";import{access as Ha}from"node:fs/promises";async function R(e){try{return await Ha(e),!0}catch{return!1}}function yn(e){return e===null?!1:e["chat.agentSkillsLocations"]!==void 0||e["chat.agentFilesLocations"]!==void 0||e["chat.useCustomAgentHooks"]===!0}import{readFile as Da}from"node:fs/promises";function Sn(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 kn(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]=Sn(s));return Object.keys(t).length===0?null:t}function Ie(e){try{let t=JSON.parse(e);if(S(t))return t}catch{}return kn(e)}async function xn(e){try{let t=await Da(e,"utf8");return Ie(t)}catch{return null}}async function Ee(e){let t=new Set;await R(L.join(e,".github/copilot-instructions.md"))&&t.add("copilot"),await R(L.join(e,".github/hooks"))&&t.add("copilot");let n=await xn(L.join(e,".vscode/settings.json"));return yn(n)&&(t.add("cursor"),t.add("copilot")),await R(L.join(e,".cursor"))&&t.add("cursor"),await R(L.join(e,".codex/config.toml"))&&t.add("codex"),await R(L.join(e,".codex/hooks.json"))&&t.add("codex"),await R(L.join(e,".codex/agents"))&&t.add("codex"),await R(L.join(e,".agent/workflows"))&&t.add("antigravity"),await R(L.join(e,".agent/README.md"))&&t.add("antigravity"),await R(L.join(e,"CLAUDE.md"))&&t.add("claude"),await R(L.join(e,".claude/settings.json"))&&t.add("claude"),await R(L.join(e,"GEMINI.md"))&&t.add("gemini"),[...t].sort()}function ve(e){return Math.ceil(e/4)}function M(e,t){return{path:e.path,lines:e.lines,bytes:e.bytes,estimatedTokens:ve(e.bytes),reason:t}}function Rn(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 ee(e,t){return e.files.find(n=>n.path===t)??null}function wn(e,t){let n=[];if(t==="copilot"){let r=ee(e,".github/copilot-instructions.md");r!==null&&n.push(M(r,"Copilot workspace instructions are loaded by Copilot Chat."))}if(t==="cursor")for(let r of e.files)r.path.startsWith(".cursor/rules/")&&Rn(e,r)&&n.push(M(r,"Cursor rule declares alwaysApply: true."));if(t==="codex"){let r=ee(e,"AGENTS.md");r!==null&&n.push(M(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(M(s,"Codex adapter guidance under .codex/."))}if(t==="antigravity"){let r=ee(e,".agent/README.md");r!==null&&n.push(M(r,"Antigravity workspace adapter README."))}if(t==="claude"){let r=ee(e,"CLAUDE.md");r!==null&&n.push(M(r,"Claude Code root instruction file."))}if(t==="gemini"){let r=ee(e,"GEMINI.md");r!==null&&n.push(M(r,"Gemini root instruction file."))}return n.toSorted((r,s)=>r.path.localeCompare(s.path))}function bn(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=wn(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:ve(o),maxRecommendedLines:250,status:s>250?"high":"ok"}}function Cn(e){return{harnesses:Q.map(t=>bn(e,t)),maxRecommendedLines:250,maxRecommendedFileLines:150}}var An=["Memory","Reflection","Planning","Action","System Operation"];function In(e){let t=new Map(An.map(i=>[i,{dimension:i,findingCount:0,error:0,warn:0,info:0,ruleIds:[]}])),n=new Map(An.map(i=>[i,new Set])),r=0,s=0;for(let i of e){let a=Ze(i.ruleId);if(a.length===0){s+=1;continue}r+=1;for(let c of a){let l=t.get(c),m=n.get(c);l===void 0||m===void 0||(l.findingCount+=1,l[i.severity]+=1,m.has(i.ruleId)||(m.add(i.ruleId),l.ruleIds.push(i.ruleId)))}}return{byDimension:An.map(i=>t.get(i)).filter(i=>i.findingCount>0),taggedFindings:r,untaggedFindings:s}}function En(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:Z(i,a),uniquePercent:Z(o,a)}}return r}function vn(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 Po=[{min:85,grade:"excellent"},{min:70,grade:"good"},{min:50,grade:"fair"},{min:0,grade:"poor"}],rt={error:12,warn:5,info:1},Mo=40;function Tn(e){let t=e.error*rt.error+e.warn*rt.warn+e.info*rt.info;return Math.min(t,Mo)}import Le from"node:path";function H(e,t){return e.files.some(n=>n.path===t)}function Ln(e,t){return e.fileContents.get(t)??null}function Oa(e,t){return e.files.find(r=>r.path===t)?.lines??null}function $a(e){return e.includes("AGENTS.md")||e.includes("docs/ai/rules.md")}function te(e){return e.files.some(t=>t.path.startsWith("skills/"))}function Te(e){return e.files.some(t=>t.path.startsWith("agents/"))}function _n(e,t){return e.settings?.[t]===!0}function st(e,t){let n=Oa(e,t);return n===null?!1:n<=W}function ot(e,t){let n=Ln(e,t);return n===null?!1:$a(n)}function Fn(e){let t=Ln(e,".agent/README.md");return t===null?!1:/\.agent\/workflows\/|workflows\//i.test(t)&&/(workflow|playbook|slash command|mission|turbo)/i.test(t)}function ne(e,t,n){let r=e.settings?.[t];if(S(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 Ho={copilot:[{id:"copilot-instructions",label:"Copilot instructions file present",weight:15,run:({context:e})=>H(e,".github/copilot-instructions.md")},{id:"copilot-references-shared",label:"Copilot instructions reference shared layers",weight:15,run:({context:e})=>ot(e,".github/copilot-instructions.md")},{id:"copilot-adapter-thin",label:"Copilot instructions stay thin",weight:10,run:({context:e})=>st(e,".github/copilot-instructions.md")},{id:"copilot-skills-location",label:"chat.agentSkillsLocations points at skills/",weight:15,run:({vscode:e})=>ne(e,"chat.agentSkillsLocations","skills")},{id:"copilot-agents-location",label:"chat.agentFilesLocations points at agents/",weight:15,run:({vscode:e})=>ne(e,"chat.agentFilesLocations","agents")},{id:"copilot-hooks-enabled",label:"Custom agent hooks enabled when .github/hooks/ exists",weight:15,run:({vscode:e})=>!e.hooksDirExists||_n(e,"chat.useCustomAgentHooks")},{id:"copilot-shared-skills",label:"Shared skills/ tree present",weight:8,run:({context:e})=>te(e)},{id:"copilot-shared-agents",label:"Shared agents/ tree present",weight:7,run:({context:e})=>Te(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/"))||ne(t,"chat.agentSkillsLocations","skills")},{id:"cursor-skills-location",label:"chat.agentSkillsLocations points at skills/",weight:20,run:({vscode:e})=>ne(e,"chat.agentSkillsLocations","skills")},{id:"cursor-agents-location",label:"chat.agentFilesLocations points at agents/",weight:20,run:({vscode:e})=>ne(e,"chat.agentFilesLocations","agents")},{id:"cursor-hooks-enabled",label:"Custom agent hooks enabled when .github/hooks/ exists",weight:15,run:({vscode:e})=>!e.hooksDirExists||_n(e,"chat.useCustomAgentHooks")},{id:"cursor-shared-skills",label:"Shared skills/ tree present",weight:13,run:({context:e})=>te(e)},{id:"cursor-shared-agents",label:"Shared agents/ tree present",weight:12,run:({context:e})=>Te(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 R(Le.join(e.repoRoot,"api/AGENTS.md"))||await R(Le.join(e.repoRoot,"react/AGENTS.md"))||await R(Le.join(e.repoRoot,"shared/AGENTS.md"))},{id:"codex-hooks",label:"Codex hooks.json present",weight:20,run:({context:e})=>R(Le.join(e.repoRoot,".codex/hooks.json"))},{id:"codex-agents-wrappers",label:"Codex agent wrappers present",weight:20,run:({context:e})=>R(Le.join(e.repoRoot,".codex/agents"))},{id:"codex-shared-entry",label:"Root AGENTS.md present",weight:20,run:({context:e})=>H(e,"AGENTS.md")},{id:"codex-shared-skills",label:"Shared skills/ tree present",weight:8,run:({context:e})=>te(e)},{id:"codex-shared-rules",label:"Canonical rules doc present",weight:7,run:({context:e})=>H(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})=>Fn(e)},{id:"antigravity-shared-entry",label:"Root AGENTS.md present",weight:20,run:({context:e})=>H(e,"AGENTS.md")},{id:"antigravity-shared-skills",label:"Shared skills/ tree present",weight:15,run:({context:e})=>te(e)},{id:"antigravity-ai-system-doc",label:"AI system layout doc present",weight:15,run:({context:e})=>H(e,"docs/ai/ai-system.md")}],claude:[{id:"claude-adapter",label:"CLAUDE.md adapter present",weight:25,run:({context:e})=>H(e,"CLAUDE.md")},{id:"claude-references-shared",label:"CLAUDE.md references shared layers",weight:25,run:({context:e})=>ot(e,"CLAUDE.md")},{id:"claude-adapter-thin",label:"CLAUDE.md stays thin",weight:20,run:({context:e})=>st(e,"CLAUDE.md")},{id:"claude-shared-skills",label:"Shared skills/ tree present",weight:15,run:({context:e})=>te(e)},{id:"claude-skills-index",label:"Skill index doc for prose discovery",weight:8,run:({context:e})=>H(e,"docs/ai/available-skills.md")},{id:"claude-shared-agents",label:"Shared agents/ tree present",weight:7,run:({context:e})=>Te(e)}],gemini:[{id:"gemini-adapter",label:"GEMINI.md adapter present",weight:30,run:({context:e})=>H(e,"GEMINI.md")},{id:"gemini-references-shared",label:"GEMINI.md references shared layers",weight:25,run:({context:e})=>ot(e,"GEMINI.md")},{id:"gemini-adapter-thin",label:"GEMINI.md stays thin",weight:20,run:({context:e})=>st(e,"GEMINI.md")},{id:"gemini-shared-skills",label:"Shared skills/ tree present",weight:15,run:({context:e})=>te(e)},{id:"gemini-shared-agents",label:"Shared agents/ tree present",weight:10,run:({context:e})=>Te(e)}]};async function Nn(e,t){let n=Ho[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 Pn(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 Mn(e){for(let{min:t,grade:n}of Po)if(e>=t)return n;return"poor"}async function Hn(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 Nn(e,{context:t,vscode:n,harness:e}),l=vn(r,e),m=Pn(c),u=Tn(l),f=Math.max(0,Math.min(100,m-u));return{harness:e,detected:!0,score:f,grade:Mn(f),checks:c,findingsCount:l,loadProfile:o[e]??null}}async function Dn(e,t,n,r){let s=En(r,e.harnesses),o=[];for(let i of Q){let a=await Hn(i,e,t,n,r,s);o.push(a)}return o}import{readFileSync as Ga}from"node:fs";import{dirname as ja,join as Do}from"node:path";import{fileURLToPath as Wa}from"node:url";var Ua=Wa(import.meta.url),Oo=ja(Ua);function it(e){return typeof e=="object"&&e!==null}function Ba(e){return it(e)&&it(e.dimensions)&&it(e.check_weights)}function Va(e){return it(e)}function $o(e,t){let n=JSON.parse(Ga(e,"utf8"));if(!t(n))throw new Error(`Invalid standards file: ${e}`);return n}var On=$o(Do(Oo,"standards","weights.json"),Ba),$n=$o(Do(Oo,"standards","reference-thresholds.json"),Va);function Gn(e){return!Number.isFinite(e)||e<0?0:e<=1?e:e<=10?e/10:e<=100?e/100:1}function Go(e,t){return e>=t?1:0}function jo(e,t){return e<=t?1:e===0?0:t/e}function Wo(e,t){if(t<=0)return 0;let n=e/t;return Math.max(0,Math.min(1,n))}function jn(e,t,n){return e>=t&&e<=n?1:e<t?t===0?0:e/t:e===0?0:n/e}function B(e){if(e.curve===void 0)return Gn(e.rawScore??0);let t=e.measuredValue??0,n=e.referenceValue,r=typeof n=="number"?n:0;switch(e.curve){case"binary":return Go(t,r);case"asymptoticDecay":return jo(t,r);case"ratio":return Wo(t,r);case"goldilocks":{let[s,o]=Array.isArray(n)?n:[0,r];return jn(t,s??0,o??0)}}}function Wn(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=B(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:be(c),passedRules:i.passedRules,applicableRules:i.applicableRules}}return r}function Un(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)}function Bn(e){return e.contextBudget!==void 0&&e.contextBudget.harnesses.length>0}function V(e){return e.intelligenceLayer??null}function z(e){return e.packageJson.path!==null||e.workflows.length>0||e.prTemplates.length>0}function Vn(e){let t=V(e);return t!==null&&z(t)}function w(e){return e.intelligenceLayer??null}function ye(e){return Object.entries(e.packageJson.scripts).map(([t,n])=>({name:t,command:n}))}function Se(e,t,n){return ye(e).some(r=>t.test(r.name)||n.test(r.command))}function Uo(e,t){return ye(e).filter(n=>t.test(n.name)||t.test(n.command)).map(n=>n.name).toSorted()}function ke(e){return e.workflows.map(t=>t.commands.join(`
|
|
151
|
+
`)}process.stdout.write(ho)}import Vl from"node:path";function gn(){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 hn(e,t){return e.harness!==void 0?t.includes(e.harness)?[e.harness]:[]:Jt.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 Z(e,t){return t===0?0:Math.round(e/t*1e3)/10}function yn(e,t){let n={files:0,lines:0,bytes:0},r=gn(),s={files:0,lines:0,bytes:0},o={files:0,lines:0,bytes:0},i=[];for(let a of e){let c=hn(a,t);if(c.length===0)continue;o.files+=1,o.lines+=a.lines,o.bytes+=a.bytes;let l=yo(a,c),m=l?"shared":"unique";if(i.push({path:a.path,lines:a.lines,scope:m,harnesses:c}),l)n.files+=1,n.lines+=a.lines,n.bytes+=a.bytes;else{let[u]=c;u!==void 0&&(r[u].files+=1,r[u].lines+=a.lines,r[u].bytes+=a.bytes),s.files+=1,s.lines+=a.lines,s.bytes+=a.bytes}}return{totals:o,shared:{...n,percentLines:Z(n.lines,o.lines)},unique:{byHarness:r,totals:{...s,percentLines:Z(s.lines,o.lines)}},files:i}}import L from"node:path";import{access as Aa}from"node:fs/promises";async function R(e){try{return await Aa(e),!0}catch{return!1}}function Sn(e){return e===null?!1:e["chat.agentSkillsLocations"]!==void 0||e["chat.agentFilesLocations"]!==void 0||e["chat.useCustomAgentHooks"]===!0}import{readFile as Ia}from"node:fs/promises";function kn(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 xn(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]=kn(s));return Object.keys(t).length===0?null:t}function Ie(e){try{let t=JSON.parse(e);if(x(t))return t}catch{}return xn(e)}async function Rn(e){try{let t=await Ia(e,"utf8");return Ie(t)}catch{return null}}async function Ee(e){let t=new Set;await R(L.join(e,".github/copilot-instructions.md"))&&t.add("copilot"),await R(L.join(e,".github/hooks"))&&t.add("copilot");let n=await Rn(L.join(e,".vscode/settings.json"));return Sn(n)&&(t.add("cursor"),t.add("copilot")),await R(L.join(e,".cursor"))&&t.add("cursor"),await R(L.join(e,".codex/config.toml"))&&t.add("codex"),await R(L.join(e,".codex/hooks.json"))&&t.add("codex"),await R(L.join(e,".codex/agents"))&&t.add("codex"),await R(L.join(e,".agent/workflows"))&&t.add("antigravity"),await R(L.join(e,".agent/README.md"))&&t.add("antigravity"),await R(L.join(e,"CLAUDE.md"))&&t.add("claude"),await R(L.join(e,".claude/settings.json"))&&t.add("claude"),await R(L.join(e,"GEMINI.md"))&&t.add("gemini"),[...t].sort()}function ve(e){return Math.ceil(e/4)}function H(e,t){return{path:e.path,lines:e.lines,bytes:e.bytes,estimatedTokens:ve(e.bytes),reason:t}}function wn(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 ee(e,t){return e.files.find(n=>n.path===t)??null}function bn(e,t){let n=[];if(t==="copilot"){let r=ee(e,".github/copilot-instructions.md");r!==null&&n.push(H(r,"Copilot workspace instructions are loaded by Copilot Chat."))}if(t==="cursor")for(let r of e.files)r.path.startsWith(".cursor/rules/")&&wn(e,r)&&n.push(H(r,"Cursor rule declares alwaysApply: true."));if(t==="codex"){let r=ee(e,"AGENTS.md");r!==null&&n.push(H(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(H(s,"Codex adapter guidance under .codex/."))}if(t==="antigravity"){let r=ee(e,".agent/README.md");r!==null&&n.push(H(r,"Antigravity workspace adapter README."))}if(t==="claude"){let r=ee(e,"CLAUDE.md");r!==null&&n.push(H(r,"Claude Code root instruction file."))}if(t==="gemini"){let r=ee(e,"GEMINI.md");r!==null&&n.push(H(r,"Gemini root instruction file."))}return n.toSorted((r,s)=>r.path.localeCompare(s.path))}function Cn(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=bn(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:ve(o),maxRecommendedLines:250,status:s>250?"high":"ok"}}function An(e){return{harnesses:Q.map(t=>Cn(e,t)),maxRecommendedLines:250,maxRecommendedFileLines:150}}var In=["Memory","Reflection","Planning","Action","System Operation"];function En(e){let t=new Map(In.map(i=>[i,{dimension:i,findingCount:0,error:0,warn:0,info:0,ruleIds:[]}])),n=new Map(In.map(i=>[i,new Set])),r=0,s=0;for(let i of e){let a=et(i.ruleId);if(a.length===0){s+=1;continue}r+=1;for(let c of a){let l=t.get(c),m=n.get(c);l===void 0||m===void 0||(l.findingCount+=1,l[i.severity]+=1,m.has(i.ruleId)||(m.add(i.ruleId),l.ruleIds.push(i.ruleId)))}}return{byDimension:In.map(i=>t.get(i)).filter(i=>i.findingCount>0),taggedFindings:r,untaggedFindings:s}}function vn(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:Z(i,a),uniquePercent:Z(o,a)}}return r}function Tn(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 bo=[{min:85,grade:"excellent"},{min:70,grade:"good"},{min:50,grade:"fair"},{min:0,grade:"poor"}],st={error:12,warn:5,info:1},Co=40;function Ln(e){let t=e.error*st.error+e.warn*st.warn+e.info*st.info;return Math.min(t,Co)}import Le from"node:path";function M(e,t){return e.files.some(n=>n.path===t)}function _n(e,t){return e.fileContents.get(t)??null}function Ea(e,t){return e.files.find(r=>r.path===t)?.lines??null}function va(e){return e.includes("AGENTS.md")||e.includes("docs/ai/rules.md")}function te(e){return e.files.some(t=>t.path.startsWith("skills/"))}function Te(e){return e.files.some(t=>t.path.startsWith("agents/"))}function Fn(e,t){return e.settings?.[t]===!0}function ot(e,t){let n=Ea(e,t);return n===null?!1:n<=W}function it(e,t){let n=_n(e,t);return n===null?!1:va(n)}function Nn(e){let t=_n(e,".agent/README.md");return t===null?!1:/\.agent\/workflows\/|workflows\//i.test(t)&&/(workflow|playbook|slash command|mission|turbo)/i.test(t)}function ne(e,t,n){let r=e.settings?.[t];if(x(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 Ao={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})=>it(e,".github/copilot-instructions.md")},{id:"copilot-adapter-thin",label:"Copilot instructions stay thin",weight:10,run:({context:e})=>ot(e,".github/copilot-instructions.md")},{id:"copilot-skills-location",label:"chat.agentSkillsLocations points at skills/",weight:15,run:({vscode:e})=>ne(e,"chat.agentSkillsLocations","skills")},{id:"copilot-agents-location",label:"chat.agentFilesLocations points at agents/",weight:15,run:({vscode:e})=>ne(e,"chat.agentFilesLocations","agents")},{id:"copilot-hooks-enabled",label:"Custom agent hooks enabled when .github/hooks/ exists",weight:15,run:({vscode:e})=>!e.hooksDirExists||Fn(e,"chat.useCustomAgentHooks")},{id:"copilot-shared-skills",label:"Shared skills/ tree present",weight:8,run:({context:e})=>te(e)},{id:"copilot-shared-agents",label:"Shared agents/ tree present",weight:7,run:({context:e})=>Te(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/"))||ne(t,"chat.agentSkillsLocations","skills")},{id:"cursor-skills-location",label:"chat.agentSkillsLocations points at skills/",weight:20,run:({vscode:e})=>ne(e,"chat.agentSkillsLocations","skills")},{id:"cursor-agents-location",label:"chat.agentFilesLocations points at agents/",weight:20,run:({vscode:e})=>ne(e,"chat.agentFilesLocations","agents")},{id:"cursor-hooks-enabled",label:"Custom agent hooks enabled when .github/hooks/ exists",weight:15,run:({vscode:e})=>!e.hooksDirExists||Fn(e,"chat.useCustomAgentHooks")},{id:"cursor-shared-skills",label:"Shared skills/ tree present",weight:13,run:({context:e})=>te(e)},{id:"cursor-shared-agents",label:"Shared agents/ tree present",weight:12,run:({context:e})=>Te(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 R(Le.join(e.repoRoot,"api/AGENTS.md"))||await R(Le.join(e.repoRoot,"react/AGENTS.md"))||await R(Le.join(e.repoRoot,"shared/AGENTS.md"))},{id:"codex-hooks",label:"Codex hooks.json present",weight:20,run:({context:e})=>R(Le.join(e.repoRoot,".codex/hooks.json"))},{id:"codex-agents-wrappers",label:"Codex agent wrappers present",weight:20,run:({context:e})=>R(Le.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})=>te(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})=>Nn(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})=>te(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})=>it(e,"CLAUDE.md")},{id:"claude-adapter-thin",label:"CLAUDE.md stays thin",weight:20,run:({context:e})=>ot(e,"CLAUDE.md")},{id:"claude-shared-skills",label:"Shared skills/ tree present",weight:15,run:({context:e})=>te(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})=>Te(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})=>it(e,"GEMINI.md")},{id:"gemini-adapter-thin",label:"GEMINI.md stays thin",weight:20,run:({context:e})=>ot(e,"GEMINI.md")},{id:"gemini-shared-skills",label:"Shared skills/ tree present",weight:15,run:({context:e})=>te(e)},{id:"gemini-shared-agents",label:"Shared agents/ tree present",weight:10,run:({context:e})=>Te(e)}]};async function Pn(e,t){let n=Ao[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 Hn(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 Mn(e){for(let{min:t,grade:n}of bo)if(e>=t)return n;return"poor"}async function Dn(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 Pn(e,{context:t,vscode:n,harness:e}),l=Tn(r,e),m=Hn(c),u=Ln(l),f=Math.max(0,Math.min(100,m-u));return{harness:e,detected:!0,score:f,grade:Mn(f),checks:c,findingsCount:l,loadProfile:o[e]??null}}async function On(e,t,n,r){let s=vn(r,e.harnesses),o=[];for(let i of Q){let a=await Dn(i,e,t,n,r,s);o.push(a)}return o}import{readFileSync as Ta}from"node:fs";import{dirname as La,join as Io}from"node:path";import{fileURLToPath as _a}from"node:url";var Fa=_a(import.meta.url),Eo=La(Fa);function at(e){return typeof e=="object"&&e!==null}function Na(e){return at(e)&&at(e.dimensions)&&at(e.check_weights)}function Pa(e){return at(e)}function vo(e,t){let n=JSON.parse(Ta(e,"utf8"));if(!t(n))throw new Error(`Invalid standards file: ${e}`);return n}var $n=vo(Io(Eo,"standards","weights.json"),Na),Gn=vo(Io(Eo,"standards","reference-thresholds.json"),Pa);function jn(e){return!Number.isFinite(e)||e<0?0:e<=1?e:e<=10?e/10:e<=100?e/100:1}function To(e,t){return e>=t?1:0}function Lo(e,t){return e<=t?1:e===0?0:t/e}function _o(e,t){if(t<=0)return 0;let n=e/t;return Math.max(0,Math.min(1,n))}function Wn(e,t,n){return e>=t&&e<=n?1:e<t?t===0?0:e/t:e===0?0:n/e}function B(e){if(e.curve===void 0)return jn(e.rawScore??0);let t=e.measuredValue??0,n=e.referenceValue,r=typeof n=="number"?n:0;switch(e.curve){case"binary":return To(t,r);case"asymptoticDecay":return Lo(t,r);case"ratio":return _o(t,r);case"goldilocks":{let[s,o]=Array.isArray(n)?n:[0,r];return Wn(t,s??0,o??0)}}}function Un(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=B(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:be(c),passedRules:i.passedRules,applicableRules:i.applicableRules}}return r}function Bn(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)}function Vn(e){return e.contextBudget!==void 0&&e.contextBudget.harnesses.length>0}function V(e){return e.intelligenceLayer??null}function z(e){return e.packageJson.path!==null||e.workflows.length>0||e.prTemplates.length>0}function zn(e){let t=V(e);return t!==null&&z(t)}function w(e){return e.intelligenceLayer??null}function ye(e){return Object.entries(e.packageJson.scripts).map(([t,n])=>({name:t,command:n}))}function Se(e,t,n){return ye(e).some(r=>t.test(r.name)||n.test(r.command))}function Fo(e,t){return ye(e).filter(n=>t.test(n.name)||t.test(n.command)).map(n=>n.name).toSorted()}function ke(e){return e.workflows.map(t=>t.commands.join(`
|
|
152
152
|
`)).join(`
|
|
153
|
-
`)}function b(e){return e.packageJson.path!==null||e.configs.length>0||e.workflows.length>0}function
|
|
153
|
+
`)}function b(e){return e.packageJson.path!==null||e.configs.length>0||e.workflows.length>0}function qn(e){let t=w(e);return t!==null&&b(t)}var Ha=["AGENTS.md","CLAUDE.md","GEMINI.md",".github/copilot-instructions.md",".agent/README.md"],No=["IMPORTANT","CRITICAL","MANDATORY","REQUIRED","MUST NOT","MUST","NEVER","ALWAYS","SHALL","DO NOT"],Po=.03,Ho=40,Mo=[{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 ct(e){return e.replaceAll(/```[\s\S]*?```/g," ")}function Do(e){let t=e.match(/\S+/g);return t===null?0:t.length}function q(e){return Ha.filter(t=>h(e,t)!==null)}function Kn(e){return q(e).length>0}function _e(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 Yn(e){let t=e.intelligenceLayer;return t===void 0?!1:_e(e,t)}function Jn(e){let t=e.intelligenceLayer;return t!==void 0&&t.memoryDocs.length>0}function Xn(e){return I(e)?!0:e.files.filter(n=>n.path.startsWith("docs/ai/")).length>=2}var Ma=new Set(["skills-index","agents-md-mentions-skills","skill-doc-deep-links"]),Da=new Set(["strict-typecheck-present","lint-gate-present","jsdoc-enforcement-present","test-gates-present","focused-test-commands-present","ci-enforcement-gates","ci-validation-gates","correction-loop-documented"]),Oa=new Set(["emphasis-keyword-density","identity-language-absent"]),$a=new Set(["adapter-context-budget","always-loaded-budget"]),Ga=new Set(["guidance-maintenance-script","pr-template-ai-harness-check","ci-guidance-lint"]);function re(e,t){return Ma.has(e)?I(t):e==="qmd-script-present"?Xn(t):e==="claude-agent-routing"?t.harnesses.includes("claude")&&S(t,"CLAUDE.md"):Da.has(e)?qn(t):Oa.has(e)?Kn(t):$a.has(e)?Vn(t):Ga.has(e)?zn(t):e==="memory-docs-indexed"?Jn(t):e==="local-context-patterns"?Yn(t):!0}var lt={"strict-typecheck-present":"repo","lint-gate-present":"repo","jsdoc-enforcement-present":"repo","test-gates-present":"repo","focused-test-commands-present":"repo","ci-enforcement-gates":"repo","ci-validation-gates":"repo","env-files-gitignored":"repo","secret-scanning-configured":"repo","actions-sha-pinned":"repo","no-pull-request-target":"repo","llm-output-schema-validated":"repo","model-interface-pinned":"repo","tool-contract-tests-present":"repo","untrusted-input-action-boundary":"repo","high-impact-action-confirmation":"repo","memory-write-provenance":"repo","shared-agents-md":"aspirational","adapter-thin-claude":"harness-core","adapter-thin-gemini":"harness-core","adapter-thin-copilot":"harness-core","adapter-points-to-shared":"harness-core","adapter-content-duplication":"harness-core","adapter-context-budget":"harness-core","always-loaded-budget":"harness-core","skills-index":"harness-core","claude-agent-routing":"harness-core","agents-md-mentions-skills":"harness-core","skill-doc-deep-links":"harness-core","skill-frontmatter":"harness-core","skill-line-count":"harness-core","agent-frontmatter":"harness-core","no-duplicate-skill-trees":"harness-core","no-duplicate-agent-trees":"harness-core","forbidden-legacy-paths":"harness-core","guidance-links-resolve":"harness-core","emphasis-keyword-density":"harness-core","identity-language-absent":"harness-core","vscode-skills-location":"harness-core","vscode-agents-location":"harness-core","vscode-custom-hooks":"harness-core","codex-hooks-valid":"harness-core","claude-hooks-valid":"harness-core","hook-stop-circuit-breaker":"harness-core","hook-no-network-exfil":"harness-core","no-dangerous-auto-approve":"harness-core","escalation-protocol-discoverability":"harness-core","agent-resource-budget-caps":"harness-core","tool-allowlist-inventory":"harness-core","shared-rules-doc":"aspirational","correction-loop-documented":"aspirational","guidance-maintenance-script":"aspirational","pr-template-ai-harness-check":"aspirational","ci-guidance-lint":"aspirational","qmd-script-present":"aspirational","local-context-patterns":"aspirational","memory-docs-indexed":"aspirational"};function Qn(e,t){let n=0,r=0,s=new Set;for(let o of e)lt[o.checkId]!=="repo"||s.has(o.checkId)||!re(o.checkId,t)||(s.add(o.checkId),r+=1,B(o)===1&&(n+=1));return r===0?null:Math.round(n/r*100)}var Oo={error:8,warn:3,info:1},$o=4,Go=1;var jo=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".py",".json",".jsonc",".yaml",".yml",".toml"]),Wo=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"]),Uo=512*1024,Zn=/(?:\.(?:test|spec)\.[a-z]+$|(?:^|\/)(?:__tests__|__fixtures__|fixtures|test|tests)\/)/i,Bo=/\b(?:claude|gpt|chatgpt|gemini|mistral|codestral|llama|grok|deepseek|command|qwen|o1|o3|o4)[a-z0-9.]*(?:-[a-z0-9.]+)*-latest\b/i,Fe=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".py"]),Vo=/\b(?:anthropic|openai|mistralai|cohere|generativeai|langchain|chat\.completions|messages\.create|responses\.create|generateobject|generatetext|streamtext|generate_content)\b/i,zo=/\.choices\s*\[|tool_?calls?\b|function_?call|\.content\s*\[|\bJSON\.parse\s*\(|\bjson\.loads\s*\(/i,qo=/\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,ut=/\btools\s*:\s*\[|\btool_choice\s*[:=]|\bfunction_?declarations\s*[:=]|\b(?:defineTool|zodFunction|registerTool)\s*\(|\bserver\.tool\s*\(|\binput_?schema\s*[:=]|^\s*@tool\b/im,Ko=/\btool\b|\barguments?\b|\bfunction_?call|\bparameters?\b|\binput_?schema\b/i,Yo=/\btothrow\b|\.rejects\b|\bassert_?raises\b|pytest\.raises|\binvalid\b|\bmalformed\b|\bmissing\b|\bsafeparse\b|\berrors?\b/i;var Jo=/\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,Xo=/\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,Qo=/\blanggraph\b|\bcrewai\b|\bautogen\b|\bAgentExecutor\b|\bcreateReactAgent\b|@modelcontextprotocol|\bmcp\.server\b|\bserver\.tool\s*\(/i;function se(e){return[...e.fileContents.values()].join(`
|
|
154
154
|
`)}function Ne(e){return(e.boundary?.sourceFiles??[]).map(t=>t.content).join(`
|
|
155
|
-
`)}var
|
|
156
|
-
`).length}async function
|
|
157
|
-
`).length}async function
|
|
158
|
-
${t}`)}function
|
|
159
|
-
`))}function
|
|
155
|
+
`)}var Zo=/\bmcpservers\b|\.mcp\.json\b|\bmcp__|modelcontextprotocol|\bmcp\s+servers?\b/i,ei=/\ballow[\s_-]?list\b|\bmcpservers\b|allowed[_\s-]?tools|permitted[_\s-]?tools|"allow"\s*:|pinned\s+(?:tool|server|mcp)/i,ti=/\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,ni=/\bprovenance\b|\bquarantin|\buntrusted\b|\btaint(?:ed)?\b|trust[\s_-]?(?:level|tag|boundary)|source[\s_-]?tag|re-?validat/i,ri=/\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,si=/\bexec(?:Sync)?\s*\(|child_process|\bspawn\s*\(|\bsubprocess\b|os\.system|writeFileSync|\bfs\.write|\bunlink\s*\(|\brm\s+-rf\b/i,oi=/saniti[sz]|\bvalidat|\ballow[\s_-]?list\b|\bescape\b|\bconfirm|\bapproval\b|\bguard(?:rail)?\b/i,ii=/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,ai=/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 Pe(e){return e.files.some(n=>n.layer==="agents")?!0:(e.boundary?.sourceFiles??[]).some(n=>ut.test(n.content)||Qo.test(n.content))}var ci=new Set(["shared-agents-md","shared-rules-doc","adapter-thin-claude","adapter-thin-gemini","adapter-thin-copilot","adapter-points-to-shared","adapter-context-budget","always-loaded-budget","skills-index","claude-agent-routing","agents-md-mentions-skills","skill-doc-deep-links","skill-frontmatter","skill-line-count","agent-frontmatter","vscode-skills-location","vscode-agents-location","vscode-custom-hooks","codex-hooks-valid","claude-hooks-valid","correction-loop-documented","guidance-maintenance-script","pr-template-ai-harness-check","ci-guidance-lint","qmd-script-present","local-context-patterns","memory-docs-indexed"]),li=new Set(["strict-typecheck-present","lint-gate-present","jsdoc-enforcement-present","test-gates-present","focused-test-commands-present","ci-enforcement-gates","ci-validation-gates","secret-scanning-configured"]),ja=["CLAUDE.md","GEMINI.md",".github/copilot-instructions.md"];function er(e,t){if(!re(e,t))return!1;switch(e){case"skill-frontmatter":case"skill-line-count":return I(t);case"agent-frontmatter":return Pe(t);case"adapter-thin-claude":return S(t,"CLAUDE.md");case"adapter-thin-gemini":return S(t,"GEMINI.md");case"adapter-thin-copilot":return S(t,".github/copilot-instructions.md");case"adapter-points-to-shared":return ja.some(n=>S(t,n));case"claude-hooks-valid":return S(t,".claude/settings.json");case"codex-hooks-valid":return S(t,".codex/hooks.json");case"vscode-skills-location":case"vscode-agents-location":case"vscode-custom-hooks":return S(t,".vscode/settings.json");default:return!0}}var ui={error:3,warn:2,info:1};function tr(e,t,n){let r=Qn(e,n),s=e.some(u=>u.checkId==="shared-agents-md"&&B(u)===1),o=n.harnesses.length===0&&!s?"implicit-only":"scored",i=new Map;for(let u of t){if(lt[u.ruleId]!=="harness-core")continue;let f=i.get(u.ruleId);(f===void 0||ui[u.severity]>ui[f])&&i.set(u.ruleId,u.severity)}let a=[],c=new Set;for(let u of e){let f=ci.has(u.checkId),d=li.has(u.checkId);if(!f&&!d||c.has(u.checkId)||(c.add(u.checkId),f&&(i.has(u.checkId)||!er(u.checkId,n)))||d&&!re(u.checkId,n))continue;let y=Math.round((f?2:Go)*B(u)*10)/10;y>0&&a.push({signal:u.checkId,points:y})}let l=[];for(let[u,f]of i)l.push({signal:u,points:-Oo[f]});for(let u of n.contextBudget?.harnesses??[])u.status==="high"&&l.push({signal:`context-budget-high:${u.harness}`,points:-$o});let m=a.reduce((u,f)=>u+f.points,0)+l.reduce((u,f)=>u+f.points,0);return{status:o,score:Math.round(m),repoReadiness:r,contributions:a,liabilities:l}}var dt=new Set(["deep","session"]);function nr(e){let t=0,n=0,r=0,s=[];for(let[o,i]of Object.entries(e))dt.has(o)||(r+=1,i.status==="run"?(n+=1,t+=i.applicableRules):s.push(o));return{rulesApplied:t,dimensionsRun:n,dimensionsTotal:r,level:n===r?"full":"partial",dimensionsNotRun:s}}function rr(e){for(let[t,n]of Object.entries(e))if(dt.has(t)&&n.status==="run")return"core+extended";return"core"}function sr(e,t,n,r,s){if(n.totals.lines>0){let u=typeof Gn.sharing_target_percent=="number"?Gn.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((f,d)=>f+(d.score??0),0)/o.length;e.push({checkId:"harness-optimization-avg",dimension:"harnessWiring",curve:"ratio",measuredValue:u,referenceValue:100})}let i=Un(e,$n),a=Bn(i,$n),c=rr(i),l=nr(i),m=tr(e,t,s);return{profile:"meta-harness",total_score:a,score_scope:c,coverage:l,harnessNet:m,dimensions:i}}import{readFile as Ka}from"node:fs/promises";import ar from"node:path";import{readdir as Ua}from"node:fs/promises";import Ba from"node:path";async function pt(e){let t=[".md",".mdc"];function n(o){return t.some(i=>o.endsWith(i))}let r=[],s=[];try{s=await Ua(e,{withFileTypes:!0})}catch{return r}for(let o of s){if(o.isSymbolicLink())continue;let i=Ba.join(e,o.name);o.isDirectory()?r.push(...await pt(i)):o.isFile()&&n(i)&&r.push(i)}return r}import{readFile as Va,stat as za}from"node:fs/promises";import qa from"node:path";function or(e){return e.length===0?0:e.split(`
|
|
156
|
+
`).length}async function ir(e,t,n,r){let s=qa.join(e,t);try{if(!(await za(s)).isFile())return null;let i=await Va(s,"utf8"),a=or(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 Ya=["AGENTS.md","docs/ai/rules.md","docs/ai/ai-system.md","docs/ai/available-skills.md","docs/ai/hooks.md"],Ja=[{path:"CLAUDE.md",harness:"claude"},{path:"GEMINI.md",harness:"gemini"},{path:".github/copilot-instructions.md",harness:"copilot"},{path:".agent/README.md",harness:"antigravity"}],Xa=[{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 He(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 l=await ir(e,c,i,a);if(l===null)return;r.add(c),t.push(l);let m=ar.join(e,c);try{let u=await Ka(m,"utf8");n.set(c,u)}catch{}}for(let o of Ya)await s(o,"shared");for(let o of Ja)await s(o.path,"adapter",o.harness);for(let{dir:o,layer:i,harness:a}of Xa){let c=ar.join(e,o),l=await pt(c);for(let m of l){let u=ar.relative(e,m).replaceAll("\\","/");await s(u,i,a)}}return t.sort((o,i)=>o.path.localeCompare(i.path)),{files:t,contents:n}}import{readFile as Qa}from"node:fs/promises";import di from"node:path";import{fileURLToPath as Za}from"node:url";function cr(e){return typeof e=="object"&&e!==null&&"version"in e&&typeof e.version=="string"}async function lr(){let e=di.resolve(di.dirname(Za(import.meta.url)),"../package.json"),t=await Qa(e,"utf8"),n=JSON.parse(t);if(!cr(n))throw new Error("package.json is missing a string version field");return{version:n.version}}var pi=null;function mi(){return pi??=lr(),pi}import{extname as sc}from"node:path";import{readdir as ec}from"node:fs/promises";import Ri from"node:path";var fi=new Set([".git","node_modules","dist","coverage"]),gi=[/^tsconfig(?:\..+)?\.json$/],hi=[/^eslint\.config\.[cm]?[jt]s$/,/^\.eslintrc(?:\..+)?$/,/^\.oxlintrc(?:\..+)?$/,/^biome\.jsonc?$/,/^ruff\.toml$/,/^\.ruff\.toml$/],yi=[/^\.prettierrc(?:\..+)?$/,/^\.markdownlint(?:rc)?(?:\..+)?$/],Si=[/^vitest\.config\.[cm]?[jt]s$/,/^jest\.config\.[cm]?[jt]s$/,/^playwright\.config\.[cm]?[jt]s$/,/^cypress\.config\.[cm]?[jt]s$/],ki=[/^package\.json$/,/^pyproject\.toml$/,/^Cargo\.toml$/,/^go\.mod$/],ur=/(scan:self|check:ai-system|check:md|lint:md|check:links|qmd|markdownlint|textlint|remark|cspell|paniolo-scan)/i,xi=/(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 xe(e,t=""){let n=Ri.join(e,t),r=[];try{r=await ec(n,{withFileTypes:!0})}catch{return[]}let s=[];for(let o of r){if(o.isSymbolicLink()||fi.has(o.name))continue;let i=Ri.join(t,o.name).replaceAll("\\","/");o.isDirectory()?s.push(...await xe(e,i)):o.isFile()&&s.push(i)}return s}import wi from"node:path";function dr(e){let t=wi.basename(e).toLowerCase();return Wo.has(t)?!1:jo.has(wi.extname(t))}import{readFile as tc,stat as nc}from"node:fs/promises";import rc from"node:path";async function pr(e,t){let n=rc.join(e,t);try{return(await nc(n)).size>Uo?null:{path:t,content:await tc(n,"utf8")}}catch{return null}}async function mr(e){let n=(await xe(e)).filter(o=>dr(o)),s=(await Promise.all(n.map(o=>pr(e,o)))).filter(o=>o!==null);return{sourceFiles:s.filter(o=>!Zn.test(o.path)).toSorted((o,i)=>o.path.localeCompare(i.path)),testFiles:s.filter(o=>Zn.test(o.path)&&Fe.has(sc(o.path))).toSorted((o,i)=>o.path.localeCompare(i.path))}}async function fr(e){let{sourceFiles:t,testFiles:n}=await mr(e);return{sourceFiles:t,testFiles:n}}import ac from"node:path";import{readFile as oc,stat as ic}from"node:fs/promises";import bi from"node:path";function Ci(e){return e.length===0?0:e.split(`
|
|
157
|
+
`).length}async function Ai(e,t){try{return(await ic(bi.join(e,t))).isFile()}catch{return!1}}async function D(e,t){try{return await oc(bi.join(e,t),"utf8")}catch{return null}}function mt(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Re(e,t){return t.some(n=>n.test(e))}function Ii(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 ft(e,t){return ur.test(`${e}
|
|
158
|
+
${t}`)}function gt(e){return ur.test(e.commands.join(`
|
|
159
|
+
`))}function vi(e){return xi.test(e)}function Ti(e){let t=e.toLowerCase();return t.includes("naming")||t.includes("comment")||t.includes("local-context")||t.includes("codebase-map")}function gr(e){let t=ac.posix.basename(e);return Re(t,gi)?{path:e,kind:"typecheck",capabilities:["typecheck"]}:Re(t,hi)?{path:e,kind:"lint",capabilities:["lint"]}:Re(t,yi)?{path:e,kind:"format",capabilities:["format"]}:Re(t,Si)?{path:e,kind:"test",capabilities:["test"]}:Re(t,ki)?{path:e,kind:"manifest",capabilities:["project-manifest"]}:null}function hr(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 yr(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 Me(e){if(!mt(e))return{};let t={};for(let[n,r]of Object.entries(e))typeof r=="string"&&(t[n]=r);return t}function Sr(e){if(e===null)return{path:null,scripts:{},dependencies:[],devDependencies:[]};try{let t=JSON.parse(e);if(!mt(t))return{path:"package.json",scripts:{},dependencies:[],devDependencies:[]};let n=Me(t.scripts),r=Object.keys(Me(t.dependencies)).toSorted(),s=Object.keys(Me(t.devDependencies)).toSorted();return{path:"package.json",scripts:n,dependencies:r,devDependencies:s}}catch{return{path:"package.json",scripts:{},dependencies:[],devDependencies:[]}}}import{stat as cc}from"node:fs/promises";import lc from"node:path";async function K(e,t,n,r,s){let o=lc.join(e,t),i=await cc(o),a=await D(e,t),c={path:t,kind:n,layer:r,capabilities:s,bytes:i.size};return a!==null&&(c.lines=Ci(a)),c}function kr(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 xr(e,t){let n=await D(e,t);return n===null?null:{path:t,commands:kr(n),content:n}}function ht(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=>ft(i,e.packageJson.scripts[i]??"")),o=e.workflows.filter(gt).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(`
|
|
160
160
|
`))).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(`
|
|
161
|
-
`))).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
|
|
162
|
-
`)})}return{hookScripts:n,referencedClaudeScripts:r}}async function
|
|
163
|
-
`);for(let r=0;r<n.length;r+=1){let s=
|
|
164
|
-
`);for(let n=0;n<t.length;n+=1)if(
|
|
165
|
-
`);return
|
|
166
|
-
${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:[]}}},
|
|
167
|
-
${Ne(e)}`;return!
|
|
168
|
-
${t}`;return
|
|
169
|
-
${Ne(e)}`;return!
|
|
170
|
-
${t}`;return Si.test(n)?$:St("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).")}},sa=[Nc,Pc,Mc,Hc,Dc,Oc];var $c=/\b(?:curl|wget|ncat|telnet|scp)\b|\bnc\s|Invoke-WebRequest|\bfetch\s*\(|\baxios\b|http\.request|urllib|requests\.(?:get|post|put|patch)/i,Gc=/localhost|127\.0\.0\.1|0\.0\.0\.0|::1/i;function zr(e){let t=[];for(let n of e.content.split(/\r?\n/)){let r=n.trim();$c.test(r)&&!Gc.test(r)&&t.push(r)}return t}var jc=new Set(["Bash","Write","Edit","MultiEdit","NotebookEdit"]);function qr(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(!jc.has(r))return!1;if(s===void 0)return!0;let o=s.trim();return o===""||o==="*"||o===":*"}var Wc=/^[0-9a-f]{40}$/i;function Kr(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):"";Wc.test(o)||t.add(s)}return[...t]}var G={findings:[],records:[]},Uc=new Set(["bypassPermissions","acceptEdits"]),Bc="stop_hook_active";function ae(e){return e.security??null}var Vc={id:"no-dangerous-auto-approve",title:"No dangerous auto-approve permissions",severity:"error",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=ae(e);if(t===null)return G;let n=[];for(let r of t.claudeSettings){r.defaultMode!==null&&Uc.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(qr))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:[]}}},zc={id:"hook-no-network-exfil",title:"Hooks do not exfiltrate over the network",severity:"error",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=ae(e);if(t===null)return G;let n=[];for(let r of t.hookScripts){let[s]=zr(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:[]}}},qc={id:"hook-stop-circuit-breaker",title:"Stop hooks guard against infinite loops",severity:"warn",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=ae(e);if(t===null)return G;let n=[];for(let r of t.hookScripts)!r.isStop||r.content.includes(Bc)||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:[]}}},Kc={id:"env-files-gitignored",title:"Env files are gitignored",severity:"warn",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=ae(e);if(t===null)return G;let r=t.gitignore!==null&&/^\s*!?[*.]*\.env(?:[.*]|\b|\/)?/m.test(t.gitignore)?[]:t.envFilesPresent;if(r.length===0)return G;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 Yc(e){return e.some(t=>/gitleaks|trufflehog|detect-secrets|ggshield/i.test(t.content))}var Jc={id:"secret-scanning-configured",title:"Secret scanning is configured",severity:"warn",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=ae(e);if(t===null)return G;let n=e.intelligenceLayer?.workflows??[];return t.secretScanningFiles.length>0||Yc(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:[]}}},Xc={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:[]}}},Qc={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=Kr(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:[]}}},Zc={id:"claude-hooks-valid",title:"Claude hooks config is valid",severity:"error",category:"hooks",dimension:"guardrails",harnesses:["claude"],check(e){let t=ae(e);if(t===null)return G;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:[]}}},el={id:"codex-hooks-valid",title:"Codex hooks config is valid",severity:"error",category:"hooks",dimension:"guardrails",harnesses:["codex"],check(e){let t=ae(e);if(t===null||t.codexHooks===null)return G;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:[]}}},oa=[Vc,zc,qc,Kc,Jc,Xc,Qc,Zc,el];var tl={id:"shared-agents-md",title:"Shared AGENTS.md entry point",severity:"warn",category:"structure",dimension:"layering",harnesses:[],check(e){return k(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:[]}}},nl={id:"shared-rules-doc",title:"Canonical rules doc",severity:"warn",category:"structure",dimension:"layering",harnesses:[],check(e){return k(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:[]}}},rl={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:[Oe("adapter-thin-claude","CLAUDE.md",t,"claude")],records:[]}}},sl={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:[Oe("adapter-thin-gemini","GEMINI.md",t,"gemini")],records:[]}}},ol={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:[Oe("adapter-thin-copilot",t,n,"copilot")],records:[]}}},il={id:"adapter-points-to-shared",title:"Adapters reference shared layers",severity:"warn",category:"adapter",dimension:"layering",harnesses:[],check:Fr},al={id:"skill-frontmatter",title:"Skill frontmatter",severity:"error",category:"skills",dimension:"maintainability",harnesses:[],check:Gr},cl={id:"skill-line-count",title:"Skill line budget",severity:"warn",category:"skills",dimension:"maintainability",harnesses:[],check:jr},ll={id:"agent-frontmatter",title:"Agent frontmatter",severity:"error",category:"agents",dimension:"maintainability",harnesses:[],check:Nr},ul={id:"skills-index",title:"Skill slug index",severity:"info",category:"discoverability",dimension:"discoverability",harnesses:[],check:Wr},dl={id:"claude-agent-routing",title:"Claude agent routing table",severity:"info",category:"discoverability",dimension:"discoverability",harnesses:["claude"],check:Mr},pl={id:"agents-md-mentions-skills",title:"AGENTS.md skill discovery",severity:"info",category:"discoverability",dimension:"discoverability",harnesses:[],check:Pr},ml={id:"skill-doc-deep-links",title:"Skills deep-link into docs",severity:"info",category:"discoverability",dimension:"discoverability",harnesses:[],check:$r},ia=[tl,nl,rl,sl,ol,il,al,cl,ll,ul,dl,pl,ml,...ra,...oa,...ea,...sa];function Yr(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 Jr(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 Xr(e){return e.files.some(n=>n.path.startsWith("agents/"))?await fe(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 Qr(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 fe(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 fl=["docs/","skills/","agents/",".cursor/",".github/",".codex/",".agent/",".claude/"],gl=new Set(["AGENTS.md","CLAUDE.md","GEMINI.md","README.md",".github/copilot-instructions.md"]);function aa(e){let t=e.replaceAll("\\","/").replace(/\/+$/,"");return gl.has(t)?!0:fl.some(n=>t===n.slice(0,-1)||t.startsWith(n))}function We(e,t){let n=e.split(`
|
|
171
|
-
`);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}var
|
|
172
|
-
`)}var
|
|
173
|
-
`),r=
|
|
174
|
-
`)),s=[],o=new Set;for(let i=0;i<=n.length-
|
|
175
|
-
`),r=ke(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:[
|
|
176
|
-
`);for(let r=0;r<n.length;r+=1){let s=n[r]??"";if(!
|
|
177
|
-
`),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
|
|
161
|
+
`))).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 Rr(e){let t=await xe(e),n=Sr(await D(e,"package.json")),r=[],s=[],o=[],i=[],a=[],c=[],l=[],m=[],u=[],f={customChecker:!1,packageScript:!1,lintRules:!1,stopHook:!1,guidance:!1};f.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=gr(d);if(g!==null){let y={...g},E=await D(e,d);g.kind==="typecheck"&&E!==null&&/"strict"\s*:\s*true/.test(E)&&(y.capabilities=[...g.capabilities,"strict-typecheck"]),g.kind==="lint"&&E!==null&&/jsdoc\/require-(returns|param)/i.test(E)&&(f.lintRules=!0),r.push(y),u.push(await K(e,d,"enforcement","config",y.capabilities))}if(Ii(d)){let y=await xr(e,d);if(y!==null){s.push(y);let E=await K(e,d,"workflow","automation",["ci-workflow"]);u.push(E)}}if(Ei(d)){o.push(d);let y=await D(e,d);y!==null&&vi(y)&&i.push(d);let E=await K(e,d,"automation","pull-request",["pr-template"]);u.push(E)}if(d.endsWith(".md")&&hr(d)&&(a.push(d),yr(d)&&c.push(d),u.push(await K(e,d,"memory","docs",["memory"]))),d.endsWith(".md")&&Ti(d)&&l.push(d),(d==="scripts/find-missing-jsdoc/analyzeFile.ts"||d==="scripts/find-missing-jsdoc/check-jsdoc-files.bun.ts")&&(f.customChecker=!0),(d==="docs/ai/code-comment-best-practices.md"||d==="skills/code-comment-best-practices/SKILL.md")&&(f.guidance=!0),d.startsWith(".github/hooks/")&&d.endsWith(".json")){let y=await D(e,d);y!==null&&/lint-on-stop|find-missing-jsdoc|jsdoc/i.test(y)&&(f.stopHook=!0)}if(d.endsWith("/AGENTS.md")){m.push(d);let y=await K(e,d,"local-context","nested-entry",["nested-agents-md"]);u.push(y)}}return n.path!==null&&await Ai(e,n.path)&&u.push(await K(e,n.path,"automation","project",["package-scripts"])),{packageJson:n,configs:r.toSorted((d,g)=>d.path.localeCompare(g.path)),workflows:s.toSorted((d,g)=>d.path.localeCompare(g.path)),prTemplates:o,guidanceMaintenanceScripts:Object.entries(n.scripts).filter(([d,g])=>ft(d,g)).map(([d])=>d).toSorted(),aiHarnessPrTemplates:i.toSorted(),guidanceCiWorkflows:s.filter(d=>gt(d)).map(d=>d.path).toSorted(),memoryDocs:a,memoryIndexes:c.toSorted(),localContextConventions:l.toSorted(),nestedAgentsFiles:m,surfaces:u.toSorted((d,g)=>d.path.localeCompare(g.path)),jsdocEnforcement:f}}import fc from"node:path";import{readdir as uc}from"node:fs/promises";import dc from"node:path";async function wr(e,t){let n=[];try{n=await uc(dc.join(e,t),{withFileTypes:!0})}catch{return[]}return n.filter(r=>r.isFile()).map(r=>`${t}/${r.name}`)}import{readFile as pc,stat as mc}from"node:fs/promises";import Di from"node:path";var Li=[".claude/settings.json",".claude/settings.local.json"],_i=[".env",".env.local",".env.development",".env.development.local",".env.production",".env.production.local",".env.test"],Fi=[".gitleaks.toml",".github/gitleaks.toml",".github/secret_scanning.yml",".github/secret_scanning.yaml"],Ni=[".pre-commit-config.yaml",".pre-commit-config.yml"],Pi=["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"],Hi=/gitleaks|trufflehog|detect-secrets|ggshield/i,Mi=/(?:\.\/)?(?:[\w.-]+\/)+[\w.-]+\.(?:tsx?|mts|cts|mjs|cjs|js|sh|bash|py)/g;async function F(e,t){try{return await pc(Di.join(e,t),"utf8")}catch{return null}}async function O(e,t){try{return(await mc(Di.join(e,t))).isFile()}catch{return!1}}function Y(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function yt(e){try{return{ok:!0,value:JSON.parse(e)}}catch{return{ok:!1,value:null}}}function Oi(e){let{permissions:t}=e;return!Y(t)||!Array.isArray(t.allow)?[]:t.allow.filter(n=>typeof n=="string")}function $i(e){let{permissions:t}=e;return!Y(t)||typeof t.defaultMode!="string"?null:t.defaultMode}function St(e){let t=e.match(Mi)??[];return[...new Set(t.map(n=>n.replace(/^\.\//,"")))]}async function Gi(e,t,n){let r=await O(e,n),s=r?await F(e,n):null;return{reference:{source:t,path:n,exists:r},content:s}}async function br(e,t){for(let n of await wr(e,".claude/hooks")){let r=await F(e,n);r!==null&&t.push({source:n,path:n,isStop:/stop/i.test(fc.posix.basename(n)),content:r})}}async function Cr(e){for(let t of Pi)if(await O(e,t))return!0;return!1}function Ar(e){let t=e.hooks;if(t===void 0)return{hooks:[],malformed:!1};if(!Y(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(!Y(i)||!Array.isArray(i.hooks)){r=!0;continue}for(let a of i.hooks){if(!Y(a)||typeof a.command!="string"){r=!0;continue}n.push({event:s,command:a.command})}}}return{hooks:n,malformed:r}}async function Ir(e,t){let n=await F(e,t);if(n===null)return null;let{ok:r,value:s}=yt(n);if(!r||!Y(s))return{path:t,valid:!1,allow:[],defaultMode:null,hooks:[],hooksMalformed:!1};let{hooks:o,malformed:i}=Ar(s);return{path:t,valid:!0,allow:Oi(s),defaultMode:$i(s),hooks:o,hooksMalformed:i}}async function Er(e){let t=".codex/hooks.json",n=await F(e,t);if(n===null)return null;let{ok:r,value:s}=yt(n);if(!r)return{path:t,valid:!1,referencedScripts:[]};let o=[];for(let i of St(JSON.stringify(s))){let a=await O(e,i);o.push({source:t,path:i,exists:a})}return{path:t,valid:!0,referencedScripts:o}}async function vr(e){let t=[];for(let n of _i)await O(e,n)&&t.push(n);return t}async function Tr(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 l of St(i.command)){let{reference:m,content:u}=await Gi(e,a,l);r.push(m),u!==null&&c.push(u)}n.push({source:a,path:null,isStop:i.event==="Stop",content:c.join(`
|
|
162
|
+
`)})}return{hookScripts:n,referencedClaudeScripts:r}}async function Lr(e){let t=[];for(let n of Fi)await O(e,n)&&t.push(n);for(let n of Ni){let r=await F(e,n);r!==null&&Hi.test(r)&&t.push(n)}return t}async function De(e){let t=[];for(let l of Li){let m=await Ir(e,l);m!==null&&t.push(m)}let{hookScripts:n,referencedClaudeScripts:r}=await Tr(e,t);await br(e,n);let[s,o,i,a,c]=await Promise.all([Er(e),F(e,".gitignore"),vr(e),Lr(e),Cr(e)]);return{claudeSettings:t,referencedClaudeScripts:r,hookScripts:n,codexHooks:s,gitignore:o,envFilesPresent:i,secretScanningFiles:a,usesKeyringSecrets:c}}import{readFile as gc,stat as hc}from"node:fs/promises";import ji from"node:path";async function oe(e){let t=ji.join(e,".github/hooks"),n=!1;try{n=(await hc(t)).isDirectory()}catch{n=!1}let r=ji.join(e,".vscode/settings.json"),s=null,o=null;try{let i=await gc(r,"utf8");o=i,s=Ie(i)}catch{s=null,o=null}return{settings:s,settingsRaw:o,hooksDirExists:n}}function Oe(e,t,n,r){return{ruleId:e,severity:"warn",message:`${t} has ${String(n)} lines; keep root adapters thin (max ${String(W)}).`,file:t,line:null,harnesses:[r],hint:"Move detailed guidance to docs/ai/ and skills/; keep the adapter as a pointer."}}import{extname as Wi}from"node:path";function _r(e){let t=[],n=e.split(`
|
|
163
|
+
`);for(let r=0;r<n.length;r+=1){let s=Bo.exec(n[r]??"");s!==null&&t.push({line:r+1,alias:s[0]})}return t}function Fr(e){if(!Vo.test(e)||qo.test(e))return null;let t=e.split(`
|
|
164
|
+
`);for(let n=0;n<t.length;n+=1)if(zo.test(t[n]??""))return n+1;return null}var $e={findings:[],records:[]},yc={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 $e;let n=[];for(let r of t)for(let{line:s,alias:o}of _r(r.content))n.push({ruleId:"model-interface-pinned",severity:"warn",message:`${r.path} references the floating model alias "${o}"; the model behind a "latest" tag can change without notice.`,file:r.path,line:s,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:[]}}},Sc={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 $e;let n=[];for(let r of t){if(!Fe.has(Wi(r.path)))continue;let s=Fr(r.content);s!==null&&n.push({ruleId:"llm-output-schema-validated",severity:"warn",message:`${r.path} consumes LLM/tool output (line ${String(s)}) without a schema validator; a shape change in the model response surfaces as a downstream type error.`,file:r.path,line:s,harnesses:[],hint:"Validate the parsed response against a Zod/Pydantic/JSON-Schema schema at the boundary before reading its fields."})}return{findings:n,records:[]}}},kc={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 $e;let n=t.sourceFiles.find(s=>Fe.has(Wi(s.path))&&ut.test(s.content));return n===void 0||t.testFiles.some(s=>Ko.test(s.content)&&Yo.test(s.content))?$e:{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:[]}}},Ui=[yc,Sc,kc];function Nr(e){let t=[];for(let n of Ke){if(!S(e,n))continue;let r=h(e,n);r===null||so(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 Pr(e){let t=[];for(let n of ge(e,"agents/")){if(!n.endsWith(".agent.md"))continue;let r=h(e,n);if(r===null)continue;let s=Ye(r);if(s===null){t.push({ruleId:"agent-frontmatter",severity:"error",message:`${n} is missing YAML frontmatter.`,file:n,line:null,harnesses:[]});continue}me(s,"name")||t.push({ruleId:"agent-frontmatter",severity:"error",message:`${n} is missing a name field in frontmatter.`,file:n,line:null,harnesses:[]}),me(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 Hr(e){if(!I(e)||!S(e,"AGENTS.md"))return{findings:[],records:[]};let t=h(e,"AGENTS.md");return t!==null&&Je(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 Mr(e){if(!e.harnesses.includes("claude")||!S(e,"CLAUDE.md"))return{findings:[],records:[]};let t=h(e,"CLAUDE.md");return t!==null&&Xe(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 Bi=/!?\[([^\]]*)\]\(([^)]+)\)/g;function ie(e){let t=[],n=Bi.exec(e);for(;n!==null;){let[r]=n;r.startsWith("!")||t.push({label:n[1]??"",href:(n[2]??"").trim()}),n=Bi.exec(e)}return t}var xc=new Set(["url","path","href","link","..."]);function Ge(e){return e.length===0||xc.has(e.toLowerCase())||e.startsWith("http://")||e.startsWith("https://")||e.startsWith("mailto:")||e.startsWith("tel:")?!0:(e.split("#")[0]??"").length===0}function Dr(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 je(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 Dr(o)}function Or(e){return!e.endsWith(".md")&&!e.endsWith(".mdc")?!1:e.startsWith("docs/")||e.includes("/docs/")}function $r(e,t){for(let n of ie(t)){if(Ge(n.href))continue;let r=je(e,n.href);if(r!==null&&Or(r))return!0}return!1}var Rc=50;function Gr(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 r=h(e,n.path);r===null||$r(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 jr(e){let t=[];for(let n of ge(e,"skills/")){if(!n.endsWith("/SKILL.md")&&!n.endsWith("SKILL.md"))continue;let r=h(e,n);if(r===null)continue;let s=Ye(r);if(s===null){t.push({ruleId:"skill-frontmatter",severity:"error",message:`${n} is missing YAML frontmatter.`,file:n,line:null,harnesses:[]});continue}me(s,"name")||t.push({ruleId:"skill-frontmatter",severity:"error",message:`${n} is missing a name field in frontmatter.`,file:n,line:null,harnesses:[]}),me(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 Wr(e){let t=[];for(let n of ge(e,"skills/")){if(!n.endsWith("SKILL.md"))continue;let r=U(e,n);r!==null&&r>Lt&&t.push({ruleId:"skill-line-count",severity:"warn",message:`${n} has ${String(r)} lines; keep skills under ${String(Lt)}.`,file:n,line:null,harnesses:[],hint:"Move detail to docs/; keep SKILL.md as a pointer."})}return{findings:t,records:[]}}var Vi="docs/ai/available-skills.md";function Ur(e){return I(e)?S(e,Vi)?{findings:[],records:[]}:{findings:[{ruleId:"skills-index",severity:"info",message:`${Vi} 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 Br(e){let t=0;for(let n of No){let r=e.match(new RegExp(`\\b${n}\\b`,"g"));r!==null&&(t+=r.length)}return t}function Vr(e){let t=[];for(let n of q(e)){let r=h(e,n);if(r===null)continue;let s=ct(r),o=Do(s);if(o<Ho)continue;let i=Br(s),a=i/o;if(a<=Po)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 zr(e){let t=[];for(let n of q(e)){let r=h(e,n);if(r===null)continue;let s=ct(r),o=Mo.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 zi=[{id:"emphasis-keyword-density",title:"Emphasis-keyword density",severity:"info",category:"instruction-quality",dimension:"maintainability",harnesses:[],check:Vr},{id:"identity-language-absent",title:"No identity-language filler",severity:"info",category:"instruction-quality",dimension:"maintainability",harnesses:[],check:zr}];function kt(e,t,n,r){return{findings:[{ruleId:e,severity:t,message:n,file:null,line:null,harnesses:[],hint:r}],records:[]}}var $={findings:[],records:[]},wc={id:"escalation-protocol-discoverability",title:"Escalation protocol discoverable",severity:"info",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=q(e);return t.length===0||Jo.test(se(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:[]}}},bc={id:"agent-resource-budget-caps",title:"Agent resource budget caps",severity:"info",category:"security",dimension:"guardrails",harnesses:[],check(e){if(!Pe(e))return $;let t=(e.boundary?.sourceFiles??[]).map(n=>n.content).join(`
|
|
165
|
+
`);return Xo.test(`${se(e)}
|
|
166
|
+
${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=`${se(e)}
|
|
167
|
+
${Ne(e)}`;return!Zo.test(t)||ei.test(t)?$:kt("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.")}},Ac={id:"untrusted-input-action-boundary",title:"Untrusted input / action boundary",severity:"warn",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=Ne(e);if(!(ri.test(t)&&si.test(t)))return $;let r=`${se(e)}
|
|
168
|
+
${t}`;return oi.test(r)?$:kt("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.")}},Ic={id:"memory-write-provenance",title:"Memory write provenance",severity:"info",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=`${se(e)}
|
|
169
|
+
${Ne(e)}`;return!ti.test(t)||ni.test(t)?$:kt("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.")}},Ec={id:"high-impact-action-confirmation",title:"High-impact action confirmation",severity:"warn",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=Ne(e);if(!ii.test(t))return $;let n=`${se(e)}
|
|
170
|
+
${t}`;return ai.test(n)?$:kt("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).")}},qi=[wc,bc,Cc,Ac,Ic,Ec];var vc=/\b(?:curl|wget|ncat|telnet|scp)\b|\bnc\s|Invoke-WebRequest|\bfetch\s*\(|\baxios\b|http\.request|urllib|requests\.(?:get|post|put|patch)/i,Tc=/localhost|127\.0\.0\.1|0\.0\.0\.0|::1/i;function qr(e){let t=[];for(let n of e.content.split(/\r?\n/)){let r=n.trim();vc.test(r)&&!Tc.test(r)&&t.push(r)}return t}var Lc=new Set(["Bash","Write","Edit","MultiEdit","NotebookEdit"]);function Kr(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(!Lc.has(r))return!1;if(s===void 0)return!0;let o=s.trim();return o===""||o==="*"||o===":*"}var _c=/^[0-9a-f]{40}$/i;function Yr(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):"";_c.test(o)||t.add(s)}return[...t]}var G={findings:[],records:[]},Fc=new Set(["bypassPermissions","acceptEdits"]),Nc="stop_hook_active";function ae(e){return e.security??null}var Pc={id:"no-dangerous-auto-approve",title:"No dangerous auto-approve permissions",severity:"error",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=ae(e);if(t===null)return G;let n=[];for(let r of t.claudeSettings){r.defaultMode!==null&&Fc.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(Kr))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:[]}}},Hc={id:"hook-no-network-exfil",title:"Hooks do not exfiltrate over the network",severity:"error",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=ae(e);if(t===null)return G;let n=[];for(let r of t.hookScripts){let[s]=qr(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:[]}}},Mc={id:"hook-stop-circuit-breaker",title:"Stop hooks guard against infinite loops",severity:"warn",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=ae(e);if(t===null)return G;let n=[];for(let r of t.hookScripts)!r.isStop||r.content.includes(Nc)||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:[]}}},Dc={id:"env-files-gitignored",title:"Env files are gitignored",severity:"warn",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=ae(e);if(t===null)return G;let r=t.gitignore!==null&&/^\s*!?[*.]*\.env(?:[.*]|\b|\/)?/m.test(t.gitignore)?[]:t.envFilesPresent;if(r.length===0)return G;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 Oc(e){return e.some(t=>/gitleaks|trufflehog|detect-secrets|ggshield/i.test(t.content))}var $c={id:"secret-scanning-configured",title:"Secret scanning is configured",severity:"warn",category:"security",dimension:"guardrails",harnesses:[],check(e){let t=ae(e);if(t===null)return G;let n=e.intelligenceLayer?.workflows??[];return t.secretScanningFiles.length>0||Oc(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:[]}}},Gc={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:[]}}},jc={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=Yr(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:[]}}},Wc={id:"claude-hooks-valid",title:"Claude hooks config is valid",severity:"error",category:"hooks",dimension:"guardrails",harnesses:["claude"],check(e){let t=ae(e);if(t===null)return G;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:[]}}},Uc={id:"codex-hooks-valid",title:"Codex hooks config is valid",severity:"error",category:"hooks",dimension:"guardrails",harnesses:["codex"],check(e){let t=ae(e);if(t===null||t.codexHooks===null)return G;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:[]}}},Ki=[Pc,Hc,Mc,Dc,$c,Gc,jc,Wc,Uc];var Bc={id:"shared-agents-md",title:"Shared AGENTS.md entry point",severity:"warn",category:"structure",dimension:"layering",harnesses:[],check(e){return S(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:[]}}},Vc={id:"shared-rules-doc",title:"Canonical rules doc",severity:"warn",category:"structure",dimension:"layering",harnesses:[],check(e){return S(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:[]}}},zc={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:[Oe("adapter-thin-claude","CLAUDE.md",t,"claude")],records:[]}}},qc={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:[Oe("adapter-thin-gemini","GEMINI.md",t,"gemini")],records:[]}}},Kc={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:[Oe("adapter-thin-copilot",t,n,"copilot")],records:[]}}},Yc={id:"adapter-points-to-shared",title:"Adapters reference shared layers",severity:"warn",category:"adapter",dimension:"layering",harnesses:[],check:Nr},Jc={id:"skill-frontmatter",title:"Skill frontmatter",severity:"error",category:"skills",dimension:"maintainability",harnesses:[],check:jr},Xc={id:"skill-line-count",title:"Skill line budget",severity:"warn",category:"skills",dimension:"maintainability",harnesses:[],check:Wr},Qc={id:"agent-frontmatter",title:"Agent frontmatter",severity:"error",category:"agents",dimension:"maintainability",harnesses:[],check:Pr},Zc={id:"skills-index",title:"Skill slug index",severity:"info",category:"discoverability",dimension:"discoverability",harnesses:[],check:Ur},el={id:"claude-agent-routing",title:"Claude agent routing table",severity:"info",category:"discoverability",dimension:"discoverability",harnesses:["claude"],check:Mr},tl={id:"agents-md-mentions-skills",title:"AGENTS.md skill discovery",severity:"info",category:"discoverability",dimension:"discoverability",harnesses:[],check:Hr},nl={id:"skill-doc-deep-links",title:"Skills deep-link into docs",severity:"info",category:"discoverability",dimension:"discoverability",harnesses:[],check:Gr},Yi=[Bc,Vc,zc,qc,Kc,Yc,Jc,Xc,Qc,Zc,el,tl,nl,...zi,...Ki,...Ui,...qi];function Jr(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 Xr(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 Qr(e){return e.files.some(n=>n.path.startsWith("agents/"))?await fe(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 Zr(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 fe(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 rl=["docs/","skills/","agents/",".cursor/",".github/",".codex/",".agent/",".claude/"],sl=new Set(["AGENTS.md","CLAUDE.md","GEMINI.md","README.md",".github/copilot-instructions.md"]);function Ji(e){let t=e.replaceAll("\\","/").replace(/\/+$/,"");return sl.has(t)?!0:rl.some(n=>t===n.slice(0,-1)||t.startsWith(n))}function We(e,t){let n=e.split(`
|
|
171
|
+
`);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}var ol=["",".md","/README.md","/index.md"];async function Xi(e,t){for(let n of ol){let r=`${t}${n}`.replaceAll("\\","/");if(await fe(e,r))return!0}return!1}function es(e){return/my-doc\.md|example\.spec\.|\/example\//i.test(e)}function ts(e){return e.endsWith("/")?!0:e.endsWith(".md")||e.endsWith(".mdc")}var il=8;async function ns(e){let t=[];for(let n of e.files){if(!n.path.endsWith(".md")&&!n.path.endsWith(".mdc"))continue;let r=h(e,n.path);if(r===null)continue;let s=0;for(let o of ie(r)){if(Ge(o.href))continue;let i=je(n.path,o.href);if(!(i===null||!Ji(i)||!ts(i)||es(i)||await Xi(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:We(r,o.href),harnesses:[],hint:"Fix the path or add the missing guidance file."}),s+=1,s>=il))break}}return{findings:t,records:[]}}import{readFile as al}from"node:fs/promises";import cl from"node:path";async function rs(e){try{let t=await al(cl.join(e,"package.json"),"utf8"),n=JSON.parse(t);if(x(n)&&"scripts"in n){let{scripts:r}=n;if(x(r))return r}return null}catch{return null}}function ss(e){return e===null?!1:Object.entries(e).some(([t,n])=>t.toLowerCase().includes("qmd")||typeof n=="string"&&n.toLowerCase().includes("qmd"))}async function os(e){let t=I(e),n=e.files.filter(s=>s.path.startsWith("docs/ai/")).length;if(!t&&n<2)return{findings:[],records:[]};let r=await rs(e.repoRoot);return ss(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 is(e){let t=await oe(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 as(e){let t=await oe(e.repoRoot),n=[];return T(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 }.'}),T(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 J(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 Ue(e,t){return e.length===0?!0:e.some(n=>t.includes(n))}function cs(e,t,n){return Ue(n,e.harnesses)?t===null||t.length===0?!0:n.some(r=>t.includes(r)):!1}function ls(e,t,n){return Ue(e.harnesses,t.harnesses)?n===null||n.length===0||e.harnesses.length===0?!0:e.harnesses.some(r=>n.includes(r)):!1}function ce(e){return e.trim().replaceAll(/\s+/g," ")}function us(e){let t=ce(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 xt(e){return e.map(t=>ce(t)).filter(t=>t.length>0).join(`
|
|
172
|
+
`)}var Rt=3,ll=80;function ds(e,t){let n=e.split(`
|
|
173
|
+
`),r=xt(t.split(`
|
|
174
|
+
`)),s=[],o=new Set;for(let i=0;i<=n.length-Rt;i+=1){if(o.has(i))continue;let a=n.slice(i,i+Rt);if(!a.every(l=>us(l)))continue;let c=xt(a);if(!(c.length<ll)&&r.includes(c)){s.push({startLine:i+1,lineCount:Rt,sample:ce(a[0]??"")}),o.add(i);for(let l=1;l<Rt;l+=1)o.add(i+l)}}return s}var ps="docs/ai/rules.md";function ms(e){let t=h(e,ps);if(t===null)return{findings:[],records:[]};let n=[];for(let r of Ke){let s=h(e,r);if(s===null)continue;let o=ds(s,t);for(let i of o)n.push({ruleId:"adapter-content-duplication",severity:"warn",message:`${r} duplicates ${String(i.lineCount)} lines from ${ps} near line ${String(i.startLine)}.`,file:r,line:i.startLine,harnesses:[],hint:`Replace duplicated rules with a pointer to ${ps}.`})}return{findings:n,records:[]}}function k(e,t,n,r){return{ruleId:e,severity:"info",message:t,file:r,line:null,harnesses:[],hint:n}}function fs(e){let t=w(e);if(t===null||!b(t))return{findings:[],records:[]};let n=ke(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 gs(e){let t=V(e);return t===null||!z(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 hs(e){let t=w(e);if(t===null||!b(t))return{findings:[],records:[]};let n=ke(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 ys(e){let t=w(e);if(t===null||!b(t))return{findings:[],records:[]};let n=ye(t).map(a=>`${a.name} ${a.command}`).join(`
|
|
175
|
+
`),r=ke(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:[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 Ss(e){let t=w(e);return t===null||!b(t)?{findings:[],records:[]}:Fo(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 ks(e,t){return t.lastIndex=0,t.test(e)}function xs(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 Rs(e,t){let n=e.split(`
|
|
176
|
+
`);for(let r=0;r<n.length;r+=1){let s=n[r]??"";if(!xs(s)&&(t.lastIndex=0,t.test(s)))return r+1}return null}var ul=[{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 ws(e){let t=[];for(let n of e.files){if(!n.path.endsWith(".md")&&!n.path.endsWith(".mdc"))continue;let r=h(e,n.path);if(r!==null)for(let s of ul){let o=Rs(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 ie(r))ks(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:We(r,i.href),harnesses:[],hint:s.message})}}return{findings:t,records:[]}}function bs(e){let t=V(e);return t===null||!z(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 Cs(e){let t=w(e);if(t===null||!b(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 As(e){let t=w(e);if(t===null||!b(t))return{findings:[],records:[]};let n=Se(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:[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 Is(e){let t=e.intelligenceLayer;if(t===void 0||!_e(e,t))return{findings:[],records:[]};let n=t.localContextConventions.join(`
|
|
177
|
+
`),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 Es(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 vs(e){let t=V(e);return t===null||!z(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 Ts(e){let t=w(e);if(t===null||!b(t))return{findings:[],records:[]};let n=Se(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=ye(t).some(o=>/\b(mypy|pyright|cargo\s+check)\b/i.test(o.command));return n&&(r||s)?{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 Ls(e){let t=w(e);if(t===null||!b(t))return{findings:[],records:[]};let n=Se(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:[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 Qi={"shared-agents-md":"layering","shared-rules-doc":"layering","adapter-thin-claude":"layering","adapter-thin-gemini":"layering","adapter-thin-copilot":"layering","adapter-points-to-shared":"layering","skill-frontmatter":"maintainability","skill-line-count":"maintainability","agent-frontmatter":"maintainability","no-duplicate-skill-trees":"maintainability","no-duplicate-agent-trees":"maintainability","vscode-skills-location":"harnessWiring","vscode-agents-location":"harnessWiring","vscode-custom-hooks":"guardrails","skills-index":"discoverability","claude-agent-routing":"discoverability","agents-md-mentions-skills":"discoverability","skill-doc-deep-links":"discoverability","qmd-script-present":"discoverability","guidance-links-resolve":"maintainability","adapter-content-duplication":"sharing","forbidden-legacy-paths":"maintainability","strict-typecheck-present":"guardrails","lint-gate-present":"guardrails","jsdoc-enforcement-present":"guardrails","test-gates-present":"guardrails","focused-test-commands-present":"discoverability","ci-enforcement-gates":"guardrails","ci-validation-gates":"guardrails","correction-loop-documented":"maintainability","guidance-maintenance-script":"maintainability","pr-template-ai-harness-check":"maintainability","ci-guidance-lint":"guardrails","adapter-context-budget":"sharing","always-loaded-budget":"sharing","memory-docs-indexed":"discoverability","local-context-patterns":"maintainability","emphasis-keyword-density":"maintainability","identity-language-absent":"maintainability","model-interface-pinned":"guardrails","llm-output-schema-validated":"guardrails","tool-contract-tests-present":"guardrails","escalation-protocol-discoverability":"guardrails","agent-resource-budget-caps":"guardrails","tool-allowlist-inventory":"guardrails","untrusted-input-action-boundary":"guardrails","memory-write-provenance":"guardrails","high-impact-action-confirmation":"guardrails"};var dl=[["adapter-content-duplication",ms],["forbidden-legacy-paths",ws],["strict-typecheck-present",Ts],["lint-gate-present",As],["jsdoc-enforcement-present",Cs],["test-gates-present",Ls],["focused-test-commands-present",Ss],["ci-enforcement-gates",fs],["ci-validation-gates",hs],["correction-loop-documented",ys],["guidance-maintenance-script",bs],["pr-template-ai-harness-check",vs],["ci-guidance-lint",gs],["memory-docs-indexed",Es],["local-context-patterns",Is]];function Zi(e){let t=[],n=[];for(let[r,s]of dl){let o=s(e);t.push(...o.findings),n.push(...o.records),o.records.length===0&&n.push({checkId:r,dimension:Qi[r]??"maintainability",rawScore:o.findings.length>0?0:1})}return{findings:t,records:n}}async function wt(e,t){let n=[],r=[],s=Yi.filter(c=>ls(c,e,t)),o=await Promise.all(s.map(async c=>({rule:c,result:await c.check(e)})));for(let{rule:c,result:l}of o)J(n,r,c.id,c.dimension,l);if(cs(e,t,["cursor","copilot"])){let c=await as(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(l=>l.ruleId==="vscode-skills-location")?0:1}),r.push({checkId:"vscode-agents-location",dimension:"harnessWiring",rawScore:c.findings.some(l=>l.ruleId==="vscode-agents-location")?0:1})),J(n,r,"vscode-custom-hooks","harnessWiring",await is(e))}J(n,r,"no-duplicate-skill-trees","layering",await Zr(e)),J(n,r,"no-duplicate-agent-trees","layering",await Qr(e)),J(n,r,"qmd-script-present","discoverability",await os(e)),J(n,r,"guidance-links-resolve","maintainability",await ns(e));let i=Zi(e);n.push(...i.findings),r.push(...i.records);let a=[...Jr(e).findings,...Xr(e).findings];if(t===null||t.length===0)n.push(...a);else{let c=a.filter(l=>l.harnesses.some(m=>t.includes(m)));n.push(...c)}return{findings:n,records:r}}function _s(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 pl from"node:path";var le="AGENTS.md",ea=[le,"docs/ai/rules.md"],bt=["CLAUDE.md","GEMINI.md",".github/copilot-instructions.md",".agent/README.md"];function Fs(e){let t=h(e,le);if(t===null)return[];let n=C["AI2-adapter-fidelity"],r=[];for(let s of bt){let o=h(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.
|
|
178
178
|
|
|
179
179
|
The adapter should defer to the shared layer, not restate or contradict it. Find
|
|
180
180
|
claims in the ADAPTER that drift from the SHARED ENTRY: instructions the shared
|
|
@@ -195,13 +195,13 @@ ${o}
|
|
|
195
195
|
|
|
196
196
|
Respond with JSON only, no prose, exactly this shape:
|
|
197
197
|
{ "${n.schemaKey}": [ { "claim": "<quote from adapter>", "explanation": "<how it drifts>" } ] }
|
|
198
|
-
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,le],schemaKey:n.schemaKey,prompt:i})}return r}function Be(e,t){let n=[];for(let r of t){let s=h(e,r);s!==null&&s.trim().length>0&&n.push({path:r,content:s})}return n}function ue(e){let t=e.files.filter(n=>n.path.startsWith("skills/")&&n.path.endsWith("SKILL.md")).map(n=>n.path);return Be(e,[...
|
|
198
|
+
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,le],schemaKey:n.schemaKey,prompt:i})}return r}function Be(e,t){let n=[];for(let r of t){let s=h(e,r);s!==null&&s.trim().length>0&&n.push({path:r,content:s})}return n}function ue(e){let t=e.files.filter(n=>n.path.startsWith("skills/")&&n.path.endsWith("SKILL.md")).map(n=>n.path);return Be(e,[...ea,...t])}function j(e){return e.map(t=>`### FILE: ${t.path}
|
|
199
199
|
|
|
200
200
|
\`\`\`markdown
|
|
201
201
|
${t.content}
|
|
202
202
|
\`\`\``).join(`
|
|
203
203
|
|
|
204
|
-
`)}function
|
|
204
|
+
`)}function Ns(e){let t=ue(e);if(t.length<2)return null;let n=C["AI1-contradiction"],r=`You are auditing one repository's AI-agent guidance for internal contradictions.
|
|
205
205
|
|
|
206
206
|
Read every file below. Find places where one rule directly contradicts another \u2014
|
|
207
207
|
where an agent could not satisfy both at once. Be strict: only report clear,
|
|
@@ -211,7 +211,7 @@ ${j(t)}
|
|
|
211
211
|
|
|
212
212
|
Respond with JSON only, no prose, exactly this shape:
|
|
213
213
|
{ "${n.schemaKey}": [ { "ruleA": "<quote>", "ruleB": "<quote>", "explanation": "<why they conflict>" } ] }
|
|
214
|
-
Return an empty array if there are no clear contradictions.`;return{taskId:"AI1-contradiction",checkId:n.checkId,title:n.title,targetPaths:t.map(s=>s.path),schemaKey:n.schemaKey,prompt:r}}function
|
|
214
|
+
Return an empty array if there are no clear contradictions.`;return{taskId:"AI1-contradiction",checkId:n.checkId,title:n.title,targetPaths:t.map(s=>s.path),schemaKey:n.schemaKey,prompt:r}}function Ps(e){let t=ue(e);if(t.length===0)return null;let n=C["AI4-deadweight"],r=`You are auditing one repository's AI-agent guidance for dead weight.
|
|
215
215
|
|
|
216
216
|
Apply the deletion test to each rule or instruction below: if this line were
|
|
217
217
|
deleted, would a competent coding agent behave any differently? Flag the lines a
|
|
@@ -223,7 +223,7 @@ ${j(t)}
|
|
|
223
223
|
|
|
224
224
|
Respond with JSON only, no prose, exactly this shape:
|
|
225
225
|
{ "${n.schemaKey}": [ { "rule": "<quote>", "reason": "<why deleting it changes nothing>" } ] }
|
|
226
|
-
Return an empty array if every line earns its place.`;return{taskId:"AI4-deadweight",checkId:n.checkId,title:n.title,targetPaths:t.map(s=>s.path),schemaKey:n.schemaKey,prompt:r}}function
|
|
226
|
+
Return an empty array if every line earns its place.`;return{taskId:"AI4-deadweight",checkId:n.checkId,title:n.title,targetPaths:t.map(s=>s.path),schemaKey:n.schemaKey,prompt:r}}function Hs(e){let t=[le,"docs/ai/rules.md",...bt,...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=Be(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 Ms(e){let t=Hs(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:
|
|
227
227
|
its always-loaded instructions, skills, agent definitions, and lifecycle hook
|
|
228
228
|
scripts.
|
|
229
229
|
|
|
@@ -247,7 +247,7 @@ ${j(t)}
|
|
|
247
247
|
|
|
248
248
|
Respond with JSON only, no prose, exactly this shape:
|
|
249
249
|
{ "${n.schemaKey}": [ { "location": "<file or area>", "risk": "<short category>", "explanation": "<quote and why it is a risk>" } ] }
|
|
250
|
-
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
|
|
250
|
+
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 Ds(e){let t=ue(e);if(t.length===0)return null;let n=C["AI5-vague-rules"],r=`You are auditing one repository's AI-agent guidance for vague rules.
|
|
251
251
|
|
|
252
252
|
Flag each rule below that lacks a clear, testable decision boundary \u2014 where an
|
|
253
253
|
agent cannot determine whether it is complying. Examples: "keep files small"
|
|
@@ -259,12 +259,12 @@ ${j(t)}
|
|
|
259
259
|
|
|
260
260
|
Respond with JSON only, no prose, exactly this shape:
|
|
261
261
|
{ "${n.schemaKey}": [ { "rule": "<quote>", "reason": "<what decision boundary is missing>" } ] }
|
|
262
|
-
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(s=>s.path),schemaKey:n.schemaKey,prompt:r}}function
|
|
263
|
-
`);
|
|
264
|
-
`).
|
|
265
|
-
`)){let r=n.trim();if(/^[-*]\s*(don't|dont|never|always|do not|important)\b[:\s-]*(.*)$/i.exec(r)===null)continue;let o=r.replace(/^[-*]\s*/,""),i=
|
|
262
|
+
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(s=>s.path),schemaKey:n.schemaKey,prompt:r}}function Os(e){let t=[],n=Ns(e);n!==null&&t.push(n);let r=Ps(e);r!==null&&t.push(r);let s=Ds(e);s!==null&&t.push(s),t.push(...Fs(e));let o=Ms(e);return o!==null&&t.push(o),t}async function Ct(e){let t=pl.resolve(e),n=await Ee(t),{files:r,contents:s}=await He(t),o=await De(t);return{version:1,root:t,tasks:Os({repoRoot:t,harnesses:n,files:r,fileContents:s,security:o})}}import Bl from"node:path";import{homedir as ml}from"node:os";import ta from"node:path";import na from"node:path";import{lstatSync as gl}from"node:fs";import{readdirSync as yl}from"node:fs";import{existsSync as xl,statSync as Rl}from"node:fs";import wl from"node:path";import bl from"node:path";import{createReadStream as Il}from"node:fs";import El from"node:path";import{createInterface as vl}from"node:readline";function fl(e){return e!==null&&e.length>0?ta.resolve(e):ta.join(ml(),".claude","projects")}function hl(e){try{return gl(e).mtimeMs}catch{return null}}function Sl(e){try{return yl(e,{withFileTypes:!0})}catch{return[]}}function kl(e,t){let n=[];for(let r of Sl(e)){if(r.isSymbolicLink()||!r.isFile()||na.extname(r.name).toLowerCase()!==".jsonl")continue;let s=na.join(e,r.name),o=hl(s);o!==null&&n.push({file:s,mtimeMs:o})}return n.toSorted((r,s)=>s.mtimeMs-r.mtimeMs).slice(0,Math.max(0,t)).map(r=>r.file)}function Cl(e){return bl.resolve(e).replaceAll(/[/\\]/g,"-")}function Al(e,t){let n=wl.join(e,Cl(t));return!xl(n)||!Rl(n).isDirectory()?null:n}function Ve(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Tl(e){let{type:t,message:n}=e;return typeof t=="string"&&t.trim().length>0?t.trim().toLowerCase():Ve(n)&&typeof n.role=="string"?n.role.trim().toLowerCase():""}var Ll=[/^<[a-z-]+>/i,/^<\/[a-z-]+>/i,/^─{4,}/,/^={4,}/,/^-{4,}/,/^\*{4,}/,/^#{4,}\s*$/,/^UserPromptSubmit/,/^SessionStart/,/^OK$/,/^Tool loaded/];function _l(e){let t=e.trim();return t.length<5?!0:Ll.some(n=>n.test(t))}function Fl(e){if(!Ve(e))return"";let{message:t}=e;if(!Ve(t))return"";let{content:n}=t,r="";if(typeof n=="string")r=n.trim();else if(Array.isArray(n)){let o=[];for(let i of n)Ve(i)&&i.type==="text"&&typeof i.text=="string"&&o.push(i.text);r=o.join(`
|
|
263
|
+
`).trim()}let s=r.replaceAll(/<system-reminder>[\s\S]*?<\/system-reminder>/g,"").trim();return _l(s)?"":s}function Nl(e){try{return JSON.parse(e)}catch{return}}async function Pl(e){let t=El.basename(e,".jsonl"),n=[],r=vl({input:Il(e,{encoding:"utf8"}),crlfDelay:1/0});try{for await(let s of r){let o=s.trim();if(o.length===0)continue;let i=Nl(o);if(!Ve(i))continue;let a=Fl(i);a.length!==0&&n.push({sessionId:t,role:Tl(i),text:a})}}catch{return n}return n}async function Hl(e){let t=fl(e.sessionRoot),n=Al(t,e.repoRoot);if(n===null)return[];let r=kl(n,e.maxSessions);return(await Promise.all(r.map(o=>Pl(o)))).flat()}var Ml={harness:"claude",collectMessages:Hl},ra=Ml;function $s(e){let t=Array.from({length:e},(o,i)=>i),n=Array.from({length:e},()=>0);function r(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 s(o,i){let a=r(o),c=r(i);if(a===c)return;let l=n[a]??0,m=n[c]??0;if(l<m){t[a]=c;return}if(l>m){t[c]=a;return}t[c]=a,n[a]=l+1}return{findRoot:r,union:s}}function N(e){return String(e??"").replaceAll(/\s+/g," ").trim().toLowerCase()}function js(e,t=20){let n=new Set,r=N(e);if(r.length<t)return n;let s=Math.max(5,Math.floor(t/4));for(let i=0;i+t<=r.length;i+=s)n.add(r.slice(i,i+t));let o=r.length-t;return o>0&&n.add(r.slice(o)),n}function Ws(e){let t=null,n=0,r=0;for(let[s,o]of e.entries()){let i=o.sessions.size;(i>n||i===n&&o.occurrences>r)&&(t=s,n=i,r=o.occurrences)}return t}function de(e,t=20,n=Number.POSITIVE_INFINITY){let r=e.map(m=>({sessionId:m.sessionId,normalized:N(m.text)})).filter(m=>m.normalized.length>=t),s=r.length;if(s<2)return[];let o=r.map(m=>js(m.normalized,t)),i=new Map;for(let[m,u]of o.entries())for(let f of u){let d=i.get(f);d===void 0?i.set(f,[m]):d.push(m)}let a=$s(s);for(let m of i.values()){let[u,...f]=m;if(u!==void 0)for(let d of f)a.union(u,d)}let c=new Map;for(let m=0;m<s;m+=1){let u=a.findRoot(m),f=c.get(u)??[];f.push(m),c.set(u,f)}let l=[];for(let m of c.values()){if(m.length<2)continue;let u=new Set,f=new Map;for(let g of m){let y=r[g],E=o[g];if(!(y===void 0||E===void 0)){u.add(y.sessionId);for(let we of E){let X=f.get(we)??{sessions:new Set,occurrences:0};X.occurrences+=1,X.sessions.add(y.sessionId),f.set(we,X)}}}if(u.size<2&&m.length<n)continue;let d=Ws(f);d!==null&&l.push({instruction:d,occurrences:m.length,sessions:u.size})}return l.toSorted((m,u)=>u.sessions-m.sessions||u.occurrences-m.occurrences)}import{createHash as Ol}from"node:crypto";function Us(e){let t=String(e??""),n=Ol("sha256").update(t).digest("hex").slice(0,8);return`[redacted ${t.length}ch #${n}]`}function pe(e,t){return t?String(e??""):Us(e)}function ze(e,t){return t.some(n=>n.test(e))}function qe(e){return ze(e,lo)}function Bs(e,t){let n=e.filter(l=>l.role==="user"&&qe(l.text));if(n.length===0)return[];let r=new Set(n.map(l=>l.sessionId)),s=new Set(e.filter(l=>l.role==="user").map(l=>l.sessionId)).size,o=s===0?0:n.length/s,i={checkId:"SS3",name:_.SS3,detail:`${n.length} corrections across ${r.size} of ${s} sessions (${o.toFixed(2)} per session)`,sessions:r.size,occurrences:n.length,snippet:null},a=n.map(l=>({sessionId:l.sessionId,text:l.text})),c=de(a).map(l=>{let m=pe(l.instruction,t);return{checkId:"SS3",name:_.SS3,detail:`Recurring friction ${m}: corrected in ${l.sessions} sessions (${l.occurrences} times)`,sessions:l.sessions,occurrences:l.occurrences,snippet:m}});return[i,...c]}function Vs(e,t){return e.keywords.length===0?t.includes(N(e.text)):e.keywords.some(n=>new RegExp(`\\b${n}\\b`).test(t))}function zs(e,t){if(t.length===0)return[];let n=new Map;for(let s of e){let o=n.get(s.sessionId)??[];o.push(s),n.set(s.sessionId,o)}let r=new Map;for(let[s,o]of n.entries()){let i=o.map(a=>N(a.text));for(let[a,c]of o.entries()){if(c.role!=="user"||!qe(c.text))continue;let l=[i[a-1],i[a],i[a+1]].filter(m=>typeof m=="string").join(`
|
|
264
|
+
`);if(uo.test(l))for(let m of t){if(!Vs(m,l))continue;let u=r.get(m.text)??{rule:m.text,occurrences:0,sessions:new Set};u.occurrences+=1,u.sessions.add(s),r.set(m.text,u)}}}return[...r.values()].toSorted((s,o)=>o.sessions.size-s.sessions.size||o.occurrences-s.occurrences).map(s=>({checkId:"SS2",name:_.SS2,detail:`Possibly ignored rule "${s.rule}": ${s.occurrences} corrections in tool-use context across ${s.sessions.size} sessions`,sessions:s.sessions.size,occurrences:s.occurrences,snippet:s.rule}))}function qs(e){return ze(e,co)}function Ks(e,t){let n=e.filter(r=>r.role==="user"&&qs(r.text)).map(r=>({sessionId:r.sessionId,text:r.text}));return de(n,void 0,3).map(r=>{let s=pe(r.instruction,t),o=r.sessions>=2?`repeated across ${r.sessions} sessions (${r.occurrences} times)`:`repeated ${r.occurrences} times within a single session`;return{checkId:"SS4",name:_.SS4,detail:`Candidate missing rule ${s}: ${o} but likely not in committed guidance`,sessions:r.sessions,occurrences:r.occurrences,snippet:s}})}function Ys(e,t){let n=e.filter(r=>r.role==="user").map(r=>({sessionId:r.sessionId,text:r.text}));return de(n).map(r=>{let s=pe(r.instruction,t);return{checkId:"SS1",name:_.SS1,detail:`Repeated prompt ${s} seen in ${r.sessions} sessions (${r.occurrences} times)`,sessions:r.sessions,occurrences:r.occurrences,snippet:s}})}function Js(e,t,n){return[...Ks(e,n),...zs(e,t),...Bs(e,n),...Ys(e,n)]}import Wl from"node:path";import{readFile as Gl}from"node:fs/promises";async function Xs(e){try{return await Gl(e,"utf8")}catch{return null}}function Qs(e){return N(e).replaceAll(/[^a-z0-9 ]/g," ").replaceAll(/\s+/g," ").trim()}var jl=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 Zs(e){let t=[];for(let n of e.split(`
|
|
265
|
+
`)){let r=n.trim();if(/^[-*]\s*(don't|dont|never|always|do not|important)\b[:\s-]*(.*)$/i.exec(r)===null)continue;let o=r.replace(/^[-*]\s*/,""),i=Qs(o).split(/\s+/).filter(a=>a.length>=3&&!jl.has(a));t.push({text:o,keywords:i})}return t}var Ul=["CLAUDE.md","AGENTS.md"];async function eo(e){let t=await Promise.all(Ul.map(n=>Xs(Wl.join(e,n))));for(let n of t){if(n===null)continue;let r=Zs(n);if(r.length>0)return r}return[]}async function At(e,t=ra){let n=Bl.resolve(e.repoRoot),r=await t.collectMessages({...e,repoRoot:n}),s=new Set(r.map(a=>a.sessionId)).size;if(r.length===0)return{version:1,root:n,harness:t.harness,tier:"extended",status:"no-sessions",sessionsAnalyzed:0,redacted:!e.includeRawSnippets,findings:[]};let o=await eo(n),i=Js(r,o,e.includeRawSnippets);return{version:1,root:n,harness:t.harness,tier:"extended",status:"run",sessionsAnalyzed:s,redacted:!e.includeRawSnippets,findings:i}}var oa={error:3,warn:2,info:1};function It(e,t){let n=oa[t];return e.some(r=>oa[r.severity]>=n)}async function to(e){let t=Vl.resolve(e.repoRoot),n=mi(),r=await Ee(t),{files:s,contents:o}=await He(t),i=await Rr(t),a=await De(t),c=await fr(t),l={repoRoot:t,harnesses:r,files:s,fileContents:o,intelligenceLayer:i,security:a,boundary:c},m=An(l);l.contextBudget=m;let{findings:u,records:f}=await wt(l,e.harnessFilter),d=_s(u),g=En(u),y=yn(s,r),E=await oe(t),we=await On(l,E,u,y),X=sr(f,u,y,we,l),ia=await cn(l,E),aa=await n,ca=ht(i),la=e.aiReviewResults===void 0?vt:Qe(e.aiReviewResults);return{version:aa.version,root:t,harnesses:r,total_score:X.total_score,score_scope:X.score_scope,inventory:{fileCount:s.length,files:s},sharing:y,metaHarness:X,harnessGapMatrix:ia,harnessOptimization:we,intelligenceLayer:ca,contextBudget:m,aiReview:la,findings:u,failureModeExposure:g,summary:d}}async function no(){let e=jt(process.argv.slice(2));if(e.help){Wt(),process.exitCode=0;return}if(e.emitAiTasks){try{let t=await Ct(e.repoRoot);process.stdout.write(`${JSON.stringify(t,null,2)}
|
|
266
266
|
`),process.exitCode=0}catch(t){let n=t instanceof Error?t.message:String(t);process.stderr.write(`error: ${n}
|
|
267
|
-
`),process.exitCode=2}return}if(e.sessionAnalysis){try{let t=await
|
|
268
|
-
`):
|
|
269
|
-
`),process.exitCode=2}return}try{let t=e.ingestResultsPath===null?void 0:await
|
|
270
|
-
`),process.exitCode=2}}await
|
|
267
|
+
`),process.exitCode=2}return}if(e.sessionAnalysis){try{let t=await At({repoRoot:e.repoRoot,sessionRoot:e.sessionRoot,maxSessions:e.maxSessions,includeRawSnippets:e.includeRawSnippets});e.format==="json"?process.stdout.write(`${JSON.stringify(t,null,2)}
|
|
268
|
+
`):Bt(t),process.exitCode=0}catch(t){let n=t instanceof Error?t.message:String(t);process.stderr.write(`error: ${n}
|
|
269
|
+
`),process.exitCode=2}return}try{let t=e.ingestResultsPath===null?void 0:await $t(e.ingestResultsPath),n=await to({repoRoot:e.repoRoot,harnessFilter:e.harnessFilter,...t===void 0?{}:{aiReviewResults:t}});e.format==="json"?Ut(n):fn(n),process.exitCode=It(n.findings,e.failOn)?1:0}catch(t){let n=t instanceof Error?t.message:String(t);process.stderr.write(`error: ${n}
|
|
270
|
+
`),process.exitCode=2}}await no();
|
|
@@ -1,13 +1,44 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dimensions": {
|
|
3
|
-
"layering": {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
"layering": {
|
|
4
|
+
"weight": 1,
|
|
5
|
+
"max_score": 100
|
|
6
|
+
},
|
|
7
|
+
"sharing": {
|
|
8
|
+
"weight": 1,
|
|
9
|
+
"max_score": 100
|
|
10
|
+
},
|
|
11
|
+
"discoverability": {
|
|
12
|
+
"weight": 1,
|
|
13
|
+
"max_score": 100
|
|
14
|
+
},
|
|
15
|
+
"harnessWiring": {
|
|
16
|
+
"weight": 1,
|
|
17
|
+
"max_score": 100
|
|
18
|
+
},
|
|
19
|
+
"maintainability": {
|
|
20
|
+
"weight": 1,
|
|
21
|
+
"max_score": 100
|
|
22
|
+
},
|
|
23
|
+
"guardrails": {
|
|
24
|
+
"weight": 1,
|
|
25
|
+
"max_score": 100
|
|
26
|
+
},
|
|
27
|
+
"session": {
|
|
28
|
+
"weight": 1,
|
|
29
|
+
"max_score": 100
|
|
30
|
+
},
|
|
31
|
+
"deep": {
|
|
32
|
+
"weight": 1,
|
|
33
|
+
"max_score": 100
|
|
34
|
+
}
|
|
11
35
|
},
|
|
12
|
-
"check_weights": {
|
|
36
|
+
"check_weights": {
|
|
37
|
+
"shared-rules-doc": 0.5,
|
|
38
|
+
"jsdoc-enforcement-present": 0.5,
|
|
39
|
+
"correction-loop-documented": 0.5,
|
|
40
|
+
"guidance-maintenance-script": 0.5,
|
|
41
|
+
"pr-template-ai-harness-check": 0.5,
|
|
42
|
+
"ci-guidance-lint": 0.5
|
|
43
|
+
}
|
|
13
44
|
}
|
package/package.json
CHANGED
|
@@ -1,93 +1,57 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
"check:md:style": "markdownlint-cli2",
|
|
59
|
-
"check:md:text": "textlint --rulesdir textlint-rules --config .textlintrc.json \"docs/**/*.md\" \".claude/**/*.md\" && textlint --config .textlintrc.skills.json \"skills/*/SKILL.md\" \"agents/**/*.md\" && textlint --config .textlintrc.instructions.json \"AGENTS.md\" \"CLAUDE.md\" \"GEMINI.md\" \".github/copilot-instructions.md\"",
|
|
60
|
-
"check:links": "remark --quiet --frail \"docs/**/*.md\" \"skills/**/*.md\" \"agents/**/*.md\" \".github/*.md\" \".claude/**/*.md\" \"*.md\"",
|
|
61
|
-
"check:spelling": "cspell --no-progress --no-summary \"**/*.md\"",
|
|
62
|
-
"lint:md": "npm run check:md && npm run check:links && npm run check:spelling",
|
|
63
|
-
"start": "node dist/cli.js",
|
|
64
|
-
"test": "vitest run",
|
|
65
|
-
"test:file": "vitest run",
|
|
66
|
-
"typecheck": "tsc --noEmit"
|
|
67
|
-
},
|
|
68
|
-
"devDependencies": {
|
|
69
|
-
"@tobilu/qmd": "^2.5.3",
|
|
70
|
-
"@types/bun": "^1.3.14",
|
|
71
|
-
"@types/node": "^22.19.20",
|
|
72
|
-
"@typescript-eslint/parser": "^8.61.0",
|
|
73
|
-
"@typescript-eslint/utils": "^8.61.0",
|
|
74
|
-
"cspell": "^9.2.1",
|
|
75
|
-
"esbuild": "^0.27.7",
|
|
76
|
-
"eslint": "^10.4.1",
|
|
77
|
-
"jiti": "^2.7.0",
|
|
78
|
-
"markdownlint-cli2": "^0.22.1",
|
|
79
|
-
"oxfmt": "^0.36.0",
|
|
80
|
-
"oxlint": "^1.68.0",
|
|
81
|
-
"oxlint-tsgolint": "^0.23.0",
|
|
82
|
-
"remark-cli": "^12.0.1",
|
|
83
|
-
"remark-validate-links": "^13.1.0",
|
|
84
|
-
"textlint": "^15.7.0",
|
|
85
|
-
"textlint-rule-max-number-of-lines": "^1.0.3",
|
|
86
|
-
"typescript": "^5.8.3",
|
|
87
|
-
"unist-util-visit": "^5.0.0",
|
|
88
|
-
"vitest": "^3.2.4"
|
|
89
|
-
},
|
|
90
|
-
"engines": {
|
|
91
|
-
"node": ">=20"
|
|
92
|
-
}
|
|
93
|
-
}
|
|
2
|
+
"name": "@paniolo/scan",
|
|
3
|
+
"version": "0.2.3",
|
|
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
|
+
"keywords": [
|
|
6
|
+
"agents",
|
|
7
|
+
"agents-md",
|
|
8
|
+
"ai",
|
|
9
|
+
"antigravity",
|
|
10
|
+
"claude-code",
|
|
11
|
+
"cli",
|
|
12
|
+
"codex",
|
|
13
|
+
"coding-agents",
|
|
14
|
+
"copilot",
|
|
15
|
+
"cursor",
|
|
16
|
+
"diagnostic",
|
|
17
|
+
"gemini",
|
|
18
|
+
"harness",
|
|
19
|
+
"harness-engineering",
|
|
20
|
+
"lint",
|
|
21
|
+
"static-analysis",
|
|
22
|
+
"technical-debt"
|
|
23
|
+
],
|
|
24
|
+
"homepage": "https://paniolo.ai",
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/paniolo-ai/paniolo/issues"
|
|
27
|
+
},
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/paniolo-ai/paniolo.git",
|
|
32
|
+
"directory": "packages/scan"
|
|
33
|
+
},
|
|
34
|
+
"bin": {
|
|
35
|
+
"paniolo-scan": "dist/cli.js"
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist/**/*.js",
|
|
39
|
+
"dist/**/*.json",
|
|
40
|
+
"README.md"
|
|
41
|
+
],
|
|
42
|
+
"type": "module",
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^22.19.20",
|
|
45
|
+
"typescript": "^5.8.3",
|
|
46
|
+
"@paniolo/session-source": "0.2.0"
|
|
47
|
+
},
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=20"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "pnpm run typecheck && node scripts/build.mjs",
|
|
53
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
54
|
+
"pack:dry-run": "npm pack --dry-run",
|
|
55
|
+
"start": "node dist/cli.js"
|
|
56
|
+
}
|
|
57
|
+
}
|