arkgate 4.6.1 → 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.
Files changed (46) hide show
  1. package/CHANGELOG.md +30 -1
  2. package/README.md +5 -3
  3. package/bin/ark-check-runtime.mjs +23 -127
  4. package/bin/ark-mcp-runtime.mjs +70 -48
  5. package/bin/ark.mjs +19 -78
  6. package/bin/lib/doctor-next-actions.mjs +92 -0
  7. package/bin/lib/doctor-plan.mjs +59 -69
  8. package/bin/lib/first-run-help.mjs +221 -0
  9. package/bin/lib/start-preview.mjs +17 -10
  10. package/bin/lib/status-command.mjs +5 -0
  11. package/bin/lib/status-manifest.mjs +6 -0
  12. package/dist/index.cjs +19 -19
  13. package/dist/index.d.ts +6 -1
  14. package/dist/index.js +22 -22
  15. package/docs/README.md +5 -5
  16. package/docs/agent-guide.md +1 -1
  17. package/docs/enthusiast/how-to-agent-gates.md +1 -1
  18. package/docs/package-surface.md +3 -3
  19. package/docs/use.md +4 -4
  20. package/package.json +2 -2
  21. package/server.json +3 -3
  22. package/templates/agent-skills/README.md +1 -1
  23. package/templates/agent-skills/ark-adopt/SKILL.md +14 -5
  24. package/templates/agent-skills/ark-architect/SKILL.md +2 -2
  25. package/templates/agent-skills/ark-autopilot/SKILL.md +12 -5
  26. package/templates/agent-skills/ark-contract/SKILL.md +1 -1
  27. package/templates/agent-skills/ark-coverage/SKILL.md +6 -5
  28. package/templates/agent-skills/ark-explain/SKILL.md +3 -2
  29. package/templates/agent-skills/ark-explore/SKILL.md +13 -4
  30. package/templates/agent-skills/ark-fix/SKILL.md +1 -1
  31. package/templates/agent-skills/ark-loop/SKILL.md +1 -1
  32. package/templates/agent-skills/ark-place/SKILL.md +10 -1
  33. package/templates/agent-skills/ark-think/SKILL.md +3 -2
  34. package/templates/agent-skills/ark-upgrade/SKILL.md +10 -3
  35. package/templates/skills/ark-adopt.md +14 -5
  36. package/templates/skills/ark-architect.md +2 -2
  37. package/templates/skills/ark-autopilot.md +12 -5
  38. package/templates/skills/ark-contract.md +1 -1
  39. package/templates/skills/ark-coverage.md +6 -5
  40. package/templates/skills/ark-explain.md +3 -2
  41. package/templates/skills/ark-explore.md +13 -4
  42. package/templates/skills/ark-fix.md +1 -1
  43. package/templates/skills/ark-loop.md +1 -1
  44. package/templates/skills/ark-place.md +10 -1
  45. package/templates/skills/ark-think.md +3 -2
  46. package/templates/skills/ark-upgrade.md +10 -3
@@ -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
+ }
@@ -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';
@@ -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
 
@@ -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
- if (postGreenPath) {
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-adopt)');
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-autopilot`
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
  }
@@ -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
+ }
@@ -147,21 +147,16 @@ export function renderStartPreview(preview, options = {}) {
147
147
  } else {
148
148
  console.log('Ark start preview — no files were changed.');
149
149
  }
150
+ if (!applying) {
151
+ console.log('Apply this plan with: arkgate start --apply');
152
+ }
150
153
  if (preview.analysis) {
151
154
  console.log(`Your project looks like: ${preview.analysis.label} (${preview.analysis.archetype}, confidence ${preview.analysis.confidence}).`);
152
155
  }
153
- console.log(`Projected governed coverage: ${preview.projectedCoverage.percent ?? 'unknown'}% (${preview.projectedCoverage.classifiedFiles}/${preview.projectedCoverage.totalFiles} files)`);
154
- const budget = preview.setupBudget;
155
- const arkrulesNote =
156
- budget.arkrulesFiles > 0 ? ` (+${budget.arkrulesFiles} arkrules)` : '';
157
- const gateCount = budget.gateFiles ?? budget.files;
158
- console.log(
159
- `Compact setup budget: ${gateCount}/${budget.maxFiles} gate files${arkrulesNote}, ${budget.bytes}/${budget.maxBytes} bytes${budget.ok ? '' : ' (exceeded)'}.`
160
- );
161
156
  console.log(applying ? 'Files create/edit/delete:' : 'Files to create/edit/delete:');
162
157
  if (preview.changes.length === 0) console.log(' (none)');
163
158
  for (const change of preview.changes) {
164
- console.log(` ${change.action.padEnd(6)} ${change.path} ${change.afterHash ?? '(deleted)'}`);
159
+ console.log(` ${change.action.padEnd(6)} ${change.path}`);
165
160
  }
166
161
  if (!applying) {
167
162
  console.log('Commands in the approved setup plan:');
@@ -179,8 +174,20 @@ export function renderStartPreview(preview, options = {}) {
179
174
  console.log('Unresolved decisions:');
180
175
  for (const decision of preview.unresolvedDecisions) console.log(` ${decision}`);
181
176
  }
177
+ console.log('Details (optional):');
178
+ console.log(`Projected governed coverage: ${preview.projectedCoverage.percent ?? 'unknown'}% (${preview.projectedCoverage.classifiedFiles}/${preview.projectedCoverage.totalFiles} files)`);
179
+ const budget = preview.setupBudget;
180
+ const arkrulesNote =
181
+ budget.arkrulesFiles > 0 ? ` (+${budget.arkrulesFiles} arkrules)` : '';
182
+ const gateCount = budget.gateFiles ?? budget.files;
183
+ console.log(
184
+ `Compact setup budget: ${gateCount}/${budget.maxFiles} gate files${arkrulesNote}, ${budget.bytes}/${budget.maxBytes} bytes${budget.ok ? '' : ' (exceeded)'}.`
185
+ );
186
+ for (const change of preview.changes) {
187
+ console.log(` ${change.action.padEnd(6)} ${change.path} ${change.afterHash ?? '(deleted)'}`);
188
+ }
182
189
  if (!applying) {
183
- console.log('Review complete file contents with --json. Apply this plan with: ark start --apply');
190
+ console.log('Review complete file contents with --json.');
184
191
  }
185
192
  }
186
193
 
@@ -382,6 +382,11 @@ export function collectStatusFacts(options = {}) {
382
382
  : arkRulesLoaded
383
383
  ? 0
384
384
  : null,
385
+ leftoverDesignWork:
386
+ options.leftoverDesignWork === true ||
387
+ latest?.leftoverDesignWork === true ||
388
+ latest?.designFitness?.designWeak === true ||
389
+ latest?.doctor?.designFitness?.designWeak === true,
385
390
  improvementCompass,
386
391
  vsBase: (() => {
387
392
  const vsRef = typeof options.vs === 'string' ? options.vs.trim() : '';
@@ -230,6 +230,12 @@ export function resolveStatusNextAction(facts, binding, activation, lastCheck, r
230
230
  summary: 'Local write is advisory for this host — keep a required GitHub status on arkgate-check --strict-merge as the hard merge boundary.',
231
231
  };
232
232
  }
233
+ if (facts.leftoverDesignWork === true) {
234
+ return {
235
+ id: 'map-leftover-design',
236
+ summary: 'Leftover design work remains. Map with /ark-explore, then apply one small refactor with /ark-autopilot. Green imports are not done.',
237
+ };
238
+ }
233
239
  if (rules.arkRulesLoaded && (rules.frozenResidual ?? 0) > 0) {
234
240
  return {
235
241
  id: 'review-arkrules-residual',