arkgate 4.7.0 → 4.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -2
- package/README.md +32 -23
- package/bin/lib/agent-projection.mjs +1 -1
- package/bin/lib/agent-skills-package.mjs +29 -0
- package/bin/lib/check-args.mjs +1 -0
- package/bin/lib/ci-and-commands.mjs +3 -3
- package/bin/lib/doctor-next-actions.mjs +5 -1
- package/bin/lib/enforcement-honesty.mjs +1 -1
- package/bin/lib/first-run-help.mjs +5 -5
- package/bin/lib/install-migrate.mjs +29 -57
- package/bin/lib/managed-upgrade.mjs +2 -7
- package/bin/lib/skill-catalog-apply.mjs +126 -0
- package/bin/lib/skill-install.mjs +264 -33
- package/bin/lib/skill-write.mjs +3 -0
- package/dist/index.cjs +25 -25
- package/dist/index.d.ts +19 -2
- package/dist/index.js +19 -19
- package/docs/README.md +8 -5
- package/docs/agent-guide.md +6 -5
- package/docs/ai-gates.md +4 -3
- package/docs/develop.md +4 -0
- package/docs/enthusiast/README.md +3 -0
- package/docs/enthusiast/how-to-agent-gates.md +1 -1
- package/docs/package-surface.md +6 -3
- package/docs/product-voice.md +118 -5
- package/docs/use.md +15 -8
- package/package.json +2 -2
- package/server.json +4 -4
- package/templates/agent-skills/README.md +1 -1
- package/templates/agent-skills/ark-adopt/SKILL.md +2 -2
- package/templates/agent-skills/ark-architect/SKILL.md +1 -1
- package/templates/agent-skills/ark-autopilot/SKILL.md +2 -2
- package/templates/agent-skills/ark-contract/SKILL.md +8 -7
- package/templates/agent-skills/ark-coverage/SKILL.md +1 -1
- package/templates/agent-skills/ark-explain/SKILL.md +1 -1
- package/templates/agent-skills/ark-explore/SKILL.md +1 -1
- package/templates/agent-skills/ark-fix/SKILL.md +1 -1
- package/templates/agent-skills/ark-loop/SKILL.md +1 -1
- package/templates/agent-skills/ark-place/SKILL.md +1 -1
- package/templates/agent-skills/ark-runtime/SKILL.md +1 -1
- package/templates/agent-skills/ark-think/SKILL.md +1 -1
- package/templates/agent-skills/ark-upgrade/SKILL.md +1 -1
- package/templates/skills/ark-adopt.md +2 -2
- package/templates/skills/ark-architect.md +1 -1
- package/templates/skills/ark-autopilot.md +2 -2
- package/templates/skills/ark-contract.md +8 -7
- package/templates/skills/ark-coverage.md +1 -1
- package/templates/skills/ark-explain.md +1 -1
- package/templates/skills/ark-explore.md +1 -1
- package/templates/skills/ark-fix.md +1 -1
- package/templates/skills/ark-loop.md +1 -1
- package/templates/skills/ark-place.md +1 -1
- package/templates/skills/ark-runtime.md +1 -1
- package/templates/skills/ark-think.md +1 -1
- package/templates/skills/ark-upgrade.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,58 @@ in the immutable pre-2.0 archive linked below.
|
|
|
5
5
|
|
|
6
6
|
## Unreleased
|
|
7
7
|
|
|
8
|
+
## 4.7.2 — 2026-08-25
|
|
9
|
+
|
|
10
|
+
**Patch** over **4.7.1**. Public copy uses ordinary software words: if the AI writes an
|
|
11
|
+
illegal import, the write is rejected; the same check fails the pull request. Not an API Gateway.
|
|
12
|
+
Not a folder linter. If the check is not required on the PR, the rules file is
|
|
13
|
+
just documentation. **No required config migration.** Does not close Z09 / K01.
|
|
14
|
+
|
|
15
|
+
**Status: prepared** (see `docs/releases/4.7.2.md`). npm `latest` remains **4.7.1** until
|
|
16
|
+
this patch is published.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- **First-contact wording (common language):** README, use/develop/docs hub/enthusiast,
|
|
21
|
+
agent-guide, ai-gates, package-surface openings, compact agent router, skill picker
|
|
22
|
+
`description` frontmatter, first-run CLI help, compact doctor strings, Action and MCP
|
|
23
|
+
descriptions, npm `description`, and the live product site lead with the deny. How:
|
|
24
|
+
one rules file, one check, one next step. Authority:
|
|
25
|
+
[product voice](docs/product-voice.md). ADR 0001 product title unchanged. Historical
|
|
26
|
+
4.6.2 three-beat line stays in that release note.
|
|
27
|
+
|
|
28
|
+
## 4.7.1 — 2026-08-25
|
|
29
|
+
|
|
30
|
+
**Patch** over **4.7.0**. One project skill catalog, visible package version in the
|
|
31
|
+
skill picker, no home duplicates, ArkRun routed through existing skill names.
|
|
32
|
+
**No required config migration.** Does not close Z09 / K01.
|
|
33
|
+
|
|
34
|
+
**Status: published** (on npm `latest`; see `docs/releases/4.7.1.md`).
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
|
|
38
|
+
- **Visible skill version (picker):** install stamps `description` with
|
|
39
|
+
`arkgate@<version>. ` so Codex/Claude/Cursor/Grok show the package pin without
|
|
40
|
+
opening the file. `arkVersion:` in YAML stays for doctor. Same-body stamp drift
|
|
41
|
+
refreshes without `--force` (`stamp-refresh`).
|
|
42
|
+
- **`--prune-home-duplicates`:** removes frozen `/ark-*` copies from
|
|
43
|
+
`$CODEX_HOME/skills`, `~/.claude/skills`, and `~/.grok/skills` when the project
|
|
44
|
+
already has `.agents/skills`. Never deletes non-Ark skills.
|
|
45
|
+
|
|
46
|
+
### Changed
|
|
47
|
+
|
|
48
|
+
- **One project catalog:** `.agents/skills/<name>/SKILL.md` is the byte source.
|
|
49
|
+
Claude / Grok / OpenCode get relative adapter links. Cursor/Codex/Antigravity
|
|
50
|
+
already read `.agents/skills` — no second copy. `.cursor/commands/ark-*.md` is
|
|
51
|
+
no longer written (Cursor listed commands + skills as two copies).
|
|
52
|
+
- **`--codex-home` / `--agent-homes`:** skip home skill write (and home MCP bind)
|
|
53
|
+
when the project catalog or `.codex/config.toml` already exists. Codex lists
|
|
54
|
+
user+repo; a home copy is why `/ark-*` appeared twice and stayed old.
|
|
55
|
+
- **Doctor:** when home `ark-*` and project `.agents/skills` both exist, next
|
|
56
|
+
action is prune, not `--codex-home --force`.
|
|
57
|
+
- **`/ark-contract`:** routes ArkRun extra edits (first extra `/ark-adopt`,
|
|
58
|
+
companion `/ark-runtime`, new files `/ark-place`). No new skill names.
|
|
59
|
+
|
|
8
60
|
## 4.7.0 — 2026-08-25
|
|
9
61
|
|
|
10
62
|
**Minor** over **4.6.7**. Ships **ArkRun**: an opt-in extra on schema `1.2` for kernel
|
|
@@ -12,8 +64,7 @@ usage and complete declarations, plus companion `@arkgate/runtime` DX. Absence i
|
|
|
12
64
|
silent (Layers / ArkRules verdicts unchanged). In-memory stores remain
|
|
13
65
|
reference-only. **No required config migration.** Does not close Z09 / K01.
|
|
14
66
|
|
|
15
|
-
**Status:
|
|
16
|
-
until publish.
|
|
67
|
+
**Status: published** (on npm `latest`; see `docs/releases/4.7.0.md`).
|
|
17
68
|
|
|
18
69
|
### Added
|
|
19
70
|
|
package/README.md
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
# ArkGate — Architecture Co-pilot for AI TypeScript
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**If the AI writes an illegal import, the write is rejected. The same check fails the pull request.**
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
Not an API Gateway. Not a folder linter. If the check is not required on the PR, the rules
|
|
8
|
+
file is just documentation.
|
|
9
|
+
|
|
10
|
+
**One rules file. One check. One next step.**
|
|
9
11
|
|
|
10
12
|
[](https://www.arkgate.online/)
|
|
11
13
|
[](https://github.com/pedroknigge/arkgate/actions/workflows/ci.yml)
|
|
@@ -16,11 +18,12 @@ and makes sure a “green” check means something real.
|
|
|
16
18
|
|
|
17
19
|
</div>
|
|
18
20
|
|
|
19
|
-
> **ArkGate 4.7.
|
|
21
|
+
> **ArkGate 4.7.2** is prepared. npm `latest` remains **4.7.1** until this patch is published.
|
|
22
|
+
> If the AI writes an illegal import, the write is rejected. Optional **ArkRun** extra on schema `1.2`.
|
|
20
23
|
> A tree is **adopted** only with a required GitHub status running `arkgate-check --strict-merge`,
|
|
21
24
|
> or `.ark/adoption-stance.json` `stance: "advisory-only"`. Doctor is compact (`--doctor --all`
|
|
22
|
-
> for Details). [4.7.
|
|
23
|
-
> [4.
|
|
25
|
+
> for Details). [4.7.2 notes](docs/releases/4.7.2.md) · [4.7.1](docs/releases/4.7.1.md) ·
|
|
26
|
+
> [4.7.0](docs/releases/4.7.0.md) · [Docs hub](docs/README.md) · [Product voice](docs/product-voice.md)
|
|
24
27
|
|
|
25
28
|
---
|
|
26
29
|
|
|
@@ -41,21 +44,20 @@ Full map: **[docs/README.md](docs/README.md)**
|
|
|
41
44
|
```bash
|
|
42
45
|
npm install -D arkgate typescript
|
|
43
46
|
npx arkgate start # preview files + commands
|
|
44
|
-
npx arkgate start --apply # compact
|
|
45
|
-
npx arkgate-check --doctor #
|
|
46
|
-
npx arkgate-check --doctor --all #
|
|
47
|
+
npx arkgate start --apply # compact config + host router + CI plan
|
|
48
|
+
npx arkgate-check --doctor # what's wrong, what to do first
|
|
49
|
+
npx arkgate-check --doctor --all # full details
|
|
47
50
|
```
|
|
48
51
|
|
|
49
|
-
That is the product.
|
|
50
|
-
JSON still carries improvement compass and coach (**not a score**). Compact human output does not.
|
|
52
|
+
That is the product. Stuck? Run `--doctor` and do action **#1**.
|
|
51
53
|
|
|
52
54
|
```text
|
|
53
|
-
start → doctor
|
|
54
|
-
|
|
55
|
+
start → doctor → new files in the right folder
|
|
56
|
+
↘ leftover mess: map, then one small refactor
|
|
55
57
|
```
|
|
56
58
|
|
|
57
|
-
|
|
58
|
-
`ark-check --changed --base origin/dev`.
|
|
59
|
+
Keep the rules file out of product PRs. Local check:
|
|
60
|
+
`ark-check --changed --base origin/dev`. Changing the rules themselves uses `--contract-session`.
|
|
59
61
|
|
|
60
62
|
Aliases `ark` / `ark-check` / `ark-mcp` still work. npm / pnpm / yarn. No install lifecycle scripts.
|
|
61
63
|
|
|
@@ -65,11 +67,13 @@ Aliases `ark` / `ark-check` / `ark-mcp` still work. npm / pnpm / yarn. No instal
|
|
|
65
67
|
|
|
66
68
|
## What it is
|
|
67
69
|
|
|
68
|
-
|
|
70
|
+
Import rules for TypeScript, enforced twice: the editor hook rejects the write, and a
|
|
71
|
+
**required** CI check rejects the pull request. `ark.config.json` is the rules file those
|
|
72
|
+
checks read.
|
|
69
73
|
|
|
70
74
|
| When | Tool |
|
|
71
75
|
|------|------|
|
|
72
|
-
| **While the AI writes** |
|
|
76
|
+
| **While the AI writes** | The write is rejected on supported hosts; warning only elsewhere |
|
|
73
77
|
| **Before merge** | `arkgate-check` as a **required** CI status |
|
|
74
78
|
|
|
75
79
|
### Two planes (4.0)
|
|
@@ -83,7 +87,9 @@ A machine-readable architecture file (`ark.config.json`) plus enforcement:
|
|
|
83
87
|
Absence of ArkRules or ArkRun changes no inter-layer verdict. Label residual **`[Layer]`** vs **`[ArkRules]`**.
|
|
84
88
|
Details: [configuration](docs/configuration.md) · [use path](docs/use.md).
|
|
85
89
|
|
|
86
|
-
**Not** a web framework, ORM, or job runner. Optional
|
|
90
|
+
**Not** an API Gateway, a folder linter, a web framework, ORM, or job runner. Optional
|
|
91
|
+
**ArkRules** and **ArkRun** extras are off unless you turn them on. In-memory stores are
|
|
92
|
+
not production durability.
|
|
87
93
|
|
|
88
94
|
**Name note:** npm package `arkgate` — not affiliated with the separate Archgate CLI project.
|
|
89
95
|
|
|
@@ -91,8 +97,9 @@ Details: [configuration](docs/configuration.md) · [use path](docs/use.md).
|
|
|
91
97
|
|
|
92
98
|
ArkGate is overkill for small trees with **no AI agents** and **no multi-layer boundaries**, for
|
|
93
99
|
single-developer hobby CRUDs under no integration pressure, and for teams that will not maintain
|
|
94
|
-
`ark.config.json` or a **required** CI status running `arkgate-check --strict-merge`.
|
|
95
|
-
|
|
100
|
+
`ark.config.json` or a **required** CI status running `arkgate-check --strict-merge`. Without that
|
|
101
|
+
status the rules file is just documentation — stay with a boundary linter alone (see
|
|
102
|
+
[Why not only ESLint / Nx / cruiser?](#why-not-only-eslint--nx--cruiser)).
|
|
96
103
|
Anyone path: [docs/use.md — When not to adopt](docs/use.md#when-not-to-adopt). Limits of a green
|
|
97
104
|
check: [4.3.0 — What ArkGate is / isn't](docs/releases/4.3.0.md#what-arkgate-is--isnt).
|
|
98
105
|
|
|
@@ -227,8 +234,10 @@ for real systems. Details: [docs/production-hardening.md](docs/production-harden
|
|
|
227
234
|
| Config · package surface · TS | [configuration](docs/configuration.md) · [package-surface](docs/package-surface.md) · [typescript-support](docs/typescript-support.md) |
|
|
228
235
|
| Brownfield | [docs/brownfield-adoption.md](docs/brownfield-adoption.md) |
|
|
229
236
|
| Security | [SECURITY.md](SECURITY.md) |
|
|
230
|
-
| Current tree (4.7.
|
|
231
|
-
| Current published (4.
|
|
237
|
+
| Current tree (4.7.2 prepared) | [docs/releases/4.7.2.md](docs/releases/4.7.2.md) · [CHANGELOG](CHANGELOG.md) |
|
|
238
|
+
| Current published (4.7.1 on npm `latest`) | [docs/releases/4.7.1.md](docs/releases/4.7.1.md) |
|
|
239
|
+
| Prior published (4.7.0) | [docs/releases/4.7.0.md](docs/releases/4.7.0.md) |
|
|
240
|
+
| Prior published (4.6.7) | [docs/releases/4.6.7.md](docs/releases/4.6.7.md) |
|
|
232
241
|
| Prior published (4.6.6) | [docs/releases/4.6.6.md](docs/releases/4.6.6.md) |
|
|
233
242
|
| Prior published (4.6.5) | [docs/releases/4.6.5.md](docs/releases/4.6.5.md) |
|
|
234
243
|
| Prior published (4.6.3) | [docs/releases/4.6.3.md](docs/releases/4.6.3.md) |
|
|
@@ -266,4 +275,4 @@ Full guide: [CONTRIBUTING.md](CONTRIBUTING.md) · queue: [ROADMAP.md](ROADMAP.md
|
|
|
266
275
|
**MCP:** [`io.github.pedroknigge/arkgate`](https://registry.modelcontextprotocol.io/)
|
|
267
276
|
Node ≥ 18 · **MIT**
|
|
268
277
|
|
|
269
|
-
**Ark doesn’t invent your product. It
|
|
278
|
+
**Ark doesn’t invent your product. It rejects the illegal write — and tells you when it isn’t really enforcing anything yet.**
|
|
@@ -148,7 +148,7 @@ export function buildAgentProjectionBody(facts) {
|
|
|
148
148
|
'',
|
|
149
149
|
];
|
|
150
150
|
if (profile === 'compact') {
|
|
151
|
-
lines.push('### Primary path', '', '1. Run doctor (`ark-check --doctor`) —
|
|
151
|
+
lines.push('### Primary path', '', '1. Run doctor (`ark-check --doctor`) — what is wrong and what to do first. Prefer the project-local CLI; do not wait on MCP “still connecting”.', '2. Name leftover work in plain language; never “done” on green imports alone while leftover design work remains.', '3. Identity handshake is optional when the CLI already resolved the project root. Call `ark_identity` only when using MCP evidence.', '4. Read the rules file with `ark_manifest` (same expectation) or the local `ark.config.json`. `ark://manifest` is compatibility-only / unverified.', '5. Place files inside configured layers; validate; run the check command above on violations — fix the import, do not weaken the rules file.', '6. Single door: illegal imports → fix; leftover design work → map then one small refactor with user OK.', '', '### Layers (summary)', '', formatAgentProjectionLayers(layers), '');
|
|
152
152
|
}
|
|
153
153
|
else {
|
|
154
154
|
lines.push('### Contract layers', '', formatAgentProjectionLayers(layers), '', 'When creating a **new** kind of code that no layer covers, update `ark.config.json` first (`/ark-adopt`), then place the file.', '', '### Diagnostic codes (short list)', '', formatAgentProjectionCatalogShortList(catalog, docsPath), '', '### Session truth', '', '- Machine snapshot: `ark status --json` (or MCP `ark_status`) — identity, activation honesty, last check, residual counts. **Not a score.**', '- Authoritative contract: local `ark.config.json` / CLI, or `ark_manifest` after a matched `ark_identity` handshake. Identity is optional when CLI already resolved the root.', '- Host docs: the same projection schema is merged into `AGENTS.md` and `CLAUDE.md` (`ark agents-md --write`).', '');
|
|
@@ -234,6 +234,35 @@ export function validateAgentSkillsPackage(entries) {
|
|
|
234
234
|
presentCount: names.length,
|
|
235
235
|
};
|
|
236
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* Visible package stamp at the start of Agent Skills `description`.
|
|
239
|
+
* Hosts show `description` in the picker; `arkVersion:` in YAML is invisible there.
|
|
240
|
+
* Example: `arkgate@4.7.1. Session 0 — mark the Ark path.`
|
|
241
|
+
*/
|
|
242
|
+
export const ARK_SKILL_DESCRIPTION_VERSION_PATTERN = /^arkgate@(\S+)\.\s/;
|
|
243
|
+
/** Prefix written at install time (`arkgate@<version>. `). */
|
|
244
|
+
export function skillDescriptionVersionPrefix(version) {
|
|
245
|
+
const v = String(version ?? '').trim();
|
|
246
|
+
return v ? `arkgate@${v}. ` : '';
|
|
247
|
+
}
|
|
248
|
+
/** Drop a leading `arkgate@<version>. ` stamp; other text is unchanged. */
|
|
249
|
+
export function stripSkillDescriptionVersion(description) {
|
|
250
|
+
return String(description ?? '').replace(ARK_SKILL_DESCRIPTION_VERSION_PATTERN, '');
|
|
251
|
+
}
|
|
252
|
+
/** Version inside a stamped description, or null when the prefix is absent. */
|
|
253
|
+
export function parseSkillDescriptionVersion(description) {
|
|
254
|
+
const match = String(description ?? '').match(ARK_SKILL_DESCRIPTION_VERSION_PATTERN);
|
|
255
|
+
return match?.[1] ?? null;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Idempotent: replace an existing `arkgate@…` prefix or add one.
|
|
259
|
+
* Empty `version` strips the prefix (authoring templates stay unversioned).
|
|
260
|
+
*/
|
|
261
|
+
export function stampSkillDescription(description, version) {
|
|
262
|
+
const rest = stripSkillDescriptionVersion(description);
|
|
263
|
+
const v = typeof version === 'string' ? version.trim() : '';
|
|
264
|
+
return v ? `${skillDescriptionVersionPrefix(v)}${rest}` : rest;
|
|
265
|
+
}
|
|
237
266
|
/**
|
|
238
267
|
* Normalize skill file content for identity compare (LF newlines, strip BOM).
|
|
239
268
|
* Does not strip or rewrite frontmatter — Agent Skills export is 1:1 with flat templates.
|
package/bin/lib/check-args.mjs
CHANGED
|
@@ -124,6 +124,7 @@ export function parseArgs(argv) {
|
|
|
124
124
|
else if (arg === '--watch') args.watch = true;
|
|
125
125
|
else if (arg === '--beginner') args.beginner = true;
|
|
126
126
|
else if (arg === '--codex-home') args.codexHome = true;
|
|
127
|
+
else if (arg === '--prune-home-duplicates') args.pruneHomeDuplicates = true;
|
|
127
128
|
else if (arg === '--claude-home') args.claudeHome = true;
|
|
128
129
|
else if (arg === '--grok-home') args.grokHome = true;
|
|
129
130
|
else if (arg === '--agent-homes') {
|
|
@@ -314,7 +314,7 @@ ${placementTable}`;
|
|
|
314
314
|
${projectionBlock}
|
|
315
315
|
## Default agent flow (if unsure, do only this)
|
|
316
316
|
|
|
317
|
-
1. Status anytime: \`${doctorCmd}\` —
|
|
317
|
+
1. Status anytime: \`${doctorCmd}\` — what's wrong and what to do first (not a mode picker).
|
|
318
318
|
2. If \`ark.config.json\` is missing: run \`${startCmd}\` once (preview), then \`${startCmd} --apply\`.
|
|
319
319
|
3. Guided end-to-end work (“make architecture sound”): **\`/ark-autopilot\`** — explore → dual plan A (edges) + B (shape) → write mechanical-safe and judgment; one Shape refactor. Day-zero origin is frozen by \`ark start\`/\`ark init\` (or adopt if missing) **before** agent docs.
|
|
320
320
|
4. After ordinary feature edits: run \`${checkCmd}\` (teams: \`ark-check --changed --base origin/dev\`). On violations → **\`/ark-autopilot\`** (or \`/ark-place\` for new files). **Do not edit** \`ark.config.json\` / \`.ark-baseline.json\` in a product PR — that is a steward \`--contract-session\`. If doctor shows **Stewards (advisory)**, ask who owns the law — do not invent \`stewards[]\`. Leftover names \`/ark-fix\` / \`/ark-loop\` / \`/ark-contract\` are shortcuts to those doors.
|
|
@@ -405,10 +405,10 @@ ${projectionBlock}
|
|
|
405
405
|
|
|
406
406
|
**Primary path (do this):**
|
|
407
407
|
|
|
408
|
-
1. Status anytime: \`${doctorCmd}\` —
|
|
408
|
+
1. Status anytime: \`${doctorCmd}\` — what's wrong and what to do first.
|
|
409
409
|
2. Read the **Improvement compass** section (not a score). Name residual lenses in plain language when present (SoC, DIP, domain, …). Out-of-scope lenses (performance, app security tooling, full resilience) stay honest — do not invent Ark enforcement for them.
|
|
410
410
|
3. CLI-first: if the local CLI already resolved this project root, do not wait on MCP “still connecting”. Identity handshake is optional in that case. When you do trust MCP evidence: call \`ark_identity\` with \`project.expectedRoot\` set to this project's exact absolute root, then reuse that root plus the returned \`projectIdentity.projectId\` on every Ark MCP call. A descendant path is authoritative only with that matching id. Missing tool, non-\`matched\` binding, or wrong root means this is not proven to be the right project: restart the host and use the local CLI meanwhile.
|
|
411
|
-
4. Day to day: call \`ark_manifest\` with the same project expectation (or skip if CLI already bound the root); place new files with \`ark_place\` (filePath required — fail-closed); validate after edits; run \`${checkCmd}\`. The \`ark://manifest\` resource is compatibility-only and always unverified. On a
|
|
411
|
+
4. Day to day: call \`ark_manifest\` with the same project expectation (or skip if CLI already bound the root); place new files with \`ark_place\` (filePath required — fail-closed); validate after edits; run \`${checkCmd}\`. The \`ark://manifest\` resource is compatibility-only and always unverified. On a deny, fix the illegal import — do not weaken \`ark.config.json\`.
|
|
412
412
|
5. If MCP is unavailable: inspect \`ark.config.json\` and run \`${checkCmd}\`. The host-readable projection is AGENTS.md and CLAUDE.md (same schema).
|
|
413
413
|
|
|
414
414
|
**Single door when residual remains:**
|
|
@@ -73,7 +73,11 @@ export function collectDoctorNextActions(ctx) {
|
|
|
73
73
|
} else if (remStale > 0) {
|
|
74
74
|
actions.push('refresh stale /ark-* skills (--install-agent-gates --skills-only --force) — gates are installed, catalog is stale');
|
|
75
75
|
}
|
|
76
|
-
if (ctx.codexHomeGap && ctx.codexConcernActive && ctx.codexHomeGap.
|
|
76
|
+
if (ctx.codexHomeGap && ctx.codexConcernActive && ctx.codexHomeGap.duplicateHome) {
|
|
77
|
+
actions.push(
|
|
78
|
+
'remove duplicate Codex home /ark-* skills (project .agents/skills is enough): --install-agent-gates --skills-only --prune-home-duplicates'
|
|
79
|
+
);
|
|
80
|
+
} else if (ctx.codexHomeGap && ctx.codexConcernActive && ctx.codexHomeGap.preferProject !== true) {
|
|
77
81
|
actions.push(
|
|
78
82
|
ctx.codexHomeGap.catalogMetadataInvalid
|
|
79
83
|
? 'repair invalid Codex home catalog metadata after verifying the newest installed version'
|
|
@@ -432,7 +432,7 @@ export function buildProductHonesty(input = {}) {
|
|
|
432
432
|
message:
|
|
433
433
|
operatingMode === 'adapt'
|
|
434
434
|
? 'Operating mode is ADAPT — not finished until whole-tree green, zero blocking, and zero design smells (contract and tree still disagree).'
|
|
435
|
-
: 'Operating mode is SUGGEST — not finished until whole-tree green, zero blocking, and zero design smells (
|
|
435
|
+
: 'Operating mode is SUGGEST — not finished until whole-tree green, zero blocking, and zero design smells (the rules file is not yet binding).',
|
|
436
436
|
});
|
|
437
437
|
}
|
|
438
438
|
}
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
export function setupUsage() {
|
|
6
|
-
return `arkgate (alias ark) —
|
|
6
|
+
return `arkgate (alias ark) — Illegal import: write rejected. Same check fails the PR.
|
|
7
7
|
|
|
8
8
|
arkgate start preview (no writes)
|
|
9
9
|
arkgate start --apply write host + CI setup
|
|
10
|
-
arkgate-check --doctor
|
|
10
|
+
arkgate-check --doctor what's wrong, what to do first
|
|
11
11
|
|
|
12
12
|
Stuck? Run doctor. Do #1.
|
|
13
13
|
`;
|
|
@@ -27,7 +27,7 @@ Every flag: arkgate --help --all
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
export function setupUsageAll() {
|
|
30
|
-
return `arkgate (alias ark) —
|
|
30
|
+
return `arkgate (alias ark) — Illegal import: write rejected. Same check fails the PR.
|
|
31
31
|
|
|
32
32
|
Usage:
|
|
33
33
|
arkgate start [--root <project>] [--tools <host>] [--require-write-hook <host>] [--install] [--apply] [--json]
|
|
@@ -200,8 +200,8 @@ export function checkUsageAll() {
|
|
|
200
200
|
'windsurf, cline, copilot, kiro, roo, continue, gemini',
|
|
201
201
|
'(instruction-tier rule files derived from the same contract).',
|
|
202
202
|
'It also installs the /ark-* skills shipped in templates/skills/ into each',
|
|
203
|
-
'detected tool\'s command location (.
|
|
204
|
-
'.
|
|
203
|
+
'detected tool\'s command location (.agents/skills/ canonical catalog;',
|
|
204
|
+
'.claude/skills/ and .grok/skills/ adapters; .windsurf/workflows/,',
|
|
205
205
|
'.clinerules/workflows/, .github/prompts/).',
|
|
206
206
|
'Kiro, Roo, Continue, and Gemini have no command mechanism and receive only their',
|
|
207
207
|
'rule file. Existing files are never overwritten without --force, so re-running',
|
|
@@ -68,8 +68,11 @@ import {
|
|
|
68
68
|
detectSkillGaps,
|
|
69
69
|
arkPackageVersion,
|
|
70
70
|
verifyHostSkillCatalog,
|
|
71
|
+
canonicalSkillPath,
|
|
72
|
+
usesCanonicalSkillCatalog,
|
|
71
73
|
} from './skill-install.mjs';
|
|
72
|
-
import {
|
|
74
|
+
import { applySkillCatalogFollowup } from './skill-catalog-apply.mjs';
|
|
75
|
+
import { installRepoSkillFile, skillInstallNote } from './skill-write.mjs';
|
|
73
76
|
import { detectDeployPathQuality } from './deploy-path.mjs';
|
|
74
77
|
import {
|
|
75
78
|
stripMcpServerArgs,
|
|
@@ -80,7 +83,6 @@ import {
|
|
|
80
83
|
RUNNER_BEFORE_ARK,
|
|
81
84
|
} from './mcp-adoption.mjs';
|
|
82
85
|
import { inspectCodexInstallActivation, printCodexActivationHandoff, reportPartialInstall } from './install-activation.mjs';
|
|
83
|
-
import { installRequestedAgentHomes } from './agent-homes.mjs';
|
|
84
86
|
import {
|
|
85
87
|
hasHardWriteHook,
|
|
86
88
|
validateHardWriteRequest,
|
|
@@ -235,9 +237,18 @@ export function buildManagedAssetCatalog({ root, tools, compact = false, skillsO
|
|
|
235
237
|
const skills = skillTemplates().map(([name, content]) => [name, stampSkill(content, version)]);
|
|
236
238
|
const skillPaths = new Set();
|
|
237
239
|
if (!compact) {
|
|
238
|
-
|
|
240
|
+
const skillTools = [...selectedTools].filter((tool) => SKILL_TOOL_TARGETS[tool]);
|
|
241
|
+
const writeCanonical = skillTools.some((tool) => usesCanonicalSkillCatalog(tool));
|
|
242
|
+
if (writeCanonical) {
|
|
243
|
+
for (const [name, content] of skills) {
|
|
244
|
+
const relativePath = canonicalSkillPath(name);
|
|
245
|
+
skillPaths.add(relativePath);
|
|
246
|
+
add(relativePath, content, 'skill');
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
for (const tool of skillTools) {
|
|
250
|
+
if (usesCanonicalSkillCatalog(tool)) continue;
|
|
239
251
|
const target = SKILL_TOOL_TARGETS[tool];
|
|
240
|
-
if (!target) continue;
|
|
241
252
|
for (const [name, content] of skills) {
|
|
242
253
|
const relativePath = target(name);
|
|
243
254
|
skillPaths.add(relativePath);
|
|
@@ -613,60 +624,12 @@ export function runInstallAgentGates(args) {
|
|
|
613
624
|
console.log(` ${arkCommand(root, 'ark-check', '--install-agent-gates --skills-only --force')}`);
|
|
614
625
|
}
|
|
615
626
|
|
|
616
|
-
|
|
617
|
-
// Codex's real catalog loads skill directories (not flat $CODEX_HOME/prompts).
|
|
618
|
-
// Repo installs already write `.agents/skills/<name>/SKILL.md` when `codex` is
|
|
619
|
-
// selected; home install is for multi-project / non-repo-local refresh.
|
|
620
|
-
const homeResults = [];
|
|
621
|
-
if (args.codexHome) {
|
|
622
|
-
const dir = codexSkillsDir();
|
|
623
|
-
console.log('');
|
|
624
|
-
console.log(
|
|
625
|
-
`Codex home skills (scope=home-shared; source=${version ? `arkgate@${version}` : 'arkgate@unknown'}; target=${dir}/<name>/SKILL.md):`
|
|
626
|
-
);
|
|
627
|
-
console.log(
|
|
628
|
-
' Compatibility: monotonic downgrade protection requires every shared-catalog writer ' +
|
|
629
|
-
'to use ArkGate 4.2.0+; pre-4.2 --codex-home ignores this catalog. Upgrade legacy repos first.'
|
|
630
|
-
);
|
|
631
|
-
try {
|
|
632
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
633
|
-
} catch (error) {
|
|
634
|
-
console.error(` FAILED to create ${dir} (${error.message})`);
|
|
635
|
-
homeResults.push({ relativePath: dir, status: 'failed' });
|
|
636
|
-
}
|
|
637
|
-
if (homeResults.length === 0) {
|
|
638
|
-
const skillName = (skill) =>
|
|
639
|
-
Array.isArray(skill) ? skill[0] : skill?.name || skill;
|
|
640
|
-
const projectHasCatalog = skills.some((skill) =>
|
|
641
|
-
fs.existsSync(path.join(root, '.agents', 'skills', skillName(skill), 'SKILL.md'))
|
|
642
|
-
);
|
|
643
|
-
if (projectHasCatalog) {
|
|
644
|
-
console.log(
|
|
645
|
-
' Project .agents/skills already has this catalog; home write is optional. Prefer the project copy.'
|
|
646
|
-
);
|
|
647
|
-
}
|
|
648
|
-
for (const result of installSkillCatalog({
|
|
649
|
-
directory: dir,
|
|
650
|
-
skills,
|
|
651
|
-
packageVersion: version,
|
|
652
|
-
force: args.force,
|
|
653
|
-
scope: 'home',
|
|
654
|
-
})) {
|
|
655
|
-
console.log(skillInstallLine(result));
|
|
656
|
-
homeResults.push(result);
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
installRequestedAgentHomes({
|
|
627
|
+
const { skillNames, homeResults } = applySkillCatalogFollowup({
|
|
662
628
|
root,
|
|
629
|
+
tools,
|
|
663
630
|
skills,
|
|
664
631
|
version,
|
|
665
|
-
|
|
666
|
-
claudeHome: args.claudeHome,
|
|
667
|
-
grokHome: args.grokHome,
|
|
668
|
-
agentHomes: args.agentHomes,
|
|
669
|
-
json: args.json,
|
|
632
|
+
args,
|
|
670
633
|
});
|
|
671
634
|
|
|
672
635
|
// Optional legacy/home fallback. Normal Codex installs use the project-scoped
|
|
@@ -679,8 +642,10 @@ export function runInstallAgentGates(args) {
|
|
|
679
642
|
// A redirected CODEX_HOME (tests/isolation) may still wire as requested.
|
|
680
643
|
let codexMcp = null;
|
|
681
644
|
const wantCodexWire = !args.compact && !args.skillsOnly && args.codexHome;
|
|
645
|
+
const projectCodexMcp = fs.existsSync(path.join(root, '.codex', 'config.toml'));
|
|
682
646
|
const skipHomeWire =
|
|
683
|
-
wantCodexWire &&
|
|
647
|
+
wantCodexWire &&
|
|
648
|
+
((isTempOrUpgradeRoot(root) && usesDefaultCodexHome()) || projectCodexMcp);
|
|
684
649
|
if (wantCodexWire && !skipHomeWire) {
|
|
685
650
|
codexMcp = wireCodexMcp(root, args.force);
|
|
686
651
|
console.log('');
|
|
@@ -702,7 +667,14 @@ export function runInstallAgentGates(args) {
|
|
|
702
667
|
);
|
|
703
668
|
}
|
|
704
669
|
} else if (skipHomeWire) {
|
|
705
|
-
|
|
670
|
+
const reason = projectCodexMcp ? 'project-config' : 'temp-root';
|
|
671
|
+
codexMcp = { status: 'skipped', file: codexConfigPath(), reason };
|
|
672
|
+
if (projectCodexMcp && !args.json) {
|
|
673
|
+
console.log('');
|
|
674
|
+
console.log(
|
|
675
|
+
'Skip Codex home MCP — project .codex/config.toml is the binding. Home config pointing at another checkout is leftover; do not rebind it from this install.'
|
|
676
|
+
);
|
|
677
|
+
}
|
|
706
678
|
}
|
|
707
679
|
|
|
708
680
|
const { codexProjectConfigured, runtimeActivation } =
|
|
@@ -126,13 +126,8 @@ function hasArkText(root, relativePath) {
|
|
|
126
126
|
|
|
127
127
|
const HOST_SIGNALS = {
|
|
128
128
|
claude: ['.claude/settings.json', '.claude/skills/ark-upgrade/SKILL.md'],
|
|
129
|
-
cursor: [
|
|
130
|
-
|
|
131
|
-
'.cursor/hooks.json',
|
|
132
|
-
'.cursor/rules/ark.mdc',
|
|
133
|
-
'.cursor/commands/ark-upgrade.md',
|
|
134
|
-
],
|
|
135
|
-
codex: ['.codex/hooks.json', '.codex/config.toml', '.agents/skills/ark-upgrade/SKILL.md'],
|
|
129
|
+
cursor: ['.cursor/mcp.json', '.cursor/hooks.json', '.cursor/rules/ark.mdc'],
|
|
130
|
+
codex: ['.codex/hooks.json', '.codex/config.toml'],
|
|
136
131
|
grok: ['.grok/config.toml', '.grok/hooks/ark-write-gate.json', '.grok/skills/ark-upgrade/SKILL.md'],
|
|
137
132
|
antigravity: ['.agents/hooks.json'],
|
|
138
133
|
opencode: ['opencode.json', '.opencode/skills/ark-upgrade/SKILL.md'],
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HS post-write skill catalog: adapters, home skip/prune, Claude/Grok home skip.
|
|
3
|
+
* Kept out of install-migrate so that file stays inside its module budget.
|
|
4
|
+
*/
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { arkCommand } from '../ark-shared.mjs';
|
|
8
|
+
import { installRequestedAgentHomes } from './agent-homes.mjs';
|
|
9
|
+
import { codexSkillsDir } from './codex-home.mjs';
|
|
10
|
+
import {
|
|
11
|
+
canonicalSkillPath,
|
|
12
|
+
linkSkillHostAdapters,
|
|
13
|
+
pruneHomeArkSkillDuplicates,
|
|
14
|
+
skillTemplateNames,
|
|
15
|
+
} from './skill-install.mjs';
|
|
16
|
+
import { installSkillCatalog, skillInstallLine } from './skill-write.mjs';
|
|
17
|
+
|
|
18
|
+
function skillName(skill) {
|
|
19
|
+
return Array.isArray(skill) ? skill[0] : skill?.name || skill;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function projectCatalogReady(root, skillNames) {
|
|
23
|
+
return skillNames.some((name) => fs.existsSync(path.join(root, canonicalSkillPath(name))));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function applySkillCatalogFollowup({
|
|
27
|
+
root,
|
|
28
|
+
tools,
|
|
29
|
+
skills,
|
|
30
|
+
version,
|
|
31
|
+
args,
|
|
32
|
+
}) {
|
|
33
|
+
const skillNames = skills.map(skillName);
|
|
34
|
+
if (!args.compact && skillNames.length > 0) {
|
|
35
|
+
const adapterResults = linkSkillHostAdapters(root, tools, skillNames, Boolean(args.force));
|
|
36
|
+
for (const row of adapterResults) {
|
|
37
|
+
if (row.status === 'linked' || row.status === 'copied') {
|
|
38
|
+
console.log(
|
|
39
|
+
` ${row.status.padEnd(7)} ${row.relativePath} (adapter → .agents/skills/${row.name})`
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (args.pruneHomeDuplicates) {
|
|
45
|
+
const pruned = pruneHomeArkSkillDuplicates(
|
|
46
|
+
root,
|
|
47
|
+
skillNames.length ? skillNames : skillTemplateNames()
|
|
48
|
+
);
|
|
49
|
+
if (!pruned.ok) {
|
|
50
|
+
console.log(' skip --prune-home-duplicates (no project .agents/skills catalog yet)');
|
|
51
|
+
} else if (pruned.removed.length === 0) {
|
|
52
|
+
console.log(' skip --prune-home-duplicates (no home ark-* copies)');
|
|
53
|
+
} else {
|
|
54
|
+
console.log(` pruned ${pruned.removed.length} home ark-* path(s) (project catalog is enough)`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const homeResults = [];
|
|
59
|
+
if (args.codexHome) {
|
|
60
|
+
const dir = codexSkillsDir();
|
|
61
|
+
console.log('');
|
|
62
|
+
console.log(
|
|
63
|
+
`Codex home skills (scope=home-shared; source=${version ? `arkgate@${version}` : 'arkgate@unknown'}; target=${dir}/<name>/SKILL.md):`
|
|
64
|
+
);
|
|
65
|
+
console.log(
|
|
66
|
+
' Compatibility: monotonic downgrade protection requires every shared-catalog writer ' +
|
|
67
|
+
'to use ArkGate 4.2.0+; pre-4.2 --codex-home ignores this catalog. Upgrade legacy repos first.'
|
|
68
|
+
);
|
|
69
|
+
try {
|
|
70
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error(` FAILED to create ${dir} (${error.message})`);
|
|
73
|
+
homeResults.push({ relativePath: dir, status: 'failed' });
|
|
74
|
+
}
|
|
75
|
+
if (homeResults.length === 0) {
|
|
76
|
+
const hasCatalog = skills.some((skill) =>
|
|
77
|
+
fs.existsSync(path.join(root, '.agents', 'skills', skillName(skill), 'SKILL.md'))
|
|
78
|
+
);
|
|
79
|
+
if (hasCatalog) {
|
|
80
|
+
console.log(
|
|
81
|
+
' Skip home write — project .agents/skills is the catalog. Codex lists user+repo; a home copy duplicates every /ark-*.'
|
|
82
|
+
);
|
|
83
|
+
console.log(
|
|
84
|
+
` Remove leftover home copies: ${arkCommand(root, 'ark-check', '--install-agent-gates --skills-only --prune-home-duplicates')}`
|
|
85
|
+
);
|
|
86
|
+
} else {
|
|
87
|
+
for (const result of installSkillCatalog({
|
|
88
|
+
directory: dir,
|
|
89
|
+
skills,
|
|
90
|
+
packageVersion: version,
|
|
91
|
+
force: args.force,
|
|
92
|
+
scope: 'home',
|
|
93
|
+
})) {
|
|
94
|
+
console.log(skillInstallLine(result));
|
|
95
|
+
homeResults.push(result);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const catalogReady = projectCatalogReady(root, skillNames);
|
|
102
|
+
if ((args.claudeHome || args.grokHome || args.agentHomes) && catalogReady) {
|
|
103
|
+
if (!args.json) {
|
|
104
|
+
console.log('');
|
|
105
|
+
console.log(
|
|
106
|
+
'Skip Claude/Grok home skill write — project .agents/skills + adapters are the catalog. Home ark-* copies override or duplicate.'
|
|
107
|
+
);
|
|
108
|
+
console.log(
|
|
109
|
+
` Remove leftover home copies: ${arkCommand(root, 'ark-check', '--install-agent-gates --skills-only --prune-home-duplicates')}`
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
installRequestedAgentHomes({
|
|
114
|
+
root,
|
|
115
|
+
skills,
|
|
116
|
+
version,
|
|
117
|
+
force: args.force,
|
|
118
|
+
claudeHome: args.claudeHome,
|
|
119
|
+
grokHome: args.grokHome,
|
|
120
|
+
agentHomes: args.agentHomes,
|
|
121
|
+
json: args.json,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return { skillNames, homeResults };
|
|
126
|
+
}
|