arkgate 2.3.0 → 2.5.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 +64 -0
- package/README.md +28 -17
- package/SECURITY.md +9 -8
- package/bin/ark-check.mjs +599 -53
- package/bin/ark-shared.mjs +53 -0
- package/bin/ark.mjs +20 -5
- package/dist/eslint/index.cjs +258 -23
- package/dist/eslint/index.cjs.map +1 -1
- package/dist/eslint/index.d.cts +38 -1
- package/dist/eslint/index.d.ts +38 -1
- package/dist/eslint/index.js +240 -22
- package/dist/eslint/index.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/nestjs/index.cjs +1 -1
- package/dist/nestjs/index.cjs.map +1 -1
- package/dist/nestjs/index.js +1 -1
- package/dist/nestjs/index.js.map +1 -1
- package/docs/agent-guide.md +15 -8
- package/docs/ai-gates.md +26 -36
- package/docs/brownfield-adoption.md +14 -13
- package/docs/demos/03-copilot-autopilot.md +5 -3
- package/docs/enthusiast/README.md +4 -3
- package/docs/enthusiast/how-to-agent-gates.md +14 -6
- package/docs/enthusiast/reference-commands.md +23 -8
- package/docs/migrate-from-ark-runtime-kernel.md +18 -0
- package/docs/typescript-support.md +142 -0
- package/package.json +12 -3
- package/server.json +2 -2
- package/templates/skills/ark-autopilot.md +6 -4
- package/templates/skills/ark-explain.md +7 -2
- package/templates/skills/ark-fix.md +16 -12
- package/templates/skills/ark-loop.md +14 -4
- package/templates/skills/ark-upgrade.md +26 -1
- package/templates/tests/ark-adoption-gaps.test.ts +68 -0
- package/tests/fixtures/ts-consumer/ark.config.json +11 -0
- package/tests/fixtures/ts-consumer/src/app/types.ts +1 -0
- package/tests/fixtures/ts-consumer/src/domain/bad.ts +1 -0
- package/tests/fixtures/ts-consumer/src/domain/ok.ts +1 -0
- package/tests/fixtures/ts-consumer/src/domain/user.ts +1 -0
- package/tests/fixtures/ts-consumer/tsconfig.json +16 -0
|
@@ -47,18 +47,22 @@ paste output you can generate yourself.
|
|
|
47
47
|
with the impure implementation outside the domain, and pass it in.
|
|
48
48
|
- **Intent prefix mismatch**: rename the intent to the layer's declared prefix,
|
|
49
49
|
or move the handler to the layer that owns that prefix.
|
|
50
|
-
- **Type-only inversion** (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
`tsc --noEmit
|
|
56
|
-
|
|
57
|
-
(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
50
|
+
- **Type-only inversion** (`typeOnly: true` on a `LAYER_IMPORT_VIOLATION` — plan class
|
|
51
|
+
`mechanical-safe`, `remediationKind: type-only-import-move`): a lower layer `import type`s
|
|
52
|
+
something from an upper layer (e.g. domain importing a type that lives in a UI hook). Move the
|
|
53
|
+
TYPE down to the layer that owns it and re-export for back-compat
|
|
54
|
+
(`export type { X } from "@/lib/<domain>/types"`). Highest-volume safe fix — verify with the
|
|
55
|
+
gate (and `tsc --noEmit` if present). Not mechanical if: (a) the type extends a persistence/ORM
|
|
56
|
+
row — needs a domain-owned type/port; (b) the source mixes types with runtime logic — split
|
|
57
|
+
first, then move (or use pure-type file relocate when the *whole file* is type-only).
|
|
58
|
+
- **Pure-type file relocate** (`sourcePureTypeModule` + type-only edge —
|
|
59
|
+
`remediationKind: pure-type-file-relocate`): the entire source file is type-surface only (no
|
|
60
|
+
runtime statements). Relocate the **file** to the owning layer (or extract the type module
|
|
61
|
+
there). Behavior-preserving; do not invent runtime ports.
|
|
62
|
+
- **Value-syntax import of a pure type-only module** (`targetTypeOnlyExports` —
|
|
63
|
+
`remediationKind: import-type-from-pure-type-module`): convert static `import { T } from …`
|
|
64
|
+
to `import type { T } from …`. Never auto-apply for `require()` / dynamic `import()` (those stay
|
|
65
|
+
judgment — they still execute the module).
|
|
62
66
|
- **Raw infrastructure access in an orchestration/UI layer** (a route/handler or component
|
|
63
67
|
that runs SQL or imports the DB client directly — e.g. `sqlClient\`SELECT …\`` or
|
|
64
68
|
`import { db } from "@/lib/db"` inside `src/app/**`): this is the value-import counterpart
|
|
@@ -21,15 +21,25 @@ If Ark isn't set up yet, run `ark start` (or `ark-check --recommend` then `ark i
|
|
|
21
21
|
1. **Read the plan.** Run `ark-check --plan --json` (add `--baseline .ark-baseline.json` if the
|
|
22
22
|
repo uses a baseline). It returns `goal` (with `met`, `activeViolations`, `autoApplicable`,
|
|
23
23
|
`needsDecision`, `deferred`) and `steps[]`, each tagged `class` (`mechanical-safe` /
|
|
24
|
-
`judgment` / `deferred`) with a `confidence
|
|
25
|
-
`goal.met` is already true, report "nothing to do" and stop.
|
|
24
|
+
`judgment` / `deferred`) with a `confidence`, plain-language `rationale`, and often
|
|
25
|
+
`remediationKind`. If `goal.met` is already true, report "nothing to do" and stop.
|
|
26
|
+
|
|
27
|
+
**`mechanical-safe` kinds you may auto-apply** (zero false-safe — never invent others):
|
|
28
|
+
|
|
29
|
+
| `remediationKind` | What to do |
|
|
30
|
+
|-------------------|------------|
|
|
31
|
+
| `type-only-import-move` | Edge is already `import type` / type-only: move the **type** to the owning layer + re-export for back-compat |
|
|
32
|
+
| `pure-type-file-relocate` | Whole **source file** is pure type-surface (`sourcePureTypeModule`) + type-only edge: relocate the file (or extract types) to the owning layer |
|
|
33
|
+
| `import-type-from-pure-type-module` | Static value-syntax import of a pure type-only **target** module (`targetTypeOnlyExports`): convert to `import type` (and place type if needed) |
|
|
34
|
+
|
|
35
|
+
Still **judgment** (never auto): value imports, `require()` / dynamic `import()`, mixed modules with side effects, forbidden globals, cycles, verbatim infra relocation.
|
|
26
36
|
|
|
27
37
|
2. **Work in a discardable git worktree.** Create one (`git worktree add`) so the entire run is
|
|
28
38
|
reversible and never disturbs the user's working tree. Do all edits there. Nothing is
|
|
29
39
|
permanent until the user reviews the final diff.
|
|
30
40
|
|
|
31
|
-
3. **Apply the `mechanical-safe` steps, one at a time, validated.**
|
|
32
|
-
(
|
|
41
|
+
3. **Apply the `mechanical-safe` steps, one at a time, validated.** Match the step's
|
|
42
|
+
`remediationKind` (table above) — do not expand the edit into a broader refactor:
|
|
33
43
|
- Record the current active-violation count from the plan.
|
|
34
44
|
- Make the edit at the SOURCE (fix the placement; don't add an `ark-*-disable` or edit the
|
|
35
45
|
baseline/config to hide it).
|
|
@@ -18,6 +18,26 @@ npx arkgate-check --install-agent-gates --force
|
|
|
18
18
|
|
|
19
19
|
Guide: `docs/migrate-from-ark-runtime-kernel.md` in the package (or on GitHub).
|
|
20
20
|
|
|
21
|
+
**TypeScript 7 projects:** ArkGate falls back to a nested JS-API TypeScript when the
|
|
22
|
+
project's `typescript` main export is version-only (TS 7.0). After upgrade, point users at
|
|
23
|
+
`docs/typescript-support.md` if the gate or `ARK_DEBUG_TS=1` mentions fallback. Dual install
|
|
24
|
+
(TS6 JS API + TS7 CLI) is optional for tooling that still needs classic `tsc` APIs.
|
|
25
|
+
|
|
26
|
+
**MCP double-bin check (identity cutover):** after upgrade, open `.mcp.json` and
|
|
27
|
+
`.cursor/mcp.json`. `args` must contain **exactly one** of `arkgate-mcp` / `ark-mcp`
|
|
28
|
+
(prefer `arkgate-mcp`), never both. If both appear, run:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
npx arkgate-check --install-agent-gates --migrate-commands
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`ark upgrade` already runs migrate-commands; re-run it if an older 2.x left dual names.
|
|
35
|
+
|
|
36
|
+
**Adoption completeness:** run `npx arkgate-check --doctor` (or `--doctor --json`) and
|
|
37
|
+
read the **Adoption** section — host gaps, Codex home temp paths, optional-but-populated
|
|
38
|
+
core layers, missing origin snapshot, baseline policy. Fix commands are printed per gap.
|
|
39
|
+
HTML reports include the same Adoption card (separate from the 0–100 fitness score).
|
|
40
|
+
|
|
21
41
|
## Fast path
|
|
22
42
|
|
|
23
43
|
One command does the whole flow — update the package, refresh gates + `/ark-*` skills
|
|
@@ -30,7 +50,12 @@ arkgate upgrade
|
|
|
30
50
|
|
|
31
51
|
Use it when the user just wants the update done. Run the detailed steps below instead when
|
|
32
52
|
you need to inspect the changelog first, handle a pnpm cooling-off window, or the one-liner
|
|
33
|
-
reports a problem to triage.
|
|
53
|
+
reports a problem to triage. Always refresh skills so agents pick up new `mechanical-safe`
|
|
54
|
+
kinds and TS guidance:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
npx arkgate-check --install-agent-gates --skills-only --force
|
|
58
|
+
```
|
|
34
59
|
|
|
35
60
|
## Steps
|
|
36
61
|
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural adoption-gap tests — copy into your project (e.g. tests/ark-adoption-gaps.test.ts)
|
|
3
|
+
* and run with Vitest/Jest. Asserts real on-disk gate artifacts (no mocks).
|
|
4
|
+
*
|
|
5
|
+
* Install reminder after copy:
|
|
6
|
+
* npx arkgate-check --install-agent-gates
|
|
7
|
+
* npx arkgate-check --doctor
|
|
8
|
+
*/
|
|
9
|
+
import { describe, it, expect } from 'vitest';
|
|
10
|
+
import fs from 'node:fs';
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
|
|
13
|
+
const root = process.cwd();
|
|
14
|
+
|
|
15
|
+
function exists(rel: string) {
|
|
16
|
+
return fs.existsSync(path.join(root, rel));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe('ArkGate adoption gaps (structural)', () => {
|
|
20
|
+
it('has architecture contract + primary gate files', () => {
|
|
21
|
+
expect(exists('ark.config.json')).toBe(true);
|
|
22
|
+
expect(exists('AGENTS.md')).toBe(true);
|
|
23
|
+
expect(exists('.mcp.json')).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('MCP argv uses a single preferred bin (no dual ark-mcp + arkgate-mcp)', () => {
|
|
27
|
+
const raw = fs.readFileSync(path.join(root, '.mcp.json'), 'utf8');
|
|
28
|
+
const json = JSON.parse(raw);
|
|
29
|
+
const args: string[] = json?.mcpServers?.ark?.args ?? [];
|
|
30
|
+
const bins = args.filter((a) => a === 'ark-mcp' || a === 'arkgate-mcp');
|
|
31
|
+
expect(bins.length).toBe(1);
|
|
32
|
+
expect(bins[0]).toBe('arkgate-mcp');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('has /ark-* skills for at least one agent host when that host dir exists', () => {
|
|
36
|
+
const hosts: Array<{ dir: string; skill: (n: string) => string }> = [
|
|
37
|
+
{ dir: '.grok', skill: (n) => path.join('.grok', 'skills', n, 'SKILL.md') },
|
|
38
|
+
{ dir: '.claude', skill: (n) => path.join('.claude', 'skills', n, 'SKILL.md') },
|
|
39
|
+
{ dir: '.cursor', skill: (n) => path.join('.cursor', 'commands', `${n}.md`) },
|
|
40
|
+
];
|
|
41
|
+
const required = [
|
|
42
|
+
'ark-autopilot',
|
|
43
|
+
'ark-loop',
|
|
44
|
+
'ark-fix',
|
|
45
|
+
'ark-adopt',
|
|
46
|
+
'ark-architect',
|
|
47
|
+
'ark-upgrade',
|
|
48
|
+
];
|
|
49
|
+
for (const h of hosts) {
|
|
50
|
+
if (!exists(h.dir)) continue;
|
|
51
|
+
for (const name of required) {
|
|
52
|
+
expect(exists(h.skill(name)), `missing skill ${name} under ${h.dir}`).toBe(true);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('origin report exists after first --report (or documents the command)', () => {
|
|
58
|
+
// Prefer real origin; if missing, the suite still documents the one-liner.
|
|
59
|
+
if (exists(path.join('.ark', 'reports', 'origin.json'))) {
|
|
60
|
+
expect(exists(path.join('.ark', 'reports', 'origin.json'))).toBe(true);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// Soft path: ensure doctor/report is still the sanctioned fix.
|
|
64
|
+
expect(
|
|
65
|
+
'npx arkgate-check --report ark-report.html'.includes('--report')
|
|
66
|
+
).toBe(true);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"include": ["src"],
|
|
3
|
+
"layers": [
|
|
4
|
+
{ "name": "DomainModel", "patterns": ["src/domain/**"], "forbiddenGlobals": ["fetch"] },
|
|
5
|
+
{ "name": "ApplicationOrchestration", "patterns": ["src/app/**"] }
|
|
6
|
+
],
|
|
7
|
+
"rules": [
|
|
8
|
+
{ "from": "DomainModel", "to": "ApplicationOrchestration", "allowed": false },
|
|
9
|
+
{ "from": "ApplicationOrchestration", "to": "DomainModel", "allowed": true }
|
|
10
|
+
]
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import type { User } from '../domain/user'; export type U = User;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import type { U } from '../app/types'; export type X = U;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const ok = 1;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type UserId = string; export interface User { id: UserId }
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"types": ["node"],
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"noEmit": true,
|
|
11
|
+
"paths": {
|
|
12
|
+
"@domain/*": ["./src/domain/*"]
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"include": ["src/**/*.ts"]
|
|
16
|
+
}
|