arkgate 2.13.0 → 3.0.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 +39 -0
- package/README.md +37 -22
- package/bin/ark-check.mjs +62 -4
- package/bin/ark-mcp.mjs +108 -1
- package/bin/ark-shared.mjs +204 -149
- package/bin/ark.mjs +90 -25
- package/bin/lib/adapter-contract.mjs +93 -0
- package/bin/lib/agent-gates.mjs +1 -0
- package/bin/lib/analysis-engine.mjs +1171 -0
- package/bin/lib/architecture-scan.mjs +84 -135
- package/bin/lib/ci-and-commands.mjs +31 -0
- package/bin/lib/config-warnings.mjs +7 -205
- package/bin/lib/field-install.mjs +67 -10
- package/bin/lib/gate-files.mjs +42 -3
- package/bin/lib/graph-cycles.mjs +4 -54
- package/bin/lib/hook-templates.mjs +33 -1
- package/bin/lib/host-support-matrix.mjs +7 -1
- package/bin/lib/install-migrate.mjs +54 -16
- package/bin/lib/presets.mjs +42 -2
- package/bin/lib/safety-diagnostics.mjs +18 -17
- package/bin/lib/scan-files.mjs +12 -1
- package/bin/lib/skill-install.mjs +8 -1
- package/bin/lib/source-policy.mjs +36 -0
- package/bin/lib/start-preview.mjs +271 -0
- package/bin/lib/ts-resolve.mjs +11 -2
- package/bin/lib/write-path-capabilities.mjs +4 -0
- package/compat/nestjs.cjs +2 -0
- package/compat/nestjs.d.ts +2 -0
- package/compat/nestjs.js +1 -0
- package/compat/runtime.cjs +2 -0
- package/compat/runtime.d.ts +2 -0
- package/compat/runtime.js +1 -0
- package/dist/configContract-BxSIwVRo.d.cts +259 -0
- package/dist/configContract-BxSIwVRo.d.ts +259 -0
- package/dist/eslint/index.cjs +125 -48
- package/dist/eslint/index.d.cts +7 -1
- package/dist/eslint/index.d.ts +7 -1
- package/dist/eslint/index.js +125 -48
- package/dist/index.cjs +1248 -3302
- package/dist/index.d.cts +359 -483
- package/dist/index.d.ts +359 -483
- package/dist/index.js +1231 -3248
- package/docs/agent-guide.md +28 -16
- package/docs/ai-gates.md +30 -7
- package/docs/migrate-from-ark-runtime-kernel.md +2 -3
- package/docs/package-surface.md +8 -13
- package/docs/production-hardening.md +17 -4
- package/docs/typescript-support.md +27 -0
- package/package.json +33 -11
- package/schemas/ark.analysis-result.schema.json +91 -0
- package/server.json +2 -2
- package/templates/skills/ark-architect.md +3 -2
- package/dist/configContract-iBLxx5Tz.d.cts +0 -53
- package/dist/configContract-iBLxx5Tz.d.ts +0 -53
- package/dist/eslint/index.cjs.map +0 -1
- package/dist/eslint/index.js.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/nestjs/index.cjs +0 -2606
- package/dist/nestjs/index.cjs.map +0 -1
- package/dist/nestjs/index.d.cts +0 -23
- package/dist/nestjs/index.d.ts +0 -23
- package/dist/nestjs/index.js +0 -2582
- package/dist/nestjs/index.js.map +0 -1
- package/dist/runtime/index.cjs +0 -4014
- package/dist/runtime/index.cjs.map +0 -1
- package/dist/runtime/index.d.cts +0 -3
- package/dist/runtime/index.d.ts +0 -3
- package/dist/runtime/index.js +0 -3925
- package/dist/runtime/index.js.map +0 -1
- package/dist/types-BxBwnBpC.d.cts +0 -1041
- package/dist/types-Wcs_l1_J.d.ts +0 -1041
package/dist/eslint/index.js
CHANGED
|
@@ -475,6 +475,63 @@ function parseArkConfigJson(json, source = "ark.config.json") {
|
|
|
475
475
|
return loadArkConfigContract(input, source);
|
|
476
476
|
}
|
|
477
477
|
|
|
478
|
+
// src/domain/adapterContract.ts
|
|
479
|
+
function text(value) {
|
|
480
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
481
|
+
}
|
|
482
|
+
function positiveInteger(value, fallback) {
|
|
483
|
+
return Number.isInteger(value) && Number(value) > 0 ? Number(value) : fallback;
|
|
484
|
+
}
|
|
485
|
+
function toAdapterDiagnostic(violation, fallbackSeverity = "error") {
|
|
486
|
+
const ruleId = text(violation.ruleId) ?? text(violation.code) ?? "ARK_UNKNOWN";
|
|
487
|
+
const severity = violation.severity === "warning" ? "warning" : fallbackSeverity;
|
|
488
|
+
const evidence = {
|
|
489
|
+
...text(violation.target) ? { target: text(violation.target) } : {},
|
|
490
|
+
...text(violation.fromLayer) ? { fromLayer: text(violation.fromLayer) } : {},
|
|
491
|
+
...text(violation.toLayer) ? { toLayer: text(violation.toLayer) } : {},
|
|
492
|
+
...typeof violation.typeOnly === "boolean" ? { typeOnly: violation.typeOnly } : {}
|
|
493
|
+
};
|
|
494
|
+
return {
|
|
495
|
+
ruleId,
|
|
496
|
+
severity,
|
|
497
|
+
message: text(violation.message) ?? ruleId,
|
|
498
|
+
location: {
|
|
499
|
+
file: text(violation.file) ?? "<unknown>",
|
|
500
|
+
line: positiveInteger(violation.line, 1),
|
|
501
|
+
column: positiveInteger(violation.column, 1)
|
|
502
|
+
},
|
|
503
|
+
evidence
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// src/domain/sourcePolicy.ts
|
|
508
|
+
var SOURCE_POLICY_MESSAGES = {
|
|
509
|
+
RAW_EVENT_PUBLISH: "Publish through a registered intent creator; raw event objects or intent strings bypass Ark contracts and tooling.",
|
|
510
|
+
PUBLISH_MISSING_SOURCE: "Strict Ark publish calls must include metadata.source."
|
|
511
|
+
};
|
|
512
|
+
function looksLikeArkIntent(value) {
|
|
513
|
+
return /^(Domain|Application|Adapter|Workflow|Job|Presentation|Reporting|Metadata|Security|Audit|Observability|Kernel)\.[A-Za-z0-9_.]+$/.test(
|
|
514
|
+
value
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
function classifyPublishFacts(facts) {
|
|
518
|
+
if (!facts.publishCall) return [];
|
|
519
|
+
const findings = [];
|
|
520
|
+
if (facts.rawIntentName !== void 0 && looksLikeArkIntent(facts.rawIntentName) || facts.objectHasIntent) {
|
|
521
|
+
findings.push({
|
|
522
|
+
ruleId: "RAW_EVENT_PUBLISH",
|
|
523
|
+
message: SOURCE_POLICY_MESSAGES.RAW_EVENT_PUBLISH
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
if (facts.arkPublishCandidate && !facts.hasSource) {
|
|
527
|
+
findings.push({
|
|
528
|
+
ruleId: "PUBLISH_MISSING_SOURCE",
|
|
529
|
+
message: SOURCE_POLICY_MESSAGES.PUBLISH_MISSING_SOURCE
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
return findings;
|
|
533
|
+
}
|
|
534
|
+
|
|
478
535
|
// src/eslint/index.ts
|
|
479
536
|
function lintedFilename(context) {
|
|
480
537
|
if (typeof context.physicalFilename === "string" && context.physicalFilename.length > 0) {
|
|
@@ -492,6 +549,15 @@ function lintedFilename(context) {
|
|
|
492
549
|
}
|
|
493
550
|
return "";
|
|
494
551
|
}
|
|
552
|
+
function reportAdapterDiagnostic(context, node, messageId, violation, data) {
|
|
553
|
+
const diagnostic = toAdapterDiagnostic({
|
|
554
|
+
...violation,
|
|
555
|
+
line: violation.line ?? node.loc?.start?.line,
|
|
556
|
+
column: violation.column ?? (typeof node.loc?.start?.column === "number" ? node.loc.start.column + 1 : void 0)
|
|
557
|
+
});
|
|
558
|
+
context.report({ node, messageId, ...data ? { data } : {}, diagnostic });
|
|
559
|
+
return diagnostic;
|
|
560
|
+
}
|
|
495
561
|
function findConfigPath(startFile) {
|
|
496
562
|
if (!startFile || startFile === "<input>" || startFile.startsWith("stdin")) return null;
|
|
497
563
|
let dir = path.dirname(path.resolve(startFile));
|
|
@@ -593,38 +659,14 @@ function objectHasMetadataSource(node) {
|
|
|
593
659
|
const metadata = objectProperty(node, "metadata")?.value;
|
|
594
660
|
return objectHasProperty(metadata, "source");
|
|
595
661
|
}
|
|
596
|
-
function looksLikeIntent(value) {
|
|
597
|
-
return /^(Domain|Application|Adapter|Workflow|Job|Presentation|Reporting|Metadata|Security|Audit|Observability|Kernel)\.[A-Za-z0-9_.]+$/.test(
|
|
598
|
-
value
|
|
599
|
-
);
|
|
600
|
-
}
|
|
601
662
|
function isPublishCall(node) {
|
|
602
663
|
return calleePropertyName(node) === "publish";
|
|
603
664
|
}
|
|
604
|
-
function isDomainFileHeuristic(filename) {
|
|
605
|
-
const normalized = filename.split("\\").join("/").toLowerCase();
|
|
606
|
-
return normalized.includes("/domain/") || normalized.endsWith("/domain.ts");
|
|
607
|
-
}
|
|
608
|
-
function isInfraImportHeuristic(specifier) {
|
|
609
|
-
const normalized = specifier.toLowerCase();
|
|
610
|
-
return [
|
|
611
|
-
"adapter",
|
|
612
|
-
"adapters",
|
|
613
|
-
"infrastructure",
|
|
614
|
-
"persistence",
|
|
615
|
-
"repository",
|
|
616
|
-
"repositories",
|
|
617
|
-
"integration",
|
|
618
|
-
"database",
|
|
619
|
-
"db"
|
|
620
|
-
].some((token) => normalized.includes(token));
|
|
621
|
-
}
|
|
622
|
-
var DEFAULT_FORBIDDEN_GLOBALS = ["fetch", "process", "Date.now", "Math.random"];
|
|
623
665
|
var noDomainInfraImports = {
|
|
624
666
|
meta: {
|
|
625
667
|
type: "problem",
|
|
626
668
|
docs: {
|
|
627
|
-
description: "Disallow imports that violate ark.config.json layer rules (same contract as arkgate-check).
|
|
669
|
+
description: "Disallow imports that violate ark.config.json layer rules (same contract as arkgate-check)."
|
|
628
670
|
},
|
|
629
671
|
messages: {
|
|
630
672
|
forbiddenImport: "Architecture: {{fromLayer}} must not import {{toLayer}} (ark.config.json). Specifier: {{specifier}}",
|
|
@@ -656,17 +698,24 @@ var noDomainInfraImports = {
|
|
|
656
698
|
toPath: relTarget,
|
|
657
699
|
layers: config.layers
|
|
658
700
|
})) {
|
|
659
|
-
|
|
701
|
+
reportAdapterDiagnostic(
|
|
702
|
+
context,
|
|
660
703
|
node,
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
704
|
+
"forbiddenImport",
|
|
705
|
+
{
|
|
706
|
+
ruleId: "LAYER_IMPORT_VIOLATION",
|
|
707
|
+
file: relFile,
|
|
708
|
+
fromLayer,
|
|
709
|
+
toLayer,
|
|
710
|
+
target: relTarget,
|
|
711
|
+
...node.importKind === "type" ? { typeOnly: true } : {},
|
|
712
|
+
message: `${fromLayer} must not import ${toLayer}.`
|
|
713
|
+
},
|
|
714
|
+
{ fromLayer, toLayer, specifier: source }
|
|
715
|
+
);
|
|
664
716
|
}
|
|
665
717
|
return;
|
|
666
718
|
}
|
|
667
|
-
if (isDomainFileHeuristic(filename) && isInfraImportHeuristic(source)) {
|
|
668
|
-
context.report({ node, messageId: "forbiddenImportHeuristic" });
|
|
669
|
-
}
|
|
670
719
|
};
|
|
671
720
|
return {
|
|
672
721
|
ImportDeclaration: check,
|
|
@@ -689,11 +738,21 @@ var noRawEventPublish = {
|
|
|
689
738
|
create(context) {
|
|
690
739
|
return {
|
|
691
740
|
CallExpression(node) {
|
|
692
|
-
if (!isPublishCall(node)) return;
|
|
693
741
|
const firstArg = node.arguments?.[0];
|
|
694
742
|
const firstValue = stringValue(firstArg);
|
|
695
|
-
|
|
696
|
-
|
|
743
|
+
const findings = classifyPublishFacts({
|
|
744
|
+
publishCall: isPublishCall(node),
|
|
745
|
+
rawIntentName: firstValue,
|
|
746
|
+
objectHasIntent: objectHasProperty(firstArg, "intent"),
|
|
747
|
+
arkPublishCandidate: false,
|
|
748
|
+
hasSource: true
|
|
749
|
+
});
|
|
750
|
+
if (findings.some((finding) => finding.ruleId === "RAW_EVENT_PUBLISH")) {
|
|
751
|
+
const finding = findings.find((item) => item.ruleId === "RAW_EVENT_PUBLISH");
|
|
752
|
+
reportAdapterDiagnostic(context, node, "rawPublish", {
|
|
753
|
+
...finding,
|
|
754
|
+
file: lintedFilename(context)
|
|
755
|
+
});
|
|
697
756
|
}
|
|
698
757
|
}
|
|
699
758
|
};
|
|
@@ -713,13 +772,22 @@ var requirePublishSource = {
|
|
|
713
772
|
create(context) {
|
|
714
773
|
return {
|
|
715
774
|
CallExpression(node) {
|
|
716
|
-
if (!isPublishCall(node)) return;
|
|
717
775
|
const firstArg = node.arguments?.[0];
|
|
718
776
|
const metadataArg = node.arguments?.[2];
|
|
719
|
-
|
|
720
|
-
|
|
777
|
+
const findings = classifyPublishFacts({
|
|
778
|
+
publishCall: isPublishCall(node),
|
|
779
|
+
rawIntentName: stringValue(firstArg),
|
|
780
|
+
objectHasIntent: objectHasProperty(firstArg, "intent"),
|
|
781
|
+
arkPublishCandidate: true,
|
|
782
|
+
hasSource: objectHasMetadataSource(firstArg) || objectHasProperty(metadataArg, "source")
|
|
783
|
+
});
|
|
784
|
+
const finding = findings.find((item) => item.ruleId === "PUBLISH_MISSING_SOURCE");
|
|
785
|
+
if (finding) {
|
|
786
|
+
reportAdapterDiagnostic(context, node, "missingSource", {
|
|
787
|
+
...finding,
|
|
788
|
+
file: lintedFilename(context)
|
|
789
|
+
});
|
|
721
790
|
}
|
|
722
|
-
context.report({ node, messageId: "missingSource" });
|
|
723
791
|
}
|
|
724
792
|
};
|
|
725
793
|
}
|
|
@@ -728,7 +796,7 @@ var noForbiddenGlobals = {
|
|
|
728
796
|
meta: {
|
|
729
797
|
type: "problem",
|
|
730
798
|
docs: {
|
|
731
|
-
description: "Disallow ambient globals from the layer\u2019s forbiddenGlobals in ark.config.json (same purity surface as
|
|
799
|
+
description: "Disallow ambient globals from the layer\u2019s forbiddenGlobals in ark.config.json (same purity surface as ark-check). Option `globals` explicitly overrides."
|
|
732
800
|
},
|
|
733
801
|
messages: {
|
|
734
802
|
forbiddenGlobal: 'Ambient global "{{name}}" is forbidden in {{layer}} (ark.config.json); inject the capability through a port instead.',
|
|
@@ -766,18 +834,28 @@ var noForbiddenGlobals = {
|
|
|
766
834
|
} else {
|
|
767
835
|
globals = null;
|
|
768
836
|
}
|
|
769
|
-
} else if (isDomainFileHeuristic(filename)) {
|
|
770
|
-
globals = new Set(DEFAULT_FORBIDDEN_GLOBALS);
|
|
771
837
|
}
|
|
772
838
|
if (!globals) {
|
|
773
839
|
return {};
|
|
774
840
|
}
|
|
775
841
|
const scopeAware = typeof sourceCodeFor(context)?.getScope === "function";
|
|
776
|
-
const report = (node, name) =>
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
842
|
+
const report = (node, name) => {
|
|
843
|
+
const absFile = path.isAbsolute(filename) ? filename : path.resolve(filename);
|
|
844
|
+
const reportFile = root ? path.relative(root, absFile).split(path.sep).join("/") : filename;
|
|
845
|
+
reportAdapterDiagnostic(
|
|
846
|
+
context,
|
|
847
|
+
node,
|
|
848
|
+
config ? "forbiddenGlobal" : "forbiddenGlobalDefault",
|
|
849
|
+
{
|
|
850
|
+
ruleId: "FORBIDDEN_GLOBAL",
|
|
851
|
+
file: reportFile,
|
|
852
|
+
fromLayer: layerName,
|
|
853
|
+
target: name,
|
|
854
|
+
message: `${layerName} must not use the ambient global "${name}".`
|
|
855
|
+
},
|
|
856
|
+
{ name, layer: layerName }
|
|
857
|
+
);
|
|
858
|
+
};
|
|
781
859
|
return {
|
|
782
860
|
MemberExpression(node) {
|
|
783
861
|
if (node.parent?.type === "MemberExpression" && node.parent.object === node) return;
|
|
@@ -851,4 +929,3 @@ export {
|
|
|
851
929
|
requirePublishSource,
|
|
852
930
|
resolveRelativeImport
|
|
853
931
|
};
|
|
854
|
-
//# sourceMappingURL=index.js.map
|