arkgate 2.8.3 → 2.9.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 +46 -0
- package/README.md +2 -1
- package/bin/ark-check.mjs +2 -2
- package/bin/ark-layer-match.mjs +88 -5
- package/bin/ark-mcp.mjs +7 -70
- package/bin/ark-shared.mjs +88 -8
- package/bin/ark.mjs +3 -2
- package/bin/lib/architecture-scan.mjs +16 -4
- package/bin/lib/config-warnings.mjs +11 -2
- package/bin/lib/doctor-plan.mjs +20 -0
- package/bin/lib/import-resolve.mjs +133 -0
- package/bin/lib/presets.mjs +207 -11
- package/bin/lib/remediation.mjs +15 -0
- package/bin/lib/suggestions.mjs +8 -3
- package/dist/eslint/index.cjs +63 -5
- package/dist/eslint/index.cjs.map +1 -1
- package/dist/eslint/index.d.cts +33 -1
- package/dist/eslint/index.d.ts +33 -1
- package/dist/eslint/index.js +63 -5
- package/dist/eslint/index.js.map +1 -1
- package/dist/index.cjs +103 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -9
- package/dist/index.d.ts +21 -9
- package/dist/index.js +103 -14
- package/dist/index.js.map +1 -1
- package/dist/nestjs/index.cjs +78 -4
- package/dist/nestjs/index.cjs.map +1 -1
- package/dist/nestjs/index.d.cts +1 -1
- package/dist/nestjs/index.d.ts +1 -1
- package/dist/nestjs/index.js +78 -4
- package/dist/nestjs/index.js.map +1 -1
- package/dist/runtime/index.cjs +103 -14
- package/dist/runtime/index.cjs.map +1 -1
- package/dist/runtime/index.d.cts +1 -1
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +103 -14
- package/dist/runtime/index.js.map +1 -1
- package/dist/{types-CSJhEOk2.d.cts → types-D6Q8WHes.d.cts} +7 -0
- package/dist/{types-CSJhEOk2.d.ts → types-D6Q8WHes.d.ts} +7 -0
- package/docs/agent-guide.md +55 -4
- package/package.json +3 -1
- package/server.json +2 -2
- package/templates/architecture-playbook.json +65 -1
- package/templates/policy-packs/enthusiast-ddd-bounded-contexts.json +19 -0
- package/templates/policy-packs/enthusiast-ui-surface.json +18 -0
- package/templates/policy-packs/enthusiast-vertical-slice.json +18 -0
- package/templates/skills/ark-adopt.md +4 -0
- package/templates/skills/ark-architect.md +5 -1
- package/templates/skills/ark-autopilot.md +3 -1
- package/templates/skills/ark-fix.md +3 -0
- package/templates/skills/ark-place.md +7 -0
- package/templates/skills/ark-think.md +43 -0
package/dist/index.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { I as IntentRegistry, a as IntentName, D as DefineIntentOptions, b as IntentCreator, P as PolicyViolation, c as PolicySeverity, d as PolicyEnforcementMode, e as Policy, f as CreateArchitectureProfileOptions, g as ArchitectureProfile, h as ArkCheckConfig, i as CreateArchitectureProfileFromArkConfigOptions, j as CreateElevenLayerArkConfigOptions, k as DependencyGraph, G as GraphEdge, l as IntentRelationship, m as AuditStore, n as AuditRecord, o as AuditQuery, p as CreateAuditTrailOptions, q as AuditTrail, E as EventContractRegistry, r as EventContract, s as DomainEvent, t as EventContractValidationResult, O as OutboxStore, u as OutboxRecord, v as OutboxStatus, w as EventBusOptions, x as EventBus, y as CreateObservabilityReporterOptions, z as ObservabilityReporter, M as MetadataRegistry, R as ReadModelStore, B as CreateProjectionRegistryOptions, F as ProjectionRegistry, H as PolicyEngine, J as ArkManifest, W as WorkflowStore, S as SagaContext, K as WorkflowSnapshot, L as SagaDefinition, N as CreateWorkflowEngineOptions, Q as SagaInstance, T as WorkflowEngine, C as CreateArkKernelOptions, A as ArkKernel, U as ArkKernelConfig, V as CreateArkKernelFromConfigOptions, X as TraceRecordType, Y as TraceRecord, Z as ObservabilityDriftReport } from './types-
|
|
2
|
-
export { _ as ArchitectureLayer, $ as ArchitectureLayerConfig, a0 as ArchitectureRule, a1 as ArkManifestArchitecture, a2 as ArkManifestData, a3 as ArkManifestEntityLink, a4 as ArkManifestGraph, a5 as ArkManifestIntent, a6 as ArkManifestPolicy, a7 as ArkManifestProjection, a8 as AuditRecordInput, a9 as AuditRecordType, aa as CorrelationId, ab as EntityMeta, ac as EventContractIssue, ad as EventHandler, ae as EventInterceptionInfo, af as EventInterceptor, ag as EventInterceptorContext, ah as EventMetadata, ai as EventPayloadPatch, aj as EventPayloadSchema, ak as EventPublisher, al as EventSchemaField, am as EventSchemaFieldType, an as FieldMeta, ao as GraphNode, ap as IntentRelationshipKind, aq as ObservabilityFlow, ar as ObservedLayerFlowMode, as as PolicyEvaluationResult, at as ProjectionCheckpoint, au as ProjectionDefinition, av as PublishedEventRecord, aw as RetryPolicy, ax as SagaStatus, ay as SagaStep, az as TraceSink, aA as Unsubscribe, aB as WorkflowDefinition, aC as WorkflowStatus, aD as WorkflowStep } from './types-
|
|
1
|
+
import { I as IntentRegistry, a as IntentName, D as DefineIntentOptions, b as IntentCreator, P as PolicyViolation, c as PolicySeverity, d as PolicyEnforcementMode, e as Policy, f as CreateArchitectureProfileOptions, g as ArchitectureProfile, h as ArkCheckConfig, i as CreateArchitectureProfileFromArkConfigOptions, j as CreateElevenLayerArkConfigOptions, k as DependencyGraph, G as GraphEdge, l as IntentRelationship, m as AuditStore, n as AuditRecord, o as AuditQuery, p as CreateAuditTrailOptions, q as AuditTrail, E as EventContractRegistry, r as EventContract, s as DomainEvent, t as EventContractValidationResult, O as OutboxStore, u as OutboxRecord, v as OutboxStatus, w as EventBusOptions, x as EventBus, y as CreateObservabilityReporterOptions, z as ObservabilityReporter, M as MetadataRegistry, R as ReadModelStore, B as CreateProjectionRegistryOptions, F as ProjectionRegistry, H as PolicyEngine, J as ArkManifest, W as WorkflowStore, S as SagaContext, K as WorkflowSnapshot, L as SagaDefinition, N as CreateWorkflowEngineOptions, Q as SagaInstance, T as WorkflowEngine, C as CreateArkKernelOptions, A as ArkKernel, U as ArkKernelConfig, V as CreateArkKernelFromConfigOptions, X as TraceRecordType, Y as TraceRecord, Z as ObservabilityDriftReport } from './types-D6Q8WHes.cjs';
|
|
2
|
+
export { _ as ArchitectureLayer, $ as ArchitectureLayerConfig, a0 as ArchitectureRule, a1 as ArkManifestArchitecture, a2 as ArkManifestData, a3 as ArkManifestEntityLink, a4 as ArkManifestGraph, a5 as ArkManifestIntent, a6 as ArkManifestPolicy, a7 as ArkManifestProjection, a8 as AuditRecordInput, a9 as AuditRecordType, aa as CorrelationId, ab as EntityMeta, ac as EventContractIssue, ad as EventHandler, ae as EventInterceptionInfo, af as EventInterceptor, ag as EventInterceptorContext, ah as EventMetadata, ai as EventPayloadPatch, aj as EventPayloadSchema, ak as EventPublisher, al as EventSchemaField, am as EventSchemaFieldType, an as FieldMeta, ao as GraphNode, ap as IntentRelationshipKind, aq as ObservabilityFlow, ar as ObservedLayerFlowMode, as as PolicyEvaluationResult, at as ProjectionCheckpoint, au as ProjectionDefinition, av as PublishedEventRecord, aw as RetryPolicy, ax as SagaStatus, ay as SagaStep, az as TraceSink, aA as Unsubscribe, aB as WorkflowDefinition, aC as WorkflowStatus, aD as WorkflowStep } from './types-D6Q8WHes.cjs';
|
|
3
3
|
|
|
4
4
|
/** ArkGate library version — single source of truth. */
|
|
5
|
-
declare const version = "2.
|
|
5
|
+
declare const version = "2.9.0";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* defineIntent
|
|
@@ -583,14 +583,26 @@ interface AICodeGateOptions<Context = AICodeGateContext> {
|
|
|
583
583
|
*/
|
|
584
584
|
infrastructureLayers?: string[];
|
|
585
585
|
/**
|
|
586
|
-
*
|
|
587
|
-
*
|
|
588
|
-
* layer
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
586
|
+
* Preferred single resolve step: import specifier or absolute source file →
|
|
587
|
+
* `{ layer, relPath }` for contract + peerIsolation. Prefer this over the
|
|
588
|
+
* legacy layer-only callback.
|
|
589
|
+
*/
|
|
590
|
+
resolveImportTarget?: (specifierOrFilePath: string, fromFilePath?: string) => {
|
|
591
|
+
layer?: string;
|
|
592
|
+
relPath?: string;
|
|
593
|
+
} | undefined;
|
|
594
|
+
/**
|
|
595
|
+
* @deprecated Prefer resolveImportTarget. Layer-only resolve for governed imports.
|
|
592
596
|
*/
|
|
593
597
|
resolveImportLayer?: (specifier: string, fromFilePath?: string) => string | undefined;
|
|
598
|
+
/**
|
|
599
|
+
* Layer configs (patterns) used to infer sliceFolders when a peerIsolation rule
|
|
600
|
+
* omits an explicit list.
|
|
601
|
+
*/
|
|
602
|
+
architectureLayers?: Array<{
|
|
603
|
+
name: string;
|
|
604
|
+
patterns?: string[];
|
|
605
|
+
}>;
|
|
594
606
|
}
|
|
595
607
|
declare function createAICodeGate<Context = AICodeGateContext>(options?: AICodeGateOptions<Context>): AICodeGate<Context>;
|
|
596
608
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { I as IntentRegistry, a as IntentName, D as DefineIntentOptions, b as IntentCreator, P as PolicyViolation, c as PolicySeverity, d as PolicyEnforcementMode, e as Policy, f as CreateArchitectureProfileOptions, g as ArchitectureProfile, h as ArkCheckConfig, i as CreateArchitectureProfileFromArkConfigOptions, j as CreateElevenLayerArkConfigOptions, k as DependencyGraph, G as GraphEdge, l as IntentRelationship, m as AuditStore, n as AuditRecord, o as AuditQuery, p as CreateAuditTrailOptions, q as AuditTrail, E as EventContractRegistry, r as EventContract, s as DomainEvent, t as EventContractValidationResult, O as OutboxStore, u as OutboxRecord, v as OutboxStatus, w as EventBusOptions, x as EventBus, y as CreateObservabilityReporterOptions, z as ObservabilityReporter, M as MetadataRegistry, R as ReadModelStore, B as CreateProjectionRegistryOptions, F as ProjectionRegistry, H as PolicyEngine, J as ArkManifest, W as WorkflowStore, S as SagaContext, K as WorkflowSnapshot, L as SagaDefinition, N as CreateWorkflowEngineOptions, Q as SagaInstance, T as WorkflowEngine, C as CreateArkKernelOptions, A as ArkKernel, U as ArkKernelConfig, V as CreateArkKernelFromConfigOptions, X as TraceRecordType, Y as TraceRecord, Z as ObservabilityDriftReport } from './types-
|
|
2
|
-
export { _ as ArchitectureLayer, $ as ArchitectureLayerConfig, a0 as ArchitectureRule, a1 as ArkManifestArchitecture, a2 as ArkManifestData, a3 as ArkManifestEntityLink, a4 as ArkManifestGraph, a5 as ArkManifestIntent, a6 as ArkManifestPolicy, a7 as ArkManifestProjection, a8 as AuditRecordInput, a9 as AuditRecordType, aa as CorrelationId, ab as EntityMeta, ac as EventContractIssue, ad as EventHandler, ae as EventInterceptionInfo, af as EventInterceptor, ag as EventInterceptorContext, ah as EventMetadata, ai as EventPayloadPatch, aj as EventPayloadSchema, ak as EventPublisher, al as EventSchemaField, am as EventSchemaFieldType, an as FieldMeta, ao as GraphNode, ap as IntentRelationshipKind, aq as ObservabilityFlow, ar as ObservedLayerFlowMode, as as PolicyEvaluationResult, at as ProjectionCheckpoint, au as ProjectionDefinition, av as PublishedEventRecord, aw as RetryPolicy, ax as SagaStatus, ay as SagaStep, az as TraceSink, aA as Unsubscribe, aB as WorkflowDefinition, aC as WorkflowStatus, aD as WorkflowStep } from './types-
|
|
1
|
+
import { I as IntentRegistry, a as IntentName, D as DefineIntentOptions, b as IntentCreator, P as PolicyViolation, c as PolicySeverity, d as PolicyEnforcementMode, e as Policy, f as CreateArchitectureProfileOptions, g as ArchitectureProfile, h as ArkCheckConfig, i as CreateArchitectureProfileFromArkConfigOptions, j as CreateElevenLayerArkConfigOptions, k as DependencyGraph, G as GraphEdge, l as IntentRelationship, m as AuditStore, n as AuditRecord, o as AuditQuery, p as CreateAuditTrailOptions, q as AuditTrail, E as EventContractRegistry, r as EventContract, s as DomainEvent, t as EventContractValidationResult, O as OutboxStore, u as OutboxRecord, v as OutboxStatus, w as EventBusOptions, x as EventBus, y as CreateObservabilityReporterOptions, z as ObservabilityReporter, M as MetadataRegistry, R as ReadModelStore, B as CreateProjectionRegistryOptions, F as ProjectionRegistry, H as PolicyEngine, J as ArkManifest, W as WorkflowStore, S as SagaContext, K as WorkflowSnapshot, L as SagaDefinition, N as CreateWorkflowEngineOptions, Q as SagaInstance, T as WorkflowEngine, C as CreateArkKernelOptions, A as ArkKernel, U as ArkKernelConfig, V as CreateArkKernelFromConfigOptions, X as TraceRecordType, Y as TraceRecord, Z as ObservabilityDriftReport } from './types-D6Q8WHes.js';
|
|
2
|
+
export { _ as ArchitectureLayer, $ as ArchitectureLayerConfig, a0 as ArchitectureRule, a1 as ArkManifestArchitecture, a2 as ArkManifestData, a3 as ArkManifestEntityLink, a4 as ArkManifestGraph, a5 as ArkManifestIntent, a6 as ArkManifestPolicy, a7 as ArkManifestProjection, a8 as AuditRecordInput, a9 as AuditRecordType, aa as CorrelationId, ab as EntityMeta, ac as EventContractIssue, ad as EventHandler, ae as EventInterceptionInfo, af as EventInterceptor, ag as EventInterceptorContext, ah as EventMetadata, ai as EventPayloadPatch, aj as EventPayloadSchema, ak as EventPublisher, al as EventSchemaField, am as EventSchemaFieldType, an as FieldMeta, ao as GraphNode, ap as IntentRelationshipKind, aq as ObservabilityFlow, ar as ObservedLayerFlowMode, as as PolicyEvaluationResult, at as ProjectionCheckpoint, au as ProjectionDefinition, av as PublishedEventRecord, aw as RetryPolicy, ax as SagaStatus, ay as SagaStep, az as TraceSink, aA as Unsubscribe, aB as WorkflowDefinition, aC as WorkflowStatus, aD as WorkflowStep } from './types-D6Q8WHes.js';
|
|
3
3
|
|
|
4
4
|
/** ArkGate library version — single source of truth. */
|
|
5
|
-
declare const version = "2.
|
|
5
|
+
declare const version = "2.9.0";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* defineIntent
|
|
@@ -583,14 +583,26 @@ interface AICodeGateOptions<Context = AICodeGateContext> {
|
|
|
583
583
|
*/
|
|
584
584
|
infrastructureLayers?: string[];
|
|
585
585
|
/**
|
|
586
|
-
*
|
|
587
|
-
*
|
|
588
|
-
* layer
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
586
|
+
* Preferred single resolve step: import specifier or absolute source file →
|
|
587
|
+
* `{ layer, relPath }` for contract + peerIsolation. Prefer this over the
|
|
588
|
+
* legacy layer-only callback.
|
|
589
|
+
*/
|
|
590
|
+
resolveImportTarget?: (specifierOrFilePath: string, fromFilePath?: string) => {
|
|
591
|
+
layer?: string;
|
|
592
|
+
relPath?: string;
|
|
593
|
+
} | undefined;
|
|
594
|
+
/**
|
|
595
|
+
* @deprecated Prefer resolveImportTarget. Layer-only resolve for governed imports.
|
|
592
596
|
*/
|
|
593
597
|
resolveImportLayer?: (specifier: string, fromFilePath?: string) => string | undefined;
|
|
598
|
+
/**
|
|
599
|
+
* Layer configs (patterns) used to infer sliceFolders when a peerIsolation rule
|
|
600
|
+
* omits an explicit list.
|
|
601
|
+
*/
|
|
602
|
+
architectureLayers?: Array<{
|
|
603
|
+
name: string;
|
|
604
|
+
patterns?: string[];
|
|
605
|
+
}>;
|
|
594
606
|
}
|
|
595
607
|
declare function createAICodeGate<Context = AICodeGateContext>(options?: AICodeGateOptions<Context>): AICodeGate<Context>;
|
|
596
608
|
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/version.ts
|
|
2
|
-
var version = "2.
|
|
2
|
+
var version = "2.9.0";
|
|
3
3
|
|
|
4
4
|
// src/kernel/intent/IntentRegistry.ts
|
|
5
5
|
var IntentRegistry = class {
|
|
@@ -662,6 +662,82 @@ async function recordInterceptorError(interceptor, event, error, deps) {
|
|
|
662
662
|
});
|
|
663
663
|
}
|
|
664
664
|
|
|
665
|
+
// src/domain/layerMatch.ts
|
|
666
|
+
function normalizeGlobSeparators(pattern) {
|
|
667
|
+
let out = "";
|
|
668
|
+
for (let i = 0; i < pattern.length; i += 1) {
|
|
669
|
+
const c = pattern[i];
|
|
670
|
+
if (c === "\\" && i + 1 < pattern.length) {
|
|
671
|
+
const next = pattern[i + 1];
|
|
672
|
+
if ("*?{}[],".includes(next) || next === "\\") {
|
|
673
|
+
out += "\\" + next;
|
|
674
|
+
i += 1;
|
|
675
|
+
continue;
|
|
676
|
+
}
|
|
677
|
+
out += "/";
|
|
678
|
+
continue;
|
|
679
|
+
}
|
|
680
|
+
out += c;
|
|
681
|
+
}
|
|
682
|
+
return out;
|
|
683
|
+
}
|
|
684
|
+
function sliceIdForPath(relPath, sliceFolders) {
|
|
685
|
+
if (!sliceFolders?.length) return void 0;
|
|
686
|
+
const parts = String(relPath).split(/[/\\]/).filter(Boolean);
|
|
687
|
+
const folders = new Set(sliceFolders.map((s) => String(s).toLowerCase()));
|
|
688
|
+
for (let i = 0; i < parts.length - 1; i += 1) {
|
|
689
|
+
if (folders.has(parts[i].toLowerCase())) {
|
|
690
|
+
return `${parts[i]}/${parts[i + 1]}`;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
return void 0;
|
|
694
|
+
}
|
|
695
|
+
function inferSliceFoldersFromPatterns(patterns) {
|
|
696
|
+
const out = /* @__PURE__ */ new Set();
|
|
697
|
+
for (const pattern of patterns ?? []) {
|
|
698
|
+
const glob = normalizeGlobSeparators(String(pattern));
|
|
699
|
+
const parts = glob.split("/").filter(Boolean);
|
|
700
|
+
for (let i = 0; i < parts.length; i += 1) {
|
|
701
|
+
const part = parts[i];
|
|
702
|
+
if ((part === "**" || part === "*") && i > 0) {
|
|
703
|
+
const prev = parts[i - 1];
|
|
704
|
+
if (prev && !prev.includes("*") && !prev.includes("{") && !prev.includes("}")) {
|
|
705
|
+
out.add(prev);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
return [...out];
|
|
711
|
+
}
|
|
712
|
+
function resolveSliceFolders(rule, layerName, layers) {
|
|
713
|
+
if (Array.isArray(rule.sliceFolders) && rule.sliceFolders.length > 0) {
|
|
714
|
+
return rule.sliceFolders.filter((s) => typeof s === "string" && s.length > 0);
|
|
715
|
+
}
|
|
716
|
+
const layer = (layers ?? []).find((l) => l.name === layerName);
|
|
717
|
+
return inferSliceFoldersFromPatterns(layer?.patterns);
|
|
718
|
+
}
|
|
719
|
+
function findDeniedEdgeRule(rules, from, to, options) {
|
|
720
|
+
for (const rule of rules ?? []) {
|
|
721
|
+
if (rule.from !== from || rule.to !== to) continue;
|
|
722
|
+
if (rule.allowed !== false) continue;
|
|
723
|
+
if (rule.peerIsolation) {
|
|
724
|
+
const fromPath = options?.fromPath;
|
|
725
|
+
const toPath = options?.toPath;
|
|
726
|
+
if (!fromPath || !toPath) continue;
|
|
727
|
+
const folders = resolveSliceFolders(rule, from, options?.layers);
|
|
728
|
+
if (folders.length === 0) continue;
|
|
729
|
+
const fromSlice = sliceIdForPath(fromPath, folders);
|
|
730
|
+
const toSlice = sliceIdForPath(toPath, folders);
|
|
731
|
+
if (!fromSlice || !toSlice) continue;
|
|
732
|
+
if (fromSlice !== toSlice) return rule;
|
|
733
|
+
continue;
|
|
734
|
+
}
|
|
735
|
+
if (from === to) continue;
|
|
736
|
+
return rule;
|
|
737
|
+
}
|
|
738
|
+
return void 0;
|
|
739
|
+
}
|
|
740
|
+
|
|
665
741
|
// src/kernel/event-bus/observedLayerFlow.ts
|
|
666
742
|
async function assertObservedLayerFlowAllowed(event, deps) {
|
|
667
743
|
if (deps.mode === "off" || !deps.architectureProfile) {
|
|
@@ -673,9 +749,7 @@ async function assertObservedLayerFlowAllowed(event, deps) {
|
|
|
673
749
|
const fromLayer = profile.resolveLayer(source);
|
|
674
750
|
const toLayer = profile.resolveLayer(event.intent);
|
|
675
751
|
if (!fromLayer || !toLayer) return;
|
|
676
|
-
const blocked = profile.rules
|
|
677
|
-
(rule) => !rule.allowed && rule.from === fromLayer && rule.to === toLayer
|
|
678
|
-
);
|
|
752
|
+
const blocked = findDeniedEdgeRule(profile.rules, fromLayer, toLayer);
|
|
679
753
|
if (!blocked) return;
|
|
680
754
|
const severity = deps.mode;
|
|
681
755
|
const message = blocked.message ?? `Observed layer violation: "${source}" (${fromLayer}) must not produce "${event.intent}" (${toLayer}).`;
|
|
@@ -2325,16 +2399,26 @@ function createAICodeGate(options = {}) {
|
|
|
2325
2399
|
}
|
|
2326
2400
|
}
|
|
2327
2401
|
for (const specifier of extractModuleSpecifiers(source)) {
|
|
2328
|
-
const
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2402
|
+
const targetHit = options.resolveImportTarget?.(specifier.value, filePath) ?? (options.resolveImportLayer ? { layer: options.resolveImportLayer(specifier.value, filePath) } : void 0);
|
|
2403
|
+
const sourceHit = typeof filePath === "string" ? options.resolveImportTarget?.(filePath) ?? (options.resolveImportLayer ? { layer: contextLayer, relPath: void 0 } : void 0) : void 0;
|
|
2404
|
+
const targetLayer = targetHit?.layer;
|
|
2405
|
+
if (targetLayer && contextLayer) {
|
|
2406
|
+
const blocked = findDeniedEdgeRule(
|
|
2407
|
+
options.architectureProfile?.rules,
|
|
2408
|
+
contextLayer,
|
|
2409
|
+
targetLayer,
|
|
2410
|
+
{
|
|
2411
|
+
fromPath: sourceHit?.relPath,
|
|
2412
|
+
toPath: targetHit?.relPath,
|
|
2413
|
+
layers: options.architectureLayers
|
|
2414
|
+
}
|
|
2332
2415
|
);
|
|
2333
2416
|
if (blocked) {
|
|
2417
|
+
const peer = Boolean(blocked.peerIsolation);
|
|
2334
2418
|
violations.push(
|
|
2335
2419
|
violation(
|
|
2336
2420
|
"LAYER_IMPORT_VIOLATION",
|
|
2337
|
-
blocked.message ?? `Layer "${contextLayer}" must not import "${targetLayer}"
|
|
2421
|
+
blocked.message ?? (peer ? `Layer "${contextLayer}" must not import across slices into "${targetLayer}".` : `Layer "${contextLayer}" must not import "${targetLayer}".`),
|
|
2338
2422
|
{
|
|
2339
2423
|
line: lineOf(source, specifier.index),
|
|
2340
2424
|
source: specifier.value,
|
|
@@ -2342,13 +2426,16 @@ function createAICodeGate(options = {}) {
|
|
|
2342
2426
|
filePath,
|
|
2343
2427
|
fromLayer: contextLayer,
|
|
2344
2428
|
toLayer: targetLayer,
|
|
2345
|
-
suggestion: "Depend on a port/interface owned by an inner layer instead, or move this code to a layer allowed to make this import.",
|
|
2346
|
-
details: { importKind: specifier.kind }
|
|
2429
|
+
suggestion: peer ? "Extract shared code to a shared layer, or coordinate slices via events/ports \u2014 do not import across feature/context slices." : "Depend on a port/interface owned by an inner layer instead, or move this code to a layer allowed to make this import.",
|
|
2430
|
+
details: { importKind: specifier.kind, peerIsolation: peer }
|
|
2347
2431
|
}
|
|
2348
2432
|
)
|
|
2349
2433
|
);
|
|
2434
|
+
continue;
|
|
2435
|
+
}
|
|
2436
|
+
if (targetLayer !== contextLayer) {
|
|
2437
|
+
continue;
|
|
2350
2438
|
}
|
|
2351
|
-
continue;
|
|
2352
2439
|
}
|
|
2353
2440
|
if (exemptFromInfraHeuristics) continue;
|
|
2354
2441
|
if (!hasInfrastructureToken(specifier.value) && !isKnownInfrastructurePackage(specifier.value)) {
|
|
@@ -2417,8 +2504,10 @@ function createAICodeGate(options = {}) {
|
|
|
2417
2504
|
if (!looksLikeIntentName(literal.value)) continue;
|
|
2418
2505
|
const targetLayer = options.architectureProfile.resolveLayer(literal.value);
|
|
2419
2506
|
if (!targetLayer) continue;
|
|
2420
|
-
const blocked =
|
|
2421
|
-
|
|
2507
|
+
const blocked = findDeniedEdgeRule(
|
|
2508
|
+
options.architectureProfile.rules,
|
|
2509
|
+
contextLayer,
|
|
2510
|
+
targetLayer
|
|
2422
2511
|
);
|
|
2423
2512
|
if (blocked) {
|
|
2424
2513
|
violations.push(
|