arkgate 4.7.6 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -3
- package/README.md +8 -9
- package/bin/lib/analysis-engine.mjs +6 -6
- package/bin/lib/ark-order-error.mjs +18 -0
- package/bin/lib/ark-order-facts.mjs +53 -0
- package/bin/lib/ark-order-invariants.mjs +160 -0
- package/bin/lib/ark-order-sensors.mjs +118 -0
- package/bin/lib/ark-order-types.mjs +11 -0
- package/bin/lib/ark-run-sensors.mjs +13 -5
- package/bin/lib/config-contract.mjs +16 -72
- package/bin/lib/config-extras.mjs +151 -0
- package/bin/lib/diagnostic-catalog.mjs +7 -2
- package/bin/lib/extra-merge-teeth.mjs +8 -2
- package/bin/lib/install-migrate.mjs +4 -2
- package/bin/lib/managed-upgrade.mjs +1 -1
- package/bin/lib/mcp-adoption.mjs +9 -3
- package/bin/lib/remediation.mjs +48 -9
- package/bin/lib/resolved-candidate-facts.mjs +43 -0
- package/bin/lib/skill-install.mjs +17 -2
- package/bin/lib/start-preview.mjs +1 -0
- package/bin/lib/status-manifest.mjs +1 -1
- package/bin/lib/write-path-capabilities.mjs +2 -2
- package/dist/{configTypes-CgJimx9o.d.ts → configTypes-BdCe_gvv.d.ts} +22 -6
- package/dist/diagnosticCatalog-RiKPUFRG.d.ts +2307 -0
- package/dist/eslint/index.cjs +7 -6
- package/dist/eslint/index.d.ts +33 -2
- package/dist/eslint/index.js +7 -6
- package/dist/index.cjs +35 -35
- package/dist/index.d.ts +271 -2554
- package/dist/index.js +35 -35
- package/dist/nestjs/index.cjs +18 -0
- package/dist/nestjs/index.d.ts +24 -0
- package/dist/nestjs/index.js +18 -0
- package/dist/order/index.cjs +1 -0
- package/dist/order/index.d.ts +79 -0
- package/dist/order/index.js +1 -0
- package/dist/runtime/index.cjs +25 -0
- package/dist/runtime/index.d.ts +497 -0
- package/dist/runtime/index.js +25 -0
- package/dist/types-C9KApBzX.d.ts +1237 -0
- package/dist/types-DCSlrRnV.d.ts +181 -0
- package/docs/README.md +4 -4
- package/docs/agent-guide.md +1 -1
- package/docs/ai-gates.md +9 -2
- package/docs/configuration.md +13 -6
- package/docs/develop.md +4 -3
- package/docs/diagnostics.md +57 -3
- package/docs/package-surface.md +20 -16
- package/docs/product-voice.md +2 -1
- package/package.json +21 -2
- package/schemas/ark.config.schema.json +54 -2
- package/schemas/ark.resolved-candidate-facts.schema.json +1 -1
- package/server.json +2 -2
- package/templates/agent-skills/README.md +1 -1
- package/templates/agent-skills/ark-adopt/SKILL.md +2 -2
- package/templates/agent-skills/ark-contract/SKILL.md +1 -1
- package/templates/agent-skills/ark-place/SKILL.md +15 -6
- package/templates/agent-skills/ark-runtime/SKILL.md +10 -15
- package/templates/skills/ark-adopt.md +2 -2
- package/templates/skills/ark-contract.md +1 -1
- package/templates/skills/ark-place.md +15 -6
- package/templates/skills/ark-runtime.md +10 -15
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GENERATED FILE — do not edit by hand.
|
|
3
|
+
*
|
|
4
|
+
* Canonical algorithm: src/domain/configExtras.ts
|
|
5
|
+
* Regenerate: node scripts/generate-cli-pure.mjs
|
|
6
|
+
* Drift check: node scripts/generate-cli-pure.mjs --check
|
|
7
|
+
*
|
|
8
|
+
* Pure CLI helper (bin/lib/config-extras.mjs). Zero Node I/O.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const stringArraySchema = {
|
|
12
|
+
type: 'array',
|
|
13
|
+
items: { type: 'string', minLength: 1 },
|
|
14
|
+
uniqueItems: true,
|
|
15
|
+
};
|
|
16
|
+
export const ARK_RUN_SCHEMA_DEF = {
|
|
17
|
+
type: 'object',
|
|
18
|
+
additionalProperties: false,
|
|
19
|
+
properties: {
|
|
20
|
+
mode: {
|
|
21
|
+
type: 'string',
|
|
22
|
+
enum: ['advisory', 'enforced'],
|
|
23
|
+
default: 'advisory',
|
|
24
|
+
},
|
|
25
|
+
compositionRoots: { ...stringArraySchema, default: [] },
|
|
26
|
+
kernelRoots: { ...stringArraySchema },
|
|
27
|
+
managedLayers: { ...stringArraySchema, default: [] },
|
|
28
|
+
requireDeclarations: { type: 'boolean', default: true },
|
|
29
|
+
ignoreDirectNewForErrors: { type: 'boolean', default: true },
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
export const ARK_ORDER_SCHEMA_DEF = {
|
|
33
|
+
type: 'object',
|
|
34
|
+
additionalProperties: false,
|
|
35
|
+
properties: {
|
|
36
|
+
mode: {
|
|
37
|
+
type: 'string',
|
|
38
|
+
enum: ['advisory', 'enforced'],
|
|
39
|
+
default: 'advisory',
|
|
40
|
+
},
|
|
41
|
+
planeRoots: { ...stringArraySchema, default: [] },
|
|
42
|
+
managedLayers: { ...stringArraySchema, default: [] },
|
|
43
|
+
maxXiKeys: { type: 'integer', minimum: 1, default: 7 },
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
function isObject(value) {
|
|
47
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
48
|
+
}
|
|
49
|
+
function declaredLayerNames(config) {
|
|
50
|
+
const layerNames = new Set();
|
|
51
|
+
if (!Array.isArray(config.layers))
|
|
52
|
+
return layerNames;
|
|
53
|
+
for (const layer of config.layers) {
|
|
54
|
+
if (isObject(layer) && typeof layer.name === 'string' && layer.name.length > 0) {
|
|
55
|
+
layerNames.add(layer.name);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return layerNames;
|
|
59
|
+
}
|
|
60
|
+
export function defaultedArkRun(value) {
|
|
61
|
+
if (!isObject(value))
|
|
62
|
+
return value;
|
|
63
|
+
const out = {
|
|
64
|
+
mode: value.mode === undefined ? 'advisory' : value.mode,
|
|
65
|
+
compositionRoots: value.compositionRoots === undefined ? [] : value.compositionRoots,
|
|
66
|
+
managedLayers: value.managedLayers === undefined ? [] : value.managedLayers,
|
|
67
|
+
requireDeclarations: value.requireDeclarations === undefined ? true : value.requireDeclarations,
|
|
68
|
+
};
|
|
69
|
+
if (value.kernelRoots !== undefined)
|
|
70
|
+
out.kernelRoots = value.kernelRoots;
|
|
71
|
+
if (value.ignoreDirectNewForErrors !== undefined) {
|
|
72
|
+
out.ignoreDirectNewForErrors = value.ignoreDirectNewForErrors;
|
|
73
|
+
}
|
|
74
|
+
return { ...value, ...out };
|
|
75
|
+
}
|
|
76
|
+
export function defaultedArkOrder(value) {
|
|
77
|
+
if (!isObject(value))
|
|
78
|
+
return value;
|
|
79
|
+
const max = typeof value.maxXiKeys === 'number' && value.maxXiKeys > 0 ? value.maxXiKeys : 7;
|
|
80
|
+
return {
|
|
81
|
+
...value,
|
|
82
|
+
mode: value.mode === undefined ? 'advisory' : value.mode,
|
|
83
|
+
planeRoots: value.planeRoots === undefined ? [] : value.planeRoots,
|
|
84
|
+
managedLayers: value.managedLayers === undefined ? [] : value.managedLayers,
|
|
85
|
+
maxXiKeys: max,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
export function validateArkRunExtra(config, issues) {
|
|
89
|
+
const extra = config.arkRun;
|
|
90
|
+
if (extra === undefined || !isObject(extra))
|
|
91
|
+
return;
|
|
92
|
+
const layerNames = declaredLayerNames(config);
|
|
93
|
+
const managed = extra.managedLayers;
|
|
94
|
+
if (Array.isArray(managed)) {
|
|
95
|
+
managed.forEach((name, index) => {
|
|
96
|
+
if (typeof name === 'string' && name.length > 0 && !layerNames.has(name)) {
|
|
97
|
+
issues.push({
|
|
98
|
+
path: `$.arkRun.managedLayers[${index}]`,
|
|
99
|
+
message: `layer ${JSON.stringify(name)} is not declared in layers[]`,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
if (extra.mode === 'enforced') {
|
|
105
|
+
const roots = extra.kernelRoots ?? extra.compositionRoots;
|
|
106
|
+
if (!Array.isArray(roots) || roots.length === 0) {
|
|
107
|
+
issues.push({
|
|
108
|
+
path: extra.kernelRoots !== undefined ? '$.arkRun.kernelRoots' : '$.arkRun.compositionRoots',
|
|
109
|
+
message: 'ARKRUN_MISSING_ROOT: enforced mode requires at least one kernel root',
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (!Array.isArray(managed) || managed.length === 0) {
|
|
113
|
+
issues.push({
|
|
114
|
+
path: '$.arkRun.managedLayers',
|
|
115
|
+
message: 'enforced mode requires at least one managed layer',
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
export function validateArkOrderExtra(config, issues) {
|
|
121
|
+
const extra = config.arkOrder;
|
|
122
|
+
if (extra === undefined || !isObject(extra))
|
|
123
|
+
return;
|
|
124
|
+
const layerNames = declaredLayerNames(config);
|
|
125
|
+
const managed = extra.managedLayers;
|
|
126
|
+
if (Array.isArray(managed)) {
|
|
127
|
+
managed.forEach((name, index) => {
|
|
128
|
+
if (typeof name === 'string' && name.length > 0 && !layerNames.has(name)) {
|
|
129
|
+
issues.push({
|
|
130
|
+
path: `$.arkOrder.managedLayers[${index}]`,
|
|
131
|
+
message: `layer ${JSON.stringify(name)} is not declared in layers[]`,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
if (extra.mode === 'enforced') {
|
|
137
|
+
const roots = extra.planeRoots;
|
|
138
|
+
if (!Array.isArray(roots) || roots.length === 0) {
|
|
139
|
+
issues.push({
|
|
140
|
+
path: '$.arkOrder.planeRoots',
|
|
141
|
+
message: 'ARKORDER_MISSING_PLANE: enforced mode requires at least one plane root',
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
if (!Array.isArray(managed) || managed.length === 0) {
|
|
145
|
+
issues.push({
|
|
146
|
+
path: '$.arkOrder.managedLayers',
|
|
147
|
+
message: 'enforced mode requires at least one managed layer',
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -57,13 +57,18 @@ export const DIAGNOSTIC_CATALOG = Object.freeze([
|
|
|
57
57
|
entry('ARKRULE_SCOPE_EMPTY', 'arkrules', 'ArkRule appliesTo matched zero files', 'An ArkRule’s appliesTo globs matched no governed files — the rule cannot observe what it claims to protect.', 'Fix appliesTo globs so they match governed files, or remove the rule. Enforced empty scope fails; advisory empty scope warns.', { oftenAdvisory: true }),
|
|
58
58
|
entry('INVARIANT_UNCOVERED', 'arkrules', 'Invariant without coverage evidence', 'An ArkRules invariant is under contract but no covering test title or declared symbol evidence was found (or coverage is partial). Kind is never-had-tests (adopt residual) vs tests-disappeared (suite exists).', 'Add a test title or declared symbol covering the arkruleId, then preflight again. Treat never-had-tests as adopt residual; treat tests-disappeared as a regression. Missing test globs report partial — never fake green.'),
|
|
59
59
|
// ── ArkRun (opt-in extra; RN05 dual-depth nextAction) ────────────────────
|
|
60
|
-
entry('ARKRUN_MISSING_ROOT', 'arkrun', 'No kernel factory in composition roots', 'The ArkRun extra is on but no createArkKernel / createStrictArkKernel / createArkKernelFromConfig / createStrictArkKernelFromConfig factory was found in arkRun.compositionRoots, so agents can skip the kernel while the write gate stays green.', 'Import createStrictArkKernel from
|
|
61
|
-
entry('ARKRUN_KERNEL_IN_DOMAIN', 'arkrun', 'Domain-role layer imports the kernel', 'A Domain-role layer imports @arkgate/runtime or kernel types. Domain stays kernel-free; composition roots and adapters own the factory.', 'Move the kernel import out of the Domain-role layer into a composition root or adapter. Import from
|
|
60
|
+
entry('ARKRUN_MISSING_ROOT', 'arkrun', 'No kernel factory in composition roots', 'The ArkRun extra is on but no createArkKernel / createStrictArkKernel / createArkKernelFromConfig / createStrictArkKernelFromConfig factory was found in arkRun.compositionRoots, so agents can skip the kernel while the write gate stays green.', 'Import createStrictArkKernel from arkgate/runtime (same npm package; @arkgate/runtime is deprecated) and call it in a composition root listed in arkRun.compositionRoots, then preflight again. Never mechanical-safe — factory placement is a design decision.'),
|
|
61
|
+
entry('ARKRUN_KERNEL_IN_DOMAIN', 'arkrun', 'Domain-role layer imports the kernel', 'A Domain-role layer imports arkgate/runtime, @arkgate/runtime, or kernel types. Domain stays kernel-free; composition roots and adapters own the factory.', 'Move the kernel import out of the Domain-role layer into a composition root or adapter. Import from arkgate/runtime (same npm package; @arkgate/runtime is deprecated), then preflight again. Never mechanical-safe.'),
|
|
62
62
|
entry('ARKRUN_DIRECT_NEW', 'arkrun', 'Managed type constructed with new', 'A managed non-Domain file constructs an admitted type with new outside an ArkRun composition-root factory, skipping kernel resolve/registration.', 'Resolve the type from the kernel instead of constructing it with new, then preflight again. Never mechanical-safe — rewiring construction is a design decision.'),
|
|
63
63
|
entry('ARKRUN_UNDECLARED_EMIT', 'arkrun', 'Emit name not in raises/sends', 'A publisher / publish / raise / send call-site literal is not listed in the file’s raises or sends declaration.', 'Add the existing call-site name to raises or sends on the managed component, then preflight again. Mechanical-safe only when that literal already exists and the edit is the declaration list; inventing a new emit stays judgment.'),
|
|
64
64
|
entry('ARKRUN_UNDECLARED_HANDLE', 'arkrun', 'Handle name not in reactsTo', 'A subscribe / registerHandler call-site literal is not listed in the file’s reactsTo declaration.', 'Add the existing call-site name to reactsTo on the managed component, then preflight again. Mechanical-safe only when that literal already exists and the edit is the declaration list; inventing a new handle stays judgment.'),
|
|
65
65
|
entry('ARKRUN_UNDECLARED_DEPEND', 'arkrun', 'Depend name not in uses', 'A resolve / resolveSingleton call-site literal is not listed in the file’s uses declaration.', 'Add the existing call-site name to uses on the managed component, then preflight again. Mechanical-safe only when that literal already exists and the edit is the declaration list; inventing a new depend stays judgment.'),
|
|
66
66
|
entry('ARKRUN_TRANSPORT_BYPASS', 'arkrun', 'Homemade broker or emitter import', 'A managed layer imports a closed broker/queue/emitter specifier (EventEmitter, queue clients, …) instead of the ArkRun kernel transport.', 'Send through the ArkRun kernel transport instead of importing that broker or emitter, then preflight again. Never mechanical-safe — homemade buses stay judgment.'),
|
|
67
|
+
entry('ARKORDER_MISSING_PLANE', 'arkorder', 'No createOrderPlane in plane roots', 'The ArkOrder extra is on but no createOrderPlane factory was found in arkOrder.planeRoots, so agents can skip the pattern plane while the write gate stays green.', 'Import createOrderPlane from arkgate/order and call it in a plane root listed in arkOrder.planeRoots, then preflight again. Never mechanical-safe — factory placement is a design decision.'),
|
|
68
|
+
entry('ARKORDER_KERNEL_IN_DOMAIN', 'arkorder', 'Domain-role layer imports the order plane', 'A Domain-role layer imports arkgate/order. Domain stays plane-free; planeRoots own the factory.', 'Move the arkgate/order import out of the Domain-role layer into a plane root or adapter, then preflight again. Never mechanical-safe.'),
|
|
69
|
+
entry('ARKORDER_GENERIC_UPDATE', 'arkorder', 'Generic update of ξ', 'A call to update/patch/set on the order plane rewrites the slow pattern. Haken slaving forbids generic ξ mutation.', 'Use release() to freeze ξ or proposeRelease() for a pattern change with blast radius, then preflight again. Never mechanical-safe.'),
|
|
70
|
+
entry('ARKORDER_TOO_MANY_PARAMS', 'arkorder', 'Too many slow keys', 'ξ has more keys than arkOrder.maxXiKeys. Haken requires a few slow modes, not a dump of microstate.', 'Cut ξ to the slow keys that actually slave the rest, then preflight again. Never mechanical-safe.'),
|
|
71
|
+
entry('ARKORDER_INGEST_WRITES_XI', 'arkorder', 'ingest assigned into ξ', 'An ingest() result is written into a Release or ξ store. ingest may absorb or escalate; it never mints a pattern.', 'Keep ingest results as absorb/escalate only. Change ξ with proposeRelease + release. Never mechanical-safe.'),
|
|
67
72
|
// ── atomic preflight / change set ────────────────────────────────────────
|
|
68
73
|
entry('INVALID_CHANGE_PATH', 'preflight', 'Unsafe change path', 'A change set entry is not a safe, non-empty project-relative path (absolute, escape, empty, or NUL).', 'Use canonical project-relative paths only in the atomic change set, then preflight again.'),
|
|
69
74
|
entry('DUPLICATE_CHANGE_PATH', 'preflight', 'Duplicate path in change set', 'The atomic change set lists more than one operation for the same path.', 'Collapse to one create/update/delete per path, then preflight again.'),
|
|
@@ -49,11 +49,17 @@ export function classifyResolvedLayerCoverage(files) {
|
|
|
49
49
|
export function isArkRunRuleId(ruleId) {
|
|
50
50
|
return typeof ruleId === 'string' && ruleId.startsWith('ARKRUN_');
|
|
51
51
|
}
|
|
52
|
+
export function isArkOrderRuleId(ruleId) {
|
|
53
|
+
return typeof ruleId === 'string' && ruleId.startsWith('ARKORDER_');
|
|
54
|
+
}
|
|
52
55
|
export function isExtraPlaneFinding(violation) {
|
|
53
56
|
if (violation?.arkruleId != null)
|
|
54
57
|
return true;
|
|
55
58
|
const id = typeof violation?.ruleId === 'string' ? violation.ruleId : '';
|
|
56
|
-
return id.startsWith('ARKRULE') ||
|
|
59
|
+
return (id.startsWith('ARKRULE') ||
|
|
60
|
+
id.startsWith('arkrule') ||
|
|
61
|
+
id.startsWith('ARKRUN_') ||
|
|
62
|
+
id.startsWith('ARKORDER_'));
|
|
57
63
|
}
|
|
58
64
|
/**
|
|
59
65
|
* Under the classification floor, demote enforced extra-plane findings in place
|
|
@@ -74,7 +80,7 @@ export function demoteExtraPlaneTeethUnderClassificationFloor(violations, classi
|
|
|
74
80
|
return violations;
|
|
75
81
|
}
|
|
76
82
|
/** Stamp for extra-plane honesty: never one architecture score. */
|
|
77
|
-
export const MERGE_PLANES_DUAL_STAMP = 'Structure = heuristics; invariants = catalog+coverage evidence (not business runtime); ArkRun = kernel usage + declarations (not a score). Extra planes never merge into one architecture score. Advisory ArkRules ≠ merge teeth. Advisory ArkRun ≠ merge teeth.';
|
|
83
|
+
export const MERGE_PLANES_DUAL_STAMP = 'Structure = heuristics; invariants = catalog+coverage evidence (not business runtime); ArkRun = kernel usage + declarations (not a score); ArkOrder = pattern slaving (not a score). Extra planes never merge into one architecture score. Advisory ArkRules ≠ merge teeth. Advisory ArkRun ≠ merge teeth. Advisory ArkOrder ≠ merge teeth.';
|
|
78
84
|
function countOrZero(value) {
|
|
79
85
|
return typeof value === 'number' && Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;
|
|
80
86
|
}
|
|
@@ -216,6 +216,8 @@ export function buildManagedAssetCatalog({ root, tools, compact = false, skillsO
|
|
|
216
216
|
}
|
|
217
217
|
if (selectedTools.has('antigravity')) {
|
|
218
218
|
add('.agents/hooks.json', antigravityHooks(root));
|
|
219
|
+
// Official workspace MCP. Antigravity does not load repo-root `.mcp.json`.
|
|
220
|
+
add('.agents/mcp_config.json', mcpJson(root));
|
|
219
221
|
// Still useful for Gemini CLI / legacy Gemini consumers sharing the tree.
|
|
220
222
|
add('GEMINI.md', instructionRule(root));
|
|
221
223
|
}
|
|
@@ -747,8 +749,8 @@ export function runInstallAgentGates(args) {
|
|
|
747
749
|
if (tools.has('antigravity') && !args.compact) {
|
|
748
750
|
console.log('');
|
|
749
751
|
console.log(' Antigravity: PreToolUse deny is hard for listed write tools when hooks are trusted.');
|
|
750
|
-
console.log(' - Install path: `.agents/hooks.json` (+ GEMINI.md for legacy Gemini consumers).');
|
|
751
|
-
console.log(' - Trust project hooks
|
|
752
|
+
console.log(' - Install path: `.agents/hooks.json` + `.agents/mcp_config.json` (+ GEMINI.md for legacy Gemini consumers).');
|
|
753
|
+
console.log(' - Trust project hooks; refresh MCP (`/mcp` or restart); pair with required CI --strict-merge.');
|
|
752
754
|
}
|
|
753
755
|
if (tools.has('opencode') && !args.compact) {
|
|
754
756
|
console.log('');
|
|
@@ -129,7 +129,7 @@ const HOST_SIGNALS = {
|
|
|
129
129
|
cursor: ['.cursor/mcp.json', '.cursor/hooks.json', '.cursor/rules/ark.mdc'],
|
|
130
130
|
codex: ['.codex/hooks.json', '.codex/config.toml'],
|
|
131
131
|
grok: ['.grok/config.toml', '.grok/hooks/ark-write-gate.json', '.grok/skills/ark-upgrade/SKILL.md'],
|
|
132
|
-
antigravity: ['.agents/hooks.json'],
|
|
132
|
+
antigravity: ['.agents/hooks.json', '.agents/mcp_config.json'],
|
|
133
133
|
opencode: ['opencode.json', '.opencode/skills/ark-upgrade/SKILL.md'],
|
|
134
134
|
windsurf: ['.windsurf/rules/ark.md', '.windsurf/workflows/ark-upgrade.md'],
|
|
135
135
|
cline: ['.clinerules/ark.md', '.clinerules/workflows/ark-upgrade.md'],
|
package/bin/lib/mcp-adoption.mjs
CHANGED
|
@@ -36,6 +36,7 @@ export const COMMAND_GATE_JSON_FILES = [
|
|
|
36
36
|
'.mcp.json',
|
|
37
37
|
'.cursor/mcp.json',
|
|
38
38
|
'.cursor/hooks.json',
|
|
39
|
+
'.agents/mcp_config.json',
|
|
39
40
|
'opencode.json',
|
|
40
41
|
];
|
|
41
42
|
// Primary CLI names (product) + one-major aliases. migrate-commands must strip ALL of these
|
|
@@ -208,10 +209,15 @@ export function collectAdoptionGaps(root, config, coverage) {
|
|
|
208
209
|
host: 'antigravity',
|
|
209
210
|
dir: '.agents',
|
|
210
211
|
skill: (n) => path.join(root, '.agents', 'skills', n, 'SKILL.md'),
|
|
211
|
-
extras: [
|
|
212
|
+
extras: [
|
|
213
|
+
['.agents/hooks.json', 'write-gate hook'],
|
|
214
|
+
['.agents/mcp_config.json', 'workspace MCP'],
|
|
215
|
+
],
|
|
212
216
|
toolsFlag: 'antigravity',
|
|
213
|
-
//
|
|
214
|
-
presentIf: () =>
|
|
217
|
+
// Hooks or official workspace MCP — `.agents/skills` alone is Codex scope.
|
|
218
|
+
presentIf: () =>
|
|
219
|
+
fs.existsSync(path.join(root, '.agents', 'hooks.json')) ||
|
|
220
|
+
fs.existsSync(path.join(root, '.agents', 'mcp_config.json')),
|
|
215
221
|
},
|
|
216
222
|
{
|
|
217
223
|
host: 'opencode',
|
package/bin/lib/remediation.mjs
CHANGED
|
@@ -100,6 +100,13 @@ const ARKRUN_JUDGMENT_RULE_IDS = new Set([
|
|
|
100
100
|
'ARKRUN_DIRECT_NEW',
|
|
101
101
|
'ARKRUN_TRANSPORT_BYPASS',
|
|
102
102
|
]);
|
|
103
|
+
const ARKORDER_JUDGMENT_RULE_IDS = new Set([
|
|
104
|
+
'ARKORDER_MISSING_PLANE',
|
|
105
|
+
'ARKORDER_KERNEL_IN_DOMAIN',
|
|
106
|
+
'ARKORDER_GENERIC_UPDATE',
|
|
107
|
+
'ARKORDER_TOO_MANY_PARAMS',
|
|
108
|
+
'ARKORDER_INGEST_WRITES_XI',
|
|
109
|
+
]);
|
|
103
110
|
function arkRunCallSiteName(violation) {
|
|
104
111
|
return typeof violation.target === 'string' && violation.target.trim().length > 0
|
|
105
112
|
? violation.target.trim()
|
|
@@ -119,12 +126,12 @@ function arkRunNextAction(violation) {
|
|
|
119
126
|
switch (violation.ruleId) {
|
|
120
127
|
case 'ARKRUN_MISSING_ROOT':
|
|
121
128
|
return target
|
|
122
|
-
? `Import createStrictArkKernel from
|
|
123
|
-
: 'Import createStrictArkKernel from
|
|
129
|
+
? `Import createStrictArkKernel from arkgate/runtime and call it in composition root ${target} listed in arkRun.compositionRoots, then preflight again.`
|
|
130
|
+
: 'Import createStrictArkKernel from arkgate/runtime (same npm package; @arkgate/runtime is deprecated) and call it in a composition root listed in arkRun.compositionRoots, then preflight again. Never mechanical-safe — factory placement is a design decision.';
|
|
124
131
|
case 'ARKRUN_KERNEL_IN_DOMAIN':
|
|
125
132
|
return target
|
|
126
|
-
? `Move the kernel import of ${target} out of ${fromLayer ?? 'the Domain-role layer'} into a composition root or adapter. Import from
|
|
127
|
-
: 'Move the kernel import out of the Domain-role layer into a composition root or adapter. Import from
|
|
133
|
+
? `Move the kernel import of ${target} out of ${fromLayer ?? 'the Domain-role layer'} into a composition root or adapter. Import from arkgate/runtime, then preflight again.`
|
|
134
|
+
: 'Move the kernel import out of the Domain-role layer into a composition root or adapter. Import from arkgate/runtime (same npm package; @arkgate/runtime is deprecated), then preflight again. Never mechanical-safe.';
|
|
128
135
|
case 'ARKRUN_DIRECT_NEW':
|
|
129
136
|
return target
|
|
130
137
|
? `Resolve ${target} from the kernel instead of constructing it with new, then preflight again.`
|
|
@@ -154,12 +161,12 @@ function arkRunEnthusiastHint(violation) {
|
|
|
154
161
|
switch (violation.ruleId) {
|
|
155
162
|
case 'ARKRUN_MISSING_ROOT':
|
|
156
163
|
return target
|
|
157
|
-
? `Call createStrictArkKernel from
|
|
158
|
-
: 'Call createStrictArkKernel from
|
|
164
|
+
? `Call createStrictArkKernel from arkgate/runtime in ${target} so the app actually uses the kernel.`
|
|
165
|
+
: 'Call createStrictArkKernel from arkgate/runtime in a listed composition root so the app actually uses the kernel.';
|
|
159
166
|
case 'ARKRUN_KERNEL_IN_DOMAIN':
|
|
160
167
|
return target
|
|
161
|
-
? `Domain stays kernel-free. Move the ${target} import to a composition root or adapter
|
|
162
|
-
: 'Domain stays kernel-free. Move that
|
|
168
|
+
? `Domain stays kernel-free. Move the ${target} import to a composition root or adapter. Prefer arkgate/runtime.`
|
|
169
|
+
: 'Domain stays kernel-free. Move that kernel import to a composition root or adapter. Prefer arkgate/runtime; @arkgate/runtime is deprecated.';
|
|
163
170
|
case 'ARKRUN_DIRECT_NEW':
|
|
164
171
|
return target
|
|
165
172
|
? `Do not construct ${target} with new. Resolve it from the kernel instead.`
|
|
@@ -215,6 +222,18 @@ export function deterministicNextAction(violation) {
|
|
|
215
222
|
case 'ARKRUN_UNDECLARED_DEPEND':
|
|
216
223
|
case 'ARKRUN_TRANSPORT_BYPASS':
|
|
217
224
|
return arkRunNextAction(violation);
|
|
225
|
+
case 'ARKORDER_MISSING_PLANE':
|
|
226
|
+
return typeof violation.target === 'string' && violation.target.length > 0
|
|
227
|
+
? `Import createOrderPlane from arkgate/order and call it in plane root ${violation.target} listed in arkOrder.planeRoots, then preflight again.`
|
|
228
|
+
: 'Import createOrderPlane from arkgate/order and call it in a plane root listed in arkOrder.planeRoots, then preflight again. Never mechanical-safe — factory placement is a design decision.';
|
|
229
|
+
case 'ARKORDER_KERNEL_IN_DOMAIN':
|
|
230
|
+
return 'Move the arkgate/order import out of the Domain-role layer into a plane root or adapter, then preflight again. Never mechanical-safe.';
|
|
231
|
+
case 'ARKORDER_GENERIC_UPDATE':
|
|
232
|
+
return 'Use release() to freeze ξ or proposeRelease() for a pattern change with blast radius, then preflight again. Never mechanical-safe.';
|
|
233
|
+
case 'ARKORDER_TOO_MANY_PARAMS':
|
|
234
|
+
return 'Cut ξ to the slow keys that actually slave the rest, then preflight again. Never mechanical-safe.';
|
|
235
|
+
case 'ARKORDER_INGEST_WRITES_XI':
|
|
236
|
+
return 'Keep ingest results as absorb/escalate only. Change ξ with proposeRelease + release. Never mechanical-safe.';
|
|
218
237
|
default:
|
|
219
238
|
if (typeof violation.ruleId === 'string' && violation.ruleId.startsWith('ARKRULE_')) {
|
|
220
239
|
return `Fix the ArkRule ${typeof violation.arkruleId === 'string' ? violation.arkruleId : violation.ruleId}, then preflight again.`;
|
|
@@ -340,7 +359,9 @@ export function classifyRemediation(violation) {
|
|
|
340
359
|
};
|
|
341
360
|
}
|
|
342
361
|
if (typeof ruleId === 'string' &&
|
|
343
|
-
(ARKRUN_JUDGMENT_RULE_IDS.has(ruleId) ||
|
|
362
|
+
(ARKRUN_JUDGMENT_RULE_IDS.has(ruleId) ||
|
|
363
|
+
ARKRUN_UNDECLARED_RULE_IDS.has(ruleId) ||
|
|
364
|
+
ARKORDER_JUDGMENT_RULE_IDS.has(ruleId))) {
|
|
344
365
|
return {
|
|
345
366
|
class: 'judgment',
|
|
346
367
|
confidence: 0.85,
|
|
@@ -470,6 +491,24 @@ export function enrichViolationWithFixClass(violation) {
|
|
|
470
491
|
enriched.effort = ARKRUN_UNDECLARED_RULE_IDS.has(violation.ruleId ?? '') ? 'small' : 'medium';
|
|
471
492
|
enriched.enthusiastHint = arkRunEnthusiastHint(violation);
|
|
472
493
|
break;
|
|
494
|
+
case 'ARKORDER_MISSING_PLANE':
|
|
495
|
+
case 'ARKORDER_KERNEL_IN_DOMAIN':
|
|
496
|
+
case 'ARKORDER_GENERIC_UPDATE':
|
|
497
|
+
case 'ARKORDER_TOO_MANY_PARAMS':
|
|
498
|
+
case 'ARKORDER_INGEST_WRITES_XI':
|
|
499
|
+
enriched.fixClass = 'arkorder-usage';
|
|
500
|
+
enriched.effort = 'medium';
|
|
501
|
+
enriched.enthusiastHint =
|
|
502
|
+
violation.ruleId === 'ARKORDER_GENERIC_UPDATE'
|
|
503
|
+
? 'Do not PATCH the slow pattern. Freeze ξ with release() or propose a pattern change that lists what dies.'
|
|
504
|
+
: violation.ruleId === 'ARKORDER_KERNEL_IN_DOMAIN'
|
|
505
|
+
? 'Domain stays plane-free. Import arkgate/order only from a listed plane root.'
|
|
506
|
+
: violation.ruleId === 'ARKORDER_TOO_MANY_PARAMS'
|
|
507
|
+
? 'Too many slow keys. Keep ξ small — the rest is derived noise.'
|
|
508
|
+
: violation.ruleId === 'ARKORDER_INGEST_WRITES_XI'
|
|
509
|
+
? 'ingest can absorb or escalate. It never writes a new house.'
|
|
510
|
+
: 'Call createOrderPlane from arkgate/order in a listed plane root so the app actually freezes a pattern.';
|
|
511
|
+
break;
|
|
473
512
|
default:
|
|
474
513
|
enriched.fixClass = 'review-contract';
|
|
475
514
|
enriched.effort = 'small';
|
|
@@ -40,6 +40,10 @@ import {
|
|
|
40
40
|
extractArkRunKernelCallsFromSource,
|
|
41
41
|
extractArkRunManagedNewsFromSource,
|
|
42
42
|
} from './ark-run-facts.mjs';
|
|
43
|
+
import {
|
|
44
|
+
extractArkOrderGenericUpdatesFromSource,
|
|
45
|
+
extractArkOrderPlaneCallsFromSource,
|
|
46
|
+
} from './ark-order-facts.mjs';
|
|
43
47
|
import {
|
|
44
48
|
collectGovernedFiles,
|
|
45
49
|
isGovernableSourceFile,
|
|
@@ -1008,7 +1012,11 @@ export function resolveCandidateFacts({
|
|
|
1008
1012
|
const arkRunManagedNews = [];
|
|
1009
1013
|
const arkRunCompositionRootHits = [];
|
|
1010
1014
|
const arkRunDeclarations = [];
|
|
1015
|
+
const arkOrderPlaneCalls = [];
|
|
1016
|
+
const arkOrderGenericUpdates = [];
|
|
1017
|
+
const arkOrderRootHits = [];
|
|
1011
1018
|
const compositionRootPatterns = [...(config.arkRun?.compositionRoots ?? [])];
|
|
1019
|
+
const planeRootPatterns = [...(config.arkOrder?.planeRoots ?? [])];
|
|
1012
1020
|
|
|
1013
1021
|
for (const candidate of candidateFiles) {
|
|
1014
1022
|
const sourceFile = ts.createSourceFile(
|
|
@@ -1112,6 +1120,20 @@ export function resolveCandidateFacts({
|
|
|
1112
1120
|
} catch {
|
|
1113
1121
|
// Never fail the resolver for ArkRun declaration extraction.
|
|
1114
1122
|
}
|
|
1123
|
+
try {
|
|
1124
|
+
arkOrderPlaneCalls.push(
|
|
1125
|
+
...extractArkOrderPlaneCallsFromSource(candidate.path, candidate.content)
|
|
1126
|
+
);
|
|
1127
|
+
} catch {
|
|
1128
|
+
// Never fail the resolver for ArkOrder factory extraction.
|
|
1129
|
+
}
|
|
1130
|
+
try {
|
|
1131
|
+
arkOrderGenericUpdates.push(
|
|
1132
|
+
...extractArkOrderGenericUpdatesFromSource(candidate.path, candidate.content)
|
|
1133
|
+
);
|
|
1134
|
+
} catch {
|
|
1135
|
+
// Never fail the resolver for ArkOrder generic-update extraction.
|
|
1136
|
+
}
|
|
1115
1137
|
}
|
|
1116
1138
|
}
|
|
1117
1139
|
|
|
@@ -1131,6 +1153,24 @@ export function resolveCandidateFacts({
|
|
|
1131
1153
|
}
|
|
1132
1154
|
}
|
|
1133
1155
|
|
|
1156
|
+
if (planeRootPatterns.length > 0) {
|
|
1157
|
+
const factoryFiles = new Set(arkOrderPlaneCalls.map((call) => call.file));
|
|
1158
|
+
for (const candidate of candidateFiles) {
|
|
1159
|
+
for (const pattern of planeRootPatterns) {
|
|
1160
|
+
try {
|
|
1161
|
+
if (!globToRegExp(pattern).test(candidate.path)) continue;
|
|
1162
|
+
} catch {
|
|
1163
|
+
continue;
|
|
1164
|
+
}
|
|
1165
|
+
arkOrderRootHits.push({
|
|
1166
|
+
file: candidate.path,
|
|
1167
|
+
matchedRoot: pattern,
|
|
1168
|
+
hasPlaneFactory: factoryFiles.has(candidate.path),
|
|
1169
|
+
});
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1134
1174
|
if (compositionRootPatterns.length > 0) {
|
|
1135
1175
|
const factoryFiles = new Set(
|
|
1136
1176
|
arkRunKernelCalls.filter((call) => call.kind === 'factory').map((call) => call.file)
|
|
@@ -1234,5 +1274,8 @@ export function resolveCandidateFacts({
|
|
|
1234
1274
|
arkRunManagedNews,
|
|
1235
1275
|
arkRunCompositionRootHits,
|
|
1236
1276
|
arkRunDeclarations,
|
|
1277
|
+
arkOrderPlaneCalls,
|
|
1278
|
+
arkOrderGenericUpdates,
|
|
1279
|
+
arkOrderRootHits,
|
|
1237
1280
|
});
|
|
1238
1281
|
}
|
|
@@ -136,8 +136,13 @@ export function resolveTools(args) {
|
|
|
136
136
|
if (fs.existsSync(path.join(root, '.cursor'))) detected.add('cursor');
|
|
137
137
|
if (fs.existsSync(path.join(root, '.codex'))) detected.add('codex');
|
|
138
138
|
if (fs.existsSync(path.join(root, '.grok'))) detected.add('grok');
|
|
139
|
-
// Antigravity project hooks (distinct from Codex-only `.agents/skills`).
|
|
140
|
-
if (
|
|
139
|
+
// Antigravity project hooks or official workspace MCP (distinct from Codex-only `.agents/skills`).
|
|
140
|
+
if (
|
|
141
|
+
fs.existsSync(path.join(root, '.agents', 'hooks.json')) ||
|
|
142
|
+
fs.existsSync(path.join(root, '.agents', 'mcp_config.json'))
|
|
143
|
+
) {
|
|
144
|
+
detected.add('antigravity');
|
|
145
|
+
}
|
|
141
146
|
if (
|
|
142
147
|
fs.existsSync(path.join(root, 'opencode.json')) ||
|
|
143
148
|
fs.existsSync(path.join(root, 'opencode.jsonc')) ||
|
|
@@ -167,6 +172,16 @@ export function resolveTools(args) {
|
|
|
167
172
|
) {
|
|
168
173
|
detected.add('grok');
|
|
169
174
|
}
|
|
175
|
+
// Same idea as Grok env markers: opening Antigravity has no `.agents/hooks.json` yet.
|
|
176
|
+
if (
|
|
177
|
+
envTruthy(process.env.ANTIGRAVITY) ||
|
|
178
|
+
envTruthy(process.env.AGY) ||
|
|
179
|
+
process.env.ANTIGRAVITY_WORKSPACE ||
|
|
180
|
+
process.env.AGY_WORKSPACE ||
|
|
181
|
+
/antigravity/i.test(String(process.env.TERM_PROGRAM ?? ''))
|
|
182
|
+
) {
|
|
183
|
+
detected.add('antigravity');
|
|
184
|
+
}
|
|
170
185
|
// No signal at all: fall back to a complete starter set including Grok (field
|
|
171
186
|
// log: default claude+cursor+codex silently omitted Grok skills for Grok hosts).
|
|
172
187
|
if (detected.size === 0) {
|
|
@@ -246,7 +246,7 @@ export function resolveStatusNextAction(facts, binding, activation, lastCheck, r
|
|
|
246
246
|
if (facts.arkRun?.present === true && (facts.arkRun.residual ?? 0) > 0) {
|
|
247
247
|
return {
|
|
248
248
|
id: 'review-arkrun-residual',
|
|
249
|
-
summary: 'ArkRun residual remains — wire kernel usage or declarations through
|
|
249
|
+
summary: 'ArkRun residual remains — wire kernel usage or declarations through arkgate/runtime. Not a score.',
|
|
250
250
|
};
|
|
251
251
|
}
|
|
252
252
|
if (facts.adopted === 'required-merge' || facts.adopted === 'advisory-only-acked') {
|
|
@@ -464,8 +464,8 @@ export function detectWritePathInventory(root) {
|
|
|
464
464
|
),
|
|
465
465
|
antigravity: hostRecord(
|
|
466
466
|
antigravityHook.hard,
|
|
467
|
-
//
|
|
468
|
-
mcpEvidence(root, '.
|
|
467
|
+
// Official workspace MCP. Shared `.mcp.json` is not loaded by Antigravity.
|
|
468
|
+
mcpEvidence(root, '.agents/mcp_config.json'),
|
|
469
469
|
antigravityHook.repair,
|
|
470
470
|
merge
|
|
471
471
|
),
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
* Type vocabulary for the ark.config.json contract (U02 pilot 1).
|
|
3
3
|
*
|
|
4
4
|
* Pure declarations only — no runtime values. The loader/validator logic and the
|
|
5
|
-
* published JSON Schema live in ./configContract.ts
|
|
6
|
-
*
|
|
7
|
-
* this
|
|
5
|
+
* published JSON Schema live in ./configContract.ts. Extra defaulting lives in
|
|
6
|
+
* ./configExtras.ts (generated sibling `config-extras.mjs`). Type-only imports
|
|
7
|
+
* from this file are erased on transpile.
|
|
8
8
|
*/
|
|
9
|
-
type ArkConfigSchemaVersion = '1.0' | '1.1' | '1.2';
|
|
9
|
+
type ArkConfigSchemaVersion = '1.0' | '1.1' | '1.2' | '1.3';
|
|
10
10
|
type ArkConfigCyclePolicy = 'strict' | 'soft' | 'framework-soft' | 'off';
|
|
11
11
|
type ArkConfigLayerCapabilities = {
|
|
12
12
|
deny?: string[];
|
|
@@ -60,8 +60,22 @@ type ArkConfigArkRunMode = 'advisory' | 'enforced';
|
|
|
60
60
|
type ArkConfigArkRun = {
|
|
61
61
|
mode: ArkConfigArkRunMode;
|
|
62
62
|
compositionRoots: string[];
|
|
63
|
+
kernelRoots?: string[];
|
|
63
64
|
managedLayers: string[];
|
|
64
65
|
requireDeclarations: boolean;
|
|
66
|
+
ignoreDirectNewForErrors?: boolean;
|
|
67
|
+
};
|
|
68
|
+
/** ADR 0027 — advisory never adds merge teeth; enforced is the extra's merge plane. */
|
|
69
|
+
type ArkConfigArkOrderMode = 'advisory' | 'enforced';
|
|
70
|
+
/**
|
|
71
|
+
* ADR 0027 — optional inline ArkOrder extra (schema 1.3+). Absence is silent.
|
|
72
|
+
* Present objects are fully defaulted by the loader.
|
|
73
|
+
*/
|
|
74
|
+
type ArkConfigArkOrder = {
|
|
75
|
+
mode: ArkConfigArkOrderMode;
|
|
76
|
+
planeRoots: string[];
|
|
77
|
+
managedLayers: string[];
|
|
78
|
+
maxXiKeys: number;
|
|
65
79
|
};
|
|
66
80
|
type ArkConfig = {
|
|
67
81
|
$schema: string;
|
|
@@ -80,6 +94,8 @@ type ArkConfig = {
|
|
|
80
94
|
arkRules?: ArkConfigArkRulesRefs;
|
|
81
95
|
/** ADR 0020 — optional ArkRun extra (schema 1.2+). Absence changes no Layers/ArkRules verdict. */
|
|
82
96
|
arkRun?: ArkConfigArkRun;
|
|
97
|
+
/** ADR 0027 — optional ArkOrder extra (schema 1.3+). Absence changes no Layers/ArkRules/ArkRun verdict. */
|
|
98
|
+
arkOrder?: ArkConfigArkOrder;
|
|
83
99
|
/**
|
|
84
100
|
* Optional GitHub handles or emails who may loosen the contract or grow the baseline.
|
|
85
101
|
* Metadata — excluded from policy hash. Absence means no steward lock (policy-ack still applies).
|
|
@@ -91,10 +107,10 @@ type ArkConfigIssue = {
|
|
|
91
107
|
message: string;
|
|
92
108
|
};
|
|
93
109
|
/** Original input version when the loader rewrote schemaVersion toward current. */
|
|
94
|
-
type ArkConfigMigratedFrom = 'unversioned' | '1.0' | '1.1' | null;
|
|
110
|
+
type ArkConfigMigratedFrom = 'unversioned' | '1.0' | '1.1' | '1.2' | null;
|
|
95
111
|
type ArkConfigLoadResult = {
|
|
96
112
|
config: ArkConfig;
|
|
97
113
|
migratedFrom: ArkConfigMigratedFrom;
|
|
98
114
|
};
|
|
99
115
|
|
|
100
|
-
export type { ArkConfig as A, ArkConfigRule as a, ArkConfigSchemaVersion as b, ArkConfigLoadResult as c,
|
|
116
|
+
export type { ArkConfig as A, ArkConfigRule as a, ArkConfigSchemaVersion as b, ArkConfigLoadResult as c, ArkConfigIssue as d, ArkConfigArkRun as e, ArkConfigLayer as f, ArkConfigArkOrder as g };
|