arkgate 3.1.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 +82 -0
- package/README.md +29 -12
- package/bin/lib/analysis-engine.mjs +6 -5
- package/bin/lib/contract-smells.mjs +514 -0
- package/bin/lib/doctor-plan.mjs +8 -0
- 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 +32 -4
- package/docs/ai-gates.md +9 -14
- package/docs/demos/01-write-gate-self-correction.md +2 -2
- package/docs/enthusiast/README.md +5 -1
- package/docs/enthusiast/how-to-agent-gates.md +3 -5
- package/docs/enthusiast/how-to-policy-pack.md +4 -1
- package/docs/enthusiast/reference-archetypes.md +8 -1
- package/docs/enthusiast/reference-commands.md +8 -2
- package/docs/package-surface.md +5 -1
- package/docs/threat-model.md +3 -2
- package/package.json +2 -2
- package/server.json +3 -3
- package/dist/configContract-BxSIwVRo.d.cts +0 -259
- package/dist/configContract-BxSIwVRo.d.ts +0 -259
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,88 @@ 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
|
+
|
|
44
|
+
## 3.2.0 — 2026-07-15
|
|
45
|
+
|
|
46
|
+
Contract health (Phase W): ArkGate now also meta-lints the contract itself and describes its
|
|
47
|
+
governance weight, and the docs name the enforcement-boundary trade-off explicitly. Everything in
|
|
48
|
+
this release is **advisory only** — no verdict, `designFitness`, `patternBets`, or gate result
|
|
49
|
+
changes. **No breaking** CLI or `ark.config.json` changes. **No gate weaken.**
|
|
50
|
+
|
|
51
|
+
### Added
|
|
52
|
+
|
|
53
|
+
- **W01 contract smells:** `ark-check --doctor --json` gains `doctor.contractHealth` with four
|
|
54
|
+
stable, deterministic smell ids that lint the contract rather than the code:
|
|
55
|
+
`contract-bidirectional-allow` (both directions explicitly allowed between two layers),
|
|
56
|
+
`contract-peripheral-depends-core` (audit/observability layer allowed into
|
|
57
|
+
orchestration/persistence), `contract-lateral-adapter-allow` (adapter layer allowed into a
|
|
58
|
+
sibling adapter layer), and `contract-dead-rule` (rule referencing an unknown or empty layer, or
|
|
59
|
+
a same-layer no-op; `optional: true` layers are exempt). Each smell carries `severity`,
|
|
60
|
+
sorted `evidence[]` with honest `…(+N more)` truncation, technical `message`, plain-language
|
|
61
|
+
`outcome`, and `fix`. Human doctor prints a "Contract health (advisory)" section.
|
|
62
|
+
- **Acknowledgment sidecar:** deliberate edges are recorded in an optional
|
|
63
|
+
`.ark/contract-smell-acks.json` (`{ acks: [{ id, edge, reason }] }`; bidirectional edges
|
|
64
|
+
order-insensitive) — the versioned `ark.config.json` schema is untouched. The file is bounded
|
|
65
|
+
(≤64 KB, ≤200 entries); a malformed file or edge grammar is reported via `ackFile.invalid` and
|
|
66
|
+
never suppresses a smell. `contractHealth.acknowledged` counts applied acks only.
|
|
67
|
+
- **W02 governance weight:** `doctor.contractHealth.governanceWeight` reports raw facts
|
|
68
|
+
(declared/populated layers, governed files, rules, denied/allowed edges, files-per-layer,
|
|
69
|
+
rules-per-layer) plus a fixed comparative band — `heavy` (fewer than 25 governed files per layer
|
|
70
|
+
AND 6+ layers or 4+ rules per layer), `light` (≤2 layers over 150+ governed files), `typical`,
|
|
71
|
+
or `unknown` — with fixed wording and an explicit `notAScore: true`. Banding uses raw ratios;
|
|
72
|
+
reported ratios are rounded for display. The heavy note asks to justify NEW layers with
|
|
73
|
+
demonstrated pressure and never suggests deleting working ones.
|
|
74
|
+
- **W03 enforcement-boundary positioning:** README explains why the hard guarantee lives at the
|
|
75
|
+
required merge status ("deliberate trade-off, not a gap"; the contract doubles as a pressure
|
|
76
|
+
sensor), and `docs/ai-gates.md` / `docs/agent-guide.md` carry the same framing next to the
|
|
77
|
+
canonical host support matrix. A docs regression pins the wording without strengthening any
|
|
78
|
+
guarantee claim.
|
|
79
|
+
|
|
80
|
+
### Fixed
|
|
81
|
+
|
|
82
|
+
- Contract meta-lint reads the rules actually in force (manifest-aware), not only `config.rules`.
|
|
83
|
+
- Hostile ack-file inputs (FIFO/symlink targets, oversized files, sloppy edge strings) can no
|
|
84
|
+
longer hang `--doctor`, exhaust memory, or silently suppress findings; null rule entries and
|
|
85
|
+
malformed coverage rows no longer throw.
|
|
86
|
+
- Governance-weight banding is size-relative in both clauses: a large tree with a proportionate
|
|
87
|
+
dense rule matrix never reads `heavy`, and NaN/negative counts read `unknown`.
|
|
88
|
+
|
|
7
89
|
## 3.1.0 — 2026-07-15
|
|
8
90
|
|
|
9
91
|
Deterministic change integrity. **No breaking** CLI or `ark.config.json` changes. **No gate
|
package/README.md
CHANGED
|
@@ -16,8 +16,9 @@ and makes sure a “green” check means something real.
|
|
|
16
16
|
|
|
17
17
|
</div>
|
|
18
18
|
|
|
19
|
-
> **ArkGate 3.0**
|
|
20
|
-
>
|
|
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).
|
|
21
22
|
|
|
22
23
|
---
|
|
23
24
|
|
|
@@ -156,7 +157,7 @@ Aliases `ark` / `ark-check` / `ark-mcp` still work. **npm / pnpm / yarn**. No in
|
|
|
156
157
|
<details>
|
|
157
158
|
<summary>What <code>/ark-autopilot</code> does under the hood (optional detail)</summary>
|
|
158
159
|
|
|
159
|
-
1. Setup if needed (`ark start`
|
|
160
|
+
1. Setup if needed (`ark start` previews; review, then `ark start --apply`).
|
|
160
161
|
2. **Explore pass** (decision-grade map of *this* product; field path when demos exist).
|
|
161
162
|
3. **Dual plan:** **A** remediation from `--plan` (mechanical-safe only by default); **B** pattern/evolution bets (never auto-applied as mechanical-safe). Empty plan ≠ “healthy” without explore/B.
|
|
162
163
|
4. Apply A → re-check; judgment only when you ask for full apply.
|
|
@@ -243,6 +244,22 @@ Brownfield phases: **Align** (honest contract) → **Stabilize** (real baseline)
|
|
|
243
244
|
This table describes the supported profile **after its files are installed and the host loads/trusts them**. A hard local boundary covers only the listed hook operations; alternate tools, direct filesystem writes, and human edits still rely on CI. MCP validation is advisory because the agent must call it. The CI check blocks a merge only when the repository makes that status required. Repair payloads never write code silently: the host must re-inject the candidate and ArkGate revalidates it. Run `arkgate-check --doctor` for the evidence actually detected in the current repository.
|
|
244
245
|
<!-- arkgate-host-support:end -->
|
|
245
246
|
|
|
247
|
+
#### Why the hard guarantee lives at the merge gate
|
|
248
|
+
|
|
249
|
+
The split above is a deliberate trade-off, not a gap. ArkGate validates at the earliest boundary
|
|
250
|
+
each host offers and enforces at the earliest boundary a repository can make non-bypassable: the
|
|
251
|
+
required merge status. Hard hooks (Claude Code, Grok Build) deny the listed write operations at
|
|
252
|
+
write time; advisory surfaces (MCP, rules) coach the agent while it works. But any local boundary
|
|
253
|
+
can be routed around — another tool, a direct filesystem write, a human edit — so the only
|
|
254
|
+
guarantee ArkGate claims for every path is the `arkgate-check --strict-merge` check, and only when
|
|
255
|
+
the repository makes that status required. Local checks optimize feedback speed; the merge gate
|
|
256
|
+
owns correctness.
|
|
257
|
+
|
|
258
|
+
A useful consequence: the contract doubles as a pressure sensor. Recurring violations or baseline
|
|
259
|
+
exceptions concentrated on one layer edge are evidence that the current design stopped fitting the
|
|
260
|
+
code — a reason to reshape the contract deliberately (start with `/ark-explore`), never to weaken
|
|
261
|
+
the gate.
|
|
262
|
+
|
|
246
263
|
Detailed setup: [docs/ai-gates.md](docs/ai-gates.md).
|
|
247
264
|
|
|
248
265
|
---
|
|
@@ -264,7 +281,9 @@ ark.config.json
|
|
|
264
281
|
finding ids. See the [configuration and editor guide](docs/configuration.md).
|
|
265
282
|
- **Frameworks:** Nest / Next / express / library layouts get sensible globs on init so day-one coverage is real.
|
|
266
283
|
- **Brownfield:** baseline ratchet, refuse to freeze a wrong contract, `/ark-adopt` for mature trees.
|
|
267
|
-
- **Agents:** `ark start`
|
|
284
|
+
- **Agents:** `ark start` previews one compact active-host router (≤5 files / 25 KB); `--apply`
|
|
285
|
+
writes those exact bytes. Full skills remain explicit via `--install-agent-gates --skills-only`;
|
|
286
|
+
reports remain opt-in via `ark-check --report`.
|
|
268
287
|
- **Write protocol (2.10 / Track W):** mechanical-safe **autoPatch** on the write gate (`import type`); MCP **`ark_prepare_write`** (place + validate + patch + judgmentBrief); opt-in hook **`--hook-repair`** (`ARK_REPAIR_JSON`); doctor **`writePath`** (repair vs reject-only); loop-cost eval (`npm run eval:loop-cost`). Port-proof inject is **judgment** (arity change), not silent auto-apply.
|
|
269
288
|
- **Enforcement ladder (Phase T):** doctor JSON exposes `writePath.enforcementLadder` with separate
|
|
270
289
|
`supported`, `installed`, `active`, `bypassable`, evidence, operation coverage, and required-status
|
|
@@ -274,11 +293,8 @@ ark.config.json
|
|
|
274
293
|
casts, InMemory runtime defaults, and disabled peer isolation. `--strict` is a compatibility
|
|
275
294
|
alias. Neither requires an editor hook; use `--require-write-hook claude|grok` when that local
|
|
276
295
|
guarantee is part of the check.
|
|
277
|
-
- **
|
|
278
|
-
|
|
279
|
-
branch). The V05 beta-exit audit passed with 12 pinned public adoptions, 97% median governed
|
|
280
|
-
coverage, and zero P0/P1 findings. Stable publication remains the signed-tag, GitHub Release,
|
|
281
|
-
and provenance-backed npm workflow documented in [the 3.0.0 release notes](docs/releases/3.0.0.md).
|
|
296
|
+
- **Release evidence:** independent 3.0 audit baseline plus signed-tag, GitHub Release, and
|
|
297
|
+
provenance-backed npm publication; see the [3.1.0 release notes](docs/releases/3.1.0.md).
|
|
282
298
|
- **TypeScript:** project compilers 5.x / 6.x / 7.x — gate falls back to a nested JS-API TypeScript when TS 7’s main export is version-only ([docs/typescript-support.md](docs/typescript-support.md)).
|
|
283
299
|
|
|
284
300
|
### Why not only ESLint / dependency-cruiser / Nx?
|
|
@@ -357,16 +373,17 @@ for real systems. Details: [production-hardening.md](https://github.com/pedrokni
|
|
|
357
373
|
| Audience | Link |
|
|
358
374
|
|----------|------|
|
|
359
375
|
| New builders (plain language) | [docs/enthusiast/](docs/enthusiast/README.md) |
|
|
360
|
-
| **Package surface
|
|
361
|
-
| Wire
|
|
376
|
+
| **Package surface and configuration** | [package policy](docs/package-surface.md) · [contract](docs/configuration.md) |
|
|
377
|
+
| Wire agents + **ESLint (CI-parity)** | [docs/ai-gates.md](docs/ai-gates.md) · [threat model](docs/threat-model.md) |
|
|
362
378
|
| **TypeScript 5 / 6 / 7 support** | [docs/typescript-support.md](docs/typescript-support.md) |
|
|
363
379
|
| Migrate from `ark-runtime-kernel` | [docs/migrate-from-ark-runtime-kernel.md](https://github.com/pedroknigge/arkgate/blob/main/docs/migrate-from-ark-runtime-kernel.md) |
|
|
364
380
|
| Messy existing repo | [docs/brownfield-adoption.md](docs/brownfield-adoption.md) |
|
|
365
381
|
| Agent / MCP tools | [docs/agent-guide.md](docs/agent-guide.md) |
|
|
382
|
+
| Security reporting | [SECURITY.md](SECURITY.md) |
|
|
366
383
|
| Demos | [docs/demos/](docs/demos/) |
|
|
367
384
|
| Examples | [examples/](examples/README.md) |
|
|
368
385
|
| Latest release (3.1.0) | [release notes](docs/releases/3.1.0.md) · [3.0.0 baseline](docs/releases/3.0.0.md) |
|
|
369
|
-
| Roadmap | [ROADMAP.md](ROADMAP.md) · [Changelog](CHANGELOG.md) |
|
|
386
|
+
| Roadmap and decisions | [ROADMAP.md](ROADMAP.md) · [ADRs](docs/adr/) · [Changelog](CHANGELOG.md) |
|
|
370
387
|
|
|
371
388
|
---
|
|
372
389
|
|
|
@@ -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};
|