arkgate 2.11.0 → 2.13.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 +147 -0
- package/README.md +70 -41
- package/bin/ark-check.mjs +95 -36
- package/bin/ark-mcp.mjs +11 -5
- package/bin/ark-shared.mjs +88 -56
- package/bin/ark.mjs +97 -29
- package/bin/lib/agent-gates.mjs +79 -2093
- package/bin/lib/architecture-scan.mjs +8 -0
- package/bin/lib/ci-and-commands.mjs +392 -0
- package/bin/lib/codex-home.mjs +7 -0
- package/bin/lib/config-contract.mjs +331 -0
- package/bin/lib/deploy-path.mjs +205 -0
- package/bin/lib/doctor-plan.mjs +43 -16
- package/bin/lib/enforcement-profiles.mjs +97 -0
- package/bin/lib/gate-files.mjs +223 -0
- package/bin/lib/hook-templates.mjs +99 -0
- package/bin/lib/host-support-matrix.mjs +77 -0
- package/bin/lib/install-migrate.mjs +473 -0
- package/bin/lib/mcp-adoption.mjs +455 -0
- package/bin/lib/open-html.mjs +75 -0
- package/bin/lib/presets.mjs +6 -2
- package/bin/lib/safety-diagnostics.mjs +31 -11
- package/bin/lib/skill-install.mjs +323 -0
- package/bin/lib/ts-resolve.mjs +2 -1
- package/bin/lib/typescript-host.mjs +88 -0
- package/bin/lib/weakest-link.mjs +417 -0
- package/bin/lib/write-path-capabilities.mjs +182 -0
- package/bin/lib/write-path-detect.mjs +101 -0
- package/dist/configContract-iBLxx5Tz.d.cts +53 -0
- package/dist/configContract-iBLxx5Tz.d.ts +53 -0
- package/dist/eslint/index.cjs +375 -13
- package/dist/eslint/index.cjs.map +1 -1
- package/dist/eslint/index.d.cts +30 -20
- package/dist/eslint/index.d.ts +30 -20
- package/dist/eslint/index.js +375 -13
- package/dist/eslint/index.js.map +1 -1
- package/dist/index.cjs +723 -61
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +95 -5
- package/dist/index.d.ts +95 -5
- package/dist/index.js +716 -61
- package/dist/index.js.map +1 -1
- package/dist/nestjs/index.cjs +150 -42
- package/dist/nestjs/index.cjs.map +1 -1
- package/dist/nestjs/index.d.cts +2 -1
- package/dist/nestjs/index.d.ts +2 -1
- package/dist/nestjs/index.js +150 -42
- package/dist/nestjs/index.js.map +1 -1
- package/dist/runtime/index.cjs +723 -61
- package/dist/runtime/index.cjs.map +1 -1
- package/dist/runtime/index.d.cts +3 -2
- package/dist/runtime/index.d.ts +3 -2
- package/dist/runtime/index.js +716 -61
- package/dist/runtime/index.js.map +1 -1
- package/dist/{types-BZ17b9i5.d.cts → types-BxBwnBpC.d.cts} +9 -36
- package/dist/{types-BZ17b9i5.d.ts → types-Wcs_l1_J.d.ts} +9 -36
- package/docs/agent-guide.md +43 -21
- package/docs/ai-gates.md +53 -18
- package/docs/configuration.md +97 -0
- package/docs/enthusiast/README.md +3 -3
- package/docs/enthusiast/how-to-agent-gates.md +7 -3
- package/docs/migrate-from-ark-runtime-kernel.md +3 -0
- package/docs/package-surface.md +22 -10
- package/docs/production-hardening.md +15 -2
- package/docs/threat-model.md +65 -0
- package/docs/typescript-support.md +3 -3
- package/package.json +15 -2
- package/schemas/ark.config.schema.json +750 -0
- package/server.json +2 -2
- package/templates/hooks/pre-commit-ark +37 -0
- package/templates/skills/ark-autopilot.md +77 -45
- package/templates/skills/ark-coverage.md +2 -2
- package/templates/skills/ark-explain.md +2 -1
- package/templates/skills/ark-explore.md +135 -34
- package/templates/skills/ark-runtime.md +8 -5
- package/templates/skills/ark-upgrade.md +36 -16
- package/tests/fixtures/ts-consumer/ark.config.json +2 -0
package/bin/ark.mjs
CHANGED
|
@@ -19,10 +19,37 @@ import {
|
|
|
19
19
|
resolveOperatingMode,
|
|
20
20
|
} from './ark-shared.mjs';
|
|
21
21
|
import { pinArkgateDevDependency, FALSE_GREEN_GAP_ID } from './lib/field-install.mjs';
|
|
22
|
+
import { validateHardWriteRequest } from './lib/enforcement-profiles.mjs';
|
|
22
23
|
|
|
23
24
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
24
25
|
const arkCheck = path.join(here, 'ark-check.mjs');
|
|
25
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Day-zero architecture picture: freeze origin under `.ark/reports/` as soon as
|
|
29
|
+
* `ark.config.json` exists — **before** agent docs, skills, CI templates, or cleanups.
|
|
30
|
+
* Idempotent: origin is written only once (`--report` archive semantics).
|
|
31
|
+
*/
|
|
32
|
+
function freezeDayZeroOrigin(root) {
|
|
33
|
+
const configPath = path.join(root, 'ark.config.json');
|
|
34
|
+
if (!fs.existsSync(configPath)) {
|
|
35
|
+
console.log(
|
|
36
|
+
` Skip origin freeze — no ark.config.json yet. After init: ${arkCommand(root, 'ark-check', '--report ark-report.html')}`
|
|
37
|
+
);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const originJson = path.join(root, '.ark', 'reports', 'origin.json');
|
|
41
|
+
const already = fs.existsSync(originJson);
|
|
42
|
+
console.log(
|
|
43
|
+
already
|
|
44
|
+
? 'Architecture origin already frozen (.ark/reports/origin.*) — leaving it untouched.'
|
|
45
|
+
: 'Freezing day-zero architecture picture (origin) before agent docs / gates…'
|
|
46
|
+
);
|
|
47
|
+
runArkCheck(
|
|
48
|
+
['--root', root, '--config', 'ark.config.json', '--report', 'ark-report.html'],
|
|
49
|
+
{ cwd: root }
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
26
53
|
function parseArgs(argv) {
|
|
27
54
|
const args = {
|
|
28
55
|
command: undefined,
|
|
@@ -31,6 +58,7 @@ function parseArgs(argv) {
|
|
|
31
58
|
force: false,
|
|
32
59
|
strict: true,
|
|
33
60
|
install: true,
|
|
61
|
+
requireWriteHook: undefined,
|
|
34
62
|
help: false,
|
|
35
63
|
version: false,
|
|
36
64
|
};
|
|
@@ -55,6 +83,9 @@ function parseArgs(argv) {
|
|
|
55
83
|
else if (arg === '--preset') args.preset = requireValue(arg, i++);
|
|
56
84
|
else if (arg === '--archetype') args.archetype = requireValue(arg, i++);
|
|
57
85
|
else if (arg === '--tools') args.tools = requireValue(arg, i++);
|
|
86
|
+
else if (arg === '--require-write-hook') {
|
|
87
|
+
args.requireWriteHook = requireValue(arg, i++).trim().toLowerCase();
|
|
88
|
+
}
|
|
58
89
|
else if (arg === '--help' || arg === '-h' || arg === 'help') args.help = true;
|
|
59
90
|
else if (arg === '--version' || arg === '-V') args.version = true;
|
|
60
91
|
else if (!arg.startsWith('-') && args.command === undefined) args.command = arg;
|
|
@@ -66,9 +97,9 @@ function parseArgs(argv) {
|
|
|
66
97
|
|
|
67
98
|
function usage() {
|
|
68
99
|
return `Usage:
|
|
69
|
-
ark start [--root <project>] [--yes]
|
|
100
|
+
ark start [--root <project>] [--tools <list>] [--require-write-hook <host>] [--yes]
|
|
70
101
|
ark init [--root <project>] [--preset hexagonal|layered|feature-sliced|monorepo|ui-surface|vertical-slice|ddd-bounded-contexts|clean-architecture|onion-architecture]
|
|
71
|
-
[--archetype <playbook-id>] [--tools <list>] [--yes] [--force] [--no-strict]
|
|
102
|
+
[--archetype <playbook-id>] [--tools <list>] [--require-write-hook <host>] [--yes] [--force] [--no-strict]
|
|
72
103
|
ark upgrade [--root <project>] [--no-install] [--no-strict]
|
|
73
104
|
|
|
74
105
|
Commands:
|
|
@@ -93,6 +124,9 @@ Options:
|
|
|
93
124
|
vertical-slice-product, ddd-bounded-contexts.
|
|
94
125
|
--tools Comma-separated agents to gate (claude,cursor,codex,grok,windsurf,cline,copilot,kiro,roo,continue,gemini).
|
|
95
126
|
Omit to auto-detect from each tool's config dir, falling back to claude+cursor+codex+grok.
|
|
127
|
+
--require-write-hook <host>
|
|
128
|
+
Require and verify a hard local write hook for Claude or Grok. Cursor/Codex are
|
|
129
|
+
advisory-write plus hard CI merge only; impossible requests fail before any write.
|
|
96
130
|
|
|
97
131
|
Interactive mode (TTY, no --yes): asks what application shape you are building and maps it to a preset.
|
|
98
132
|
Non-interactive (no TTY): uses the same defaults as --yes — never calls readline on a null interface.
|
|
@@ -177,7 +211,7 @@ async function upgrade(args) {
|
|
|
177
211
|
}
|
|
178
212
|
console.log('\n4/4 Verifying architecture…');
|
|
179
213
|
return runArkCheck(
|
|
180
|
-
['--root', root, '--config', 'ark.config.json', '--strict-
|
|
214
|
+
['--root', root, '--config', 'ark.config.json', '--strict-merge'],
|
|
181
215
|
{ cwd: root }
|
|
182
216
|
);
|
|
183
217
|
}
|
|
@@ -330,11 +364,18 @@ async function init(args) {
|
|
|
330
364
|
console.log('Skipped ark.config.json generation.');
|
|
331
365
|
}
|
|
332
366
|
|
|
367
|
+
// Origin first: contract-on-tree picture before AGENTS.md / skills / CI templates.
|
|
368
|
+
console.log('');
|
|
369
|
+
freezeDayZeroOrigin(root);
|
|
370
|
+
|
|
333
371
|
const installGates =
|
|
334
372
|
nonInteractive || (await askYesNo(rl, 'Configure agent and CI gate templates?', true));
|
|
335
373
|
if (installGates) {
|
|
336
374
|
const gateArgs = ['--root', root, '--install-agent-gates'];
|
|
337
375
|
if (args.tools) gateArgs.push('--tools', args.tools);
|
|
376
|
+
if (args.requireWriteHook) {
|
|
377
|
+
gateArgs.push('--require-write-hook', args.requireWriteHook);
|
|
378
|
+
}
|
|
338
379
|
if (args.force) gateArgs.push('--force');
|
|
339
380
|
const status = runArkCheck(gateArgs, { cwd: root });
|
|
340
381
|
if (status !== 0) return status;
|
|
@@ -344,20 +385,21 @@ async function init(args) {
|
|
|
344
385
|
args.strict &&
|
|
345
386
|
(nonInteractive || (await askYesNo(rl, 'Run strict architecture check now?', true)));
|
|
346
387
|
if (runStrict) {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
388
|
+
const strictArgs = ['--root', root, '--config', 'ark.config.json', '--strict-merge'];
|
|
389
|
+
if (args.requireWriteHook) {
|
|
390
|
+
strictArgs.push('--require-write-hook', args.requireWriteHook);
|
|
391
|
+
}
|
|
392
|
+
return runArkCheck(strictArgs, { cwd: root });
|
|
351
393
|
}
|
|
352
394
|
|
|
353
395
|
console.log(
|
|
354
|
-
`Ark init complete. Run \`${arkCommand(root, 'ark-check', '--root . --config ark.config.json --strict-
|
|
396
|
+
`Ark init complete. Run \`${arkCommand(root, 'ark-check', '--root . --config ark.config.json --strict-merge')}\` before merging.`
|
|
355
397
|
);
|
|
356
398
|
if (archetype) {
|
|
357
399
|
console.log(`Shape: ${archetype}. Plan: ${arkCommand(root, 'ark-check', '--recommend')}`);
|
|
358
400
|
}
|
|
359
401
|
console.log(
|
|
360
|
-
`
|
|
402
|
+
`Day-zero origin: .ark/reports/origin.* (frozen once; later --report shows evolution vs origin).`
|
|
361
403
|
);
|
|
362
404
|
console.log(`Adoption health: ${arkCommand(root, 'ark-check', '--doctor')}`);
|
|
363
405
|
return 0;
|
|
@@ -381,9 +423,11 @@ async function start(args) {
|
|
|
381
423
|
try {
|
|
382
424
|
console.log("Let's set up Ark for your project.");
|
|
383
425
|
console.log(
|
|
384
|
-
"I'll
|
|
426
|
+
"I'll walk the tree, freeze a day-zero architecture picture, then set up guardrails and show a plan."
|
|
427
|
+
);
|
|
428
|
+
console.log(
|
|
429
|
+
'Nothing in your product code is changed — only Ark config, then origin snapshot, then agent/CI templates.'
|
|
385
430
|
);
|
|
386
|
-
console.log('Nothing in your code is changed — this only adds Ark configuration.');
|
|
387
431
|
if (nonInteractive && !args.yes) {
|
|
388
432
|
console.log(
|
|
389
433
|
'Non-interactive session (no TTY) — using guided defaults (same as --yes). Pass flags to override.'
|
|
@@ -440,10 +484,10 @@ async function start(args) {
|
|
|
440
484
|
console.log(' Skipping arkgate package pin (--no-install).');
|
|
441
485
|
}
|
|
442
486
|
|
|
443
|
-
// 3)
|
|
444
|
-
// so the contract anchors to
|
|
487
|
+
// 3) Contract first (config only). Greenfield → shape preset; established repo → detection,
|
|
488
|
+
// so the contract anchors to directories you already have instead of aspirational globs.
|
|
445
489
|
console.log('');
|
|
446
|
-
console.log('Setting up Ark…');
|
|
490
|
+
console.log('Setting up Ark contract…');
|
|
447
491
|
const configPath = path.join(root, 'ark.config.json');
|
|
448
492
|
if (!fs.existsSync(configPath)) {
|
|
449
493
|
const initArgs = ['--root', root, '--init'];
|
|
@@ -482,14 +526,27 @@ async function start(args) {
|
|
|
482
526
|
} else {
|
|
483
527
|
console.log(' Found an existing ark.config.json — keeping it.');
|
|
484
528
|
}
|
|
529
|
+
|
|
530
|
+
// 4) Day-zero origin — freeze the architecture picture *before* agent docs / CI / skills.
|
|
531
|
+
// Later --report runs show evolution vs this snapshot. Idempotent (origin once).
|
|
532
|
+
console.log('');
|
|
533
|
+
freezeDayZeroOrigin(root);
|
|
534
|
+
|
|
535
|
+
// 5) Agent + CI gate templates (docs, hooks, skills) — after origin is frozen.
|
|
536
|
+
console.log('');
|
|
537
|
+
console.log('Installing agent and CI gate templates…');
|
|
485
538
|
{
|
|
486
539
|
const gateArgs = ['--root', root, '--install-agent-gates'];
|
|
487
540
|
if (args.tools) gateArgs.push('--tools', args.tools);
|
|
541
|
+
if (args.requireWriteHook) {
|
|
542
|
+
gateArgs.push('--require-write-hook', args.requireWriteHook);
|
|
543
|
+
}
|
|
488
544
|
if (args.force) gateArgs.push('--force');
|
|
489
|
-
runArkCheck(gateArgs, { cwd: root });
|
|
545
|
+
const status = runArkCheck(gateArgs, { cwd: root });
|
|
546
|
+
if (status !== 0) return status;
|
|
490
547
|
}
|
|
491
548
|
|
|
492
|
-
//
|
|
549
|
+
// 6) Show the plan: what's safe to auto-fix vs what needs a decision.
|
|
493
550
|
console.log('');
|
|
494
551
|
console.log('Your architecture plan:');
|
|
495
552
|
runArkCheck(['--root', root, '--config', 'ark.config.json', '--plan'], { cwd: root });
|
|
@@ -571,7 +628,7 @@ async function start(args) {
|
|
|
571
628
|
planOk = false;
|
|
572
629
|
}
|
|
573
630
|
|
|
574
|
-
//
|
|
631
|
+
// 7) Plain-language wrap-up — one next step, status light only.
|
|
575
632
|
// Modes are detected (Suggest/Adapt/Enforce), not user-picked settings.
|
|
576
633
|
// Soft-block false-green using the same doctor adoption gap (no second detector).
|
|
577
634
|
let falseGreenGap = null;
|
|
@@ -620,26 +677,18 @@ async function start(args) {
|
|
|
620
677
|
console.log(' → reclassify I/O dirs out of Application; then /ark-autopilot for residual debt.');
|
|
621
678
|
} else {
|
|
622
679
|
console.log(' 1. In your agent: /ark-autopilot');
|
|
623
|
-
console.log(' →
|
|
680
|
+
console.log(' → explore first, dual plan (remediation + pattern bets), safe fixes, leave gates on.');
|
|
624
681
|
}
|
|
625
682
|
console.log(` 2. Status anytime: ${arkCommand(root, 'ark-check', '--doctor')}`);
|
|
626
|
-
console.log(` 3. After edits: ${arkCommand(root, 'ark-check', '--root . --config ark.config.json --strict-
|
|
683
|
+
console.log(` 3. After edits: ${arkCommand(root, 'ark-check', '--root . --config ark.config.json --strict-merge')}`);
|
|
627
684
|
if (mode === 'adapt' && planOk && !falseGreenGap) {
|
|
628
685
|
console.log(
|
|
629
686
|
` 4. When green but cores still optional: ${arkCommand(root, 'ark-check', '--ratchet-cores')} → honest ENFORCE`
|
|
630
687
|
);
|
|
631
688
|
}
|
|
632
689
|
console.log('');
|
|
633
|
-
console.log('
|
|
634
|
-
|
|
635
|
-
// 6) First architecture report — freezes an origin snapshot under .ark/reports/
|
|
636
|
-
// so later --report runs can show evolution. Idempotent: origin is written only once.
|
|
637
|
-
console.log('');
|
|
638
|
-
console.log('Capturing architecture report (origin snapshot on first run)…');
|
|
639
|
-
runArkCheck(
|
|
640
|
-
['--root', root, '--config', 'ark.config.json', '--report', 'ark-report.html'],
|
|
641
|
-
{ cwd: root }
|
|
642
|
-
);
|
|
690
|
+
console.log('Day-zero origin is under .ark/reports/origin.* — re-run --report later for evolution.');
|
|
691
|
+
console.log('Optional later: --plan · --coverage · /ark-explore · /ark-fix · /ark-place · ark upgrade');
|
|
643
692
|
return 0;
|
|
644
693
|
} finally {
|
|
645
694
|
rl?.close();
|
|
@@ -663,6 +712,25 @@ async function main() {
|
|
|
663
712
|
return 0;
|
|
664
713
|
}
|
|
665
714
|
|
|
715
|
+
if (args.requireWriteHook && !['start', 'init'].includes(args.command)) {
|
|
716
|
+
console.error('--require-write-hook is supported by ark start and ark init.');
|
|
717
|
+
return 2;
|
|
718
|
+
}
|
|
719
|
+
const enforcement = validateHardWriteRequest({
|
|
720
|
+
root: args.root,
|
|
721
|
+
host: args.requireWriteHook,
|
|
722
|
+
tools: args.tools,
|
|
723
|
+
force: args.force,
|
|
724
|
+
});
|
|
725
|
+
if (!enforcement.ok) {
|
|
726
|
+
console.error(enforcement.error);
|
|
727
|
+
return 2;
|
|
728
|
+
}
|
|
729
|
+
if (enforcement.host) {
|
|
730
|
+
args.requireWriteHook = enforcement.host;
|
|
731
|
+
if (!args.tools) args.tools = enforcement.tools.join(',');
|
|
732
|
+
}
|
|
733
|
+
|
|
666
734
|
if (args.command === 'start') {
|
|
667
735
|
try {
|
|
668
736
|
return await start(args);
|