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.
Files changed (45) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/README.md +28 -17
  3. package/SECURITY.md +9 -8
  4. package/bin/ark-check.mjs +599 -53
  5. package/bin/ark-shared.mjs +53 -0
  6. package/bin/ark.mjs +20 -5
  7. package/dist/eslint/index.cjs +258 -23
  8. package/dist/eslint/index.cjs.map +1 -1
  9. package/dist/eslint/index.d.cts +38 -1
  10. package/dist/eslint/index.d.ts +38 -1
  11. package/dist/eslint/index.js +240 -22
  12. package/dist/eslint/index.js.map +1 -1
  13. package/dist/index.cjs +1 -1
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.d.cts +1 -1
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.js +1 -1
  18. package/dist/index.js.map +1 -1
  19. package/dist/nestjs/index.cjs +1 -1
  20. package/dist/nestjs/index.cjs.map +1 -1
  21. package/dist/nestjs/index.js +1 -1
  22. package/dist/nestjs/index.js.map +1 -1
  23. package/docs/agent-guide.md +15 -8
  24. package/docs/ai-gates.md +26 -36
  25. package/docs/brownfield-adoption.md +14 -13
  26. package/docs/demos/03-copilot-autopilot.md +5 -3
  27. package/docs/enthusiast/README.md +4 -3
  28. package/docs/enthusiast/how-to-agent-gates.md +14 -6
  29. package/docs/enthusiast/reference-commands.md +23 -8
  30. package/docs/migrate-from-ark-runtime-kernel.md +18 -0
  31. package/docs/typescript-support.md +142 -0
  32. package/package.json +12 -3
  33. package/server.json +2 -2
  34. package/templates/skills/ark-autopilot.md +6 -4
  35. package/templates/skills/ark-explain.md +7 -2
  36. package/templates/skills/ark-fix.md +16 -12
  37. package/templates/skills/ark-loop.md +14 -4
  38. package/templates/skills/ark-upgrade.md +26 -1
  39. package/templates/tests/ark-adoption-gaps.test.ts +68 -0
  40. package/tests/fixtures/ts-consumer/ark.config.json +11 -0
  41. package/tests/fixtures/ts-consumer/src/app/types.ts +1 -0
  42. package/tests/fixtures/ts-consumer/src/domain/bad.ts +1 -0
  43. package/tests/fixtures/ts-consumer/src/domain/ok.ts +1 -0
  44. package/tests/fixtures/ts-consumer/src/domain/user.ts +1 -0
  45. 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** (a lower layer `import type`s something from an upper layer,
51
- e.g. a domain module importing a type that happens to live in a UI hook): move the
52
- TYPE down to the layer that owns it (e.g. `src/lib/<domain>/types.ts`), and re-export
53
- it from the original module for back-compat (`export type { X } from "@/lib/<domain>/types"`)
54
- so no consumer breaks. This is the highest-volume, safest adoption fix — verify with
55
- `tsc --noEmit`. It often also breaks a circular dependency that ran through the hook.
56
- Two cases where the move is NOT mechanical stop and flag instead of forcing it:
57
- (a) the type extends a persistence/ORM row (e.g. a Drizzle schema type) — moving it to a
58
- domain layer would couple domain→Persistence (the write gate will block it), so it needs a
59
- domain-owned type or port, not a move; (b) the source file mixes the type with runtime
60
- logic (stubs, helpers, mock builders) split the types into their own module first, then
61
- move.
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` and a plain-language `rationale`. If
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.** For each such step
32
- (e.g. a type-only import moved to the layer that owns it + a re-export for back-compat):
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
+ }