jssm 5.157.0 → 5.157.1

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.
package/README.md CHANGED
@@ -18,10 +18,10 @@ Please edit the file it's derived from, instead: `./src/md/readme_base.md`
18
18
 
19
19
 
20
20
 
21
- * Generated for version 5.157.0 at 7/2/2026, 1:06:52 AM
21
+ * Generated for version 5.157.1 at 7/2/2026, 1:36:48 AM
22
22
 
23
23
  -->
24
- # jssm 5.157.0
24
+ # jssm 5.157.1
25
25
 
26
26
  [**Try the live editor**](https://stonecypher.github.io/jssm-viz-demo/graph_explorer.html) ·
27
27
  [Documentation](https://stonecypher.github.io/jssm/docs/) ·
@@ -312,7 +312,7 @@ That decision shows up everywhere downstream:
312
312
  or run `npm run benny` against your own machine.
313
313
 
314
314
  - **More thoroughly tested than any other JavaScript state-machine
315
- library.** 7,862 tests at 100.0% line coverage
315
+ library.** 7,866 tests at 100.0% line coverage
316
316
  ([report](https://coveralls.io/github/StoneCypher/jssm)), plus
317
317
  fuzz testing via `fast-check`, with parser test data across ten natural
318
318
  languages and Emoji.
@@ -445,11 +445,11 @@ If your contribution is missing here, please open an issue.
445
445
 
446
446
  <br/>
447
447
 
448
- ***7,862 tests***, run 82,904 times.
448
+ ***7,866 tests***, run 82,908 times.
449
449
 
450
- - 7,104 specs with 100.0% coverage
451
- - 758 fuzz tests with 53.4% coverage
452
- - 9,871 TypeScript lines - 0.8 tests per line, 8.4 generated tests per line
450
+ - 7,108 specs with 100.0% coverage
451
+ - 758 fuzz tests with 53.5% coverage
452
+ - 9,879 TypeScript lines - 0.8 tests per line, 8.4 generated tests per line
453
453
 
454
454
  [![Actions Status](https://github.com/StoneCypher/jssm/workflows/Node%20CI/badge.svg)](https://github.com/StoneCypher/jssm/actions)
455
455
  [![NPM version](https://img.shields.io/npm/v/jssm.svg)](https://www.npmjs.com/package/jssm)
@@ -20769,11 +20769,26 @@ const weighted_rand_select = (options, probability_property = 'probability', rng
20769
20769
  if (!(typeof options[0] === 'object')) {
20770
20770
  throw new TypeError('options must be a non-empty array of objects');
20771
20771
  }
20772
- const frand = rng
20773
- ? (cap) => rng() * cap
20774
- : (cap) => Math.random() * cap, or_one = (item) => item === undefined ? 1 : item, prob_sum = options.reduce((acc, val) => acc + or_one(val[probability_property]), 0), rnd = frand(prob_sum);
20772
+ // called once per probabilistic walk step: plain loops, no per-call closure
20773
+ // allocations (previously frand, or_one, and a reduce callback each call).
20774
+ // undefined weights count as 1, as before.
20775
+ let prob_sum = 0;
20776
+ for (const opt of options) { // eslint-disable-line fp/no-loops
20777
+ const p = opt[probability_property];
20778
+ prob_sum += (p === undefined) ? 1 : p;
20779
+ }
20780
+ const rnd = (rng ? rng() : Math.random()) * prob_sum;
20775
20781
  let cursor = 0, cursor_sum = 0;
20776
- while (cursor < options.length && (cursor_sum += or_one(options[cursor++][probability_property])) <= rnd) { } // eslint-disable-line no-empty,fp/no-loops
20782
+ // advance past each element whose running sum is <= rnd; the element that
20783
+ // pushes the sum over rnd is the selection
20784
+ while (cursor < options.length) { // eslint-disable-line fp/no-loops
20785
+ const p = options[cursor][probability_property];
20786
+ cursor_sum += (p === undefined) ? 1 : p;
20787
+ ++cursor;
20788
+ if (cursor_sum > rnd) {
20789
+ break;
20790
+ }
20791
+ }
20777
20792
  return options[cursor - 1];
20778
20793
  };
20779
20794
  /* eslint-enable flowtype/no-weak-types */
@@ -23563,7 +23578,7 @@ var constants = /*#__PURE__*/Object.freeze({
23563
23578
  * Useful for runtime diagnostics and for embedding in serialized machine
23564
23579
  * snapshots so that deserializers can detect version-skew.
23565
23580
  */
23566
- const version = "5.157.0";
23581
+ const version = "5.157.1";
23567
23582
 
23568
23583
  // whargarbl lots of these return arrays could/should be sets
23569
23584
  const { state_name_chars, state_name_first_chars, action_label_chars } = constants;
@@ -23864,8 +23879,11 @@ function find_connected_components(states, edges) {
23864
23879
  const component = [];
23865
23880
  const queue = [start];
23866
23881
  visited.add(start);
23867
- while (queue.length > 0) {
23868
- const node = queue.shift();
23882
+ // index-pointer pop: Array.shift is O(n) per pop, making the BFS O(V²)
23883
+ // worst case; reading by cursor keeps it O(V + E)
23884
+ let head = 0;
23885
+ while (head < queue.length) {
23886
+ const node = queue[head++];
23869
23887
  component.push(node);
23870
23888
  for (const neighbor of adj.get(node)) {
23871
23889
  if (!visited.has(neighbor)) {
@@ -24080,6 +24098,9 @@ class Machine {
24080
24098
  // nested Map+Set keeps the check O(1) per edge rather than an O(out-degree)
24081
24099
  // scan (which made construction O(V*E) on dense graphs). #673
24082
24100
  const seen_edges = new Map();
24101
+ // complete.includes was an O(|complete|) array scan per newly-created
24102
+ // state — O(V·C) overall; one Set turns it into O(V)
24103
+ const complete_set = new Set(complete);
24083
24104
  // walk the transitions. single-lookup cursor fetches: each endpoint was
24084
24105
  // previously a get followed by a has on the same key (four hashes per
24085
24106
  // edge); the undefined check on the get's result carries the same
@@ -24094,12 +24115,12 @@ class Machine {
24094
24115
  // get the cursors. what a mess
24095
24116
  let cursor_from = this._states.get(tr.from);
24096
24117
  if (cursor_from === undefined) {
24097
- cursor_from = { name: tr.from, from: [], to: [], complete: complete.includes(tr.from) };
24118
+ cursor_from = { name: tr.from, from: [], to: [], complete: complete_set.has(tr.from) };
24098
24119
  this._new_state(cursor_from);
24099
24120
  }
24100
24121
  let cursor_to = this._states.get(tr.to);
24101
24122
  if (cursor_to === undefined) {
24102
- cursor_to = { name: tr.to, from: [], to: [], complete: complete.includes(tr.to) };
24123
+ cursor_to = { name: tr.to, from: [], to: [], complete: complete_set.has(tr.to) };
24103
24124
  this._new_state(cursor_to);
24104
24125
  }
24105
24126
  // record (from -> to) adjacency once per distinct target, even when
@@ -25345,11 +25366,17 @@ class Machine {
25345
25366
  // filter -> filter chain and its three intermediate arrays; selection and
25346
25367
  // ordering semantics are unchanged
25347
25368
  const legal_exits = [], probability_bearing = [];
25369
+ // hoisted: every exit shares whichState, so probe _edge_map for the
25370
+ // from-side once instead of re-hashing the same key per exit inside
25371
+ // lookup_transition_for. wstate.to is non-empty only when at least one
25372
+ // outbound edge exists, and every outbound edge creates the from-side
25373
+ // mapping at construction — so emg is defined whenever the loop runs.
25374
+ const emg = this._edge_map.get(whichState);
25348
25375
  for (const ws of wstate.to) {
25349
- // wstate.to is built from the same edge set lookup_transition_for
25350
- // resolves against, so the lookup cannot miss; the guard mirrors the
25351
- // old defensive .filter(Boolean) and is equally unreachable.
25352
- const edge = this.lookup_transition_for(whichState, ws);
25376
+ // wstate.to is built from the same edge set _edge_map indexes, so the
25377
+ // per-target get cannot miss; the guard mirrors the old defensive
25378
+ // .filter(Boolean) and is equally unreachable.
25379
+ const edge = this._edges[emg.get(ws)];
25353
25380
  /* v8 ignore next */
25354
25381
  if (!edge) {
25355
25382
  continue;
@@ -26750,12 +26777,23 @@ class Machine {
26750
26777
  // instead of O(E) — a large win on dense graphs where d << E. The `?? []`
26751
26778
  // covers from-states that have no outgoing edges (terminal states) and
26752
26779
  // states that don't exist at all, both of which return [] without iterating.
26780
+ //
26781
+ // The match itself compares interned numeric state ids against the packed
26782
+ // _edge_to_ids array rather than dereferencing each edge object for a
26783
+ // string compare: non-matching edges never touch an edge object, which is
26784
+ // most of the cost on dense shapes (heavier edge objects degrade a deref
26785
+ // loop — the 5.142/5.143 regression mechanism). Every state named by any
26786
+ // edge is interned at construction, so an unknown `to` provably has no
26787
+ // edges and returns [] immediately.
26788
+ const to_id = this._state_interner.id_of(to);
26789
+ if (to_id === undefined) {
26790
+ return [];
26791
+ }
26753
26792
  const outbound = (_a = this._outbound_edge_ids.get(from)) !== null && _a !== void 0 ? _a : [];
26754
26793
  const result = [];
26755
26794
  for (const edgeId of outbound) {
26756
- const edge = this._edges[edgeId];
26757
- if (edge.to === to) {
26758
- result.push(edge);
26795
+ if (this._edge_to_ids[edgeId] === to_id) {
26796
+ result.push(this._edges[edgeId]);
26759
26797
  }
26760
26798
  }
26761
26799
  return result;
@@ -27045,19 +27083,15 @@ class Machine {
27045
27083
  const edgeId = (to_id === undefined) ? undefined : this._edge_id_by_pair.get(pair_key(this._state_id, to_id));
27046
27084
  if ((edgeId !== undefined) && (!(this._edges[edgeId].forced_only))) {
27047
27085
  if (this._has_transition_hooks || this._has_post_transition_hooks) {
27048
- // first matching outbound edge's kind, without building the result
27049
- // array edges_between allocated here on every hooked transition.
27050
- // First-match semantics are kept deliberately: _edge_map is
27051
- // last-wins for multi-edge (from, to) pairs, so lookup_transition_for
27052
- // could disagree with the old edges_between(...)[0]. #735
27053
- // TODO this won't do the right thing if various edges have different types
27054
- for (const ob_eid of this._outbound_edge_ids.get(this._state)) {
27055
- const ob_edge = this._edges[ob_eid];
27056
- if (ob_edge.to === newStateOrAction) {
27057
- trans_type = ob_edge.kind;
27058
- break;
27059
- }
27060
- }
27086
+ // kind of the dispatched edge. _edge_id_by_pair and _edge_map are
27087
+ // both first-declared-wins for parallel (from, to) pairs (see the
27088
+ // constructor around _edge_map / _edge_id_by_pair), and
27089
+ // _outbound_edge_ids fills in declaration order so the old
27090
+ // first-match outbound scan always resolved to this same edgeId.
27091
+ // Direct read replaces the O(out-degree) object-deref scan; the
27092
+ // first-declared-kind semantics are pinned by the parallel-edge
27093
+ // transition-kind hook spec. #735
27094
+ trans_type = this._edges[edgeId].kind;
27061
27095
  }
27062
27096
  valid = true;
27063
27097
  newState = newStateOrAction;
@@ -27457,6 +27491,13 @@ class Machine {
27457
27491
  * Called internally after each transition.
27458
27492
  */
27459
27493
  auto_set_state_timeout() {
27494
+ // called on every successful transition-commit. Machines with no `after`
27495
+ // clauses at all (the overwhelmingly common case) previously still paid a
27496
+ // string hash + map probe here per transition; one integer size read
27497
+ // short-circuits that.
27498
+ if (this._after_mapping.size === 0) {
27499
+ return;
27500
+ }
27460
27501
  const after_res = this._after_mapping.get(this._state);
27461
27502
  if (after_res !== undefined) {
27462
27503
  const [next_state, after_time] = after_res;
@@ -28742,6 +28783,14 @@ function is_hook_complex_result(hr) {
28742
28783
  *
28743
28784
  */
28744
28785
  function _update_hook_fields(hook_args, res) {
28786
+ // HOOK_PASSED is the shared frozen outcome for "no hook installed" and for
28787
+ // hooks returning true/undefined — the overwhelming majority of the up-to-
28788
+ // ~10 steps per hooked transition. It can never carry `data` (frozen, built
28789
+ // without one), so one pointer compare replaces the hasOwnProperty
28790
+ // reflection call for the common case.
28791
+ if (res === HOOK_PASSED) {
28792
+ return false;
28793
+ }
28745
28794
  if (Object.prototype.hasOwnProperty.call(res, 'data')) {
28746
28795
  hook_args.data = res.data;
28747
28796
  hook_args.next_data = res.next_data;
@@ -28760,6 +28809,8 @@ function _update_hook_fields(hook_args, res) {
28760
28809
  * so a shared instance is observationally identical; freezing turns that
28761
28810
  * read-only contract from incidental into enforced. Complex results (hooks
28762
28811
  * returning `{ pass, data, ... }`) still pass through untouched. #705
28812
+ * _update_hook_fields additionally identity-checks HOOK_PASSED to skip its
28813
+ * own-property probe on the common no-op outcome.
28763
28814
  *
28764
28815
  * @see abstract_hook_step
28765
28816
  * @see abstract_everything_hook_step
package/dist/cdn/viz.js CHANGED
@@ -20794,11 +20794,26 @@ const weighted_rand_select = (options, probability_property = 'probability', rng
20794
20794
  if (!(typeof options[0] === 'object')) {
20795
20795
  throw new TypeError('options must be a non-empty array of objects');
20796
20796
  }
20797
- const frand = rng
20798
- ? (cap) => rng() * cap
20799
- : (cap) => Math.random() * cap, or_one = (item) => item === undefined ? 1 : item, prob_sum = options.reduce((acc, val) => acc + or_one(val[probability_property]), 0), rnd = frand(prob_sum);
20797
+ // called once per probabilistic walk step: plain loops, no per-call closure
20798
+ // allocations (previously frand, or_one, and a reduce callback each call).
20799
+ // undefined weights count as 1, as before.
20800
+ let prob_sum = 0;
20801
+ for (const opt of options) { // eslint-disable-line fp/no-loops
20802
+ const p = opt[probability_property];
20803
+ prob_sum += (p === undefined) ? 1 : p;
20804
+ }
20805
+ const rnd = (rng ? rng() : Math.random()) * prob_sum;
20800
20806
  let cursor = 0, cursor_sum = 0;
20801
- while (cursor < options.length && (cursor_sum += or_one(options[cursor++][probability_property])) <= rnd) { } // eslint-disable-line no-empty,fp/no-loops
20807
+ // advance past each element whose running sum is <= rnd; the element that
20808
+ // pushes the sum over rnd is the selection
20809
+ while (cursor < options.length) { // eslint-disable-line fp/no-loops
20810
+ const p = options[cursor][probability_property];
20811
+ cursor_sum += (p === undefined) ? 1 : p;
20812
+ ++cursor;
20813
+ if (cursor_sum > rnd) {
20814
+ break;
20815
+ }
20816
+ }
20802
20817
  return options[cursor - 1];
20803
20818
  };
20804
20819
  /* eslint-enable flowtype/no-weak-types */
@@ -23588,7 +23603,7 @@ var constants = /*#__PURE__*/Object.freeze({
23588
23603
  * Useful for runtime diagnostics and for embedding in serialized machine
23589
23604
  * snapshots so that deserializers can detect version-skew.
23590
23605
  */
23591
- const version = "5.157.0";
23606
+ const version = "5.157.1";
23592
23607
 
23593
23608
  // whargarbl lots of these return arrays could/should be sets
23594
23609
  const { state_name_chars, state_name_first_chars, action_label_chars } = constants;
@@ -23889,8 +23904,11 @@ function find_connected_components(states, edges) {
23889
23904
  const component = [];
23890
23905
  const queue = [start];
23891
23906
  visited.add(start);
23892
- while (queue.length > 0) {
23893
- const node = queue.shift();
23907
+ // index-pointer pop: Array.shift is O(n) per pop, making the BFS O(V²)
23908
+ // worst case; reading by cursor keeps it O(V + E)
23909
+ let head = 0;
23910
+ while (head < queue.length) {
23911
+ const node = queue[head++];
23894
23912
  component.push(node);
23895
23913
  for (const neighbor of adj.get(node)) {
23896
23914
  if (!visited.has(neighbor)) {
@@ -24105,6 +24123,9 @@ class Machine {
24105
24123
  // nested Map+Set keeps the check O(1) per edge rather than an O(out-degree)
24106
24124
  // scan (which made construction O(V*E) on dense graphs). #673
24107
24125
  const seen_edges = new Map();
24126
+ // complete.includes was an O(|complete|) array scan per newly-created
24127
+ // state — O(V·C) overall; one Set turns it into O(V)
24128
+ const complete_set = new Set(complete);
24108
24129
  // walk the transitions. single-lookup cursor fetches: each endpoint was
24109
24130
  // previously a get followed by a has on the same key (four hashes per
24110
24131
  // edge); the undefined check on the get's result carries the same
@@ -24119,12 +24140,12 @@ class Machine {
24119
24140
  // get the cursors. what a mess
24120
24141
  let cursor_from = this._states.get(tr.from);
24121
24142
  if (cursor_from === undefined) {
24122
- cursor_from = { name: tr.from, from: [], to: [], complete: complete.includes(tr.from) };
24143
+ cursor_from = { name: tr.from, from: [], to: [], complete: complete_set.has(tr.from) };
24123
24144
  this._new_state(cursor_from);
24124
24145
  }
24125
24146
  let cursor_to = this._states.get(tr.to);
24126
24147
  if (cursor_to === undefined) {
24127
- cursor_to = { name: tr.to, from: [], to: [], complete: complete.includes(tr.to) };
24148
+ cursor_to = { name: tr.to, from: [], to: [], complete: complete_set.has(tr.to) };
24128
24149
  this._new_state(cursor_to);
24129
24150
  }
24130
24151
  // record (from -> to) adjacency once per distinct target, even when
@@ -25370,11 +25391,17 @@ class Machine {
25370
25391
  // filter -> filter chain and its three intermediate arrays; selection and
25371
25392
  // ordering semantics are unchanged
25372
25393
  const legal_exits = [], probability_bearing = [];
25394
+ // hoisted: every exit shares whichState, so probe _edge_map for the
25395
+ // from-side once instead of re-hashing the same key per exit inside
25396
+ // lookup_transition_for. wstate.to is non-empty only when at least one
25397
+ // outbound edge exists, and every outbound edge creates the from-side
25398
+ // mapping at construction — so emg is defined whenever the loop runs.
25399
+ const emg = this._edge_map.get(whichState);
25373
25400
  for (const ws of wstate.to) {
25374
- // wstate.to is built from the same edge set lookup_transition_for
25375
- // resolves against, so the lookup cannot miss; the guard mirrors the
25376
- // old defensive .filter(Boolean) and is equally unreachable.
25377
- const edge = this.lookup_transition_for(whichState, ws);
25401
+ // wstate.to is built from the same edge set _edge_map indexes, so the
25402
+ // per-target get cannot miss; the guard mirrors the old defensive
25403
+ // .filter(Boolean) and is equally unreachable.
25404
+ const edge = this._edges[emg.get(ws)];
25378
25405
  /* v8 ignore next */
25379
25406
  if (!edge) {
25380
25407
  continue;
@@ -26775,12 +26802,23 @@ class Machine {
26775
26802
  // instead of O(E) — a large win on dense graphs where d << E. The `?? []`
26776
26803
  // covers from-states that have no outgoing edges (terminal states) and
26777
26804
  // states that don't exist at all, both of which return [] without iterating.
26805
+ //
26806
+ // The match itself compares interned numeric state ids against the packed
26807
+ // _edge_to_ids array rather than dereferencing each edge object for a
26808
+ // string compare: non-matching edges never touch an edge object, which is
26809
+ // most of the cost on dense shapes (heavier edge objects degrade a deref
26810
+ // loop — the 5.142/5.143 regression mechanism). Every state named by any
26811
+ // edge is interned at construction, so an unknown `to` provably has no
26812
+ // edges and returns [] immediately.
26813
+ const to_id = this._state_interner.id_of(to);
26814
+ if (to_id === undefined) {
26815
+ return [];
26816
+ }
26778
26817
  const outbound = (_a = this._outbound_edge_ids.get(from)) !== null && _a !== void 0 ? _a : [];
26779
26818
  const result = [];
26780
26819
  for (const edgeId of outbound) {
26781
- const edge = this._edges[edgeId];
26782
- if (edge.to === to) {
26783
- result.push(edge);
26820
+ if (this._edge_to_ids[edgeId] === to_id) {
26821
+ result.push(this._edges[edgeId]);
26784
26822
  }
26785
26823
  }
26786
26824
  return result;
@@ -27070,19 +27108,15 @@ class Machine {
27070
27108
  const edgeId = (to_id === undefined) ? undefined : this._edge_id_by_pair.get(pair_key(this._state_id, to_id));
27071
27109
  if ((edgeId !== undefined) && (!(this._edges[edgeId].forced_only))) {
27072
27110
  if (this._has_transition_hooks || this._has_post_transition_hooks) {
27073
- // first matching outbound edge's kind, without building the result
27074
- // array edges_between allocated here on every hooked transition.
27075
- // First-match semantics are kept deliberately: _edge_map is
27076
- // last-wins for multi-edge (from, to) pairs, so lookup_transition_for
27077
- // could disagree with the old edges_between(...)[0]. #735
27078
- // TODO this won't do the right thing if various edges have different types
27079
- for (const ob_eid of this._outbound_edge_ids.get(this._state)) {
27080
- const ob_edge = this._edges[ob_eid];
27081
- if (ob_edge.to === newStateOrAction) {
27082
- trans_type = ob_edge.kind;
27083
- break;
27084
- }
27085
- }
27111
+ // kind of the dispatched edge. _edge_id_by_pair and _edge_map are
27112
+ // both first-declared-wins for parallel (from, to) pairs (see the
27113
+ // constructor around _edge_map / _edge_id_by_pair), and
27114
+ // _outbound_edge_ids fills in declaration order so the old
27115
+ // first-match outbound scan always resolved to this same edgeId.
27116
+ // Direct read replaces the O(out-degree) object-deref scan; the
27117
+ // first-declared-kind semantics are pinned by the parallel-edge
27118
+ // transition-kind hook spec. #735
27119
+ trans_type = this._edges[edgeId].kind;
27086
27120
  }
27087
27121
  valid = true;
27088
27122
  newState = newStateOrAction;
@@ -27482,6 +27516,13 @@ class Machine {
27482
27516
  * Called internally after each transition.
27483
27517
  */
27484
27518
  auto_set_state_timeout() {
27519
+ // called on every successful transition-commit. Machines with no `after`
27520
+ // clauses at all (the overwhelmingly common case) previously still paid a
27521
+ // string hash + map probe here per transition; one integer size read
27522
+ // short-circuits that.
27523
+ if (this._after_mapping.size === 0) {
27524
+ return;
27525
+ }
27485
27526
  const after_res = this._after_mapping.get(this._state);
27486
27527
  if (after_res !== undefined) {
27487
27528
  const [next_state, after_time] = after_res;
@@ -28731,6 +28772,14 @@ function is_hook_complex_result(hr) {
28731
28772
  *
28732
28773
  */
28733
28774
  function _update_hook_fields(hook_args, res) {
28775
+ // HOOK_PASSED is the shared frozen outcome for "no hook installed" and for
28776
+ // hooks returning true/undefined — the overwhelming majority of the up-to-
28777
+ // ~10 steps per hooked transition. It can never carry `data` (frozen, built
28778
+ // without one), so one pointer compare replaces the hasOwnProperty
28779
+ // reflection call for the common case.
28780
+ if (res === HOOK_PASSED) {
28781
+ return false;
28782
+ }
28734
28783
  if (Object.prototype.hasOwnProperty.call(res, 'data')) {
28735
28784
  hook_args.data = res.data;
28736
28785
  hook_args.next_data = res.next_data;
@@ -28749,6 +28798,8 @@ function _update_hook_fields(hook_args, res) {
28749
28798
  * so a shared instance is observationally identical; freezing turns that
28750
28799
  * read-only contract from incidental into enforced. Complex results (hooks
28751
28800
  * returning `{ pass, data, ... }`) still pass through untouched. #705
28801
+ * _update_hook_fields additionally identity-checks HOOK_PASSED to skip its
28802
+ * own-property probe on the common no-op outcome.
28752
28803
  *
28753
28804
  * @see abstract_hook_step
28754
28805
  * @see abstract_everything_hook_step
@@ -108,7 +108,7 @@ function parseFslArgs(argv, spec) {
108
108
  return { positional, flags, helpText };
109
109
  }
110
110
 
111
- const getVersion = () => "5.157.0";
111
+ const getVersion = () => "5.157.1";
112
112
  const SPEC = {
113
113
  flags: {
114
114
  help: { short: "h", boolean: true },