arkgate 2.12.0 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/README.md +55 -31
  3. package/bin/ark-check.mjs +95 -36
  4. package/bin/ark-mcp.mjs +11 -5
  5. package/bin/ark-shared.mjs +88 -56
  6. package/bin/ark.mjs +45 -10
  7. package/bin/lib/agent-gates.mjs +12 -0
  8. package/bin/lib/architecture-scan.mjs +8 -0
  9. package/bin/lib/ci-and-commands.mjs +9 -3
  10. package/bin/lib/codex-home.mjs +7 -0
  11. package/bin/lib/config-contract.mjs +331 -0
  12. package/bin/lib/doctor-plan.mjs +43 -16
  13. package/bin/lib/enforcement-profiles.mjs +97 -0
  14. package/bin/lib/host-support-matrix.mjs +77 -0
  15. package/bin/lib/install-migrate.mjs +45 -14
  16. package/bin/lib/mcp-adoption.mjs +35 -3
  17. package/bin/lib/open-html.mjs +75 -0
  18. package/bin/lib/presets.mjs +3 -2
  19. package/bin/lib/safety-diagnostics.mjs +31 -11
  20. package/bin/lib/skill-install.mjs +64 -0
  21. package/bin/lib/ts-resolve.mjs +2 -1
  22. package/bin/lib/weakest-link.mjs +417 -0
  23. package/bin/lib/write-path-capabilities.mjs +182 -0
  24. package/bin/lib/write-path-detect.mjs +62 -99
  25. package/dist/configContract-iBLxx5Tz.d.cts +53 -0
  26. package/dist/configContract-iBLxx5Tz.d.ts +53 -0
  27. package/dist/eslint/index.cjs +375 -13
  28. package/dist/eslint/index.cjs.map +1 -1
  29. package/dist/eslint/index.d.cts +30 -20
  30. package/dist/eslint/index.d.ts +30 -20
  31. package/dist/eslint/index.js +375 -13
  32. package/dist/eslint/index.js.map +1 -1
  33. package/dist/index.cjs +723 -61
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.cts +95 -5
  36. package/dist/index.d.ts +95 -5
  37. package/dist/index.js +716 -61
  38. package/dist/index.js.map +1 -1
  39. package/dist/nestjs/index.cjs +150 -42
  40. package/dist/nestjs/index.cjs.map +1 -1
  41. package/dist/nestjs/index.d.cts +2 -1
  42. package/dist/nestjs/index.d.ts +2 -1
  43. package/dist/nestjs/index.js +150 -42
  44. package/dist/nestjs/index.js.map +1 -1
  45. package/dist/runtime/index.cjs +723 -61
  46. package/dist/runtime/index.cjs.map +1 -1
  47. package/dist/runtime/index.d.cts +3 -2
  48. package/dist/runtime/index.d.ts +3 -2
  49. package/dist/runtime/index.js +716 -61
  50. package/dist/runtime/index.js.map +1 -1
  51. package/dist/{types-BZ17b9i5.d.cts → types-BxBwnBpC.d.cts} +9 -36
  52. package/dist/{types-BZ17b9i5.d.ts → types-Wcs_l1_J.d.ts} +9 -36
  53. package/docs/agent-guide.md +32 -20
  54. package/docs/ai-gates.md +53 -18
  55. package/docs/configuration.md +97 -0
  56. package/docs/enthusiast/README.md +3 -3
  57. package/docs/enthusiast/how-to-agent-gates.md +7 -3
  58. package/docs/migrate-from-ark-runtime-kernel.md +3 -0
  59. package/docs/package-surface.md +14 -9
  60. package/docs/production-hardening.md +15 -2
  61. package/docs/threat-model.md +65 -0
  62. package/docs/typescript-support.md +3 -3
  63. package/package.json +15 -2
  64. package/schemas/ark.config.schema.json +750 -0
  65. package/server.json +2 -2
  66. package/templates/hooks/pre-commit-ark +37 -0
  67. package/templates/skills/ark-coverage.md +2 -2
  68. package/templates/skills/ark-runtime.md +8 -5
  69. package/templates/skills/ark-upgrade.md +36 -16
  70. package/tests/fixtures/ts-consumer/ark.config.json +2 -0
@@ -1,118 +1,63 @@
1
1
  /**
2
- * W5 — Write-path capability surface for doctor (stable additive JSON).
3
- * Extracted from agent-gates so install orchestration stays scannable.
2
+ * Active-host write-path capability surface for doctor and install checks.
4
3
  *
5
- * Detects whether installed agent gates expose:
6
- * - MCP prepare-write / validate_code (autoPatch) tools
7
- * - PreToolUse hook in reject-only vs repair mode (--hook-repair / ARK_HOOK_REPAIR)
8
- *
9
- * Never claims silent apply; "repair" means host can re-inject a patch after hard deny.
4
+ * `inventory` records every supported host found in the repository. Top-level
5
+ * capabilities and compatibility fields describe only `activeHost`, so a
6
+ * Claude/Grok hook can never become a Codex/Cursor guarantee.
10
7
  */
11
- import fs from 'node:fs';
12
- import path from 'node:path';
13
8
  import { arkCommand } from '../ark-shared.mjs';
9
+ import { formatHostSupportSummary } from './host-support-matrix.mjs';
10
+ import { buildWritePathCapabilityModel } from './write-path-capabilities.mjs';
14
11
 
15
- /**
16
- * @returns {{
17
- * mode: 'repair' | 'reject-only' | 'mcp-only' | 'none',
18
- * prepareWrite: boolean,
19
- * autoPatch: boolean,
20
- * hookPresent: boolean,
21
- * hookRepair: boolean,
22
- * mcpPresent: boolean,
23
- * evidence: string[],
24
- * gap: null | { id: string, severity: string, message: string, fix: string },
25
- * }}
26
- */
27
- export function detectWritePathCapabilities(root) {
28
- const evidence = [];
29
- let hookPresent = false;
30
- let hookRepair = false;
31
-
32
- const hookFiles = [
33
- '.claude/settings.json',
34
- '.grok/hooks/ark-write-gate.json',
35
- ];
36
- for (const rel of hookFiles) {
37
- const abs = path.join(root, rel);
38
- if (!fs.existsSync(abs)) continue;
39
- let text = '';
40
- try {
41
- text = fs.readFileSync(abs, 'utf8');
42
- } catch {
43
- continue;
44
- }
45
- // PreToolUse / write-gate command referencing ark(-gate)?-mcp --hook
46
- if (
47
- /--hook\b/.test(text) ||
48
- /\b(ark|arkgate)-mcp\b[\s\S]{0,80}--hook\b/.test(text) ||
49
- /\b--hook\b[\s\S]{0,80}\b(ark|arkgate)-mcp\b/.test(text)
50
- ) {
51
- hookPresent = true;
52
- evidence.push(rel);
53
- }
54
- if (
55
- /--hook-repair\b/.test(text) ||
56
- /ARK_HOOK_REPAIR\s*=\s*['"]?(1|true|yes|on)/i.test(text)
57
- ) {
58
- hookRepair = true;
59
- if (!evidence.includes(rel)) evidence.push(rel);
60
- }
61
- }
62
-
63
- let mcpPresent = false;
64
- const mcpFiles = ['.mcp.json', '.cursor/mcp.json', '.grok/config.toml'];
65
- for (const rel of mcpFiles) {
66
- const abs = path.join(root, rel);
67
- if (!fs.existsSync(abs)) continue;
68
- let text = '';
69
- try {
70
- text = fs.readFileSync(abs, 'utf8');
71
- } catch {
72
- continue;
73
- }
74
- if (
75
- /\b(ark|arkgate)-mcp\b/.test(text) ||
76
- /mcp_servers\.ark\b/.test(text) ||
77
- /"ark"\s*:\s*\{/.test(text) ||
78
- /mcpServers[\s\S]*\bark\b/.test(text)
79
- ) {
80
- mcpPresent = true;
81
- evidence.push(rel);
82
- }
83
- }
12
+ function installToolsForHost(activeHost) {
13
+ return activeHost === 'unknown'
14
+ ? 'claude,grok,cursor,codex'
15
+ : activeHost;
16
+ }
84
17
 
85
- // Package tools when MCP is wired: ark_prepare_write + validate_code(autoPatch).
86
- // Hook repair emits machine-readable autoPatch without silent write.
87
- const prepareWrite = mcpPresent;
88
- const autoPatch = mcpPresent || hookRepair;
18
+ export function detectWritePathCapabilities(root, explicitHost) {
19
+ const model = buildWritePathCapabilityModel(root, explicitHost);
20
+ const { activeHost, support, capabilities, capabilityEvidence, inventory } = model;
21
+ const hardWrite = capabilities['hard-write'];
22
+ const advisoryWrite = capabilities['advisory-write'];
23
+ const repairPayload = capabilities['repair-payload'];
89
24
 
90
25
  /** @type {'repair' | 'reject-only' | 'mcp-only' | 'none'} */
91
26
  let mode = 'none';
92
- if (hookPresent && hookRepair) mode = 'repair';
93
- else if (hookPresent && !hookRepair) mode = 'reject-only';
94
- else if (mcpPresent) mode = 'mcp-only';
27
+ if (hardWrite && repairPayload) mode = 'repair';
28
+ else if (hardWrite) mode = 'reject-only';
29
+ else if (advisoryWrite) mode = 'mcp-only';
95
30
 
31
+ const tools = installToolsForHost(activeHost);
96
32
  let gap = null;
97
33
  if (mode === 'none') {
98
34
  gap = {
99
35
  id: 'write-path-none',
100
36
  severity: 'warn',
101
37
  message:
102
- 'Write path is not installed no PreToolUse hook and no Ark MCP. Agents write without architecture gate or prepare-write.',
103
- fix: arkCommand(root, 'ark-check', '--install-agent-gates'),
38
+ `Active host ${activeHost} has no hard write boundary or advisory Ark MCP. ` +
39
+ (capabilities['merge-gate']
40
+ ? 'The CI check remains separate and does not block local writes.'
41
+ : 'No Ark CI check was detected either.'),
42
+ fix: arkCommand(
43
+ root,
44
+ 'ark-check',
45
+ `--install-agent-gates --tools ${tools}`
46
+ ),
104
47
  };
105
48
  } else if (mode === 'reject-only') {
106
49
  gap = {
107
50
  id: 'write-path-reject-only',
108
51
  severity: 'info',
109
- message: mcpPresent
110
- ? 'PreToolUse hook is reject-only (hard block, no ARK_REPAIR_JSON). MCP still exposes prepare-write/autoPatch — enable --hook-repair so the write boundary itself can re-inject patches.'
111
- : 'Write path is reject-only (hard block with prose; no repair payload). Enable --hook-repair or ARK_HOOK_REPAIR=1 so hosts can re-inject patches without full re-draft.',
52
+ message:
53
+ `Active host ${activeHost} has a hard write boundary without a repair payload. ` +
54
+ (advisoryWrite
55
+ ? 'Advisory MCP tools remain available.'
56
+ : 'Install its MCP surface or enable hook repair for guided re-entry.'),
112
57
  fix: arkCommand(
113
58
  root,
114
59
  'ark-check',
115
- '--install-agent-gates --tools claude,grok --force'
60
+ `--install-agent-gates --tools ${tools} --force`
116
61
  ),
117
62
  };
118
63
  } else if (mode === 'mcp-only') {
@@ -120,19 +65,37 @@ export function detectWritePathCapabilities(root) {
120
65
  id: 'write-path-mcp-only',
121
66
  severity: 'info',
122
67
  message:
123
- 'MCP exposes prepare-write / autoPatch tools, but no PreToolUse write hook is installed — enforcement is advisory unless the agent calls tools.',
124
- fix: arkCommand(root, 'ark-check', '--install-agent-gates --tools claude,grok'),
68
+ `Active host ${activeHost} has advisory prepare-write/autoPatch tools, ` +
69
+ 'but no hard write boundary; the CI check can still reject the change before merge.',
70
+ fix: arkCommand(
71
+ root,
72
+ 'ark-check',
73
+ `--install-agent-gates --tools ${tools}`
74
+ ),
125
75
  };
126
76
  }
127
77
 
128
78
  return {
79
+ activeHost,
80
+ support,
81
+ supportSummary: formatHostSupportSummary(support),
82
+ capabilities,
83
+ capabilityEvidence,
84
+ inventory,
85
+ // Compatibility projection for existing doctor/API consumers.
129
86
  mode,
130
- prepareWrite,
131
- autoPatch,
132
- hookPresent,
133
- hookRepair,
134
- mcpPresent,
135
- evidence: [...new Set(evidence)],
87
+ prepareWrite: advisoryWrite,
88
+ autoPatch: advisoryWrite || repairPayload,
89
+ hookPresent: hardWrite,
90
+ hookRepair: repairPayload,
91
+ mcpPresent: advisoryWrite,
92
+ evidence: [
93
+ ...new Set([
94
+ ...capabilityEvidence['hard-write'],
95
+ ...capabilityEvidence['advisory-write'],
96
+ ...capabilityEvidence['repair-payload'],
97
+ ]),
98
+ ],
136
99
  gap,
137
100
  };
138
101
  }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Canonical, pure contract for ark.config.json.
3
+ *
4
+ * Tooling adapters own filesystem I/O; this module owns JSON parsing, deterministic
5
+ * migration, defaults, validation, diagnostics, and the published JSON Schema.
6
+ * The standalone CLI artifact is generated into bin/lib/config-contract.mjs.
7
+ */
8
+ declare const ARK_CONFIG_SCHEMA_VERSION: "1.0";
9
+ type ArkConfigCyclePolicy = 'strict' | 'soft' | 'framework-soft' | 'off';
10
+ type ArkConfigLayer = {
11
+ name: string;
12
+ patterns: string[];
13
+ exclude?: string[];
14
+ intentPrefixes?: string[];
15
+ description?: string;
16
+ forbiddenGlobals?: string[];
17
+ mayImportInfrastructure?: boolean;
18
+ optional?: boolean;
19
+ };
20
+ type ArkConfigRule = {
21
+ from: string;
22
+ to: string;
23
+ allowed: boolean;
24
+ message?: string;
25
+ peerIsolation?: boolean;
26
+ sliceFolders?: string[];
27
+ };
28
+ type ArkConfigSafety = {
29
+ maxTsSuppressions?: number;
30
+ maxAnyCasts?: number;
31
+ allowInMemory?: boolean;
32
+ allowDisabledPeerIsolation?: boolean;
33
+ };
34
+ type ArkConfig = {
35
+ $schema: string;
36
+ schemaVersion: typeof ARK_CONFIG_SCHEMA_VERSION;
37
+ name?: string;
38
+ include: string[];
39
+ exclude?: string[];
40
+ excludeGenerated?: boolean;
41
+ frameworkOverlay?: string;
42
+ layers: ArkConfigLayer[];
43
+ rules: ArkConfigRule[];
44
+ cyclePolicy?: ArkConfigCyclePolicy;
45
+ dynamicImportAllowlist?: string[];
46
+ safety?: ArkConfigSafety;
47
+ };
48
+ type ArkConfigLoadResult = {
49
+ config: ArkConfig;
50
+ migratedFrom: 'unversioned' | null;
51
+ };
52
+
53
+ export type { ArkConfig as A, ArkConfigRule as a, ArkConfigLayer as b, ArkConfigLoadResult as c };
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Canonical, pure contract for ark.config.json.
3
+ *
4
+ * Tooling adapters own filesystem I/O; this module owns JSON parsing, deterministic
5
+ * migration, defaults, validation, diagnostics, and the published JSON Schema.
6
+ * The standalone CLI artifact is generated into bin/lib/config-contract.mjs.
7
+ */
8
+ declare const ARK_CONFIG_SCHEMA_VERSION: "1.0";
9
+ type ArkConfigCyclePolicy = 'strict' | 'soft' | 'framework-soft' | 'off';
10
+ type ArkConfigLayer = {
11
+ name: string;
12
+ patterns: string[];
13
+ exclude?: string[];
14
+ intentPrefixes?: string[];
15
+ description?: string;
16
+ forbiddenGlobals?: string[];
17
+ mayImportInfrastructure?: boolean;
18
+ optional?: boolean;
19
+ };
20
+ type ArkConfigRule = {
21
+ from: string;
22
+ to: string;
23
+ allowed: boolean;
24
+ message?: string;
25
+ peerIsolation?: boolean;
26
+ sliceFolders?: string[];
27
+ };
28
+ type ArkConfigSafety = {
29
+ maxTsSuppressions?: number;
30
+ maxAnyCasts?: number;
31
+ allowInMemory?: boolean;
32
+ allowDisabledPeerIsolation?: boolean;
33
+ };
34
+ type ArkConfig = {
35
+ $schema: string;
36
+ schemaVersion: typeof ARK_CONFIG_SCHEMA_VERSION;
37
+ name?: string;
38
+ include: string[];
39
+ exclude?: string[];
40
+ excludeGenerated?: boolean;
41
+ frameworkOverlay?: string;
42
+ layers: ArkConfigLayer[];
43
+ rules: ArkConfigRule[];
44
+ cyclePolicy?: ArkConfigCyclePolicy;
45
+ dynamicImportAllowlist?: string[];
46
+ safety?: ArkConfigSafety;
47
+ };
48
+ type ArkConfigLoadResult = {
49
+ config: ArkConfig;
50
+ migratedFrom: 'unversioned' | null;
51
+ };
52
+
53
+ export type { ArkConfig as A, ArkConfigRule as a, ArkConfigLayer as b, ArkConfigLoadResult as c };