arkgate 2.11.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 (77) hide show
  1. package/CHANGELOG.md +147 -0
  2. package/README.md +70 -41
  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 +97 -29
  7. package/bin/lib/agent-gates.mjs +79 -2093
  8. package/bin/lib/architecture-scan.mjs +8 -0
  9. package/bin/lib/ci-and-commands.mjs +392 -0
  10. package/bin/lib/codex-home.mjs +7 -0
  11. package/bin/lib/config-contract.mjs +331 -0
  12. package/bin/lib/deploy-path.mjs +205 -0
  13. package/bin/lib/doctor-plan.mjs +43 -16
  14. package/bin/lib/enforcement-profiles.mjs +97 -0
  15. package/bin/lib/gate-files.mjs +223 -0
  16. package/bin/lib/hook-templates.mjs +99 -0
  17. package/bin/lib/host-support-matrix.mjs +77 -0
  18. package/bin/lib/install-migrate.mjs +473 -0
  19. package/bin/lib/mcp-adoption.mjs +455 -0
  20. package/bin/lib/open-html.mjs +75 -0
  21. package/bin/lib/presets.mjs +6 -2
  22. package/bin/lib/safety-diagnostics.mjs +31 -11
  23. package/bin/lib/skill-install.mjs +323 -0
  24. package/bin/lib/ts-resolve.mjs +2 -1
  25. package/bin/lib/typescript-host.mjs +88 -0
  26. package/bin/lib/weakest-link.mjs +417 -0
  27. package/bin/lib/write-path-capabilities.mjs +182 -0
  28. package/bin/lib/write-path-detect.mjs +101 -0
  29. package/dist/configContract-iBLxx5Tz.d.cts +53 -0
  30. package/dist/configContract-iBLxx5Tz.d.ts +53 -0
  31. package/dist/eslint/index.cjs +375 -13
  32. package/dist/eslint/index.cjs.map +1 -1
  33. package/dist/eslint/index.d.cts +30 -20
  34. package/dist/eslint/index.d.ts +30 -20
  35. package/dist/eslint/index.js +375 -13
  36. package/dist/eslint/index.js.map +1 -1
  37. package/dist/index.cjs +723 -61
  38. package/dist/index.cjs.map +1 -1
  39. package/dist/index.d.cts +95 -5
  40. package/dist/index.d.ts +95 -5
  41. package/dist/index.js +716 -61
  42. package/dist/index.js.map +1 -1
  43. package/dist/nestjs/index.cjs +150 -42
  44. package/dist/nestjs/index.cjs.map +1 -1
  45. package/dist/nestjs/index.d.cts +2 -1
  46. package/dist/nestjs/index.d.ts +2 -1
  47. package/dist/nestjs/index.js +150 -42
  48. package/dist/nestjs/index.js.map +1 -1
  49. package/dist/runtime/index.cjs +723 -61
  50. package/dist/runtime/index.cjs.map +1 -1
  51. package/dist/runtime/index.d.cts +3 -2
  52. package/dist/runtime/index.d.ts +3 -2
  53. package/dist/runtime/index.js +716 -61
  54. package/dist/runtime/index.js.map +1 -1
  55. package/dist/{types-BZ17b9i5.d.cts → types-BxBwnBpC.d.cts} +9 -36
  56. package/dist/{types-BZ17b9i5.d.ts → types-Wcs_l1_J.d.ts} +9 -36
  57. package/docs/agent-guide.md +43 -21
  58. package/docs/ai-gates.md +53 -18
  59. package/docs/configuration.md +97 -0
  60. package/docs/enthusiast/README.md +3 -3
  61. package/docs/enthusiast/how-to-agent-gates.md +7 -3
  62. package/docs/migrate-from-ark-runtime-kernel.md +3 -0
  63. package/docs/package-surface.md +22 -10
  64. package/docs/production-hardening.md +15 -2
  65. package/docs/threat-model.md +65 -0
  66. package/docs/typescript-support.md +3 -3
  67. package/package.json +15 -2
  68. package/schemas/ark.config.schema.json +750 -0
  69. package/server.json +2 -2
  70. package/templates/hooks/pre-commit-ark +37 -0
  71. package/templates/skills/ark-autopilot.md +77 -45
  72. package/templates/skills/ark-coverage.md +2 -2
  73. package/templates/skills/ark-explain.md +2 -1
  74. package/templates/skills/ark-explore.md +135 -34
  75. package/templates/skills/ark-runtime.md +8 -5
  76. package/templates/skills/ark-upgrade.md +36 -16
  77. package/tests/fixtures/ts-consumer/ark.config.json +2 -0
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var version = "2.11.0";
2
+ var version = "2.13.0";
3
3
 
4
4
  // src/kernel/intent/IntentRegistry.ts
5
5
  var IntentRegistry = class {
@@ -663,6 +663,10 @@ async function recordInterceptorError(interceptor, event, error, deps) {
663
663
  }
664
664
 
665
665
  // src/domain/layerMatch.ts
666
+ var regexpCache = /* @__PURE__ */ new Map();
667
+ function escapeLiteral(ch) {
668
+ return /[.*+?^${}()|[\]\\]/.test(ch) ? `\\${ch}` : ch;
669
+ }
666
670
  function normalizeGlobSeparators(pattern) {
667
671
  let out = "";
668
672
  for (let i = 0; i < pattern.length; i += 1) {
@@ -681,6 +685,91 @@ function normalizeGlobSeparators(pattern) {
681
685
  }
682
686
  return out;
683
687
  }
688
+ function bracesBalanced(glob) {
689
+ let depth = 0;
690
+ for (let i = 0; i < glob.length; i += 1) {
691
+ const c = glob[i];
692
+ if (c === "\\") {
693
+ i += 1;
694
+ continue;
695
+ }
696
+ if (c === "{") depth += 1;
697
+ else if (c === "}") {
698
+ depth -= 1;
699
+ if (depth < 0) return false;
700
+ }
701
+ }
702
+ return depth === 0;
703
+ }
704
+ function globToRegExp(pattern) {
705
+ const cached = regexpCache.get(pattern);
706
+ if (cached) return cached;
707
+ const glob = normalizeGlobSeparators(pattern);
708
+ const useBraces = bracesBalanced(glob);
709
+ let out = "";
710
+ let braceDepth = 0;
711
+ for (let i = 0; i < glob.length; i += 1) {
712
+ const c = glob[i];
713
+ if (c === "\\" && i + 1 < glob.length) {
714
+ out += escapeLiteral(glob[i + 1]);
715
+ i += 1;
716
+ } else if (c === "*") {
717
+ if (glob[i + 1] === "*") {
718
+ if (glob[i + 2] === "/") {
719
+ out += "(?:.*/)?";
720
+ i += 2;
721
+ } else {
722
+ out += ".*";
723
+ i += 1;
724
+ }
725
+ } else {
726
+ out += "[^/]*";
727
+ }
728
+ } else if (c === "?") {
729
+ out += "[^/]";
730
+ } else if (c === "{" && useBraces) {
731
+ out += "(?:";
732
+ braceDepth += 1;
733
+ } else if (c === "}" && useBraces && braceDepth > 0) {
734
+ out += ")";
735
+ braceDepth -= 1;
736
+ } else if (c === "," && useBraces && braceDepth > 0) {
737
+ out += "|";
738
+ } else {
739
+ out += escapeLiteral(c);
740
+ }
741
+ }
742
+ const re = new RegExp(`^${out}$`);
743
+ regexpCache.set(pattern, re);
744
+ return re;
745
+ }
746
+ function patternSpecificity(pattern) {
747
+ const glob = normalizeGlobSeparators(String(pattern));
748
+ const beforeWildcard = glob.split("*")[0];
749
+ const literalSegments = beforeWildcard.split("/").filter(Boolean).length;
750
+ const literalLength = glob.replace(/\*/g, "").length;
751
+ return literalSegments * 1e4 + literalLength;
752
+ }
753
+ function layerForRelativePath(relPath, layers) {
754
+ const rel = String(relPath).split(/[/\\]/).join("/");
755
+ let bestName;
756
+ let bestScore = -1;
757
+ for (const layer of layers ?? []) {
758
+ if ((layer.exclude ?? []).some((pattern) => globToRegExp(pattern).test(rel))) {
759
+ continue;
760
+ }
761
+ for (const pattern of layer.patterns ?? []) {
762
+ if (globToRegExp(pattern).test(rel)) {
763
+ const score = patternSpecificity(pattern);
764
+ if (score > bestScore) {
765
+ bestScore = score;
766
+ bestName = layer.name;
767
+ }
768
+ }
769
+ }
770
+ }
771
+ return bestName;
772
+ }
684
773
  function sliceIdForPath(relPath, sliceFolders) {
685
774
  if (!sliceFolders?.length) return void 0;
686
775
  const parts = String(relPath).split(/[/\\]/).filter(Boolean);
@@ -1275,13 +1364,13 @@ function formatPath(parent, field) {
1275
1364
  return parent ? `${parent}.${field}` : field;
1276
1365
  }
1277
1366
  function validateSchemaField(value, fieldSchema, path, contract, issues) {
1278
- const valueType = actualType(value);
1279
- if (fieldSchema.type !== "unknown" && valueType !== fieldSchema.type) {
1367
+ const valueType2 = actualType(value);
1368
+ if (fieldSchema.type !== "unknown" && valueType2 !== fieldSchema.type) {
1280
1369
  issues.push({
1281
1370
  intent: contract.intent,
1282
1371
  version: contract.version,
1283
1372
  field: path,
1284
- message: `Expected ${fieldSchema.type}, received ${valueType}.`
1373
+ message: `Expected ${fieldSchema.type}, received ${valueType2}.`
1285
1374
  });
1286
1375
  return;
1287
1376
  }
@@ -1838,6 +1927,321 @@ function syncRegistryToGraph(registry, graph, options = {}) {
1838
1927
  }
1839
1928
  }
1840
1929
 
1930
+ // src/domain/configContract.ts
1931
+ var ARK_CONFIG_SCHEMA_VERSION = "1.0";
1932
+ var ARK_CONFIG_SCHEMA_URL = "https://unpkg.com/arkgate@2/schemas/ark.config.schema.json";
1933
+ var DEFAULT_LAYER_NAMES = [
1934
+ "DomainModel",
1935
+ "ApplicationOrchestration",
1936
+ "PersistenceAdapters",
1937
+ "IntegrationAdapters",
1938
+ "WorkflowSagaEngine",
1939
+ "BackgroundJobsScheduling",
1940
+ "PresentationAdapters",
1941
+ "ReportingReadModels",
1942
+ "ExtensibilityMetadata",
1943
+ "SecurityAuditObservability",
1944
+ "Kernel"
1945
+ ];
1946
+ var DEFAULT_ALLOWED_FLOWS = /* @__PURE__ */ new Set([
1947
+ "PresentationAdapters->ApplicationOrchestration",
1948
+ "ApplicationOrchestration->DomainModel",
1949
+ "WorkflowSagaEngine->ApplicationOrchestration",
1950
+ "WorkflowSagaEngine->DomainModel",
1951
+ "BackgroundJobsScheduling->ApplicationOrchestration"
1952
+ ]);
1953
+ function createDefaultRules() {
1954
+ const rules = [];
1955
+ for (const from of DEFAULT_LAYER_NAMES) {
1956
+ for (const to of DEFAULT_LAYER_NAMES) {
1957
+ if (from === to || DEFAULT_ALLOWED_FLOWS.has(`${from}->${to}`)) continue;
1958
+ rules.push({ from, to, allowed: false });
1959
+ }
1960
+ }
1961
+ return rules;
1962
+ }
1963
+ var DEFAULT_ARK_CONFIG_RULES = createDefaultRules();
1964
+ var stringArraySchema = {
1965
+ type: "array",
1966
+ items: { type: "string", minLength: 1 },
1967
+ uniqueItems: true
1968
+ };
1969
+ var ARK_CONFIG_SCHEMA = {
1970
+ $schema: "https://json-schema.org/draft/2020-12/schema",
1971
+ $id: ARK_CONFIG_SCHEMA_URL,
1972
+ title: "ArkGate architecture contract",
1973
+ description: "Versioned contract consumed identically by ArkGate CLI, MCP, and ESLint surfaces.",
1974
+ type: "object",
1975
+ additionalProperties: false,
1976
+ required: ["$schema", "schemaVersion", "include", "layers", "rules"],
1977
+ properties: {
1978
+ $schema: {
1979
+ type: "string",
1980
+ minLength: 1,
1981
+ default: ARK_CONFIG_SCHEMA_URL,
1982
+ description: "Editor-facing URL or local path for this JSON Schema."
1983
+ },
1984
+ schemaVersion: {
1985
+ type: "string",
1986
+ const: ARK_CONFIG_SCHEMA_VERSION,
1987
+ default: ARK_CONFIG_SCHEMA_VERSION
1988
+ },
1989
+ name: { type: "string", minLength: 1 },
1990
+ include: { ...stringArraySchema, minItems: 1, default: ["src"] },
1991
+ exclude: { ...stringArraySchema, default: [] },
1992
+ excludeGenerated: { type: "boolean", default: true },
1993
+ frameworkOverlay: { type: "string", minLength: 1 },
1994
+ layers: {
1995
+ type: "array",
1996
+ default: [],
1997
+ items: { $ref: "#/$defs/layer" }
1998
+ },
1999
+ rules: {
2000
+ type: "array",
2001
+ default: DEFAULT_ARK_CONFIG_RULES,
2002
+ items: { $ref: "#/$defs/rule" }
2003
+ },
2004
+ cyclePolicy: {
2005
+ type: "string",
2006
+ enum: ["strict", "soft", "framework-soft", "off"],
2007
+ default: "strict"
2008
+ },
2009
+ dynamicImportAllowlist: { ...stringArraySchema, default: [] },
2010
+ safety: {
2011
+ $ref: "#/$defs/safety",
2012
+ default: {
2013
+ maxTsSuppressions: 0,
2014
+ maxAnyCasts: 0,
2015
+ allowInMemory: false,
2016
+ allowDisabledPeerIsolation: false
2017
+ }
2018
+ }
2019
+ },
2020
+ $defs: {
2021
+ layer: {
2022
+ type: "object",
2023
+ additionalProperties: false,
2024
+ required: ["name", "patterns"],
2025
+ properties: {
2026
+ name: { type: "string", minLength: 1 },
2027
+ patterns: { ...stringArraySchema, minItems: 1 },
2028
+ exclude: stringArraySchema,
2029
+ intentPrefixes: stringArraySchema,
2030
+ description: { type: "string", minLength: 1 },
2031
+ forbiddenGlobals: stringArraySchema,
2032
+ mayImportInfrastructure: { type: "boolean" },
2033
+ optional: { type: "boolean" }
2034
+ }
2035
+ },
2036
+ rule: {
2037
+ type: "object",
2038
+ additionalProperties: false,
2039
+ required: ["from", "to", "allowed"],
2040
+ properties: {
2041
+ from: { type: "string", minLength: 1 },
2042
+ to: { type: "string", minLength: 1 },
2043
+ allowed: { type: "boolean" },
2044
+ message: { type: "string", minLength: 1 },
2045
+ peerIsolation: { type: "boolean" },
2046
+ sliceFolders: { ...stringArraySchema, minItems: 1 }
2047
+ }
2048
+ },
2049
+ safety: {
2050
+ type: "object",
2051
+ additionalProperties: false,
2052
+ properties: {
2053
+ maxTsSuppressions: { type: "integer", minimum: 0, default: 0 },
2054
+ maxAnyCasts: { type: "integer", minimum: 0, default: 0 },
2055
+ allowInMemory: { type: "boolean", default: false },
2056
+ allowDisabledPeerIsolation: { type: "boolean", default: false }
2057
+ }
2058
+ }
2059
+ }
2060
+ };
2061
+ var ArkConfigValidationError = class extends Error {
2062
+ issues;
2063
+ source;
2064
+ constructor(source, issues) {
2065
+ super(
2066
+ `Invalid ArkGate config (${source}):
2067
+ ${issues.map((issue) => `- ${issue.path}: ${issue.message}`).join("\n")}`
2068
+ );
2069
+ this.name = "ArkConfigValidationError";
2070
+ this.source = source;
2071
+ this.issues = issues;
2072
+ }
2073
+ };
2074
+ function isObject(value) {
2075
+ return value !== null && typeof value === "object" && !Array.isArray(value);
2076
+ }
2077
+ function propertyPath(parent, key) {
2078
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? `${parent}.${key}` : `${parent}[${JSON.stringify(key)}]`;
2079
+ }
2080
+ function valueType(value) {
2081
+ if (value === null) return "null";
2082
+ if (Array.isArray(value)) return "array";
2083
+ return typeof value;
2084
+ }
2085
+ function resolveSchemaRef(ref, root) {
2086
+ const prefix = "#/$defs/";
2087
+ if (!ref.startsWith(prefix)) return void 0;
2088
+ return root.$defs[ref.slice(prefix.length)];
2089
+ }
2090
+ function validateNode(value, schema, path, root, issues) {
2091
+ if (schema.$ref) {
2092
+ const referenced = resolveSchemaRef(schema.$ref, root);
2093
+ if (!referenced) {
2094
+ issues.push({ path, message: `schema reference ${schema.$ref} cannot be resolved` });
2095
+ return;
2096
+ }
2097
+ validateNode(value, referenced, path, root, issues);
2098
+ return;
2099
+ }
2100
+ if (schema.const !== void 0 && !Object.is(value, schema.const)) {
2101
+ issues.push({ path, message: `must equal ${JSON.stringify(schema.const)}` });
2102
+ return;
2103
+ }
2104
+ if (schema.enum && !schema.enum.some((candidate) => Object.is(candidate, value))) {
2105
+ issues.push({ path, message: `must be one of ${schema.enum.map(String).join(", ")}` });
2106
+ return;
2107
+ }
2108
+ if (schema.type === "object") {
2109
+ if (!isObject(value)) {
2110
+ issues.push({ path, message: `must be an object; received ${valueType(value)}` });
2111
+ return;
2112
+ }
2113
+ const properties = schema.properties ?? {};
2114
+ for (const key of schema.required ?? []) {
2115
+ if (value[key] === void 0) {
2116
+ issues.push({ path: propertyPath(path, key), message: "is required" });
2117
+ }
2118
+ }
2119
+ if (schema.additionalProperties === false) {
2120
+ for (const key of Object.keys(value)) {
2121
+ if (!(key in properties)) {
2122
+ issues.push({ path: propertyPath(path, key), message: "unknown field" });
2123
+ }
2124
+ }
2125
+ }
2126
+ for (const [key, childSchema] of Object.entries(properties)) {
2127
+ if (value[key] !== void 0) {
2128
+ validateNode(value[key], childSchema, propertyPath(path, key), root, issues);
2129
+ }
2130
+ }
2131
+ return;
2132
+ }
2133
+ if (schema.type === "array") {
2134
+ if (!Array.isArray(value)) {
2135
+ issues.push({ path, message: `must be an array; received ${valueType(value)}` });
2136
+ return;
2137
+ }
2138
+ if (schema.minItems !== void 0 && value.length < schema.minItems) {
2139
+ issues.push({ path, message: `must contain at least ${schema.minItems} item(s)` });
2140
+ }
2141
+ if (schema.uniqueItems) {
2142
+ const serialized = value.map((entry) => JSON.stringify(entry));
2143
+ if (new Set(serialized).size !== serialized.length) {
2144
+ issues.push({ path, message: "must not contain duplicate items" });
2145
+ }
2146
+ }
2147
+ if (schema.items) {
2148
+ value.forEach(
2149
+ (entry, index) => validateNode(entry, schema.items, `${path}[${index}]`, root, issues)
2150
+ );
2151
+ }
2152
+ return;
2153
+ }
2154
+ if (schema.type === "string") {
2155
+ if (typeof value !== "string") {
2156
+ issues.push({ path, message: `must be a string; received ${valueType(value)}` });
2157
+ return;
2158
+ }
2159
+ if (schema.minLength !== void 0 && value.length < schema.minLength) {
2160
+ issues.push({ path, message: `must contain at least ${schema.minLength} character(s)` });
2161
+ }
2162
+ return;
2163
+ }
2164
+ if (schema.type === "boolean") {
2165
+ if (typeof value !== "boolean") {
2166
+ issues.push({ path, message: `must be a boolean; received ${valueType(value)}` });
2167
+ }
2168
+ return;
2169
+ }
2170
+ if (schema.type === "integer") {
2171
+ if (!Number.isInteger(value)) {
2172
+ issues.push({ path, message: `must be an integer; received ${valueType(value)}` });
2173
+ return;
2174
+ }
2175
+ if (schema.minimum !== void 0 && value < schema.minimum) {
2176
+ issues.push({ path, message: `must be at least ${schema.minimum}` });
2177
+ }
2178
+ }
2179
+ }
2180
+ function defaultedConfig(input) {
2181
+ return {
2182
+ ...input,
2183
+ $schema: input.$schema === void 0 ? ARK_CONFIG_SCHEMA_URL : input.$schema,
2184
+ schemaVersion: input.schemaVersion === void 0 ? ARK_CONFIG_SCHEMA_VERSION : input.schemaVersion,
2185
+ include: input.include === void 0 ? ["src"] : input.include,
2186
+ layers: input.layers === void 0 ? [] : input.layers,
2187
+ rules: input.rules === void 0 ? DEFAULT_ARK_CONFIG_RULES.map((rule) => ({ ...rule })) : input.rules
2188
+ };
2189
+ }
2190
+ function migrateArkConfig(input, source = "ark.config.json") {
2191
+ if (!isObject(input)) {
2192
+ throw new ArkConfigValidationError(source, [
2193
+ { path: "$", message: `must be an object; received ${valueType(input)}` }
2194
+ ]);
2195
+ }
2196
+ const migratedFrom = input.schemaVersion === void 0 ? "unversioned" : null;
2197
+ if (input.schemaVersion !== void 0 && input.schemaVersion !== ARK_CONFIG_SCHEMA_VERSION) {
2198
+ throw new ArkConfigValidationError(source, [
2199
+ {
2200
+ path: "$.schemaVersion",
2201
+ message: `unsupported version ${JSON.stringify(input.schemaVersion)}; expected ${ARK_CONFIG_SCHEMA_VERSION}`
2202
+ }
2203
+ ]);
2204
+ }
2205
+ return { candidate: defaultedConfig(input), migratedFrom };
2206
+ }
2207
+ function loadArkConfigContract(input, source = "ark.config.json") {
2208
+ const { candidate, migratedFrom } = migrateArkConfig(input, source);
2209
+ const issues = [];
2210
+ validateNode(
2211
+ candidate,
2212
+ ARK_CONFIG_SCHEMA,
2213
+ "$",
2214
+ ARK_CONFIG_SCHEMA,
2215
+ issues
2216
+ );
2217
+ if (issues.length > 0) throw new ArkConfigValidationError(source, issues);
2218
+ return { config: candidate, migratedFrom };
2219
+ }
2220
+ function parseArkConfigJson(json, source = "ark.config.json") {
2221
+ let input;
2222
+ try {
2223
+ input = JSON.parse(json);
2224
+ } catch (error) {
2225
+ throw new ArkConfigValidationError(source, [
2226
+ {
2227
+ path: "$",
2228
+ message: `invalid JSON: ${error instanceof Error ? error.message : String(error)}`
2229
+ }
2230
+ ]);
2231
+ }
2232
+ return loadArkConfigContract(input, source);
2233
+ }
2234
+ function withArkConfigMetadata(config) {
2235
+ const result = {
2236
+ $schema: typeof config.$schema === "string" && config.$schema.length > 0 ? config.$schema : ARK_CONFIG_SCHEMA_URL,
2237
+ schemaVersion: ARK_CONFIG_SCHEMA_VERSION
2238
+ };
2239
+ for (const [key, value] of Object.entries(config)) {
2240
+ if (key !== "$schema" && key !== "schemaVersion") result[key] = value;
2241
+ }
2242
+ return result;
2243
+ }
2244
+
1841
2245
  // src/kernel/layers/ArchitectureProfile.ts
1842
2246
  function normalizePrefix(prefix) {
1843
2247
  return prefix.endsWith(".") ? prefix : `${prefix}.`;
@@ -1847,21 +2251,6 @@ function byLongestPrefix(a, b) {
1847
2251
  const maxB = b.prefixes.length ? Math.max(...b.prefixes.map((p) => p.length)) : 0;
1848
2252
  return maxB - maxA;
1849
2253
  }
1850
- function flowKey2(from, to) {
1851
- return `${from}->${to}`;
1852
- }
1853
- function createStrictDenyRules(layers, allowedFlows) {
1854
- const allowed = new Set(allowedFlows.map((flow) => flowKey2(flow.from, flow.to)));
1855
- const rules = [];
1856
- for (const from of layers) {
1857
- for (const to of layers) {
1858
- if (from.name === to.name) continue;
1859
- if (allowed.has(flowKey2(from.name, to.name))) continue;
1860
- rules.push({ from: from.name, to: to.name, allowed: false });
1861
- }
1862
- }
1863
- return rules;
1864
- }
1865
2254
  function createArchitectureProfile(options) {
1866
2255
  const layers = options.layers.map((layer) => ({
1867
2256
  ...layer,
@@ -1960,20 +2349,10 @@ var elevenLayerProfileLayers = [
1960
2349
  order: 11
1961
2350
  }
1962
2351
  ];
1963
- var elevenLayerAllowedFlows = [
1964
- { from: "PresentationAdapters", to: "ApplicationOrchestration" },
1965
- { from: "ApplicationOrchestration", to: "DomainModel" },
1966
- { from: "WorkflowSagaEngine", to: "ApplicationOrchestration" },
1967
- { from: "WorkflowSagaEngine", to: "DomainModel" },
1968
- { from: "BackgroundJobsScheduling", to: "ApplicationOrchestration" }
1969
- ];
1970
2352
  var elevenLayerProfile = createArchitectureProfile({
1971
2353
  name: "Ark 11-layer Hexagonal Event-Driven Profile",
1972
2354
  layers: elevenLayerProfileLayers,
1973
- rules: createStrictDenyRules(
1974
- elevenLayerProfileLayers,
1975
- elevenLayerAllowedFlows
1976
- )
2355
+ rules: DEFAULT_ARK_CONFIG_RULES.map((rule) => ({ ...rule }))
1977
2356
  });
1978
2357
  var defaultElevenLayerDirectories = {
1979
2358
  DomainModel: ["domain"],
@@ -1997,7 +2376,7 @@ function createElevenLayerArkConfig(options = {}) {
1997
2376
  const rootDir = options.rootDir ?? "src";
1998
2377
  const optional = options.optionalLayers ?? true;
1999
2378
  const prefix = rootDir === "." ? "" : `${rootDir}/`;
2000
- return {
2379
+ return withArkConfigMetadata({
2001
2380
  include: options.include ?? [rootDir],
2002
2381
  layers: elevenLayerProfile.layers.map((layer) => ({
2003
2382
  name: layer.name,
@@ -2008,7 +2387,7 @@ function createElevenLayerArkConfig(options = {}) {
2008
2387
  optional
2009
2388
  })),
2010
2389
  rules: [...elevenLayerProfile.rules]
2011
- };
2390
+ });
2012
2391
  }
2013
2392
 
2014
2393
  // src/kernel/metadata/MetadataRegistry.ts
@@ -2212,7 +2591,11 @@ function extractModuleSpecifiersAst(ts, source) {
2212
2591
  "export",
2213
2592
  Boolean(node.isTypeOnly || specifiersOnly)
2214
2593
  );
2215
- } else if (ts.isCallExpression(node) && node.arguments.length === 1) {
2594
+ } else if (ts.isImportEqualsDeclaration(node) && ts.isExternalModuleReference(node.moduleReference)) {
2595
+ const argument = node.moduleReference.expression;
2596
+ const value = tsStringLiteralText(ts, argument);
2597
+ if (value !== void 0) push(argument, value, "require");
2598
+ } else if (ts.isCallExpression(node)) {
2216
2599
  const argument = node.arguments[0];
2217
2600
  const value = tsStringLiteralText(ts, argument);
2218
2601
  if (value !== void 0 && node.expression.kind === ts.SyntaxKind.ImportKeyword) {
@@ -2226,17 +2609,25 @@ function extractModuleSpecifiersAst(ts, source) {
2226
2609
  visit(sourceFile);
2227
2610
  return matches.sort((a, b) => a.index - b.index);
2228
2611
  }
2229
- function nonLiteralDynamicImportLines(ts, source) {
2612
+ function nonLiteralDynamicDependencies(ts, source) {
2230
2613
  const sourceFile = ts.createSourceFile("generated.ts", source, ts.ScriptTarget.Latest, true);
2231
- const lines = [];
2614
+ const uses = [];
2232
2615
  const visit = (node) => {
2233
- if (ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword && (!node.arguments[0] || !ts.isStringLiteralLike(node.arguments[0]))) {
2234
- lines.push(sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1);
2616
+ if (ts.isCallExpression(node)) {
2617
+ const dynamicImport = node.expression.kind === ts.SyntaxKind.ImportKeyword;
2618
+ const directRequire = ts.isIdentifier(node.expression) && node.expression.text === "require";
2619
+ const argument = node.arguments[0];
2620
+ if ((dynamicImport || directRequire) && (!argument || !ts.isStringLiteralLike(argument))) {
2621
+ uses.push({
2622
+ line: sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1,
2623
+ kind: directRequire ? "require" : "import"
2624
+ });
2625
+ }
2235
2626
  }
2236
2627
  ts.forEachChild(node, visit);
2237
2628
  };
2238
2629
  visit(sourceFile);
2239
- return lines;
2630
+ return uses;
2240
2631
  }
2241
2632
  function extractQuotedStringsAst(ts, source) {
2242
2633
  const sourceFile = ts.createSourceFile("generated.ts", source, ts.ScriptTarget.Latest, true);
@@ -2347,10 +2738,45 @@ function tsPublishSourceLiteral(ts, node) {
2347
2738
  const rawMetadata = tsObjectPropertyValue(ts, firstArg, "metadata");
2348
2739
  return tsStringLiteralText(ts, tsObjectPropertyValue(ts, rawMetadata, "source")) ?? tsStringLiteralText(ts, tsObjectPropertyValue(ts, secondArg, "source")) ?? tsStringLiteralText(ts, tsObjectPropertyValue(ts, thirdArg, "source"));
2349
2740
  }
2741
+ function singleFileTypeChecker(ts, sourceFile) {
2742
+ const options = {
2743
+ noLib: true,
2744
+ noResolve: true,
2745
+ target: ts.ScriptTarget.Latest
2746
+ };
2747
+ const host = ts.createCompilerHost(options, true);
2748
+ host.getSourceFile = (fileName) => fileName === sourceFile.fileName ? sourceFile : void 0;
2749
+ host.fileExists = (fileName) => fileName === sourceFile.fileName;
2750
+ host.readFile = (fileName) => fileName === sourceFile.fileName ? sourceFile.text : void 0;
2751
+ return ts.createProgram([sourceFile.fileName], options, host).getTypeChecker();
2752
+ }
2753
+ function propertyAccessPath(ts, node) {
2754
+ const segments = [];
2755
+ let current = node;
2756
+ while (ts.isPropertyAccessExpression(current)) {
2757
+ segments.unshift(current.name.text);
2758
+ current = current.expression;
2759
+ }
2760
+ if (!ts.isIdentifier(current)) return void 0;
2761
+ segments.unshift(current.text);
2762
+ return { root: current, segments };
2763
+ }
2764
+ function isRuntimeIdentifierReference(ts, node) {
2765
+ if (ts.isPropertyAccessExpression(node.parent) && node.parent.name === node) return false;
2766
+ return ts.isExpressionNode(node) && !ts.isInTypeQuery(node) || ts.isShorthandPropertyAssignment(node.parent) && node.parent.name === node;
2767
+ }
2768
+ function hasLocalDeclaration(ts, checker, sourceFile, node) {
2769
+ const shorthand = ts.isShorthandPropertyAssignment(node.parent) && node.parent.name === node;
2770
+ const symbol = shorthand ? checker.getShorthandAssignmentValueSymbol(node.parent) : checker.getSymbolAtLocation(node);
2771
+ return Boolean(
2772
+ symbol?.declarations?.some((declaration) => declaration.getSourceFile() === sourceFile)
2773
+ );
2774
+ }
2350
2775
  function analyzeForbiddenGlobals(ts, source, filePath, layer, forbidden) {
2351
2776
  const entries = new Set(forbidden);
2352
2777
  if (entries.size === 0) return [];
2353
2778
  const sourceFile = ts.createSourceFile("generated.ts", source, ts.ScriptTarget.Latest, true);
2779
+ const checker = singleFileTypeChecker(ts, sourceFile);
2354
2780
  const violations = [];
2355
2781
  const flag = (name, node) => violations.push(
2356
2782
  violation("FORBIDDEN_GLOBAL", `${layer} must not use the ambient global "${name}".`, {
@@ -2362,12 +2788,24 @@ function analyzeForbiddenGlobals(ts, source, filePath, layer, forbidden) {
2362
2788
  })
2363
2789
  );
2364
2790
  const visit = (node) => {
2365
- if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression)) {
2366
- const dotted = `${node.expression.text}.${node.name.text}`;
2367
- if (entries.has(dotted)) flag(dotted, node);
2368
- else if (entries.has(node.expression.text)) flag(node.expression.text, node);
2369
- } else if ((ts.isCallExpression(node) || ts.isNewExpression(node)) && node.expression && ts.isIdentifier(node.expression) && entries.has(node.expression.text)) {
2370
- flag(node.expression.text, node);
2791
+ const nestedPropertyAccess = ts.isPropertyAccessExpression(node) && ts.isPropertyAccessExpression(node.parent) && node.parent.expression === node;
2792
+ if (ts.isPropertyAccessExpression(node) && !nestedPropertyAccess) {
2793
+ const path = propertyAccessPath(ts, node);
2794
+ if (path && !hasLocalDeclaration(ts, checker, sourceFile, path.root)) {
2795
+ const explicitGlobalThis = path.segments[0] === "globalThis";
2796
+ const normalized = explicitGlobalThis ? path.segments.slice(1) : path.segments;
2797
+ let match;
2798
+ for (let length = normalized.length; length >= (explicitGlobalThis ? 1 : 2); length -= 1) {
2799
+ const candidate = normalized.slice(0, length).join(".");
2800
+ if (entries.has(candidate)) {
2801
+ match = candidate;
2802
+ break;
2803
+ }
2804
+ }
2805
+ if (match) flag(match, node);
2806
+ }
2807
+ } else if (ts.isIdentifier(node) && entries.has(node.text) && isRuntimeIdentifierReference(ts, node) && !hasLocalDeclaration(ts, checker, sourceFile, node)) {
2808
+ flag(node.text, node);
2371
2809
  }
2372
2810
  ts.forEachChild(node, visit);
2373
2811
  };
@@ -2444,15 +2882,16 @@ function createAICodeGate(options = {}) {
2444
2882
  const gateContext = context;
2445
2883
  const filePath = gateContext?.filePath;
2446
2884
  const contextLayer = gateContext?.layer;
2447
- const moduleSpecifiers = options.typescript ? extractModuleSpecifiersAst(options.typescript, source) : extractModuleSpecifiers(source);
2885
+ const moduleSpecifiers2 = options.typescript ? extractModuleSpecifiersAst(options.typescript, source) : extractModuleSpecifiers(source);
2448
2886
  const quotedStrings = options.typescript ? extractQuotedStringsAst(options.typescript, source) : extractQuotedStrings(source);
2449
2887
  if (options.typescript && !options.allowNonLiteralDynamicImport?.(filePath)) {
2450
- for (const line of nonLiteralDynamicImportLines(options.typescript, source)) {
2888
+ for (const dependency of nonLiteralDynamicDependencies(options.typescript, source)) {
2889
+ const isRequire = dependency.kind === "require";
2451
2890
  violations.push(
2452
2891
  violation(
2453
- "DYNAMIC_IMPORT_NOT_ALLOWLISTED",
2454
- "Non-literal dynamic import cannot be resolved statically; add the reviewed file to dynamicImportAllowlist.",
2455
- { line, filePath }
2892
+ isRequire ? "DYNAMIC_REQUIRE_NOT_ALLOWLISTED" : "DYNAMIC_IMPORT_NOT_ALLOWLISTED",
2893
+ `Non-literal ${isRequire ? "require call" : "dynamic import"} cannot be resolved statically; add the reviewed file to dynamicImportAllowlist.`,
2894
+ { line: dependency.line, filePath }
2456
2895
  )
2457
2896
  );
2458
2897
  }
@@ -2482,7 +2921,7 @@ function createAICodeGate(options = {}) {
2482
2921
  );
2483
2922
  }
2484
2923
  }
2485
- for (const specifier of moduleSpecifiers) {
2924
+ for (const specifier of moduleSpecifiers2) {
2486
2925
  const targetHit = options.resolveImportTarget?.(specifier.value, filePath) ?? (options.resolveImportLayer ? { layer: options.resolveImportLayer(specifier.value, filePath) } : void 0);
2487
2926
  const sourceHit = typeof filePath === "string" ? options.resolveImportTarget?.(filePath) ?? (options.resolveImportLayer ? { layer: contextLayer, relPath: void 0 } : void 0) : void 0;
2488
2927
  const targetLayer = targetHit?.layer;
@@ -2681,6 +3120,214 @@ function createAICodeGate(options = {}) {
2681
3120
  };
2682
3121
  }
2683
3122
 
3123
+ // src/domain/analysis.ts
3124
+ var ANALYSIS_IR_SCHEMA_VERSION = "1.0";
3125
+ function deterministicHash(value) {
3126
+ let hash = 2166136261;
3127
+ for (let index = 0; index < value.length; index += 1) {
3128
+ hash ^= value.charCodeAt(index);
3129
+ hash = Math.imul(hash, 16777619);
3130
+ }
3131
+ return `fnv1a-${(hash >>> 0).toString(16).padStart(8, "0")}`;
3132
+ }
3133
+ function stableSerialize(value) {
3134
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
3135
+ if (Array.isArray(value)) return `[${value.map(stableSerialize).join(",")}]`;
3136
+ const object = value;
3137
+ return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${stableSerialize(object[key])}`).join(",")}}`;
3138
+ }
3139
+
3140
+ // src/kernel/analysis.ts
3141
+ function loadContract(input, source) {
3142
+ const loaded = typeof input === "string" ? parseArkConfigJson(input, source) : loadArkConfigContract(input, source);
3143
+ return { ...loaded, policyHash: deterministicHash(stableSerialize(loaded.config)) };
3144
+ }
3145
+ function normalizePath(value) {
3146
+ return value.replace(/\\/g, "/").replace(/^\.\//, "");
3147
+ }
3148
+ function isIdentifierCharacter(value) {
3149
+ return value !== void 0 && /[A-Za-z0-9_$]/.test(value);
3150
+ }
3151
+ function skipWhitespace(source, index) {
3152
+ while (index < source.length && /\s/.test(source[index])) index += 1;
3153
+ return index;
3154
+ }
3155
+ function readString(source, index) {
3156
+ const quote = source[index];
3157
+ if (quote !== "'" && quote !== '"') return void 0;
3158
+ const start = index;
3159
+ let value = "";
3160
+ for (index += 1; index < source.length; index += 1) {
3161
+ const current = source[index];
3162
+ if (current === quote) {
3163
+ return { value, offset: start, excerpt: source.slice(start, index + 1) };
3164
+ }
3165
+ if (current === "\\" && index + 1 < source.length) {
3166
+ value += source[index + 1];
3167
+ index += 1;
3168
+ } else {
3169
+ value += current;
3170
+ }
3171
+ }
3172
+ return void 0;
3173
+ }
3174
+ function isWordAt(source, word, index) {
3175
+ return source.startsWith(word, index) && !isIdentifierCharacter(source[index - 1]) && !isIdentifierCharacter(source[index + word.length]);
3176
+ }
3177
+ function specifierAfterImport(source, index) {
3178
+ index = skipWhitespace(source, index + "import".length);
3179
+ if (source[index] === "(") return readString(source, skipWhitespace(source, index + 1));
3180
+ return specifierInStaticStatement(source, index, true);
3181
+ }
3182
+ function specifierAfterExport(source, index) {
3183
+ return specifierInStaticStatement(source, index + "export".length, false);
3184
+ }
3185
+ function specifierInStaticStatement(source, index, allowDirectSpecifier) {
3186
+ for (; index < source.length; index += 1) {
3187
+ if (source[index] === ";") return void 0;
3188
+ if (isWordAt(source, "from", index)) {
3189
+ return readString(source, skipWhitespace(source, index + "from".length));
3190
+ }
3191
+ if (allowDirectSpecifier && (source[index] === "'" || source[index] === '"')) {
3192
+ return readString(source, index);
3193
+ }
3194
+ if (index > 0 && (isWordAt(source, "import", index) || isWordAt(source, "export", index))) {
3195
+ return void 0;
3196
+ }
3197
+ }
3198
+ return void 0;
3199
+ }
3200
+ function moduleSpecifiers(source) {
3201
+ const result = [];
3202
+ for (let index = 0; index < source.length; index += 1) {
3203
+ const current = source[index];
3204
+ if (current === "/" && source[index + 1] === "/") {
3205
+ index = source.indexOf("\n", index + 2);
3206
+ if (index < 0) break;
3207
+ continue;
3208
+ }
3209
+ if (current === "/" && source[index + 1] === "*") {
3210
+ const end = source.indexOf("*/", index + 2);
3211
+ if (end < 0) break;
3212
+ index = end + 1;
3213
+ continue;
3214
+ }
3215
+ if (current === "'" || current === '"' || current === "`") {
3216
+ const string = readString(source, index);
3217
+ if (string) index = string.offset + string.excerpt.length - 1;
3218
+ continue;
3219
+ }
3220
+ const specifier = isWordAt(source, "import", index) ? specifierAfterImport(source, index) : isWordAt(source, "export", index) ? specifierAfterExport(source, index) : void 0;
3221
+ if (specifier) result.push(specifier);
3222
+ }
3223
+ return result;
3224
+ }
3225
+ function importEdges(file, files) {
3226
+ const edges = [];
3227
+ for (const moduleSpecifier of moduleSpecifiers(file.content)) {
3228
+ const specifier = moduleSpecifier.value;
3229
+ if (!specifier.startsWith(".")) continue;
3230
+ const line = file.content.slice(0, moduleSpecifier.offset).split("\n").length;
3231
+ const evidence = {
3232
+ kind: "import",
3233
+ file: file.path,
3234
+ line,
3235
+ excerpt: moduleSpecifier.excerpt
3236
+ };
3237
+ const target = resolveSpecifier(file.path, specifier, files);
3238
+ edges.push({
3239
+ from: file.path,
3240
+ specifier,
3241
+ to: target?.path ?? null,
3242
+ resolution: target ? "resolved" : "unresolved",
3243
+ fromLayer: file.layer,
3244
+ toLayer: target?.layer ?? null,
3245
+ evidence
3246
+ });
3247
+ }
3248
+ return edges;
3249
+ }
3250
+ function resolveSpecifier(from, specifier, files) {
3251
+ const segments = from.split("/");
3252
+ segments.pop();
3253
+ for (const segment of specifier.split("/")) {
3254
+ if (segment === "." || segment === "") continue;
3255
+ if (segment === "..") segments.pop();
3256
+ else segments.push(segment);
3257
+ }
3258
+ const base = segments.join("/");
3259
+ for (const candidate of [base, `${base}.ts`, `${base}.tsx`, `${base}.mts`, `${base}.cts`, `${base}/index.ts`, `${base}/index.tsx`]) {
3260
+ const found = files.get(candidate);
3261
+ if (found) return found;
3262
+ }
3263
+ return void 0;
3264
+ }
3265
+ function violationsFor(edges, config) {
3266
+ const violations = [];
3267
+ for (const edge of edges) {
3268
+ if (!edge.to || !edge.fromLayer || !edge.toLayer) continue;
3269
+ const rule = findDeniedEdgeRule(config.rules, edge.fromLayer, edge.toLayer, {
3270
+ fromPath: edge.from,
3271
+ toPath: edge.to,
3272
+ layers: config.layers
3273
+ });
3274
+ if (!rule) continue;
3275
+ violations.push({
3276
+ ruleId: `layer-dependency:${rule.from}->${rule.to}`,
3277
+ message: rule.message ?? `${rule.from} must not depend on ${rule.to}.`,
3278
+ edge,
3279
+ evidence: edge.evidence
3280
+ });
3281
+ }
3282
+ return violations;
3283
+ }
3284
+ function analyzeProject(input) {
3285
+ const files = input.files.map((inputFile) => {
3286
+ const path = normalizePath(inputFile.path);
3287
+ return {
3288
+ path,
3289
+ content: inputFile.content,
3290
+ contentHash: deterministicHash(inputFile.content),
3291
+ layer: layerForRelativePath(path, input.contract.config.layers) ?? null
3292
+ };
3293
+ }).sort((left, right) => left.path.localeCompare(right.path));
3294
+ const fileByPath = new Map(files.map((file) => [file.path, file]));
3295
+ const edges = files.flatMap((file) => importEdges(file, fileByPath));
3296
+ const capabilityUses = [];
3297
+ const violations = violationsFor(edges, input.contract.config);
3298
+ return {
3299
+ ir: {
3300
+ schemaVersion: ANALYSIS_IR_SCHEMA_VERSION,
3301
+ policyHash: input.contract.policyHash,
3302
+ compilerOptionsHash: deterministicHash(stableSerialize(input.compilerOptions ?? {})),
3303
+ files,
3304
+ layers: input.contract.config.layers.map((layer) => layer.name),
3305
+ edges,
3306
+ capabilityUses,
3307
+ violations
3308
+ }
3309
+ };
3310
+ }
3311
+ function analyzeChange(input) {
3312
+ const files = new Map(input.files.map((file) => [normalizePath(file.path), file]));
3313
+ for (const change of input.changes) {
3314
+ const path = normalizePath(change.path);
3315
+ if ("delete" in change && change.delete) files.delete(path);
3316
+ else if ("content" in change) files.set(path, { path, content: change.content });
3317
+ }
3318
+ return analyzeProject({
3319
+ contract: input.contract,
3320
+ files: [...files.values()],
3321
+ compilerOptions: input.compilerOptions
3322
+ });
3323
+ }
3324
+ function explainViolation(violation2) {
3325
+ const location = `${violation2.evidence.file}:${violation2.evidence.line}`;
3326
+ if (!violation2.edge) return `${violation2.ruleId} at ${location}: ${violation2.message}`;
3327
+ const target = violation2.edge.to ?? violation2.edge.specifier;
3328
+ return `${violation2.ruleId} at ${location}: ${violation2.edge.from} imports ${target}. ${violation2.message}`;
3329
+ }
3330
+
2684
3331
  // src/kernel/projections/ProjectionRegistry.ts
2685
3332
  var InMemoryReadModelStore = class {
2686
3333
  states = /* @__PURE__ */ new Map();
@@ -2989,22 +3636,13 @@ var WorkflowEngineImpl = class {
2989
3636
  for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
2990
3637
  snapshot.attempts[step.name] = attempt;
2991
3638
  await this.store.save(snapshot);
3639
+ let result;
2992
3640
  try {
2993
- const result = await withTimeout(
3641
+ result = await withTimeout(
2994
3642
  (signal) => Promise.resolve(step.execute(snapshot.context, this.bus, signal)),
2995
3643
  step.timeoutMs,
2996
3644
  step.name
2997
3645
  );
2998
- if (result) Object.assign(snapshot.context, result);
2999
- snapshot.completedSteps.push(step.name);
3000
- snapshot.currentStep = void 0;
3001
- snapshot.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
3002
- await this.store.save(snapshot);
3003
- await this.audit("workflow.step.completed", snapshot, {
3004
- step: step.name,
3005
- attempt
3006
- });
3007
- return;
3008
3646
  } catch (err) {
3009
3647
  if (attempt < maxAttempts) {
3010
3648
  if (retry.delayMs) await sleep(retry.delayMs);
@@ -3020,6 +3658,16 @@ var WorkflowEngineImpl = class {
3020
3658
  });
3021
3659
  throw err;
3022
3660
  }
3661
+ if (result) Object.assign(snapshot.context, result);
3662
+ snapshot.completedSteps.push(step.name);
3663
+ snapshot.currentStep = void 0;
3664
+ snapshot.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
3665
+ await this.store.save(snapshot);
3666
+ await this.audit("workflow.step.completed", snapshot, {
3667
+ step: step.name,
3668
+ attempt
3669
+ });
3670
+ return;
3023
3671
  }
3024
3672
  throw new Error(`Workflow step "${step.name}" did not complete.`);
3025
3673
  }
@@ -3210,6 +3858,7 @@ function createLenientArkKernel(options = {}) {
3210
3858
  });
3211
3859
  }
3212
3860
  export {
3861
+ ANALYSIS_IR_SCHEMA_VERSION,
3213
3862
  DEFAULT_MAX_HISTORY_SIZE,
3214
3863
  EventContractRegistryImpl,
3215
3864
  EventContractViolationError,
@@ -3227,6 +3876,8 @@ export {
3227
3876
  SourceMetadataOverrideError,
3228
3877
  UnknownEventSourceError,
3229
3878
  UnregisteredIntentError,
3879
+ analyzeChange,
3880
+ analyzeProject,
3230
3881
  architecturalPolicies,
3231
3882
  buildPublishPolicyContext,
3232
3883
  checkAdapterGovernance,
@@ -3261,8 +3912,12 @@ export {
3261
3912
  definePolicy,
3262
3913
  definePort,
3263
3914
  definePublishPolicy,
3915
+ deterministicHash,
3264
3916
  elevenLayerProfile,
3917
+ explainViolation,
3265
3918
  isLayerPolicy,
3919
+ loadContract,
3920
+ stableSerialize,
3266
3921
  syncRegistryToGraph,
3267
3922
  validateIntentName,
3268
3923
  version