arkgate 4.2.1 → 4.3.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 +59 -3
- package/README.md +19 -6
- package/bin/ark-mcp-runtime.mjs +64 -0
- package/bin/ark.mjs +55 -1
- package/bin/lib/adapter-contract.mjs +88 -5
- package/bin/lib/agent-projection-command.mjs +396 -0
- package/bin/lib/agent-projection.mjs +319 -0
- package/bin/lib/agent-skills-package.mjs +266 -0
- package/bin/lib/baseline-key.mjs +32 -0
- package/bin/lib/ci-and-commands.mjs +44 -0
- package/bin/lib/diagnostic-catalog.mjs +155 -0
- package/bin/lib/status-command.mjs +369 -0
- package/bin/lib/status-manifest.mjs +394 -0
- package/dist/eslint/index.cjs +3 -3
- package/dist/eslint/index.js +3 -3
- package/dist/index.cjs +46 -11
- package/dist/index.d.ts +729 -6
- package/dist/index.js +46 -11
- package/docs/README.md +6 -6
- package/docs/agent-guide.md +112 -14
- package/docs/configuration.md +7 -0
- package/docs/develop.md +8 -0
- package/docs/diagnostics.md +606 -0
- package/docs/package-surface.md +18 -8
- package/docs/product-voice.md +45 -0
- package/docs/use.md +23 -0
- package/package.json +7 -1
- package/schemas/ark.analysis-result.schema.json +14 -1
- package/schemas/ark.status-manifest.schema.json +244 -0
- package/server.json +2 -2
- package/templates/agent-skills/README.md +59 -0
- package/templates/agent-skills/ark-adopt/SKILL.md +171 -0
- package/templates/agent-skills/ark-architect/SKILL.md +175 -0
- package/templates/agent-skills/ark-autopilot/SKILL.md +242 -0
- package/templates/agent-skills/ark-contract/SKILL.md +136 -0
- package/templates/agent-skills/ark-coverage/SKILL.md +167 -0
- package/templates/agent-skills/ark-explain/SKILL.md +210 -0
- package/templates/agent-skills/ark-explore/SKILL.md +377 -0
- package/templates/agent-skills/ark-fix/SKILL.md +185 -0
- package/templates/agent-skills/ark-loop/SKILL.md +180 -0
- package/templates/agent-skills/ark-place/SKILL.md +162 -0
- package/templates/agent-skills/ark-runtime/SKILL.md +120 -0
- package/templates/agent-skills/ark-think/SKILL.md +133 -0
- package/templates/agent-skills/ark-upgrade/SKILL.md +218 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,12 +5,68 @@ in the immutable pre-2.0 archive linked below.
|
|
|
5
5
|
|
|
6
6
|
## Unreleased
|
|
7
7
|
|
|
8
|
-
## 4.
|
|
8
|
+
## 4.3.0 — 2026-08-09 (prepared)
|
|
9
|
+
|
|
10
|
+
**Minor** over 4.2.1. Phase ACS — agent contract surface: diagnostic code catalog, unified
|
|
11
|
+
status snapshot, version-matched agent projection, Agent Skills packaging of the existing 13
|
|
12
|
+
skills, stable finding refs, and maintainer placement A/B eval. **No required config migration.**
|
|
13
|
+
Codex remains advisory at write time. Skills and AGENTS projection never enforce. Z09 / RB-11
|
|
14
|
+
remain open. **Status: prepared** (`arkgate@4.3.0` not published yet; **4.2.1** remains on npm
|
|
15
|
+
`latest` until publication).
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- **Diagnostic code catalog (ACS02):** closed public `ruleId` vocabulary with why/fix text and
|
|
20
|
+
docs anchors (`docs/diagnostics.md#RULE_ID`). Domain source `src/domain/diagnosticCatalog.ts`,
|
|
21
|
+
generated CLI mirror `bin/lib/diagnostic-catalog.mjs`, root exports (`DIAGNOSTIC_CATALOG`,
|
|
22
|
+
`getDiagnosticCatalogEntry`, `diagnosticDocsPath`, …). Remediation/parity fixtures forbid
|
|
23
|
+
unknown production codes. No new rule semantics — cataloguing only.
|
|
24
|
+
- **Unified status manifest (ACS03):** `ark status --json` (+ MCP `ark_status`) returns one
|
|
25
|
+
session/project snapshot — identity binding, honest write-path activation, last-check summary,
|
|
26
|
+
ArkRules residual counts, primary next action. Domain `src/domain/statusManifest.ts`, generated
|
|
27
|
+
pure `bin/lib/status-manifest.mjs`, schema `arkgate/schema/status-manifest`, root exports
|
|
28
|
+
(`buildStatusManifest`, `ARK_STATUS_MANIFEST_SCHEMA`, …). Never prompts; `CI=1` forces JSON.
|
|
29
|
+
Optional `--expected-root` / `--expected-project-id` for matched vs stale identity. Not a score.
|
|
30
|
+
- **Version-matched agent projection (ACS04):** `ark agents-md` regenerates a managed
|
|
31
|
+
AGENTS.md projection block stamped with the installed package version + contract summary
|
|
32
|
+
(layers, diagnostic short list). Install/upgrade templates (`agentInstructions` /
|
|
33
|
+
`compactAgentInstructions`) embed the same block. Content-identity merge preserves customized
|
|
34
|
+
regions outside markers. Explicitly **non-authoritative** — enforcement remains ark-check /
|
|
35
|
+
hooks / CI; projection is never a gate input. Domain `src/domain/agentProjection.ts`, generated
|
|
36
|
+
pure `bin/lib/agent-projection.mjs`, root exports (`buildAgentProjectionBlock`,
|
|
37
|
+
`mergeAgentProjectionDocument`, …). Drift: `ark agents-md --check`.
|
|
38
|
+
- **Agent Skills packaging (ACS05):** the existing **13** `/ark-*` skills ship in an Agent
|
|
39
|
+
Skills–compatible layout at `templates/agent-skills/<name>/SKILL.md` (1:1 with flat
|
|
40
|
+
`templates/skills/*.md`). Ecosystem install: `npx skills add ./node_modules/arkgate/templates/agent-skills`
|
|
41
|
+
(or the GitHub tree). Ark install path unchanged (`--install-agent-gates` / `--skills-only`).
|
|
42
|
+
Domain `src/domain/agentSkillsPackage.ts` (frozen `ARK_SKILL_NAMES`, frontmatter/layout
|
|
43
|
+
validation), generated pure `bin/lib/agent-skills-package.mjs`, `npm run generate:agent-skills` /
|
|
44
|
+
`check:agent-skills`. **No new skill names.** Skills remain non-enforcing.
|
|
45
|
+
- **Stable finding refs (ACS06):** analysis-result schema **`1.5`** — every factory-emitted
|
|
46
|
+
diagnostic (CLI JSON, MCP, opt-in `ARK_REPAIR_JSON` repair payload) includes `findingRef`
|
|
47
|
+
(`fnv1a-…`), baseline-compatible `targetKey`, and `docsCodePath`. `targetKey` is exactly the
|
|
48
|
+
baseline (occurrence) freeze key so multi-turn agent loops never orphan baselined debt.
|
|
49
|
+
Domain helpers on `adapterContract` / `baselineKey`; multi-turn fixture
|
|
50
|
+
`tests/fixtures/finding-refs/multi-turn-stability.json`.
|
|
51
|
+
- **Maintainer placement A/B eval (ACS07):** under `eval/placement-ab/`, fixture pairs compare
|
|
52
|
+
agent placement **with** Ark gates+skills (`ark-place` / `ark-architect` markers) vs
|
|
53
|
+
**without**. CI-safe dry mode (`npm run eval:placement-ab`) measures real `ark-check` on both
|
|
54
|
+
arms; results path `eval/placement-ab-report.json` + template
|
|
55
|
+
`eval/placement-ab/results/RESULTS.template.json`. Live mode optional and never fails when no
|
|
56
|
+
agent/API key is present. **Not a product score.**
|
|
57
|
+
|
|
58
|
+
### Docs / claims (ACS08)
|
|
59
|
+
|
|
60
|
+
- Claims matrix refreshed for 4.3.0 agent-contract statements (**0 Contradicted** on public
|
|
61
|
+
lanes). Release notes at `docs/releases/4.3.0.md` (**Status: prepared**). Public lanes name
|
|
62
|
+
the prepared candidate while npm `latest` remains **4.2.1** until Trusted Publishing.
|
|
63
|
+
|
|
64
|
+
## 4.2.1 — 2026-08-08 (published)
|
|
9
65
|
|
|
10
66
|
**Patch** over 4.2.0. Next.js **16.3** field compatibility: root `proxy.ts` (Next 16 network-boundary
|
|
11
67
|
rename of middleware) is scanned and classified; eval fixtures and release-surface pins track
|
|
12
68
|
`next@16.3.0`. **No required config migration.** Codex remains advisory at write time.
|
|
13
|
-
**Status:
|
|
69
|
+
**Status: published** (`arkgate@4.2.1` on npm `latest`).
|
|
14
70
|
|
|
15
71
|
### Fixed
|
|
16
72
|
|
|
@@ -39,7 +95,7 @@ handshake, and project-bound `ark_manifest`; cross-project/config paths fail bef
|
|
|
39
95
|
ArkRules analysis; Codex setup distinguishes files configured on disk from a runtime observed
|
|
40
96
|
after restart. **No required config migration.** Legacy MCP calls remain callable but explicitly
|
|
41
97
|
non-authoritative until bound. Codex remains advisory at write time. **Status: published**
|
|
42
|
-
(`arkgate@4.2.0
|
|
98
|
+
(`arkgate@4.2.0`; superseded by 4.2.1 on `latest`).
|
|
43
99
|
|
|
44
100
|
### Added
|
|
45
101
|
|
package/README.md
CHANGED
|
@@ -16,9 +16,9 @@ and makes sure a “green” check means something real.
|
|
|
16
16
|
|
|
17
17
|
</div>
|
|
18
18
|
|
|
19
|
-
> **ArkGate 4.
|
|
20
|
-
> **4.2.
|
|
21
|
-
> [4.
|
|
19
|
+
> **ArkGate 4.3.0** is prepared (agent contract surface: catalog, status, projection, skills packaging, finding refs);
|
|
20
|
+
> **4.2.1** remains on npm `latest` until publication.
|
|
21
|
+
> [4.3.0 candidate](docs/releases/4.3.0.md) · [4.2.1](docs/releases/4.2.1.md) · [4.2.0](docs/releases/4.2.0.md) · [Docs hub](docs/README.md) · [Product voice](docs/product-voice.md)
|
|
22
22
|
|
|
23
23
|
---
|
|
24
24
|
|
|
@@ -79,6 +79,15 @@ Details: [configuration](docs/configuration.md#arkrules-intra-layer-opt-in) · [
|
|
|
79
79
|
|
|
80
80
|
**Name note:** npm package `arkgate` — not affiliated with the separate Archgate CLI project.
|
|
81
81
|
|
|
82
|
+
### When not to adopt
|
|
83
|
+
|
|
84
|
+
ArkGate is overkill for small trees with **no AI agents** and **no multi-layer boundaries**, for
|
|
85
|
+
single-developer hobby CRUDs under no integration pressure, and for teams that will not maintain
|
|
86
|
+
`ark.config.json` or a **required** CI status running `arkgate-check --strict-merge`. In those
|
|
87
|
+
cases stay with a boundary linter alone (see [Why not only ESLint / Nx / cruiser?](#why-not-only-eslint--nx--cruiser)).
|
|
88
|
+
Anyone path: [docs/use.md — When not to adopt](docs/use.md#when-not-to-adopt). Limits of a green
|
|
89
|
+
check: [4.3.0 — What ArkGate is / isn't](docs/releases/4.3.0.md#what-arkgate-is--isnt).
|
|
90
|
+
|
|
82
91
|
---
|
|
83
92
|
|
|
84
93
|
## Status lights (not settings)
|
|
@@ -158,14 +167,17 @@ expectation.
|
|
|
158
167
|
|
|
159
168
|
```bash
|
|
160
169
|
npx arkgate start --apply
|
|
170
|
+
npx arkgate status --json # session/project snapshot (identity, activation, last check)
|
|
161
171
|
npx arkgate-check --doctor
|
|
162
172
|
npx arkgate-check --plan
|
|
163
173
|
npx arkgate-check --coverage
|
|
164
174
|
npx arkgate-check --strict-merge # CI / required status
|
|
165
175
|
npx arkgate-check --install-agent-gates --tools claude,cursor,codex,grok
|
|
176
|
+
# optional: same 13 skills via Agent Skills ecosystem (no new names)
|
|
177
|
+
# npx skills add ./node_modules/arkgate/templates/agent-skills
|
|
166
178
|
```
|
|
167
179
|
|
|
168
|
-
More: [docs/develop.md](docs/develop.md) · enthusiast track: [docs/enthusiast/](docs/enthusiast/README.md)
|
|
180
|
+
More: [docs/develop.md](docs/develop.md) · skills install: [docs/agent-guide.md](docs/agent-guide.md#install-skills-ark-and-ecosystem) · enthusiast track: [docs/enthusiast/](docs/enthusiast/README.md)
|
|
169
181
|
|
|
170
182
|
---
|
|
171
183
|
|
|
@@ -194,8 +206,9 @@ for real systems. Details: [docs/production-hardening.md](docs/production-harden
|
|
|
194
206
|
| Config · package surface · TS | [configuration](docs/configuration.md) · [package-surface](docs/package-surface.md) · [typescript-support](docs/typescript-support.md) |
|
|
195
207
|
| Brownfield | [docs/brownfield-adoption.md](docs/brownfield-adoption.md) |
|
|
196
208
|
| Security | [SECURITY.md](SECURITY.md) |
|
|
197
|
-
| Prepared candidate (4.
|
|
198
|
-
| Current published (4.2.
|
|
209
|
+
| Prepared candidate (4.3.0) | [docs/releases/4.3.0.md](docs/releases/4.3.0.md) · [CHANGELOG](CHANGELOG.md) |
|
|
210
|
+
| Current published (4.2.1) | [docs/releases/4.2.1.md](docs/releases/4.2.1.md) |
|
|
211
|
+
| Previous (4.2.0) | [docs/releases/4.2.0.md](docs/releases/4.2.0.md) |
|
|
199
212
|
| Previous (4.1.1) | [docs/releases/4.1.1.md](docs/releases/4.1.1.md) |
|
|
200
213
|
| Previous (4.1.0) | [docs/releases/4.1.0.md](docs/releases/4.1.0.md) |
|
|
201
214
|
| Previous patch (4.0.1) | [docs/releases/4.0.1.md](docs/releases/4.0.1.md) |
|
package/bin/ark-mcp-runtime.mjs
CHANGED
|
@@ -36,6 +36,8 @@ import {
|
|
|
36
36
|
createProjectId,
|
|
37
37
|
createProjectIdentity,
|
|
38
38
|
} from './lib/project-identity.mjs';
|
|
39
|
+
import { buildProjectStatusManifest } from './lib/status-command.mjs';
|
|
40
|
+
import { ARK_STATUS_MANIFEST_SCHEMA } from './lib/status-manifest.mjs';
|
|
39
41
|
|
|
40
42
|
function arkRulesCatalogForManifest(snapshot) {
|
|
41
43
|
if (snapshot?.errors?.length || !snapshot?.arkRules) return {};
|
|
@@ -2143,6 +2145,25 @@ export async function runArkMcp({ hookInput } = {}) {
|
|
|
2143
2145
|
'— never a numeric score. Same plane as ark-check --rules-inventory.',
|
|
2144
2146
|
inputSchema: { type: 'object', properties: {} },
|
|
2145
2147
|
},
|
|
2148
|
+
{
|
|
2149
|
+
name: 'ark_status',
|
|
2150
|
+
description:
|
|
2151
|
+
'Unified session/project status manifest (ACS03): project identity binding, honest write-path ' +
|
|
2152
|
+
'activation, last-check summary, ArkRules residual counts, and primary next action. Same ' +
|
|
2153
|
+
'envelope as `ark status --json`. Never prompts; never a numeric score. Prefer after ' +
|
|
2154
|
+
'ark_identity so project.expectedRoot is bound.',
|
|
2155
|
+
inputSchema: { type: 'object', properties: {} },
|
|
2156
|
+
outputSchema: {
|
|
2157
|
+
type: 'object',
|
|
2158
|
+
additionalProperties: true,
|
|
2159
|
+
properties: {
|
|
2160
|
+
status: ARK_STATUS_MANIFEST_SCHEMA,
|
|
2161
|
+
projectIdentity: projectIdentityOutputSchema,
|
|
2162
|
+
binding: PROJECT_BINDING_SCHEMA,
|
|
2163
|
+
authoritative: { type: 'boolean' },
|
|
2164
|
+
},
|
|
2165
|
+
},
|
|
2166
|
+
},
|
|
2146
2167
|
];
|
|
2147
2168
|
|
|
2148
2169
|
for (const tool of TOOLS) {
|
|
@@ -2664,6 +2685,48 @@ export async function runArkMcp({ hookInput } = {}) {
|
|
|
2664
2685
|
}
|
|
2665
2686
|
}
|
|
2666
2687
|
|
|
2688
|
+
function runStatusTool(_params, binding) {
|
|
2689
|
+
try {
|
|
2690
|
+
const status = buildProjectStatusManifest({
|
|
2691
|
+
root: args.root,
|
|
2692
|
+
config: path.basename(configPath) === 'ark.config.json' ? 'ark.config.json' : configPath,
|
|
2693
|
+
expectedRoot: binding?.expectedRoot ?? _params?.arguments?.project?.expectedRoot,
|
|
2694
|
+
expectedProjectId:
|
|
2695
|
+
binding?.expectedProjectId ?? _params?.arguments?.project?.expectedProjectId,
|
|
2696
|
+
arkgateVersion: ark.version,
|
|
2697
|
+
});
|
|
2698
|
+
// Prefer MCP binding status when the tool framework already evaluated expectation.
|
|
2699
|
+
if (binding && typeof binding.status === 'string') {
|
|
2700
|
+
status.projectIdentity.binding = binding.status;
|
|
2701
|
+
status.projectIdentity.authoritative = binding.authoritative === true;
|
|
2702
|
+
if (binding.code) status.projectIdentity.code = binding.code;
|
|
2703
|
+
if (binding.message) status.projectIdentity.message = binding.message;
|
|
2704
|
+
if (binding.status === 'mismatch') {
|
|
2705
|
+
status.nextAction = {
|
|
2706
|
+
id: 'rebind-project-identity',
|
|
2707
|
+
summary:
|
|
2708
|
+
binding.message ||
|
|
2709
|
+
'Project expectation does not match this MCP process — re-run ark_identity with the correct root.',
|
|
2710
|
+
};
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
2713
|
+
const payload = {
|
|
2714
|
+
ok: binding?.status !== 'mismatch',
|
|
2715
|
+
status,
|
|
2716
|
+
};
|
|
2717
|
+
return {
|
|
2718
|
+
content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }],
|
|
2719
|
+
structuredContent: payload,
|
|
2720
|
+
isError: binding?.status === 'mismatch',
|
|
2721
|
+
};
|
|
2722
|
+
} catch (error) {
|
|
2723
|
+
return {
|
|
2724
|
+
content: [{ type: 'text', text: error instanceof Error ? error.message : String(error) }],
|
|
2725
|
+
isError: true,
|
|
2726
|
+
};
|
|
2727
|
+
}
|
|
2728
|
+
}
|
|
2729
|
+
|
|
2667
2730
|
function runRulesInventoryTool() {
|
|
2668
2731
|
try {
|
|
2669
2732
|
const governed = collectGovernedFiles(args.root, config);
|
|
@@ -2772,6 +2835,7 @@ export async function runArkMcp({ hookInput } = {}) {
|
|
|
2772
2835
|
ark_recommend: runRecommendTool,
|
|
2773
2836
|
ark_suggest_include: runSuggestIncludeTool,
|
|
2774
2837
|
ark_rules_inventory: runRulesInventoryTool,
|
|
2838
|
+
ark_status: runStatusTool,
|
|
2775
2839
|
};
|
|
2776
2840
|
|
|
2777
2841
|
const send = (msg) => process.stdout.write(`${JSON.stringify(msg)}\n`);
|
package/bin/ark.mjs
CHANGED
|
@@ -33,6 +33,8 @@ import {
|
|
|
33
33
|
readChangeSetFile,
|
|
34
34
|
renderChangePreflight,
|
|
35
35
|
} from './lib/prepare-change.mjs';
|
|
36
|
+
import { runStatusCommand } from './lib/status-command.mjs';
|
|
37
|
+
import { runAgentProjectionCommand } from './lib/agent-projection-command.mjs';
|
|
36
38
|
|
|
37
39
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
38
40
|
const arkCheck = path.join(here, 'ark-check.mjs');
|
|
@@ -81,6 +83,11 @@ function parseArgs(argv) {
|
|
|
81
83
|
skipPackageManager: false,
|
|
82
84
|
removeHost: undefined,
|
|
83
85
|
requireWriteHook: undefined,
|
|
86
|
+
expectedRoot: undefined,
|
|
87
|
+
expectedProjectId: undefined,
|
|
88
|
+
write: false,
|
|
89
|
+
check: false,
|
|
90
|
+
stdout: false,
|
|
84
91
|
help: false,
|
|
85
92
|
version: false,
|
|
86
93
|
};
|
|
@@ -127,6 +134,11 @@ function parseArgs(argv) {
|
|
|
127
134
|
else if (arg === '--require-write-hook') {
|
|
128
135
|
args.requireWriteHook = requireValue(arg, i++).trim().toLowerCase();
|
|
129
136
|
}
|
|
137
|
+
else if (arg === '--expected-root') args.expectedRoot = path.resolve(requireValue(arg, i++));
|
|
138
|
+
else if (arg === '--expected-project-id') args.expectedProjectId = requireValue(arg, i++);
|
|
139
|
+
else if (arg === '--write') args.write = true;
|
|
140
|
+
else if (arg === '--check') args.check = true;
|
|
141
|
+
else if (arg === '--stdout') args.stdout = true;
|
|
130
142
|
else if (arg === '--help' || arg === '-h' || arg === 'help') args.help = true;
|
|
131
143
|
else if (arg === '--version' || arg === '-V') args.version = true;
|
|
132
144
|
else if (!arg.startsWith('-') && args.command === undefined) args.command = arg;
|
|
@@ -143,6 +155,10 @@ function usage() {
|
|
|
143
155
|
[--archetype <playbook-id>] [--tools <list>] [--require-write-hook <host>] [--yes] [--force] [--no-strict]
|
|
144
156
|
ark upgrade [--root <project>] [--tools <list>] [--apply] [--plan-digest <sha256>] [--accept-conflicts] [--json] [--no-install] [--no-strict]
|
|
145
157
|
ark preflight --changes <change-set.json> [--change-map <map.json>] [--root <project>] [--config ark.config.json] [--manifest <manifest.json>] [--tsconfig <tsconfig.json>] [--json]
|
|
158
|
+
ark status [--root <project>] [--config ark.config.json] [--json]
|
|
159
|
+
[--expected-root <abs>] [--expected-project-id sha256:…] [--tools <host>]
|
|
160
|
+
ark agents-md [--root <project>] [--config ark.config.json] [--write] [--check] [--stdout] [--json]
|
|
161
|
+
[--tools <host>]
|
|
146
162
|
|
|
147
163
|
Commands:
|
|
148
164
|
start New here? Analyze and preview the complete setup. Read-only unless --apply.
|
|
@@ -152,6 +168,13 @@ Commands:
|
|
|
152
168
|
--apply --no-install applies those exact bytes and verifies them.
|
|
153
169
|
(alias: ark update)
|
|
154
170
|
preflight Validate one atomic create/update/delete set without writing project files.
|
|
171
|
+
status Unified session/project manifest (identity, activation, last check, rules).
|
|
172
|
+
Never prompts. Prefer --json for agents; CI=1 forces JSON.
|
|
173
|
+
agents-md Version-matched agent contract projection (ACS04). Stamps package version +
|
|
174
|
+
contract summary into a managed AGENTS.md block. Non-authoritative — not a
|
|
175
|
+
gate input. Preview by default; --write merges without clobbering outside
|
|
176
|
+
regions; --check fails on version drift; --stdout prints the block only.
|
|
177
|
+
(aliases: agents-md, agent-projection)
|
|
155
178
|
|
|
156
179
|
Options:
|
|
157
180
|
--yes Non-interactive defaults: create config if needed, install gate templates, run strict check.
|
|
@@ -164,7 +187,12 @@ Options:
|
|
|
164
187
|
--accept-conflicts
|
|
165
188
|
Allow upgrade to recreate deleted managed assets or replace recorded conflicts.
|
|
166
189
|
--plan-digest Digest emitted by an upgrade preview; required to apply managed bytes.
|
|
167
|
-
--json Emit the start/upgrade preview as deterministic machine-readable JSON.
|
|
190
|
+
--json Emit the start/upgrade/status/agents-md preview as deterministic machine-readable JSON.
|
|
191
|
+
--write For agents-md: merge the version-matched projection into AGENTS.md.
|
|
192
|
+
--check For agents-md: exit 1 when projection stamp drifts from package version.
|
|
193
|
+
--stdout For agents-md: print the projection block only (no file write).
|
|
194
|
+
--expected-root / --expected-project-id
|
|
195
|
+
Optional project expectation for status (MCP-compatible binding check).
|
|
168
196
|
--preset Start from a named architecture preset instead of detection.
|
|
169
197
|
--archetype Application shape from templates/architecture-playbook.json (maps to the matching preset).
|
|
170
198
|
Valid ids: crud-product, api-backend, frontend-surface, library-sdk, cli-utility,
|
|
@@ -900,6 +928,32 @@ async function main() {
|
|
|
900
928
|
}
|
|
901
929
|
}
|
|
902
930
|
|
|
931
|
+
if (args.command === 'status') {
|
|
932
|
+
return runStatusCommand({
|
|
933
|
+
root: args.root,
|
|
934
|
+
config: args.config,
|
|
935
|
+
json: args.json,
|
|
936
|
+
expectedRoot: args.expectedRoot,
|
|
937
|
+
expectedProjectId: args.expectedProjectId,
|
|
938
|
+
host: args.tools,
|
|
939
|
+
arkgateVersion: cliVersion(),
|
|
940
|
+
});
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
if (args.command === 'agents-md' || args.command === 'agent-projection') {
|
|
944
|
+
return runAgentProjectionCommand({
|
|
945
|
+
root: args.root,
|
|
946
|
+
config: args.config,
|
|
947
|
+
json: args.json,
|
|
948
|
+
write: args.write,
|
|
949
|
+
apply: args.apply,
|
|
950
|
+
check: args.check,
|
|
951
|
+
stdout: args.stdout,
|
|
952
|
+
host: args.tools,
|
|
953
|
+
arkgateVersion: cliVersion(),
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
|
|
903
957
|
console.error(`Unknown command: ${args.command}`);
|
|
904
958
|
console.error(usage());
|
|
905
959
|
return 2;
|
|
@@ -8,14 +8,72 @@
|
|
|
8
8
|
* Pure CLI helper (bin/lib/adapter-contract.mjs). Zero Node I/O.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
/**
|
|
12
|
-
|
|
11
|
+
/**
|
|
12
|
+
* 1.5 adds stable finding refs on every factory-emitted diagnostic (ACS06):
|
|
13
|
+
* `findingRef`, `targetKey` (baseline-compatible), `docsCodePath`.
|
|
14
|
+
* 1.4 added optional evidence.arkruleId + evidence.arkruleSource (ADR 0012 / AR03).
|
|
15
|
+
*/
|
|
16
|
+
export const ARK_ANALYSIS_RESULT_SCHEMA_VERSION = '1.5';
|
|
17
|
+
/** Repo-relative diagnostics docs path (parity with ACS02 diagnostic catalog). */
|
|
18
|
+
export const ADAPTER_DIAGNOSTIC_DOCS_RELATIVE_PATH = 'docs/diagnostics.md';
|
|
13
19
|
function text(value) {
|
|
14
20
|
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
15
21
|
}
|
|
16
22
|
function positiveInteger(value, fallback) {
|
|
17
23
|
return Number.isInteger(value) && Number(value) > 0 ? Number(value) : fallback;
|
|
18
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Baseline-compatible target key for a violation input.
|
|
27
|
+
* Field order and empty-string fallbacks **must** match `baselineKey` in
|
|
28
|
+
* `baselineKey.ts` — parity tests guard this so finding refs never orphan freezes.
|
|
29
|
+
*
|
|
30
|
+
* Note: uses raw ruleId/file strings (including empty) the same way baseline does;
|
|
31
|
+
* display `ruleId` / `location.file` may still normalize to ARK_UNKNOWN / `<unknown>`.
|
|
32
|
+
*/
|
|
33
|
+
export function adapterFindingTargetKey(violation) {
|
|
34
|
+
const ruleId = typeof violation.ruleId === 'string'
|
|
35
|
+
? violation.ruleId
|
|
36
|
+
: typeof violation.code === 'string'
|
|
37
|
+
? violation.code
|
|
38
|
+
: undefined;
|
|
39
|
+
const file = typeof violation.file === 'string' ? violation.file : undefined;
|
|
40
|
+
const fromLayer = typeof violation.fromLayer === 'string' ? violation.fromLayer : undefined;
|
|
41
|
+
const toLayer = typeof violation.toLayer === 'string' ? violation.toLayer : undefined;
|
|
42
|
+
const target = typeof violation.target === 'string' ? violation.target : undefined;
|
|
43
|
+
return [
|
|
44
|
+
ruleId,
|
|
45
|
+
file,
|
|
46
|
+
fromLayer ?? '',
|
|
47
|
+
toLayer ?? '',
|
|
48
|
+
target ?? '',
|
|
49
|
+
].join('|');
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Occurrence-aware target keys for a violation list (parity with baselineOccurrenceKeys).
|
|
53
|
+
* First occurrence keeps the historical base key; duplicates get `#N`.
|
|
54
|
+
*/
|
|
55
|
+
export function adapterFindingOccurrenceTargetKeys(violations) {
|
|
56
|
+
const counts = new Map();
|
|
57
|
+
return violations.map((violation) => {
|
|
58
|
+
const base = adapterFindingTargetKey(violation);
|
|
59
|
+
const occurrence = (counts.get(base) ?? 0) + 1;
|
|
60
|
+
counts.set(base, occurrence);
|
|
61
|
+
return occurrence === 1 ? base : `${base}#${occurrence}`;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/** FNV-1a finding ref from a baseline-compatible targetKey (not a security hash). */
|
|
65
|
+
export function adapterFindingRefFromTargetKey(targetKey) {
|
|
66
|
+
let hash = 0x811c9dc5;
|
|
67
|
+
for (let index = 0; index < targetKey.length; index += 1) {
|
|
68
|
+
hash ^= targetKey.charCodeAt(index);
|
|
69
|
+
hash = Math.imul(hash, 0x01000193);
|
|
70
|
+
}
|
|
71
|
+
return `fnv1a-${(hash >>> 0).toString(16).padStart(8, '0')}`;
|
|
72
|
+
}
|
|
73
|
+
/** Package-relative docs path with fragment for a public ruleId. */
|
|
74
|
+
export function adapterDocsCodePath(ruleId) {
|
|
75
|
+
return `${ADAPTER_DIAGNOSTIC_DOCS_RELATIVE_PATH}#${ruleId}`;
|
|
76
|
+
}
|
|
19
77
|
function nextActionForDiagnostic(ruleId, evidence, violation) {
|
|
20
78
|
if (ruleId === 'LAYER_IMPORT_VIOLATION') {
|
|
21
79
|
if (evidence.typeOnly ||
|
|
@@ -51,7 +109,12 @@ function nextActionForDiagnostic(ruleId, evidence, violation) {
|
|
|
51
109
|
}
|
|
52
110
|
return `Resolve ${ruleId} without weakening ark.config.json, then run Ark again.`;
|
|
53
111
|
}
|
|
54
|
-
export function toAdapterDiagnostic(violation, fallbackSeverity = 'error'
|
|
112
|
+
export function toAdapterDiagnostic(violation, fallbackSeverity = 'error',
|
|
113
|
+
/**
|
|
114
|
+
* Optional precomputed baseline-compatible targetKey (e.g. occurrence-aware from
|
|
115
|
+
* `adapterFindingOccurrenceTargetKeys`). When omitted, uses the first-occurrence key.
|
|
116
|
+
*/
|
|
117
|
+
targetKeyOverride) {
|
|
55
118
|
const ruleId = text(violation.ruleId) ?? text(violation.code) ?? 'ARK_UNKNOWN';
|
|
56
119
|
// Type-only placement debt (failsStrict:false / typeOnly non-peer) is warning severity.
|
|
57
120
|
const severity = violation.severity === 'warning' ||
|
|
@@ -84,6 +147,8 @@ export function toAdapterDiagnostic(violation, fallbackSeverity = 'error') {
|
|
|
84
147
|
...(text(violation.arkruleId) ? { arkruleId: text(violation.arkruleId) } : {}),
|
|
85
148
|
...(text(violation.arkruleSource) ? { arkruleSource: text(violation.arkruleSource) } : {}),
|
|
86
149
|
};
|
|
150
|
+
const targetKey = targetKeyOverride ?? adapterFindingTargetKey(violation);
|
|
151
|
+
const findingRef = adapterFindingRefFromTargetKey(targetKey);
|
|
87
152
|
return {
|
|
88
153
|
ruleId,
|
|
89
154
|
severity,
|
|
@@ -95,6 +160,9 @@ export function toAdapterDiagnostic(violation, fallbackSeverity = 'error') {
|
|
|
95
160
|
},
|
|
96
161
|
evidence,
|
|
97
162
|
nextAction: text(violation.nextAction) ?? nextActionForDiagnostic(ruleId, evidence, violation),
|
|
163
|
+
findingRef,
|
|
164
|
+
targetKey,
|
|
165
|
+
docsCodePath: adapterDocsCodePath(ruleId),
|
|
98
166
|
};
|
|
99
167
|
}
|
|
100
168
|
export function createAdapterResult(input) {
|
|
@@ -133,10 +201,16 @@ export function createAdapterResult(input) {
|
|
|
133
201
|
}
|
|
134
202
|
}
|
|
135
203
|
}
|
|
204
|
+
// Occurrence-aware targetKeys (violations and warnings counted separately) so
|
|
205
|
+
// list identity matches baselineOccurrenceKeys on each stream — ACS06 freeze parity.
|
|
206
|
+
const violationList = input.violations ?? [];
|
|
207
|
+
const warningList = input.warnings ?? [];
|
|
208
|
+
const violationTargetKeys = adapterFindingOccurrenceTargetKeys(violationList);
|
|
209
|
+
const warningTargetKeys = adapterFindingOccurrenceTargetKeys(warningList);
|
|
136
210
|
const diagnostics = [
|
|
137
211
|
// toAdapterDiagnostic maps failsStrict:false / typeOnly non-peer → warning severity.
|
|
138
|
-
...
|
|
139
|
-
...
|
|
212
|
+
...violationList.map((item, index) => toAdapterDiagnostic(item, 'error', violationTargetKeys[index])),
|
|
213
|
+
...warningList.map((item, index) => toAdapterDiagnostic(item, 'warning', warningTargetKeys[index])),
|
|
140
214
|
];
|
|
141
215
|
const base = {
|
|
142
216
|
schemaVersion: ARK_ANALYSIS_RESULT_SCHEMA_VERSION,
|
|
@@ -286,6 +360,15 @@ export const ARK_ANALYSIS_RESULT_SCHEMA = {
|
|
|
286
360
|
},
|
|
287
361
|
},
|
|
288
362
|
nextAction: { type: 'string', minLength: 1 },
|
|
363
|
+
/** ACS06 — compact multi-turn id; always derived from targetKey when emitted. */
|
|
364
|
+
findingRef: { type: 'string', minLength: 1, pattern: '^fnv1a-[0-9a-f]{8}$' },
|
|
365
|
+
/**
|
|
366
|
+
* ACS06 — baseline-compatible freeze identity
|
|
367
|
+
* (`ruleId|file|from|to|target` with optional `#N` occurrence suffix).
|
|
368
|
+
*/
|
|
369
|
+
targetKey: { type: 'string', minLength: 1 },
|
|
370
|
+
/** ACS06 — package-relative diagnostics anchor path. */
|
|
371
|
+
docsCodePath: { type: 'string', minLength: 1 },
|
|
289
372
|
},
|
|
290
373
|
},
|
|
291
374
|
},
|