arkgate 2.10.0 → 2.12.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 +107 -0
- package/README.md +21 -12
- package/SECURITY.md +3 -4
- package/bin/ark-check.mjs +41 -16
- package/bin/ark-mcp.mjs +54 -10
- package/bin/ark.mjs +87 -24
- package/bin/lib/agent-gates.mjs +68 -2090
- package/bin/lib/architecture-scan.mjs +4 -1
- package/bin/lib/baseline-key.mjs +17 -0
- package/bin/lib/ci-and-commands.mjs +386 -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/deploy-path.mjs +205 -0
- package/bin/lib/doctor-plan.mjs +29 -5
- package/bin/lib/gate-files.mjs +223 -0
- package/bin/lib/hook-templates.mjs +99 -0
- package/bin/lib/install-migrate.mjs +442 -0
- package/bin/lib/mcp-adoption.mjs +423 -0
- package/bin/lib/presets.mjs +3 -0
- package/bin/lib/safety-diagnostics.mjs +263 -0
- package/bin/lib/scan-files.mjs +51 -6
- package/bin/lib/skill-install.mjs +259 -0
- package/bin/lib/typescript-host.mjs +88 -0
- package/bin/lib/violations.mjs +3 -3
- package/bin/lib/write-path-detect.mjs +138 -0
- package/dist/index.cjs +103 -8
- 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 +103 -8
- 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 +103 -8
- 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 +103 -8
- 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 +12 -2
- package/docs/ai-gates.md +20 -2
- package/docs/package-surface.md +10 -3
- package/docs/production-hardening.md +5 -0
- package/package.json +5 -2
- package/server.json +2 -2
- package/templates/skills/ark-autopilot.md +77 -45
- package/templates/skills/ark-explain.md +2 -1
- package/templates/skills/ark-explore.md +135 -34
package/bin/ark.mjs
CHANGED
|
@@ -23,6 +23,32 @@ import { pinArkgateDevDependency, FALSE_GREEN_GAP_ID } from './lib/field-install
|
|
|
23
23
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
24
24
|
const arkCheck = path.join(here, 'ark-check.mjs');
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Day-zero architecture picture: freeze origin under `.ark/reports/` as soon as
|
|
28
|
+
* `ark.config.json` exists — **before** agent docs, skills, CI templates, or cleanups.
|
|
29
|
+
* Idempotent: origin is written only once (`--report` archive semantics).
|
|
30
|
+
*/
|
|
31
|
+
function freezeDayZeroOrigin(root) {
|
|
32
|
+
const configPath = path.join(root, 'ark.config.json');
|
|
33
|
+
if (!fs.existsSync(configPath)) {
|
|
34
|
+
console.log(
|
|
35
|
+
` Skip origin freeze — no ark.config.json yet. After init: ${arkCommand(root, 'ark-check', '--report ark-report.html')}`
|
|
36
|
+
);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const originJson = path.join(root, '.ark', 'reports', 'origin.json');
|
|
40
|
+
const already = fs.existsSync(originJson);
|
|
41
|
+
console.log(
|
|
42
|
+
already
|
|
43
|
+
? 'Architecture origin already frozen (.ark/reports/origin.*) — leaving it untouched.'
|
|
44
|
+
: 'Freezing day-zero architecture picture (origin) before agent docs / gates…'
|
|
45
|
+
);
|
|
46
|
+
runArkCheck(
|
|
47
|
+
['--root', root, '--config', 'ark.config.json', '--report', 'ark-report.html'],
|
|
48
|
+
{ cwd: root }
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
26
52
|
function parseArgs(argv) {
|
|
27
53
|
const args = {
|
|
28
54
|
command: undefined,
|
|
@@ -32,22 +58,33 @@ function parseArgs(argv) {
|
|
|
32
58
|
strict: true,
|
|
33
59
|
install: true,
|
|
34
60
|
help: false,
|
|
61
|
+
version: false,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const requireValue = (flag, index) => {
|
|
65
|
+
const value = argv[index + 1];
|
|
66
|
+
if (value === undefined || value.startsWith('-')) {
|
|
67
|
+
throw new Error(`Missing value for ${flag}. Run ark --help for usage.`);
|
|
68
|
+
}
|
|
69
|
+
return value;
|
|
35
70
|
};
|
|
36
71
|
|
|
37
72
|
// Scan from the first user token (index 2) so a leading flag like `ark --help` is
|
|
38
73
|
// recognized: the command is the first NON-dash argument, not blindly argv[2].
|
|
39
74
|
for (let i = 2; i < argv.length; i += 1) {
|
|
40
75
|
const arg = argv[i];
|
|
41
|
-
if (arg === '--root') args.root = path.resolve(
|
|
76
|
+
if (arg === '--root') args.root = path.resolve(requireValue(arg, i++));
|
|
42
77
|
else if (arg === '--yes' || arg === '-y') args.yes = true;
|
|
43
78
|
else if (arg === '--force') args.force = true;
|
|
44
79
|
else if (arg === '--no-strict') args.strict = false;
|
|
45
80
|
else if (arg === '--no-install') args.install = false;
|
|
46
|
-
else if (arg === '--preset') args.preset =
|
|
47
|
-
else if (arg === '--archetype') args.archetype =
|
|
48
|
-
else if (arg === '--tools') args.tools =
|
|
81
|
+
else if (arg === '--preset') args.preset = requireValue(arg, i++);
|
|
82
|
+
else if (arg === '--archetype') args.archetype = requireValue(arg, i++);
|
|
83
|
+
else if (arg === '--tools') args.tools = requireValue(arg, i++);
|
|
49
84
|
else if (arg === '--help' || arg === '-h' || arg === 'help') args.help = true;
|
|
85
|
+
else if (arg === '--version' || arg === '-V') args.version = true;
|
|
50
86
|
else if (!arg.startsWith('-') && args.command === undefined) args.command = arg;
|
|
87
|
+
else throw new Error(`Unknown argument: ${arg}. Run ark --help for usage.`);
|
|
51
88
|
}
|
|
52
89
|
|
|
53
90
|
return args;
|
|
@@ -88,6 +125,15 @@ Non-interactive (no TTY): uses the same defaults as --yes — never calls readli
|
|
|
88
125
|
`;
|
|
89
126
|
}
|
|
90
127
|
|
|
128
|
+
function cliVersion() {
|
|
129
|
+
try {
|
|
130
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(here, '..', 'package.json'), 'utf8'));
|
|
131
|
+
return typeof pkg.version === 'string' ? pkg.version : 'unknown';
|
|
132
|
+
} catch {
|
|
133
|
+
return 'unknown';
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
91
137
|
// The package-manager command that adds arkgate as a dev dependency.
|
|
92
138
|
// Prefer an explicit version/range when pin already chose one (avoid pin=^2.9.0 then
|
|
93
139
|
// `npm i arkgate@latest` rewriting package.json to a different range).
|
|
@@ -310,6 +356,10 @@ async function init(args) {
|
|
|
310
356
|
console.log('Skipped ark.config.json generation.');
|
|
311
357
|
}
|
|
312
358
|
|
|
359
|
+
// Origin first: contract-on-tree picture before AGENTS.md / skills / CI templates.
|
|
360
|
+
console.log('');
|
|
361
|
+
freezeDayZeroOrigin(root);
|
|
362
|
+
|
|
313
363
|
const installGates =
|
|
314
364
|
nonInteractive || (await askYesNo(rl, 'Configure agent and CI gate templates?', true));
|
|
315
365
|
if (installGates) {
|
|
@@ -337,7 +387,7 @@ async function init(args) {
|
|
|
337
387
|
console.log(`Shape: ${archetype}. Plan: ${arkCommand(root, 'ark-check', '--recommend')}`);
|
|
338
388
|
}
|
|
339
389
|
console.log(
|
|
340
|
-
`
|
|
390
|
+
`Day-zero origin: .ark/reports/origin.* (frozen once; later --report shows evolution vs origin).`
|
|
341
391
|
);
|
|
342
392
|
console.log(`Adoption health: ${arkCommand(root, 'ark-check', '--doctor')}`);
|
|
343
393
|
return 0;
|
|
@@ -361,9 +411,11 @@ async function start(args) {
|
|
|
361
411
|
try {
|
|
362
412
|
console.log("Let's set up Ark for your project.");
|
|
363
413
|
console.log(
|
|
364
|
-
"I'll
|
|
414
|
+
"I'll walk the tree, freeze a day-zero architecture picture, then set up guardrails and show a plan."
|
|
415
|
+
);
|
|
416
|
+
console.log(
|
|
417
|
+
'Nothing in your product code is changed — only Ark config, then origin snapshot, then agent/CI templates.'
|
|
365
418
|
);
|
|
366
|
-
console.log('Nothing in your code is changed — this only adds Ark configuration.');
|
|
367
419
|
if (nonInteractive && !args.yes) {
|
|
368
420
|
console.log(
|
|
369
421
|
'Non-interactive session (no TTY) — using guided defaults (same as --yes). Pass flags to override.'
|
|
@@ -420,10 +472,10 @@ async function start(args) {
|
|
|
420
472
|
console.log(' Skipping arkgate package pin (--no-install).');
|
|
421
473
|
}
|
|
422
474
|
|
|
423
|
-
// 3)
|
|
424
|
-
// so the contract anchors to
|
|
475
|
+
// 3) Contract first (config only). Greenfield → shape preset; established repo → detection,
|
|
476
|
+
// so the contract anchors to directories you already have instead of aspirational globs.
|
|
425
477
|
console.log('');
|
|
426
|
-
console.log('Setting up Ark…');
|
|
478
|
+
console.log('Setting up Ark contract…');
|
|
427
479
|
const configPath = path.join(root, 'ark.config.json');
|
|
428
480
|
if (!fs.existsSync(configPath)) {
|
|
429
481
|
const initArgs = ['--root', root, '--init'];
|
|
@@ -462,6 +514,15 @@ async function start(args) {
|
|
|
462
514
|
} else {
|
|
463
515
|
console.log(' Found an existing ark.config.json — keeping it.');
|
|
464
516
|
}
|
|
517
|
+
|
|
518
|
+
// 4) Day-zero origin — freeze the architecture picture *before* agent docs / CI / skills.
|
|
519
|
+
// Later --report runs show evolution vs this snapshot. Idempotent (origin once).
|
|
520
|
+
console.log('');
|
|
521
|
+
freezeDayZeroOrigin(root);
|
|
522
|
+
|
|
523
|
+
// 5) Agent + CI gate templates (docs, hooks, skills) — after origin is frozen.
|
|
524
|
+
console.log('');
|
|
525
|
+
console.log('Installing agent and CI gate templates…');
|
|
465
526
|
{
|
|
466
527
|
const gateArgs = ['--root', root, '--install-agent-gates'];
|
|
467
528
|
if (args.tools) gateArgs.push('--tools', args.tools);
|
|
@@ -469,7 +530,7 @@ async function start(args) {
|
|
|
469
530
|
runArkCheck(gateArgs, { cwd: root });
|
|
470
531
|
}
|
|
471
532
|
|
|
472
|
-
//
|
|
533
|
+
// 6) Show the plan: what's safe to auto-fix vs what needs a decision.
|
|
473
534
|
console.log('');
|
|
474
535
|
console.log('Your architecture plan:');
|
|
475
536
|
runArkCheck(['--root', root, '--config', 'ark.config.json', '--plan'], { cwd: root });
|
|
@@ -551,7 +612,7 @@ async function start(args) {
|
|
|
551
612
|
planOk = false;
|
|
552
613
|
}
|
|
553
614
|
|
|
554
|
-
//
|
|
615
|
+
// 7) Plain-language wrap-up — one next step, status light only.
|
|
555
616
|
// Modes are detected (Suggest/Adapt/Enforce), not user-picked settings.
|
|
556
617
|
// Soft-block false-green using the same doctor adoption gap (no second detector).
|
|
557
618
|
let falseGreenGap = null;
|
|
@@ -600,7 +661,7 @@ async function start(args) {
|
|
|
600
661
|
console.log(' → reclassify I/O dirs out of Application; then /ark-autopilot for residual debt.');
|
|
601
662
|
} else {
|
|
602
663
|
console.log(' 1. In your agent: /ark-autopilot');
|
|
603
|
-
console.log(' →
|
|
664
|
+
console.log(' → explore first, dual plan (remediation + pattern bets), safe fixes, leave gates on.');
|
|
604
665
|
}
|
|
605
666
|
console.log(` 2. Status anytime: ${arkCommand(root, 'ark-check', '--doctor')}`);
|
|
606
667
|
console.log(` 3. After edits: ${arkCommand(root, 'ark-check', '--root . --config ark.config.json --strict-config')}`);
|
|
@@ -610,16 +671,8 @@ async function start(args) {
|
|
|
610
671
|
);
|
|
611
672
|
}
|
|
612
673
|
console.log('');
|
|
613
|
-
console.log('
|
|
614
|
-
|
|
615
|
-
// 6) First architecture report — freezes an origin snapshot under .ark/reports/
|
|
616
|
-
// so later --report runs can show evolution. Idempotent: origin is written only once.
|
|
617
|
-
console.log('');
|
|
618
|
-
console.log('Capturing architecture report (origin snapshot on first run)…');
|
|
619
|
-
runArkCheck(
|
|
620
|
-
['--root', root, '--config', 'ark.config.json', '--report', 'ark-report.html'],
|
|
621
|
-
{ cwd: root }
|
|
622
|
-
);
|
|
674
|
+
console.log('Day-zero origin is under .ark/reports/origin.* — re-run --report later for evolution.');
|
|
675
|
+
console.log('Optional later: --plan · --coverage · /ark-explore · /ark-fix · /ark-place · ark upgrade');
|
|
623
676
|
return 0;
|
|
624
677
|
} finally {
|
|
625
678
|
rl?.close();
|
|
@@ -627,7 +680,17 @@ async function start(args) {
|
|
|
627
680
|
}
|
|
628
681
|
|
|
629
682
|
async function main() {
|
|
630
|
-
|
|
683
|
+
let args;
|
|
684
|
+
try {
|
|
685
|
+
args = parseArgs(process.argv);
|
|
686
|
+
} catch (error) {
|
|
687
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
688
|
+
return 2;
|
|
689
|
+
}
|
|
690
|
+
if (args.version) {
|
|
691
|
+
console.log(cliVersion());
|
|
692
|
+
return 0;
|
|
693
|
+
}
|
|
631
694
|
if (args.help || !args.command) {
|
|
632
695
|
console.log(usage());
|
|
633
696
|
return 0;
|