arkgate 2.9.2 → 2.11.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 (50) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/README.md +12 -2
  3. package/SECURITY.md +3 -4
  4. package/bin/ark-check.mjs +41 -16
  5. package/bin/ark-mcp.mjs +335 -111
  6. package/bin/ark.mjs +35 -5
  7. package/bin/lib/agent-gates.mjs +161 -8
  8. package/bin/lib/architecture-scan.mjs +23 -1
  9. package/bin/lib/auto-patch.mjs +264 -0
  10. package/bin/lib/baseline-key.mjs +17 -0
  11. package/bin/lib/config-warnings.mjs +22 -0
  12. package/bin/lib/core-layers.mjs +7 -0
  13. package/bin/lib/core-ratchet.mjs +3 -7
  14. package/bin/lib/doctor-plan.mjs +83 -5
  15. package/bin/lib/port-proof.mjs +309 -0
  16. package/bin/lib/prepare-write.mjs +130 -0
  17. package/bin/lib/remediation.mjs +21 -0
  18. package/bin/lib/safety-diagnostics.mjs +263 -0
  19. package/bin/lib/scan-files.mjs +51 -6
  20. package/bin/lib/violations.mjs +3 -3
  21. package/dist/index.cjs +115 -11
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.cts +5 -3
  24. package/dist/index.d.ts +5 -3
  25. package/dist/index.js +115 -11
  26. package/dist/index.js.map +1 -1
  27. package/dist/nestjs/index.cjs +18 -5
  28. package/dist/nestjs/index.cjs.map +1 -1
  29. package/dist/nestjs/index.d.cts +1 -1
  30. package/dist/nestjs/index.d.ts +1 -1
  31. package/dist/nestjs/index.js +18 -5
  32. package/dist/nestjs/index.js.map +1 -1
  33. package/dist/runtime/index.cjs +115 -11
  34. package/dist/runtime/index.cjs.map +1 -1
  35. package/dist/runtime/index.d.cts +1 -1
  36. package/dist/runtime/index.d.ts +1 -1
  37. package/dist/runtime/index.js +115 -11
  38. package/dist/runtime/index.js.map +1 -1
  39. package/dist/{types-D6Q8WHes.d.cts → types-BZ17b9i5.d.cts} +5 -1
  40. package/dist/{types-D6Q8WHes.d.ts → types-BZ17b9i5.d.ts} +5 -1
  41. package/docs/agent-guide.md +15 -1
  42. package/docs/ai-gates.md +63 -5
  43. package/docs/enthusiast/how-to-agent-gates.md +8 -0
  44. package/docs/enthusiast/reference-commands.md +1 -1
  45. package/docs/package-surface.md +2 -2
  46. package/docs/production-hardening.md +5 -0
  47. package/package.json +6 -2
  48. package/server.json +2 -2
  49. package/templates/skills/ark-explain.md +1 -1
  50. package/templates/skills/ark-loop.md +2 -1
package/dist/index.d.cts CHANGED
@@ -1,8 +1,8 @@
1
- import { I as IntentRegistry, a as IntentName, D as DefineIntentOptions, b as IntentCreator, P as PolicyViolation, c as PolicySeverity, d as PolicyEnforcementMode, e as Policy, f as CreateArchitectureProfileOptions, g as ArchitectureProfile, h as ArkCheckConfig, i as CreateArchitectureProfileFromArkConfigOptions, j as CreateElevenLayerArkConfigOptions, k as DependencyGraph, G as GraphEdge, l as IntentRelationship, m as AuditStore, n as AuditRecord, o as AuditQuery, p as CreateAuditTrailOptions, q as AuditTrail, E as EventContractRegistry, r as EventContract, s as DomainEvent, t as EventContractValidationResult, O as OutboxStore, u as OutboxRecord, v as OutboxStatus, w as EventBusOptions, x as EventBus, y as CreateObservabilityReporterOptions, z as ObservabilityReporter, M as MetadataRegistry, R as ReadModelStore, B as CreateProjectionRegistryOptions, F as ProjectionRegistry, H as PolicyEngine, J as ArkManifest, W as WorkflowStore, S as SagaContext, K as WorkflowSnapshot, L as SagaDefinition, N as CreateWorkflowEngineOptions, Q as SagaInstance, T as WorkflowEngine, C as CreateArkKernelOptions, A as ArkKernel, U as ArkKernelConfig, V as CreateArkKernelFromConfigOptions, X as TraceRecordType, Y as TraceRecord, Z as ObservabilityDriftReport } from './types-D6Q8WHes.cjs';
2
- export { _ as ArchitectureLayer, $ as ArchitectureLayerConfig, a0 as ArchitectureRule, a1 as ArkManifestArchitecture, a2 as ArkManifestData, a3 as ArkManifestEntityLink, a4 as ArkManifestGraph, a5 as ArkManifestIntent, a6 as ArkManifestPolicy, a7 as ArkManifestProjection, a8 as AuditRecordInput, a9 as AuditRecordType, aa as CorrelationId, ab as EntityMeta, ac as EventContractIssue, ad as EventHandler, ae as EventInterceptionInfo, af as EventInterceptor, ag as EventInterceptorContext, ah as EventMetadata, ai as EventPayloadPatch, aj as EventPayloadSchema, ak as EventPublisher, al as EventSchemaField, am as EventSchemaFieldType, an as FieldMeta, ao as GraphNode, ap as IntentRelationshipKind, aq as ObservabilityFlow, ar as ObservedLayerFlowMode, as as PolicyEvaluationResult, at as ProjectionCheckpoint, au as ProjectionDefinition, av as PublishedEventRecord, aw as RetryPolicy, ax as SagaStatus, ay as SagaStep, az as TraceSink, aA as Unsubscribe, aB as WorkflowDefinition, aC as WorkflowStatus, aD as WorkflowStep } from './types-D6Q8WHes.cjs';
1
+ import { I as IntentRegistry, a as IntentName, D as DefineIntentOptions, b as IntentCreator, P as PolicyViolation, c as PolicySeverity, d as PolicyEnforcementMode, e as Policy, f as CreateArchitectureProfileOptions, g as ArchitectureProfile, h as ArkCheckConfig, i as CreateArchitectureProfileFromArkConfigOptions, j as CreateElevenLayerArkConfigOptions, k as DependencyGraph, G as GraphEdge, l as IntentRelationship, m as AuditStore, n as AuditRecord, o as AuditQuery, p as CreateAuditTrailOptions, q as AuditTrail, E as EventContractRegistry, r as EventContract, s as DomainEvent, t as EventContractValidationResult, O as OutboxStore, u as OutboxRecord, v as OutboxStatus, w as EventBusOptions, x as EventBus, y as CreateObservabilityReporterOptions, z as ObservabilityReporter, M as MetadataRegistry, R as ReadModelStore, B as CreateProjectionRegistryOptions, F as ProjectionRegistry, H as PolicyEngine, J as ArkManifest, W as WorkflowStore, S as SagaContext, K as WorkflowSnapshot, L as SagaDefinition, N as CreateWorkflowEngineOptions, Q as SagaInstance, T as WorkflowEngine, C as CreateArkKernelOptions, A as ArkKernel, U as ArkKernelConfig, V as CreateArkKernelFromConfigOptions, X as TraceRecordType, Y as TraceRecord, Z as ObservabilityDriftReport } from './types-BZ17b9i5.cjs';
2
+ export { _ as ArchitectureLayer, $ as ArchitectureLayerConfig, a0 as ArchitectureRule, a1 as ArkManifestArchitecture, a2 as ArkManifestData, a3 as ArkManifestEntityLink, a4 as ArkManifestGraph, a5 as ArkManifestIntent, a6 as ArkManifestPolicy, a7 as ArkManifestProjection, a8 as AuditRecordInput, a9 as AuditRecordType, aa as CorrelationId, ab as EntityMeta, ac as EventContractIssue, ad as EventHandler, ae as EventInterceptionInfo, af as EventInterceptor, ag as EventInterceptorContext, ah as EventMetadata, ai as EventPayloadPatch, aj as EventPayloadSchema, ak as EventPublisher, al as EventSchemaField, am as EventSchemaFieldType, an as FieldMeta, ao as GraphNode, ap as IntentRelationshipKind, aq as ObservabilityFlow, ar as ObservedLayerFlowMode, as as PolicyEvaluationResult, at as ProjectionCheckpoint, au as ProjectionDefinition, av as PublishedEventRecord, aw as RetryPolicy, ax as SagaStatus, ay as SagaStep, az as TraceSink, aA as Unsubscribe, aB as WorkflowDefinition, aC as WorkflowStatus, aD as WorkflowStep } from './types-BZ17b9i5.cjs';
3
3
 
4
4
  /** ArkGate library version — single source of truth. */
5
- declare const version = "2.9.2";
5
+ declare const version = "2.11.0";
6
6
 
7
7
  /**
8
8
  * defineIntent
@@ -603,6 +603,8 @@ interface AICodeGateOptions<Context = AICodeGateContext> {
603
603
  name: string;
604
604
  patterns?: string[];
605
605
  }>;
606
+ /** Explicit file-level escape hatch for reviewed non-literal dynamic imports. */
607
+ allowNonLiteralDynamicImport?: (filePath?: string) => boolean;
606
608
  }
607
609
  declare function createAICodeGate<Context = AICodeGateContext>(options?: AICodeGateOptions<Context>): AICodeGate<Context>;
608
610
 
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { I as IntentRegistry, a as IntentName, D as DefineIntentOptions, b as IntentCreator, P as PolicyViolation, c as PolicySeverity, d as PolicyEnforcementMode, e as Policy, f as CreateArchitectureProfileOptions, g as ArchitectureProfile, h as ArkCheckConfig, i as CreateArchitectureProfileFromArkConfigOptions, j as CreateElevenLayerArkConfigOptions, k as DependencyGraph, G as GraphEdge, l as IntentRelationship, m as AuditStore, n as AuditRecord, o as AuditQuery, p as CreateAuditTrailOptions, q as AuditTrail, E as EventContractRegistry, r as EventContract, s as DomainEvent, t as EventContractValidationResult, O as OutboxStore, u as OutboxRecord, v as OutboxStatus, w as EventBusOptions, x as EventBus, y as CreateObservabilityReporterOptions, z as ObservabilityReporter, M as MetadataRegistry, R as ReadModelStore, B as CreateProjectionRegistryOptions, F as ProjectionRegistry, H as PolicyEngine, J as ArkManifest, W as WorkflowStore, S as SagaContext, K as WorkflowSnapshot, L as SagaDefinition, N as CreateWorkflowEngineOptions, Q as SagaInstance, T as WorkflowEngine, C as CreateArkKernelOptions, A as ArkKernel, U as ArkKernelConfig, V as CreateArkKernelFromConfigOptions, X as TraceRecordType, Y as TraceRecord, Z as ObservabilityDriftReport } from './types-D6Q8WHes.js';
2
- export { _ as ArchitectureLayer, $ as ArchitectureLayerConfig, a0 as ArchitectureRule, a1 as ArkManifestArchitecture, a2 as ArkManifestData, a3 as ArkManifestEntityLink, a4 as ArkManifestGraph, a5 as ArkManifestIntent, a6 as ArkManifestPolicy, a7 as ArkManifestProjection, a8 as AuditRecordInput, a9 as AuditRecordType, aa as CorrelationId, ab as EntityMeta, ac as EventContractIssue, ad as EventHandler, ae as EventInterceptionInfo, af as EventInterceptor, ag as EventInterceptorContext, ah as EventMetadata, ai as EventPayloadPatch, aj as EventPayloadSchema, ak as EventPublisher, al as EventSchemaField, am as EventSchemaFieldType, an as FieldMeta, ao as GraphNode, ap as IntentRelationshipKind, aq as ObservabilityFlow, ar as ObservedLayerFlowMode, as as PolicyEvaluationResult, at as ProjectionCheckpoint, au as ProjectionDefinition, av as PublishedEventRecord, aw as RetryPolicy, ax as SagaStatus, ay as SagaStep, az as TraceSink, aA as Unsubscribe, aB as WorkflowDefinition, aC as WorkflowStatus, aD as WorkflowStep } from './types-D6Q8WHes.js';
1
+ import { I as IntentRegistry, a as IntentName, D as DefineIntentOptions, b as IntentCreator, P as PolicyViolation, c as PolicySeverity, d as PolicyEnforcementMode, e as Policy, f as CreateArchitectureProfileOptions, g as ArchitectureProfile, h as ArkCheckConfig, i as CreateArchitectureProfileFromArkConfigOptions, j as CreateElevenLayerArkConfigOptions, k as DependencyGraph, G as GraphEdge, l as IntentRelationship, m as AuditStore, n as AuditRecord, o as AuditQuery, p as CreateAuditTrailOptions, q as AuditTrail, E as EventContractRegistry, r as EventContract, s as DomainEvent, t as EventContractValidationResult, O as OutboxStore, u as OutboxRecord, v as OutboxStatus, w as EventBusOptions, x as EventBus, y as CreateObservabilityReporterOptions, z as ObservabilityReporter, M as MetadataRegistry, R as ReadModelStore, B as CreateProjectionRegistryOptions, F as ProjectionRegistry, H as PolicyEngine, J as ArkManifest, W as WorkflowStore, S as SagaContext, K as WorkflowSnapshot, L as SagaDefinition, N as CreateWorkflowEngineOptions, Q as SagaInstance, T as WorkflowEngine, C as CreateArkKernelOptions, A as ArkKernel, U as ArkKernelConfig, V as CreateArkKernelFromConfigOptions, X as TraceRecordType, Y as TraceRecord, Z as ObservabilityDriftReport } from './types-BZ17b9i5.js';
2
+ export { _ as ArchitectureLayer, $ as ArchitectureLayerConfig, a0 as ArchitectureRule, a1 as ArkManifestArchitecture, a2 as ArkManifestData, a3 as ArkManifestEntityLink, a4 as ArkManifestGraph, a5 as ArkManifestIntent, a6 as ArkManifestPolicy, a7 as ArkManifestProjection, a8 as AuditRecordInput, a9 as AuditRecordType, aa as CorrelationId, ab as EntityMeta, ac as EventContractIssue, ad as EventHandler, ae as EventInterceptionInfo, af as EventInterceptor, ag as EventInterceptorContext, ah as EventMetadata, ai as EventPayloadPatch, aj as EventPayloadSchema, ak as EventPublisher, al as EventSchemaField, am as EventSchemaFieldType, an as FieldMeta, ao as GraphNode, ap as IntentRelationshipKind, aq as ObservabilityFlow, ar as ObservedLayerFlowMode, as as PolicyEvaluationResult, at as ProjectionCheckpoint, au as ProjectionDefinition, av as PublishedEventRecord, aw as RetryPolicy, ax as SagaStatus, ay as SagaStep, az as TraceSink, aA as Unsubscribe, aB as WorkflowDefinition, aC as WorkflowStatus, aD as WorkflowStep } from './types-BZ17b9i5.js';
3
3
 
4
4
  /** ArkGate library version — single source of truth. */
5
- declare const version = "2.9.2";
5
+ declare const version = "2.11.0";
6
6
 
7
7
  /**
8
8
  * defineIntent
@@ -603,6 +603,8 @@ interface AICodeGateOptions<Context = AICodeGateContext> {
603
603
  name: string;
604
604
  patterns?: string[];
605
605
  }>;
606
+ /** Explicit file-level escape hatch for reviewed non-literal dynamic imports. */
607
+ allowNonLiteralDynamicImport?: (filePath?: string) => boolean;
606
608
  }
607
609
  declare function createAICodeGate<Context = AICodeGateContext>(options?: AICodeGateOptions<Context>): AICodeGate<Context>;
608
610
 
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var version = "2.9.2";
2
+ var version = "2.11.0";
3
3
 
4
4
  // src/kernel/intent/IntentRegistry.ts
5
5
  var IntentRegistry = class {
@@ -2174,11 +2174,82 @@ function extractModuleSpecifiers(source) {
2174
2174
  let match;
2175
2175
  while ((match = pattern.re.exec(source)) !== null) {
2176
2176
  const index = match.index + match[0].indexOf(match[1]);
2177
- matches.push({ value: match[1], index, kind: pattern.kind });
2177
+ const raw = match[0];
2178
+ const typeOnly = pattern.kind === "import" && /\bimport\s+type\b/.test(raw) || pattern.kind === "export" && /\bexport\s+type\b/.test(raw);
2179
+ matches.push({ value: match[1], index, kind: pattern.kind, typeOnly });
2178
2180
  }
2179
2181
  }
2180
2182
  return matches.sort((a, b) => a.index - b.index);
2181
2183
  }
2184
+ function extractModuleSpecifiersAst(ts, source) {
2185
+ const sourceFile = ts.createSourceFile("generated.ts", source, ts.ScriptTarget.Latest, true);
2186
+ const matches = [];
2187
+ const push = (node, value, kind, typeOnly = false) => {
2188
+ matches.push({
2189
+ value,
2190
+ index: node.getStart(sourceFile),
2191
+ kind,
2192
+ typeOnly
2193
+ });
2194
+ };
2195
+ const visit = (node) => {
2196
+ if (ts.isImportDeclaration(node) && ts.isStringLiteralLike(node.moduleSpecifier)) {
2197
+ const clause = node.importClause;
2198
+ const namedBindings = clause?.namedBindings;
2199
+ const specifiersOnly = clause && !clause.name && namedBindings && ts.isNamedImports(namedBindings) && namedBindings.elements.length > 0 && namedBindings.elements.every((element) => element.isTypeOnly === true);
2200
+ push(
2201
+ node.moduleSpecifier,
2202
+ node.moduleSpecifier.text,
2203
+ "import",
2204
+ Boolean(clause?.isTypeOnly || specifiersOnly)
2205
+ );
2206
+ } else if (ts.isExportDeclaration(node) && ts.isStringLiteralLike(node.moduleSpecifier)) {
2207
+ const clause = node.exportClause;
2208
+ const specifiersOnly = clause && ts.isNamedExports(clause) && clause.elements.length > 0 && clause.elements.every((element) => element.isTypeOnly === true);
2209
+ push(
2210
+ node.moduleSpecifier,
2211
+ node.moduleSpecifier.text,
2212
+ "export",
2213
+ Boolean(node.isTypeOnly || specifiersOnly)
2214
+ );
2215
+ } else if (ts.isCallExpression(node) && node.arguments.length === 1) {
2216
+ const argument = node.arguments[0];
2217
+ const value = tsStringLiteralText(ts, argument);
2218
+ if (value !== void 0 && node.expression.kind === ts.SyntaxKind.ImportKeyword) {
2219
+ push(argument, value, "dynamic-import");
2220
+ } else if (value !== void 0 && ts.isIdentifier(node.expression) && node.expression.text === "require") {
2221
+ push(argument, value, "require");
2222
+ }
2223
+ }
2224
+ ts.forEachChild(node, visit);
2225
+ };
2226
+ visit(sourceFile);
2227
+ return matches.sort((a, b) => a.index - b.index);
2228
+ }
2229
+ function nonLiteralDynamicImportLines(ts, source) {
2230
+ const sourceFile = ts.createSourceFile("generated.ts", source, ts.ScriptTarget.Latest, true);
2231
+ const lines = [];
2232
+ 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);
2235
+ }
2236
+ ts.forEachChild(node, visit);
2237
+ };
2238
+ visit(sourceFile);
2239
+ return lines;
2240
+ }
2241
+ function extractQuotedStringsAst(ts, source) {
2242
+ const sourceFile = ts.createSourceFile("generated.ts", source, ts.ScriptTarget.Latest, true);
2243
+ const matches = [];
2244
+ const visit = (node) => {
2245
+ if (ts.isStringLiteralLike(node)) {
2246
+ matches.push({ value: node.text, index: node.getStart(sourceFile) });
2247
+ }
2248
+ ts.forEachChild(node, visit);
2249
+ };
2250
+ visit(sourceFile);
2251
+ return matches;
2252
+ }
2182
2253
  function looksLikeIntentName(s) {
2183
2254
  return /^(Domain|Application|Adapter|Workflow|Job|Presentation|Reporting|Metadata|Security|Audit|Observability|Kernel)\.[A-Za-z0-9_.]+$/.test(s);
2184
2255
  }
@@ -2373,6 +2444,19 @@ function createAICodeGate(options = {}) {
2373
2444
  const gateContext = context;
2374
2445
  const filePath = gateContext?.filePath;
2375
2446
  const contextLayer = gateContext?.layer;
2447
+ const moduleSpecifiers = options.typescript ? extractModuleSpecifiersAst(options.typescript, source) : extractModuleSpecifiers(source);
2448
+ const quotedStrings = options.typescript ? extractQuotedStringsAst(options.typescript, source) : extractQuotedStrings(source);
2449
+ if (options.typescript && !options.allowNonLiteralDynamicImport?.(filePath)) {
2450
+ for (const line of nonLiteralDynamicImportLines(options.typescript, source)) {
2451
+ violations.push(
2452
+ violation(
2453
+ "DYNAMIC_IMPORT_NOT_ALLOWLISTED",
2454
+ "Non-literal dynamic import cannot be resolved statically; add the reviewed file to dynamicImportAllowlist.",
2455
+ { line, filePath }
2456
+ )
2457
+ );
2458
+ }
2459
+ }
2376
2460
  const exemptFromInfraHeuristics = contextLayer !== void 0 && (explicitInfraLayers.has(contextLayer) || layerHasInfrastructureRole(contextLayer));
2377
2461
  const infraLayerEscapeHatch = contextLayer !== void 0 ? ` If "${contextLayer}" is an infrastructure layer, mark it in ark.config.json with "mayImportInfrastructure": true (or name it with an infra token like Adapters/Persistence/Repository).` : "";
2378
2462
  for (const pat of userForbidden) {
@@ -2398,7 +2482,7 @@ function createAICodeGate(options = {}) {
2398
2482
  );
2399
2483
  }
2400
2484
  }
2401
- for (const specifier of extractModuleSpecifiers(source)) {
2485
+ for (const specifier of moduleSpecifiers) {
2402
2486
  const targetHit = options.resolveImportTarget?.(specifier.value, filePath) ?? (options.resolveImportLayer ? { layer: options.resolveImportLayer(specifier.value, filePath) } : void 0);
2403
2487
  const sourceHit = typeof filePath === "string" ? options.resolveImportTarget?.(filePath) ?? (options.resolveImportLayer ? { layer: contextLayer, relPath: void 0 } : void 0) : void 0;
2404
2488
  const targetLayer = targetHit?.layer;
@@ -2414,6 +2498,9 @@ function createAICodeGate(options = {}) {
2414
2498
  }
2415
2499
  );
2416
2500
  if (blocked) {
2501
+ if (specifier.typeOnly && !blocked.peerIsolation) {
2502
+ continue;
2503
+ }
2417
2504
  const peer = Boolean(blocked.peerIsolation);
2418
2505
  violations.push(
2419
2506
  violation(
@@ -2427,7 +2514,11 @@ function createAICodeGate(options = {}) {
2427
2514
  fromLayer: contextLayer,
2428
2515
  toLayer: targetLayer,
2429
2516
  suggestion: peer ? "Extract shared code to a shared layer, or coordinate slices via events/ports \u2014 do not import across feature/context slices." : "Depend on a port/interface owned by an inner layer instead, or move this code to a layer allowed to make this import.",
2430
- details: { importKind: specifier.kind, peerIsolation: peer }
2517
+ details: {
2518
+ importKind: specifier.kind,
2519
+ peerIsolation: peer,
2520
+ ...specifier.typeOnly ? { typeOnly: true } : {}
2521
+ }
2431
2522
  }
2432
2523
  )
2433
2524
  );
@@ -2437,7 +2528,7 @@ function createAICodeGate(options = {}) {
2437
2528
  continue;
2438
2529
  }
2439
2530
  }
2440
- if (exemptFromInfraHeuristics) continue;
2531
+ if (exemptFromInfraHeuristics || specifier.typeOnly) continue;
2441
2532
  if (!hasInfrastructureToken(specifier.value) && !isKnownInfrastructurePackage(specifier.value)) {
2442
2533
  continue;
2443
2534
  }
@@ -2482,7 +2573,7 @@ function createAICodeGate(options = {}) {
2482
2573
  }
2483
2574
  }
2484
2575
  if (enforceAllowlist && intentNames.size > 0) {
2485
- for (const literal of extractQuotedStrings(source)) {
2576
+ for (const literal of quotedStrings) {
2486
2577
  if (looksLikeIntentName(literal.value) && !intentNames.has(literal.value)) {
2487
2578
  violations.push(
2488
2579
  violation(
@@ -2500,7 +2591,7 @@ function createAICodeGate(options = {}) {
2500
2591
  }
2501
2592
  }
2502
2593
  if (options.architectureProfile && contextLayer) {
2503
- for (const literal of extractQuotedStrings(source)) {
2594
+ for (const literal of quotedStrings) {
2504
2595
  if (!looksLikeIntentName(literal.value)) continue;
2505
2596
  const targetLayer = options.architectureProfile.resolveLayer(literal.value);
2506
2597
  if (!targetLayer) continue;
@@ -2776,15 +2867,18 @@ function sleep(ms) {
2776
2867
  });
2777
2868
  }
2778
2869
  async function withTimeout(operation, timeoutMs, stepName) {
2779
- if (timeoutMs === void 0) return operation;
2870
+ const controller = new AbortController();
2871
+ if (timeoutMs === void 0) return operation(controller.signal);
2780
2872
  let timeout;
2781
2873
  const timeoutPromise = new Promise((_, reject) => {
2782
2874
  timeout = setTimeout(() => {
2783
- reject(new Error(`Workflow step "${stepName}" timed out after ${timeoutMs}ms.`));
2875
+ const error = new Error(`Workflow step "${stepName}" timed out after ${timeoutMs}ms.`);
2876
+ controller.abort(error);
2877
+ reject(error);
2784
2878
  }, timeoutMs);
2785
2879
  });
2786
2880
  try {
2787
- return await Promise.race([operation, timeoutPromise]);
2881
+ return await Promise.race([operation(controller.signal), timeoutPromise]);
2788
2882
  } finally {
2789
2883
  if (timeout) clearTimeout(timeout);
2790
2884
  }
@@ -2819,6 +2913,15 @@ var WorkflowEngineImpl = class {
2819
2913
  if (this.definitions.has(definition.name)) {
2820
2914
  throw new Error(`Workflow "${definition.name}" is already registered.`);
2821
2915
  }
2916
+ const names = /* @__PURE__ */ new Set();
2917
+ for (const step of definition.steps) {
2918
+ if (names.has(step.name)) {
2919
+ throw new Error(
2920
+ `Workflow "${definition.name}" has duplicate step name "${step.name}".`
2921
+ );
2922
+ }
2923
+ names.add(step.name);
2924
+ }
2822
2925
  this.definitions.set(definition.name, definition);
2823
2926
  if (definition.startOn) {
2824
2927
  const trigger = definition.startOn;
@@ -2859,6 +2962,7 @@ var WorkflowEngineImpl = class {
2859
2962
  } catch (err) {
2860
2963
  await this.compensate(snapshot, definition.steps, err);
2861
2964
  snapshot.status = "failed";
2965
+ snapshot.currentStep = void 0;
2862
2966
  snapshot.error = errorMessage(err);
2863
2967
  snapshot.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2864
2968
  await this.store.save(snapshot);
@@ -2887,7 +2991,7 @@ var WorkflowEngineImpl = class {
2887
2991
  await this.store.save(snapshot);
2888
2992
  try {
2889
2993
  const result = await withTimeout(
2890
- Promise.resolve(step.execute(snapshot.context, this.bus)),
2994
+ (signal) => Promise.resolve(step.execute(snapshot.context, this.bus, signal)),
2891
2995
  step.timeoutMs,
2892
2996
  step.name
2893
2997
  );