@haibun/core 4.0.0-alpha.2 → 4.0.0-alpha.3

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 (297) hide show
  1. package/build/currentVersion.d.ts +1 -1
  2. package/build/currentVersion.js +1 -1
  3. package/build/index.d.ts +1 -1
  4. package/build/index.d.ts.map +1 -1
  5. package/build/index.js +1 -1
  6. package/build/index.js.map +1 -1
  7. package/build/kireji/converter.d.ts +2 -2
  8. package/build/kireji/converter.d.ts.map +1 -1
  9. package/build/kireji/converter.js +12 -9
  10. package/build/kireji/converter.js.map +1 -1
  11. package/build/kireji/withAction.d.ts +16 -4
  12. package/build/kireji/withAction.d.ts.map +1 -1
  13. package/build/kireji/withAction.js +40 -11
  14. package/build/kireji/withAction.js.map +1 -1
  15. package/build/lib/EventLogger.d.ts +5 -5
  16. package/build/lib/EventLogger.d.ts.map +1 -1
  17. package/build/lib/EventLogger.js +39 -37
  18. package/build/lib/EventLogger.js.map +1 -1
  19. package/build/lib/PhaseRunner.d.ts +3 -3
  20. package/build/lib/PhaseRunner.d.ts.map +1 -1
  21. package/build/lib/PhaseRunner.js +7 -5
  22. package/build/lib/PhaseRunner.js.map +1 -1
  23. package/build/lib/astepper.d.ts +90 -13
  24. package/build/lib/astepper.d.ts.map +1 -1
  25. package/build/lib/astepper.js +35 -6
  26. package/build/lib/astepper.js.map +1 -1
  27. package/build/lib/base-prompt-manager.d.ts +1 -1
  28. package/build/lib/base-prompt-manager.d.ts.map +1 -1
  29. package/build/lib/base-prompt-manager.js.map +1 -1
  30. package/build/lib/capture-locator.d.ts +1 -1
  31. package/build/lib/capture-locator.d.ts.map +1 -1
  32. package/build/lib/capture-locator.js +5 -5
  33. package/build/lib/capture-locator.js.map +1 -1
  34. package/build/lib/core/flow-runner.d.ts +8 -7
  35. package/build/lib/core/flow-runner.d.ts.map +1 -1
  36. package/build/lib/core/flow-runner.js +42 -71
  37. package/build/lib/core/flow-runner.js.map +1 -1
  38. package/build/lib/core-domains.d.ts +2 -2
  39. package/build/lib/core-domains.d.ts.map +1 -1
  40. package/build/lib/core-domains.js +17 -18
  41. package/build/lib/core-domains.js.map +1 -1
  42. package/build/lib/defs.d.ts +2 -13
  43. package/build/lib/defs.d.ts.map +1 -1
  44. package/build/lib/defs.js.map +1 -1
  45. package/build/lib/document-content.d.ts +18 -0
  46. package/build/lib/document-content.d.ts.map +1 -0
  47. package/build/lib/document-content.js +158 -0
  48. package/build/lib/document-content.js.map +1 -0
  49. package/build/lib/domains.d.ts +31 -0
  50. package/build/lib/domains.d.ts.map +1 -0
  51. package/build/lib/domains.js +105 -0
  52. package/build/lib/domains.js.map +1 -0
  53. package/build/lib/execution.d.ts +304 -0
  54. package/build/lib/execution.d.ts.map +1 -0
  55. package/build/lib/execution.js +23 -0
  56. package/build/lib/execution.js.map +1 -0
  57. package/build/lib/feature-variables.d.ts +21 -50
  58. package/build/lib/feature-variables.d.ts.map +1 -1
  59. package/build/lib/feature-variables.js +122 -232
  60. package/build/lib/feature-variables.js.map +1 -1
  61. package/build/lib/features.d.ts +2 -2
  62. package/build/lib/features.d.ts.map +1 -1
  63. package/build/lib/features.js +13 -17
  64. package/build/lib/features.js.map +1 -1
  65. package/build/lib/fixme.d.ts.map +1 -1
  66. package/build/lib/host-id.d.ts +44 -0
  67. package/build/lib/host-id.d.ts.map +1 -0
  68. package/build/lib/host-id.js +51 -0
  69. package/build/lib/host-id.js.map +1 -0
  70. package/build/lib/http-observations.d.ts +15 -2
  71. package/build/lib/http-observations.d.ts.map +1 -1
  72. package/build/lib/http-observations.js +40 -23
  73. package/build/lib/http-observations.js.map +1 -1
  74. package/build/lib/hypermedia.d.ts +62 -0
  75. package/build/lib/hypermedia.d.ts.map +1 -0
  76. package/build/lib/hypermedia.js +228 -0
  77. package/build/lib/hypermedia.js.map +1 -0
  78. package/build/lib/namedVars.d.ts +2 -2
  79. package/build/lib/namedVars.d.ts.map +1 -1
  80. package/build/lib/namedVars.js +25 -30
  81. package/build/lib/namedVars.js.map +1 -1
  82. package/build/lib/node-http-events.d.ts +3 -3
  83. package/build/lib/node-http-events.d.ts.map +1 -1
  84. package/build/lib/node-http-events.js +26 -26
  85. package/build/lib/node-http-events.js.map +1 -1
  86. package/build/lib/populateActionArgs.d.ts +4 -4
  87. package/build/lib/populateActionArgs.d.ts.map +1 -1
  88. package/build/lib/populateActionArgs.js +4 -6
  89. package/build/lib/populateActionArgs.js.map +1 -1
  90. package/build/lib/prompter.d.ts.map +1 -1
  91. package/build/lib/prompter.js +10 -7
  92. package/build/lib/prompter.js.map +1 -1
  93. package/build/lib/quad-store.d.ts +34 -10
  94. package/build/lib/quad-store.d.ts.map +1 -1
  95. package/build/lib/quad-store.js +169 -21
  96. package/build/lib/quad-store.js.map +1 -1
  97. package/build/lib/quad-types.d.ts +80 -9
  98. package/build/lib/quad-types.d.ts.map +1 -1
  99. package/build/lib/quad-types.js +46 -2
  100. package/build/lib/quad-types.js.map +1 -1
  101. package/build/lib/readline-prompter.d.ts +1 -1
  102. package/build/lib/readline-prompter.js +4 -4
  103. package/build/lib/remote-stepper-proxy.d.ts +56 -0
  104. package/build/lib/remote-stepper-proxy.d.ts.map +1 -0
  105. package/build/lib/remote-stepper-proxy.js +123 -0
  106. package/build/lib/remote-stepper-proxy.js.map +1 -0
  107. package/build/lib/resolver-features.d.ts +1 -1
  108. package/build/lib/resolver-features.d.ts.map +1 -1
  109. package/build/lib/resolver-features.js +2 -2
  110. package/build/lib/resolver-features.js.map +1 -1
  111. package/build/lib/resources.d.ts +461 -0
  112. package/build/lib/resources.d.ts.map +1 -0
  113. package/build/lib/resources.js +249 -0
  114. package/build/lib/resources.js.map +1 -0
  115. package/build/lib/rpc-client.d.ts +68 -0
  116. package/build/lib/rpc-client.d.ts.map +1 -0
  117. package/build/lib/rpc-client.js +186 -0
  118. package/build/lib/rpc-client.js.map +1 -0
  119. package/build/lib/sse-subscriber.d.ts +57 -0
  120. package/build/lib/sse-subscriber.d.ts.map +1 -0
  121. package/build/lib/sse-subscriber.js +110 -0
  122. package/build/lib/sse-subscriber.js.map +1 -0
  123. package/build/lib/step-dispatch.d.ts +92 -28
  124. package/build/lib/step-dispatch.d.ts.map +1 -1
  125. package/build/lib/step-dispatch.js +331 -75
  126. package/build/lib/step-dispatch.js.map +1 -1
  127. package/build/lib/step-validation.d.ts +3 -3
  128. package/build/lib/step-validation.d.ts.map +1 -1
  129. package/build/lib/step-validation.js +2 -2
  130. package/build/lib/step-validation.js.map +1 -1
  131. package/build/lib/stepper-cycles.d.ts +5 -0
  132. package/build/lib/stepper-cycles.d.ts.map +1 -0
  133. package/build/lib/stepper-cycles.js +31 -0
  134. package/build/lib/stepper-cycles.js.map +1 -0
  135. package/build/lib/stepper-registry.d.ts +6 -3
  136. package/build/lib/stepper-registry.d.ts.map +1 -1
  137. package/build/lib/stepper-registry.js +9 -8
  138. package/build/lib/stepper-registry.js.map +1 -1
  139. package/build/lib/subprocess-runner.d.ts +35 -0
  140. package/build/lib/subprocess-runner.d.ts.map +1 -0
  141. package/build/lib/subprocess-runner.js +60 -0
  142. package/build/lib/subprocess-runner.js.map +1 -0
  143. package/build/lib/subprocess-transport.d.ts +37 -0
  144. package/build/lib/subprocess-transport.d.ts.map +1 -0
  145. package/build/lib/subprocess-transport.js +113 -0
  146. package/build/lib/subprocess-transport.js.map +1 -0
  147. package/build/lib/test/EventCollectorStepper.d.ts +3 -3
  148. package/build/lib/test/EventCollectorStepper.d.ts.map +1 -1
  149. package/build/lib/test/EventCollectorStepper.js +3 -3
  150. package/build/lib/test/EventCollectorStepper.js.map +1 -1
  151. package/build/lib/test/SetTimeStepper.d.ts +3 -3
  152. package/build/lib/test/SetTimeStepper.d.ts.map +1 -1
  153. package/build/lib/test/SetTimeStepper.js +7 -7
  154. package/build/lib/test/SetTimeStepper.js.map +1 -1
  155. package/build/lib/test/TestSteps.d.ts +7 -7
  156. package/build/lib/test/TestSteps.d.ts.map +1 -1
  157. package/build/lib/test/TestSteps.js +7 -7
  158. package/build/lib/test/TestSteps.js.map +1 -1
  159. package/build/lib/test/TestStepsWithOptions.d.ts +6 -6
  160. package/build/lib/test/TestStepsWithOptions.js +7 -7
  161. package/build/lib/test/lib.d.ts +3 -3
  162. package/build/lib/test/lib.d.ts.map +1 -1
  163. package/build/lib/test/lib.js +27 -21
  164. package/build/lib/test/lib.js.map +1 -1
  165. package/build/lib/test/resolvedTestFeatures.d.ts +6 -6
  166. package/build/lib/test/resolvedTestFeatures.d.ts.map +1 -1
  167. package/build/lib/test/resolvedTestFeatures.js +5 -5
  168. package/build/lib/test/subprocess-fixture.d.ts +8 -0
  169. package/build/lib/test/subprocess-fixture.d.ts.map +1 -0
  170. package/build/lib/test/subprocess-fixture.js +27 -0
  171. package/build/lib/test/subprocess-fixture.js.map +1 -0
  172. package/build/lib/ttag.d.ts +7 -1
  173. package/build/lib/ttag.d.ts.map +1 -1
  174. package/build/lib/ttag.js +5 -4
  175. package/build/lib/ttag.js.map +1 -1
  176. package/build/lib/util/dot-path.d.ts +2 -2
  177. package/build/lib/util/dot-path.d.ts.map +1 -1
  178. package/build/lib/util/dot-path.js +8 -7
  179. package/build/lib/util/dot-path.js.map +1 -1
  180. package/build/lib/util/index.d.ts +10 -24
  181. package/build/lib/util/index.d.ts.map +1 -1
  182. package/build/lib/util/index.js +43 -93
  183. package/build/lib/util/index.js.map +1 -1
  184. package/build/lib/util/node/actualURI.d.ts +4 -0
  185. package/build/lib/util/node/actualURI.d.ts.map +1 -0
  186. package/build/lib/util/node/actualURI.js +10 -0
  187. package/build/lib/util/node/actualURI.js.map +1 -0
  188. package/build/lib/util/node/module-loader.d.ts +14 -0
  189. package/build/lib/util/node/module-loader.d.ts.map +1 -0
  190. package/build/lib/util/node/module-loader.js +51 -0
  191. package/build/lib/util/node/module-loader.js.map +1 -0
  192. package/build/lib/util/node/workspace-lib.d.ts +15 -0
  193. package/build/lib/util/node/workspace-lib.d.ts.map +1 -0
  194. package/build/lib/util/node/workspace-lib.js +119 -0
  195. package/build/lib/util/node/workspace-lib.js.map +1 -0
  196. package/build/lib/util/secret-utils.d.ts.map +1 -1
  197. package/build/lib/util/secret-utils.js +2 -2
  198. package/build/lib/util/secret-utils.js.map +1 -1
  199. package/build/lib/vertex-crud.d.ts +22 -0
  200. package/build/lib/vertex-crud.d.ts.map +1 -0
  201. package/build/lib/vertex-crud.js +73 -0
  202. package/build/lib/vertex-crud.js.map +1 -0
  203. package/build/lib/workspace-discovery.d.ts +1 -1
  204. package/build/lib/workspace-discovery.d.ts.map +1 -1
  205. package/build/lib/workspace-discovery.js +10 -10
  206. package/build/lib/workspace-discovery.js.map +1 -1
  207. package/build/lib/zcap-like-authority.d.ts +38 -0
  208. package/build/lib/zcap-like-authority.d.ts.map +1 -0
  209. package/build/lib/zcap-like-authority.js +56 -0
  210. package/build/lib/zcap-like-authority.js.map +1 -0
  211. package/build/monitor/index.d.ts +1 -1
  212. package/build/monitor/index.d.ts.map +1 -1
  213. package/build/monitor/index.js +1 -1
  214. package/build/monitor/index.js.map +1 -1
  215. package/build/phases/Executor.d.ts +31 -7
  216. package/build/phases/Executor.d.ts.map +1 -1
  217. package/build/phases/Executor.js +201 -219
  218. package/build/phases/Executor.js.map +1 -1
  219. package/build/phases/Resolver.d.ts +2 -2
  220. package/build/phases/Resolver.d.ts.map +1 -1
  221. package/build/phases/Resolver.js +35 -30
  222. package/build/phases/Resolver.js.map +1 -1
  223. package/build/phases/collector.d.ts +3 -3
  224. package/build/phases/collector.d.ts.map +1 -1
  225. package/build/phases/collector.js +19 -17
  226. package/build/phases/collector.js.map +1 -1
  227. package/build/run-policy/run-policy-schema.d.ts +3 -5
  228. package/build/run-policy/run-policy-schema.d.ts.map +1 -1
  229. package/build/run-policy/run-policy-schema.js +41 -37
  230. package/build/run-policy/run-policy-schema.js.map +1 -1
  231. package/build/run-policy/run-policy-types.d.ts +1 -1
  232. package/build/run-policy/run-policy-types.d.ts.map +1 -1
  233. package/build/run-policy/run-policy-types.js +19 -16
  234. package/build/run-policy/run-policy-types.js.map +1 -1
  235. package/build/runner.d.ts +4 -4
  236. package/build/runner.d.ts.map +1 -1
  237. package/build/runner.js +15 -13
  238. package/build/runner.js.map +1 -1
  239. package/build/schema/protocol.d.ts +153 -61
  240. package/build/schema/protocol.d.ts.map +1 -1
  241. package/build/schema/protocol.js +177 -148
  242. package/build/schema/protocol.js.map +1 -1
  243. package/build/steps/activities-stepper.d.ts +13 -13
  244. package/build/steps/activities-stepper.d.ts.map +1 -1
  245. package/build/steps/activities-stepper.js +105 -79
  246. package/build/steps/activities-stepper.js.map +1 -1
  247. package/build/steps/conformance.d.ts +5 -5
  248. package/build/steps/conformance.js +4 -4
  249. package/build/steps/console-monitor-stepper.d.ts +2 -2
  250. package/build/steps/console-monitor-stepper.d.ts.map +1 -1
  251. package/build/steps/console-monitor-stepper.js +22 -22
  252. package/build/steps/console-monitor-stepper.js.map +1 -1
  253. package/build/steps/debugger-stepper.d.ts +11 -11
  254. package/build/steps/debugger-stepper.d.ts.map +1 -1
  255. package/build/steps/debugger-stepper.js +65 -64
  256. package/build/steps/debugger-stepper.js.map +1 -1
  257. package/build/steps/finalizer-stepper.d.ts +3 -4
  258. package/build/steps/finalizer-stepper.d.ts.map +1 -1
  259. package/build/steps/finalizer-stepper.js +16 -19
  260. package/build/steps/finalizer-stepper.js.map +1 -1
  261. package/build/steps/haibun.d.ts +27 -20
  262. package/build/steps/haibun.d.ts.map +1 -1
  263. package/build/steps/haibun.js +76 -67
  264. package/build/steps/haibun.js.map +1 -1
  265. package/build/steps/lib/tts.d.ts +1 -1
  266. package/build/steps/lib/tts.d.ts.map +1 -1
  267. package/build/steps/lib/tts.js +28 -28
  268. package/build/steps/lib/tts.js.map +1 -1
  269. package/build/steps/logic-stepper.d.ts +5 -5
  270. package/build/steps/logic-stepper.d.ts.map +1 -1
  271. package/build/steps/logic-stepper.js +76 -76
  272. package/build/steps/logic-stepper.js.map +1 -1
  273. package/build/steps/narrator.d.ts +9 -9
  274. package/build/steps/narrator.d.ts.map +1 -1
  275. package/build/steps/narrator.js +32 -28
  276. package/build/steps/narrator.js.map +1 -1
  277. package/build/steps/resources-stepper.d.ts +47 -0
  278. package/build/steps/resources-stepper.d.ts.map +1 -0
  279. package/build/steps/resources-stepper.js +100 -0
  280. package/build/steps/resources-stepper.js.map +1 -0
  281. package/build/steps/variables-stepper.d.ts +57 -57
  282. package/build/steps/variables-stepper.d.ts.map +1 -1
  283. package/build/steps/variables-stepper.js +252 -224
  284. package/build/steps/variables-stepper.js.map +1 -1
  285. package/build/steps/zcap-like-stepper.d.ts +50 -0
  286. package/build/steps/zcap-like-stepper.d.ts.map +1 -0
  287. package/build/steps/zcap-like-stepper.js +113 -0
  288. package/build/steps/zcap-like-stepper.js.map +1 -0
  289. package/package.json +1 -1
  290. package/build/lib/consts.d.ts +0 -5
  291. package/build/lib/consts.d.ts.map +0 -1
  292. package/build/lib/consts.js +0 -5
  293. package/build/lib/consts.js.map +0 -1
  294. package/build/lib/step-helpers.d.ts +0 -10
  295. package/build/lib/step-helpers.d.ts.map +0 -1
  296. package/build/lib/step-helpers.js +0 -16
  297. package/build/lib/step-helpers.js.map +0 -1
@@ -1,24 +1,22 @@
1
- import { z } from 'zod';
2
- import { OK, Origin } from '../schema/protocol.js';
3
- import { AStepper } from '../lib/astepper.js';
4
- import { actionOK, actionNotOK, actionOKWithProducts, getStepTerm } from '../lib/util/index.js';
5
- import { FlowRunner } from '../lib/core/flow-runner.js';
6
- import { FeatureVariables, OBSCURED_VALUE } from '../lib/feature-variables.js';
7
- import { sanitizeObjectSecrets } from '../lib/util/secret-utils.js';
8
- import { DOMAIN_STATEMENT, DOMAIN_STRING, normalizeDomainKey, createEnumDomainDefinition, registerDomains } from '../lib/domain-types.js';
9
- const clearVars = (vars) => () => {
10
- vars.getWorld().shared.clear();
11
- return;
1
+ import { z } from "zod";
2
+ import { OK, Origin } from "../schema/protocol.js";
3
+ import { AStepper } from "../lib/astepper.js";
4
+ import { actionOK, actionNotOK, actionOKWithProducts, getStepTerm } from "../lib/util/index.js";
5
+ import { FlowRunner } from "../lib/core/flow-runner.js";
6
+ import { FeatureVariables, OBSCURED_VALUE } from "../lib/feature-variables.js";
7
+ import { sanitizeObjectSecrets } from "../lib/util/secret-utils.js";
8
+ import { DOMAIN_STATEMENT, DOMAIN_STRING, normalizeDomainKey, createEnumDomainDefinition, registerDomains, } from "../lib/domains.js";
9
+ const clearVars = (vars) => async () => {
10
+ await vars.getWorld().shared.getStore().clear();
12
11
  };
13
12
  const cycles = (variablesStepper) => ({
14
13
  startFeature: clearVars(variablesStepper),
15
- startScenario: ({ scopedVars }) => {
16
- variablesStepper.getWorld().shared = new FeatureVariables(variablesStepper.getWorld(), { ...scopedVars.all() });
17
- return Promise.resolve();
14
+ startScenario: async ({ scopedVars }) => {
15
+ variablesStepper.getWorld().shared = new FeatureVariables(variablesStepper.getWorld(), { ...(await scopedVars.all()) });
18
16
  },
19
17
  });
20
18
  class VariablesStepper extends AStepper {
21
- description = 'Set, get, and compare variables; define domains and check membership';
19
+ description = "Set, get, and compare variables; define domains and check membership";
22
20
  cycles = cycles(this);
23
21
  steppers;
24
22
  runner;
@@ -31,49 +29,49 @@ class VariablesStepper extends AStepper {
31
29
  steps = {
32
30
  defineOpenSet: {
33
31
  gwta: `set of {domain: string} as {superdomains: ${DOMAIN_STATEMENT}}`,
34
- handlesUndefined: ['domain'],
35
- action: ({ domain, superdomains }, featureStep) => this.registerSubdomainFromStatement(domain, superdomains, featureStep)
32
+ handlesUndefined: ["domain"],
33
+ action: ({ domain, superdomains }, featureStep) => this.registerSubdomainFromStatement(domain, superdomains, featureStep),
36
34
  },
37
35
  defineOrderedSet: {
38
36
  precludes: [`${VariablesStepper.name}.defineValuesSet`, `${VariablesStepper.name}.defineSet`],
39
- handlesUndefined: ['domain'],
37
+ handlesUndefined: ["domain"],
40
38
  gwta: `ordered set of {domain: string} is {values:${DOMAIN_STATEMENT}}`,
41
- action: ({ domain, values }, featureStep) => this.registerValuesDomainFromStatement(domain, values, featureStep, { ordered: true, label: 'ordered set' })
39
+ action: ({ domain, values }, featureStep) => this.registerValuesDomainFromStatement(domain, values, featureStep, { ordered: true, label: "ordered set" }),
42
40
  },
43
41
  defineValuesSet: {
44
42
  gwta: `set of {domain: string} is {values:${DOMAIN_STATEMENT}}`,
45
- handlesUndefined: ['domain'],
46
- action: ({ domain, values }, featureStep) => this.registerValuesDomainFromStatement(domain, values, featureStep, { ordered: false, label: 'set' })
43
+ handlesUndefined: ["domain"],
44
+ action: ({ domain, values }, featureStep) => this.registerValuesDomainFromStatement(domain, values, featureStep, { ordered: false, label: "set" }),
47
45
  },
48
46
  statementSetValues: {
49
- expose: false,
50
- gwta: '\\[{items: string}\\]',
47
+ exposeMCP: false,
48
+ gwta: "\\[{items: string}\\]",
51
49
  action: () => OK,
52
50
  },
53
51
  composeAs: {
54
- gwta: 'compose {what} as {domain} with {template}',
55
- handlesUndefined: ['what', 'template'],
52
+ gwta: "compose {what} as {domain} with {template}",
53
+ handlesUndefined: ["what", "template"],
56
54
  precludes: [`${VariablesStepper.name}.compose`],
57
- action: ({ domain }, featureStep) => {
55
+ action: async ({ domain }, featureStep) => {
58
56
  const { term } = featureStep.action.stepValuesMap.what;
59
57
  const templateVal = featureStep.action.stepValuesMap.template;
60
58
  if (!templateVal?.term)
61
- return actionNotOK('template not provided');
62
- const result = this.interpolateTemplate(templateVal.term, featureStep);
59
+ return actionNotOK("template not provided");
60
+ const result = await this.interpolateTemplate(templateVal.term, featureStep);
63
61
  if (result.error)
64
62
  return actionNotOK(result.error);
65
63
  return trySetVariable(this.getWorld().shared, { term: String(term), value: result.value, domain, origin: Origin.var, secret: result.secret }, provenanceFromFeatureStep(featureStep));
66
- }
64
+ },
67
65
  },
68
66
  compose: {
69
- gwta: 'compose {what} with {template}',
70
- handlesUndefined: ['what', 'template'],
71
- action: (_, featureStep) => {
67
+ gwta: "compose {what} with {template}",
68
+ handlesUndefined: ["what", "template"],
69
+ action: async (_, featureStep) => {
72
70
  const { term } = featureStep.action.stepValuesMap.what;
73
71
  const templateVal = featureStep.action.stepValuesMap.template;
74
72
  if (!templateVal?.term)
75
- return actionNotOK('template not provided');
76
- const result = this.interpolateTemplate(templateVal.term, featureStep);
73
+ return actionNotOK("template not provided");
74
+ const result = await this.interpolateTemplate(templateVal.term, featureStep);
77
75
  if (result.error)
78
76
  return actionNotOK(result.error);
79
77
  return trySetVariable(this.getWorld().shared, { term: String(term), value: result.value, domain: DOMAIN_STRING, origin: Origin.var, secret: result.secret }, provenanceFromFeatureStep(featureStep));
@@ -81,31 +79,27 @@ class VariablesStepper extends AStepper {
81
79
  },
82
80
  setFromStatement: {
83
81
  gwta: `set {what: string} from {statement: ${DOMAIN_STATEMENT}}`,
84
- handlesUndefined: ['what'],
82
+ handlesUndefined: ["what"],
85
83
  precludes: [`${VariablesStepper.name}.set`],
86
84
  action: async ({ statement }, featureStep) => {
87
85
  const { term } = featureStep.action.stepValuesMap.what;
88
- const result = await this.runner.runSteps(statement, { intent: { mode: 'authoritative' }, parentStep: featureStep });
89
- if (result.kind !== 'ok')
90
- return actionNotOK(`set from statement failed: ${result.message}`);
91
- const stepActionResult = result.products;
92
- const products = stepActionResult && 'products' in stepActionResult
93
- ? stepActionResult.products
94
- : stepActionResult ?? {};
95
- this.getWorld().shared.setJSON(String(term), products, Origin.var, featureStep);
86
+ const result = await this.runner.runSteps(statement, { intent: { mode: "authoritative" }, parentStep: featureStep });
87
+ if (!result.ok)
88
+ return actionNotOK(`set from statement failed: ${result.errorMessage}`);
89
+ await this.getWorld().shared.setJSON(String(term), result.products ?? {}, Origin.var, featureStep);
96
90
  return actionOK();
97
91
  },
98
92
  },
99
93
  increment: {
100
- gwta: 'increment {what}',
101
- handlesUndefined: ['what'],
102
- action: (_, featureStep) => {
94
+ gwta: "increment {what}",
95
+ handlesUndefined: ["what"],
96
+ action: async (_, featureStep) => {
103
97
  const { term: rawTerm } = featureStep.action.stepValuesMap.what;
104
- const interpolated = this.interpolateTemplate(rawTerm, featureStep);
98
+ const interpolated = await this.interpolateTemplate(rawTerm, featureStep);
105
99
  if (interpolated.error)
106
100
  return actionNotOK(interpolated.error);
107
101
  const term = interpolated?.value;
108
- const resolved = this.getWorld().shared.resolveVariable({ term, origin: Origin.var }, featureStep);
102
+ const resolved = await this.getWorld().shared.resolveVariable({ term, origin: Origin.var }, featureStep);
109
103
  const presentVal = resolved.value;
110
104
  const effectiveDomain = resolved.domain;
111
105
  if (presentVal === undefined) {
@@ -125,7 +119,7 @@ class VariablesStepper extends AStepper {
125
119
  if (nextVal === presentVal) {
126
120
  return OK;
127
121
  }
128
- this.getWorld().shared.set({ term: String(term), value: nextVal, domain: effectiveDomain, origin: Origin.var }, provenanceFromFeatureStep(featureStep));
122
+ await this.getWorld().shared.set({ term: String(term), value: nextVal, domain: effectiveDomain, origin: Origin.var }, provenanceFromFeatureStep(featureStep));
129
123
  return OK;
130
124
  }
131
125
  // Fallback: numeric increment
@@ -134,252 +128,267 @@ class VariablesStepper extends AStepper {
134
128
  return actionNotOK(`cannot increment non-numeric variable ${term} with value "${presentVal}"`);
135
129
  }
136
130
  const newNum = numVal + 1;
137
- this.getWorld().shared.set({ term: String(term), value: String(newNum), domain: effectiveDomain, origin: Origin.var }, provenanceFromFeatureStep(featureStep));
138
- this.getWorld().eventLogger.log(featureStep, 'info', `incremented ${term} to ${newNum}`, {
131
+ await this.getWorld().shared.set({ term: String(term), value: String(newNum), domain: effectiveDomain, origin: Origin.var }, provenanceFromFeatureStep(featureStep));
132
+ this.getWorld().eventLogger.log(featureStep, "info", `incremented ${term} to ${newNum}`, {
139
133
  variable: term,
140
134
  oldValue: presentVal,
141
135
  newValue: newNum,
142
- operation: 'increment'
136
+ operation: "increment",
143
137
  });
144
138
  return OK;
145
- }
139
+ },
146
140
  },
147
141
  showEnv: {
148
- gwta: 'show env',
149
- expose: false,
142
+ gwta: "show env",
143
+ exposeMCP: false,
150
144
  action: () => {
151
- // Obscure secret environment variables (matching /password/i)
152
145
  const envVars = this.world.options.envVariables || {};
153
146
  const shared = this.getWorld().shared;
154
147
  const safeEnv = sanitizeObjectSecrets(envVars, (key) => shared.isSecret(key));
155
- this.getWorld().eventLogger.info(`env: ${JSON.stringify(safeEnv, null, 2)}`, { env: safeEnv });
156
- return Promise.resolve(OK);
157
- }
148
+ const count = Object.keys(safeEnv).length;
149
+ return actionOKWithProducts({ _type: "Environment", _summary: `${count} environment variables`, env: safeEnv });
150
+ },
158
151
  },
159
152
  showVars: {
160
- gwta: 'show vars',
161
- action: () => {
153
+ gwta: "show vars",
154
+ action: async () => {
162
155
  const shared = this.getWorld().shared;
163
- const displayVars = Object.fromEntries(Object.entries(shared.all()).map(([key, variable]) => [key, variable.value]));
156
+ const displayVars = Object.fromEntries(Object.entries(await shared.all()).map(([key, variable]) => [key, variable.value]));
164
157
  const safeVars = sanitizeObjectSecrets(displayVars, (key) => shared.isSecret(key));
165
- this.getWorld().eventLogger.info(`vars: ${JSON.stringify(safeVars, null, 2)}`, { vars: safeVars });
166
- return actionOK();
158
+ const count = Object.keys(safeVars).length;
159
+ return actionOKWithProducts({ _type: "Variables", _summary: `${count} variables`, vars: safeVars });
167
160
  },
168
161
  },
169
162
  set: {
170
- gwta: 'set( empty)? {what: string} to {value: string}',
171
- handlesUndefined: ['what', 'value'],
172
- precludes: ['Haibun.prose'],
173
- action: (args, featureStep) => {
163
+ gwta: "set( empty)? {what: string} to {value: string}",
164
+ handlesUndefined: ["what", "value"],
165
+ precludes: ["Haibun.prose"],
166
+ action: async (_, featureStep) => {
174
167
  const { term: rawTerm, domain, origin } = featureStep.action.stepValuesMap.what;
175
- const parsedValue = this.getWorld().shared.resolveVariable(featureStep.action.stepValuesMap.value, featureStep, undefined, { secure: true });
168
+ const parsedValue = await this.getWorld().shared.resolveVariable(featureStep.action.stepValuesMap.value, featureStep, undefined, {
169
+ secure: true,
170
+ });
176
171
  if (parsedValue.value === undefined)
177
172
  return actionNotOK(`Variable ${featureStep.action.stepValuesMap.value.term} not found`);
178
173
  const resolved = { value: String(parsedValue.value) };
179
- const interpolated = this.interpolateTemplate(rawTerm, featureStep);
174
+ const interpolated = await this.interpolateTemplate(rawTerm, featureStep);
180
175
  if (interpolated.error)
181
176
  return actionNotOK(interpolated.error);
182
177
  const term = interpolated?.value;
183
- const skip = shouldSkipEmpty(featureStep, term, this.getWorld().shared);
178
+ const skip = await shouldSkipEmpty(featureStep, term, this.getWorld().shared);
184
179
  if (skip)
185
180
  return skip;
186
181
  // Inherit domain from existing variable if not explicitly specified
187
- const existing = this.getWorld().shared.resolveVariable({ term, origin: Origin.var }, featureStep);
188
- const effectiveDomain = (domain === DOMAIN_STRING && existing?.domain) ? existing.domain : (domain || DOMAIN_STRING);
182
+ const existing = await this.getWorld().shared.resolveVariable({ term, origin: Origin.var }, featureStep);
183
+ const effectiveDomain = domain === DOMAIN_STRING && existing?.domain ? existing.domain : domain || DOMAIN_STRING;
189
184
  const result = trySetVariable(this.getWorld().shared, { term, value: resolved.value, domain: effectiveDomain, origin, secret: interpolated.secret || parsedValue.secret }, provenanceFromFeatureStep(featureStep));
190
185
  return result;
191
- }
186
+ },
192
187
  },
193
188
  setAs: {
194
- gwta: 'set( empty)? {what} as {domain} to {value}',
195
- handlesUndefined: ['what', 'domain', 'value'],
189
+ gwta: "set( empty)? {what} as {domain} to {value}",
190
+ handlesUndefined: ["what", "domain", "value"],
196
191
  precludes: [`${VariablesStepper.name}.set`],
197
- action: ({ value, domain }, featureStep) => {
192
+ action: async ({ domain }, featureStep) => {
198
193
  const readonly = !!featureStep.in.match(/ as read-only /);
199
194
  const { term: rawTerm, origin } = featureStep.action.stepValuesMap.what;
200
- const parsedValue = this.getWorld().shared.resolveVariable(featureStep.action.stepValuesMap.value, featureStep, undefined, { secure: true });
195
+ const parsedValue = await this.getWorld().shared.resolveVariable(featureStep.action.stepValuesMap.value, featureStep, undefined, {
196
+ secure: true,
197
+ });
201
198
  if (parsedValue.value === undefined)
202
199
  return actionNotOK(`Variable ${featureStep.action.stepValuesMap.value.term} not found`);
203
200
  const resolved = { value: String(parsedValue.value) };
204
- const interpolated = this.interpolateTemplate(rawTerm, featureStep);
201
+ const interpolated = await this.interpolateTemplate(rawTerm, featureStep);
205
202
  if (interpolated.error)
206
203
  return actionNotOK(interpolated.error);
207
204
  const term = interpolated.value;
208
- const skip = shouldSkipEmpty(featureStep, term, this.getWorld().shared);
205
+ const skip = await shouldSkipEmpty(featureStep, term, this.getWorld().shared);
209
206
  if (skip)
210
207
  return skip;
211
208
  // Fallback for unquoted domain names (e.g. 'as number') that resolve to undefined
212
- let effectiveDomain = domain ?? getStepTerm(featureStep, 'domain');
209
+ let effectiveDomain = domain ?? getStepTerm(featureStep, "domain");
213
210
  if (effectiveDomain) {
214
- if (effectiveDomain.startsWith('read-only ')) {
215
- effectiveDomain = effectiveDomain.replace('read-only ', '');
211
+ if (effectiveDomain.startsWith("read-only ")) {
212
+ effectiveDomain = effectiveDomain.replace("read-only ", "");
216
213
  }
217
214
  if (effectiveDomain.startsWith('"') && effectiveDomain.endsWith('"')) {
218
215
  effectiveDomain = effectiveDomain.slice(1, -1);
219
216
  }
220
217
  }
221
218
  let finalValue = resolved.value;
222
- if (typeof finalValue === 'string' && finalValue.startsWith('"') && finalValue.endsWith('"')) {
219
+ if (typeof finalValue === "string" && finalValue.startsWith('"') && finalValue.endsWith('"')) {
223
220
  finalValue = finalValue.slice(1, -1);
224
221
  }
225
222
  return trySetVariable(this.getWorld().shared, { term, value: finalValue, domain: effectiveDomain, origin, readonly, secret: interpolated.secret || parsedValue.secret }, provenanceFromFeatureStep(featureStep));
226
- }
223
+ },
227
224
  },
228
225
  unset: {
229
- gwta: 'unset {what: string}',
230
- action: ({ what }, featureStep) => {
226
+ gwta: "unset {what: string}",
227
+ action: async (_, featureStep) => {
231
228
  const { term } = featureStep.action.stepValuesMap.what;
232
- this.getWorld().shared.unset(term);
233
- return Promise.resolve(OK);
234
- }
229
+ await this.getWorld().shared.unset(term);
230
+ return OK;
231
+ },
235
232
  },
236
233
  setRandom: {
237
234
  precludes: [`${VariablesStepper.name}.set`],
238
235
  gwta: `set( empty)? {what: string} to {length: number} random characters`,
239
- handlesUndefined: ['what'],
240
- action: ({ length }, featureStep) => {
236
+ handlesUndefined: ["what"],
237
+ action: async ({ length }, featureStep) => {
241
238
  const { term } = featureStep.action.stepValuesMap.what;
242
239
  if (length < 1 || length > 100) {
243
240
  return actionNotOK(`length ${length} must be between 1 and 100`);
244
241
  }
245
- const skip = shouldSkipEmpty(featureStep, term, this.getWorld().shared);
242
+ const skip = await shouldSkipEmpty(featureStep, term, this.getWorld().shared);
246
243
  if (skip)
247
244
  return skip;
248
- let rand = '';
245
+ let rand = "";
249
246
  while (rand.length < length) {
250
- rand += Math.random().toString(36).substring(2, 2 + length);
247
+ rand += Math.random()
248
+ .toString(36)
249
+ .substring(2, 2 + length);
251
250
  }
252
251
  rand = rand.substring(0, length);
253
252
  return trySetVariable(this.getWorld().shared, { term, value: rand, domain: DOMAIN_STRING, origin: Origin.var }, provenanceFromFeatureStep(featureStep));
254
- }
253
+ },
255
254
  },
256
255
  is: {
257
- gwta: 'variable {what} is {value}',
258
- handlesUndefined: ['what', 'value'],
259
- action: (_, featureStep) => {
256
+ gwta: "variable {what} is {value}",
257
+ handlesUndefined: ["what", "value"],
258
+ action: async (_, featureStep) => {
260
259
  const { term: rawTerm } = featureStep.action.stepValuesMap.what;
261
- const interpolated = this.interpolateTemplate(rawTerm, featureStep);
260
+ const interpolated = await this.interpolateTemplate(rawTerm, featureStep);
262
261
  if (interpolated.error)
263
262
  return actionNotOK(interpolated.error);
264
263
  const term = interpolated.value;
265
- const resolved = this.getWorld().shared.resolveVariable({ term, origin: Origin.defined }, featureStep, undefined, { secure: true });
264
+ const resolved = await this.getWorld().shared.resolveVariable({ term, origin: Origin.defined }, featureStep, undefined, {
265
+ secure: true,
266
+ });
266
267
  if (resolved.value === undefined || (resolved.origin !== Origin.var && resolved.origin !== Origin.env)) {
267
268
  return actionNotOK(`${term} is not set`);
268
269
  }
269
- const parsedValue = this.getWorld().shared.resolveVariable(featureStep.action.stepValuesMap.value, featureStep, undefined, { secure: true });
270
+ const parsedValue = await this.getWorld().shared.resolveVariable(featureStep.action.stepValuesMap.value, featureStep, undefined, {
271
+ secure: true,
272
+ });
270
273
  if (parsedValue.value === undefined)
271
274
  return actionNotOK(`Variable ${featureStep.action.stepValuesMap.value.term} not found`);
272
275
  const value = String(parsedValue.value);
273
276
  const domainKey = normalizeDomainKey(resolved.domain);
274
- const compareVal = this.getWorld().domains[domainKey].coerce({ term: '_cmp', value, domain: domainKey, origin: Origin.quoted }, featureStep, this.steppers);
275
- return JSON.stringify(resolved.value) === JSON.stringify(compareVal) ? OK : actionNotOK(`${term} is ${JSON.stringify(resolved.value)}, not ${JSON.stringify(compareVal)}`);
276
- }
277
+ const compareVal = this.getWorld().domains[domainKey].coerce({ term: "_cmp", value, domain: domainKey, origin: Origin.quoted }, featureStep, this.steppers);
278
+ return JSON.stringify(resolved.value) === JSON.stringify(compareVal)
279
+ ? OK
280
+ : actionNotOK(`${term} is ${JSON.stringify(resolved.value)}, not ${JSON.stringify(compareVal)}`);
281
+ },
277
282
  },
278
283
  isLessThan: {
279
- gwta: 'variable {what} is less than {value}',
280
- handlesUndefined: ['what', 'value'],
281
- precludes: ['VariablesStepper.is'],
284
+ gwta: "variable {what} is less than {value}",
285
+ handlesUndefined: ["what", "value"],
286
+ precludes: ["VariablesStepper.is"],
282
287
  action: ({ what, value }, featureStep) => {
283
- const term = getStepTerm(featureStep, 'what') ?? what;
284
- return this.compareValues(featureStep, term, value, '<');
285
- }
288
+ const term = getStepTerm(featureStep, "what") ?? what;
289
+ return this.compareValues(featureStep, term, value, "<");
290
+ },
286
291
  },
287
292
  isMoreThan: {
288
- gwta: 'variable {what} is more than {value}',
289
- handlesUndefined: ['what', 'value'],
290
- precludes: ['VariablesStepper.is'],
293
+ gwta: "variable {what} is more than {value}",
294
+ handlesUndefined: ["what", "value"],
295
+ precludes: ["VariablesStepper.is"],
291
296
  action: ({ what, value }, featureStep) => {
292
- const term = getStepTerm(featureStep, 'what') ?? what;
293
- return this.compareValues(featureStep, term, value, '>');
294
- }
297
+ const term = getStepTerm(featureStep, "what") ?? what;
298
+ return this.compareValues(featureStep, term, value, ">");
299
+ },
295
300
  },
296
301
  exists: {
297
- gwta: 'variable {what} exists',
298
- handlesUndefined: ['what'],
299
- action: ({ what }, featureStep) => {
300
- const term = (getStepTerm(featureStep, 'what') ?? what);
301
- const sharedVars = this.getWorld().shared.all();
302
+ gwta: "variable {what} exists",
303
+ handlesUndefined: ["what"],
304
+ action: async ({ what }, featureStep) => {
305
+ const term = (getStepTerm(featureStep, "what") ?? what);
306
+ const sharedVars = await this.getWorld().shared.all();
302
307
  if (sharedVars[term])
303
308
  return OK;
304
309
  const envVars = this.getWorld().options.envVariables || {};
305
310
  return envVars[term] !== undefined ? OK : actionNotOK(`${what} not set`);
306
- }
311
+ },
307
312
  },
308
313
  showVar: {
309
- gwta: 'show var {what}',
310
- handlesUndefined: ['what'],
314
+ gwta: "show var {what}",
315
+ handlesUndefined: ["what"],
311
316
  outputSchema: z.object({ term: z.string(), value: z.unknown(), domain: z.string().optional() }),
312
- action: (_, featureStep) => {
313
- const rawTerm = getStepTerm(featureStep, 'what');
317
+ action: async (_, featureStep) => {
318
+ const rawTerm = getStepTerm(featureStep, "what");
314
319
  if (rawTerm === undefined)
315
- return actionNotOK('variable not provided');
316
- const interpolated = this.interpolateTemplate(rawTerm, featureStep);
320
+ return actionNotOK("variable not provided");
321
+ const interpolated = await this.interpolateTemplate(rawTerm, featureStep);
317
322
  if (interpolated.error)
318
323
  return actionNotOK(interpolated.error);
319
- const term = interpolated.value || '';
324
+ const term = interpolated.value || "";
320
325
  const shared = this.getWorld().shared;
321
- const stepValue = shared.resolveVariable({ term, origin: Origin.defined }, featureStep);
326
+ const stepValue = await shared.resolveVariable({ term, origin: Origin.defined }, featureStep);
322
327
  const isSecret = shared.isSecret(term) || stepValue.secret === true;
323
328
  if (stepValue.value === undefined) {
324
329
  this.getWorld().eventLogger.info(`${term} is undefined`);
325
330
  return actionOKWithProducts({ term, value: undefined, domain: stepValue.domain });
326
331
  }
327
- const displayValue = isSecret ? { ...stepValue, value: OBSCURED_VALUE } : stepValue;
328
- const provenance = featureStep.action.stepValuesMap.what.provenance?.map((p, i) => ({ [i]: { in: p.in, seq: p.seq.join(','), when: p.when } }));
329
- this.getWorld().eventLogger.info(`${term} is ${JSON.stringify({ ...displayValue, provenance }, null, 2)}`, { variable: term, value: displayValue });
330
- return actionOKWithProducts({ term, value: stepValue.value, domain: stepValue.domain });
331
- }
332
+ const displayValue = isSecret ? OBSCURED_VALUE : stepValue.value;
333
+ const summary = `${term} = ${typeof displayValue === "object" ? JSON.stringify(displayValue) : String(displayValue)}`;
334
+ return actionOKWithProducts({ _type: "Variable", _summary: summary, term, value: stepValue.value, domain: stepValue.domain });
335
+ },
332
336
  },
333
337
  showDomains: {
334
- gwta: 'show domains',
335
- action: () => {
338
+ gwta: "show domains",
339
+ action: async () => {
336
340
  const domains = this.getWorld().domains;
337
- const allVars = this.getWorld().shared.all();
338
- const summary = {};
341
+ const allVars = await this.getWorld().shared.all();
342
+ const items = [];
343
+ // Collect vertexLabel→name mapping for base type edge targets
344
+ const labelToDomain = new Map();
345
+ for (const [dname, ddef] of Object.entries(domains)) {
346
+ const vl = ddef.topology?.vertexLabel;
347
+ labelToDomain.set(vl || dname, vl || dname);
348
+ }
339
349
  for (const [name, def] of Object.entries(domains)) {
340
350
  let members = 0;
341
351
  for (const variable of Object.values(allVars)) {
342
- if (variable.domain && normalizeDomainKey(variable.domain) === name) {
352
+ if (variable.domain && normalizeDomainKey(variable.domain) === name)
343
353
  members++;
344
- }
345
- }
346
- let type = 'schema';
347
- if (def.values) {
348
- type = def.values;
349
354
  }
350
- else if (def.description) {
351
- type = def.description;
355
+ const description = def.values || def.description || "schema";
356
+ const topology = def.topology;
357
+ const vertexLabel = topology?.vertexLabel;
358
+ const _edges = [];
359
+ // Edges from topology (vertex→vertex relationships like Email→Contact)
360
+ const topologyEdges = topology?.edges;
361
+ if (topologyEdges) {
362
+ for (const [edgeName, edge] of Object.entries(topologyEdges)) {
363
+ if (edge.range && edge.range !== vertexLabel)
364
+ _edges.push({ type: edgeName, targetId: edge.range });
365
+ }
352
366
  }
353
- summary[name] = {
354
- type,
355
- members,
356
- ordered: !!def.comparator
357
- };
367
+ items.push({ name, description, members, ...(vertexLabel ? { vertexLabel } : {}), ...(_edges.length ? { _edges } : {}) });
358
368
  }
359
- this.getWorld().eventLogger.info(`Domains: ${JSON.stringify(summary, null, 2)}`, { domains: summary });
360
- return OK;
361
- }
369
+ return actionOKWithProducts({ _type: "Domain", _summary: `${items.length} domains`, items });
370
+ },
362
371
  },
363
372
  showDomain: {
364
- gwta: 'show domain {name}',
365
- handlesUndefined: ['name'],
366
- action: (_, featureStep) => {
367
- const name = getStepTerm(featureStep, 'name');
373
+ gwta: "show domain {name}",
374
+ handlesUndefined: ["name"],
375
+ action: async (_, featureStep) => {
376
+ const name = getStepTerm(featureStep, "name");
368
377
  const domain = this.getWorld().domains[name];
369
378
  if (!domain) {
370
379
  return actionNotOK(`Domain "${name}" not found`);
371
380
  }
372
381
  const shared = this.getWorld().shared;
373
- const allVars = shared.all();
382
+ const allVars = await shared.all();
374
383
  const members = {};
375
384
  for (const [key, variable] of Object.entries(allVars)) {
376
385
  if (variable.domain && normalizeDomainKey(variable.domain) === name) {
377
386
  members[key] = shared.isSecret(key) ? OBSCURED_VALUE : variable.value;
378
387
  }
379
388
  }
380
- this.getWorld().eventLogger.info(`Domain "${name}": ${JSON.stringify({ ...domain, members }, null, 2)}`, { domain: name, ...domain, members });
381
- return OK;
382
- }
389
+ const memberCount = Object.keys(members).length;
390
+ return actionOKWithProducts({ _type: "Domain", _summary: `${name}: ${memberCount} members`, domain: name, ...domain, members });
391
+ },
383
392
  },
384
393
  // Membership check: value is in domain (enum or member values)
385
394
  // Handles quoted ("value"), braced ({var}), or bare (value) forms
@@ -387,23 +396,22 @@ class VariablesStepper extends AStepper {
387
396
  isIn: {
388
397
  match: /^(.+) is in ([a-zA-Z][a-zA-Z0-9 ]*)$/,
389
398
  fallback: true,
390
- action: (_, featureStep) => {
399
+ action: async (_, featureStep) => {
391
400
  const matchResult = featureStep.in.match(/^(.+) is in ([a-zA-Z][a-zA-Z0-9 ]*)$/);
392
401
  if (!matchResult) {
393
402
  return actionNotOK('Invalid "is in" syntax');
394
403
  }
395
404
  let valueTerm = matchResult[1].trim();
396
405
  // Strip quotes if present
397
- if ((valueTerm.startsWith('"') && valueTerm.endsWith('"')) ||
398
- (valueTerm.startsWith('`') && valueTerm.endsWith('`'))) {
406
+ if ((valueTerm.startsWith('"') && valueTerm.endsWith('"')) || (valueTerm.startsWith("`") && valueTerm.endsWith("`"))) {
399
407
  valueTerm = valueTerm.slice(1, -1);
400
408
  }
401
409
  // Strip braces if present and resolve variable
402
- if (valueTerm.startsWith('{') && valueTerm.endsWith('}')) {
410
+ if (valueTerm.startsWith("{") && valueTerm.endsWith("}")) {
403
411
  valueTerm = valueTerm.slice(1, -1);
404
412
  }
405
413
  // Try to resolve as variable, fall back to literal
406
- const resolvedValue = this.getWorld().shared.get(valueTerm, true);
414
+ const resolvedValue = await this.getWorld().shared.get(valueTerm, true);
407
415
  const actualValue = resolvedValue !== undefined ? String(resolvedValue) : valueTerm;
408
416
  const domainName = matchResult[2].trim();
409
417
  const domainKey = normalizeDomainKey(domainName);
@@ -416,14 +424,12 @@ class VariablesStepper extends AStepper {
416
424
  return OK;
417
425
  }
418
426
  // Check member values
419
- const allVars = this.getWorld().shared.all();
427
+ const allVars = await this.getWorld().shared.all();
420
428
  const memberValues = Object.values(allVars)
421
- .filter(v => v.domain && normalizeDomainKey(v.domain) === domainKey)
422
- .map(v => String(v.value));
423
- return memberValues.includes(actualValue)
424
- ? OK
425
- : actionNotOK(`"${actualValue}" is not in ${domainName}`);
426
- }
429
+ .filter((v) => v.domain && normalizeDomainKey(v.domain) === domainKey)
430
+ .map((v) => String(v.value));
431
+ return memberValues.includes(actualValue) ? OK : actionNotOK(`"${actualValue}" is not in ${domainName}`);
432
+ },
427
433
  },
428
434
  // Pattern matching: glob-style patterns for human-readable matching
429
435
  // Usage: matches {host} with "*.wikipedia.org"
@@ -432,40 +438,40 @@ class VariablesStepper extends AStepper {
432
438
  // Supports * as wildcard (matches any characters)
433
439
  // Variables in pattern are interpolated: "{counter URI}*" resolves to actual value
434
440
  matches: {
435
- gwta: 'matches {value} with {pattern}',
436
- action: ({ value, pattern }, featureStep) => {
441
+ gwta: "matches {value} with {pattern}",
442
+ action: async ({ value, pattern }, featureStep) => {
437
443
  // Interpolate value (e.g. "{request}/url" -> "req-1/url")
438
- const interpolatedValue = this.interpolateTemplate(value, featureStep);
444
+ const interpolatedValue = await this.interpolateTemplate(value, featureStep);
439
445
  if (interpolatedValue.error)
440
446
  return actionNotOK(interpolatedValue.error);
441
447
  const term = interpolatedValue.value;
442
448
  // Resolve value as a variable (e.g., "WebPlaywright/currentURI" -> actual URL)
443
- const resolvedValue = this.getWorld().shared.get(term, true);
449
+ const resolvedValue = await this.getWorld().shared.get(term, true);
444
450
  const actualValue = resolvedValue !== undefined ? String(resolvedValue) : String(term);
445
451
  // Interpolate variables in pattern (e.g., "{counter URI}*" -> "http://localhost:8123/*")
446
- const interpolated = this.interpolateTemplate(pattern, featureStep);
452
+ const interpolated = await this.interpolateTemplate(pattern, featureStep);
447
453
  if (interpolated.error)
448
454
  return actionNotOK(interpolated.error);
449
455
  const actualPattern = interpolated.value;
450
456
  // Convert glob pattern to regex
451
457
  // Escape regex special chars except *, then replace * with .*
452
- const escaped = actualPattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
453
- const regexPattern = escaped.replace(/\*/g, '.*');
458
+ const escaped = actualPattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
459
+ const regexPattern = escaped.replace(/\*/g, ".*");
454
460
  const regex = new RegExp(`^${regexPattern}$`);
455
461
  const isMatch = regex.test(actualValue);
456
- return isMatch
457
- ? OK
458
- : actionNotOK(`"${actualValue}" does not match pattern "${actualPattern}"`);
459
- }
462
+ return isMatch ? OK : actionNotOK(`"${actualValue}" does not match pattern "${actualPattern}"`);
463
+ },
460
464
  },
461
465
  };
462
466
  typedSteps = this.steps;
463
- compareValues(featureStep, rawTerm, value, operator) {
464
- const interpolated = this.interpolateTemplate(rawTerm, featureStep);
467
+ async compareValues(featureStep, rawTerm, value, operator) {
468
+ const interpolated = await this.interpolateTemplate(rawTerm, featureStep);
465
469
  if (interpolated.error)
466
470
  return actionNotOK(interpolated.error);
467
471
  const term = interpolated.value;
468
- const stored = this.getWorld().shared.resolveVariable({ term, origin: Origin.var }, featureStep, this.steppers, { secure: true });
472
+ const stored = await this.getWorld().shared.resolveVariable({ term, origin: Origin.var }, featureStep, this.steppers, {
473
+ secure: true,
474
+ });
469
475
  if (!stored) {
470
476
  return actionNotOK(`${term} is not set`);
471
477
  }
@@ -477,20 +483,20 @@ class VariablesStepper extends AStepper {
477
483
  const left = domainEntry.coerce({ ...stored, domain: domainKey }, featureStep, this.steppers);
478
484
  let rightValue = value;
479
485
  if (rightValue === undefined) {
480
- const parsed = this.getWorld().shared.resolveVariable(featureStep.action.stepValuesMap.value, featureStep);
486
+ const parsed = await this.getWorld().shared.resolveVariable(featureStep.action.stepValuesMap.value, featureStep);
481
487
  if (parsed.value === undefined)
482
488
  return actionNotOK(`Variable ${featureStep.action.stepValuesMap.value.term} not found`);
483
489
  rightValue = String(parsed.value);
484
490
  }
485
- if (typeof rightValue === 'string' && rightValue.startsWith('"') && rightValue.endsWith('"')) {
491
+ if (typeof rightValue === "string" && rightValue.startsWith('"') && rightValue.endsWith('"')) {
486
492
  rightValue = rightValue.slice(1, -1);
487
493
  }
488
494
  const right = domainEntry.coerce({ term: `${term}__comparison`, value: rightValue, domain: domainKey, origin: Origin.quoted }, featureStep, this.steppers);
489
495
  const comparison = compareDomainValues(domainEntry, left, right, stored.domain);
490
- if (operator === '>') {
496
+ if (operator === ">") {
491
497
  return comparison > 0 ? OK : actionNotOK(`${term} is ${JSON.stringify(left)}, not ${JSON.stringify(right)}`);
492
498
  }
493
- if (operator === '<') {
499
+ if (operator === "<") {
494
500
  return comparison < 0 ? OK : actionNotOK(`${term} is ${JSON.stringify(left)}, not ${JSON.stringify(right)}`);
495
501
  }
496
502
  return actionNotOK(`Unsupported operator: ${operator}`);
@@ -499,7 +505,7 @@ class VariablesStepper extends AStepper {
499
505
  * Interpolates a template string by replacing {varName} placeholders with variable values.
500
506
  * Returns the interpolated string or an error if a variable is not found.
501
507
  */
502
- interpolateTemplate(template, featureStep) {
508
+ async interpolateTemplate(template, featureStep) {
503
509
  const placeholderRegex = /\{([^}]+)\}/g;
504
510
  let result = template;
505
511
  let match;
@@ -510,7 +516,9 @@ class VariablesStepper extends AStepper {
510
516
  if (this.getWorld().shared.isSecret(varName)) {
511
517
  secret = true;
512
518
  }
513
- const resolved = this.getWorld().shared.resolveVariable({ term: varName, origin: Origin.defined }, featureStep, undefined, { secure: true });
519
+ const resolved = await this.getWorld().shared.resolveVariable({ term: varName, origin: Origin.defined }, featureStep, undefined, {
520
+ secure: true,
521
+ });
514
522
  if (resolved.value === undefined) {
515
523
  return { error: `Variable ${varName} not found` };
516
524
  }
@@ -520,15 +528,15 @@ class VariablesStepper extends AStepper {
520
528
  }
521
529
  registerSubdomainFromStatement(domain, superdomains, featureStep) {
522
530
  try {
523
- const fallback = getStepTerm(featureStep, 'superdomains') ?? featureStep.in;
531
+ const fallback = getStepTerm(featureStep, "superdomains") ?? featureStep.in;
524
532
  const superdomainNames = extractValuesFromFragments(superdomains, fallback);
525
533
  if (!superdomainNames.length) {
526
- throw new Error('Superdomain set must specify at least one superdomain');
534
+ throw new Error("Superdomain set must specify at least one superdomain");
527
535
  }
528
536
  const uniqueNames = Array.from(new Set(superdomainNames));
529
- const effectiveDomain = domain ?? getStepTerm(featureStep, 'domain');
537
+ const effectiveDomain = domain ?? getStepTerm(featureStep, "domain");
530
538
  if (!effectiveDomain)
531
- return actionNotOK('Domain name must be provided');
539
+ return actionNotOK("Domain name must be provided");
532
540
  const domainKey = normalizeDomainKey(effectiveDomain);
533
541
  if (this.getWorld().domains[domainKey]) {
534
542
  return actionNotOK(`Domain "${domainKey}" already exists`);
@@ -543,7 +551,7 @@ class VariablesStepper extends AStepper {
543
551
  });
544
552
  const enumSources = superdomainDefs.filter((entry) => Array.isArray(entry.values) && entry.values.length);
545
553
  const uniqueValues = Array.from(new Set(enumSources.flatMap((entry) => entry.values)));
546
- const description = `Values inherited from ${uniqueNames.join(', ')}`;
554
+ const description = `Values inherited from ${uniqueNames.join(", ")}`;
547
555
  if (enumSources.length === superdomainDefs.length && uniqueValues.length) {
548
556
  const definition = createEnumDomainDefinition({ name: domainKey, values: uniqueValues, description });
549
557
  registerDomains(this.getWorld(), [[definition]]);
@@ -551,7 +559,7 @@ class VariablesStepper extends AStepper {
551
559
  }
552
560
  const schemaList = superdomainDefs.map((entry) => entry.schema);
553
561
  if (!schemaList.length) {
554
- throw new Error('Superdomains did not expose any schema to derive from');
562
+ throw new Error("Superdomains did not expose any schema to derive from");
555
563
  }
556
564
  let mergedSchema = schemaList[0];
557
565
  for (let i = 1; i < schemaList.length; i++) {
@@ -572,15 +580,20 @@ class VariablesStepper extends AStepper {
572
580
  }
573
581
  registerValuesDomainFromStatement(domain, valueFragments, featureStep, options) {
574
582
  try {
575
- const values = extractValuesFromFragments(valueFragments, getStepTerm(featureStep, 'values') ?? featureStep.in);
576
- const effectiveDomain = domain ?? getStepTerm(featureStep, 'domain');
583
+ const values = extractValuesFromFragments(valueFragments, getStepTerm(featureStep, "values") ?? featureStep.in);
584
+ const effectiveDomain = domain ?? getStepTerm(featureStep, "domain");
577
585
  if (!effectiveDomain)
578
- return actionNotOK('Domain name must be provided');
586
+ return actionNotOK("Domain name must be provided");
579
587
  const domainKey = normalizeDomainKey(effectiveDomain);
580
588
  if (this.getWorld().domains[domainKey]) {
581
589
  return actionNotOK(`Domain "${domainKey}" already exists`);
582
590
  }
583
- const definition = createEnumDomainDefinition({ name: domainKey, values, description: options?.description, ordered: options?.ordered });
591
+ const definition = createEnumDomainDefinition({
592
+ name: domainKey,
593
+ values,
594
+ description: options?.description,
595
+ ordered: options?.ordered,
596
+ });
584
597
  registerDomains(this.getWorld(), [[definition]]);
585
598
  return OK;
586
599
  }
@@ -597,53 +610,58 @@ export function provenanceFromFeatureStep(featureStep) {
597
610
  return {
598
611
  in: featureStep.in,
599
612
  seq: featureStep.seqPath,
600
- when: `${featureStep.action.stepperName}.steps.${featureStep.action.actionName}`
613
+ when: `${featureStep.action.stepperName}.steps.${featureStep.action.actionName}`,
601
614
  };
602
615
  }
603
616
  const QUOTED_STRING = /"([^"]+)"/g;
604
617
  const extractValuesFromFragments = (valueFragments, fallback) => {
605
618
  if (valueFragments?.length) {
606
- const innerChunks = valueFragments.map(fragment => {
607
- const raw = fragment.in ?? fragment.action?.stepValuesMap?.items?.term ?? '';
619
+ const innerChunks = valueFragments
620
+ .map((fragment) => {
621
+ const raw = fragment.in ?? fragment.action?.stepValuesMap?.items?.term ?? "";
608
622
  const trimmed = raw.trim();
609
- if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
623
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
610
624
  return trimmed.slice(1, -1).trim();
611
625
  }
612
626
  return trimmed;
613
- }).filter(Boolean);
614
- const inner = innerChunks.join(' ').trim();
627
+ })
628
+ .filter(Boolean);
629
+ const inner = innerChunks.join(" ").trim();
615
630
  if (!inner) {
616
- throw new Error('Set values cannot be empty');
631
+ throw new Error("Set values cannot be empty");
617
632
  }
618
633
  return parseQuotedOrWordList(inner);
619
634
  }
620
635
  if (fallback) {
621
636
  return parseBracketedValues(fallback);
622
637
  }
623
- throw new Error('Set statement missing values');
638
+ throw new Error("Set statement missing values");
624
639
  };
625
640
  const parseBracketedValues = (raw) => {
626
641
  const trimmed = raw.trim();
627
- const start = trimmed.indexOf('[');
628
- const end = trimmed.lastIndexOf(']');
642
+ const start = trimmed.indexOf("[");
643
+ const end = trimmed.lastIndexOf("]");
629
644
  if (start === -1 || end === -1 || end <= start) {
630
- throw new Error('Set values must include [ ]');
645
+ throw new Error("Set values must include [ ]");
631
646
  }
632
647
  const inner = trimmed.substring(start + 1, end).trim();
633
648
  return parseQuotedOrWordList(inner);
634
649
  };
635
650
  const parseQuotedOrWordList = (value) => {
636
- const quoted = [...value.matchAll(QUOTED_STRING)].map(match => match[1].trim()).filter(Boolean);
651
+ const quoted = [...value.matchAll(QUOTED_STRING)].map((match) => match[1].trim()).filter(Boolean);
637
652
  if (quoted.length) {
638
653
  return quoted;
639
654
  }
640
- return value.split(/[\s,]+/).map(token => token.trim()).filter(Boolean);
655
+ return value
656
+ .split(/[\s,]+/)
657
+ .map((token) => token.trim())
658
+ .filter(Boolean);
641
659
  };
642
660
  const compareDomainValues = (domain, left, right, domainName) => {
643
661
  if (domain.comparator) {
644
662
  return domain.comparator(left, right);
645
663
  }
646
- if (typeof left === 'number' && typeof right === 'number') {
664
+ if (typeof left === "number" && typeof right === "number") {
647
665
  return left - right;
648
666
  }
649
667
  if (left instanceof Date && right instanceof Date) {
@@ -653,13 +671,23 @@ const compareDomainValues = (domain, left, right, domainName) => {
653
671
  };
654
672
  // ======== Helpers ========
655
673
  // Returns OK if "set empty" and variable exists
656
- function shouldSkipEmpty(featureStep, term, shared) {
657
- return (featureStep.in.includes('set empty ') && shared.resolveVariable({ term, origin: Origin.var }, featureStep, undefined, { secure: true }).value !== undefined) ? OK : undefined;
674
+ async function shouldSkipEmpty(featureStep, term, shared) {
675
+ if (!featureStep.in.includes("set empty "))
676
+ return undefined;
677
+ const resolved = await shared.resolveVariable({ term, origin: Origin.var }, featureStep, undefined, { secure: true });
678
+ return resolved.value !== undefined ? OK : undefined;
658
679
  }
659
680
  // Wraps shared.set in try/catch
660
- function trySetVariable(shared, opts, provenance) {
681
+ async function trySetVariable(shared, opts, provenance) {
661
682
  try {
662
- shared.set({ term: opts.term, value: opts.value, domain: opts.domain, origin: opts.origin, readonly: opts.readonly, secret: opts.secret }, provenance);
683
+ await shared.set({
684
+ term: opts.term,
685
+ value: opts.value,
686
+ domain: opts.domain,
687
+ origin: opts.origin,
688
+ readonly: opts.readonly,
689
+ secret: opts.secret,
690
+ }, provenance);
663
691
  return OK;
664
692
  }
665
693
  catch (e) {