@haibun/core 3.0.3 → 3.1.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 (209) hide show
  1. package/build/currentVersion.d.ts +1 -1
  2. package/build/currentVersion.js +1 -2
  3. package/build/lib/EventLogger.d.ts +22 -0
  4. package/build/lib/EventLogger.d.ts.map +1 -0
  5. package/build/lib/EventLogger.js +95 -0
  6. package/build/lib/EventLogger.js.map +1 -0
  7. package/build/lib/Logger.d.ts.map +1 -1
  8. package/build/lib/Logger.js +2 -1
  9. package/build/lib/Logger.js.map +1 -1
  10. package/build/lib/astepper.d.ts +11 -1
  11. package/build/lib/astepper.d.ts.map +1 -1
  12. package/build/lib/astepper.js +8 -0
  13. package/build/lib/astepper.js.map +1 -1
  14. package/build/lib/core/flow-runner.d.ts +25 -0
  15. package/build/lib/core/flow-runner.d.ts.map +1 -0
  16. package/build/lib/core/flow-runner.js +128 -0
  17. package/build/lib/core/flow-runner.js.map +1 -0
  18. package/build/lib/core/protocol.d.ts +58 -0
  19. package/build/lib/core/protocol.d.ts.map +1 -0
  20. package/build/lib/core/protocol.js +18 -0
  21. package/build/lib/core/protocol.js.map +1 -0
  22. package/build/lib/core-domains.d.ts +2 -16
  23. package/build/lib/core-domains.d.ts.map +1 -1
  24. package/build/lib/core-domains.js +46 -27
  25. package/build/lib/core-domains.js.map +1 -1
  26. package/build/lib/defs.d.ts +42 -11
  27. package/build/lib/defs.d.ts.map +1 -1
  28. package/build/lib/defs.js +6 -1
  29. package/build/lib/defs.js.map +1 -1
  30. package/build/lib/domain-types.d.ts +12 -1
  31. package/build/lib/domain-types.d.ts.map +1 -1
  32. package/build/lib/domain-types.js +63 -3
  33. package/build/lib/domain-types.js.map +1 -1
  34. package/build/lib/event-bridge.d.ts +28 -0
  35. package/build/lib/event-bridge.d.ts.map +1 -0
  36. package/build/lib/event-bridge.js +114 -0
  37. package/build/lib/event-bridge.js.map +1 -0
  38. package/build/lib/feature-variables.d.ts +14 -0
  39. package/build/lib/feature-variables.d.ts.map +1 -1
  40. package/build/lib/feature-variables.js +128 -6
  41. package/build/lib/feature-variables.js.map +1 -1
  42. package/build/lib/interfaces/logger.d.ts +19 -3
  43. package/build/lib/interfaces/logger.d.ts.map +1 -1
  44. package/build/lib/interfaces/logger.js +11 -1
  45. package/build/lib/interfaces/logger.js.map +1 -1
  46. package/build/lib/namedVars.d.ts.map +1 -1
  47. package/build/lib/namedVars.js +18 -10
  48. package/build/lib/namedVars.js.map +1 -1
  49. package/build/lib/populateActionArgs.d.ts +1 -1
  50. package/build/lib/populateActionArgs.d.ts.map +1 -1
  51. package/build/lib/populateActionArgs.js +11 -49
  52. package/build/lib/populateActionArgs.js.map +1 -1
  53. package/build/lib/test/TestSteps.d.ts +1 -0
  54. package/build/lib/test/TestSteps.d.ts.map +1 -1
  55. package/build/lib/test/TestStepsWithOptions.d.ts +1 -0
  56. package/build/lib/test/TestStepsWithOptions.d.ts.map +1 -1
  57. package/build/lib/test/lib.d.ts.map +1 -1
  58. package/build/lib/test/lib.js +2 -0
  59. package/build/lib/test/lib.js.map +1 -1
  60. package/build/lib/util/actualURI.js +1 -1
  61. package/build/lib/util/actualURI.js.map +1 -1
  62. package/build/lib/util/index.d.ts +11 -2
  63. package/build/lib/util/index.d.ts.map +1 -1
  64. package/build/lib/util/index.js +46 -2
  65. package/build/lib/util/index.js.map +1 -1
  66. package/build/lib/util/variables.d.ts +9 -0
  67. package/build/lib/util/variables.d.ts.map +1 -0
  68. package/build/lib/util/variables.js +40 -0
  69. package/build/lib/util/variables.js.map +1 -0
  70. package/build/lib/util/workspace-lib.d.ts.map +1 -1
  71. package/build/lib/util/workspace-lib.js +30 -3
  72. package/build/lib/util/workspace-lib.js.map +1 -1
  73. package/build/monitor/browser-stubs.d.ts +12 -0
  74. package/build/monitor/browser-stubs.d.ts.map +1 -0
  75. package/build/monitor/browser-stubs.js +20 -0
  76. package/build/monitor/browser-stubs.js.map +1 -0
  77. package/build/monitor/constants.d.ts +9 -0
  78. package/build/monitor/constants.d.ts.map +1 -0
  79. package/build/monitor/constants.js +9 -0
  80. package/build/monitor/constants.js.map +1 -0
  81. package/build/monitor/event-view.d.ts +40 -0
  82. package/build/monitor/event-view.d.ts.map +1 -0
  83. package/build/monitor/event-view.js +104 -0
  84. package/build/monitor/event-view.js.map +1 -0
  85. package/build/monitor/filters.d.ts +17 -0
  86. package/build/monitor/filters.d.ts.map +1 -0
  87. package/build/monitor/filters.js +32 -0
  88. package/build/monitor/filters.js.map +1 -0
  89. package/build/monitor/formatters.d.ts +27 -0
  90. package/build/monitor/formatters.d.ts.map +1 -0
  91. package/build/monitor/formatters.js +89 -0
  92. package/build/monitor/formatters.js.map +1 -0
  93. package/build/monitor/index.d.ts +11 -0
  94. package/build/monitor/index.d.ts.map +1 -0
  95. package/build/monitor/index.js +15 -0
  96. package/build/monitor/index.js.map +1 -0
  97. package/build/monitor/jit-serialization.d.ts +9 -0
  98. package/build/monitor/jit-serialization.d.ts.map +1 -0
  99. package/build/monitor/jit-serialization.js +73 -0
  100. package/build/monitor/jit-serialization.js.map +1 -0
  101. package/build/monitor/monitor-types.d.ts +119 -0
  102. package/build/monitor/monitor-types.d.ts.map +1 -0
  103. package/build/monitor/monitor-types.js +43 -0
  104. package/build/monitor/monitor-types.js.map +1 -0
  105. package/build/monitor/speculative-tracker.d.ts +20 -0
  106. package/build/monitor/speculative-tracker.d.ts.map +1 -0
  107. package/build/monitor/speculative-tracker.js +38 -0
  108. package/build/monitor/speculative-tracker.js.map +1 -0
  109. package/build/monitor/state.d.ts +31 -0
  110. package/build/monitor/state.d.ts.map +1 -0
  111. package/build/monitor/state.js +110 -0
  112. package/build/monitor/state.js.map +1 -0
  113. package/build/monitor/timer.d.ts +11 -0
  114. package/build/monitor/timer.d.ts.map +1 -0
  115. package/build/monitor/timer.js +13 -0
  116. package/build/monitor/timer.js.map +1 -0
  117. package/build/monitor/tree-builder.d.ts +25 -0
  118. package/build/monitor/tree-builder.d.ts.map +1 -0
  119. package/build/monitor/tree-builder.js +36 -0
  120. package/build/monitor/tree-builder.js.map +1 -0
  121. package/build/phases/Executor.d.ts.map +1 -1
  122. package/build/phases/Executor.js +102 -43
  123. package/build/phases/Executor.js.map +1 -1
  124. package/build/phases/Resolver.d.ts +2 -1
  125. package/build/phases/Resolver.d.ts.map +1 -1
  126. package/build/phases/Resolver.js +64 -1
  127. package/build/phases/Resolver.js.map +1 -1
  128. package/build/runner.d.ts.map +1 -1
  129. package/build/runner.js +5 -0
  130. package/build/runner.js.map +1 -1
  131. package/build/schema/events.d.ts +174 -0
  132. package/build/schema/events.d.ts.map +1 -0
  133. package/build/schema/events.js +55 -0
  134. package/build/schema/events.js.map +1 -0
  135. package/build/steps/activities-stepper.d.ts +55 -20
  136. package/build/steps/activities-stepper.d.ts.map +1 -1
  137. package/build/steps/activities-stepper.js +342 -207
  138. package/build/steps/activities-stepper.js.map +1 -1
  139. package/build/steps/conformance.d.ts +1 -0
  140. package/build/steps/conformance.d.ts.map +1 -1
  141. package/build/steps/console-monitor-stepper.d.ts +44 -0
  142. package/build/steps/console-monitor-stepper.d.ts.map +1 -0
  143. package/build/steps/console-monitor-stepper.js +106 -0
  144. package/build/steps/console-monitor-stepper.js.map +1 -0
  145. package/build/steps/debugger-stepper.d.ts +5 -3
  146. package/build/steps/debugger-stepper.d.ts.map +1 -1
  147. package/build/steps/debugger-stepper.js +35 -11
  148. package/build/steps/debugger-stepper.js.map +1 -1
  149. package/build/steps/haibun.d.ts +11 -18
  150. package/build/steps/haibun.d.ts.map +1 -1
  151. package/build/steps/haibun.js +51 -55
  152. package/build/steps/haibun.js.map +1 -1
  153. package/build/steps/lib/tts.d.ts.map +1 -1
  154. package/build/steps/lib/tts.js +2 -1
  155. package/build/steps/lib/tts.js.map +1 -1
  156. package/build/steps/logic-stepper.d.ts +42 -0
  157. package/build/steps/logic-stepper.d.ts.map +1 -0
  158. package/build/steps/logic-stepper.js +143 -0
  159. package/build/steps/logic-stepper.js.map +1 -0
  160. package/build/steps/narrator.d.ts.map +1 -1
  161. package/build/steps/narrator.js +1 -1
  162. package/build/steps/narrator.js.map +1 -1
  163. package/build/steps/parse.d.ts +1 -0
  164. package/build/steps/parse.d.ts.map +1 -1
  165. package/build/steps/variables-stepper.d.ts +11 -71
  166. package/build/steps/variables-stepper.d.ts.map +1 -1
  167. package/build/steps/variables-stepper.js +534 -84
  168. package/build/steps/variables-stepper.js.map +1 -1
  169. package/package.json +16 -3
  170. package/build/applyEffectFeatures.d.ts +0 -4
  171. package/build/applyEffectFeatures.d.ts.map +0 -1
  172. package/build/applyEffectFeatures.js +0 -31
  173. package/build/applyEffectFeatures.js.map +0 -1
  174. package/build/jsprolog/converter.d.ts +0 -9
  175. package/build/jsprolog/converter.d.ts.map +0 -1
  176. package/build/jsprolog/converter.js +0 -42
  177. package/build/jsprolog/converter.js.map +0 -1
  178. package/build/jsprolog/stepper-utils.d.ts +0 -8
  179. package/build/jsprolog/stepper-utils.d.ts.map +0 -1
  180. package/build/jsprolog/stepper-utils.js +0 -8
  181. package/build/jsprolog/stepper-utils.js.map +0 -1
  182. package/build/jsprolog/test.jsprolog.d.ts +0 -4
  183. package/build/jsprolog/test.jsprolog.d.ts.map +0 -1
  184. package/build/jsprolog/test.jsprolog.js +0 -19
  185. package/build/jsprolog/test.jsprolog.js.map +0 -1
  186. package/build/jsprolog/test.kireji.d.ts +0 -4
  187. package/build/jsprolog/test.kireji.d.ts.map +0 -1
  188. package/build/jsprolog/test.kireji.js +0 -19
  189. package/build/jsprolog/test.kireji.js.map +0 -1
  190. package/build/jsprolog/withAction.d.ts +0 -32
  191. package/build/jsprolog/withAction.d.ts.map +0 -1
  192. package/build/jsprolog/withAction.js +0 -65
  193. package/build/jsprolog/withAction.js.map +0 -1
  194. package/build/kireji/test.kireji.d.ts +0 -4
  195. package/build/kireji/test.kireji.d.ts.map +0 -1
  196. package/build/kireji/test.kireji.js +0 -19
  197. package/build/kireji/test.kireji.js.map +0 -1
  198. package/build/lib/errors.d.ts +0 -13
  199. package/build/lib/errors.d.ts.map +0 -1
  200. package/build/lib/errors.js +0 -18
  201. package/build/lib/errors.js.map +0 -1
  202. package/build/lib/util/featureStep-executor.d.ts +0 -7
  203. package/build/lib/util/featureStep-executor.d.ts.map +0 -1
  204. package/build/lib/util/featureStep-executor.js +0 -63
  205. package/build/lib/util/featureStep-executor.js.map +0 -1
  206. package/build/steps/conditions-stepper.d.ts +0 -27
  207. package/build/steps/conditions-stepper.d.ts.map +0 -1
  208. package/build/steps/conditions-stepper.js +0 -99
  209. package/build/steps/conditions-stepper.js.map +0 -1
@@ -1,131 +1,234 @@
1
1
  import { AStepper } from '../lib/astepper.js';
2
- import { OK } from '../lib/defs.js';
3
- import { executeSubFeatureSteps, findFeatureStepsFromStatement } from '../lib/util/featureStep-executor.js';
4
- import { ExecMode } from '../lib/defs.js';
2
+ import { OK, CycleWhen } from '../lib/defs.js';
5
3
  import { actionOK, actionNotOK, getActionable } from '../lib/util/index.js';
6
4
  import { DOMAIN_STATEMENT } from '../lib/domain-types.js';
7
5
  import { EExecutionMessageType } from '../lib/interfaces/logger.js';
6
+ import { FlowRunner } from '../lib/core/flow-runner.js';
8
7
  /**
9
8
  * Stepper that dynamically builds virtual steps from `waypoint` statements.
10
9
  * implements this logic: P ∨ (¬P ∧ [A]P)
11
10
  */
12
11
  export class ActivitiesStepper extends AStepper {
13
- steppers = [];
14
- // Track which outcome patterns were defined in backgrounds vs features
12
+ runner;
15
13
  backgroundOutcomePatterns = new Set();
16
14
  featureOutcomePatterns = new Set();
17
- // Track which feature each feature-scoped outcome belongs to (for proper cleanup)
18
15
  outcomeToFeaturePath = new Map();
19
- // Track the currently running feature path
16
+ featureSteps = new Map();
20
17
  currentFeaturePath = '';
21
- // Track the last feature path to clear outcomes from it when starting a new feature
22
18
  lastFeaturePath = '';
23
- // Track ensured waypoint instances with their interpolated proofs
19
+ lastResolutionPath = '';
24
20
  ensuredInstances = new Map();
21
+ ensureAttempts = new Map();
22
+ registeredOutcomeMetadata = new Map();
23
+ inActivityBlock = false;
24
+ cycles = {
25
+ startExecution: () => {
26
+ this.sendGraphLinkMessages();
27
+ },
28
+ startFeature: (startFeature) => {
29
+ this.getWorld().logger.debug(`ActivitiesStepper.startFeature: starting feature at path "${startFeature.resolvedFeature.path}"`);
30
+ if (this.lastFeaturePath && this.lastFeaturePath !== startFeature.resolvedFeature.path) {
31
+ this.getWorld().logger.debug(`ActivitiesStepper.startFeature: clearing outcomes from previous feature "${this.lastFeaturePath}"`);
32
+ const previousSteps = this.featureSteps.get(this.lastFeaturePath);
33
+ if (previousSteps) {
34
+ for (const outcome of Object.keys(previousSteps)) {
35
+ delete this.steps[outcome];
36
+ }
37
+ }
38
+ }
39
+ const currentSteps = this.featureSteps.get(startFeature.resolvedFeature.path);
40
+ if (currentSteps) {
41
+ for (const [outcome, step] of Object.entries(currentSteps)) {
42
+ this.steps[outcome] = step;
43
+ }
44
+ }
45
+ this.currentFeaturePath = startFeature.resolvedFeature.path;
46
+ this.sendGraphLinkMessages();
47
+ },
48
+ endFeature: () => {
49
+ this.lastFeaturePath = this.currentFeaturePath;
50
+ this.ensuredInstances.clear();
51
+ return Promise.resolve();
52
+ }
53
+ };
54
+ cyclesWhen = {
55
+ startExecution: CycleWhen.FIRST,
56
+ startFeature: CycleWhen.FIRST,
57
+ };
25
58
  baseSteps = {
26
59
  activity: {
27
60
  gwta: 'Activity: {activity}',
28
- action: () => OK
29
- },
30
- waypoint: {
31
- gwta: `waypoint {outcome} with {proof:${DOMAIN_STATEMENT}}`,
32
- resolveFeatureLine: (line, path, stepper, _backgrounds, allLines, lineIndex) => {
33
- // Simple regex match to check if this is a waypoint statement
34
- if (!line.match(/^waypoint\s+.+?\s+with\s+/i)) {
35
- return false;
36
- }
37
- const activitiesStepper = stepper;
38
- // Extract outcome name
39
- const match = line.match(/^waypoint\s+(.+?)\s+with\s+(.+?)$/i);
40
- if (!match) {
41
- return false;
61
+ action: () => OK,
62
+ resolveFeatureLine: (line, path, _stepper, _backgrounds, allLines, lineIndex) => {
63
+ if (this.lastResolutionPath && this.lastResolutionPath !== path) {
64
+ const previousSteps = this.featureSteps.get(this.lastResolutionPath);
65
+ if (previousSteps) {
66
+ for (const outcome of Object.keys(previousSteps)) {
67
+ delete this.steps[outcome];
68
+ }
69
+ }
42
70
  }
43
- const outcome = match[1].trim();
44
- // Skip if this outcome pattern is already registered
45
- // This prevents infinite loops if resolveFeatureLine is called multiple times
46
- if (activitiesStepper.backgroundOutcomePatterns.has(outcome) || activitiesStepper.featureOutcomePatterns.has(outcome)) {
47
- return true;
71
+ this.lastResolutionPath = path;
72
+ if (line.match(/^Activity:/i)) {
73
+ this.inActivityBlock = true;
74
+ return true; // Skip the Activity definition line itself
48
75
  }
49
- const isBackground = path.includes('backgrounds/');
50
- const proofRaw = match[2].trim();
51
- // Parse the proof statements from the waypoint clause (DOMAIN_STATEMENT)
52
- const proofFromRemember = proofRaw.split('\n').map(s => s.trim()).filter(s => s.length > 0);
53
- // Check if we're in an activity block by scanning backwards through allLines
54
- let activityBlockSteps;
55
- if (allLines && lineIndex !== undefined) {
56
- // Scan backwards from current line to find the Activity: marker
57
- let activityStartLine = -1;
58
- for (let i = lineIndex - 1; i >= 0; i--) {
59
- const prevLine = getActionable(allLines[i]);
60
- if (prevLine.match(/^Activity:/i)) {
61
- activityStartLine = i;
62
- break;
63
- }
64
- // Stop if we hit another major section marker
65
- if (prevLine.match(/^(Feature|Scenario|Background):/i)) {
66
- break;
67
- }
76
+ if (this.inActivityBlock) {
77
+ // Check for block terminators
78
+ if (line.match(/^(Feature|Scenario|Background|Activity):/i)) {
79
+ this.inActivityBlock = false;
80
+ return false; // Process this line normally
68
81
  }
69
- if (activityStartLine !== -1) {
70
- // Collect ALL steps in the activity block up to and including the current waypoint statement
71
- const blockLines = [];
72
- for (let i = activityStartLine + 1; i < lineIndex; i++) { // Use < instead of <= to exclude waypoint line
73
- const stepLine = getActionable(allLines[i]);
74
- if (stepLine) {
75
- blockLines.push(stepLine);
82
+ if (line.match(/^waypoint\s+/i)) {
83
+ this.resolveWaypointCommon(line, path, allLines, lineIndex, line.includes(' with '));
84
+ // Check if this is the last waypoint in the block
85
+ let hasMoreWaypoints = false;
86
+ if (allLines && lineIndex !== undefined) {
87
+ for (let i = lineIndex + 1; i < allLines.length; i++) {
88
+ const nextLine = allLines[i].trim();
89
+ if (nextLine.match(/^(Feature|Scenario|Background|Activity):/i)) {
90
+ break;
91
+ }
92
+ if (nextLine.match(/^waypoint\s+/i)) {
93
+ hasMoreWaypoints = true;
94
+ break;
95
+ }
76
96
  }
77
97
  }
78
- activityBlockSteps = blockLines;
98
+ if (!hasMoreWaypoints) {
99
+ this.inActivityBlock = false;
100
+ }
101
+ return true; // Skip the waypoint definition line
79
102
  }
103
+ // Inside block
104
+ return true; // Skip lines inside the block
80
105
  }
81
- // Register the outcome with its proof from the DOMAIN_STATEMENT
82
- activitiesStepper.registerOutcome(outcome, proofFromRemember, path, isBackground, activityBlockSteps);
83
- return true; // Skip normal step resolution since we've registered the outcome
84
- },
106
+ return false;
107
+ }
108
+ },
109
+ waypointWithProof: {
110
+ gwta: `waypoint {outcome} with {proof:${DOMAIN_STATEMENT}}`,
111
+ precludes: ['ActivitiesStepper.waypointLabel'],
85
112
  action: async ({ proof }, featureStep) => {
86
- // Execute the proof statements to satisfy this outcome
87
113
  this.getWorld().logger.debug(`waypoint action: executing ${proof?.length || 0} proof steps`);
88
- const result = await executeSubFeatureSteps(featureStep, proof, this.steppers, this.getWorld(), ExecMode.NO_CYCLES);
89
- if (!result.ok) {
90
- return actionNotOK(`waypoint: failed to execute proof steps`);
114
+ try {
115
+ const result = await this.runner.runSteps(proof, { intent: { mode: 'authoritative' }, parentStep: featureStep });
116
+ if (result.kind !== 'ok') {
117
+ return actionNotOK(`waypoint: failed to execute proof steps: ${result.message}`);
118
+ }
119
+ return actionOK();
120
+ }
121
+ catch (err) {
122
+ const msg = err instanceof Error ? err.message : String(err);
123
+ this.getWorld().logger.debug(`waypoint action: exception executing proof steps: ${msg}`);
124
+ const messageContext = {
125
+ incident: EExecutionMessageType.ACTION,
126
+ incidentDetails: { error: msg }
127
+ };
128
+ return actionNotOK(`waypoint: failed to execute proof steps: ${msg}`, { messageContext });
91
129
  }
92
- return actionOK();
93
130
  },
94
131
  },
132
+ waypointLabel: {
133
+ gwta: `waypoint {outcome}`,
134
+ action: async () => actionOK(),
135
+ },
95
136
  ensure: {
96
- description: 'Ensure a waypoint condition by always running the proof. If proof passes, waypoint is already satisfied. If proof fails, run the full activity to satisfy it.',
137
+ description: 'Ensure a waypoint condition by always running the proof. If proof passes, waypoint is already satisfied. If proof fails, run the full activity, then try the proof again',
97
138
  gwta: `ensure {outcome:${DOMAIN_STATEMENT}}`,
139
+ unique: true, // Ensure takes priority over dynamically registered outcomes
98
140
  action: async ({ outcome }, featureStep) => {
99
- // Build outcome key from the resolved outcome steps
100
141
  const outcomeKey = outcome.map(step => step.in).join(' ');
142
+ // Guard: prevent infinite ensure retry loops by counting attempts per outcome+seq
143
+ const attemptKey = outcomeKey; // key by outcome only to avoid differing seqPaths
144
+ const prevAttempts = this.ensureAttempts.get(attemptKey) ?? 0;
145
+ const MAX_ENSURE_ATTEMPTS = 10;
146
+ this.ensureAttempts.set(attemptKey, prevAttempts + 1);
147
+ if (prevAttempts + 1 > MAX_ENSURE_ATTEMPTS) {
148
+ this.getWorld().logger.warn(`ensure: exceeded max attempts (${MAX_ENSURE_ATTEMPTS}) for ${outcomeKey}`);
149
+ if (this.getWorld().runtime) {
150
+ this.getWorld().runtime.exhaustionError = 'ensure max attempts exceeded';
151
+ }
152
+ const messageContext = {
153
+ incident: EExecutionMessageType.ACTION,
154
+ incidentDetails: { waypoint: outcomeKey, satisfied: false, error: 'max ensure attempts exceeded', terminal: true }
155
+ };
156
+ return actionNotOK(`ensure: max attempts exceeded for waypoint "${outcomeKey}"`, { messageContext });
157
+ }
158
+ // Log ENSURE_START
159
+ const startMessageContext = {
160
+ incident: EExecutionMessageType.ENSURE_START,
161
+ incidentDetails: { waypoint: outcomeKey, step: featureStep }
162
+ };
163
+ this.getWorld().logger.log(`⏳ Ensuring ${outcomeKey}`, startMessageContext);
101
164
  this.getWorld().logger.debug(`ensure: verifying waypoint "${outcomeKey}"`);
102
- // Get the pattern from the first outcome step's action
103
165
  const pattern = outcome[0]?.action?.actionName || outcomeKey;
104
- // Get the registered waypoint to access its proof
105
166
  const registeredWaypoint = this.steps[pattern];
106
167
  if (!registeredWaypoint) {
107
- const messageContext = {
108
- incident: EExecutionMessageType.ACTION,
109
- incidentDetails: { waypoint: outcomeKey, error: 'waypoint not registered' }
110
- };
111
- return actionNotOK(`ensure: waypoint "${outcomeKey}" (pattern "${pattern}") is not registered`, { messageContext });
168
+ return actionNotOK(`ensure: "${outcomeKey}" is not a registered waypoint. ensure can only be used with waypoints.`);
169
+ }
170
+ const metadata = this.registeredOutcomeMetadata.get(pattern);
171
+ if (!metadata || metadata.proofStatements.length === 0) {
172
+ return actionNotOK(`ensure: waypoint "${outcomeKey}" has no proof. ensure can only be used with waypoints that have a proof.`);
173
+ }
174
+ // Extract args from the outcome step(s) to pass to the activity
175
+ // This ensures that variables (e.g. {name}) defined in the waypoint are available in the activity
176
+ const activityArgs = {};
177
+ for (const step of outcome) {
178
+ if (step.action.stepValuesMap) {
179
+ for (const [key, val] of Object.entries(step.action.stepValuesMap)) {
180
+ // Use the value if available (it should be resolved), otherwise term
181
+ const value = val.value !== undefined ? String(val.value) : val.term;
182
+ if (value !== undefined) {
183
+ activityArgs[key] = value;
184
+ }
185
+ }
186
+ }
112
187
  }
113
- // Always execute the full waypoint (which includes the proof verification)
114
- const result = await executeSubFeatureSteps(featureStep, outcome, this.steppers, this.getWorld(), ExecMode.NO_CYCLES);
115
- if (!result.ok) {
188
+ let proofStatements;
189
+ try {
190
+ // Use FlowRunner for the proof execution
191
+ // Pass activityArgs so they are available to the Outcome Action
192
+ const flowResult = await this.runner.runSteps(outcome, { intent: { mode: 'authoritative', usage: featureStep.intent?.usage, stepperOptions: { isEnsure: true } }, parentStep: featureStep });
193
+ if (flowResult.kind !== 'ok') {
194
+ // Log ENSURE_END for failure
195
+ const endMessageContext = {
196
+ incident: EExecutionMessageType.ENSURE_END,
197
+ incidentDetails: { waypoint: outcomeKey, satisfied: false, error: flowResult.message, actionResult: { ok: false } }
198
+ };
199
+ this.getWorld().logger.log(`❌ Failed ensuring ${outcomeKey}`, endMessageContext);
200
+ const messageContext = {
201
+ incident: EExecutionMessageType.ACTION,
202
+ incidentDetails: { waypoint: outcomeKey, satisfied: false, error: flowResult.message }
203
+ };
204
+ return actionNotOK(`ensure: waypoint "${outcomeKey}" proof failed: ${flowResult.message}`, { messageContext });
205
+ }
206
+ proofStatements = flowResult.payload?.messageContext?.incidentDetails?.proofStatements;
207
+ if (!proofStatements) {
208
+ return actionNotOK(`ensure: waypoint "${outcomeKey}" succeeded but returned no proofStatements`);
209
+ }
210
+ }
211
+ catch (err) {
212
+ const msg = err instanceof Error ? err.message : String(err);
213
+ this.getWorld().logger.debug(`ensure: exception while executing proof for ${outcomeKey}: ${msg}`);
116
214
  const messageContext = {
117
215
  incident: EExecutionMessageType.ACTION,
118
- incidentDetails: { waypoint: outcomeKey, satisfied: false, error: result }
216
+ incidentDetails: { waypoint: outcomeKey, satisfied: false, error: msg }
119
217
  };
120
- return actionNotOK(`ensure: waypoint "${outcomeKey}" could not be satisfied`, { messageContext });
121
- }
122
- // Extract the interpolated proof statements from the result
123
- const proofStatements = result.stepActionResult?.messageContext?.incidentDetails?.proofStatements;
124
- // Track this ensured instance
125
- if (proofStatements) {
126
- this.ensuredInstances.set(outcomeKey, { proof: proofStatements, valid: true });
218
+ return actionNotOK(`ensure: waypoint "${outcomeKey}" proof execution error: ${msg}`, { messageContext });
127
219
  }
220
+ // FIXME: We don't have easy access to proofStatements from FlowRunner result yet unless we pass them back
221
+ // For now, we assume if it passed, it passed.
222
+ this.ensuredInstances.set(outcomeKey, { proof: proofStatements, valid: true });
223
+ // On success or after one ensure action completes, reset attempt counter for this outcome
224
+ this.ensureAttempts.delete(attemptKey);
128
225
  this.getWorld().logger.debug(`ensure: waypoint "${outcomeKey}" verified and satisfied`);
226
+ // Log ENSURE_END for success at trace level (just to hide the ENSURE_START)
227
+ const endMessageContext = {
228
+ incident: EExecutionMessageType.ENSURE_END,
229
+ incidentDetails: { waypoint: outcomeKey, satisfied: true, proofStatements, actionResult: { ok: true } }
230
+ };
231
+ this.getWorld().logger.trace(`✓ Ensured ${outcomeKey}`, endMessageContext);
129
232
  const messageContext = {
130
233
  incident: EExecutionMessageType.ACTION,
131
234
  incidentDetails: {
@@ -137,52 +240,18 @@ export class ActivitiesStepper extends AStepper {
137
240
  return actionOK({ messageContext });
138
241
  },
139
242
  },
140
- forget: {
141
- description: 'Deprecated: forget is no longer needed since ensure always re-verifies outcomes',
142
- gwta: `forget {outcome:${DOMAIN_STATEMENT}}`,
143
- action: ({ outcome }, featureStep) => {
144
- const outcomeKey = outcome.map(step => step.in).join(' ');
145
- this.getWorld().logger.debug(`forget: deprecated no-op for outcome "${outcomeKey}" (from ${featureStep.in}). Outcomes are no longer cached, so forget is unnecessary.`);
146
- const messageContext = { incident: EExecutionMessageType.ACTION, incidentDetails: { outcome: outcomeKey, deprecated: true } };
147
- return actionOK({ messageContext });
148
- },
149
- },
150
- waypointed: {
151
- description: 'Deprecated: waypointed is no longer meaningful since outcomes are not cached',
152
- gwta: `waypointed {outcome:${DOMAIN_STATEMENT}}`,
153
- action: ({ outcome }) => {
154
- const outcomeKey = outcome.map(step => step.in).join(' ');
155
- this.getWorld().logger.debug(`waypointed: deprecated for outcome "${outcomeKey}". Outcomes are verified on each ensure, not cached.`);
156
- const messageContext = { incident: EExecutionMessageType.ACTION, incidentDetails: { outcome: outcomeKey, deprecated: true } };
157
- return actionOK({ messageContext });
158
- },
159
- },
160
243
  showWaypoints: {
161
244
  exact: 'show waypoints',
162
245
  action: async (_args, featureStep) => {
163
- // Show ensured waypoint instances with their current validity
164
246
  const waypointResults = {};
165
- // Check validity of all ensured instances
166
247
  for (const [instanceKey, instanceData] of this.ensuredInstances.entries()) {
167
248
  this.getWorld().logger.debug(`show waypoints: verifying "${instanceKey}"`);
168
249
  try {
169
- // Re-verify the proof for this instance
170
- const resolvedSteps = [];
171
- for (let i = 0; i < instanceData.proof.length; i++) {
172
- const statement = instanceData.proof[i];
173
- const resolved = findFeatureStepsFromStatement(statement, this.steppers, this.getWorld(), featureStep.path, [...featureStep.seqPath, i], 1);
174
- // Add waypoint context to each proof step
175
- const contextualizedSteps = resolved.map(step => ({
176
- ...step,
177
- in: `[${instanceKey} proof] ${step.in}`
178
- }));
179
- resolvedSteps.push(...contextualizedSteps);
180
- }
181
- // Execute the proof statements with NO_CYCLES to check current validity
182
- const result = await executeSubFeatureSteps(featureStep, resolvedSteps, this.steppers, this.getWorld(), ExecMode.NO_CYCLES);
250
+ // Use FlowRunner to run the proof statements directly
251
+ const result = await this.runner.runStatements(instanceData.proof, { intent: { mode: 'speculative' }, parentStep: featureStep });
183
252
  waypointResults[instanceKey] = {
184
253
  proof: instanceData.proof.join('; '),
185
- currentlyValid: result.ok
254
+ currentlyValid: result.kind === 'ok'
186
255
  };
187
256
  }
188
257
  catch (error) {
@@ -200,38 +269,9 @@ export class ActivitiesStepper extends AStepper {
200
269
  };
201
270
  typedSteps = this.baseSteps;
202
271
  steps = { ...this.baseSteps };
203
- cycles = {
204
- startFeature: (startFeature) => {
205
- this.getWorld().logger.debug(`ActivitiesStepper.startFeature: starting feature at path "${startFeature.resolvedFeature.path}"`);
206
- // If we were running a different feature before, clear its outcomes
207
- if (this.lastFeaturePath && this.lastFeaturePath !== startFeature.resolvedFeature.path) {
208
- this.getWorld().logger.debug(`ActivitiesStepper.startFeature: clearing outcomes from previous feature "${this.lastFeaturePath}"`);
209
- const outcomesToClear = [];
210
- for (const [outcome, featurePath] of this.outcomeToFeaturePath.entries()) {
211
- if (featurePath === this.lastFeaturePath) {
212
- outcomesToClear.push(outcome);
213
- delete this.steps[outcome];
214
- this.featureOutcomePatterns.delete(outcome);
215
- }
216
- }
217
- for (const outcome of outcomesToClear) {
218
- this.outcomeToFeaturePath.delete(outcome);
219
- }
220
- this.getWorld().logger.debug(`ActivitiesStepper.startFeature: cleared ${outcomesToClear.length} outcomes from previous feature`);
221
- }
222
- this.currentFeaturePath = startFeature.resolvedFeature.path;
223
- },
224
- endFeature: async () => {
225
- // Track this feature path so we can clean it up when the next feature starts
226
- this.lastFeaturePath = this.currentFeaturePath;
227
- // Clear ensured instances for next feature
228
- this.ensuredInstances.clear();
229
- return Promise.resolve();
230
- }
231
- };
232
272
  async setWorld(world, steppers) {
233
273
  await super.setWorld(world, steppers);
234
- this.steppers = steppers;
274
+ this.runner = new FlowRunner(world, steppers);
235
275
  }
236
276
  /**
237
277
  * Register a dynamic outcome step.
@@ -248,6 +288,15 @@ export class ActivitiesStepper extends AStepper {
248
288
  if (this.steps[outcome]) {
249
289
  throw new Error(`Outcome "${outcome}" is already registered. Each outcome can only be defined once.`);
250
290
  }
291
+ // Normalize activity steps (split multiline strings)
292
+ const normalizedActivitySteps = activityBlockSteps?.flatMap(s => s.split('\n')).map(s => s.trim()).filter(s => s.length > 0) ?? [];
293
+ // Store metadata for runtime re-emission via TEST_LINKS messages
294
+ this.registeredOutcomeMetadata.set(outcome, {
295
+ proofStatements,
296
+ proofPath,
297
+ isBackground: isBackground ?? false,
298
+ activityBlockSteps: normalizedActivitySteps,
299
+ });
251
300
  // Track whether this is a background or feature outcome
252
301
  if (isBackground) {
253
302
  this.backgroundOutcomePatterns.add(outcome);
@@ -259,84 +308,170 @@ export class ActivitiesStepper extends AStepper {
259
308
  }
260
309
  this.getWorld().logger.debug(`ActivitiesStepper: registerOutcome called with ${proofStatements.length} proof steps for "${outcome}"`);
261
310
  this.getWorld().logger.debug(`ActivitiesStepper: outcome is background=${isBackground}, will be added to ${isBackground ? 'backgroundOutcomePatterns' : 'featureOutcomePatterns'}`);
262
- // Store proofStatements for later retrieval
263
- const outcomeProofStatements = proofStatements;
264
- this.steps[outcome] = {
311
+ // FIXME: maybe we don't care if normalizedActivitySteps is empty
312
+ const step = {
265
313
  gwta: outcome,
266
314
  virtual: true, // Dynamically registered outcomes are virtual
315
+ handlesUndefined: true, // FIXME they should not need to handle undefined at the virtual stepper level
267
316
  description: `Outcome: ${outcome}. Proof: ${proofStatements.join('; ')}`,
268
317
  action: async (args, featureStep) => {
269
- this.getWorld().logger.debug(`ActivitiesStepper: executing recipe for outcome "${outcome}" with args ${JSON.stringify(args)}`);
270
- // Helper to expand variables in statements
271
- const expandStatements = (statements) => statements.map(statement => {
272
- let expanded = statement;
273
- for (const [key, value] of Object.entries(args)) {
274
- expanded = expanded.replace(new RegExp(`\\{${key}\\}`, 'g'), String(value));
318
+ // Reconstruct args to include unresolved terms (skipped by strict populateActionArgs)
319
+ const robustArgs = { ...args };
320
+ if (featureStep.action.stepValuesMap) {
321
+ for (const [key, val] of Object.entries(featureStep.action.stepValuesMap)) {
322
+ if (robustArgs[key] === undefined && val.term !== undefined) {
323
+ robustArgs[key] = val.term;
324
+ }
275
325
  }
276
- return expanded;
277
- });
278
- // Helper to resolve and execute statements
279
- const resolveAndExecute = async (statements, stepOffset = 0, execMode = ExecMode.NO_CYCLES) => {
280
- const expandedStatements = expandStatements(statements);
281
- const resolvedSteps = [];
282
- for (let i = 0; i < expandedStatements.length; i++) {
283
- const statement = expandedStatements[i];
284
- this.getWorld().logger.debug(`ActivitiesStepper: resolving statement ${i}: "${statement}"`);
285
- const resolved = findFeatureStepsFromStatement(statement, this.steppers, this.getWorld(), proofPath, [...featureStep.seqPath, stepOffset + i], 1);
286
- resolvedSteps.push(...resolved);
326
+ }
327
+ this.getWorld().logger.debug(`ActivitiesStepper: executing recipe for outcome "${outcome}" with args ${JSON.stringify(robustArgs)}`);
328
+ // 1. Check Proof (Speculative)
329
+ if (proofStatements.length > 0) {
330
+ const proof = await this.runner.runStatements(proofStatements, { args: robustArgs, intent: { mode: 'speculative' }, parentStep: featureStep });
331
+ if (proof.kind === 'ok') {
332
+ this.getWorld().logger.debug(`ActivitiesStepper: proof passed for outcome "${outcome}", skipping activity body`);
333
+ return actionOK({
334
+ messageContext: {
335
+ incident: EExecutionMessageType.ACTION,
336
+ incidentDetails: { proofStatements, proofSatisfied: true }
337
+ }
338
+ });
287
339
  }
288
- return await executeSubFeatureSteps(featureStep, resolvedSteps, this.steppers, this.getWorld(), execMode);
289
- };
290
- // ALWAYS-VERIFY SEMANTICS: Try proof first
291
- // Use NO_CYCLES for proof checking to avoid triggering hooks
292
- this.getWorld().logger.debug(`ActivitiesStepper: checking proof for outcome "${outcome}"`);
293
- this.getWorld().logger.debug(`ActivitiesStepper: proof statements: ${JSON.stringify(proofStatements)}`);
294
- const proofResult = await resolveAndExecute(proofStatements, 0, ExecMode.NO_CYCLES);
295
- // If proof passes, we're done (waypoint already satisfied)
296
- if (proofResult.ok) {
297
- this.getWorld().logger.debug(`ActivitiesStepper: proof passed for outcome "${outcome}", skipping activity body`);
298
- const interpolatedProof = expandStatements(outcomeProofStatements);
299
- return actionOK({
300
- messageContext: {
301
- incident: EExecutionMessageType.ACTION,
302
- incidentDetails: { proofStatements: interpolatedProof, proofSatisfied: true }
340
+ }
341
+ // 2. Proof Failed or not present
342
+ if (!featureStep.intent?.stepperOptions?.isEnsure) {
343
+ if (normalizedActivitySteps && normalizedActivitySteps.length > 0) {
344
+ this.getWorld().logger.debug(`ActivitiesStepper: running activity body for outcome "${outcome}" (no ensure)`);
345
+ const mode = featureStep.intent?.mode === 'speculative' ? 'speculative' : 'authoritative';
346
+ const act = await this.runner.runStatements(normalizedActivitySteps, { args: robustArgs, intent: { mode, usage: featureStep.intent?.usage }, parentStep: featureStep });
347
+ if (act.kind !== 'ok') {
348
+ return actionNotOK(`ActivitiesStepper: activity body failed for outcome "${outcome}": ${act.message}`);
303
349
  }
304
- });
350
+ return actionOK();
351
+ }
352
+ if (proofStatements.length > 0) {
353
+ return actionNotOK(`ActivitiesStepper: proof failed for outcome "${outcome}"`);
354
+ }
355
+ // No proof (waypointLabel) and not ensure: do nothing.
356
+ return actionOK();
305
357
  }
306
- // Proof failed - execute activity body (WITHOUT waypoint line), then verify proof
307
- // Flow: 1) Execute activity body steps, 2) Execute proof to verify, 3) Success or fail
308
- if (activityBlockSteps && activityBlockSteps.length > 0) {
358
+ // 3. Ensure Mode: Run Activity Body
359
+ if (normalizedActivitySteps && normalizedActivitySteps.length > 0) {
309
360
  this.getWorld().logger.debug(`ActivitiesStepper: proof failed for outcome "${outcome}", running activity body`);
310
- // Step 1: Execute activity body (does NOT include the waypoint line to avoid recursion)
311
- // Use WITH_CYCLES so that activity body steps can trigger hooks
312
- const activityResult = await resolveAndExecute(activityBlockSteps, 100, ExecMode.WITH_CYCLES);
313
- if (!activityResult.ok) {
314
- return actionNotOK(`ActivitiesStepper: activity body failed for outcome "${outcome}"`);
361
+ const mode = featureStep.intent?.mode === 'speculative' ? 'speculative' : 'authoritative';
362
+ const act = await this.runner.runStatements(normalizedActivitySteps, { args: robustArgs, intent: { mode, usage: featureStep.intent?.usage }, parentStep: featureStep });
363
+ if (act.kind !== 'ok') {
364
+ return actionNotOK(`ActivitiesStepper: activity body failed for outcome "${outcome}": ${act.message}`);
315
365
  }
316
- // Step 2: Activity body succeeded - now verify the proof passes
317
- // Use NO_CYCLES for proof verification to avoid triggering hooks
366
+ // 4. Verify Proof After Activity
318
367
  this.getWorld().logger.debug(`ActivitiesStepper: verifying proof after activity body for outcome "${outcome}"`);
319
- const verifyResult = await resolveAndExecute(proofStatements, 200, ExecMode.NO_CYCLES);
320
- if (!verifyResult.ok) {
321
- return actionNotOK(`ActivitiesStepper: proof verification failed after activity body for outcome "${outcome}"`);
368
+ if (proofStatements.length > 0) {
369
+ const verify = await this.runner.runStatements(proofStatements, { args: robustArgs, intent: { mode, usage: featureStep.intent?.usage }, parentStep: featureStep });
370
+ if (verify.kind !== 'ok') {
371
+ return actionNotOK(`ActivitiesStepper: proof verification failed after activity body for outcome "${outcome}": ${verify.message}`);
372
+ }
322
373
  }
323
- // Step 3: Success - proof now passes
324
- const interpolatedProof = expandStatements(outcomeProofStatements);
325
374
  return actionOK({
326
375
  messageContext: {
327
376
  incident: EExecutionMessageType.ACTION,
328
- incidentDetails: { proofStatements: interpolatedProof }
377
+ incidentDetails: { proofStatements, proofSatisfied: true }
329
378
  }
330
379
  });
331
380
  }
332
- else {
333
- // No activity body, just proof - and it failed
334
- return actionNotOK(`ActivitiesStepper: proof failed and no activity body available for outcome "${outcome}"`);
335
- }
381
+ return actionNotOK(`ActivitiesStepper: no activity body for outcome "${outcome}"`);
336
382
  }
337
383
  };
384
+ this.steps[outcome] = step;
385
+ if (!isBackground) {
386
+ if (!this.featureSteps.has(proofPath)) {
387
+ this.featureSteps.set(proofPath, {});
388
+ }
389
+ this.featureSteps.get(proofPath)[outcome] = step;
390
+ }
338
391
  this.getWorld().logger.debug(`ActivitiesStepper: registered outcome pattern "${outcome}" with ${proofStatements.length} proof steps`);
339
392
  }
393
+ /**
394
+ * Re-emit GRAPH_LINK messages for waypoint metadata.
395
+ * MonitorHandler subscribes after resolution, so we retransmit stored metadata.
396
+ */
397
+ sendGraphLinkMessages() {
398
+ for (const [outcome, metadata] of this.registeredOutcomeMetadata.entries()) {
399
+ const messageContext = {
400
+ incident: EExecutionMessageType.GRAPH_LINK,
401
+ incidentDetails: {
402
+ outcome,
403
+ proofStatements: metadata.proofStatements,
404
+ proofPath: metadata.proofPath,
405
+ isBackground: metadata.isBackground,
406
+ activityBlockSteps: metadata.activityBlockSteps ?? null,
407
+ }
408
+ };
409
+ this.getWorld().logger.debug(`waypoint registered: "${outcome}"`, messageContext);
410
+ }
411
+ }
412
+ resolveWaypointCommon(line, path, allLines, lineIndex, requireProof) {
413
+ if (!line.match(/^waypoint\s+/i)) {
414
+ return false;
415
+ }
416
+ let outcome;
417
+ let proofStatements = [];
418
+ if (requireProof) {
419
+ if (!line.match(/^waypoint\s+.+?\s+with\s+/i)) {
420
+ return false;
421
+ }
422
+ // Find the LAST occurrence of ' with ' to separate outcome from proof
423
+ // This allows 'with' to appear in outcome names (e.g., "{name} agreed with {concern}")
424
+ const withoutPrefix = line.replace(/^waypoint\s+/i, '');
425
+ const lastWithIndex = withoutPrefix.lastIndexOf(' with ');
426
+ if (lastWithIndex === -1)
427
+ return false;
428
+ outcome = withoutPrefix.substring(0, lastWithIndex).trim();
429
+ const proofRaw = withoutPrefix.substring(lastWithIndex + 6).trim(); // ' with ' is 6 chars
430
+ proofStatements = proofRaw.split('\n').map(s => s.trim()).filter(s => s.length > 0);
431
+ }
432
+ else {
433
+ if (line.match(/^waypoint\s+.+?\s+with\s+/i)) {
434
+ return false;
435
+ }
436
+ const match = line.match(/^waypoint\s+(.+?)$/i);
437
+ if (!match)
438
+ return false;
439
+ outcome = match[1].trim();
440
+ }
441
+ // Skip if already registered (prevents infinite loops)
442
+ if (this.backgroundOutcomePatterns.has(outcome) || this.featureOutcomePatterns.has(outcome)) {
443
+ return true;
444
+ }
445
+ const isBackground = path.includes('backgrounds/');
446
+ // Scan backwards to find containing Activity block
447
+ let activityBlockSteps;
448
+ if (allLines && lineIndex !== undefined) {
449
+ let activityStartLine = -1;
450
+ for (let i = lineIndex - 1; i >= 0; i--) {
451
+ const prevLine = getActionable(allLines[i]);
452
+ if (prevLine.match(/^Activity:/i)) {
453
+ activityStartLine = i;
454
+ break;
455
+ }
456
+ if (prevLine.match(/^(Feature|Scenario|Background):/i)) {
457
+ break;
458
+ }
459
+ }
460
+ if (activityStartLine !== -1) {
461
+ // Collect steps between Activity: and waypoint (excluding waypoint itself)
462
+ const blockLines = [];
463
+ for (let i = activityStartLine + 1; i < lineIndex; i++) {
464
+ const stepLine = getActionable(allLines[i]);
465
+ if (stepLine && !stepLine.match(/^waypoint\s+/i)) {
466
+ blockLines.push(stepLine);
467
+ }
468
+ }
469
+ activityBlockSteps = blockLines;
470
+ }
471
+ }
472
+ this.registerOutcome(outcome, proofStatements, path, isBackground, activityBlockSteps);
473
+ return true;
474
+ }
340
475
  }
341
476
  export default ActivitiesStepper;
342
477
  //# sourceMappingURL=activities-stepper.js.map