arkgate 2.9.2 → 2.11.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 +87 -0
- package/README.md +12 -2
- package/SECURITY.md +3 -4
- package/bin/ark-check.mjs +41 -16
- package/bin/ark-mcp.mjs +335 -111
- package/bin/ark.mjs +35 -5
- package/bin/lib/agent-gates.mjs +161 -8
- package/bin/lib/architecture-scan.mjs +23 -1
- package/bin/lib/auto-patch.mjs +264 -0
- package/bin/lib/baseline-key.mjs +17 -0
- package/bin/lib/config-warnings.mjs +22 -0
- package/bin/lib/core-layers.mjs +7 -0
- package/bin/lib/core-ratchet.mjs +3 -7
- package/bin/lib/doctor-plan.mjs +83 -5
- package/bin/lib/port-proof.mjs +309 -0
- package/bin/lib/prepare-write.mjs +130 -0
- package/bin/lib/remediation.mjs +21 -0
- package/bin/lib/safety-diagnostics.mjs +263 -0
- package/bin/lib/scan-files.mjs +51 -6
- package/bin/lib/violations.mjs +3 -3
- package/dist/index.cjs +115 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +115 -11
- package/dist/index.js.map +1 -1
- package/dist/nestjs/index.cjs +18 -5
- package/dist/nestjs/index.cjs.map +1 -1
- package/dist/nestjs/index.d.cts +1 -1
- package/dist/nestjs/index.d.ts +1 -1
- package/dist/nestjs/index.js +18 -5
- package/dist/nestjs/index.js.map +1 -1
- package/dist/runtime/index.cjs +115 -11
- package/dist/runtime/index.cjs.map +1 -1
- package/dist/runtime/index.d.cts +1 -1
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +115 -11
- package/dist/runtime/index.js.map +1 -1
- package/dist/{types-D6Q8WHes.d.cts → types-BZ17b9i5.d.cts} +5 -1
- package/dist/{types-D6Q8WHes.d.ts → types-BZ17b9i5.d.ts} +5 -1
- package/docs/agent-guide.md +15 -1
- package/docs/ai-gates.md +63 -5
- package/docs/enthusiast/how-to-agent-gates.md +8 -0
- package/docs/enthusiast/reference-commands.md +1 -1
- package/docs/package-surface.md +2 -2
- package/docs/production-hardening.md +5 -0
- package/package.json +6 -2
- package/server.json +2 -2
- package/templates/skills/ark-explain.md +1 -1
- package/templates/skills/ark-loop.md +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,93 @@ All notable changes to ArkGate (`arkgate`; formerly `ark-runtime-kernel`) are do
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 2.11.0 — 2026-07-10
|
|
8
|
+
|
|
9
|
+
Fail-closed enforcement hardening: `--strict` now combines contract coverage, installed-gate
|
|
10
|
+
checks, write-hook presence, and bypass diagnostics in one CI profile. The GitHub Action runs
|
|
11
|
+
the exact checked-out revision by default, and runtime workflows cancel timed-out work
|
|
12
|
+
cooperatively.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- **Strict CI profile:** `arkgate-check --strict` enables strict config validation, requires
|
|
17
|
+
generated gates plus a PreToolUse write hook, and fails on configured safety diagnostics.
|
|
18
|
+
- **Bypass diagnostics:** new `dynamicImportAllowlist` and `safety` config fields detect
|
|
19
|
+
non-literal dynamic imports, TypeScript suppression directives, explicit `any` casts,
|
|
20
|
+
production InMemory defaults, and disabled or omitted peer isolation. `--doctor --json`
|
|
21
|
+
exposes the same evidence under `doctor.safety`.
|
|
22
|
+
- **Release-quality CI:** JavaScript syntax validation, enforced coverage thresholds, and a
|
|
23
|
+
Node 18/20/22/24 compatibility matrix now run before merge.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- **Pinned GitHub Action execution:** `uses: pedroknigge/arkgate@<tag-or-SHA>` now runs that
|
|
28
|
+
checked-out ArkGate source. The `version` input remains available only as an explicit exact
|
|
29
|
+
npm compatibility override.
|
|
30
|
+
- **Complete MCP contract:** `ark://manifest` exposes every configured file layer separately
|
|
31
|
+
from runtime intent layers, plus reviewed dynamic-import and safety policy.
|
|
32
|
+
- **Workflow cancellation contract:** workflow steps receive an `AbortSignal` as their third
|
|
33
|
+
argument. `timeoutMs` aborts that signal, clears the active step, and rejects duplicate step
|
|
34
|
+
names before execution can corrupt compensation order.
|
|
35
|
+
- **Filesystem confinement:** source scans follow internal symlinks once and reject symlinks
|
|
36
|
+
that escape the project root.
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
|
|
40
|
+
- **Baseline duplicate honesty:** repeated violations now receive stable per-occurrence keys,
|
|
41
|
+
so adding a second identical violation is new debt instead of being hidden by one baseline
|
|
42
|
+
entry.
|
|
43
|
+
- **Write-hook duplicate honesty:** proposed writes compare violation counts, preventing a new
|
|
44
|
+
duplicate from being mistaken for an already-existing violation.
|
|
45
|
+
- **CLI argument safety:** unknown flags and missing flag values fail with usage guidance
|
|
46
|
+
instead of silently weakening enforcement or throwing an internal error.
|
|
47
|
+
- **Action gate detection:** repositories using the ArkGate composite Action satisfy the CI
|
|
48
|
+
gate check without needing a separate literal `ark-check` command.
|
|
49
|
+
|
|
50
|
+
## 2.10.0 — 2026-07-10
|
|
51
|
+
|
|
52
|
+
Track W — **Constrained write → verified repair**: write-boundary autoPatch, prepare_write,
|
|
53
|
+
loop-cost measurement, opt-in hook repair payloads, doctor write-path awareness, and a
|
|
54
|
+
proof-gated port-inject transform (judgment for auto-apply).
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
|
|
58
|
+
- **W1 write-boundary autoPatch:** `validate_code` and PreToolUse `--hook` may return
|
|
59
|
+
additive `autoPatch: { source, remediationKind, confidence, valid }` for mechanical-safe
|
|
60
|
+
**import type** rewrites (`import-type-from-pure-type-module`, `import-type-of-type-exports`).
|
|
61
|
+
Post-patch revalidation must be green or the patch is discarded (never silent write).
|
|
62
|
+
Implementation: `bin/lib/auto-patch.mjs`.
|
|
63
|
+
- **W2 `ark_prepare_write` MCP tool:** place + constrain + validate + optional autoPatch +
|
|
64
|
+
judgmentBrief + contentHash in one call (`bin/lib/prepare-write.mjs`). Composes
|
|
65
|
+
`ark_place` + write gate — not a second contract.
|
|
66
|
+
- **W3 loop-cost eval harness:** `eval/loop-cost-run.mjs` / `npm run eval:loop-cost`
|
|
67
|
+
records turns-to-green, optional tokens, CHEATED (fixture-measured). Baseline
|
|
68
|
+
`eval/loop-cost-baseline.json` (medianTurnsTypeOnly=1, cheatedRate=0).
|
|
69
|
+
- **W4 opt-in hook repair payload:** `--hook-repair` / `ARK_HOOK_REPAIR=1` on deny emits
|
|
70
|
+
`ARK_REPAIR_JSON` + `ARK_AUTOPATCH_JSON` (stderr) and optional Grok `autoPatch` (stdout).
|
|
71
|
+
Default `--hook` remains hard-block prose only. Install templates (Claude/Grok) include
|
|
72
|
+
`--hook-repair`. Never silent write.
|
|
73
|
+
- **W5 doctor write-path awareness:** `ark-check --doctor` (JSON + human) surfaces
|
|
74
|
+
`writePath.mode` (`repair` | `reject-only` | `mcp-only` | `none`) and
|
|
75
|
+
`prepareWrite` / `autoPatch` flags from installed hooks/MCP. Reject-only gap is
|
|
76
|
+
additive (info) with install fix.
|
|
77
|
+
- **W6 port-proof inject binding (eval-gated):** prove+transform for
|
|
78
|
+
`port-proof-inject-binding` — single named value import used only as
|
|
79
|
+
`binding.method(...)` inside function declarations. Removes the import, emits a
|
|
80
|
+
port type, injects the binding as a parameter (call sites preserved). **Judgment for
|
|
81
|
+
auto-apply** (call arity changes; not write-path autoPatch). Fail-closed static proof;
|
|
82
|
+
rest params refuse apply. Labeled eval case. Implementation: `bin/lib/port-proof.mjs` +
|
|
83
|
+
scan flag `portProofEligible`.
|
|
84
|
+
|
|
85
|
+
### Changed
|
|
86
|
+
|
|
87
|
+
- **Write gate type-only edges:** `import type` / `export type` no longer hard-block
|
|
88
|
+
LAYER_IMPORT / infra heuristics on the write path (erased at runtime). Value imports
|
|
89
|
+
and peerIsolation still deny. ark-check plan continues to surface type placement debt.
|
|
90
|
+
- **`ark_prepare_write` isError:** always `isError` when proposed source is invalid
|
|
91
|
+
(autoPatch is additive recovery, not soft-success).
|
|
92
|
+
- **`resolveImportFileAbs`:** confines disk reads under project root (no path escape).
|
|
93
|
+
|
|
7
94
|
## 2.9.2 — 2026-07-09
|
|
8
95
|
|
|
9
96
|
Skill surface hardening: dual-engine, explore, STOP handoffs, AGENTS routing, subagent fan-out.
|
package/README.md
CHANGED
|
@@ -151,6 +151,11 @@ critical handoffs say **STOP** and name the next skill (hosts must follow — ma
|
|
|
151
151
|
When the host allows it, skills may **fan out parallel subagents** (disjoint scopes);
|
|
152
152
|
otherwise they **fall back to sequential**.
|
|
153
153
|
|
|
154
|
+
**Write path (Track W):** Prefer MCP **`ark_prepare_write`** when you have a snippet (place +
|
|
155
|
+
constrain + validate + optional `autoPatch` + `judgmentBrief`). PreToolUse hooks with
|
|
156
|
+
`--hook-repair` emit machine-readable repair payloads on deny (still hard block; never silent
|
|
157
|
+
write). See [docs/ai-gates.md](docs/ai-gates.md).
|
|
158
|
+
|
|
154
159
|
| Need | Skill |
|
|
155
160
|
|------|--------|
|
|
156
161
|
| Only the apply loop (plan already exists) | `/ark-loop` |
|
|
@@ -184,6 +189,10 @@ ark.config.json
|
|
|
184
189
|
- **Frameworks:** Nest / Next / express / library layouts get sensible globs on init so day-one coverage is real.
|
|
185
190
|
- **Brownfield:** baseline ratchet, refuse to freeze a wrong contract, `/ark-adopt` for mature trees.
|
|
186
191
|
- **Agents:** skills install into Claude / Cursor / Codex / Grok; `ark start` freezes an origin report under `.ark/reports/`.
|
|
192
|
+
- **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.
|
|
193
|
+
- **Fail-closed CI (2.11):** `--strict` combines config coverage, required CI/MCP/write gates,
|
|
194
|
+
PreToolUse hook presence, and bypass diagnostics for dynamic imports, TypeScript suppressions,
|
|
195
|
+
explicit `any` casts, InMemory runtime defaults, and disabled peer isolation.
|
|
187
196
|
- **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)).
|
|
188
197
|
|
|
189
198
|
### Why not only ESLint / dependency-cruiser / Nx?
|
|
@@ -208,6 +217,7 @@ ark.config.json
|
|
|
208
217
|
npx arkgate start # guided setup + plan + origin report
|
|
209
218
|
npx arkgate-check --doctor # health + Adoption gaps (not just fitness)
|
|
210
219
|
npx arkgate-check --doctor --json # machine-readable doctor.adoption
|
|
220
|
+
npx arkgate-check --strict # fail-closed CI + installed-gate/safety checks
|
|
211
221
|
npx arkgate-check --plan # safe-to-auto-fix vs your call
|
|
212
222
|
npx arkgate-check --coverage # Governed: N%
|
|
213
223
|
npx arkgate-check --report ark-report.html # showcase HTML + Adoption card + origin/latest
|
|
@@ -218,8 +228,8 @@ npx arkgate upgrade # package + gates/skills + MCP/Codex n
|
|
|
218
228
|
CI (example):
|
|
219
229
|
|
|
220
230
|
```yaml
|
|
221
|
-
- run: npx arkgate-check --root . --config ark.config.json --strict
|
|
222
|
-
# or: uses: pedroknigge/arkgate
|
|
231
|
+
- run: npx arkgate-check --root . --config ark.config.json --strict
|
|
232
|
+
# or: uses: pedroknigge/arkgate@<tag-or-SHA> # runs that checked-out revision
|
|
223
233
|
```
|
|
224
234
|
|
|
225
235
|
---
|
package/SECURITY.md
CHANGED
|
@@ -28,10 +28,9 @@ a private security contact without including exploit details.
|
|
|
28
28
|
ArkGate releases are GitHub-first:
|
|
29
29
|
|
|
30
30
|
1. Changes land on GitHub and must pass CI plus the dedicated security workflow.
|
|
31
|
-
2. A GitHub Release is created from
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
wired). Signed tags can later require `ARK_REQUIRE_SIGNED_RELEASE_TAG=true`.
|
|
31
|
+
2. A GitHub Release is created from a signed `vX.Y.Z` tag (`git tag -s`). The publish
|
|
32
|
+
workflow verifies the signature and fails closed for unsigned tags. The local override
|
|
33
|
+
exists only for explicit emergency use and is not enabled in CI.
|
|
35
34
|
3. The manual `Publish npm` workflow verifies the tag, requires the GitHub Release to
|
|
36
35
|
exist, reruns release checks, publishes npm with provenance, and uploads a SHA-256
|
|
37
36
|
checksum for the npm tarball to the GitHub Release.
|
package/bin/ark-check.mjs
CHANGED
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
arkPackageVersion,
|
|
44
44
|
REQUIRED_GATE_FILES,
|
|
45
45
|
codexPromptsDir,
|
|
46
|
+
detectWritePathCapabilities,
|
|
46
47
|
} from './lib/agent-gates.mjs';
|
|
47
48
|
import { syncBaselineIntoCheckSurfaces } from './lib/field-install.mjs';
|
|
48
49
|
import {
|
|
@@ -64,6 +65,7 @@ import {
|
|
|
64
65
|
import { runRatchetCores } from './lib/core-ratchet.mjs';
|
|
65
66
|
import {
|
|
66
67
|
baselineKey,
|
|
68
|
+
baselineOccurrenceKeys,
|
|
67
69
|
readBaseline,
|
|
68
70
|
summarizeViolations,
|
|
69
71
|
writeBaseline,
|
|
@@ -99,6 +101,7 @@ function parseArgs(argv) {
|
|
|
99
101
|
printConfig: undefined,
|
|
100
102
|
tsconfig: undefined,
|
|
101
103
|
json: false,
|
|
104
|
+
strict: false,
|
|
102
105
|
strictConfig: false,
|
|
103
106
|
requireGates: false,
|
|
104
107
|
init: false,
|
|
@@ -122,13 +125,25 @@ function parseArgs(argv) {
|
|
|
122
125
|
version: false,
|
|
123
126
|
help: false,
|
|
124
127
|
};
|
|
128
|
+
const requireValue = (flag, index) => {
|
|
129
|
+
const value = argv[index + 1];
|
|
130
|
+
if (value === undefined || value.startsWith('-')) {
|
|
131
|
+
throw new Error(`Missing value for ${flag}. Run ark-check --help for usage.`);
|
|
132
|
+
}
|
|
133
|
+
return value;
|
|
134
|
+
};
|
|
125
135
|
for (let i = 2; i < argv.length; i += 1) {
|
|
126
136
|
const arg = argv[i];
|
|
127
137
|
if (arg === '--json') args.json = true;
|
|
138
|
+
else if (arg === '--strict') {
|
|
139
|
+
args.strict = true;
|
|
140
|
+
args.strictConfig = true;
|
|
141
|
+
args.requireGates = true;
|
|
142
|
+
}
|
|
128
143
|
else if (arg === '--strict-config') args.strictConfig = true;
|
|
129
144
|
else if (arg === '--require-gates') args.requireGates = true;
|
|
130
145
|
else if (arg === '--init') args.init = true;
|
|
131
|
-
else if (arg === '--preset') args.preset =
|
|
146
|
+
else if (arg === '--preset') args.preset = requireValue(arg, i++);
|
|
132
147
|
else if (arg === '--install-agent-gates') args.installAgentGates = true;
|
|
133
148
|
else if (arg === '--tools') {
|
|
134
149
|
// Consume the next arg only when it isn't another flag (same rule as --baseline),
|
|
@@ -152,7 +167,7 @@ function parseArgs(argv) {
|
|
|
152
167
|
else if (arg === '--recommend') args.recommend = true;
|
|
153
168
|
else if (arg === '--write-plan') args.writePlan = true;
|
|
154
169
|
else if (arg === '--list-policy-packs') args.listPolicyPacks = true;
|
|
155
|
-
else if (arg === '--apply-policy-pack') args.applyPolicyPack =
|
|
170
|
+
else if (arg === '--apply-policy-pack') args.applyPolicyPack = requireValue(arg, i++);
|
|
156
171
|
else if (arg === '--suggest-include') args.suggestInclude = true;
|
|
157
172
|
else if (arg === '--adopt-contract') args.adoptContract = true;
|
|
158
173
|
else if (arg === '--ratchet-cores') args.ratchetCores = true;
|
|
@@ -174,13 +189,14 @@ function parseArgs(argv) {
|
|
|
174
189
|
const next = argv[i + 1];
|
|
175
190
|
args.baseline = next && !next.startsWith('-') ? argv[++i] : '.ark-baseline.json';
|
|
176
191
|
}
|
|
177
|
-
else if (arg === '--root') args.root = path.resolve(
|
|
178
|
-
else if (arg === '--config') args.config =
|
|
179
|
-
else if (arg === '--manifest') args.manifest =
|
|
180
|
-
else if (arg === '--print-config') args.printConfig =
|
|
181
|
-
else if (arg === '--tsconfig') args.tsconfig =
|
|
192
|
+
else if (arg === '--root') args.root = path.resolve(requireValue(arg, i++));
|
|
193
|
+
else if (arg === '--config') args.config = requireValue(arg, i++);
|
|
194
|
+
else if (arg === '--manifest') args.manifest = requireValue(arg, i++);
|
|
195
|
+
else if (arg === '--print-config') args.printConfig = requireValue(arg, i++);
|
|
196
|
+
else if (arg === '--tsconfig') args.tsconfig = requireValue(arg, i++);
|
|
182
197
|
else if (arg === '--help' || arg === '-h') args.help = true;
|
|
183
198
|
else if (arg === '--version' || arg === '-V') args.version = true;
|
|
199
|
+
else throw new Error(`Unknown argument: ${arg}. Run ark-check --help for usage.`);
|
|
184
200
|
}
|
|
185
201
|
return args;
|
|
186
202
|
}
|
|
@@ -198,7 +214,7 @@ function usage() {
|
|
|
198
214
|
return [
|
|
199
215
|
'Usage: arkgate-check | ark-check (identical bins; product name ArkGate)',
|
|
200
216
|
' ark-check --version',
|
|
201
|
-
' ark-check --root <project> --config <ark.config.json> [--manifest <ark.manifest.json>] [--tsconfig <tsconfig.json>] [--strict-config] [--require-gates] [--json] [--baseline [file]] [--report [file.html]] [--no-cache]',
|
|
217
|
+
' ark-check --root <project> --config <ark.config.json> [--manifest <ark.manifest.json>] [--tsconfig <tsconfig.json>] [--strict | --strict-config] [--require-gates] [--json] [--baseline [file]] [--report [file.html]] [--no-cache]',
|
|
202
218
|
' ark-check --coverage [--json] per-layer file counts + full unclassified list (report only, exit 0)',
|
|
203
219
|
' ark-check --plan [--json] classified remediation plan (mechanical-safe / judgment / deferred) + goal; report only',
|
|
204
220
|
' ark-check --recommend [--json] [--write-plan] application-shape plan; --write-plan emits ark-adoption-plan.json',
|
|
@@ -251,6 +267,8 @@ function usage() {
|
|
|
251
267
|
'',
|
|
252
268
|
'Config warnings are advisory by default and are included in JSON output.',
|
|
253
269
|
'Use --strict-config to make config warnings fail the check.',
|
|
270
|
+
'Use --strict for the fail-closed CI profile: --strict-config + --require-gates',
|
|
271
|
+
'plus the security diagnostics surfaced by doctor.',
|
|
254
272
|
'',
|
|
255
273
|
'--require-gates fails the check when AGENTS.md, .mcp.json, or the generated CI',
|
|
256
274
|
'workflow is missing, so "installed but never configured" is a red CI. Combine it',
|
|
@@ -301,6 +319,10 @@ function readConfig(root, configPath) {
|
|
|
301
319
|
...(raw.exclude ? { exclude: raw.exclude } : {}),
|
|
302
320
|
...(raw.excludeGenerated !== undefined ? { excludeGenerated: raw.excludeGenerated } : {}),
|
|
303
321
|
...(raw.cyclePolicy ? { cyclePolicy: raw.cyclePolicy } : {}),
|
|
322
|
+
...(raw.dynamicImportAllowlist
|
|
323
|
+
? { dynamicImportAllowlist: raw.dynamicImportAllowlist }
|
|
324
|
+
: {}),
|
|
325
|
+
...(raw.safety ? { safety: raw.safety } : {}),
|
|
304
326
|
};
|
|
305
327
|
}
|
|
306
328
|
|
|
@@ -316,7 +338,7 @@ function detectConfig(root) {
|
|
|
316
338
|
|
|
317
339
|
for (const entry of DEFAULT_INTENT_PREFIXES) {
|
|
318
340
|
const directories = (DEFAULT_LAYER_DIRECTORIES[entry.layer] ?? []).filter(
|
|
319
|
-
(directory) => walk(path.join(root, srcDir, directory)).length > 0
|
|
341
|
+
(directory) => walk(path.join(root, srcDir, directory), [], { root }).length > 0
|
|
320
342
|
);
|
|
321
343
|
if (directories.length === 0) continue;
|
|
322
344
|
layers.push({
|
|
@@ -784,7 +806,7 @@ function runInit(args) {
|
|
|
784
806
|
}
|
|
785
807
|
// The starter profile only governs src/. Existing source elsewhere would make the
|
|
786
808
|
// gate silently green, so surface it instead of pretending the project is covered.
|
|
787
|
-
const outside = walk(args.root)
|
|
809
|
+
const outside = walk(args.root, [], { root: args.root })
|
|
788
810
|
.map((file) => normalize(path.relative(args.root, file)))
|
|
789
811
|
.filter((rel) => !rel.startsWith('src/') && !rel.split('/').some((s) => s.startsWith('.')));
|
|
790
812
|
if (outside.length > 0) {
|
|
@@ -956,6 +978,9 @@ async function main() {
|
|
|
956
978
|
|
|
957
979
|
if (args.requireGates) {
|
|
958
980
|
const missing = missingGates(args.root);
|
|
981
|
+
if (args.strict && !detectWritePathCapabilities(args.root).hookPresent) {
|
|
982
|
+
missing.push('PreToolUse write hook');
|
|
983
|
+
}
|
|
959
984
|
if (missing.length > 0) {
|
|
960
985
|
const payload = {
|
|
961
986
|
ok: false,
|
|
@@ -1032,7 +1057,7 @@ async function main() {
|
|
|
1032
1057
|
);
|
|
1033
1058
|
}
|
|
1034
1059
|
|
|
1035
|
-
const { violations, warnings } = runArchitectureScan({
|
|
1060
|
+
const { violations, warnings, safety } = runArchitectureScan({
|
|
1036
1061
|
root,
|
|
1037
1062
|
config,
|
|
1038
1063
|
manifest,
|
|
@@ -1046,6 +1071,7 @@ async function main() {
|
|
|
1046
1071
|
runDoctor(root, config, files, rules, violations, args.json, {
|
|
1047
1072
|
configPath: path.isAbsolute(args.config) ? args.config : path.join(root, args.config),
|
|
1048
1073
|
configMissing: !fs.existsSync(path.isAbsolute(args.config) ? args.config : path.join(root, args.config)),
|
|
1074
|
+
safety,
|
|
1049
1075
|
});
|
|
1050
1076
|
return;
|
|
1051
1077
|
}
|
|
@@ -1118,11 +1144,10 @@ async function main() {
|
|
|
1118
1144
|
if (args.baseline) {
|
|
1119
1145
|
const baseline = readBaseline(root, args.baseline);
|
|
1120
1146
|
if (baseline.exists) {
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
);
|
|
1125
|
-
const currentKeys = new Set(violations.map(baselineKey));
|
|
1147
|
+
const occurrenceKeys = baselineOccurrenceKeys(violations);
|
|
1148
|
+
suppressed = violations.filter((_, index) => baseline.keys.has(occurrenceKeys[index]));
|
|
1149
|
+
activeViolations = violations.filter((_, index) => !baseline.keys.has(occurrenceKeys[index]));
|
|
1150
|
+
const currentKeys = new Set(occurrenceKeys);
|
|
1126
1151
|
staleBaselineKeys = [...baseline.keys].filter((key) => !currentKeys.has(key)).length;
|
|
1127
1152
|
} else {
|
|
1128
1153
|
warnings.push(
|