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.
Files changed (78) hide show
  1. package/CHANGELOG.md +54 -1
  2. package/README.md +11 -5
  3. package/bin/ark-check-runtime.mjs +115 -128
  4. package/bin/ark-mcp-runtime.mjs +86 -48
  5. package/bin/ark.mjs +21 -78
  6. package/bin/lib/agent-projection.mjs +1 -1
  7. package/bin/lib/analysis-engine.mjs +3 -3
  8. package/bin/lib/ci-and-commands.mjs +11 -11
  9. package/bin/lib/config-contract.mjs +2 -0
  10. package/bin/lib/contract-smells.mjs +5 -5
  11. package/bin/lib/design-smells.mjs +1 -1
  12. package/bin/lib/doctor-advisories.mjs +9 -0
  13. package/bin/lib/doctor-next-actions.mjs +92 -0
  14. package/bin/lib/doctor-plan.mjs +61 -71
  15. package/bin/lib/field-install.mjs +1 -1
  16. package/bin/lib/first-run-help.mjs +221 -0
  17. package/bin/lib/html-report-advisories.mjs +20 -0
  18. package/bin/lib/improvement-compass-map.mjs +20 -20
  19. package/bin/lib/pilot-loop.mjs +1 -1
  20. package/bin/lib/post-green-path.mjs +2 -2
  21. package/bin/lib/prepare-change.mjs +9 -0
  22. package/bin/lib/product-copy.mjs +1 -1
  23. package/bin/lib/start-preview.mjs +17 -10
  24. package/bin/lib/status-command.mjs +19 -0
  25. package/bin/lib/status-manifest.mjs +23 -0
  26. package/bin/lib/team-parliament-io.mjs +338 -0
  27. package/bin/lib/team-parliament.mjs +383 -0
  28. package/bin/lib/upgrade-whats-new.mjs +16 -0
  29. package/bin/lib/violations.mjs +8 -4
  30. package/dist/{configTypes-CC0FEXoF.d.ts → configTypes-B8uIcLaG.d.ts} +5 -0
  31. package/dist/eslint/index.cjs +2 -2
  32. package/dist/eslint/index.d.ts +1 -1
  33. package/dist/eslint/index.js +2 -2
  34. package/dist/index.cjs +8 -8
  35. package/dist/index.d.ts +66 -2
  36. package/dist/index.js +8 -8
  37. package/docs/README.md +5 -5
  38. package/docs/agent-guide.md +21 -17
  39. package/docs/configuration.md +36 -2
  40. package/docs/develop.md +13 -1
  41. package/docs/enthusiast/README.md +1 -1
  42. package/docs/enthusiast/how-to-agent-gates.md +3 -3
  43. package/docs/enthusiast/how-to-pick-shape.md +2 -2
  44. package/docs/enthusiast/tutorial-first-project.md +4 -3
  45. package/docs/package-surface.md +5 -3
  46. package/docs/product-voice.md +48 -10
  47. package/docs/use.md +10 -5
  48. package/package.json +2 -2
  49. package/schemas/ark.config.schema.json +9 -0
  50. package/schemas/ark.status-manifest.schema.json +51 -0
  51. package/server.json +3 -3
  52. package/templates/agent-skills/README.md +1 -1
  53. package/templates/agent-skills/ark-adopt/SKILL.md +59 -23
  54. package/templates/agent-skills/ark-architect/SKILL.md +24 -145
  55. package/templates/agent-skills/ark-autopilot/SKILL.md +49 -32
  56. package/templates/agent-skills/ark-contract/SKILL.md +21 -105
  57. package/templates/agent-skills/ark-coverage/SKILL.md +7 -3
  58. package/templates/agent-skills/ark-explain/SKILL.md +8 -4
  59. package/templates/agent-skills/ark-explore/SKILL.md +38 -21
  60. package/templates/agent-skills/ark-fix/SKILL.md +34 -157
  61. package/templates/agent-skills/ark-loop/SKILL.md +31 -153
  62. package/templates/agent-skills/ark-place/SKILL.md +35 -14
  63. package/templates/agent-skills/ark-runtime/SKILL.md +3 -3
  64. package/templates/agent-skills/ark-think/SKILL.md +6 -2
  65. package/templates/agent-skills/ark-upgrade/SKILL.md +21 -10
  66. package/templates/skills/ark-adopt.md +59 -23
  67. package/templates/skills/ark-architect.md +24 -145
  68. package/templates/skills/ark-autopilot.md +49 -32
  69. package/templates/skills/ark-contract.md +21 -105
  70. package/templates/skills/ark-coverage.md +7 -3
  71. package/templates/skills/ark-explain.md +8 -4
  72. package/templates/skills/ark-explore.md +38 -21
  73. package/templates/skills/ark-fix.md +34 -157
  74. package/templates/skills/ark-loop.md +31 -153
  75. package/templates/skills/ark-place.md +35 -14
  76. package/templates/skills/ark-runtime.md +3 -3
  77. package/templates/skills/ark-think.md +6 -2
  78. package/templates/skills/ark-upgrade.md +21 -10
@@ -73,6 +73,8 @@ import {
73
73
  } from './lib/prepare-change.mjs';
74
74
  import { detectWritePathCapabilities } from './lib/write-path-detect.mjs';
75
75
  import { collectGovernedFiles, isGovernableSourceFile } from './lib/scan-files.mjs';
76
+ import { classifyChangeSet, evaluateTeamGate } from './lib/team-parliament.mjs';
77
+ import { contractSessionFrom } from './lib/team-parliament-io.mjs';
76
78
  import {
77
79
  canonicalizeCandidateChanges,
78
80
  resolvedCompilerInputPaths,
@@ -641,6 +643,25 @@ function emitHostAllow(output, { antigravityStyle, cursorStyle }) {
641
643
  emitCursorAllow(output, cursorStyle);
642
644
  }
643
645
 
646
+ /**
647
+ * Socket-style write-gate deny: two lines first. Pass/fail, no score.
648
+ * Rule id stays on a following line, not the first sentence.
649
+ */
650
+ function formatWriteGateDeny({ file, reason, ruleId, nextAction, extraLines = [] }) {
651
+ const target = file || 'this write';
652
+ const why = String(reason || 'this change breaks the architecture layers').replace(/\s+/g, ' ').trim();
653
+ const next =
654
+ nextAction && /place|move|import|port/i.test(nextAction)
655
+ ? nextAction
656
+ : 'Move the import or run /ark-place. Do not weaken ark.config.json.';
657
+ const lines = [`blocked ${target} — ${why}`, `Next: ${next}`];
658
+ if (ruleId) lines.push(`[${ruleId}]`);
659
+ for (const extra of extraLines) {
660
+ if (extra) lines.push(extra);
661
+ }
662
+ return lines.join('\n');
663
+ }
664
+
644
665
  function runHookPayload(payload, gate, config, args, ts, attemptContext, output = processHookOutput()) {
645
666
  const { toolName, toolInput, grokStyle, antigravityStyle, cursorStyle, operation } =
646
667
  normalizeHookPayload(
@@ -657,6 +678,20 @@ function runHookPayload(payload, gate, config, args, ts, attemptContext, output
657
678
  return;
658
679
  }
659
680
  const patchWrites = parsedPatch.writes;
681
+ const patchChangeSet = classifyChangeSet(patchWrites.map((change) => String(change.path)));
682
+ const patchLawGate = evaluateTeamGate({
683
+ changeSet: patchChangeSet,
684
+ contractSession: contractSessionFrom({}),
685
+ });
686
+ if (patchLawGate.deny && patchChangeSet.mixed) {
687
+ const message = patchLawGate.message;
688
+ output.stderr(`Ark architecture gate: ${message}\n`);
689
+ if (grokStyle) {
690
+ output.stdout(`${JSON.stringify({ decision: 'deny', reason: message })}\n`);
691
+ }
692
+ output.status(2);
693
+ return;
694
+ }
660
695
  const sourceWrites = patchWrites.filter((change) =>
661
696
  isGovernableSourceFile(path.basename(String(change.path)))
662
697
  );
@@ -780,17 +815,20 @@ function runHookPayload(payload, gate, config, args, ts, attemptContext, output
780
815
  emitHostAllow(output, { antigravityStyle, cursorStyle });
781
816
  return;
782
817
  }
783
- const message = [
784
- `Ark architecture gate blocked this complete ${toolName} (${changes.length} governed file(s)):`,
785
- ...result.diagnostics.map(
786
- (diagnostic) =>
787
- `- [${diagnostic.ruleId}] ${diagnostic.message}\n Next action: ${diagnostic.nextAction}`
788
- ),
789
- ...(designDelta && !designDelta.valid
790
- ? formatDesignDeltaBlock(designDelta).split('\n').slice(1)
791
- : []),
792
- 'No project file was written. Fix the complete patch and retry.',
793
- ].join('\n');
818
+ const first = result.diagnostics[0];
819
+ const message = formatWriteGateDeny({
820
+ file: `${changes.length} file(s)`,
821
+ reason: first?.message || `this ${toolName} breaks the architecture layers`,
822
+ ruleId: first?.ruleId,
823
+ nextAction: first?.nextAction,
824
+ extraLines: [
825
+ ...result.diagnostics.slice(1).map((d) => `[${d.ruleId}] ${d.message}`),
826
+ ...(designDelta && !designDelta.valid
827
+ ? formatDesignDeltaBlock(designDelta).split('\n').slice(1)
828
+ : []),
829
+ 'No project file was written. Fix the complete patch and retry.',
830
+ ],
831
+ });
794
832
  output.stderr(`${message}\n`);
795
833
  if (args.hookRepair) {
796
834
  output.stderr(
@@ -910,13 +948,7 @@ function runHookPayload(payload, gate, config, args, ts, attemptContext, output
910
948
  })),
911
949
  });
912
950
 
913
- const lines = adapterResult.diagnostics.map(
914
- (diagnostic) =>
915
- `- [${diagnostic.ruleId}] ${diagnostic.message}${diagnostic.location.line ? ` (line ${diagnostic.location.line})` : ''}\n Next action: ${diagnostic.nextAction}`
916
- );
917
- // Surface the per-violation fix hints (the gate carries them in `suggestion`,
918
- // but the hook was dropping them). Dedupe so two infra violations sharing one
919
- // hint — e.g. the mayImportInfrastructure escape hatch — print it once.
951
+ const firstDiagnostic = adapterResult.diagnostics[0];
920
952
  const suggestions = [
921
953
  ...new Set(combinedViolations.map((violation) => violation.suggestion).filter(Boolean)),
922
954
  ];
@@ -924,27 +956,34 @@ function runHookPayload(payload, gate, config, args, ts, attemptContext, output
924
956
  // W4: structured repair payload is opt-in (--hook-repair / ARK_HOOK_REPAIR).
925
957
  // Default remains hard block with prose only — hosts that cannot re-inject stay clean.
926
958
  const repair = Boolean(args.hookRepair);
927
- const message = [
928
- `Ark architecture gate blocked this write to ${rel}${layer ? ` (layer: ${layer})` : ''}:`,
929
- ...lines,
930
- ...(suggestions.length > 0 ? ['Fix:', ...suggestions.map((s) => ` ${s}`)] : []),
931
- ...(autoPatch && repair
932
- ? [
933
- `autoPatch available (${autoPatch.remediationKind}, confidence ${autoPatch.confidence}): ` +
934
- 'apply the patched source from ARK_AUTOPATCH_JSON / ARK_REPAIR_JSON on stderr' +
935
- (grokStyle ? ' (or autoPatch in the deny JSON on stdout)' : '') +
936
- ' instead of re-drafting. Gate still denies this write (never silent apply).',
937
- ]
938
- : []),
939
- ...(autoPatch && !repair
940
- ? [
941
- `Mechanical-safe autoPatch is available (${autoPatch.remediationKind}). ` +
942
- 'Enable repair payload with ARK_HOOK_REPAIR=1 or --hook-repair to receive ' +
943
- 'machine-readable source (still hard-blocks; host re-injects).',
944
- ]
945
- : []),
946
- 'Fix the violations and retry. Call the project-bound ark_manifest MCP tool for the architecture contract.',
947
- ].join('\n');
959
+ const message = formatWriteGateDeny({
960
+ file: rel,
961
+ reason: firstDiagnostic?.message || (layer ? `${layer} write breaks the layers` : 'this write breaks the layers'),
962
+ ruleId: firstDiagnostic?.ruleId,
963
+ nextAction: firstDiagnostic?.nextAction,
964
+ extraLines: [
965
+ ...adapterResult.diagnostics.slice(1).map(
966
+ (diagnostic) =>
967
+ `[${diagnostic.ruleId}] ${diagnostic.message}${diagnostic.location.line ? ` (line ${diagnostic.location.line})` : ''}`
968
+ ),
969
+ ...(suggestions.length > 0 ? suggestions.map((s) => `Fix: ${s}`) : []),
970
+ ...(autoPatch && repair
971
+ ? [
972
+ `autoPatch available (${autoPatch.remediationKind}, confidence ${autoPatch.confidence}): ` +
973
+ 'apply the patched source from ARK_AUTOPATCH_JSON / ARK_REPAIR_JSON on stderr' +
974
+ (grokStyle ? ' (or autoPatch in the deny JSON on stdout)' : '') +
975
+ ' instead of re-drafting. Gate still denies this write (never silent apply).',
976
+ ]
977
+ : []),
978
+ ...(autoPatch && !repair
979
+ ? [
980
+ `Mechanical-safe autoPatch is available (${autoPatch.remediationKind}). ` +
981
+ 'Enable repair payload with ARK_HOOK_REPAIR=1 or --hook-repair to receive ' +
982
+ 'machine-readable source (still hard-blocks; host re-injects).',
983
+ ]
984
+ : []),
985
+ ],
986
+ });
948
987
  output.stderr(message + '\n');
949
988
 
950
989
  if (repair) {
@@ -1387,7 +1426,7 @@ function printSessionContext(config, profile, forbiddenGlobals, args, configPath
1387
1426
  const governedPercent = coverage?.coverage?.governed?.percent ?? coverage?.governed?.percent;
1388
1427
  if (shouldShowNewHereNudge(args.root, configPath, governedPercent, false)) {
1389
1428
  lines.push('');
1390
- lines.push('New to Ark? Run /ark-architect or: ark-check --recommend');
1429
+ lines.push('New to Ark? /ark-adopt or: arkgate-check --doctor');
1391
1430
  }
1392
1431
 
1393
1432
  process.stdout.write(`${lines.join('\n')}\n`);
@@ -2002,9 +2041,9 @@ export async function runArkMcp({ hookInput } = {}) {
2002
2041
  {
2003
2042
  name: 'ark_identity',
2004
2043
  description:
2005
- 'Return the canonical ArkGate project, config, contract, and live MCP runtime identity. ' +
2006
- 'Pass project.expectedRoot and/or expectedProjectId to verify this process before ' +
2007
- 'trusting any architecture evidence.',
2044
+ 'First call. Prove this MCP process is the right project: pass project.expectedRoot ' +
2045
+ '(exact absolute root) and reuse the returned projectId. Do this before any other Ark tool. ' +
2046
+ 'A missing, unmatched, or different root means restart the host and use the local CLI.',
2008
2047
  inputSchema: { type: 'object', properties: {} },
2009
2048
  },
2010
2049
  {
@@ -2047,11 +2086,10 @@ export async function runArkMcp({ hookInput } = {}) {
2047
2086
  {
2048
2087
  name: 'ark_check',
2049
2088
  description:
2050
- 'Run the full Ark architecture check on the project and return structured results ' +
2051
- '(layer-import violations, forbidden globals, circular deps, config warnings). Use ' +
2052
- 'this to answer "is the architecture currently valid?" instead of shelling out to ' +
2053
- 'ark-check. Preserves legacy ok and adds identity/completeness/graph/coverage/gates/' +
2054
- 'overall verdicts. Applies the baseline automatically when one exists. isError when not ok.',
2089
+ 'Scan the project for architecture findings (layer-import violations, forbidden globals, ' +
2090
+ 'cycles, config warnings). Returns pass/fail/incomplete plus evidence — not a yes/no ' +
2091
+ 'architecture score. Same engine as arkgate-check. Applies the baseline when one exists. ' +
2092
+ 'isError when the scan fails. Prefer after ark_identity.',
2055
2093
  inputSchema: {
2056
2094
  type: 'object',
2057
2095
  properties: {
package/bin/ark.mjs CHANGED
@@ -35,6 +35,7 @@ import {
35
35
  } from './lib/prepare-change.mjs';
36
36
  import { runStatusCommand } from './lib/status-command.mjs';
37
37
  import { runAgentProjectionCommand } from './lib/agent-projection-command.mjs';
38
+ import { setupUsage, setupUsageAll, upgradeUsage } from './lib/first-run-help.mjs';
38
39
 
39
40
  const here = path.dirname(fileURLToPath(import.meta.url));
40
41
  const arkCheck = path.join(here, 'ark-check.mjs');
@@ -90,13 +91,14 @@ function parseArgs(argv) {
90
91
  check: false,
91
92
  stdout: false,
92
93
  help: false,
94
+ all: false,
93
95
  version: false,
94
96
  };
95
97
 
96
98
  const requireValue = (flag, index) => {
97
99
  const value = argv[index + 1];
98
100
  if (value === undefined || value.startsWith('-')) {
99
- throw new Error(`Missing value for ${flag}. Run ark --help for usage.`);
101
+ throw new Error(`Missing value for ${flag}. Run arkgate --help for usage.`);
100
102
  }
101
103
  return value;
102
104
  };
@@ -138,83 +140,20 @@ function parseArgs(argv) {
138
140
  }
139
141
  else if (arg === '--expected-root') args.expectedRoot = path.resolve(requireValue(arg, i++));
140
142
  else if (arg === '--expected-project-id') args.expectedProjectId = requireValue(arg, i++);
143
+ else if (arg === '--vs') args.vs = requireValue(arg, i++);
141
144
  else if (arg === '--write') args.write = true;
142
145
  else if (arg === '--check') args.check = true;
143
146
  else if (arg === '--stdout') args.stdout = true;
144
147
  else if (arg === '--help' || arg === '-h' || arg === 'help') args.help = true;
148
+ else if (arg === '--all') args.all = true;
145
149
  else if (arg === '--version' || arg === '-V') args.version = true;
146
150
  else if (!arg.startsWith('-') && args.command === undefined) args.command = arg;
147
- else throw new Error(`Unknown argument: ${arg}. Run ark --help for usage.`);
151
+ else throw new Error(`Unknown argument: ${arg}. Run arkgate --help for usage.`);
148
152
  }
149
153
 
150
154
  return args;
151
155
  }
152
156
 
153
- function usage() {
154
- return `Usage:
155
- ark start [--root <project>] [--tools <host>] [--require-write-hook <host>] [--install] [--apply] [--json]
156
- ark init [--root <project>] [--preset hexagonal|layered|feature-sliced|monorepo|ui-surface|vertical-slice|ddd-bounded-contexts|clean-architecture|onion-architecture]
157
- [--archetype <playbook-id>] [--tools <list>] [--require-write-hook <host>] [--yes] [--force] [--no-strict]
158
- ark upgrade [--root <project>] [--tools <list>] [--apply] [--plan-digest <sha256>] [--accept-conflicts] [--refresh-skills] [--json] [--no-install] [--no-strict]
159
- ark preflight --changes <change-set.json> [--change-map <map.json>] [--root <project>] [--config ark.config.json] [--manifest <manifest.json>] [--tsconfig <tsconfig.json>] [--json]
160
- ark status [--root <project>] [--config ark.config.json] [--json]
161
- [--expected-root <abs>] [--expected-project-id sha256:…] [--tools <host>]
162
- ark agents-md [--root <project>] [--config ark.config.json] [--write] [--check] [--stdout] [--json]
163
- [--tools <host>]
164
-
165
- Commands:
166
- start New here? Analyze and preview the complete setup. Read-only unless --apply.
167
- init Configure Ark project enforcement with explicit prompts.
168
- upgrade Preview identity-proven Ark-managed asset updates. With package install,
169
- --apply bumps toward registry latest when behind (not only when CLI ≠ pin)
170
- and recomputes the preview; a second explicit --apply --no-install applies
171
- those exact bytes and verifies them. --refresh-skills opts in to rewrite
172
- customized managed skills to package templates (never silent default).
173
- (alias: ark update)
174
- preflight Validate one atomic create/update/delete set without writing project files.
175
- status Unified session/project manifest (identity, activation, last check, rules).
176
- Never prompts. Prefer --json for agents; CI=1 forces JSON.
177
- agents-md Version-matched agent contract projection (ACS04). Stamps package version +
178
- contract summary into a managed AGENTS.md block. Non-authoritative — not a
179
- gate input. Preview by default; --write merges without clobbering outside
180
- regions; --check fails on version drift; --stdout prints the block only.
181
- (aliases: agents-md, agent-projection)
182
-
183
- Options:
184
- --yes Non-interactive defaults: create config if needed, install gate templates, run strict check.
185
- (Also the implicit default when stdin/stdout are not a TTY — agents never hang on prompts.)
186
- --force Allow generated files to overwrite existing files.
187
- --no-strict Skip the final strict ark-check run.
188
- --install Pin and install arkgate as a project devDependency (default for start).
189
- --no-install Skip adding/installing arkgate as a project devDependency (start/upgrade).
190
- --apply Apply a start plan; for upgrade, update/repreview or apply managed bytes.
191
- --accept-conflicts
192
- Allow upgrade to recreate deleted managed assets or replace recorded conflicts.
193
- --plan-digest Digest emitted by an upgrade preview; required to apply managed bytes.
194
- --json Emit the start/upgrade/status/agents-md preview as deterministic machine-readable JSON.
195
- --write For agents-md: merge the version-matched projection into AGENTS.md.
196
- --check For agents-md: exit 1 when projection stamp drifts from package version.
197
- --stdout For agents-md: print the projection block only (no file write).
198
- --expected-root / --expected-project-id
199
- Optional project expectation for status (MCP-compatible binding check).
200
- --preset Start from a named architecture preset instead of detection.
201
- --archetype Application shape from templates/architecture-playbook.json (maps to the matching preset).
202
- Valid ids: crud-product, api-backend, frontend-surface, library-sdk, cli-utility,
203
- worker-pipeline, event-coordinator, integration-bridge, multi-app-workspace, prototype-spike,
204
- vertical-slice-product, ddd-bounded-contexts.
205
- --tools One active agent host for start (claude,cursor,codex,grok,windsurf,cline,copilot,kiro,roo,continue,gemini).
206
- Omit to use the active host; an unknown host creates only the shared compact router.
207
- --remove-host <host>
208
- Preview or apply removal of that compact host integration; re-add it with --tools <host>.
209
- --require-write-hook <host>
210
- Require and verify a hard local write hook for Claude, Grok, Antigravity, or Cursor.
211
- Codex/OpenCode are advisory-write plus hard CI merge only; impossible requests fail before any write.
212
-
213
- Interactive mode (TTY, no --yes): asks what application shape you are building and maps it to a preset.
214
- Non-interactive (no TTY): uses the same defaults as --yes — never calls readline on a null interface.
215
- `;
216
- }
217
-
218
157
  function cliVersion() {
219
158
  try {
220
159
  const pkg = JSON.parse(fs.readFileSync(path.join(here, '..', 'package.json'), 'utf8'));
@@ -795,23 +734,22 @@ async function start(args) {
795
734
  }
796
735
  console.log('');
797
736
  console.log('Next (the only flow you need):');
737
+ console.log(` 1. Status: ${arkCommand(root, 'arkgate-check', '--doctor')} — do primary next action #1`);
798
738
  if (falseGreenGap) {
799
- console.log(' 1. In your agent: /ark-adopt (or /ark-contract) — fix the contract first');
800
- console.log(' → reclassify I/O dirs out of Application; then /ark-autopilot for residual debt.');
739
+ console.log(' 2. Session 0 in your agent: /ark-adopt — fix the architecture config first');
740
+ console.log(' → reclassify I/O dirs out of Application; leftover design later via /ark-explore then /ark-autopilot.');
801
741
  } else {
802
- console.log(' 1. In your agent: /ark-autopilot');
803
- console.log(' → explore first, dual plan (remediation + pattern bets), safe fixes, leave gates on.');
742
+ console.log(' 2. Session 0 in your agent: /ark-adopt');
743
+ console.log(' → mark the path (greenfield or brownfield). Day-to-day new files: /ark-place.');
804
744
  }
805
- console.log(` 2. Status anytime: ${arkCommand(root, 'ark-check', '--doctor')}`);
806
- console.log(` 3. After edits: ${arkCommand(root, 'ark-check', '--root . --config ark.config.json --strict-merge')}`);
745
+ console.log(` 3. After edits: ${arkCommand(root, 'arkgate-check', '--root . --config ark.config.json --strict-merge')}`);
807
746
  if (mode === 'adapt' && planOk && !falseGreenGap) {
808
747
  console.log(
809
- ` 4. When green but cores still optional: ${arkCommand(root, 'ark-check', '--ratchet-cores')} → honest ENFORCE`
748
+ ` 4. When green but cores still optional: ${arkCommand(root, 'arkgate-check', '--ratchet-cores')} → honest ENFORCE`
810
749
  );
811
750
  }
812
751
  console.log('');
813
- console.log('Optional later: ark-check --report ark-report.html (captures a day-zero/evolution report).');
814
- console.log('Optional later: --plan · --coverage · /ark-explore · /ark-fix · /ark-place · ark upgrade');
752
+ console.log('Optional later: leftover design → /ark-explore then /ark-autopilot; bump arkgate upgrade.');
815
753
  return 0;
816
754
  } finally {
817
755
  rl?.close();
@@ -830,8 +768,12 @@ async function main() {
830
768
  console.log(cliVersion());
831
769
  return 0;
832
770
  }
771
+ if (args.help && (args.command === 'upgrade' || args.command === 'update')) {
772
+ console.log(upgradeUsage());
773
+ return 0;
774
+ }
833
775
  if (args.help || !args.command) {
834
- console.log(usage());
776
+ console.log(args.all ? setupUsageAll() : setupUsage());
835
777
  return 0;
836
778
  }
837
779
 
@@ -941,6 +883,7 @@ async function main() {
941
883
  expectedProjectId: args.expectedProjectId,
942
884
  host: args.tools,
943
885
  arkgateVersion: cliVersion(),
886
+ vs: args.vs,
944
887
  });
945
888
  }
946
889
 
@@ -959,7 +902,7 @@ async function main() {
959
902
  }
960
903
 
961
904
  console.error(`Unknown command: ${args.command}`);
962
- console.error(usage());
905
+ console.error(setupUsage());
963
906
  return 2;
964
907
  }
965
908
 
@@ -151,7 +151,7 @@ export function buildAgentProjectionBody(facts) {
151
151
  lines.push('### Primary path', '', '1. Run doctor (`ark-check --doctor`) — status light + primary next action.', '2. Read the improvement compass (not a score). Name leftover work in plain language; never “done” on green imports alone while leftover design work remains.', '3. Call `ark_identity` with `project.expectedRoot` at the exact project root; reuse root + `projectId` on Ark MCP calls.', '4. Read architecture config with `ark_manifest` (same expectation). `ark://manifest` is compatibility-only / unverified.', '5. Place files inside configured layers; validate; run the check command above on violations — fix architecture, do not weaken the gate.', '6. Single door: import-rule debt → fix; leftover design work / residual shape lenses → map then guided apply with user OK.', '', '### Contract layers (summary)', '', formatAgentProjectionLayers(layers), '');
152
152
  }
153
153
  else {
154
- lines.push('### Contract layers', '', formatAgentProjectionLayers(layers), '', 'When creating a **new** kind of code that no layer covers, update `ark.config.json` first (`/ark-contract`), then place the file.', '', '### Diagnostic codes (short list)', '', formatAgentProjectionCatalogShortList(catalog, docsPath), '', '### Session truth', '', '- Machine snapshot: `ark status --json` (or MCP `ark_status`) — identity, activation honesty, last check, residual counts. **Not a score.**', '- Authoritative contract: `ark_manifest` after a matched `ark_identity` handshake.', '');
154
+ lines.push('### Contract layers', '', formatAgentProjectionLayers(layers), '', 'When creating a **new** kind of code that no layer covers, update `ark.config.json` first (`/ark-adopt`), then place the file.', '', '### Diagnostic codes (short list)', '', formatAgentProjectionCatalogShortList(catalog, docsPath), '', '### Session truth', '', '- Machine snapshot: `ark status --json` (or MCP `ark_status`) — identity, activation honesty, last check, residual counts. **Not a score.**', '- Authoritative contract: `ark_manifest` after a matched `ark_identity` handshake.', '');
155
155
  }
156
156
  lines.push('### Enforcement surfaces (authoritative)', '', AGENT_PROJECTION_ENFORCEMENT_SURFACES.map((surface) => `- \`${surface}\``).join('\n'), '');
157
157
  return lines.join('\n').replace(/\n{3,}/g, '\n\n').trimEnd() + '\n';