arkgate 4.0.0 → 4.1.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 +142 -0
- package/README.md +7 -5
- package/bin/ark-check-runtime.mjs +244 -25
- package/bin/ark-check.mjs +10 -1
- package/bin/ark-layer-match.mjs +80 -5
- package/bin/ark-shared.mjs +170 -9
- package/bin/ark.mjs +52 -5
- package/bin/lib/adapter-contract.mjs +7 -1
- package/bin/lib/agent-gates.mjs +2 -0
- package/bin/lib/analysis-engine.mjs +6 -6
- package/bin/lib/arkrules-sensors.mjs +63 -22
- package/bin/lib/ci-and-commands.mjs +148 -8
- package/bin/lib/core-ratchet.mjs +9 -4
- package/bin/lib/doctor-advisories.mjs +8 -1
- package/bin/lib/doctor-plan.mjs +277 -59
- package/bin/lib/enforcement-honesty.mjs +351 -26
- package/bin/lib/enforcement-state.mjs +1 -1
- package/bin/lib/field-install.mjs +35 -2
- package/bin/lib/graph-blind.mjs +1 -1
- package/bin/lib/html-report-advisories.mjs +8 -25
- package/bin/lib/html-report-depth.mjs +167 -3
- package/bin/lib/html-report.mjs +12 -5
- package/bin/lib/install-migrate.mjs +109 -6
- package/bin/lib/managed-upgrade.mjs +100 -1
- package/bin/lib/presets.mjs +314 -46
- package/bin/lib/project-root.mjs +268 -0
- package/bin/lib/remediation.mjs +12 -11
- package/bin/lib/rules-inventory.mjs +71 -29
- package/bin/lib/rules-under-contract.mjs +389 -5
- package/bin/lib/start-preview.mjs +48 -14
- package/bin/lib/suggestions.mjs +118 -3
- package/bin/lib/unavailable-analysis.mjs +2 -0
- package/bin/lib/upgrade-command.mjs +325 -14
- package/bin/lib/write-path-capabilities.mjs +38 -9
- package/dist/eslint/index.cjs +2 -2
- package/dist/eslint/index.d.ts +27 -2
- package/dist/eslint/index.js +2 -2
- package/dist/index.cjs +16 -14
- package/dist/index.d.ts +3 -1
- package/dist/index.js +16 -14
- package/docs/README.md +3 -2
- package/docs/ai-gates.md +15 -11
- package/docs/brownfield-adoption.md +38 -0
- package/docs/configuration.md +59 -7
- package/docs/package-surface.md +3 -2
- package/docs/product-voice.md +10 -1
- package/docs/typescript-support.md +9 -5
- package/docs/use.md +7 -5
- package/package.json +3 -1
- package/server.json +3 -3
- package/templates/architecture-playbook.json +3 -0
- package/templates/layers/shared-types.starter.json +29 -0
- package/templates/skills/ark-adopt.md +2 -0
- package/templates/skills/ark-explain.md +23 -5
- package/templates/skills/ark-explore.md +21 -1
- package/templates/skills/ark-fix.md +16 -5
- package/templates/skills/ark-upgrade.md +57 -11
package/bin/lib/presets.mjs
CHANGED
|
@@ -56,6 +56,143 @@ export function peerIsolationEdges(layerNames, sliceFolders, message) {
|
|
|
56
56
|
// `src/**/domain/**` would otherwise swallow `src/kernel/domain`. Do NOT use `**/kernel/**`
|
|
57
57
|
// (that carves out legitimate `src/shared/kernel/**` SharedKernel paths).
|
|
58
58
|
export const FRAMEWORK_INTERNAL_EXCLUDE = ['src/kernel/**', '**/src/kernel/**'];
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Shared high-spec domain globs. Prefer these over Application/Presentation scatter
|
|
62
|
+
* (path-anchored specificity ranks interior domain above broad src/lib bags).
|
|
63
|
+
* Include kernel/domain paths for event-kernel trees; framework src/kernel
|
|
64
|
+
* exclude still applies when set on a layer.
|
|
65
|
+
*/
|
|
66
|
+
export const DOMAIN_PATH_PATTERNS = Object.freeze([
|
|
67
|
+
'**/domain/**',
|
|
68
|
+
'**/entities/**',
|
|
69
|
+
'**/kernel/domain/**',
|
|
70
|
+
'src/**/domain/**',
|
|
71
|
+
'src/**/entities/**',
|
|
72
|
+
'src/domain/**',
|
|
73
|
+
'src/entities/**',
|
|
74
|
+
]);
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Next / App Router API shells — Application orchestration, not Presentation UI.
|
|
78
|
+
* High-spec patterns win over broad app Presentation globs (P0-A / DL-P0A-RETROFIT).
|
|
79
|
+
*/
|
|
80
|
+
export const NEXT_API_APPLICATION_PATTERNS = Object.freeze([
|
|
81
|
+
'**/app/api/**',
|
|
82
|
+
'**/pages/api/**',
|
|
83
|
+
'**/app/**/api/**',
|
|
84
|
+
'**/pages/**/api/**',
|
|
85
|
+
'app/api/**',
|
|
86
|
+
'pages/api/**',
|
|
87
|
+
'src/app/api/**',
|
|
88
|
+
'src/pages/api/**',
|
|
89
|
+
'src/app/**/api/**',
|
|
90
|
+
'app/**/api/**',
|
|
91
|
+
// Explicit route handlers under api/ — beat Presentation src/**/route.ts when present.
|
|
92
|
+
'src/app/api/**/route.ts',
|
|
93
|
+
'src/app/api/**/route.tsx',
|
|
94
|
+
'src/app/api/**/route.js',
|
|
95
|
+
'app/api/**/route.ts',
|
|
96
|
+
'app/api/**/route.tsx',
|
|
97
|
+
'**/app/api/**/route.ts',
|
|
98
|
+
'**/app/api/**/route.tsx',
|
|
99
|
+
'**/pages/api/**/*.ts',
|
|
100
|
+
'**/pages/api/**/*.js',
|
|
101
|
+
]);
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Data-client / repository / auth-client bags. Higher path-anchored specificity than
|
|
105
|
+
* bare `lib/**` or `src/lib/**` Application vacuum (NEW-APP-VACUUM-LIB, NEW-ADOPT-LIB-AS-PRESENTATION).
|
|
106
|
+
*/
|
|
107
|
+
export const PERSISTENCE_PATH_PATTERNS = Object.freeze([
|
|
108
|
+
'**/repositories/**',
|
|
109
|
+
'**/repository/**',
|
|
110
|
+
'**/persistence/**',
|
|
111
|
+
'**/infrastructure/**',
|
|
112
|
+
'**/infra/**',
|
|
113
|
+
'**/db/**',
|
|
114
|
+
'**/data/**',
|
|
115
|
+
'**/supabase/**',
|
|
116
|
+
'**/airtable/**',
|
|
117
|
+
'**/prisma/**',
|
|
118
|
+
'**/turso/**',
|
|
119
|
+
'**/drizzle/**',
|
|
120
|
+
'**/kysely/**',
|
|
121
|
+
'**/mongoose/**',
|
|
122
|
+
'**/mongodb/**',
|
|
123
|
+
'**/firebase/**',
|
|
124
|
+
'**/firestore/**',
|
|
125
|
+
'**/planetscale/**',
|
|
126
|
+
'**/neon/**',
|
|
127
|
+
'**/lib/db/**',
|
|
128
|
+
'**/lib/prisma/**',
|
|
129
|
+
'**/lib/supabase/**',
|
|
130
|
+
'**/lib/airtable/**',
|
|
131
|
+
'**/lib/turso/**',
|
|
132
|
+
'**/lib/drizzle/**',
|
|
133
|
+
'**/lib/firebase/**',
|
|
134
|
+
'**/lib/firestore/**',
|
|
135
|
+
'**/lib/mongodb/**',
|
|
136
|
+
'**/lib/mongoose/**',
|
|
137
|
+
'**/lib/kysely/**',
|
|
138
|
+
'**/lib/auth/**',
|
|
139
|
+
'src/db/**',
|
|
140
|
+
'src/data/**',
|
|
141
|
+
'src/repositories/**',
|
|
142
|
+
'src/persistence/**',
|
|
143
|
+
'src/infrastructure/**',
|
|
144
|
+
'src/lib/db/**',
|
|
145
|
+
'src/lib/prisma/**',
|
|
146
|
+
'src/lib/supabase/**',
|
|
147
|
+
'src/lib/airtable/**',
|
|
148
|
+
'src/lib/turso/**',
|
|
149
|
+
'src/lib/drizzle/**',
|
|
150
|
+
'src/lib/firebase/**',
|
|
151
|
+
'src/lib/firestore/**',
|
|
152
|
+
'src/lib/mongodb/**',
|
|
153
|
+
'src/lib/mongoose/**',
|
|
154
|
+
'src/lib/kysely/**',
|
|
155
|
+
'src/lib/auth/**',
|
|
156
|
+
'src/server/db/**',
|
|
157
|
+
'lib/db/**',
|
|
158
|
+
'lib/prisma/**',
|
|
159
|
+
'lib/supabase/**',
|
|
160
|
+
'lib/airtable/**',
|
|
161
|
+
'lib/turso/**',
|
|
162
|
+
'lib/auth/**',
|
|
163
|
+
// Single-file clients at lib root (SPA / Vercel serverless companions)
|
|
164
|
+
'lib/turso.js',
|
|
165
|
+
'lib/turso.ts',
|
|
166
|
+
'lib/prisma.js',
|
|
167
|
+
'lib/prisma.ts',
|
|
168
|
+
'lib/supabase.js',
|
|
169
|
+
'lib/supabase.ts',
|
|
170
|
+
'lib/airtable.js',
|
|
171
|
+
'lib/airtable.ts',
|
|
172
|
+
'lib/auth.js',
|
|
173
|
+
'lib/auth.ts',
|
|
174
|
+
'lib/db.js',
|
|
175
|
+
'lib/db.ts',
|
|
176
|
+
]);
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Application orchestration under lib without the whole-src-lib vacuum.
|
|
180
|
+
* Never use lone `src/**` or bare `src/lib/**` as Application on Next/event trees.
|
|
181
|
+
*/
|
|
182
|
+
export const APPLICATION_LIB_ORCHESTRATION_PATTERNS = Object.freeze([
|
|
183
|
+
'src/lib/actions/**',
|
|
184
|
+
'src/lib/services/**',
|
|
185
|
+
'src/lib/server/**',
|
|
186
|
+
'src/lib/use-cases/**',
|
|
187
|
+
'src/lib/usecases/**',
|
|
188
|
+
'src/lib/api-handlers/**',
|
|
189
|
+
'src/lib/handlers/**',
|
|
190
|
+
'**/lib/actions/**',
|
|
191
|
+
'**/lib/services/**',
|
|
192
|
+
'**/lib/server/**',
|
|
193
|
+
'**/lib/api-handlers/**',
|
|
194
|
+
]);
|
|
195
|
+
|
|
59
196
|
/**
|
|
60
197
|
* AR08 — attach lean arkRules map. Keys are always exact project layer names.
|
|
61
198
|
* Sensor roles (domain-structure / orchestration / adapter-thin / generic) are
|
|
@@ -306,7 +443,7 @@ export const ARCHITECTURE_PRESETS = {
|
|
|
306
443
|
{
|
|
307
444
|
name: 'DomainModel',
|
|
308
445
|
description: 'Pure business rules and entities. No I/O, no framework, no ambient globals.',
|
|
309
|
-
patterns: [
|
|
446
|
+
patterns: [...DOMAIN_PATH_PATTERNS],
|
|
310
447
|
exclude: FRAMEWORK_INTERNAL_EXCLUDE,
|
|
311
448
|
forbiddenGlobals: DEFAULT_DOMAIN_FORBIDDEN_GLOBALS,
|
|
312
449
|
optional: true,
|
|
@@ -314,7 +451,14 @@ export const ARCHITECTURE_PRESETS = {
|
|
|
314
451
|
{
|
|
315
452
|
name: 'ApplicationOrchestration',
|
|
316
453
|
description: 'Use cases that coordinate the domain through ports. No I/O of its own.',
|
|
317
|
-
|
|
454
|
+
// Never lone src/** — Application is intentional orchestration folders only.
|
|
455
|
+
patterns: [
|
|
456
|
+
'src/**/application/**',
|
|
457
|
+
'src/**/use-cases/**',
|
|
458
|
+
'src/**/usecases/**',
|
|
459
|
+
...APPLICATION_LIB_ORCHESTRATION_PATTERNS,
|
|
460
|
+
...NEXT_API_APPLICATION_PATTERNS,
|
|
461
|
+
],
|
|
318
462
|
exclude: FRAMEWORK_INTERNAL_EXCLUDE,
|
|
319
463
|
optional: true,
|
|
320
464
|
},
|
|
@@ -336,8 +480,7 @@ export const ARCHITECTURE_PRESETS = {
|
|
|
336
480
|
patterns: [
|
|
337
481
|
'src/**/infrastructure/**',
|
|
338
482
|
'src/**/adapters/**',
|
|
339
|
-
|
|
340
|
-
'src/**/repositories/**',
|
|
483
|
+
...PERSISTENCE_PATH_PATTERNS,
|
|
341
484
|
],
|
|
342
485
|
exclude: FRAMEWORK_INTERNAL_EXCLUDE,
|
|
343
486
|
optional: true,
|
|
@@ -376,15 +519,26 @@ export const ARCHITECTURE_PRESETS = {
|
|
|
376
519
|
},
|
|
377
520
|
{
|
|
378
521
|
name: 'ApplicationOrchestration',
|
|
379
|
-
description:
|
|
380
|
-
|
|
522
|
+
description:
|
|
523
|
+
'Business services and use-case coordination. Residual `src/**` is Application on non-Next layered trees only (specific domain/ui/db patterns win by specificity).',
|
|
524
|
+
patterns: [
|
|
525
|
+
'src/**/application/**',
|
|
526
|
+
'src/**/services/**',
|
|
527
|
+
'src/**/use-cases/**',
|
|
528
|
+
...APPLICATION_LIB_ORCHESTRATION_PATTERNS,
|
|
529
|
+
...NEXT_API_APPLICATION_PATTERNS,
|
|
530
|
+
// Greenfield residual: bare src/index.ts etc. Domain/Presentation/Persistence
|
|
531
|
+
// patterns outrank this by specificity. Next overlay replaces Application bags
|
|
532
|
+
// and must NOT reintroduce a lone src/** catch-all on App Router trees.
|
|
533
|
+
'src/**',
|
|
534
|
+
],
|
|
381
535
|
exclude: FRAMEWORK_INTERNAL_EXCLUDE,
|
|
382
536
|
optional: true,
|
|
383
537
|
},
|
|
384
538
|
{
|
|
385
539
|
name: 'DomainModel',
|
|
386
540
|
description: 'Pure business rules and entities. No I/O, no framework, no ambient globals.',
|
|
387
|
-
patterns: [
|
|
541
|
+
patterns: [...DOMAIN_PATH_PATTERNS],
|
|
388
542
|
exclude: FRAMEWORK_INTERNAL_EXCLUDE,
|
|
389
543
|
forbiddenGlobals: DEFAULT_DOMAIN_FORBIDDEN_GLOBALS,
|
|
390
544
|
optional: true,
|
|
@@ -392,12 +546,7 @@ export const ARCHITECTURE_PRESETS = {
|
|
|
392
546
|
{
|
|
393
547
|
name: 'PersistenceAdapters',
|
|
394
548
|
description: 'Data access and infrastructure.',
|
|
395
|
-
patterns: [
|
|
396
|
-
'src/**/persistence/**',
|
|
397
|
-
'src/**/data/**',
|
|
398
|
-
'src/**/repositories/**',
|
|
399
|
-
'src/**/infrastructure/**',
|
|
400
|
-
],
|
|
549
|
+
patterns: [...PERSISTENCE_PATH_PATTERNS],
|
|
401
550
|
exclude: FRAMEWORK_INTERNAL_EXCLUDE,
|
|
402
551
|
optional: true,
|
|
403
552
|
},
|
|
@@ -490,8 +639,7 @@ export const ARCHITECTURE_PRESETS = {
|
|
|
490
639
|
// Domain by intentional folders only — NOT bare **/types.ts (that mis-classifies
|
|
491
640
|
// application bags like frontend/src/core/**/types.ts as Domain and creates false edges).
|
|
492
641
|
patterns: [
|
|
493
|
-
|
|
494
|
-
'**/entities/**',
|
|
642
|
+
...DOMAIN_PATH_PATTERNS,
|
|
495
643
|
'**/cinematic/types.ts',
|
|
496
644
|
...librarySourcePatterns,
|
|
497
645
|
],
|
|
@@ -500,18 +648,24 @@ export const ARCHITECTURE_PRESETS = {
|
|
|
500
648
|
},
|
|
501
649
|
{
|
|
502
650
|
name: 'ApplicationOrchestration',
|
|
503
|
-
description:
|
|
651
|
+
description:
|
|
652
|
+
'Use cases and services that coordinate the domain through ports. Next App Router API (`app/api/**`) and Pages API (`pages/api/**`) are orchestration shells, not UI.',
|
|
504
653
|
patterns: [
|
|
505
654
|
'**/application/**',
|
|
506
655
|
'**/use-cases/**',
|
|
507
656
|
'**/services/**',
|
|
657
|
+
// Next API route handlers (higher specificity than **/app/** Presentation).
|
|
658
|
+
// Route groups: app/(marketing)/api/** also match **/app/**/api/**
|
|
659
|
+
...NEXT_API_APPLICATION_PATTERNS,
|
|
660
|
+
...APPLICATION_LIB_ORCHESTRATION_PATTERNS,
|
|
508
661
|
...applicationSourcePatterns,
|
|
509
662
|
],
|
|
510
663
|
optional: true,
|
|
511
664
|
},
|
|
512
665
|
{
|
|
513
666
|
name: 'PresentationAdapters',
|
|
514
|
-
description:
|
|
667
|
+
description:
|
|
668
|
+
'Entrypoints — UI, framework app/pages dirs, controllers. Next `app/api` is Application, not this layer. Never bare lib/** (data clients are Persistence).',
|
|
515
669
|
patterns: [
|
|
516
670
|
'**/app/**',
|
|
517
671
|
'**/pages/**',
|
|
@@ -520,7 +674,7 @@ export const ARCHITECTURE_PRESETS = {
|
|
|
520
674
|
'**/http/**',
|
|
521
675
|
'**/routes/**',
|
|
522
676
|
'**/hooks/**',
|
|
523
|
-
|
|
677
|
+
// No bare **/lib/** — NEW-ADOPT-LIB-AS-PRESENTATION / NEW-APP-VACUUM-LIB.
|
|
524
678
|
],
|
|
525
679
|
optional: true,
|
|
526
680
|
},
|
|
@@ -528,10 +682,8 @@ export const ARCHITECTURE_PRESETS = {
|
|
|
528
682
|
name: 'PersistenceAdapters',
|
|
529
683
|
description: 'Implements ports with real infrastructure: DB, external APIs, filesystem.',
|
|
530
684
|
patterns: [
|
|
531
|
-
'**/infrastructure/**',
|
|
532
685
|
'**/adapters/**',
|
|
533
|
-
|
|
534
|
-
'**/repositories/**',
|
|
686
|
+
...PERSISTENCE_PATH_PATTERNS,
|
|
535
687
|
],
|
|
536
688
|
optional: true,
|
|
537
689
|
},
|
|
@@ -574,7 +726,7 @@ export const ARCHITECTURE_PRESETS = {
|
|
|
574
726
|
description: 'Shared types and pure view-models (optional on UI-first trees).',
|
|
575
727
|
// Avoid bare **/types.ts — see monorepo DomainModel note (false Domain on core/**/types.ts).
|
|
576
728
|
patterns: [
|
|
577
|
-
|
|
729
|
+
...DOMAIN_PATH_PATTERNS,
|
|
578
730
|
'**/cinematic/types.ts',
|
|
579
731
|
// Common pure types bag (not **/types.ts — that traps core/**/types.ts).
|
|
580
732
|
'src/lib/types.ts',
|
|
@@ -585,17 +737,18 @@ export const ARCHITECTURE_PRESETS = {
|
|
|
585
737
|
},
|
|
586
738
|
{
|
|
587
739
|
name: 'ApplicationOrchestration',
|
|
588
|
-
description:
|
|
740
|
+
description:
|
|
741
|
+
'Server actions, features, Next API routes (`app/api/**` / `pages/api/**`), and non-UI lib orchestration (when present).',
|
|
589
742
|
patterns: [
|
|
590
743
|
'src/features/**',
|
|
591
744
|
'src/server/**',
|
|
592
745
|
'src/services/**',
|
|
593
746
|
'src/use-cases/**',
|
|
594
747
|
'src/actions/**',
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
748
|
+
// Specific lib orchestration only — never bare src/lib/** (NEW-APP-VACUUM-LIB).
|
|
749
|
+
...APPLICATION_LIB_ORCHESTRATION_PATTERNS,
|
|
750
|
+
// Next API = Application shell (wins over **/app/** Presentation by specificity).
|
|
751
|
+
...NEXT_API_APPLICATION_PATTERNS,
|
|
599
752
|
],
|
|
600
753
|
exclude: FRAMEWORK_INTERNAL_EXCLUDE,
|
|
601
754
|
optional: true,
|
|
@@ -605,26 +758,8 @@ export const ARCHITECTURE_PRESETS = {
|
|
|
605
758
|
description: 'Client data access and external API adapters (when present).',
|
|
606
759
|
// Prefer specific data-client bags over a presentation catch-all on **/lib/**
|
|
607
760
|
patterns: [
|
|
608
|
-
'**/infrastructure/**',
|
|
609
761
|
'**/adapters/**',
|
|
610
|
-
|
|
611
|
-
'**/persistence/**',
|
|
612
|
-
'src/db/**',
|
|
613
|
-
'src/data/**',
|
|
614
|
-
'src/lib/db/**',
|
|
615
|
-
'src/lib/prisma/**',
|
|
616
|
-
'src/lib/supabase/**',
|
|
617
|
-
'src/lib/airtable/**',
|
|
618
|
-
'src/lib/firebase/**',
|
|
619
|
-
'src/lib/firestore/**',
|
|
620
|
-
'src/lib/mongodb/**',
|
|
621
|
-
'src/lib/mongoose/**',
|
|
622
|
-
'src/lib/drizzle/**',
|
|
623
|
-
'src/lib/kysely/**',
|
|
624
|
-
'**/lib/supabase/**',
|
|
625
|
-
'**/lib/airtable/**',
|
|
626
|
-
'**/lib/prisma/**',
|
|
627
|
-
'**/lib/db/**',
|
|
762
|
+
...PERSISTENCE_PATH_PATTERNS,
|
|
628
763
|
],
|
|
629
764
|
exclude: FRAMEWORK_INTERNAL_EXCLUDE,
|
|
630
765
|
optional: true,
|
|
@@ -850,6 +985,104 @@ export const ARCHITECTURE_PRESETS = {
|
|
|
850
985
|
root
|
|
851
986
|
);
|
|
852
987
|
},
|
|
988
|
+
|
|
989
|
+
/**
|
|
990
|
+
* Vite SPA + root Vercel `api/` / `lib/` (NEW-SPA-DEFAULT-LAYOUT).
|
|
991
|
+
* include covers src + serverless api + shared lib; never hexagonal src-only vacuum.
|
|
992
|
+
*/
|
|
993
|
+
'vite-vercel-spa': (_workspaces, root) =>
|
|
994
|
+
presetWithOverlays(
|
|
995
|
+
{
|
|
996
|
+
include: (() => {
|
|
997
|
+
if (!root) return ['src', 'api', 'lib'];
|
|
998
|
+
const dirs = ['src', 'api', 'lib'];
|
|
999
|
+
try {
|
|
1000
|
+
return dirs.filter((d) => fs.existsSync(path.join(root, d)));
|
|
1001
|
+
} catch {
|
|
1002
|
+
return dirs;
|
|
1003
|
+
}
|
|
1004
|
+
})(),
|
|
1005
|
+
layers: [
|
|
1006
|
+
{
|
|
1007
|
+
name: 'DomainModel',
|
|
1008
|
+
description: 'Pure domain folders when present (optional on SPA trees).',
|
|
1009
|
+
patterns: [...DOMAIN_PATH_PATTERNS],
|
|
1010
|
+
exclude: FRAMEWORK_INTERNAL_EXCLUDE,
|
|
1011
|
+
forbiddenGlobals: DEFAULT_DOMAIN_FORBIDDEN_GLOBALS,
|
|
1012
|
+
optional: true,
|
|
1013
|
+
},
|
|
1014
|
+
{
|
|
1015
|
+
name: 'ApplicationOrchestration',
|
|
1016
|
+
description:
|
|
1017
|
+
'Vercel/serverless `api/**` handlers and non-UI orchestration (not Presentation).',
|
|
1018
|
+
patterns: [
|
|
1019
|
+
'api/**',
|
|
1020
|
+
'**/api/**',
|
|
1021
|
+
'src/api/**',
|
|
1022
|
+
'src/server/**',
|
|
1023
|
+
'src/services/**',
|
|
1024
|
+
'src/actions/**',
|
|
1025
|
+
...APPLICATION_LIB_ORCHESTRATION_PATTERNS,
|
|
1026
|
+
...NEXT_API_APPLICATION_PATTERNS,
|
|
1027
|
+
],
|
|
1028
|
+
exclude: FRAMEWORK_INTERNAL_EXCLUDE,
|
|
1029
|
+
optional: true,
|
|
1030
|
+
},
|
|
1031
|
+
{
|
|
1032
|
+
name: 'PersistenceAdapters',
|
|
1033
|
+
description: 'DB / CRM / auth clients under lib/ and data folders.',
|
|
1034
|
+
patterns: [...PERSISTENCE_PATH_PATTERNS, '**/adapters/**'],
|
|
1035
|
+
exclude: FRAMEWORK_INTERNAL_EXCLUDE,
|
|
1036
|
+
optional: true,
|
|
1037
|
+
},
|
|
1038
|
+
{
|
|
1039
|
+
name: 'PresentationAdapters',
|
|
1040
|
+
description:
|
|
1041
|
+
'React/Vite UI surface. Not bare lib/** (data clients stay Persistence).',
|
|
1042
|
+
patterns: [
|
|
1043
|
+
'src/components/**',
|
|
1044
|
+
'src/hooks/**',
|
|
1045
|
+
'src/pages/**',
|
|
1046
|
+
'src/routes/**',
|
|
1047
|
+
'src/ui/**',
|
|
1048
|
+
'src/layouts/**',
|
|
1049
|
+
'src/App.tsx',
|
|
1050
|
+
'src/App.jsx',
|
|
1051
|
+
'src/App.ts',
|
|
1052
|
+
'src/App.js',
|
|
1053
|
+
'src/main.tsx',
|
|
1054
|
+
'src/main.jsx',
|
|
1055
|
+
'src/main.ts',
|
|
1056
|
+
'src/main.js',
|
|
1057
|
+
'src/index.tsx',
|
|
1058
|
+
'src/index.jsx',
|
|
1059
|
+
'**/components/**',
|
|
1060
|
+
'**/hooks/**',
|
|
1061
|
+
'**/pages/**',
|
|
1062
|
+
'**/routes/**',
|
|
1063
|
+
],
|
|
1064
|
+
exclude: FRAMEWORK_INTERNAL_EXCLUDE,
|
|
1065
|
+
optional: true,
|
|
1066
|
+
},
|
|
1067
|
+
],
|
|
1068
|
+
rules: [
|
|
1069
|
+
{ from: 'DomainModel', to: 'PresentationAdapters', allowed: false },
|
|
1070
|
+
{ from: 'DomainModel', to: 'PersistenceAdapters', allowed: false },
|
|
1071
|
+
{ from: 'DomainModel', to: 'ApplicationOrchestration', allowed: false },
|
|
1072
|
+
{ from: 'ApplicationOrchestration', to: 'PresentationAdapters', allowed: false },
|
|
1073
|
+
{
|
|
1074
|
+
from: 'PresentationAdapters',
|
|
1075
|
+
to: 'PersistenceAdapters',
|
|
1076
|
+
allowed: true,
|
|
1077
|
+
message:
|
|
1078
|
+
'SPA day-one UI may reach data clients; prefer ports as the product grows.',
|
|
1079
|
+
},
|
|
1080
|
+
{ from: 'PersistenceAdapters', to: 'PresentationAdapters', allowed: false },
|
|
1081
|
+
{ from: 'PersistenceAdapters', to: 'ApplicationOrchestration', allowed: false },
|
|
1082
|
+
],
|
|
1083
|
+
},
|
|
1084
|
+
root
|
|
1085
|
+
),
|
|
853
1086
|
};
|
|
854
1087
|
|
|
855
1088
|
// Aliases: Clean / Onion map to the hexagonal factory (same matrix + globs). Avoid dual maintenance.
|
|
@@ -859,6 +1092,41 @@ ARCHITECTURE_PRESETS['onion-architecture'] = ARCHITECTURE_PRESETS.hexagonal;
|
|
|
859
1092
|
/** Stable public preset keys (CLI help, score fit, docs). Order is display order. */
|
|
860
1093
|
export const ARCHITECTURE_PRESET_NAMES = Object.keys(ARCHITECTURE_PRESETS);
|
|
861
1094
|
|
|
1095
|
+
/**
|
|
1096
|
+
* Additive P0-A retrofit: inject high-spec Next API → Application patterns when missing.
|
|
1097
|
+
* Pure — does not write files (DL-P0A-RETROFIT).
|
|
1098
|
+
*
|
|
1099
|
+
* @param {object} config ark.config-shaped object
|
|
1100
|
+
* @returns {{ changed: boolean, injected: string[], targetLayer: string|null, config: object }}
|
|
1101
|
+
*/
|
|
1102
|
+
export function retrofitP0aApiApplicationPatterns(config) {
|
|
1103
|
+
const layers = Array.isArray(config?.layers) ? config.layers : [];
|
|
1104
|
+
const appLayer =
|
|
1105
|
+
layers.find((l) => l?.name === 'ApplicationOrchestration') ||
|
|
1106
|
+
layers.find((l) => /application|orchestr/i.test(l?.name ?? ''));
|
|
1107
|
+
if (!appLayer) {
|
|
1108
|
+
return { changed: false, injected: [], targetLayer: null, config };
|
|
1109
|
+
}
|
|
1110
|
+
const existing = new Set(appLayer.patterns ?? []);
|
|
1111
|
+
const injected = NEXT_API_APPLICATION_PATTERNS.filter((p) => !existing.has(p));
|
|
1112
|
+
if (injected.length === 0) {
|
|
1113
|
+
return { changed: false, injected: [], targetLayer: appLayer.name, config };
|
|
1114
|
+
}
|
|
1115
|
+
const nextLayers = layers.map((layer) => {
|
|
1116
|
+
if (layer.name !== appLayer.name) return layer;
|
|
1117
|
+
return {
|
|
1118
|
+
...layer,
|
|
1119
|
+
patterns: [...new Set([...(layer.patterns ?? []), ...injected])],
|
|
1120
|
+
};
|
|
1121
|
+
});
|
|
1122
|
+
return {
|
|
1123
|
+
changed: true,
|
|
1124
|
+
injected: [...injected],
|
|
1125
|
+
targetLayer: appLayer.name,
|
|
1126
|
+
config: { ...config, layers: nextLayers },
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
|
|
862
1130
|
// ── Layer suggestion engine ──────────────────────────────────────────────────
|
|
863
1131
|
// Everything here is HARVESTED from Ark's own canonical sources — the 11-layer defaults
|
|
864
1132
|
// (DEFAULT_LAYER_DIRECTORIES) and the named presets — so a suggestion can never drift from
|