arkgate 2.12.0 → 2.13.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 (70) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/README.md +55 -31
  3. package/bin/ark-check.mjs +95 -36
  4. package/bin/ark-mcp.mjs +11 -5
  5. package/bin/ark-shared.mjs +88 -56
  6. package/bin/ark.mjs +45 -10
  7. package/bin/lib/agent-gates.mjs +12 -0
  8. package/bin/lib/architecture-scan.mjs +8 -0
  9. package/bin/lib/ci-and-commands.mjs +9 -3
  10. package/bin/lib/codex-home.mjs +7 -0
  11. package/bin/lib/config-contract.mjs +331 -0
  12. package/bin/lib/doctor-plan.mjs +43 -16
  13. package/bin/lib/enforcement-profiles.mjs +97 -0
  14. package/bin/lib/host-support-matrix.mjs +77 -0
  15. package/bin/lib/install-migrate.mjs +45 -14
  16. package/bin/lib/mcp-adoption.mjs +35 -3
  17. package/bin/lib/open-html.mjs +75 -0
  18. package/bin/lib/presets.mjs +3 -2
  19. package/bin/lib/safety-diagnostics.mjs +31 -11
  20. package/bin/lib/skill-install.mjs +64 -0
  21. package/bin/lib/ts-resolve.mjs +2 -1
  22. package/bin/lib/weakest-link.mjs +417 -0
  23. package/bin/lib/write-path-capabilities.mjs +182 -0
  24. package/bin/lib/write-path-detect.mjs +62 -99
  25. package/dist/configContract-iBLxx5Tz.d.cts +53 -0
  26. package/dist/configContract-iBLxx5Tz.d.ts +53 -0
  27. package/dist/eslint/index.cjs +375 -13
  28. package/dist/eslint/index.cjs.map +1 -1
  29. package/dist/eslint/index.d.cts +30 -20
  30. package/dist/eslint/index.d.ts +30 -20
  31. package/dist/eslint/index.js +375 -13
  32. package/dist/eslint/index.js.map +1 -1
  33. package/dist/index.cjs +723 -61
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.cts +95 -5
  36. package/dist/index.d.ts +95 -5
  37. package/dist/index.js +716 -61
  38. package/dist/index.js.map +1 -1
  39. package/dist/nestjs/index.cjs +150 -42
  40. package/dist/nestjs/index.cjs.map +1 -1
  41. package/dist/nestjs/index.d.cts +2 -1
  42. package/dist/nestjs/index.d.ts +2 -1
  43. package/dist/nestjs/index.js +150 -42
  44. package/dist/nestjs/index.js.map +1 -1
  45. package/dist/runtime/index.cjs +723 -61
  46. package/dist/runtime/index.cjs.map +1 -1
  47. package/dist/runtime/index.d.cts +3 -2
  48. package/dist/runtime/index.d.ts +3 -2
  49. package/dist/runtime/index.js +716 -61
  50. package/dist/runtime/index.js.map +1 -1
  51. package/dist/{types-BZ17b9i5.d.cts → types-BxBwnBpC.d.cts} +9 -36
  52. package/dist/{types-BZ17b9i5.d.ts → types-Wcs_l1_J.d.ts} +9 -36
  53. package/docs/agent-guide.md +32 -20
  54. package/docs/ai-gates.md +53 -18
  55. package/docs/configuration.md +97 -0
  56. package/docs/enthusiast/README.md +3 -3
  57. package/docs/enthusiast/how-to-agent-gates.md +7 -3
  58. package/docs/migrate-from-ark-runtime-kernel.md +3 -0
  59. package/docs/package-surface.md +14 -9
  60. package/docs/production-hardening.md +15 -2
  61. package/docs/threat-model.md +65 -0
  62. package/docs/typescript-support.md +3 -3
  63. package/package.json +15 -2
  64. package/schemas/ark.config.schema.json +750 -0
  65. package/server.json +2 -2
  66. package/templates/hooks/pre-commit-ark +37 -0
  67. package/templates/skills/ark-coverage.md +2 -2
  68. package/templates/skills/ark-runtime.md +8 -5
  69. package/templates/skills/ark-upgrade.md +36 -16
  70. package/tests/fixtures/ts-consumer/ark.config.json +2 -0
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/runtime/index.ts
21
21
  var runtime_exports = {};
22
22
  __export(runtime_exports, {
23
+ ANALYSIS_IR_SCHEMA_VERSION: () => ANALYSIS_IR_SCHEMA_VERSION,
23
24
  DEFAULT_MAX_HISTORY_SIZE: () => DEFAULT_MAX_HISTORY_SIZE,
24
25
  EventContractRegistryImpl: () => EventContractRegistryImpl,
25
26
  EventContractViolationError: () => EventContractViolationError,
@@ -37,6 +38,8 @@ __export(runtime_exports, {
37
38
  SourceMetadataOverrideError: () => SourceMetadataOverrideError,
38
39
  UnknownEventSourceError: () => UnknownEventSourceError,
39
40
  UnregisteredIntentError: () => UnregisteredIntentError,
41
+ analyzeChange: () => analyzeChange,
42
+ analyzeProject: () => analyzeProject,
40
43
  architecturalPolicies: () => architecturalPolicies,
41
44
  buildPublishPolicyContext: () => buildPublishPolicyContext,
42
45
  checkAdapterGovernance: () => checkAdapterGovernance,
@@ -71,8 +74,12 @@ __export(runtime_exports, {
71
74
  definePolicy: () => definePolicy,
72
75
  definePort: () => definePort,
73
76
  definePublishPolicy: () => definePublishPolicy,
77
+ deterministicHash: () => deterministicHash,
74
78
  elevenLayerProfile: () => elevenLayerProfile,
79
+ explainViolation: () => explainViolation,
75
80
  isLayerPolicy: () => isLayerPolicy,
81
+ loadContract: () => loadContract,
82
+ stableSerialize: () => stableSerialize,
76
83
  syncRegistryToGraph: () => syncRegistryToGraph,
77
84
  validateIntentName: () => validateIntentName,
78
85
  version: () => version
@@ -80,7 +87,7 @@ __export(runtime_exports, {
80
87
  module.exports = __toCommonJS(runtime_exports);
81
88
 
82
89
  // src/version.ts
83
- var version = "2.12.0";
90
+ var version = "2.13.0";
84
91
 
85
92
  // src/kernel/intent/IntentRegistry.ts
86
93
  var IntentRegistry = class {
@@ -744,6 +751,10 @@ async function recordInterceptorError(interceptor, event, error, deps) {
744
751
  }
745
752
 
746
753
  // src/domain/layerMatch.ts
754
+ var regexpCache = /* @__PURE__ */ new Map();
755
+ function escapeLiteral(ch) {
756
+ return /[.*+?^${}()|[\]\\]/.test(ch) ? `\\${ch}` : ch;
757
+ }
747
758
  function normalizeGlobSeparators(pattern) {
748
759
  let out = "";
749
760
  for (let i = 0; i < pattern.length; i += 1) {
@@ -762,6 +773,91 @@ function normalizeGlobSeparators(pattern) {
762
773
  }
763
774
  return out;
764
775
  }
776
+ function bracesBalanced(glob) {
777
+ let depth = 0;
778
+ for (let i = 0; i < glob.length; i += 1) {
779
+ const c = glob[i];
780
+ if (c === "\\") {
781
+ i += 1;
782
+ continue;
783
+ }
784
+ if (c === "{") depth += 1;
785
+ else if (c === "}") {
786
+ depth -= 1;
787
+ if (depth < 0) return false;
788
+ }
789
+ }
790
+ return depth === 0;
791
+ }
792
+ function globToRegExp(pattern) {
793
+ const cached = regexpCache.get(pattern);
794
+ if (cached) return cached;
795
+ const glob = normalizeGlobSeparators(pattern);
796
+ const useBraces = bracesBalanced(glob);
797
+ let out = "";
798
+ let braceDepth = 0;
799
+ for (let i = 0; i < glob.length; i += 1) {
800
+ const c = glob[i];
801
+ if (c === "\\" && i + 1 < glob.length) {
802
+ out += escapeLiteral(glob[i + 1]);
803
+ i += 1;
804
+ } else if (c === "*") {
805
+ if (glob[i + 1] === "*") {
806
+ if (glob[i + 2] === "/") {
807
+ out += "(?:.*/)?";
808
+ i += 2;
809
+ } else {
810
+ out += ".*";
811
+ i += 1;
812
+ }
813
+ } else {
814
+ out += "[^/]*";
815
+ }
816
+ } else if (c === "?") {
817
+ out += "[^/]";
818
+ } else if (c === "{" && useBraces) {
819
+ out += "(?:";
820
+ braceDepth += 1;
821
+ } else if (c === "}" && useBraces && braceDepth > 0) {
822
+ out += ")";
823
+ braceDepth -= 1;
824
+ } else if (c === "," && useBraces && braceDepth > 0) {
825
+ out += "|";
826
+ } else {
827
+ out += escapeLiteral(c);
828
+ }
829
+ }
830
+ const re = new RegExp(`^${out}$`);
831
+ regexpCache.set(pattern, re);
832
+ return re;
833
+ }
834
+ function patternSpecificity(pattern) {
835
+ const glob = normalizeGlobSeparators(String(pattern));
836
+ const beforeWildcard = glob.split("*")[0];
837
+ const literalSegments = beforeWildcard.split("/").filter(Boolean).length;
838
+ const literalLength = glob.replace(/\*/g, "").length;
839
+ return literalSegments * 1e4 + literalLength;
840
+ }
841
+ function layerForRelativePath(relPath, layers) {
842
+ const rel = String(relPath).split(/[/\\]/).join("/");
843
+ let bestName;
844
+ let bestScore = -1;
845
+ for (const layer of layers ?? []) {
846
+ if ((layer.exclude ?? []).some((pattern) => globToRegExp(pattern).test(rel))) {
847
+ continue;
848
+ }
849
+ for (const pattern of layer.patterns ?? []) {
850
+ if (globToRegExp(pattern).test(rel)) {
851
+ const score = patternSpecificity(pattern);
852
+ if (score > bestScore) {
853
+ bestScore = score;
854
+ bestName = layer.name;
855
+ }
856
+ }
857
+ }
858
+ }
859
+ return bestName;
860
+ }
765
861
  function sliceIdForPath(relPath, sliceFolders) {
766
862
  if (!sliceFolders?.length) return void 0;
767
863
  const parts = String(relPath).split(/[/\\]/).filter(Boolean);
@@ -1356,13 +1452,13 @@ function formatPath(parent, field) {
1356
1452
  return parent ? `${parent}.${field}` : field;
1357
1453
  }
1358
1454
  function validateSchemaField(value, fieldSchema, path, contract, issues) {
1359
- const valueType = actualType(value);
1360
- if (fieldSchema.type !== "unknown" && valueType !== fieldSchema.type) {
1455
+ const valueType2 = actualType(value);
1456
+ if (fieldSchema.type !== "unknown" && valueType2 !== fieldSchema.type) {
1361
1457
  issues.push({
1362
1458
  intent: contract.intent,
1363
1459
  version: contract.version,
1364
1460
  field: path,
1365
- message: `Expected ${fieldSchema.type}, received ${valueType}.`
1461
+ message: `Expected ${fieldSchema.type}, received ${valueType2}.`
1366
1462
  });
1367
1463
  return;
1368
1464
  }
@@ -1919,6 +2015,321 @@ function syncRegistryToGraph(registry, graph, options = {}) {
1919
2015
  }
1920
2016
  }
1921
2017
 
2018
+ // src/domain/configContract.ts
2019
+ var ARK_CONFIG_SCHEMA_VERSION = "1.0";
2020
+ var ARK_CONFIG_SCHEMA_URL = "https://unpkg.com/arkgate@2/schemas/ark.config.schema.json";
2021
+ var DEFAULT_LAYER_NAMES = [
2022
+ "DomainModel",
2023
+ "ApplicationOrchestration",
2024
+ "PersistenceAdapters",
2025
+ "IntegrationAdapters",
2026
+ "WorkflowSagaEngine",
2027
+ "BackgroundJobsScheduling",
2028
+ "PresentationAdapters",
2029
+ "ReportingReadModels",
2030
+ "ExtensibilityMetadata",
2031
+ "SecurityAuditObservability",
2032
+ "Kernel"
2033
+ ];
2034
+ var DEFAULT_ALLOWED_FLOWS = /* @__PURE__ */ new Set([
2035
+ "PresentationAdapters->ApplicationOrchestration",
2036
+ "ApplicationOrchestration->DomainModel",
2037
+ "WorkflowSagaEngine->ApplicationOrchestration",
2038
+ "WorkflowSagaEngine->DomainModel",
2039
+ "BackgroundJobsScheduling->ApplicationOrchestration"
2040
+ ]);
2041
+ function createDefaultRules() {
2042
+ const rules = [];
2043
+ for (const from of DEFAULT_LAYER_NAMES) {
2044
+ for (const to of DEFAULT_LAYER_NAMES) {
2045
+ if (from === to || DEFAULT_ALLOWED_FLOWS.has(`${from}->${to}`)) continue;
2046
+ rules.push({ from, to, allowed: false });
2047
+ }
2048
+ }
2049
+ return rules;
2050
+ }
2051
+ var DEFAULT_ARK_CONFIG_RULES = createDefaultRules();
2052
+ var stringArraySchema = {
2053
+ type: "array",
2054
+ items: { type: "string", minLength: 1 },
2055
+ uniqueItems: true
2056
+ };
2057
+ var ARK_CONFIG_SCHEMA = {
2058
+ $schema: "https://json-schema.org/draft/2020-12/schema",
2059
+ $id: ARK_CONFIG_SCHEMA_URL,
2060
+ title: "ArkGate architecture contract",
2061
+ description: "Versioned contract consumed identically by ArkGate CLI, MCP, and ESLint surfaces.",
2062
+ type: "object",
2063
+ additionalProperties: false,
2064
+ required: ["$schema", "schemaVersion", "include", "layers", "rules"],
2065
+ properties: {
2066
+ $schema: {
2067
+ type: "string",
2068
+ minLength: 1,
2069
+ default: ARK_CONFIG_SCHEMA_URL,
2070
+ description: "Editor-facing URL or local path for this JSON Schema."
2071
+ },
2072
+ schemaVersion: {
2073
+ type: "string",
2074
+ const: ARK_CONFIG_SCHEMA_VERSION,
2075
+ default: ARK_CONFIG_SCHEMA_VERSION
2076
+ },
2077
+ name: { type: "string", minLength: 1 },
2078
+ include: { ...stringArraySchema, minItems: 1, default: ["src"] },
2079
+ exclude: { ...stringArraySchema, default: [] },
2080
+ excludeGenerated: { type: "boolean", default: true },
2081
+ frameworkOverlay: { type: "string", minLength: 1 },
2082
+ layers: {
2083
+ type: "array",
2084
+ default: [],
2085
+ items: { $ref: "#/$defs/layer" }
2086
+ },
2087
+ rules: {
2088
+ type: "array",
2089
+ default: DEFAULT_ARK_CONFIG_RULES,
2090
+ items: { $ref: "#/$defs/rule" }
2091
+ },
2092
+ cyclePolicy: {
2093
+ type: "string",
2094
+ enum: ["strict", "soft", "framework-soft", "off"],
2095
+ default: "strict"
2096
+ },
2097
+ dynamicImportAllowlist: { ...stringArraySchema, default: [] },
2098
+ safety: {
2099
+ $ref: "#/$defs/safety",
2100
+ default: {
2101
+ maxTsSuppressions: 0,
2102
+ maxAnyCasts: 0,
2103
+ allowInMemory: false,
2104
+ allowDisabledPeerIsolation: false
2105
+ }
2106
+ }
2107
+ },
2108
+ $defs: {
2109
+ layer: {
2110
+ type: "object",
2111
+ additionalProperties: false,
2112
+ required: ["name", "patterns"],
2113
+ properties: {
2114
+ name: { type: "string", minLength: 1 },
2115
+ patterns: { ...stringArraySchema, minItems: 1 },
2116
+ exclude: stringArraySchema,
2117
+ intentPrefixes: stringArraySchema,
2118
+ description: { type: "string", minLength: 1 },
2119
+ forbiddenGlobals: stringArraySchema,
2120
+ mayImportInfrastructure: { type: "boolean" },
2121
+ optional: { type: "boolean" }
2122
+ }
2123
+ },
2124
+ rule: {
2125
+ type: "object",
2126
+ additionalProperties: false,
2127
+ required: ["from", "to", "allowed"],
2128
+ properties: {
2129
+ from: { type: "string", minLength: 1 },
2130
+ to: { type: "string", minLength: 1 },
2131
+ allowed: { type: "boolean" },
2132
+ message: { type: "string", minLength: 1 },
2133
+ peerIsolation: { type: "boolean" },
2134
+ sliceFolders: { ...stringArraySchema, minItems: 1 }
2135
+ }
2136
+ },
2137
+ safety: {
2138
+ type: "object",
2139
+ additionalProperties: false,
2140
+ properties: {
2141
+ maxTsSuppressions: { type: "integer", minimum: 0, default: 0 },
2142
+ maxAnyCasts: { type: "integer", minimum: 0, default: 0 },
2143
+ allowInMemory: { type: "boolean", default: false },
2144
+ allowDisabledPeerIsolation: { type: "boolean", default: false }
2145
+ }
2146
+ }
2147
+ }
2148
+ };
2149
+ var ArkConfigValidationError = class extends Error {
2150
+ issues;
2151
+ source;
2152
+ constructor(source, issues) {
2153
+ super(
2154
+ `Invalid ArkGate config (${source}):
2155
+ ${issues.map((issue) => `- ${issue.path}: ${issue.message}`).join("\n")}`
2156
+ );
2157
+ this.name = "ArkConfigValidationError";
2158
+ this.source = source;
2159
+ this.issues = issues;
2160
+ }
2161
+ };
2162
+ function isObject(value) {
2163
+ return value !== null && typeof value === "object" && !Array.isArray(value);
2164
+ }
2165
+ function propertyPath(parent, key) {
2166
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? `${parent}.${key}` : `${parent}[${JSON.stringify(key)}]`;
2167
+ }
2168
+ function valueType(value) {
2169
+ if (value === null) return "null";
2170
+ if (Array.isArray(value)) return "array";
2171
+ return typeof value;
2172
+ }
2173
+ function resolveSchemaRef(ref, root) {
2174
+ const prefix = "#/$defs/";
2175
+ if (!ref.startsWith(prefix)) return void 0;
2176
+ return root.$defs[ref.slice(prefix.length)];
2177
+ }
2178
+ function validateNode(value, schema, path, root, issues) {
2179
+ if (schema.$ref) {
2180
+ const referenced = resolveSchemaRef(schema.$ref, root);
2181
+ if (!referenced) {
2182
+ issues.push({ path, message: `schema reference ${schema.$ref} cannot be resolved` });
2183
+ return;
2184
+ }
2185
+ validateNode(value, referenced, path, root, issues);
2186
+ return;
2187
+ }
2188
+ if (schema.const !== void 0 && !Object.is(value, schema.const)) {
2189
+ issues.push({ path, message: `must equal ${JSON.stringify(schema.const)}` });
2190
+ return;
2191
+ }
2192
+ if (schema.enum && !schema.enum.some((candidate) => Object.is(candidate, value))) {
2193
+ issues.push({ path, message: `must be one of ${schema.enum.map(String).join(", ")}` });
2194
+ return;
2195
+ }
2196
+ if (schema.type === "object") {
2197
+ if (!isObject(value)) {
2198
+ issues.push({ path, message: `must be an object; received ${valueType(value)}` });
2199
+ return;
2200
+ }
2201
+ const properties = schema.properties ?? {};
2202
+ for (const key of schema.required ?? []) {
2203
+ if (value[key] === void 0) {
2204
+ issues.push({ path: propertyPath(path, key), message: "is required" });
2205
+ }
2206
+ }
2207
+ if (schema.additionalProperties === false) {
2208
+ for (const key of Object.keys(value)) {
2209
+ if (!(key in properties)) {
2210
+ issues.push({ path: propertyPath(path, key), message: "unknown field" });
2211
+ }
2212
+ }
2213
+ }
2214
+ for (const [key, childSchema] of Object.entries(properties)) {
2215
+ if (value[key] !== void 0) {
2216
+ validateNode(value[key], childSchema, propertyPath(path, key), root, issues);
2217
+ }
2218
+ }
2219
+ return;
2220
+ }
2221
+ if (schema.type === "array") {
2222
+ if (!Array.isArray(value)) {
2223
+ issues.push({ path, message: `must be an array; received ${valueType(value)}` });
2224
+ return;
2225
+ }
2226
+ if (schema.minItems !== void 0 && value.length < schema.minItems) {
2227
+ issues.push({ path, message: `must contain at least ${schema.minItems} item(s)` });
2228
+ }
2229
+ if (schema.uniqueItems) {
2230
+ const serialized = value.map((entry) => JSON.stringify(entry));
2231
+ if (new Set(serialized).size !== serialized.length) {
2232
+ issues.push({ path, message: "must not contain duplicate items" });
2233
+ }
2234
+ }
2235
+ if (schema.items) {
2236
+ value.forEach(
2237
+ (entry, index) => validateNode(entry, schema.items, `${path}[${index}]`, root, issues)
2238
+ );
2239
+ }
2240
+ return;
2241
+ }
2242
+ if (schema.type === "string") {
2243
+ if (typeof value !== "string") {
2244
+ issues.push({ path, message: `must be a string; received ${valueType(value)}` });
2245
+ return;
2246
+ }
2247
+ if (schema.minLength !== void 0 && value.length < schema.minLength) {
2248
+ issues.push({ path, message: `must contain at least ${schema.minLength} character(s)` });
2249
+ }
2250
+ return;
2251
+ }
2252
+ if (schema.type === "boolean") {
2253
+ if (typeof value !== "boolean") {
2254
+ issues.push({ path, message: `must be a boolean; received ${valueType(value)}` });
2255
+ }
2256
+ return;
2257
+ }
2258
+ if (schema.type === "integer") {
2259
+ if (!Number.isInteger(value)) {
2260
+ issues.push({ path, message: `must be an integer; received ${valueType(value)}` });
2261
+ return;
2262
+ }
2263
+ if (schema.minimum !== void 0 && value < schema.minimum) {
2264
+ issues.push({ path, message: `must be at least ${schema.minimum}` });
2265
+ }
2266
+ }
2267
+ }
2268
+ function defaultedConfig(input) {
2269
+ return {
2270
+ ...input,
2271
+ $schema: input.$schema === void 0 ? ARK_CONFIG_SCHEMA_URL : input.$schema,
2272
+ schemaVersion: input.schemaVersion === void 0 ? ARK_CONFIG_SCHEMA_VERSION : input.schemaVersion,
2273
+ include: input.include === void 0 ? ["src"] : input.include,
2274
+ layers: input.layers === void 0 ? [] : input.layers,
2275
+ rules: input.rules === void 0 ? DEFAULT_ARK_CONFIG_RULES.map((rule) => ({ ...rule })) : input.rules
2276
+ };
2277
+ }
2278
+ function migrateArkConfig(input, source = "ark.config.json") {
2279
+ if (!isObject(input)) {
2280
+ throw new ArkConfigValidationError(source, [
2281
+ { path: "$", message: `must be an object; received ${valueType(input)}` }
2282
+ ]);
2283
+ }
2284
+ const migratedFrom = input.schemaVersion === void 0 ? "unversioned" : null;
2285
+ if (input.schemaVersion !== void 0 && input.schemaVersion !== ARK_CONFIG_SCHEMA_VERSION) {
2286
+ throw new ArkConfigValidationError(source, [
2287
+ {
2288
+ path: "$.schemaVersion",
2289
+ message: `unsupported version ${JSON.stringify(input.schemaVersion)}; expected ${ARK_CONFIG_SCHEMA_VERSION}`
2290
+ }
2291
+ ]);
2292
+ }
2293
+ return { candidate: defaultedConfig(input), migratedFrom };
2294
+ }
2295
+ function loadArkConfigContract(input, source = "ark.config.json") {
2296
+ const { candidate, migratedFrom } = migrateArkConfig(input, source);
2297
+ const issues = [];
2298
+ validateNode(
2299
+ candidate,
2300
+ ARK_CONFIG_SCHEMA,
2301
+ "$",
2302
+ ARK_CONFIG_SCHEMA,
2303
+ issues
2304
+ );
2305
+ if (issues.length > 0) throw new ArkConfigValidationError(source, issues);
2306
+ return { config: candidate, migratedFrom };
2307
+ }
2308
+ function parseArkConfigJson(json, source = "ark.config.json") {
2309
+ let input;
2310
+ try {
2311
+ input = JSON.parse(json);
2312
+ } catch (error) {
2313
+ throw new ArkConfigValidationError(source, [
2314
+ {
2315
+ path: "$",
2316
+ message: `invalid JSON: ${error instanceof Error ? error.message : String(error)}`
2317
+ }
2318
+ ]);
2319
+ }
2320
+ return loadArkConfigContract(input, source);
2321
+ }
2322
+ function withArkConfigMetadata(config) {
2323
+ const result = {
2324
+ $schema: typeof config.$schema === "string" && config.$schema.length > 0 ? config.$schema : ARK_CONFIG_SCHEMA_URL,
2325
+ schemaVersion: ARK_CONFIG_SCHEMA_VERSION
2326
+ };
2327
+ for (const [key, value] of Object.entries(config)) {
2328
+ if (key !== "$schema" && key !== "schemaVersion") result[key] = value;
2329
+ }
2330
+ return result;
2331
+ }
2332
+
1922
2333
  // src/kernel/layers/ArchitectureProfile.ts
1923
2334
  function normalizePrefix(prefix) {
1924
2335
  return prefix.endsWith(".") ? prefix : `${prefix}.`;
@@ -1928,21 +2339,6 @@ function byLongestPrefix(a, b) {
1928
2339
  const maxB = b.prefixes.length ? Math.max(...b.prefixes.map((p) => p.length)) : 0;
1929
2340
  return maxB - maxA;
1930
2341
  }
1931
- function flowKey2(from, to) {
1932
- return `${from}->${to}`;
1933
- }
1934
- function createStrictDenyRules(layers, allowedFlows) {
1935
- const allowed = new Set(allowedFlows.map((flow) => flowKey2(flow.from, flow.to)));
1936
- const rules = [];
1937
- for (const from of layers) {
1938
- for (const to of layers) {
1939
- if (from.name === to.name) continue;
1940
- if (allowed.has(flowKey2(from.name, to.name))) continue;
1941
- rules.push({ from: from.name, to: to.name, allowed: false });
1942
- }
1943
- }
1944
- return rules;
1945
- }
1946
2342
  function createArchitectureProfile(options) {
1947
2343
  const layers = options.layers.map((layer) => ({
1948
2344
  ...layer,
@@ -2041,20 +2437,10 @@ var elevenLayerProfileLayers = [
2041
2437
  order: 11
2042
2438
  }
2043
2439
  ];
2044
- var elevenLayerAllowedFlows = [
2045
- { from: "PresentationAdapters", to: "ApplicationOrchestration" },
2046
- { from: "ApplicationOrchestration", to: "DomainModel" },
2047
- { from: "WorkflowSagaEngine", to: "ApplicationOrchestration" },
2048
- { from: "WorkflowSagaEngine", to: "DomainModel" },
2049
- { from: "BackgroundJobsScheduling", to: "ApplicationOrchestration" }
2050
- ];
2051
2440
  var elevenLayerProfile = createArchitectureProfile({
2052
2441
  name: "Ark 11-layer Hexagonal Event-Driven Profile",
2053
2442
  layers: elevenLayerProfileLayers,
2054
- rules: createStrictDenyRules(
2055
- elevenLayerProfileLayers,
2056
- elevenLayerAllowedFlows
2057
- )
2443
+ rules: DEFAULT_ARK_CONFIG_RULES.map((rule) => ({ ...rule }))
2058
2444
  });
2059
2445
  var defaultElevenLayerDirectories = {
2060
2446
  DomainModel: ["domain"],
@@ -2078,7 +2464,7 @@ function createElevenLayerArkConfig(options = {}) {
2078
2464
  const rootDir = options.rootDir ?? "src";
2079
2465
  const optional = options.optionalLayers ?? true;
2080
2466
  const prefix = rootDir === "." ? "" : `${rootDir}/`;
2081
- return {
2467
+ return withArkConfigMetadata({
2082
2468
  include: options.include ?? [rootDir],
2083
2469
  layers: elevenLayerProfile.layers.map((layer) => ({
2084
2470
  name: layer.name,
@@ -2089,7 +2475,7 @@ function createElevenLayerArkConfig(options = {}) {
2089
2475
  optional
2090
2476
  })),
2091
2477
  rules: [...elevenLayerProfile.rules]
2092
- };
2478
+ });
2093
2479
  }
2094
2480
 
2095
2481
  // src/kernel/metadata/MetadataRegistry.ts
@@ -2293,7 +2679,11 @@ function extractModuleSpecifiersAst(ts, source) {
2293
2679
  "export",
2294
2680
  Boolean(node.isTypeOnly || specifiersOnly)
2295
2681
  );
2296
- } else if (ts.isCallExpression(node) && node.arguments.length === 1) {
2682
+ } else if (ts.isImportEqualsDeclaration(node) && ts.isExternalModuleReference(node.moduleReference)) {
2683
+ const argument = node.moduleReference.expression;
2684
+ const value = tsStringLiteralText(ts, argument);
2685
+ if (value !== void 0) push(argument, value, "require");
2686
+ } else if (ts.isCallExpression(node)) {
2297
2687
  const argument = node.arguments[0];
2298
2688
  const value = tsStringLiteralText(ts, argument);
2299
2689
  if (value !== void 0 && node.expression.kind === ts.SyntaxKind.ImportKeyword) {
@@ -2307,17 +2697,25 @@ function extractModuleSpecifiersAst(ts, source) {
2307
2697
  visit(sourceFile);
2308
2698
  return matches.sort((a, b) => a.index - b.index);
2309
2699
  }
2310
- function nonLiteralDynamicImportLines(ts, source) {
2700
+ function nonLiteralDynamicDependencies(ts, source) {
2311
2701
  const sourceFile = ts.createSourceFile("generated.ts", source, ts.ScriptTarget.Latest, true);
2312
- const lines = [];
2702
+ const uses = [];
2313
2703
  const visit = (node) => {
2314
- if (ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword && (!node.arguments[0] || !ts.isStringLiteralLike(node.arguments[0]))) {
2315
- lines.push(sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1);
2704
+ if (ts.isCallExpression(node)) {
2705
+ const dynamicImport = node.expression.kind === ts.SyntaxKind.ImportKeyword;
2706
+ const directRequire = ts.isIdentifier(node.expression) && node.expression.text === "require";
2707
+ const argument = node.arguments[0];
2708
+ if ((dynamicImport || directRequire) && (!argument || !ts.isStringLiteralLike(argument))) {
2709
+ uses.push({
2710
+ line: sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1,
2711
+ kind: directRequire ? "require" : "import"
2712
+ });
2713
+ }
2316
2714
  }
2317
2715
  ts.forEachChild(node, visit);
2318
2716
  };
2319
2717
  visit(sourceFile);
2320
- return lines;
2718
+ return uses;
2321
2719
  }
2322
2720
  function extractQuotedStringsAst(ts, source) {
2323
2721
  const sourceFile = ts.createSourceFile("generated.ts", source, ts.ScriptTarget.Latest, true);
@@ -2428,10 +2826,45 @@ function tsPublishSourceLiteral(ts, node) {
2428
2826
  const rawMetadata = tsObjectPropertyValue(ts, firstArg, "metadata");
2429
2827
  return tsStringLiteralText(ts, tsObjectPropertyValue(ts, rawMetadata, "source")) ?? tsStringLiteralText(ts, tsObjectPropertyValue(ts, secondArg, "source")) ?? tsStringLiteralText(ts, tsObjectPropertyValue(ts, thirdArg, "source"));
2430
2828
  }
2829
+ function singleFileTypeChecker(ts, sourceFile) {
2830
+ const options = {
2831
+ noLib: true,
2832
+ noResolve: true,
2833
+ target: ts.ScriptTarget.Latest
2834
+ };
2835
+ const host = ts.createCompilerHost(options, true);
2836
+ host.getSourceFile = (fileName) => fileName === sourceFile.fileName ? sourceFile : void 0;
2837
+ host.fileExists = (fileName) => fileName === sourceFile.fileName;
2838
+ host.readFile = (fileName) => fileName === sourceFile.fileName ? sourceFile.text : void 0;
2839
+ return ts.createProgram([sourceFile.fileName], options, host).getTypeChecker();
2840
+ }
2841
+ function propertyAccessPath(ts, node) {
2842
+ const segments = [];
2843
+ let current = node;
2844
+ while (ts.isPropertyAccessExpression(current)) {
2845
+ segments.unshift(current.name.text);
2846
+ current = current.expression;
2847
+ }
2848
+ if (!ts.isIdentifier(current)) return void 0;
2849
+ segments.unshift(current.text);
2850
+ return { root: current, segments };
2851
+ }
2852
+ function isRuntimeIdentifierReference(ts, node) {
2853
+ if (ts.isPropertyAccessExpression(node.parent) && node.parent.name === node) return false;
2854
+ return ts.isExpressionNode(node) && !ts.isInTypeQuery(node) || ts.isShorthandPropertyAssignment(node.parent) && node.parent.name === node;
2855
+ }
2856
+ function hasLocalDeclaration(ts, checker, sourceFile, node) {
2857
+ const shorthand = ts.isShorthandPropertyAssignment(node.parent) && node.parent.name === node;
2858
+ const symbol = shorthand ? checker.getShorthandAssignmentValueSymbol(node.parent) : checker.getSymbolAtLocation(node);
2859
+ return Boolean(
2860
+ symbol?.declarations?.some((declaration) => declaration.getSourceFile() === sourceFile)
2861
+ );
2862
+ }
2431
2863
  function analyzeForbiddenGlobals(ts, source, filePath, layer, forbidden) {
2432
2864
  const entries = new Set(forbidden);
2433
2865
  if (entries.size === 0) return [];
2434
2866
  const sourceFile = ts.createSourceFile("generated.ts", source, ts.ScriptTarget.Latest, true);
2867
+ const checker = singleFileTypeChecker(ts, sourceFile);
2435
2868
  const violations = [];
2436
2869
  const flag = (name, node) => violations.push(
2437
2870
  violation("FORBIDDEN_GLOBAL", `${layer} must not use the ambient global "${name}".`, {
@@ -2443,12 +2876,24 @@ function analyzeForbiddenGlobals(ts, source, filePath, layer, forbidden) {
2443
2876
  })
2444
2877
  );
2445
2878
  const visit = (node) => {
2446
- if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression)) {
2447
- const dotted = `${node.expression.text}.${node.name.text}`;
2448
- if (entries.has(dotted)) flag(dotted, node);
2449
- else if (entries.has(node.expression.text)) flag(node.expression.text, node);
2450
- } else if ((ts.isCallExpression(node) || ts.isNewExpression(node)) && node.expression && ts.isIdentifier(node.expression) && entries.has(node.expression.text)) {
2451
- flag(node.expression.text, node);
2879
+ const nestedPropertyAccess = ts.isPropertyAccessExpression(node) && ts.isPropertyAccessExpression(node.parent) && node.parent.expression === node;
2880
+ if (ts.isPropertyAccessExpression(node) && !nestedPropertyAccess) {
2881
+ const path = propertyAccessPath(ts, node);
2882
+ if (path && !hasLocalDeclaration(ts, checker, sourceFile, path.root)) {
2883
+ const explicitGlobalThis = path.segments[0] === "globalThis";
2884
+ const normalized = explicitGlobalThis ? path.segments.slice(1) : path.segments;
2885
+ let match;
2886
+ for (let length = normalized.length; length >= (explicitGlobalThis ? 1 : 2); length -= 1) {
2887
+ const candidate = normalized.slice(0, length).join(".");
2888
+ if (entries.has(candidate)) {
2889
+ match = candidate;
2890
+ break;
2891
+ }
2892
+ }
2893
+ if (match) flag(match, node);
2894
+ }
2895
+ } else if (ts.isIdentifier(node) && entries.has(node.text) && isRuntimeIdentifierReference(ts, node) && !hasLocalDeclaration(ts, checker, sourceFile, node)) {
2896
+ flag(node.text, node);
2452
2897
  }
2453
2898
  ts.forEachChild(node, visit);
2454
2899
  };
@@ -2525,15 +2970,16 @@ function createAICodeGate(options = {}) {
2525
2970
  const gateContext = context;
2526
2971
  const filePath = gateContext?.filePath;
2527
2972
  const contextLayer = gateContext?.layer;
2528
- const moduleSpecifiers = options.typescript ? extractModuleSpecifiersAst(options.typescript, source) : extractModuleSpecifiers(source);
2973
+ const moduleSpecifiers2 = options.typescript ? extractModuleSpecifiersAst(options.typescript, source) : extractModuleSpecifiers(source);
2529
2974
  const quotedStrings = options.typescript ? extractQuotedStringsAst(options.typescript, source) : extractQuotedStrings(source);
2530
2975
  if (options.typescript && !options.allowNonLiteralDynamicImport?.(filePath)) {
2531
- for (const line of nonLiteralDynamicImportLines(options.typescript, source)) {
2976
+ for (const dependency of nonLiteralDynamicDependencies(options.typescript, source)) {
2977
+ const isRequire = dependency.kind === "require";
2532
2978
  violations.push(
2533
2979
  violation(
2534
- "DYNAMIC_IMPORT_NOT_ALLOWLISTED",
2535
- "Non-literal dynamic import cannot be resolved statically; add the reviewed file to dynamicImportAllowlist.",
2536
- { line, filePath }
2980
+ isRequire ? "DYNAMIC_REQUIRE_NOT_ALLOWLISTED" : "DYNAMIC_IMPORT_NOT_ALLOWLISTED",
2981
+ `Non-literal ${isRequire ? "require call" : "dynamic import"} cannot be resolved statically; add the reviewed file to dynamicImportAllowlist.`,
2982
+ { line: dependency.line, filePath }
2537
2983
  )
2538
2984
  );
2539
2985
  }
@@ -2563,7 +3009,7 @@ function createAICodeGate(options = {}) {
2563
3009
  );
2564
3010
  }
2565
3011
  }
2566
- for (const specifier of moduleSpecifiers) {
3012
+ for (const specifier of moduleSpecifiers2) {
2567
3013
  const targetHit = options.resolveImportTarget?.(specifier.value, filePath) ?? (options.resolveImportLayer ? { layer: options.resolveImportLayer(specifier.value, filePath) } : void 0);
2568
3014
  const sourceHit = typeof filePath === "string" ? options.resolveImportTarget?.(filePath) ?? (options.resolveImportLayer ? { layer: contextLayer, relPath: void 0 } : void 0) : void 0;
2569
3015
  const targetLayer = targetHit?.layer;
@@ -2762,6 +3208,214 @@ function createAICodeGate(options = {}) {
2762
3208
  };
2763
3209
  }
2764
3210
 
3211
+ // src/domain/analysis.ts
3212
+ var ANALYSIS_IR_SCHEMA_VERSION = "1.0";
3213
+ function deterministicHash(value) {
3214
+ let hash = 2166136261;
3215
+ for (let index = 0; index < value.length; index += 1) {
3216
+ hash ^= value.charCodeAt(index);
3217
+ hash = Math.imul(hash, 16777619);
3218
+ }
3219
+ return `fnv1a-${(hash >>> 0).toString(16).padStart(8, "0")}`;
3220
+ }
3221
+ function stableSerialize(value) {
3222
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
3223
+ if (Array.isArray(value)) return `[${value.map(stableSerialize).join(",")}]`;
3224
+ const object = value;
3225
+ return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${stableSerialize(object[key])}`).join(",")}}`;
3226
+ }
3227
+
3228
+ // src/kernel/analysis.ts
3229
+ function loadContract(input, source) {
3230
+ const loaded = typeof input === "string" ? parseArkConfigJson(input, source) : loadArkConfigContract(input, source);
3231
+ return { ...loaded, policyHash: deterministicHash(stableSerialize(loaded.config)) };
3232
+ }
3233
+ function normalizePath(value) {
3234
+ return value.replace(/\\/g, "/").replace(/^\.\//, "");
3235
+ }
3236
+ function isIdentifierCharacter(value) {
3237
+ return value !== void 0 && /[A-Za-z0-9_$]/.test(value);
3238
+ }
3239
+ function skipWhitespace(source, index) {
3240
+ while (index < source.length && /\s/.test(source[index])) index += 1;
3241
+ return index;
3242
+ }
3243
+ function readString(source, index) {
3244
+ const quote = source[index];
3245
+ if (quote !== "'" && quote !== '"') return void 0;
3246
+ const start = index;
3247
+ let value = "";
3248
+ for (index += 1; index < source.length; index += 1) {
3249
+ const current = source[index];
3250
+ if (current === quote) {
3251
+ return { value, offset: start, excerpt: source.slice(start, index + 1) };
3252
+ }
3253
+ if (current === "\\" && index + 1 < source.length) {
3254
+ value += source[index + 1];
3255
+ index += 1;
3256
+ } else {
3257
+ value += current;
3258
+ }
3259
+ }
3260
+ return void 0;
3261
+ }
3262
+ function isWordAt(source, word, index) {
3263
+ return source.startsWith(word, index) && !isIdentifierCharacter(source[index - 1]) && !isIdentifierCharacter(source[index + word.length]);
3264
+ }
3265
+ function specifierAfterImport(source, index) {
3266
+ index = skipWhitespace(source, index + "import".length);
3267
+ if (source[index] === "(") return readString(source, skipWhitespace(source, index + 1));
3268
+ return specifierInStaticStatement(source, index, true);
3269
+ }
3270
+ function specifierAfterExport(source, index) {
3271
+ return specifierInStaticStatement(source, index + "export".length, false);
3272
+ }
3273
+ function specifierInStaticStatement(source, index, allowDirectSpecifier) {
3274
+ for (; index < source.length; index += 1) {
3275
+ if (source[index] === ";") return void 0;
3276
+ if (isWordAt(source, "from", index)) {
3277
+ return readString(source, skipWhitespace(source, index + "from".length));
3278
+ }
3279
+ if (allowDirectSpecifier && (source[index] === "'" || source[index] === '"')) {
3280
+ return readString(source, index);
3281
+ }
3282
+ if (index > 0 && (isWordAt(source, "import", index) || isWordAt(source, "export", index))) {
3283
+ return void 0;
3284
+ }
3285
+ }
3286
+ return void 0;
3287
+ }
3288
+ function moduleSpecifiers(source) {
3289
+ const result = [];
3290
+ for (let index = 0; index < source.length; index += 1) {
3291
+ const current = source[index];
3292
+ if (current === "/" && source[index + 1] === "/") {
3293
+ index = source.indexOf("\n", index + 2);
3294
+ if (index < 0) break;
3295
+ continue;
3296
+ }
3297
+ if (current === "/" && source[index + 1] === "*") {
3298
+ const end = source.indexOf("*/", index + 2);
3299
+ if (end < 0) break;
3300
+ index = end + 1;
3301
+ continue;
3302
+ }
3303
+ if (current === "'" || current === '"' || current === "`") {
3304
+ const string = readString(source, index);
3305
+ if (string) index = string.offset + string.excerpt.length - 1;
3306
+ continue;
3307
+ }
3308
+ const specifier = isWordAt(source, "import", index) ? specifierAfterImport(source, index) : isWordAt(source, "export", index) ? specifierAfterExport(source, index) : void 0;
3309
+ if (specifier) result.push(specifier);
3310
+ }
3311
+ return result;
3312
+ }
3313
+ function importEdges(file, files) {
3314
+ const edges = [];
3315
+ for (const moduleSpecifier of moduleSpecifiers(file.content)) {
3316
+ const specifier = moduleSpecifier.value;
3317
+ if (!specifier.startsWith(".")) continue;
3318
+ const line = file.content.slice(0, moduleSpecifier.offset).split("\n").length;
3319
+ const evidence = {
3320
+ kind: "import",
3321
+ file: file.path,
3322
+ line,
3323
+ excerpt: moduleSpecifier.excerpt
3324
+ };
3325
+ const target = resolveSpecifier(file.path, specifier, files);
3326
+ edges.push({
3327
+ from: file.path,
3328
+ specifier,
3329
+ to: target?.path ?? null,
3330
+ resolution: target ? "resolved" : "unresolved",
3331
+ fromLayer: file.layer,
3332
+ toLayer: target?.layer ?? null,
3333
+ evidence
3334
+ });
3335
+ }
3336
+ return edges;
3337
+ }
3338
+ function resolveSpecifier(from, specifier, files) {
3339
+ const segments = from.split("/");
3340
+ segments.pop();
3341
+ for (const segment of specifier.split("/")) {
3342
+ if (segment === "." || segment === "") continue;
3343
+ if (segment === "..") segments.pop();
3344
+ else segments.push(segment);
3345
+ }
3346
+ const base = segments.join("/");
3347
+ for (const candidate of [base, `${base}.ts`, `${base}.tsx`, `${base}.mts`, `${base}.cts`, `${base}/index.ts`, `${base}/index.tsx`]) {
3348
+ const found = files.get(candidate);
3349
+ if (found) return found;
3350
+ }
3351
+ return void 0;
3352
+ }
3353
+ function violationsFor(edges, config) {
3354
+ const violations = [];
3355
+ for (const edge of edges) {
3356
+ if (!edge.to || !edge.fromLayer || !edge.toLayer) continue;
3357
+ const rule = findDeniedEdgeRule(config.rules, edge.fromLayer, edge.toLayer, {
3358
+ fromPath: edge.from,
3359
+ toPath: edge.to,
3360
+ layers: config.layers
3361
+ });
3362
+ if (!rule) continue;
3363
+ violations.push({
3364
+ ruleId: `layer-dependency:${rule.from}->${rule.to}`,
3365
+ message: rule.message ?? `${rule.from} must not depend on ${rule.to}.`,
3366
+ edge,
3367
+ evidence: edge.evidence
3368
+ });
3369
+ }
3370
+ return violations;
3371
+ }
3372
+ function analyzeProject(input) {
3373
+ const files = input.files.map((inputFile) => {
3374
+ const path = normalizePath(inputFile.path);
3375
+ return {
3376
+ path,
3377
+ content: inputFile.content,
3378
+ contentHash: deterministicHash(inputFile.content),
3379
+ layer: layerForRelativePath(path, input.contract.config.layers) ?? null
3380
+ };
3381
+ }).sort((left, right) => left.path.localeCompare(right.path));
3382
+ const fileByPath = new Map(files.map((file) => [file.path, file]));
3383
+ const edges = files.flatMap((file) => importEdges(file, fileByPath));
3384
+ const capabilityUses = [];
3385
+ const violations = violationsFor(edges, input.contract.config);
3386
+ return {
3387
+ ir: {
3388
+ schemaVersion: ANALYSIS_IR_SCHEMA_VERSION,
3389
+ policyHash: input.contract.policyHash,
3390
+ compilerOptionsHash: deterministicHash(stableSerialize(input.compilerOptions ?? {})),
3391
+ files,
3392
+ layers: input.contract.config.layers.map((layer) => layer.name),
3393
+ edges,
3394
+ capabilityUses,
3395
+ violations
3396
+ }
3397
+ };
3398
+ }
3399
+ function analyzeChange(input) {
3400
+ const files = new Map(input.files.map((file) => [normalizePath(file.path), file]));
3401
+ for (const change of input.changes) {
3402
+ const path = normalizePath(change.path);
3403
+ if ("delete" in change && change.delete) files.delete(path);
3404
+ else if ("content" in change) files.set(path, { path, content: change.content });
3405
+ }
3406
+ return analyzeProject({
3407
+ contract: input.contract,
3408
+ files: [...files.values()],
3409
+ compilerOptions: input.compilerOptions
3410
+ });
3411
+ }
3412
+ function explainViolation(violation2) {
3413
+ const location = `${violation2.evidence.file}:${violation2.evidence.line}`;
3414
+ if (!violation2.edge) return `${violation2.ruleId} at ${location}: ${violation2.message}`;
3415
+ const target = violation2.edge.to ?? violation2.edge.specifier;
3416
+ return `${violation2.ruleId} at ${location}: ${violation2.edge.from} imports ${target}. ${violation2.message}`;
3417
+ }
3418
+
2765
3419
  // src/kernel/projections/ProjectionRegistry.ts
2766
3420
  var InMemoryReadModelStore = class {
2767
3421
  states = /* @__PURE__ */ new Map();
@@ -3070,22 +3724,13 @@ var WorkflowEngineImpl = class {
3070
3724
  for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
3071
3725
  snapshot.attempts[step.name] = attempt;
3072
3726
  await this.store.save(snapshot);
3727
+ let result;
3073
3728
  try {
3074
- const result = await withTimeout(
3729
+ result = await withTimeout(
3075
3730
  (signal) => Promise.resolve(step.execute(snapshot.context, this.bus, signal)),
3076
3731
  step.timeoutMs,
3077
3732
  step.name
3078
3733
  );
3079
- if (result) Object.assign(snapshot.context, result);
3080
- snapshot.completedSteps.push(step.name);
3081
- snapshot.currentStep = void 0;
3082
- snapshot.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
3083
- await this.store.save(snapshot);
3084
- await this.audit("workflow.step.completed", snapshot, {
3085
- step: step.name,
3086
- attempt
3087
- });
3088
- return;
3089
3734
  } catch (err) {
3090
3735
  if (attempt < maxAttempts) {
3091
3736
  if (retry.delayMs) await sleep(retry.delayMs);
@@ -3101,6 +3746,16 @@ var WorkflowEngineImpl = class {
3101
3746
  });
3102
3747
  throw err;
3103
3748
  }
3749
+ if (result) Object.assign(snapshot.context, result);
3750
+ snapshot.completedSteps.push(step.name);
3751
+ snapshot.currentStep = void 0;
3752
+ snapshot.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
3753
+ await this.store.save(snapshot);
3754
+ await this.audit("workflow.step.completed", snapshot, {
3755
+ step: step.name,
3756
+ attempt
3757
+ });
3758
+ return;
3104
3759
  }
3105
3760
  throw new Error(`Workflow step "${step.name}" did not complete.`);
3106
3761
  }
@@ -3292,6 +3947,7 @@ function createLenientArkKernel(options = {}) {
3292
3947
  }
3293
3948
  // Annotate the CommonJS export names for ESM import in node:
3294
3949
  0 && (module.exports = {
3950
+ ANALYSIS_IR_SCHEMA_VERSION,
3295
3951
  DEFAULT_MAX_HISTORY_SIZE,
3296
3952
  EventContractRegistryImpl,
3297
3953
  EventContractViolationError,
@@ -3309,6 +3965,8 @@ function createLenientArkKernel(options = {}) {
3309
3965
  SourceMetadataOverrideError,
3310
3966
  UnknownEventSourceError,
3311
3967
  UnregisteredIntentError,
3968
+ analyzeChange,
3969
+ analyzeProject,
3312
3970
  architecturalPolicies,
3313
3971
  buildPublishPolicyContext,
3314
3972
  checkAdapterGovernance,
@@ -3343,8 +4001,12 @@ function createLenientArkKernel(options = {}) {
3343
4001
  definePolicy,
3344
4002
  definePort,
3345
4003
  definePublishPolicy,
4004
+ deterministicHash,
3346
4005
  elevenLayerProfile,
4006
+ explainViolation,
3347
4007
  isLayerPolicy,
4008
+ loadContract,
4009
+ stableSerialize,
3348
4010
  syncRegistryToGraph,
3349
4011
  validateIntentName,
3350
4012
  version