arkgate 4.6.0 → 4.6.1
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 +25 -1
- package/README.md +9 -5
- package/bin/ark-check-runtime.mjs +98 -7
- package/bin/ark-mcp-runtime.mjs +17 -1
- package/bin/ark.mjs +5 -3
- 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-plan.mjs +4 -4
- package/bin/lib/field-install.mjs +1 -1
- 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/status-command.mjs +14 -0
- package/bin/lib/status-manifest.mjs +17 -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 +19 -19
- package/dist/index.d.ts +61 -2
- package/dist/index.js +22 -22
- 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 +6 -1
- 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 +46 -19
- package/templates/agent-skills/ark-architect/SKILL.md +24 -145
- package/templates/agent-skills/ark-autopilot/SKILL.md +40 -30
- package/templates/agent-skills/ark-contract/SKILL.md +21 -105
- package/templates/agent-skills/ark-coverage/SKILL.md +3 -0
- package/templates/agent-skills/ark-explain/SKILL.md +7 -4
- package/templates/agent-skills/ark-explore/SKILL.md +25 -17
- 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 +25 -13
- package/templates/agent-skills/ark-runtime/SKILL.md +3 -3
- package/templates/agent-skills/ark-think/SKILL.md +5 -2
- package/templates/agent-skills/ark-upgrade/SKILL.md +11 -7
- package/templates/skills/ark-adopt.md +46 -19
- package/templates/skills/ark-architect.md +24 -145
- package/templates/skills/ark-autopilot.md +40 -30
- package/templates/skills/ark-contract.md +21 -105
- package/templates/skills/ark-coverage.md +3 -0
- package/templates/skills/ark-explain.md +7 -4
- package/templates/skills/ark-explore.md +25 -17
- package/templates/skills/ark-fix.md +34 -157
- package/templates/skills/ark-loop.md +31 -153
- package/templates/skills/ark-place.md +25 -13
- package/templates/skills/ark-runtime.md +3 -3
- package/templates/skills/ark-think.md +5 -2
- package/templates/skills/ark-upgrade.md +11 -7
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,30 @@ in the immutable pre-2.0 archive linked below.
|
|
|
5
5
|
|
|
6
6
|
## Unreleased
|
|
7
7
|
|
|
8
|
+
## 4.6.1 — 2026-08-14
|
|
9
|
+
|
|
10
|
+
**Patch** over **4.6.0**. Five-door autonomy (skills write or map in-turn; CLI is sensor +
|
|
11
|
+
gate) plus team parliament (law vs feature: stewards, mixed-PR deny, ratchet vs the merge
|
|
12
|
+
base, cheap `--changed` check). Same 13 skill names. Steward identity is a GitHub handle or
|
|
13
|
+
email, not git `user.name`. **No required config migration.**
|
|
14
|
+
|
|
15
|
+
**Status: prepared** (not yet on npm `latest`; see `docs/releases/4.6.1.md`).
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- **Five-door autonomy (SK01–SK05):** `/ark-adopt`, `/ark-place`, `/ark-autopilot`,
|
|
20
|
+
`/ark-explore`, `/ark-upgrade` write or map in the same turn. The other eight names stay
|
|
21
|
+
installed as shortcuts. Invoking a door is the approval; the CLI does not apply the change.
|
|
22
|
+
- **Team parliament (TW01–TW08):** mixed law+product deny; optional `stewards` (GitHub handle
|
|
23
|
+
or email); `--contract-session` / `--contract-diff` / `--changed --base` / `--against` /
|
|
24
|
+
`--persona` / `--author`; `ark status --vs`; doctor `stewardNudge` (ask or show list drift).
|
|
25
|
+
`stewards` is excluded from the policy hash.
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- Doctor, compact router, and public lanes prefer the five doors. Historical changelogs stay
|
|
30
|
+
as shipped.
|
|
31
|
+
|
|
8
32
|
## 4.6.0 — 2026-08-12
|
|
9
33
|
|
|
10
34
|
**Minor** over **4.5.7**. Understandable Ark: doctor, HTML, skills, and public docs use common
|
|
@@ -13,7 +37,7 @@ software words (import rules, leftover design work, pre-write block) while **Ark
|
|
|
13
37
|
“always latest” floor Codex already had. **No required config migration.** JSON field names
|
|
14
38
|
and `ruleId`s stay stable. No new skill names, sensors, or scores.
|
|
15
39
|
|
|
16
|
-
**Status:
|
|
40
|
+
**Status: published** (on npm `latest`; see `docs/releases/4.6.0.md`).
|
|
17
41
|
|
|
18
42
|
### Added
|
|
19
43
|
|
package/README.md
CHANGED
|
@@ -16,8 +16,8 @@ and makes sure a “green” check means something real.
|
|
|
16
16
|
|
|
17
17
|
</div>
|
|
18
18
|
|
|
19
|
-
> **ArkGate 4.6.0** is
|
|
20
|
-
> [4.6.0 notes](docs/releases/4.6.0.md) · [4.5.7](docs/releases/4.5.7.md)
|
|
19
|
+
> **ArkGate 4.6.0** is on npm `latest` — clearer language + shared agent home skills.
|
|
20
|
+
> [4.6.0 notes](docs/releases/4.6.0.md) · [4.5.7](docs/releases/4.5.7.md) · [4.5.6](docs/releases/4.5.6.md) · [Docs hub](docs/README.md) · [Product voice](docs/product-voice.md)
|
|
21
21
|
|
|
22
22
|
---
|
|
23
23
|
|
|
@@ -48,10 +48,13 @@ dependency inversion — **not a score**). Leftover lenses mean design work may
|
|
|
48
48
|
imports are green. Details: [use.md — Improvement compass](docs/use.md#improvement-compass-not-a-score).
|
|
49
49
|
|
|
50
50
|
```text
|
|
51
|
-
start → doctor (+ compass) → day-to-day
|
|
52
|
-
↘
|
|
51
|
+
start → doctor (+ compass) → /ark-adopt (session 0) → day-to-day /ark-place
|
|
52
|
+
↘ /ark-explore then /ark-autopilot when leftover design remains
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
+
Teams: keep the constitution out of product PRs. Local gate
|
|
56
|
+
`ark-check --changed --base origin/dev`. Steward law PRs use `--contract-session`.
|
|
57
|
+
|
|
55
58
|
Aliases `ark` / `ark-check` / `ark-mcp` still work. npm / pnpm / yarn. No install lifecycle scripts.
|
|
56
59
|
|
|
57
60
|

|
|
@@ -210,7 +213,8 @@ for real systems. Details: [docs/production-hardening.md](docs/production-harden
|
|
|
210
213
|
| Config · package surface · TS | [configuration](docs/configuration.md) · [package-surface](docs/package-surface.md) · [typescript-support](docs/typescript-support.md) |
|
|
211
214
|
| Brownfield | [docs/brownfield-adoption.md](docs/brownfield-adoption.md) |
|
|
212
215
|
| Security | [SECURITY.md](SECURITY.md) |
|
|
213
|
-
| Current release (4.
|
|
216
|
+
| Current release (4.6.0 on npm `latest`) | [docs/releases/4.6.0.md](docs/releases/4.6.0.md) · [CHANGELOG](CHANGELOG.md) |
|
|
217
|
+
| Prior (4.5.7) | [docs/releases/4.5.7.md](docs/releases/4.5.7.md) |
|
|
214
218
|
| Prior (4.5.0) | [docs/releases/4.5.0.md](docs/releases/4.5.0.md) |
|
|
215
219
|
| Prior (4.4.0) | [docs/releases/4.4.0.md](docs/releases/4.4.0.md) |
|
|
216
220
|
| Prior (4.3.0) | [docs/releases/4.3.0.md](docs/releases/4.3.0.md) |
|
|
@@ -103,6 +103,13 @@ import { ANALYSIS_COMPLETENESS, analysisIncompleteStatement } from './lib/analys
|
|
|
103
103
|
import { reportUnavailableAnalysis } from './lib/unavailable-analysis.mjs';
|
|
104
104
|
import { validateHardWriteRequest } from './lib/enforcement-profiles.mjs';
|
|
105
105
|
import { analyzePolicyTransition } from './lib/policy-delta-io.mjs';
|
|
106
|
+
import {
|
|
107
|
+
applyAgainstRatchet,
|
|
108
|
+
bindTeamBaseRefs,
|
|
109
|
+
filterChangedGovernedFiles,
|
|
110
|
+
runTeamPreflight,
|
|
111
|
+
ungovernedDumpMessage,
|
|
112
|
+
} from './lib/team-parliament-io.mjs';
|
|
106
113
|
import { tryResidentDoctor } from './lib/resident-doctor-client.mjs';
|
|
107
114
|
import { createDesignDeltaCheck } from './lib/design-delta.mjs';
|
|
108
115
|
import {
|
|
@@ -134,6 +141,14 @@ function parseArgs(argv) {
|
|
|
134
141
|
policyBase: undefined,
|
|
135
142
|
policyBaseRef: undefined,
|
|
136
143
|
policyAck: undefined, failOnNewSmells: false, baseRef: undefined,
|
|
144
|
+
contractSession: false,
|
|
145
|
+
contractDiff: false,
|
|
146
|
+
changed: false,
|
|
147
|
+
against: undefined,
|
|
148
|
+
base: undefined,
|
|
149
|
+
persona: undefined,
|
|
150
|
+
author: undefined,
|
|
151
|
+
failUngoverned: false,
|
|
137
152
|
updateBaseline: false,
|
|
138
153
|
noCache: false,
|
|
139
154
|
resident: false,
|
|
@@ -241,6 +256,13 @@ function parseArgs(argv) {
|
|
|
241
256
|
else if (arg === '--policy-base') args.policyBase = requireValue(arg, i++);
|
|
242
257
|
else if (arg === '--policy-base-ref') args.policyBaseRef = requireValue(arg, i++);
|
|
243
258
|
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++);
|
|
259
|
+
else if (arg === '--contract-session') args.contractSession = true;
|
|
260
|
+
else if (arg === '--contract-diff') args.contractDiff = true;
|
|
261
|
+
else if (arg === '--changed') args.changed = true;
|
|
262
|
+
else if (arg === '--against') args.against = requireValue(arg, i++);
|
|
263
|
+
else if (arg === '--base') args.base = requireValue(arg, i++);
|
|
264
|
+
else if (arg === '--persona') args.persona = requireValue(arg, i++);
|
|
265
|
+
else if (arg === '--author') args.author = requireValue(arg, i++);
|
|
244
266
|
else if (arg === '--root') args.root = path.resolve(requireValue(arg, i++));
|
|
245
267
|
else if (arg === '--config') args.config = requireValue(arg, i++);
|
|
246
268
|
else if (arg === '--manifest') args.manifest = requireValue(arg, i++);
|
|
@@ -265,7 +287,7 @@ function usage() {
|
|
|
265
287
|
return [
|
|
266
288
|
'Usage: arkgate-check | ark-check (identical bins; product name ArkGate)',
|
|
267
289
|
' 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]',
|
|
290
|
+
' 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>] [--contract-diff] [--contract-session] [--changed] [--against <git-ref>] [--base <git-ref>] [--persona touch|contributor|agent|steward] [--author <id>] [--require-gates] [--require-write-hook <host>] [--json] [--baseline [file]] [--report [file.html]] [--no-cache]',
|
|
269
291
|
' ark-check --doctor [--json] [--resident] [--fail-on-new-smells --base-ref <git-ref>] read-only diagnosis; resident JSON falls back cold',
|
|
270
292
|
' ark-check --coverage [--json] per-layer file counts + full unclassified list (report only, exit 0)',
|
|
271
293
|
' ark-check --plan [--json] classified remediation plan (mechanical-safe / judgment / deferred) + goal; report only',
|
|
@@ -291,6 +313,11 @@ function usage() {
|
|
|
291
313
|
'violations, commit the baseline file, and gate CI with --baseline: only NEW violations',
|
|
292
314
|
'fail the check, so the ratchet only moves toward zero.',
|
|
293
315
|
'',
|
|
316
|
+
'Team parliament: law files (ark.config / arkrules / .ark-baseline.json) cannot ship in',
|
|
317
|
+
'the same diff as product source. --changed --base <ref> checks touched files only.',
|
|
318
|
+
'--against <ref> ratchets new keys vs that ref\'s baseline. --contract-session is a',
|
|
319
|
+
'steward law-only PR. Loosen / baseline-grow need stewards[] + --author when set.',
|
|
320
|
+
'',
|
|
294
321
|
'--init scans the project for the built-in layer directory conventions (src/domain,',
|
|
295
322
|
'src/application, src/adapters/persistence, ...) and writes an ark.config.json covering',
|
|
296
323
|
'only the layers that actually exist, with the default rules filtered to those layers.',
|
|
@@ -546,7 +573,7 @@ function runApplyPolicyPack(args) {
|
|
|
546
573
|
|
|
547
574
|
if (fs.existsSync(configPath) && !args.force) {
|
|
548
575
|
console.error(
|
|
549
|
-
`${configPath} already exists. Re-run with --force to overwrite, or use /ark-
|
|
576
|
+
`${configPath} already exists. Re-run with --force to overwrite, or use /ark-adopt to evolve it.`
|
|
550
577
|
);
|
|
551
578
|
process.exitCode = 2;
|
|
552
579
|
return;
|
|
@@ -1030,7 +1057,7 @@ function runInit(args) {
|
|
|
1030
1057
|
console.log('A green check ignores this code; it is not "clean", it is unchecked.');
|
|
1031
1058
|
if (recognized.length > 0) {
|
|
1032
1059
|
console.log('');
|
|
1033
|
-
console.log('Proposed layer for each (from the 11-layer profile + presets — apply via /ark-
|
|
1060
|
+
console.log('Proposed layer for each (from the 11-layer profile + presets — apply via /ark-adopt):');
|
|
1034
1061
|
for (const p of recognized) {
|
|
1035
1062
|
const alt = p.alternatives?.length ? ` (or ${p.alternatives.join(' / ')} — confirm)` : '';
|
|
1036
1063
|
console.log(` ${p.dir}/ → ${p.layer}${alt}`);
|
|
@@ -1281,19 +1308,71 @@ async function main() {
|
|
|
1281
1308
|
}
|
|
1282
1309
|
|
|
1283
1310
|
const root = args.root;
|
|
1311
|
+
const bound = bindTeamBaseRefs(args, root);
|
|
1312
|
+
Object.assign(args, bound.args);
|
|
1284
1313
|
const config = readConfig(root, args.config);
|
|
1285
1314
|
const policyDelta = analyzePolicyTransition({
|
|
1286
1315
|
root,
|
|
1287
1316
|
configPath: args.config,
|
|
1288
1317
|
candidateConfig: config,
|
|
1289
|
-
strictMerge: args.strictMerge,
|
|
1318
|
+
strictMerge: args.strictMerge || args.contractDiff,
|
|
1290
1319
|
basePath: args.policyBase,
|
|
1291
1320
|
baseRef: args.policyBaseRef,
|
|
1292
1321
|
acknowledgementPath: args.policyAck,
|
|
1293
1322
|
});
|
|
1323
|
+
const preflight = runTeamPreflight({
|
|
1324
|
+
root,
|
|
1325
|
+
args,
|
|
1326
|
+
config,
|
|
1327
|
+
policyDelta,
|
|
1328
|
+
teamBase: bound.teamBase,
|
|
1329
|
+
});
|
|
1330
|
+
const teamParliament = preflight.teamParliament;
|
|
1331
|
+
const changedPaths = preflight.changedPaths;
|
|
1332
|
+
if (preflight.halt) {
|
|
1333
|
+
if (args.json) {
|
|
1334
|
+
console.log(
|
|
1335
|
+
JSON.stringify(
|
|
1336
|
+
{
|
|
1337
|
+
ok: preflight.halt.exitCode === 0,
|
|
1338
|
+
...(preflight.halt.cheap ? { cheap: true } : {}),
|
|
1339
|
+
teamParliament: preflight.halt.teamParliament,
|
|
1340
|
+
...(policyDelta ? { policyDelta } : {}),
|
|
1341
|
+
},
|
|
1342
|
+
null,
|
|
1343
|
+
2
|
|
1344
|
+
)
|
|
1345
|
+
);
|
|
1346
|
+
} else if (preflight.halt.exitCode === 0) {
|
|
1347
|
+
console.log('✔ Ark check passed (no governed source or constitution files in the diff).');
|
|
1348
|
+
} else {
|
|
1349
|
+
console.error(preflight.halt.message);
|
|
1350
|
+
}
|
|
1351
|
+
process.exitCode = preflight.halt.exitCode;
|
|
1352
|
+
return;
|
|
1353
|
+
}
|
|
1294
1354
|
const manifest = readManifest(root, args.manifest);
|
|
1295
1355
|
const rules = manifest?.architecture?.rules ?? config.rules;
|
|
1296
|
-
const
|
|
1356
|
+
const allGovernedFiles = collectGovernedFiles(root, config);
|
|
1357
|
+
if (args.failUngoverned && teamParliament?.changeSet?.productPaths?.length) {
|
|
1358
|
+
const governedRel = new Set(
|
|
1359
|
+
allGovernedFiles.map((abs) => normalize(path.relative(root, abs)))
|
|
1360
|
+
);
|
|
1361
|
+
const dumped = teamParliament.changeSet.productPaths.filter((rel) => !governedRel.has(rel));
|
|
1362
|
+
if (dumped.length > 0) {
|
|
1363
|
+
const message = ungovernedDumpMessage(dumped);
|
|
1364
|
+
if (args.json) {
|
|
1365
|
+
console.log(JSON.stringify({ ok: false, teamParliament: { ...teamParliament, ungoverned: dumped }, message }, null, 2));
|
|
1366
|
+
} else {
|
|
1367
|
+
console.error(message);
|
|
1368
|
+
}
|
|
1369
|
+
process.exitCode = 1;
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
const files = args.changed
|
|
1374
|
+
? filterChangedGovernedFiles(allGovernedFiles, root, changedPaths, normalize)
|
|
1375
|
+
: allGovernedFiles;
|
|
1297
1376
|
|
|
1298
1377
|
// --coverage is a pure glob/report view (no TypeScript resolver), so serve it BEFORE the
|
|
1299
1378
|
// TS import: the report must work — and exit 0 — even when typescript isn't installed.
|
|
@@ -1381,7 +1460,7 @@ async function main() {
|
|
|
1381
1460
|
printViolationBreakdown(summary, { toStderr: true });
|
|
1382
1461
|
console.error('');
|
|
1383
1462
|
console.error('Freezing this would bury a likely CONTRACT bug as "debt". Fix the contract');
|
|
1384
|
-
console.error('first (/ark-
|
|
1463
|
+
console.error('first (/ark-adopt), then re-run. To freeze anyway: --update-baseline --force.');
|
|
1385
1464
|
process.exitCode = 2;
|
|
1386
1465
|
return;
|
|
1387
1466
|
}
|
|
@@ -1430,7 +1509,18 @@ async function main() {
|
|
|
1430
1509
|
let suppressed = [];
|
|
1431
1510
|
let activeViolations = violations;
|
|
1432
1511
|
let staleBaselineKeys = 0;
|
|
1433
|
-
if (args.
|
|
1512
|
+
if (args.against) {
|
|
1513
|
+
const ratcheted = applyAgainstRatchet({
|
|
1514
|
+
violations,
|
|
1515
|
+
againstRef: args.against,
|
|
1516
|
+
root,
|
|
1517
|
+
changed: args.changed,
|
|
1518
|
+
changedPaths,
|
|
1519
|
+
occurrenceKeys: baselineOccurrenceKeys(violations),
|
|
1520
|
+
});
|
|
1521
|
+
activeViolations = ratcheted.activeViolations;
|
|
1522
|
+
suppressed = ratcheted.suppressed;
|
|
1523
|
+
} else if (args.baseline) {
|
|
1434
1524
|
const baseline = readBaseline(root, args.baseline);
|
|
1435
1525
|
if (baseline.exists) {
|
|
1436
1526
|
const occurrenceKeys = baselineOccurrenceKeys(violations);
|
|
@@ -1755,6 +1845,7 @@ async function main() {
|
|
|
1755
1845
|
}
|
|
1756
1846
|
: {}),
|
|
1757
1847
|
...(codexRepoSkillGap ? { codexRepoSkillGap } : {}), ...(policyDelta ? { policyDelta } : {}), ...(designDelta ? { edgeValid: edgeOk, designDelta } : {}),
|
|
1848
|
+
...(teamParliament ? { teamParliament } : {}),
|
|
1758
1849
|
}, null, 2));
|
|
1759
1850
|
} else {
|
|
1760
1851
|
for (const warning of warnings) {
|
package/bin/ark-mcp-runtime.mjs
CHANGED
|
@@ -73,6 +73,8 @@ import {
|
|
|
73
73
|
} from './lib/prepare-change.mjs';
|
|
74
74
|
import { detectWritePathCapabilities } from './lib/write-path-detect.mjs';
|
|
75
75
|
import { collectGovernedFiles, isGovernableSourceFile } from './lib/scan-files.mjs';
|
|
76
|
+
import { classifyChangeSet, evaluateTeamGate } from './lib/team-parliament.mjs';
|
|
77
|
+
import { contractSessionFrom } from './lib/team-parliament-io.mjs';
|
|
76
78
|
import {
|
|
77
79
|
canonicalizeCandidateChanges,
|
|
78
80
|
resolvedCompilerInputPaths,
|
|
@@ -657,6 +659,20 @@ function runHookPayload(payload, gate, config, args, ts, attemptContext, output
|
|
|
657
659
|
return;
|
|
658
660
|
}
|
|
659
661
|
const patchWrites = parsedPatch.writes;
|
|
662
|
+
const patchChangeSet = classifyChangeSet(patchWrites.map((change) => String(change.path)));
|
|
663
|
+
const patchLawGate = evaluateTeamGate({
|
|
664
|
+
changeSet: patchChangeSet,
|
|
665
|
+
contractSession: contractSessionFrom({}),
|
|
666
|
+
});
|
|
667
|
+
if (patchLawGate.deny && patchChangeSet.mixed) {
|
|
668
|
+
const message = patchLawGate.message;
|
|
669
|
+
output.stderr(`Ark architecture gate: ${message}\n`);
|
|
670
|
+
if (grokStyle) {
|
|
671
|
+
output.stdout(`${JSON.stringify({ decision: 'deny', reason: message })}\n`);
|
|
672
|
+
}
|
|
673
|
+
output.status(2);
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
660
676
|
const sourceWrites = patchWrites.filter((change) =>
|
|
661
677
|
isGovernableSourceFile(path.basename(String(change.path)))
|
|
662
678
|
);
|
|
@@ -1387,7 +1403,7 @@ function printSessionContext(config, profile, forbiddenGlobals, args, configPath
|
|
|
1387
1403
|
const governedPercent = coverage?.coverage?.governed?.percent ?? coverage?.governed?.percent;
|
|
1388
1404
|
if (shouldShowNewHereNudge(args.root, configPath, governedPercent, false)) {
|
|
1389
1405
|
lines.push('');
|
|
1390
|
-
lines.push('New to Ark? Run /ark-architect or: ark-check --recommend');
|
|
1406
|
+
lines.push('New to Ark? Run /ark-adopt (or /ark-architect) or: ark-check --recommend');
|
|
1391
1407
|
}
|
|
1392
1408
|
|
|
1393
1409
|
process.stdout.write(`${lines.join('\n')}\n`);
|
package/bin/ark.mjs
CHANGED
|
@@ -138,6 +138,7 @@ function parseArgs(argv) {
|
|
|
138
138
|
}
|
|
139
139
|
else if (arg === '--expected-root') args.expectedRoot = path.resolve(requireValue(arg, i++));
|
|
140
140
|
else if (arg === '--expected-project-id') args.expectedProjectId = requireValue(arg, i++);
|
|
141
|
+
else if (arg === '--vs') args.vs = requireValue(arg, i++);
|
|
141
142
|
else if (arg === '--write') args.write = true;
|
|
142
143
|
else if (arg === '--check') args.check = true;
|
|
143
144
|
else if (arg === '--stdout') args.stdout = true;
|
|
@@ -157,7 +158,7 @@ function usage() {
|
|
|
157
158
|
[--archetype <playbook-id>] [--tools <list>] [--require-write-hook <host>] [--yes] [--force] [--no-strict]
|
|
158
159
|
ark upgrade [--root <project>] [--tools <list>] [--apply] [--plan-digest <sha256>] [--accept-conflicts] [--refresh-skills] [--json] [--no-install] [--no-strict]
|
|
159
160
|
ark preflight --changes <change-set.json> [--change-map <map.json>] [--root <project>] [--config ark.config.json] [--manifest <manifest.json>] [--tsconfig <tsconfig.json>] [--json]
|
|
160
|
-
ark status [--root <project>] [--config ark.config.json] [--json]
|
|
161
|
+
ark status [--root <project>] [--config ark.config.json] [--json] [--vs <git-ref>]
|
|
161
162
|
[--expected-root <abs>] [--expected-project-id sha256:…] [--tools <host>]
|
|
162
163
|
ark agents-md [--root <project>] [--config ark.config.json] [--write] [--check] [--stdout] [--json]
|
|
163
164
|
[--tools <host>]
|
|
@@ -796,7 +797,7 @@ async function start(args) {
|
|
|
796
797
|
console.log('');
|
|
797
798
|
console.log('Next (the only flow you need):');
|
|
798
799
|
if (falseGreenGap) {
|
|
799
|
-
console.log(' 1. In your agent: /ark-adopt
|
|
800
|
+
console.log(' 1. In your agent: /ark-adopt — fix the architecture config first');
|
|
800
801
|
console.log(' → reclassify I/O dirs out of Application; then /ark-autopilot for residual debt.');
|
|
801
802
|
} else {
|
|
802
803
|
console.log(' 1. In your agent: /ark-autopilot');
|
|
@@ -811,7 +812,7 @@ async function start(args) {
|
|
|
811
812
|
}
|
|
812
813
|
console.log('');
|
|
813
814
|
console.log('Optional later: ark-check --report ark-report.html (captures a day-zero/evolution report).');
|
|
814
|
-
console.log('Optional later: --plan · --coverage · /ark-explore · /ark-
|
|
815
|
+
console.log('Optional later: --plan · --coverage · /ark-explore · /ark-autopilot · /ark-place · ark upgrade');
|
|
815
816
|
return 0;
|
|
816
817
|
} finally {
|
|
817
818
|
rl?.close();
|
|
@@ -941,6 +942,7 @@ async function main() {
|
|
|
941
942
|
expectedProjectId: args.expectedProjectId,
|
|
942
943
|
host: args.tools,
|
|
943
944
|
arkgateVersion: cliVersion(),
|
|
945
|
+
vs: args.vs,
|
|
944
946
|
});
|
|
945
947
|
}
|
|
946
948
|
|
|
@@ -151,7 +151,7 @@ export function buildAgentProjectionBody(facts) {
|
|
|
151
151
|
lines.push('### Primary path', '', '1. Run doctor (`ark-check --doctor`) — status light + primary next action.', '2. Read the improvement compass (not a score). Name leftover work in plain language; never “done” on green imports alone while leftover design work remains.', '3. Call `ark_identity` with `project.expectedRoot` at the exact project root; reuse root + `projectId` on Ark MCP calls.', '4. Read architecture config with `ark_manifest` (same expectation). `ark://manifest` is compatibility-only / unverified.', '5. Place files inside configured layers; validate; run the check command above on violations — fix architecture, do not weaken the gate.', '6. Single door: import-rule debt → fix; leftover design work / residual shape lenses → map then guided apply with user OK.', '', '### Contract layers (summary)', '', formatAgentProjectionLayers(layers), '');
|
|
152
152
|
}
|
|
153
153
|
else {
|
|
154
|
-
lines.push('### Contract layers', '', formatAgentProjectionLayers(layers), '', 'When creating a **new** kind of code that no layer covers, update `ark.config.json` first (`/ark-
|
|
154
|
+
lines.push('### Contract layers', '', formatAgentProjectionLayers(layers), '', 'When creating a **new** kind of code that no layer covers, update `ark.config.json` first (`/ark-adopt`), then place the file.', '', '### Diagnostic codes (short list)', '', formatAgentProjectionCatalogShortList(catalog, docsPath), '', '### Session truth', '', '- Machine snapshot: `ark status --json` (or MCP `ark_status`) — identity, activation honesty, last check, residual counts. **Not a score.**', '- Authoritative contract: `ark_manifest` after a matched `ark_identity` handshake.', '');
|
|
155
155
|
}
|
|
156
156
|
lines.push('### Enforcement surfaces (authoritative)', '', AGENT_PROJECTION_ENFORCEMENT_SURFACES.map((surface) => `- \`${surface}\``).join('\n'), '');
|
|
157
157
|
return lines.join('\n').replace(/\n{3,}/g, '\n\n').trimEnd() + '\n';
|