@patterkit/cli 0.3.8 → 0.3.9

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 (2) hide show
  1. package/dist/cli.js +633 -331
  2. package/package.json +3 -3
package/dist/cli.js CHANGED
@@ -105,7 +105,7 @@ var require_under_dash = __commonJS({
105
105
  const bType = typeof b;
106
106
  const aArray = Array.isArray(a);
107
107
  const bArray = Array.isArray(b);
108
- let keys;
108
+ let keys2;
109
109
  if (aType !== bType) {
110
110
  return false;
111
111
  }
@@ -123,11 +123,11 @@ var require_under_dash = __commonJS({
123
123
  if (a === null || b === null) {
124
124
  return a === b;
125
125
  }
126
- keys = Object.keys(a);
127
- if (Object.keys(b).length !== keys.length) {
126
+ keys2 = Object.keys(a);
127
+ if (Object.keys(b).length !== keys2.length) {
128
128
  return false;
129
129
  }
130
- for (const key2 of keys) {
130
+ for (const key2 of keys2) {
131
131
  if (!b.hasOwnProperty(key2)) {
132
132
  return false;
133
133
  }
@@ -4908,11 +4908,11 @@ var require_stream_duplex = __commonJS({
4908
4908
  "use strict";
4909
4909
  var pna = require_process_nextick_args();
4910
4910
  var objectKeys = Object.keys || function(obj2) {
4911
- var keys2 = [];
4911
+ var keys3 = [];
4912
4912
  for (var key2 in obj2) {
4913
- keys2.push(key2);
4913
+ keys3.push(key2);
4914
4914
  }
4915
- return keys2;
4915
+ return keys3;
4916
4916
  };
4917
4917
  module2.exports = Duplex;
4918
4918
  var util2 = Object.create(require_util());
@@ -4921,13 +4921,13 @@ var require_stream_duplex = __commonJS({
4921
4921
  var Writable = require_stream_writable();
4922
4922
  util2.inherits(Duplex, Readable);
4923
4923
  {
4924
- keys = objectKeys(Writable.prototype);
4925
- for (v = 0; v < keys.length; v++) {
4926
- method = keys[v];
4924
+ keys2 = objectKeys(Writable.prototype);
4925
+ for (v = 0; v < keys2.length; v++) {
4926
+ method = keys2[v];
4927
4927
  if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];
4928
4928
  }
4929
4929
  }
4930
- var keys;
4930
+ var keys2;
4931
4931
  var method;
4932
4932
  var v;
4933
4933
  function Duplex(options) {
@@ -13820,14 +13820,14 @@ var require_buffer_list = __commonJS({
13820
13820
  "../../node_modules/readable-stream/lib/internal/streams/buffer_list.js"(exports2, module2) {
13821
13821
  "use strict";
13822
13822
  function ownKeys2(object, enumerableOnly) {
13823
- var keys = Object.keys(object);
13823
+ var keys2 = Object.keys(object);
13824
13824
  if (Object.getOwnPropertySymbols) {
13825
13825
  var symbols = Object.getOwnPropertySymbols(object);
13826
13826
  enumerableOnly && (symbols = symbols.filter(function(sym) {
13827
13827
  return Object.getOwnPropertyDescriptor(object, sym).enumerable;
13828
- })), keys.push.apply(keys, symbols);
13828
+ })), keys2.push.apply(keys2, symbols);
13829
13829
  }
13830
- return keys;
13830
+ return keys2;
13831
13831
  }
13832
13832
  function _objectSpread(target) {
13833
13833
  for (var i = 1; i < arguments.length; i++) {
@@ -14747,22 +14747,22 @@ var require_stream_duplex2 = __commonJS({
14747
14747
  "../../node_modules/readable-stream/lib/_stream_duplex.js"(exports2, module2) {
14748
14748
  "use strict";
14749
14749
  var objectKeys = Object.keys || function(obj2) {
14750
- var keys2 = [];
14751
- for (var key2 in obj2) keys2.push(key2);
14752
- return keys2;
14750
+ var keys3 = [];
14751
+ for (var key2 in obj2) keys3.push(key2);
14752
+ return keys3;
14753
14753
  };
14754
14754
  module2.exports = Duplex;
14755
14755
  var Readable = require_stream_readable2();
14756
14756
  var Writable = require_stream_writable2();
14757
14757
  require_inherits()(Duplex, Readable);
14758
14758
  {
14759
- keys = objectKeys(Writable.prototype);
14760
- for (v = 0; v < keys.length; v++) {
14761
- method = keys[v];
14759
+ keys2 = objectKeys(Writable.prototype);
14760
+ for (v = 0; v < keys2.length; v++) {
14761
+ method = keys2[v];
14762
14762
  if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];
14763
14763
  }
14764
14764
  }
14765
- var keys;
14765
+ var keys2;
14766
14766
  var method;
14767
14767
  var v;
14768
14768
  function Duplex(options) {
@@ -15141,14 +15141,14 @@ var require_from = __commonJS({
15141
15141
  };
15142
15142
  }
15143
15143
  function ownKeys2(object, enumerableOnly) {
15144
- var keys = Object.keys(object);
15144
+ var keys2 = Object.keys(object);
15145
15145
  if (Object.getOwnPropertySymbols) {
15146
15146
  var symbols = Object.getOwnPropertySymbols(object);
15147
15147
  enumerableOnly && (symbols = symbols.filter(function(sym) {
15148
15148
  return Object.getOwnPropertyDescriptor(object, sym).enumerable;
15149
- })), keys.push.apply(keys, symbols);
15149
+ })), keys2.push.apply(keys2, symbols);
15150
15150
  }
15151
- return keys;
15151
+ return keys2;
15152
15152
  }
15153
15153
  function _objectSpread(target) {
15154
15154
  for (var i = 1; i < arguments.length; i++) {
@@ -29807,7 +29807,7 @@ var require_lodash2 = __commonJS({
29807
29807
  return result;
29808
29808
  }
29809
29809
  function getAllKeys(object) {
29810
- return baseGetAllKeys(object, keys, getSymbols);
29810
+ return baseGetAllKeys(object, keys2, getSymbols);
29811
29811
  }
29812
29812
  function getMapData(map2, key2) {
29813
29813
  var data = map2.__data__;
@@ -29929,7 +29929,7 @@ var require_lodash2 = __commonJS({
29929
29929
  return value != null && typeof value == "object";
29930
29930
  }
29931
29931
  var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;
29932
- function keys(object) {
29932
+ function keys2(object) {
29933
29933
  return isArrayLike2(object) ? arrayLikeKeys(object) : baseKeys(object);
29934
29934
  }
29935
29935
  function stubArray() {
@@ -31263,7 +31263,7 @@ var require_lodash8 = __commonJS({
31263
31263
  var baseEach = createBaseEach(baseForOwn);
31264
31264
  var baseFor = createBaseFor();
31265
31265
  function baseForOwn(object, iteratee) {
31266
- return object && baseFor(object, iteratee, keys);
31266
+ return object && baseFor(object, iteratee, keys2);
31267
31267
  }
31268
31268
  function baseGet(object, path) {
31269
31269
  path = isKey(path, object) ? [path] : castPath(path);
@@ -31542,7 +31542,7 @@ var require_lodash8 = __commonJS({
31542
31542
  return false;
31543
31543
  }
31544
31544
  function equalObjects(object, other, equalFunc, customizer, bitmask, stack2) {
31545
- var isPartial = bitmask & PARTIAL_COMPARE_FLAG, objProps = keys(object), objLength = objProps.length, othProps = keys(other), othLength = othProps.length;
31545
+ var isPartial = bitmask & PARTIAL_COMPARE_FLAG, objProps = keys2(object), objLength = objProps.length, othProps = keys2(other), othLength = othProps.length;
31546
31546
  if (objLength != othLength && !isPartial) {
31547
31547
  return false;
31548
31548
  }
@@ -31588,7 +31588,7 @@ var require_lodash8 = __commonJS({
31588
31588
  return isKeyable(key2) ? data[typeof key2 == "string" ? "string" : "hash"] : data.map;
31589
31589
  }
31590
31590
  function getMatchData(object) {
31591
- var result = keys(object), length = result.length;
31591
+ var result = keys2(object), length = result.length;
31592
31592
  while (length--) {
31593
31593
  var key2 = result[length], value = object[key2];
31594
31594
  result[length] = [key2, value, isStrictComparable(value)];
@@ -31768,7 +31768,7 @@ var require_lodash8 = __commonJS({
31768
31768
  function hasIn(object, path) {
31769
31769
  return object != null && hasPath(object, path, baseHasIn);
31770
31770
  }
31771
- function keys(object) {
31771
+ function keys2(object) {
31772
31772
  return isArrayLike2(object) ? arrayLikeKeys(object) : baseKeys(object);
31773
31773
  }
31774
31774
  function identity(value) {
@@ -36918,9 +36918,9 @@ var require_legacy_streams = __commonJS({
36918
36918
  this.mode = 438;
36919
36919
  this.bufferSize = 64 * 1024;
36920
36920
  options = options || {};
36921
- var keys = Object.keys(options);
36922
- for (var index2 = 0, length = keys.length; index2 < length; index2++) {
36923
- var key2 = keys[index2];
36921
+ var keys2 = Object.keys(options);
36922
+ for (var index2 = 0, length = keys2.length; index2 < length; index2++) {
36923
+ var key2 = keys2[index2];
36924
36924
  this[key2] = options[key2];
36925
36925
  }
36926
36926
  if (this.encoding) this.setEncoding(this.encoding);
@@ -36966,9 +36966,9 @@ var require_legacy_streams = __commonJS({
36966
36966
  this.mode = 438;
36967
36967
  this.bytesWritten = 0;
36968
36968
  options = options || {};
36969
- var keys = Object.keys(options);
36970
- for (var index2 = 0, length = keys.length; index2 < length; index2++) {
36971
- var key2 = keys[index2];
36969
+ var keys2 = Object.keys(options);
36970
+ for (var index2 = 0, length = keys2.length; index2 < length; index2++) {
36971
+ var key2 = keys2[index2];
36972
36972
  this[key2] = options[key2];
36973
36973
  }
36974
36974
  if (this.start !== void 0) {
@@ -37987,11 +37987,11 @@ var require_stream_duplex3 = __commonJS({
37987
37987
  "use strict";
37988
37988
  var pna = require_process_nextick_args();
37989
37989
  var objectKeys = Object.keys || function(obj2) {
37990
- var keys2 = [];
37990
+ var keys3 = [];
37991
37991
  for (var key2 in obj2) {
37992
- keys2.push(key2);
37992
+ keys3.push(key2);
37993
37993
  }
37994
- return keys2;
37994
+ return keys3;
37995
37995
  };
37996
37996
  module2.exports = Duplex;
37997
37997
  var util2 = Object.create(require_util());
@@ -38000,13 +38000,13 @@ var require_stream_duplex3 = __commonJS({
38000
38000
  var Writable = require_stream_writable3();
38001
38001
  util2.inherits(Duplex, Readable);
38002
38002
  {
38003
- keys = objectKeys(Writable.prototype);
38004
- for (v = 0; v < keys.length; v++) {
38005
- method = keys[v];
38003
+ keys2 = objectKeys(Writable.prototype);
38004
+ for (v = 0; v < keys2.length; v++) {
38005
+ method = keys2[v];
38006
38006
  if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];
38007
38007
  }
38008
38008
  }
38009
- var keys;
38009
+ var keys2;
38010
38010
  var method;
38011
38011
  var v;
38012
38012
  function Duplex(options) {
@@ -39752,11 +39752,11 @@ var require_stream_duplex4 = __commonJS({
39752
39752
  "use strict";
39753
39753
  var pna = require_process_nextick_args();
39754
39754
  var objectKeys = Object.keys || function(obj2) {
39755
- var keys2 = [];
39755
+ var keys3 = [];
39756
39756
  for (var key2 in obj2) {
39757
- keys2.push(key2);
39757
+ keys3.push(key2);
39758
39758
  }
39759
- return keys2;
39759
+ return keys3;
39760
39760
  };
39761
39761
  module2.exports = Duplex;
39762
39762
  var util2 = Object.create(require_util());
@@ -39765,13 +39765,13 @@ var require_stream_duplex4 = __commonJS({
39765
39765
  var Writable = require_stream_writable4();
39766
39766
  util2.inherits(Duplex, Readable);
39767
39767
  {
39768
- keys = objectKeys(Writable.prototype);
39769
- for (v = 0; v < keys.length; v++) {
39770
- method = keys[v];
39768
+ keys2 = objectKeys(Writable.prototype);
39769
+ for (v = 0; v < keys2.length; v++) {
39770
+ method = keys2[v];
39771
39771
  if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];
39772
39772
  }
39773
39773
  }
39774
- var keys;
39774
+ var keys2;
39775
39775
  var method;
39776
39776
  var v;
39777
39777
  function Duplex(options) {
@@ -43509,10 +43509,10 @@ var require_glob = __commonJS({
43509
43509
  if (add === null || typeof add !== "object") {
43510
43510
  return origin;
43511
43511
  }
43512
- var keys = Object.keys(add);
43513
- var i = keys.length;
43512
+ var keys2 = Object.keys(add);
43513
+ var i = keys2.length;
43514
43514
  while (i--) {
43515
- origin[keys[i]] = add[keys[i]];
43515
+ origin[keys2[i]] = add[keys2[i]];
43516
43516
  }
43517
43517
  return origin;
43518
43518
  }
@@ -49354,15 +49354,15 @@ var require_traverse = __commonJS({
49354
49354
  if (modifiers.before) modifiers.before.call(state, state.node);
49355
49355
  if (typeof state.node == "object" && state.node !== null && !state.circular) {
49356
49356
  parents.push(state);
49357
- var keys = Object.keys(state.node);
49358
- keys.forEach(function(key2, i2) {
49357
+ var keys2 = Object.keys(state.node);
49358
+ keys2.forEach(function(key2, i2) {
49359
49359
  path.push(key2);
49360
49360
  if (modifiers.pre) modifiers.pre.call(state, state.node[key2], key2);
49361
49361
  var child = walker(state.node[key2]);
49362
49362
  if (immutable && Object.hasOwnProperty.call(state.node, key2)) {
49363
49363
  state.node[key2] = child.node;
49364
49364
  }
49365
- child.isLast = i2 == keys.length - 1;
49365
+ child.isLast = i2 == keys2.length - 1;
49366
49366
  child.isFirst = i2 == 0;
49367
49367
  if (modifiers.post) modifiers.post.call(state, child);
49368
49368
  path.pop();
@@ -49742,12 +49742,12 @@ var require_vars = __commonJS({
49742
49742
  module2.exports = function(store) {
49743
49743
  function getset(name, value) {
49744
49744
  var node = vars.store;
49745
- var keys = name.split(".");
49746
- keys.slice(0, -1).forEach(function(k) {
49745
+ var keys2 = name.split(".");
49746
+ keys2.slice(0, -1).forEach(function(k) {
49747
49747
  if (node[k] === void 0) node[k] = {};
49748
49748
  node = node[k];
49749
49749
  });
49750
- var key2 = keys[keys.length - 1];
49750
+ var key2 = keys2[keys2.length - 1];
49751
49751
  if (arguments.length == 1) {
49752
49752
  return node[key2];
49753
49753
  } else {
@@ -50282,14 +50282,14 @@ var require_util4 = __commonJS({
50282
50282
  var ret2 = [];
50283
50283
  var visitedKeys = /* @__PURE__ */ Object.create(null);
50284
50284
  while (obj2 != null && !isExcludedProto(obj2)) {
50285
- var keys;
50285
+ var keys2;
50286
50286
  try {
50287
- keys = getKeys(obj2);
50287
+ keys2 = getKeys(obj2);
50288
50288
  } catch (e) {
50289
50289
  return ret2;
50290
50290
  }
50291
- for (var i = 0; i < keys.length; ++i) {
50292
- var key2 = keys[i];
50291
+ for (var i = 0; i < keys2.length; ++i) {
50292
+ var key2 = keys2[i];
50293
50293
  if (visitedKeys[key2]) continue;
50294
50294
  visitedKeys[key2] = true;
50295
50295
  var desc = Object.getOwnPropertyDescriptor(obj2, key2);
@@ -50326,9 +50326,9 @@ var require_util4 = __commonJS({
50326
50326
  function isClass(fn) {
50327
50327
  try {
50328
50328
  if (typeof fn === "function") {
50329
- var keys = es5.names(fn.prototype);
50330
- var hasMethods = es5.isES5 && keys.length > 1;
50331
- var hasMethodsOtherThanConstructor = keys.length > 0 && !(keys.length === 1 && keys[0] === "constructor");
50329
+ var keys2 = es5.names(fn.prototype);
50330
+ var hasMethods = es5.isES5 && keys2.length > 1;
50331
+ var hasMethodsOtherThanConstructor = keys2.length > 0 && !(keys2.length === 1 && keys2[0] === "constructor");
50332
50332
  var hasThisAssignmentAndStaticMethods = thisAssignmentPattern.test(fn + "") && es5.names(fn).length > 0;
50333
50333
  if (hasMethods || hasMethodsOtherThanConstructor || hasThisAssignmentAndStaticMethods) {
50334
50334
  return true;
@@ -50403,9 +50403,9 @@ var require_util4 = __commonJS({
50403
50403
  return {}.toString.call(obj2);
50404
50404
  }
50405
50405
  function copyDescriptors(from, to, filter2) {
50406
- var keys = es5.names(from);
50407
- for (var i = 0; i < keys.length; ++i) {
50408
- var key2 = keys[i];
50406
+ var keys2 = es5.names(from);
50407
+ for (var i = 0; i < keys2.length; ++i) {
50408
+ var key2 = keys2[i];
50409
50409
  if (filter2(key2)) {
50410
50410
  try {
50411
50411
  es5.defineProperty(to, key2, es5.getDescriptor(from, key2));
@@ -52207,9 +52207,9 @@ var require_catch_filter = __commonJS({
52207
52207
  return tryCatch2(cb).call(boundTo, e);
52208
52208
  }
52209
52209
  } else if (util2.isObject(e)) {
52210
- var keys = getKeys(item);
52211
- for (var j = 0; j < keys.length; ++j) {
52212
- var key2 = keys[j];
52210
+ var keys2 = getKeys(item);
52211
+ for (var j = 0; j < keys2.length; ++j) {
52212
+ var key2 = keys2[j];
52213
52213
  if (item[key2] != e[key2]) {
52214
52214
  continue predicateLoop;
52215
52215
  }
@@ -52245,9 +52245,9 @@ var require_nodeback = __commonJS({
52245
52245
  ret2.name = obj2.name;
52246
52246
  ret2.message = obj2.message;
52247
52247
  ret2.stack = obj2.stack;
52248
- var keys = es52.keys(obj2);
52249
- for (var i = 0; i < keys.length; ++i) {
52250
- var key2 = keys[i];
52248
+ var keys2 = es52.keys(obj2);
52249
+ for (var i = 0; i < keys2.length; ++i) {
52250
+ var key2 = keys2[i];
52251
52251
  if (!rErrorKey.test(key2)) {
52252
52252
  ret2[key2] = obj2[key2];
52253
52253
  }
@@ -52993,9 +52993,9 @@ var require_call_get = __commonJS({
52993
52993
  cache2[name] = ret2;
52994
52994
  cache2[" size"]++;
52995
52995
  if (cache2[" size"] > 512) {
52996
- var keys = Object.keys(cache2);
52997
- for (var i = 0; i < 256; ++i) delete cache2[keys[i]];
52998
- cache2[" size"] = keys.length - 256;
52996
+ var keys2 = Object.keys(cache2);
52997
+ for (var i = 0; i < 256; ++i) delete cache2[keys2[i]];
52998
+ cache2[" size"] = keys2.length - 256;
52999
52999
  }
53000
53000
  }
53001
53001
  return ret2;
@@ -53714,10 +53714,10 @@ var require_promisify = __commonJS({
53714
53714
  }
53715
53715
  }
53716
53716
  function promisifiableMethods(obj2, suffix, suffixRegexp, filter2) {
53717
- var keys = util2.inheritedDataKeys(obj2);
53717
+ var keys2 = util2.inheritedDataKeys(obj2);
53718
53718
  var ret2 = [];
53719
- for (var i = 0; i < keys.length; ++i) {
53720
- var key2 = keys[i];
53719
+ for (var i = 0; i < keys2.length; ++i) {
53720
+ var key2 = keys2[i];
53721
53721
  var value = obj2[key2];
53722
53722
  var passesDefaultFilter = filter2 === defaultFilter ? true : defaultFilter(key2, value, obj2);
53723
53723
  if (typeof value === "function" && !isPromisified(value) && !hasPromisified(obj2, key2, suffix) && filter2(key2, value, obj2, passesDefaultFilter)) {
@@ -53904,10 +53904,10 @@ var require_promisify = __commonJS({
53904
53904
  if (!util2.isIdentifier(suffix)) {
53905
53905
  throw new RangeError("suffix must be a valid identifier\n\n See http://goo.gl/MqrFmX\n");
53906
53906
  }
53907
- var keys = util2.inheritedDataKeys(target);
53908
- for (var i = 0; i < keys.length; ++i) {
53909
- var value = target[keys[i]];
53910
- if (keys[i] !== "constructor" && util2.isClass(value)) {
53907
+ var keys2 = util2.inheritedDataKeys(target);
53908
+ for (var i = 0; i < keys2.length; ++i) {
53909
+ var value = target[keys2[i]];
53910
+ if (keys2[i] !== "constructor" && util2.isClass(value)) {
53911
53911
  promisifyAll(
53912
53912
  value.prototype,
53913
53913
  suffix,
@@ -53967,11 +53967,11 @@ var require_props = __commonJS({
53967
53967
  entries = mapToEntries(obj2);
53968
53968
  isMap = true;
53969
53969
  } else {
53970
- var keys = es52.keys(obj2);
53971
- var len = keys.length;
53970
+ var keys2 = es52.keys(obj2);
53971
+ var len = keys2.length;
53972
53972
  entries = new Array(len * 2);
53973
53973
  for (var i = 0; i < len; ++i) {
53974
- var key2 = keys[i];
53974
+ var key2 = keys2[i];
53975
53975
  entries[i] = obj2[key2];
53976
53976
  entries[i + len] = key2;
53977
53977
  }
@@ -55796,11 +55796,11 @@ var require_stream_duplex5 = __commonJS({
55796
55796
  "use strict";
55797
55797
  var pna = require_process_nextick_args();
55798
55798
  var objectKeys = Object.keys || function(obj2) {
55799
- var keys2 = [];
55799
+ var keys3 = [];
55800
55800
  for (var key2 in obj2) {
55801
- keys2.push(key2);
55801
+ keys3.push(key2);
55802
55802
  }
55803
- return keys2;
55803
+ return keys3;
55804
55804
  };
55805
55805
  module2.exports = Duplex;
55806
55806
  var util2 = Object.create(require_util());
@@ -55809,13 +55809,13 @@ var require_stream_duplex5 = __commonJS({
55809
55809
  var Writable = require_stream_writable5();
55810
55810
  util2.inherits(Duplex, Readable);
55811
55811
  {
55812
- keys = objectKeys(Writable.prototype);
55813
- for (v = 0; v < keys.length; v++) {
55814
- method = keys[v];
55812
+ keys2 = objectKeys(Writable.prototype);
55813
+ for (v = 0; v < keys2.length; v++) {
55814
+ method = keys2[v];
55815
55815
  if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];
55816
55816
  }
55817
55817
  }
55818
- var keys;
55818
+ var keys2;
55819
55819
  var method;
55820
55820
  var v;
55821
55821
  function Duplex(options) {
@@ -57708,11 +57708,11 @@ var require_stream_duplex6 = __commonJS({
57708
57708
  "use strict";
57709
57709
  var pna = require_process_nextick_args();
57710
57710
  var objectKeys = Object.keys || function(obj2) {
57711
- var keys2 = [];
57711
+ var keys3 = [];
57712
57712
  for (var key2 in obj2) {
57713
- keys2.push(key2);
57713
+ keys3.push(key2);
57714
57714
  }
57715
- return keys2;
57715
+ return keys3;
57716
57716
  };
57717
57717
  module2.exports = Duplex;
57718
57718
  var util2 = Object.create(require_util());
@@ -57721,13 +57721,13 @@ var require_stream_duplex6 = __commonJS({
57721
57721
  var Writable = require_stream_writable6();
57722
57722
  util2.inherits(Duplex, Readable);
57723
57723
  {
57724
- keys = objectKeys(Writable.prototype);
57725
- for (v = 0; v < keys.length; v++) {
57726
- method = keys[v];
57724
+ keys2 = objectKeys(Writable.prototype);
57725
+ for (v = 0; v < keys2.length; v++) {
57726
+ method = keys2[v];
57727
57727
  if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];
57728
57728
  }
57729
57729
  }
57730
- var keys;
57730
+ var keys2;
57731
57731
  var method;
57732
57732
  var v;
57733
57733
  function Duplex(options) {
@@ -64001,7 +64001,7 @@ var require_fast_deep_equal = __commonJS({
64001
64001
  if (a === b) return true;
64002
64002
  if (a && b && typeof a == "object" && typeof b == "object") {
64003
64003
  if (a.constructor !== b.constructor) return false;
64004
- var length, i, keys;
64004
+ var length, i, keys2;
64005
64005
  if (Array.isArray(a)) {
64006
64006
  length = a.length;
64007
64007
  if (length != b.length) return false;
@@ -64012,13 +64012,13 @@ var require_fast_deep_equal = __commonJS({
64012
64012
  if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
64013
64013
  if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
64014
64014
  if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
64015
- keys = Object.keys(a);
64016
- length = keys.length;
64015
+ keys2 = Object.keys(a);
64016
+ length = keys2.length;
64017
64017
  if (length !== Object.keys(b).length) return false;
64018
64018
  for (i = length; i-- !== 0; )
64019
- if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
64019
+ if (!Object.prototype.hasOwnProperty.call(b, keys2[i])) return false;
64020
64020
  for (i = length; i-- !== 0; ) {
64021
- var key2 = keys[i];
64021
+ var key2 = keys2[i];
64022
64022
  if (!equal(a[key2], b[key2])) return false;
64023
64023
  }
64024
64024
  return true;
@@ -191986,9 +191986,9 @@ var stringify = function stringify2(value, replacer2, space) {
191986
191986
  stack2.push(value2);
191987
191987
  let stepback = indent;
191988
191988
  indent = indent + gap;
191989
- let keys = propertyList || Object.keys(value2);
191989
+ let keys2 = propertyList || Object.keys(value2);
191990
191990
  let partial = [];
191991
- for (const key2 of keys) {
191991
+ for (const key2 of keys2) {
191992
191992
  const propertyString = serializeProperty(key2, value2);
191993
191993
  if (propertyString !== void 0) {
191994
191994
  let member = serializeKey(key2) + ":";
@@ -192151,8 +192151,8 @@ function tokenise(src) {
192151
192151
  while (i < src.length && src[i] !== quote) {
192152
192152
  if (src[i] === "\\" && i + 1 < src.length) {
192153
192153
  i++;
192154
- const esc2 = { n: "\n", t: " ", r: "\r", "\\": "\\", "'": "'", '"': '"' };
192155
- s += esc2[src[i]] ?? src[i];
192154
+ const esc3 = { n: "\n", t: " ", r: "\r", "\\": "\\", "'": "'", '"': '"' };
192155
+ s += esc3[src[i]] ?? src[i];
192156
192156
  } else {
192157
192157
  s += src[i];
192158
192158
  }
@@ -193141,6 +193141,7 @@ function castStringKey(name) {
193141
193141
  }
193142
193142
  var DEFAULT_CAPTION_DELIMITERS = { open: "[", close: "]" };
193143
193143
  var DEFAULT_CAPTION_CHARACTER = "SFX";
193144
+ var SAVE_VERSION = 3;
193144
193145
 
193145
193146
  // ../core/src/noderefs.ts
193146
193147
  var VISIT_FN_RE = /\b(patter_visits|patter_seen|visits|seen)\s*\(\s*(?:(['"])(.*?)\2|([A-Za-z_]\w*))\s*\)/g;
@@ -193166,10 +193167,10 @@ ${indent}]`;
193166
193167
  }
193167
193168
  if (typeof v === "object") {
193168
193169
  const obj2 = v;
193169
- const keys = Object.keys(obj2).filter((k) => obj2[k] !== void 0).sort();
193170
- if (keys.length === 0) return "{}";
193170
+ const keys2 = Object.keys(obj2).filter((k) => obj2[k] !== void 0).sort();
193171
+ if (keys2.length === 0) return "{}";
193171
193172
  const next = indent + " ";
193172
- const entries = keys.map((k) => `${next}${JSON.stringify(k)}: ${write(obj2[k], next, tc)}`);
193173
+ const entries = keys2.map((k) => `${next}${JSON.stringify(k)}: ${write(obj2[k], next, tc)}`);
193173
193174
  return `{
193174
193175
  ${entries.join(",\n")}${tail}
193175
193176
  ${indent}}`;
@@ -194046,6 +194047,12 @@ function checkDuplicateIds(root2, conflicts) {
194046
194047
  var idMap = (nodes) => new Map(nodes.filter((n) => n.id).map((n) => [n.id, n]));
194047
194048
  var arrEq = (a, b) => a.length === b.length && a.every((x, i) => x === b[i]);
194048
194049
 
194050
+ // ../dialect/src/engine-scopes.ts
194051
+ var ENGINE_SCOPES = [
194052
+ { token: "patter", engine: "Patterplay", means: "Patter's shared globals" },
194053
+ { token: "story", engine: "Storylet Engine", means: "the Storylet Engine's shared @story properties" }
194054
+ ];
194055
+
194049
194056
  // ../dialect/src/index.ts
194050
194057
  function host(h) {
194051
194058
  return h.ctx.host ?? {};
@@ -194143,8 +194150,15 @@ var patterDialect = {
194143
194150
  }
194144
194151
  }
194145
194152
  };
194146
- function dialectWithForeignScopes(spec) {
194147
- if (!spec || spec.scopes.length === 0) return patterDialect;
194153
+ var EXTERNAL_SCOPES = ENGINE_SCOPES.map((s) => s.token).filter((t) => t !== "patter" && t !== "scene");
194154
+ function withEngineScopes(spec) {
194155
+ const present = new Set((spec?.scopes ?? []).map((s) => s.token));
194156
+ const extra = EXTERNAL_SCOPES.filter((t) => !present.has(t)).map((token2) => ({ token: token2 }));
194157
+ return { version: spec?.version ?? 1, scopes: [...spec?.scopes ?? [], ...extra] };
194158
+ }
194159
+ function dialectWithForeignScopes(given) {
194160
+ const spec = withEngineScopes(given);
194161
+ if (spec.scopes.length === 0) return patterDialect;
194148
194162
  const known = new Set(patterDialect.scopes.map((s) => s.token));
194149
194163
  const extra = spec.scopes.filter((s) => !known.has(s.token)).map((s) => ({ token: s.token }));
194150
194164
  if (extra.length === 0) return patterDialect;
@@ -194383,7 +194397,7 @@ function compileExpression(src, foreign) {
194383
194397
  }
194384
194398
  function validateConditions(input, options = {}) {
194385
194399
  const issues = [];
194386
- const foreign = options.foreignScopes;
194400
+ const foreign = withEngineScopes(options.foreignScopes);
194387
194401
  const dialect = dialectWithForeignScopes(foreign);
194388
194402
  const readOnly = readOnlyForeignTargets(foreign);
194389
194403
  const opaqueForeign = opaqueForeignTokens(foreign);
@@ -194478,10 +194492,11 @@ function validateInterpolation(input, options = {}) {
194478
194492
  const voiced = input.project.voiced ?? false;
194479
194493
  const tables = (input.locales ?? []).map((l2) => ({ locale: l2.locale, strings: l2.strings }));
194480
194494
  const defaultLocale = input.project.locales.default;
194481
- const opaqueForeign = opaqueForeignTokens(options.foreignScopes);
194482
- const isScopeToken = scopeTokenTest(options.foreignScopes);
194495
+ const foreign = withEngineScopes(options.foreignScopes);
194496
+ const opaqueForeign = opaqueForeignTokens(foreign);
194497
+ const isScopeToken = scopeTokenTest(foreign);
194483
194498
  for (const scene of input.scenes) {
194484
- const schema = buildSchema(input.project, scene.sceneProps, options.foreignScopes);
194499
+ const schema = buildSchema(input.project, scene.sceneProps, foreign);
194485
194500
  const known = (ref) => {
194486
194501
  const { scope, name } = splitRef(ref, isScopeToken);
194487
194502
  if (opaqueForeign.has(scope)) return true;
@@ -194644,11 +194659,33 @@ function compileScene(scene, foreign) {
194644
194659
  blocks: scene.blocks.map((b) => compileBlock(b, foreign))
194645
194660
  };
194646
194661
  }
194662
+ function externalScopesIn(scenes) {
194663
+ const found = /* @__PURE__ */ new Set();
194664
+ const external = new Set(EXTERNAL_SCOPES);
194665
+ const walk2 = (node) => {
194666
+ if (!Array.isArray(node) && (node === null || typeof node !== "object")) return;
194667
+ if (Array.isArray(node)) {
194668
+ if (node[0] === "sv" && typeof node[1] === "string" && external.has(node[1])) found.add(node[1]);
194669
+ for (const n of node) walk2(n);
194670
+ return;
194671
+ }
194672
+ const o = node;
194673
+ if (o["kind"] === "set" && typeof o["target"] === "string") {
194674
+ const head = o["target"].replace(/^@/, "").split(".")[0];
194675
+ if (o["target"].includes(".") && external.has(head)) found.add(head);
194676
+ }
194677
+ for (const v of Object.values(o)) walk2(v);
194678
+ };
194679
+ walk2(scenes);
194680
+ return [...found].sort();
194681
+ }
194647
194682
  function exportBundle(input) {
194648
194683
  const { project, scenes, locales = [], includeLocales } = input;
194649
194684
  const foreignScopes = input.foreignScopes ?? hostScopesToSpec(project.scopeRegistry);
194685
+ const compileScopes = withEngineScopes(foreignScopes);
194650
194686
  const scenesOut = {};
194651
- for (const scene of scenes) scenesOut[scene.id] = compileScene(scene, foreignScopes);
194687
+ for (const scene of scenes) scenesOut[scene.id] = compileScene(scene, compileScopes);
194688
+ const externalScopes = externalScopesIn(scenesOut);
194652
194689
  const strings = {};
194653
194690
  for (const loc of locales) {
194654
194691
  if (includeLocales && !includeLocales.includes(loc.locale)) continue;
@@ -194704,7 +194741,9 @@ function exportBundle(input) {
194704
194741
  // runtime falls back to `[` / `]` when absent, so default projects keep their exact prior bundle.
194705
194742
  ...project.closedCaptions ? { closedCaptions: project.closedCaptions } : {},
194706
194743
  scenes: scenesOut,
194707
- strings
194744
+ strings,
194745
+ // Other engines' scopes the content names, so the engine can say when the game has not registered one.
194746
+ ...externalScopes.length > 0 ? { externalScopes } : {}
194708
194747
  };
194709
194748
  }
194710
194749
 
@@ -195017,7 +195056,7 @@ function bundleOutputPath(loaded) {
195017
195056
  }
195018
195057
 
195019
195058
  // ../ops/src/playable-runtime.ts
195020
- var PLAYABLE_RUNTIME_JS = 'var Patterplay=(()=>{var V=Object.defineProperty;var ye=Object.getOwnPropertyDescriptor;var ve=Object.getOwnPropertyNames;var be=Object.prototype.hasOwnProperty;var we=(n,e)=>{for(var t in e)V(n,t,{get:e[t],enumerable:!0})},xe=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of ve(e))!be.call(n,s)&&s!==t&&V(n,s,{get:()=>e[s],enumerable:!(r=ye(e,s))||r.enumerable});return n};var Ee=n=>xe(V({},"__esModule",{value:!0}),n);var Le={};we(Le,{Engine:()=>F,Flow:()=>C,buildTagIndex:()=>A,describeBundle:()=>ue,effectiveGameData:()=>fe,gameDataFields:()=>he,gameDataValue:()=>K});function w(n){switch(n[0]){case"b":return{kind:"bool",value:n[1]};case"n":return{kind:"number",value:n[1]};case"s":return{kind:"string",value:n[1]};case"sv":return{kind:"scopedvar",scope:n[1],name:n[2]};case"u":return{kind:"unary",op:n[1],operand:w(n[2])};case"bin":return{kind:"binary",op:n[1],left:w(n[2]),right:w(n[3])};case"call":{let e=n.slice(2).map(w);return{kind:"call",name:n[1],args:e}}case"fd":return{kind:"flagdelta",sign:n[1],name:n[2]}}}var l=class extends Error{constructor(e){super(e),this.name="EvalError"}};function B(n,e,t){let r=new Map(t.scopes.map(i=>[i.token,i.missing??"false"])),s=i=>{switch(i.kind){case"bool":return i.value;case"number":return i.value;case"string":return i.value;case"scopedvar":{let o=e.scopes[i.scope];if(o===void 0)return!1;let a=typeof o.get=="function"?o.get(i.name):o[i.name];if(a===void 0){if(r.get(i.scope)==="throw")throw new l(`@${i.scope}.${i.name} is not declared on the current ${i.scope}.`);return!1}return a}case"call":{if(i.name==="advance"&&!t.functions[i.name]){let a=i.args[0];if(i.args.length!==1||a===void 0)throw new l(`advance() takes exactly 1 argument, got ${i.args.length}`);let c=M(a,e);if(c===void 0)throw new l("advance() needs a quality reference (@scope.name of a quality property)");let d=y(s(a),c,"advance");return c[Math.min(d+1,c.length-1)]}let o=t.functions[i.name];if(!o)throw new l(`unknown function \'${i.name}\'`);return o.eval(i.args,{evaluate:s,ctx:e})}case"flagdelta":throw new l("flagdelta node is only valid as an argument to a flag-delta function");case"unary":{if(i.op==="not"){let a=s(i.operand);if(typeof a!="boolean")throw new l(`\'not\' requires a boolean operand, got ${typeof a}`);return!a}let o=s(i.operand);if(typeof o!="number")throw new l(`unary \'-\' requires a numeric operand, got ${typeof o}`);return-o}case"binary":{if(i.op==="and"){let u=s(i.left);if(typeof u!="boolean")throw new l(`\'and\' requires boolean operands, left is ${typeof u}`);if(!u)return!1;let f=s(i.right);if(typeof f!="boolean")throw new l(`\'and\' requires boolean operands, right is ${typeof f}`);return f}if(i.op==="or"){let u=s(i.left);if(typeof u!="boolean")throw new l(`\'or\' requires boolean operands, left is ${typeof u}`);if(u)return!0;let f=s(i.right);if(typeof f!="boolean")throw new l(`\'or\' requires boolean operands, right is ${typeof f}`);return f}let o=s(i.left),a=s(i.right),c=M(i.left,e),d=M(i.right,e),p=c??d;if(p!==void 0){if(c&&d&&!ke(c,d)&&(i.op===">"||i.op===">="||i.op==="<"||i.op==="<="))throw new l(`\'${i.op}\' compares two different qualities, whose stage orders are unrelated`);switch(i.op){case">":return y(o,p,">")>y(a,p,">");case">=":return y(o,p,">=")>=y(a,p,">=");case"<":return y(o,p,"<")<y(a,p,"<");case"<=":return y(o,p,"<=")<=y(a,p,"<=");case"+":case"-":case"*":case"/":throw new l(`\'${i.op}\' cannot be applied to a quality - a stage is a position, not a number; use advance() to move it`);default:break}}switch(i.op){case"==":return Z(o,a);case"!=":return!Z(o,a);case">":return x(o,a,">"),o>a;case">=":return x(o,a,">="),o>=a;case"<":return x(o,a,"<"),o<a;case"<=":return x(o,a,"<="),o<=a;case"+":if(typeof o=="number"&&typeof a=="number"||typeof o=="string"&&typeof a=="string")return o+a;throw new l(`\'+\' requires two numbers or two strings, got ${typeof o} and ${typeof a}`);case"-":return x(o,a,"-"),o-a;case"*":return x(o,a,"*"),o*a;case"/":if(x(o,a,"/"),a===0)throw new l("division by zero");return o/a}}}};return s(n)}function Z(n,e){if(Array.isArray(n)||Array.isArray(e)){if(!Array.isArray(n)||!Array.isArray(e)||n.length!==e.length)return!1;let t=[...n].sort(),r=[...e].sort();for(let s=0;s<t.length;s++)if(t[s]!==r[s])return!1;return!0}return n===e}function x(n,e,t){if(typeof n!="number"||typeof e!="number")throw new l(`\'${t}\' requires numeric operands, got ${typeof n} and ${typeof e}`)}function M(n,e){if(!(n.kind!=="scopedvar"||e.qualities===void 0))return e.qualities(n.scope,n.name)}function y(n,e,t){if(typeof n!="string")throw new l(`\'${t}\' on a quality compares stages, got ${typeof n}`);let r=e.indexOf(n);if(r<0)throw new l(`"${n}" is not a stage of this quality (stages: ${e.join(", ")})`);return r}var ke=(n,e)=>n.length===e.length&&n.every((t,r)=>t===e[r]);function I(n){if(Number.isNaN(n)||!Number.isFinite(n))return 0;let e=Math.trunc(n)%4294967296;return e<0?e+4294967296:e}function j(n){let e=I(n);return{next(){e=e+1831565813>>>0;let t=Math.imul(e^e>>>15,1|e);return t=t+Math.imul(t^t>>>7,61|t)^t,((t^t>>>14)>>>0)/4294967296},state(){return e}}}var Ce={name:"check_flags",count:n=>Math.max(1,n.args.length-1)},Ie=[Ce];function Q(n,e,t){let r=t?.countingCalls??Ie;return P(n,t?.want??!0,e,r)}function P(n,e,t,r){if(n.kind==="binary"&&(n.op==="and"||n.op==="or")){let s=P(n.left,e,t,r),i=P(n.right,e,t,r);return n.op==="and"===e?s>0&&i>0?s+i:0:Math.max(s,i)}if(n.kind==="unary"&&n.op==="not")return P(n.operand,!e,t,r);if(n.kind==="call"){let s=r.find(i=>i.name===n.name);if(s){let i=s.count(n),o=t(n);return e?o?i:0:o?0:1}}return t(n)===e?1:0}var b=class n{values={};decls=new Map;subscribers=new Set;auditors=new Set;norm;pathPrefix;constructor(e=[],t){this.norm=t?.normalise??(r=>r.toLowerCase()),this.pathPrefix=t?.pathPrefix??"",this.seed(e)}seed(e){for(let t of e){let r=this.norm(t.name);this.decls.set(r,t),this.values[r]=structuredClone(t.default??E(t))}}get(e){return this.values[this.norm(e)]}set(e,t,r){let s=this.norm(e);if(!r?.host&&this.decls.get(s)?.writable===!1)throw new Error(`\'${e}\' is read-only`);let i={name:s,prev:this.values[s],next:t,silent:r?.silent??!1,reason:r?.reason};this.values[s]=t;for(let o of this.auditors)o(i);if(!i.silent)for(let o of this.subscribers)o(i);return i}subscribe(e){return this.subscribers.add(e),()=>this.subscribers.delete(e)}onAudit(e){return this.auditors.add(e),()=>this.auditors.delete(e)}rows(){return[...this.decls.entries()].map(([e,t])=>ee(t,this.get(e),void 0,e,this.pathPrefix))}declarations(){return[...this.decls.values()]}clone(){let e=new n([],{normalise:this.norm,pathPrefix:this.pathPrefix});return e.decls=new Map(this.decls),Object.assign(e.values,structuredClone(this.values)),e}reseed(e){for(let t of Object.keys(this.values))delete this.values[t];this.decls.clear(),this.seed(e)}save(){return structuredClone(this.values)}load(e){for(let[t,r]of Object.entries(e))this.values[this.norm(t)]=r}};function ee(n,e,t,r,s=""){let i=r??n.name.toLowerCase();return{name:i,path:s+i,type:n.type,value:e,default:n.default??E(n),...n.values!==void 0?{values:n.values}:{},...n.stages!==void 0?{stages:n.stages}:{},writable:t??n.writable??!0}}var $=1,D=class{scopes=new Map;defineOwned(e,t,r){return this.mountOwned(e,new b(t,{pathPrefix:r??`${e}.`}))}mountOwned(e,t){return this.assertFree(e),this.scopes.set(e,{kind:"owned",bag:t}),this}ownedBag(e){let t=this.scopes.get(e);if(!t||t.kind!=="owned")throw new Error(`\'@${e}\' is not an owned scope`);return t.bag}reseedOwned(e,t){return this.ownedBag(e).reseed(t),this}defineForeign(e,t,r=[],s=!0){this.assertFree(e);let i=new Map;for(let o of r)i.set(o.name.toLowerCase(),o);return this.scopes.set(e,{kind:"foreign",resolver:t,decls:i,scopeWritable:s}),this}has(e){return this.scopes.has(e)}get(e,t){let r=this.scopes.get(e);if(r)return r.kind==="owned"?r.bag.get(t):r.resolver.get(t.toLowerCase())}set(e,t,r,s){let i=this.scopes.get(e);if(!i)throw new Error(`unknown scope \'@${e}\'`);if(i.kind==="owned"){try{i.bag.set(t,r,s?.host?{host:!0}:void 0)}catch{throw new Error(`\'@${e}.${t}\' is read-only`)}return}let o=t.toLowerCase();if(!i.resolver.set)throw new Error(`\'@${e}.${t}\' is read-only`);if(!s?.host&&!this.foreignWritable(i,o))throw new Error(`\'@${e}.${t}\' is read-only`);i.resolver.set(o,r)}foreignWritable(e,t){return e.resolver.set?e.decls.get(t)?.writable??e.scopeWritable:!1}listProperties(){let e=[];for(let[t,r]of this.scopes)if(r.kind==="owned")for(let s of r.bag.rows())e.push({scope:t,...s});else for(let s of r.decls.values())e.push({scope:t,...ee(s,r.resolver.get(s.name.toLowerCase()),this.foreignWritable(r,s.name.toLowerCase()),void 0,`${t}.`)});return e}toEvalContext(e){let t={};for(let[s,i]of this.scopes)t[s]=i.kind==="owned"?i.bag.values:i.resolver;let r=this.qualityLadders();return r.size===0?{scopes:t,host:e}:{scopes:t,host:e,qualities:(s,i)=>r.get(s)?.get(i.toLowerCase())}}qualityLadders(){let e=new Map;for(let[t,r]of this.scopes){let s=r.kind==="owned"?r.bag.declarations():[...r.decls.values()];for(let i of s){if(i.type!=="quality"||i.stages===void 0)continue;let o=e.get(t);o||(o=new Map,e.set(t,o)),o.set(i.name.toLowerCase(),i.stages)}}return e}toSchema(){let e=new Map;for(let[t,r]of this.scopes){let s=r.kind==="owned"?r.bag.declarations():[...r.decls.values()];if(s.length===0)continue;let i=new Map;for(let o of s)i.set(o.name.toLowerCase(),{type:o.type,enumValues:o.values,...o.stages!==void 0?{stages:o.stages}:{}});e.set(t,i)}return{properties:e}}save(){let e={};for(let[t,r]of this.scopes)r.kind==="owned"&&(e[t]=r.bag.save());return e}load(e){for(let[t,r]of Object.entries(e)){let s=this.scopes.get(t);s?.kind==="owned"&&s.bag.load(r)}}saveFragment(){return{version:$,scopes:this.save()}}loadFragment(e){if(e.version!==$)throw new Error(`unsupported owned-state fragment version ${e.version} (supported: ${$})`);this.load(e.scopes)}assertFree(e){if(this.scopes.has(e))throw new Error(`scope \'@${e}\' is already registered`)}};function E(n){if(n.default!==void 0)return n.default;switch(n.type){case"boolean":return!1;case"number":return 0;case"string":return"";case"enum":return n.values?.[0]??"";case"flags":return[];case"quality":return n.stages?.[0]??"";default:return!1}}function R(n){return n.ctx.host??{}}var q={defaultScope:"patter",scopes:[{token:"patter"},{token:"scene"}],functions:{random:{minArgs:2,maxArgs:2,returnType:"number",eval(n,e){if(n.length!==2)throw new l("random(a, b) requires exactly 2 arguments");let t=R(e).nextRandom;if(!t)throw new l("random() called without a PRNG in context");let r=e.evaluate(n[0]),s=e.evaluate(n[1]);if(typeof r!="number"||typeof s!="number")throw new l("random(a, b) arguments must be numbers");if(!Number.isInteger(r)||!Number.isInteger(s))throw new l("random(a, b) arguments must be integers");let i=Math.min(r,s),o=Math.max(r,s);return Math.floor(t()*(o-i+1))+i}},check_flags:{minArgs:1,returnType:"boolean",flagDeltaArgs:!0,validate:re("check_flags"),eval(n,e){let t=te(n[0],e,"check_flags");for(let r=1;r<n.length;r++){let s=n[r];if(s.kind!=="flagdelta")throw new l("check_flags() flag args must be +flagName or -flagName");if(s.sign==="+"?!t.includes(s.name):t.includes(s.name))return!1}return!0}},set_flags:{minArgs:1,returnType:"flags",flagDeltaArgs:!0,validate:re("set_flags"),eval(n,e){let t=[...te(n[0],e,"set_flags")];for(let r=1;r<n.length;r++){let s=n[r];if(s.kind!=="flagdelta")throw new l("set_flags() flag args must be +flagName or -flagName");if(s.sign==="+")t.includes(s.name)||t.push(s.name);else{let i=t.indexOf(s.name);i>=0&&t.splice(i,1)}}return t}},visits:{minArgs:1,maxArgs:1,returnType:"number",validate:N("visits"),eval:(n,e)=>R(e).visits?.(O(n,e,"visits"))??0},seen:{minArgs:1,maxArgs:1,returnType:"boolean",validate:N("seen"),eval:(n,e)=>(R(e).visits?.(O(n,e,"seen"))??0)>0},patter_visits:{minArgs:1,maxArgs:1,returnType:"number",validate:N("patter_visits"),eval:(n,e)=>R(e).patterVisits?.(O(n,e,"patter_visits"))??0},patter_seen:{minArgs:1,maxArgs:1,returnType:"boolean",validate:N("patter_seen"),eval:(n,e)=>(R(e).patterVisits?.(O(n,e,"patter_seen"))??0)>0}}};function H(n,e){let t=n.replace(/^@/,"").split(".");return t.length===2&&e(t[0])?{scope:t[0],name:t[1].toLowerCase()}:{scope:"patter",name:t.join(".").toLowerCase()}}function O(n,e,t){let r=e.evaluate(n[0]);if(typeof r!="string")throw new l(`${t}(id) requires a string node id`);return r}function N(n){return(e,t)=>{let r=e[0];r&&r.kind!=="string"&&t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${n}(id): the argument must be a string id literal (a scene / block / node id)`})}}function te(n,e,t){if(!n)throw new l(`${t}() requires at least one argument (the flags variable)`);let r=e.evaluate(n);if(Array.isArray(r))return r;if(r===!1||r===null||r===void 0)return[];throw new l(`${t}() first argument must be a flags property`)}function re(n){return(e,t)=>{if(e.length===0)return;let r=e[0];if(r.kind!=="scopedvar"){t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${n}(): first argument must be a flags property reference (@name or @scope.name)`});return}let s=t.schema.properties.get(r.scope)?.get(r.name);if(s&&s.type!=="flags"){let i=r.scope===t.defaultScope?r.name:`${r.scope}.${r.name}`;t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${n}(): \'@${i}\' is not a flags property (got ${s.type})`});return}for(let i=1;i<e.length;i++){let o=e[i];o.kind!=="flagdelta"?t.report({path:[...t.path,"args",i],kind:"wrong-arg-type",severity:"error",message:`${n}(): argument ${i+1} must be +flagName or -flagName`}):s?.type==="flags"&&s.enumValues&&!s.enumValues.includes(o.name)&&t.report({path:[...t.path,"args",i],kind:"unknown-flag-name",severity:"error",message:`${n}(): unknown flag \'${o.name}\'`,reference:o.name})}}}var De=/^@[A-Za-z0-9_.]+$/;function*Re(n){let e="",t=0;for(;t<n.length;){let r=n[t];if(r==="{"&&n[t+1]==="{"){e+="{",t+=2;continue}if(r==="}"&&n[t+1]==="}"){e+="}",t+=2;continue}if(r==="{"){let s=n.indexOf("}",t+1);if(s!==-1){let i=n.slice(t,s+1),o=n.slice(t+1,s).trim();if(o.startsWith("@")){e&&(yield{kind:"text",value:e},e=""),yield{kind:"slot",raw:i,inner:o,ref:De.test(o)?o:void 0},t=s+1;continue}e+=i,t=s+1;continue}}e+=r,t+=1}e&&(yield{kind:"text",value:e})}function Be(n){return Array.isArray(n)?n.join(", "):typeof n=="boolean"?n?"true":"false":String(n)}function Pe(n){return n===" "||n===" "||n===`\n`||n==="\\r"||n==="\\f"||n==="\\v"}function Oe(n){let e="",t=!1;for(let r of n){if(Pe(r)){t=!0;continue}t&&e.length>0&&(e+=" "),t=!1,e+=r}return e}function ne(n,e,t){if(e.length===0||n.indexOf(e)<0)return n;let r="",s=0,i=!1;for(;s<n.length;){if(n.startsWith(e,s)){let o=n.indexOf(t,s+e.length);if(o>=0){s=o+t.length,i=!0;continue}r+=n.slice(s);break}r+=n[s],s+=1}return i?Oe(r):n}function se(n,e){if(n.indexOf("{")<0)return n;let t="";for(let r of Re(n)){if(r.kind==="text"){t+=r.value;continue}if(!r.ref){t+=r.raw;continue}let s=e(r.ref);t+=s===void 0?"":Be(s)}return t}function k(n,e){for(let t of n){e(t);let r=t.children;r&&k(r,e)}}function Ne(n){return n.toLowerCase().replace(/[\'\u2019]/g,"").replace(/[^a-z0-9-]+/g,"-").replace(/-+/g,"-").replace(/^-+|-+$/g,"")}function h(n){let e=n.gameId?.trim();return e||Ne(n.name)}function _(n){return`cast:${n}`}var U={open:"[",close:"]"},ie="SFX";function T(n){let e=new Set,t=[];for(let r of n)e.has(r)||(e.add(r),t.push(r));return t}function A(n){let e=new Map,t=(r,s)=>{let i=T([...s,...r.tags??[]]);if(e.set(r.id,i),r.type==="group")for(let o of r.children)t(o,i);else for(let o of r.beats??[])e.set(o.id,T([...i,...o.tags??[]]))};for(let r of Object.values(n.scenes)){let s=T(r.tags??[]);e.set(r.id,s);for(let i of r.blocks){let o=T([...s,...i.tags??[]]);e.set(i.id,o);for(let a of i.children)t(a,o)}}return e}var oe=new WeakMap,F=class n{host;defaultSeed;flowsById=new Map;allStrings;currentLocale;sourceDebug;sceneGameIdToId=new Map;blockGameIdToId=new Map;creationOptions;engineLog=[];engineTraceHandlers=new Set;constructor(e,t={}){this.creationOptions=t;let r=t.locale??e.locales.default,s=e.strings;this.allStrings=s,this.currentLocale=r;let i=s[r]??{},o=s[e.locales.default]??{},a=e.localisation,c=a?.mode==="ids"&&!a.sourceDebug;this.sourceDebug=a?.mode==="ids"&&!!a.sourceDebug,this.sourceDebug&&typeof console<"u"&&console.warn("[Patterplay] source-only DEBUG build: strings are the source language for debugging, not a shippable localised build.");let d=new Map;for(let g of e.cast??[])g.displayName&&d.set(g.name,g.displayName);this.defaultSeed=(t.seed??2654435769)>>>0;let p=new Map,u=new Map,f=new Map;for(let[g,m]of Object.entries(e.scenes)){this.sceneGameIdToId.set(h(m),g);let v=new Map;for(let S of m.blocks)u.set(S.id,{sceneId:g}),f.set(S.id,S),v.set(h(S),S.id),k(S.children,X=>p.set(X.id,X));this.blockGameIdToId.set(g,v)}let J=e.properties??[],G=J.filter(g=>g.shared??!0).map(ce),me=J.filter(g=>!(g.shared??!0)).map(ce),Se=new Set(G.map(g=>g.name.toLowerCase())),L=new D().defineOwned("patter",G,"@patter."),z=new Set;if(t.world){let g=e.scopeRegistry?.scopes.find(v=>v.token==="world"),m=(g?.declarations??[]).map(le);L.defineForeign("world",t.world,m,g?.writable??!0),z.add("world")}for(let g of e.scopeRegistry?.scopes??[]){if(z.has(g.token))continue;let m=(g.declarations??[]).map(le);L.defineForeign(g.token,Te(g.declarations??[]),m,g.writable??!0)}let Y=new Map;for(let[g,m]of Object.entries(e.scenes)){let v=new Set((m.sceneProps??[]).filter(S=>S.shared??!1).map(S=>S.name.toLowerCase()));Y.set(g,v)}this.host={logEnabled:t.log??!1,emitEngine:(g,m,v)=>this.emitEngine(g,m,v),bundle:e,emitIds:c,strings:i,defaultStrings:o,castDisplay:d,nodeIndex:p,blockIndex:u,blockById:f,sceneGameIdToId:this.sceneGameIdToId,blockGameIdToId:this.blockGameIdToId,tagIndex:A(e),shared:L,patterSharedDecls:G,patterLocalDecls:me,patterSharedNames:Se,sceneSharedNames:Y,sharedVisits:new Map,sharedSelectors:new Map,stageBags:new Map,customRng:t.rng,onDryChoice:t.onDryChoice,replayPromptOnChoose:t.replayPromptOnChoose??!1,captionsOn:t.closedCaptions??!0,captionOpen:(e.closedCaptions??U).open,captionClose:(e.closedCaptions??U).close,captionCharacter:e.closedCaptions?.character||ie,refSplitCache:new Map}}get locale(){return this.currentLocale}get isSourceDebug(){return this.sourceDebug}setLocale(e){this.currentLocale=e,this.host.strings=this.allStrings[e]??{}}replaceStrings(e){this.allStrings=e.strings,this.host.strings=this.allStrings[this.currentLocale]??{},this.host.defaultStrings=this.allStrings[this.host.bundle.locales.default]??{}}hotSwap(e){let t=this.saveGame(),r=i=>(i.setLocale(this.currentLocale),i.setClosedCaptions(this.host.captionsOn),i),s=new n(e,this.creationOptions);try{return s.loadGame(t),r(s)}catch{let i=new n(e,this.creationOptions);for(let[o,a]of Object.entries(t.flows)){let c=a.cursor.currentSceneId;try{i.openFlow(o,c!==null?{scene:c}:{})}catch{}}return r(i)}}get closedCaptions(){return this.host.captionsOn}setClosedCaptions(e){this.host.captionsOn=e}openFlow(e,t={}){let r=this.resolveSceneRef(t.scene),s=this.resolveBlockRef(r,t.block);this.flowsById.get(e)?.close();let i=new C(e,this.host,t.seed??this.defaultSeed);return this.flowsById.set(e,i),i.start(r,s),i}runFlow(e,t,r){let s=this.flowsById.get(e);if(!s)return this.openFlow(e,{scene:t,block:r}).advanceToStop().played;if(!s.goto(t,r))throw new Error(`runFlow: address not found: ${t}${r===void 0?"":` / ${r}`}`);return s.advanceToStop().played}resolveSceneRef(e){if(e!=null)return this.host.bundle.scenes[e]?e:this.sceneGameIdToId.get(e)??e}resolveBlockRef(e,t){if(t!=null){if(this.host.blockById.has(t))return t;if(e!=null){let r=this.blockGameIdToId.get(e)?.get(t);if(r)return r}return t}}sceneAddress(e){let t=this.host.bundle.scenes[e];return t?h(t):void 0}blockAddress(e){let t=this.host.blockById.get(e);return t?h(t):void 0}tagsForBeat(e){return this.host.tagIndex.get(e)??[]}tagsForScene(e){let t=this.resolveSceneRef(e);return(t!=null?this.host.tagIndex.get(t):void 0)??[]}tagsForBlock(e,t){let r=this.resolveSceneRef(e),s=this.resolveBlockRef(r,t);return(s!=null?this.host.tagIndex.get(s):void 0)??[]}getCast(){let e=[];for(let t of this.host.bundle.cast??[])t?.name&&e.push(t.name);return e}castForScene(e){let t=this.resolveSceneRef(e),r=t!=null?this.host.bundle.scenes[t]:void 0;if(!r)return[];let s=new Set;for(let i of r.blocks)ae(i.children,s);return[...s]}castForBlock(e,t){let r=this.resolveSceneRef(e),s=this.resolveBlockRef(r,t),i=s!=null?this.host.blockById.get(s):void 0;if(!i)return[];let o=new Set;return ae(i.children,o),[...o]}getOutline(){return Object.values(this.host.bundle.scenes).map(e=>({id:e.id,...h(e)?{gameId:h(e)}:{},name:e.name,...this.tagsField(e.id),blocks:e.blocks.map(t=>({id:t.id,...h(t)?{gameId:h(t)}:{},name:t.name,...this.tagsField(t.id),children:t.children.map(r=>this.outlineNode(r))}))}))}getBeatSequence(){let e=[];for(let t of Object.values(this.host.bundle.scenes))for(let r of t.blocks)k(r.children,s=>{if(s.type==="snippet")for(let i of s.beats??[])e.push({sceneId:t.id,blockId:r.id,snippetId:s.id,beat:this.beatInfo(i)})});return e}outlineNode(e){return e.type==="group"?{type:"group",id:e.id,...this.tagsField(e.id),...e.selector?{selector:e.selector}:{},...e.prompt?{prompt:this.beatInfo(e.prompt)}:{},children:e.children.map(t=>this.outlineNode(t))}:{type:"snippet",id:e.id,...this.tagsField(e.id),beats:(e.beats??[]).map(t=>this.beatInfo(t)),...e.jump?{jumpTo:e.jump.to,...e.jump.mode?{jumpMode:e.jump.mode}:{}}:{}}}beatInfo(e){let t=this.host.tagIndex.get(e.id),r={id:e.id,kind:e.kind};if(e.kind==="line"){if(e.character!==void 0){r.character=e.character;let s=this.host.defaultStrings[_(e.character)]??this.host.castDisplay.get(e.character);s!==void 0&&(r.characterName=s)}e.direction!==void 0&&(r.direction=e.direction)}if(e.kind==="line"||e.kind==="text"){let s=this.host.defaultStrings[e.id];s!==void 0&&(r.text=s)}return e.gameData&&Object.keys(e.gameData).length&&(r.gameData=e.gameData),t&&t.length&&(r.tags=t),r}tagsField(e){let t=this.host.tagIndex.get(e);return t&&t.length?{tags:t}:{}}getFlow(e){return this.flowsById.get(e)}flows(){return[...this.flowsById.values()]}listBags(){let e=[{bag:this.host.shared.ownedBag("patter")}];for(let[t,r]of this.host.stageBags)e.push({bag:r,pathPrefix:`@scene:${t}.`});return e}closeFlow(e){this.flowsById.get(e)?.close(),this.flowsById.delete(e)}reset(){for(let e of this.flowsById.values())e.close();this.flowsById.clear(),this.host.shared.reseedOwned("patter",this.host.patterSharedDecls),this.host.sharedVisits.clear(),this.host.sharedSelectors.clear(),this.host.stageBags.clear()}getProperty(e){let{scope:t,name:r}=this.splitShared(e);return this.host.shared.get(t,r)}setProperty(e,t){let{scope:r,name:s}=this.splitShared(e);this.host.shared.set(r,s,t,{host:!0})}log(){return this.engineLog}clearLog(){this.engineLog.length=0}onTrace(e){return this.engineTraceHandlers.add(e),()=>this.engineTraceHandlers.delete(e)}emitEngine(e,t,r){for(let s of this.engineTraceHandlers)s(e,t);this.host.logEnabled&&this.engineLog.push({...t,flow:e,seq:this.engineLog.length,...r?{scene:r}:{}})}listProperties(){return this.host.patterSharedDecls.map(e=>({name:e.name,path:`@patter.${e.name}`,type:e.type,values:e.values,stages:e.stages,value:this.getProperty(`@${e.name}`),default:E(e),writable:e.writable??!0}))}splitShared(e){let t=this.host.refSplitCache.get(e);if(t||(t=H(e,r=>r==="scene"||this.host.shared.has(r)),this.host.refSplitCache.set(e,t)),t.scope==="scene")throw new Error(`\'${e}\': @scene properties are scene-scoped - read/write them on a Flow, not the Engine`);return t}save(){return this.host.shared.save()}load(e){this.host.shared.load(e)}saveGame(){let e={};for(let[t,r]of this.flowsById)e[t]=r.snapshot();return{version:2,shared:this.host.shared.save(),sharedVisits:Object.fromEntries(this.host.sharedVisits),sharedSelectors:de(this.host.sharedSelectors),stageBags:Object.fromEntries([...this.host.stageBags].map(([t,r])=>[t,r.save()])),flows:e}}loadGame(e){if(e.version!==2)throw new Error(`unsupported save version: ${e.version}`);this.host.shared.load(e.shared),this.host.sharedVisits.clear();for(let[t,r]of Object.entries(e.sharedVisits??{}))this.host.sharedVisits.set(t,r);this.host.sharedSelectors.clear();for(let[t,r]of ge(e.sharedSelectors))this.host.sharedSelectors.set(t,r);this.host.stageBags.clear();for(let[t,r]of Object.entries(e.stageBags??{})){let s=this.host.sceneSharedNames.get(t)??new Set,i=(this.host.bundle.scenes[t]?.sceneProps??[]).filter(a=>s.has(a.name.toLowerCase())),o=new b(i);o.load(r),this.host.stageBags.set(t,o)}this.flowsById.clear();for(let[t,r]of Object.entries(e.flows)){let s=new C(t,this.host,this.defaultSeed);s.restore(r),this.flowsById.set(t,s)}}},C=class{id;host;local;rngState;started=!1;flowEnded=!1;closed=!1;currentSceneId=null;stack=[];activeSnippet=null;beatIndex=0;pendingChoice=null;pendingPromptBeat=null;pendingPromptOwnerId=null;selectors=new Map;visitCounts=new Map;sceneBags=new Map;patterResolver={get:e=>this.host.patterSharedNames.has(e)?this.host.shared.get("patter",e):this.local.get("patter",e),set:(e,t)=>{this.host.patterSharedNames.has(e)?this.host.shared.set("patter",e,t):this.local.set("patter",e,t)}};sceneResolver={get:e=>{let t=this.currentSceneId;return t===null?void 0:(this.host.sceneSharedNames.get(t)?.has(e)?this.host.stageBags.get(t):this.sceneBags.get(t))?.get(e)},set:(e,t)=>{let r=this.currentSceneId;if(r===null)return;let s=this.host.sceneSharedNames.get(r)?.has(e)?this.host.stageBags.get(r):this.sceneBags.get(r);s&&s.set(e,t)}};evalCtx;flowLog=[];flowSeq=0;constructor(e,t,r){this.id=e,this.host=t,this.rngState=I(r),this.local=this.freshLocal();let s={...t.shared.toEvalContext().scopes};s.patter=this.patterResolver,s.scene=this.sceneResolver,this.evalCtx={scopes:s,host:{nextRandom:this.rng,visits:i=>this.visitCounts.get(i)??0,patterVisits:i=>this.host.sharedVisits.get(i)??0},qualities:(i,o)=>this.stagesFor(i,o)}}stagesFor(e,t){let r=t.toLowerCase(),s=i=>i?.find(o=>o.name.toLowerCase()===r&&o.type==="quality")?.stages;if(e==="patter")return s(this.host.patterSharedDecls)??s(this.host.patterLocalDecls);if(e==="scene"){let i=this.currentSceneId!=null?this.host.bundle.scenes[this.currentSceneId]:void 0;return s(i?.sceneProps)}return s(this.host.bundle.scopeRegistry?.scopes.find(i=>i.token===e)?.declarations)}start(e,t){if(this.sceneBags.clear(),this.local=this.freshLocal(),this.selectors.clear(),this.visitCounts.clear(),this.stack=[],this.currentSceneId=null,this.flowEnded=!1,this.activeSnippet=null,this.beatIndex=0,this.pendingChoice=null,this.started=!0,t){let r=this.host.blockIndex.get(t);if(!r)throw new Error(`unknown block: ${t}`);this.enterSceneSetup(r.sceneId),this.stack=[{sceneId:r.sceneId,containerId:t,index:0}],this.enter(t)}else{let r=e??Object.keys(this.host.bundle.scenes)[0],s=r?this.host.bundle.scenes[r]:void 0;if(!s)throw new Error(r?`unknown scene: ${r}`:"no scenes in bundle");this.enterSceneSetup(r);let i=s.blocks[0];i&&(this.stack=[{sceneId:r,containerId:i.id,index:0}],this.enter(i.id))}this.settle()}reset(e,t){this.start(e,t)}goto(e,t){if(this.closed)return!1;if(e==="END")return this.started=!0,this.pendingChoice=null,this.pendingPromptBeat=null,this.pendingPromptOwnerId=null,this.activeSnippet=null,this.beatIndex=0,this.flowEnded=!0,this.stack=[],!0;let r=this.host.sceneGameIdToId.get(e)??(this.host.bundle.scenes[e]?e:void 0);if(r===void 0)return!1;let s;return t!==void 0&&(s=this.host.blockGameIdToId.get(r)?.get(t)??(this.host.blockIndex.get(t)?.sceneId===r?t:void 0),s===void 0)?!1:this.started?(this.pendingChoice=null,this.pendingPromptBeat=null,this.pendingPromptOwnerId=null,this.activeSnippet=null,this.beatIndex=0,this.flowEnded=!1,this.enterTarget(s??r,"jump"),this.settle(),!0):(this.start(r,s),!0)}close(){this.closed=!0,this.flowEnded=!0,this.stack=[],this.activeSnippet=null,this.beatIndex=0,this.pendingChoice=null,this.pendingPromptBeat=null,this.pendingPromptOwnerId=null}get isClosed(){return this.closed}get currentScene(){return this.currentSceneId}advance(){if(this.closed)return{type:"end"};if(!this.started)throw new Error("flow has not been started");if(this.pendingPromptBeat){let e=this.pendingPromptBeat;return this.pendingPromptBeat=null,this.pendingPromptOwnerId=null,this.beatResult(e)}return this.settle(),this.flowEnded?{type:"end"}:this.pendingChoice?{type:"choice",groupId:this.pendingChoice.groupId,options:this.pendingChoice.options}:this.activeSnippet?this.beatResult(this.activeSnippet.beats[this.beatIndex++]):(this.flowEnded=!0,{type:"end"})}advanceToStop(){let e=[];for(;;){let t=this.advance();if(t.type==="choice"||t.type==="end")return{played:e,stop:t};e.push(t)}}settle(){let e=0;for(;;){if(++e>1e4)throw new Error("flow did not settle after 10000 transitions - likely a jump cycle with no deliverable content");if(this.flowEnded||this.pendingChoice)return;if(this.activeSnippet){if(this.beatIndex<(this.activeSnippet.beats?.length??0))return;this.runEffects(this.activeSnippet.onExit);let i=this.activeSnippet.jump;this.activeSnippet=null,this.beatIndex=0,this.resolveJump(i);continue}let t=this.stack[this.stack.length-1];if(!t){this.flowEnded=!0;return}t.sceneId!==this.currentSceneId&&(this.currentSceneId=t.sceneId);let r=this.childrenOf(t.containerId);if(!r){this.stack.pop();continue}let s=t.index;for(;t.index<r.length&&!this.eligible(r[t.index]);)t.index++;if(this.host.logEnabled&&t.index!==s&&this.emit({type:"select",group:t.containerId,selector:"run",children:r.slice(s,t.index+1).map((i,o)=>({id:i.id,eligible:s+o===t.index})),picked:r[t.index]?.id??null}),t.index>=r.length){this.stack.pop();continue}this.enterChild(r[t.index++])}}listBags(){let e=[{bag:this.local.ownedBag("patter"),pathPrefix:`${this.id}/@patter.`}];for(let[t,r]of this.sceneBags)e.push({bag:r,pathPrefix:`${this.id}/@scene:${t}.`});return e}log(){return this.flowLog}clearLog(){this.flowLog.length=0}emit(e){let t=this.currentSceneId??void 0;this.host.emitEngine(this.id,e,t),this.host.logEnabled&&this.flowLog.push({...e,seq:this.flowSeq++,...t?{scene:t}:{}})}getChoices(){return this.pendingChoice?.options??[]}choose(e){let t=this.pendingChoice;if(!t)throw new Error("no choice is pending");let r=t.options.find(i=>i.id===e);if(!r)throw new Error(`unknown choice option: ${e}`);if(!r.eligible)throw new Error(`choice option is not eligible: ${e}`);let s=t.byId.get(e);this.emit({type:"chose",group:t.groupId,option:e}),this.pendingChoice=null,this.pendingPromptBeat=this.host.replayPromptOnChoose?this.promptBeatOf(s)??null:null,this.pendingPromptOwnerId=this.pendingPromptBeat?s.id:null,this.enterChild(s)}isEnded(){return this.flowEnded}getProperty(e){let{scope:t,name:r}=this.splitRef(e);return t==="patter"?this.patterResolver.get(r):t==="scene"?this.sceneResolver.get(r):this.host.shared.get(t,r)}setProperty(e,t){this.writeProperty(e,t,!0)}writeProperty(e,t,r){let{scope:s,name:i}=this.splitRef(e);if(s==="patter")this.patterResolver.set(i,t);else if(s==="scene"){if(this.currentSceneId===null)throw new Error(`\'${e}\': the flow has not entered a scene yet`);this.sceneResolver.set(i,t)}else this.host.shared.set(s,i,t,r?{host:!0}:void 0)}snapshot(){return{scopes:this.local.save(),sceneBags:Object.fromEntries([...this.sceneBags].map(([e,t])=>[e,t.save()])),rngState:this.rngState,visits:Object.fromEntries(this.visitCounts),cursor:{flowEnded:this.flowEnded,currentSceneId:this.currentSceneId,stack:this.stack.map(e=>{let t=this.childrenOf(e.containerId)?.[e.index];return t?{...e,nextId:t.id}:{...e}}),activeSnippetId:this.activeSnippet?.id??null,beatIndex:this.beatIndex,pendingChoice:this.pendingChoice?{groupId:this.pendingChoice.groupId,options:this.pendingChoice.options.map(e=>({...e}))}:null,pendingPromptOwnerId:this.pendingPromptOwnerId,selectors:de(this.selectors)}}}restore(e){this.rngState=I(e.rngState),this.visitCounts=new Map(Object.entries(e.visits??{}));let t=e.cursor;if(this.started=!0,this.flowEnded=t.flowEnded,this.beatIndex=t.beatIndex,this.currentSceneId=t.currentSceneId,this.stack=t.stack.map(r=>{let{nextId:s,...i}=r;if(s!==void 0){let o=this.childrenOf(i.containerId)?.findIndex(a=>a.id===s)??-1;if(o>=0)return{...i,index:o}}return{...i}}),this.sceneBags=new Map(Object.entries(e.sceneBags??{}).map(([r,s])=>{let i=this.host.sceneSharedNames.get(r)??new Set,o=(this.host.bundle.scenes[r]?.sceneProps??[]).filter(c=>!i.has(c.name.toLowerCase())),a=new b(o);return a.load(s),[r,a]})),this.local=this.freshLocal(),this.local.load(e.scopes),this.activeSnippet=null,t.activeSnippetId!==null){let r=this.host.nodeIndex.get(t.activeSnippetId);r&&r.type==="snippet"&&(this.activeSnippet=r)}if(this.selectors=ge(t.selectors),this.pendingChoice=null,t.pendingChoice!==null){let r=new Map,s=[];for(let i of t.pendingChoice.options){let o=this.host.nodeIndex.get(i.id);o&&(r.set(i.id,o),s.push({...i}))}s.length>0&&(this.pendingChoice={groupId:t.pendingChoice.groupId,options:s,byId:r})}if(this.pendingPromptBeat=null,this.pendingPromptOwnerId=t.pendingPromptOwnerId??null,this.pendingPromptOwnerId){let r=this.host.nodeIndex.get(this.pendingPromptOwnerId);this.pendingPromptBeat=r?this.promptBeatOf(r)??null:null,this.pendingPromptBeat||(this.pendingPromptOwnerId=null)}}enterSceneSetup(e){let t=this.host.bundle.scenes[e];if(!t)throw new Error(`unknown scene: ${e}`);this.currentSceneId=e,this.enter(e),this.seedScene(t),this.runEffects(t.onEntry)}enterChild(e){if(this.enter(e.id),e.type==="snippet"){this.beginSnippet(e);return}let t=e.selector??"run";if(t==="run"){this.stack.push({sceneId:this.currentSceneId,containerId:e.id,index:0});return}if(t==="choice"){this.setupChoice(e);return}let r=this.selectChild(e);r&&this.enterChild(r)}childrenOf(e){let t=this.host.blockById.get(e);if(t)return t.children;let r=this.host.nodeIndex.get(e);if(r&&r.type==="group")return r.children}beginSnippet(e){this.runEffects(e.onEnter),this.activeSnippet=e,this.beatIndex=0}setupChoice(e){let t=[],r=new Map,s=[];for(let o of e.children){if(o.fallback===!0){s.push(o);continue}if(o.sticky!==!0&&(this.visitCounts.get(o.id)??0)>=1)continue;let a=this.eligible(o),c=o.secretUntilEligible===!0;!a&&c||(t.push({id:o.id,prompt:this.promptFor(o),eligible:a,gameData:o.gameData}),r.set(o.id,o))}if(t.length>0){this.emit({type:"choice",group:e.id,options:t.map(o=>({id:o.id,eligible:o.eligible}))}),this.pendingChoice={groupId:e.id,options:t,byId:r};return}let i=s.find(o=>this.eligible(o));if(i){this.enterChild(i);return}this.emit({type:"dry",group:e.id}),this.host.onDryChoice?.(e.id)}resolveJump(e){e&&this.enterTarget(e.to,e.mode==="call"?"call":"jump")}enterTarget(e,t){if(this.emit({type:"jump",to:e,mode:t}),e==="END"){this.flowEnded=!0,this.stack=[];return}let r,s,i=this.host.bundle.scenes[e];if(i){this.enterSceneSetup(e);let a=i.blocks[0];if(!a){t==="jump"&&(this.stack=[]);return}r=e,s=a.id}else{let a=this.host.blockIndex.get(e);if(!a)throw new Error(`jump target not found: ${e}`);a.sceneId!==this.currentSceneId&&this.enterSceneSetup(a.sceneId),r=a.sceneId,s=e}this.enter(s);let o={sceneId:r,containerId:s,index:0};t==="call"?this.stack.push(o):this.stack=[o]}selectChild(e){let t=e.children.map(c=>({id:c.id,eligible:this.eligible(c)})),r=e.children.filter(c=>this.eligible(c)),s=e.options?.order??"sequential",i=e.options?.exhaust??"once",o=c=>(this.emit({type:"select",group:e.id,selector:e.selector??"default",...e.selector==="sequence"?{order:s,exhaust:i}:{},children:t,picked:c?.id??null}),c);if(r.length===0)return o(null);let a=this.selectorState(e);switch(e.selector){case"branch":return o(r[0]);case"sequence":return o(s==="shuffle"?this.pickShuffle(r,i,a):s==="specificity"?this.pickSpecificity(r,i,a):this.pickSequential(r,i,a));default:return null}}pickSequential(e,t,r){let s=e.length,i=r.seq??0;return r.seq=i+1,t==="repeat"?e[i%s]:i<s?e[i]:t==="stick"?e[s-1]:null}pickShuffle(e,t,r){let s=e.length,i=t==="stick",o=()=>(i?e.slice(0,s-1):e).map(u=>u.id);if(r.bag===void 0&&(r.bag=o()),r.bag.length===0){if(t==="once")return null;if(i){let u=e[s-1];return r.last=u.id,u}r.bag=o()}let a=r.bag,c=r.last!==void 0&&a.length>1?a.indexOf(r.last):-1,d=Math.floor(this.rng()*(c>=0?a.length-1:a.length));c>=0&&d>=c&&d++;let p=a[d];return a.splice(d,1),r.last=p,e.find(u=>u.id===p)}pickSpecificity(e,t,r){let s=e;if(t!=="repeat"){r.bag===void 0&&(r.bag=e.map(p=>p.id));let d=new Set(r.bag);if(s=e.filter(p=>d.has(p.id)),s.length===0)return t==="stick"&&r.last!==void 0?e.find(p=>p.id===r.last)??null:null}let i=-1,a=s.map(d=>{let p=this.specScore(d);return p>i&&(i=p),{c:d,s:p}}).filter(d=>d.s===i).map(d=>d.c),c;if(a.length===1)c=a[0];else{let d=r.last!==void 0?a.findIndex(u=>u.id===r.last):-1,p=Math.floor(this.rng()*(d>=0?a.length-1:a.length));d>=0&&p>=d&&p++,c=a[p]}return t!=="repeat"&&(r.bag=r.bag.filter(d=>d!==c.id)),r.last=c.id,c}specScore(e){return e.condition?this.matchedSpec(this.conditionAst(e.condition),!0):0}matchedSpec(e,t){return Q(e,s=>pe(B(s,this.evalCtx,q)),{want:t})}selectorState(e){let t=e.shared?this.host.sharedSelectors:this.selectors,r=t.get(e.id);return r||(r={},t.set(e.id,r)),r}runEffects(e){for(let t of e??[]){let r=this.evalExpr(t.value),s=this.host.logEnabled?this.getProperty(t.target):void 0;this.writeProperty(t.target,r,!1),this.emit({type:"write",target:t.target,value:r,...s!==void 0?{prev:s}:{}})}}eligible(e){return e.condition?pe(this.evalExpr(e.condition)):!0}evalExpr(e){return B(this.conditionAst(e),this.evalCtx,q)}conditionAst(e){let t=oe.get(e);return t||(t=w(e.ast),oe.set(e,t)),t}enter(e){this.visitCounts.set(e,(this.visitCounts.get(e)??0)+1),this.host.sharedVisits.set(e,(this.host.sharedVisits.get(e)??0)+1)}rng=()=>{if(this.host.customRng)return this.host.customRng();let e=j(this.rngState),t=e.next();return this.rngState=e.state(),t};beatResult(e){let t=this.host.tagIndex.get(e.id),r=t&&t.length?{tags:t}:{};switch(e.kind){case"gameEvent":return{type:"gameEvent",id:e.id,gameData:e.gameData,...r};case"text":return{type:"text",id:e.id,text:this.interpolate(this.resolveString(e.id)),gameData:e.gameData,...r};case"line":{let s=this.resolveString(e.id),i=!this.host.captionsOn,a=i&&e.character===this.host.captionCharacter?"":this.captionLine(this.host.bundle.voiced?s:this.interpolate(s)),c=i&&a.length===0;return{type:"line",id:e.id,text:a,character:c?void 0:e.character,characterName:c?void 0:this.resolveCharacterName(e.character),direction:c?void 0:e.direction,gameData:e.gameData,...r}}}}interpolate(e){return se(e,t=>this.getProperty(t))}stripCaptions(e){return ne(e,this.host.captionOpen,this.host.captionClose)}captionLine(e){return this.host.captionsOn?e:this.stripCaptions(e)}promptFor(e){let t=this.promptBeatOf(e);if(!t)return;let r=this.interpolate(this.resolveString(t.id));return t.kind==="line"?{kind:"line",text:this.captionLine(r),character:t.character,characterName:this.resolveCharacterName(t.character),direction:t.direction}:{kind:"text",text:r}}promptBeatOf(e){return e.type==="group"&&e.prompt?e.prompt:((e.type==="snippet"?e:this.firstTextSnippetIn(e.children))?.beats??[]).find(r=>r.kind==="line"||r.kind==="text")}firstTextSnippetIn(e){let t;return k(e,r=>{!t&&r.type==="snippet"&&(r.beats??[]).some(s=>s.kind==="line"||s.kind==="text")&&(t=r)}),t}resolveString(e){if(this.host.emitIds)return e;let t=this.host.strings[e];if(t!==void 0)return t;let r=this.host.defaultStrings[e];return r!==void 0?`<Untranslated: ${e}> ${r}`:e}resolveCharacterName(e){if(e===void 0||this.host.emitIds)return;let t=_(e);return this.host.strings[t]??this.host.defaultStrings[t]??this.host.castDisplay.get(e)}splitRef(e){let t=this.host.refSplitCache.get(e);return t||(t=H(e,r=>r==="scene"||this.host.shared.has(r)),this.host.refSplitCache.set(e,t)),t}freshLocal(){return new D().defineOwned("patter",this.host.patterLocalDecls,"@patter.")}seedScene(e){let t=this.host.sceneSharedNames.get(e.id)??new Set,r=e.sceneProps??[];this.sceneBags.has(e.id)||this.sceneBags.set(e.id,new b(r.filter(s=>!t.has(s.name.toLowerCase())))),this.host.stageBags.has(e.id)||this.host.stageBags.set(e.id,new b(r.filter(s=>t.has(s.name.toLowerCase()))));for(let s of e.sceneProps??[]){if(!s.temporary)continue;let i=s.name.toLowerCase(),o=t.has(i)?this.host.stageBags.get(e.id):this.sceneBags.get(e.id);o&&o.set(i,E(s))}}};function ae(n,e){k(n,t=>{if(t.type==="group"){t.prompt?.kind==="line"&&t.prompt.character&&e.add(t.prompt.character);return}for(let r of t.beats??[])r.kind==="line"&&r.character&&e.add(r.character)})}function de(n){let e={};for(let[t,r]of n){let s={};r.seq!==void 0&&(s.seq=r.seq),r.bag&&(s.bag=[...r.bag]),r.last!==void 0&&(s.last=r.last),e[t]=s}return e}function ge(n){let e=new Map;for(let[t,r]of Object.entries(n??{})){let s={};r.seq!==void 0&&(s.seq=r.seq),r.bag&&(s.bag=[...r.bag]),r.last!==void 0&&(s.last=r.last),e.set(t,s)}return e}function ce(n){return{name:n.name,type:n.type,values:n.values,stages:n.stages,default:n.default}}function le(n){return{name:n.name,type:n.type,values:n.values,stages:n.stages,default:n.default,writable:n.writable}}function Te(n){let e=r=>r.toLowerCase(),t=new Map;for(let r of n)t.set(e(r.name),E(r));return{get:r=>t.get(e(r)),set:(r,s)=>{t.set(e(r),s)}}}function pe(n){return typeof n=="boolean"?n:typeof n=="number"?n!==0:typeof n=="string"?n!=="":n.length>0}var Ae=(n,e)=>n.shared??e;function W(n,e){return{name:n.name,type:n.type,hasDefault:n.default!==void 0,...n.default!==void 0?{default:n.default}:{},shared:Ae(n,e)}}function Fe(n){return{name:n.name,type:n.type,hasDefault:n.default!==void 0,...n.values?{values:[...n.values]}:{},...n.purpose?{purpose:n.purpose}:{}}}function Ge(n,e){e.blocks++;let t=[...n.children];for(;t.length;){let r=t.pop();if(r.type==="group"){e.groups++,r.prompt&&e.prompts++,t.push(...r.children);continue}e.snippets++;for(let s of r.beats??[])e.beats++,s.kind==="gameEvent"&&e.gameEvents++}}function ue(n){let e={scenes:0,blocks:0,groups:0,snippets:0,beats:0,prompts:0,gameEvents:0,cast:n.cast?.length??0},t=[],r=[];for(let o of Object.values(n.scenes)){e.scenes++;let a=h(o);t.push({gameId:a,name:o.name,blocks:o.blocks.map(c=>({gameId:h(c),name:c.name}))});for(let c of o.blocks)Ge(c,e);o.sceneProps?.length&&r.push({gameId:a,properties:o.sceneProps.map(c=>W(c,!1))})}let s=(n.scopeRegistry?.scopes??[]).map(o=>({token:o.token,writable:o.writable??!0,opaque:o.declarations===void 0,properties:(o.declarations??[]).map(a=>W(a,!0))})),i=Object.entries(n.gameDataFields??{}).filter(([,o])=>(o?.length??0)>0).map(([o,a])=>({kind:o,fields:(a??[]).map(Fe)}));return{identity:{schema:n.schema,project:n.content.project,...n.content.version!==void 0?{version:n.content.version}:{},...n.content.hash!==void 0?{hash:n.content.hash}:{},...n.content.structureHash!==void 0?{structureHash:n.content.structureHash}:{},voiced:n.voiced,defaultLocale:n.locales.default,locales:[...n.locales.included],localisation:n.localisation?.mode??"embedded",sourceDebug:n.localisation?.sourceDebug??!1},addresses:t,hostScopes:s,properties:{patter:(n.properties??[]).map(o=>W(o,!0)),scene:r},gameData:i,counts:e}}function he(n,e){return n.gameDataFields?.[e]??[]}function K(n,e,t){return e&&Object.prototype.hasOwnProperty.call(e,t)?e[t]:n.find(r=>r.name===t)?.default}function fe(n,e){let t={};for(let r of n){let s=K(n,e,r.name);s!==void 0&&(t[r.name]=s)}for(let[r,s]of Object.entries(e??{}))r in t||(t[r]=s);return t}return Ee(Le);})();\n';
195059
+ var PLAYABLE_RUNTIME_JS = 'var Patterplay=(()=>{var q=Object.defineProperty;var Oe=Object.getOwnPropertyDescriptor;var Be=Object.getOwnPropertyNames;var Pe=Object.prototype.hasOwnProperty;var Ne=(n,e)=>{for(var t in e)q(n,t,{get:e[t],enumerable:!0})},Fe=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of Be(e))!Pe.call(n,s)&&s!==t&&q(n,s,{get:()=>e[s],enumerable:!(r=Oe(e,s))||r.enumerable});return n};var Te=n=>Fe(q({},"__esModule",{value:!0}),n);var Qe={};Ne(Qe,{Engine:()=>$,Flow:()=>D,buildTagIndex:()=>M,describeBundle:()=>ke,effectiveGameData:()=>Ie,gameDataFields:()=>Ce,gameDataValue:()=>Q});function E(n){switch(n[0]){case"b":return{kind:"bool",value:n[1]};case"n":return{kind:"number",value:n[1]};case"s":return{kind:"string",value:n[1]};case"sv":return{kind:"scopedvar",scope:n[1],name:n[2]};case"u":return{kind:"unary",op:n[1],operand:E(n[2])};case"bin":return{kind:"binary",op:n[1],left:E(n[2]),right:E(n[3])};case"call":{let e=n.slice(2).map(E);return{kind:"call",name:n[1],args:e}}case"fd":return{kind:"flagdelta",sign:n[1],name:n[2]}}}var p=class extends Error{constructor(e){super(e),this.name="EvalError"}};function F(n,e,t){let r=new Map(t.scopes.map(i=>[i.token,i.missing??"false"])),s=i=>{switch(i.kind){case"bool":return i.value;case"number":return i.value;case"string":return i.value;case"scopedvar":{let o=e.scopes[i.scope];if(o===void 0)return!1;let a=typeof o.get=="function"?o.get(i.name):o[i.name];if(a===void 0){if(r.get(i.scope)==="throw")throw new p(`@${i.scope}.${i.name} is not declared on the current ${i.scope}.`);return!1}return a}case"call":{if(i.name==="advance"&&!t.functions[i.name]){let a=i.args[0];if(i.args.length!==1||a===void 0)throw new p(`advance() takes exactly 1 argument, got ${i.args.length}`);let c=_(a,e);if(c===void 0)throw new p("advance() needs a quality reference (@scope.name of a quality property)");let l=w(s(a),c,"advance");return c[Math.min(l+1,c.length-1)]}let o=t.functions[i.name];if(!o)throw new p(`unknown function \'${i.name}\'`);return o.eval(i.args,{evaluate:s,ctx:e})}case"flagdelta":throw new p("flagdelta node is only valid as an argument to a flag-delta function");case"unary":{if(i.op==="not"){let a=s(i.operand);if(typeof a!="boolean")throw new p(`\'not\' requires a boolean operand, got ${typeof a}`);return!a}let o=s(i.operand);if(typeof o!="number")throw new p(`unary \'-\' requires a numeric operand, got ${typeof o}`);return-o}case"binary":{if(i.op==="and"){let u=s(i.left);if(typeof u!="boolean")throw new p(`\'and\' requires boolean operands, left is ${typeof u}`);if(!u)return!1;let S=s(i.right);if(typeof S!="boolean")throw new p(`\'and\' requires boolean operands, right is ${typeof S}`);return S}if(i.op==="or"){let u=s(i.left);if(typeof u!="boolean")throw new p(`\'or\' requires boolean operands, left is ${typeof u}`);if(u)return!0;let S=s(i.right);if(typeof S!="boolean")throw new p(`\'or\' requires boolean operands, right is ${typeof S}`);return S}let o=s(i.left),a=s(i.right),c=_(i.left,e),l=_(i.right,e),d=c??l;if(d!==void 0){if(c&&l&&!Ae(c,l)&&(i.op===">"||i.op===">="||i.op==="<"||i.op==="<="))throw new p(`\'${i.op}\' compares two different qualities, whose stage orders are unrelated`);switch(i.op){case">":return w(o,d,">")>w(a,d,">");case">=":return w(o,d,">=")>=w(a,d,">=");case"<":return w(o,d,"<")<w(a,d,"<");case"<=":return w(o,d,"<=")<=w(a,d,"<=");case"+":case"-":case"*":case"/":throw new p(`\'${i.op}\' cannot be applied to a quality - a stage is a position, not a number; use advance() to move it`);default:break}}switch(i.op){case"==":return se(o,a);case"!=":return!se(o,a);case">":return k(o,a,">"),o>a;case">=":return k(o,a,">="),o>=a;case"<":return k(o,a,"<"),o<a;case"<=":return k(o,a,"<="),o<=a;case"+":if(typeof o=="number"&&typeof a=="number"||typeof o=="string"&&typeof a=="string")return o+a;throw new p(`\'+\' requires two numbers or two strings, got ${typeof o} and ${typeof a}`);case"-":return k(o,a,"-"),o-a;case"*":return k(o,a,"*"),o*a;case"/":if(k(o,a,"/"),a===0)throw new p("division by zero");return o/a}}}};return s(n)}function se(n,e){if(Array.isArray(n)||Array.isArray(e)){if(!Array.isArray(n)||!Array.isArray(e)||n.length!==e.length)return!1;let t=[...n].sort(),r=[...e].sort();for(let s=0;s<t.length;s++)if(t[s]!==r[s])return!1;return!0}return n===e}function k(n,e,t){if(typeof n!="number"||typeof e!="number")throw new p(`\'${t}\' requires numeric operands, got ${typeof n} and ${typeof e}`)}function _(n,e){if(!(n.kind!=="scopedvar"||e.qualities===void 0))return e.qualities(n.scope,n.name)}function w(n,e,t){if(typeof n!="string")throw new p(`\'${t}\' on a quality compares stages, got ${typeof n}`);let r=e.indexOf(n);if(r<0)throw new p(`"${n}" is not a stage of this quality (stages: ${e.join(", ")})`);return r}var Ae=(n,e)=>n.length===e.length&&n.every((t,r)=>t===e[r]);function R(n){if(Number.isNaN(n)||!Number.isFinite(n))return 0;let e=Math.trunc(n)%4294967296;return e<0?e+4294967296:e}function H(n){let e=R(n);return{next(){e=e+1831565813>>>0;let t=Math.imul(e^e>>>15,1|e);return t=t+Math.imul(t^t>>>7,61|t)^t,((t^t>>>14)>>>0)/4294967296},state(){return e}}}var Ge={name:"check_flags",count:n=>Math.max(1,n.args.length-1)},Ve=[Ge];function ie(n,e,t){let r=t?.countingCalls??Ve;return T(n,t?.want??!0,e,r)}function T(n,e,t,r){if(n.kind==="binary"&&(n.op==="and"||n.op==="or")){let s=T(n.left,e,t,r),i=T(n.right,e,t,r);return n.op==="and"===e?s>0&&i>0?s+i:0:Math.max(s,i)}if(n.kind==="unary"&&n.op==="not")return T(n.operand,!e,t,r);if(n.kind==="call"){let s=r.find(i=>i.name===n.name);if(s){let i=s.count(n),o=t(n);return e?o?i:0:o?0:1}}return t(n)===e?1:0}var b=class n{values={};decls=new Map;subscribers=new Set;auditors=new Set;norm;pathPrefix;constructor(e=[],t){this.norm=t?.normalise??(r=>r.toLowerCase()),this.pathPrefix=t?.pathPrefix??"",this.seed(e)}seed(e){for(let t of e){let r=this.norm(t.name);this.decls.set(r,t),this.values[r]=structuredClone(t.default??O(t))}}get(e){return this.values[this.norm(e)]}normalise(e){return this.norm(e)}set(e,t,r){let s=this.norm(e);if(!r?.host&&this.decls.get(s)?.writable===!1)throw new Error(`\'${e}\' is read-only`);let i={name:s,prev:this.values[s],next:t,silent:r?.silent??!1,reason:r?.reason};this.values[s]=t;for(let o of this.auditors)o(i);if(!i.silent)for(let o of this.subscribers)o(i);return i}subscribe(e){return this.subscribers.add(e),()=>this.subscribers.delete(e)}onAudit(e){return this.auditors.add(e),()=>this.auditors.delete(e)}rows(){return[...this.decls.entries()].map(([e,t])=>ae(t,this.get(e),void 0,e,this.pathPrefix))}declarations(){return[...this.decls.values()]}clone(){let e=new n([],{normalise:this.norm,pathPrefix:this.pathPrefix});return e.decls=new Map(this.decls),Object.assign(e.values,structuredClone(this.values)),e}reseed(e){for(let t of Object.keys(this.values))delete this.values[t];this.decls.clear(),this.seed(e)}save(){return structuredClone(this.values)}load(e){for(let[t,r]of Object.entries(e))this.values[this.norm(t)]=r}};function ae(n,e,t,r,s=""){let i=r??n.name.toLowerCase();return{name:i,path:s+i,type:n.type,value:e,default:n.default??O(n),...n.values!==void 0?{values:n.values}:{},...n.stages!==void 0?{stages:n.stages}:{},writable:t??n.writable??!0}}var Le=n=>n.toLowerCase(),U=1,A=class{scopes=new Map;parked=new Map;rev=0;get revision(){return this.rev}defineOwned(e,t,r){let s=typeof r=="string"?{pathPrefix:r}:r??{},i=new b(t,{pathPrefix:s.pathPrefix??`${e}.`,...s.normalise?{normalise:s.normalise}:{}});return this.mountOwned(e,i,s.owner!==void 0?{owner:s.owner}:void 0)}mountOwned(e,t,r){this.assertFree(e,r?.owner),this.scopes.set(e,{kind:"owned",bag:t,...r?.owner!==void 0?{owner:r.owner}:{}}),this.rev++;let s=this.parked.get(e);return s&&(t.load(s),this.parked.delete(e)),this}remove(e,t){let r=this.scopes.get(e);if(!r)throw new Error(`unknown scope \'@${e}\'`);return t?.keep&&r.kind==="owned"&&this.parked.set(e,r.bag.save()),this.scopes.delete(e),this.rev++,this}discardParked(e){if(e===void 0)this.parked.clear();else for(let t of[...this.parked.keys()])t.startsWith(e)&&this.parked.delete(t);return this}ownedBag(e){let t=this.scopes.get(e);if(!t||t.kind!=="owned")throw new Error(`\'@${e}\' is not an owned scope`);return t.bag}reseedOwned(e,t){return this.ownedBag(e).reseed(t),this}defineForeign(e,t,r=[],s=!0){let i=typeof s=="boolean"?{writable:s}:s;this.assertFree(e,i.owner);let o=i.normalise??Le,a=new Map;for(let c of r)a.set(o(c.name),c);return this.scopes.set(e,{kind:"foreign",resolver:t,decls:a,scopeWritable:i.writable??!0,norm:o,...i.owner!==void 0?{owner:i.owner}:{}}),this.rev++,this}has(e){return this.scopes.has(e)}get(e,t){let r=this.scopes.get(e);if(r)return r.kind==="owned"?r.bag.get(t):r.resolver.get(r.norm(t))}set(e,t,r,s){let i=this.scopes.get(e);if(!i)throw new Error(`unknown scope \'@${e}\'`);if(i.kind==="owned"){try{i.bag.set(t,r,s?.host?{host:!0}:void 0)}catch{throw new Error(`\'@${e}.${t}\' is read-only`)}return}let o=i.norm(t);if(!i.resolver.set)throw new Error(`\'@${e}.${t}\' is read-only`);if(!s?.host&&!this.foreignWritable(i,o))throw new Error(`\'@${e}.${t}\' is read-only`);i.resolver.set(o,r)}foreignWritable(e,t){return e.resolver.set?e.decls.get(t)?.writable??e.scopeWritable:!1}listProperties(){let e=[];for(let[t,r]of this.scopes){let s=r.owner!==void 0?{owner:r.owner}:{};if(r.kind==="owned")for(let i of r.bag.rows())e.push({scope:t,...s,...i});else for(let[i,o]of r.decls)e.push({scope:t,...s,...ae(o,r.resolver.get(i),this.foreignWritable(r,i),i,`${t}.`)})}return e}toEvalContext(e,t){let r=this.view(t?.aliases),s={};for(let[o,a]of r)s[o]=a.kind==="owned"?a.bag.values:a.resolver;let i=this.qualityLadders(r);return i.size===0?{scopes:s,host:e}:{scopes:s,host:e,qualities:(o,a)=>{let c=r.get(o);return c?i.get(o)?.get(Me(c)(a)):void 0}}}view(e){let t=new Map(this.scopes);for(let[r,s]of Object.entries(e??{})){let i=this.scopes.get(s);if(!i)throw new Error(`alias \'@${r}\' names \'${s}\', which is not registered`);t.set(r,i)}return t}qualityLadders(e){let t=new Map;for(let[r,s]of e)for(let[i,o]of oe(s)){if(o.type!=="quality"||o.stages===void 0)continue;let a=t.get(r);a||(a=new Map,t.set(r,a)),a.set(i,o.stages)}return t}toSchema(e){let t=new Map;for(let[r,s]of this.view(e?.aliases)){let i=oe(s);if(i.length===0)continue;let o=new Map;for(let[a,c]of i)o.set(a,{type:c.type,enumValues:c.values,...c.stages!==void 0?{stages:c.stages}:{}});t.set(r,o)}return{properties:t}}save(){let e={};for(let[t,r]of this.scopes)r.kind==="owned"&&(e[t]=r.bag.save());for(let[t,r]of this.parked)e[t]=structuredClone(r);return e}load(e,t){t?.keepParked||this.parked.clear();for(let[r,s]of Object.entries(e)){let i=this.scopes.get(r);i?.kind==="owned"?i.bag.load(s):i||this.parked.set(r,structuredClone(s))}}saveFragment(){return{version:U,scopes:this.save()}}loadFragment(e){if(e.version!==U)throw new Error(`unsupported owned-state fragment version ${e.version} (supported: ${U})`);this.load(e.scopes)}assertFree(e,t){let r=this.scopes.get(e);if(!r)return;let s=r.owner!==void 0?` by ${r.owner}`:"",i=t!==void 0?` (wanted by ${t})`:"";throw new Error(`scope \'@${e}\' is already registered${s}${i}`)}};function oe(n){return n.kind==="foreign"?[...n.decls.entries()]:n.bag.declarations().map(e=>[n.bag.normalise(e.name),e])}function Me(n){return n.kind==="foreign"?n.norm:e=>n.bag.normalise(e)}function O(n){if(n.default!==void 0)return n.default;switch(n.type){case"boolean":return!1;case"number":return 0;case"string":return"";case"enum":return n.values?.[0]??"";case"flags":return[];case"quality":return n.stages?.[0]??"";default:return!1}}var ce=[{token:"patter",engine:"Patterplay",means:"Patter\'s shared globals"},{token:"story",engine:"Storylet Engine",means:"the Storylet Engine\'s shared @story properties"}];function B(n){return n.ctx.host??{}}var W={defaultScope:"patter",scopes:[{token:"patter"},{token:"scene"}],functions:{random:{minArgs:2,maxArgs:2,returnType:"number",eval(n,e){if(n.length!==2)throw new p("random(a, b) requires exactly 2 arguments");let t=B(e).nextRandom;if(!t)throw new p("random() called without a PRNG in context");let r=e.evaluate(n[0]),s=e.evaluate(n[1]);if(typeof r!="number"||typeof s!="number")throw new p("random(a, b) arguments must be numbers");if(!Number.isInteger(r)||!Number.isInteger(s))throw new p("random(a, b) arguments must be integers");let i=Math.min(r,s),o=Math.max(r,s);return Math.floor(t()*(o-i+1))+i}},check_flags:{minArgs:1,returnType:"boolean",flagDeltaArgs:!0,validate:pe("check_flags"),eval(n,e){let t=le(n[0],e,"check_flags");for(let r=1;r<n.length;r++){let s=n[r];if(s.kind!=="flagdelta")throw new p("check_flags() flag args must be +flagName or -flagName");if(s.sign==="+"?!t.includes(s.name):t.includes(s.name))return!1}return!0}},set_flags:{minArgs:1,returnType:"flags",flagDeltaArgs:!0,validate:pe("set_flags"),eval(n,e){let t=[...le(n[0],e,"set_flags")];for(let r=1;r<n.length;r++){let s=n[r];if(s.kind!=="flagdelta")throw new p("set_flags() flag args must be +flagName or -flagName");if(s.sign==="+")t.includes(s.name)||t.push(s.name);else{let i=t.indexOf(s.name);i>=0&&t.splice(i,1)}}return t}},visits:{minArgs:1,maxArgs:1,returnType:"number",validate:V("visits"),eval:(n,e)=>B(e).visits?.(G(n,e,"visits"))??0},seen:{minArgs:1,maxArgs:1,returnType:"boolean",validate:V("seen"),eval:(n,e)=>(B(e).visits?.(G(n,e,"seen"))??0)>0},patter_visits:{minArgs:1,maxArgs:1,returnType:"number",validate:V("patter_visits"),eval:(n,e)=>B(e).patterVisits?.(G(n,e,"patter_visits"))??0},patter_seen:{minArgs:1,maxArgs:1,returnType:"boolean",validate:V("patter_seen"),eval:(n,e)=>(B(e).patterVisits?.(G(n,e,"patter_seen"))??0)>0}}},ut=ce.map(n=>n.token).filter(n=>n!=="patter"&&n!=="scene");function de(n,e){let t=n.replace(/^@/,"").split(".");return t.length===2&&e(t[0])?{scope:t[0],name:t[1].toLowerCase()}:{scope:"patter",name:t.join(".").toLowerCase()}}function G(n,e,t){let r=e.evaluate(n[0]);if(typeof r!="string")throw new p(`${t}(id) requires a string node id`);return r}function V(n){return(e,t)=>{let r=e[0];r&&r.kind!=="string"&&t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${n}(id): the argument must be a string id literal (a scene / block / node id)`})}}function le(n,e,t){if(!n)throw new p(`${t}() requires at least one argument (the flags variable)`);let r=e.evaluate(n);if(Array.isArray(r))return r;if(r===!1||r===null||r===void 0)return[];throw new p(`${t}() first argument must be a flags property`)}function pe(n){return(e,t)=>{if(e.length===0)return;let r=e[0];if(r.kind!=="scopedvar"){t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${n}(): first argument must be a flags property reference (@name or @scope.name)`});return}let s=t.schema.properties.get(r.scope)?.get(r.name);if(s&&s.type!=="flags"){let i=r.scope===t.defaultScope?r.name:`${r.scope}.${r.name}`;t.report({path:[...t.path,"args",0],kind:"wrong-arg-type",severity:"error",message:`${n}(): \'@${i}\' is not a flags property (got ${s.type})`});return}for(let i=1;i<e.length;i++){let o=e[i];o.kind!=="flagdelta"?t.report({path:[...t.path,"args",i],kind:"wrong-arg-type",severity:"error",message:`${n}(): argument ${i+1} must be +flagName or -flagName`}):s?.type==="flags"&&s.enumValues&&!s.enumValues.includes(o.name)&&t.report({path:[...t.path,"args",i],kind:"unknown-flag-name",severity:"error",message:`${n}(): unknown flag \'${o.name}\'`,reference:o.name})}}}var $e=/^@[A-Za-z0-9_.]+$/;function*je(n){let e="",t=0;for(;t<n.length;){let r=n[t];if(r==="{"&&n[t+1]==="{"){e+="{",t+=2;continue}if(r==="}"&&n[t+1]==="}"){e+="}",t+=2;continue}if(r==="{"){let s=n.indexOf("}",t+1);if(s!==-1){let i=n.slice(t,s+1),o=n.slice(t+1,s).trim();if(o.startsWith("@")){e&&(yield{kind:"text",value:e},e=""),yield{kind:"slot",raw:i,inner:o,ref:$e.test(o)?o:void 0},t=s+1;continue}e+=i,t=s+1;continue}}e+=r,t+=1}e&&(yield{kind:"text",value:e})}function qe(n){return Array.isArray(n)?n.join(", "):typeof n=="boolean"?n?"true":"false":String(n)}function _e(n){return n===" "||n===" "||n===`\n`||n==="\\r"||n==="\\f"||n==="\\v"}function He(n){let e="",t=!1;for(let r of n){if(_e(r)){t=!0;continue}t&&e.length>0&&(e+=" "),t=!1,e+=r}return e}function ge(n,e,t){if(e.length===0||n.indexOf(e)<0)return n;let r="",s=0,i=!1;for(;s<n.length;){if(n.startsWith(e,s)){let o=n.indexOf(t,s+e.length);if(o>=0){s=o+t.length,i=!0;continue}r+=n.slice(s);break}r+=n[s],s+=1}return i?He(r):n}function ue(n,e){if(n.indexOf("{")<0)return n;let t="";for(let r of je(n)){if(r.kind==="text"){t+=r.value;continue}if(!r.ref){t+=r.raw;continue}let s=e(r.ref);t+=s===void 0?"":qe(s)}return t}function C(n,e){for(let t of n){e(t);let r=t.children;r&&C(r,e)}}function Ue(n){return n.toLowerCase().replace(/[\'\u2019]/g,"").replace(/[^a-z0-9-]+/g,"-").replace(/-+/g,"-").replace(/^-+|-+$/g,"")}function m(n){let e=n.gameId?.trim();return e||Ue(n.name)}function K(n){return`cast:${n}`}var J={open:"[",close:"]"},he="SFX";var z=3;function L(n){let e=new Set,t=[];for(let r of n)e.has(r)||(e.add(r),t.push(r));return t}function M(n){let e=new Map,t=(r,s)=>{let i=L([...s,...r.tags??[]]);if(e.set(r.id,i),r.type==="group")for(let o of r.children)t(o,i);else for(let o of r.beats??[])e.set(o.id,L([...i,...o.tags??[]]))};for(let r of Object.values(n.scenes)){let s=L(r.tags??[]);e.set(r.id,s);for(let i of r.blocks){let o=L([...s,...i.tags??[]]);e.set(i.id,o);for(let a of i.children)t(a,o)}}return e}var fe=new WeakMap,I="Patter",P=n=>n.replace(/%/g,"%25").replace(/\\//g,"%2F"),me=Symbol("ownsRegistry"),v={stage:n=>`patter/scene/${P(n)}`,flow:n=>`patter/flow/${P(n)}/`,flowGlobals:n=>`patter/flow/${P(n)}/patter`,flowScene:(n,e)=>`patter/flow/${P(n)}/scene/${P(e)}`},$=class n{host;defaultSeed;flowsById=new Map;allStrings;currentLocale;sourceDebug;sceneGameIdToId=new Map;blockGameIdToId=new Map;creationOptions;engineLog=[];engineTraceHandlers=new Set;constructor(e,t={}){this.creationOptions=t;let r=t.locale??e.locales.default,s=e.strings;this.allStrings=s,this.currentLocale=r;let i=s[r]??{},o=s[e.locales.default]??{},a=e.localisation,c=a?.mode==="ids"&&!a.sourceDebug;this.sourceDebug=a?.mode==="ids"&&!!a.sourceDebug,this.sourceDebug&&typeof console<"u"&&console.warn("[Patterplay] source-only DEBUG build: strings are the source language for debugging, not a shippable localised build.");let l=new Map;for(let g of e.cast??[])g.displayName&&l.set(g.name,g.displayName);this.defaultSeed=(t.seed??2654435769)>>>0;let d=new Map,u=new Map,S=new Map;for(let[g,h]of Object.entries(e.scenes)){this.sceneGameIdToId.set(m(h),g);let y=new Map;for(let f of h.blocks)u.set(f.id,{sceneId:g}),S.set(f.id,f),y.set(m(f),f.id),C(f.children,ne=>d.set(ne.id,ne));this.blockGameIdToId.set(g,y)}let X=e.properties??[],j=X.filter(g=>g.shared??!0).map(ye),De=X.filter(g=>!(g.shared??!0)).map(ye),Re=new Set(j.map(g=>g.name.toLowerCase())),x=t.registry??new A,Z=!t.registry||t[me]===!0,ee=new b(j,{pathPrefix:"@patter."}),te=[],N=[];try{x.mountOwned("patter",ee,{owner:I}),N.push("patter");let g=new Set;if(t.world){let h=e.scopeRegistry?.scopes.find(f=>f.token==="world"),y=(h?.declarations??[]).map(xe);x.defineForeign("world",t.world,y,{writable:h?.writable??!0,owner:I}),N.push("world"),g.add("world")}for(let h of Z?e.scopeRegistry?.scopes??[]:[]){if(g.has(h.token)||x.has(h.token))continue;let y=(h.declarations??[]).map(f=>We(f,h.writable));x.defineOwned(h.token,y,{owner:I}),N.push(h.token),te.push(h.token)}}catch(g){for(let h of N)x.remove(h,{keep:!0});throw g}let re=new Map;for(let[g,h]of Object.entries(e.scenes)){let y=new Set((h.sceneProps??[]).filter(f=>f.shared??!1).map(f=>f.name.toLowerCase()));re.set(g,y)}this.host={logEnabled:t.log??!1,emitEngine:(g,h,y)=>this.emitEngine(g,h,y),bundle:e,emitIds:c,strings:i,defaultStrings:o,castDisplay:l,nodeIndex:d,blockIndex:u,blockById:S,sceneGameIdToId:this.sceneGameIdToId,blockGameIdToId:this.blockGameIdToId,tagIndex:M(e),registry:x,ownsRegistry:Z,patterBag:ee,hostScopes:te,patterSharedDecls:j,patterLocalDecls:De,patterSharedNames:Re,sceneSharedNames:re,sharedVisits:new Map,sharedSelectors:new Map,stageBags:new Map,customRng:t.rng,onDryChoice:t.onDryChoice,replayPromptOnChoose:t.replayPromptOnChoose??!1,captionsOn:t.closedCaptions??!0,captionOpen:(e.closedCaptions??J).open,captionClose:(e.closedCaptions??J).close,captionCharacter:e.closedCaptions?.character||he,refSplitCache:new Map,refSplitRevision:x.revision}}get locale(){return this.currentLocale}get isSourceDebug(){return this.sourceDebug}setLocale(e){this.currentLocale=e,this.host.strings=this.allStrings[e]??{}}replaceStrings(e){this.allStrings=e.strings,this.host.strings=this.allStrings[this.currentLocale]??{},this.host.defaultStrings=this.allStrings[this.host.bundle.locales.default]??{}}hotSwap(e){let t=this.saveGame(),r=o=>(o.setLocale(this.currentLocale),o.setClosedCaptions(this.host.captionsOn),o),s=()=>new n(e,{...this.creationOptions,registry:this.host.registry,[me]:this.host.ownsRegistry});this.release(!0);let i=s();try{return i.loadGame(t),r(i)}catch{i.release(!0);let o=s();for(let[a,c]of Object.entries(t.flows)){let l=c.cursor.currentSceneId;try{o.openFlow(a,l!==null?{scene:l}:{})}catch{}}return r(o)}}get closedCaptions(){return this.host.captionsOn}setClosedCaptions(e){this.host.captionsOn=e}openFlow(e,t={}){this.assertExternalScopes();let r=this.resolveSceneRef(t.scene),s=this.resolveBlockRef(r,t.block);this.flowsById.get(e)?.close();let i=new D(e,this.host,t.seed??this.defaultSeed);return this.flowsById.set(e,i),i.start(r,s),i}runFlow(e,t,r){let s=this.flowsById.get(e);if(!s)return this.openFlow(e,{scene:t,block:r}).advanceToStop().played;if(!s.goto(t,r))throw new Error(`runFlow: address not found: ${t}${r===void 0?"":` / ${r}`}`);return s.advanceToStop().played}assertExternalScopes(){for(let e of this.host.bundle.externalScopes??[])if(!this.host.registry.has(e))throw new Error(`this content names @${e}, which no engine on this registry registered: give every engine the game\'s one registry`)}resolveSceneRef(e){if(e!=null)return this.host.bundle.scenes[e]?e:this.sceneGameIdToId.get(e)??e}resolveBlockRef(e,t){if(t!=null){if(this.host.blockById.has(t))return t;if(e!=null){let r=this.blockGameIdToId.get(e)?.get(t);if(r)return r}return t}}sceneAddress(e){let t=this.host.bundle.scenes[e];return t?m(t):void 0}blockAddress(e){let t=this.host.blockById.get(e);return t?m(t):void 0}tagsForBeat(e){return this.host.tagIndex.get(e)??[]}tagsForScene(e){let t=this.resolveSceneRef(e);return(t!=null?this.host.tagIndex.get(t):void 0)??[]}tagsForBlock(e,t){let r=this.resolveSceneRef(e),s=this.resolveBlockRef(r,t);return(s!=null?this.host.tagIndex.get(s):void 0)??[]}getCast(){let e=[];for(let t of this.host.bundle.cast??[])t?.name&&e.push(t.name);return e}castForScene(e){let t=this.resolveSceneRef(e),r=t!=null?this.host.bundle.scenes[t]:void 0;if(!r)return[];let s=new Set;for(let i of r.blocks)Se(i.children,s);return[...s]}castForBlock(e,t){let r=this.resolveSceneRef(e),s=this.resolveBlockRef(r,t),i=s!=null?this.host.blockById.get(s):void 0;if(!i)return[];let o=new Set;return Se(i.children,o),[...o]}getOutline(){return Object.values(this.host.bundle.scenes).map(e=>({id:e.id,...m(e)?{gameId:m(e)}:{},name:e.name,...this.tagsField(e.id),blocks:e.blocks.map(t=>({id:t.id,...m(t)?{gameId:m(t)}:{},name:t.name,...this.tagsField(t.id),children:t.children.map(r=>this.outlineNode(r))}))}))}getBeatSequence(){let e=[];for(let t of Object.values(this.host.bundle.scenes))for(let r of t.blocks)C(r.children,s=>{if(s.type==="snippet")for(let i of s.beats??[])e.push({sceneId:t.id,blockId:r.id,snippetId:s.id,beat:this.beatInfo(i)})});return e}outlineNode(e){return e.type==="group"?{type:"group",id:e.id,...this.tagsField(e.id),...e.selector?{selector:e.selector}:{},...e.prompt?{prompt:this.beatInfo(e.prompt)}:{},children:e.children.map(t=>this.outlineNode(t))}:{type:"snippet",id:e.id,...this.tagsField(e.id),beats:(e.beats??[]).map(t=>this.beatInfo(t)),...e.jump?{jumpTo:e.jump.to,...e.jump.mode?{jumpMode:e.jump.mode}:{}}:{}}}beatInfo(e){let t=this.host.tagIndex.get(e.id),r={id:e.id,kind:e.kind};if(e.kind==="line"){if(e.character!==void 0){r.character=e.character;let s=this.host.defaultStrings[K(e.character)]??this.host.castDisplay.get(e.character);s!==void 0&&(r.characterName=s)}e.direction!==void 0&&(r.direction=e.direction)}if(e.kind==="line"||e.kind==="text"){let s=this.host.defaultStrings[e.id];s!==void 0&&(r.text=s)}return e.gameData&&Object.keys(e.gameData).length&&(r.gameData=e.gameData),t&&t.length&&(r.tags=t),r}tagsField(e){let t=this.host.tagIndex.get(e);return t&&t.length?{tags:t}:{}}getFlow(e){return this.flowsById.get(e)}flows(){return[...this.flowsById.values()]}listBags(){let e=[{bag:this.host.patterBag}];for(let[t,r]of this.host.stageBags)e.push({bag:r,pathPrefix:`@scene:${t}.`});return e}closeFlow(e){this.flowsById.get(e)?.close(),this.flowsById.delete(e)}reset(){for(let e of this.flowsById.values())e.close();this.flowsById.clear(),this.host.patterBag.reseed(this.host.patterSharedDecls),this.host.sharedVisits.clear(),this.host.sharedSelectors.clear();for(let e of this.host.stageBags.keys())this.host.registry.remove(v.stage(e));this.host.stageBags.clear(),this.host.registry.discardParked("patter/")}release(e){for(let r of this.flowsById.values())r.releaseBags(e),r.close();this.flowsById.clear();let t=this.host.registry;for(let r of this.host.stageBags.keys())t.remove(v.stage(r),{keep:e});this.host.stageBags.clear();for(let r of["patter",...this.host.hostScopes])t.has(r)&&t.remove(r,{keep:e});this.creationOptions.world&&t.has("world")&&t.remove("world")}getProperty(e){let{scope:t,name:r}=this.splitShared(e);return this.host.registry.get(t,r)}setProperty(e,t){let{scope:r,name:s}=this.splitShared(e);this.host.registry.set(r,s,t,{host:!0})}log(){return this.engineLog}clearLog(){this.engineLog.length=0}onTrace(e){return this.engineTraceHandlers.add(e),()=>this.engineTraceHandlers.delete(e)}emitEngine(e,t,r){for(let s of this.engineTraceHandlers)s(e,t);this.host.logEnabled&&this.engineLog.push({...t,flow:e,seq:this.engineLog.length,...r?{scene:r}:{}})}listProperties(){return this.host.patterSharedDecls.map(e=>({name:e.name,path:`@patter.${e.name}`,type:e.type,values:e.values,stages:e.stages,value:this.getProperty(`@${e.name}`),default:O(e),writable:e.writable??!0}))}splitShared(e){let t=Ee(this.host,e);if(t.scope==="scene")throw new Error(`\'${e}\': @scene properties are scene-scoped - read/write them on a Flow, not the Engine`);return t}save(){return{patter:this.host.patterBag.save()}}load(e){e.patter&&this.host.patterBag.load(e.patter)}saveGame(){let e={};for(let[t,r]of this.flowsById)e[t]=r.snapshot();return{version:z,...this.host.ownsRegistry?{registry:this.host.registry.save()}:{},sharedVisits:Object.fromEntries(this.host.sharedVisits),sharedSelectors:we(this.host.sharedSelectors),flows:e}}loadGame(e){let t=e.version;if(t!==2&&t!==z)throw new Error(`unsupported save version: ${String(t)}`);this.assertExternalScopes();let r=this.host.registry;for(let[i,o]of this.flowsById)o.releaseBags(i in e.flows),o.close();this.flowsById.clear();for(let i of this.host.stageBags.keys())r.remove(v.stage(i),{keep:!0});this.host.stageBags.clear();let s=e.version===2?Ke(e):e.registry;s&&(this.host.ownsRegistry?r.load(s):r.load(s,{keepParked:!0})),this.host.sharedVisits.clear();for(let[i,o]of Object.entries(e.sharedVisits??{}))this.host.sharedVisits.set(i,o);this.host.sharedSelectors.clear();for(let[i,o]of be(e.sharedSelectors))this.host.sharedSelectors.set(i,o);for(let[i,o]of Object.entries(e.flows)){let a=new D(i,this.host,this.defaultSeed);a.restore(o),this.flowsById.set(i,a)}}},D=class{id;host;local;registered=new Set;rngState;started=!1;flowEnded=!1;closed=!1;currentSceneId=null;stack=[];activeSnippet=null;beatIndex=0;pendingChoice=null;pendingPromptBeat=null;pendingPromptOwnerId=null;selectors=new Map;visitCounts=new Map;sceneBags=new Map;patterResolver={get:e=>this.host.patterSharedNames.has(e)?this.host.patterBag.get(e):this.local.get(e),set:(e,t)=>{this.host.patterSharedNames.has(e)?this.host.registry.set("patter",e,t):this.local.set(e,t)}};sceneResolver={get:e=>{let t=this.currentSceneId;if(t!==null)return this.sceneBagFor(t,e)?.get(e)},set:(e,t)=>{let r=this.currentSceneId;if(r===null)return;let s=this.sceneBagFor(r,e);s&&s.set(e,t)}};evalCtx;ctxRevision=-1;registryQualities;flowLog=[];flowSeq=0;constructor(e,t,r){this.id=e,this.host=t,this.rngState=R(r),this.local=this.newLocal(),this.evalCtx={scopes:{},host:{nextRandom:this.rng,visits:s=>this.visitCounts.get(s)??0,patterVisits:s=>this.host.sharedVisits.get(s)??0},qualities:(s,i)=>this.stagesFor(s,i)}}context(){let e=this.host.registry;if(e.revision!==this.ctxRevision){let t=e.toEvalContext(),r=this.evalCtx.scopes;for(let s of Object.keys(r))delete r[s];Object.assign(r,t.scopes),r.patter=this.patterResolver,r.scene=this.sceneResolver,this.registryQualities=t.qualities,this.ctxRevision=e.revision}return this.evalCtx}stagesFor(e,t){let r=t.toLowerCase(),s=i=>i?.find(o=>o.name.toLowerCase()===r&&o.type==="quality")?.stages;if(e==="patter")return s(this.host.patterSharedDecls)??s(this.host.patterLocalDecls);if(e==="scene"){let i=this.currentSceneId!=null?this.host.bundle.scenes[this.currentSceneId]:void 0;return s(i?.sceneProps)}return this.registryQualities?.(e,t)??s(this.host.bundle.scopeRegistry?.scopes.find(i=>i.token===e)?.declarations)}start(e,t){if(this.releaseBags(!1),this.host.registry.discardParked(v.flow(this.id)),this.mountLocal(),this.selectors.clear(),this.visitCounts.clear(),this.stack=[],this.currentSceneId=null,this.flowEnded=!1,this.activeSnippet=null,this.beatIndex=0,this.pendingChoice=null,this.started=!0,t){let r=this.host.blockIndex.get(t);if(!r)throw new Error(`unknown block: ${t}`);this.enterSceneSetup(r.sceneId),this.stack=[{sceneId:r.sceneId,containerId:t,index:0}],this.enter(t)}else{let r=e??Object.keys(this.host.bundle.scenes)[0],s=r?this.host.bundle.scenes[r]:void 0;if(!s)throw new Error(r?`unknown scene: ${r}`:"no scenes in bundle");this.enterSceneSetup(r);let i=s.blocks[0];i&&(this.stack=[{sceneId:r,containerId:i.id,index:0}],this.enter(i.id))}this.settle()}reset(e,t){this.start(e,t)}goto(e,t){if(this.closed)return!1;if(e==="END")return this.started=!0,this.pendingChoice=null,this.pendingPromptBeat=null,this.pendingPromptOwnerId=null,this.activeSnippet=null,this.beatIndex=0,this.flowEnded=!0,this.stack=[],!0;let r=this.host.sceneGameIdToId.get(e)??(this.host.bundle.scenes[e]?e:void 0);if(r===void 0)return!1;let s;return t!==void 0&&(s=this.host.blockGameIdToId.get(r)?.get(t)??(this.host.blockIndex.get(t)?.sceneId===r?t:void 0),s===void 0)?!1:this.started?(this.pendingChoice=null,this.pendingPromptBeat=null,this.pendingPromptOwnerId=null,this.activeSnippet=null,this.beatIndex=0,this.flowEnded=!1,this.enterTarget(s??r,"jump"),this.settle(),!0):(this.start(r,s),!0)}close(){this.releaseBags(!1),this.closed=!0,this.flowEnded=!0,this.stack=[],this.activeSnippet=null,this.beatIndex=0,this.pendingChoice=null,this.pendingPromptBeat=null,this.pendingPromptOwnerId=null}get isClosed(){return this.closed}get currentScene(){return this.currentSceneId}advance(){if(this.closed)return{type:"end"};if(!this.started)throw new Error("flow has not been started");if(this.pendingPromptBeat){let e=this.pendingPromptBeat;return this.pendingPromptBeat=null,this.pendingPromptOwnerId=null,this.beatResult(e)}return this.settle(),this.flowEnded?{type:"end"}:this.pendingChoice?{type:"choice",groupId:this.pendingChoice.groupId,options:this.pendingChoice.options}:this.activeSnippet?this.beatResult(this.activeSnippet.beats[this.beatIndex++]):(this.flowEnded=!0,{type:"end"})}advanceToStop(){let e=[];for(;;){let t=this.advance();if(t.type==="choice"||t.type==="end")return{played:e,stop:t};e.push(t)}}settle(){let e=0;for(;;){if(++e>1e4)throw new Error("flow did not settle after 10000 transitions - likely a jump cycle with no deliverable content");if(this.flowEnded||this.pendingChoice)return;if(this.activeSnippet){if(this.beatIndex<(this.activeSnippet.beats?.length??0))return;this.runEffects(this.activeSnippet.onExit);let i=this.activeSnippet.jump;this.activeSnippet=null,this.beatIndex=0,this.resolveJump(i);continue}let t=this.stack[this.stack.length-1];if(!t){this.flowEnded=!0;return}t.sceneId!==this.currentSceneId&&(this.currentSceneId=t.sceneId);let r=this.childrenOf(t.containerId);if(!r){this.stack.pop();continue}let s=t.index;for(;t.index<r.length&&!this.eligible(r[t.index]);)t.index++;if(this.host.logEnabled&&t.index!==s&&this.emit({type:"select",group:t.containerId,selector:"run",children:r.slice(s,t.index+1).map((i,o)=>({id:i.id,eligible:s+o===t.index})),picked:r[t.index]?.id??null}),t.index>=r.length){this.stack.pop();continue}this.enterChild(r[t.index++])}}listBags(){let e=[{bag:this.local,pathPrefix:`${this.id}/@patter.`}];for(let[t,r]of this.sceneBags)e.push({bag:r,pathPrefix:`${this.id}/@scene:${t}.`});return e}log(){return this.flowLog}clearLog(){this.flowLog.length=0}emit(e){let t=this.currentSceneId??void 0;this.host.emitEngine(this.id,e,t),this.host.logEnabled&&this.flowLog.push({...e,seq:this.flowSeq++,...t?{scene:t}:{}})}getChoices(){return this.pendingChoice?.options??[]}choose(e){let t=this.pendingChoice;if(!t)throw new Error("no choice is pending");let r=t.options.find(i=>i.id===e);if(!r)throw new Error(`unknown choice option: ${e}`);if(!r.eligible)throw new Error(`choice option is not eligible: ${e}`);let s=t.byId.get(e);this.emit({type:"chose",group:t.groupId,option:e}),this.pendingChoice=null,this.pendingPromptBeat=this.host.replayPromptOnChoose?this.promptBeatOf(s)??null:null,this.pendingPromptOwnerId=this.pendingPromptBeat?s.id:null,this.enterChild(s)}isEnded(){return this.flowEnded}getProperty(e){let{scope:t,name:r}=this.splitRef(e);return t==="patter"?this.patterResolver.get(r):t==="scene"?this.sceneResolver.get(r):this.host.registry.get(t,r)}setProperty(e,t){this.writeProperty(e,t,!0)}writeProperty(e,t,r){let{scope:s,name:i}=this.splitRef(e);if(s==="patter")this.patterResolver.set(i,t);else if(s==="scene"){if(this.currentSceneId===null)throw new Error(`\'${e}\': the flow has not entered a scene yet`);this.sceneResolver.set(i,t)}else this.host.registry.set(s,i,t,r?{host:!0}:void 0)}snapshot(){return{rngState:this.rngState,visits:Object.fromEntries(this.visitCounts),cursor:{flowEnded:this.flowEnded,currentSceneId:this.currentSceneId,stack:this.stack.map(e=>{let t=this.childrenOf(e.containerId)?.[e.index];return t?{...e,nextId:t.id}:{...e}}),activeSnippetId:this.activeSnippet?.id??null,beatIndex:this.beatIndex,pendingChoice:this.pendingChoice?{groupId:this.pendingChoice.groupId,options:this.pendingChoice.options.map(e=>({...e}))}:null,pendingPromptOwnerId:this.pendingPromptOwnerId,selectors:we(this.selectors)}}}restore(e){this.rngState=R(e.rngState),this.visitCounts=new Map(Object.entries(e.visits??{}));let t=e.cursor;this.started=!0,this.flowEnded=t.flowEnded,this.beatIndex=t.beatIndex,this.currentSceneId=t.currentSceneId,this.stack=t.stack.map(r=>{let{nextId:s,...i}=r;if(s!==void 0){let o=this.childrenOf(i.containerId)?.findIndex(a=>a.id===s)??-1;if(o>=0)return{...i,index:o}}return{...i}}),this.releaseBags(!1),this.mountLocal();for(let r of new Set([t.currentSceneId,...this.stack.map(s=>s.sceneId)]))r!==null&&this.host.bundle.scenes[r]&&this.ensureSceneBags(r);if(this.activeSnippet=null,t.activeSnippetId!==null){let r=this.host.nodeIndex.get(t.activeSnippetId);r&&r.type==="snippet"&&(this.activeSnippet=r)}if(this.selectors=be(t.selectors),this.pendingChoice=null,t.pendingChoice!==null){let r=new Map,s=[];for(let i of t.pendingChoice.options){let o=this.host.nodeIndex.get(i.id);o&&(r.set(i.id,o),s.push({...i}))}s.length>0&&(this.pendingChoice={groupId:t.pendingChoice.groupId,options:s,byId:r})}if(this.pendingPromptBeat=null,this.pendingPromptOwnerId=t.pendingPromptOwnerId??null,this.pendingPromptOwnerId){let r=this.host.nodeIndex.get(this.pendingPromptOwnerId);this.pendingPromptBeat=r?this.promptBeatOf(r)??null:null,this.pendingPromptBeat||(this.pendingPromptOwnerId=null)}}enterSceneSetup(e){let t=this.host.bundle.scenes[e];if(!t)throw new Error(`unknown scene: ${e}`);this.currentSceneId=e,this.enter(e),this.seedScene(t),this.runEffects(t.onEntry)}enterChild(e){if(this.enter(e.id),e.type==="snippet"){this.beginSnippet(e);return}let t=e.selector??"run";if(t==="run"){this.stack.push({sceneId:this.currentSceneId,containerId:e.id,index:0});return}if(t==="choice"){this.setupChoice(e);return}let r=this.selectChild(e);r&&this.enterChild(r)}childrenOf(e){let t=this.host.blockById.get(e);if(t)return t.children;let r=this.host.nodeIndex.get(e);if(r&&r.type==="group")return r.children}beginSnippet(e){this.runEffects(e.onEnter),this.activeSnippet=e,this.beatIndex=0}setupChoice(e){let t=[],r=new Map,s=[];for(let o of e.children){if(o.fallback===!0){s.push(o);continue}if(o.sticky!==!0&&(this.visitCounts.get(o.id)??0)>=1)continue;let a=this.eligible(o),c=o.secretUntilEligible===!0;!a&&c||(t.push({id:o.id,prompt:this.promptFor(o),eligible:a,gameData:o.gameData}),r.set(o.id,o))}if(t.length>0){this.emit({type:"choice",group:e.id,options:t.map(o=>({id:o.id,eligible:o.eligible}))}),this.pendingChoice={groupId:e.id,options:t,byId:r};return}let i=s.find(o=>this.eligible(o));if(i){this.enterChild(i);return}this.emit({type:"dry",group:e.id}),this.host.onDryChoice?.(e.id)}resolveJump(e){e&&this.enterTarget(e.to,e.mode==="call"?"call":"jump")}enterTarget(e,t){if(this.emit({type:"jump",to:e,mode:t}),e==="END"){this.flowEnded=!0,this.stack=[];return}let r,s,i=this.host.bundle.scenes[e];if(i){this.enterSceneSetup(e);let a=i.blocks[0];if(!a){t==="jump"&&(this.stack=[]);return}r=e,s=a.id}else{let a=this.host.blockIndex.get(e);if(!a)throw new Error(`jump target not found: ${e}`);a.sceneId!==this.currentSceneId&&this.enterSceneSetup(a.sceneId),r=a.sceneId,s=e}this.enter(s);let o={sceneId:r,containerId:s,index:0};t==="call"?this.stack.push(o):this.stack=[o]}selectChild(e){let t=e.children.map(c=>({id:c.id,eligible:this.eligible(c)})),r=e.children.filter(c=>this.eligible(c)),s=e.options?.order??"sequential",i=e.options?.exhaust??"once",o=c=>(this.emit({type:"select",group:e.id,selector:e.selector??"default",...e.selector==="sequence"?{order:s,exhaust:i}:{},children:t,picked:c?.id??null}),c);if(r.length===0)return o(null);let a=this.selectorState(e);switch(e.selector){case"branch":return o(r[0]);case"sequence":return o(s==="shuffle"?this.pickShuffle(r,i,a):s==="specificity"?this.pickSpecificity(r,i,a):this.pickSequential(r,i,a));default:return null}}pickSequential(e,t,r){let s=e.length,i=r.seq??0;return r.seq=i+1,t==="repeat"?e[i%s]:i<s?e[i]:t==="stick"?e[s-1]:null}pickShuffle(e,t,r){let s=e.length,i=t==="stick",o=()=>(i?e.slice(0,s-1):e).map(u=>u.id);if(r.bag===void 0&&(r.bag=o()),r.bag.length===0){if(t==="once")return null;if(i){let u=e[s-1];return r.last=u.id,u}r.bag=o()}let a=r.bag,c=r.last!==void 0&&a.length>1?a.indexOf(r.last):-1,l=Math.floor(this.rng()*(c>=0?a.length-1:a.length));c>=0&&l>=c&&l++;let d=a[l];return a.splice(l,1),r.last=d,e.find(u=>u.id===d)}pickSpecificity(e,t,r){let s=e;if(t!=="repeat"){r.bag===void 0&&(r.bag=e.map(d=>d.id));let l=new Set(r.bag);if(s=e.filter(d=>l.has(d.id)),s.length===0)return t==="stick"&&r.last!==void 0?e.find(d=>d.id===r.last)??null:null}let i=-1,a=s.map(l=>{let d=this.specScore(l);return d>i&&(i=d),{c:l,s:d}}).filter(l=>l.s===i).map(l=>l.c),c;if(a.length===1)c=a[0];else{let l=r.last!==void 0?a.findIndex(u=>u.id===r.last):-1,d=Math.floor(this.rng()*(l>=0?a.length-1:a.length));l>=0&&d>=l&&d++,c=a[d]}return t!=="repeat"&&(r.bag=r.bag.filter(l=>l!==c.id)),r.last=c.id,c}specScore(e){return e.condition?this.matchedSpec(this.conditionAst(e.condition),!0):0}matchedSpec(e,t){return ie(e,s=>ve(F(s,this.context(),W)),{want:t})}selectorState(e){let t=e.shared?this.host.sharedSelectors:this.selectors,r=t.get(e.id);return r||(r={},t.set(e.id,r)),r}runEffects(e){for(let t of e??[]){let r=this.evalExpr(t.value),s=this.host.logEnabled?this.getProperty(t.target):void 0;this.writeProperty(t.target,r,!1),this.emit({type:"write",target:t.target,value:r,...s!==void 0?{prev:s}:{}})}}eligible(e){return e.condition?ve(this.evalExpr(e.condition)):!0}evalExpr(e){return F(this.conditionAst(e),this.context(),W)}conditionAst(e){let t=fe.get(e);return t||(t=E(e.ast),fe.set(e,t)),t}enter(e){this.visitCounts.set(e,(this.visitCounts.get(e)??0)+1),this.host.sharedVisits.set(e,(this.host.sharedVisits.get(e)??0)+1)}rng=()=>{if(this.host.customRng)return this.host.customRng();let e=H(this.rngState),t=e.next();return this.rngState=e.state(),t};beatResult(e){let t=this.host.tagIndex.get(e.id),r=t&&t.length?{tags:t}:{};switch(e.kind){case"gameEvent":return{type:"gameEvent",id:e.id,gameData:e.gameData,...r};case"text":return{type:"text",id:e.id,text:this.interpolate(this.resolveString(e.id)),gameData:e.gameData,...r};case"line":{let s=this.resolveString(e.id),i=!this.host.captionsOn,a=i&&e.character===this.host.captionCharacter?"":this.captionLine(this.host.bundle.voiced?s:this.interpolate(s)),c=i&&a.length===0;return{type:"line",id:e.id,text:a,character:c?void 0:e.character,characterName:c?void 0:this.resolveCharacterName(e.character),direction:c?void 0:e.direction,gameData:e.gameData,...r}}}}interpolate(e){return ue(e,t=>this.getProperty(t))}stripCaptions(e){return ge(e,this.host.captionOpen,this.host.captionClose)}captionLine(e){return this.host.captionsOn?e:this.stripCaptions(e)}promptFor(e){let t=this.promptBeatOf(e);if(!t)return;let r=this.interpolate(this.resolveString(t.id));return t.kind==="line"?{kind:"line",text:this.captionLine(r),character:t.character,characterName:this.resolveCharacterName(t.character),direction:t.direction}:{kind:"text",text:r}}promptBeatOf(e){return e.type==="group"&&e.prompt?e.prompt:((e.type==="snippet"?e:this.firstTextSnippetIn(e.children))?.beats??[]).find(r=>r.kind==="line"||r.kind==="text")}firstTextSnippetIn(e){let t;return C(e,r=>{!t&&r.type==="snippet"&&(r.beats??[]).some(s=>s.kind==="line"||s.kind==="text")&&(t=r)}),t}resolveString(e){if(this.host.emitIds)return e;let t=this.host.strings[e];if(t!==void 0)return t;let r=this.host.defaultStrings[e];return r!==void 0?`<Untranslated: ${e}> ${r}`:e}resolveCharacterName(e){if(e===void 0||this.host.emitIds)return;let t=K(e);return this.host.strings[t]??this.host.defaultStrings[t]??this.host.castDisplay.get(e)}splitRef(e){return Ee(this.host,e)}newLocal(){return new b(this.host.patterLocalDecls,{pathPrefix:"@patter."})}mountLocal(){this.local=this.newLocal();let e=v.flowGlobals(this.id);this.host.registry.mountOwned(e,this.local,{owner:I}),this.registered.add(e)}releaseBags(e){for(let t of this.registered)this.host.registry.remove(t,{keep:e});this.registered.clear(),this.sceneBags.clear()}sceneBagFor(e,t){if(this.host.bundle.scenes[e])return this.ensureSceneBags(e),this.host.sceneSharedNames.get(e)?.has(t.toLowerCase())?this.host.stageBags.get(e):this.sceneBags.get(e)}ensureSceneBags(e){let t=this.host.sceneSharedNames.get(e)??new Set,r=this.host.bundle.scenes[e]?.sceneProps??[];if(!this.sceneBags.has(e)){let s=new b(r.filter(o=>!t.has(o.name.toLowerCase())),{pathPrefix:"@scene."}),i=v.flowScene(this.id,e);this.host.registry.mountOwned(i,s,{owner:I}),this.registered.add(i),this.sceneBags.set(e,s)}if(!this.host.stageBags.has(e)){let s=new b(r.filter(i=>t.has(i.name.toLowerCase())),{pathPrefix:"@scene."});this.host.registry.mountOwned(v.stage(e),s,{owner:I}),this.host.stageBags.set(e,s)}}seedScene(e){let t=this.host.sceneSharedNames.get(e.id)??new Set;this.ensureSceneBags(e.id);for(let r of e.sceneProps??[]){if(!r.temporary)continue;let s=r.name.toLowerCase(),i=t.has(s)?this.host.stageBags.get(e.id):this.sceneBags.get(e.id);i&&i.set(s,O(r))}}};function Se(n,e){C(n,t=>{if(t.type==="group"){t.prompt?.kind==="line"&&t.prompt.character&&e.add(t.prompt.character);return}for(let r of t.beats??[])r.kind==="line"&&r.character&&e.add(r.character)})}function we(n){let e={};for(let[t,r]of n){let s={};r.seq!==void 0&&(s.seq=r.seq),r.bag&&(s.bag=[...r.bag]),r.last!==void 0&&(s.last=r.last),e[t]=s}return e}function be(n){let e=new Map;for(let[t,r]of Object.entries(n??{})){let s={};r.seq!==void 0&&(s.seq=r.seq),r.bag&&(s.bag=[...r.bag]),r.last!==void 0&&(s.last=r.last),e.set(t,s)}return e}function ye(n){return{name:n.name,type:n.type,values:n.values,stages:n.stages,default:n.default}}function xe(n){return{name:n.name,type:n.type,values:n.values,stages:n.stages,default:n.default,writable:n.writable}}function We(n,e){let t=xe(n),r=n.writable??e;return r===void 0?t:{...t,writable:r}}function Ee(n,e){n.refSplitRevision!==n.registry.revision&&(n.refSplitCache.clear(),n.refSplitRevision=n.registry.revision);let t=n.refSplitCache.get(e);return t||(t=de(e,r=>r==="scene"||n.registry.has(r)||(n.bundle.externalScopes?.includes(r)??!1)),n.refSplitCache.set(e,t)),t}function Ke(n){let e={};n.shared?.patter&&(e.patter=n.shared.patter);for(let[t,r]of Object.entries(n.stageBags??{}))e[v.stage(t)]=r;for(let[t,r]of Object.entries(n.flows??{})){r.scopes?.patter&&(e[v.flowGlobals(t)]=r.scopes.patter);for(let[s,i]of Object.entries(r.sceneBags??{}))e[v.flowScene(t,s)]=i}return e}function ve(n){return typeof n=="boolean"?n:typeof n=="number"?n!==0:typeof n=="string"?n!=="":n.length>0}var Je=(n,e)=>n.shared??e;function Y(n,e){return{name:n.name,type:n.type,hasDefault:n.default!==void 0,...n.default!==void 0?{default:n.default}:{},shared:Je(n,e)}}function ze(n){return{name:n.name,type:n.type,hasDefault:n.default!==void 0,...n.values?{values:[...n.values]}:{},...n.purpose?{purpose:n.purpose}:{}}}function Ye(n,e){e.blocks++;let t=[...n.children];for(;t.length;){let r=t.pop();if(r.type==="group"){e.groups++,r.prompt&&e.prompts++,t.push(...r.children);continue}e.snippets++;for(let s of r.beats??[])e.beats++,s.kind==="gameEvent"&&e.gameEvents++}}function ke(n){let e={scenes:0,blocks:0,groups:0,snippets:0,beats:0,prompts:0,gameEvents:0,cast:n.cast?.length??0},t=[],r=[];for(let o of Object.values(n.scenes)){e.scenes++;let a=m(o);t.push({gameId:a,name:o.name,blocks:o.blocks.map(c=>({gameId:m(c),name:c.name}))});for(let c of o.blocks)Ye(c,e);o.sceneProps?.length&&r.push({gameId:a,properties:o.sceneProps.map(c=>Y(c,!1))})}let s=(n.scopeRegistry?.scopes??[]).map(o=>({token:o.token,writable:o.writable??!0,opaque:o.declarations===void 0,properties:(o.declarations??[]).map(a=>Y(a,!0))})),i=Object.entries(n.gameDataFields??{}).filter(([,o])=>(o?.length??0)>0).map(([o,a])=>({kind:o,fields:(a??[]).map(ze)}));return{identity:{schema:n.schema,project:n.content.project,...n.content.version!==void 0?{version:n.content.version}:{},...n.content.hash!==void 0?{hash:n.content.hash}:{},...n.content.structureHash!==void 0?{structureHash:n.content.structureHash}:{},voiced:n.voiced,defaultLocale:n.locales.default,locales:[...n.locales.included],localisation:n.localisation?.mode??"embedded",sourceDebug:n.localisation?.sourceDebug??!1},addresses:t,hostScopes:s,properties:{patter:(n.properties??[]).map(o=>Y(o,!0)),scene:r},gameData:i,counts:e}}function Ce(n,e){return n.gameDataFields?.[e]??[]}function Q(n,e,t){return e&&Object.prototype.hasOwnProperty.call(e,t)?e[t]:n.find(r=>r.name===t)?.default}function Ie(n,e){let t={};for(let r of n){let s=Q(n,e,r.name);s!==void 0&&(t[r.name]=s)}for(let[r,s]of Object.entries(e??{}))r in t||(t[r]=s);return t}return Te(Qe);})();\n';
195021
195060
 
195022
195061
  // ../ops/src/export-html.ts
195023
195062
  var esc = (s) => s.replace(/[&<>]/g, (c2) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;" })[c2]);
@@ -195284,6 +195323,13 @@ var PropertyBag = class _PropertyBag {
195284
195323
  get(name) {
195285
195324
  return this.values[this.norm(name)];
195286
195325
  }
195326
+ /** A name as this bag keys it: its normalisation policy applied. The registry
195327
+ * uses it to key quality ladders and the validation schema the bag's own way,
195328
+ * so a case-significant (identity) bag is not quietly folded to lower case
195329
+ * one layer up. */
195330
+ normalise(name) {
195331
+ return this.norm(name);
195332
+ }
195287
195333
  /** Write a property. Engine writes (the default) notify subscribers;
195288
195334
  * pass `silent: true` for a host write, which reaches only the audit
195289
195335
  * hook. Throws on a read-only property unless the caller says it is the
@@ -195367,25 +195413,82 @@ function rowFor(d, value, writable, name, pathPrefix = "") {
195367
195413
  writable: writable ?? d.writable ?? true
195368
195414
  };
195369
195415
  }
195416
+ var lowerCase = (name) => name.toLowerCase();
195370
195417
  var SAVE_FRAGMENT_VERSION = 1;
195371
195418
  var ScopeRegistry = class {
195372
195419
  scopes = /* @__PURE__ */ new Map();
195420
+ /** Values loaded for keys nobody has registered yet, waiting to be claimed. */
195421
+ parked = /* @__PURE__ */ new Map();
195422
+ rev = 0;
195423
+ /**
195424
+ * A counter that moves whenever a scope is registered or removed, and at no
195425
+ * other time: it starts at 0 and each registration or removal adds 1. Values
195426
+ * changing does not move it. A caller that caches a context built by
195427
+ * `toEvalContext()` rebuilds it when this moves, because the context's set of
195428
+ * scopes is fixed when it is built while the values it reads stay live.
195429
+ */
195430
+ get revision() {
195431
+ return this.rev;
195432
+ }
195373
195433
  /**
195374
195434
  * Register a scope this registry **owns and stores**. Its bag is seeded from
195375
195435
  * each declaration's `default` (or a type default). Owned scopes are
195376
195436
  * type-checked (declarations) and serialized by `save`/`load`.
195437
+ *
195438
+ * The third argument may be the path prefix alone (the pre-0.7 form) or an
195439
+ * options object.
195440
+ */
195441
+ defineOwned(token2, declarations, opts) {
195442
+ const o = typeof opts === "string" ? { pathPrefix: opts } : opts ?? {};
195443
+ const bag = new PropertyBag(declarations, {
195444
+ pathPrefix: o.pathPrefix ?? `${token2}.`,
195445
+ ...o.normalise ? { normalise: o.normalise } : {}
195446
+ });
195447
+ return this.mountOwned(token2, bag, o.owner !== void 0 ? { owner: o.owner } : void 0);
195448
+ }
195449
+ /**
195450
+ * Attach an EXISTING bag as an owned scope: an engine (or a host) holds the
195451
+ * bag and this registry reads, writes, lists and saves it like its own.
195452
+ *
195453
+ * If values were loaded for this key before anyone registered it, the bag
195454
+ * claims them now: laid over its seeded defaults by the bag's own `load` rule.
195455
+ */
195456
+ mountOwned(token2, bag, opts) {
195457
+ this.assertFree(token2, opts?.owner);
195458
+ this.scopes.set(token2, { kind: "owned", bag, ...opts?.owner !== void 0 ? { owner: opts.owner } : {} });
195459
+ this.rev++;
195460
+ const waiting = this.parked.get(token2);
195461
+ if (waiting) {
195462
+ bag.load(waiting);
195463
+ this.parked.delete(token2);
195464
+ }
195465
+ return this;
195466
+ }
195467
+ /**
195468
+ * Unregister a scope. With `{ keep: true }` an owned scope's values are parked
195469
+ * and handed back when the same key is next registered, which is how a live
195470
+ * reload hands an engine's state to its replacement. Throws on an unknown key.
195377
195471
  */
195378
- defineOwned(token2, declarations, pathPrefix) {
195379
- return this.mountOwned(token2, new PropertyBag(declarations, { pathPrefix: pathPrefix ?? `${token2}.` }));
195472
+ remove(token2, opts) {
195473
+ const e = this.scopes.get(token2);
195474
+ if (!e) throw new Error(`unknown scope '@${token2}'`);
195475
+ if (opts?.keep && e.kind === "owned") this.parked.set(token2, e.bag.save());
195476
+ this.scopes.delete(token2);
195477
+ this.rev++;
195478
+ return this;
195380
195479
  }
195381
195480
  /**
195382
- * Attach an EXISTING bag as an owned scope - the shared-container move: a
195383
- * host (or the other product) holds the bag; this registry reads, writes
195384
- * and lists it like its own, but the holder saves it.
195481
+ * Drop parked values nobody claimed. Parked values are kept in the next save by
195482
+ * default, so nothing loaded is lost to a flow or deck that simply has not
195483
+ * reopened yet; a game that knows they are dead drops them here.
195484
+ *
195485
+ * With a `prefix`, only keys starting with it are dropped: an engine resetting
195486
+ * itself drops its own instance keys (`my-engine/`) and leaves every other
195487
+ * engine's alone.
195385
195488
  */
195386
- mountOwned(token2, bag) {
195387
- this.assertFree(token2);
195388
- this.scopes.set(token2, { kind: "owned", bag });
195489
+ discardParked(prefix) {
195490
+ if (prefix === void 0) this.parked.clear();
195491
+ else for (const key2 of [...this.parked.keys()]) if (key2.startsWith(prefix)) this.parked.delete(key2);
195389
195492
  return this;
195390
195493
  }
195391
195494
  /** An owned scope's bag (subscribe, audit, rows live there). */
@@ -195411,11 +195514,21 @@ var ScopeRegistry = class {
195411
195514
  * `declarations` (optional, e.g. imported from a `scopeRegistrySpec`) are used
195412
195515
  * only for validation; omit them for an opaque scope.
195413
195516
  */
195414
- defineForeign(token2, resolver, declarations = [], scopeWritable = true) {
195415
- this.assertFree(token2);
195517
+ defineForeign(token2, resolver, declarations = [], opts = true) {
195518
+ const o = typeof opts === "boolean" ? { writable: opts } : opts;
195519
+ this.assertFree(token2, o.owner);
195520
+ const norm = o.normalise ?? lowerCase;
195416
195521
  const decls = /* @__PURE__ */ new Map();
195417
- for (const d of declarations) decls.set(d.name.toLowerCase(), d);
195418
- this.scopes.set(token2, { kind: "foreign", resolver, decls, scopeWritable });
195522
+ for (const d of declarations) decls.set(norm(d.name), d);
195523
+ this.scopes.set(token2, {
195524
+ kind: "foreign",
195525
+ resolver,
195526
+ decls,
195527
+ scopeWritable: o.writable ?? true,
195528
+ norm,
195529
+ ...o.owner !== void 0 ? { owner: o.owner } : {}
195530
+ });
195531
+ this.rev++;
195419
195532
  return this;
195420
195533
  }
195421
195534
  has(token2) {
@@ -195425,7 +195538,7 @@ var ScopeRegistry = class {
195425
195538
  get(scope, name) {
195426
195539
  const e = this.scopes.get(scope);
195427
195540
  if (!e) return void 0;
195428
- return e.kind === "owned" ? e.bag.get(name) : e.resolver.get(name.toLowerCase());
195541
+ return e.kind === "owned" ? e.bag.get(name) : e.resolver.get(e.norm(name));
195429
195542
  }
195430
195543
  /** Write a property (an ENGINE write: the bag's subscribers fire; use
195431
195544
  * the bag directly for silent host writes). Throws on an unknown scope.
@@ -195447,7 +195560,7 @@ var ScopeRegistry = class {
195447
195560
  }
195448
195561
  return;
195449
195562
  }
195450
- const n = name.toLowerCase();
195563
+ const n = e.norm(name);
195451
195564
  if (!e.resolver.set) throw new Error(`'@${scope}.${name}' is read-only`);
195452
195565
  if (!opts?.host && !this.foreignWritable(e, n)) throw new Error(`'@${scope}.${name}' is read-only`);
195453
195566
  e.resolver.set(n, value);
@@ -195462,19 +195575,15 @@ var ScopeRegistry = class {
195462
195575
  listProperties() {
195463
195576
  const out = [];
195464
195577
  for (const [token2, e] of this.scopes) {
195578
+ const owner = e.owner !== void 0 ? { owner: e.owner } : {};
195465
195579
  if (e.kind === "owned") {
195466
- for (const row of e.bag.rows()) out.push({ scope: token2, ...row });
195580
+ for (const row of e.bag.rows()) out.push({ scope: token2, ...owner, ...row });
195467
195581
  } else {
195468
- for (const d of e.decls.values()) {
195582
+ for (const [n, d] of e.decls) {
195469
195583
  out.push({
195470
195584
  scope: token2,
195471
- ...rowFor(
195472
- d,
195473
- e.resolver.get(d.name.toLowerCase()),
195474
- this.foreignWritable(e, d.name.toLowerCase()),
195475
- void 0,
195476
- `${token2}.`
195477
- )
195585
+ ...owner,
195586
+ ...rowFor(d, e.resolver.get(n), this.foreignWritable(e, n), n, `${token2}.`)
195478
195587
  });
195479
195588
  }
195480
195589
  }
@@ -195486,31 +195595,48 @@ var ScopeRegistry = class {
195486
195595
  * bags, foreign scopes as their resolvers. `host` carries dialect-function
195487
195596
  * callbacks (PRNG, tag lookups) and is passed through untouched.
195488
195597
  */
195489
- toEvalContext(host2) {
195598
+ toEvalContext(host2, opts) {
195599
+ const view = this.view(opts?.aliases);
195490
195600
  const scopes = {};
195491
- for (const [token2, e] of this.scopes) {
195492
- scopes[token2] = e.kind === "owned" ? e.bag.values : e.resolver;
195493
- }
195494
- const qualities = this.qualityLadders();
195601
+ for (const [token2, e] of view) scopes[token2] = e.kind === "owned" ? e.bag.values : e.resolver;
195602
+ const qualities = this.qualityLadders(view);
195495
195603
  return qualities.size === 0 ? { scopes, host: host2 } : {
195496
195604
  scopes,
195497
195605
  host: host2,
195498
- qualities: (scope, name) => qualities.get(scope)?.get(name.toLowerCase())
195606
+ qualities: (scope, name) => {
195607
+ const e = view.get(scope);
195608
+ return e ? qualities.get(scope)?.get(normOf(e)(name)) : void 0;
195609
+ }
195499
195610
  };
195500
195611
  }
195501
- /** Every quality declaration's ladder, keyed scope token then name. */
195502
- qualityLadders() {
195612
+ /**
195613
+ * The scopes an expression sees: every registered key under its own token,
195614
+ * then each alias token pointing at its key's entry (an alias shadows a key of
195615
+ * the same name). Keys an engine uses for instance bags (`engine/flow-2/...`)
195616
+ * are not valid expression tokens, so they are present but unreachable.
195617
+ */
195618
+ view(aliases) {
195619
+ const out = new Map(this.scopes);
195620
+ for (const [token2, key2] of Object.entries(aliases ?? {})) {
195621
+ const e = this.scopes.get(key2);
195622
+ if (!e) throw new Error(`alias '@${token2}' names '${key2}', which is not registered`);
195623
+ out.set(token2, e);
195624
+ }
195625
+ return out;
195626
+ }
195627
+ /** Every quality declaration's ladder, keyed scope token then name (the
195628
+ * scope's own normalisation). */
195629
+ qualityLadders(view) {
195503
195630
  const out = /* @__PURE__ */ new Map();
195504
- for (const [token2, e] of this.scopes) {
195505
- const decls = e.kind === "owned" ? e.bag.declarations() : [...e.decls.values()];
195506
- for (const d of decls) {
195631
+ for (const [token2, e] of view) {
195632
+ for (const [n, d] of declsOf(e)) {
195507
195633
  if (d.type !== "quality" || d.stages === void 0) continue;
195508
195634
  let m = out.get(token2);
195509
195635
  if (!m) {
195510
195636
  m = /* @__PURE__ */ new Map();
195511
195637
  out.set(token2, m);
195512
195638
  }
195513
- m.set(d.name.toLowerCase(), d.stages);
195639
+ m.set(n, d.stages);
195514
195640
  }
195515
195641
  }
195516
195642
  return out;
@@ -195518,15 +195644,17 @@ var ScopeRegistry = class {
195518
195644
  /**
195519
195645
  * Build the `ExpressionSchema` expr's validator consumes. Scopes with no
195520
195646
  * declarations are **omitted** (opaque - references into them are not flagged);
195521
- * declared scopes contribute their property types for validation.
195647
+ * declared scopes contribute their property types for validation. Aliases
195648
+ * apply as they do to `toEvalContext`, so a condition written against `@scene`
195649
+ * validates against the instance bag the engine names.
195522
195650
  */
195523
- toSchema() {
195651
+ toSchema(opts) {
195524
195652
  const properties = /* @__PURE__ */ new Map();
195525
- for (const [token2, e] of this.scopes) {
195526
- const decls = e.kind === "owned" ? e.bag.declarations() : [...e.decls.values()];
195653
+ for (const [token2, e] of this.view(opts?.aliases)) {
195654
+ const decls = declsOf(e);
195527
195655
  if (decls.length === 0) continue;
195528
195656
  const m = /* @__PURE__ */ new Map();
195529
- for (const d of decls) m.set(d.name.toLowerCase(), {
195657
+ for (const [n, d] of decls) m.set(n, {
195530
195658
  type: d.type,
195531
195659
  enumValues: d.values,
195532
195660
  ...d.stages !== void 0 ? { stages: d.stages } : {}
@@ -195535,40 +195663,78 @@ var ScopeRegistry = class {
195535
195663
  }
195536
195664
  return { properties };
195537
195665
  }
195538
- /** Serialize **owned** scopes only (foreign scopes are host-owned,
195539
- * host-saved), as bare bags - the 0.1.x shape, kept stable so existing
195540
- * consumers' save formats are untouched. A product embedding the
195541
- * versioned cross-product shape uses `saveFragment`. */
195666
+ /** Serialize **owned** scopes (foreign scopes are the game's, and the game
195667
+ * saves them), as bare bags keyed by token, plus any values still parked, so
195668
+ * a save taken before every engine has re-registered loses nothing. The
195669
+ * registry knows nothing about game saves: a game embeds this in its own. */
195542
195670
  save() {
195543
195671
  const out = {};
195544
195672
  for (const [token2, e] of this.scopes) if (e.kind === "owned") out[token2] = e.bag.save();
195673
+ for (const [token2, vals] of this.parked) out[token2] = structuredClone(vals);
195545
195674
  return out;
195546
195675
  }
195547
- /** Restore owned-scope values from a `save` blob. Unknown/foreign scopes
195548
- * are ignored. */
195549
- load(blob) {
195676
+ /**
195677
+ * Restore from a `save` blob. An owned scope lays its section over its current
195678
+ * values (the bag's `load` rule). A section for a key nobody has registered
195679
+ * yet is PARKED and handed over when that key registers, so a game can load
195680
+ * its registry before its engines have reopened their flows or decks. A
195681
+ * section for a foreign scope is ignored: those values are the game's.
195682
+ *
195683
+ * A load replaces whatever was parked before it: it is a whole restore, and
195684
+ * residue from an earlier load must not leak into this one.
195685
+ *
195686
+ * Changed in 0.7.0: sections for unregistered keys used to be dropped.
195687
+ */
195688
+ load(blob, opts) {
195689
+ if (!opts?.keepParked) this.parked.clear();
195550
195690
  for (const [token2, vals] of Object.entries(blob)) {
195551
195691
  const e = this.scopes.get(token2);
195552
195692
  if (e?.kind === "owned") e.bag.load(vals);
195693
+ else if (!e) this.parked.set(token2, structuredClone(vals));
195553
195694
  }
195554
195695
  }
195555
- /** The versioned owned-state fragment (the one serialisation shape both
195556
- * product families' save envelopes embed when they adopt the kernel;
195557
- * design/engine-runtimes.md 3.1). `save()` wrapped with a version stamp. */
195696
+ /**
195697
+ * `save()` wrapped with a version stamp.
195698
+ *
195699
+ * @deprecated Versioning belongs to the save that embeds the values; no
195700
+ * engine ever called this. Embed `save()` in your own versioned save.
195701
+ * Removed at the next breaking release.
195702
+ */
195558
195703
  saveFragment() {
195559
195704
  return { version: SAVE_FRAGMENT_VERSION, scopes: this.save() };
195560
195705
  }
195561
- /** Restore from a versioned fragment; an unsupported version throws. */
195706
+ /**
195707
+ * Restore from a versioned fragment; an unsupported version throws.
195708
+ *
195709
+ * @deprecated See `saveFragment`. Removed at the next breaking release.
195710
+ */
195562
195711
  loadFragment(fragment) {
195563
195712
  if (fragment.version !== SAVE_FRAGMENT_VERSION) {
195564
195713
  throw new Error(`unsupported owned-state fragment version ${fragment.version} (supported: ${SAVE_FRAGMENT_VERSION})`);
195565
195714
  }
195566
195715
  this.load(fragment.scopes);
195567
195716
  }
195568
- assertFree(token2) {
195569
- if (this.scopes.has(token2)) throw new Error(`scope '@${token2}' is already registered`);
195717
+ /**
195718
+ * A token is taken once. There is no reserved-token list: a clash surfaces
195719
+ * here, the moment a game combines its engines, which is the only moment
195720
+ * anyone knows which engines are present. With owners recorded the error says
195721
+ * whose token it already is.
195722
+ */
195723
+ assertFree(token2, owner) {
195724
+ const e = this.scopes.get(token2);
195725
+ if (!e) return;
195726
+ const by = e.owner !== void 0 ? ` by ${e.owner}` : "";
195727
+ const wants = owner !== void 0 ? ` (wanted by ${owner})` : "";
195728
+ throw new Error(`scope '@${token2}' is already registered${by}${wants}`);
195570
195729
  }
195571
195730
  };
195731
+ function declsOf(e) {
195732
+ if (e.kind === "foreign") return [...e.decls.entries()];
195733
+ return e.bag.declarations().map((d) => [e.bag.normalise(d.name), d]);
195734
+ }
195735
+ function normOf(e) {
195736
+ return e.kind === "foreign" ? e.norm : (n) => e.bag.normalise(n);
195737
+ }
195572
195738
  function defaultFor(d) {
195573
195739
  if (d.default !== void 0) return d.default;
195574
195740
  switch (d.type) {
@@ -195630,6 +195796,19 @@ function buildTagIndex(bundle) {
195630
195796
 
195631
195797
  // ../runtime/src/engine.ts
195632
195798
  var astCache = /* @__PURE__ */ new WeakMap();
195799
+ var OWNER = "Patter";
195800
+ var esc2 = (id) => id.replace(/%/g, "%25").replace(/\//g, "%2F");
195801
+ var OWNS_REGISTRY = /* @__PURE__ */ Symbol("ownsRegistry");
195802
+ var keys = {
195803
+ /** A scene's SHARED `@scene` props (one bag per scene, every flow's). */
195804
+ stage: (sceneId) => `patter/scene/${esc2(sceneId)}`,
195805
+ /** Everything one flow registers starts with this. */
195806
+ flow: (flowId) => `patter/flow/${esc2(flowId)}/`,
195807
+ /** A flow's NOT-shared `@patter` globals. */
195808
+ flowGlobals: (flowId) => `patter/flow/${esc2(flowId)}/patter`,
195809
+ /** A flow's NOT-shared `@scene` props for one scene. */
195810
+ flowScene: (flowId, sceneId) => `patter/flow/${esc2(flowId)}/scene/${esc2(sceneId)}`
195811
+ };
195633
195812
  var Engine = class _Engine {
195634
195813
  host;
195635
195814
  defaultSeed;
@@ -195689,18 +195868,32 @@ var Engine = class _Engine {
195689
195868
  const patterSharedDecls = props.filter((p) => p.shared ?? true).map(toDecl);
195690
195869
  const patterLocalDecls = props.filter((p) => !(p.shared ?? true)).map(toDecl);
195691
195870
  const patterSharedNames = new Set(patterSharedDecls.map((d) => d.name.toLowerCase()));
195692
- const shared = new ScopeRegistry().defineOwned("patter", patterSharedDecls, "@patter.");
195693
- const hostBound = /* @__PURE__ */ new Set();
195694
- if (options.world) {
195695
- const worldSpec = bundle.scopeRegistry?.scopes.find((s) => s.token === "world");
195696
- const decls = (worldSpec?.declarations ?? []).map(toForeignDecl);
195697
- shared.defineForeign("world", options.world, decls, worldSpec?.writable ?? true);
195698
- hostBound.add("world");
195699
- }
195700
- for (const spec of bundle.scopeRegistry?.scopes ?? []) {
195701
- if (hostBound.has(spec.token)) continue;
195702
- const decls = (spec.declarations ?? []).map(toForeignDecl);
195703
- shared.defineForeign(spec.token, selfBackedResolver(spec.declarations ?? []), decls, spec.writable ?? true);
195871
+ const registry = options.registry ?? new ScopeRegistry();
195872
+ const ownsRegistry = !options.registry || options[OWNS_REGISTRY] === true;
195873
+ const patterBag = new PropertyBag(patterSharedDecls, { pathPrefix: "@patter." });
195874
+ const hostScopes = [];
195875
+ const registered = [];
195876
+ try {
195877
+ registry.mountOwned("patter", patterBag, { owner: OWNER });
195878
+ registered.push("patter");
195879
+ const hostBound = /* @__PURE__ */ new Set();
195880
+ if (options.world) {
195881
+ const worldSpec = bundle.scopeRegistry?.scopes.find((s) => s.token === "world");
195882
+ const decls = (worldSpec?.declarations ?? []).map(toForeignDecl);
195883
+ registry.defineForeign("world", options.world, decls, { writable: worldSpec?.writable ?? true, owner: OWNER });
195884
+ registered.push("world");
195885
+ hostBound.add("world");
195886
+ }
195887
+ for (const spec of ownsRegistry ? bundle.scopeRegistry?.scopes ?? [] : []) {
195888
+ if (hostBound.has(spec.token) || registry.has(spec.token)) continue;
195889
+ const decls = (spec.declarations ?? []).map((d) => selfBackedDecl(d, spec.writable));
195890
+ registry.defineOwned(spec.token, decls, { owner: OWNER });
195891
+ registered.push(spec.token);
195892
+ hostScopes.push(spec.token);
195893
+ }
195894
+ } catch (e) {
195895
+ for (const k of registered) registry.remove(k, { keep: true });
195896
+ throw e;
195704
195897
  }
195705
195898
  const sceneSharedNames = /* @__PURE__ */ new Map();
195706
195899
  for (const [sceneId, scene] of Object.entries(bundle.scenes)) {
@@ -195722,7 +195915,10 @@ var Engine = class _Engine {
195722
195915
  blockGameIdToId: this.blockGameIdToId,
195723
195916
  // same instances the engine resolves with
195724
195917
  tagIndex: buildTagIndex(bundle),
195725
- shared,
195918
+ registry,
195919
+ ownsRegistry,
195920
+ patterBag,
195921
+ hostScopes,
195726
195922
  patterSharedDecls,
195727
195923
  patterLocalDecls,
195728
195924
  patterSharedNames,
@@ -195739,7 +195935,8 @@ var Engine = class _Engine {
195739
195935
  captionClose: (bundle.closedCaptions ?? DEFAULT_CAPTION_DELIMITERS).close,
195740
195936
  captionCharacter: bundle.closedCaptions?.character || DEFAULT_CAPTION_CHARACTER,
195741
195937
  // absent/empty -> SFX
195742
- refSplitCache: /* @__PURE__ */ new Map()
195938
+ refSplitCache: /* @__PURE__ */ new Map(),
195939
+ refSplitRevision: registry.revision
195743
195940
  };
195744
195941
  }
195745
195942
  /** The active locale (string + character-name lookups resolve in it). */
@@ -195784,10 +195981,12 @@ var Engine = class _Engine {
195784
195981
  * content-drift policy (§9.8) resolves edits under the cursor: stack frames re-find their next
195785
195982
  * child by id, drifted options drop, a vanished snippet is skipped.
195786
195983
  *
195787
- * Returns the REPLACEMENT engine; this one is left untouched and should be discarded. Hosts
195788
- * re-bind their flow handles via `next.getFlow(id)`. If the restore throws (defensive - §9.8
195789
- * makes this unreachable for ordinary edits), the swap falls back to a cold engine with each
195790
- * saved flow restarted from the top of the scene it was in.
195984
+ * Returns the REPLACEMENT engine, on the same registry. This one hands its bags over (each is
195985
+ * removed from the registry with its values kept, and the replacement claims them as it
195986
+ * registers), its flows are closed, and it should be discarded. Hosts re-bind their flow handles
195987
+ * via `next.getFlow(id)`. If the restore throws (defensive - §9.8 makes this unreachable for
195988
+ * ordinary edits), the swap falls back to a fresh engine with each saved flow restarted from the
195989
+ * top of the scene it was in; the shared properties carry over.
195791
195990
  */
195792
195991
  hotSwap(bundle) {
195793
195992
  const snapshot = this.saveGame();
@@ -195796,12 +195995,19 @@ var Engine = class _Engine {
195796
195995
  next2.setClosedCaptions(this.host.captionsOn);
195797
195996
  return next2;
195798
195997
  };
195799
- const next = new _Engine(bundle, this.creationOptions);
195998
+ const make = () => new _Engine(bundle, {
195999
+ ...this.creationOptions,
196000
+ registry: this.host.registry,
196001
+ [OWNS_REGISTRY]: this.host.ownsRegistry
196002
+ });
196003
+ this.release(true);
196004
+ const next = make();
195800
196005
  try {
195801
196006
  next.loadGame(snapshot);
195802
196007
  return carryOver(next);
195803
196008
  } catch {
195804
- const fresh = new _Engine(bundle, this.creationOptions);
196009
+ next.release(true);
196010
+ const fresh = make();
195805
196011
  for (const [id, f] of Object.entries(snapshot.flows)) {
195806
196012
  const sceneId = f.cursor.currentSceneId;
195807
196013
  try {
@@ -195840,6 +196046,7 @@ var Engine = class _Engine {
195840
196046
  * call to reach for when you want a speaker's variation state to carry on.
195841
196047
  */
195842
196048
  openFlow(id, opts = {}) {
196049
+ this.assertExternalScopes();
195843
196050
  const sceneId = this.resolveSceneRef(opts.scene);
195844
196051
  const blockId = this.resolveBlockRef(sceneId, opts.block);
195845
196052
  this.flowsById.get(id)?.close();
@@ -195879,6 +196086,17 @@ var Engine = class _Engine {
195879
196086
  }
195880
196087
  return existing.advanceToStop().played;
195881
196088
  }
196089
+ /** Content that names another engine's scope (`@story.act`) runs only where that engine is on this
196090
+ * registry: without it every read would answer false and every write fail, so the flow is refused as
196091
+ * it opens (or the save as it loads), before anything changes. By then a game has built all of its
196092
+ * engines, whatever order it built them in. The same message on every runtime. */
196093
+ assertExternalScopes() {
196094
+ for (const token2 of this.host.bundle.externalScopes ?? []) {
196095
+ if (!this.host.registry.has(token2)) {
196096
+ throw new Error(`this content names @${token2}, which no engine on this registry registered: give every engine the game's one registry`);
196097
+ }
196098
+ }
196099
+ }
195882
196100
  /** Resolve a scene reference (a gameId address OR an internal id) to its internal id. */
195883
196101
  resolveSceneRef(ref) {
195884
196102
  if (ref == null) return void 0;
@@ -196064,7 +196282,7 @@ var Engine = class _Engine {
196064
196282
  * loadGame() replaces every bag, so re-enumerate after a load.
196065
196283
  */
196066
196284
  listBags() {
196067
- const mounts = [{ bag: this.host.shared.ownedBag("patter") }];
196285
+ const mounts = [{ bag: this.host.patterBag }];
196068
196286
  for (const [sceneId, bag] of this.host.stageBags) mounts.push({ bag, pathPrefix: `@scene:${sceneId}.` });
196069
196287
  return mounts;
196070
196288
  }
@@ -196083,15 +196301,31 @@ var Engine = class _Engine {
196083
196301
  reset() {
196084
196302
  for (const flow of this.flowsById.values()) flow.close();
196085
196303
  this.flowsById.clear();
196086
- this.host.shared.reseedOwned("patter", this.host.patterSharedDecls);
196304
+ this.host.patterBag.reseed(this.host.patterSharedDecls);
196087
196305
  this.host.sharedVisits.clear();
196088
196306
  this.host.sharedSelectors.clear();
196307
+ for (const s of this.host.stageBags.keys()) this.host.registry.remove(keys.stage(s));
196089
196308
  this.host.stageBags.clear();
196309
+ this.host.registry.discardParked("patter/");
196310
+ }
196311
+ /** Remove every bag this engine registered, keeping the values parked when `keep` (a live reload
196312
+ * handing its state to a replacement), and close its flows. The engine is inert afterwards. */
196313
+ release(keep) {
196314
+ for (const flow of this.flowsById.values()) {
196315
+ flow.releaseBags(keep);
196316
+ flow.close();
196317
+ }
196318
+ this.flowsById.clear();
196319
+ const reg = this.host.registry;
196320
+ for (const s of this.host.stageBags.keys()) reg.remove(keys.stage(s), { keep });
196321
+ this.host.stageBags.clear();
196322
+ for (const t of ["patter", ...this.host.hostScopes]) if (reg.has(t)) reg.remove(t, { keep });
196323
+ if (this.creationOptions.world && reg.has("world")) reg.remove("world");
196090
196324
  }
196091
196325
  /** Read a shared (`@patter` / foreign) property by ref. `@scene` refs are rejected (flow-level). */
196092
196326
  getProperty(ref) {
196093
196327
  const { scope, name } = this.splitShared(ref);
196094
- return this.host.shared.get(scope, name);
196328
+ return this.host.registry.get(scope, name);
196095
196329
  }
196096
196330
  /** Write a shared (`@patter` / foreign) property by ref. `@scene` refs are rejected (flow-level).
196097
196331
  *
@@ -196102,7 +196336,7 @@ var Engine = class _Engine {
196102
196336
  * were each refused the one property they existed to move.) */
196103
196337
  setProperty(ref, value) {
196104
196338
  const { scope, name } = this.splitShared(ref);
196105
- this.host.shared.set(scope, name, value, { host: true });
196339
+ this.host.registry.set(scope, name, value, { host: true });
196106
196340
  }
196107
196341
  /** The shared `@patter` properties, for a live state inspector: each with its ref, type, current
196108
196342
  * value, declared default (for reset), and enum options. Mirrors the Unity / Godot ports. */
@@ -196149,54 +196383,66 @@ var Engine = class _Engine {
196149
196383
  // @scene is scene-namespaced and needs a flow's current scene - silently
196150
196384
  // routing it into the shared bag (as a junk "scene.x" key) was a trap.
196151
196385
  splitShared(ref) {
196152
- let split = this.host.refSplitCache.get(ref);
196153
- if (!split) {
196154
- split = splitRef(ref, (t) => t === "scene" || this.host.shared.has(t));
196155
- this.host.refSplitCache.set(ref, split);
196156
- }
196386
+ const split = splitHostRef(this.host, ref);
196157
196387
  if (split.scope === "scene") {
196158
196388
  throw new Error(`'${ref}': @scene properties are scene-scoped - read/write them on a Flow, not the Engine`);
196159
196389
  }
196160
196390
  return split;
196161
196391
  }
196162
- /** Snapshot shared `@patter` state only (for a unified cross-engine save blob, Phase D). */
196392
+ /** The shared `@patter` values alone, as `{ patter: {...} }`.
196393
+ * @deprecated The registry holds every property now: a game saves `registry.save()` once, and a
196394
+ * standalone engine's `saveGame()` carries its registry's values. Removed at the next breaking release. */
196163
196395
  save() {
196164
- return this.host.shared.save();
196396
+ return { patter: this.host.patterBag.save() };
196165
196397
  }
196166
- /** Restore shared `@patter` values (world properties untouched). */
196398
+ /** Lay a `{ patter: {...} }` section over the shared `@patter` values; anything else is ignored.
196399
+ * @deprecated See `save`. Removed at the next breaking release. */
196167
196400
  load(blob) {
196168
- this.host.shared.load(blob);
196401
+ if (blob.patter) this.host.patterBag.load(blob.patter);
196169
196402
  }
196170
- /** Snapshot the whole game: shared `@patter` + visit counts + every live flow. */
196403
+ /** Snapshot the whole game's NON-property state: visit counts, shared selector cursors, and every
196404
+ * live flow's cursor and PRNG. The property values are the registry's: a standalone engine (one that
196405
+ * made its own registry) carries them here under `registry`; a game that passed a registry saves it
196406
+ * once itself, beside each engine's `saveGame()`. */
196171
196407
  saveGame() {
196172
196408
  const flows = {};
196173
196409
  for (const [id, flow] of this.flowsById) flows[id] = flow.snapshot();
196174
196410
  return {
196175
- version: 2,
196176
- shared: this.host.shared.save(),
196411
+ version: SAVE_VERSION,
196412
+ ...this.host.ownsRegistry ? { registry: this.host.registry.save() } : {},
196177
196413
  sharedVisits: Object.fromEntries(this.host.sharedVisits),
196178
196414
  sharedSelectors: serialiseSelectors(this.host.sharedSelectors),
196179
- stageBags: Object.fromEntries([...this.host.stageBags].map(([s, bag]) => [s, bag.save()])),
196180
196415
  flows
196181
196416
  };
196182
196417
  }
196183
- /** Restore a `saveGame()`: shared globals + visit counts + shared scene bags + reconstruct every flow. */
196418
+ /**
196419
+ * Restore a `saveGame()`: visit counts, shared selector cursors, and every flow. Property values come
196420
+ * from the registry. A save that carries them (a standalone engine's, or a version 2 save from before
196421
+ * the registry held them) has them moved into the registry here; otherwise the game loads its
196422
+ * registry itself, before or after this call. Either order works: this engine's bags are handed back
196423
+ * to the registry (values kept) and the restored flows claim them as they register.
196424
+ */
196184
196425
  loadGame(save) {
196185
- if (save.version !== 2) throw new Error(`unsupported save version: ${save.version}`);
196186
- this.host.shared.load(save.shared);
196426
+ const version2 = save.version;
196427
+ if (version2 !== 2 && version2 !== SAVE_VERSION) throw new Error(`unsupported save version: ${String(version2)}`);
196428
+ this.assertExternalScopes();
196429
+ const reg = this.host.registry;
196430
+ for (const [id, flow] of this.flowsById) {
196431
+ flow.releaseBags(id in save.flows);
196432
+ flow.close();
196433
+ }
196434
+ this.flowsById.clear();
196435
+ for (const s of this.host.stageBags.keys()) reg.remove(keys.stage(s), { keep: true });
196436
+ this.host.stageBags.clear();
196437
+ const values = save.version === 2 ? sectionsFromV2(save) : save.registry;
196438
+ if (values) {
196439
+ if (this.host.ownsRegistry) reg.load(values);
196440
+ else reg.load(values, { keepParked: true });
196441
+ }
196187
196442
  this.host.sharedVisits.clear();
196188
196443
  for (const [id, n] of Object.entries(save.sharedVisits ?? {})) this.host.sharedVisits.set(id, n);
196189
196444
  this.host.sharedSelectors.clear();
196190
196445
  for (const [id, st] of deserialiseSelectors(save.sharedSelectors)) this.host.sharedSelectors.set(id, st);
196191
- this.host.stageBags.clear();
196192
- for (const [s, values] of Object.entries(save.stageBags ?? {})) {
196193
- const shared = this.host.sceneSharedNames.get(s) ?? /* @__PURE__ */ new Set();
196194
- const decls = (this.host.bundle.scenes[s]?.sceneProps ?? []).filter((d) => shared.has(d.name.toLowerCase()));
196195
- const bag = new PropertyBag(decls);
196196
- bag.load(values);
196197
- this.host.stageBags.set(s, bag);
196198
- }
196199
- this.flowsById.clear();
196200
196446
  for (const [id, snap] of Object.entries(save.flows)) {
196201
196447
  const flow = new Flow(id, this.host, this.defaultSeed);
196202
196448
  flow.restore(snap);
@@ -196208,7 +196454,9 @@ var Flow = class {
196208
196454
  id;
196209
196455
  host;
196210
196456
  local;
196211
- // owns "patter" = the NOT-shared globals (this flow's copy)
196457
+ // the NOT-shared `@patter` globals (this flow's copy), keys.flowGlobals
196458
+ /** The registry keys this flow has registered (its globals and each scene bag). */
196459
+ registered = /* @__PURE__ */ new Set();
196212
196460
  rngState;
196213
196461
  // Execution cursor. The `stack` is the continuation stack: each frame is a
196214
196462
  // position within a block's children (the top frame is the active block run;
@@ -196233,40 +196481,44 @@ var Flow = class {
196233
196481
  /** Per-node entry counts for this flow (node id -> times entered). */
196234
196482
  visitCounts = /* @__PURE__ */ new Map();
196235
196483
  // Per-flow halves of the two scopes. The NOT-shared `@patter` globals live in
196236
- // `local` (owned scope "patter"); the NOT-shared `@scene` props live in
196237
- // `sceneBags` (namespaced per scene; they PERSIST across re-entries, spec §7).
196238
- // The SHARED halves live on the host (`host.shared` / `host.stageBags`). Each
196239
- // resolver presents one merged scope, routing each property to its half by the
196240
- // declared `shared` flag.
196484
+ // `local`; the NOT-shared `@scene` props live in `sceneBags` (namespaced per
196485
+ // scene; they PERSIST across re-entries, spec §7). The SHARED halves live on the
196486
+ // host (`host.patterBag` / `host.stageBags`). All of them are registered in the
196487
+ // game's registry. Each resolver presents one merged scope, routing each property
196488
+ // to its half by the declared `shared` flag: that split is why `@patter` and
196489
+ // `@scene` are composed here rather than aliased to a single registry key.
196241
196490
  /** This flow's per-scene LOCAL scene props; see FlowHost.stageBags. */
196242
196491
  sceneBags = /* @__PURE__ */ new Map();
196243
196492
  patterResolver = {
196244
- get: (n) => this.host.patterSharedNames.has(n) ? this.host.shared.get("patter", n) : this.local.get("patter", n),
196493
+ get: (n) => this.host.patterSharedNames.has(n) ? this.host.patterBag.get(n) : this.local.get(n),
196245
196494
  set: (n, v) => {
196246
- if (this.host.patterSharedNames.has(n)) this.host.shared.set("patter", n, v);
196247
- else this.local.set("patter", n, v);
196495
+ if (this.host.patterSharedNames.has(n)) this.host.registry.set("patter", n, v);
196496
+ else this.local.set(n, v);
196248
196497
  }
196249
196498
  };
196250
196499
  sceneResolver = {
196251
196500
  get: (n) => {
196252
196501
  const s = this.currentSceneId;
196253
196502
  if (s === null) return void 0;
196254
- const bag = this.host.sceneSharedNames.get(s)?.has(n) ? this.host.stageBags.get(s) : this.sceneBags.get(s);
196255
- return bag?.get(n);
196503
+ return this.sceneBagFor(s, n)?.get(n);
196256
196504
  },
196257
196505
  set: (n, v) => {
196258
196506
  const s = this.currentSceneId;
196259
196507
  if (s === null) return;
196260
- const bag = this.host.sceneSharedNames.get(s)?.has(n) ? this.host.stageBags.get(s) : this.sceneBags.get(s);
196508
+ const bag = this.sceneBagFor(s, n);
196261
196509
  if (bag) bag.set(n, v);
196262
196510
  }
196263
196511
  };
196264
- // The eval context is built ONCE: every constituent resolves live state at
196265
- // call time (shared bags mutate in place per scoperegistry's contract;
196266
- // patter/scene route through this flow's resolvers, which read the current
196267
- // `local`/`sceneBags`/`currentSceneId`; the host callbacks read current flow
196268
- // fields). Rebuilding it per evaluation was the engine's hottest allocation.
196512
+ // The eval context is built once and REFRESHED only when the registry's set of
196513
+ // scopes moves (its `revision`): every constituent resolves live state at call
196514
+ // time (bags mutate in place per scoperegistry's contract; patter/scene route
196515
+ // through this flow's resolvers, which read the current `local`/`sceneBags`/
196516
+ // `currentSceneId`; the host callbacks read current flow fields), but another
196517
+ // engine registering `@story` after this flow opened must still be readable.
196518
+ // Rebuilding it per evaluation was the engine's hottest allocation.
196269
196519
  evalCtx;
196520
+ ctxRevision = -1;
196521
+ registryQualities;
196270
196522
  flowLog = [];
196271
196523
  /** Monotonic across the flow's life; survives clearLog so two reads agree on order. */
196272
196524
  flowSeq = 0;
@@ -196274,12 +196526,9 @@ var Flow = class {
196274
196526
  this.id = id;
196275
196527
  this.host = host2;
196276
196528
  this.rngState = toUint32(seed);
196277
- this.local = this.freshLocal();
196278
- const scopes = { ...host2.shared.toEvalContext().scopes };
196279
- scopes["patter"] = this.patterResolver;
196280
- scopes["scene"] = this.sceneResolver;
196529
+ this.local = this.newLocal();
196281
196530
  this.evalCtx = {
196282
- scopes,
196531
+ scopes: {},
196283
196532
  host: {
196284
196533
  nextRandom: this.rng,
196285
196534
  visits: (id2) => this.visitCounts.get(id2) ?? 0,
@@ -196292,6 +196541,21 @@ var Flow = class {
196292
196541
  qualities: (scope, name) => this.stagesFor(scope, name)
196293
196542
  };
196294
196543
  }
196544
+ /** The eval context, its scopes refreshed if the registry's set of scopes has moved since. */
196545
+ context() {
196546
+ const reg = this.host.registry;
196547
+ if (reg.revision !== this.ctxRevision) {
196548
+ const base = reg.toEvalContext();
196549
+ const scopes = this.evalCtx.scopes;
196550
+ for (const k of Object.keys(scopes)) delete scopes[k];
196551
+ Object.assign(scopes, base.scopes);
196552
+ scopes["patter"] = this.patterResolver;
196553
+ scopes["scene"] = this.sceneResolver;
196554
+ this.registryQualities = base.qualities;
196555
+ this.ctxRevision = reg.revision;
196556
+ }
196557
+ return this.evalCtx;
196558
+ }
196295
196559
  /** The stage ladder of `@scope.name` when it is a declared quality, else undefined. Names compare
196296
196560
  * lowercase, as the compiler emits references (the selfBackedResolver lesson). */
196297
196561
  stagesFor(scope, name) {
@@ -196304,13 +196568,14 @@ var Flow = class {
196304
196568
  const scene = this.currentSceneId != null ? this.host.bundle.scenes[this.currentSceneId] : void 0;
196305
196569
  return fromDecls(scene?.sceneProps);
196306
196570
  }
196307
- return fromDecls(this.host.bundle.scopeRegistry?.scopes.find((s) => s.token === scope)?.declarations);
196571
+ return this.registryQualities?.(scope, name) ?? fromDecls(this.host.bundle.scopeRegistry?.scopes.find((s) => s.token === scope)?.declarations);
196308
196572
  }
196309
196573
  // -- Host API -------------------------------------------------------------
196310
196574
  /** Begin this flow at a scene (and optionally a specific block within it). */
196311
196575
  start(sceneId, blockId) {
196312
- this.sceneBags.clear();
196313
- this.local = this.freshLocal();
196576
+ this.releaseBags(false);
196577
+ this.host.registry.discardParked(keys.flow(this.id));
196578
+ this.mountLocal();
196314
196579
  this.selectors.clear();
196315
196580
  this.visitCounts.clear();
196316
196581
  this.stack = [];
@@ -196410,6 +196675,7 @@ var Flow = class {
196410
196675
  * cannot quietly mutate the world. Terminal: unlike ending, a close is never revived.
196411
196676
  */
196412
196677
  close() {
196678
+ this.releaseBags(false);
196413
196679
  this.closed = true;
196414
196680
  this.flowEnded = true;
196415
196681
  this.stack = [];
@@ -196519,7 +196785,7 @@ var Flow = class {
196519
196785
  * halves are the Engine's listBags.
196520
196786
  */
196521
196787
  listBags() {
196522
- const mounts = [{ bag: this.local.ownedBag("patter"), pathPrefix: `${this.id}/@patter.` }];
196788
+ const mounts = [{ bag: this.local, pathPrefix: `${this.id}/@patter.` }];
196523
196789
  for (const [sceneId, bag] of this.sceneBags) mounts.push({ bag, pathPrefix: `${this.id}/@scene:${sceneId}.` });
196524
196790
  return mounts;
196525
196791
  }
@@ -196567,7 +196833,7 @@ var Flow = class {
196567
196833
  const { scope, name } = this.splitRef(ref);
196568
196834
  if (scope === "patter") return this.patterResolver.get(name);
196569
196835
  if (scope === "scene") return this.sceneResolver.get(name);
196570
- return this.host.shared.get(scope, name);
196836
+ return this.host.registry.get(scope, name);
196571
196837
  }
196572
196838
  /** Write a property by ref (routed by scope, then by the property's `shared` flag). The GAME's
196573
196839
  * surface: it writes with host authority, so a `writable: false` host declaration does not refuse
@@ -196585,16 +196851,13 @@ var Flow = class {
196585
196851
  if (this.currentSceneId === null) throw new Error(`'${ref}': the flow has not entered a scene yet`);
196586
196852
  this.sceneResolver.set(name, value);
196587
196853
  } else {
196588
- this.host.shared.set(scope, name, value, host2 ? { host: true } : void 0);
196854
+ this.host.registry.set(scope, name, value, host2 ? { host: true } : void 0);
196589
196855
  }
196590
196856
  }
196591
196857
  // -- Save / restore (engine-driven) --------------------------------------
196592
- /** @internal Snapshot this flow's cursor + per-flow scopes (not-shared `@patter`/`@scene`) + PRNG. */
196858
+ /** @internal Snapshot this flow's cursor + PRNG + visits. Its properties are the registry's. */
196593
196859
  snapshot() {
196594
196860
  return {
196595
- scopes: this.local.save(),
196596
- // owned scope "patter" = the NOT-shared globals (@scene saved separately)
196597
- sceneBags: Object.fromEntries([...this.sceneBags].map(([s, bag]) => [s, bag.save()])),
196598
196861
  rngState: this.rngState,
196599
196862
  visits: Object.fromEntries(this.visitCounts),
196600
196863
  cursor: {
@@ -196632,15 +196895,11 @@ var Flow = class {
196632
196895
  }
196633
196896
  return { ...frame };
196634
196897
  });
196635
- this.sceneBags = new Map(Object.entries(snap.sceneBags ?? {}).map(([s, values]) => {
196636
- const shared = this.host.sceneSharedNames.get(s) ?? /* @__PURE__ */ new Set();
196637
- const decls = (this.host.bundle.scenes[s]?.sceneProps ?? []).filter((d) => !shared.has(d.name.toLowerCase()));
196638
- const bag = new PropertyBag(decls);
196639
- bag.load(values);
196640
- return [s, bag];
196641
- }));
196642
- this.local = this.freshLocal();
196643
- this.local.load(snap.scopes);
196898
+ this.releaseBags(false);
196899
+ this.mountLocal();
196900
+ for (const s of /* @__PURE__ */ new Set([c2.currentSceneId, ...this.stack.map((f) => f.sceneId)])) {
196901
+ if (s !== null && this.host.bundle.scenes[s]) this.ensureSceneBags(s);
196902
+ }
196644
196903
  this.activeSnippet = null;
196645
196904
  if (c2.activeSnippetId !== null) {
196646
196905
  const node = this.host.nodeIndex.get(c2.activeSnippetId);
@@ -196911,7 +197170,7 @@ var Flow = class {
196911
197170
  * node (comparisons, scoped vars, literals, other calls) is an atom, evaluated whole.
196912
197171
  */
196913
197172
  matchedSpec(node, want) {
196914
- const evalTruthy = (n) => truthy(evaluate(n, this.evalCtx, patterDialect));
197173
+ const evalTruthy = (n) => truthy(evaluate(n, this.context(), patterDialect));
196915
197174
  return matchedSpecificity(node, evalTruthy, { want });
196916
197175
  }
196917
197176
  /** A selector's cursor state - shared across flows (`group.shared`) or this flow's own. */
@@ -196938,7 +197197,7 @@ var Flow = class {
196938
197197
  return truthy(this.evalExpr(node.condition));
196939
197198
  }
196940
197199
  evalExpr(expr) {
196941
- return evaluate(this.conditionAst(expr), this.evalCtx, patterDialect);
197200
+ return evaluate(this.conditionAst(expr), this.context(), patterDialect);
196942
197201
  }
196943
197202
  /** The deserialised (in-memory) AST for an expression, cached per Expression. Shared by the
196944
197203
  * evaluator and the Best-match specificity walker so both work off one parse. */
@@ -197063,18 +197322,51 @@ var Flow = class {
197063
197322
  const key2 = castStringKey(character);
197064
197323
  return this.host.strings[key2] ?? this.host.defaultStrings[key2] ?? this.host.castDisplay.get(character);
197065
197324
  }
197066
- /** Split a ref into scope + name. Tokens: `@scene`, foreign tokens, else `@patter` (incl. bare `@name`). */
197325
+ /** Split a ref into scope + name. Tokens: `@scene`, registered tokens, else `@patter` (incl. bare `@name`). */
197067
197326
  splitRef(ref) {
197068
- let hit = this.host.refSplitCache.get(ref);
197069
- if (!hit) {
197070
- hit = splitRef(ref, (t) => t === "scene" || this.host.shared.has(t));
197071
- this.host.refSplitCache.set(ref, hit);
197072
- }
197073
- return hit;
197327
+ return splitHostRef(this.host, ref);
197328
+ }
197329
+ /** A fresh, unregistered bag for the NOT-shared `@patter` globals (the shared ones live on the host). */
197330
+ newLocal() {
197331
+ return new PropertyBag(this.host.patterLocalDecls, { pathPrefix: "@patter." });
197332
+ }
197333
+ /** Register a fresh globals bag under this flow's key; it claims any values waiting there. */
197334
+ mountLocal() {
197335
+ this.local = this.newLocal();
197336
+ const key2 = keys.flowGlobals(this.id);
197337
+ this.host.registry.mountOwned(key2, this.local, { owner: OWNER });
197338
+ this.registered.add(key2);
197339
+ }
197340
+ /** @internal Remove every bag this flow registered; with `keep`, their values wait in the registry for
197341
+ * the flow that replaces this one. Engine-driven (close, loadGame, hotSwap). */
197342
+ releaseBags(keep) {
197343
+ for (const key2 of this.registered) this.host.registry.remove(key2, { keep });
197344
+ this.registered.clear();
197345
+ this.sceneBags.clear();
197074
197346
  }
197075
- /** The per-flow registry: the NOT-shared `@patter` globals (the shared ones live on the host). */
197076
- freshLocal() {
197077
- return new ScopeRegistry().defineOwned("patter", this.host.patterLocalDecls, "@patter.");
197347
+ /** The bag a `@scene` property of scene `s` lives in (stage or this flow's), made if missing. */
197348
+ sceneBagFor(s, name) {
197349
+ if (!this.host.bundle.scenes[s]) return void 0;
197350
+ this.ensureSceneBags(s);
197351
+ return this.host.sceneSharedNames.get(s)?.has(name.toLowerCase()) ? this.host.stageBags.get(s) : this.sceneBags.get(s);
197352
+ }
197353
+ /** Make (and register) scene `s`'s stage bag and this flow's bag for it, if not made yet. A bag made
197354
+ * here claims whatever values the registry holds for its key: that is how a loaded save reaches it. */
197355
+ ensureSceneBags(s) {
197356
+ const shared = this.host.sceneSharedNames.get(s) ?? /* @__PURE__ */ new Set();
197357
+ const props = this.host.bundle.scenes[s]?.sceneProps ?? [];
197358
+ if (!this.sceneBags.has(s)) {
197359
+ const bag = new PropertyBag(props.filter((d) => !shared.has(d.name.toLowerCase())), { pathPrefix: "@scene." });
197360
+ const key2 = keys.flowScene(this.id, s);
197361
+ this.host.registry.mountOwned(key2, bag, { owner: OWNER });
197362
+ this.registered.add(key2);
197363
+ this.sceneBags.set(s, bag);
197364
+ }
197365
+ if (!this.host.stageBags.has(s)) {
197366
+ const bag = new PropertyBag(props.filter((d) => shared.has(d.name.toLowerCase())), { pathPrefix: "@scene." });
197367
+ this.host.registry.mountOwned(keys.stage(s), bag, { owner: OWNER });
197368
+ this.host.stageBags.set(s, bag);
197369
+ }
197078
197370
  }
197079
197371
  /**
197080
197372
  * Seed a scene's `@scene` props (spec §7). The not-shared props seed THIS flow's
@@ -197085,13 +197377,7 @@ var Flow = class {
197085
197377
  */
197086
197378
  seedScene(scene) {
197087
197379
  const shared = this.host.sceneSharedNames.get(scene.id) ?? /* @__PURE__ */ new Set();
197088
- const props = scene.sceneProps ?? [];
197089
- if (!this.sceneBags.has(scene.id)) {
197090
- this.sceneBags.set(scene.id, new PropertyBag(props.filter((d) => !shared.has(d.name.toLowerCase()))));
197091
- }
197092
- if (!this.host.stageBags.has(scene.id)) {
197093
- this.host.stageBags.set(scene.id, new PropertyBag(props.filter((d) => shared.has(d.name.toLowerCase()))));
197094
- }
197380
+ this.ensureSceneBags(scene.id);
197095
197381
  for (const decl of scene.sceneProps ?? []) {
197096
197382
  if (!decl.temporary) continue;
197097
197383
  const name = decl.name.toLowerCase();
@@ -197137,16 +197423,32 @@ function toDecl(decl) {
197137
197423
  function toForeignDecl(decl) {
197138
197424
  return { name: decl.name, type: decl.type, values: decl.values, stages: decl.stages, default: decl.default, writable: decl.writable };
197139
197425
  }
197140
- function selfBackedResolver(decls) {
197141
- const key2 = (name) => name.toLowerCase();
197142
- const bag = /* @__PURE__ */ new Map();
197143
- for (const d of decls) bag.set(key2(d.name), defaultFor(d));
197144
- return {
197145
- get: (name) => bag.get(key2(name)),
197146
- set: (name, value) => {
197147
- bag.set(key2(name), value);
197148
- }
197149
- };
197426
+ function selfBackedDecl(decl, scopeWritable) {
197427
+ const d = toForeignDecl(decl);
197428
+ const writable = decl.writable ?? scopeWritable;
197429
+ return writable === void 0 ? d : { ...d, writable };
197430
+ }
197431
+ function splitHostRef(host2, ref) {
197432
+ if (host2.refSplitRevision !== host2.registry.revision) {
197433
+ host2.refSplitCache.clear();
197434
+ host2.refSplitRevision = host2.registry.revision;
197435
+ }
197436
+ let hit = host2.refSplitCache.get(ref);
197437
+ if (!hit) {
197438
+ hit = splitRef(ref, (t) => t === "scene" || host2.registry.has(t) || (host2.bundle.externalScopes?.includes(t) ?? false));
197439
+ host2.refSplitCache.set(ref, hit);
197440
+ }
197441
+ return hit;
197442
+ }
197443
+ function sectionsFromV2(save) {
197444
+ const out = {};
197445
+ if (save.shared?.patter) out["patter"] = save.shared.patter;
197446
+ for (const [s, v] of Object.entries(save.stageBags ?? {})) out[keys.stage(s)] = v;
197447
+ for (const [id, f] of Object.entries(save.flows ?? {})) {
197448
+ if (f.scopes?.patter) out[keys.flowGlobals(id)] = f.scopes.patter;
197449
+ for (const [s, v] of Object.entries(f.sceneBags ?? {})) out[keys.flowScene(id, s)] = v;
197450
+ }
197451
+ return out;
197150
197452
  }
197151
197453
  function truthy(v) {
197152
197454
  if (typeof v === "boolean") return v;
@@ -198712,8 +199014,8 @@ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
198712
199014
  var __esmMin = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
198713
199015
  var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
198714
199016
  var __copyProps2 = (to, from, except, desc) => {
198715
- if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames2(from), i = 0, n = keys.length, key2; i < n; i++) {
198716
- key2 = keys[i];
199017
+ if (from && typeof from === "object" || typeof from === "function") for (var keys2 = __getOwnPropNames2(from), i = 0, n = keys2.length, key2; i < n; i++) {
199018
+ key2 = keys2[i];
198717
199019
  if (!__hasOwnProp2.call(to, key2) && key2 !== except) __defProp2(to, key2, {
198718
199020
  get: ((k) => from[k]).bind(null, key2),
198719
199021
  enumerable: !(desc = __getOwnPropDesc2(from, key2)) || desc.enumerable
@@ -199169,10 +199471,10 @@ var require_events = /* @__PURE__ */ __commonJSMin(((exports2, module2) => {
199169
199471
  return this;
199170
199472
  }
199171
199473
  if (arguments.length === 0) {
199172
- var keys = Object.keys(events);
199474
+ var keys2 = Object.keys(events);
199173
199475
  var key2;
199174
- for (i = 0; i < keys.length; ++i) {
199175
- key2 = keys[i];
199476
+ for (i = 0; i < keys2.length; ++i) {
199477
+ key2 = keys2[i];
199176
199478
  if (key2 === "removeListener") continue;
199177
199479
  this.removeAllListeners(key2);
199178
199480
  }
@@ -201785,9 +202087,9 @@ var require_isBufferBrowser = /* @__PURE__ */ __commonJSMin(((exports2, module2)
201785
202087
  var require_util5 = /* @__PURE__ */ __commonJSMin(((exports2) => {
201786
202088
  init_dist();
201787
202089
  var getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors || function getOwnPropertyDescriptors2(obj2) {
201788
- var keys = Object.keys(obj2);
202090
+ var keys2 = Object.keys(obj2);
201789
202091
  var descriptors = {};
201790
- for (var i = 0; i < keys.length; i++) descriptors[keys[i]] = Object.getOwnPropertyDescriptor(obj2, keys[i]);
202092
+ for (var i = 0; i < keys2.length; i++) descriptors[keys2[i]] = Object.getOwnPropertyDescriptor(obj2, keys2[i]);
201791
202093
  return descriptors;
201792
202094
  };
201793
202095
  var formatRegExp = /%[sdj%]/g;
@@ -201923,11 +202225,11 @@ var require_util5 = /* @__PURE__ */ __commonJSMin(((exports2) => {
201923
202225
  }
201924
202226
  var primitive = formatPrimitive(ctx, value);
201925
202227
  if (primitive) return primitive;
201926
- var keys = Object.keys(value);
201927
- var visibleKeys = arrayToHash(keys);
201928
- if (ctx.showHidden) keys = Object.getOwnPropertyNames(value);
201929
- if (isError2(value) && (keys.indexOf("message") >= 0 || keys.indexOf("description") >= 0)) return formatError(value);
201930
- if (keys.length === 0) {
202228
+ var keys2 = Object.keys(value);
202229
+ var visibleKeys = arrayToHash(keys2);
202230
+ if (ctx.showHidden) keys2 = Object.getOwnPropertyNames(value);
202231
+ if (isError2(value) && (keys2.indexOf("message") >= 0 || keys2.indexOf("description") >= 0)) return formatError(value);
202232
+ if (keys2.length === 0) {
201931
202233
  if (isFunction(value)) {
201932
202234
  var name = value.name ? ": " + value.name : "";
201933
202235
  return ctx.stylize("[Function" + name + "]", "special");
@@ -201945,13 +202247,13 @@ var require_util5 = /* @__PURE__ */ __commonJSMin(((exports2) => {
201945
202247
  if (isRegExp(value)) base = " " + RegExp.prototype.toString.call(value);
201946
202248
  if (isDate(value)) base = " " + Date.prototype.toUTCString.call(value);
201947
202249
  if (isError2(value)) base = " " + formatError(value);
201948
- if (keys.length === 0 && (!array || value.length == 0)) return braces[0] + base + braces[1];
202250
+ if (keys2.length === 0 && (!array || value.length == 0)) return braces[0] + base + braces[1];
201949
202251
  if (recurseTimes < 0) if (isRegExp(value)) return ctx.stylize(RegExp.prototype.toString.call(value), "regexp");
201950
202252
  else return ctx.stylize("[Object]", "special");
201951
202253
  ctx.seen.push(value);
201952
202254
  var output;
201953
- if (array) output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
201954
- else output = keys.map(function(key2) {
202255
+ if (array) output = formatArray(ctx, value, recurseTimes, visibleKeys, keys2);
202256
+ else output = keys2.map(function(key2) {
201955
202257
  return formatProperty(ctx, value, recurseTimes, visibleKeys, key2, array);
201956
202258
  });
201957
202259
  ctx.seen.pop();
@@ -201970,11 +202272,11 @@ var require_util5 = /* @__PURE__ */ __commonJSMin(((exports2) => {
201970
202272
  function formatError(value) {
201971
202273
  return "[" + Error.prototype.toString.call(value) + "]";
201972
202274
  }
201973
- function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
202275
+ function formatArray(ctx, value, recurseTimes, visibleKeys, keys2) {
201974
202276
  var output = [];
201975
202277
  for (var i = 0, l2 = value.length; i < l2; ++i) if (hasOwnProperty(value, String(i))) output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, String(i), true));
201976
202278
  else output.push("");
201977
- keys.forEach(function(key2) {
202279
+ keys2.forEach(function(key2) {
201978
202280
  if (!key2.match(/^\d+$/)) output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, key2, true));
201979
202281
  });
201980
202282
  return output;
@@ -202117,9 +202419,9 @@ var require_util5 = /* @__PURE__ */ __commonJSMin(((exports2) => {
202117
202419
  exports2.inherits = require_inherits_browser2();
202118
202420
  exports2._extend = function(origin, add) {
202119
202421
  if (!add || !isObject3(add)) return origin;
202120
- var keys = Object.keys(add);
202121
- var i = keys.length;
202122
- while (i--) origin[keys[i]] = add[keys[i]];
202422
+ var keys2 = Object.keys(add);
202423
+ var i = keys2.length;
202424
+ while (i--) origin[keys2[i]] = add[keys2[i]];
202123
202425
  return origin;
202124
202426
  };
202125
202427
  function hasOwnProperty(obj2, prop) {
@@ -202201,14 +202503,14 @@ var require_util5 = /* @__PURE__ */ __commonJSMin(((exports2) => {
202201
202503
  }));
202202
202504
  var require_buffer_list2 = /* @__PURE__ */ __commonJSMin(((exports2, module2) => {
202203
202505
  function ownKeys2(object, enumerableOnly) {
202204
- var keys = Object.keys(object);
202506
+ var keys2 = Object.keys(object);
202205
202507
  if (Object.getOwnPropertySymbols) {
202206
202508
  var symbols = Object.getOwnPropertySymbols(object);
202207
202509
  enumerableOnly && (symbols = symbols.filter(function(sym) {
202208
202510
  return Object.getOwnPropertyDescriptor(object, sym).enumerable;
202209
- })), keys.push.apply(keys, symbols);
202511
+ })), keys2.push.apply(keys2, symbols);
202210
202512
  }
202211
- return keys;
202513
+ return keys2;
202212
202514
  }
202213
202515
  function _objectSpread(target) {
202214
202516
  for (var i = 1; i < arguments.length; i++) {
@@ -203056,17 +203358,17 @@ var require__stream_writable = /* @__PURE__ */ __commonJSMin(((exports2, module2
203056
203358
  var require__stream_duplex = /* @__PURE__ */ __commonJSMin(((exports2, module2) => {
203057
203359
  init_dist();
203058
203360
  var objectKeys = Object.keys || function(obj2) {
203059
- var keys2 = [];
203060
- for (var key2 in obj2) keys2.push(key2);
203061
- return keys2;
203361
+ var keys3 = [];
203362
+ for (var key2 in obj2) keys3.push(key2);
203363
+ return keys3;
203062
203364
  };
203063
203365
  module2.exports = Duplex;
203064
203366
  var Readable = require__stream_readable();
203065
203367
  var Writable = require__stream_writable();
203066
203368
  require_inherits_browser2()(Duplex, Readable);
203067
- var keys = objectKeys(Writable.prototype);
203068
- for (var v = 0; v < keys.length; v++) {
203069
- var method = keys[v];
203369
+ var keys2 = objectKeys(Writable.prototype);
203370
+ for (var v = 0; v < keys2.length; v++) {
203371
+ var method = keys2[v];
203070
203372
  if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];
203071
203373
  }
203072
203374
  function Duplex(options) {
@@ -217473,12 +217775,12 @@ var Bitfield = class extends Base {
217473
217775
  size() {
217474
217776
  return this.type.size();
217475
217777
  }
217476
- encode(stream2, keys) {
217778
+ encode(stream2, keys2) {
217477
217779
  let val = 0;
217478
217780
  for (let i = 0; i < this.flags.length; i++) {
217479
217781
  const flag = this.flags[i];
217480
217782
  if (flag != null) {
217481
- if (keys[flag]) {
217783
+ if (keys2[flag]) {
217482
217784
  val |= 1 << i;
217483
217785
  }
217484
217786
  }
@@ -238875,8 +239177,8 @@ function parsePropertyQuery(query) {
238875
239177
  if (!m) return null;
238876
239178
  const prop = m[1];
238877
239179
  const value = m[2].replace(/^[\s=<>!]+/, "").replace(/^["']|["']$/g, "").trim().toLowerCase() || void 0;
238878
- const esc2 = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
238879
- const regexes = prop.includes(".") ? [new RegExp(`@${esc2(prop)}\\b`, "i")] : [new RegExp(`@${esc2(prop)}\\b`, "i"), new RegExp(`@patter\\.${esc2(prop)}\\b`, "i")];
239180
+ const esc3 = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
239181
+ const regexes = prop.includes(".") ? [new RegExp(`@${esc3(prop)}\\b`, "i")] : [new RegExp(`@${esc3(prop)}\\b`, "i"), new RegExp(`@patter\\.${esc3(prop)}\\b`, "i")];
238880
239182
  return { regexes, value };
238881
239183
  }
238882
239184
  var indexCache = null;
@@ -240971,7 +241273,7 @@ function writeTextFiles(files, encoding = "utf8") {
240971
241273
  // package.json
240972
241274
  var package_default = {
240973
241275
  name: "@patterkit/cli",
240974
- version: "0.3.8",
241276
+ version: "0.3.9",
240975
241277
  description: "The `patter` CLI: validate, format, export, and play a Patter project.",
240976
241278
  type: "module",
240977
241279
  license: "MIT",
@@ -241000,8 +241302,8 @@ var package_default = {
241000
241302
  "build:standalone:others": "node scripts/build-standalone.mjs --targets=linux-x64,linux-arm64,windows-x64"
241001
241303
  },
241002
241304
  dependencies: {
241003
- "@patterkit/core": "0.2.4",
241004
- "@patterkit/ops": "0.7.6",
241305
+ "@patterkit/core": "0.2.5",
241306
+ "@patterkit/ops": "0.7.7",
241005
241307
  "@wildwinter/simple-vc-lib": "^0.4.1"
241006
241308
  }
241007
241309
  };