arkgate 4.6.0 → 4.6.2
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 +54 -1
- package/README.md +11 -5
- package/bin/ark-check-runtime.mjs +115 -128
- package/bin/ark-mcp-runtime.mjs +86 -48
- package/bin/ark.mjs +21 -78
- package/bin/lib/agent-projection.mjs +1 -1
- package/bin/lib/analysis-engine.mjs +3 -3
- package/bin/lib/ci-and-commands.mjs +11 -11
- package/bin/lib/config-contract.mjs +2 -0
- package/bin/lib/contract-smells.mjs +5 -5
- package/bin/lib/design-smells.mjs +1 -1
- package/bin/lib/doctor-advisories.mjs +9 -0
- package/bin/lib/doctor-next-actions.mjs +92 -0
- package/bin/lib/doctor-plan.mjs +61 -71
- package/bin/lib/field-install.mjs +1 -1
- package/bin/lib/first-run-help.mjs +221 -0
- package/bin/lib/html-report-advisories.mjs +20 -0
- package/bin/lib/improvement-compass-map.mjs +20 -20
- package/bin/lib/pilot-loop.mjs +1 -1
- package/bin/lib/post-green-path.mjs +2 -2
- package/bin/lib/prepare-change.mjs +9 -0
- package/bin/lib/product-copy.mjs +1 -1
- package/bin/lib/start-preview.mjs +17 -10
- package/bin/lib/status-command.mjs +19 -0
- package/bin/lib/status-manifest.mjs +23 -0
- package/bin/lib/team-parliament-io.mjs +338 -0
- package/bin/lib/team-parliament.mjs +383 -0
- package/bin/lib/upgrade-whats-new.mjs +16 -0
- package/bin/lib/violations.mjs +8 -4
- package/dist/{configTypes-CC0FEXoF.d.ts → configTypes-B8uIcLaG.d.ts} +5 -0
- package/dist/eslint/index.cjs +2 -2
- package/dist/eslint/index.d.ts +1 -1
- package/dist/eslint/index.js +2 -2
- package/dist/index.cjs +8 -8
- package/dist/index.d.ts +66 -2
- package/dist/index.js +8 -8
- package/docs/README.md +5 -5
- package/docs/agent-guide.md +21 -17
- package/docs/configuration.md +36 -2
- package/docs/develop.md +13 -1
- package/docs/enthusiast/README.md +1 -1
- package/docs/enthusiast/how-to-agent-gates.md +3 -3
- package/docs/enthusiast/how-to-pick-shape.md +2 -2
- package/docs/enthusiast/tutorial-first-project.md +4 -3
- package/docs/package-surface.md +5 -3
- package/docs/product-voice.md +48 -10
- package/docs/use.md +10 -5
- package/package.json +2 -2
- package/schemas/ark.config.schema.json +9 -0
- package/schemas/ark.status-manifest.schema.json +51 -0
- package/server.json +3 -3
- package/templates/agent-skills/README.md +1 -1
- package/templates/agent-skills/ark-adopt/SKILL.md +59 -23
- package/templates/agent-skills/ark-architect/SKILL.md +24 -145
- package/templates/agent-skills/ark-autopilot/SKILL.md +49 -32
- package/templates/agent-skills/ark-contract/SKILL.md +21 -105
- package/templates/agent-skills/ark-coverage/SKILL.md +7 -3
- package/templates/agent-skills/ark-explain/SKILL.md +8 -4
- package/templates/agent-skills/ark-explore/SKILL.md +38 -21
- package/templates/agent-skills/ark-fix/SKILL.md +34 -157
- package/templates/agent-skills/ark-loop/SKILL.md +31 -153
- package/templates/agent-skills/ark-place/SKILL.md +35 -14
- package/templates/agent-skills/ark-runtime/SKILL.md +3 -3
- package/templates/agent-skills/ark-think/SKILL.md +6 -2
- package/templates/agent-skills/ark-upgrade/SKILL.md +21 -10
- package/templates/skills/ark-adopt.md +59 -23
- package/templates/skills/ark-architect.md +24 -145
- package/templates/skills/ark-autopilot.md +49 -32
- package/templates/skills/ark-contract.md +21 -105
- package/templates/skills/ark-coverage.md +7 -3
- package/templates/skills/ark-explain.md +8 -4
- package/templates/skills/ark-explore.md +38 -21
- package/templates/skills/ark-fix.md +34 -157
- package/templates/skills/ark-loop.md +31 -153
- package/templates/skills/ark-place.md +35 -14
- package/templates/skills/ark-runtime.md +3 -3
- package/templates/skills/ark-think.md +6 -2
- package/templates/skills/ark-upgrade.md +21 -10
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,59 @@ in the immutable pre-2.0 archive linked below.
|
|
|
5
5
|
|
|
6
6
|
## Unreleased
|
|
7
7
|
|
|
8
|
+
## 4.6.2 — 2026-08-16
|
|
9
|
+
|
|
10
|
+
**Patch** over **4.6.1**. First-contact copy: a newcomer (human or coding agent) sees what
|
|
11
|
+
to do in a few lines — `arkgate` / `arkgate-check --help`, start wrap-up, doctor light +
|
|
12
|
+
#1, write-gate deny, SessionStart, MCP tool order, and the five doors. Same 13 skill names.
|
|
13
|
+
**No required config migration.**
|
|
14
|
+
|
|
15
|
+
**Status: prepared** (not yet on npm `latest`; see `docs/releases/4.6.2.md`).
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- **First-run help:** `arkgate --help` and `arkgate-check --help` are short; encyclopedia
|
|
20
|
+
text is `--help --all`. `arkgate upgrade --help` is preview vs apply.
|
|
21
|
+
- **Start wrap-up:** doctor → `/ark-adopt` session 0 (not `/ark-autopilot` as step 1).
|
|
22
|
+
- **Doctor:** operating-mode light + primary next action #1 print first.
|
|
23
|
+
- **Write-gate deny:** `blocked {file} — {reason}` then `Next:` (move the import / `/ark-place`).
|
|
24
|
+
Rule id on a following line. No “call ark_manifest”.
|
|
25
|
+
- **Agents:** SessionStart points at `/ark-adopt` or `arkgate-check --doctor`. `ark_identity`
|
|
26
|
+
is first. `ark_check` is a scan (pass/fail/incomplete), not a yes/no architecture score.
|
|
27
|
+
`server.json` first sentence is the layers definition.
|
|
28
|
+
- **Skills:** five doors open with when + steps. Shortcuts are not the first-run menu.
|
|
29
|
+
- **Status:** `nextAction` is `map-leftover-design` when leftover design work remains
|
|
30
|
+
(never `stay-enforced`).
|
|
31
|
+
- **npm `description`:** `One architecture config. One check. One coach.` (not “co-pilot”).
|
|
32
|
+
- **`docs/use.md`:** Cursor hard-blocks Write/StrReplace when hooks are trusted;
|
|
33
|
+
Codex/OpenCode stay advisory.
|
|
34
|
+
|
|
35
|
+
## 4.6.1 — 2026-08-14
|
|
36
|
+
|
|
37
|
+
**Patch** over **4.6.0**. Five-door autonomy (skills write or map in-turn; CLI is sensor +
|
|
38
|
+
gate) plus team parliament (law vs feature: stewards, mixed-PR deny, ratchet vs the merge
|
|
39
|
+
base, cheap `--changed` check). Same 13 skill names. Steward identity is a GitHub handle or
|
|
40
|
+
email, not git `user.name`. **No required config migration.**
|
|
41
|
+
|
|
42
|
+
**Status: published** (on npm `latest`; see `docs/releases/4.6.1.md`).
|
|
43
|
+
|
|
44
|
+
### Added
|
|
45
|
+
|
|
46
|
+
- **Five-door autonomy (SK01–SK05):** `/ark-adopt`, `/ark-place`, `/ark-autopilot`,
|
|
47
|
+
`/ark-explore`, `/ark-upgrade` write or map in the same turn. The other eight names stay
|
|
48
|
+
installed as shortcuts. Invoking a door is the approval; the CLI does not apply the change.
|
|
49
|
+
- **Team parliament (TW01–TW08):** mixed law+product deny; optional `stewards` (GitHub handle
|
|
50
|
+
or email); `--contract-session` / `--contract-diff` / `--changed --base` / `--against` /
|
|
51
|
+
`--persona` / `--author`; `ark status --vs`; doctor `stewardNudge` (ask or show list drift).
|
|
52
|
+
`stewards` is excluded from the policy hash.
|
|
53
|
+
|
|
54
|
+
### Changed
|
|
55
|
+
|
|
56
|
+
- Doctor, compact router, and public lanes prefer the five doors. Historical changelogs stay
|
|
57
|
+
as shipped.
|
|
58
|
+
- Published 4.6.1 tarball `README.md` still banners 4.6.0 (packed at `1eadc96` before the
|
|
59
|
+
pointer flip). Tree README on `main` is current. No 4.6.2 for that banner.
|
|
60
|
+
|
|
8
61
|
## 4.6.0 — 2026-08-12
|
|
9
62
|
|
|
10
63
|
**Minor** over **4.5.7**. Understandable Ark: doctor, HTML, skills, and public docs use common
|
|
@@ -13,7 +66,7 @@ software words (import rules, leftover design work, pre-write block) while **Ark
|
|
|
13
66
|
“always latest” floor Codex already had. **No required config migration.** JSON field names
|
|
14
67
|
and `ruleId`s stay stable. No new skill names, sensors, or scores.
|
|
15
68
|
|
|
16
|
-
**Status:
|
|
69
|
+
**Status: published** (on npm `latest`; see `docs/releases/4.6.0.md`).
|
|
17
70
|
|
|
18
71
|
### Added
|
|
19
72
|
|
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 4.6.
|
|
20
|
-
>
|
|
19
|
+
> **ArkGate 4.6.1** is on npm `latest` — five doors + a lock on the constitution.
|
|
20
|
+
> **4.6.2** is prepared on this tree (first-contact copy; not yet `latest`).
|
|
21
|
+
> [4.6.2 notes](docs/releases/4.6.2.md) · [4.6.1](docs/releases/4.6.1.md) · [4.6.0](docs/releases/4.6.0.md) · [Docs hub](docs/README.md) · [Product voice](docs/product-voice.md)
|
|
21
22
|
|
|
22
23
|
---
|
|
23
24
|
|
|
@@ -48,10 +49,13 @@ dependency inversion — **not a score**). Leftover lenses mean design work may
|
|
|
48
49
|
imports are green. Details: [use.md — Improvement compass](docs/use.md#improvement-compass-not-a-score).
|
|
49
50
|
|
|
50
51
|
```text
|
|
51
|
-
start → doctor (+ compass) → day-to-day
|
|
52
|
-
↘
|
|
52
|
+
start → doctor (+ compass) → /ark-adopt (session 0) → day-to-day /ark-place
|
|
53
|
+
↘ /ark-explore then /ark-autopilot when leftover design remains
|
|
53
54
|
```
|
|
54
55
|
|
|
56
|
+
Teams: keep the constitution out of product PRs. Local gate
|
|
57
|
+
`ark-check --changed --base origin/dev`. Steward law PRs use `--contract-session`.
|
|
58
|
+
|
|
55
59
|
Aliases `ark` / `ark-check` / `ark-mcp` still work. npm / pnpm / yarn. No install lifecycle scripts.
|
|
56
60
|
|
|
57
61
|

|
|
@@ -210,7 +214,9 @@ for real systems. Details: [docs/production-hardening.md](docs/production-harden
|
|
|
210
214
|
| Config · package surface · TS | [configuration](docs/configuration.md) · [package-surface](docs/package-surface.md) · [typescript-support](docs/typescript-support.md) |
|
|
211
215
|
| Brownfield | [docs/brownfield-adoption.md](docs/brownfield-adoption.md) |
|
|
212
216
|
| Security | [SECURITY.md](SECURITY.md) |
|
|
213
|
-
| Current release (4.
|
|
217
|
+
| Current release (4.6.1 on npm `latest`) | [docs/releases/4.6.1.md](docs/releases/4.6.1.md) · [CHANGELOG](CHANGELOG.md) |
|
|
218
|
+
| Prepared (4.6.2 — not yet `latest`) | [docs/releases/4.6.2.md](docs/releases/4.6.2.md) |
|
|
219
|
+
| Prior (4.5.7) | [docs/releases/4.5.7.md](docs/releases/4.5.7.md) |
|
|
214
220
|
| Prior (4.5.0) | [docs/releases/4.5.0.md](docs/releases/4.5.0.md) |
|
|
215
221
|
| Prior (4.4.0) | [docs/releases/4.4.0.md](docs/releases/4.4.0.md) |
|
|
216
222
|
| Prior (4.3.0) | [docs/releases/4.3.0.md](docs/releases/4.3.0.md) |
|
|
@@ -95,6 +95,7 @@ import {
|
|
|
95
95
|
writeArkRulesTemplates,
|
|
96
96
|
} from './lib/presets.mjs';
|
|
97
97
|
import { loadArkConfigContract, parseArkConfigJson } from './lib/config-contract.mjs';
|
|
98
|
+
import { checkUsage, checkUsageAll } from './lib/first-run-help.mjs';
|
|
98
99
|
import { createAdapterResult } from './lib/adapter-contract.mjs';
|
|
99
100
|
import { collectGovernedFiles, normalize, walk } from './lib/scan-files.mjs';
|
|
100
101
|
import { configWarning } from './lib/config-warnings.mjs';
|
|
@@ -103,6 +104,13 @@ import { ANALYSIS_COMPLETENESS, analysisIncompleteStatement } from './lib/analys
|
|
|
103
104
|
import { reportUnavailableAnalysis } from './lib/unavailable-analysis.mjs';
|
|
104
105
|
import { validateHardWriteRequest } from './lib/enforcement-profiles.mjs';
|
|
105
106
|
import { analyzePolicyTransition } from './lib/policy-delta-io.mjs';
|
|
107
|
+
import {
|
|
108
|
+
applyAgainstRatchet,
|
|
109
|
+
bindTeamBaseRefs,
|
|
110
|
+
filterChangedGovernedFiles,
|
|
111
|
+
runTeamPreflight,
|
|
112
|
+
ungovernedDumpMessage,
|
|
113
|
+
} from './lib/team-parliament-io.mjs';
|
|
106
114
|
import { tryResidentDoctor } from './lib/resident-doctor-client.mjs';
|
|
107
115
|
import { createDesignDeltaCheck } from './lib/design-delta.mjs';
|
|
108
116
|
import {
|
|
@@ -134,6 +142,14 @@ function parseArgs(argv) {
|
|
|
134
142
|
policyBase: undefined,
|
|
135
143
|
policyBaseRef: undefined,
|
|
136
144
|
policyAck: undefined, failOnNewSmells: false, baseRef: undefined,
|
|
145
|
+
contractSession: false,
|
|
146
|
+
contractDiff: false,
|
|
147
|
+
changed: false,
|
|
148
|
+
against: undefined,
|
|
149
|
+
base: undefined,
|
|
150
|
+
persona: undefined,
|
|
151
|
+
author: undefined,
|
|
152
|
+
failUngoverned: false,
|
|
137
153
|
updateBaseline: false,
|
|
138
154
|
noCache: false,
|
|
139
155
|
resident: false,
|
|
@@ -151,12 +167,13 @@ function parseArgs(argv) {
|
|
|
151
167
|
noOpenReport: false,
|
|
152
168
|
version: false,
|
|
153
169
|
help: false,
|
|
170
|
+
all: false,
|
|
154
171
|
followConfigRoot: false,
|
|
155
172
|
};
|
|
156
173
|
const requireValue = (flag, index) => {
|
|
157
174
|
const value = argv[index + 1];
|
|
158
175
|
if (value === undefined || value.startsWith('-')) {
|
|
159
|
-
throw new Error(`Missing value for ${flag}. Run
|
|
176
|
+
throw new Error(`Missing value for ${flag}. Run arkgate-check --help for usage.`);
|
|
160
177
|
}
|
|
161
178
|
return value;
|
|
162
179
|
};
|
|
@@ -241,14 +258,22 @@ function parseArgs(argv) {
|
|
|
241
258
|
else if (arg === '--policy-base') args.policyBase = requireValue(arg, i++);
|
|
242
259
|
else if (arg === '--policy-base-ref') args.policyBaseRef = requireValue(arg, i++);
|
|
243
260
|
else if (arg === '--policy-ack') args.policyAck = requireValue(arg, i++); else if (arg === '--fail-on-new-smells') args.failOnNewSmells = true; else if (arg === '--base-ref') args.baseRef = requireValue(arg, i++);
|
|
261
|
+
else if (arg === '--contract-session') args.contractSession = true;
|
|
262
|
+
else if (arg === '--contract-diff') args.contractDiff = true;
|
|
263
|
+
else if (arg === '--changed') args.changed = true;
|
|
264
|
+
else if (arg === '--against') args.against = requireValue(arg, i++);
|
|
265
|
+
else if (arg === '--base') args.base = requireValue(arg, i++);
|
|
266
|
+
else if (arg === '--persona') args.persona = requireValue(arg, i++);
|
|
267
|
+
else if (arg === '--author') args.author = requireValue(arg, i++);
|
|
244
268
|
else if (arg === '--root') args.root = path.resolve(requireValue(arg, i++));
|
|
245
269
|
else if (arg === '--config') args.config = requireValue(arg, i++);
|
|
246
270
|
else if (arg === '--manifest') args.manifest = requireValue(arg, i++);
|
|
247
271
|
else if (arg === '--print-config') args.printConfig = requireValue(arg, i++);
|
|
248
272
|
else if (arg === '--tsconfig') args.tsconfig = requireValue(arg, i++);
|
|
249
273
|
else if (arg === '--help' || arg === '-h') args.help = true;
|
|
274
|
+
else if (arg === '--all') args.all = true;
|
|
250
275
|
else if (arg === '--version' || arg === '-V') args.version = true;
|
|
251
|
-
else throw new Error(`Unknown argument: ${arg}. Run
|
|
276
|
+
else throw new Error(`Unknown argument: ${arg}. Run arkgate-check --help for usage.`);
|
|
252
277
|
}
|
|
253
278
|
return args;
|
|
254
279
|
}
|
|
@@ -261,111 +286,6 @@ function displayPathFromRoot(root, absPath) {
|
|
|
261
286
|
}
|
|
262
287
|
return rel.split(path.sep).join('/');
|
|
263
288
|
}
|
|
264
|
-
function usage() {
|
|
265
|
-
return [
|
|
266
|
-
'Usage: arkgate-check | ark-check (identical bins; product name ArkGate)',
|
|
267
|
-
' ark-check --version',
|
|
268
|
-
' ark-check --root <project> --config <ark.config.json> [--manifest <ark.manifest.json>] [--tsconfig <tsconfig.json>] [--strict-merge | --strict | --strict-config] [--policy-base <file> | --policy-base-ref <git-ref>] [--policy-ack <file>] [--fail-on-new-smells --base-ref <git-ref>] [--require-gates] [--require-write-hook <host>] [--json] [--baseline [file]] [--report [file.html]] [--no-cache]',
|
|
269
|
-
' ark-check --doctor [--json] [--resident] [--fail-on-new-smells --base-ref <git-ref>] read-only diagnosis; resident JSON falls back cold',
|
|
270
|
-
' ark-check --coverage [--json] per-layer file counts + full unclassified list (report only, exit 0)',
|
|
271
|
-
' ark-check --plan [--json] classified remediation plan (mechanical-safe / judgment / deferred) + goal; report only',
|
|
272
|
-
' ark-check --rules-inventory [--json] brownfield rules inventory (AR13; deterministic candidates, not a score)',
|
|
273
|
-
' ark-check --recommend [--json] [--write-plan] application-shape plan; --write-plan emits ark-adoption-plan.json',
|
|
274
|
-
' ark-check --list-policy-packs enthusiast packs (hexagonal, layered, feature-sliced, monorepo, ui-surface, vertical-slice, ddd-bounded-contexts)',
|
|
275
|
-
' ark-check --apply-policy-pack <id> [--force] write ark.config.json from templates/policy-packs/ (uses preset factory)',
|
|
276
|
-
' ark-check --suggest-include [--json] propose include roots (TS packages / workspaces)',
|
|
277
|
-
' ark-check --adopt-contract [--write] expand include + layer patterns from ungoverned dirs (never bare lib→Presentation)',
|
|
278
|
-
' ark-check --migrate-contract [--write] additive P0-A retrofit: inject app/api/** → Application when missing',
|
|
279
|
-
' ark-check --ratchet-cores when raw graph is green (0 violations; baseline ignored), set optional:false on populated cores only (writes ark.config.json)',
|
|
280
|
-
' ark-check --watch re-run the check when governed files change (debounced)',
|
|
281
|
-
' ark-check --report [file.html] [--beginner] [--reset-origin] [--no-archive] [--open|--no-open]',
|
|
282
|
-
' HTML report + snapshots under .ark/reports/ (origin once, latest each run, history JSON)',
|
|
283
|
-
' Best-effort open in browser (local TTY). No-op if open fails. --no-open / ARK_NO_OPEN_REPORT=1 to skip; --open forces open.',
|
|
284
|
-
' ark-check --init [--preset hexagonal|layered|feature-sliced|monorepo|ui-surface|vertical-slice|ddd-bounded-contexts|vite-vercel-spa|clean-architecture|onion-architecture] [--force] [--follow-config-root]',
|
|
285
|
-
' --follow-config-root On writes (init/install-agent-gates/migrate --write/…), adopt walked-up monorepo config root (default: keep explicit --root)',
|
|
286
|
-
' ark-check --install-agent-gates [--tools claude,cursor,codex,grok] [--require-write-hook <host>] [--skills-only] [--codex-home] [--claude-home] [--grok-home] [--agent-homes] [--force]',
|
|
287
|
-
' ark-check --update-baseline [file] freeze current violations (default .ark-baseline.json)',
|
|
288
|
-
' ark-check --print-config eleven-layer',
|
|
289
|
-
'',
|
|
290
|
-
'Adopting Ark in an existing codebase? Run --update-baseline once to freeze existing',
|
|
291
|
-
'violations, commit the baseline file, and gate CI with --baseline: only NEW violations',
|
|
292
|
-
'fail the check, so the ratchet only moves toward zero.',
|
|
293
|
-
'',
|
|
294
|
-
'--init scans the project for the built-in layer directory conventions (src/domain,',
|
|
295
|
-
'src/application, src/adapters/persistence, ...) and writes an ark.config.json covering',
|
|
296
|
-
'only the layers that actually exist, with the default rules filtered to those layers.',
|
|
297
|
-
'Undetected profile layers are printed as suggestions with their conventional',
|
|
298
|
-
'directories. When nothing is detected, the full 11-layer starter profile is written',
|
|
299
|
-
'instead (all layers optional, anchored at src/), so the strict check passes today and',
|
|
300
|
-
'each layer starts being enforced as soon as its directory gains source files.',
|
|
301
|
-
'',
|
|
302
|
-
'Resolves relative, tsconfig path-alias, and package imports via the TypeScript',
|
|
303
|
-
'module resolver, then checks each resolved cross-layer import against the rules.',
|
|
304
|
-
'Path aliases resolve against the NEAREST tsconfig.json above each source file, so',
|
|
305
|
-
'monorepo packages with per-package configs work under a single --root. Pass',
|
|
306
|
-
'--tsconfig to force one config for every file. If no tsconfig is found, path',
|
|
307
|
-
'aliases are unavailable but relative/package imports still resolve.',
|
|
308
|
-
'',
|
|
309
|
-
'The correctness path resolves and parses one complete candidate on every invocation.',
|
|
310
|
-
'Legacy node_modules/.cache/ark-check.json files are ignored. --no-cache remains an',
|
|
311
|
-
'accepted compatibility no-op; the identity-keyed warm snapshot is introduced in Z07.',
|
|
312
|
-
'',
|
|
313
|
-
'Config shape:',
|
|
314
|
-
'{',
|
|
315
|
-
' "include": ["src"],',
|
|
316
|
-
' // optional: "exclude": ["**/vendor/**"], "excludeGenerated": false (default skips *.gen.ts / *.generated.ts)',
|
|
317
|
-
' "layers": [',
|
|
318
|
-
' { "name": "DomainModel", "patterns": ["src/domain/**"], "intentPrefixes": ["Domain."],',
|
|
319
|
-
' "forbiddenGlobals": ["fetch", "process", "Date.now", "Math.random"] }',
|
|
320
|
-
' ],',
|
|
321
|
-
' "rules": [{ "from": "DomainModel", "to": "PersistenceAdapters", "allowed": false }]',
|
|
322
|
-
'}',
|
|
323
|
-
'',
|
|
324
|
-
'Config warnings are advisory by default and are included in JSON output.',
|
|
325
|
-
'Use --strict-config to make config warnings fail the check.',
|
|
326
|
-
'Use --strict-merge for the fail-closed CI profile: --strict-config + --require-gates',
|
|
327
|
-
'plus the security diagnostics surfaced by doctor. --strict is a compatibility alias.',
|
|
328
|
-
'This merge profile never depends on an editor/agent hook.',
|
|
329
|
-
'When a Git merge base is available, --strict-merge classifies the ark.config.json',
|
|
330
|
-
'transition. Weakening or judgment-required findings fail unless --policy-ack names',
|
|
331
|
-
'every finding and is bound to both policy hashes. Use --policy-base/--policy-base-ref',
|
|
332
|
-
'for an explicit comparison; ARK_POLICY_BASE_REF is the CI environment equivalent.',
|
|
333
|
-
'Add --require-write-hook claude|grok|antigravity|cursor to validate a hard local write',
|
|
334
|
-
'boundary for that specific host. Codex and OpenCode expose advisory MCP (plus best-effort',
|
|
335
|
-
'hooks where applicable) and the shared CI check; merge blocking requires repository policy',
|
|
336
|
-
'to make that status required.',
|
|
337
|
-
'',
|
|
338
|
-
'--require-gates implies --strict-config and fails when the Ark contract in AGENTS.md,',
|
|
339
|
-
'the project-rooted Ark server in .mcp.json, or fail-closed CI is missing/invalid.',
|
|
340
|
-
'Included but unclassified source files therefore stay red instead of false-green.',
|
|
341
|
-
'',
|
|
342
|
-
'--install-agent-gates writes AGENTS.md, .mcp.json, and the CI workflow for every',
|
|
343
|
-
'project, plus tool-specific templates. Known tools: claude, cursor, codex, grok',
|
|
344
|
-
'(Claude/Grok/Antigravity/Cursor hard-write hooks when covered; Codex advisory MCP;',
|
|
345
|
-
'shared CI check for all) and',
|
|
346
|
-
'windsurf, cline, copilot, kiro, roo, continue, gemini',
|
|
347
|
-
'(instruction-tier rule files derived from the same contract).',
|
|
348
|
-
'It also installs the /ark-* skills shipped in templates/skills/ into each',
|
|
349
|
-
'detected tool\'s command location (.claude/skills/, .cursor/commands/,',
|
|
350
|
-
'.agents/skills/ (Codex REPO catalog), .grok/skills/, .windsurf/workflows/,',
|
|
351
|
-
'.clinerules/workflows/, .github/prompts/).',
|
|
352
|
-
'Kiro, Roo, Continue, and Gemini have no command mechanism and receive only their',
|
|
353
|
-
'rule file. Existing files are never overwritten without --force, so re-running',
|
|
354
|
-
'after an update only adds what is missing. --skills-only restricts the write to',
|
|
355
|
-
'just the /ark-* skills (safe to --force-refresh — it leaves a customized AGENTS.md,',
|
|
356
|
-
'settings, and CI workflow untouched).',
|
|
357
|
-
'Pass --tools to pick which tool configs to write; otherwise they are auto-detected',
|
|
358
|
-
'from their config directories (.claude/, .cursor/, .codex/, .grok/, .windsurf/,',
|
|
359
|
-
'.clinerules/, .kiro/, .roo/, .continue/, .gemini/; copilot is explicit-only).',
|
|
360
|
-
'claude+cursor+codex+grok are written when nothing is detected.',
|
|
361
|
-
'',
|
|
362
|
-
'Generate a starter 11-layer config:',
|
|
363
|
-
' ark-check --print-config eleven-layer > ark.config.json',
|
|
364
|
-
'',
|
|
365
|
-
'Install agent + CI enforcement templates:',
|
|
366
|
-
' ark-check --install-agent-gates',
|
|
367
|
-
].join('\n');
|
|
368
|
-
}
|
|
369
289
|
|
|
370
290
|
function readConfig(root, configPath) {
|
|
371
291
|
const fullPath = path.isAbsolute(configPath)
|
|
@@ -546,7 +466,7 @@ function runApplyPolicyPack(args) {
|
|
|
546
466
|
|
|
547
467
|
if (fs.existsSync(configPath) && !args.force) {
|
|
548
468
|
console.error(
|
|
549
|
-
`${configPath} already exists. Re-run with --force to overwrite, or use /ark-
|
|
469
|
+
`${configPath} already exists. Re-run with --force to overwrite, or use /ark-adopt to evolve it.`
|
|
550
470
|
);
|
|
551
471
|
process.exitCode = 2;
|
|
552
472
|
return;
|
|
@@ -1030,7 +950,7 @@ function runInit(args) {
|
|
|
1030
950
|
console.log('A green check ignores this code; it is not "clean", it is unchecked.');
|
|
1031
951
|
if (recognized.length > 0) {
|
|
1032
952
|
console.log('');
|
|
1033
|
-
console.log('Proposed layer for each (from the 11-layer profile + presets — apply via /ark-
|
|
953
|
+
console.log('Proposed layer for each (from the 11-layer profile + presets — apply via /ark-adopt):');
|
|
1034
954
|
for (const p of recognized) {
|
|
1035
955
|
const alt = p.alternatives?.length ? ` (or ${p.alternatives.join(' / ')} — confirm)` : '';
|
|
1036
956
|
console.log(` ${p.dir}/ → ${p.layer}${alt}`);
|
|
@@ -1121,7 +1041,7 @@ async function main() {
|
|
|
1121
1041
|
process.exit(0);
|
|
1122
1042
|
}
|
|
1123
1043
|
if (args.help) {
|
|
1124
|
-
console.log(
|
|
1044
|
+
console.log(args.all ? checkUsageAll() : checkUsage());
|
|
1125
1045
|
return;
|
|
1126
1046
|
}
|
|
1127
1047
|
if (args.init) {
|
|
@@ -1281,19 +1201,71 @@ async function main() {
|
|
|
1281
1201
|
}
|
|
1282
1202
|
|
|
1283
1203
|
const root = args.root;
|
|
1204
|
+
const bound = bindTeamBaseRefs(args, root);
|
|
1205
|
+
Object.assign(args, bound.args);
|
|
1284
1206
|
const config = readConfig(root, args.config);
|
|
1285
1207
|
const policyDelta = analyzePolicyTransition({
|
|
1286
1208
|
root,
|
|
1287
1209
|
configPath: args.config,
|
|
1288
1210
|
candidateConfig: config,
|
|
1289
|
-
strictMerge: args.strictMerge,
|
|
1211
|
+
strictMerge: args.strictMerge || args.contractDiff,
|
|
1290
1212
|
basePath: args.policyBase,
|
|
1291
1213
|
baseRef: args.policyBaseRef,
|
|
1292
1214
|
acknowledgementPath: args.policyAck,
|
|
1293
1215
|
});
|
|
1216
|
+
const preflight = runTeamPreflight({
|
|
1217
|
+
root,
|
|
1218
|
+
args,
|
|
1219
|
+
config,
|
|
1220
|
+
policyDelta,
|
|
1221
|
+
teamBase: bound.teamBase,
|
|
1222
|
+
});
|
|
1223
|
+
const teamParliament = preflight.teamParliament;
|
|
1224
|
+
const changedPaths = preflight.changedPaths;
|
|
1225
|
+
if (preflight.halt) {
|
|
1226
|
+
if (args.json) {
|
|
1227
|
+
console.log(
|
|
1228
|
+
JSON.stringify(
|
|
1229
|
+
{
|
|
1230
|
+
ok: preflight.halt.exitCode === 0,
|
|
1231
|
+
...(preflight.halt.cheap ? { cheap: true } : {}),
|
|
1232
|
+
teamParliament: preflight.halt.teamParliament,
|
|
1233
|
+
...(policyDelta ? { policyDelta } : {}),
|
|
1234
|
+
},
|
|
1235
|
+
null,
|
|
1236
|
+
2
|
|
1237
|
+
)
|
|
1238
|
+
);
|
|
1239
|
+
} else if (preflight.halt.exitCode === 0) {
|
|
1240
|
+
console.log('✔ Ark check passed (no governed source or constitution files in the diff).');
|
|
1241
|
+
} else {
|
|
1242
|
+
console.error(preflight.halt.message);
|
|
1243
|
+
}
|
|
1244
|
+
process.exitCode = preflight.halt.exitCode;
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1294
1247
|
const manifest = readManifest(root, args.manifest);
|
|
1295
1248
|
const rules = manifest?.architecture?.rules ?? config.rules;
|
|
1296
|
-
const
|
|
1249
|
+
const allGovernedFiles = collectGovernedFiles(root, config);
|
|
1250
|
+
if (args.failUngoverned && teamParliament?.changeSet?.productPaths?.length) {
|
|
1251
|
+
const governedRel = new Set(
|
|
1252
|
+
allGovernedFiles.map((abs) => normalize(path.relative(root, abs)))
|
|
1253
|
+
);
|
|
1254
|
+
const dumped = teamParliament.changeSet.productPaths.filter((rel) => !governedRel.has(rel));
|
|
1255
|
+
if (dumped.length > 0) {
|
|
1256
|
+
const message = ungovernedDumpMessage(dumped);
|
|
1257
|
+
if (args.json) {
|
|
1258
|
+
console.log(JSON.stringify({ ok: false, teamParliament: { ...teamParliament, ungoverned: dumped }, message }, null, 2));
|
|
1259
|
+
} else {
|
|
1260
|
+
console.error(message);
|
|
1261
|
+
}
|
|
1262
|
+
process.exitCode = 1;
|
|
1263
|
+
return;
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
const files = args.changed
|
|
1267
|
+
? filterChangedGovernedFiles(allGovernedFiles, root, changedPaths, normalize)
|
|
1268
|
+
: allGovernedFiles;
|
|
1297
1269
|
|
|
1298
1270
|
// --coverage is a pure glob/report view (no TypeScript resolver), so serve it BEFORE the
|
|
1299
1271
|
// TS import: the report must work — and exit 0 — even when typescript isn't installed.
|
|
@@ -1381,7 +1353,7 @@ async function main() {
|
|
|
1381
1353
|
printViolationBreakdown(summary, { toStderr: true });
|
|
1382
1354
|
console.error('');
|
|
1383
1355
|
console.error('Freezing this would bury a likely CONTRACT bug as "debt". Fix the contract');
|
|
1384
|
-
console.error('first (/ark-
|
|
1356
|
+
console.error('first (/ark-adopt), then re-run. To freeze anyway: --update-baseline --force.');
|
|
1385
1357
|
process.exitCode = 2;
|
|
1386
1358
|
return;
|
|
1387
1359
|
}
|
|
@@ -1430,7 +1402,18 @@ async function main() {
|
|
|
1430
1402
|
let suppressed = [];
|
|
1431
1403
|
let activeViolations = violations;
|
|
1432
1404
|
let staleBaselineKeys = 0;
|
|
1433
|
-
if (args.
|
|
1405
|
+
if (args.against) {
|
|
1406
|
+
const ratcheted = applyAgainstRatchet({
|
|
1407
|
+
violations,
|
|
1408
|
+
againstRef: args.against,
|
|
1409
|
+
root,
|
|
1410
|
+
changed: args.changed,
|
|
1411
|
+
changedPaths,
|
|
1412
|
+
occurrenceKeys: baselineOccurrenceKeys(violations),
|
|
1413
|
+
});
|
|
1414
|
+
activeViolations = ratcheted.activeViolations;
|
|
1415
|
+
suppressed = ratcheted.suppressed;
|
|
1416
|
+
} else if (args.baseline) {
|
|
1434
1417
|
const baseline = readBaseline(root, args.baseline);
|
|
1435
1418
|
if (baseline.exists) {
|
|
1436
1419
|
const occurrenceKeys = baselineOccurrenceKeys(violations);
|
|
@@ -1616,20 +1599,23 @@ async function main() {
|
|
|
1616
1599
|
}),
|
|
1617
1600
|
}
|
|
1618
1601
|
: null;
|
|
1619
|
-
const currentSnapshot =
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1602
|
+
const currentSnapshot = {
|
|
1603
|
+
...buildReportSnapshot({
|
|
1604
|
+
root,
|
|
1605
|
+
config,
|
|
1606
|
+
coverage,
|
|
1607
|
+
violations: activeViolations,
|
|
1608
|
+
ok,
|
|
1609
|
+
suppressed: suppressed.length,
|
|
1610
|
+
version: arkPackageVersion(),
|
|
1611
|
+
fileCountByLayer,
|
|
1612
|
+
enforcement: enforcementForReport,
|
|
1613
|
+
score: fitness.score,
|
|
1614
|
+
mode: fitness.mode,
|
|
1615
|
+
improvementCompass: reportCompass,
|
|
1616
|
+
}),
|
|
1617
|
+
leftoverDesignWork: designDepth?.designFitness?.designWeak === true,
|
|
1618
|
+
};
|
|
1633
1619
|
const reportPayload = {
|
|
1634
1620
|
root,
|
|
1635
1621
|
config,
|
|
@@ -1755,6 +1741,7 @@ async function main() {
|
|
|
1755
1741
|
}
|
|
1756
1742
|
: {}),
|
|
1757
1743
|
...(codexRepoSkillGap ? { codexRepoSkillGap } : {}), ...(policyDelta ? { policyDelta } : {}), ...(designDelta ? { edgeValid: edgeOk, designDelta } : {}),
|
|
1744
|
+
...(teamParliament ? { teamParliament } : {}),
|
|
1758
1745
|
}, null, 2));
|
|
1759
1746
|
} else {
|
|
1760
1747
|
for (const warning of warnings) {
|