arkgate 3.2.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/README.md +3 -3
- package/bin/lib/analysis-engine.mjs +6 -5
- package/dist/configTypes-CVWWhBoe.d.cts +54 -0
- package/dist/configTypes-CVWWhBoe.d.ts +54 -0
- package/dist/eslint/index.cjs +3 -3
- package/dist/eslint/index.d.cts +1 -1
- package/dist/eslint/index.d.ts +1 -1
- package/dist/eslint/index.js +3 -3
- package/dist/index.cjs +7 -6
- package/dist/index.d.cts +314 -82
- package/dist/index.d.ts +314 -82
- package/dist/index.js +6 -5
- package/docs/agent-guide.md +8 -0
- package/docs/package-surface.md +2 -1
- package/package.json +1 -1
- package/server.json +2 -2
- package/dist/configContract-BxSIwVRo.d.cts +0 -259
- package/dist/configContract-BxSIwVRo.d.ts +0 -259
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,43 @@ All notable changes to ArkGate (`arkgate`; formerly `ark-runtime-kernel`) are do
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 3.3.0 — 2026-07-16
|
|
8
|
+
|
|
9
|
+
Understandable execution, first slice (Phase U: U01–U03): typed effect capabilities as
|
|
10
|
+
**evidence-only** architecture facts, a locked ADR boundary, and a legibility dogfood of the
|
|
11
|
+
engine itself. Nothing blocks on capabilities in this release — walls arrive with the second
|
|
12
|
+
slice (U04+) after the corpus matures in the field. **No breaking** CLI or `ark.config.json`
|
|
13
|
+
changes. **No gate weaken.**
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **ADR 0009 (U01):** the accepted architecture-vs-style boundary — seven closed capability ids
|
|
18
|
+
(`network`, `filesystem`, `clock`, `randomness`, `environment`, `process`, `persistence`),
|
|
19
|
+
direct-evidence-only blocking threshold (transitive inference never blocks), config lowering
|
|
20
|
+
design (`forbiddenGlobals` and future capability policy lower to one semantic space;
|
|
21
|
+
`pure: true` planned as the casual surface), coverage-faithful lowering for prefix-matched
|
|
22
|
+
globals (bare `process` covers `environment` too), surface-ownership dedup rule, and the
|
|
23
|
+
W02 governance-weight reconciliation. Backed by a 25-case executable fixture corpus
|
|
24
|
+
(`tests/fixtures/capability-corpus/`) with a content-aware structural guard.
|
|
25
|
+
- **Effect capabilities in the canonical analysis (U03):** `collectCapabilityUses(ts, sourceFile)`
|
|
26
|
+
composes the existing symbol-aware collectors (shadowing / type-only / `globalThis`-alias
|
|
27
|
+
precision; no second scanner); the Domain vocabulary ships as
|
|
28
|
+
`CAPABILITY_IDS` / `capabilityForModuleSpecifier` / `capabilityForAmbientName` /
|
|
29
|
+
`lowerForbiddenGlobal`; the compiler-free IR engine now populates `ir.capabilityUses` with
|
|
30
|
+
import-based evidence (exact module/subpath matching — never substring; textual
|
|
31
|
+
`import type` / `export type` erasure). Additive within IR `1.0`; evidence only.
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
- **Engine legibility dogfood (U02):** `src/kernel/analysis.ts` is now a pure facade over six
|
|
36
|
+
cohesive kernel modules and the `ark.config.json` contract types moved to
|
|
37
|
+
`src/domain/configTypes.ts` — zero consumer import changes, byte-identical generated
|
|
38
|
+
config artifacts, identical hashes and verdicts (verified by execution old-vs-new). ArkGate's
|
|
39
|
+
own doctor now reports **zero design smells** on this repository.
|
|
40
|
+
- The experimental `@arkgate/runtime` distribution is minified with `keepNames` (stable
|
|
41
|
+
class/function names for reflection and Nest diagnostics) and stays well inside its
|
|
42
|
+
release-artifact budget.
|
|
43
|
+
|
|
7
44
|
## 3.2.0 — 2026-07-15
|
|
8
45
|
|
|
9
46
|
Contract health (Phase W): ArkGate now also meta-lints the contract itself and describes its
|
package/README.md
CHANGED
|
@@ -16,9 +16,9 @@ and makes sure a “green” check means something real.
|
|
|
16
16
|
|
|
17
17
|
</div>
|
|
18
18
|
|
|
19
|
-
> **ArkGate 3.
|
|
20
|
-
>
|
|
21
|
-
>
|
|
19
|
+
> **ArkGate 3.3.0** is current stable: typed effect-capability evidence (seven closed ids,
|
|
20
|
+
> evidence-only until walls opt in), on top of 3.2's contract health and 3.1's change-integrity
|
|
21
|
+
> loop. [Release notes](docs/releases/3.3.0.md).
|
|
22
22
|
|
|
23
23
|
---
|
|
24
24
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// GENERATED from src/kernel/analysis.ts by scripts/generate-analysis-engine.mjs.
|
|
2
2
|
// Do not edit this file directly.
|
|
3
|
-
function
|
|
3
|
+
function w(e){let t=2166136261;for(let n=0;n<e.length;n+=1)t^=e.charCodeAt(n),t=Math.imul(t,16777619);return`fnv1a-${(t>>>0).toString(16).padStart(8,"0")}`}function E(e){if(e===null||typeof e!="object")return JSON.stringify(e);if(Array.isArray(e))return`[${e.map(E).join(",")}]`;let t=e;return`{${Object.keys(t).sort().map(n=>`${JSON.stringify(n)}:${E(t[n])}`).join(",")}}`}var ye=new Map;function he(e){return/[.*+?^${}()|[\]\\]/.test(e)?`\\${e}`:e}function W(e){let t="";for(let n=0;n<e.length;n+=1){let r=e[n];if(r==="\\"&&n+1<e.length){let i=e[n+1];if("*?{}[],".includes(i)||i==="\\"){t+="\\"+i,n+=1;continue}t+="/";continue}t+=r}return t}function De(e){let t=0;for(let n=0;n<e.length;n+=1){let r=e[n];if(r==="\\"){n+=1;continue}if(r==="{")t+=1;else if(r==="}"&&(t-=1,t<0))return!1}return t===0}function D(e){let t=ye.get(e);if(t)return t;let n=W(e),r=De(n),i="",a=0;for(let l=0;l<n.length;l+=1){let p=n[l];p==="\\"&&l+1<n.length?(i+=he(n[l+1]),l+=1):p==="*"?n[l+1]==="*"?n[l+2]==="/"?(i+="(?:.*/)?",l+=2):(i+=".*",l+=1):i+="[^/]*":p==="?"?i+="[^/]":p==="{"&&r?(i+="(?:",a+=1):p==="}"&&r&&a>0?(i+=")",a-=1):p===","&&r&&a>0?i+="|":i+=he(p)}let o=new RegExp(`^${i}$`);return ye.set(e,o),o}function J(e){let t=W(String(e)),r=t.split("*")[0].split("/").filter(Boolean).length,i=t.replace(/\*/g,"").length;return r*1e4+i}function L(e,t){let n=String(e).split(/[/\\]/).join("/"),r,i=-1;for(let a of t??[])if(!(a.exclude??[]).some(o=>D(o).test(n))){for(let o of a.patterns??[])if(D(o).test(n)){let l=J(o);l>i&&(i=l,r=a.name)}}return r}function me(e,t){if(!t?.length)return;let n=String(e).split(/[/\\]/).filter(Boolean),r=new Set(t.map(i=>String(i).toLowerCase()));for(let i=0;i<n.length-1;i+=1)if(r.has(n[i].toLowerCase()))return`${n[i]}/${n[i+1]}`}function Fe(e){let t=new Set;for(let n of e??[]){let i=W(String(n)).split("/").filter(Boolean);for(let a=0;a<i.length;a+=1){let o=i[a];if((o==="**"||o==="*")&&a>0){let l=i[a-1];l&&!l.includes("*")&&!l.includes("{")&&!l.includes("}")&&t.add(l)}}}return[...t]}function je(e,t,n){if(Array.isArray(e.sliceFolders)&&e.sliceFolders.length>0)return e.sliceFolders.filter(i=>typeof i=="string"&&i.length>0);let r=(n??[]).find(i=>i.name===t);return Fe(r?.patterns)}function H(e,t,n,r){for(let i of e??[])if(!(i.from!==t||i.to!==n)&&i.allowed===!1){if(i.peerIsolation){let a=r?.fromPath,o=r?.toPath;if(!a||!o)continue;let l=je(i,t,r?.layers);if(l.length===0)continue;let p=me(a,l),u=me(o,l);if(!p||!u)continue;if(p!==u)return i;continue}if(t!==n)return i}}var Z="1.0";var V=class extends Error{issues;source;constructor(t,n){super(`Invalid architecture change map (${t}):
|
|
4
4
|
${n.map(r=>`- ${r.path}: ${r.message}`).join(`
|
|
5
|
-
`)}`),this.name="ArkConfigValidationError",this.source=t,this.issues=n}};function oe(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function B(e,t){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(t)?`${e}.${t}`:`${e}[${JSON.stringify(t)}]`}function R(e){return e===null?"null":Array.isArray(e)?"array":typeof e}function $e(e,t){let n="#/$defs/";if(e.startsWith(n))return t.$defs[e.slice(n.length)]}function F(e,t,n,r,i){if(t.$ref){let a=$e(t.$ref,r);if(!a){i.push({path:n,message:`schema reference ${t.$ref} cannot be resolved`});return}F(e,a,n,r,i);return}if(t.const!==void 0&&!Object.is(e,t.const)){i.push({path:n,message:`must equal ${JSON.stringify(t.const)}`});return}if(t.enum&&!t.enum.some(a=>Object.is(a,e))){i.push({path:n,message:`must be one of ${t.enum.map(String).join(", ")}`});return}if(t.type==="object"){if(!oe(e)){i.push({path:n,message:`must be an object; received ${R(e)}`});return}let a=t.properties??{};for(let o of t.required??[])e[o]===void 0&&i.push({path:B(n,o),message:"is required"});if(t.additionalProperties===!1)for(let o of Object.keys(e))o in a||i.push({path:B(n,o),message:"unknown field"});for(let[o,l]of Object.entries(a))e[o]!==void 0&&F(e[o],l,B(n,o),r,i);return}if(t.type==="array"){if(!Array.isArray(e)){i.push({path:n,message:`must be an array; received ${R(e)}`});return}if(t.minItems!==void 0&&e.length<t.minItems&&i.push({path:n,message:`must contain at least ${t.minItems} item(s)`}),t.uniqueItems){let a=e.map(o=>JSON.stringify(o));new Set(a).size!==a.length&&i.push({path:n,message:"must not contain duplicate items"})}t.items&&e.forEach((a,o)=>F(a,t.items,`${n}[${o}]`,r,i));return}if(t.type==="string"){if(typeof e!="string"){i.push({path:n,message:`must be a string; received ${R(e)}`});return}t.minLength!==void 0&&e.length<t.minLength&&i.push({path:n,message:`must contain at least ${t.minLength} character(s)`});return}if(t.type==="boolean"){typeof e!="boolean"&&i.push({path:n,message:`must be a boolean; received ${R(e)}`});return}if(t.type==="integer"){if(!Number.isInteger(e)){i.push({path:n,message:`must be an integer; received ${R(e)}`});return}t.minimum!==void 0&&e<t.minimum&&i.push({path:n,message:`must be at least ${t.minimum}`})}}function Oe(e){return{...e,$schema:e.$schema===void 0?K:e.$schema,schemaVersion:e.schemaVersion===void 0?"1.0":e.schemaVersion,include:e.include===void 0?["src"]:e.include,layers:e.layers===void 0?[]:e.layers,rules:e.rules===void 0?se.map(t=>({...t})):e.rules}}function Re(e,t="ark.config.json"){if(!oe(e))throw new P(t,[{path:"$",message:`must be an object; received ${R(e)}`}]);let n=e.schemaVersion===void 0?"unversioned":null;if(e.schemaVersion!==void 0&&e.schemaVersion!=="1.0")throw new P(t,[{path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(e.schemaVersion)}; expected 1.0`}]);return{candidate:Oe(e),migratedFrom:n}}function q(e,t="ark.config.json"){let{candidate:n,migratedFrom:r}=Re(e,t),i=[];if(F(n,ae,"$",ae,i),i.length>0)throw new P(t,i);return{config:n,migratedFrom:r}}function ce(e,t="ark.config.json"){let n;try{n=JSON.parse(e)}catch(r){throw new P(t,[{path:"$",message:`invalid JSON: ${r instanceof Error?r.message:String(r)}`}])}return q(n,t)}var le=new Map;function de(e){return/[.*+?^${}()|[\]\\]/.test(e)?`\\${e}`:e}function z(e){let t="";for(let n=0;n<e.length;n+=1){let r=e[n];if(r==="\\"&&n+1<e.length){let i=e[n+1];if("*?{}[],".includes(i)||i==="\\"){t+="\\"+i,n+=1;continue}t+="/";continue}t+=r}return t}function Pe(e){let t=0;for(let n=0;n<e.length;n+=1){let r=e[n];if(r==="\\"){n+=1;continue}if(r==="{")t+=1;else if(r==="}"&&(t-=1,t<0))return!1}return t===0}function _(e){let t=le.get(e);if(t)return t;let n=z(e),r=Pe(n),i="",a=0;for(let l=0;l<n.length;l+=1){let d=n[l];d==="\\"&&l+1<n.length?(i+=de(n[l+1]),l+=1):d==="*"?n[l+1]==="*"?n[l+2]==="/"?(i+="(?:.*/)?",l+=2):(i+=".*",l+=1):i+="[^/]*":d==="?"?i+="[^/]":d==="{"&&r?(i+="(?:",a+=1):d==="}"&&r&&a>0?(i+=")",a-=1):d===","&&r&&a>0?i+="|":i+=de(d)}let o=new RegExp(`^${i}$`);return le.set(e,o),o}function Y(e){let t=z(String(e)),r=t.split("*")[0].split("/").filter(Boolean).length,i=t.replace(/\*/g,"").length;return r*1e4+i}function M(e,t){let n=String(e).split(/[/\\]/).join("/"),r,i=-1;for(let a of t??[])if(!(a.exclude??[]).some(o=>_(o).test(n))){for(let o of a.patterns??[])if(_(o).test(n)){let l=Y(o);l>i&&(i=l,r=a.name)}}return r}function pe(e,t){if(!t?.length)return;let n=String(e).split(/[/\\]/).filter(Boolean),r=new Set(t.map(i=>String(i).toLowerCase()));for(let i=0;i<n.length-1;i+=1)if(r.has(n[i].toLowerCase()))return`${n[i]}/${n[i+1]}`}function Le(e){let t=new Set;for(let n of e??[]){let i=z(String(n)).split("/").filter(Boolean);for(let a=0;a<i.length;a+=1){let o=i[a];if((o==="**"||o==="*")&&a>0){let l=i[a-1];l&&!l.includes("*")&&!l.includes("{")&&!l.includes("}")&&t.add(l)}}}return[...t]}function ve(e,t,n){if(Array.isArray(e.sliceFolders)&&e.sliceFolders.length>0)return e.sliceFolders.filter(i=>typeof i=="string"&&i.length>0);let r=(n??[]).find(i=>i.name===t);return Le(r?.patterns)}function W(e,t,n,r){for(let i of e??[])if(!(i.from!==t||i.to!==n)&&i.allowed===!1){if(i.peerIsolation){let a=r?.fromPath,o=r?.toPath;if(!a||!o)continue;let l=ve(i,t,r?.layers);if(l.length===0)continue;let d=pe(a,l),u=pe(o,l);if(!d||!u)continue;if(d!==u)return i;continue}if(t!==n)return i}}function C(e,t){e.push({id:`${t.classification}:${t.path}:${t.kind}`,path:t.path,classification:t.classification,message:t.message,...t.classification==="weakening"||t.classification==="judgment-required"?{nextAction:`Restore the previous protection at ${t.path}, then run ArkGate again.`}:{},...t.before===void 0?{}:{before:t.before},...t.after===void 0?{}:{after:t.after}})}function S(e){return[...new Set(e??[])].sort()}function L(e,t,n,r,i){let a=S(n),o=S(r),l=new Set(a),d=new Set(o),u=o.filter(g=>!l.has(g)),m=a.filter(g=>!d.has(g));u.length===0&&m.length===0||(u.length>0&&C(e,{kind:"added",path:t,classification:i.added,message:i.addedMessage,before:a,after:o}),m.length>0&&C(e,{kind:"removed",path:t,classification:i.removed,message:i.removedMessage,before:a,after:o}))}function j(e,t,n,r,i,a,o){if(n===r)return;C(e,{kind:r?"enabled":"disabled",path:t,classification:r?i:i==="strengthening"?"weakening":"strengthening",message:r?a:o,before:n,after:r})}function H(e,t){let n=new Map,r=new Set;for(let i of e){let a=t(i);n.has(a)?r.add(a):n.set(a,i)}return{values:n,duplicates:[...r].sort()}}function _e(e,t,n){let r=H(t,a=>a.name),i=H(n,a=>a.name);(r.duplicates.length>0||i.duplicates.length>0)&&C(e,{kind:"duplicate-layer",path:"$.layers",classification:"judgment-required",message:"Duplicate layer names make policy ownership ambiguous.",before:r.duplicates,after:i.duplicates});for(let a of[...new Set([...r.values.keys(),...i.values.keys()])].sort()){let o=r.values.get(a),l=i.values.get(a),d=`$.layers[${a}]`;if(!o&&l){C(e,{kind:"layer-added",path:d,classification:"judgment-required",message:"A layer was added; verify overlap, ownership, and rule coverage.",after:l});continue}if(o&&!l){C(e,{kind:"layer-removed",path:d,classification:"weakening",message:"Removing a layer can leave its source paths ungoverned.",before:o});continue}!o||!l||(L(e,`${d}.patterns`,o.patterns,l.patterns,{added:"strengthening",removed:"weakening",addedMessage:"Additional paths are governed by this layer.",removedMessage:"Paths were removed from this layer and may become ungoverned."}),L(e,`${d}.exclude`,o.exclude,l.exclude,{added:"weakening",removed:"strengthening",addedMessage:"Additional paths are excluded from this layer.",removedMessage:"Fewer paths are excluded from this layer."}),L(e,`${d}.forbiddenGlobals`,o.forbiddenGlobals,l.forbiddenGlobals,{added:"strengthening",removed:"weakening",addedMessage:"Additional forbidden globals are enforced in this layer.",removedMessage:"A forbidden-global protection was removed from this layer."}),S(o.intentPrefixes).join("\0")!==S(l.intentPrefixes).join("\0")&&C(e,{kind:"intent-prefixes-changed",path:`${d}.intentPrefixes`,classification:"judgment-required",message:"Intent ownership changed and must be reviewed against publishers and consumers.",before:S(o.intentPrefixes),after:S(l.intentPrefixes)}),j(e,`${d}.mayImportInfrastructure`,o.mayImportInfrastructure===!0,l.mayImportInfrastructure===!0,"weakening","The layer may now import infrastructure directly.","Direct infrastructure imports are no longer allowed for this layer."),j(e,`${d}.optional`,o.optional===!0,l.optional===!0,"weakening","The layer is now optional and can be absent without a strict warning.","The layer is now required when its contract is active."))}}function Me(e,t,n){let r=o=>`${o.from}->${o.to}`,i=H(t,r),a=H(n,r);(i.duplicates.length>0||a.duplicates.length>0)&&C(e,{kind:"duplicate-rule",path:"$.rules",classification:"judgment-required",message:"Duplicate rule edges make the effective verdict order-dependent.",before:i.duplicates,after:a.duplicates});for(let o of[...new Set([...i.values.keys(),...a.values.keys()])].sort()){let l=i.values.get(o),d=a.values.get(o),u=`$.rules[${o}]`;if(!l&&d){d.allowed===!1&&C(e,{kind:"deny-added",path:u,classification:"strengthening",message:"A denied dependency edge was added.",after:d});continue}if(l&&!d){l.allowed===!1&&C(e,{kind:"deny-removed",path:u,classification:"weakening",message:"A denied dependency edge was removed.",before:l});continue}if(!l||!d)continue;l.allowed!==d.allowed&&C(e,{kind:d.allowed?"deny-disabled":"deny-enabled",path:`${u}.allowed`,classification:d.allowed?"weakening":"strengthening",message:d.allowed?"A previously denied dependency edge is now allowed.":"A dependency edge is now denied.",before:l.allowed,after:d.allowed});let m=l.peerIsolation===!0,g=d.peerIsolation===!0;if(m!==g){let s=l.from===l.to&&d.from===d.to;C(e,{kind:g?"peer-isolation-enabled":"peer-isolation-disabled",path:`${u}.peerIsolation`,classification:s?g?"strengthening":"weakening":"judgment-required",message:s?g?"Cross-slice dependencies inside this layer are now denied.":"Cross-slice dependencies inside this layer are no longer denied.":"Changing peer isolation on a cross-layer edge changes the denial scope.",before:m,after:g})}S(l.sliceFolders).join("\0")!==S(d.sliceFolders).join("\0")&&C(e,{kind:"slice-folders-changed",path:`${u}.sliceFolders`,classification:"judgment-required",message:"Slice ownership folders changed and can reclassify existing dependencies.",before:S(l.sliceFolders),after:S(d.sliceFolders)})}}function Ne(e,t,n){let r=t.safety??{},i=n.safety??{};for(let a of["maxTsSuppressions","maxAnyCasts"]){let o=r[a]??0,l=i[a]??0;o!==l&&C(e,{kind:l>o?"threshold-raised":"threshold-lowered",path:`$.safety.${a}`,classification:l>o?"weakening":"strengthening",message:l>o?"The safety threshold allows more violations.":"The safety threshold allows fewer violations.",before:o,after:l})}for(let a of["allowInMemory","allowDisabledPeerIsolation"])j(e,`$.safety.${a}`,r[a]===!0,i[a]===!0,"weakening","A safety exception was enabled.","A safety exception was disabled.")}function De(e){return e.some(t=>t.classification==="weakening")?"weakening":e.some(t=>t.classification==="judgment-required")?"judgment-required":e.some(t=>t.classification==="strengthening")?"strengthening":"neutral"}function fe(e,t){let n=[];L(n,"$.include",e.include,t.include,{added:"strengthening",removed:"weakening",addedMessage:"Additional project roots are governed.",removedMessage:"Project roots were removed from governance."}),L(n,"$.exclude",e.exclude,t.exclude,{added:"weakening",removed:"strengthening",addedMessage:"Additional project paths are excluded from governance.",removedMessage:"Fewer project paths are excluded from governance."}),L(n,"$.dynamicImportAllowlist",e.dynamicImportAllowlist,t.dynamicImportAllowlist,{added:"weakening",removed:"strengthening",addedMessage:"Additional files may use non-literal dynamic imports.",removedMessage:"Fewer files may use non-literal dynamic imports."}),j(n,"$.excludeGenerated",e.excludeGenerated!==!1,t.excludeGenerated!==!1,"weakening","Generated source is now excluded from governance.","Generated source is now governed.");let r={off:0,soft:1,"framework-soft":1,strict:2},i=e.cyclePolicy??"strict",a=t.cyclePolicy??"strict";if(i!==a){let o=r[a]===r[i]?"judgment-required":r[a]>r[i]?"strengthening":"weakening";C(n,{kind:"cycle-policy-changed",path:"$.cyclePolicy",classification:o,message:"The cycle enforcement level changed.",before:i,after:a})}return(e.frameworkOverlay??null)!==(t.frameworkOverlay??null)&&C(n,{kind:"framework-overlay-changed",path:"$.frameworkOverlay",classification:"judgment-required",message:"The framework overlay changed and may alter effective layer matching.",before:e.frameworkOverlay??null,after:t.frameworkOverlay??null}),_e(n,e.layers,t.layers),Me(n,e.rules,t.rules),Ne(n,e,t),n.sort((o,l)=>o.path.localeCompare(l.path)||o.id.localeCompare(l.id)),{schemaVersion:"1.0",classification:De(n),findings:n}}function ue(e,t){if(!e||e.schemaVersion!=="1.0"||typeof e.basePolicyHash!="string"||typeof e.candidatePolicyHash!="string"||typeof e.reason!="string"||!Array.isArray(e.findingIds)||e.findingIds.some(i=>typeof i!="string")||e.reason.trim().length===0||e.basePolicyHash!==t.basePolicyHash||e.candidatePolicyHash!==t.candidatePolicyHash)return!1;let n=S(e.findingIds),r=S(t.findingIds);return n.length===r.length&&n.every((i,a)=>i===r[a])}function k(e){return`${e.from}->${e.to}`}function N(e,t,n,r="dependency"){return{id:`${e}:${r}:${k(t)}`,classification:e,subject:"dependency",from:t.from,to:t.to,message:n,...e==="missing"?{nextAction:`Add the planned dependency ${k(t)} to the candidate, then preflight again.`}:e==="contradictory"?{nextAction:`Replace the reverse dependency with ${k(t)}, then preflight again.`}:e==="unplanned"?{nextAction:`Remove the unplanned dependency ${k(t)} from the candidate, then preflight again.`}:{}}}function J(e){let t=[],n=new Map(e.changeMap.map.files.map(s=>[s.path,s])),r=new Map(e.changes.map(s=>[s.path,s])),i=new Map(e.changeMap.map.dependencies.map(s=>[k(s),s])),a=new Map(e.baseDependencies.map(s=>[k(s),s])),o=new Map(e.candidateDependencies.map(s=>[k(s),s]));for(let s of[...n.values()].sort((c,p)=>c.path.localeCompare(p.path))){let c=r.get(s.path);c?c.operation!==s.operation?t.push({id:`contradictory:file:${s.path}`,classification:"contradictory",subject:"file",path:s.path,expectedOperation:s.operation,actualOperation:c.operation,message:`${s.path} was planned as ${s.operation} but the actual operation is ${c.operation}.`,nextAction:`Change ${s.path} to the planned ${s.operation} operation, then preflight again.`}):t.push({id:`satisfied:file:${s.path}`,classification:"satisfied",subject:"file",path:s.path,expectedOperation:s.operation,actualOperation:c.operation,message:`${s.path} matches the planned ${s.operation} operation.`}):t.push({id:`missing:file:${s.path}`,classification:"missing",subject:"file",path:s.path,expectedOperation:s.operation,message:`${s.path} was planned as ${s.operation} but is absent from the actual change.`,nextAction:`${s.operation[0].toUpperCase()}${s.operation.slice(1)} ${s.path} in the complete change set, then preflight again.`})}for(let s of[...r.values()].sort((c,p)=>c.path.localeCompare(p.path)))n.has(s.path)||t.push({id:`unplanned:file:${s.path}`,classification:"unplanned",subject:"file",path:s.path,actualOperation:s.operation,message:`${s.path} has an unplanned ${s.operation} operation.`,nextAction:`Remove ${s.path} from the change set, then preflight again.`});let l=new Set;for(let s of[...i.values()].sort((c,p)=>k(c).localeCompare(k(p)))){if(o.has(k(s))){t.push(N("satisfied",s,`${s.from} -> ${s.to} exists in the candidate architecture.`));continue}let c={from:s.to,to:s.from};o.has(k(c))?(l.add(k(c)),t.push(N("contradictory",s,`${s.from} -> ${s.to} was planned, but the candidate contains the reverse edge.`))):t.push(N("missing",s,`${s.from} -> ${s.to} is absent from the candidate architecture.`))}let d=new Set([...n.keys(),...r.keys()]);for(let[s,c]of[...o].sort(([p],[f])=>p.localeCompare(f)))a.has(s)||i.has(s)||l.has(s)||!d.has(c.from)&&!d.has(c.to)||t.push({...N("unplanned",c,`${c.from} -> ${c.to} was added without a matching planned dependency.`,"dependency-added"),actualOperation:"added"});let u=new Set(e.changeMap.map.files.filter(s=>s.operation==="delete").map(s=>s.path));for(let[s,c]of[...a].sort(([p],[f])=>p.localeCompare(f)))o.has(s)||u.has(c.from)||u.has(c.to)||!d.has(c.from)&&!d.has(c.to)||t.push({...N("unplanned",c,`${c.from} -> ${c.to} was removed without a planned file deletion.`,"dependency-removed"),actualOperation:"removed"});let m={satisfied:0,missing:1,contradictory:2,unplanned:3};t.sort((s,c)=>m[s.classification]-m[c.classification]||(s.subject===c.subject?0:s.subject==="file"?-1:1)||s.id.localeCompare(c.id));let g={satisfied:t.filter(s=>s.classification==="satisfied").length,missing:t.filter(s=>s.classification==="missing").length,contradictory:t.filter(s=>s.classification==="contradictory").length,unplanned:t.filter(s=>s.classification==="unplanned").length};return{schemaVersion:"1.0",readOnly:!0,changeMapHash:e.changeMap.hash,structurallyConverged:g.missing===0&&g.contradictory===0&&g.unplanned===0,behavioralCompletion:"not-evaluated",summary:g,findings:t}}function ge(e){switch(e.ruleId){case"LAYER_IMPORT_VIOLATION":return e.typeOnly||e.targetTypeOnlyExports||e.namedBindingsTypeOnly?"Move the referenced type to a mutually allowed layer, use `import type`, then preflight again.":e.peerIsolation?"Extract the shared dependency to a shared layer, then preflight again.":`Define a port in ${e.fromLayer??"the source layer"}, inject the ${e.toLayer??"outer-layer"} implementation, then preflight again.`;case"FORBIDDEN_GLOBAL":return`Inject ${e.target??"the capability"} through a port, then preflight again.`;case"CIRCULAR_DEPENDENCY":return"Extract the shared dependency into a third module, then preflight again.";case"RAW_EVENT_PUBLISH":return"Publish through a registered intent creator, then run Ark again.";case"PUBLISH_MISSING_SOURCE":return"Add metadata.source to the publish call, then run Ark again.";default:return`Resolve ${typeof e.ruleId=="string"&&e.ruleId.length>0?e.ruleId:"ARK_UNKNOWN"} without weakening ark.config.json, then run Ark again.`}}var Z="1.0";var V=class extends Error{issues;source;constructor(t,n){super(`Invalid architecture change map (${t}):
|
|
5
|
+
`)}`),this.name="ArchitectureChangeMapValidationError",this.source=t,this.issues=n}};function X(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function Q(e,t,n,r){for(let i of Object.keys(e))t.includes(i)||r.push({path:`${n}.${i}`,message:"unknown field"})}function O(e,t,n,r){let i=e[t];if(typeof i=="string"&&i.length>0)return i;r.push({path:`${n}.${t}`,message:"must be a non-empty string"})}function He(e){let t=e.replace(/\\/g,"/");if(!t||t.startsWith("/")||/^[A-Za-z]:\//.test(t)||t.includes("\0"))return;let n=[];for(let i of t.split("/"))if(!(!i||i==="."))if(i===".."){if(n.length===0)return;n.pop()}else n.push(i);let r=n.join("/");return r&&r===t?r:void 0}function Ve(e,t,n="architecture change map"){let r=[];if(!X(e))throw new V(n,[{path:"$",message:"must be an object"}]);Q(e,["$schema","schemaVersion","files","dependencies"],"$",r);let i=O(e,"$schema","$",r),a=O(e,"schemaVersion","$",r);a&&a!==Z&&r.push({path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(a)}; expected ${Z}`});let o=new Set(t.layers.map(d=>d.name)),l=[],p=new Set;!Array.isArray(e.files)||e.files.length===0?r.push({path:"$.files",message:"must be a non-empty array"}):e.files.forEach((d,f)=>{let y=`$.files[${f}]`;if(!X(d)){r.push({path:y,message:"must be an object"});return}Q(d,["path","operation","layer"],y,r);let m=O(d,"path",y,r),A=O(d,"operation",y,r),C=O(d,"layer",y,r),k=m?He(m):void 0;m&&!k&&r.push({path:`${y}.path`,message:"must be a canonical project-relative path"}),A&&!["create","update","delete"].includes(A)&&r.push({path:`${y}.operation`,message:"must be create, update, or delete"}),C&&!o.has(C)&&r.push({path:`${y}.layer`,message:`references unknown layer ${JSON.stringify(C)}`}),k&&p.has(k)&&r.push({path:`${y}.path`,message:`duplicates planned path ${k}`}),k&&p.add(k);let Y=k?L(k,t.layers):void 0;k&&C&&o.has(C)&&Y!==C&&r.push({path:`${y}.layer`,message:Y?`${k} resolves to ${Y}, not ${C}`:`${k} is not assigned to an architecture layer`}),k&&A&&["create","update","delete"].includes(A)&&C&&l.push({path:k,operation:A,layer:C})});let u=[],h=new Map(l.map(d=>[d.path,d.operation])),g=new Set,s=e.dependencies??[];if(Array.isArray(s)?s.forEach((d,f)=>{let y=`$.dependencies[${f}]`;if(!X(d)){r.push({path:y,message:"must be an object"});return}Q(d,["from","to"],y,r);let m=O(d,"from",y,r),A=O(d,"to",y,r);m&&!p.has(m)&&r.push({path:`${y}.from`,message:`must reference a planned file path: ${m}`}),A&&!p.has(A)&&r.push({path:`${y}.to`,message:`must reference a planned file path: ${A}`}),m&&h.get(m)==="delete"&&r.push({path:`${y}.from`,message:`cannot depend from deleted file ${m}`}),A&&h.get(A)==="delete"&&r.push({path:`${y}.to`,message:`cannot depend on deleted file ${A}`}),m&&A&&m===A&&r.push({path:y,message:"must not declare a self dependency"});let C=m&&A?`${m}\0${A}`:void 0;C&&g.has(C)&&r.push({path:y,message:`duplicates dependency ${m} -> ${A}`}),C&&g.add(C),m&&A&&u.push({from:m,to:A})}):r.push({path:"$.dependencies",message:"must be an array"}),r.length>0)throw new V(n,r);let c={$schema:i,schemaVersion:Z,files:l.sort((d,f)=>d.path.localeCompare(f.path)),dependencies:u.sort((d,f)=>d.from.localeCompare(f.from)||d.to.localeCompare(f.to))};return{map:c,hash:w(E(c))}}function S(e){return`${e.from}->${e.to}`}function F(e,t,n,r="dependency"){return{id:`${e}:${r}:${S(t)}`,classification:e,subject:"dependency",from:t.from,to:t.to,message:n,...e==="missing"?{nextAction:`Add the planned dependency ${S(t)} to the candidate, then preflight again.`}:e==="contradictory"?{nextAction:`Replace the reverse dependency with ${S(t)}, then preflight again.`}:e==="unplanned"?{nextAction:`Remove the unplanned dependency ${S(t)} from the candidate, then preflight again.`}:{}}}function ee(e){let t=[],n=new Map(e.changeMap.map.files.map(s=>[s.path,s])),r=new Map(e.changes.map(s=>[s.path,s])),i=new Map(e.changeMap.map.dependencies.map(s=>[S(s),s])),a=new Map(e.baseDependencies.map(s=>[S(s),s])),o=new Map(e.candidateDependencies.map(s=>[S(s),s]));for(let s of[...n.values()].sort((c,d)=>c.path.localeCompare(d.path))){let c=r.get(s.path);c?c.operation!==s.operation?t.push({id:`contradictory:file:${s.path}`,classification:"contradictory",subject:"file",path:s.path,expectedOperation:s.operation,actualOperation:c.operation,message:`${s.path} was planned as ${s.operation} but the actual operation is ${c.operation}.`,nextAction:`Change ${s.path} to the planned ${s.operation} operation, then preflight again.`}):t.push({id:`satisfied:file:${s.path}`,classification:"satisfied",subject:"file",path:s.path,expectedOperation:s.operation,actualOperation:c.operation,message:`${s.path} matches the planned ${s.operation} operation.`}):t.push({id:`missing:file:${s.path}`,classification:"missing",subject:"file",path:s.path,expectedOperation:s.operation,message:`${s.path} was planned as ${s.operation} but is absent from the actual change.`,nextAction:`${s.operation[0].toUpperCase()}${s.operation.slice(1)} ${s.path} in the complete change set, then preflight again.`})}for(let s of[...r.values()].sort((c,d)=>c.path.localeCompare(d.path)))n.has(s.path)||t.push({id:`unplanned:file:${s.path}`,classification:"unplanned",subject:"file",path:s.path,actualOperation:s.operation,message:`${s.path} has an unplanned ${s.operation} operation.`,nextAction:`Remove ${s.path} from the change set, then preflight again.`});let l=new Set;for(let s of[...i.values()].sort((c,d)=>S(c).localeCompare(S(d)))){if(o.has(S(s))){t.push(F("satisfied",s,`${s.from} -> ${s.to} exists in the candidate architecture.`));continue}let c={from:s.to,to:s.from};o.has(S(c))?(l.add(S(c)),t.push(F("contradictory",s,`${s.from} -> ${s.to} was planned, but the candidate contains the reverse edge.`))):t.push(F("missing",s,`${s.from} -> ${s.to} is absent from the candidate architecture.`))}let p=new Set([...n.keys(),...r.keys()]);for(let[s,c]of[...o].sort(([d],[f])=>d.localeCompare(f)))a.has(s)||i.has(s)||l.has(s)||!p.has(c.from)&&!p.has(c.to)||t.push({...F("unplanned",c,`${c.from} -> ${c.to} was added without a matching planned dependency.`,"dependency-added"),actualOperation:"added"});let u=new Set(e.changeMap.map.files.filter(s=>s.operation==="delete").map(s=>s.path));for(let[s,c]of[...a].sort(([d],[f])=>d.localeCompare(f)))o.has(s)||u.has(c.from)||u.has(c.to)||!p.has(c.from)&&!p.has(c.to)||t.push({...F("unplanned",c,`${c.from} -> ${c.to} was removed without a planned file deletion.`,"dependency-removed"),actualOperation:"removed"});let h={satisfied:0,missing:1,contradictory:2,unplanned:3};t.sort((s,c)=>h[s.classification]-h[c.classification]||(s.subject===c.subject?0:s.subject==="file"?-1:1)||s.id.localeCompare(c.id));let g={satisfied:t.filter(s=>s.classification==="satisfied").length,missing:t.filter(s=>s.classification==="missing").length,contradictory:t.filter(s=>s.classification==="contradictory").length,unplanned:t.filter(s=>s.classification==="unplanned").length};return{schemaVersion:"1.0",readOnly:!0,changeMapHash:e.changeMap.hash,structurallyConverged:g.missing===0&&g.contradictory===0&&g.unplanned===0,behavioralCompletion:"not-evaluated",summary:g,findings:t}}function _(e,t){return t&&e.isStringLiteralLike(t)?t.text:void 0}function Ce(e,t){return e.getLineAndCharacterOfPosition(t.getStart(e)).line+1}function Ae(e,t){if(e.isImportDeclaration(t)){let n=t.importClause;if(!n)return!1;if(n.isTypeOnly)return!0;let r=n.namedBindings;return!!(r&&e.isNamedImports(r)&&r.elements.length>0&&r.elements.every(i=>i.isTypeOnly))}if(e.isExportDeclaration(t)){if(t.isTypeOnly)return!0;let n=t.exportClause;return!!(n&&e.isNamedExports(n)&&n.elements.length>0&&n.elements.every(r=>r.isTypeOnly))}return!1}function Ie(e,t){let n={noLib:!0,noResolve:!0,target:e.ScriptTarget.Latest},r=e.createCompilerHost(n,!0);return r.getSourceFile=i=>i===t.fileName?t:void 0,r.fileExists=i=>i===t.fileName,r.readFile=i=>i===t.fileName?t.text:void 0,e.createProgram([t.fileName],n,r).getTypeChecker()}function te(e,t){try{return e.getSymbolAtLocation(t)}catch{return}}function ne(e,t,n,r){let i=r.parent&&e.isShorthandPropertyAssignment(r.parent)&&r.parent.name===r,a;try{a=i?t.getShorthandAssignmentValueSymbol(r.parent):te(t,r)}catch{a=void 0}return!!a?.declarations?.some(o=>o.getSourceFile().fileName===n.fileName)}function re(e,t){let n,r=[],i=(o,l,p,u=!1)=>r.push({specifier:p,kind:l,line:Ce(t,o),typeOnly:u,unresolved:p===void 0,node:o}),a=o=>{if(e.isImportDeclaration(o))i(o,"import",_(e,o.moduleSpecifier),Ae(e,o));else if(e.isExportDeclaration(o)&&o.moduleSpecifier)i(o,"export",_(e,o.moduleSpecifier),Ae(e,o));else if(e.isImportEqualsDeclaration(o)&&e.isExternalModuleReference(o.moduleReference))i(o,"require",_(e,o.moduleReference.expression));else if(e.isCallExpression(o)){let l=o.expression.kind===e.SyntaxKind.ImportKeyword,u=e.isIdentifier(o.expression)&&o.expression.text==="require"&&!ne(e,n??(n=Ie(e,t)),t,o.expression);(l||u)&&i(o,u?"require":"dynamic-import",_(e,o.arguments[0]))}e.forEachChild(o,a)};return a(t),r}function Ge(e,t){let n=[],r=t;for(;e.isPropertyAccessExpression(r)||e.isElementAccessExpression(r);){if(e.isPropertyAccessExpression(r))n.unshift(r.name.text);else{let i=_(e,r.argumentExpression);if(i===void 0)return;n.unshift(i)}r=r.expression}if(e.isIdentifier(r))return n.unshift(r.text),{root:r,segments:n}}function Ue(e,t){let n=t.parent;return e.isPropertyAccessExpression(n)||e.isElementAccessExpression(n)?!1:e.isExpressionNode(t)&&!e.isInTypeQuery(t)||e.isShorthandPropertyAssignment(n)&&n.name===t}function be(e,t){let n=t[0]==="globalThis"?t.slice(1):t;for(let r=n.length;r>=1;r-=1){let i=n.slice(0,r).join(".");if(e.has(i))return i}}function ie(e,t,n){if(n.length===0)return[];let r=new Set(n),i=Ie(e,t),a=new Map,o=new Set;for(let s of t.statements)if(e.isVariableStatement(s))for(let c of s.declarationList.declarations)e.isIdentifier(c.name)&&o.add(c.name.text);let l=s=>{let c=Ge(e,s);if(!c)return;let d=te(i,c.root),f=d?a.get(d):void 0;return f?[...f,...c.segments.slice(1)]:ne(e,i,t,c.root)||o.has(c.root.text)?void 0:c.segments};for(let s of t.statements)if(e.isVariableStatement(s))for(let c of s.declarationList.declarations){if(!c.initializer||!e.isIdentifier(c.name))continue;let d=l(c.initializer),f=te(i,c.name);!d||!f||a.set(f,d)}let p=[],u=new Set,h=(s,c)=>{let d=Ce(t,c),f=`${s}:${c.getStart(t)}`;u.has(f)||(u.add(f),p.push({name:s,line:d,node:c}))},g=s=>{let c=s.parent&&(e.isPropertyAccessExpression(s.parent)||e.isElementAccessExpression(s.parent))&&s.parent.expression===s;if((e.isPropertyAccessExpression(s)||e.isElementAccessExpression(s))&&!c){let d=l(s),f=d?be(r,d):void 0;f&&h(f,s)}else e.isIdentifier(s)&&r.has(s.text)&&Ue(e,s)&&!ne(e,i,t,s)&&h(s.text,s);if(e.isVariableDeclaration(s)&&e.isObjectBindingPattern(s.name)&&s.initializer){let d=l(s.initializer);if(d)for(let f of s.name.elements){if(!e.isIdentifier(f.name))continue;let y=f.propertyName?_(e,f.propertyName)??f.propertyName.text:f.name.text,m=be(r,[...d,y]);m&&h(m,s.initializer)}}e.forEachChild(s,g)};return g(t),p}var ae={RAW_EVENT_PUBLISH:"Publish through a registered intent creator; raw event objects or intent strings bypass Ark contracts and tooling.",PUBLISH_MISSING_SOURCE:"Strict Ark publish calls must include metadata.source."};function ke(e){return/^(Domain|Application|Adapter|Workflow|Job|Presentation|Reporting|Metadata|Security|Audit|Observability|Kernel)\.[A-Za-z0-9_.]+$/.test(e)}function Be(e){if(!e.publishCall)return[];let t=[];return(e.rawIntentName!==void 0&&ke(e.rawIntentName)||e.objectHasIntent)&&t.push({ruleId:"RAW_EVENT_PUBLISH",message:ae.RAW_EVENT_PUBLISH}),e.arkPublishCandidate&&!e.hasSource&&t.push({ruleId:"PUBLISH_MISSING_SOURCE",message:ae.PUBLISH_MISSING_SOURCE}),t}var ze=Object.freeze(["network","filesystem","clock","randomness","environment","process","persistence"]),oe=Object.freeze({fetch:"network",XMLHttpRequest:"network",Date:"clock","Date.now":"clock","Math.random":"randomness","process.env":"environment",process:"process"}),ce=Object.freeze(Object.keys(oe).sort()),se=Object.freeze({fs:"filesystem","node:fs":"filesystem","fs/promises":"filesystem","node:fs/promises":"filesystem","fs-extra":"filesystem","graceful-fs":"filesystem",memfs:"filesystem",chokidar:"filesystem",http:"network",https:"network",http2:"network",net:"network",tls:"network",dgram:"network",dns:"network","node:http":"network","node:https":"network","node:http2":"network","node:net":"network","node:tls":"network","node:dgram":"network","node:dns":"network",axios:"network",undici:"network","node-fetch":"network",got:"network",ky:"network",superagent:"network",ws:"network",process:"process","node:process":"process",child_process:"process","node:child_process":"process","@prisma/client":"persistence",prisma:"persistence",pg:"persistence",mysql:"persistence",mysql2:"persistence",mongodb:"persistence",mongoose:"persistence",sqlite3:"persistence","better-sqlite3":"persistence",redis:"persistence",ioredis:"persistence",typeorm:"persistence",knex:"persistence","drizzle-orm":"persistence",sequelize:"persistence",kysely:"persistence","@supabase/supabase-js":"persistence"});function j(e){if(!e||e.startsWith(".")||e.startsWith("/"))return null;let t=se[e];if(t)return t;let n=e.indexOf("/");if(n<0)return null;let r=e.slice(0,n),i=se[r];if(i)return i;let a=e.indexOf("/",n+1);return a<0?null:se[e.slice(0,a)]??null}function G(e){let t=e.split(".");for(let n=t.length;n>=1;n-=1){let r=t.slice(0,n).join("."),i=oe[r];if(i)return i}return null}function qe(e){let t=new Set,n=G(e);n&&t.add(n);for(let[r,i]of Object.entries(oe))(r===e||r.startsWith(`${e}.`))&&t.add(i);return[...t].sort()}function Ke(e,t){let n=[];for(let r of re(e,t)){if(r.typeOnly||!r.specifier)continue;let i=j(r.specifier);i&&n.push({capability:i,symbol:r.specifier,line:r.line,source:"import-based"})}for(let r of ie(e,t,ce)){let i=G(r.name);i&&n.push({capability:i,symbol:r.name,line:r.line,source:"ambient-global"})}return n.sort((r,i)=>r.line-i.line||r.capability.localeCompare(i.capability)||r.symbol.localeCompare(i.symbol))}var pe="https://unpkg.com/arkgate@2/schemas/ark.config.schema.json",Se=["DomainModel","ApplicationOrchestration","PersistenceAdapters","IntegrationAdapters","WorkflowSagaEngine","BackgroundJobsScheduling","PresentationAdapters","ReportingReadModels","ExtensibilityMetadata","SecurityAuditObservability","Kernel"],Ye=new Set(["PresentationAdapters->ApplicationOrchestration","ApplicationOrchestration->DomainModel","WorkflowSagaEngine->ApplicationOrchestration","WorkflowSagaEngine->DomainModel","BackgroundJobsScheduling->ApplicationOrchestration"]);function We(){let e=[];for(let t of Se)for(let n of Se)t===n||Ye.has(`${t}->${n}`)||e.push({from:t,to:n,allowed:!1});return e}var Ee=We();var $={type:"array",items:{type:"string",minLength:1},uniqueItems:!0},xe={$schema:"https://json-schema.org/draft/2020-12/schema",$id:pe,title:"ArkGate architecture contract",description:"Versioned contract consumed identically by ArkGate CLI, MCP, and ESLint surfaces.",type:"object",additionalProperties:!1,required:["$schema","schemaVersion","include","layers","rules"],properties:{$schema:{type:"string",minLength:1,default:pe,description:"Editor-facing URL or local path for this JSON Schema."},schemaVersion:{type:"string",const:"1.0",default:"1.0"},name:{type:"string",minLength:1},include:{...$,minItems:1,default:["src"]},exclude:{...$,default:[]},excludeGenerated:{type:"boolean",default:!0},frameworkOverlay:{type:"string",minLength:1},layers:{type:"array",default:[],items:{$ref:"#/$defs/layer"}},rules:{type:"array",default:Ee,items:{$ref:"#/$defs/rule"}},cyclePolicy:{type:"string",enum:["strict","soft","framework-soft","off"],default:"strict"},dynamicImportAllowlist:{...$,default:[]},safety:{$ref:"#/$defs/safety",default:{maxTsSuppressions:0,maxAnyCasts:0,allowInMemory:!1,allowDisabledPeerIsolation:!1}}},$defs:{layer:{type:"object",additionalProperties:!1,required:["name","patterns"],properties:{name:{type:"string",minLength:1},patterns:{...$,minItems:1},exclude:$,intentPrefixes:$,description:{type:"string",minLength:1},forbiddenGlobals:$,mayImportInfrastructure:{type:"boolean"},optional:{type:"boolean"}}},rule:{type:"object",additionalProperties:!1,required:["from","to","allowed"],properties:{from:{type:"string",minLength:1},to:{type:"string",minLength:1},allowed:{type:"boolean"},message:{type:"string",minLength:1},peerIsolation:{type:"boolean"},sliceFolders:{...$,minItems:1}}},safety:{type:"object",additionalProperties:!1,properties:{maxTsSuppressions:{type:"integer",minimum:0,default:0},maxAnyCasts:{type:"integer",minimum:0,default:0},allowInMemory:{type:"boolean",default:!1},allowDisabledPeerIsolation:{type:"boolean",default:!1}}}}},M=class extends Error{issues;source;constructor(t,n){super(`Invalid ArkGate config (${t}):
|
|
6
6
|
${n.map(r=>`- ${r.path}: ${r.message}`).join(`
|
|
7
|
-
`)}`),this.name="ArchitectureChangeMapValidationError",this.source=t,this.issues=n}};function Q(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function X(e,t,n,r){for(let i of Object.keys(e))t.includes(i)||r.push({path:`${n}.${i}`,message:"unknown field"})}function O(e,t,n,r){let i=e[t];if(typeof i=="string"&&i.length>0)return i;r.push({path:`${n}.${t}`,message:"must be a non-empty string"})}function Te(e){let t=e.replace(/\\/g,"/");if(!t||t.startsWith("/")||/^[A-Za-z]:\//.test(t)||t.includes("\0"))return;let n=[];for(let i of t.split("/"))if(!(!i||i==="."))if(i===".."){if(n.length===0)return;n.pop()}else n.push(i);let r=n.join("/");return r&&r===t?r:void 0}function Fe(e,t,n="architecture change map"){let r=[];if(!Q(e))throw new V(n,[{path:"$",message:"must be an object"}]);X(e,["$schema","schemaVersion","files","dependencies"],"$",r);let i=O(e,"$schema","$",r),a=O(e,"schemaVersion","$",r);a&&a!==Z&&r.push({path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(a)}; expected ${Z}`});let o=new Set(t.layers.map(p=>p.name)),l=[],d=new Set;!Array.isArray(e.files)||e.files.length===0?r.push({path:"$.files",message:"must be a non-empty array"}):e.files.forEach((p,f)=>{let h=`$.files[${f}]`;if(!Q(p)){r.push({path:h,message:"must be an object"});return}X(p,["path","operation","layer"],h,r);let y=O(p,"path",h,r),A=O(p,"operation",h,r),b=O(p,"layer",h,r),x=y?Te(y):void 0;y&&!x&&r.push({path:`${h}.path`,message:"must be a canonical project-relative path"}),A&&!["create","update","delete"].includes(A)&&r.push({path:`${h}.operation`,message:"must be create, update, or delete"}),b&&!o.has(b)&&r.push({path:`${h}.layer`,message:`references unknown layer ${JSON.stringify(b)}`}),x&&d.has(x)&&r.push({path:`${h}.path`,message:`duplicates planned path ${x}`}),x&&d.add(x);let U=x?M(x,t.layers):void 0;x&&b&&o.has(b)&&U!==b&&r.push({path:`${h}.layer`,message:U?`${x} resolves to ${U}, not ${b}`:`${x} is not assigned to an architecture layer`}),x&&A&&["create","update","delete"].includes(A)&&b&&l.push({path:x,operation:A,layer:b})});let u=[],m=new Map(l.map(p=>[p.path,p.operation])),g=new Set,s=e.dependencies??[];if(Array.isArray(s)?s.forEach((p,f)=>{let h=`$.dependencies[${f}]`;if(!Q(p)){r.push({path:h,message:"must be an object"});return}X(p,["from","to"],h,r);let y=O(p,"from",h,r),A=O(p,"to",h,r);y&&!d.has(y)&&r.push({path:`${h}.from`,message:`must reference a planned file path: ${y}`}),A&&!d.has(A)&&r.push({path:`${h}.to`,message:`must reference a planned file path: ${A}`}),y&&m.get(y)==="delete"&&r.push({path:`${h}.from`,message:`cannot depend from deleted file ${y}`}),A&&m.get(A)==="delete"&&r.push({path:`${h}.to`,message:`cannot depend on deleted file ${A}`}),y&&A&&y===A&&r.push({path:h,message:"must not declare a self dependency"});let b=y&&A?`${y}\0${A}`:void 0;b&&g.has(b)&&r.push({path:h,message:`duplicates dependency ${y} -> ${A}`}),b&&g.add(b),y&&A&&u.push({from:y,to:A})}):r.push({path:"$.dependencies",message:"must be an array"}),r.length>0)throw new V(n,r);let c={$schema:i,schemaVersion:Z,files:l.sort((p,f)=>p.path.localeCompare(f.path)),dependencies:u.sort((p,f)=>p.from.localeCompare(f.from)||p.to.localeCompare(f.to))};return{map:c,hash:$(E(c))}}function v(e,t){return t&&e.isStringLiteralLike(t)?t.text:void 0}function me(e,t){return e.getLineAndCharacterOfPosition(t.getStart(e)).line+1}function he(e,t){if(e.isImportDeclaration(t)){let n=t.importClause;if(!n)return!1;if(n.isTypeOnly)return!0;let r=n.namedBindings;return!!(r&&e.isNamedImports(r)&&r.elements.length>0&&r.elements.every(i=>i.isTypeOnly))}if(e.isExportDeclaration(t)){if(t.isTypeOnly)return!0;let n=t.exportClause;return!!(n&&e.isNamedExports(n)&&n.elements.length>0&&n.elements.every(r=>r.isTypeOnly))}return!1}function Ae(e,t){let n={noLib:!0,noResolve:!0,target:e.ScriptTarget.Latest},r=e.createCompilerHost(n,!0);return r.getSourceFile=i=>i===t.fileName?t:void 0,r.fileExists=i=>i===t.fileName,r.readFile=i=>i===t.fileName?t.text:void 0,e.createProgram([t.fileName],n,r).getTypeChecker()}function ee(e,t){try{return e.getSymbolAtLocation(t)}catch{return}}function te(e,t,n,r){let i=r.parent&&e.isShorthandPropertyAssignment(r.parent)&&r.parent.name===r,a;try{a=i?t.getShorthandAssignmentValueSymbol(r.parent):ee(t,r)}catch{a=void 0}return!!a?.declarations?.some(o=>o.getSourceFile().fileName===n.fileName)}function je(e,t){let n,r=[],i=(o,l,d,u=!1)=>r.push({specifier:d,kind:l,line:me(t,o),typeOnly:u,unresolved:d===void 0,node:o}),a=o=>{if(e.isImportDeclaration(o))i(o,"import",v(e,o.moduleSpecifier),he(e,o));else if(e.isExportDeclaration(o)&&o.moduleSpecifier)i(o,"export",v(e,o.moduleSpecifier),he(e,o));else if(e.isImportEqualsDeclaration(o)&&e.isExternalModuleReference(o.moduleReference))i(o,"require",v(e,o.moduleReference.expression));else if(e.isCallExpression(o)){let l=o.expression.kind===e.SyntaxKind.ImportKeyword,u=e.isIdentifier(o.expression)&&o.expression.text==="require"&&!te(e,n??(n=Ae(e,t)),t,o.expression);(l||u)&&i(o,u?"require":"dynamic-import",v(e,o.arguments[0]))}e.forEachChild(o,a)};return a(t),r}function He(e,t){let n=[],r=t;for(;e.isPropertyAccessExpression(r)||e.isElementAccessExpression(r);){if(e.isPropertyAccessExpression(r))n.unshift(r.name.text);else{let i=v(e,r.argumentExpression);if(i===void 0)return;n.unshift(i)}r=r.expression}if(e.isIdentifier(r))return n.unshift(r.text),{root:r,segments:n}}function Ve(e,t){let n=t.parent;return e.isPropertyAccessExpression(n)||e.isElementAccessExpression(n)?!1:e.isExpressionNode(t)&&!e.isInTypeQuery(t)||e.isShorthandPropertyAssignment(n)&&n.name===t}function ye(e,t){let n=t[0]==="globalThis"?t.slice(1):t;for(let r=n.length;r>=1;r-=1){let i=n.slice(0,r).join(".");if(e.has(i))return i}}function Ge(e,t,n){if(n.length===0)return[];let r=new Set(n),i=Ae(e,t),a=new Map,o=new Set;for(let s of t.statements)if(e.isVariableStatement(s))for(let c of s.declarationList.declarations)e.isIdentifier(c.name)&&o.add(c.name.text);let l=s=>{let c=He(e,s);if(!c)return;let p=ee(i,c.root),f=p?a.get(p):void 0;return f?[...f,...c.segments.slice(1)]:te(e,i,t,c.root)||o.has(c.root.text)?void 0:c.segments};for(let s of t.statements)if(e.isVariableStatement(s))for(let c of s.declarationList.declarations){if(!c.initializer||!e.isIdentifier(c.name))continue;let p=l(c.initializer),f=ee(i,c.name);!p||!f||a.set(f,p)}let d=[],u=new Set,m=(s,c)=>{let p=me(t,c),f=`${s}:${c.getStart(t)}`;u.has(f)||(u.add(f),d.push({name:s,line:p,node:c}))},g=s=>{let c=s.parent&&(e.isPropertyAccessExpression(s.parent)||e.isElementAccessExpression(s.parent))&&s.parent.expression===s;if((e.isPropertyAccessExpression(s)||e.isElementAccessExpression(s))&&!c){let p=l(s),f=p?ye(r,p):void 0;f&&m(f,s)}else e.isIdentifier(s)&&r.has(s.text)&&Ve(e,s)&&!te(e,i,t,s)&&m(s.text,s);if(e.isVariableDeclaration(s)&&e.isObjectBindingPattern(s.name)&&s.initializer){let p=l(s.initializer);if(p)for(let f of s.name.elements){if(!e.isIdentifier(f.name))continue;let h=f.propertyName?v(e,f.propertyName)??f.propertyName.text:f.name.text,y=ye(r,[...p,h]);y&&m(y,s.initializer)}}e.forEachChild(s,g)};return g(t),d}var ne={RAW_EVENT_PUBLISH:"Publish through a registered intent creator; raw event objects or intent strings bypass Ark contracts and tooling.",PUBLISH_MISSING_SOURCE:"Strict Ark publish calls must include metadata.source."};function Ce(e){return/^(Domain|Application|Adapter|Workflow|Job|Presentation|Reporting|Metadata|Security|Audit|Observability|Kernel)\.[A-Za-z0-9_.]+$/.test(e)}function Ue(e){if(!e.publishCall)return[];let t=[];return(e.rawIntentName!==void 0&&Ce(e.rawIntentName)||e.objectHasIntent)&&t.push({ruleId:"RAW_EVENT_PUBLISH",message:ne.RAW_EVENT_PUBLISH}),e.arkPublishCandidate&&!e.hasSource&&t.push({ruleId:"PUBLISH_MISSING_SOURCE",message:ne.PUBLISH_MISSING_SOURCE}),t}function be(e,t){let n=typeof e=="string"?ce(e,t):q(e,t);return{...n,policyHash:$(E(n.config))}}function mt(e){let t=be(e.baseConfig,e.baseSource??"base ark.config.json"),n=be(e.candidateConfig,e.candidateSource??"candidate ark.config.json"),r=fe(t.config,n.config),i=r.findings.filter(l=>l.classification==="weakening"||l.classification==="judgment-required").map(l=>l.id).sort(),a=i.length>0,o=a&&ue(e.acknowledgement,{basePolicyHash:t.policyHash,candidatePolicyHash:n.policyHash,findingIds:i});return{schemaVersion:r.schemaVersion,basePolicyHash:t.policyHash,candidatePolicyHash:n.policyHash,classification:r.classification,findings:r.findings,blockingFindingIds:i,requiresAcknowledgement:a,acknowledged:o,valid:!a||o}}function T(e){let t=[];for(let n of e.replace(/\\/g,"/").split("/"))!n||n==="."||(n===".."&&t.length>0&&t.at(-1)!==".."?t.pop():t.push(n));return t.join("/")}function Ie(e){return e!==void 0&&/[A-Za-z0-9_$]/.test(e)}function re(e,t){for(;t<e.length&&/\s/.test(e[t]);)t+=1;return t}function G(e,t){let n=e[t];if(n!=="'"&&n!=='"')return;let r=t,i="";for(t+=1;t<e.length;t+=1){let a=e[t];if(a===n)return{value:i,offset:r,excerpt:e.slice(r,t+1)};a==="\\"&&t+1<e.length?(i+=e[t+1],t+=1):i+=a}}function D(e,t,n){return e.startsWith(t,n)&&!Ie(e[n-1])&&!Ie(e[n+t.length])}function Ke(e,t){return t=re(e,t+6),e[t]==="("?G(e,re(e,t+1)):Se(e,t,!0)}function qe(e,t){return Se(e,t+6,!1)}function Se(e,t,n){for(;t<e.length;t+=1){if(e[t]===";")return;if(D(e,"from",t))return G(e,re(e,t+4));if(n&&(e[t]==="'"||e[t]==='"'))return G(e,t);if(t>0&&(D(e,"import",t)||D(e,"export",t)))return}}function ze(e){let t=[];for(let n=0;n<e.length;n+=1){let r=e[n];if(r==="/"&&e[n+1]==="/"){if(n=e.indexOf(`
|
|
8
|
-
`,n+2),n<0)break;continue}if(r==="/"&&e[n+1]==="*"){let a=e.indexOf("*/",n+2);if(a<0)break;n=a+1;continue}if(r==="'"||r==='"'||r==="`"){let a=
|
|
9
|
-
`).length
|
|
7
|
+
`)}`),this.name="ArkConfigValidationError",this.source=t,this.issues=n}};function we(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function le(e,t){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(t)?`${e}.${t}`:`${e}[${JSON.stringify(t)}]`}function v(e){return e===null?"null":Array.isArray(e)?"array":typeof e}function Je(e,t){let n="#/$defs/";if(e.startsWith(n))return t.$defs[e.slice(n.length)]}function U(e,t,n,r,i){if(t.$ref){let a=Je(t.$ref,r);if(!a){i.push({path:n,message:`schema reference ${t.$ref} cannot be resolved`});return}U(e,a,n,r,i);return}if(t.const!==void 0&&!Object.is(e,t.const)){i.push({path:n,message:`must equal ${JSON.stringify(t.const)}`});return}if(t.enum&&!t.enum.some(a=>Object.is(a,e))){i.push({path:n,message:`must be one of ${t.enum.map(String).join(", ")}`});return}if(t.type==="object"){if(!we(e)){i.push({path:n,message:`must be an object; received ${v(e)}`});return}let a=t.properties??{};for(let o of t.required??[])e[o]===void 0&&i.push({path:le(n,o),message:"is required"});if(t.additionalProperties===!1)for(let o of Object.keys(e))o in a||i.push({path:le(n,o),message:"unknown field"});for(let[o,l]of Object.entries(a))e[o]!==void 0&&U(e[o],l,le(n,o),r,i);return}if(t.type==="array"){if(!Array.isArray(e)){i.push({path:n,message:`must be an array; received ${v(e)}`});return}if(t.minItems!==void 0&&e.length<t.minItems&&i.push({path:n,message:`must contain at least ${t.minItems} item(s)`}),t.uniqueItems){let a=e.map(o=>JSON.stringify(o));new Set(a).size!==a.length&&i.push({path:n,message:"must not contain duplicate items"})}t.items&&e.forEach((a,o)=>U(a,t.items,`${n}[${o}]`,r,i));return}if(t.type==="string"){if(typeof e!="string"){i.push({path:n,message:`must be a string; received ${v(e)}`});return}t.minLength!==void 0&&e.length<t.minLength&&i.push({path:n,message:`must contain at least ${t.minLength} character(s)`});return}if(t.type==="boolean"){typeof e!="boolean"&&i.push({path:n,message:`must be a boolean; received ${v(e)}`});return}if(t.type==="integer"){if(!Number.isInteger(e)){i.push({path:n,message:`must be an integer; received ${v(e)}`});return}t.minimum!==void 0&&e<t.minimum&&i.push({path:n,message:`must be at least ${t.minimum}`})}}function Ze(e){return{...e,$schema:e.$schema===void 0?pe:e.$schema,schemaVersion:e.schemaVersion===void 0?"1.0":e.schemaVersion,include:e.include===void 0?["src"]:e.include,layers:e.layers===void 0?[]:e.layers,rules:e.rules===void 0?Ee.map(t=>({...t})):e.rules}}function Xe(e,t="ark.config.json"){if(!we(e))throw new M(t,[{path:"$",message:`must be an object; received ${v(e)}`}]);let n=e.schemaVersion===void 0?"unversioned":null;if(e.schemaVersion!==void 0&&e.schemaVersion!=="1.0")throw new M(t,[{path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(e.schemaVersion)}; expected 1.0`}]);return{candidate:Ze(e),migratedFrom:n}}function de(e,t="ark.config.json"){let{candidate:n,migratedFrom:r}=Xe(e,t),i=[];if(U(n,xe,"$",xe,i),i.length>0)throw new M(t,i);return{config:n,migratedFrom:r}}function $e(e,t="ark.config.json"){let n;try{n=JSON.parse(e)}catch(r){throw new M(t,[{path:"$",message:`invalid JSON: ${r instanceof Error?r.message:String(r)}`}])}return de(n,t)}function b(e,t){e.push({id:`${t.classification}:${t.path}:${t.kind}`,path:t.path,classification:t.classification,message:t.message,...t.classification==="weakening"||t.classification==="judgment-required"?{nextAction:`Restore the previous protection at ${t.path}, then run ArkGate again.`}:{},...t.before===void 0?{}:{before:t.before},...t.after===void 0?{}:{after:t.after}})}function x(e){return[...new Set(e??[])].sort()}function N(e,t,n,r,i){let a=x(n),o=x(r),l=new Set(a),p=new Set(o),u=o.filter(g=>!l.has(g)),h=a.filter(g=>!p.has(g));u.length===0&&h.length===0||(u.length>0&&b(e,{kind:"added",path:t,classification:i.added,message:i.addedMessage,before:a,after:o}),h.length>0&&b(e,{kind:"removed",path:t,classification:i.removed,message:i.removedMessage,before:a,after:o}))}function B(e,t,n,r,i,a,o){if(n===r)return;b(e,{kind:r?"enabled":"disabled",path:t,classification:r?i:i==="strengthening"?"weakening":"strengthening",message:r?a:o,before:n,after:r})}function z(e,t){let n=new Map,r=new Set;for(let i of e){let a=t(i);n.has(a)?r.add(a):n.set(a,i)}return{values:n,duplicates:[...r].sort()}}function Qe(e,t,n){let r=z(t,a=>a.name),i=z(n,a=>a.name);(r.duplicates.length>0||i.duplicates.length>0)&&b(e,{kind:"duplicate-layer",path:"$.layers",classification:"judgment-required",message:"Duplicate layer names make policy ownership ambiguous.",before:r.duplicates,after:i.duplicates});for(let a of[...new Set([...r.values.keys(),...i.values.keys()])].sort()){let o=r.values.get(a),l=i.values.get(a),p=`$.layers[${a}]`;if(!o&&l){b(e,{kind:"layer-added",path:p,classification:"judgment-required",message:"A layer was added; verify overlap, ownership, and rule coverage.",after:l});continue}if(o&&!l){b(e,{kind:"layer-removed",path:p,classification:"weakening",message:"Removing a layer can leave its source paths ungoverned.",before:o});continue}!o||!l||(N(e,`${p}.patterns`,o.patterns,l.patterns,{added:"strengthening",removed:"weakening",addedMessage:"Additional paths are governed by this layer.",removedMessage:"Paths were removed from this layer and may become ungoverned."}),N(e,`${p}.exclude`,o.exclude,l.exclude,{added:"weakening",removed:"strengthening",addedMessage:"Additional paths are excluded from this layer.",removedMessage:"Fewer paths are excluded from this layer."}),N(e,`${p}.forbiddenGlobals`,o.forbiddenGlobals,l.forbiddenGlobals,{added:"strengthening",removed:"weakening",addedMessage:"Additional forbidden globals are enforced in this layer.",removedMessage:"A forbidden-global protection was removed from this layer."}),x(o.intentPrefixes).join("\0")!==x(l.intentPrefixes).join("\0")&&b(e,{kind:"intent-prefixes-changed",path:`${p}.intentPrefixes`,classification:"judgment-required",message:"Intent ownership changed and must be reviewed against publishers and consumers.",before:x(o.intentPrefixes),after:x(l.intentPrefixes)}),B(e,`${p}.mayImportInfrastructure`,o.mayImportInfrastructure===!0,l.mayImportInfrastructure===!0,"weakening","The layer may now import infrastructure directly.","Direct infrastructure imports are no longer allowed for this layer."),B(e,`${p}.optional`,o.optional===!0,l.optional===!0,"weakening","The layer is now optional and can be absent without a strict warning.","The layer is now required when its contract is active."))}}function et(e,t,n){let r=o=>`${o.from}->${o.to}`,i=z(t,r),a=z(n,r);(i.duplicates.length>0||a.duplicates.length>0)&&b(e,{kind:"duplicate-rule",path:"$.rules",classification:"judgment-required",message:"Duplicate rule edges make the effective verdict order-dependent.",before:i.duplicates,after:a.duplicates});for(let o of[...new Set([...i.values.keys(),...a.values.keys()])].sort()){let l=i.values.get(o),p=a.values.get(o),u=`$.rules[${o}]`;if(!l&&p){p.allowed===!1&&b(e,{kind:"deny-added",path:u,classification:"strengthening",message:"A denied dependency edge was added.",after:p});continue}if(l&&!p){l.allowed===!1&&b(e,{kind:"deny-removed",path:u,classification:"weakening",message:"A denied dependency edge was removed.",before:l});continue}if(!l||!p)continue;l.allowed!==p.allowed&&b(e,{kind:p.allowed?"deny-disabled":"deny-enabled",path:`${u}.allowed`,classification:p.allowed?"weakening":"strengthening",message:p.allowed?"A previously denied dependency edge is now allowed.":"A dependency edge is now denied.",before:l.allowed,after:p.allowed});let h=l.peerIsolation===!0,g=p.peerIsolation===!0;if(h!==g){let s=l.from===l.to&&p.from===p.to;b(e,{kind:g?"peer-isolation-enabled":"peer-isolation-disabled",path:`${u}.peerIsolation`,classification:s?g?"strengthening":"weakening":"judgment-required",message:s?g?"Cross-slice dependencies inside this layer are now denied.":"Cross-slice dependencies inside this layer are no longer denied.":"Changing peer isolation on a cross-layer edge changes the denial scope.",before:h,after:g})}x(l.sliceFolders).join("\0")!==x(p.sliceFolders).join("\0")&&b(e,{kind:"slice-folders-changed",path:`${u}.sliceFolders`,classification:"judgment-required",message:"Slice ownership folders changed and can reclassify existing dependencies.",before:x(l.sliceFolders),after:x(p.sliceFolders)})}}function tt(e,t,n){let r=t.safety??{},i=n.safety??{};for(let a of["maxTsSuppressions","maxAnyCasts"]){let o=r[a]??0,l=i[a]??0;o!==l&&b(e,{kind:l>o?"threshold-raised":"threshold-lowered",path:`$.safety.${a}`,classification:l>o?"weakening":"strengthening",message:l>o?"The safety threshold allows more violations.":"The safety threshold allows fewer violations.",before:o,after:l})}for(let a of["allowInMemory","allowDisabledPeerIsolation"])B(e,`$.safety.${a}`,r[a]===!0,i[a]===!0,"weakening","A safety exception was enabled.","A safety exception was disabled.")}function nt(e){return e.some(t=>t.classification==="weakening")?"weakening":e.some(t=>t.classification==="judgment-required")?"judgment-required":e.some(t=>t.classification==="strengthening")?"strengthening":"neutral"}function Re(e,t){let n=[];N(n,"$.include",e.include,t.include,{added:"strengthening",removed:"weakening",addedMessage:"Additional project roots are governed.",removedMessage:"Project roots were removed from governance."}),N(n,"$.exclude",e.exclude,t.exclude,{added:"weakening",removed:"strengthening",addedMessage:"Additional project paths are excluded from governance.",removedMessage:"Fewer project paths are excluded from governance."}),N(n,"$.dynamicImportAllowlist",e.dynamicImportAllowlist,t.dynamicImportAllowlist,{added:"weakening",removed:"strengthening",addedMessage:"Additional files may use non-literal dynamic imports.",removedMessage:"Fewer files may use non-literal dynamic imports."}),B(n,"$.excludeGenerated",e.excludeGenerated!==!1,t.excludeGenerated!==!1,"weakening","Generated source is now excluded from governance.","Generated source is now governed.");let r={off:0,soft:1,"framework-soft":1,strict:2},i=e.cyclePolicy??"strict",a=t.cyclePolicy??"strict";if(i!==a){let o=r[a]===r[i]?"judgment-required":r[a]>r[i]?"strengthening":"weakening";b(n,{kind:"cycle-policy-changed",path:"$.cyclePolicy",classification:o,message:"The cycle enforcement level changed.",before:i,after:a})}return(e.frameworkOverlay??null)!==(t.frameworkOverlay??null)&&b(n,{kind:"framework-overlay-changed",path:"$.frameworkOverlay",classification:"judgment-required",message:"The framework overlay changed and may alter effective layer matching.",before:e.frameworkOverlay??null,after:t.frameworkOverlay??null}),Qe(n,e.layers,t.layers),et(n,e.rules,t.rules),tt(n,e,t),n.sort((o,l)=>o.path.localeCompare(l.path)||o.id.localeCompare(l.id)),{schemaVersion:"1.0",classification:nt(n),findings:n}}function Oe(e,t){if(!e||e.schemaVersion!=="1.0"||typeof e.basePolicyHash!="string"||typeof e.candidatePolicyHash!="string"||typeof e.reason!="string"||!Array.isArray(e.findingIds)||e.findingIds.some(i=>typeof i!="string")||e.reason.trim().length===0||e.basePolicyHash!==t.basePolicyHash||e.candidatePolicyHash!==t.candidatePolicyHash)return!1;let n=x(e.findingIds),r=x(t.findingIds);return n.length===r.length&&n.every((i,a)=>i===r[a])}function P(e){let t=[];for(let n of e.replace(/\\/g,"/").split("/"))!n||n==="."||(n===".."&&t.length>0&&t.at(-1)!==".."?t.pop():t.push(n));return t.join("/")}function Pe(e){return e!==void 0&&/[A-Za-z0-9_$]/.test(e)}function T(e,t){for(;t<e.length&&/\s/.test(e[t]);)t+=1;return t}function q(e,t){let n=e[t];if(n!=="'"&&n!=='"')return;let r=t,i="";for(t+=1;t<e.length;t+=1){let a=e[t];if(a===n)return{value:i,offset:r,excerpt:e.slice(r,t+1)};a==="\\"&&t+1<e.length?(i+=e[t+1],t+=1):i+=a}}function R(e,t,n){return e.startsWith(t,n)&&!Pe(e[n-1])&&!Pe(e[n+t.length])}function rt(e,t){if(t=T(e,t+6),e[t]==="(")return q(e,T(e,t+1));let n=!1;if(R(e,"type",t)){let i=T(e,t+4);e[i]!==","&&!R(e,"from",i)&&(n=!0)}let r=Le(e,t,!0);return r&&n?{...r,typeOnly:!0}:r}function it(e,t){t=t+6;let n=T(e,t),r=!1;if(R(e,"type",n)){let a=T(e,n+4);(e[a]==="{"||e[a]==="*")&&(r=!0)}let i=Le(e,t,!1);return i&&r?{...i,typeOnly:!0}:i}function Le(e,t,n){for(;t<e.length;t+=1){if(e[t]===";")return;if(R(e,"from",t))return q(e,T(e,t+4));if(n&&(e[t]==="'"||e[t]==='"'))return q(e,t);if(t>0&&(R(e,"import",t)||R(e,"export",t)))return}}function at(e){let t=[];for(let n=0;n<e.length;n+=1){let r=e[n];if(r==="/"&&e[n+1]==="/"){if(n=e.indexOf(`
|
|
8
|
+
`,n+2),n<0)break;continue}if(r==="/"&&e[n+1]==="*"){let a=e.indexOf("*/",n+2);if(a<0)break;n=a+1;continue}if(r==="'"||r==='"'||r==="`"){let a=q(e,n);a&&(n=a.offset+a.excerpt.length-1);continue}let i=R(e,"import",n)?rt(e,n):R(e,"export",n)?it(e,n):void 0;i&&t.push(i)}return t}function _e(e,t){let n=[],r=[];for(let i of at(e.content)){let a=i.value;if(!a.startsWith(".")){if(i.typeOnly)continue;let u=j(a);if(!u)continue;let h=e.content.slice(0,i.offset).split(`
|
|
9
|
+
`).length;r.push({file:e.path,symbol:a,capability:u,evidence:{kind:"import",file:e.path,line:h,excerpt:i.excerpt}});continue}let o=e.content.slice(0,i.offset).split(`
|
|
10
|
+
`).length,l={kind:"import",file:e.path,line:o,excerpt:i.excerpt},p=st(e.path,a,t);n.push({from:e.path,specifier:a,to:p?.path??null,resolution:p?"resolved":"unresolved",fromLayer:e.layer,toLayer:p?.layer??null,evidence:l})}return{edges:n,capabilityUses:r}}function st(e,t,n){let r=e.split("/");r.pop();for(let a of t.split("/"))a==="."||a===""||(a===".."?r.pop():r.push(a));let i=r.join("/");for(let a of[i,`${i}.ts`,`${i}.tsx`,`${i}.mts`,`${i}.cts`,`${i}/index.ts`,`${i}/index.tsx`]){let o=n.get(a);if(o)return o}}function ve(e,t){let n=[];for(let r of e){if(!r.to||!r.fromLayer||!r.toLayer)continue;let i=H(t.rules,r.fromLayer,r.toLayer,{fromPath:r.from,toPath:r.to,layers:t.layers});i&&n.push({ruleId:`layer-dependency:${i.from}->${i.to}`,message:i.message??`${i.from} must not depend on ${i.to}.`,edge:r,evidence:r.evidence})}return n}function fe(e,t){let n=typeof e=="string"?$e(e,t):de(e,t);return{...n,policyHash:w(E(n.config))}}function ct(e){let t=fe(e.baseConfig,e.baseSource??"base ark.config.json"),n=fe(e.candidateConfig,e.candidateSource??"candidate ark.config.json"),r=Re(t.config,n.config),i=r.findings.filter(l=>l.classification==="weakening"||l.classification==="judgment-required").map(l=>l.id).sort(),a=i.length>0,o=a&&Oe(e.acknowledgement,{basePolicyHash:t.policyHash,candidatePolicyHash:n.policyHash,findingIds:i});return{schemaVersion:r.schemaVersion,basePolicyHash:t.policyHash,candidatePolicyHash:n.policyHash,classification:r.classification,findings:r.findings,blockingFindingIds:i,requiresAcknowledgement:a,acknowledged:o,valid:!a||o}}function K(e){let t=e.files.map(o=>{let l=P(o.path);return{path:l,content:o.content,contentHash:w(o.content),layer:L(l,e.contract.config.layers)??null}}).sort((o,l)=>o.path.localeCompare(l.path)),n=new Map(t.map(o=>[o.path,o])),r=[],i=[];for(let o of t){let l=_e(o,n);r.push(...l.edges),i.push(...l.capabilityUses)}let a=ve(r,e.contract.config);return{ir:{schemaVersion:"1.0",policyHash:e.contract.policyHash,compilerOptionsHash:w(E(e.compilerOptions??{})),files:t,layers:e.contract.config.layers.map(o=>o.name),edges:r,capabilityUses:i,violations:a}}}function ue(e){let t=new Map(e.files.map(n=>[P(n.path),n]));for(let n of e.changes){let r=P(n.path);"delete"in n&&n.delete?t.delete(r):"content"in n&&t.set(r,{path:r,content:n.content})}return K({contract:e.contract,files:[...t.values()],compilerOptions:e.compilerOptions})}function lt(e){let t=`${e.evidence.file}:${e.evidence.line}`;if(!e.edge)return`${e.ruleId} at ${t}: ${e.message}`;let n=e.edge.to??e.edge.specifier;return`${e.ruleId} at ${t}: ${e.edge.from} imports ${n}. ${e.message}`}function Me(e){let t=0,n=new Map,r=new Map,i=new Set,a=[],o=[],l=p=>{n.set(p,t),r.set(p,t),t+=1,a.push(p),i.add(p);for(let g of[...e.get(p)??[]].sort())e.has(g)&&(n.has(g)?i.has(g)&&r.set(p,Math.min(r.get(p)??0,n.get(g)??0)):(l(g),r.set(p,Math.min(r.get(p)??0,r.get(g)??0))));if(r.get(p)!==n.get(p))return;let u=[],h;do{if(h=a.pop(),h===void 0)break;i.delete(h),u.push(h)}while(h!==p);u.length>1&&o.push(u.sort())};for(let p of[...e.keys()].sort())n.has(p)||l(p);return o.sort((p,u)=>p[0].localeCompare(u[0])).map(p=>({ruleId:"CIRCULAR_DEPENDENCY",file:p[0],line:1,target:p.join(" \u2192 "),message:`Circular dependency among ${p.length} files: ${p.join(" \u2192 ")} \u2192 ${p[0]}.`,cycleKind:"value"}))}function ge(e){let t=e.contentViolations.map(a=>({...a})),n=(e.warnings??[]).map(a=>({...a})),r=new Map(e.files.map(a=>[a,new Set]));for(let a of e.edges){if(a.to&&a.to!==a.from&&!a.typeOnly&&r.has(a.from)&&r.get(a.from)?.add(a.to),!a.to||!a.toLayer)continue;let o=H(e.rules,a.fromLayer,a.toLayer,{fromPath:a.from,toPath:a.to,layers:e.config.layers});if(!o)continue;let l=!!o.peerIsolation;t.push({ruleId:"LAYER_IMPORT_VIOLATION",file:a.from,line:a.line,fromLayer:a.fromLayer,toLayer:a.toLayer,target:a.to,...a.typeOnly?{typeOnly:!0}:{},...a.targetTypeOnlyExports?{targetTypeOnlyExports:!0}:{},...a.sourcePureTypeModule?{sourcePureTypeModule:!0}:{},...a.namedBindingsTypeOnly?{namedBindingsTypeOnly:!0}:{},...!l&&a.portProofEligible?{portProofEligible:!0}:{},...a.kind?{edgeKind:a.kind}:{},...l?{peerIsolation:!0}:{},message:o.message??(l?`${a.fromLayer} must not ${a.kind} another slice of ${a.toLayer} (${a.from} \u2192 ${a.to}). Extract shared code or use events/ports across slices.`:`${a.fromLayer} must not ${a.kind} ${a.toLayer}.`)})}let i=String(e.config.cyclePolicy??"strict").toLowerCase();if(i!=="off"){let a=Me(r);i==="soft"||i==="framework-soft"?n.push(...a.map(o=>({...o,message:`${o.message} (soft cycle policy \u2014 advisory only; set cyclePolicy: "strict" to fail the check)`,failsStrict:!1}))):t.push(...a)}return{violations:t,warnings:n,safety:e.safety}}function Ne(e){switch(e.ruleId){case"LAYER_IMPORT_VIOLATION":return e.typeOnly||e.targetTypeOnlyExports||e.namedBindingsTypeOnly?"Move the referenced type to a mutually allowed layer, use `import type`, then preflight again.":e.peerIsolation?"Extract the shared dependency to a shared layer, then preflight again.":`Define a port in ${e.fromLayer??"the source layer"}, inject the ${e.toLayer??"outer-layer"} implementation, then preflight again.`;case"FORBIDDEN_GLOBAL":return`Inject ${e.target??"the capability"} through a port, then preflight again.`;case"CIRCULAR_DEPENDENCY":return"Extract the shared dependency into a third module, then preflight again.";case"RAW_EVENT_PUBLISH":return"Publish through a registered intent creator, then run Ark again.";case"PUBLISH_MISSING_SOURCE":return"Add metadata.source to the publish call, then run Ark again.";default:return`Resolve ${typeof e.ruleId=="string"&&e.ruleId.length>0?e.ruleId:"ARK_UNKNOWN"} without weakening ark.config.json, then run Ark again.`}}function Te(e){return w(E(e.map(({path:t,contentHash:n})=>({path:t,contentHash:n}))))}function pt(e){let t=K(e),n=new Map(t.ir.files.map(s=>[s.path,s])),r=[],i=new Set,a=[];for(let s of e.changes){let c=s.path.replace(/\\/g,"/"),d=P(s.path);if(!d||d===".."||d.startsWith("../")||c.startsWith("/")||/^[A-Za-z]:\//.test(c)||c.includes("\0")){a.push({ruleId:"INVALID_CHANGE_PATH",file:"<change-set>",line:1,message:"Every change requires a safe, non-empty project-relative path."});continue}if(i.has(d)){a.push({ruleId:"DUPLICATE_CHANGE_PATH",file:d,line:1,message:`The atomic change set contains more than one operation for ${d}.`});continue}i.add(d),"delete"in s&&s.delete&&!n.has(d)&&a.push({ruleId:"DELETE_TARGET_MISSING",file:d,line:1,message:`Cannot delete ${d} because it is not present in the supplied base tree.`}),r.push("delete"in s&&s.delete?{path:d,delete:!0}:{path:d,content:"content"in s?s.content:""})}e.changes.length===0&&a.push({ruleId:"CHANGE_SET_EMPTY",file:"<change-set>",line:1,message:"Atomic preflight requires at least one create, update, or delete."});let o=ue({...e,changes:r}),l=new Map(o.ir.files.map(s=>[s.path,s])),p=ge({config:e.contract.config,rules:e.contract.config.rules,files:o.ir.files.map(s=>s.path),contentViolations:[],edges:o.ir.edges.filter(s=>!!s.fromLayer).map(s=>({from:s.from,fromLayer:s.fromLayer,...s.to?{to:s.to}:{},...s.toLayer?{toLayer:s.toLayer}:{},line:s.evidence.line,kind:"import"}))}),u=r.map(s=>{let c=P(s.path),d=n.get(c),f=l.get(c);return{path:c,operation:"delete"in s&&s.delete?"delete":d?"update":"create",...d?{beforeContentHash:d.contentHash}:{},...f?{candidateContentHash:f.contentHash}:{}}}).sort((s,c)=>s.path.localeCompare(c.path)),h=[...a,...p.violations].map(s=>({...s,nextAction:Ne(s)})),g=e.changeMap?ee({changeMap:e.changeMap,changes:u,baseDependencies:t.ir.edges.flatMap(s=>s.to?[{from:s.from,to:s.to}]:[]),candidateDependencies:o.ir.edges.flatMap(s=>s.to?[{from:s.from,to:s.to}]:[])}):void 0;return{schemaVersion:"1.0",valid:h.length===0&&(g?.structurallyConverged??!0),readOnly:!0,policyHash:e.contract.policyHash,compilerOptionsHash:o.ir.compilerOptionsHash,baseTreeHash:Te(t.ir.files),candidateTreeHash:Te(o.ir.files),...e.changeMap?{changeMapHash:e.changeMap.hash}:{},...g?{convergence:g}:{},changes:u,violations:h,warnings:p.warnings}}function I(e,t,n={}){return{ruleId:e,message:t,...n}}function dt(e){let{config:t,rules:n,files:r,manifest:i}=e,a=[];if(t.dynamicImportAllowlist!==void 0&&(!Array.isArray(t.dynamicImportAllowlist)||t.dynamicImportAllowlist.some(c=>typeof c!="string"))&&a.push(I("CONFIG_INVALID_DYNAMIC_IMPORT_ALLOWLIST","dynamicImportAllowlist must be an array of file globs.")),t.safety!==void 0&&(t.safety===null||typeof t.safety!="object"||Array.isArray(t.safety)))a.push(I("CONFIG_INVALID_SAFETY","safety must be an object."));else if(t.safety)for(let c of["maxTsSuppressions","maxAnyCasts"]){let d=t.safety[c];d!==void 0&&(!Number.isInteger(d)||d<0)&&a.push(I("CONFIG_INVALID_SAFETY_THRESHOLD",`safety.${c} must be a non-negative integer.`))}let o=Array.isArray(t.layers)?t.layers:[],l=Array.isArray(i?.architecture?.layers)?i.architecture.layers:[],p=new Set([...o.map(c=>c.name).filter(Boolean),...l.map(c=>c.name).filter(c=>!!c)]);o.length===0&&a.push(I("CONFIG_NO_LAYERS","No file layers are configured; ark-check cannot classify files for import-boundary enforcement."));let u=new Set,h=new Set;for(let c of o){if(!c.name){a.push(I("CONFIG_LAYER_WITHOUT_NAME","A configured layer is missing a name."));continue}u.has(c.name)&&h.add(c.name),u.add(c.name),c.forbiddenGlobals!==void 0&&(!Array.isArray(c.forbiddenGlobals)||c.forbiddenGlobals.some(f=>typeof f!="string"))&&a.push(I("CONFIG_INVALID_FORBIDDEN_GLOBALS",`Layer "${c.name}" has an invalid forbiddenGlobals value; expected an array of strings (e.g. ["fetch", "Date.now"]). The entry is ignored.`,{layer:c.name}));let d=Array.isArray(c.patterns)?c.patterns:[];if(d.length===0){a.push(I("CONFIG_LAYER_WITHOUT_PATTERNS",`Layer "${c.name}" has no file patterns and will never classify files.`,{layer:c.name}));continue}for(let f of d){let y;try{y=D(f)}catch(m){a.push(I("CONFIG_INVALID_LAYER_PATTERN",`Layer "${c.name}" has an invalid pattern "${f}": ${m instanceof Error?m.message:String(m)}`,{layer:c.name,pattern:f}));continue}!r.some(m=>y.test(m))&&!c.optional&&a.push(I("CONFIG_LAYER_PATTERN_NO_MATCHES",`Layer "${c.name}" pattern "${f}" matched no included files.`,{layer:c.name,pattern:f,failsStrict:!1}))}}for(let c of h)a.push(I("CONFIG_DUPLICATE_LAYER",`Layer "${c}" is configured more than once.`,{layer:c}));if(p.size>0)for(let c of n??[])c.from&&!p.has(c.from)&&a.push(I("CONFIG_RULE_UNKNOWN_FROM_LAYER",`Rule references unknown source layer "${c.from}".`,{fromLayer:c.from,toLayer:c.to})),c.to&&!p.has(c.to)&&a.push(I("CONFIG_RULE_UNKNOWN_TO_LAYER",`Rule references unknown target layer "${c.to}".`,{fromLayer:c.from,toLayer:c.to}));let g=new Set;if(o.length>1)for(let c of r){let d=-1,f=[];for(let y of o)for(let m of y.patterns??[]){if(!D(m).test(c))continue;let A=J(m);A>d?(d=A,f=[y.name]):A===d&&!f.includes(y.name)&&f.push(y.name)}f.length>1&&g.add([...f].sort().join(" + "))}g.size>0&&a.push(I("CONFIG_AMBIGUOUS_LAYERS",`Some files match multiple layers at equal specificity; classification falls back to declaration order. Disambiguate the overlapping patterns: ${[...g].join(", ")}.`,{pairs:[...g]}));let s=r.filter(c=>!L(c,o));return s.length>0&&a.push(I("CONFIG_UNCLASSIFIED_FILES",`${s.length} included source file(s) are not matched by any configured layer; ark-check will not enforce import rules for those source files.`,{count:s.length,samples:s.slice(0,5)})),a}export{ce as AMBIENT_CAPABILITY_ENTRIES,ze as CAPABILITY_IDS,ae as SOURCE_POLICY_MESSAGES,ee as analyzeArchitectureConvergence,ue as analyzeChange,ct as analyzePolicyDelta,K as analyzeProject,G as capabilityForAmbientName,j as capabilityForModuleSpecifier,Be as classifyPublishFacts,dt as collectAnalysisConfigWarnings,Ke as collectCapabilityUses,ie as collectForbiddenCapabilityUses,Me as detectArchitectureCycles,ge as evaluateArchitectureGraph,lt as explainViolation,re as extractSemanticDependencies,Ve as loadArchitectureChangeMap,fe as loadContract,ke as looksLikeArkIntent,qe as lowerForbiddenGlobal,pt as preflightChange};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type vocabulary for the ark.config.json contract (U02 pilot 1).
|
|
3
|
+
*
|
|
4
|
+
* Pure declarations only — no runtime values. The loader/validator logic and the
|
|
5
|
+
* published JSON Schema live in ./configContract.ts, whose generated CLI artifact
|
|
6
|
+
* must stay self-contained: type-only imports/exports are erased on transpile, so
|
|
7
|
+
* this split never reaches bin/lib/config-contract.mjs.
|
|
8
|
+
*/
|
|
9
|
+
type ArkConfigSchemaVersion = '1.0';
|
|
10
|
+
type ArkConfigCyclePolicy = 'strict' | 'soft' | 'framework-soft' | 'off';
|
|
11
|
+
type ArkConfigLayer = {
|
|
12
|
+
name: string;
|
|
13
|
+
patterns: string[];
|
|
14
|
+
exclude?: string[];
|
|
15
|
+
intentPrefixes?: string[];
|
|
16
|
+
description?: string;
|
|
17
|
+
forbiddenGlobals?: string[];
|
|
18
|
+
mayImportInfrastructure?: boolean;
|
|
19
|
+
optional?: boolean;
|
|
20
|
+
};
|
|
21
|
+
type ArkConfigRule = {
|
|
22
|
+
from: string;
|
|
23
|
+
to: string;
|
|
24
|
+
allowed: boolean;
|
|
25
|
+
message?: string;
|
|
26
|
+
peerIsolation?: boolean;
|
|
27
|
+
sliceFolders?: string[];
|
|
28
|
+
};
|
|
29
|
+
type ArkConfigSafety = {
|
|
30
|
+
maxTsSuppressions?: number;
|
|
31
|
+
maxAnyCasts?: number;
|
|
32
|
+
allowInMemory?: boolean;
|
|
33
|
+
allowDisabledPeerIsolation?: boolean;
|
|
34
|
+
};
|
|
35
|
+
type ArkConfig = {
|
|
36
|
+
$schema: string;
|
|
37
|
+
schemaVersion: ArkConfigSchemaVersion;
|
|
38
|
+
name?: string;
|
|
39
|
+
include: string[];
|
|
40
|
+
exclude?: string[];
|
|
41
|
+
excludeGenerated?: boolean;
|
|
42
|
+
frameworkOverlay?: string;
|
|
43
|
+
layers: ArkConfigLayer[];
|
|
44
|
+
rules: ArkConfigRule[];
|
|
45
|
+
cyclePolicy?: ArkConfigCyclePolicy;
|
|
46
|
+
dynamicImportAllowlist?: string[];
|
|
47
|
+
safety?: ArkConfigSafety;
|
|
48
|
+
};
|
|
49
|
+
type ArkConfigLoadResult = {
|
|
50
|
+
config: ArkConfig;
|
|
51
|
+
migratedFrom: 'unversioned' | null;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export type { ArkConfig as A, ArkConfigRule as a, ArkConfigSchemaVersion as b, ArkConfigLoadResult as c, ArkConfigLayer as d };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type vocabulary for the ark.config.json contract (U02 pilot 1).
|
|
3
|
+
*
|
|
4
|
+
* Pure declarations only — no runtime values. The loader/validator logic and the
|
|
5
|
+
* published JSON Schema live in ./configContract.ts, whose generated CLI artifact
|
|
6
|
+
* must stay self-contained: type-only imports/exports are erased on transpile, so
|
|
7
|
+
* this split never reaches bin/lib/config-contract.mjs.
|
|
8
|
+
*/
|
|
9
|
+
type ArkConfigSchemaVersion = '1.0';
|
|
10
|
+
type ArkConfigCyclePolicy = 'strict' | 'soft' | 'framework-soft' | 'off';
|
|
11
|
+
type ArkConfigLayer = {
|
|
12
|
+
name: string;
|
|
13
|
+
patterns: string[];
|
|
14
|
+
exclude?: string[];
|
|
15
|
+
intentPrefixes?: string[];
|
|
16
|
+
description?: string;
|
|
17
|
+
forbiddenGlobals?: string[];
|
|
18
|
+
mayImportInfrastructure?: boolean;
|
|
19
|
+
optional?: boolean;
|
|
20
|
+
};
|
|
21
|
+
type ArkConfigRule = {
|
|
22
|
+
from: string;
|
|
23
|
+
to: string;
|
|
24
|
+
allowed: boolean;
|
|
25
|
+
message?: string;
|
|
26
|
+
peerIsolation?: boolean;
|
|
27
|
+
sliceFolders?: string[];
|
|
28
|
+
};
|
|
29
|
+
type ArkConfigSafety = {
|
|
30
|
+
maxTsSuppressions?: number;
|
|
31
|
+
maxAnyCasts?: number;
|
|
32
|
+
allowInMemory?: boolean;
|
|
33
|
+
allowDisabledPeerIsolation?: boolean;
|
|
34
|
+
};
|
|
35
|
+
type ArkConfig = {
|
|
36
|
+
$schema: string;
|
|
37
|
+
schemaVersion: ArkConfigSchemaVersion;
|
|
38
|
+
name?: string;
|
|
39
|
+
include: string[];
|
|
40
|
+
exclude?: string[];
|
|
41
|
+
excludeGenerated?: boolean;
|
|
42
|
+
frameworkOverlay?: string;
|
|
43
|
+
layers: ArkConfigLayer[];
|
|
44
|
+
rules: ArkConfigRule[];
|
|
45
|
+
cyclePolicy?: ArkConfigCyclePolicy;
|
|
46
|
+
dynamicImportAllowlist?: string[];
|
|
47
|
+
safety?: ArkConfigSafety;
|
|
48
|
+
};
|
|
49
|
+
type ArkConfigLoadResult = {
|
|
50
|
+
config: ArkConfig;
|
|
51
|
+
migratedFrom: 'unversioned' | null;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export type { ArkConfig as A, ArkConfigRule as a, ArkConfigSchemaVersion as b, ArkConfigLoadResult as c, ArkConfigLayer as d };
|
package/dist/eslint/index.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
${
|
|
3
|
-
`)}`),this.name="ArkConfigValidationError",this.source=n,this.issues=t}};function Z(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function j(e,n){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(n)?`${e}.${n}`:`${e}[${JSON.stringify(n)}]`}function b(e){return e===null?"null":Array.isArray(e)?"array":typeof e}function Ee(e,n){let t="#/$defs/";if(e.startsWith(t))return n.$defs[e.slice(t.length)]}function R(e,n,t,i,r){if(n.$ref){let o=Ee(n.$ref,i);if(!o){r.push({path:t,message:`schema reference ${n.$ref} cannot be resolved`});return}R(e,o,t,i,r);return}if(n.const!==void 0&&!Object.is(e,n.const)){r.push({path:t,message:`must equal ${JSON.stringify(n.const)}`});return}if(n.enum&&!n.enum.some(o=>Object.is(o,e))){r.push({path:t,message:`must be one of ${n.enum.map(String).join(", ")}`});return}if(n.type==="object"){if(!Z(e)){r.push({path:t,message:`must be an object; received ${b(e)}`});return}let o=n.properties??{};for(let s of n.required??[])e[s]===void 0&&r.push({path:j(t,s),message:"is required"});if(n.additionalProperties===!1)for(let s of Object.keys(e))s in o||r.push({path:j(t,s),message:"unknown field"});for(let[s,a]of Object.entries(o))e[s]!==void 0&&R(e[s],a,j(t,s),i,r);return}if(n.type==="array"){if(!Array.isArray(e)){r.push({path:t,message:`must be an array; received ${b(e)}`});return}if(n.minItems!==void 0&&e.length<n.minItems&&r.push({path:t,message:`must contain at least ${n.minItems} item(s)`}),n.uniqueItems){let o=e.map(s=>JSON.stringify(s));new Set(o).size!==o.length&&r.push({path:t,message:"must not contain duplicate items"})}n.items&&e.forEach((o,s)=>R(o,n.items,`${t}[${s}]`,i,r));return}if(n.type==="string"){if(typeof e!="string"){r.push({path:t,message:`must be a string; received ${b(e)}`});return}n.minLength!==void 0&&e.length<n.minLength&&r.push({path:t,message:`must contain at least ${n.minLength} character(s)`});return}if(n.type==="boolean"){typeof e!="boolean"&&r.push({path:t,message:`must be a boolean; received ${b(e)}`});return}if(n.type==="integer"){if(!Number.isInteger(e)){r.push({path:t,message:`must be an integer; received ${b(e)}`});return}n.minimum!==void 0&&e<n.minimum&&r.push({path:t,message:`must be at least ${n.minimum}`})}}function xe(e){return{...e,$schema:e.$schema===void 0?F:e.$schema,schemaVersion:e.schemaVersion===void 0?"1.0":e.schemaVersion,include:e.include===void 0?["src"]:e.include,layers:e.layers===void 0?[]:e.layers,rules:e.rules===void 0?z.map(n=>({...n})):e.rules}}function Ne(e,n="ark.config.json"){if(!Z(e))throw new h(n,[{path:"$",message:`must be an object; received ${b(e)}`}]);let t=e.schemaVersion===void 0?"unversioned":null;if(e.schemaVersion!==void 0&&e.schemaVersion!=="1.0")throw new h(n,[{path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(e.schemaVersion)}; expected 1.0`}]);return{candidate:xe(e),migratedFrom:t}}function we(e,n="ark.config.json"){let{candidate:t,migratedFrom:i}=Ne(e,n),r=[];if(R(t,Y,"$",Y,r),r.length>0)throw new h(n,r);return{config:t,migratedFrom:i}}function Q(e,n="ark.config.json"){let t;try{t=JSON.parse(e)}catch(i){throw new h(n,[{path:"$",message:`invalid JSON: ${i instanceof Error?i.message:String(i)}`}])}return we(t,n)}function m(e){return typeof e=="string"&&e.length>0?e:void 0}function X(e,n){return Number.isInteger(e)&&Number(e)>0?Number(e):n}function Le(e,n,t){return e==="LAYER_IMPORT_VIOLATION"?n.typeOnly||t.targetTypeOnlyExports===!0||t.namedBindingsTypeOnly===!0?"Move the referenced type to a mutually allowed layer, use `import type`, then preflight again.":t.peerIsolation===!0?"Extract the shared dependency to a shared layer, then preflight again.":`Define a port in ${n.fromLayer??"the source layer"}, inject the ${n.toLayer??"outer-layer"} implementation, then preflight again.`:e==="FORBIDDEN_GLOBAL"?`Inject ${n.target??"the capability"} through a port, then preflight again.`:e==="CIRCULAR_DEPENDENCY"?"Extract the shared dependency into a third module, then preflight again.":e==="RAW_EVENT_PUBLISH"?"Publish through a registered intent creator, then run Ark again.":e==="PUBLISH_MISSING_SOURCE"?"Add metadata.source to the publish call, then run Ark again.":`Resolve ${e} without weakening ark.config.json, then run Ark again.`}function ee(e,n="error"){let t=m(e.ruleId)??m(e.code)??"ARK_UNKNOWN",i=e.severity==="warning"?"warning":n,r={...m(e.target)?{target:m(e.target)}:{},...m(e.fromLayer)?{fromLayer:m(e.fromLayer)}:{},...m(e.toLayer)?{toLayer:m(e.toLayer)}:{},...typeof e.typeOnly=="boolean"?{typeOnly:e.typeOnly}:{}};return{ruleId:t,severity:i,message:m(e.message)??t,location:{file:m(e.file)??"<unknown>",line:X(e.line,1),column:X(e.column,1)},evidence:r,nextAction:m(e.nextAction)??Le(t,r,e)}}var ne={RAW_EVENT_PUBLISH:"Publish through a registered intent creator; raw event objects or intent strings bypass Ark contracts and tooling.",PUBLISH_MISSING_SOURCE:"Strict Ark publish calls must include metadata.source."};function _e(e){return/^(Domain|Application|Adapter|Workflow|Job|Presentation|Reporting|Metadata|Security|Audit|Observability|Kernel)\.[A-Za-z0-9_.]+$/.test(e)}function V(e){if(!e.publishCall)return[];let n=[];return(e.rawIntentName!==void 0&&_e(e.rawIntentName)||e.objectHasIntent)&&n.push({ruleId:"RAW_EVENT_PUBLISH",message:ne.RAW_EVENT_PUBLISH}),e.arkPublishCandidate&&!e.hasSource&&n.push({ruleId:"PUBLISH_MISSING_SOURCE",message:ne.PUBLISH_MISSING_SOURCE}),n}function x(e){if(typeof e.physicalFilename=="string"&&e.physicalFilename.length>0)return e.physicalFilename;if(typeof e.filename=="string"&&e.filename.length>0)return e.filename;if(typeof e.getFilename=="function")try{let n=e.getFilename();if(typeof n=="string"&&n.length>0)return n}catch{}return""}function N(e,n,t,i,r){let o=ee({...i,line:i.line??n.loc?.start?.line,column:i.column??(typeof n.loc?.start?.column=="number"?n.loc.start.column+1:void 0)});return e.report({node:n,messageId:t,...r?{data:r}:{},diagnostic:o}),o}function G(e){if(!e||e==="<input>"||e.startsWith("stdin"))return null;let n=c.default.dirname(c.default.resolve(e));for(;;){let t=c.default.join(n,"ark.config.json");if(A.default.existsSync(t))return t;let i=c.default.dirname(n);if(i===n)return null;n=i}}var M=new Map;function D(e){if(M.has(e))return M.get(e)??null;if(!A.default.existsSync(e))return null;let n=Q(A.default.readFileSync(e,"utf8"),e).config;return M.set(e,n),n}function re(e,n){if(!n.startsWith("."))return null;let t=c.default.resolve(c.default.dirname(e),n),i=[t,`${t}.ts`,`${t}.tsx`,`${t}.mts`,`${t}.cts`,`${t}.js`,`${t}.jsx`,c.default.join(t,"index.ts"),c.default.join(t,"index.tsx"),c.default.join(t,"index.js")];for(let r of i)try{if(A.default.existsSync(r)&&A.default.statSync(r).isFile())return r}catch{}return`${t}.ts`}function w(e){return typeof e?.value=="string"?e.value:void 0}function T(e){return e?.name??w(e)}function H(e){return e.sourceCode??e.getSourceCode?.()}function ie(e,n){let t=H(e)?.getScope?.(n);for(;t;){let i=t.references?.find(r=>r.identifier===n);if(i)return i;t=t.upper??void 0}}function te(e,n,t){let i=ie(e,n);if(i?.resolved)return(i.resolved.defs?.length??0)>0;let r=H(e)?.getScope?.(n);for(;r;){let o=r.set?.get(t);if(o)return(o.defs?.length??0)>0;r=r.upper??void 0}return!1}function Oe(e,n){let t=ie(e,n);return t?t.isValueReference!==!1:n.parent?.type==="VariableDeclarator"&&n.parent.init===n}function oe(e){if(e?.type==="Identifier"&&e.name)return{root:e,segments:[e.name]};if(!e||!(e.type==="MemberExpression"||!!(e.object&&e.property))||e.computed===!0)return;let t=oe(e.object),i=T(e.property);if(!(!t||!i))return{root:t.root,segments:[...t.segments,i]}}function $e(e){return T(e.callee?.property)}function se(e,n){return e?.properties?.find(t=>T(t.key)===n)}function C(e,n){return se(e,n)!==void 0}function Pe(e){let n=se(e,"metadata")?.value;return C(n,"source")}function ae(e){return $e(e)==="publish"}var le={meta:{type:"problem",docs:{description:"Disallow imports that violate ark.config.json layer rules (same contract as arkgate-check)."},messages:{forbiddenImport:"Architecture: {{fromLayer}} must not import {{toLayer}} (ark.config.json). Specifier: {{specifier}}",forbiddenImportHeuristic:"Domain code must not import infrastructure, adapters, repositories, or database modules."},schema:[]},create(e){let n=x(e),t=G(n),i=t?D(t):null,r=t?c.default.dirname(t):null,o=s=>{let a=w(s.source);if(a&&i&&r&&n){let d=c.default.isAbsolute(n)?n:c.default.resolve(n),p=c.default.relative(r,d).split(c.default.sep).join("/"),l=S(p,i.layers);if(!l)return;let u=re(d,a);if(!u)return;let f=c.default.relative(r,u).split(c.default.sep).join("/");if(f.startsWith(".."))return;let g=S(f,i.layers);if(!g)return;P(i.rules,l,g,{fromPath:p,toPath:f,layers:i.layers})&&N(e,s,"forbiddenImport",{ruleId:"LAYER_IMPORT_VIOLATION",file:p,fromLayer:l,toLayer:g,target:f,...s.importKind==="type"?{typeOnly:!0}:{},message:`${l} must not import ${g}.`},{fromLayer:l,toLayer:g,specifier:a});return}};return{ImportDeclaration:o,ExportNamedDeclaration:o,ExportAllDeclaration:o}}},ce={meta:{type:"problem",docs:{description:"Require event bus publish calls to use registered intent creators instead of raw event objects or intent strings."},messages:{rawPublish:"Publish through a registered intent creator; raw event objects or intent strings bypass Ark contracts."},schema:[]},create(e){return{CallExpression(n){let t=n.arguments?.[0],i=w(t),r=V({publishCall:ae(n),rawIntentName:i,objectHasIntent:C(t,"intent"),arkPublishCandidate:!1,hasSource:!0});if(r.some(o=>o.ruleId==="RAW_EVENT_PUBLISH")){let o=r.find(s=>s.ruleId==="RAW_EVENT_PUBLISH");N(e,n,"rawPublish",{...o,file:x(e)})}}}}},ue={meta:{type:"problem",docs:{description:"Require event bus publish calls to include source metadata."},messages:{missingSource:"Strict Ark publish calls must include metadata.source."},schema:[]},create(e){return{CallExpression(n){let t=n.arguments?.[0],i=n.arguments?.[2],o=V({publishCall:ae(n),rawIntentName:w(t),objectHasIntent:C(t,"intent"),arkPublishCandidate:!0,hasSource:Pe(t)||C(i,"source")}).find(s=>s.ruleId==="PUBLISH_MISSING_SOURCE");o&&N(e,n,"missingSource",{...o,file:x(e)})}}}},de={meta:{type:"problem",docs:{description:"Disallow ambient globals from the layer\u2019s forbiddenGlobals in ark.config.json (same purity surface as ark-check). Option `globals` explicitly overrides."},messages:{forbiddenGlobal:'Ambient global "{{name}}" is forbidden in {{layer}} (ark.config.json); inject the capability through a port instead.',forbiddenGlobalDefault:'Ambient global "{{name}}" is forbidden here; inject the capability through a port instead.'},schema:[{type:"object",properties:{globals:{type:"array",items:{type:"string"}}},additionalProperties:!1}]},create(e){let n=x(e),t=e.options?.[0],i=G(n),r=i?D(i):null,o=i?c.default.dirname(i):null,s=null,a="this layer";if(t?.globals)s=new Set(t.globals);else if(r&&o&&n){let l=c.default.isAbsolute(n)?n:c.default.resolve(n),u=c.default.relative(o,l).split(c.default.sep).join("/"),f=r.layers?.find(g=>g.name===S(u,r.layers));f?.forbiddenGlobals?.length?(s=new Set(f.forbiddenGlobals),a=f.name):s=null}if(!s)return{};let d=typeof H(e)?.getScope=="function",p=(l,u)=>{let f=c.default.isAbsolute(n)?n:c.default.resolve(n),g=o?c.default.relative(o,f).split(c.default.sep).join("/"):n;N(e,l,r?"forbiddenGlobal":"forbiddenGlobalDefault",{ruleId:"FORBIDDEN_GLOBAL",file:g,fromLayer:a,target:u,message:`${a} must not use the ambient global "${u}".`},{name:u,layer:a})};return{MemberExpression(l){if(l.parent?.type==="MemberExpression"&&l.parent.object===l)return;let u=oe(l);if(!u||te(e,u.root,u.segments[0]))return;let f=u.segments[0]==="globalThis",g=f?u.segments.slice(1):u.segments,L;for(let _=g.length;_>=(f?1:2);_-=1){let v=g.slice(0,_).join(".");if(s.has(v)){L=v;break}}L?p(l,L):!d&&s.has(u.segments[0])&&p(l,u.segments[0])},CallExpression(l){if(d)return;let u=l.callee?.type==="Identifier"?l.callee.name:void 0;u&&s.has(u)&&p(l,u)},NewExpression(l){if(d)return;let u=l.callee?.type==="Identifier"?l.callee.name:void 0;u&&s.has(u)&&p(l,u)},Identifier(l){!d||!l.name||!s.has(l.name)||!Oe(e,l)||te(e,l,l.name)||p(l,l.name)}}}},je={"no-domain-infra-imports":le,"no-raw-event-publish":ce,"require-publish-source":ue,"no-forbidden-globals":de},E={rules:je};E.configs={recommended:{plugins:{ark:E},rules:{"ark/no-domain-infra-imports":"error","ark/no-raw-event-publish":"error","ark/require-publish-source":"error","ark/no-forbidden-globals":"error"}}};var Fe=E;0&&(module.exports={findConfigPath,globToRegExp,isEdgeDenied,layerForRelativePath,loadArkConfig,noDomainInfraImports,noForbiddenGlobals,noRawEventPublish,patternSpecificity,plugin,requirePublishSource,resolveRelativeImport});
|
|
1
|
+
"use strict";var de=Object.create;var k=Object.defineProperty;var ge=Object.getOwnPropertyDescriptor;var pe=Object.getOwnPropertyNames;var me=Object.getPrototypeOf,ye=Object.prototype.hasOwnProperty;var he=(e,t)=>{for(var n in t)k(e,n,{get:t[n],enumerable:!0})},v=(e,t,n,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of pe(t))!ye.call(e,r)&&r!==n&&k(e,r,{get:()=>t[r],enumerable:!(i=ge(t,r))||i.enumerable});return e};var B=(e,t,n)=>(n=e!=null?de(me(e)):{},v(t||!e||!e.__esModule?k(n,"default",{value:e,enumerable:!0}):n,e)),Ae=e=>v(k({},"__esModule",{value:!0}),e);var Fe={};he(Fe,{default:()=>Ve,findConfigPath:()=>D,globToRegExp:()=>R,isEdgeDenied:()=>P,layerForRelativePath:()=>S,loadArkConfig:()=>G,noDomainInfraImports:()=>le,noForbiddenGlobals:()=>fe,noRawEventPublish:()=>ce,patternSpecificity:()=>$,plugin:()=>E,requirePublishSource:()=>ue,resolveRelativeImport:()=>re});module.exports=Ae(Fe);var b=B(require("fs"),1),c=B(require("path"),1);var K=new Map;function W(e){return/[.*+?^${}()|[\]\\]/.test(e)?`\\${e}`:e}function O(e){let t="";for(let n=0;n<e.length;n+=1){let i=e[n];if(i==="\\"&&n+1<e.length){let r=e[n+1];if("*?{}[],".includes(r)||r==="\\"){t+="\\"+r,n+=1;continue}t+="/";continue}t+=i}return t}function be(e){let t=0;for(let n=0;n<e.length;n+=1){let i=e[n];if(i==="\\"){n+=1;continue}if(i==="{")t+=1;else if(i==="}"&&(t-=1,t<0))return!1}return t===0}function R(e){let t=K.get(e);if(t)return t;let n=O(e),i=be(n),r="",o=0;for(let a=0;a<n.length;a+=1){let f=n[a];f==="\\"&&a+1<n.length?(r+=W(n[a+1]),a+=1):f==="*"?n[a+1]==="*"?n[a+2]==="/"?(r+="(?:.*/)?",a+=2):(r+=".*",a+=1):r+="[^/]*":f==="?"?r+="[^/]":f==="{"&&i?(r+="(?:",o+=1):f==="}"&&i&&o>0?(r+=")",o-=1):f===","&&i&&o>0?r+="|":r+=W(f)}let s=new RegExp(`^${r}$`);return K.set(e,s),s}function $(e){let t=O(String(e)),i=t.split("*")[0].split("/").filter(Boolean).length,r=t.replace(/\*/g,"").length;return i*1e4+r}function S(e,t){let n=String(e).split(/[/\\]/).join("/"),i,r=-1;for(let o of t??[])if(!(o.exclude??[]).some(s=>R(s).test(n))){for(let s of o.patterns??[])if(R(s).test(n)){let a=$(s);a>r&&(r=a,i=o.name)}}return i}function q(e,t){if(!t?.length)return;let n=String(e).split(/[/\\]/).filter(Boolean),i=new Set(t.map(r=>String(r).toLowerCase()));for(let r=0;r<n.length-1;r+=1)if(i.has(n[r].toLowerCase()))return`${n[r]}/${n[r+1]}`}function Se(e){let t=new Set;for(let n of e??[]){let r=O(String(n)).split("/").filter(Boolean);for(let o=0;o<r.length;o+=1){let s=r[o];if((s==="**"||s==="*")&&o>0){let a=r[o-1];a&&!a.includes("*")&&!a.includes("{")&&!a.includes("}")&&t.add(a)}}}return[...t]}function ke(e,t,n){if(Array.isArray(e.sliceFolders)&&e.sliceFolders.length>0)return e.sliceFolders.filter(r=>typeof r=="string"&&r.length>0);let i=(n??[]).find(r=>r.name===t);return Se(i?.patterns)}function Re(e,t,n,i){for(let r of e??[])if(!(r.from!==t||r.to!==n)&&r.allowed===!1){if(r.peerIsolation){let o=i?.fromPath,s=i?.toPath;if(!o||!s)continue;let a=ke(r,t,i?.layers);if(a.length===0)continue;let f=q(o,a),g=q(s,a);if(!f||!g)continue;if(f!==g)return r;continue}if(t!==n)return r}}function P(e,t,n,i){return Re(e,t,n,i)!==void 0}var V="https://unpkg.com/arkgate@2/schemas/ark.config.schema.json",J=["DomainModel","ApplicationOrchestration","PersistenceAdapters","IntegrationAdapters","WorkflowSagaEngine","BackgroundJobsScheduling","PresentationAdapters","ReportingReadModels","ExtensibilityMetadata","SecurityAuditObservability","Kernel"],Ie=new Set(["PresentationAdapters->ApplicationOrchestration","ApplicationOrchestration->DomainModel","WorkflowSagaEngine->ApplicationOrchestration","WorkflowSagaEngine->DomainModel","BackgroundJobsScheduling->ApplicationOrchestration"]);function Ce(){let e=[];for(let t of J)for(let n of J)t===n||Ie.has(`${t}->${n}`)||e.push({from:t,to:n,allowed:!1});return e}var z=Ce();var y={type:"array",items:{type:"string",minLength:1},uniqueItems:!0},Y={$schema:"https://json-schema.org/draft/2020-12/schema",$id:V,title:"ArkGate architecture contract",description:"Versioned contract consumed identically by ArkGate CLI, MCP, and ESLint surfaces.",type:"object",additionalProperties:!1,required:["$schema","schemaVersion","include","layers","rules"],properties:{$schema:{type:"string",minLength:1,default:V,description:"Editor-facing URL or local path for this JSON Schema."},schemaVersion:{type:"string",const:"1.0",default:"1.0"},name:{type:"string",minLength:1},include:{...y,minItems:1,default:["src"]},exclude:{...y,default:[]},excludeGenerated:{type:"boolean",default:!0},frameworkOverlay:{type:"string",minLength:1},layers:{type:"array",default:[],items:{$ref:"#/$defs/layer"}},rules:{type:"array",default:z,items:{$ref:"#/$defs/rule"}},cyclePolicy:{type:"string",enum:["strict","soft","framework-soft","off"],default:"strict"},dynamicImportAllowlist:{...y,default:[]},safety:{$ref:"#/$defs/safety",default:{maxTsSuppressions:0,maxAnyCasts:0,allowInMemory:!1,allowDisabledPeerIsolation:!1}}},$defs:{layer:{type:"object",additionalProperties:!1,required:["name","patterns"],properties:{name:{type:"string",minLength:1},patterns:{...y,minItems:1},exclude:y,intentPrefixes:y,description:{type:"string",minLength:1},forbiddenGlobals:y,mayImportInfrastructure:{type:"boolean"},optional:{type:"boolean"}}},rule:{type:"object",additionalProperties:!1,required:["from","to","allowed"],properties:{from:{type:"string",minLength:1},to:{type:"string",minLength:1},allowed:{type:"boolean"},message:{type:"string",minLength:1},peerIsolation:{type:"boolean"},sliceFolders:{...y,minItems:1}}},safety:{type:"object",additionalProperties:!1,properties:{maxTsSuppressions:{type:"integer",minimum:0,default:0},maxAnyCasts:{type:"integer",minimum:0,default:0},allowInMemory:{type:"boolean",default:!1},allowDisabledPeerIsolation:{type:"boolean",default:!1}}}}},A=class extends Error{issues;source;constructor(t,n){super(`Invalid ArkGate config (${t}):
|
|
2
|
+
${n.map(i=>`- ${i.path}: ${i.message}`).join(`
|
|
3
|
+
`)}`),this.name="ArkConfigValidationError",this.source=t,this.issues=n}};function Z(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function j(e,t){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(t)?`${e}.${t}`:`${e}[${JSON.stringify(t)}]`}function h(e){return e===null?"null":Array.isArray(e)?"array":typeof e}function Ee(e,t){let n="#/$defs/";if(e.startsWith(n))return t.$defs[e.slice(n.length)]}function I(e,t,n,i,r){if(t.$ref){let o=Ee(t.$ref,i);if(!o){r.push({path:n,message:`schema reference ${t.$ref} cannot be resolved`});return}I(e,o,n,i,r);return}if(t.const!==void 0&&!Object.is(e,t.const)){r.push({path:n,message:`must equal ${JSON.stringify(t.const)}`});return}if(t.enum&&!t.enum.some(o=>Object.is(o,e))){r.push({path:n,message:`must be one of ${t.enum.map(String).join(", ")}`});return}if(t.type==="object"){if(!Z(e)){r.push({path:n,message:`must be an object; received ${h(e)}`});return}let o=t.properties??{};for(let s of t.required??[])e[s]===void 0&&r.push({path:j(n,s),message:"is required"});if(t.additionalProperties===!1)for(let s of Object.keys(e))s in o||r.push({path:j(n,s),message:"unknown field"});for(let[s,a]of Object.entries(o))e[s]!==void 0&&I(e[s],a,j(n,s),i,r);return}if(t.type==="array"){if(!Array.isArray(e)){r.push({path:n,message:`must be an array; received ${h(e)}`});return}if(t.minItems!==void 0&&e.length<t.minItems&&r.push({path:n,message:`must contain at least ${t.minItems} item(s)`}),t.uniqueItems){let o=e.map(s=>JSON.stringify(s));new Set(o).size!==o.length&&r.push({path:n,message:"must not contain duplicate items"})}t.items&&e.forEach((o,s)=>I(o,t.items,`${n}[${s}]`,i,r));return}if(t.type==="string"){if(typeof e!="string"){r.push({path:n,message:`must be a string; received ${h(e)}`});return}t.minLength!==void 0&&e.length<t.minLength&&r.push({path:n,message:`must contain at least ${t.minLength} character(s)`});return}if(t.type==="boolean"){typeof e!="boolean"&&r.push({path:n,message:`must be a boolean; received ${h(e)}`});return}if(t.type==="integer"){if(!Number.isInteger(e)){r.push({path:n,message:`must be an integer; received ${h(e)}`});return}t.minimum!==void 0&&e<t.minimum&&r.push({path:n,message:`must be at least ${t.minimum}`})}}function Ne(e){return{...e,$schema:e.$schema===void 0?V:e.$schema,schemaVersion:e.schemaVersion===void 0?"1.0":e.schemaVersion,include:e.include===void 0?["src"]:e.include,layers:e.layers===void 0?[]:e.layers,rules:e.rules===void 0?z.map(t=>({...t})):e.rules}}function xe(e,t="ark.config.json"){if(!Z(e))throw new A(t,[{path:"$",message:`must be an object; received ${h(e)}`}]);let n=e.schemaVersion===void 0?"unversioned":null;if(e.schemaVersion!==void 0&&e.schemaVersion!=="1.0")throw new A(t,[{path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(e.schemaVersion)}; expected 1.0`}]);return{candidate:Ne(e),migratedFrom:n}}function we(e,t="ark.config.json"){let{candidate:n,migratedFrom:i}=xe(e,t),r=[];if(I(n,Y,"$",Y,r),r.length>0)throw new A(t,r);return{config:n,migratedFrom:i}}function Q(e,t="ark.config.json"){let n;try{n=JSON.parse(e)}catch(i){throw new A(t,[{path:"$",message:`invalid JSON: ${i instanceof Error?i.message:String(i)}`}])}return we(n,t)}function m(e){return typeof e=="string"&&e.length>0?e:void 0}function X(e,t){return Number.isInteger(e)&&Number(e)>0?Number(e):t}function Le(e,t,n){return e==="LAYER_IMPORT_VIOLATION"?t.typeOnly||n.targetTypeOnlyExports===!0||n.namedBindingsTypeOnly===!0?"Move the referenced type to a mutually allowed layer, use `import type`, then preflight again.":n.peerIsolation===!0?"Extract the shared dependency to a shared layer, then preflight again.":`Define a port in ${t.fromLayer??"the source layer"}, inject the ${t.toLayer??"outer-layer"} implementation, then preflight again.`:e==="FORBIDDEN_GLOBAL"?`Inject ${t.target??"the capability"} through a port, then preflight again.`:e==="CIRCULAR_DEPENDENCY"?"Extract the shared dependency into a third module, then preflight again.":e==="RAW_EVENT_PUBLISH"?"Publish through a registered intent creator, then run Ark again.":e==="PUBLISH_MISSING_SOURCE"?"Add metadata.source to the publish call, then run Ark again.":`Resolve ${e} without weakening ark.config.json, then run Ark again.`}function ee(e,t="error"){let n=m(e.ruleId)??m(e.code)??"ARK_UNKNOWN",i=e.severity==="warning"?"warning":t,r={...m(e.target)?{target:m(e.target)}:{},...m(e.fromLayer)?{fromLayer:m(e.fromLayer)}:{},...m(e.toLayer)?{toLayer:m(e.toLayer)}:{},...typeof e.typeOnly=="boolean"?{typeOnly:e.typeOnly}:{}};return{ruleId:n,severity:i,message:m(e.message)??n,location:{file:m(e.file)??"<unknown>",line:X(e.line,1),column:X(e.column,1)},evidence:r,nextAction:m(e.nextAction)??Le(n,r,e)}}var te={RAW_EVENT_PUBLISH:"Publish through a registered intent creator; raw event objects or intent strings bypass Ark contracts and tooling.",PUBLISH_MISSING_SOURCE:"Strict Ark publish calls must include metadata.source."};function _e(e){return/^(Domain|Application|Adapter|Workflow|Job|Presentation|Reporting|Metadata|Security|Audit|Observability|Kernel)\.[A-Za-z0-9_.]+$/.test(e)}function F(e){if(!e.publishCall)return[];let t=[];return(e.rawIntentName!==void 0&&_e(e.rawIntentName)||e.objectHasIntent)&&t.push({ruleId:"RAW_EVENT_PUBLISH",message:te.RAW_EVENT_PUBLISH}),e.arkPublishCandidate&&!e.hasSource&&t.push({ruleId:"PUBLISH_MISSING_SOURCE",message:te.PUBLISH_MISSING_SOURCE}),t}function N(e){if(typeof e.physicalFilename=="string"&&e.physicalFilename.length>0)return e.physicalFilename;if(typeof e.filename=="string"&&e.filename.length>0)return e.filename;if(typeof e.getFilename=="function")try{let t=e.getFilename();if(typeof t=="string"&&t.length>0)return t}catch{}return""}function x(e,t,n,i,r){let o=ee({...i,line:i.line??t.loc?.start?.line,column:i.column??(typeof t.loc?.start?.column=="number"?t.loc.start.column+1:void 0)});return e.report({node:t,messageId:n,...r?{data:r}:{},diagnostic:o}),o}function D(e){if(!e||e==="<input>"||e.startsWith("stdin"))return null;let t=c.default.dirname(c.default.resolve(e));for(;;){let n=c.default.join(t,"ark.config.json");if(b.default.existsSync(n))return n;let i=c.default.dirname(t);if(i===t)return null;t=i}}var M=new Map;function G(e){if(M.has(e))return M.get(e)??null;if(!b.default.existsSync(e))return null;let t=Q(b.default.readFileSync(e,"utf8"),e).config;return M.set(e,t),t}function re(e,t){if(!t.startsWith("."))return null;let n=c.default.resolve(c.default.dirname(e),t),i=[n,`${n}.ts`,`${n}.tsx`,`${n}.mts`,`${n}.cts`,`${n}.js`,`${n}.jsx`,c.default.join(n,"index.ts"),c.default.join(n,"index.tsx"),c.default.join(n,"index.js")];for(let r of i)try{if(b.default.existsSync(r)&&b.default.statSync(r).isFile())return r}catch{}return`${n}.ts`}function w(e){return typeof e?.value=="string"?e.value:void 0}function T(e){return e?.name??w(e)}function H(e){return e.sourceCode??e.getSourceCode?.()}function ie(e,t){let n=H(e)?.getScope?.(t);for(;n;){let i=n.references?.find(r=>r.identifier===t);if(i)return i;n=n.upper??void 0}}function ne(e,t,n){let i=ie(e,t);if(i?.resolved)return(i.resolved.defs?.length??0)>0;let r=H(e)?.getScope?.(t);for(;r;){let o=r.set?.get(n);if(o)return(o.defs?.length??0)>0;r=r.upper??void 0}return!1}function Oe(e,t){let n=ie(e,t);return n?n.isValueReference!==!1:t.parent?.type==="VariableDeclarator"&&t.parent.init===t}function oe(e){if(e?.type==="Identifier"&&e.name)return{root:e,segments:[e.name]};if(!e||!(e.type==="MemberExpression"||!!(e.object&&e.property))||e.computed===!0)return;let n=oe(e.object),i=T(e.property);if(!(!n||!i))return{root:n.root,segments:[...n.segments,i]}}function $e(e){return T(e.callee?.property)}function se(e,t){return e?.properties?.find(n=>T(n.key)===t)}function C(e,t){return se(e,t)!==void 0}function Pe(e){let t=se(e,"metadata")?.value;return C(t,"source")}function ae(e){return $e(e)==="publish"}var le={meta:{type:"problem",docs:{description:"Disallow imports that violate ark.config.json layer rules (same contract as arkgate-check)."},messages:{forbiddenImport:"Architecture: {{fromLayer}} must not import {{toLayer}} (ark.config.json). Specifier: {{specifier}}",forbiddenImportHeuristic:"Domain code must not import infrastructure, adapters, repositories, or database modules."},schema:[]},create(e){let t=N(e),n=D(t),i=n?G(n):null,r=n?c.default.dirname(n):null,o=s=>{let a=w(s.source);if(a&&i&&r&&t){let f=c.default.isAbsolute(t)?t:c.default.resolve(t),g=c.default.relative(r,f).split(c.default.sep).join("/"),l=S(g,i.layers);if(!l)return;let u=re(f,a);if(!u)return;let d=c.default.relative(r,u).split(c.default.sep).join("/");if(d.startsWith(".."))return;let p=S(d,i.layers);if(!p)return;P(i.rules,l,p,{fromPath:g,toPath:d,layers:i.layers})&&x(e,s,"forbiddenImport",{ruleId:"LAYER_IMPORT_VIOLATION",file:g,fromLayer:l,toLayer:p,target:d,...s.importKind==="type"?{typeOnly:!0}:{},message:`${l} must not import ${p}.`},{fromLayer:l,toLayer:p,specifier:a});return}};return{ImportDeclaration:o,ExportNamedDeclaration:o,ExportAllDeclaration:o}}},ce={meta:{type:"problem",docs:{description:"Require event bus publish calls to use registered intent creators instead of raw event objects or intent strings."},messages:{rawPublish:"Publish through a registered intent creator; raw event objects or intent strings bypass Ark contracts."},schema:[]},create(e){return{CallExpression(t){let n=t.arguments?.[0],i=w(n),r=F({publishCall:ae(t),rawIntentName:i,objectHasIntent:C(n,"intent"),arkPublishCandidate:!1,hasSource:!0});if(r.some(o=>o.ruleId==="RAW_EVENT_PUBLISH")){let o=r.find(s=>s.ruleId==="RAW_EVENT_PUBLISH");x(e,t,"rawPublish",{...o,file:N(e)})}}}}},ue={meta:{type:"problem",docs:{description:"Require event bus publish calls to include source metadata."},messages:{missingSource:"Strict Ark publish calls must include metadata.source."},schema:[]},create(e){return{CallExpression(t){let n=t.arguments?.[0],i=t.arguments?.[2],o=F({publishCall:ae(t),rawIntentName:w(n),objectHasIntent:C(n,"intent"),arkPublishCandidate:!0,hasSource:Pe(n)||C(i,"source")}).find(s=>s.ruleId==="PUBLISH_MISSING_SOURCE");o&&x(e,t,"missingSource",{...o,file:N(e)})}}}},fe={meta:{type:"problem",docs:{description:"Disallow ambient globals from the layer\u2019s forbiddenGlobals in ark.config.json (same purity surface as ark-check). Option `globals` explicitly overrides."},messages:{forbiddenGlobal:'Ambient global "{{name}}" is forbidden in {{layer}} (ark.config.json); inject the capability through a port instead.',forbiddenGlobalDefault:'Ambient global "{{name}}" is forbidden here; inject the capability through a port instead.'},schema:[{type:"object",properties:{globals:{type:"array",items:{type:"string"}}},additionalProperties:!1}]},create(e){let t=N(e),n=e.options?.[0],i=D(t),r=i?G(i):null,o=i?c.default.dirname(i):null,s=null,a="this layer";if(n?.globals)s=new Set(n.globals);else if(r&&o&&t){let l=c.default.isAbsolute(t)?t:c.default.resolve(t),u=c.default.relative(o,l).split(c.default.sep).join("/"),d=r.layers?.find(p=>p.name===S(u,r.layers));d?.forbiddenGlobals?.length?(s=new Set(d.forbiddenGlobals),a=d.name):s=null}if(!s)return{};let f=typeof H(e)?.getScope=="function",g=(l,u)=>{let d=c.default.isAbsolute(t)?t:c.default.resolve(t),p=o?c.default.relative(o,d).split(c.default.sep).join("/"):t;x(e,l,r?"forbiddenGlobal":"forbiddenGlobalDefault",{ruleId:"FORBIDDEN_GLOBAL",file:p,fromLayer:a,target:u,message:`${a} must not use the ambient global "${u}".`},{name:u,layer:a})};return{MemberExpression(l){if(l.parent?.type==="MemberExpression"&&l.parent.object===l)return;let u=oe(l);if(!u||ne(e,u.root,u.segments[0]))return;let d=u.segments[0]==="globalThis",p=d?u.segments.slice(1):u.segments,L;for(let _=p.length;_>=(d?1:2);_-=1){let U=p.slice(0,_).join(".");if(s.has(U)){L=U;break}}L?g(l,L):!f&&s.has(u.segments[0])&&g(l,u.segments[0])},CallExpression(l){if(f)return;let u=l.callee?.type==="Identifier"?l.callee.name:void 0;u&&s.has(u)&&g(l,u)},NewExpression(l){if(f)return;let u=l.callee?.type==="Identifier"?l.callee.name:void 0;u&&s.has(u)&&g(l,u)},Identifier(l){!f||!l.name||!s.has(l.name)||!Oe(e,l)||ne(e,l,l.name)||g(l,l.name)}}}},je={"no-domain-infra-imports":le,"no-raw-event-publish":ce,"require-publish-source":ue,"no-forbidden-globals":fe},E={rules:je};E.configs={recommended:{plugins:{ark:E},rules:{"ark/no-domain-infra-imports":"error","ark/no-raw-event-publish":"error","ark/require-publish-source":"error","ark/no-forbidden-globals":"error"}}};var Ve=E;0&&(module.exports={findConfigPath,globToRegExp,isEdgeDenied,layerForRelativePath,loadArkConfig,noDomainInfraImports,noForbiddenGlobals,noRawEventPublish,patternSpecificity,plugin,requirePublishSource,resolveRelativeImport});
|
package/dist/eslint/index.d.cts
CHANGED
package/dist/eslint/index.d.ts
CHANGED