arkgate 3.0.3 → 3.0.4
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 +34 -1
- package/bin/ark-check.mjs +10 -0
- package/bin/lib/html-report-depth.mjs +282 -0
- package/bin/lib/html-report.mjs +214 -21
- package/bin/lib/skill-install.mjs +2 -1
- package/bin/lib/write-path-detect.mjs +25 -14
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/server.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,7 +4,40 @@ All notable changes to ArkGate (`arkgate`; formerly `ark-runtime-kernel`) are do
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
-
No changes are scheduled after 3.0.
|
|
7
|
+
No changes are scheduled after 3.0.4.
|
|
8
|
+
|
|
9
|
+
## 3.0.4 — 2026-07-14
|
|
10
|
+
|
|
11
|
+
Report honesty + showcase depth patch. **No breaking** CLI or `ark.config.json` changes.
|
|
12
|
+
**No gate weaken.**
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- **HTML report false ADAPT:** `computeReportFitness` counted *any* `optional: true` layer
|
|
17
|
+
with files as `coreOptionalWithFiles`, so doctor could report **ENFORCE** while
|
|
18
|
+
`ark-report.html` / `latest.json` mode stayed **ADAPT** (secondary layers like
|
|
19
|
+
SharedKernel / Integration / Workflow). Report now uses the same `CORE_LAYER_NAMES`
|
|
20
|
+
filter as doctor adoption (`DomainModel`, `ApplicationOrchestration`,
|
|
21
|
+
`PresentationAdapters`, `PersistenceAdapters`).
|
|
22
|
+
- **False adoption gap `write-path-none` on report/CI:** when `activeHost` is `unknown`
|
|
23
|
+
(plain `npx ark-check --report` outside an agent session) but the repo inventory already
|
|
24
|
+
has hard-write hooks or advisory MCP for Claude/Grok/Cursor/Codex, doctor/report no longer
|
|
25
|
+
open a `write-path-none` adoption gap. Session projection still reports `mode: none` for
|
|
26
|
+
honesty (other hosts' hooks are not a guarantee for this process). `detectActiveAgentHost`
|
|
27
|
+
also recognizes `GROK_AGENT`.
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- **Report metric hints:** HTML showcase KPIs (hero, adoption, contract density, debt) show
|
|
32
|
+
plain-language micro-copy under each tile plus native tooltips; PASS/mode badges and score
|
|
33
|
+
parts (Coverage/Clean/Gates/Rules) explain what they mean for newcomers.
|
|
34
|
+
- **Report design-depth strip:** `ark-check --report` includes doctor-parity Shape residual
|
|
35
|
+
(design-weak badge, smell outcomes, one next pilot, post-green door, optional golden pattern).
|
|
36
|
+
Clean ENFORCE with no smells shows a short “Design depth · OK” note (only when sensors ran).
|
|
37
|
+
- **Report adoption extras:** write-path line (active host · mode · inventory on disk) and a
|
|
38
|
+
fixed baseline-policy legend (`keep-empty` / `active-ratchet` / `absent`).
|
|
39
|
+
|
|
40
|
+
Release note: `docs/releases/3.0.4.md`.
|
|
8
41
|
|
|
9
42
|
## 3.0.3 — 2026-07-13
|
|
10
43
|
|
package/bin/ark-check.mjs
CHANGED
|
@@ -58,6 +58,7 @@ import {
|
|
|
58
58
|
reportsDir,
|
|
59
59
|
readJsonSafe,
|
|
60
60
|
} from './lib/html-report.mjs';
|
|
61
|
+
import { buildReportDepthPayload } from './lib/html-report-depth.mjs';
|
|
61
62
|
import { shouldOpenHtmlReport, openHtmlInBrowser } from './lib/open-html.mjs';
|
|
62
63
|
import {
|
|
63
64
|
computeCoverage,
|
|
@@ -1266,6 +1267,13 @@ async function main() {
|
|
|
1266
1267
|
const existingOrigin = args.resetOrigin
|
|
1267
1268
|
? null
|
|
1268
1269
|
: readJsonSafe(path.join(reportsDir(root), 'origin.json'));
|
|
1270
|
+
const { adoption: adoptionForReport, designDepth } = buildReportDepthPayload(
|
|
1271
|
+
root,
|
|
1272
|
+
config,
|
|
1273
|
+
files,
|
|
1274
|
+
coverage,
|
|
1275
|
+
activeViolations
|
|
1276
|
+
);
|
|
1269
1277
|
const reportPayload = {
|
|
1270
1278
|
root,
|
|
1271
1279
|
config,
|
|
@@ -1282,6 +1290,8 @@ async function main() {
|
|
|
1282
1290
|
originSnapshot: existingOrigin,
|
|
1283
1291
|
currentSnapshot,
|
|
1284
1292
|
originJustCreated: !existingOrigin,
|
|
1293
|
+
adoption: adoptionForReport,
|
|
1294
|
+
designDepth,
|
|
1285
1295
|
};
|
|
1286
1296
|
const html = args.beginner
|
|
1287
1297
|
? renderBeginnerHtmlReport(reportPayload)
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Design-depth + adoption extras for the HTML showcase report.
|
|
3
|
+
* Kept separate from html-report.mjs so the main renderer stays under LOC budget.
|
|
4
|
+
* Does not import html-report.mjs (avoids a cycle).
|
|
5
|
+
*/
|
|
6
|
+
import {
|
|
7
|
+
detectDesignSmells,
|
|
8
|
+
summarizeDesignFitness,
|
|
9
|
+
buildPatternBetsFromSmells,
|
|
10
|
+
} from './design-smells.mjs';
|
|
11
|
+
import { summarizePilotLoop } from './pilot-loop.mjs';
|
|
12
|
+
import { buildPostGreenNextAction } from './post-green-path.mjs';
|
|
13
|
+
import { loadGoldenPattern, summarizeGoldenPattern } from './golden-pattern.mjs';
|
|
14
|
+
import { collectAdoptionGaps } from './mcp-adoption.mjs';
|
|
15
|
+
|
|
16
|
+
function esc(value) {
|
|
17
|
+
return String(value)
|
|
18
|
+
.replace(/&/g, '&')
|
|
19
|
+
.replace(/</g, '<')
|
|
20
|
+
.replace(/>/g, '>')
|
|
21
|
+
.replace(/"/g, '"');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Doctor-parity design depth + adoption for ark-check --report.
|
|
26
|
+
* @param {string} root
|
|
27
|
+
* @param {object} config
|
|
28
|
+
* @param {string[]} files
|
|
29
|
+
* @param {object} coverage
|
|
30
|
+
* @param {object[]} activeViolations
|
|
31
|
+
*/
|
|
32
|
+
export function buildReportDepthPayload(root, config, files, coverage, activeViolations = []) {
|
|
33
|
+
const designSmells = detectDesignSmells(root, config, files, coverage);
|
|
34
|
+
const designFitness = summarizeDesignFitness(designSmells, {
|
|
35
|
+
activeViolations: activeViolations.length,
|
|
36
|
+
governedPercent: coverage?.governed?.percent,
|
|
37
|
+
totalFiles: coverage?.governed?.totalFiles,
|
|
38
|
+
});
|
|
39
|
+
const postGreenPath = buildPostGreenNextAction(designFitness);
|
|
40
|
+
const patternBets = buildPatternBetsFromSmells(designSmells);
|
|
41
|
+
const pilotLoop = summarizePilotLoop({
|
|
42
|
+
designWeak: designFitness.designWeak,
|
|
43
|
+
patternBets,
|
|
44
|
+
designSmells,
|
|
45
|
+
});
|
|
46
|
+
const goldenPattern = summarizeGoldenPattern(loadGoldenPattern(root));
|
|
47
|
+
const adoption = collectAdoptionGaps(root, config, coverage);
|
|
48
|
+
return {
|
|
49
|
+
adoption,
|
|
50
|
+
designDepth: {
|
|
51
|
+
designFitness,
|
|
52
|
+
designSmells,
|
|
53
|
+
pilotLoop,
|
|
54
|
+
postGreenPath,
|
|
55
|
+
goldenPattern,
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Write-path mode → human meaning (active host projection). */
|
|
61
|
+
export function writePathModeHint(mode) {
|
|
62
|
+
switch (String(mode || '')) {
|
|
63
|
+
case 'repair':
|
|
64
|
+
return 'Hard write hook with repair payload — best co-pilot path for the active host.';
|
|
65
|
+
case 'reject-only':
|
|
66
|
+
return 'Hard write boundary without repair payload; edits can be blocked without guided re-entry.';
|
|
67
|
+
case 'mcp-only':
|
|
68
|
+
return 'Advisory MCP only — prepare-write/autoPatch available, no hard PreToolUse for this host.';
|
|
69
|
+
case 'none':
|
|
70
|
+
return 'No hard write boundary or advisory MCP for the active host (or host is unknown in this process).';
|
|
71
|
+
default:
|
|
72
|
+
return 'Session write-path capability for the active agent host.';
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Configured hosts from writePath inventory (hard or advisory evidence on disk).
|
|
78
|
+
* @param {object|null|undefined} writePath
|
|
79
|
+
* @returns {string[]}
|
|
80
|
+
*/
|
|
81
|
+
export function inventoryConfiguredHosts(writePath) {
|
|
82
|
+
const hosts = writePath?.inventory?.hosts;
|
|
83
|
+
if (!hosts || typeof hosts !== 'object') return [];
|
|
84
|
+
return Object.entries(hosts)
|
|
85
|
+
.filter(([, rec]) => rec && rec.configured)
|
|
86
|
+
.map(([name]) => name);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Compact write-path line for the Adoption card.
|
|
91
|
+
* @param {object|null|undefined} writePath
|
|
92
|
+
*/
|
|
93
|
+
export function renderWritePathAdoptionBlock(writePath) {
|
|
94
|
+
if (!writePath || typeof writePath !== 'object') return '';
|
|
95
|
+
const mode = writePath.mode || 'none';
|
|
96
|
+
const host = writePath.activeHost || 'unknown';
|
|
97
|
+
const inv = inventoryConfiguredHosts(writePath);
|
|
98
|
+
const invLine =
|
|
99
|
+
inv.length > 0
|
|
100
|
+
? `Inventory on disk: ${inv.map((h) => esc(h)).join(', ')}.`
|
|
101
|
+
: 'No host write gates found on disk yet.';
|
|
102
|
+
const unknownNote =
|
|
103
|
+
host === 'unknown' && inv.length > 0
|
|
104
|
+
? ' Session host unknown (shell/CI) — inventory is still real; set ARK_ACTIVE_HOST or run from an agent for session-accurate mode.'
|
|
105
|
+
: '';
|
|
106
|
+
const gapNote = writePath.gap
|
|
107
|
+
? ` Gap: <b>${esc(writePath.gap.id)}</b> — ${esc(writePath.gap.message || '')}`
|
|
108
|
+
: '';
|
|
109
|
+
// invLine / gapNote already include escaped user content; only plain strings go through esc().
|
|
110
|
+
return `<div class="write-path-block" title="${esc(writePathModeHint(mode))}">
|
|
111
|
+
<p class="dim" style="margin:.65rem 0 .2rem;font-size:.84rem">
|
|
112
|
+
<b>Write path</b> · active host <code>${esc(host)}</code>
|
|
113
|
+
· mode <code>${esc(mode)}</code>
|
|
114
|
+
${writePath.hookRepair ? '· repair ✓' : writePath.hookPresent ? '· reject-only' : ''}
|
|
115
|
+
${writePath.mcpPresent ? '· MCP ✓' : ''}
|
|
116
|
+
</p>
|
|
117
|
+
<p class="kpi-hint" style="max-width:none;margin:0">
|
|
118
|
+
${esc(writePathModeHint(mode))} ${invLine}${esc(unknownNote)}${gapNote}
|
|
119
|
+
</p>
|
|
120
|
+
</div>`;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Fixed legend for baseline policy signals. */
|
|
124
|
+
export function renderBaselineSignalLegend() {
|
|
125
|
+
return `<details class="baseline-legend" style="margin-top:.75rem">
|
|
126
|
+
<summary>Baseline policy signals (legend)</summary>
|
|
127
|
+
<ul class="senior-list" style="margin-top:.4rem">
|
|
128
|
+
<li><b>keep-empty</b> — ${esc(baselineLegendBody('keep-empty'))}</li>
|
|
129
|
+
<li><b>active-ratchet</b> — ${esc(baselineLegendBody('active-ratchet'))}</li>
|
|
130
|
+
<li><b>absent</b> — ${esc(baselineLegendBody('absent'))}</li>
|
|
131
|
+
</ul>
|
|
132
|
+
</details>`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function baselineLegendBody(signal) {
|
|
136
|
+
switch (signal) {
|
|
137
|
+
case 'keep-empty':
|
|
138
|
+
return '`.ark-baseline.json` exists with 0 frozen keys; every violation is active (honest green).';
|
|
139
|
+
case 'active-ratchet':
|
|
140
|
+
return 'Known debt keys are frozen; new distinct violations still fail the check.';
|
|
141
|
+
case 'absent':
|
|
142
|
+
return 'No baseline file — all findings are active (or freeze not adopted).';
|
|
143
|
+
default:
|
|
144
|
+
return '';
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Design-weak / Shape residual strip for the showcase report.
|
|
150
|
+
* Null HTML when there is nothing useful to show.
|
|
151
|
+
*
|
|
152
|
+
* @param {{
|
|
153
|
+
* designFitness?: object|null,
|
|
154
|
+
* designSmells?: object[],
|
|
155
|
+
* pilotLoop?: object|null,
|
|
156
|
+
* postGreenPath?: object|null,
|
|
157
|
+
* goldenPattern?: object|null,
|
|
158
|
+
* mode?: string,
|
|
159
|
+
* }} depth
|
|
160
|
+
*/
|
|
161
|
+
export function renderDesignDepthStrip(depth = {}) {
|
|
162
|
+
const fitness = depth.designFitness;
|
|
163
|
+
const smells = Array.isArray(depth.designSmells) ? depth.designSmells : [];
|
|
164
|
+
const designWeak = fitness?.designWeak === true;
|
|
165
|
+
if (!designWeak && smells.length === 0) return '';
|
|
166
|
+
|
|
167
|
+
const mode = String(depth.mode || '').toLowerCase();
|
|
168
|
+
const title = designWeak
|
|
169
|
+
? mode === 'enforce'
|
|
170
|
+
? 'ENFORCE · design-weak'
|
|
171
|
+
: `${(mode || 'edges').toUpperCase()} · design-weak`
|
|
172
|
+
: 'Design smells (edges still open)';
|
|
173
|
+
const lede = designWeak
|
|
174
|
+
? 'Contract edges are clean, but lived design residual remains. This does not fail PASS — it blocks “healthy finished” until Shape work lands.'
|
|
175
|
+
: 'Design smells exist alongside open edge debt. Fix edges first; treat smells as Shape residual after green.';
|
|
176
|
+
|
|
177
|
+
const smellItems = smells
|
|
178
|
+
.slice(0, 6)
|
|
179
|
+
.map((s) => {
|
|
180
|
+
const outcome = s.outcome || s.message || s.id;
|
|
181
|
+
const evidence = (s.evidence || [])
|
|
182
|
+
.filter((e) => typeof e === 'string' && !e.startsWith('layer:') && !e.startsWith('layout:'))
|
|
183
|
+
.slice(0, 3);
|
|
184
|
+
const ev =
|
|
185
|
+
evidence.length > 0
|
|
186
|
+
? ` <span class="dim">· ${evidence.map((e) => `<code>${esc(e)}</code>`).join(' ')}</span>`
|
|
187
|
+
: '';
|
|
188
|
+
return `<li><b>${esc(s.id)}</b> — ${esc(outcome)}${ev}</li>`;
|
|
189
|
+
})
|
|
190
|
+
.join('');
|
|
191
|
+
|
|
192
|
+
const pilot = depth.pilotLoop?.active && depth.pilotLoop?.nextPilot ? depth.pilotLoop.nextPilot : null;
|
|
193
|
+
const pilotHtml = pilot
|
|
194
|
+
? `<div class="pilot-card">
|
|
195
|
+
<h3 style="margin-top:.85rem">Next pilot (one at a time)</h3>
|
|
196
|
+
<p class="dim" style="margin:.15rem 0 .4rem;font-size:.86rem">
|
|
197
|
+
Judgment only — never mechanical-safe · never multi-pilot batch
|
|
198
|
+
</p>
|
|
199
|
+
<ul class="senior-list">
|
|
200
|
+
<li><b>Smell</b> · <code>${esc(pilot.smellId || pilot.id || '—')}</code></li>
|
|
201
|
+
<li><b>Target</b> · <code>${esc(pilot.pilotTarget || pilot.pilot || '—')}</code></li>
|
|
202
|
+
${
|
|
203
|
+
pilot.move || pilot.fix
|
|
204
|
+
? `<li><b>Move</b> · ${esc(pilot.move || pilot.fix)}</li>`
|
|
205
|
+
: ''
|
|
206
|
+
}
|
|
207
|
+
${
|
|
208
|
+
pilot.successSignal
|
|
209
|
+
? `<li><b>Success</b> · ${esc(pilot.successSignal)}</li>`
|
|
210
|
+
: ''
|
|
211
|
+
}
|
|
212
|
+
${
|
|
213
|
+
pilot.killSwitch
|
|
214
|
+
? `<li><b>Kill-switch</b> · ${esc(pilot.killSwitch)}</li>`
|
|
215
|
+
: ''
|
|
216
|
+
}
|
|
217
|
+
</ul>
|
|
218
|
+
</div>`
|
|
219
|
+
: '';
|
|
220
|
+
|
|
221
|
+
const next =
|
|
222
|
+
depth.postGreenPath?.short ||
|
|
223
|
+
depth.postGreenPath?.action ||
|
|
224
|
+
(designWeak
|
|
225
|
+
? '/ark-explore shape-focus → dual-plan B, then /ark-autopilot only with OK'
|
|
226
|
+
: null);
|
|
227
|
+
const nextHtml = next
|
|
228
|
+
? `<p class="meta" style="margin-top:.75rem"><b>Primary next</b> · ${esc(next)}</p>`
|
|
229
|
+
: '';
|
|
230
|
+
|
|
231
|
+
const golden = depth.goldenPattern;
|
|
232
|
+
const goldenHtml =
|
|
233
|
+
golden && golden.present !== false && (golden.name || golden.norm)
|
|
234
|
+
? `<p class="dim" style="margin-top:.5rem;font-size:.84rem">
|
|
235
|
+
Golden pattern (advisory for <b>new</b> code only):
|
|
236
|
+
<code>${esc(golden.name || 'pattern')}</code>
|
|
237
|
+
${golden.norm ? ` — ${esc(golden.norm)}` : ''}
|
|
238
|
+
${golden.examplePath ? ` · e.g. <code>${esc(golden.examplePath)}</code>` : ''}
|
|
239
|
+
</p>`
|
|
240
|
+
: designWeak
|
|
241
|
+
? `<p class="dim" style="margin-top:.5rem;font-size:.84rem">
|
|
242
|
+
No <code>.ark/golden-pattern.json</code> yet — optional; helps agents place <b>new</b> code only.
|
|
243
|
+
</p>`
|
|
244
|
+
: '';
|
|
245
|
+
|
|
246
|
+
return `<div class="section card design-strip ${designWeak ? 'is-weak' : 'has-smells'}" id="design-depth">
|
|
247
|
+
<div class="design-head">
|
|
248
|
+
<span class="badge design" title="Shape residual — separate from PASS/FAIL edge honesty">${esc(title)}</span>
|
|
249
|
+
<span class="dim" style="font-size:.86rem">${designWeak ? 'Edges clean · residual remains' : 'Smells + open edges'}</span>
|
|
250
|
+
</div>
|
|
251
|
+
<p class="dim" style="margin:.55rem 0 .5rem;font-size:.9rem">${esc(lede)}</p>
|
|
252
|
+
${smellItems ? `<ul class="senior-list">${smellItems}</ul>` : ''}
|
|
253
|
+
${pilotHtml}
|
|
254
|
+
${nextHtml}
|
|
255
|
+
${goldenHtml}
|
|
256
|
+
</div>`;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Optional clean-depth note when edges + design are both healthy.
|
|
261
|
+
* Requires designFitness from a real sensor run (object). Null/undefined means
|
|
262
|
+
* depth was not computed — do not claim “OK” from missing data.
|
|
263
|
+
* @param {{ designFitness?: object|null, ok?: boolean, mode?: string }} depth
|
|
264
|
+
*/
|
|
265
|
+
export function renderDesignCleanNote(depth = {}) {
|
|
266
|
+
if (!depth.ok) return '';
|
|
267
|
+
// Sensors never ran (callers that omit designDepth) → no strip.
|
|
268
|
+
if (depth.designFitness == null || typeof depth.designFitness !== 'object') return '';
|
|
269
|
+
if (depth.designFitness.designWeak) return '';
|
|
270
|
+
if ((depth.designFitness.smellCount ?? 0) > 0) return '';
|
|
271
|
+
if (String(depth.mode || '').toLowerCase() !== 'enforce') return '';
|
|
272
|
+
return `<div class="section card design-strip is-clean" id="design-depth">
|
|
273
|
+
<div class="design-head">
|
|
274
|
+
<span class="badge design-ok" title="No deterministic design smells with clean edges">Design depth · OK</span>
|
|
275
|
+
<span class="dim" style="font-size:.86rem">No design-weak residual detected</span>
|
|
276
|
+
</div>
|
|
277
|
+
<p class="dim" style="margin:.45rem 0 0;font-size:.88rem">
|
|
278
|
+
Edges and deterministic design sensors agree. Keep placing new code on the golden path;
|
|
279
|
+
re-run doctor after large refactors.
|
|
280
|
+
</p>
|
|
281
|
+
</div>`;
|
|
282
|
+
}
|
package/bin/lib/html-report.mjs
CHANGED
|
@@ -11,6 +11,13 @@ import {
|
|
|
11
11
|
resolveOperatingMode,
|
|
12
12
|
} from '../ark-shared.mjs';
|
|
13
13
|
import { collectAdoptionGaps, arkCheckCommand } from './agent-gates.mjs';
|
|
14
|
+
import { CORE_LAYER_NAMES } from './core-layers.mjs';
|
|
15
|
+
import {
|
|
16
|
+
renderBaselineSignalLegend,
|
|
17
|
+
renderDesignCleanNote,
|
|
18
|
+
renderDesignDepthStrip,
|
|
19
|
+
renderWritePathAdoptionBlock,
|
|
20
|
+
} from './html-report-depth.mjs';
|
|
14
21
|
import { FIX_HINTS } from './violations.mjs';
|
|
15
22
|
|
|
16
23
|
export function detectEnforcement(root) {
|
|
@@ -58,6 +65,53 @@ export function htmlEscape(value) {
|
|
|
58
65
|
.replace(/"/g, '"');
|
|
59
66
|
}
|
|
60
67
|
|
|
68
|
+
/**
|
|
69
|
+
* KPI tile with plain-language hint (visible micro-copy + native tooltip).
|
|
70
|
+
* Helps newcomers read the showcase without memorizing Ark jargon.
|
|
71
|
+
*
|
|
72
|
+
* @param {string|number} value
|
|
73
|
+
* @param {string} label short metric name
|
|
74
|
+
* @param {string} hint one-sentence meaning
|
|
75
|
+
*/
|
|
76
|
+
export function metricKpi(value, label, hint) {
|
|
77
|
+
const v = htmlEscape(String(value));
|
|
78
|
+
const l = htmlEscape(label);
|
|
79
|
+
const h = htmlEscape(hint);
|
|
80
|
+
return `<div class="kpi" title="${h}" aria-label="${l}: ${v}. ${h}">
|
|
81
|
+
<b>${v}</b>
|
|
82
|
+
<span>${l}</span>
|
|
83
|
+
<em class="kpi-hint">${h}</em>
|
|
84
|
+
</div>`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Baseline policy signal → human meaning (adoption card). */
|
|
88
|
+
export function baselineSignalHint(signal) {
|
|
89
|
+
switch (String(signal || '')) {
|
|
90
|
+
case 'keep-empty':
|
|
91
|
+
return 'Baseline file exists and freezes 0 keys — every violation is active (honest green).';
|
|
92
|
+
case 'active-ratchet':
|
|
93
|
+
return 'Baseline freezes known debt keys; new distinct violations still fail the check.';
|
|
94
|
+
case 'absent':
|
|
95
|
+
return 'No .ark-baseline.json — all findings are active (or you have not adopted a freeze file).';
|
|
96
|
+
default:
|
|
97
|
+
return 'How frozen debt is handled relative to active architecture violations.';
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Operating mode badge tooltip. */
|
|
102
|
+
export function modeBadgeHint(mode) {
|
|
103
|
+
switch (String(mode || '').toLowerCase()) {
|
|
104
|
+
case 'enforce':
|
|
105
|
+
return 'Contract matches the tree: cores are required where populated, coverage is honest, gates can hold the line.';
|
|
106
|
+
case 'adapt':
|
|
107
|
+
return 'Contract is live but still aligning (optional cores with files, empty cores, or presentation-bag false green).';
|
|
108
|
+
case 'suggest':
|
|
109
|
+
return 'Starter shape — expand layers and raise governed coverage as the codebase grows.';
|
|
110
|
+
default:
|
|
111
|
+
return 'Operating mode for co-pilot surfaces (suggest · adapt · enforce).';
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
61
115
|
/** Directory for origin / latest / history architecture report snapshots. */
|
|
62
116
|
const ARK_REPORTS_DIR = path.join('.ark', 'reports');
|
|
63
117
|
const ARK_REPORT_HISTORY_MAX = 20;
|
|
@@ -159,7 +213,10 @@ export function computeReportFitness({ coverage, violations, ok, enforcement, co
|
|
|
159
213
|
const presentationRow = (coverage?.layers ?? []).find(
|
|
160
214
|
(r) => r.name === 'PresentationAdapters'
|
|
161
215
|
);
|
|
216
|
+
// Same honesty gate as doctor (`mcp-adoption` coreOptional): only the four cores
|
|
217
|
+
// matter. Secondary optional layers with files must not force ADAPT on the HTML report.
|
|
162
218
|
const coreOptionalWithFiles = (config?.layers ?? []).filter((layer) => {
|
|
219
|
+
if (!CORE_LAYER_NAMES.has(layer.name)) return false;
|
|
163
220
|
if (layer.optional !== true) return false;
|
|
164
221
|
const row = (coverage?.layers ?? []).find((r) => r.name === layer.name);
|
|
165
222
|
return (row?.files ?? 0) > 0;
|
|
@@ -396,6 +453,8 @@ export function renderHtmlReport({
|
|
|
396
453
|
currentSnapshot = null,
|
|
397
454
|
originJustCreated = false,
|
|
398
455
|
adoption = null,
|
|
456
|
+
/** Optional design-depth (doctor parity): designFitness, designSmells, pilotLoop, postGreenPath, goldenPattern */
|
|
457
|
+
designDepth = null,
|
|
399
458
|
}) {
|
|
400
459
|
const layers = Array.isArray(config.layers) ? config.layers : [];
|
|
401
460
|
const rules = Array.isArray(config.rules) ? config.rules : [];
|
|
@@ -448,6 +507,29 @@ export function renderHtmlReport({
|
|
|
448
507
|
} = fitness;
|
|
449
508
|
|
|
450
509
|
const adoptionView = adoption || collectAdoptionGaps(root, config, coverage);
|
|
510
|
+
const depth = designDepth && typeof designDepth === 'object' ? designDepth : {};
|
|
511
|
+
const designFitness = depth.designFitness ?? null;
|
|
512
|
+
const designSmells = Array.isArray(depth.designSmells) ? depth.designSmells : [];
|
|
513
|
+
const designWeakBadge =
|
|
514
|
+
designFitness?.designWeak === true
|
|
515
|
+
? ` <span class="badge design" title="Edges can be green while lived design residual remains (Shape). Not a FAIL.">design-weak</span>`
|
|
516
|
+
: '';
|
|
517
|
+
const designStripHtml =
|
|
518
|
+
renderDesignDepthStrip({
|
|
519
|
+
designFitness,
|
|
520
|
+
designSmells,
|
|
521
|
+
pilotLoop: depth.pilotLoop,
|
|
522
|
+
postGreenPath: depth.postGreenPath,
|
|
523
|
+
goldenPattern: depth.goldenPattern,
|
|
524
|
+
mode,
|
|
525
|
+
}) ||
|
|
526
|
+
renderDesignCleanNote({
|
|
527
|
+
designFitness,
|
|
528
|
+
ok,
|
|
529
|
+
mode,
|
|
530
|
+
});
|
|
531
|
+
const writePathHtml = renderWritePathAdoptionBlock(adoptionView.writePath);
|
|
532
|
+
const baselineLegendHtml = renderBaselineSignalLegend();
|
|
451
533
|
|
|
452
534
|
// ── Senior diagnostics (coupling, purity, contract density) ──────────────
|
|
453
535
|
const layerNames = ordered.map((l) => l.name);
|
|
@@ -818,9 +900,33 @@ export function renderHtmlReport({
|
|
|
818
900
|
.score-cap { color: var(--dim); font-size: .85rem; margin: 0; }
|
|
819
901
|
.kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: .65rem; margin: 1rem 0 0; }
|
|
820
902
|
@media (max-width: 720px) { .kpis { grid-template-columns: repeat(2, 1fr); } }
|
|
821
|
-
.kpi { background: var(--panel2); border: 1px solid var(--line); border-radius: 12px; padding: .7rem .8rem; }
|
|
903
|
+
.kpi { background: var(--panel2); border: 1px solid var(--line); border-radius: 12px; padding: .7rem .8rem; cursor: help; }
|
|
822
904
|
.kpi b { display: block; font-size: 1.25rem; letter-spacing: -0.02em; }
|
|
823
905
|
.kpi span { color: var(--dim); font-size: .75rem; text-transform: uppercase; letter-spacing: .05em; }
|
|
906
|
+
.kpi-hint {
|
|
907
|
+
display: block; margin-top: .4rem; color: var(--dim); font-size: .68rem; font-style: normal;
|
|
908
|
+
font-weight: 450; line-height: 1.35; letter-spacing: 0; text-transform: none; max-width: 16rem;
|
|
909
|
+
}
|
|
910
|
+
.score-parts span { cursor: help; border-bottom: 1px dotted color-mix(in srgb, var(--dim) 55%, transparent); }
|
|
911
|
+
.badge[title] { cursor: help; }
|
|
912
|
+
.badge.design {
|
|
913
|
+
background: color-mix(in srgb, var(--gold) 18%, transparent); color: var(--gold);
|
|
914
|
+
border-color: color-mix(in srgb, var(--gold) 40%, transparent);
|
|
915
|
+
}
|
|
916
|
+
.badge.design-ok {
|
|
917
|
+
background: color-mix(in srgb, var(--green) 16%, transparent); color: var(--green);
|
|
918
|
+
border-color: color-mix(in srgb, var(--green) 35%, transparent);
|
|
919
|
+
}
|
|
920
|
+
.design-strip { border-left: 3px solid var(--gold); }
|
|
921
|
+
.design-strip.is-clean { border-left-color: var(--green); }
|
|
922
|
+
.design-strip.has-smells { border-left-color: var(--gold); }
|
|
923
|
+
.design-head { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
|
|
924
|
+
.pilot-card {
|
|
925
|
+
margin-top: .35rem; padding: .75rem .9rem; border-radius: 12px;
|
|
926
|
+
background: var(--panel2); border: 1px solid var(--line);
|
|
927
|
+
}
|
|
928
|
+
.write-path-block { margin-top: .15rem; }
|
|
929
|
+
.baseline-legend summary { cursor: pointer; color: var(--dim); font-size: .84rem; }
|
|
824
930
|
.section { margin-top: 1.35rem; }
|
|
825
931
|
.grid-2 { display: grid; grid-template-columns: 1.1fr 0.9fr; gap: 1rem; }
|
|
826
932
|
@media (max-width: 900px) { .grid-2 { grid-template-columns: 1fr; } }
|
|
@@ -936,34 +1042,79 @@ export function renderHtmlReport({
|
|
|
936
1042
|
<div class="hero">
|
|
937
1043
|
<div class="card">
|
|
938
1044
|
<div class="brand"><i></i> Ark architecture report</div>
|
|
939
|
-
<h1>${esc(project)} <span class="badge ${status}">${status}</span> <span class="badge mode">${esc(modeLabel)}</span
|
|
940
|
-
<p class="lede">${esc(modeBlurb)} One machine-readable contract · write gate · CI · optional runtime.</p>
|
|
1045
|
+
<h1>${esc(project)} <span class="badge ${status}" title="${status === 'PASS' ? 'Architecture check is green: 0 active violations against the contract.' : 'Architecture check failed: active violations remain (or the scan could not complete cleanly).'}">${status}</span> <span class="badge mode" title="${esc(modeBadgeHint(mode))}">${esc(modeLabel)}</span>${designWeakBadge}</h1>
|
|
1046
|
+
<p class="lede">${esc(modeBlurb)}${designFitness?.designWeak ? ' Design residual remains (see strip below) — not a FAIL.' : ''} One machine-readable contract · write gate · CI · optional runtime.</p>
|
|
941
1047
|
<div class="kpis">
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
1048
|
+
${metricKpi(
|
|
1049
|
+
govLabel,
|
|
1050
|
+
'Governed',
|
|
1051
|
+
'Share of scanned files assigned to a contract layer. 100% means every in-scope file has a home.'
|
|
1052
|
+
)}
|
|
1053
|
+
${metricKpi(
|
|
1054
|
+
layers.length,
|
|
1055
|
+
'Layers',
|
|
1056
|
+
'How many architecture layers the contract defines (cores + optional product layers).'
|
|
1057
|
+
)}
|
|
1058
|
+
${metricKpi(
|
|
1059
|
+
`${gatesOn}/${enforcement.length}`,
|
|
1060
|
+
'Gates live',
|
|
1061
|
+
'Write hook, CI workflow, ESLint plugin, and baseline file — how many enforcement points are actually present.'
|
|
1062
|
+
)}
|
|
1063
|
+
${metricKpi(
|
|
1064
|
+
`${violations.length}${suppressed ? ` · ${suppressed}Δ` : ''}`,
|
|
1065
|
+
`Violations${suppressed ? ' · frozen' : ''}`,
|
|
1066
|
+
suppressed
|
|
1067
|
+
? 'Active contract breaks right now; Δ = keys frozen in baseline (not failing until ratchet).'
|
|
1068
|
+
: 'Active contract breaks (layer imports, purity, etc.). Zero means edges match the rules.'
|
|
1069
|
+
)}
|
|
946
1070
|
</div>
|
|
947
1071
|
<p class="meta">${meta}</p>
|
|
948
1072
|
${skillsNote}
|
|
949
1073
|
</div>
|
|
950
|
-
<div class="card score-card">
|
|
1074
|
+
<div class="card score-card" title="Human fitness signal only — not a CI gate. Weighted blend of coverage, cleanliness, live gates, and rule density.">
|
|
951
1075
|
<div class="score-ring ${scoreTone}"><div><div class="score-n">${score}</div><div class="dim" style="font-size:.72rem;letter-spacing:.08em;text-transform:uppercase">Ark score</div></div></div>
|
|
952
1076
|
<p class="score-cap">${esc(scoreCaption)}</p>
|
|
953
|
-
<p class="meta" style="margin-top:.65rem">
|
|
1077
|
+
<p class="meta score-parts" style="margin-top:.65rem">
|
|
1078
|
+
<span title="0.4 weight — governed file percent (or 50 if coverage unknown).">${esc(`Coverage ${scoreCoverage}`)}</span>
|
|
1079
|
+
· <span title="0.3 weight — 100 with zero active violations; drops as violations pile up.">${esc(`Clean ${scoreClean}`)}</span>
|
|
1080
|
+
· <span title="0.2 weight — share of enforcement points that are present on disk (hook, CI, ESLint, baseline).">${esc(`Gates ${scoreGates}`)}</span>
|
|
1081
|
+
· <span title="0.1 weight — how dense the deny matrix is relative to layer pairs (stricter inward architecture scores higher).">${esc(`Rules ${scoreRules}`)}</span>
|
|
1082
|
+
</p>
|
|
954
1083
|
</div>
|
|
955
1084
|
</div>
|
|
956
1085
|
|
|
1086
|
+
${designStripHtml}
|
|
1087
|
+
|
|
957
1088
|
<div class="section card" id="adoption">
|
|
958
1089
|
<h2>Adoption</h2>
|
|
959
1090
|
<p class="dim" style="margin:.15rem 0 .75rem;font-size:.88rem">
|
|
960
1091
|
Co-pilot completeness — separate from the 0–100 fitness score above. Hosts, MCP health, origin snapshot, core optionality, baseline policy.
|
|
961
1092
|
</p>
|
|
962
1093
|
<div class="kpis" style="margin-bottom:.75rem">
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
1094
|
+
${metricKpi(
|
|
1095
|
+
adoptionView.gaps.length === 0 ? 'OK' : adoptionView.gaps.length,
|
|
1096
|
+
adoptionView.gaps.length === 0 ? 'No adoption gaps' : 'Adoption gap(s)',
|
|
1097
|
+
adoptionView.gaps.length === 0
|
|
1098
|
+
? 'Hosts, MCP argv, origin snapshot, and core optionality look complete for co-pilot use.'
|
|
1099
|
+
: 'Install or fix the listed gaps so agents get write gates, MCP, and honest cores.'
|
|
1100
|
+
)}
|
|
1101
|
+
${metricKpi(
|
|
1102
|
+
adoptionView.originReport.present ? 'yes' : 'no',
|
|
1103
|
+
'Origin report',
|
|
1104
|
+
'First architecture snapshot under .ark/reports/origin.* — future reports show evolution deltas against it.'
|
|
1105
|
+
)}
|
|
1106
|
+
${metricKpi(
|
|
1107
|
+
adoptionView.baseline.signal,
|
|
1108
|
+
'Baseline policy',
|
|
1109
|
+
baselineSignalHint(adoptionView.baseline.signal)
|
|
1110
|
+
)}
|
|
1111
|
+
${metricKpi(
|
|
1112
|
+
adoptionView.mcp.ok ? 'ok' : 'fix',
|
|
1113
|
+
'Repo MCP argv',
|
|
1114
|
+
adoptionView.mcp.ok
|
|
1115
|
+
? 'Repo MCP config points at a single ark/arkgate MCP bin (no dual-bin conflict).'
|
|
1116
|
+
: 'Broken MCP argv: more than one of ark-mcp/arkgate-mcp — migrate with --install-agent-gates --migrate-commands.'
|
|
1117
|
+
)}
|
|
967
1118
|
</div>
|
|
968
1119
|
${
|
|
969
1120
|
adoptionView.gaps.length
|
|
@@ -991,6 +1142,8 @@ export function renderHtmlReport({
|
|
|
991
1142
|
.join(' · ')}</p>`
|
|
992
1143
|
: ''
|
|
993
1144
|
}
|
|
1145
|
+
${writePathHtml}
|
|
1146
|
+
${baselineLegendHtml}
|
|
994
1147
|
</div>
|
|
995
1148
|
|
|
996
1149
|
<div class="section grid-2">
|
|
@@ -1138,10 +1291,26 @@ export function renderHtmlReport({
|
|
|
1138
1291
|
|
|
1139
1292
|
<h3>Contract density</h3>
|
|
1140
1293
|
<div class="kpis" style="margin-top:.35rem">
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1294
|
+
${metricKpi(
|
|
1295
|
+
`${denyRatio}%`,
|
|
1296
|
+
'Edges denied',
|
|
1297
|
+
'Denied directed layer pairs ÷ all possible pairs. Higher = stricter inward dependency rules.'
|
|
1298
|
+
)}
|
|
1299
|
+
${metricKpi(
|
|
1300
|
+
deniedCount,
|
|
1301
|
+
'Deny rules',
|
|
1302
|
+
'Explicit allowed:false rules in ark.config.json (row may not import column).'
|
|
1303
|
+
)}
|
|
1304
|
+
${metricKpi(
|
|
1305
|
+
allowedCount,
|
|
1306
|
+
'Explicit allows',
|
|
1307
|
+
'Explicit allowed:true edges. Most opens are implicit (no rule) unless you document them.'
|
|
1308
|
+
)}
|
|
1309
|
+
${metricKpi(
|
|
1310
|
+
pairCount,
|
|
1311
|
+
'Directed pairs',
|
|
1312
|
+
'layers × (layers − 1) — every ordered from→to pair the matrix can constrain.'
|
|
1313
|
+
)}
|
|
1145
1314
|
</div>
|
|
1146
1315
|
<p class="dim" style="margin:.55rem 0 0;font-size:.84rem">
|
|
1147
1316
|
Deny ratio = denied ÷ (layers × (layers−1)). High ratio = strict inward architecture.
|
|
@@ -1270,10 +1439,26 @@ export function renderHtmlReport({
|
|
|
1270
1439
|
|
|
1271
1440
|
<h3>Debt & violation taxonomy</h3>
|
|
1272
1441
|
<div class="kpis" style="margin-top:.35rem">
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1442
|
+
${metricKpi(
|
|
1443
|
+
violations.length,
|
|
1444
|
+
'Active',
|
|
1445
|
+
'Violations that fail the check right now (not frozen by baseline).'
|
|
1446
|
+
)}
|
|
1447
|
+
${metricKpi(
|
|
1448
|
+
valueN,
|
|
1449
|
+
'Value edges',
|
|
1450
|
+
'Runtime import edges that cross a deny rule (stronger debt than type-only).'
|
|
1451
|
+
)}
|
|
1452
|
+
${metricKpi(
|
|
1453
|
+
typeOnlyN,
|
|
1454
|
+
'Type-only',
|
|
1455
|
+
'Type-only imports across a deny edge — often mechanical-safe to rewrite as import type.'
|
|
1456
|
+
)}
|
|
1457
|
+
${metricKpi(
|
|
1458
|
+
suppressed || baselineKeys,
|
|
1459
|
+
'Baseline keys',
|
|
1460
|
+
'Distinct frozen debt keys in .ark-baseline.json (or suppressed count for this run).'
|
|
1461
|
+
)}
|
|
1277
1462
|
</div>
|
|
1278
1463
|
${
|
|
1279
1464
|
topEdges.length
|
|
@@ -1291,6 +1476,14 @@ export function renderHtmlReport({
|
|
|
1291
1476
|
Coverage=${scoreCoverage}, clean=${scoreClean}, gates=${scoreGates}, rules=${scoreRules} → <b>${score}</b>.
|
|
1292
1477
|
This is a fitness signal for humans, not a CI gate.
|
|
1293
1478
|
</p>
|
|
1479
|
+
<ul class="senior-list" style="margin-top:.45rem">
|
|
1480
|
+
<li><b>Coverage</b> — % of in-scope files that match a layer pattern.</li>
|
|
1481
|
+
<li><b>Clean</b> — 100 with zero active violations; falls as breaks accumulate.</li>
|
|
1482
|
+
<li><b>Gates</b> — share of write / CI / ESLint / baseline enforcement points present.</li>
|
|
1483
|
+
<li><b>Rules</b> — deny-matrix density (more inward denies → higher component).</li>
|
|
1484
|
+
<li><b>PASS / FAIL</b> — binary edge honesty (active violations), independent of the 0–100 score.</li>
|
|
1485
|
+
<li><b>SUGGEST / ADAPT / ENFORCE</b> — whether the contract is honest enough to protect the tree (not a skill grade).</li>
|
|
1486
|
+
</ul>
|
|
1294
1487
|
</details>
|
|
1295
1488
|
</div>
|
|
1296
1489
|
|
|
@@ -43,10 +43,11 @@ export function detectActiveAgentHost(env = process.env) {
|
|
|
43
43
|
.toLowerCase();
|
|
44
44
|
if (explicit) return explicit;
|
|
45
45
|
|
|
46
|
-
// Grok / xAI Build
|
|
46
|
+
// Grok / xAI Build (include GROK_AGENT — common session signal missing in older detect)
|
|
47
47
|
if (
|
|
48
48
|
envTruthy(env.GROK_BUILD) ||
|
|
49
49
|
envTruthy(env.XAI_GROK) ||
|
|
50
|
+
envTruthy(env.GROK_AGENT) ||
|
|
50
51
|
env.GROK_WORKSPACE_ROOT ||
|
|
51
52
|
env.GROK_SESSION_ID
|
|
52
53
|
) {
|
|
@@ -30,21 +30,32 @@ export function detectWritePathCapabilities(root, explicitHost) {
|
|
|
30
30
|
|
|
31
31
|
const tools = installToolsForHost(activeHost);
|
|
32
32
|
let gap = null;
|
|
33
|
+
// Repo inventory (any host) can show hard/advisory write while activeHost is
|
|
34
|
+
// unknown (plain shell / `npx ark-check --report` outside an agent session).
|
|
35
|
+
// Session projection stays mode=none (other hosts' hooks are not a guarantee for
|
|
36
|
+
// this process) — but do not open an adoption gap: gates exist on disk.
|
|
37
|
+
const inventoryHasWriteBoundary =
|
|
38
|
+
Boolean(inventory?.capabilities?.['hard-write']) ||
|
|
39
|
+
Boolean(inventory?.capabilities?.['advisory-write']);
|
|
33
40
|
if (mode === 'none') {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
41
|
+
if (activeHost === 'unknown' && inventoryHasWriteBoundary) {
|
|
42
|
+
gap = null;
|
|
43
|
+
} else {
|
|
44
|
+
gap = {
|
|
45
|
+
id: 'write-path-none',
|
|
46
|
+
severity: 'warn',
|
|
47
|
+
message:
|
|
48
|
+
`Active host ${activeHost} has no hard write boundary or advisory Ark MCP. ` +
|
|
49
|
+
(capabilities['merge-gate']
|
|
50
|
+
? 'The CI check remains separate and does not block local writes.'
|
|
51
|
+
: 'No Ark CI check was detected either.'),
|
|
52
|
+
fix: arkCommand(
|
|
53
|
+
root,
|
|
54
|
+
'ark-check',
|
|
55
|
+
`--install-agent-gates --tools ${tools}`
|
|
56
|
+
),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
48
59
|
} else if (mode === 'reject-only') {
|
|
49
60
|
gap = {
|
|
50
61
|
id: 'write-path-reject-only',
|
package/dist/index.cjs
CHANGED
package/dist/index.d.cts
CHANGED
|
@@ -2,7 +2,7 @@ import { a as ArkConfigRule, b as ArkConfigLayer, A as ArkConfig, c as ArkConfig
|
|
|
2
2
|
export { d as ARK_CONFIG_SCHEMA, e as ARK_CONFIG_SCHEMA_VERSION, l as loadArkConfigContract, p as parseArkConfigJson } from './configContract-BxSIwVRo.cjs';
|
|
3
3
|
|
|
4
4
|
/** ArkGate library version — single source of truth. */
|
|
5
|
-
declare const version = "3.0.
|
|
5
|
+
declare const version = "3.0.4";
|
|
6
6
|
|
|
7
7
|
/** Versioned public result contract shared by every ArkGate enforcement adapter. */
|
|
8
8
|
declare const ARK_ANALYSIS_RESULT_SCHEMA_VERSION: "1.0";
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { a as ArkConfigRule, b as ArkConfigLayer, A as ArkConfig, c as ArkConfig
|
|
|
2
2
|
export { d as ARK_CONFIG_SCHEMA, e as ARK_CONFIG_SCHEMA_VERSION, l as loadArkConfigContract, p as parseArkConfigJson } from './configContract-BxSIwVRo.js';
|
|
3
3
|
|
|
4
4
|
/** ArkGate library version — single source of truth. */
|
|
5
|
-
declare const version = "3.0.
|
|
5
|
+
declare const version = "3.0.4";
|
|
6
6
|
|
|
7
7
|
/** Versioned public result contract shared by every ArkGate enforcement adapter. */
|
|
8
8
|
declare const ARK_ANALYSIS_RESULT_SCHEMA_VERSION: "1.0";
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/pedroknigge/arkgate",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "3.0.
|
|
9
|
+
"version": "3.0.4",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "arkgate",
|
|
14
|
-
"version": "3.0.
|
|
14
|
+
"version": "3.0.4",
|
|
15
15
|
"runtimeHint": "npx",
|
|
16
16
|
"transport": {
|
|
17
17
|
"type": "stdio"
|