@patterkit/cli 0.3.7 → 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 +640 -336
  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,13 @@ 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;
193145
+
193146
+ // ../core/src/noderefs.ts
193147
+ var VISIT_FN_RE = /\b(patter_visits|patter_seen|visits|seen)\s*\(\s*(?:(['"])(.*?)\2|([A-Za-z_]\w*))\s*\)/g;
193148
+ function humanizeNodeRefs(cond, label) {
193149
+ return cond.replace(VISIT_FN_RE, (_m, fn, _q, quoted, bare) => `${fn}(${label(quoted ?? bare ?? "")})`);
193150
+ }
193144
193151
 
193145
193152
  // ../core/src/serialize.ts
193146
193153
  function canonicalStringify(value, opts) {
@@ -193160,10 +193167,10 @@ ${indent}]`;
193160
193167
  }
193161
193168
  if (typeof v === "object") {
193162
193169
  const obj2 = v;
193163
- const keys = Object.keys(obj2).filter((k) => obj2[k] !== void 0).sort();
193164
- if (keys.length === 0) return "{}";
193170
+ const keys2 = Object.keys(obj2).filter((k) => obj2[k] !== void 0).sort();
193171
+ if (keys2.length === 0) return "{}";
193165
193172
  const next = indent + " ";
193166
- 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)}`);
193167
193174
  return `{
193168
193175
  ${entries.join(",\n")}${tail}
193169
193176
  ${indent}}`;
@@ -194040,6 +194047,12 @@ function checkDuplicateIds(root2, conflicts) {
194040
194047
  var idMap = (nodes) => new Map(nodes.filter((n) => n.id).map((n) => [n.id, n]));
194041
194048
  var arrEq = (a, b) => a.length === b.length && a.every((x, i) => x === b[i]);
194042
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
+
194043
194056
  // ../dialect/src/index.ts
194044
194057
  function host(h) {
194045
194058
  return h.ctx.host ?? {};
@@ -194137,8 +194150,15 @@ var patterDialect = {
194137
194150
  }
194138
194151
  }
194139
194152
  };
194140
- function dialectWithForeignScopes(spec) {
194141
- 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;
194142
194162
  const known = new Set(patterDialect.scopes.map((s) => s.token));
194143
194163
  const extra = spec.scopes.filter((s) => !known.has(s.token)).map((s) => ({ token: s.token }));
194144
194164
  if (extra.length === 0) return patterDialect;
@@ -194377,7 +194397,7 @@ function compileExpression(src, foreign) {
194377
194397
  }
194378
194398
  function validateConditions(input, options = {}) {
194379
194399
  const issues = [];
194380
- const foreign = options.foreignScopes;
194400
+ const foreign = withEngineScopes(options.foreignScopes);
194381
194401
  const dialect = dialectWithForeignScopes(foreign);
194382
194402
  const readOnly = readOnlyForeignTargets(foreign);
194383
194403
  const opaqueForeign = opaqueForeignTokens(foreign);
@@ -194472,10 +194492,11 @@ function validateInterpolation(input, options = {}) {
194472
194492
  const voiced = input.project.voiced ?? false;
194473
194493
  const tables = (input.locales ?? []).map((l2) => ({ locale: l2.locale, strings: l2.strings }));
194474
194494
  const defaultLocale = input.project.locales.default;
194475
- const opaqueForeign = opaqueForeignTokens(options.foreignScopes);
194476
- const isScopeToken = scopeTokenTest(options.foreignScopes);
194495
+ const foreign = withEngineScopes(options.foreignScopes);
194496
+ const opaqueForeign = opaqueForeignTokens(foreign);
194497
+ const isScopeToken = scopeTokenTest(foreign);
194477
194498
  for (const scene of input.scenes) {
194478
- const schema = buildSchema(input.project, scene.sceneProps, options.foreignScopes);
194499
+ const schema = buildSchema(input.project, scene.sceneProps, foreign);
194479
194500
  const known = (ref) => {
194480
194501
  const { scope, name } = splitRef(ref, isScopeToken);
194481
194502
  if (opaqueForeign.has(scope)) return true;
@@ -194638,11 +194659,33 @@ function compileScene(scene, foreign) {
194638
194659
  blocks: scene.blocks.map((b) => compileBlock(b, foreign))
194639
194660
  };
194640
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
+ }
194641
194682
  function exportBundle(input) {
194642
194683
  const { project, scenes, locales = [], includeLocales } = input;
194643
194684
  const foreignScopes = input.foreignScopes ?? hostScopesToSpec(project.scopeRegistry);
194685
+ const compileScopes = withEngineScopes(foreignScopes);
194644
194686
  const scenesOut = {};
194645
- 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);
194646
194689
  const strings = {};
194647
194690
  for (const loc of locales) {
194648
194691
  if (includeLocales && !includeLocales.includes(loc.locale)) continue;
@@ -194698,7 +194741,9 @@ function exportBundle(input) {
194698
194741
  // runtime falls back to `[` / `]` when absent, so default projects keep their exact prior bundle.
194699
194742
  ...project.closedCaptions ? { closedCaptions: project.closedCaptions } : {},
194700
194743
  scenes: scenesOut,
194701
- 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 } : {}
194702
194747
  };
194703
194748
  }
194704
194749
 
@@ -195011,7 +195056,7 @@ function bundleOutputPath(loaded) {
195011
195056
  }
195012
195057
 
195013
195058
  // ../ops/src/playable-runtime.ts
195014
- 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';
195015
195060
 
195016
195061
  // ../ops/src/export-html.ts
195017
195062
  var esc = (s) => s.replace(/[&<>]/g, (c2) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;" })[c2]);
@@ -195278,6 +195323,13 @@ var PropertyBag = class _PropertyBag {
195278
195323
  get(name) {
195279
195324
  return this.values[this.norm(name)];
195280
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
+ }
195281
195333
  /** Write a property. Engine writes (the default) notify subscribers;
195282
195334
  * pass `silent: true` for a host write, which reaches only the audit
195283
195335
  * hook. Throws on a read-only property unless the caller says it is the
@@ -195361,25 +195413,82 @@ function rowFor(d, value, writable, name, pathPrefix = "") {
195361
195413
  writable: writable ?? d.writable ?? true
195362
195414
  };
195363
195415
  }
195416
+ var lowerCase = (name) => name.toLowerCase();
195364
195417
  var SAVE_FRAGMENT_VERSION = 1;
195365
195418
  var ScopeRegistry = class {
195366
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
+ }
195367
195433
  /**
195368
195434
  * Register a scope this registry **owns and stores**. Its bag is seeded from
195369
195435
  * each declaration's `default` (or a type default). Owned scopes are
195370
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.
195371
195440
  */
195372
- defineOwned(token2, declarations, pathPrefix) {
195373
- return this.mountOwned(token2, new PropertyBag(declarations, { pathPrefix: pathPrefix ?? `${token2}.` }));
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);
195374
195448
  }
195375
195449
  /**
195376
- * Attach an EXISTING bag as an owned scope - the shared-container move: a
195377
- * host (or the other product) holds the bag; this registry reads, writes
195378
- * and lists it like its own, but the holder saves it.
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.
195379
195455
  */
195380
- mountOwned(token2, bag) {
195381
- this.assertFree(token2);
195382
- this.scopes.set(token2, { kind: "owned", bag });
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.
195471
+ */
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;
195479
+ }
195480
+ /**
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.
195488
+ */
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);
195383
195492
  return this;
195384
195493
  }
195385
195494
  /** An owned scope's bag (subscribe, audit, rows live there). */
@@ -195405,11 +195514,21 @@ var ScopeRegistry = class {
195405
195514
  * `declarations` (optional, e.g. imported from a `scopeRegistrySpec`) are used
195406
195515
  * only for validation; omit them for an opaque scope.
195407
195516
  */
195408
- defineForeign(token2, resolver, declarations = [], scopeWritable = true) {
195409
- 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;
195410
195521
  const decls = /* @__PURE__ */ new Map();
195411
- for (const d of declarations) decls.set(d.name.toLowerCase(), d);
195412
- 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++;
195413
195532
  return this;
195414
195533
  }
195415
195534
  has(token2) {
@@ -195419,7 +195538,7 @@ var ScopeRegistry = class {
195419
195538
  get(scope, name) {
195420
195539
  const e = this.scopes.get(scope);
195421
195540
  if (!e) return void 0;
195422
- 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));
195423
195542
  }
195424
195543
  /** Write a property (an ENGINE write: the bag's subscribers fire; use
195425
195544
  * the bag directly for silent host writes). Throws on an unknown scope.
@@ -195441,7 +195560,7 @@ var ScopeRegistry = class {
195441
195560
  }
195442
195561
  return;
195443
195562
  }
195444
- const n = name.toLowerCase();
195563
+ const n = e.norm(name);
195445
195564
  if (!e.resolver.set) throw new Error(`'@${scope}.${name}' is read-only`);
195446
195565
  if (!opts?.host && !this.foreignWritable(e, n)) throw new Error(`'@${scope}.${name}' is read-only`);
195447
195566
  e.resolver.set(n, value);
@@ -195456,19 +195575,15 @@ var ScopeRegistry = class {
195456
195575
  listProperties() {
195457
195576
  const out = [];
195458
195577
  for (const [token2, e] of this.scopes) {
195578
+ const owner = e.owner !== void 0 ? { owner: e.owner } : {};
195459
195579
  if (e.kind === "owned") {
195460
- 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 });
195461
195581
  } else {
195462
- for (const d of e.decls.values()) {
195582
+ for (const [n, d] of e.decls) {
195463
195583
  out.push({
195464
195584
  scope: token2,
195465
- ...rowFor(
195466
- d,
195467
- e.resolver.get(d.name.toLowerCase()),
195468
- this.foreignWritable(e, d.name.toLowerCase()),
195469
- void 0,
195470
- `${token2}.`
195471
- )
195585
+ ...owner,
195586
+ ...rowFor(d, e.resolver.get(n), this.foreignWritable(e, n), n, `${token2}.`)
195472
195587
  });
195473
195588
  }
195474
195589
  }
@@ -195480,31 +195595,48 @@ var ScopeRegistry = class {
195480
195595
  * bags, foreign scopes as their resolvers. `host` carries dialect-function
195481
195596
  * callbacks (PRNG, tag lookups) and is passed through untouched.
195482
195597
  */
195483
- toEvalContext(host2) {
195598
+ toEvalContext(host2, opts) {
195599
+ const view = this.view(opts?.aliases);
195484
195600
  const scopes = {};
195485
- for (const [token2, e] of this.scopes) {
195486
- scopes[token2] = e.kind === "owned" ? e.bag.values : e.resolver;
195487
- }
195488
- 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);
195489
195603
  return qualities.size === 0 ? { scopes, host: host2 } : {
195490
195604
  scopes,
195491
195605
  host: host2,
195492
- 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
+ }
195493
195610
  };
195494
195611
  }
195495
- /** Every quality declaration's ladder, keyed scope token then name. */
195496
- 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) {
195497
195630
  const out = /* @__PURE__ */ new Map();
195498
- for (const [token2, e] of this.scopes) {
195499
- const decls = e.kind === "owned" ? e.bag.declarations() : [...e.decls.values()];
195500
- for (const d of decls) {
195631
+ for (const [token2, e] of view) {
195632
+ for (const [n, d] of declsOf(e)) {
195501
195633
  if (d.type !== "quality" || d.stages === void 0) continue;
195502
195634
  let m = out.get(token2);
195503
195635
  if (!m) {
195504
195636
  m = /* @__PURE__ */ new Map();
195505
195637
  out.set(token2, m);
195506
195638
  }
195507
- m.set(d.name.toLowerCase(), d.stages);
195639
+ m.set(n, d.stages);
195508
195640
  }
195509
195641
  }
195510
195642
  return out;
@@ -195512,15 +195644,17 @@ var ScopeRegistry = class {
195512
195644
  /**
195513
195645
  * Build the `ExpressionSchema` expr's validator consumes. Scopes with no
195514
195646
  * declarations are **omitted** (opaque - references into them are not flagged);
195515
- * 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.
195516
195650
  */
195517
- toSchema() {
195651
+ toSchema(opts) {
195518
195652
  const properties = /* @__PURE__ */ new Map();
195519
- for (const [token2, e] of this.scopes) {
195520
- 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);
195521
195655
  if (decls.length === 0) continue;
195522
195656
  const m = /* @__PURE__ */ new Map();
195523
- for (const d of decls) m.set(d.name.toLowerCase(), {
195657
+ for (const [n, d] of decls) m.set(n, {
195524
195658
  type: d.type,
195525
195659
  enumValues: d.values,
195526
195660
  ...d.stages !== void 0 ? { stages: d.stages } : {}
@@ -195529,40 +195663,78 @@ var ScopeRegistry = class {
195529
195663
  }
195530
195664
  return { properties };
195531
195665
  }
195532
- /** Serialize **owned** scopes only (foreign scopes are host-owned,
195533
- * host-saved), as bare bags - the 0.1.x shape, kept stable so existing
195534
- * consumers' save formats are untouched. A product embedding the
195535
- * 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. */
195536
195670
  save() {
195537
195671
  const out = {};
195538
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);
195539
195674
  return out;
195540
195675
  }
195541
- /** Restore owned-scope values from a `save` blob. Unknown/foreign scopes
195542
- * are ignored. */
195543
- 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();
195544
195690
  for (const [token2, vals] of Object.entries(blob)) {
195545
195691
  const e = this.scopes.get(token2);
195546
195692
  if (e?.kind === "owned") e.bag.load(vals);
195693
+ else if (!e) this.parked.set(token2, structuredClone(vals));
195547
195694
  }
195548
195695
  }
195549
- /** The versioned owned-state fragment (the one serialisation shape both
195550
- * product families' save envelopes embed when they adopt the kernel;
195551
- * 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
+ */
195552
195703
  saveFragment() {
195553
195704
  return { version: SAVE_FRAGMENT_VERSION, scopes: this.save() };
195554
195705
  }
195555
- /** 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
+ */
195556
195711
  loadFragment(fragment) {
195557
195712
  if (fragment.version !== SAVE_FRAGMENT_VERSION) {
195558
195713
  throw new Error(`unsupported owned-state fragment version ${fragment.version} (supported: ${SAVE_FRAGMENT_VERSION})`);
195559
195714
  }
195560
195715
  this.load(fragment.scopes);
195561
195716
  }
195562
- assertFree(token2) {
195563
- 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}`);
195564
195729
  }
195565
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
+ }
195566
195738
  function defaultFor(d) {
195567
195739
  if (d.default !== void 0) return d.default;
195568
195740
  switch (d.type) {
@@ -195624,6 +195796,19 @@ function buildTagIndex(bundle) {
195624
195796
 
195625
195797
  // ../runtime/src/engine.ts
195626
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
+ };
195627
195812
  var Engine = class _Engine {
195628
195813
  host;
195629
195814
  defaultSeed;
@@ -195683,18 +195868,32 @@ var Engine = class _Engine {
195683
195868
  const patterSharedDecls = props.filter((p) => p.shared ?? true).map(toDecl);
195684
195869
  const patterLocalDecls = props.filter((p) => !(p.shared ?? true)).map(toDecl);
195685
195870
  const patterSharedNames = new Set(patterSharedDecls.map((d) => d.name.toLowerCase()));
195686
- const shared = new ScopeRegistry().defineOwned("patter", patterSharedDecls, "@patter.");
195687
- const hostBound = /* @__PURE__ */ new Set();
195688
- if (options.world) {
195689
- const worldSpec = bundle.scopeRegistry?.scopes.find((s) => s.token === "world");
195690
- const decls = (worldSpec?.declarations ?? []).map(toForeignDecl);
195691
- shared.defineForeign("world", options.world, decls, worldSpec?.writable ?? true);
195692
- hostBound.add("world");
195693
- }
195694
- for (const spec of bundle.scopeRegistry?.scopes ?? []) {
195695
- if (hostBound.has(spec.token)) continue;
195696
- const decls = (spec.declarations ?? []).map(toForeignDecl);
195697
- 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;
195698
195897
  }
195699
195898
  const sceneSharedNames = /* @__PURE__ */ new Map();
195700
195899
  for (const [sceneId, scene] of Object.entries(bundle.scenes)) {
@@ -195716,7 +195915,10 @@ var Engine = class _Engine {
195716
195915
  blockGameIdToId: this.blockGameIdToId,
195717
195916
  // same instances the engine resolves with
195718
195917
  tagIndex: buildTagIndex(bundle),
195719
- shared,
195918
+ registry,
195919
+ ownsRegistry,
195920
+ patterBag,
195921
+ hostScopes,
195720
195922
  patterSharedDecls,
195721
195923
  patterLocalDecls,
195722
195924
  patterSharedNames,
@@ -195733,7 +195935,8 @@ var Engine = class _Engine {
195733
195935
  captionClose: (bundle.closedCaptions ?? DEFAULT_CAPTION_DELIMITERS).close,
195734
195936
  captionCharacter: bundle.closedCaptions?.character || DEFAULT_CAPTION_CHARACTER,
195735
195937
  // absent/empty -> SFX
195736
- refSplitCache: /* @__PURE__ */ new Map()
195938
+ refSplitCache: /* @__PURE__ */ new Map(),
195939
+ refSplitRevision: registry.revision
195737
195940
  };
195738
195941
  }
195739
195942
  /** The active locale (string + character-name lookups resolve in it). */
@@ -195778,10 +195981,12 @@ var Engine = class _Engine {
195778
195981
  * content-drift policy (§9.8) resolves edits under the cursor: stack frames re-find their next
195779
195982
  * child by id, drifted options drop, a vanished snippet is skipped.
195780
195983
  *
195781
- * Returns the REPLACEMENT engine; this one is left untouched and should be discarded. Hosts
195782
- * re-bind their flow handles via `next.getFlow(id)`. If the restore throws (defensive - §9.8
195783
- * makes this unreachable for ordinary edits), the swap falls back to a cold engine with each
195784
- * 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.
195785
195990
  */
195786
195991
  hotSwap(bundle) {
195787
195992
  const snapshot = this.saveGame();
@@ -195790,12 +195995,19 @@ var Engine = class _Engine {
195790
195995
  next2.setClosedCaptions(this.host.captionsOn);
195791
195996
  return next2;
195792
195997
  };
195793
- 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();
195794
196005
  try {
195795
196006
  next.loadGame(snapshot);
195796
196007
  return carryOver(next);
195797
196008
  } catch {
195798
- const fresh = new _Engine(bundle, this.creationOptions);
196009
+ next.release(true);
196010
+ const fresh = make();
195799
196011
  for (const [id, f] of Object.entries(snapshot.flows)) {
195800
196012
  const sceneId = f.cursor.currentSceneId;
195801
196013
  try {
@@ -195834,6 +196046,7 @@ var Engine = class _Engine {
195834
196046
  * call to reach for when you want a speaker's variation state to carry on.
195835
196047
  */
195836
196048
  openFlow(id, opts = {}) {
196049
+ this.assertExternalScopes();
195837
196050
  const sceneId = this.resolveSceneRef(opts.scene);
195838
196051
  const blockId = this.resolveBlockRef(sceneId, opts.block);
195839
196052
  this.flowsById.get(id)?.close();
@@ -195873,6 +196086,17 @@ var Engine = class _Engine {
195873
196086
  }
195874
196087
  return existing.advanceToStop().played;
195875
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
+ }
195876
196100
  /** Resolve a scene reference (a gameId address OR an internal id) to its internal id. */
195877
196101
  resolveSceneRef(ref) {
195878
196102
  if (ref == null) return void 0;
@@ -196058,7 +196282,7 @@ var Engine = class _Engine {
196058
196282
  * loadGame() replaces every bag, so re-enumerate after a load.
196059
196283
  */
196060
196284
  listBags() {
196061
- const mounts = [{ bag: this.host.shared.ownedBag("patter") }];
196285
+ const mounts = [{ bag: this.host.patterBag }];
196062
196286
  for (const [sceneId, bag] of this.host.stageBags) mounts.push({ bag, pathPrefix: `@scene:${sceneId}.` });
196063
196287
  return mounts;
196064
196288
  }
@@ -196077,15 +196301,31 @@ var Engine = class _Engine {
196077
196301
  reset() {
196078
196302
  for (const flow of this.flowsById.values()) flow.close();
196079
196303
  this.flowsById.clear();
196080
- this.host.shared.reseedOwned("patter", this.host.patterSharedDecls);
196304
+ this.host.patterBag.reseed(this.host.patterSharedDecls);
196081
196305
  this.host.sharedVisits.clear();
196082
196306
  this.host.sharedSelectors.clear();
196307
+ for (const s of this.host.stageBags.keys()) this.host.registry.remove(keys.stage(s));
196083
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");
196084
196324
  }
196085
196325
  /** Read a shared (`@patter` / foreign) property by ref. `@scene` refs are rejected (flow-level). */
196086
196326
  getProperty(ref) {
196087
196327
  const { scope, name } = this.splitShared(ref);
196088
- return this.host.shared.get(scope, name);
196328
+ return this.host.registry.get(scope, name);
196089
196329
  }
196090
196330
  /** Write a shared (`@patter` / foreign) property by ref. `@scene` refs are rejected (flow-level).
196091
196331
  *
@@ -196096,7 +196336,7 @@ var Engine = class _Engine {
196096
196336
  * were each refused the one property they existed to move.) */
196097
196337
  setProperty(ref, value) {
196098
196338
  const { scope, name } = this.splitShared(ref);
196099
- this.host.shared.set(scope, name, value, { host: true });
196339
+ this.host.registry.set(scope, name, value, { host: true });
196100
196340
  }
196101
196341
  /** The shared `@patter` properties, for a live state inspector: each with its ref, type, current
196102
196342
  * value, declared default (for reset), and enum options. Mirrors the Unity / Godot ports. */
@@ -196143,54 +196383,66 @@ var Engine = class _Engine {
196143
196383
  // @scene is scene-namespaced and needs a flow's current scene - silently
196144
196384
  // routing it into the shared bag (as a junk "scene.x" key) was a trap.
196145
196385
  splitShared(ref) {
196146
- let split = this.host.refSplitCache.get(ref);
196147
- if (!split) {
196148
- split = splitRef(ref, (t) => t === "scene" || this.host.shared.has(t));
196149
- this.host.refSplitCache.set(ref, split);
196150
- }
196386
+ const split = splitHostRef(this.host, ref);
196151
196387
  if (split.scope === "scene") {
196152
196388
  throw new Error(`'${ref}': @scene properties are scene-scoped - read/write them on a Flow, not the Engine`);
196153
196389
  }
196154
196390
  return split;
196155
196391
  }
196156
- /** 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. */
196157
196395
  save() {
196158
- return this.host.shared.save();
196396
+ return { patter: this.host.patterBag.save() };
196159
196397
  }
196160
- /** 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. */
196161
196400
  load(blob) {
196162
- this.host.shared.load(blob);
196401
+ if (blob.patter) this.host.patterBag.load(blob.patter);
196163
196402
  }
196164
- /** 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()`. */
196165
196407
  saveGame() {
196166
196408
  const flows = {};
196167
196409
  for (const [id, flow] of this.flowsById) flows[id] = flow.snapshot();
196168
196410
  return {
196169
- version: 2,
196170
- shared: this.host.shared.save(),
196411
+ version: SAVE_VERSION,
196412
+ ...this.host.ownsRegistry ? { registry: this.host.registry.save() } : {},
196171
196413
  sharedVisits: Object.fromEntries(this.host.sharedVisits),
196172
196414
  sharedSelectors: serialiseSelectors(this.host.sharedSelectors),
196173
- stageBags: Object.fromEntries([...this.host.stageBags].map(([s, bag]) => [s, bag.save()])),
196174
196415
  flows
196175
196416
  };
196176
196417
  }
196177
- /** 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
+ */
196178
196425
  loadGame(save) {
196179
- if (save.version !== 2) throw new Error(`unsupported save version: ${save.version}`);
196180
- 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
+ }
196181
196442
  this.host.sharedVisits.clear();
196182
196443
  for (const [id, n] of Object.entries(save.sharedVisits ?? {})) this.host.sharedVisits.set(id, n);
196183
196444
  this.host.sharedSelectors.clear();
196184
196445
  for (const [id, st] of deserialiseSelectors(save.sharedSelectors)) this.host.sharedSelectors.set(id, st);
196185
- this.host.stageBags.clear();
196186
- for (const [s, values] of Object.entries(save.stageBags ?? {})) {
196187
- const shared = this.host.sceneSharedNames.get(s) ?? /* @__PURE__ */ new Set();
196188
- const decls = (this.host.bundle.scenes[s]?.sceneProps ?? []).filter((d) => shared.has(d.name.toLowerCase()));
196189
- const bag = new PropertyBag(decls);
196190
- bag.load(values);
196191
- this.host.stageBags.set(s, bag);
196192
- }
196193
- this.flowsById.clear();
196194
196446
  for (const [id, snap] of Object.entries(save.flows)) {
196195
196447
  const flow = new Flow(id, this.host, this.defaultSeed);
196196
196448
  flow.restore(snap);
@@ -196202,7 +196454,9 @@ var Flow = class {
196202
196454
  id;
196203
196455
  host;
196204
196456
  local;
196205
- // 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();
196206
196460
  rngState;
196207
196461
  // Execution cursor. The `stack` is the continuation stack: each frame is a
196208
196462
  // position within a block's children (the top frame is the active block run;
@@ -196227,40 +196481,44 @@ var Flow = class {
196227
196481
  /** Per-node entry counts for this flow (node id -> times entered). */
196228
196482
  visitCounts = /* @__PURE__ */ new Map();
196229
196483
  // Per-flow halves of the two scopes. The NOT-shared `@patter` globals live in
196230
- // `local` (owned scope "patter"); the NOT-shared `@scene` props live in
196231
- // `sceneBags` (namespaced per scene; they PERSIST across re-entries, spec §7).
196232
- // The SHARED halves live on the host (`host.shared` / `host.stageBags`). Each
196233
- // resolver presents one merged scope, routing each property to its half by the
196234
- // 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.
196235
196490
  /** This flow's per-scene LOCAL scene props; see FlowHost.stageBags. */
196236
196491
  sceneBags = /* @__PURE__ */ new Map();
196237
196492
  patterResolver = {
196238
- 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),
196239
196494
  set: (n, v) => {
196240
- if (this.host.patterSharedNames.has(n)) this.host.shared.set("patter", n, v);
196241
- 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);
196242
196497
  }
196243
196498
  };
196244
196499
  sceneResolver = {
196245
196500
  get: (n) => {
196246
196501
  const s = this.currentSceneId;
196247
196502
  if (s === null) return void 0;
196248
- const bag = this.host.sceneSharedNames.get(s)?.has(n) ? this.host.stageBags.get(s) : this.sceneBags.get(s);
196249
- return bag?.get(n);
196503
+ return this.sceneBagFor(s, n)?.get(n);
196250
196504
  },
196251
196505
  set: (n, v) => {
196252
196506
  const s = this.currentSceneId;
196253
196507
  if (s === null) return;
196254
- 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);
196255
196509
  if (bag) bag.set(n, v);
196256
196510
  }
196257
196511
  };
196258
- // The eval context is built ONCE: every constituent resolves live state at
196259
- // call time (shared bags mutate in place per scoperegistry's contract;
196260
- // patter/scene route through this flow's resolvers, which read the current
196261
- // `local`/`sceneBags`/`currentSceneId`; the host callbacks read current flow
196262
- // 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.
196263
196519
  evalCtx;
196520
+ ctxRevision = -1;
196521
+ registryQualities;
196264
196522
  flowLog = [];
196265
196523
  /** Monotonic across the flow's life; survives clearLog so two reads agree on order. */
196266
196524
  flowSeq = 0;
@@ -196268,12 +196526,9 @@ var Flow = class {
196268
196526
  this.id = id;
196269
196527
  this.host = host2;
196270
196528
  this.rngState = toUint32(seed);
196271
- this.local = this.freshLocal();
196272
- const scopes = { ...host2.shared.toEvalContext().scopes };
196273
- scopes["patter"] = this.patterResolver;
196274
- scopes["scene"] = this.sceneResolver;
196529
+ this.local = this.newLocal();
196275
196530
  this.evalCtx = {
196276
- scopes,
196531
+ scopes: {},
196277
196532
  host: {
196278
196533
  nextRandom: this.rng,
196279
196534
  visits: (id2) => this.visitCounts.get(id2) ?? 0,
@@ -196286,6 +196541,21 @@ var Flow = class {
196286
196541
  qualities: (scope, name) => this.stagesFor(scope, name)
196287
196542
  };
196288
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
+ }
196289
196559
  /** The stage ladder of `@scope.name` when it is a declared quality, else undefined. Names compare
196290
196560
  * lowercase, as the compiler emits references (the selfBackedResolver lesson). */
196291
196561
  stagesFor(scope, name) {
@@ -196298,13 +196568,14 @@ var Flow = class {
196298
196568
  const scene = this.currentSceneId != null ? this.host.bundle.scenes[this.currentSceneId] : void 0;
196299
196569
  return fromDecls(scene?.sceneProps);
196300
196570
  }
196301
- 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);
196302
196572
  }
196303
196573
  // -- Host API -------------------------------------------------------------
196304
196574
  /** Begin this flow at a scene (and optionally a specific block within it). */
196305
196575
  start(sceneId, blockId) {
196306
- this.sceneBags.clear();
196307
- this.local = this.freshLocal();
196576
+ this.releaseBags(false);
196577
+ this.host.registry.discardParked(keys.flow(this.id));
196578
+ this.mountLocal();
196308
196579
  this.selectors.clear();
196309
196580
  this.visitCounts.clear();
196310
196581
  this.stack = [];
@@ -196404,6 +196675,7 @@ var Flow = class {
196404
196675
  * cannot quietly mutate the world. Terminal: unlike ending, a close is never revived.
196405
196676
  */
196406
196677
  close() {
196678
+ this.releaseBags(false);
196407
196679
  this.closed = true;
196408
196680
  this.flowEnded = true;
196409
196681
  this.stack = [];
@@ -196513,7 +196785,7 @@ var Flow = class {
196513
196785
  * halves are the Engine's listBags.
196514
196786
  */
196515
196787
  listBags() {
196516
- const mounts = [{ bag: this.local.ownedBag("patter"), pathPrefix: `${this.id}/@patter.` }];
196788
+ const mounts = [{ bag: this.local, pathPrefix: `${this.id}/@patter.` }];
196517
196789
  for (const [sceneId, bag] of this.sceneBags) mounts.push({ bag, pathPrefix: `${this.id}/@scene:${sceneId}.` });
196518
196790
  return mounts;
196519
196791
  }
@@ -196561,7 +196833,7 @@ var Flow = class {
196561
196833
  const { scope, name } = this.splitRef(ref);
196562
196834
  if (scope === "patter") return this.patterResolver.get(name);
196563
196835
  if (scope === "scene") return this.sceneResolver.get(name);
196564
- return this.host.shared.get(scope, name);
196836
+ return this.host.registry.get(scope, name);
196565
196837
  }
196566
196838
  /** Write a property by ref (routed by scope, then by the property's `shared` flag). The GAME's
196567
196839
  * surface: it writes with host authority, so a `writable: false` host declaration does not refuse
@@ -196579,16 +196851,13 @@ var Flow = class {
196579
196851
  if (this.currentSceneId === null) throw new Error(`'${ref}': the flow has not entered a scene yet`);
196580
196852
  this.sceneResolver.set(name, value);
196581
196853
  } else {
196582
- 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);
196583
196855
  }
196584
196856
  }
196585
196857
  // -- Save / restore (engine-driven) --------------------------------------
196586
- /** @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. */
196587
196859
  snapshot() {
196588
196860
  return {
196589
- scopes: this.local.save(),
196590
- // owned scope "patter" = the NOT-shared globals (@scene saved separately)
196591
- sceneBags: Object.fromEntries([...this.sceneBags].map(([s, bag]) => [s, bag.save()])),
196592
196861
  rngState: this.rngState,
196593
196862
  visits: Object.fromEntries(this.visitCounts),
196594
196863
  cursor: {
@@ -196626,15 +196895,11 @@ var Flow = class {
196626
196895
  }
196627
196896
  return { ...frame };
196628
196897
  });
196629
- this.sceneBags = new Map(Object.entries(snap.sceneBags ?? {}).map(([s, values]) => {
196630
- const shared = this.host.sceneSharedNames.get(s) ?? /* @__PURE__ */ new Set();
196631
- const decls = (this.host.bundle.scenes[s]?.sceneProps ?? []).filter((d) => !shared.has(d.name.toLowerCase()));
196632
- const bag = new PropertyBag(decls);
196633
- bag.load(values);
196634
- return [s, bag];
196635
- }));
196636
- this.local = this.freshLocal();
196637
- 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
+ }
196638
196903
  this.activeSnippet = null;
196639
196904
  if (c2.activeSnippetId !== null) {
196640
196905
  const node = this.host.nodeIndex.get(c2.activeSnippetId);
@@ -196905,7 +197170,7 @@ var Flow = class {
196905
197170
  * node (comparisons, scoped vars, literals, other calls) is an atom, evaluated whole.
196906
197171
  */
196907
197172
  matchedSpec(node, want) {
196908
- const evalTruthy = (n) => truthy(evaluate(n, this.evalCtx, patterDialect));
197173
+ const evalTruthy = (n) => truthy(evaluate(n, this.context(), patterDialect));
196909
197174
  return matchedSpecificity(node, evalTruthy, { want });
196910
197175
  }
196911
197176
  /** A selector's cursor state - shared across flows (`group.shared`) or this flow's own. */
@@ -196932,7 +197197,7 @@ var Flow = class {
196932
197197
  return truthy(this.evalExpr(node.condition));
196933
197198
  }
196934
197199
  evalExpr(expr) {
196935
- return evaluate(this.conditionAst(expr), this.evalCtx, patterDialect);
197200
+ return evaluate(this.conditionAst(expr), this.context(), patterDialect);
196936
197201
  }
196937
197202
  /** The deserialised (in-memory) AST for an expression, cached per Expression. Shared by the
196938
197203
  * evaluator and the Best-match specificity walker so both work off one parse. */
@@ -197057,18 +197322,51 @@ var Flow = class {
197057
197322
  const key2 = castStringKey(character);
197058
197323
  return this.host.strings[key2] ?? this.host.defaultStrings[key2] ?? this.host.castDisplay.get(character);
197059
197324
  }
197060
- /** 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`). */
197061
197326
  splitRef(ref) {
197062
- let hit = this.host.refSplitCache.get(ref);
197063
- if (!hit) {
197064
- hit = splitRef(ref, (t) => t === "scene" || this.host.shared.has(t));
197065
- this.host.refSplitCache.set(ref, hit);
197066
- }
197067
- 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();
197068
197346
  }
197069
- /** The per-flow registry: the NOT-shared `@patter` globals (the shared ones live on the host). */
197070
- freshLocal() {
197071
- 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
+ }
197072
197370
  }
197073
197371
  /**
197074
197372
  * Seed a scene's `@scene` props (spec §7). The not-shared props seed THIS flow's
@@ -197079,13 +197377,7 @@ var Flow = class {
197079
197377
  */
197080
197378
  seedScene(scene) {
197081
197379
  const shared = this.host.sceneSharedNames.get(scene.id) ?? /* @__PURE__ */ new Set();
197082
- const props = scene.sceneProps ?? [];
197083
- if (!this.sceneBags.has(scene.id)) {
197084
- this.sceneBags.set(scene.id, new PropertyBag(props.filter((d) => !shared.has(d.name.toLowerCase()))));
197085
- }
197086
- if (!this.host.stageBags.has(scene.id)) {
197087
- this.host.stageBags.set(scene.id, new PropertyBag(props.filter((d) => shared.has(d.name.toLowerCase()))));
197088
- }
197380
+ this.ensureSceneBags(scene.id);
197089
197381
  for (const decl of scene.sceneProps ?? []) {
197090
197382
  if (!decl.temporary) continue;
197091
197383
  const name = decl.name.toLowerCase();
@@ -197131,16 +197423,32 @@ function toDecl(decl) {
197131
197423
  function toForeignDecl(decl) {
197132
197424
  return { name: decl.name, type: decl.type, values: decl.values, stages: decl.stages, default: decl.default, writable: decl.writable };
197133
197425
  }
197134
- function selfBackedResolver(decls) {
197135
- const key2 = (name) => name.toLowerCase();
197136
- const bag = /* @__PURE__ */ new Map();
197137
- for (const d of decls) bag.set(key2(d.name), defaultFor(d));
197138
- return {
197139
- get: (name) => bag.get(key2(name)),
197140
- set: (name, value) => {
197141
- bag.set(key2(name), value);
197142
- }
197143
- };
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;
197144
197452
  }
197145
197453
  function truthy(v) {
197146
197454
  if (typeof v === "boolean") return v;
@@ -198535,10 +198843,6 @@ function colourIndex(name) {
198535
198843
  function characterColour(name) {
198536
198844
  return CHAR_PALETTE[colourIndex(name)];
198537
198845
  }
198538
- var VISIT_FN_RE = /\b(patter_visits|patter_seen|visits|seen)\s*\(\s*(['"])(.*?)\2\s*\)/g;
198539
- function humanizeCondition(cond, label) {
198540
- return cond.replace(VISIT_FN_RE, (_m, fn, _q, id) => `${fn}(${label(id)})`);
198541
- }
198542
198846
  var MARKUP_RE = /<(b|i|bi)>([\s\S]*?)<\/\1>/g;
198543
198847
  var INTERP_RE = /\{@[^}]*\}/g;
198544
198848
  function textRuns(text) {
@@ -198613,7 +198917,7 @@ function runScriptDoc(loaded) {
198613
198917
  blockName.set(block.id, block.name);
198614
198918
  }
198615
198919
  }
198616
- const humanize = (cond) => humanizeCondition(cond, (id) => blockName.get(id) ?? sceneOf.get(id) ?? id);
198920
+ const humanize = (cond) => humanizeNodeRefs(cond, (id) => blockName.get(id) ?? sceneOf.get(id) ?? id);
198617
198921
  const els = [];
198618
198922
  const textOf = (id) => source2[id] ?? "";
198619
198923
  const jumpText = (j) => {
@@ -198710,8 +199014,8 @@ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
198710
199014
  var __esmMin = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
198711
199015
  var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
198712
199016
  var __copyProps2 = (to, from, except, desc) => {
198713
- if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames2(from), i = 0, n = keys.length, key2; i < n; i++) {
198714
- 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];
198715
199019
  if (!__hasOwnProp2.call(to, key2) && key2 !== except) __defProp2(to, key2, {
198716
199020
  get: ((k) => from[k]).bind(null, key2),
198717
199021
  enumerable: !(desc = __getOwnPropDesc2(from, key2)) || desc.enumerable
@@ -199167,10 +199471,10 @@ var require_events = /* @__PURE__ */ __commonJSMin(((exports2, module2) => {
199167
199471
  return this;
199168
199472
  }
199169
199473
  if (arguments.length === 0) {
199170
- var keys = Object.keys(events);
199474
+ var keys2 = Object.keys(events);
199171
199475
  var key2;
199172
- for (i = 0; i < keys.length; ++i) {
199173
- key2 = keys[i];
199476
+ for (i = 0; i < keys2.length; ++i) {
199477
+ key2 = keys2[i];
199174
199478
  if (key2 === "removeListener") continue;
199175
199479
  this.removeAllListeners(key2);
199176
199480
  }
@@ -201783,9 +202087,9 @@ var require_isBufferBrowser = /* @__PURE__ */ __commonJSMin(((exports2, module2)
201783
202087
  var require_util5 = /* @__PURE__ */ __commonJSMin(((exports2) => {
201784
202088
  init_dist();
201785
202089
  var getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors || function getOwnPropertyDescriptors2(obj2) {
201786
- var keys = Object.keys(obj2);
202090
+ var keys2 = Object.keys(obj2);
201787
202091
  var descriptors = {};
201788
- 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]);
201789
202093
  return descriptors;
201790
202094
  };
201791
202095
  var formatRegExp = /%[sdj%]/g;
@@ -201921,11 +202225,11 @@ var require_util5 = /* @__PURE__ */ __commonJSMin(((exports2) => {
201921
202225
  }
201922
202226
  var primitive = formatPrimitive(ctx, value);
201923
202227
  if (primitive) return primitive;
201924
- var keys = Object.keys(value);
201925
- var visibleKeys = arrayToHash(keys);
201926
- if (ctx.showHidden) keys = Object.getOwnPropertyNames(value);
201927
- if (isError2(value) && (keys.indexOf("message") >= 0 || keys.indexOf("description") >= 0)) return formatError(value);
201928
- 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) {
201929
202233
  if (isFunction(value)) {
201930
202234
  var name = value.name ? ": " + value.name : "";
201931
202235
  return ctx.stylize("[Function" + name + "]", "special");
@@ -201943,13 +202247,13 @@ var require_util5 = /* @__PURE__ */ __commonJSMin(((exports2) => {
201943
202247
  if (isRegExp(value)) base = " " + RegExp.prototype.toString.call(value);
201944
202248
  if (isDate(value)) base = " " + Date.prototype.toUTCString.call(value);
201945
202249
  if (isError2(value)) base = " " + formatError(value);
201946
- 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];
201947
202251
  if (recurseTimes < 0) if (isRegExp(value)) return ctx.stylize(RegExp.prototype.toString.call(value), "regexp");
201948
202252
  else return ctx.stylize("[Object]", "special");
201949
202253
  ctx.seen.push(value);
201950
202254
  var output;
201951
- if (array) output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
201952
- else output = keys.map(function(key2) {
202255
+ if (array) output = formatArray(ctx, value, recurseTimes, visibleKeys, keys2);
202256
+ else output = keys2.map(function(key2) {
201953
202257
  return formatProperty(ctx, value, recurseTimes, visibleKeys, key2, array);
201954
202258
  });
201955
202259
  ctx.seen.pop();
@@ -201968,11 +202272,11 @@ var require_util5 = /* @__PURE__ */ __commonJSMin(((exports2) => {
201968
202272
  function formatError(value) {
201969
202273
  return "[" + Error.prototype.toString.call(value) + "]";
201970
202274
  }
201971
- function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
202275
+ function formatArray(ctx, value, recurseTimes, visibleKeys, keys2) {
201972
202276
  var output = [];
201973
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));
201974
202278
  else output.push("");
201975
- keys.forEach(function(key2) {
202279
+ keys2.forEach(function(key2) {
201976
202280
  if (!key2.match(/^\d+$/)) output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, key2, true));
201977
202281
  });
201978
202282
  return output;
@@ -202115,9 +202419,9 @@ var require_util5 = /* @__PURE__ */ __commonJSMin(((exports2) => {
202115
202419
  exports2.inherits = require_inherits_browser2();
202116
202420
  exports2._extend = function(origin, add) {
202117
202421
  if (!add || !isObject3(add)) return origin;
202118
- var keys = Object.keys(add);
202119
- var i = keys.length;
202120
- 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]];
202121
202425
  return origin;
202122
202426
  };
202123
202427
  function hasOwnProperty(obj2, prop) {
@@ -202199,14 +202503,14 @@ var require_util5 = /* @__PURE__ */ __commonJSMin(((exports2) => {
202199
202503
  }));
202200
202504
  var require_buffer_list2 = /* @__PURE__ */ __commonJSMin(((exports2, module2) => {
202201
202505
  function ownKeys2(object, enumerableOnly) {
202202
- var keys = Object.keys(object);
202506
+ var keys2 = Object.keys(object);
202203
202507
  if (Object.getOwnPropertySymbols) {
202204
202508
  var symbols = Object.getOwnPropertySymbols(object);
202205
202509
  enumerableOnly && (symbols = symbols.filter(function(sym) {
202206
202510
  return Object.getOwnPropertyDescriptor(object, sym).enumerable;
202207
- })), keys.push.apply(keys, symbols);
202511
+ })), keys2.push.apply(keys2, symbols);
202208
202512
  }
202209
- return keys;
202513
+ return keys2;
202210
202514
  }
202211
202515
  function _objectSpread(target) {
202212
202516
  for (var i = 1; i < arguments.length; i++) {
@@ -203054,17 +203358,17 @@ var require__stream_writable = /* @__PURE__ */ __commonJSMin(((exports2, module2
203054
203358
  var require__stream_duplex = /* @__PURE__ */ __commonJSMin(((exports2, module2) => {
203055
203359
  init_dist();
203056
203360
  var objectKeys = Object.keys || function(obj2) {
203057
- var keys2 = [];
203058
- for (var key2 in obj2) keys2.push(key2);
203059
- return keys2;
203361
+ var keys3 = [];
203362
+ for (var key2 in obj2) keys3.push(key2);
203363
+ return keys3;
203060
203364
  };
203061
203365
  module2.exports = Duplex;
203062
203366
  var Readable = require__stream_readable();
203063
203367
  var Writable = require__stream_writable();
203064
203368
  require_inherits_browser2()(Duplex, Readable);
203065
- var keys = objectKeys(Writable.prototype);
203066
- for (var v = 0; v < keys.length; v++) {
203067
- var method = keys[v];
203369
+ var keys2 = objectKeys(Writable.prototype);
203370
+ for (var v = 0; v < keys2.length; v++) {
203371
+ var method = keys2[v];
203068
203372
  if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];
203069
203373
  }
203070
203374
  function Duplex(options) {
@@ -217471,12 +217775,12 @@ var Bitfield = class extends Base {
217471
217775
  size() {
217472
217776
  return this.type.size();
217473
217777
  }
217474
- encode(stream2, keys) {
217778
+ encode(stream2, keys2) {
217475
217779
  let val = 0;
217476
217780
  for (let i = 0; i < this.flags.length; i++) {
217477
217781
  const flag = this.flags[i];
217478
217782
  if (flag != null) {
217479
- if (keys[flag]) {
217783
+ if (keys2[flag]) {
217480
217784
  val |= 1 << i;
217481
217785
  }
217482
217786
  }
@@ -238873,8 +239177,8 @@ function parsePropertyQuery(query) {
238873
239177
  if (!m) return null;
238874
239178
  const prop = m[1];
238875
239179
  const value = m[2].replace(/^[\s=<>!]+/, "").replace(/^["']|["']$/g, "").trim().toLowerCase() || void 0;
238876
- const esc2 = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
238877
- 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")];
238878
239182
  return { regexes, value };
238879
239183
  }
238880
239184
  var indexCache = null;
@@ -240969,7 +241273,7 @@ function writeTextFiles(files, encoding = "utf8") {
240969
241273
  // package.json
240970
241274
  var package_default = {
240971
241275
  name: "@patterkit/cli",
240972
- version: "0.3.7",
241276
+ version: "0.3.9",
240973
241277
  description: "The `patter` CLI: validate, format, export, and play a Patter project.",
240974
241278
  type: "module",
240975
241279
  license: "MIT",
@@ -240998,8 +241302,8 @@ var package_default = {
240998
241302
  "build:standalone:others": "node scripts/build-standalone.mjs --targets=linux-x64,linux-arm64,windows-x64"
240999
241303
  },
241000
241304
  dependencies: {
241001
- "@patterkit/core": "0.2.3",
241002
- "@patterkit/ops": "0.7.5",
241305
+ "@patterkit/core": "0.2.5",
241306
+ "@patterkit/ops": "0.7.7",
241003
241307
  "@wildwinter/simple-vc-lib": "^0.4.1"
241004
241308
  }
241005
241309
  };