arkgate 4.8.11 → 4.8.14
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 +125 -2
- package/README.md +39 -46
- package/SECURITY.md +5 -3
- package/bin/ark-check-runtime.mjs +11 -9
- package/bin/lib/agent-projection-formatters.mjs +2 -0
- package/bin/lib/agent-skills-package.mjs +63 -8
- package/bin/lib/analysis-engine.mjs +4 -4
- package/bin/lib/architecture-scan.mjs +8 -2
- package/bin/lib/ark-order-doctor.mjs +160 -0
- package/bin/lib/ark-order-report.mjs +65 -0
- package/bin/lib/ark-order-sensors.mjs +1 -1
- package/bin/lib/ci-and-commands.mjs +7 -2
- package/bin/lib/design-smells.mjs +21 -1
- package/bin/lib/diagnostic-catalog.mjs +4 -4
- package/bin/lib/doctor-advisories.mjs +99 -18
- package/bin/lib/doctor-human.mjs +4 -11
- package/bin/lib/doctor-plan.mjs +4 -3
- package/bin/lib/extra-merge-teeth.mjs +32 -4
- package/bin/lib/first-run-help.mjs +11 -2
- package/bin/lib/gate-files.mjs +40 -3
- package/bin/lib/html-report-advisories.mjs +2 -0
- package/bin/lib/html-report-depth.mjs +8 -18
- package/bin/lib/html-report.mjs +16 -0
- package/bin/lib/install-migrate.mjs +23 -0
- package/bin/lib/mcp-hook-payload.mjs +1 -1
- package/bin/lib/product-copy.mjs +4 -0
- package/bin/lib/remediation.mjs +7 -7
- package/bin/lib/resolved-candidate-facts.mjs +144 -36
- package/bin/lib/rules-under-contract.mjs +14 -0
- package/bin/lib/scan-files.mjs +39 -0
- package/bin/lib/start-preview.mjs +4 -0
- package/bin/lib/status-command.mjs +28 -0
- package/bin/lib/status-manifest.mjs +23 -0
- package/bin/lib/upgrade-whats-new.mjs +3 -3
- package/bin/lib/violations.mjs +40 -1
- package/dist/{diagnosticCatalog-DiflIock.d.ts → diagnosticCatalog-DVx_2RmF.d.ts} +1 -1
- package/dist/eslint/index.cjs +4 -4
- package/dist/eslint/index.js +4 -4
- package/dist/index.cjs +31 -31
- package/dist/index.d.ts +129 -15
- package/dist/index.js +31 -31
- package/dist/nestjs/index.cjs +1 -1
- package/dist/nestjs/index.js +1 -1
- package/dist/runtime/index.cjs +15 -15
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +15 -15
- package/docs/README.md +11 -8
- package/docs/agent-guide.md +30 -13
- package/docs/ai-gates.md +3 -1
- package/docs/arkorder.md +35 -10
- package/docs/configuration.md +7 -6
- package/docs/develop.md +3 -1
- package/docs/diagnostics.md +7 -7
- package/docs/enthusiast/README.md +6 -1
- package/docs/enthusiast/how-to-gallery-starter.md +2 -1
- package/docs/package-surface.md +8 -5
- package/docs/product-voice.md +40 -13
- package/docs/threat-model.md +2 -2
- package/docs/typescript-support.md +3 -3
- package/docs/use.md +18 -11
- package/package.json +1 -1
- package/schemas/ark.status-manifest.schema.json +47 -0
- package/server.json +2 -2
- package/templates/agent-skills/README.md +7 -4
- package/templates/agent-skills/ark-adopt/SKILL.md +9 -5
- package/templates/agent-skills/ark-architect/SKILL.md +5 -18
- package/templates/agent-skills/ark-autopilot/SKILL.md +8 -4
- package/templates/agent-skills/ark-contract/SKILL.md +9 -20
- package/templates/agent-skills/ark-coverage/SKILL.md +12 -8
- package/templates/agent-skills/ark-explain/SKILL.md +7 -3
- package/templates/agent-skills/ark-explore/SKILL.md +25 -4
- package/templates/agent-skills/ark-fix/SKILL.md +15 -20
- package/templates/agent-skills/ark-loop/SKILL.md +14 -20
- package/templates/agent-skills/ark-order/SKILL.md +200 -0
- package/templates/agent-skills/ark-place/SKILL.md +11 -8
- package/templates/agent-skills/ark-runtime/SKILL.md +17 -4
- package/templates/agent-skills/ark-think/SKILL.md +24 -126
- package/templates/agent-skills/ark-upgrade/SKILL.md +13 -2
- package/templates/skills/ark-adopt.md +9 -5
- package/templates/skills/ark-architect.md +5 -18
- package/templates/skills/ark-autopilot.md +8 -4
- package/templates/skills/ark-contract.md +9 -20
- package/templates/skills/ark-coverage.md +12 -8
- package/templates/skills/ark-explain.md +7 -3
- package/templates/skills/ark-explore.md +25 -4
- package/templates/skills/ark-fix.md +15 -20
- package/templates/skills/ark-loop.md +14 -20
- package/templates/skills/ark-order.md +200 -0
- package/templates/skills/ark-place.md +11 -8
- package/templates/skills/ark-runtime.md +17 -4
- package/templates/skills/ark-think.md +24 -126
- package/templates/skills/ark-upgrade.md +13 -2
- package/templates/tests/ark-adoption-gaps.test.ts +5 -4
|
@@ -80,7 +80,7 @@ export function demoteExtraPlaneTeethUnderClassificationFloor(violations, classi
|
|
|
80
80
|
return violations;
|
|
81
81
|
}
|
|
82
82
|
/** Stamp for extra-plane honesty: never one architecture score. */
|
|
83
|
-
export const MERGE_PLANES_DUAL_STAMP = 'Structure = heuristics; invariants = catalog+coverage evidence (not business runtime); ArkRun = kernel usage + declarations (not a score); ArkOrder =
|
|
83
|
+
export const MERGE_PLANES_DUAL_STAMP = 'Structure = heuristics; invariants = catalog+coverage evidence (not business runtime); ArkRun = kernel usage + declarations (not a score); ArkOrder = the few big product choices (not a score). Extra planes never merge into one architecture score. Advisory ArkRules ≠ merge teeth. Advisory ArkRun ≠ merge teeth. Advisory ArkOrder ≠ merge teeth.';
|
|
84
84
|
function countOrZero(value) {
|
|
85
85
|
return typeof value === 'number' && Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;
|
|
86
86
|
}
|
|
@@ -112,7 +112,14 @@ export function composeMergePlanesHonesty(input = {}) {
|
|
|
112
112
|
const arkRunResidual = countOrZero(input.arkRun?.residualCount);
|
|
113
113
|
const arkRunHasEnforced = arkRunPresent && arkRunMode === 'enforced';
|
|
114
114
|
const arkRunTeeth = arkRunHasEnforced && classificationAllowsTeeth;
|
|
115
|
-
const
|
|
115
|
+
const arkOrderPresent = input.arkOrder?.present === true;
|
|
116
|
+
const arkOrderMode = input.arkOrder?.mode === 'enforced' || input.arkOrder?.mode === 'advisory'
|
|
117
|
+
? input.arkOrder.mode
|
|
118
|
+
: null;
|
|
119
|
+
const arkOrderResidual = countOrZero(input.arkOrder?.residualCount);
|
|
120
|
+
const arkOrderHasEnforced = arkOrderPresent && arkOrderMode === 'enforced';
|
|
121
|
+
const arkOrderTeeth = arkOrderHasEnforced && classificationAllowsTeeth;
|
|
122
|
+
const hasEnforcedTeeth = arkRulesHasEnforced || arkRunHasEnforced || arkOrderHasEnforced;
|
|
116
123
|
const extraMergeTeeth = hasEnforcedTeeth && classificationAllowsTeeth;
|
|
117
124
|
const teethDeferredForClassification = hasEnforcedTeeth && classificationKnown && !classificationAllowsTeeth;
|
|
118
125
|
let failMergeWhen;
|
|
@@ -122,12 +129,15 @@ export function composeMergePlanesHonesty(input = {}) {
|
|
|
122
129
|
extras.push('enforced structure/invariant findings');
|
|
123
130
|
if (arkRunHasEnforced)
|
|
124
131
|
extras.push('enforced ArkRun skip findings');
|
|
132
|
+
if (arkOrderHasEnforced)
|
|
133
|
+
extras.push('enforced ArkOrder skip findings');
|
|
125
134
|
failMergeWhen = `Layer graph failures plus ${extras.join(' and ')} (advisory extras never fail merge alone).`;
|
|
126
135
|
}
|
|
127
136
|
else if (teethDeferredForClassification) {
|
|
128
137
|
const which = [
|
|
129
138
|
arkRulesHasEnforced ? 'ArkRules structure/invariant' : null,
|
|
130
139
|
arkRunHasEnforced ? 'ArkRun' : null,
|
|
140
|
+
arkOrderHasEnforced ? 'ArkOrder' : null,
|
|
131
141
|
]
|
|
132
142
|
.filter((part) => Boolean(part))
|
|
133
143
|
.join(' and ');
|
|
@@ -139,15 +149,21 @@ export function composeMergePlanesHonesty(input = {}) {
|
|
|
139
149
|
: arkRunMode === 'advisory'
|
|
140
150
|
? ' Advisory ArkRun never merge-blocks.'
|
|
141
151
|
: ' ArkRun extra is present but does not arm merge teeth.';
|
|
152
|
+
const arkOrderBit = !arkOrderPresent
|
|
153
|
+
? ' Absence of arkOrder is silent.'
|
|
154
|
+
: arkOrderMode === 'advisory'
|
|
155
|
+
? ' Advisory ArkOrder never merge-blocks.'
|
|
156
|
+
: ' ArkOrder extra is present but does not arm merge teeth.';
|
|
142
157
|
failMergeWhen =
|
|
143
158
|
'Layer graph only — no enforced ArkRules structure/invariant teeth on this tree. Advisory packs do not arm merge teeth.' +
|
|
144
|
-
arkRunBit
|
|
159
|
+
arkRunBit +
|
|
160
|
+
arkOrderBit;
|
|
145
161
|
}
|
|
146
162
|
const out = {
|
|
147
163
|
layers: {
|
|
148
164
|
role: 'inter-layer-edges',
|
|
149
165
|
alwaysOnGate: true,
|
|
150
|
-
note: 'Import/export layer graph — the default merge plane. Absent
|
|
166
|
+
note: 'Import/export layer graph — the default merge plane. Absent extras change nothing here.',
|
|
151
167
|
},
|
|
152
168
|
structureSensors: {
|
|
153
169
|
role: 'intra-layer-heuristics',
|
|
@@ -177,6 +193,18 @@ export function composeMergePlanesHonesty(input = {}) {
|
|
|
177
193
|
: 'Advisory ArkRun never adds merge teeth and never flips valid. Residual is a count, never a score.'
|
|
178
194
|
: 'Absence of arkRun is silent — Layers and ArkRules verdicts unchanged. The extra never becomes a score.',
|
|
179
195
|
},
|
|
196
|
+
arkOrder: {
|
|
197
|
+
role: 'pattern-slaving',
|
|
198
|
+
present: arkOrderPresent,
|
|
199
|
+
mode: arkOrderMode,
|
|
200
|
+
residualCount: arkOrderResidual,
|
|
201
|
+
extraMergeTeeth: arkOrderTeeth,
|
|
202
|
+
note: arkOrderPresent
|
|
203
|
+
? arkOrderMode === 'enforced'
|
|
204
|
+
? 'Enforced ArkOrder arms extra merge teeth only when the layer plane is classified. Residual is a count, never a score.'
|
|
205
|
+
: 'Advisory ArkOrder never adds merge teeth and never flips valid. Residual is a count, never a score.'
|
|
206
|
+
: 'Absence of arkOrder is silent — Layers verdicts unchanged. The extra never becomes a score.',
|
|
207
|
+
},
|
|
180
208
|
extraMergeTeeth,
|
|
181
209
|
dualPlaneStamp: MERGE_PLANES_DUAL_STAMP,
|
|
182
210
|
failMergeWhen,
|
|
@@ -2,9 +2,12 @@
|
|
|
2
2
|
* First-run CLI help (setup + check). Encyclopedia text stays behind --help --all.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { NORTH_STAR_ONE_LINE } from './product-copy.mjs';
|
|
6
|
+
|
|
5
7
|
export function setupUsage() {
|
|
6
8
|
return `arkgate (alias ark) — Write. Check. Ship.
|
|
7
9
|
When the agent writes a bad import, the write doesn’t land. Same check fails the PR.
|
|
10
|
+
${NORTH_STAR_ONE_LINE}
|
|
8
11
|
|
|
9
12
|
arkgate start preview (no writes)
|
|
10
13
|
arkgate start --apply write host + CI setup
|
|
@@ -30,6 +33,7 @@ Every flag: arkgate --help --all
|
|
|
30
33
|
export function setupUsageAll() {
|
|
31
34
|
return `arkgate (alias ark) — Write. Check. Ship.
|
|
32
35
|
When the agent writes a bad import, the write doesn’t land. Same check fails the PR.
|
|
36
|
+
${NORTH_STAR_ONE_LINE}
|
|
33
37
|
|
|
34
38
|
Usage:
|
|
35
39
|
arkgate start [--root <project>] [--tools <host>] [--require-write-hook <host>] [--install] [--apply] [--json]
|
|
@@ -158,9 +162,12 @@ export async function withSensorsPartialModeHonesty(args, run) {
|
|
|
158
162
|
|
|
159
163
|
export function checkUsage() {
|
|
160
164
|
return [
|
|
161
|
-
'arkgate-check (alias ark-check) —
|
|
165
|
+
'arkgate-check (alias ark-check) — Write. Check. Ship.',
|
|
166
|
+
'When the agent writes a bad import, the write doesn’t land. Same check fails the PR.',
|
|
167
|
+
NORTH_STAR_ONE_LINE,
|
|
162
168
|
'',
|
|
163
169
|
' arkgate-check --doctor where you are: one status light, one next action',
|
|
170
|
+
' arkgate-check --changed --base <ref> local / pre-push: checks touched files only',
|
|
164
171
|
' arkgate-check --strict-merge CI / merge gate (required GitHub status)',
|
|
165
172
|
' arkgate-check --sensors which sensors can ever be enforced (does not run analysis)',
|
|
166
173
|
'',
|
|
@@ -170,7 +177,9 @@ export function checkUsage() {
|
|
|
170
177
|
|
|
171
178
|
export function checkUsageAll() {
|
|
172
179
|
return [
|
|
173
|
-
'arkgate-check (alias ark-check) —
|
|
180
|
+
'arkgate-check (alias ark-check) — Write. Check. Ship.',
|
|
181
|
+
'When the agent writes a bad import, the write doesn’t land. Same check fails the PR.',
|
|
182
|
+
NORTH_STAR_ONE_LINE,
|
|
174
183
|
'',
|
|
175
184
|
'Usage: arkgate-check | ark-check (identical bins; product name ArkGate)',
|
|
176
185
|
' arkgate-check --version',
|
package/bin/lib/gate-files.mjs
CHANGED
|
@@ -257,6 +257,42 @@ export function hasArkMcpRegistration(root, relativePath = '.mcp.json') {
|
|
|
257
257
|
}
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
+
/**
|
|
261
|
+
* Shared MCP JSON destinations written by install-agent-gates (catalog + host copies).
|
|
262
|
+
* Upsert `mcpServers.ark` without clobbering sibling servers — same contract as
|
|
263
|
+
* mergeOpencodeArkMcp / mergeCursorArkHook.
|
|
264
|
+
*/
|
|
265
|
+
export const MCP_JSON_GATE_FILES = ['.mcp.json', '.cursor/mcp.json', '.agents/mcp_config.json'];
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Upsert mcpServers.ark into an existing MCP JSON document.
|
|
269
|
+
* Preserves sibling servers and unknown top-level keys. Returns null if unreadable.
|
|
270
|
+
*/
|
|
271
|
+
export function mergeArkMcpJson(existingText, generatedText) {
|
|
272
|
+
let existing;
|
|
273
|
+
let generated;
|
|
274
|
+
try {
|
|
275
|
+
existing = existingText && existingText.trim() ? JSON.parse(existingText) : {};
|
|
276
|
+
generated = JSON.parse(generatedText);
|
|
277
|
+
} catch {
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
if (!existing || typeof existing !== 'object' || Array.isArray(existing)) return null;
|
|
281
|
+
if (!generated || typeof generated !== 'object' || Array.isArray(generated)) return null;
|
|
282
|
+
const generatedArk = generated.mcpServers?.ark;
|
|
283
|
+
if (!generatedArk || typeof generatedArk !== 'object' || Array.isArray(generatedArk)) {
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
const servers =
|
|
287
|
+
existing.mcpServers &&
|
|
288
|
+
typeof existing.mcpServers === 'object' &&
|
|
289
|
+
!Array.isArray(existing.mcpServers)
|
|
290
|
+
? { ...existing.mcpServers }
|
|
291
|
+
: {};
|
|
292
|
+
const next = { ...existing, mcpServers: { ...servers, ark: generatedArk } };
|
|
293
|
+
return `${JSON.stringify(next, null, 2)}\n`;
|
|
294
|
+
}
|
|
295
|
+
|
|
260
296
|
function commandArkMcpArgs(command) {
|
|
261
297
|
if (typeof command !== 'string') return null;
|
|
262
298
|
const words = [];
|
|
@@ -747,12 +783,13 @@ export function writeTemplate(root, relativePath, content, force) {
|
|
|
747
783
|
return { relativePath, status: 'skipped-self-hosted' };
|
|
748
784
|
}
|
|
749
785
|
if (existing && !isArkAgentsContent(existing)) {
|
|
750
|
-
// Never
|
|
751
|
-
//
|
|
786
|
+
// Never replace a project-owned AGENTS.md — even with --force.
|
|
787
|
+
// Merge the Ark section once when missing so start / install-agent-gates
|
|
788
|
+
// leave a contract doctor accepts (issue #210). Subsequent runs leave it.
|
|
752
789
|
const hasArkSection =
|
|
753
790
|
/#\s*Ark(Gate)?\s+Enforcement\b/.test(existing) ||
|
|
754
791
|
/ark\.config\.json is authoritative/i.test(existing);
|
|
755
|
-
if (
|
|
792
|
+
if (isArkAgentsContent(content) && !hasArkSection) {
|
|
756
793
|
try {
|
|
757
794
|
const merged = `${existing.replace(/\s*$/, '')}\n\n---\n\n${content}`;
|
|
758
795
|
ensureDirForFile(fullPath);
|
|
@@ -11,6 +11,7 @@ import { effectiveCapabilityDeny } from './analysis-engine.mjs';
|
|
|
11
11
|
import { graphBlindSpotsHtml } from './graph-blind.mjs';
|
|
12
12
|
import { formatRulesUnderContractHtml } from './rules-under-contract.mjs';
|
|
13
13
|
import { formatArkRunHtml } from './ark-run-report.mjs';
|
|
14
|
+
import { formatArkOrderHtml } from './ark-order-report.mjs';
|
|
14
15
|
import { primaryImprovementCompassNextAction } from './improvement-compass.mjs';
|
|
15
16
|
|
|
16
17
|
// htmlEscape is injected by the caller (html-report.mjs) — importing it back
|
|
@@ -353,6 +354,7 @@ export function renderAdvisorySections(advisories, escape) {
|
|
|
353
354
|
graphBlindSpotsHtml(advisories.graphBlindSpots, esc),
|
|
354
355
|
rulesUnderContractHtml(advisories.rulesUnderContract),
|
|
355
356
|
formatArkRunHtml(advisories.arkRun, esc),
|
|
357
|
+
formatArkOrderHtml(advisories.arkOrder, esc),
|
|
356
358
|
]
|
|
357
359
|
.filter(Boolean)
|
|
358
360
|
.join('\n');
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
buildProductHonesty,
|
|
20
20
|
} from './enforcement-honesty.mjs';
|
|
21
21
|
import { summarizeRulesUnderContract } from './rules-under-contract.mjs';
|
|
22
|
-
import {
|
|
22
|
+
import { attachExtraDoctorSections } from './doctor-advisories.mjs';
|
|
23
23
|
import { readBaseline, baselineOccurrenceKeys } from './violations.mjs';
|
|
24
24
|
import { describePackageVersionDualTruth } from './field-install.mjs';
|
|
25
25
|
import { buildDoctorImprovementCompass } from './improvement-compass-doctor.mjs';
|
|
@@ -136,23 +136,12 @@ export function buildReportDepthPayload(
|
|
|
136
136
|
classifiedFiles: coverage?.governed?.classifiedFiles ?? null,
|
|
137
137
|
};
|
|
138
138
|
const rulesUnderContract = summarizeRulesUnderContract(root, config, undefined, classification);
|
|
139
|
-
const arkRun =
|
|
140
|
-
|
|
141
|
-
|
|
139
|
+
const { arkRun, arkOrder } = attachExtraDoctorSections(
|
|
140
|
+
rulesUnderContract,
|
|
141
|
+
config,
|
|
142
142
|
classification,
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
structureEnforced: rulesUnderContract?.mergePlanes?.structureSensors?.enforced,
|
|
146
|
-
structureTotal: rulesUnderContract?.mergePlanes?.structureSensors?.total,
|
|
147
|
-
structureAdvisory: rulesUnderContract?.mergePlanes?.structureSensors?.advisory,
|
|
148
|
-
invariantEnforced: rulesUnderContract?.mergePlanes?.invariants?.enforced,
|
|
149
|
-
invariantTotal: rulesUnderContract?.mergePlanes?.invariants?.total,
|
|
150
|
-
invariantAdvisory: rulesUnderContract?.mergePlanes?.invariants?.advisory,
|
|
151
|
-
covered: rulesUnderContract?.mergePlanes?.invariants?.covered,
|
|
152
|
-
uncovered: rulesUnderContract?.mergePlanes?.invariants?.uncovered,
|
|
153
|
-
},
|
|
154
|
-
});
|
|
155
|
-
if (rulesUnderContract?.mergePlanes) rulesUnderContract.mergePlanes = arkRun.mergePlanes;
|
|
143
|
+
activeViolations
|
|
144
|
+
);
|
|
156
145
|
// Single residual expression (parity with doctor): nextPilot || extractionCard.
|
|
157
146
|
const residualPilot =
|
|
158
147
|
pilotLoop?.nextPilot || pilotLoop?.extractionCard || null;
|
|
@@ -174,7 +163,7 @@ export function buildReportDepthPayload(
|
|
|
174
163
|
residualPilots: Boolean(residualPilot) && designFitness.designWeak === true,
|
|
175
164
|
pilotTarget: residualPilot?.pilotTarget ?? residualPilot?.pilot ?? null,
|
|
176
165
|
arkRulesMergeHonesty: rulesUnderContract?.mergePlanes
|
|
177
|
-
? { active: rulesUnderContract.active === true || arkRun?.active === true, ...rulesUnderContract.mergePlanes }
|
|
166
|
+
? { active: rulesUnderContract.active === true || arkRun?.active === true || arkOrder?.active === true, ...rulesUnderContract.mergePlanes }
|
|
178
167
|
: null,
|
|
179
168
|
primaryNextAction: postGreenPath?.action ?? dualTruthNext,
|
|
180
169
|
activeBlockingViolations: activeBlockingCount,
|
|
@@ -218,6 +207,7 @@ export function buildReportDepthPayload(
|
|
|
218
207
|
productHonesty,
|
|
219
208
|
mergePlanes: rulesUnderContract?.mergePlanes ?? null,
|
|
220
209
|
arkRun,
|
|
210
|
+
arkOrder,
|
|
221
211
|
improvementCompass,
|
|
222
212
|
deepModuleCoach,
|
|
223
213
|
},
|
package/bin/lib/html-report.mjs
CHANGED
|
@@ -152,6 +152,8 @@ export function buildReportSnapshot({
|
|
|
152
152
|
improvementCompass = null,
|
|
153
153
|
/** RN08 — thin status ArkRun slice (notAScore; residual count, never a score). */
|
|
154
154
|
arkRun = null,
|
|
155
|
+
/** Thin status ArkOrder slice (notAScore; residual count, never a score). */
|
|
156
|
+
arkOrder = null,
|
|
155
157
|
}) {
|
|
156
158
|
const layers = Array.isArray(config?.layers) ? config.layers : [];
|
|
157
159
|
const rules = Array.isArray(config?.rules) ? config.rules : [];
|
|
@@ -213,6 +215,20 @@ export function buildReportSnapshot({
|
|
|
213
215
|
: null,
|
|
214
216
|
};
|
|
215
217
|
}
|
|
218
|
+
if (arkOrder && typeof arkOrder === 'object' && arkOrder.notAScore === true) {
|
|
219
|
+
snapshot.arkOrder = {
|
|
220
|
+
notAScore: true,
|
|
221
|
+
present: arkOrder.active === true || arkOrder.present === true,
|
|
222
|
+
mode: arkOrder.mode === 'enforced' || arkOrder.mode === 'advisory' ? arkOrder.mode : null,
|
|
223
|
+
extraMergeTeeth: arkOrder.extraMergeTeeth === true,
|
|
224
|
+
residual:
|
|
225
|
+
typeof arkOrder.residual === 'number'
|
|
226
|
+
? arkOrder.residual
|
|
227
|
+
: typeof arkOrder.residual?.count === 'number'
|
|
228
|
+
? arkOrder.residual.count
|
|
229
|
+
: null,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
216
232
|
return snapshot;
|
|
217
233
|
}
|
|
218
234
|
|
|
@@ -37,6 +37,8 @@ import {
|
|
|
37
37
|
hasCheckArchitectureScript,
|
|
38
38
|
ensureTypecheckScript,
|
|
39
39
|
compactRouterHost,
|
|
40
|
+
mergeArkMcpJson,
|
|
41
|
+
MCP_JSON_GATE_FILES,
|
|
40
42
|
writeTemplate,
|
|
41
43
|
} from './gate-files.mjs';
|
|
42
44
|
import {
|
|
@@ -573,6 +575,27 @@ export function runInstallAgentGates(args) {
|
|
|
573
575
|
// Upsert ark-write-gate without requiring --force; never wipe sibling named hooks.
|
|
574
576
|
return writeTemplate(root, relativePath, merged, true);
|
|
575
577
|
}
|
|
578
|
+
if (MCP_JSON_GATE_FILES.includes(relativePath)) {
|
|
579
|
+
const fullPath = path.join(root, relativePath);
|
|
580
|
+
let existing = '';
|
|
581
|
+
try {
|
|
582
|
+
existing = fs.readFileSync(fullPath, 'utf8');
|
|
583
|
+
} catch {
|
|
584
|
+
// Missing MCP JSON → write generated ark server.
|
|
585
|
+
}
|
|
586
|
+
if (!existing) {
|
|
587
|
+
return writeTemplate(root, relativePath, content, true);
|
|
588
|
+
}
|
|
589
|
+
const merged = mergeArkMcpJson(existing, content);
|
|
590
|
+
if (merged == null) {
|
|
591
|
+
return args.force
|
|
592
|
+
? writeTemplate(root, relativePath, content, true)
|
|
593
|
+
: { relativePath, status: 'skipped-non-ark' };
|
|
594
|
+
}
|
|
595
|
+
if (merged === existing) return { relativePath, status: 'skipped' };
|
|
596
|
+
// Upsert mcpServers.ark without requiring --force; never wipe sibling servers.
|
|
597
|
+
return writeTemplate(root, relativePath, merged, true);
|
|
598
|
+
}
|
|
576
599
|
return writeTemplate(
|
|
577
600
|
root,
|
|
578
601
|
relativePath,
|
|
@@ -314,7 +314,7 @@ export function emitHostAllow(output, { antigravityStyle, cursorStyle }) {
|
|
|
314
314
|
*/
|
|
315
315
|
export function formatWriteGateDeny({ file, reason, ruleId, nextAction, extraLines = [] }) {
|
|
316
316
|
const target = file || 'this write';
|
|
317
|
-
const why = String(reason || '
|
|
317
|
+
const why = String(reason || 'a bad import — the write doesn’t land').replace(/\s+/g, ' ').trim();
|
|
318
318
|
const next =
|
|
319
319
|
nextAction && /place|move|import|port/i.test(nextAction)
|
|
320
320
|
? nextAction
|
package/bin/lib/product-copy.mjs
CHANGED
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
* common software words. See docs/product-voice.md.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
/** First-contact north star. Ordinary English. Spanish names once. */
|
|
10
|
+
export const NORTH_STAR_ONE_LINE =
|
|
11
|
+
'Contener · Guiar · Ordenar — contain the write, guide the next step, order leftover mess.';
|
|
12
|
+
|
|
9
13
|
/** Status-light leftover-design qualifier (was “design-weak”). */
|
|
10
14
|
export const LEFTOVER_DESIGN_LABEL = 'leftover design work';
|
|
11
15
|
|
package/bin/lib/remediation.mjs
CHANGED
|
@@ -239,17 +239,17 @@ export function deterministicNextAction(violation) {
|
|
|
239
239
|
case 'ARKORDER_KERNEL_IN_DOMAIN':
|
|
240
240
|
return 'Move the arkgate/order import out of the Domain-role layer into a plane root or adapter, then preflight again. Never mechanical-safe.';
|
|
241
241
|
case 'ARKORDER_GENERIC_UPDATE':
|
|
242
|
-
return '
|
|
242
|
+
return 'Don\'t use a generic update. First freeze with release(). Later, propose the change, then apply it.';
|
|
243
243
|
case 'ARKORDER_TOO_MANY_PARAMS':
|
|
244
244
|
return 'Cut ξ to the slow keys that actually slave the rest, then preflight again. Never mechanical-safe.';
|
|
245
245
|
case 'ARKORDER_INGEST_WRITES_XI':
|
|
246
246
|
return 'Keep ingest results as absorb/escalate_up/hold only. Change ξ with proposeRelease then apply(ProposeResult). Never mechanical-safe.';
|
|
247
247
|
case 'ARKORDER_XI_FIELD_WRITE':
|
|
248
248
|
return typeof violation.target === 'string' && violation.target.length > 0
|
|
249
|
-
? `
|
|
250
|
-
: '
|
|
249
|
+
? `Don't write ${violation.target} from a use-case. Take the event in, or change that choice through the valve (proposeRelease then apply), not a generic update.`
|
|
250
|
+
: "Don't write a named product choice from a use-case. Take the event in, or change that choice through the valve (proposeRelease then apply), not a generic update.";
|
|
251
251
|
case 'ARKORDER_UNVALVED_RELEASE':
|
|
252
|
-
return 'Change
|
|
252
|
+
return 'Change the choice with proposeRelease then apply. release() is only the first freeze. Never mechanical-safe.';
|
|
253
253
|
default:
|
|
254
254
|
if (typeof violation.ruleId === 'string' && violation.ruleId.startsWith('ARKRULE_')) {
|
|
255
255
|
return `Fix the ArkRule ${typeof violation.arkruleId === 'string' ? violation.arkruleId : violation.ruleId}, then preflight again.`;
|
|
@@ -528,7 +528,7 @@ export function enrichViolationWithFixClass(violation) {
|
|
|
528
528
|
enriched.effort = 'medium';
|
|
529
529
|
enriched.enthusiastHint =
|
|
530
530
|
violation.ruleId === 'ARKORDER_GENERIC_UPDATE'
|
|
531
|
-
? '
|
|
531
|
+
? 'Don\'t PATCH the billing plan. First freeze with release(), or propose the change then apply it.'
|
|
532
532
|
: violation.ruleId === 'ARKORDER_KERNEL_IN_DOMAIN'
|
|
533
533
|
? 'Domain stays plane-free. Import arkgate/order only from a listed plane root.'
|
|
534
534
|
: violation.ruleId === 'ARKORDER_TOO_MANY_PARAMS'
|
|
@@ -536,7 +536,7 @@ export function enrichViolationWithFixClass(violation) {
|
|
|
536
536
|
: violation.ruleId === 'ARKORDER_INGEST_WRITES_XI'
|
|
537
537
|
? 'ingest can absorb or escalate. It never writes a new house.'
|
|
538
538
|
: violation.ruleId === 'ARKORDER_XI_FIELD_WRITE'
|
|
539
|
-
? 'Name the
|
|
539
|
+
? 'Name the few big choices in arkOrder.xiKeys. Invoices and seats still flow; changing the plan goes through the valve, not a generic update.'
|
|
540
540
|
: violation.ruleId === 'ARKORDER_INFORMATION_BUDGET'
|
|
541
541
|
? 'A scale may not observe a denied kind. Cut it from the projector or from cannotObserve.'
|
|
542
542
|
: violation.ruleId === 'ARKORDER_XI_TTL'
|
|
@@ -544,7 +544,7 @@ export function enrichViolationWithFixClass(violation) {
|
|
|
544
544
|
: violation.ruleId === 'ARKORDER_STALE_SIGMA'
|
|
545
545
|
? 'Refresh σ. ξ does not expire.'
|
|
546
546
|
: violation.ruleId === 'ARKORDER_UNVALVED_RELEASE'
|
|
547
|
-
? 'The
|
|
547
|
+
? 'The choice is already frozen. proposeRelease then apply — do not call release() again with a different value.'
|
|
548
548
|
: 'Call createOrderPlane from arkgate/order in a listed plane root so the app actually freezes a pattern.';
|
|
549
549
|
break;
|
|
550
550
|
default:
|