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
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
import { printParseHealthSection, summarizeParseHealth } from './parse-health.mjs';
|
|
20
20
|
import { detectGraphBlindSpots, printGraphBlindSection } from './graph-blind.mjs';
|
|
21
21
|
import { summarizeRulesUnderContract } from './rules-under-contract.mjs';
|
|
22
|
+
import { collectStewardNudge } from './team-parliament-io.mjs';
|
|
22
23
|
|
|
23
24
|
export function computeDoctorAdvisories(root, config, cov, rules, files, ts, parseHealth, facts) {
|
|
24
25
|
const physicalCohesion = computePhysicalCohesion(root, files);
|
|
@@ -49,6 +50,7 @@ export function computeDoctorAdvisories(root, config, cov, rules, files, ts, par
|
|
|
49
50
|
graphBlindSpots: detectGraphBlindSpots(ts, root, files),
|
|
50
51
|
// AR12 — Rules under contract (honest counts; real test I/O, never empty-fileContents stub).
|
|
51
52
|
// P1M: pass classification so extraMergeTeeth cannot arm at 0% governed.
|
|
53
|
+
stewardNudge: collectStewardNudge(root, config),
|
|
52
54
|
rulesUnderContract: summarizeRulesUnderContract(root, config, factPaths, {
|
|
53
55
|
governedPercent: cov?.governed?.percent ?? null,
|
|
54
56
|
populatedLayerCount: Array.isArray(cov?.layers)
|
|
@@ -70,4 +72,11 @@ export function printDoctorAdvisories(advisories, io) {
|
|
|
70
72
|
printReshapeDecisionsSection(advisories.physicalCohesion?.reshapeDecisions, io);
|
|
71
73
|
printParseHealthSection(advisories.parseHealth, io);
|
|
72
74
|
printGraphBlindSection(advisories.graphBlindSpots, io);
|
|
75
|
+
const nudge = advisories.stewardNudge;
|
|
76
|
+
if ((nudge?.needsStewards || nudge?.drift) && nudge.ask) {
|
|
77
|
+
console.log('');
|
|
78
|
+
console.log(io.color.bold('Stewards (advisory)'));
|
|
79
|
+
io.line(io.warn, nudge.ask);
|
|
80
|
+
if (nudge.nextAction) io.line(' ', io.color.dim(`Next: ${nudge.nextAction}`));
|
|
81
|
+
}
|
|
73
82
|
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rank doctor next actions from already-computed facts (no I/O).
|
|
3
|
+
* Lets the human printer show light + #1 before honesty/compass sections.
|
|
4
|
+
*/
|
|
5
|
+
import { arkCommand } from '../ark-shared.mjs';
|
|
6
|
+
import { skillGapsForActiveHost } from './agent-gates.mjs';
|
|
7
|
+
import { agentHomeConcernIsActive, agentHomeRefreshCommand } from './agent-homes.mjs';
|
|
8
|
+
import { mergePostGreenTopActions } from './post-green-path.mjs';
|
|
9
|
+
|
|
10
|
+
export function collectDoctorNextActions(ctx) {
|
|
11
|
+
const actions = [];
|
|
12
|
+
if (!ctx.analysisComplete) actions.push('restore complete analysis, then rerun ark-check --doctor');
|
|
13
|
+
if (ctx.designSmells.length > 0 && ctx.postGreenPath) actions.push(ctx.postGreenPath.action);
|
|
14
|
+
if (ctx.coverageHonesty.greenIsNotEnforcement && ctx.coverageHonesty.worseThanNoGate) {
|
|
15
|
+
actions.push('raise governed coverage above a minority slice before treating green as enforcement');
|
|
16
|
+
}
|
|
17
|
+
if (ctx.cov.suggestions.length > 0) actions.push('classify the ungoverned directories (/ark-adopt)');
|
|
18
|
+
if (ctx.packageVersionTruth?.dualTruth) {
|
|
19
|
+
actions.push(
|
|
20
|
+
ctx.dualTruthNext ||
|
|
21
|
+
'bump package.json arkgate pin to match this CLI (or install without --no-install)'
|
|
22
|
+
);
|
|
23
|
+
} else if (ctx.packageVersionTruth?.code === 'PACKAGE_PIN_ABSENT') {
|
|
24
|
+
actions.push(
|
|
25
|
+
ctx.dualTruthNext ||
|
|
26
|
+
'Add arkgate to package.json and install so CI/npx resolve this CLI (PACKAGE_PIN_ABSENT)'
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
if (ctx.activeCount > 0) {
|
|
30
|
+
actions.push(
|
|
31
|
+
`resolve the non-baselined violations — see the classified plan (${arkCommand(ctx.root, 'ark-check', '--plan')}), then /ark-autopilot`
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
if (ctx.writePath?.gap?.fix) actions.push(ctx.writePath.gap.fix);
|
|
35
|
+
if (ctx.gatesMissing.length > 0) {
|
|
36
|
+
actions.push(`install gates (${arkCommand(ctx.root, 'ark-check', '--install-agent-gates')})`);
|
|
37
|
+
}
|
|
38
|
+
const humanSkillGaps = skillGapsForActiveHost(ctx.skillGaps);
|
|
39
|
+
const legacyCodex = humanSkillGaps.some((g) => g.tool === 'codex' && g.legacyPromptsOnly);
|
|
40
|
+
const remainingGaps = humanSkillGaps.filter(
|
|
41
|
+
(g) => !(g.tool === 'codex' && (g.legacyPromptsOnly || g.legacyAdvisory))
|
|
42
|
+
);
|
|
43
|
+
const remMiss = remainingGaps.reduce((s, g) => s + g.missing, 0);
|
|
44
|
+
const remStale = remainingGaps.reduce((s, g) => s + g.stale, 0);
|
|
45
|
+
if (legacyCodex) {
|
|
46
|
+
actions.push('install Codex SKILL.md catalog (--install-agent-gates --skills-only --tools codex --force)');
|
|
47
|
+
}
|
|
48
|
+
if (remMiss + remStale > 0) {
|
|
49
|
+
actions.push('refresh /ark-* skills (--install-agent-gates --skills-only --force)');
|
|
50
|
+
}
|
|
51
|
+
if (ctx.codexHomeGap && ctx.codexConcernActive) {
|
|
52
|
+
actions.push(
|
|
53
|
+
ctx.codexHomeGap.catalogMetadataInvalid
|
|
54
|
+
? 'repair invalid Codex home catalog metadata after verifying the newest installed version'
|
|
55
|
+
: 'refresh Codex home skills (--install-agent-gates --skills-only --codex-home --force)'
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
for (const gap of ctx.agentHomeGaps) {
|
|
59
|
+
if (agentHomeConcernIsActive(gap.host)) {
|
|
60
|
+
actions.push(
|
|
61
|
+
gap.catalogMetadataInvalid
|
|
62
|
+
? `repair invalid ${gap.label} home catalog metadata after verifying the newest installed version`
|
|
63
|
+
: `refresh ${gap.label} shared agent skills (${agentHomeRefreshCommand(ctx.root, gap)})`
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (ctx.analysisComplete && ctx.baselineHonesty?.dirtyBaselineRisk) {
|
|
68
|
+
actions.push('review dirty baseline freezes — fix the contract before trusting green-via-freeze');
|
|
69
|
+
}
|
|
70
|
+
if (ctx.analysisComplete && ctx.staleBaseline > 0) {
|
|
71
|
+
actions.push('tighten the baseline (--update-baseline)');
|
|
72
|
+
}
|
|
73
|
+
if (ctx.staleRunners.length > 0) {
|
|
74
|
+
actions.push(
|
|
75
|
+
`migrate command runners (${arkCommand(ctx.root, 'ark-check', '--install-agent-gates --migrate-commands')})`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
for (const gap of ctx.adoption.gaps) {
|
|
79
|
+
if (!gap.deferred) actions.push(gap.fix || gap.message);
|
|
80
|
+
}
|
|
81
|
+
if (ctx.safety && ctx.safetyHasEntries) {
|
|
82
|
+
actions.push('resolve strict safety diagnostics before treating CI as enforcement');
|
|
83
|
+
}
|
|
84
|
+
if (ctx.showNewHere) {
|
|
85
|
+
actions.unshift('finish ark start (preview + --apply), then re-run --doctor');
|
|
86
|
+
}
|
|
87
|
+
const unique = mergePostGreenTopActions(actions, ctx.postGreenPath);
|
|
88
|
+
if (ctx.designFitness.designWeak && unique.length === 0 && ctx.postGreenPath) {
|
|
89
|
+
unique.push(ctx.postGreenPath.action);
|
|
90
|
+
}
|
|
91
|
+
return unique;
|
|
92
|
+
}
|
package/bin/lib/doctor-plan.mjs
CHANGED
|
@@ -15,9 +15,9 @@ import { describePackageVersionDualTruth } from './field-install.mjs';
|
|
|
15
15
|
import {
|
|
16
16
|
detectAgentHomeGaps,
|
|
17
17
|
agentHomeConcernIsActive,
|
|
18
|
-
agentHomeRefreshCommand,
|
|
19
18
|
} from './agent-homes.mjs';
|
|
20
19
|
import { operatingModeTitle } from './product-copy.mjs';
|
|
20
|
+
import { collectDoctorNextActions } from './doctor-next-actions.mjs';
|
|
21
21
|
export { summarizeRulesUnderContract };
|
|
22
22
|
|
|
23
23
|
/** Optional S3 dual-match classifier when ark-shared exports it (soft dep for S5 landing). */
|
|
@@ -50,7 +50,6 @@ import {
|
|
|
50
50
|
} from './design-smells.mjs';
|
|
51
51
|
import {
|
|
52
52
|
buildPostGreenNextAction,
|
|
53
|
-
mergePostGreenTopActions,
|
|
54
53
|
isDoctorHealthyNothingToDo,
|
|
55
54
|
DESIGN_WEAK_HONESTY_FLAGS,
|
|
56
55
|
} from './post-green-path.mjs';
|
|
@@ -208,7 +207,7 @@ export function runCoverage(root, config, files, rules, asJson) {
|
|
|
208
207
|
}
|
|
209
208
|
}
|
|
210
209
|
console.log('');
|
|
211
|
-
console.log('Apply these via /ark-
|
|
210
|
+
console.log('Apply these via /ark-adopt (adds the layer patterns to ark.config.json).');
|
|
212
211
|
}
|
|
213
212
|
if (layersWithoutRules.length > 0) {
|
|
214
213
|
console.log('');
|
|
@@ -825,9 +824,7 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
825
824
|
const ok = color.green('✓');
|
|
826
825
|
const warn = color.yellow('!');
|
|
827
826
|
const bad = color.red('✗');
|
|
828
|
-
const actions = [];
|
|
829
827
|
const line = (mark, text) => console.log(` ${mark} ${text}`);
|
|
830
|
-
if (!analysisComplete) actions.push('restore complete analysis, then rerun ark-check --doctor');
|
|
831
828
|
console.log(color.bold(`Ark doctor — ${path.basename(path.resolve(root)) || '.'}`));
|
|
832
829
|
if (!analysisComplete) line(warn, analysisIncompleteStatement(completeness));
|
|
833
830
|
|
|
@@ -846,7 +843,7 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
846
843
|
suggest:
|
|
847
844
|
'thin or new tree; architecture config is not yet in charge. You do not pick this light. Next: ark start (preview), then ark start --apply; re-check with --doctor.',
|
|
848
845
|
adapt:
|
|
849
|
-
'config and tree still disagree, or debt is open. The write path does not fully protect you yet. You do not pick this light. Next: do doctor top action #1 (often /ark-adopt
|
|
846
|
+
'config and tree still disagree, or debt is open. The write path does not fully protect you yet. You do not pick this light. Next: do doctor top action #1 (often /ark-adopt or /ark-autopilot).',
|
|
850
847
|
enforce:
|
|
851
848
|
'honest coverage and clean checked imports. You arrived here; you never turn Enforce on. Next: keep the host write path and CI check; only NEW violations should fail.',
|
|
852
849
|
};
|
|
@@ -866,6 +863,63 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
866
863
|
);
|
|
867
864
|
}
|
|
868
865
|
|
|
866
|
+
const safetyHasEntries = Boolean(
|
|
867
|
+
options.safety &&
|
|
868
|
+
[
|
|
869
|
+
options.safety.nonLiteralDynamicImports,
|
|
870
|
+
options.safety.tsSuppressions,
|
|
871
|
+
options.safety.anyCasts,
|
|
872
|
+
options.safety.inMemoryProductionStores,
|
|
873
|
+
options.safety.disabledPeerIsolationRules,
|
|
874
|
+
].some((entries) => Array.isArray(entries) && entries.length > 0)
|
|
875
|
+
);
|
|
876
|
+
const uniqueActions = collectDoctorNextActions({
|
|
877
|
+
root,
|
|
878
|
+
analysisComplete,
|
|
879
|
+
designSmells,
|
|
880
|
+
postGreenPath,
|
|
881
|
+
coverageHonesty,
|
|
882
|
+
cov,
|
|
883
|
+
packageVersionTruth,
|
|
884
|
+
dualTruthNext,
|
|
885
|
+
activeCount,
|
|
886
|
+
writePath,
|
|
887
|
+
gatesMissing,
|
|
888
|
+
skillGaps,
|
|
889
|
+
codexHomeGap: detectCodexHomeGap(root),
|
|
890
|
+
codexConcernActive: codexConcernIsActive(),
|
|
891
|
+
agentHomeGaps,
|
|
892
|
+
baselineHonesty,
|
|
893
|
+
staleBaseline,
|
|
894
|
+
staleRunners,
|
|
895
|
+
adoption,
|
|
896
|
+
safety: options.safety,
|
|
897
|
+
safetyHasEntries,
|
|
898
|
+
showNewHere,
|
|
899
|
+
designFitness,
|
|
900
|
+
});
|
|
901
|
+
console.log('');
|
|
902
|
+
if (isDoctorHealthyNothingToDo(designFitness, uniqueActions)) {
|
|
903
|
+
console.log(color.green('✔ Healthy — nothing to do.'));
|
|
904
|
+
console.log(color.dim(' Contract edges and design residual are clear. Keep write path + CI.'));
|
|
905
|
+
} else {
|
|
906
|
+
console.log(color.bold('Primary next action'));
|
|
907
|
+
console.log(` 1. ${uniqueActions[0]}`);
|
|
908
|
+
if (uniqueActions.length > 1) {
|
|
909
|
+
console.log(color.bold(`Also (${uniqueActions.length - 1}):`));
|
|
910
|
+
uniqueActions.slice(1).forEach((action, index) => console.log(` ${index + 2}. ${action}`));
|
|
911
|
+
}
|
|
912
|
+
if (postGreenPath) {
|
|
913
|
+
console.log(
|
|
914
|
+
color.dim(
|
|
915
|
+
` Shape residual is the primary door under ${modeTitle} — do not skill-shop explore vs coverage vs think.`
|
|
916
|
+
)
|
|
917
|
+
);
|
|
918
|
+
} else {
|
|
919
|
+
console.log(color.dim(' Doctor is the control plane: do #1 first, then re-run --doctor.'));
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
|
|
869
923
|
// P0-B — single honesty surface (never a score; never "all good" when residual remains).
|
|
870
924
|
if (productHonesty) {
|
|
871
925
|
console.log('');
|
|
@@ -907,11 +961,7 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
907
961
|
line(' ', color.dim(`evidence: ${smell.evidence.slice(0, 4).join(', ')}`));
|
|
908
962
|
}
|
|
909
963
|
}
|
|
910
|
-
|
|
911
|
-
// Rank first via mergePostGreenTopActions at the end (Q01 single door).
|
|
912
|
-
actions.push(postGreenPath.action);
|
|
913
|
-
}
|
|
914
|
-
// Q04 — surface one next pilot under design-weak.
|
|
964
|
+
// Q04 — surface one next pilot under leftover design work.
|
|
915
965
|
if (pilotLoop?.active && pilotLoop.nextPilot) {
|
|
916
966
|
const np = pilotLoop.nextPilot;
|
|
917
967
|
line(
|
|
@@ -967,13 +1017,9 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
967
1017
|
line(govMark, `Governed: ${cov.governed.percent}% (${cov.governed.classifiedFiles}/${cov.governed.totalFiles} files)`);
|
|
968
1018
|
if (coverageHonesty.greenIsNotEnforcement) {
|
|
969
1019
|
line(coverageHonesty.worseThanNoGate ? bad : warn, coverageHonesty.message);
|
|
970
|
-
if (coverageHonesty.worseThanNoGate) {
|
|
971
|
-
actions.push('raise governed coverage above a minority slice before treating green as enforcement');
|
|
972
|
-
}
|
|
973
1020
|
}
|
|
974
1021
|
if (cov.suggestions.length > 0) {
|
|
975
1022
|
line(warn, `${cov.suggestions.length} ungoverned director(y/ies) — proposals: ${arkCommand(root, 'ark-check', '--coverage')}`);
|
|
976
|
-
actions.push('classify the ungoverned directories (/ark-contract)');
|
|
977
1023
|
}
|
|
978
1024
|
if (cov.emptyLayers.length > 0) line(warn, `Empty layers (pattern matches nothing): ${cov.emptyLayers.join(', ')}`);
|
|
979
1025
|
if (cov.layersWithoutRules.length > 0) line(warn, `Layers with no rule edge: ${cov.layersWithoutRules.join(', ')}`);
|
|
@@ -989,18 +1035,10 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
989
1035
|
console.log('');
|
|
990
1036
|
console.log(color.bold('Package pin (dual-truth)'));
|
|
991
1037
|
line(warn, packageVersionTruth.note);
|
|
992
|
-
actions.push(
|
|
993
|
-
dualTruthNext ||
|
|
994
|
-
'bump package.json arkgate pin to match this CLI (or install without --no-install)'
|
|
995
|
-
);
|
|
996
1038
|
} else if (packageVersionTruth?.code === 'PACKAGE_PIN_ABSENT') {
|
|
997
1039
|
console.log('');
|
|
998
1040
|
console.log(color.bold('Package pin'));
|
|
999
1041
|
line(warn, packageVersionTruth.note);
|
|
1000
|
-
actions.push(
|
|
1001
|
-
dualTruthNext ||
|
|
1002
|
-
'Add arkgate to package.json and install so CI/npx resolve this CLI (PACKAGE_PIN_ABSENT)'
|
|
1003
|
-
);
|
|
1004
1042
|
}
|
|
1005
1043
|
if (options.configWalkedUp && options.configRoot) {
|
|
1006
1044
|
line(
|
|
@@ -1030,7 +1068,6 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
1030
1068
|
line(warn, 'Low governed coverage or fresh config — finish start, then re-run doctor before adding layers of code.');
|
|
1031
1069
|
}
|
|
1032
1070
|
line(ok, `Optional sensor detail: ${arkCommand(root, 'ark-check', '--recommend')}`);
|
|
1033
|
-
actions.unshift('finish ark start (preview + --apply), then re-run --doctor');
|
|
1034
1071
|
}
|
|
1035
1072
|
|
|
1036
1073
|
console.log('');
|
|
@@ -1058,11 +1095,6 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
1058
1095
|
if (summary.concentrated) {
|
|
1059
1096
|
line(warn, color.dim(`${Math.round(summary.dominantShare * 100)}% on one edge (${summary.dominant}) — likely a contract fix, not debt`));
|
|
1060
1097
|
}
|
|
1061
|
-
if (activeCount > 0) {
|
|
1062
|
-
actions.push(
|
|
1063
|
-
`resolve the non-baselined violations — see the classified plan (${arkCommand(root, 'ark-check', '--plan')}), then /ark-fix`
|
|
1064
|
-
);
|
|
1065
|
-
}
|
|
1066
1098
|
}
|
|
1067
1099
|
|
|
1068
1100
|
console.log('');
|
|
@@ -1105,7 +1137,6 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
1105
1137
|
line(writePath.gap.severity === 'warn' ? warn : warn, writePath.gap.message);
|
|
1106
1138
|
if (writePath.gap.fix) {
|
|
1107
1139
|
line(' ', color.dim(`Fix: ${writePath.gap.fix}`));
|
|
1108
|
-
actions.push(writePath.gap.fix);
|
|
1109
1140
|
}
|
|
1110
1141
|
}
|
|
1111
1142
|
|
|
@@ -1114,7 +1145,6 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
1114
1145
|
if (gatesMissing.length === 0) line(ok, 'Shared gate artifacts found on disk (AGENTS.md, .mcp.json, CI); runtime activation is reported separately');
|
|
1115
1146
|
else {
|
|
1116
1147
|
line(bad, `Missing gates: ${gatesMissing.join(', ')}`);
|
|
1117
|
-
actions.push(`install gates (${arkCommand(root, 'ark-check', '--install-agent-gates')})`);
|
|
1118
1148
|
}
|
|
1119
1149
|
const humanSkillGaps = skillGapsForActiveHost(skillGaps);
|
|
1120
1150
|
const legacyCodex = humanSkillGaps.some((g) => g.tool === 'codex' && g.legacyPromptsOnly);
|
|
@@ -1129,7 +1159,6 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
1129
1159
|
if (remMiss + remStale === 0 && !legacyCodex) line(ok, '/ark-* skills current for detected tools');
|
|
1130
1160
|
if (legacyCodex) {
|
|
1131
1161
|
line(warn, 'Codex: legacy flat .codex/prompts only (not a loadable skill catalog)');
|
|
1132
|
-
actions.push('install Codex SKILL.md catalog (--install-agent-gates --skills-only --tools codex --force)');
|
|
1133
1162
|
}
|
|
1134
1163
|
if (codexLegacySafeDelete) {
|
|
1135
1164
|
line(
|
|
@@ -1144,7 +1173,6 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
1144
1173
|
warn,
|
|
1145
1174
|
`${remMiss} missing / ${remStale} content-behind-package /ark-* skill(s) for ${remainingGaps.map((g) => g.tool).join(', ')}`
|
|
1146
1175
|
);
|
|
1147
|
-
actions.push('refresh /ark-* skills (--install-agent-gates --skills-only --force)');
|
|
1148
1176
|
}
|
|
1149
1177
|
const codexHomeGap = detectCodexHomeGap(root);
|
|
1150
1178
|
if (codexHomeGap) {
|
|
@@ -1159,7 +1187,6 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
1159
1187
|
line(color.dim('·'), color.dim(`Codex home skills ${parts.join(', ')} (deferred — not on Codex session)`));
|
|
1160
1188
|
} else {
|
|
1161
1189
|
line(warn, `Codex home skills ${parts.join(', ')}`);
|
|
1162
|
-
actions.push(codexHomeGap.catalogMetadataInvalid ? 'repair invalid Codex home catalog metadata after verifying the newest installed version' : 'refresh Codex home skills (--install-agent-gates --skills-only --codex-home --force)');
|
|
1163
1190
|
}
|
|
1164
1191
|
}
|
|
1165
1192
|
for (const gap of agentHomeGaps) {
|
|
@@ -1174,11 +1201,6 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
1174
1201
|
line(color.dim('·'), color.dim(`${summary} (deferred — not this session)`));
|
|
1175
1202
|
} else {
|
|
1176
1203
|
line(warn, summary);
|
|
1177
|
-
actions.push(
|
|
1178
|
-
gap.catalogMetadataInvalid
|
|
1179
|
-
? `repair invalid ${gap.label} home catalog metadata after verifying the newest installed version`
|
|
1180
|
-
: `refresh ${gap.label} shared agent skills (${agentHomeRefreshCommand(root, gap)})`
|
|
1181
|
-
);
|
|
1182
1204
|
}
|
|
1183
1205
|
}
|
|
1184
1206
|
|
|
@@ -1193,11 +1215,9 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
1193
1215
|
line(baseMark, `${baseline.keys.size} frozen key(s)${analysisComplete ? '' : ' — stale comparison not verified'}`);
|
|
1194
1216
|
if (analysisComplete && baselineHonesty.dirtyBaselineRisk) {
|
|
1195
1217
|
line(warn, baselineHonesty.message);
|
|
1196
|
-
actions.push('review dirty baseline freezes — fix the contract before trusting green-via-freeze');
|
|
1197
1218
|
}
|
|
1198
1219
|
if (analysisComplete && staleBaseline > 0) {
|
|
1199
1220
|
line(warn, `${staleBaseline} stale entr(y/ies) no longer occur — tighten with --update-baseline`);
|
|
1200
|
-
actions.push('tighten the baseline (--update-baseline)');
|
|
1201
1221
|
}
|
|
1202
1222
|
}
|
|
1203
1223
|
|
|
@@ -1206,7 +1226,6 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
1206
1226
|
if (staleRunners.length === 0) line(ok, 'Emitted commands match the package manager');
|
|
1207
1227
|
else {
|
|
1208
1228
|
line(warn, `Stale runner in ${staleRunners.join(', ')}`);
|
|
1209
|
-
actions.push(`migrate command runners (${arkCommand(root, 'ark-check', '--install-agent-gates --migrate-commands')})`);
|
|
1210
1229
|
}
|
|
1211
1230
|
|
|
1212
1231
|
// Adoption completeness (hosts, MCP health, codex home, core optionality, origin, baseline policy)
|
|
@@ -1232,7 +1251,6 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
1232
1251
|
if (gap.fix) {
|
|
1233
1252
|
line(' ', color.dim(gap.deferred ? `When using Codex: ${gap.fix}` : `Fix: ${gap.fix}`));
|
|
1234
1253
|
}
|
|
1235
|
-
if (!gap.deferred) actions.push(gap.fix || gap.message);
|
|
1236
1254
|
}
|
|
1237
1255
|
if (adoption.layerBalance) {
|
|
1238
1256
|
line(warn, color.dim(adoption.layerBalance.educational));
|
|
@@ -1269,34 +1287,6 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
1269
1287
|
for (const [label, entries] of rows) {
|
|
1270
1288
|
line(entries.length === 0 ? ok : warn, `${label}: ${entries.length}`);
|
|
1271
1289
|
}
|
|
1272
|
-
if (rows.some(([, entries]) => entries.length > 0)) {
|
|
1273
|
-
actions.push('resolve strict safety diagnostics before treating CI as enforcement');
|
|
1274
|
-
}
|
|
1275
1290
|
}
|
|
1276
1291
|
|
|
1277
|
-
console.log('');
|
|
1278
|
-
const uniqueActions = mergePostGreenTopActions(actions, postGreenPath);
|
|
1279
|
-
if (isDoctorHealthyNothingToDo(designFitness, uniqueActions)) {
|
|
1280
|
-
console.log(color.green('✔ Healthy — nothing to do.'));
|
|
1281
|
-
console.log(color.dim(' Contract edges and design residual are clear. Keep write path + CI.'));
|
|
1282
|
-
} else {
|
|
1283
|
-
if (designFitness.designWeak && uniqueActions.length === 0 && postGreenPath) {
|
|
1284
|
-
uniqueActions.push(postGreenPath.action);
|
|
1285
|
-
}
|
|
1286
|
-
console.log(color.bold(`Primary next action`));
|
|
1287
|
-
console.log(` 1. ${uniqueActions[0]}`);
|
|
1288
|
-
if (uniqueActions.length > 1) {
|
|
1289
|
-
console.log(color.bold(`Also (${uniqueActions.length - 1}):`));
|
|
1290
|
-
uniqueActions.slice(1).forEach((action, index) => console.log(` ${index + 2}. ${action}`));
|
|
1291
|
-
}
|
|
1292
|
-
if (postGreenPath) {
|
|
1293
|
-
console.log(
|
|
1294
|
-
color.dim(
|
|
1295
|
-
` Shape residual is the primary door under ${modeTitle} — do not skill-shop explore vs coverage vs think.`
|
|
1296
|
-
)
|
|
1297
|
-
);
|
|
1298
|
-
} else {
|
|
1299
|
-
console.log(color.dim(' Doctor is the control plane: do #1 first, then re-run --doctor.'));
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
1292
|
}
|
|
@@ -506,7 +506,7 @@ export function detectContractFalseGreenRisk(root, config, coverage) {
|
|
|
506
506
|
`Contract may be a false green: empty core layer(s) [${emptyCores.join(', ')}] while ` +
|
|
507
507
|
`Application-class globs still cover I/O paths (${ioPaths.slice(0, 5).join(', ')}` +
|
|
508
508
|
`${ioPaths.length > 5 ? ', …' : ''}). A clean check can miss real coupling.`,
|
|
509
|
-
fix: 'Run /ark-adopt
|
|
509
|
+
fix: 'Run /ark-adopt — reclassify persistence/auth dirs out of Application before claiming ENFORCE.',
|
|
510
510
|
};
|
|
511
511
|
}
|
|
512
512
|
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* First-run CLI help (setup + check). Encyclopedia text stays behind --help --all.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export function setupUsage() {
|
|
6
|
+
return `arkgate (alias ark) — One architecture config. One check. One coach.
|
|
7
|
+
|
|
8
|
+
arkgate start preview what will change (no writes)
|
|
9
|
+
arkgate start --apply write the compact contract + host router + CI
|
|
10
|
+
arkgate-check --doctor status light + primary next action
|
|
11
|
+
|
|
12
|
+
Then session 0 in your agent: /ark-adopt
|
|
13
|
+
Stuck? Run doctor. Do #1.
|
|
14
|
+
|
|
15
|
+
More commands and flags: arkgate --help --all
|
|
16
|
+
`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function upgradeUsage() {
|
|
20
|
+
return `arkgate upgrade (alias ark upgrade) — preview vs apply.
|
|
21
|
+
|
|
22
|
+
arkgate upgrade preview managed updates (no writes)
|
|
23
|
+
arkgate upgrade --apply apply the previewed bytes (needs --plan-digest when applying managed files)
|
|
24
|
+
|
|
25
|
+
Customized files stay unless you pass --accept-conflicts or --refresh-skills.
|
|
26
|
+
Then: arkgate-check --doctor
|
|
27
|
+
|
|
28
|
+
Every flag: arkgate --help --all
|
|
29
|
+
`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function setupUsageAll() {
|
|
33
|
+
return `arkgate (alias ark) — One architecture config. One check. One coach.
|
|
34
|
+
|
|
35
|
+
Usage:
|
|
36
|
+
arkgate start [--root <project>] [--tools <host>] [--require-write-hook <host>] [--install] [--apply] [--json]
|
|
37
|
+
arkgate init [--root <project>] [--preset hexagonal|layered|feature-sliced|monorepo|ui-surface|vertical-slice|ddd-bounded-contexts|clean-architecture|onion-architecture]
|
|
38
|
+
[--archetype <playbook-id>] [--tools <list>] [--require-write-hook <host>] [--yes] [--force] [--no-strict]
|
|
39
|
+
arkgate upgrade [--root <project>] [--tools <list>] [--apply] [--plan-digest <sha256>] [--accept-conflicts] [--refresh-skills] [--json] [--no-install] [--no-strict]
|
|
40
|
+
arkgate preflight --changes <change-set.json> [--change-map <map.json>] [--root <project>] [--config ark.config.json] [--manifest <manifest.json>] [--tsconfig <tsconfig.json>] [--json]
|
|
41
|
+
arkgate status [--root <project>] [--config ark.config.json] [--json] [--vs <git-ref>]
|
|
42
|
+
[--expected-root <abs>] [--expected-project-id sha256:…] [--tools <host>]
|
|
43
|
+
arkgate agents-md [--root <project>] [--config ark.config.json] [--write] [--check] [--stdout] [--json]
|
|
44
|
+
[--tools <host>]
|
|
45
|
+
|
|
46
|
+
Commands:
|
|
47
|
+
start New here? Analyze and preview the complete setup. Read-only unless --apply.
|
|
48
|
+
init Configure Ark project enforcement with explicit prompts.
|
|
49
|
+
upgrade Preview identity-proven Ark-managed asset updates. With package install,
|
|
50
|
+
--apply bumps toward registry latest when behind (not only when CLI ≠ pin)
|
|
51
|
+
and recomputes the preview; a second explicit --apply --no-install applies
|
|
52
|
+
those exact bytes and verifies them. --refresh-skills opts in to rewrite
|
|
53
|
+
customized managed skills to package templates (never silent default).
|
|
54
|
+
(alias: ark update)
|
|
55
|
+
preflight Validate one atomic create/update/delete set without writing project files.
|
|
56
|
+
status Unified session/project manifest (identity, activation, last check, rules).
|
|
57
|
+
Never prompts. Prefer --json for agents; CI=1 forces JSON.
|
|
58
|
+
agents-md Version-matched agent contract projection (ACS04). Stamps package version +
|
|
59
|
+
contract summary into a managed AGENTS.md block. Non-authoritative — not a
|
|
60
|
+
gate input. Preview by default; --write merges without clobbering outside
|
|
61
|
+
regions; --check fails on version drift; --stdout prints the block only.
|
|
62
|
+
(aliases: agents-md, agent-projection)
|
|
63
|
+
|
|
64
|
+
Options:
|
|
65
|
+
--yes Non-interactive defaults: create config if needed, install gate templates, run strict check.
|
|
66
|
+
(Also the implicit default when stdin/stdout are not a TTY — agents never hang on prompts.)
|
|
67
|
+
--force Allow generated files to overwrite existing files.
|
|
68
|
+
--no-strict Skip the final strict ark-check run.
|
|
69
|
+
--install Pin and install arkgate as a project devDependency (default for start).
|
|
70
|
+
--no-install Skip adding/installing arkgate as a project devDependency (start/upgrade).
|
|
71
|
+
--apply Apply a start plan; for upgrade, update/repreview or apply managed bytes.
|
|
72
|
+
--accept-conflicts
|
|
73
|
+
Allow upgrade to recreate deleted managed assets or replace recorded conflicts.
|
|
74
|
+
--plan-digest Digest emitted by an upgrade preview; required to apply managed bytes.
|
|
75
|
+
--json Emit the start/upgrade/status/agents-md preview as deterministic machine-readable JSON.
|
|
76
|
+
--write For agents-md: merge the version-matched projection into AGENTS.md.
|
|
77
|
+
--check For agents-md: exit 1 when projection stamp drifts from package version.
|
|
78
|
+
--stdout For agents-md: print the projection block only (no file write).
|
|
79
|
+
--expected-root / --expected-project-id
|
|
80
|
+
Optional project expectation for status (MCP-compatible binding check).
|
|
81
|
+
--preset Start from a named architecture preset instead of detection.
|
|
82
|
+
--archetype Application shape from templates/architecture-playbook.json (maps to the matching preset).
|
|
83
|
+
Valid ids: crud-product, api-backend, frontend-surface, library-sdk, cli-utility,
|
|
84
|
+
worker-pipeline, event-coordinator, integration-bridge, multi-app-workspace, prototype-spike,
|
|
85
|
+
vertical-slice-product, ddd-bounded-contexts.
|
|
86
|
+
--tools One active agent host for start (claude,cursor,codex,grok,windsurf,cline,copilot,kiro,roo,continue,gemini).
|
|
87
|
+
Omit to use the active host; an unknown host creates only the shared compact router.
|
|
88
|
+
--remove-host <host>
|
|
89
|
+
Preview or apply removal of that compact host integration; re-add it with --tools <host>.
|
|
90
|
+
--require-write-hook <host>
|
|
91
|
+
Require and verify a hard local write hook for Claude, Grok, Antigravity, or Cursor.
|
|
92
|
+
Codex/OpenCode are advisory-write plus hard CI merge only; impossible requests fail before any write.
|
|
93
|
+
|
|
94
|
+
Interactive mode (TTY, no --yes): asks what application shape you are building and maps it to a preset.
|
|
95
|
+
Non-interactive (no TTY): uses the same defaults as --yes — never calls readline on a null interface.
|
|
96
|
+
`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function checkUsage() {
|
|
100
|
+
return [
|
|
101
|
+
'arkgate-check (alias ark-check) — the architecture check.',
|
|
102
|
+
'',
|
|
103
|
+
' arkgate-check --doctor where you are: one status light, one next action',
|
|
104
|
+
' arkgate-check --strict-merge CI / merge gate (required GitHub status)',
|
|
105
|
+
'',
|
|
106
|
+
'Every flag and command: arkgate-check --help --all',
|
|
107
|
+
].join('\n');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function checkUsageAll() {
|
|
111
|
+
return [
|
|
112
|
+
'arkgate-check (alias ark-check) — the architecture check.',
|
|
113
|
+
'',
|
|
114
|
+
'Usage: arkgate-check | ark-check (identical bins; product name ArkGate)',
|
|
115
|
+
' arkgate-check --version',
|
|
116
|
+
' arkgate-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]',
|
|
117
|
+
' ark-check --doctor [--json] [--resident] [--fail-on-new-smells --base-ref <git-ref>] read-only diagnosis; resident JSON falls back cold',
|
|
118
|
+
' ark-check --coverage [--json] per-layer file counts + full unclassified list (report only, exit 0)',
|
|
119
|
+
' ark-check --plan [--json] classified remediation plan (mechanical-safe / judgment / deferred) + goal; report only',
|
|
120
|
+
' ark-check --rules-inventory [--json] brownfield rules inventory (AR13; deterministic candidates, not a score)',
|
|
121
|
+
' ark-check --recommend [--json] [--write-plan] application-shape plan; --write-plan emits ark-adoption-plan.json',
|
|
122
|
+
' ark-check --list-policy-packs enthusiast packs (hexagonal, layered, feature-sliced, monorepo, ui-surface, vertical-slice, ddd-bounded-contexts)',
|
|
123
|
+
' ark-check --apply-policy-pack <id> [--force] write ark.config.json from templates/policy-packs/ (uses preset factory)',
|
|
124
|
+
' ark-check --suggest-include [--json] propose include roots (TS packages / workspaces)',
|
|
125
|
+
' ark-check --adopt-contract [--write] expand include + layer patterns from ungoverned dirs (never bare lib→Presentation)',
|
|
126
|
+
' ark-check --migrate-contract [--write] additive P0-A retrofit: inject app/api/** → Application when missing',
|
|
127
|
+
' ark-check --ratchet-cores when raw graph is green (0 violations; baseline ignored), set optional:false on populated cores only (writes ark.config.json)',
|
|
128
|
+
' ark-check --watch re-run the check when governed files change (debounced)',
|
|
129
|
+
' ark-check --report [file.html] [--beginner] [--reset-origin] [--no-archive] [--open|--no-open]',
|
|
130
|
+
' HTML report + snapshots under .ark/reports/ (origin once, latest each run, history JSON)',
|
|
131
|
+
' Best-effort open in browser (local TTY). No-op if open fails. --no-open / ARK_NO_OPEN_REPORT=1 to skip; --open forces open.',
|
|
132
|
+
' 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]',
|
|
133
|
+
' --follow-config-root On writes (init/install-agent-gates/migrate --write/…), adopt walked-up monorepo config root (default: keep explicit --root)',
|
|
134
|
+
' 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]',
|
|
135
|
+
' ark-check --update-baseline [file] freeze current violations (default .ark-baseline.json)',
|
|
136
|
+
' ark-check --print-config eleven-layer',
|
|
137
|
+
'',
|
|
138
|
+
'Adopting Ark in an existing codebase? Run --update-baseline once to freeze existing',
|
|
139
|
+
'violations, commit the baseline file, and gate CI with --baseline: only NEW violations',
|
|
140
|
+
'fail the check, so the ratchet only moves toward zero.',
|
|
141
|
+
'',
|
|
142
|
+
'Team parliament: law files (ark.config / arkrules / .ark-baseline.json) cannot ship in',
|
|
143
|
+
'the same diff as product source. --changed --base <ref> checks touched files only.',
|
|
144
|
+
'--against <ref> ratchets new keys vs that ref\'s baseline. --contract-session is a',
|
|
145
|
+
'steward law-only PR. Loosen / baseline-grow need stewards[] + --author when set.',
|
|
146
|
+
'',
|
|
147
|
+
'--init scans the project for the built-in layer directory conventions (src/domain,',
|
|
148
|
+
'src/application, src/adapters/persistence, ...) and writes an ark.config.json covering',
|
|
149
|
+
'only the layers that actually exist, with the default rules filtered to those layers.',
|
|
150
|
+
'Undetected profile layers are printed as suggestions with their conventional',
|
|
151
|
+
'directories. When nothing is detected, the full 11-layer starter profile is written',
|
|
152
|
+
'instead (all layers optional, anchored at src/), so the strict check passes today and',
|
|
153
|
+
'each layer starts being enforced as soon as its directory gains source files.',
|
|
154
|
+
'',
|
|
155
|
+
'Resolves relative, tsconfig path-alias, and package imports via the TypeScript',
|
|
156
|
+
'module resolver, then checks each resolved cross-layer import against the rules.',
|
|
157
|
+
'Path aliases resolve against the NEAREST tsconfig.json above each source file, so',
|
|
158
|
+
'monorepo packages with per-package configs work under a single --root. Pass',
|
|
159
|
+
'--tsconfig to force one config for every file. If no tsconfig is found, path',
|
|
160
|
+
'aliases are unavailable but relative/package imports still resolve.',
|
|
161
|
+
'',
|
|
162
|
+
'The correctness path resolves and parses one complete candidate on every invocation.',
|
|
163
|
+
'Legacy node_modules/.cache/ark-check.json files are ignored. --no-cache remains an',
|
|
164
|
+
'accepted compatibility no-op; the identity-keyed warm snapshot is introduced in Z07.',
|
|
165
|
+
'',
|
|
166
|
+
'Config shape:',
|
|
167
|
+
'{',
|
|
168
|
+
' "include": ["src"],',
|
|
169
|
+
' // optional: "exclude": ["**/vendor/**"], "excludeGenerated": false (default skips *.gen.ts / *.generated.ts)',
|
|
170
|
+
' "layers": [',
|
|
171
|
+
' { "name": "DomainModel", "patterns": ["src/domain/**"], "intentPrefixes": ["Domain."],',
|
|
172
|
+
' "forbiddenGlobals": ["fetch", "process", "Date.now", "Math.random"] }',
|
|
173
|
+
' ],',
|
|
174
|
+
' "rules": [{ "from": "DomainModel", "to": "PersistenceAdapters", "allowed": false }]',
|
|
175
|
+
'}',
|
|
176
|
+
'',
|
|
177
|
+
'Config warnings are advisory by default and are included in JSON output.',
|
|
178
|
+
'Use --strict-config to make config warnings fail the check.',
|
|
179
|
+
'Use --strict-merge for the fail-closed CI profile: --strict-config + --require-gates',
|
|
180
|
+
'plus the security diagnostics surfaced by doctor. --strict is a compatibility alias.',
|
|
181
|
+
'This merge profile never depends on an editor/agent hook.',
|
|
182
|
+
'When a Git merge base is available, --strict-merge classifies the ark.config.json',
|
|
183
|
+
'transition. Weakening or judgment-required findings fail unless --policy-ack names',
|
|
184
|
+
'every finding and is bound to both policy hashes. Use --policy-base/--policy-base-ref',
|
|
185
|
+
'for an explicit comparison; ARK_POLICY_BASE_REF is the CI environment equivalent.',
|
|
186
|
+
'Add --require-write-hook claude|grok|antigravity|cursor to validate a hard local write',
|
|
187
|
+
'boundary for that specific host. Codex and OpenCode expose advisory MCP (plus best-effort',
|
|
188
|
+
'hooks where applicable) and the shared CI check; merge blocking requires repository policy',
|
|
189
|
+
'to make that status required.',
|
|
190
|
+
'',
|
|
191
|
+
'--require-gates implies --strict-config and fails when the Ark contract in AGENTS.md,',
|
|
192
|
+
'the project-rooted Ark server in .mcp.json, or fail-closed CI is missing/invalid.',
|
|
193
|
+
'Included but unclassified source files therefore stay red instead of false-green.',
|
|
194
|
+
'',
|
|
195
|
+
'--install-agent-gates writes AGENTS.md, .mcp.json, and the CI workflow for every',
|
|
196
|
+
'project, plus tool-specific templates. Known tools: claude, cursor, codex, grok',
|
|
197
|
+
'(Claude/Grok/Antigravity/Cursor hard-write hooks when covered; Codex advisory MCP;',
|
|
198
|
+
'shared CI check for all) and',
|
|
199
|
+
'windsurf, cline, copilot, kiro, roo, continue, gemini',
|
|
200
|
+
'(instruction-tier rule files derived from the same contract).',
|
|
201
|
+
'It also installs the /ark-* skills shipped in templates/skills/ into each',
|
|
202
|
+
'detected tool\'s command location (.claude/skills/, .cursor/commands/,',
|
|
203
|
+
'.agents/skills/ (Codex REPO catalog), .grok/skills/, .windsurf/workflows/,',
|
|
204
|
+
'.clinerules/workflows/, .github/prompts/).',
|
|
205
|
+
'Kiro, Roo, Continue, and Gemini have no command mechanism and receive only their',
|
|
206
|
+
'rule file. Existing files are never overwritten without --force, so re-running',
|
|
207
|
+
'after an update only adds what is missing. --skills-only restricts the write to',
|
|
208
|
+
'just the /ark-* skills (safe to --force-refresh — it leaves a customized AGENTS.md,',
|
|
209
|
+
'settings, and CI workflow untouched).',
|
|
210
|
+
'Pass --tools to pick which tool configs to write; otherwise they are auto-detected',
|
|
211
|
+
'from their config directories (.claude/, .cursor/, .codex/, .grok/, .windsurf/,',
|
|
212
|
+
'.clinerules/, .kiro/, .roo/, .continue/, .gemini/; copilot is explicit-only).',
|
|
213
|
+
'claude+cursor+codex+grok are written when nothing is detected.',
|
|
214
|
+
'',
|
|
215
|
+
'Generate a starter 11-layer config:',
|
|
216
|
+
' ark-check --print-config eleven-layer > ark.config.json',
|
|
217
|
+
'',
|
|
218
|
+
'Install agent + CI enforcement templates:',
|
|
219
|
+
' ark-check --install-agent-gates',
|
|
220
|
+
].join('\n');
|
|
221
|
+
}
|