wildcrane-runner 0.6.0 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/runner.mjs CHANGED
@@ -1,4 +1,4 @@
1
- // wildcrane-runner 0.6.0 — built by runner/scripts/build.mjs. Do not edit.
1
+ // wildcrane-runner 0.6.2 — built by runner/scripts/build.mjs. Do not edit.
2
2
  import { createRequire as __ai4kanbanRequire } from 'node:module'
3
3
  const require = __ai4kanbanRequire(import.meta.url)
4
4
  var __create = Object.create;
@@ -28,9 +28,9 @@ var __commonJS = (cb, mod) => function __require2() {
28
28
  throw mod = 0, e2;
29
29
  }
30
30
  };
31
- var __export = (target, all2) => {
32
- for (var name in all2)
33
- __defProp(target, name, { get: all2[name], enumerable: true });
31
+ var __export = (target, all) => {
32
+ for (var name in all)
33
+ __defProp(target, name, { get: all[name], enumerable: true });
34
34
  };
35
35
  var __copyProps = (to, from, except, desc) => {
36
36
  if (from && typeof from === "object" || typeof from === "function") {
@@ -49,9 +49,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
49
49
  mod
50
50
  ));
51
51
 
52
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react/cjs/react.production.js
52
+ // ../../rel54-runner-deps/node_modules/react/cjs/react.production.js
53
53
  var require_react_production = __commonJS({
54
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react/cjs/react.production.js"(exports) {
54
+ "../../rel54-runner-deps/node_modules/react/cjs/react.production.js"(exports) {
55
55
  "use strict";
56
56
  var REACT_ELEMENT_TYPE = /* @__PURE__ */ Symbol.for("react.transitional.element");
57
57
  var REACT_PORTAL_TYPE = /* @__PURE__ */ Symbol.for("react.portal");
@@ -501,9 +501,9 @@ var require_react_production = __commonJS({
501
501
  }
502
502
  });
503
503
 
504
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react/cjs/react.development.js
504
+ // ../../rel54-runner-deps/node_modules/react/cjs/react.development.js
505
505
  var require_react_development = __commonJS({
506
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react/cjs/react.development.js"(exports, module) {
506
+ "../../rel54-runner-deps/node_modules/react/cjs/react.development.js"(exports, module) {
507
507
  "use strict";
508
508
  "production" !== process.env.NODE_ENV && (function() {
509
509
  function defineDeprecationWarning(methodName, info) {
@@ -1498,9 +1498,9 @@ var require_react_development = __commonJS({
1498
1498
  }
1499
1499
  });
1500
1500
 
1501
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react/index.js
1501
+ // ../../rel54-runner-deps/node_modules/react/index.js
1502
1502
  var require_react = __commonJS({
1503
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react/index.js"(exports, module) {
1503
+ "../../rel54-runner-deps/node_modules/react/index.js"(exports, module) {
1504
1504
  "use strict";
1505
1505
  if (process.env.NODE_ENV === "production") {
1506
1506
  module.exports = require_react_production();
@@ -1510,9 +1510,9 @@ var require_react = __commonJS({
1510
1510
  }
1511
1511
  });
1512
1512
 
1513
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react/cjs/react-jsx-runtime.production.js
1513
+ // ../../rel54-runner-deps/node_modules/react/cjs/react-jsx-runtime.production.js
1514
1514
  var require_react_jsx_runtime_production = __commonJS({
1515
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react/cjs/react-jsx-runtime.production.js"(exports) {
1515
+ "../../rel54-runner-deps/node_modules/react/cjs/react-jsx-runtime.production.js"(exports) {
1516
1516
  "use strict";
1517
1517
  var REACT_ELEMENT_TYPE = /* @__PURE__ */ Symbol.for("react.transitional.element");
1518
1518
  var REACT_FRAGMENT_TYPE = /* @__PURE__ */ Symbol.for("react.fragment");
@@ -1540,9 +1540,9 @@ var require_react_jsx_runtime_production = __commonJS({
1540
1540
  }
1541
1541
  });
1542
1542
 
1543
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react/cjs/react-jsx-runtime.development.js
1543
+ // ../../rel54-runner-deps/node_modules/react/cjs/react-jsx-runtime.development.js
1544
1544
  var require_react_jsx_runtime_development = __commonJS({
1545
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react/cjs/react-jsx-runtime.development.js"(exports) {
1545
+ "../../rel54-runner-deps/node_modules/react/cjs/react-jsx-runtime.development.js"(exports) {
1546
1546
  "use strict";
1547
1547
  "production" !== process.env.NODE_ENV && (function() {
1548
1548
  function getComponentNameFromType(type) {
@@ -1811,9 +1811,9 @@ var require_react_jsx_runtime_development = __commonJS({
1811
1811
  }
1812
1812
  });
1813
1813
 
1814
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react/jsx-runtime.js
1814
+ // ../../rel54-runner-deps/node_modules/react/jsx-runtime.js
1815
1815
  var require_jsx_runtime = __commonJS({
1816
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react/jsx-runtime.js"(exports, module) {
1816
+ "../../rel54-runner-deps/node_modules/react/jsx-runtime.js"(exports, module) {
1817
1817
  "use strict";
1818
1818
  if (process.env.NODE_ENV === "production") {
1819
1819
  module.exports = require_react_jsx_runtime_production();
@@ -1823,9 +1823,9 @@ var require_jsx_runtime = __commonJS({
1823
1823
  }
1824
1824
  });
1825
1825
 
1826
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-dom/cjs/react-dom.production.js
1826
+ // ../../rel54-runner-deps/node_modules/react-dom/cjs/react-dom.production.js
1827
1827
  var require_react_dom_production = __commonJS({
1828
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-dom/cjs/react-dom.production.js"(exports) {
1828
+ "../../rel54-runner-deps/node_modules/react-dom/cjs/react-dom.production.js"(exports) {
1829
1829
  "use strict";
1830
1830
  var React4 = require_react();
1831
1831
  function formatProdErrorMessage(code) {
@@ -1980,9 +1980,9 @@ var require_react_dom_production = __commonJS({
1980
1980
  }
1981
1981
  });
1982
1982
 
1983
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-dom/cjs/react-dom.development.js
1983
+ // ../../rel54-runner-deps/node_modules/react-dom/cjs/react-dom.development.js
1984
1984
  var require_react_dom_development = __commonJS({
1985
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-dom/cjs/react-dom.development.js"(exports) {
1985
+ "../../rel54-runner-deps/node_modules/react-dom/cjs/react-dom.development.js"(exports) {
1986
1986
  "use strict";
1987
1987
  "production" !== process.env.NODE_ENV && (function() {
1988
1988
  function noop() {
@@ -2235,9 +2235,9 @@ var require_react_dom_development = __commonJS({
2235
2235
  }
2236
2236
  });
2237
2237
 
2238
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-dom/index.js
2238
+ // ../../rel54-runner-deps/node_modules/react-dom/index.js
2239
2239
  var require_react_dom = __commonJS({
2240
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-dom/index.js"(exports, module) {
2240
+ "../../rel54-runner-deps/node_modules/react-dom/index.js"(exports, module) {
2241
2241
  "use strict";
2242
2242
  function checkDCE() {
2243
2243
  if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === "undefined" || typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE !== "function") {
@@ -2261,9 +2261,9 @@ var require_react_dom = __commonJS({
2261
2261
  }
2262
2262
  });
2263
2263
 
2264
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-dom/cjs/react-dom-server-legacy.node.production.js
2264
+ // ../../rel54-runner-deps/node_modules/react-dom/cjs/react-dom-server-legacy.node.production.js
2265
2265
  var require_react_dom_server_legacy_node_production = __commonJS({
2266
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-dom/cjs/react-dom-server-legacy.node.production.js"(exports) {
2266
+ "../../rel54-runner-deps/node_modules/react-dom/cjs/react-dom-server-legacy.node.production.js"(exports) {
2267
2267
  "use strict";
2268
2268
  var React4 = require_react();
2269
2269
  var ReactDOM = require_react_dom();
@@ -7512,9 +7512,9 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
7512
7512
  }
7513
7513
  });
7514
7514
 
7515
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-dom/cjs/react-dom-server.node.production.js
7515
+ // ../../rel54-runner-deps/node_modules/react-dom/cjs/react-dom-server.node.production.js
7516
7516
  var require_react_dom_server_node_production = __commonJS({
7517
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-dom/cjs/react-dom-server.node.production.js"(exports) {
7517
+ "../../rel54-runner-deps/node_modules/react-dom/cjs/react-dom-server.node.production.js"(exports) {
7518
7518
  "use strict";
7519
7519
  var util = __require("util");
7520
7520
  var crypto5 = __require("crypto");
@@ -13686,9 +13686,9 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
13686
13686
  }
13687
13687
  });
13688
13688
 
13689
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js
13689
+ // ../../rel54-runner-deps/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js
13690
13690
  var require_react_dom_server_legacy_node_development = __commonJS({
13691
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js"(exports) {
13691
+ "../../rel54-runner-deps/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js"(exports) {
13692
13692
  "use strict";
13693
13693
  "production" !== process.env.NODE_ENV && (function() {
13694
13694
  function styleReplacer(match, prefix2, s, suffix2) {
@@ -21196,9 +21196,9 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
21196
21196
  }
21197
21197
  });
21198
21198
 
21199
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-dom/cjs/react-dom-server.node.development.js
21199
+ // ../../rel54-runner-deps/node_modules/react-dom/cjs/react-dom-server.node.development.js
21200
21200
  var require_react_dom_server_node_development = __commonJS({
21201
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-dom/cjs/react-dom-server.node.development.js"(exports) {
21201
+ "../../rel54-runner-deps/node_modules/react-dom/cjs/react-dom-server.node.development.js"(exports) {
21202
21202
  "use strict";
21203
21203
  "production" !== process.env.NODE_ENV && (function() {
21204
21204
  function styleReplacer(match, prefix2, s, suffix2) {
@@ -29495,9 +29495,9 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
29495
29495
  }
29496
29496
  });
29497
29497
 
29498
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-dom/server.node.js
29498
+ // ../../rel54-runner-deps/node_modules/react-dom/server.node.js
29499
29499
  var require_server_node = __commonJS({
29500
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-dom/server.node.js"(exports) {
29500
+ "../../rel54-runner-deps/node_modules/react-dom/server.node.js"(exports) {
29501
29501
  "use strict";
29502
29502
  var l2;
29503
29503
  var s;
@@ -29518,9 +29518,9 @@ var require_server_node = __commonJS({
29518
29518
  }
29519
29519
  });
29520
29520
 
29521
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/tokenizer/keywords.js
29521
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/parser/tokenizer/keywords.js
29522
29522
  var require_keywords = __commonJS({
29523
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/tokenizer/keywords.js"(exports) {
29523
+ "../../rel54-runner-deps/node_modules/sucrase/dist/parser/tokenizer/keywords.js"(exports) {
29524
29524
  "use strict";
29525
29525
  Object.defineProperty(exports, "__esModule", { value: true });
29526
29526
  var ContextualKeyword;
@@ -29611,9 +29611,9 @@ var require_keywords = __commonJS({
29611
29611
  }
29612
29612
  });
29613
29613
 
29614
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/tokenizer/types.js
29614
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/parser/tokenizer/types.js
29615
29615
  var require_types = __commonJS({
29616
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/tokenizer/types.js"(exports) {
29616
+ "../../rel54-runner-deps/node_modules/sucrase/dist/parser/tokenizer/types.js"(exports) {
29617
29617
  "use strict";
29618
29618
  Object.defineProperty(exports, "__esModule", { value: true });
29619
29619
  var TokenType;
@@ -30095,9 +30095,9 @@ var require_types = __commonJS({
30095
30095
  }
30096
30096
  });
30097
30097
 
30098
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/tokenizer/state.js
30098
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/parser/tokenizer/state.js
30099
30099
  var require_state = __commonJS({
30100
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/tokenizer/state.js"(exports) {
30100
+ "../../rel54-runner-deps/node_modules/sucrase/dist/parser/tokenizer/state.js"(exports) {
30101
30101
  "use strict";
30102
30102
  Object.defineProperty(exports, "__esModule", { value: true });
30103
30103
  var _keywords = require_keywords();
@@ -30236,9 +30236,9 @@ var require_state = __commonJS({
30236
30236
  }
30237
30237
  });
30238
30238
 
30239
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/util/charcodes.js
30239
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/parser/util/charcodes.js
30240
30240
  var require_charcodes = __commonJS({
30241
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/util/charcodes.js"(exports) {
30241
+ "../../rel54-runner-deps/node_modules/sucrase/dist/parser/util/charcodes.js"(exports) {
30242
30242
  "use strict";
30243
30243
  Object.defineProperty(exports, "__esModule", { value: true });
30244
30244
  var charCodes;
@@ -30459,9 +30459,9 @@ var require_charcodes = __commonJS({
30459
30459
  }
30460
30460
  });
30461
30461
 
30462
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/traverser/base.js
30462
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/parser/traverser/base.js
30463
30463
  var require_base = __commonJS({
30464
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/traverser/base.js"(exports) {
30464
+ "../../rel54-runner-deps/node_modules/sucrase/dist/parser/traverser/base.js"(exports) {
30465
30465
  "use strict";
30466
30466
  Object.defineProperty(exports, "__esModule", { value: true });
30467
30467
  function _interopRequireDefault(obj3) {
@@ -30522,9 +30522,9 @@ var require_base = __commonJS({
30522
30522
  }
30523
30523
  });
30524
30524
 
30525
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/traverser/util.js
30525
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/parser/traverser/util.js
30526
30526
  var require_util = __commonJS({
30527
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/traverser/util.js"(exports) {
30527
+ "../../rel54-runner-deps/node_modules/sucrase/dist/parser/traverser/util.js"(exports) {
30528
30528
  "use strict";
30529
30529
  Object.defineProperty(exports, "__esModule", { value: true });
30530
30530
  var _index = require_tokenizer();
@@ -30608,9 +30608,9 @@ var require_util = __commonJS({
30608
30608
  }
30609
30609
  });
30610
30610
 
30611
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/util/whitespace.js
30611
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/parser/util/whitespace.js
30612
30612
  var require_whitespace = __commonJS({
30613
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/util/whitespace.js"(exports) {
30613
+ "../../rel54-runner-deps/node_modules/sucrase/dist/parser/util/whitespace.js"(exports) {
30614
30614
  "use strict";
30615
30615
  Object.defineProperty(exports, "__esModule", { value: true });
30616
30616
  var _charcodes = require_charcodes();
@@ -30663,9 +30663,9 @@ var require_whitespace = __commonJS({
30663
30663
  }
30664
30664
  });
30665
30665
 
30666
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/util/identifier.js
30666
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/parser/util/identifier.js
30667
30667
  var require_identifier = __commonJS({
30668
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/util/identifier.js"(exports) {
30668
+ "../../rel54-runner-deps/node_modules/sucrase/dist/parser/util/identifier.js"(exports) {
30669
30669
  "use strict";
30670
30670
  Object.defineProperty(exports, "__esModule", { value: true });
30671
30671
  var _charcodes = require_charcodes();
@@ -30701,9 +30701,9 @@ var require_identifier = __commonJS({
30701
30701
  }
30702
30702
  });
30703
30703
 
30704
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/tokenizer/readWordTree.js
30704
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/parser/tokenizer/readWordTree.js
30705
30705
  var require_readWordTree = __commonJS({
30706
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/tokenizer/readWordTree.js"(exports) {
30706
+ "../../rel54-runner-deps/node_modules/sucrase/dist/parser/tokenizer/readWordTree.js"(exports) {
30707
30707
  "use strict";
30708
30708
  Object.defineProperty(exports, "__esModule", { value: true });
30709
30709
  var _keywords = require_keywords();
@@ -40010,9 +40010,9 @@ var require_readWordTree = __commonJS({
40010
40010
  }
40011
40011
  });
40012
40012
 
40013
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/tokenizer/readWord.js
40013
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/parser/tokenizer/readWord.js
40014
40014
  var require_readWord = __commonJS({
40015
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/tokenizer/readWord.js"(exports) {
40015
+ "../../rel54-runner-deps/node_modules/sucrase/dist/parser/tokenizer/readWord.js"(exports) {
40016
40016
  "use strict";
40017
40017
  Object.defineProperty(exports, "__esModule", { value: true });
40018
40018
  var _base = require_base();
@@ -40073,9 +40073,9 @@ var require_readWord = __commonJS({
40073
40073
  }
40074
40074
  });
40075
40075
 
40076
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/tokenizer/index.js
40076
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/parser/tokenizer/index.js
40077
40077
  var require_tokenizer = __commonJS({
40078
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/tokenizer/index.js"(exports) {
40078
+ "../../rel54-runner-deps/node_modules/sucrase/dist/parser/tokenizer/index.js"(exports) {
40079
40079
  "use strict";
40080
40080
  Object.defineProperty(exports, "__esModule", { value: true });
40081
40081
  function _interopRequireDefault(obj3) {
@@ -40827,9 +40827,9 @@ var require_tokenizer = __commonJS({
40827
40827
  }
40828
40828
  });
40829
40829
 
40830
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/getImportExportSpecifierInfo.js
40830
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/util/getImportExportSpecifierInfo.js
40831
40831
  var require_getImportExportSpecifierInfo = __commonJS({
40832
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/getImportExportSpecifierInfo.js"(exports) {
40832
+ "../../rel54-runner-deps/node_modules/sucrase/dist/util/getImportExportSpecifierInfo.js"(exports) {
40833
40833
  "use strict";
40834
40834
  Object.defineProperty(exports, "__esModule", { value: true });
40835
40835
  var _types = require_types();
@@ -40881,9 +40881,9 @@ var require_getImportExportSpecifierInfo = __commonJS({
40881
40881
  }
40882
40882
  });
40883
40883
 
40884
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/plugins/jsx/xhtml.js
40884
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/parser/plugins/jsx/xhtml.js
40885
40885
  var require_xhtml = __commonJS({
40886
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/plugins/jsx/xhtml.js"(exports) {
40886
+ "../../rel54-runner-deps/node_modules/sucrase/dist/parser/plugins/jsx/xhtml.js"(exports) {
40887
40887
  "use strict";
40888
40888
  Object.defineProperty(exports, "__esModule", { value: true });
40889
40889
  exports.default = /* @__PURE__ */ new Map([
@@ -41144,9 +41144,9 @@ var require_xhtml = __commonJS({
41144
41144
  }
41145
41145
  });
41146
41146
 
41147
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/getJSXPragmaInfo.js
41147
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/util/getJSXPragmaInfo.js
41148
41148
  var require_getJSXPragmaInfo = __commonJS({
41149
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/getJSXPragmaInfo.js"(exports) {
41149
+ "../../rel54-runner-deps/node_modules/sucrase/dist/util/getJSXPragmaInfo.js"(exports) {
41150
41150
  "use strict";
41151
41151
  Object.defineProperty(exports, "__esModule", { value: true });
41152
41152
  function getJSXPragmaInfo(options) {
@@ -41165,9 +41165,9 @@ var require_getJSXPragmaInfo = __commonJS({
41165
41165
  }
41166
41166
  });
41167
41167
 
41168
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/Transformer.js
41168
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/transformers/Transformer.js
41169
41169
  var require_Transformer = __commonJS({
41170
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/Transformer.js"(exports) {
41170
+ "../../rel54-runner-deps/node_modules/sucrase/dist/transformers/Transformer.js"(exports) {
41171
41171
  "use strict";
41172
41172
  Object.defineProperty(exports, "__esModule", { value: true });
41173
41173
  var Transformer = class {
@@ -41186,9 +41186,9 @@ var require_Transformer = __commonJS({
41186
41186
  }
41187
41187
  });
41188
41188
 
41189
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/JSXTransformer.js
41189
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/transformers/JSXTransformer.js
41190
41190
  var require_JSXTransformer = __commonJS({
41191
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/JSXTransformer.js"(exports) {
41191
+ "../../rel54-runner-deps/node_modules/sucrase/dist/transformers/JSXTransformer.js"(exports) {
41192
41192
  "use strict";
41193
41193
  Object.defineProperty(exports, "__esModule", { value: true });
41194
41194
  function _interopRequireDefault(obj3) {
@@ -41787,9 +41787,9 @@ var require_JSXTransformer = __commonJS({
41787
41787
  }
41788
41788
  });
41789
41789
 
41790
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/getNonTypeIdentifiers.js
41790
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/util/getNonTypeIdentifiers.js
41791
41791
  var require_getNonTypeIdentifiers = __commonJS({
41792
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/getNonTypeIdentifiers.js"(exports) {
41792
+ "../../rel54-runner-deps/node_modules/sucrase/dist/util/getNonTypeIdentifiers.js"(exports) {
41793
41793
  "use strict";
41794
41794
  Object.defineProperty(exports, "__esModule", { value: true });
41795
41795
  function _interopRequireDefault(obj3) {
@@ -41828,9 +41828,9 @@ var require_getNonTypeIdentifiers = __commonJS({
41828
41828
  }
41829
41829
  });
41830
41830
 
41831
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/CJSImportProcessor.js
41831
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/CJSImportProcessor.js
41832
41832
  var require_CJSImportProcessor = __commonJS({
41833
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/CJSImportProcessor.js"(exports) {
41833
+ "../../rel54-runner-deps/node_modules/sucrase/dist/CJSImportProcessor.js"(exports) {
41834
41834
  "use strict";
41835
41835
  Object.defineProperty(exports, "__esModule", { value: true });
41836
41836
  function _interopRequireDefault(obj3) {
@@ -42196,9 +42196,9 @@ var require_CJSImportProcessor = __commonJS({
42196
42196
  }
42197
42197
  });
42198
42198
 
42199
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.umd.js
42199
+ // ../../rel54-runner-deps/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.umd.js
42200
42200
  var require_sourcemap_codec_umd = __commonJS({
42201
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.umd.js"(exports, module) {
42201
+ "../../rel54-runner-deps/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.umd.js"(exports, module) {
42202
42202
  (function(global, factory) {
42203
42203
  if (typeof exports === "object" && typeof module !== "undefined") {
42204
42204
  factory(module);
@@ -42223,9 +42223,9 @@ var require_sourcemap_codec_umd = __commonJS({
42223
42223
  var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
42224
42224
  var __getOwnPropNames2 = Object.getOwnPropertyNames;
42225
42225
  var __hasOwnProp2 = Object.prototype.hasOwnProperty;
42226
- var __export2 = (target, all2) => {
42227
- for (var name in all2)
42228
- __defProp2(target, name, { get: all2[name], enumerable: true });
42226
+ var __export2 = (target, all) => {
42227
+ for (var name in all)
42228
+ __defProp2(target, name, { get: all[name], enumerable: true });
42229
42229
  };
42230
42230
  var __copyProps2 = (to, from, except, desc) => {
42231
42231
  if (from && typeof from === "object" || typeof from === "function") {
@@ -42699,9 +42699,9 @@ var require_sourcemap_codec_umd = __commonJS({
42699
42699
  }
42700
42700
  });
42701
42701
 
42702
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/@jridgewell/resolve-uri/dist/resolve-uri.umd.js
42702
+ // ../../rel54-runner-deps/node_modules/@jridgewell/resolve-uri/dist/resolve-uri.umd.js
42703
42703
  var require_resolve_uri_umd = __commonJS({
42704
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/@jridgewell/resolve-uri/dist/resolve-uri.umd.js"(exports, module) {
42704
+ "../../rel54-runner-deps/node_modules/@jridgewell/resolve-uri/dist/resolve-uri.umd.js"(exports, module) {
42705
42705
  (function(global, factory) {
42706
42706
  typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() : typeof define === "function" && define.amd ? define(factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, global.resolveURI = factory());
42707
42707
  })(exports, (function() {
@@ -42878,9 +42878,9 @@ var require_resolve_uri_umd = __commonJS({
42878
42878
  }
42879
42879
  });
42880
42880
 
42881
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/@jridgewell/trace-mapping/dist/trace-mapping.umd.js
42881
+ // ../../rel54-runner-deps/node_modules/@jridgewell/trace-mapping/dist/trace-mapping.umd.js
42882
42882
  var require_trace_mapping_umd = __commonJS({
42883
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/@jridgewell/trace-mapping/dist/trace-mapping.umd.js"(exports, module) {
42883
+ "../../rel54-runner-deps/node_modules/@jridgewell/trace-mapping/dist/trace-mapping.umd.js"(exports, module) {
42884
42884
  (function(global, factory) {
42885
42885
  if (typeof exports === "object" && typeof module !== "undefined") {
42886
42886
  factory(module, require_resolve_uri_umd(), require_sourcemap_codec_umd());
@@ -42910,9 +42910,9 @@ var require_trace_mapping_umd = __commonJS({
42910
42910
  var __commonJS2 = (cb, mod) => function __require2() {
42911
42911
  return mod || (0, cb[__getOwnPropNames2(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
42912
42912
  };
42913
- var __export2 = (target, all2) => {
42914
- for (var name in all2)
42915
- __defProp2(target, name, { get: all2[name], enumerable: true });
42913
+ var __export2 = (target, all) => {
42914
+ for (var name in all)
42915
+ __defProp2(target, name, { get: all[name], enumerable: true });
42916
42916
  };
42917
42917
  var __copyProps2 = (to, from, except, desc) => {
42918
42918
  if (from && typeof from === "object" || typeof from === "function") {
@@ -43394,7 +43394,7 @@ var require_trace_mapping_umd = __commonJS({
43394
43394
  }
43395
43395
  return result;
43396
43396
  }
43397
- function generatedPosition(map2, source, line, column, bias, all2) {
43397
+ function generatedPosition(map2, source, line, column, bias, all) {
43398
43398
  var _a, _b;
43399
43399
  line--;
43400
43400
  if (line < 0) throw new Error(LINE_GTR_ZERO);
@@ -43402,13 +43402,13 @@ var require_trace_mapping_umd = __commonJS({
43402
43402
  const { sources, resolvedSources } = map2;
43403
43403
  let sourceIndex2 = sources.indexOf(source);
43404
43404
  if (sourceIndex2 === -1) sourceIndex2 = resolvedSources.indexOf(source);
43405
- if (sourceIndex2 === -1) return all2 ? [] : GMapping(null, null);
43405
+ if (sourceIndex2 === -1) return all ? [] : GMapping(null, null);
43406
43406
  const bySourceMemos = (_a = cast(map2))._bySourceMemos || (_a._bySourceMemos = sources.map(memoizedState));
43407
43407
  const generated = (_b = cast(map2))._bySources || (_b._bySources = buildBySources(decodedMappings(map2), bySourceMemos));
43408
43408
  const segments = generated[sourceIndex2][line];
43409
- if (segments == null) return all2 ? [] : GMapping(null, null);
43409
+ if (segments == null) return all ? [] : GMapping(null, null);
43410
43410
  const memo = bySourceMemos[sourceIndex2];
43411
- if (all2) return sliceGeneratedPositions(segments, memo, line, column, bias);
43411
+ if (all) return sliceGeneratedPositions(segments, memo, line, column, bias);
43412
43412
  const index = traceSegmentInternal(segments, memo, line, column, bias);
43413
43413
  if (index === -1) return GMapping(null, null);
43414
43414
  const segment = segments[index];
@@ -43418,9 +43418,9 @@ var require_trace_mapping_umd = __commonJS({
43418
43418
  }
43419
43419
  });
43420
43420
 
43421
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/@jridgewell/gen-mapping/dist/gen-mapping.umd.js
43421
+ // ../../rel54-runner-deps/node_modules/@jridgewell/gen-mapping/dist/gen-mapping.umd.js
43422
43422
  var require_gen_mapping_umd = __commonJS({
43423
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/@jridgewell/gen-mapping/dist/gen-mapping.umd.js"(exports, module) {
43423
+ "../../rel54-runner-deps/node_modules/@jridgewell/gen-mapping/dist/gen-mapping.umd.js"(exports, module) {
43424
43424
  (function(global, factory) {
43425
43425
  if (typeof exports === "object" && typeof module !== "undefined") {
43426
43426
  factory(module, require_sourcemap_codec_umd(), require_trace_mapping_umd());
@@ -43450,9 +43450,9 @@ var require_gen_mapping_umd = __commonJS({
43450
43450
  var __commonJS2 = (cb, mod) => function __require2() {
43451
43451
  return mod || (0, cb[__getOwnPropNames2(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
43452
43452
  };
43453
- var __export2 = (target, all2) => {
43454
- for (var name in all2)
43455
- __defProp2(target, name, { get: all2[name], enumerable: true });
43453
+ var __export2 = (target, all) => {
43454
+ for (var name in all)
43455
+ __defProp2(target, name, { get: all[name], enumerable: true });
43456
43456
  };
43457
43457
  var __copyProps2 = (to, from, except, desc) => {
43458
43458
  if (from && typeof from === "object" || typeof from === "function") {
@@ -43769,9 +43769,9 @@ var require_gen_mapping_umd = __commonJS({
43769
43769
  }
43770
43770
  });
43771
43771
 
43772
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/computeSourceMap.js
43772
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/computeSourceMap.js
43773
43773
  var require_computeSourceMap = __commonJS({
43774
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/computeSourceMap.js"(exports) {
43774
+ "../../rel54-runner-deps/node_modules/sucrase/dist/computeSourceMap.js"(exports) {
43775
43775
  "use strict";
43776
43776
  Object.defineProperty(exports, "__esModule", { value: true });
43777
43777
  var _genmapping = require_gen_mapping_umd();
@@ -43832,9 +43832,9 @@ var require_computeSourceMap = __commonJS({
43832
43832
  }
43833
43833
  });
43834
43834
 
43835
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/HelperManager.js
43835
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/HelperManager.js
43836
43836
  var require_HelperManager = __commonJS({
43837
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/HelperManager.js"(exports) {
43837
+ "../../rel54-runner-deps/node_modules/sucrase/dist/HelperManager.js"(exports) {
43838
43838
  "use strict";
43839
43839
  Object.defineProperty(exports, "__esModule", { value: true });
43840
43840
  var HELPERS = {
@@ -44021,9 +44021,9 @@ var require_HelperManager = __commonJS({
44021
44021
  }
44022
44022
  });
44023
44023
 
44024
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/identifyShadowedGlobals.js
44024
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/identifyShadowedGlobals.js
44025
44025
  var require_identifyShadowedGlobals = __commonJS({
44026
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/identifyShadowedGlobals.js"(exports) {
44026
+ "../../rel54-runner-deps/node_modules/sucrase/dist/identifyShadowedGlobals.js"(exports) {
44027
44027
  "use strict";
44028
44028
  Object.defineProperty(exports, "__esModule", { value: true });
44029
44029
  var _tokenizer = require_tokenizer();
@@ -44090,9 +44090,9 @@ var require_identifyShadowedGlobals = __commonJS({
44090
44090
  }
44091
44091
  });
44092
44092
 
44093
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/getIdentifierNames.js
44093
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/util/getIdentifierNames.js
44094
44094
  var require_getIdentifierNames = __commonJS({
44095
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/getIdentifierNames.js"(exports) {
44095
+ "../../rel54-runner-deps/node_modules/sucrase/dist/util/getIdentifierNames.js"(exports) {
44096
44096
  "use strict";
44097
44097
  Object.defineProperty(exports, "__esModule", { value: true });
44098
44098
  var _types = require_types();
@@ -44109,9 +44109,9 @@ var require_getIdentifierNames = __commonJS({
44109
44109
  }
44110
44110
  });
44111
44111
 
44112
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/NameManager.js
44112
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/NameManager.js
44113
44113
  var require_NameManager = __commonJS({
44114
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/NameManager.js"(exports) {
44114
+ "../../rel54-runner-deps/node_modules/sucrase/dist/NameManager.js"(exports) {
44115
44115
  "use strict";
44116
44116
  Object.defineProperty(exports, "__esModule", { value: true });
44117
44117
  function _interopRequireDefault(obj3) {
@@ -44148,9 +44148,9 @@ var require_NameManager = __commonJS({
44148
44148
  }
44149
44149
  });
44150
44150
 
44151
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/ts-interface-checker/dist/util.js
44151
+ // ../../rel54-runner-deps/node_modules/ts-interface-checker/dist/util.js
44152
44152
  var require_util2 = __commonJS({
44153
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/ts-interface-checker/dist/util.js"(exports) {
44153
+ "../../rel54-runner-deps/node_modules/ts-interface-checker/dist/util.js"(exports) {
44154
44154
  "use strict";
44155
44155
  var __extends = exports && exports.__extends || /* @__PURE__ */ (function() {
44156
44156
  var extendStatics = function(d2, b2) {
@@ -44289,9 +44289,9 @@ var require_util2 = __commonJS({
44289
44289
  }
44290
44290
  });
44291
44291
 
44292
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/ts-interface-checker/dist/types.js
44292
+ // ../../rel54-runner-deps/node_modules/ts-interface-checker/dist/types.js
44293
44293
  var require_types2 = __commonJS({
44294
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/ts-interface-checker/dist/types.js"(exports) {
44294
+ "../../rel54-runner-deps/node_modules/ts-interface-checker/dist/types.js"(exports) {
44295
44295
  "use strict";
44296
44296
  var __extends = exports && exports.__extends || /* @__PURE__ */ (function() {
44297
44297
  var extendStatics = function(d2, b2) {
@@ -44406,8 +44406,8 @@ var require_types2 = __commonJS({
44406
44406
  return ctx.fail(null, "is not an array", 0);
44407
44407
  }
44408
44408
  for (var i = 0; i < value.length; i++) {
44409
- var ok2 = itemChecker(value[i], ctx);
44410
- if (!ok2) {
44409
+ var ok = itemChecker(value[i], ctx);
44410
+ if (!ok) {
44411
44411
  return ctx.fail(i, null, 1);
44412
44412
  }
44413
44413
  }
@@ -44446,8 +44446,8 @@ var require_types2 = __commonJS({
44446
44446
  return ctx.fail(null, "is not an array", 0);
44447
44447
  }
44448
44448
  for (var i = 0; i < itemCheckers.length; i++) {
44449
- var ok2 = itemCheckers[i](value[i], ctx);
44450
- if (!ok2) {
44449
+ var ok = itemCheckers[i](value[i], ctx);
44450
+ if (!ok) {
44451
44451
  return ctx.fail(i, null, 1);
44452
44452
  }
44453
44453
  }
@@ -44508,8 +44508,8 @@ var require_types2 = __commonJS({
44508
44508
  return function(value, ctx) {
44509
44509
  var ur2 = ctx.unionResolver();
44510
44510
  for (var i = 0; i < itemCheckers.length; i++) {
44511
- var ok2 = itemCheckers[i](value, ur2.createContext());
44512
- if (ok2) {
44511
+ var ok = itemCheckers[i](value, ur2.createContext());
44512
+ if (ok) {
44513
44513
  return true;
44514
44514
  }
44515
44515
  }
@@ -44546,10 +44546,10 @@ var require_types2 = __commonJS({
44546
44546
  return t2.getChecker(suite, strict, allowedProps);
44547
44547
  });
44548
44548
  return function(value, ctx) {
44549
- var ok2 = itemCheckers.every(function(checker) {
44549
+ var ok = itemCheckers.every(function(checker) {
44550
44550
  return checker(value, ctx);
44551
44551
  });
44552
- if (ok2) {
44552
+ if (ok) {
44553
44553
  return true;
44554
44554
  }
44555
44555
  return ctx.fail(null, null, 0);
@@ -44674,8 +44674,8 @@ var require_types2 = __commonJS({
44674
44674
  return ctx.fail(name_1, "is missing", 1);
44675
44675
  }
44676
44676
  } else {
44677
- var ok2 = propCheckers[i](v2, ctx);
44678
- if (!ok2) {
44677
+ var ok = propCheckers[i](v2, ctx);
44678
+ if (!ok) {
44679
44679
  return ctx.fail(name_1, null, 1);
44680
44680
  }
44681
44681
  }
@@ -44815,8 +44815,8 @@ var require_types2 = __commonJS({
44815
44815
  return ctx.fail(p2.name, "is missing", 1);
44816
44816
  }
44817
44817
  } else {
44818
- var ok2 = itemCheckers[i](value[i], ctx);
44819
- if (!ok2) {
44818
+ var ok = itemCheckers[i](value[i], ctx);
44819
+ if (!ok) {
44820
44820
  return ctx.fail(p2.name, null, 1);
44821
44821
  }
44822
44822
  }
@@ -44928,9 +44928,9 @@ var require_types2 = __commonJS({
44928
44928
  }
44929
44929
  });
44930
44930
 
44931
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/ts-interface-checker/dist/index.js
44931
+ // ../../rel54-runner-deps/node_modules/ts-interface-checker/dist/index.js
44932
44932
  var require_dist = __commonJS({
44933
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/ts-interface-checker/dist/index.js"(exports) {
44933
+ "../../rel54-runner-deps/node_modules/ts-interface-checker/dist/index.js"(exports) {
44934
44934
  "use strict";
44935
44935
  var __spreadArrays = exports && exports.__spreadArrays || function() {
44936
44936
  for (var s = 0, i = 0, il2 = arguments.length; i < il2; i++) s += arguments[i].length;
@@ -45154,9 +45154,9 @@ var require_dist = __commonJS({
45154
45154
  }
45155
45155
  });
45156
45156
 
45157
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/Options-gen-types.js
45157
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/Options-gen-types.js
45158
45158
  var require_Options_gen_types = __commonJS({
45159
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/Options-gen-types.js"(exports) {
45159
+ "../../rel54-runner-deps/node_modules/sucrase/dist/Options-gen-types.js"(exports) {
45160
45160
  "use strict";
45161
45161
  Object.defineProperty(exports, "__esModule", { value: true });
45162
45162
  function _interopRequireWildcard(obj3) {
@@ -45216,9 +45216,9 @@ var require_Options_gen_types = __commonJS({
45216
45216
  }
45217
45217
  });
45218
45218
 
45219
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/Options.js
45219
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/Options.js
45220
45220
  var require_Options = __commonJS({
45221
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/Options.js"(exports) {
45221
+ "../../rel54-runner-deps/node_modules/sucrase/dist/Options.js"(exports) {
45222
45222
  "use strict";
45223
45223
  Object.defineProperty(exports, "__esModule", { value: true });
45224
45224
  function _interopRequireDefault(obj3) {
@@ -45235,9 +45235,9 @@ var require_Options = __commonJS({
45235
45235
  }
45236
45236
  });
45237
45237
 
45238
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/traverser/lval.js
45238
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/parser/traverser/lval.js
45239
45239
  var require_lval = __commonJS({
45240
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/traverser/lval.js"(exports) {
45240
+ "../../rel54-runner-deps/node_modules/sucrase/dist/parser/traverser/lval.js"(exports) {
45241
45241
  "use strict";
45242
45242
  Object.defineProperty(exports, "__esModule", { value: true });
45243
45243
  var _flow = require_flow();
@@ -45382,9 +45382,9 @@ var require_lval = __commonJS({
45382
45382
  }
45383
45383
  });
45384
45384
 
45385
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/plugins/typescript.js
45385
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/parser/plugins/typescript.js
45386
45386
  var require_typescript = __commonJS({
45387
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/plugins/typescript.js"(exports) {
45387
+ "../../rel54-runner-deps/node_modules/sucrase/dist/parser/plugins/typescript.js"(exports) {
45388
45388
  "use strict";
45389
45389
  Object.defineProperty(exports, "__esModule", { value: true });
45390
45390
  var _index = require_tokenizer();
@@ -46695,9 +46695,9 @@ var require_typescript = __commonJS({
46695
46695
  }
46696
46696
  });
46697
46697
 
46698
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/plugins/jsx/index.js
46698
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/parser/plugins/jsx/index.js
46699
46699
  var require_jsx = __commonJS({
46700
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/plugins/jsx/index.js"(exports) {
46700
+ "../../rel54-runner-deps/node_modules/sucrase/dist/parser/plugins/jsx/index.js"(exports) {
46701
46701
  "use strict";
46702
46702
  Object.defineProperty(exports, "__esModule", { value: true });
46703
46703
  var _index = require_tokenizer();
@@ -46965,9 +46965,9 @@ var require_jsx = __commonJS({
46965
46965
  }
46966
46966
  });
46967
46967
 
46968
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/plugins/types.js
46968
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/parser/plugins/types.js
46969
46969
  var require_types3 = __commonJS({
46970
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/plugins/types.js"(exports) {
46970
+ "../../rel54-runner-deps/node_modules/sucrase/dist/parser/plugins/types.js"(exports) {
46971
46971
  "use strict";
46972
46972
  Object.defineProperty(exports, "__esModule", { value: true });
46973
46973
  var _index = require_tokenizer();
@@ -47000,9 +47000,9 @@ var require_types3 = __commonJS({
47000
47000
  }
47001
47001
  });
47002
47002
 
47003
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/traverser/expression.js
47003
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/parser/traverser/expression.js
47004
47004
  var require_expression = __commonJS({
47005
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/traverser/expression.js"(exports) {
47005
+ "../../rel54-runner-deps/node_modules/sucrase/dist/parser/traverser/expression.js"(exports) {
47006
47006
  "use strict";
47007
47007
  Object.defineProperty(exports, "__esModule", { value: true });
47008
47008
  var _flow = require_flow();
@@ -47740,9 +47740,9 @@ var require_expression = __commonJS({
47740
47740
  }
47741
47741
  });
47742
47742
 
47743
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/plugins/flow.js
47743
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/parser/plugins/flow.js
47744
47744
  var require_flow = __commonJS({
47745
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/plugins/flow.js"(exports) {
47745
+ "../../rel54-runner-deps/node_modules/sucrase/dist/parser/plugins/flow.js"(exports) {
47746
47746
  "use strict";
47747
47747
  Object.defineProperty(exports, "__esModule", { value: true });
47748
47748
  var _index = require_tokenizer();
@@ -48623,9 +48623,9 @@ var require_flow = __commonJS({
48623
48623
  }
48624
48624
  });
48625
48625
 
48626
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/traverser/statement.js
48626
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/parser/traverser/statement.js
48627
48627
  var require_statement = __commonJS({
48628
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/traverser/statement.js"(exports) {
48628
+ "../../rel54-runner-deps/node_modules/sucrase/dist/parser/traverser/statement.js"(exports) {
48629
48629
  "use strict";
48630
48630
  Object.defineProperty(exports, "__esModule", { value: true });
48631
48631
  var _index = require_parser();
@@ -49620,9 +49620,9 @@ var require_statement = __commonJS({
49620
49620
  }
49621
49621
  });
49622
49622
 
49623
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/traverser/index.js
49623
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/parser/traverser/index.js
49624
49624
  var require_traverser = __commonJS({
49625
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/traverser/index.js"(exports) {
49625
+ "../../rel54-runner-deps/node_modules/sucrase/dist/parser/traverser/index.js"(exports) {
49626
49626
  "use strict";
49627
49627
  Object.defineProperty(exports, "__esModule", { value: true });
49628
49628
  var _index = require_tokenizer();
@@ -49640,9 +49640,9 @@ var require_traverser = __commonJS({
49640
49640
  }
49641
49641
  });
49642
49642
 
49643
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/index.js
49643
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/parser/index.js
49644
49644
  var require_parser = __commonJS({
49645
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/parser/index.js"(exports) {
49645
+ "../../rel54-runner-deps/node_modules/sucrase/dist/parser/index.js"(exports) {
49646
49646
  "use strict";
49647
49647
  Object.defineProperty(exports, "__esModule", { value: true });
49648
49648
  var _base = require_base();
@@ -49669,9 +49669,9 @@ var require_parser = __commonJS({
49669
49669
  }
49670
49670
  });
49671
49671
 
49672
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/isAsyncOperation.js
49672
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/util/isAsyncOperation.js
49673
49673
  var require_isAsyncOperation = __commonJS({
49674
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/isAsyncOperation.js"(exports) {
49674
+ "../../rel54-runner-deps/node_modules/sucrase/dist/util/isAsyncOperation.js"(exports) {
49675
49675
  "use strict";
49676
49676
  Object.defineProperty(exports, "__esModule", { value: true });
49677
49677
  var _keywords = require_keywords();
@@ -49700,9 +49700,9 @@ var require_isAsyncOperation = __commonJS({
49700
49700
  }
49701
49701
  });
49702
49702
 
49703
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/TokenProcessor.js
49703
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/TokenProcessor.js
49704
49704
  var require_TokenProcessor = __commonJS({
49705
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/TokenProcessor.js"(exports) {
49705
+ "../../rel54-runner-deps/node_modules/sucrase/dist/TokenProcessor.js"(exports) {
49706
49706
  "use strict";
49707
49707
  Object.defineProperty(exports, "__esModule", { value: true });
49708
49708
  function _interopRequireDefault(obj3) {
@@ -49995,9 +49995,9 @@ var require_TokenProcessor = __commonJS({
49995
49995
  }
49996
49996
  });
49997
49997
 
49998
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/getClassInfo.js
49998
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/util/getClassInfo.js
49999
49999
  var require_getClassInfo = __commonJS({
50000
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/getClassInfo.js"(exports) {
50000
+ "../../rel54-runner-deps/node_modules/sucrase/dist/util/getClassInfo.js"(exports) {
50001
50001
  "use strict";
50002
50002
  Object.defineProperty(exports, "__esModule", { value: true });
50003
50003
  var _keywords = require_keywords();
@@ -50237,9 +50237,9 @@ var require_getClassInfo = __commonJS({
50237
50237
  }
50238
50238
  });
50239
50239
 
50240
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/elideImportEquals.js
50240
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/util/elideImportEquals.js
50241
50241
  var require_elideImportEquals = __commonJS({
50242
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/elideImportEquals.js"(exports) {
50242
+ "../../rel54-runner-deps/node_modules/sucrase/dist/util/elideImportEquals.js"(exports) {
50243
50243
  "use strict";
50244
50244
  Object.defineProperty(exports, "__esModule", { value: true });
50245
50245
  var _types = require_types();
@@ -50263,9 +50263,9 @@ var require_elideImportEquals = __commonJS({
50263
50263
  }
50264
50264
  });
50265
50265
 
50266
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/getDeclarationInfo.js
50266
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/util/getDeclarationInfo.js
50267
50267
  var require_getDeclarationInfo = __commonJS({
50268
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/getDeclarationInfo.js"(exports) {
50268
+ "../../rel54-runner-deps/node_modules/sucrase/dist/util/getDeclarationInfo.js"(exports) {
50269
50269
  "use strict";
50270
50270
  Object.defineProperty(exports, "__esModule", { value: true });
50271
50271
  var _tokenizer = require_tokenizer();
@@ -50294,9 +50294,9 @@ var require_getDeclarationInfo = __commonJS({
50294
50294
  }
50295
50295
  });
50296
50296
 
50297
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/isExportFrom.js
50297
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/util/isExportFrom.js
50298
50298
  var require_isExportFrom = __commonJS({
50299
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/isExportFrom.js"(exports) {
50299
+ "../../rel54-runner-deps/node_modules/sucrase/dist/util/isExportFrom.js"(exports) {
50300
50300
  "use strict";
50301
50301
  Object.defineProperty(exports, "__esModule", { value: true });
50302
50302
  var _keywords = require_keywords();
@@ -50312,9 +50312,9 @@ var require_isExportFrom = __commonJS({
50312
50312
  }
50313
50313
  });
50314
50314
 
50315
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/removeMaybeImportAttributes.js
50315
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/util/removeMaybeImportAttributes.js
50316
50316
  var require_removeMaybeImportAttributes = __commonJS({
50317
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/removeMaybeImportAttributes.js"(exports) {
50317
+ "../../rel54-runner-deps/node_modules/sucrase/dist/util/removeMaybeImportAttributes.js"(exports) {
50318
50318
  "use strict";
50319
50319
  Object.defineProperty(exports, "__esModule", { value: true });
50320
50320
  var _keywords = require_keywords();
@@ -50331,9 +50331,9 @@ var require_removeMaybeImportAttributes = __commonJS({
50331
50331
  }
50332
50332
  });
50333
50333
 
50334
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/shouldElideDefaultExport.js
50334
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/util/shouldElideDefaultExport.js
50335
50335
  var require_shouldElideDefaultExport = __commonJS({
50336
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/shouldElideDefaultExport.js"(exports) {
50336
+ "../../rel54-runner-deps/node_modules/sucrase/dist/util/shouldElideDefaultExport.js"(exports) {
50337
50337
  "use strict";
50338
50338
  Object.defineProperty(exports, "__esModule", { value: true });
50339
50339
  var _types = require_types();
@@ -50360,9 +50360,9 @@ var require_shouldElideDefaultExport = __commonJS({
50360
50360
  }
50361
50361
  });
50362
50362
 
50363
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/CJSImportTransformer.js
50363
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/transformers/CJSImportTransformer.js
50364
50364
  var require_CJSImportTransformer = __commonJS({
50365
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/CJSImportTransformer.js"(exports) {
50365
+ "../../rel54-runner-deps/node_modules/sucrase/dist/transformers/CJSImportTransformer.js"(exports) {
50366
50366
  "use strict";
50367
50367
  Object.defineProperty(exports, "__esModule", { value: true });
50368
50368
  function _interopRequireDefault(obj3) {
@@ -51115,9 +51115,9 @@ var require_CJSImportTransformer = __commonJS({
51115
51115
  }
51116
51116
  });
51117
51117
 
51118
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/ESMImportTransformer.js
51118
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/transformers/ESMImportTransformer.js
51119
51119
  var require_ESMImportTransformer = __commonJS({
51120
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/ESMImportTransformer.js"(exports) {
51120
+ "../../rel54-runner-deps/node_modules/sucrase/dist/transformers/ESMImportTransformer.js"(exports) {
51121
51121
  "use strict";
51122
51122
  Object.defineProperty(exports, "__esModule", { value: true });
51123
51123
  function _interopRequireDefault(obj3) {
@@ -51419,9 +51419,9 @@ var require_ESMImportTransformer = __commonJS({
51419
51419
  }
51420
51420
  });
51421
51421
 
51422
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/FlowTransformer.js
51422
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/transformers/FlowTransformer.js
51423
51423
  var require_FlowTransformer = __commonJS({
51424
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/FlowTransformer.js"(exports) {
51424
+ "../../rel54-runner-deps/node_modules/sucrase/dist/transformers/FlowTransformer.js"(exports) {
51425
51425
  "use strict";
51426
51426
  Object.defineProperty(exports, "__esModule", { value: true });
51427
51427
  function _interopRequireDefault(obj3) {
@@ -51587,9 +51587,9 @@ var require_FlowTransformer = __commonJS({
51587
51587
  }
51588
51588
  });
51589
51589
 
51590
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/JestHoistTransformer.js
51590
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/transformers/JestHoistTransformer.js
51591
51591
  var require_JestHoistTransformer = __commonJS({
51592
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/JestHoistTransformer.js"(exports) {
51592
+ "../../rel54-runner-deps/node_modules/sucrase/dist/transformers/JestHoistTransformer.js"(exports) {
51593
51593
  "use strict";
51594
51594
  Object.defineProperty(exports, "__esModule", { value: true });
51595
51595
  function _interopRequireDefault(obj3) {
@@ -51693,9 +51693,9 @@ var require_JestHoistTransformer = __commonJS({
51693
51693
  }
51694
51694
  });
51695
51695
 
51696
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/NumericSeparatorTransformer.js
51696
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/transformers/NumericSeparatorTransformer.js
51697
51697
  var require_NumericSeparatorTransformer = __commonJS({
51698
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/NumericSeparatorTransformer.js"(exports) {
51698
+ "../../rel54-runner-deps/node_modules/sucrase/dist/transformers/NumericSeparatorTransformer.js"(exports) {
51699
51699
  "use strict";
51700
51700
  Object.defineProperty(exports, "__esModule", { value: true });
51701
51701
  function _interopRequireDefault(obj3) {
@@ -51725,9 +51725,9 @@ var require_NumericSeparatorTransformer = __commonJS({
51725
51725
  }
51726
51726
  });
51727
51727
 
51728
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/OptionalCatchBindingTransformer.js
51728
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/transformers/OptionalCatchBindingTransformer.js
51729
51729
  var require_OptionalCatchBindingTransformer = __commonJS({
51730
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/OptionalCatchBindingTransformer.js"(exports) {
51730
+ "../../rel54-runner-deps/node_modules/sucrase/dist/transformers/OptionalCatchBindingTransformer.js"(exports) {
51731
51731
  "use strict";
51732
51732
  Object.defineProperty(exports, "__esModule", { value: true });
51733
51733
  function _interopRequireDefault(obj3) {
@@ -51756,9 +51756,9 @@ var require_OptionalCatchBindingTransformer = __commonJS({
51756
51756
  }
51757
51757
  });
51758
51758
 
51759
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/OptionalChainingNullishTransformer.js
51759
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/transformers/OptionalChainingNullishTransformer.js
51760
51760
  var require_OptionalChainingNullishTransformer = __commonJS({
51761
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/OptionalChainingNullishTransformer.js"(exports) {
51761
+ "../../rel54-runner-deps/node_modules/sucrase/dist/transformers/OptionalChainingNullishTransformer.js"(exports) {
51762
51762
  "use strict";
51763
51763
  Object.defineProperty(exports, "__esModule", { value: true });
51764
51764
  function _interopRequireDefault(obj3) {
@@ -51894,9 +51894,9 @@ var require_OptionalChainingNullishTransformer = __commonJS({
51894
51894
  }
51895
51895
  });
51896
51896
 
51897
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/ReactDisplayNameTransformer.js
51897
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/transformers/ReactDisplayNameTransformer.js
51898
51898
  var require_ReactDisplayNameTransformer = __commonJS({
51899
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/ReactDisplayNameTransformer.js"(exports) {
51899
+ "../../rel54-runner-deps/node_modules/sucrase/dist/transformers/ReactDisplayNameTransformer.js"(exports) {
51900
51900
  "use strict";
51901
51901
  Object.defineProperty(exports, "__esModule", { value: true });
51902
51902
  function _interopRequireDefault(obj3) {
@@ -52022,9 +52022,9 @@ var require_ReactDisplayNameTransformer = __commonJS({
52022
52022
  }
52023
52023
  });
52024
52024
 
52025
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/ReactHotLoaderTransformer.js
52025
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/transformers/ReactHotLoaderTransformer.js
52026
52026
  var require_ReactHotLoaderTransformer = __commonJS({
52027
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/ReactHotLoaderTransformer.js"(exports) {
52027
+ "../../rel54-runner-deps/node_modules/sucrase/dist/transformers/ReactHotLoaderTransformer.js"(exports) {
52028
52028
  "use strict";
52029
52029
  Object.defineProperty(exports, "__esModule", { value: true });
52030
52030
  function _interopRequireDefault(obj3) {
@@ -52094,9 +52094,9 @@ ${namesToRegister.map(
52094
52094
  }
52095
52095
  });
52096
52096
 
52097
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/isIdentifier.js
52097
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/util/isIdentifier.js
52098
52098
  var require_isIdentifier = __commonJS({
52099
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/isIdentifier.js"(exports) {
52099
+ "../../rel54-runner-deps/node_modules/sucrase/dist/util/isIdentifier.js"(exports) {
52100
52100
  "use strict";
52101
52101
  Object.defineProperty(exports, "__esModule", { value: true });
52102
52102
  var _identifier = require_identifier();
@@ -52169,9 +52169,9 @@ var require_isIdentifier = __commonJS({
52169
52169
  }
52170
52170
  });
52171
52171
 
52172
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/TypeScriptTransformer.js
52172
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/transformers/TypeScriptTransformer.js
52173
52173
  var require_TypeScriptTransformer = __commonJS({
52174
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/TypeScriptTransformer.js"(exports) {
52174
+ "../../rel54-runner-deps/node_modules/sucrase/dist/transformers/TypeScriptTransformer.js"(exports) {
52175
52175
  "use strict";
52176
52176
  Object.defineProperty(exports, "__esModule", { value: true });
52177
52177
  function _interopRequireDefault(obj3) {
@@ -52410,9 +52410,9 @@ var require_TypeScriptTransformer = __commonJS({
52410
52410
  }
52411
52411
  });
52412
52412
 
52413
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/RootTransformer.js
52413
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/transformers/RootTransformer.js
52414
52414
  var require_RootTransformer = __commonJS({
52415
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/transformers/RootTransformer.js"(exports) {
52415
+ "../../rel54-runner-deps/node_modules/sucrase/dist/transformers/RootTransformer.js"(exports) {
52416
52416
  "use strict";
52417
52417
  Object.defineProperty(exports, "__esModule", { value: true });
52418
52418
  function _interopRequireDefault(obj3) {
@@ -52827,9 +52827,9 @@ var require_RootTransformer = __commonJS({
52827
52827
  }
52828
52828
  });
52829
52829
 
52830
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/lines-and-columns/build/index.js
52830
+ // ../../rel54-runner-deps/node_modules/lines-and-columns/build/index.js
52831
52831
  var require_build = __commonJS({
52832
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/lines-and-columns/build/index.js"(exports) {
52832
+ "../../rel54-runner-deps/node_modules/lines-and-columns/build/index.js"(exports) {
52833
52833
  "use strict";
52834
52834
  exports.__esModule = true;
52835
52835
  exports.LinesAndColumns = void 0;
@@ -52896,9 +52896,9 @@ var require_build = __commonJS({
52896
52896
  }
52897
52897
  });
52898
52898
 
52899
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/formatTokens.js
52899
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/util/formatTokens.js
52900
52900
  var require_formatTokens = __commonJS({
52901
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/formatTokens.js"(exports) {
52901
+ "../../rel54-runner-deps/node_modules/sucrase/dist/util/formatTokens.js"(exports) {
52902
52902
  "use strict";
52903
52903
  Object.defineProperty(exports, "__esModule", { value: true });
52904
52904
  function _interopRequireDefault(obj3) {
@@ -52969,9 +52969,9 @@ var require_formatTokens = __commonJS({
52969
52969
  }
52970
52970
  });
52971
52971
 
52972
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/getTSImportedNames.js
52972
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/util/getTSImportedNames.js
52973
52973
  var require_getTSImportedNames = __commonJS({
52974
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/util/getTSImportedNames.js"(exports) {
52974
+ "../../rel54-runner-deps/node_modules/sucrase/dist/util/getTSImportedNames.js"(exports) {
52975
52975
  "use strict";
52976
52976
  Object.defineProperty(exports, "__esModule", { value: true });
52977
52977
  function _interopRequireDefault(obj3) {
@@ -53036,9 +53036,9 @@ var require_getTSImportedNames = __commonJS({
53036
53036
  }
53037
53037
  });
53038
53038
 
53039
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/index.js
53039
+ // ../../rel54-runner-deps/node_modules/sucrase/dist/index.js
53040
53040
  var require_dist2 = __commonJS({
53041
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/sucrase/dist/index.js"(exports) {
53041
+ "../../rel54-runner-deps/node_modules/sucrase/dist/index.js"(exports) {
53042
53042
  "use strict";
53043
53043
  Object.defineProperty(exports, "__esModule", { value: true });
53044
53044
  function _interopRequireDefault(obj3) {
@@ -53151,15 +53151,15 @@ var require_dist2 = __commonJS({
53151
53151
  }
53152
53152
  });
53153
53153
 
53154
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/tailwindcss/dist/chunk-DCG7AFIE.mjs
53154
+ // ../../rel54-runner-deps/node_modules/tailwindcss/dist/chunk-DCG7AFIE.mjs
53155
53155
  var o;
53156
53156
  var init_chunk_DCG7AFIE = __esm({
53157
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/tailwindcss/dist/chunk-DCG7AFIE.mjs"() {
53157
+ "../../rel54-runner-deps/node_modules/tailwindcss/dist/chunk-DCG7AFIE.mjs"() {
53158
53158
  o = { inherit: "inherit", current: "currentcolor", transparent: "transparent", black: "#000", white: "#fff", slate: { 50: "oklch(98.4% 0.003 247.858)", 100: "oklch(96.8% 0.007 247.896)", 200: "oklch(92.9% 0.013 255.508)", 300: "oklch(86.9% 0.022 252.894)", 400: "oklch(70.4% 0.04 256.788)", 500: "oklch(55.4% 0.046 257.417)", 600: "oklch(44.6% 0.043 257.281)", 700: "oklch(37.2% 0.044 257.287)", 800: "oklch(27.9% 0.041 260.031)", 900: "oklch(20.8% 0.042 265.755)", 950: "oklch(12.9% 0.042 264.695)" }, gray: { 50: "oklch(98.5% 0.002 247.839)", 100: "oklch(96.7% 0.003 264.542)", 200: "oklch(92.8% 0.006 264.531)", 300: "oklch(87.2% 0.01 258.338)", 400: "oklch(70.7% 0.022 261.325)", 500: "oklch(55.1% 0.027 264.364)", 600: "oklch(44.6% 0.03 256.802)", 700: "oklch(37.3% 0.034 259.733)", 800: "oklch(27.8% 0.033 256.848)", 900: "oklch(21% 0.034 264.665)", 950: "oklch(13% 0.028 261.692)" }, zinc: { 50: "oklch(98.5% 0 none)", 100: "oklch(96.7% 0.001 286.375)", 200: "oklch(92% 0.004 286.32)", 300: "oklch(87.1% 0.006 286.286)", 400: "oklch(70.5% 0.015 286.067)", 500: "oklch(55.2% 0.016 285.938)", 600: "oklch(44.2% 0.017 285.786)", 700: "oklch(37% 0.013 285.805)", 800: "oklch(27.4% 0.006 286.033)", 900: "oklch(21% 0.006 285.885)", 950: "oklch(14.1% 0.005 285.823)" }, neutral: { 50: "oklch(98.5% 0 none)", 100: "oklch(97% 0 none)", 200: "oklch(92.2% 0 none)", 300: "oklch(87% 0 none)", 400: "oklch(70.8% 0 none)", 500: "oklch(55.6% 0 none)", 600: "oklch(43.9% 0 none)", 700: "oklch(37.1% 0 none)", 800: "oklch(26.9% 0 none)", 900: "oklch(20.5% 0 none)", 950: "oklch(14.5% 0 none)" }, stone: { 50: "oklch(98.5% 0.001 106.423)", 100: "oklch(97% 0.001 106.424)", 200: "oklch(92.3% 0.003 48.717)", 300: "oklch(86.9% 0.005 56.366)", 400: "oklch(70.9% 0.01 56.259)", 500: "oklch(55.3% 0.013 58.071)", 600: "oklch(44.4% 0.011 73.639)", 700: "oklch(37.4% 0.01 67.558)", 800: "oklch(26.8% 0.007 34.298)", 900: "oklch(21.6% 0.006 56.043)", 950: "oklch(14.7% 0.004 49.25)" }, mauve: { 50: "oklch(98.5% 0 none)", 100: "oklch(96% 0.003 325.6)", 200: "oklch(92.2% 0.005 325.62)", 300: "oklch(86.5% 0.012 325.68)", 400: "oklch(71.1% 0.019 323.02)", 500: "oklch(54.2% 0.034 322.5)", 600: "oklch(43.5% 0.029 321.78)", 700: "oklch(36.4% 0.029 323.89)", 800: "oklch(26.3% 0.024 320.12)", 900: "oklch(21.2% 0.019 322.12)", 950: "oklch(14.5% 0.008 326)" }, olive: { 50: "oklch(98.8% 0.003 106.5)", 100: "oklch(96.6% 0.005 106.5)", 200: "oklch(93% 0.007 106.5)", 300: "oklch(88% 0.011 106.6)", 400: "oklch(73.7% 0.021 106.9)", 500: "oklch(58% 0.031 107.3)", 600: "oklch(46.6% 0.025 107.3)", 700: "oklch(39.4% 0.023 107.4)", 800: "oklch(28.6% 0.016 107.4)", 900: "oklch(22.8% 0.013 107.4)", 950: "oklch(15.3% 0.006 107.1)" }, mist: { 50: "oklch(98.7% 0.002 197.1)", 100: "oklch(96.3% 0.002 197.1)", 200: "oklch(92.5% 0.005 214.3)", 300: "oklch(87.2% 0.007 219.6)", 400: "oklch(72.3% 0.014 214.4)", 500: "oklch(56% 0.021 213.5)", 600: "oklch(45% 0.017 213.2)", 700: "oklch(37.8% 0.015 216)", 800: "oklch(27.5% 0.011 216.9)", 900: "oklch(21.8% 0.008 223.9)", 950: "oklch(14.8% 0.004 228.8)" }, taupe: { 50: "oklch(98.6% 0.002 67.8)", 100: "oklch(96% 0.002 17.2)", 200: "oklch(92.2% 0.005 34.3)", 300: "oklch(86.8% 0.007 39.5)", 400: "oklch(71.4% 0.014 41.2)", 500: "oklch(54.7% 0.021 43.1)", 600: "oklch(43.8% 0.017 39.3)", 700: "oklch(36.7% 0.016 35.7)", 800: "oklch(26.8% 0.011 36.5)", 900: "oklch(21.4% 0.009 43.1)", 950: "oklch(14.7% 0.004 49.3)" }, red: { 50: "oklch(97.1% 0.013 17.38)", 100: "oklch(93.6% 0.032 17.717)", 200: "oklch(88.5% 0.062 18.334)", 300: "oklch(80.8% 0.114 19.571)", 400: "oklch(70.4% 0.191 22.216)", 500: "oklch(63.7% 0.237 25.331)", 600: "oklch(57.7% 0.245 27.325)", 700: "oklch(50.5% 0.213 27.518)", 800: "oklch(44.4% 0.177 26.899)", 900: "oklch(39.6% 0.141 25.723)", 950: "oklch(25.8% 0.092 26.042)" }, orange: { 50: "oklch(98% 0.016 73.684)", 100: "oklch(95.4% 0.038 75.164)", 200: "oklch(90.1% 0.076 70.697)", 300: "oklch(83.7% 0.128 66.29)", 400: "oklch(75% 0.183 55.934)", 500: "oklch(70.5% 0.213 47.604)", 600: "oklch(64.6% 0.222 41.116)", 700: "oklch(55.3% 0.195 38.402)", 800: "oklch(47% 0.157 37.304)", 900: "oklch(40.8% 0.123 38.172)", 950: "oklch(26.6% 0.079 36.259)" }, amber: { 50: "oklch(98.7% 0.022 95.277)", 100: "oklch(96.2% 0.059 95.617)", 200: "oklch(92.4% 0.12 95.746)", 300: "oklch(87.9% 0.169 91.605)", 400: "oklch(82.8% 0.189 84.429)", 500: "oklch(76.9% 0.188 70.08)", 600: "oklch(66.6% 0.179 58.318)", 700: "oklch(55.5% 0.163 48.998)", 800: "oklch(47.3% 0.137 46.201)", 900: "oklch(41.4% 0.112 45.904)", 950: "oklch(27.9% 0.077 45.635)" }, yellow: { 50: "oklch(98.7% 0.026 102.212)", 100: "oklch(97.3% 0.071 103.193)", 200: "oklch(94.5% 0.129 101.54)", 300: "oklch(90.5% 0.182 98.111)", 400: "oklch(85.2% 0.199 91.936)", 500: "oklch(79.5% 0.184 86.047)", 600: "oklch(68.1% 0.162 75.834)", 700: "oklch(55.4% 0.135 66.442)", 800: "oklch(47.6% 0.114 61.907)", 900: "oklch(42.1% 0.095 57.708)", 950: "oklch(28.6% 0.066 53.813)" }, lime: { 50: "oklch(98.6% 0.031 120.757)", 100: "oklch(96.7% 0.067 122.328)", 200: "oklch(93.8% 0.127 124.321)", 300: "oklch(89.7% 0.196 126.665)", 400: "oklch(84.1% 0.238 128.85)", 500: "oklch(76.8% 0.233 130.85)", 600: "oklch(64.8% 0.2 131.684)", 700: "oklch(53.2% 0.157 131.589)", 800: "oklch(45.3% 0.124 130.933)", 900: "oklch(40.5% 0.101 131.063)", 950: "oklch(27.4% 0.072 132.109)" }, green: { 50: "oklch(98.2% 0.018 155.826)", 100: "oklch(96.2% 0.044 156.743)", 200: "oklch(92.5% 0.084 155.995)", 300: "oklch(87.1% 0.15 154.449)", 400: "oklch(79.2% 0.209 151.711)", 500: "oklch(72.3% 0.219 149.579)", 600: "oklch(62.7% 0.194 149.214)", 700: "oklch(52.7% 0.154 150.069)", 800: "oklch(44.8% 0.119 151.328)", 900: "oklch(39.3% 0.095 152.535)", 950: "oklch(26.6% 0.065 152.934)" }, emerald: { 50: "oklch(97.9% 0.021 166.113)", 100: "oklch(95% 0.052 163.051)", 200: "oklch(90.5% 0.093 164.15)", 300: "oklch(84.5% 0.143 164.978)", 400: "oklch(76.5% 0.177 163.223)", 500: "oklch(69.6% 0.17 162.48)", 600: "oklch(59.6% 0.145 163.225)", 700: "oklch(50.8% 0.118 165.612)", 800: "oklch(43.2% 0.095 166.913)", 900: "oklch(37.8% 0.077 168.94)", 950: "oklch(26.2% 0.051 172.552)" }, teal: { 50: "oklch(98.4% 0.014 180.72)", 100: "oklch(95.3% 0.051 180.801)", 200: "oklch(91% 0.096 180.426)", 300: "oklch(85.5% 0.138 181.071)", 400: "oklch(77.7% 0.152 181.912)", 500: "oklch(70.4% 0.14 182.503)", 600: "oklch(60% 0.118 184.704)", 700: "oklch(51.1% 0.096 186.391)", 800: "oklch(43.7% 0.078 188.216)", 900: "oklch(38.6% 0.063 188.416)", 950: "oklch(27.7% 0.046 192.524)" }, cyan: { 50: "oklch(98.4% 0.019 200.873)", 100: "oklch(95.6% 0.045 203.388)", 200: "oklch(91.7% 0.08 205.041)", 300: "oklch(86.5% 0.127 207.078)", 400: "oklch(78.9% 0.154 211.53)", 500: "oklch(71.5% 0.143 215.221)", 600: "oklch(60.9% 0.126 221.723)", 700: "oklch(52% 0.105 223.128)", 800: "oklch(45% 0.085 224.283)", 900: "oklch(39.8% 0.07 227.392)", 950: "oklch(30.2% 0.056 229.695)" }, sky: { 50: "oklch(97.7% 0.013 236.62)", 100: "oklch(95.1% 0.026 236.824)", 200: "oklch(90.1% 0.058 230.902)", 300: "oklch(82.8% 0.111 230.318)", 400: "oklch(74.6% 0.16 232.661)", 500: "oklch(68.5% 0.169 237.323)", 600: "oklch(58.8% 0.158 241.966)", 700: "oklch(50% 0.134 242.749)", 800: "oklch(44.3% 0.11 240.79)", 900: "oklch(39.1% 0.09 240.876)", 950: "oklch(29.3% 0.066 243.157)" }, blue: { 50: "oklch(97% 0.014 254.604)", 100: "oklch(93.2% 0.032 255.585)", 200: "oklch(88.2% 0.059 254.128)", 300: "oklch(80.9% 0.105 251.813)", 400: "oklch(70.7% 0.165 254.624)", 500: "oklch(62.3% 0.214 259.815)", 600: "oklch(54.6% 0.245 262.881)", 700: "oklch(48.8% 0.243 264.376)", 800: "oklch(42.4% 0.199 265.638)", 900: "oklch(37.9% 0.146 265.522)", 950: "oklch(28.2% 0.091 267.935)" }, indigo: { 50: "oklch(96.2% 0.018 272.314)", 100: "oklch(93% 0.034 272.788)", 200: "oklch(87% 0.065 274.039)", 300: "oklch(78.5% 0.115 274.713)", 400: "oklch(67.3% 0.182 276.935)", 500: "oklch(58.5% 0.233 277.117)", 600: "oklch(51.1% 0.262 276.966)", 700: "oklch(45.7% 0.24 277.023)", 800: "oklch(39.8% 0.195 277.366)", 900: "oklch(35.9% 0.144 278.697)", 950: "oklch(25.7% 0.09 281.288)" }, violet: { 50: "oklch(96.9% 0.016 293.756)", 100: "oklch(94.3% 0.029 294.588)", 200: "oklch(89.4% 0.057 293.283)", 300: "oklch(81.1% 0.111 293.571)", 400: "oklch(70.2% 0.183 293.541)", 500: "oklch(60.6% 0.25 292.717)", 600: "oklch(54.1% 0.281 293.009)", 700: "oklch(49.1% 0.27 292.581)", 800: "oklch(43.2% 0.232 292.759)", 900: "oklch(38% 0.189 293.745)", 950: "oklch(28.3% 0.141 291.089)" }, purple: { 50: "oklch(97.7% 0.014 308.299)", 100: "oklch(94.6% 0.033 307.174)", 200: "oklch(90.2% 0.063 306.703)", 300: "oklch(82.7% 0.119 306.383)", 400: "oklch(71.4% 0.203 305.504)", 500: "oklch(62.7% 0.265 303.9)", 600: "oklch(55.8% 0.288 302.321)", 700: "oklch(49.6% 0.265 301.924)", 800: "oklch(43.8% 0.218 303.724)", 900: "oklch(38.1% 0.176 304.987)", 950: "oklch(29.1% 0.149 302.717)" }, fuchsia: { 50: "oklch(97.7% 0.017 320.058)", 100: "oklch(95.2% 0.037 318.852)", 200: "oklch(90.3% 0.076 319.62)", 300: "oklch(83.3% 0.145 321.434)", 400: "oklch(74% 0.238 322.16)", 500: "oklch(66.7% 0.295 322.15)", 600: "oklch(59.1% 0.293 322.896)", 700: "oklch(51.8% 0.253 323.949)", 800: "oklch(45.2% 0.211 324.591)", 900: "oklch(40.1% 0.17 325.612)", 950: "oklch(29.3% 0.136 325.661)" }, pink: { 50: "oklch(97.1% 0.014 343.198)", 100: "oklch(94.8% 0.028 342.258)", 200: "oklch(89.9% 0.061 343.231)", 300: "oklch(82.3% 0.12 346.018)", 400: "oklch(71.8% 0.202 349.761)", 500: "oklch(65.6% 0.241 354.308)", 600: "oklch(59.2% 0.249 0.584)", 700: "oklch(52.5% 0.223 3.958)", 800: "oklch(45.9% 0.187 3.815)", 900: "oklch(40.8% 0.153 2.432)", 950: "oklch(28.4% 0.109 3.907)" }, rose: { 50: "oklch(96.9% 0.015 12.422)", 100: "oklch(94.1% 0.03 12.58)", 200: "oklch(89.2% 0.058 10.001)", 300: "oklch(81% 0.117 11.638)", 400: "oklch(71.2% 0.194 13.428)", 500: "oklch(64.5% 0.246 16.439)", 600: "oklch(58.6% 0.253 17.585)", 700: "oklch(51.4% 0.222 16.935)", 800: "oklch(45.5% 0.188 13.697)", 900: "oklch(41% 0.159 10.272)", 950: "oklch(27.1% 0.105 12.094)" } };
53159
53159
  }
53160
53160
  });
53161
53161
 
53162
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/tailwindcss/dist/chunk-C2OYBFIH.mjs
53162
+ // ../../rel54-runner-deps/node_modules/tailwindcss/dist/chunk-C2OYBFIH.mjs
53163
53163
  function N(e2) {
53164
53164
  return e2.charCodeAt(0) === 35 || U.test(e2) || S.has(e2.toLowerCase());
53165
53165
  }
@@ -53379,7 +53379,7 @@ function h(e2) {
53379
53379
  }
53380
53380
  var S, U, A, E, P, z, I, D, x, W, q2, V, Z, j, K, J, X, te, g, l, f, L, w, ne, _, ye;
53381
53381
  var init_chunk_C2OYBFIH = __esm({
53382
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/tailwindcss/dist/chunk-C2OYBFIH.mjs"() {
53382
+ "../../rel54-runner-deps/node_modules/tailwindcss/dist/chunk-C2OYBFIH.mjs"() {
53383
53383
  init_chunk_DCG7AFIE();
53384
53384
  S = /* @__PURE__ */ new Set(["black", "silver", "gray", "white", "maroon", "red", "purple", "fuchsia", "green", "lime", "olive", "yellow", "navy", "blue", "teal", "aqua", "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkgrey", "darkkhaki", "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", "darkslateblue", "darkslategray", "darkslategrey", "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray", "dimgrey", "dodgerblue", "firebrick", "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold", "goldenrod", "gray", "green", "greenyellow", "grey", "honeydew", "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightgrey", "lightpink", "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightslategrey", "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", "slategrey", "snow", "springgreen", "steelblue", "tan", "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", "whitesmoke", "yellow", "yellowgreen", "transparent", "currentcolor", "canvas", "canvastext", "linktext", "visitedtext", "activetext", "buttonface", "buttontext", "buttonborder", "field", "fieldtext", "highlight", "highlighttext", "selecteditem", "selecteditemtext", "mark", "marktext", "graytext", "accentcolor", "accentcolortext"]);
53385
53385
  U = /^(rgba?|hsla?|hwb|color|(ok)?(lab|lch)|light-dark|color-mix|--alpha)\(/i;
@@ -53426,7 +53426,7 @@ var init_chunk_C2OYBFIH = __esm({
53426
53426
  }
53427
53427
  });
53428
53428
 
53429
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/tailwindcss/dist/chunk-5JIJA4QV.mjs
53429
+ // ../../rel54-runner-deps/node_modules/tailwindcss/dist/chunk-5JIJA4QV.mjs
53430
53430
  function h2(n) {
53431
53431
  if (arguments.length === 0) throw new TypeError("`CSS.escape` requires an argument.");
53432
53432
  let e2 = String(n), i = e2.length, r2 = -1, t2, s = "", l2 = e2.charCodeAt(0);
@@ -53460,7 +53460,7 @@ function g2(n, e2) {
53460
53460
  }
53461
53461
  var c, p;
53462
53462
  var init_chunk_5JIJA4QV = __esm({
53463
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/tailwindcss/dist/chunk-5JIJA4QV.mjs"() {
53463
+ "../../rel54-runner-deps/node_modules/tailwindcss/dist/chunk-5JIJA4QV.mjs"() {
53464
53464
  c = /* @__PURE__ */ new Map([["--font", ["--font-weight", "--font-size"]], ["--inset", ["--inset-shadow", "--inset-ring"]], ["--text", ["--text-color", "--text-decoration-color", "--text-decoration-thickness", "--text-indent", "--text-shadow", "--text-underline-offset"]], ["--grid-column", ["--grid-column-start", "--grid-column-end"]], ["--grid-row", ["--grid-row-start", "--grid-row-end"]]]);
53465
53465
  p = class {
53466
53466
  constructor(e2 = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Set([])) {
@@ -53580,7 +53580,7 @@ var init_chunk_5JIJA4QV = __esm({
53580
53580
  }
53581
53581
  });
53582
53582
 
53583
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/tailwindcss/dist/lib.mjs
53583
+ // ../../rel54-runner-deps/node_modules/tailwindcss/dist/lib.mjs
53584
53584
  function mn(e2) {
53585
53585
  return { kind: "combinator", value: e2 };
53586
53586
  }
@@ -58691,7 +58691,7 @@ async function zf(e2, i = {}) {
58691
58691
  }
58692
58692
  var yr, Cr, vn, Sr, Lt, Vr, wn, Rr, $r, Dt, Pr, zt, Tr, Nr, kn, Kt, Ut, Er, Or, jt, He, ct, pt, _r, Ir, bn, dt, me, mt, Ze, Je, Dr, Ft, Yt, Kr, yn, xn, Ur, Wt, An, ge2, U2, zr, Vn, jr, Mr, $n, Fr, Wr, Br, Yr, Tn, Nn, En, Gr, qr, qt, V2, Rn, Pn, On, In, Dn, Jt, Ln, Qr, Xr, ei, er, zn, jn, Fn, Bn, le, Yn, Gn, qn, Hn, yt, rr, oi, ir, fi, Zn, Jn, Qn, Xn, el, tl, rl, kt, bt, il, nl, nr, ci, gl, hl, vl, wi, ki, bi, Ti, lt, Ni, Ei, $l, Ri, Nl, Pi, Rl, or, Vt, _i, Ul, Fl, Wl, we, Vi, sr, $t, ur, Nt, Ki, fa, Et, fr, pr, Zi, wa, Aa, fn, Va, Ht, ze;
58693
58693
  var init_lib = __esm({
58694
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/tailwindcss/dist/lib.mjs"() {
58694
+ "../../rel54-runner-deps/node_modules/tailwindcss/dist/lib.mjs"() {
58695
58695
  init_chunk_C2OYBFIH();
58696
58696
  init_chunk_DCG7AFIE();
58697
58697
  init_chunk_5JIJA4QV();
@@ -59010,24 +59010,24 @@ var init_lib = __esm({
59010
59010
  }
59011
59011
  });
59012
59012
 
59013
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/tailwindcss/index.css
59013
+ // ../../rel54-runner-deps/node_modules/tailwindcss/index.css
59014
59014
  var tailwindcss_default;
59015
59015
  var init_tailwindcss = __esm({
59016
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/tailwindcss/index.css"() {
59016
+ "../../rel54-runner-deps/node_modules/tailwindcss/index.css"() {
59017
59017
  tailwindcss_default = '@layer theme, base, components, utilities;\n\n@layer theme {\n @theme default {\n --font-sans:\n -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",\n "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",\n "Segoe UI Symbol", "Noto Color Emoji";\n --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;\n --font-mono:\n ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",\n "Courier New", monospace;\n\n --color-red-50: oklch(97.1% 0.013 17.38);\n --color-red-100: oklch(93.6% 0.032 17.717);\n --color-red-200: oklch(88.5% 0.062 18.334);\n --color-red-300: oklch(80.8% 0.114 19.571);\n --color-red-400: oklch(70.4% 0.191 22.216);\n --color-red-500: oklch(63.7% 0.237 25.331);\n --color-red-600: oklch(57.7% 0.245 27.325);\n --color-red-700: oklch(50.5% 0.213 27.518);\n --color-red-800: oklch(44.4% 0.177 26.899);\n --color-red-900: oklch(39.6% 0.141 25.723);\n --color-red-950: oklch(25.8% 0.092 26.042);\n\n --color-orange-50: oklch(98% 0.016 73.684);\n --color-orange-100: oklch(95.4% 0.038 75.164);\n --color-orange-200: oklch(90.1% 0.076 70.697);\n --color-orange-300: oklch(83.7% 0.128 66.29);\n --color-orange-400: oklch(75% 0.183 55.934);\n --color-orange-500: oklch(70.5% 0.213 47.604);\n --color-orange-600: oklch(64.6% 0.222 41.116);\n --color-orange-700: oklch(55.3% 0.195 38.402);\n --color-orange-800: oklch(47% 0.157 37.304);\n --color-orange-900: oklch(40.8% 0.123 38.172);\n --color-orange-950: oklch(26.6% 0.079 36.259);\n\n --color-amber-50: oklch(98.7% 0.022 95.277);\n --color-amber-100: oklch(96.2% 0.059 95.617);\n --color-amber-200: oklch(92.4% 0.12 95.746);\n --color-amber-300: oklch(87.9% 0.169 91.605);\n --color-amber-400: oklch(82.8% 0.189 84.429);\n --color-amber-500: oklch(76.9% 0.188 70.08);\n --color-amber-600: oklch(66.6% 0.179 58.318);\n --color-amber-700: oklch(55.5% 0.163 48.998);\n --color-amber-800: oklch(47.3% 0.137 46.201);\n --color-amber-900: oklch(41.4% 0.112 45.904);\n --color-amber-950: oklch(27.9% 0.077 45.635);\n\n --color-yellow-50: oklch(98.7% 0.026 102.212);\n --color-yellow-100: oklch(97.3% 0.071 103.193);\n --color-yellow-200: oklch(94.5% 0.129 101.54);\n --color-yellow-300: oklch(90.5% 0.182 98.111);\n --color-yellow-400: oklch(85.2% 0.199 91.936);\n --color-yellow-500: oklch(79.5% 0.184 86.047);\n --color-yellow-600: oklch(68.1% 0.162 75.834);\n --color-yellow-700: oklch(55.4% 0.135 66.442);\n --color-yellow-800: oklch(47.6% 0.114 61.907);\n --color-yellow-900: oklch(42.1% 0.095 57.708);\n --color-yellow-950: oklch(28.6% 0.066 53.813);\n\n --color-lime-50: oklch(98.6% 0.031 120.757);\n --color-lime-100: oklch(96.7% 0.067 122.328);\n --color-lime-200: oklch(93.8% 0.127 124.321);\n --color-lime-300: oklch(89.7% 0.196 126.665);\n --color-lime-400: oklch(84.1% 0.238 128.85);\n --color-lime-500: oklch(76.8% 0.233 130.85);\n --color-lime-600: oklch(64.8% 0.2 131.684);\n --color-lime-700: oklch(53.2% 0.157 131.589);\n --color-lime-800: oklch(45.3% 0.124 130.933);\n --color-lime-900: oklch(40.5% 0.101 131.063);\n --color-lime-950: oklch(27.4% 0.072 132.109);\n\n --color-green-50: oklch(98.2% 0.018 155.826);\n --color-green-100: oklch(96.2% 0.044 156.743);\n --color-green-200: oklch(92.5% 0.084 155.995);\n --color-green-300: oklch(87.1% 0.15 154.449);\n --color-green-400: oklch(79.2% 0.209 151.711);\n --color-green-500: oklch(72.3% 0.219 149.579);\n --color-green-600: oklch(62.7% 0.194 149.214);\n --color-green-700: oklch(52.7% 0.154 150.069);\n --color-green-800: oklch(44.8% 0.119 151.328);\n --color-green-900: oklch(39.3% 0.095 152.535);\n --color-green-950: oklch(26.6% 0.065 152.934);\n\n --color-emerald-50: oklch(97.9% 0.021 166.113);\n --color-emerald-100: oklch(95% 0.052 163.051);\n --color-emerald-200: oklch(90.5% 0.093 164.15);\n --color-emerald-300: oklch(84.5% 0.143 164.978);\n --color-emerald-400: oklch(76.5% 0.177 163.223);\n --color-emerald-500: oklch(69.6% 0.17 162.48);\n --color-emerald-600: oklch(59.6% 0.145 163.225);\n --color-emerald-700: oklch(50.8% 0.118 165.612);\n --color-emerald-800: oklch(43.2% 0.095 166.913);\n --color-emerald-900: oklch(37.8% 0.077 168.94);\n --color-emerald-950: oklch(26.2% 0.051 172.552);\n\n --color-teal-50: oklch(98.4% 0.014 180.72);\n --color-teal-100: oklch(95.3% 0.051 180.801);\n --color-teal-200: oklch(91% 0.096 180.426);\n --color-teal-300: oklch(85.5% 0.138 181.071);\n --color-teal-400: oklch(77.7% 0.152 181.912);\n --color-teal-500: oklch(70.4% 0.14 182.503);\n --color-teal-600: oklch(60% 0.118 184.704);\n --color-teal-700: oklch(51.1% 0.096 186.391);\n --color-teal-800: oklch(43.7% 0.078 188.216);\n --color-teal-900: oklch(38.6% 0.063 188.416);\n --color-teal-950: oklch(27.7% 0.046 192.524);\n\n --color-cyan-50: oklch(98.4% 0.019 200.873);\n --color-cyan-100: oklch(95.6% 0.045 203.388);\n --color-cyan-200: oklch(91.7% 0.08 205.041);\n --color-cyan-300: oklch(86.5% 0.127 207.078);\n --color-cyan-400: oklch(78.9% 0.154 211.53);\n --color-cyan-500: oklch(71.5% 0.143 215.221);\n --color-cyan-600: oklch(60.9% 0.126 221.723);\n --color-cyan-700: oklch(52% 0.105 223.128);\n --color-cyan-800: oklch(45% 0.085 224.283);\n --color-cyan-900: oklch(39.8% 0.07 227.392);\n --color-cyan-950: oklch(30.2% 0.056 229.695);\n\n --color-sky-50: oklch(97.7% 0.013 236.62);\n --color-sky-100: oklch(95.1% 0.026 236.824);\n --color-sky-200: oklch(90.1% 0.058 230.902);\n --color-sky-300: oklch(82.8% 0.111 230.318);\n --color-sky-400: oklch(74.6% 0.16 232.661);\n --color-sky-500: oklch(68.5% 0.169 237.323);\n --color-sky-600: oklch(58.8% 0.158 241.966);\n --color-sky-700: oklch(50% 0.134 242.749);\n --color-sky-800: oklch(44.3% 0.11 240.79);\n --color-sky-900: oklch(39.1% 0.09 240.876);\n --color-sky-950: oklch(29.3% 0.066 243.157);\n\n --color-blue-50: oklch(97% 0.014 254.604);\n --color-blue-100: oklch(93.2% 0.032 255.585);\n --color-blue-200: oklch(88.2% 0.059 254.128);\n --color-blue-300: oklch(80.9% 0.105 251.813);\n --color-blue-400: oklch(70.7% 0.165 254.624);\n --color-blue-500: oklch(62.3% 0.214 259.815);\n --color-blue-600: oklch(54.6% 0.245 262.881);\n --color-blue-700: oklch(48.8% 0.243 264.376);\n --color-blue-800: oklch(42.4% 0.199 265.638);\n --color-blue-900: oklch(37.9% 0.146 265.522);\n --color-blue-950: oklch(28.2% 0.091 267.935);\n\n --color-indigo-50: oklch(96.2% 0.018 272.314);\n --color-indigo-100: oklch(93% 0.034 272.788);\n --color-indigo-200: oklch(87% 0.065 274.039);\n --color-indigo-300: oklch(78.5% 0.115 274.713);\n --color-indigo-400: oklch(67.3% 0.182 276.935);\n --color-indigo-500: oklch(58.5% 0.233 277.117);\n --color-indigo-600: oklch(51.1% 0.262 276.966);\n --color-indigo-700: oklch(45.7% 0.24 277.023);\n --color-indigo-800: oklch(39.8% 0.195 277.366);\n --color-indigo-900: oklch(35.9% 0.144 278.697);\n --color-indigo-950: oklch(25.7% 0.09 281.288);\n\n --color-violet-50: oklch(96.9% 0.016 293.756);\n --color-violet-100: oklch(94.3% 0.029 294.588);\n --color-violet-200: oklch(89.4% 0.057 293.283);\n --color-violet-300: oklch(81.1% 0.111 293.571);\n --color-violet-400: oklch(70.2% 0.183 293.541);\n --color-violet-500: oklch(60.6% 0.25 292.717);\n --color-violet-600: oklch(54.1% 0.281 293.009);\n --color-violet-700: oklch(49.1% 0.27 292.581);\n --color-violet-800: oklch(43.2% 0.232 292.759);\n --color-violet-900: oklch(38% 0.189 293.745);\n --color-violet-950: oklch(28.3% 0.141 291.089);\n\n --color-purple-50: oklch(97.7% 0.014 308.299);\n --color-purple-100: oklch(94.6% 0.033 307.174);\n --color-purple-200: oklch(90.2% 0.063 306.703);\n --color-purple-300: oklch(82.7% 0.119 306.383);\n --color-purple-400: oklch(71.4% 0.203 305.504);\n --color-purple-500: oklch(62.7% 0.265 303.9);\n --color-purple-600: oklch(55.8% 0.288 302.321);\n --color-purple-700: oklch(49.6% 0.265 301.924);\n --color-purple-800: oklch(43.8% 0.218 303.724);\n --color-purple-900: oklch(38.1% 0.176 304.987);\n --color-purple-950: oklch(29.1% 0.149 302.717);\n\n --color-fuchsia-50: oklch(97.7% 0.017 320.058);\n --color-fuchsia-100: oklch(95.2% 0.037 318.852);\n --color-fuchsia-200: oklch(90.3% 0.076 319.62);\n --color-fuchsia-300: oklch(83.3% 0.145 321.434);\n --color-fuchsia-400: oklch(74% 0.238 322.16);\n --color-fuchsia-500: oklch(66.7% 0.295 322.15);\n --color-fuchsia-600: oklch(59.1% 0.293 322.896);\n --color-fuchsia-700: oklch(51.8% 0.253 323.949);\n --color-fuchsia-800: oklch(45.2% 0.211 324.591);\n --color-fuchsia-900: oklch(40.1% 0.17 325.612);\n --color-fuchsia-950: oklch(29.3% 0.136 325.661);\n\n --color-pink-50: oklch(97.1% 0.014 343.198);\n --color-pink-100: oklch(94.8% 0.028 342.258);\n --color-pink-200: oklch(89.9% 0.061 343.231);\n --color-pink-300: oklch(82.3% 0.12 346.018);\n --color-pink-400: oklch(71.8% 0.202 349.761);\n --color-pink-500: oklch(65.6% 0.241 354.308);\n --color-pink-600: oklch(59.2% 0.249 0.584);\n --color-pink-700: oklch(52.5% 0.223 3.958);\n --color-pink-800: oklch(45.9% 0.187 3.815);\n --color-pink-900: oklch(40.8% 0.153 2.432);\n --color-pink-950: oklch(28.4% 0.109 3.907);\n\n --color-rose-50: oklch(96.9% 0.015 12.422);\n --color-rose-100: oklch(94.1% 0.03 12.58);\n --color-rose-200: oklch(89.2% 0.058 10.001);\n --color-rose-300: oklch(81% 0.117 11.638);\n --color-rose-400: oklch(71.2% 0.194 13.428);\n --color-rose-500: oklch(64.5% 0.246 16.439);\n --color-rose-600: oklch(58.6% 0.253 17.585);\n --color-rose-700: oklch(51.4% 0.222 16.935);\n --color-rose-800: oklch(45.5% 0.188 13.697);\n --color-rose-900: oklch(41% 0.159 10.272);\n --color-rose-950: oklch(27.1% 0.105 12.094);\n\n --color-slate-50: oklch(98.4% 0.003 247.858);\n --color-slate-100: oklch(96.8% 0.007 247.896);\n --color-slate-200: oklch(92.9% 0.013 255.508);\n --color-slate-300: oklch(86.9% 0.022 252.894);\n --color-slate-400: oklch(70.4% 0.04 256.788);\n --color-slate-500: oklch(55.4% 0.046 257.417);\n --color-slate-600: oklch(44.6% 0.043 257.281);\n --color-slate-700: oklch(37.2% 0.044 257.287);\n --color-slate-800: oklch(27.9% 0.041 260.031);\n --color-slate-900: oklch(20.8% 0.042 265.755);\n --color-slate-950: oklch(12.9% 0.042 264.695);\n\n --color-gray-50: oklch(98.5% 0.002 247.839);\n --color-gray-100: oklch(96.7% 0.003 264.542);\n --color-gray-200: oklch(92.8% 0.006 264.531);\n --color-gray-300: oklch(87.2% 0.01 258.338);\n --color-gray-400: oklch(70.7% 0.022 261.325);\n --color-gray-500: oklch(55.1% 0.027 264.364);\n --color-gray-600: oklch(44.6% 0.03 256.802);\n --color-gray-700: oklch(37.3% 0.034 259.733);\n --color-gray-800: oklch(27.8% 0.033 256.848);\n --color-gray-900: oklch(21% 0.034 264.665);\n --color-gray-950: oklch(13% 0.028 261.692);\n\n --color-zinc-50: oklch(98.5% 0 none);\n --color-zinc-100: oklch(96.7% 0.001 286.375);\n --color-zinc-200: oklch(92% 0.004 286.32);\n --color-zinc-300: oklch(87.1% 0.006 286.286);\n --color-zinc-400: oklch(70.5% 0.015 286.067);\n --color-zinc-500: oklch(55.2% 0.016 285.938);\n --color-zinc-600: oklch(44.2% 0.017 285.786);\n --color-zinc-700: oklch(37% 0.013 285.805);\n --color-zinc-800: oklch(27.4% 0.006 286.033);\n --color-zinc-900: oklch(21% 0.006 285.885);\n --color-zinc-950: oklch(14.1% 0.005 285.823);\n\n --color-neutral-50: oklch(98.5% 0 none);\n --color-neutral-100: oklch(97% 0 none);\n --color-neutral-200: oklch(92.2% 0 none);\n --color-neutral-300: oklch(87% 0 none);\n --color-neutral-400: oklch(70.8% 0 none);\n --color-neutral-500: oklch(55.6% 0 none);\n --color-neutral-600: oklch(43.9% 0 none);\n --color-neutral-700: oklch(37.1% 0 none);\n --color-neutral-800: oklch(26.9% 0 none);\n --color-neutral-900: oklch(20.5% 0 none);\n --color-neutral-950: oklch(14.5% 0 none);\n\n --color-stone-50: oklch(98.5% 0.001 106.423);\n --color-stone-100: oklch(97% 0.001 106.424);\n --color-stone-200: oklch(92.3% 0.003 48.717);\n --color-stone-300: oklch(86.9% 0.005 56.366);\n --color-stone-400: oklch(70.9% 0.01 56.259);\n --color-stone-500: oklch(55.3% 0.013 58.071);\n --color-stone-600: oklch(44.4% 0.011 73.639);\n --color-stone-700: oklch(37.4% 0.01 67.558);\n --color-stone-800: oklch(26.8% 0.007 34.298);\n --color-stone-900: oklch(21.6% 0.006 56.043);\n --color-stone-950: oklch(14.7% 0.004 49.25);\n\n --color-mauve-50: oklch(98.5% 0 none);\n --color-mauve-100: oklch(96% 0.003 325.6);\n --color-mauve-200: oklch(92.2% 0.005 325.62);\n --color-mauve-300: oklch(86.5% 0.012 325.68);\n --color-mauve-400: oklch(71.1% 0.019 323.02);\n --color-mauve-500: oklch(54.2% 0.034 322.5);\n --color-mauve-600: oklch(43.5% 0.029 321.78);\n --color-mauve-700: oklch(36.4% 0.029 323.89);\n --color-mauve-800: oklch(26.3% 0.024 320.12);\n --color-mauve-900: oklch(21.2% 0.019 322.12);\n --color-mauve-950: oklch(14.5% 0.008 326);\n\n --color-olive-50: oklch(98.8% 0.003 106.5);\n --color-olive-100: oklch(96.6% 0.005 106.5);\n --color-olive-200: oklch(93% 0.007 106.5);\n --color-olive-300: oklch(88% 0.011 106.6);\n --color-olive-400: oklch(73.7% 0.021 106.9);\n --color-olive-500: oklch(58% 0.031 107.3);\n --color-olive-600: oklch(46.6% 0.025 107.3);\n --color-olive-700: oklch(39.4% 0.023 107.4);\n --color-olive-800: oklch(28.6% 0.016 107.4);\n --color-olive-900: oklch(22.8% 0.013 107.4);\n --color-olive-950: oklch(15.3% 0.006 107.1);\n\n --color-mist-50: oklch(98.7% 0.002 197.1);\n --color-mist-100: oklch(96.3% 0.002 197.1);\n --color-mist-200: oklch(92.5% 0.005 214.3);\n --color-mist-300: oklch(87.2% 0.007 219.6);\n --color-mist-400: oklch(72.3% 0.014 214.4);\n --color-mist-500: oklch(56% 0.021 213.5);\n --color-mist-600: oklch(45% 0.017 213.2);\n --color-mist-700: oklch(37.8% 0.015 216);\n --color-mist-800: oklch(27.5% 0.011 216.9);\n --color-mist-900: oklch(21.8% 0.008 223.9);\n --color-mist-950: oklch(14.8% 0.004 228.8);\n\n --color-taupe-50: oklch(98.6% 0.002 67.8);\n --color-taupe-100: oklch(96% 0.002 17.2);\n --color-taupe-200: oklch(92.2% 0.005 34.3);\n --color-taupe-300: oklch(86.8% 0.007 39.5);\n --color-taupe-400: oklch(71.4% 0.014 41.2);\n --color-taupe-500: oklch(54.7% 0.021 43.1);\n --color-taupe-600: oklch(43.8% 0.017 39.3);\n --color-taupe-700: oklch(36.7% 0.016 35.7);\n --color-taupe-800: oklch(26.8% 0.011 36.5);\n --color-taupe-900: oklch(21.4% 0.009 43.1);\n --color-taupe-950: oklch(14.7% 0.004 49.3);\n\n --color-black: #000;\n --color-white: #fff;\n\n --spacing: 0.25rem;\n\n --breakpoint-sm: 40rem;\n --breakpoint-md: 48rem;\n --breakpoint-lg: 64rem;\n --breakpoint-xl: 80rem;\n --breakpoint-2xl: 96rem;\n\n --container-3xs: 16rem;\n --container-2xs: 18rem;\n --container-xs: 20rem;\n --container-sm: 24rem;\n --container-md: 28rem;\n --container-lg: 32rem;\n --container-xl: 36rem;\n --container-2xl: 42rem;\n --container-3xl: 48rem;\n --container-4xl: 56rem;\n --container-5xl: 64rem;\n --container-6xl: 72rem;\n --container-7xl: 80rem;\n\n --text-xs: 0.75rem;\n --text-xs--line-height: calc(1 / 0.75);\n --text-sm: 0.875rem;\n --text-sm--line-height: calc(1.25 / 0.875);\n --text-base: 1rem;\n --text-base--line-height: calc(1.5 / 1);\n --text-lg: 1.125rem;\n --text-lg--line-height: calc(1.75 / 1.125);\n --text-xl: 1.25rem;\n --text-xl--line-height: calc(1.75 / 1.25);\n --text-2xl: 1.5rem;\n --text-2xl--line-height: calc(2 / 1.5);\n --text-3xl: 1.875rem;\n --text-3xl--line-height: calc(2.25 / 1.875);\n --text-4xl: 2.25rem;\n --text-4xl--line-height: calc(2.5 / 2.25);\n --text-5xl: 3rem;\n --text-5xl--line-height: 1;\n --text-6xl: 3.75rem;\n --text-6xl--line-height: 1;\n --text-7xl: 4.5rem;\n --text-7xl--line-height: 1;\n --text-8xl: 6rem;\n --text-8xl--line-height: 1;\n --text-9xl: 8rem;\n --text-9xl--line-height: 1;\n\n --font-weight-thin: 100;\n --font-weight-extralight: 200;\n --font-weight-light: 300;\n --font-weight-normal: 400;\n --font-weight-medium: 500;\n --font-weight-semibold: 600;\n --font-weight-bold: 700;\n --font-weight-extrabold: 800;\n --font-weight-black: 900;\n\n --tracking-tighter: -0.05em;\n --tracking-tight: -0.025em;\n --tracking-normal: 0em;\n --tracking-wide: 0.025em;\n --tracking-wider: 0.05em;\n --tracking-widest: 0.1em;\n\n --leading-tight: 1.25;\n --leading-snug: 1.375;\n --leading-normal: 1.5;\n --leading-relaxed: 1.625;\n --leading-loose: 2;\n\n --radius-xs: 0.125rem;\n --radius-sm: 0.25rem;\n --radius-md: 0.375rem;\n --radius-lg: 0.5rem;\n --radius-xl: 0.75rem;\n --radius-2xl: 1rem;\n --radius-3xl: 1.5rem;\n --radius-4xl: 2rem;\n\n --shadow-2xs: 0 1px rgb(0 0 0 / 0.05);\n --shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.05);\n --shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);\n --shadow-md:\n 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);\n --shadow-lg:\n 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);\n --shadow-xl:\n 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);\n --shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);\n\n --inset-shadow-2xs: inset 0 1px rgb(0 0 0 / 0.05);\n --inset-shadow-xs: inset 0 1px 1px rgb(0 0 0 / 0.05);\n --inset-shadow-sm: inset 0 2px 4px rgb(0 0 0 / 0.05);\n\n --drop-shadow-xs: 0 1px 1px rgb(0 0 0 / 0.05);\n --drop-shadow-sm: 0 1px 2px rgb(0 0 0 / 0.15);\n --drop-shadow-md: 0 3px 3px rgb(0 0 0 / 0.12);\n --drop-shadow-lg: 0 4px 4px rgb(0 0 0 / 0.15);\n --drop-shadow-xl: 0 9px 7px rgb(0 0 0 / 0.1);\n --drop-shadow-2xl: 0 25px 25px rgb(0 0 0 / 0.15);\n\n --text-shadow-2xs: 0px 1px 0px rgb(0 0 0 / 0.15);\n --text-shadow-xs: 0px 1px 1px rgb(0 0 0 / 0.2);\n --text-shadow-sm:\n 0px 1px 0px rgb(0 0 0 / 0.075), 0px 1px 1px rgb(0 0 0 / 0.075),\n 0px 2px 2px rgb(0 0 0 / 0.075);\n --text-shadow-md:\n 0px 1px 1px rgb(0 0 0 / 0.1), 0px 1px 2px rgb(0 0 0 / 0.1),\n 0px 2px 4px rgb(0 0 0 / 0.1);\n --text-shadow-lg:\n 0px 1px 2px rgb(0 0 0 / 0.1), 0px 3px 2px rgb(0 0 0 / 0.1),\n 0px 4px 8px rgb(0 0 0 / 0.1);\n\n --ease-in: cubic-bezier(0.4, 0, 1, 1);\n --ease-out: cubic-bezier(0, 0, 0.2, 1);\n --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);\n\n --animate-spin: spin 1s linear infinite;\n --animate-ping: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;\n --animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n --animate-bounce: bounce 1s infinite;\n\n @keyframes spin {\n to {\n transform: rotate(360deg);\n }\n }\n\n @keyframes ping {\n 75%,\n 100% {\n transform: scale(2);\n opacity: 0;\n }\n }\n\n @keyframes pulse {\n 50% {\n opacity: 0.5;\n }\n }\n\n @keyframes bounce {\n 0%,\n 100% {\n transform: translateY(-25%);\n animation-timing-function: cubic-bezier(0.8, 0, 1, 1);\n }\n\n 50% {\n transform: none;\n animation-timing-function: cubic-bezier(0, 0, 0.2, 1);\n }\n }\n\n --blur-xs: 4px;\n --blur-sm: 8px;\n --blur-md: 12px;\n --blur-lg: 16px;\n --blur-xl: 24px;\n --blur-2xl: 40px;\n --blur-3xl: 64px;\n\n --perspective-dramatic: 100px;\n --perspective-near: 300px;\n --perspective-normal: 500px;\n --perspective-midrange: 800px;\n --perspective-distant: 1200px;\n\n --aspect-video: 16 / 9;\n\n --default-transition-duration: 150ms;\n --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n --default-font-family: --theme(--font-sans, initial);\n --default-font-feature-settings: --theme(\n --font-sans--font-feature-settings,\n initial\n );\n --default-font-variation-settings: --theme(\n --font-sans--font-variation-settings,\n initial\n );\n --default-mono-font-family: --theme(--font-mono, initial);\n --default-mono-font-feature-settings: --theme(\n --font-mono--font-feature-settings,\n initial\n );\n --default-mono-font-variation-settings: --theme(\n --font-mono--font-variation-settings,\n initial\n );\n }\n\n /* Deprecated */\n @theme default inline reference {\n --blur: 8px;\n --shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);\n --shadow-inner: inset 0 2px 4px 0 rgb(0 0 0 / 0.05);\n --drop-shadow: 0 1px 2px rgb(0 0 0 / 0.1), 0 1px 1px rgb(0 0 0 / 0.06);\n --radius: 0.25rem;\n --max-width-prose: 65ch;\n }\n}\n\n@layer base {\n /*\n 1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)\n 2. Remove default margins and padding\n 3. Reset all borders.\n*/\n\n *,\n ::after,\n ::before,\n ::backdrop,\n ::file-selector-button {\n box-sizing: border-box; /* 1 */\n margin: 0; /* 2 */\n padding: 0; /* 2 */\n border: 0 solid; /* 3 */\n }\n\n /*\n 1. Use a consistent sensible line-height in all browsers.\n 2. Prevent adjustments of font size after orientation changes in iOS.\n 3. Use a more readable tab size.\n 4. Use the user\'s configured `sans` font-family by default.\n 5. Use the user\'s configured `sans` font-feature-settings by default.\n 6. Use the user\'s configured `sans` font-variation-settings by default.\n 7. Disable tap highlights on iOS.\n*/\n\n html,\n :host {\n line-height: 1.5; /* 1 */\n -webkit-text-size-adjust: 100%; /* 2 */\n tab-size: 4; /* 3 */\n font-family: --theme(\n --default-font-family,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n Roboto,\n "Helvetica Neue",\n "Noto Sans",\n Arial,\n sans-serif,\n "Apple Color Emoji",\n "Segoe UI Emoji",\n "Segoe UI Symbol",\n "Noto Color Emoji"\n ); /* 4 */\n font-feature-settings: --theme(\n --default-font-feature-settings,\n normal\n ); /* 5 */\n font-variation-settings: --theme(\n --default-font-variation-settings,\n normal\n ); /* 6 */\n -webkit-tap-highlight-color: transparent; /* 7 */\n }\n\n /*\n 1. Add the correct height in Firefox.\n 2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)\n 3. Reset the default border style to a 1px solid border.\n*/\n\n hr {\n height: 0; /* 1 */\n color: inherit; /* 2 */\n border-top-width: 1px; /* 3 */\n }\n\n /*\n Add the correct text decoration in Chrome, Edge, and Safari.\n*/\n\n abbr:where([title]) {\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n }\n\n /*\n Remove the default font size and weight for headings.\n*/\n\n h1,\n h2,\n h3,\n h4,\n h5,\n h6 {\n font-size: inherit;\n font-weight: inherit;\n }\n\n /*\n Reset links to optimize for opt-in styling instead of opt-out.\n*/\n\n a {\n color: inherit;\n -webkit-text-decoration: inherit;\n text-decoration: inherit;\n }\n\n /*\n Add the correct font weight in Edge and Safari.\n*/\n\n b,\n strong {\n font-weight: bolder;\n }\n\n /*\n 1. Use the user\'s configured `mono` font-family by default.\n 2. Use the user\'s configured `mono` font-feature-settings by default.\n 3. Use the user\'s configured `mono` font-variation-settings by default.\n 4. Correct the odd `em` font sizing in all browsers.\n*/\n\n code,\n kbd,\n samp,\n pre {\n font-family: --theme(\n --default-mono-font-family,\n ui-monospace,\n SFMono-Regular,\n Menlo,\n Monaco,\n Consolas,\n "Liberation Mono",\n "Courier New",\n monospace\n ); /* 1 */\n font-feature-settings: --theme(\n --default-mono-font-feature-settings,\n normal\n ); /* 2 */\n font-variation-settings: --theme(\n --default-mono-font-variation-settings,\n normal\n ); /* 3 */\n font-size: 1em; /* 4 */\n }\n\n /*\n Add the correct font size in all browsers.\n*/\n\n small {\n font-size: 80%;\n }\n\n /*\n Prevent `sub` and `sup` elements from affecting the line height in all browsers.\n*/\n\n sub,\n sup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n }\n\n sub {\n bottom: -0.25em;\n }\n\n sup {\n top: -0.5em;\n }\n\n /*\n 1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)\n 2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)\n 3. Remove gaps between table borders by default.\n*/\n\n table {\n text-indent: 0; /* 1 */\n border-color: inherit; /* 2 */\n border-collapse: collapse; /* 3 */\n }\n\n /*\n Use the modern Firefox focus style for all focusable elements.\n*/\n\n :-moz-focusring:where(:not(iframe)) {\n outline: auto;\n }\n\n /*\n Add the correct vertical alignment in Chrome and Firefox.\n*/\n\n progress {\n vertical-align: baseline;\n }\n\n /*\n Add the correct display in Chrome and Safari.\n*/\n\n summary {\n display: list-item;\n }\n\n /*\n Make lists unstyled by default.\n*/\n\n ol,\n ul,\n menu {\n list-style: none;\n }\n\n /*\n 1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)\n 2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)\n This can trigger a poorly considered lint error in some tools but is included by design.\n*/\n\n img,\n svg,\n video,\n canvas,\n audio,\n iframe,\n embed,\n object {\n display: block; /* 1 */\n vertical-align: middle; /* 2 */\n }\n\n /*\n Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)\n*/\n\n img,\n video {\n max-width: 100%;\n height: auto;\n }\n\n /*\n 1. Inherit font styles in all browsers.\n 2. Remove border radius in all browsers.\n 3. Remove background color in all browsers.\n 4. Ensure consistent opacity for disabled states in all browsers.\n*/\n\n button,\n input,\n select,\n optgroup,\n textarea,\n ::file-selector-button {\n font: inherit; /* 1 */\n font-feature-settings: inherit; /* 1 */\n font-variation-settings: inherit; /* 1 */\n letter-spacing: inherit; /* 1 */\n color: inherit; /* 1 */\n border-radius: 0; /* 2 */\n background-color: transparent; /* 3 */\n opacity: 1; /* 4 */\n }\n\n /*\n Restore default font weight.\n*/\n\n :where(select:is([multiple], [size])) optgroup {\n font-weight: bolder;\n }\n\n /*\n Restore indentation.\n*/\n\n :where(select:is([multiple], [size])) optgroup option {\n padding-inline-start: 20px;\n }\n\n /*\n Restore space after button.\n*/\n\n ::file-selector-button {\n margin-inline-end: 4px;\n }\n\n /*\n Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)\n*/\n\n ::placeholder {\n opacity: 1;\n }\n\n /*\n Set the default placeholder color to a semi-transparent version of the current text color in browsers that do not\n crash when using `color-mix(\u2026)` with `currentcolor`. (https://github.com/tailwindlabs/tailwindcss/issues/17194)\n*/\n\n @supports (not (-webkit-appearance: -apple-pay-button)) /* Not Safari */ or\n (contain-intrinsic-size: 1px) /* Safari 17+ */ {\n ::placeholder {\n color: color-mix(in oklab, currentcolor 50%, transparent);\n }\n }\n\n /*\n Prevent resizing textareas horizontally by default.\n*/\n\n textarea {\n resize: vertical;\n }\n\n /*\n Remove the inner padding in Chrome and Safari on macOS.\n*/\n\n ::-webkit-search-decoration {\n -webkit-appearance: none;\n }\n\n /*\n 1. Ensure date/time inputs have the same height when empty in iOS Safari.\n 2. Ensure text alignment can be changed on date/time inputs in iOS Safari.\n*/\n\n ::-webkit-date-and-time-value {\n min-height: 1lh; /* 1 */\n text-align: inherit; /* 2 */\n }\n\n /*\n Prevent height from changing on date/time inputs in macOS Safari when the input is set to `display: block`.\n*/\n\n ::-webkit-datetime-edit {\n display: inline-flex;\n }\n\n /*\n Remove excess padding from pseudo-elements in date/time inputs to ensure consistent height across browsers.\n*/\n\n ::-webkit-datetime-edit-fields-wrapper {\n padding: 0;\n }\n\n ::-webkit-datetime-edit,\n ::-webkit-datetime-edit-year-field,\n ::-webkit-datetime-edit-month-field,\n ::-webkit-datetime-edit-day-field,\n ::-webkit-datetime-edit-hour-field,\n ::-webkit-datetime-edit-minute-field,\n ::-webkit-datetime-edit-second-field,\n ::-webkit-datetime-edit-millisecond-field,\n ::-webkit-datetime-edit-meridiem-field {\n padding-block: 0;\n }\n\n /*\n Center dropdown marker shown on inputs with paired `<datalist>`s in Chrome. (https://github.com/tailwindlabs/tailwindcss/issues/18499)\n*/\n\n ::-webkit-calendar-picker-indicator {\n line-height: 1;\n }\n\n /*\n Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)\n*/\n\n :-moz-ui-invalid {\n box-shadow: none;\n }\n\n /*\n Correct the inability to style the border radius in iOS Safari.\n*/\n\n button,\n input:where([type="button"], [type="reset"], [type="submit"]),\n ::file-selector-button {\n appearance: button;\n }\n\n /*\n Correct the cursor style of increment and decrement buttons in Safari.\n*/\n\n ::-webkit-inner-spin-button,\n ::-webkit-outer-spin-button {\n height: auto;\n }\n\n /*\n Make elements with the HTML hidden attribute stay hidden by default.\n*/\n\n [hidden]:where(:not([hidden="until-found"])) {\n display: none !important;\n }\n}\n\n@layer utilities {\n @tailwind utilities;\n}\n';
59018
59018
  }
59019
59019
  });
59020
59020
 
59021
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-icons/lib/iconsManifest.mjs
59021
+ // ../../rel54-runner-deps/node_modules/react-icons/lib/iconsManifest.mjs
59022
59022
  var init_iconsManifest = __esm({
59023
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-icons/lib/iconsManifest.mjs"() {
59023
+ "../../rel54-runner-deps/node_modules/react-icons/lib/iconsManifest.mjs"() {
59024
59024
  }
59025
59025
  });
59026
59026
 
59027
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-icons/lib/iconContext.mjs
59027
+ // ../../rel54-runner-deps/node_modules/react-icons/lib/iconContext.mjs
59028
59028
  var import_react, DefaultContext, IconContext;
59029
59029
  var init_iconContext = __esm({
59030
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-icons/lib/iconContext.mjs"() {
59030
+ "../../rel54-runner-deps/node_modules/react-icons/lib/iconContext.mjs"() {
59031
59031
  import_react = __toESM(require_react(), 1);
59032
59032
  DefaultContext = {
59033
59033
  color: void 0,
@@ -59040,7 +59040,7 @@ var init_iconContext = __esm({
59040
59040
  }
59041
59041
  });
59042
59042
 
59043
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-icons/lib/iconBase.mjs
59043
+ // ../../rel54-runner-deps/node_modules/react-icons/lib/iconBase.mjs
59044
59044
  function _objectWithoutProperties(e2, t2) {
59045
59045
  if (null == e2) return {};
59046
59046
  var o2, r2, i = _objectWithoutPropertiesLoose(e2, t2);
@@ -59141,23 +59141,23 @@ function IconBase(props) {
59141
59141
  }
59142
59142
  var import_react2, _excluded;
59143
59143
  var init_iconBase = __esm({
59144
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-icons/lib/iconBase.mjs"() {
59144
+ "../../rel54-runner-deps/node_modules/react-icons/lib/iconBase.mjs"() {
59145
59145
  import_react2 = __toESM(require_react(), 1);
59146
59146
  init_iconContext();
59147
59147
  _excluded = ["attr", "size", "title"];
59148
59148
  }
59149
59149
  });
59150
59150
 
59151
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-icons/lib/index.mjs
59151
+ // ../../rel54-runner-deps/node_modules/react-icons/lib/index.mjs
59152
59152
  var init_lib2 = __esm({
59153
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-icons/lib/index.mjs"() {
59153
+ "../../rel54-runner-deps/node_modules/react-icons/lib/index.mjs"() {
59154
59154
  init_iconsManifest();
59155
59155
  init_iconBase();
59156
59156
  init_iconContext();
59157
59157
  }
59158
59158
  });
59159
59159
 
59160
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-icons/fi/index.mjs
59160
+ // ../../rel54-runner-deps/node_modules/react-icons/fi/index.mjs
59161
59161
  var fi_exports = {};
59162
59162
  __export(fi_exports, {
59163
59163
  FiActivity: () => FiActivity,
@@ -60310,12 +60310,12 @@ function FiActivity(props) {
60310
60310
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24", "fill": "none", "stroke": "currentColor", "strokeWidth": "2", "strokeLinecap": "round", "strokeLinejoin": "round" }, "child": [{ "tag": "polyline", "attr": { "points": "22 12 18 12 15 21 9 3 6 12 2 12" }, "child": [] }] })(props);
60311
60311
  }
60312
60312
  var init_fi = __esm({
60313
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-icons/fi/index.mjs"() {
60313
+ "../../rel54-runner-deps/node_modules/react-icons/fi/index.mjs"() {
60314
60314
  init_lib2();
60315
60315
  }
60316
60316
  });
60317
60317
 
60318
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-icons/fa/index.mjs
60318
+ // ../../rel54-runner-deps/node_modules/react-icons/fa/index.mjs
60319
60319
  var fa_exports = {};
60320
60320
  __export(fa_exports, {
60321
60321
  Fa500Px: () => Fa500Px,
@@ -66764,12 +66764,12 @@ function FaRegAddressBook(props) {
66764
66764
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 448 512" }, "child": [{ "tag": "path", "attr": { "d": "M436 160c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-20V48c0-26.5-21.5-48-48-48H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h320c26.5 0 48-21.5 48-48v-48h20c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-20v-64h20c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-20v-64h20zm-68 304H48V48h320v416zM208 256c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm-89.6 128h179.2c12.4 0 22.4-8.6 22.4-19.2v-19.2c0-31.8-30.1-57.6-67.2-57.6-10.8 0-18.7 8-44.8 8-26.9 0-33.4-8-44.8-8-37.1 0-67.2 25.8-67.2 57.6v19.2c0 10.6 10 19.2 22.4 19.2z" }, "child": [] }] })(props);
66765
66765
  }
66766
66766
  var init_fa = __esm({
66767
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-icons/fa/index.mjs"() {
66767
+ "../../rel54-runner-deps/node_modules/react-icons/fa/index.mjs"() {
66768
66768
  init_lib2();
66769
66769
  }
66770
66770
  });
66771
66771
 
66772
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-icons/si/index.mjs
66772
+ // ../../rel54-runner-deps/node_modules/react-icons/si/index.mjs
66773
66773
  var si_exports = {};
66774
66774
  __export(si_exports, {
66775
66775
  Si1001Tracklists: () => Si1001Tracklists,
@@ -80558,12 +80558,12 @@ function Si1001Tracklists(props) {
80558
80558
  return GenIcon({ "tag": "svg", "attr": { "role": "img", "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "d": "M8.0957 1.334v1.3457H6.7461v1.3457H5.3984V5.371H4.0488v1.3457H2.6992v6.6816H1.3496v1.3477H0v2.4512h1.3496v1.3457h1.3496v1.3457h2.457v-7.836H3.8067V7.8223h1.3497V6.4766h1.3496V5.1309h1.3496V3.7852h8.289v1.3457h1.3496v1.3457h1.3496v1.3457h1.3497v4.2304h-1.3497v7.836h2.457V18.543h1.3497v-1.3457H24V14.746h-1.3496v-1.3477h-1.3496V6.7168h-1.3496V5.3711h-1.3496V4.0254h-1.3477V2.6797h-1.3496V1.334Zm1.3711 8v1.3515H8.1113v3.8165h2.4688v-4.0567h2.9512v4.3477h-1.3555v1.3515h-1.3535v2.4649h2.4668v-2.7051H16v-5.2188h-1.3555V9.334Zm1.3555 10.8691v2.463h2.4668v-2.463z" }, "child": [] }] })(props);
80559
80559
  }
80560
80560
  var init_si = __esm({
80561
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/react-icons/si/index.mjs"() {
80561
+ "../../rel54-runner-deps/node_modules/react-icons/si/index.mjs"() {
80562
80562
  init_lib2();
80563
80563
  }
80564
80564
  });
80565
80565
 
80566
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/clsx/dist/clsx.mjs
80566
+ // ../../rel54-runner-deps/node_modules/clsx/dist/clsx.mjs
80567
80567
  var clsx_exports = {};
80568
80568
  __export(clsx_exports, {
80569
80569
  clsx: () => clsx,
@@ -80584,12 +80584,12 @@ function clsx() {
80584
80584
  }
80585
80585
  var clsx_default;
80586
80586
  var init_clsx = __esm({
80587
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/clsx/dist/clsx.mjs"() {
80587
+ "../../rel54-runner-deps/node_modules/clsx/dist/clsx.mjs"() {
80588
80588
  clsx_default = clsx;
80589
80589
  }
80590
80590
  });
80591
80591
 
80592
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/tailwind-merge/dist/bundle-mjs.mjs
80592
+ // ../../rel54-runner-deps/node_modules/tailwind-merge/dist/bundle-mjs.mjs
80593
80593
  var bundle_mjs_exports = {};
80594
80594
  __export(bundle_mjs_exports, {
80595
80595
  createTailwindMerge: () => createTailwindMerge,
@@ -80603,7 +80603,7 @@ __export(bundle_mjs_exports, {
80603
80603
  });
80604
80604
  var concatArrays, createClassValidatorObject, createClassPartObject, CLASS_PART_SEPARATOR, EMPTY_CONFLICTS, ARBITRARY_PROPERTY_PREFIX, createClassGroupUtils, getGroupRecursive, getGroupIdForArbitraryProperty, createClassMap, processClassGroups, processClassesRecursively, processClassDefinition, processStringDefinition, processFunctionDefinition, processObjectDefinition, getPart, isThemeGetter, createLruCache, IMPORTANT_MODIFIER, MODIFIER_SEPARATOR, EMPTY_MODIFIERS, createResultObject, createParseClassName, createSortModifiers, createConfigUtils, createPostfixLookupClassGroupIds, SPLIT_CLASSES_REGEX, mergeClassList, twJoin, toValue, createTailwindMerge, fallbackThemeArr, fromTheme, arbitraryValueRegex, arbitraryVariableRegex, fractionRegex, tshirtUnitRegex, lengthUnitRegex, colorFunctionRegex, shadowRegex, imageRegex, isFraction, isNumber, isInteger, isPercent, isTshirtSize, isAny, isLengthOnly, isNever, isShadow, isImage, isAnyNonArbitrary, isNamedContainerQuery, isArbitrarySize, isArbitraryValue, isArbitraryLength, isArbitraryNumber, isArbitraryWeight, isArbitraryFamilyName, isArbitraryPosition, isArbitraryImage, isArbitraryShadow, isArbitraryVariable, isArbitraryVariableLength, isArbitraryVariableFamilyName, isArbitraryVariablePosition, isArbitraryVariableSize, isArbitraryVariableImage, isArbitraryVariableShadow, isArbitraryVariableWeight, getIsArbitraryValue, getIsArbitraryVariable, isLabelPosition, isLabelImage, isLabelSize, isLabelLength, isLabelNumber, isLabelFamilyName, isLabelWeight, isLabelShadow, validators, getDefaultConfig, mergeConfigs, overrideProperty, overrideConfigProperties, mergeConfigProperties, mergeArrayProperties, extendTailwindMerge, twMerge;
80605
80605
  var init_bundle_mjs = __esm({
80606
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/tailwind-merge/dist/bundle-mjs.mjs"() {
80606
+ "../../rel54-runner-deps/node_modules/tailwind-merge/dist/bundle-mjs.mjs"() {
80607
80607
  concatArrays = (array1, array2) => {
80608
80608
  const combinedArray = new Array(array1.length + array2.length);
80609
80609
  for (let i = 0; i < array1.length; i++) {
@@ -83943,7 +83943,7 @@ var init_bundle_mjs = __esm({
83943
83943
  }
83944
83944
  });
83945
83945
 
83946
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/class-variance-authority/dist/index.mjs
83946
+ // ../../rel54-runner-deps/node_modules/class-variance-authority/dist/index.mjs
83947
83947
  var dist_exports = {};
83948
83948
  __export(dist_exports, {
83949
83949
  cva: () => cva,
@@ -83951,7 +83951,7 @@ __export(dist_exports, {
83951
83951
  });
83952
83952
  var falsyToString, cx, cva;
83953
83953
  var init_dist = __esm({
83954
- "../../../../../../../../../private/tmp/runner-deps-2169/node_modules/class-variance-authority/dist/index.mjs"() {
83954
+ "../../rel54-runner-deps/node_modules/class-variance-authority/dist/index.mjs"() {
83955
83955
  init_clsx();
83956
83956
  falsyToString = (value) => typeof value === "boolean" ? `${value}` : value === 0 ? "0" : value;
83957
83957
  cx = clsx;
@@ -84001,8 +84001,8 @@ var mockup_exports = {};
84001
84001
  __export(mockup_exports, {
84002
84002
  drawMockup: () => drawMockup
84003
84003
  });
84004
- import fs18 from "node:fs";
84005
- import path20 from "node:path";
84004
+ import fs17 from "node:fs";
84005
+ import path19 from "node:path";
84006
84006
  import vm from "node:vm";
84007
84007
  async function loadPackage(id) {
84008
84008
  if (id === "react") return import_react3.default;
@@ -84015,20 +84015,20 @@ async function loadPackage(id) {
84015
84015
  return { __esModule: true, ...await load() };
84016
84016
  }
84017
84017
  function resolveFile(id, from, folder) {
84018
- const at2 = path20.resolve(path20.dirname(from), id);
84019
- if (at2 !== folder && !at2.startsWith(folder + path20.sep)) throw new Error(`${id} is outside the mockup's folder`);
84020
- const tries = path20.extname(at2) ? [at2] : [...CODE_EXTS.map((e2) => at2 + e2), ...CODE_EXTS.map((e2) => path20.join(at2, `index${e2}`))];
84021
- const file2 = tries.find((f2) => fs18.statSync(f2, { throwIfNoEntry: false })?.isFile());
84018
+ const at2 = path19.resolve(path19.dirname(from), id);
84019
+ if (at2 !== folder && !at2.startsWith(folder + path19.sep)) throw new Error(`${id} is outside the mockup's folder`);
84020
+ const tries = path19.extname(at2) ? [at2] : [...CODE_EXTS.map((e2) => at2 + e2), ...CODE_EXTS.map((e2) => path19.join(at2, `index${e2}`))];
84021
+ const file2 = tries.find((f2) => fs17.statSync(f2, { throwIfNoEntry: false })?.isFile());
84022
84022
  if (!file2) throw new Error(`no such file: ${id}`);
84023
84023
  return file2;
84024
84024
  }
84025
84025
  async function readGraph(entry) {
84026
- const folder = path20.dirname(entry);
84026
+ const folder = path19.dirname(entry);
84027
84027
  const graph = { code: /* @__PURE__ */ new Map(), links: /* @__PURE__ */ new Map(), sheets: [], packages: /* @__PURE__ */ new Map() };
84028
84028
  const walk = async (file2) => {
84029
84029
  if (graph.code.has(file2)) return;
84030
84030
  if (graph.code.size >= MAX_FILES) throw new Error(`a mockup imports more than ${MAX_FILES} files`);
84031
- const js = (0, import_sucrase.transform)(fs18.readFileSync(file2, "utf8"), { transforms: ["typescript", "jsx", "imports"], jsxRuntime: "automatic", production: true, filePath: file2 }).code;
84031
+ const js = (0, import_sucrase.transform)(fs17.readFileSync(file2, "utf8"), { transforms: ["typescript", "jsx", "imports"], jsxRuntime: "automatic", production: true, filePath: file2 }).code;
84032
84032
  graph.code.set(file2, js);
84033
84033
  const link = /* @__PURE__ */ new Map();
84034
84034
  graph.links.set(file2, link);
@@ -84040,7 +84040,7 @@ async function readGraph(entry) {
84040
84040
  const target = resolveFile(id, file2, folder);
84041
84041
  link.set(id, target);
84042
84042
  if (!target.endsWith(".css")) await walk(target);
84043
- else if (!graph.sheets.some((s) => s.path === target)) graph.sheets.push({ path: target, content: fs18.readFileSync(target, "utf8") });
84043
+ else if (!graph.sheets.some((s) => s.path === target)) graph.sheets.push({ path: target, content: fs17.readFileSync(target, "utf8") });
84044
84044
  }
84045
84045
  };
84046
84046
  await walk(entry);
@@ -84054,25 +84054,25 @@ function run(script, context, name, deadline) {
84054
84054
  async function tailwindFor(markup, sheets) {
84055
84055
  const source = sheets.length ? sheets.map((s) => s.content).join("\n") : '@import "tailwindcss";';
84056
84056
  const compiler = await zf(source, {
84057
- base: sheets.length ? path20.dirname(sheets[0].path) : "/",
84057
+ base: sheets.length ? path19.dirname(sheets[0].path) : "/",
84058
84058
  loadStylesheet: async (id, from) => {
84059
84059
  if (id === "tailwindcss" || id.startsWith("tailwindcss/")) return { path: "tailwindcss/index.css", base: "/", content: tailwindcss_default };
84060
84060
  if (!id.startsWith(".")) throw new Error(`a mockup cannot import ${id}`);
84061
- const at2 = path20.resolve(from, id);
84062
- return { path: at2, base: path20.dirname(at2), content: fs18.readFileSync(at2, "utf8") };
84061
+ const at2 = path19.resolve(from, id);
84062
+ return { path: at2, base: path19.dirname(at2), content: fs17.readFileSync(at2, "utf8") };
84063
84063
  }
84064
84064
  });
84065
84065
  const classes = [...markup.matchAll(/class="([^"]*)"/g)].flatMap((m) => m[1].split(/\s+/));
84066
84066
  return compiler.build(classes.filter(Boolean));
84067
84067
  }
84068
84068
  function dressPage(file2) {
84069
- const folder = path20.dirname(file2);
84070
- const html = fs18.readFileSync(file2, "utf8").replace(/<link\b[^>]*>/gi, (tag) => {
84069
+ const folder = path19.dirname(file2);
84070
+ const html = fs17.readFileSync(file2, "utf8").replace(/<link\b[^>]*>/gi, (tag) => {
84071
84071
  const href = /\bhref\s*=\s*["']?([^"'\s>]+)/i.exec(tag)?.[1];
84072
84072
  if (!/\brel\s*=\s*["']?stylesheet/i.test(tag) || !href || /^[a-z][\w+.-]*:|^\/\//i.test(href)) return tag;
84073
- const at3 = path20.resolve(folder, href);
84074
- if (!at3.startsWith(folder + path20.sep) || !fs18.existsSync(at3)) return tag;
84075
- return `<style>${fs18.readFileSync(at3, "utf8").replace(/<\/style/gi, "<\\/style")}</style>`;
84073
+ const at3 = path19.resolve(folder, href);
84074
+ if (!at3.startsWith(folder + path19.sep) || !fs17.existsSync(at3)) return tag;
84075
+ return `<style>${fs17.readFileSync(at3, "utf8").replace(/<\/style/gi, "<\\/style")}</style>`;
84076
84076
  });
84077
84077
  const at2 = /^\uFEFF?\s*(?:<!--[\s\S]*?-->\s*)*(?:<!doctype\b[^>]*>)?/i.exec(html)[0].length;
84078
84078
  return /<!doctype\b|<html[\s>]|<head[\s>]/i.test(html) ? html.slice(0, at2) + head + html.slice(at2) : `<!doctype html><html><head>${head}</head><body>${html}</body></html>`;
@@ -84453,7 +84453,7 @@ function status(line) {
84453
84453
  }
84454
84454
 
84455
84455
  // src/protocol.ts
84456
- var VERSION = true ? "0.6.0" : "0.0.0";
84456
+ var VERSION = true ? "0.6.2" : "0.0.0";
84457
84457
  var EXIT_REFUSED = 10;
84458
84458
  var EXIT_OUTDATED = 11;
84459
84459
 
@@ -85605,8 +85605,8 @@ function connect(stdout, stdin, onCall, dialect = {}) {
85605
85605
  call(method, params) {
85606
85606
  if (gone) return Promise.reject(new Error(gone));
85607
85607
  const id = dialect.stringIds ? String(nextId++) : nextId++;
85608
- return new Promise((ok2, fail) => {
85609
- waiting.set(String(id), { ok: ok2, fail });
85608
+ return new Promise((ok, fail) => {
85609
+ waiting.set(String(id), { ok, fail });
85610
85610
  send3({ id, method, params });
85611
85611
  });
85612
85612
  },
@@ -87799,7 +87799,6 @@ __export(api_exports, {
87799
87799
  claimJob: () => claimJob,
87800
87800
  commitBoard: () => commitBoard,
87801
87801
  createArtifact: () => createArtifact,
87802
- createTriage: () => createTriage,
87803
87802
  createUpload: () => createUpload,
87804
87803
  createVersion: () => createVersion,
87805
87804
  dispatchReview: () => dispatchReview,
@@ -87811,7 +87810,7 @@ __export(api_exports, {
87811
87810
  listElsewhere: () => listElsewhere,
87812
87811
  listFolders: () => listFolders,
87813
87812
  listJobs: () => listJobs,
87814
- listTriage: () => listTriage,
87813
+ listMachineTasks: () => listMachineTasks,
87815
87814
  listWorkflows: () => listWorkflows,
87816
87815
  markReviewed: () => markReviewed,
87817
87816
  openDiscussion: () => openDiscussion,
@@ -87846,6 +87845,7 @@ __export(api_exports, {
87846
87845
  showAlert: () => showAlert,
87847
87846
  startIdea: () => startIdea,
87848
87847
  startTrial: () => startTrial,
87848
+ stopTask: () => stopTask,
87849
87849
  targetVersion: () => targetVersion,
87850
87850
  upload: () => upload
87851
87851
  });
@@ -87864,17 +87864,17 @@ function readAll() {
87864
87864
  }
87865
87865
  var secretsOf = (runtime) => runtime ? readAll()[runtime] ?? {} : {};
87866
87866
  function keepSecrets(runtime, given) {
87867
- const all2 = readAll();
87868
- const held3 = { ...all2[runtime] };
87867
+ const all = readAll();
87868
+ const held3 = { ...all[runtime] };
87869
87869
  for (const [key, value] of Object.entries(given)) {
87870
87870
  if (value) held3[key] = value;
87871
87871
  else delete held3[key];
87872
87872
  }
87873
- if (Object.keys(held3).length) all2[runtime] = held3;
87874
- else delete all2[runtime];
87873
+ if (Object.keys(held3).length) all[runtime] = held3;
87874
+ else delete all[runtime];
87875
87875
  fs8.mkdirSync(runnerHome(), { recursive: true, mode: 448 });
87876
87876
  const temp = `${file()}.${process.pid}.tmp`;
87877
- fs8.writeFileSync(temp, `${JSON.stringify(all2)}
87877
+ fs8.writeFileSync(temp, `${JSON.stringify(all)}
87878
87878
  `, { mode: 384 });
87879
87879
  fs8.renameSync(temp, file());
87880
87880
  }
@@ -87971,6 +87971,8 @@ var showAlert = (machineId2, alert) => request("POST", `/v1/runner/alerts/${q(al
87971
87971
  var readAlert = (alert) => request("POST", `/v1/alerts/${q(alert)}/read`, {});
87972
87972
  var listFolders = (machineId2) => request("GET", `/v1/runner/folders?machine=${q(machineId2)}`);
87973
87973
  var listElsewhere = (machineId2) => request("GET", `/v1/runner/folders?machine=${q(machineId2)}&elsewhere=1`);
87974
+ var listMachineTasks = (machineId2) => request("GET", `/v1/runner/tasks?machine=${q(machineId2)}`);
87975
+ var stopTask = (task, how) => request("POST", how === "chat" ? `/v1/tasks/${q(task)}/chat/stop` : `/v1/tasks/${q(task)}/stop`, {});
87974
87976
  var addFolder = (machineId2, name, path28, project) => request("POST", "/v1/runner/folders", { machineId: machineId2, name, path: path28, ...project ? { project } : {} });
87975
87977
  var removeFolder = (machineId2, project) => request("POST", `/v1/runner/folders/${q(project)}/remove`, { machineId: machineId2 });
87976
87978
  var readPlan = () => request("GET", "/v1/billing");
@@ -87995,11 +87997,9 @@ var readVersion = (artifact, version) => request("GET", `/v1/artifacts/${q(artif
87995
87997
  var createArtifact = (task, name, type) => request("POST", `/v1/tasks/${q(task)}/artifacts`, { type, name });
87996
87998
  var createUpload = (artifact, contentType, size) => request("POST", `/v1/artifacts/${q(artifact)}/uploads`, { content_type: contentType, size });
87997
87999
  var createVersion = (artifact, upload2) => request("POST", `/v1/artifacts/${q(artifact)}/versions`, { upload: upload2 });
87998
- var listTriage = (project, state, after) => request("GET", `/v1/triage?project=${q(project)}&state=${state}&limit=100${after ? `&after=${q(after)}` : ""}`);
87999
- var createTriage = (project, title, text3, task, workflow) => request("POST", "/v1/triage", { project, title, text: text3, source_task: task, workflow });
88000
88000
  var readRejections = (workspace) => request("GET", `/v1/rejections?workspace=${q(workspace)}`);
88001
88001
  var markReviewed = (tasks, triage) => request("POST", "/v1/rejections/reviewed", { tasks, triage });
88002
- var openDiscussion = (project, requestId) => request("POST", "/v1/discussions/external", { project, requestId });
88002
+ var openDiscussion = (project, requestId, host = "claude-code") => request("POST", "/v1/discussions/external", { ...project ? { project } : {}, requestId, host });
88003
88003
  var readDiscussion = (id) => request("GET", `/v1/discussions/${q(id)}`);
88004
88004
  async function saveDraft(id, expectedVersion, ideas) {
88005
88005
  const sent = await send("PUT", `/v1/discussions/${q(id)}/draft`, { expectedVersion, ideas }, true, TIMEOUT_MS);
@@ -88010,7 +88010,7 @@ async function saveDraft(id, expectedVersion, ideas) {
88010
88010
  }
88011
88011
  var setIdeaWorkflow = (id, idea, workflow) => request("PATCH", `/v1/discussions/${q(id)}/ideas/${q(idea)}`, { workflow });
88012
88012
  var dropIdea = (id, idea) => request("DELETE", `/v1/discussions/${q(id)}/ideas/${q(idea)}`);
88013
- var startIdea = (id, idea, expectedVersion) => request("POST", `/v1/discussions/${q(id)}/ideas/${q(idea)}/start`, { expectedVersion });
88013
+ var startIdea = (id, idea, expectedVersion, project) => request("POST", `/v1/discussions/${q(id)}/ideas/${q(idea)}/start`, { expectedVersion, ...project ? { project } : {} });
88014
88014
 
88015
88015
  // src/runtimes.ts
88016
88016
  var HARNESSES2 = Object.fromEntries(RUNTIMES.map((name) => [name, HARNESSES.find((h3) => h3.name === name)]));
@@ -89148,6 +89148,11 @@ import { spawn as spawn2 } from "node:child_process";
89148
89148
  import fs15 from "node:fs";
89149
89149
  import path17 from "node:path";
89150
89150
  import { fileURLToPath } from "node:url";
89151
+
89152
+ // ../cli/src/lib/agent/language.ts
89153
+ var LANGUAGE_LINE_ENV = "AI4KANBAN_LANGUAGE_LINE";
89154
+
89155
+ // src/akb.ts
89151
89156
  var bundledAkb = () => ({
89152
89157
  command: process.execPath,
89153
89158
  args: [path17.join(path17.dirname(fileURLToPath(import.meta.url)), "akb", "bin", "ai4kanban.mjs")]
@@ -89168,14 +89173,16 @@ exec ${line} "$@"
89168
89173
  fs15.writeFileSync(file2, text3, { mode: 493 });
89169
89174
  return dir;
89170
89175
  }
89171
- function akbEnv(akb, board, task) {
89176
+ function akbEnv(akb, board, task, line) {
89172
89177
  const env = {};
89173
- for (const [k, v2] of Object.entries(process.env)) if (!k.startsWith("KANBAN_") && k !== "AI4KANBAN_BOARD" && k !== "AI4KANBAN_TASK") env[k] = v2;
89178
+ const dropped = ["AI4KANBAN_BOARD", "AI4KANBAN_TASK", LANGUAGE_LINE_ENV];
89179
+ for (const [k, v2] of Object.entries(process.env)) if (!k.startsWith("KANBAN_") && !dropped.includes(k)) env[k] = v2;
89174
89180
  const key = Object.keys(env).find((k) => k.toUpperCase() === "PATH") ?? "PATH";
89175
89181
  env[key] = [shimDir(akb), env[key]].filter(Boolean).join(path17.delimiter);
89176
89182
  env.AI4KANBAN_COMMAND = "akb";
89177
89183
  if (board) env.AI4KANBAN_BOARD = board;
89178
89184
  if (task) env.AI4KANBAN_TASK = task;
89185
+ if (line !== void 0) env[LANGUAGE_LINE_ENV] = line;
89179
89186
  return env;
89180
89187
  }
89181
89188
  var KEEP = 256 * 1024;
@@ -89189,7 +89196,7 @@ function runAkb(akb, args, opts) {
89189
89196
  };
89190
89197
  let child;
89191
89198
  try {
89192
- child = spawn2(akb.command, [...akb.args, ...args], { cwd: opts.cwd, env: akbEnv(akb, opts.board, opts.task), stdio: ["ignore", "pipe", "pipe"] });
89199
+ child = spawn2(akb.command, [...akb.args, ...args], { cwd: opts.cwd, env: akbEnv(akb, opts.board, opts.task, opts.line), stdio: ["ignore", "pipe", "pipe"] });
89193
89200
  } catch (e2) {
89194
89201
  return resolve2({ code: null, out: "", last: e2 instanceof Error ? e2.message : String(e2) });
89195
89202
  }
@@ -89221,10 +89228,10 @@ function answerOf2(ran) {
89221
89228
  // src/task-folder.ts
89222
89229
  import { spawnSync as spawnSync3 } from "node:child_process";
89223
89230
  import crypto2 from "node:crypto";
89224
- import fs19 from "node:fs";
89225
- import path21 from "node:path";
89231
+ import fs18 from "node:fs";
89232
+ import path20 from "node:path";
89226
89233
 
89227
- // ../../../../../../../../../private/tmp/runner-deps-2169/node_modules/node-diff3/dist/diff3.mjs
89234
+ // ../../rel54-runner-deps/node_modules/node-diff3/dist/diff3.mjs
89228
89235
  function LCS(buffer1, buffer2) {
89229
89236
  let equivalenceClasses = /* @__PURE__ */ Object.create(null);
89230
89237
  for (let j2 = 0; j2 < buffer2.length; j2++) {
@@ -89479,27 +89486,46 @@ function cardFront(body) {
89479
89486
  return out;
89480
89487
  }
89481
89488
 
89482
- // src/memory-files.ts
89489
+ // ../cloud/src/triage-files.ts
89490
+ var ITEM = /^triage\/(?:(dismissed|archived)\/)?([^/]+)\.md$/;
89491
+ function itemAt(path28) {
89492
+ const m = ITEM.exec(path28);
89493
+ if (!m) return null;
89494
+ return { state: m[1] === "dismissed" ? "dismissed" : m[1] === "archived" ? "carded" : "open", name: m[2] };
89495
+ }
89496
+ function stampItem(content, fields) {
89497
+ const lines = content.split("\n");
89498
+ const close = lines.indexOf("---", 1);
89499
+ if (close < 0) return content;
89500
+ const kept3 = lines.slice(1, close).filter((line) => {
89501
+ const key = /^([a-z_]+):/.exec(line);
89502
+ return !key || fields[key[1]] === void 0;
89503
+ });
89504
+ const added = Object.entries(fields).flatMap(([k, v2]) => v2 === null ? [] : [`${k}: ${yamlScalar(v2)}`]);
89505
+ return ["---", ...kept3, ...added, ...lines.slice(close)].join("\n");
89506
+ }
89507
+
89508
+ // ../cli/src/lib/agents/shared-memory.ts
89483
89509
  import fs16 from "node:fs";
89484
89510
  import path18 from "node:path";
89485
89511
 
89486
89512
  // ../cli/src/agents/api-designer/AGENT.md
89487
- var AGENT_default = "---\nname: api-designer\ndescription: Writes the caller's documentation for the APIs a card changes.\nakb:\n when: A card adds or changes a surface a user or third party calls directly, such as HTTP routes, WebSocket messages, MCP tools, or CLI commands and flags. Not a protocol between the project's own components.\n i18n:\n zh:\n title: \u63A5\u53E3\u8BBE\u8BA1\u5E08\n description: \u4E3A\u5361\u7247\u6539\u52A8\u7684\u63A5\u53E3\u5199\u51FA\u8C03\u7528\u65B9\u6587\u6863\u3002\n when: \u5361\u7247\u65B0\u589E\u6216\u4FEE\u6539\u7528\u6237\u6216\u7B2C\u4E09\u65B9\u76F4\u63A5\u8C03\u7528\u7684\u63A5\u53E3\u65F6\uFF0C\u5982 HTTP \u8DEF\u7531\u3001WebSocket \u6D88\u606F\u3001MCP \u5DE5\u5177\u3001CLI \u547D\u4EE4\u548C\u53C2\u6570\u3002\u4E0D\u542B\u9879\u76EE\u81EA\u8EAB\u7EC4\u4EF6\u4E4B\u95F4\u7684\u534F\u8BAE\u3002\n---\n\nWrite each surface this card changes as the documentation entry that will be committed, in\nthe project's existing docs style: inputs, outputs, errors and one example call. Use a\n`diff` when an entry already exists, and a `mermaid` `sequenceDiagram` for a message\nexchange. One design, no alternatives, nothing else in the section.\n\n- **Glanceable**: a junior engineer understands each entry in one read. Plain names, short\n lines, no field or error the card does not change.\n";
89513
+ var AGENT_default = "---\nname: api-designer\ndescription: Writes the caller's documentation for the APIs a card changes.\nakb:\n when: A card adds or changes a surface a user or third party calls directly, such as HTTP routes, WebSocket messages, MCP tools, or CLI commands and flags. Not a protocol between the project's own components.\n i18n:\n en:\n title: API docs\n zh:\n title: \u63A5\u53E3\u6587\u6863\n description: \u4E3A\u5361\u7247\u6539\u52A8\u7684\u63A5\u53E3\u5199\u51FA\u8C03\u7528\u65B9\u6587\u6863\u3002\n when: \u5361\u7247\u65B0\u589E\u6216\u4FEE\u6539\u7528\u6237\u6216\u7B2C\u4E09\u65B9\u76F4\u63A5\u8C03\u7528\u7684\u63A5\u53E3\u65F6\uFF0C\u5982 HTTP \u8DEF\u7531\u3001WebSocket \u6D88\u606F\u3001MCP \u5DE5\u5177\u3001CLI \u547D\u4EE4\u548C\u53C2\u6570\u3002\u4E0D\u542B\u9879\u76EE\u81EA\u8EAB\u7EC4\u4EF6\u4E4B\u95F4\u7684\u534F\u8BAE\u3002\n---\n\nWrite each surface this card changes as the documentation entry that will be committed, in\nthe project's existing docs style: inputs, outputs, errors and one example call. Use a\n`diff` when an entry already exists, and a `mermaid` `sequenceDiagram` for a message\nexchange. One design, no alternatives, nothing else in the section.\n\n- **Glanceable**: a junior engineer understands each entry in one read. Plain names, short\n lines, no field or error the card does not change.\n";
89488
89514
 
89489
89515
  // ../cli/src/agents/blog-illustrator/AGENT.md
89490
- var AGENT_default2 = "---\nname: blog-illustrator\ndescription: Makes a blog post's cover and in-article images, each with alt text.\nakb:\n after: [blog-planner]\n memoryFiles:\n workspace: [style.md]\n i18n:\n en:\n title: Blog illustrator\n zh:\n title: \u535A\u5BA2\u914D\u56FE\n description: \u6309\u786E\u8BA4\u7684\u5927\u7EB2\u4E3A\u535A\u5BA2\u6587\u7AE0\u65B0\u505A\u5C01\u9762\u548C\u6B63\u6587\u914D\u56FE\uFF0C\u5E76\u5199\u597D\u66FF\u4EE3\u6587\u5B57\u3002\n---\n\nMake the cover and every image the approved outline in ``## By `blog-planner` agent`` names.\nMake every image new for this post; never search for or reuse existing images. On an\nexisting card, redo only the images an outline change affects.\n\n## Methods\n\nChoose one per image:\n\n- **Screenshot**: capture the real product in the state the section describes.\n- **Drawn**: lay out a diagram or chart in HTML/CSS or SVG and render it to PNG.\n- **Generated**: `akb cloud image --aspect <ratio> --out <file> \"<prompt>\"`, which spends the\n user's Pro credits; never for a product interface.\n- **Fallback**: when a method cannot deliver, use another and say so in your section.\n\n## Rules\n\n- **Alt text**: one sentence per image saying what it shows; draw it on each in-article image as its caption.\n- **Cover**: the aspect ratio the blog's existing covers use, 16:9 when there are none;\n legible at thumbnail size.\n- **Consistent**: one post's images share palette, fonts and treatment.\n- **Review**: view each image at full size and at the width the article shows it; fix\n defects and recheck.\n\n## Paths\n\n- **Assets**: `<board-state>/assets/<card id>/` \u2014 `cover.png` and `fig-<nn>.png`, each with\n the source that renders it beside it.\n- **Hand over**: in your section, one line per image \u2014 file, the outline section it belongs\n to, and its alt text.\n\n## Memory\n\nKeep two files in your memory folder, one line each, following \"What earns a note\" in\n`akb guide board`:\n\n- **`style.md`**: diagram treatment and distilled user corrections that hold for any blog.\n- **`brand.md`**: this product's palette and fonts.\n";
89516
+ var AGENT_default2 = "---\nname: blog-illustrator\ndescription: Makes a blog post's cover and in-article images, each with alt text.\nakb:\n after: [blog-planner]\n memoryFiles:\n workspace: [style.md]\n i18n:\n en:\n title: Images\n zh:\n title: \u914D\u56FE\n description: \u6309\u786E\u8BA4\u7684\u5927\u7EB2\u4E3A\u535A\u5BA2\u6587\u7AE0\u65B0\u505A\u5C01\u9762\u548C\u6B63\u6587\u914D\u56FE\uFF0C\u5E76\u5199\u597D\u66FF\u4EE3\u6587\u5B57\u3002\n---\n\nMake the cover and every image the approved outline in ``## By `blog-planner` agent`` names.\nMake every image new for this post; never search for or reuse existing images. On an\nexisting card, redo only the images an outline change affects.\n\n## Methods\n\nChoose one per image:\n\n- **Screenshot**: capture the real product in the state the section describes.\n- **Drawn**: lay out a diagram or chart in HTML/CSS or SVG and render it to PNG.\n- **Generated**: `akb cloud image --aspect <ratio> --out <file> \"<prompt>\"`, which spends the\n user's Pro credits; never for a product interface.\n- **Fallback**: when a method cannot deliver, use another and say so in your section.\n\n## Rules\n\n- **Alt text**: one sentence per image saying what it shows; draw it on each in-article image as its caption.\n- **Cover**: the aspect ratio the blog's existing covers use, 16:9 when there are none;\n legible at thumbnail size.\n- **Consistent**: one post's images share palette, fonts and treatment.\n- **Review**: view each image at full size and at the width the article shows it; fix\n defects and recheck.\n\n## Paths\n\n- **Assets**: `<board-state>/assets/<card id>/` \u2014 `cover.png` and `fig-<nn>.png`, each with\n the source that renders it beside it.\n- **Hand over**: in your section, one line per image \u2014 file, the outline section it belongs\n to, and its alt text.\n\n## Memory\n\nKeep two files in your memory folder, one line each, following \"What earns a note\" in\n`akb guide board`:\n\n- **`style.md`**: diagram treatment and distilled user corrections that hold for any blog.\n- **`brand.md`**: this product's palette and fonts.\n";
89491
89517
 
89492
89518
  // ../cli/src/agents/blog-planner/AGENT.md
89493
- var AGENT_default3 = "---\nname: blog-planner\ndescription: Writes a blog post's brief and outline, the plan its article is written from.\nakb:\n memoryFiles:\n workspace: [general.md]\n i18n:\n en:\n title: Blog planner\n zh:\n title: \u535A\u5BA2\u7B56\u5212\n description: \u5199\u535A\u5BA2\u6587\u7AE0\u7684\u7B80\u62A5\u548C\u5927\u7EB2\uFF0C\u6B63\u6587\u6309\u5B83\u6765\u5199\u3002\n---\n\nYou write a blog post's brief and outline. Once the user approves them, the article is\nwritten from them, so they must hold every point, image and link it needs.\n\n## Deciding\n\n- **Evidence first**: settle what the card, the project, the existing blog and your memory answer.\n- **Default with a reason**: propose a justified default for every content choice.\n- **Ask little**: a `[user]` question only for what the user owns \u2014 the audience, the angle,\n the keyword to win, or a fact only they know.\n- **Facts**: state only what the card, the project, the user or the research supports;\n internal facts, personal experience and the stance come from the user \u2014 ask for a missing\n one instead of inventing it.\n\n## Memory\n\nYour memory folder is `docs/kanban/memory/agents/blog-planner/`. Read it before writing; the\ncurrent card wins.\n\n- **General**: `general.md` holds writing preferences shared by every destination.\n- **Product**: `product.md` holds how posts use this product as an example.\n- **Destinations**: `destination.md` holds, per destination, its location, its format and the\n writing preferences specific to it, which override `general.md`.\n- **Keywords**: `keywords.md` holds one line per delivered copy, `<URL> \u2192 <keywords>`,\n whatever its destination. When you read it, drop lines whose URL no longer resolves.\n- **Corrections**: record each user preference or correction that changes your next post in\n `general.md`, in `destination.md` when it applies to one destination only, or in\n `product.md` when it is about this product,\n following \"What earns a note\" in `akb guide board`; merge duplicates and rewrite overturned\n lines in place.\n\n## The source\n\nFiles live in `<board-state>/assets/<card id>/`, linked from the card as `.assets/<card id>/...`.\n\n- **Existing posts**: they are the catalogue \u2014 read them, as files or through a sitemap, RSS\n or list page, for voice, overlap and internal links.\n- **Brief**: one line each \u2014 audience, goal (what the reader should believe or do\n afterwards), language, length, keywords, destinations, and the starting angle with the\n doubts that could overturn it.\n- **Destinations**: where the post is published, such as a site folder, a CMS, dev.to or\n Medium; there may be several. Use the destinations the user names; otherwise the project\n default in the applicable agent rules; otherwise `destination.md`; otherwise infer them\n from the card and earlier posts. Ask only when all of these leave them open.\n- **Keywords**: zero or more, the first is the one to win. Ask which one the user wants to\n win; when they give none, leave it empty. No keyword research or rank tracking.\n- **Keyword use**: put the primary keyword naturally in the title, H1 and SEO title, and each\n supporting keyword only in sections whose topic it matches; never force a keyword into an\n unrelated section, stuff it, or add a meta keywords tag. Flag a keyword the topic cannot\n cover. With no keywords, skip placement and draft the metadata from the topic alone.\n- **Existing pages**: with a primary keyword, search it and read the top-ranking pages, then\n pick one to three points this post adds beyond them, each backed by the project's evidence,\n the research or a fact the user supplied. Keep this reading out of the card.\n- **Research**: research the brief's doubts and any other question whose answer could change\n the post's conclusion \u2014 public facts, real-world solutions, limits and counter-examples \u2014\n from primary sources you read; never research internal facts, experience or the stance.\n- **Research file**: `research.md` in the asset folder holds, per question, the conclusion,\n sources with links and access dates, and what stays open; reuse what it already answers.\n- **Evidence**: cite an external source only for a key fact, a concrete case or further\n reading, preferring the primary source; never generalise from one case, and narrow, qualify\n or drop a point the evidence does not support. Not every finding belongs in the article.\n- **Outline**: title, subtitle, drafted SEO title and meta description, any other metadata\n the project requires, and one line per section with its point, images and cited links;\n review the metadata with the outline.\n- **Links**: internal links go to existing posts or pages. Check that every link resolves.\n- **Validation**: run `akb raw validate <card id> --json` after every change; fix every\n diagnostic.\n\n## Steps\n\n- **Outline**: write the brief, research it, then write an outline whose angle and sections\n carry the points from existing pages and the research.\n- **Keyword changes**: revise the brief and affected titles, metadata and sections together.\n";
89519
+ var AGENT_default3 = "---\nname: blog-planner\ndescription: Writes a blog post's brief and outline, the plan its article is written from.\nakb:\n memoryFiles:\n workspace: [general.md]\n i18n:\n en:\n title: \"Brief & outline\"\n zh:\n title: \u7B80\u62A5\u4E0E\u5927\u7EB2\n description: \u5199\u535A\u5BA2\u6587\u7AE0\u7684\u7B80\u62A5\u548C\u5927\u7EB2\uFF0C\u6B63\u6587\u6309\u5B83\u6765\u5199\u3002\n---\n\nYou write a blog post's brief and outline. Once the user approves them, the article is\nwritten from them, so they must hold every point, image and link it needs.\n\n## Deciding\n\n- **Evidence first**: settle what the card, the project, the existing blog and your memory answer.\n- **Default with a reason**: propose a justified default for every content choice.\n- **Ask little**: a `[user]` question only for what the user owns \u2014 the audience, the angle,\n the keyword to win, or a fact only they know.\n- **Facts**: state only what the card, the project, the user or the research supports;\n internal facts, personal experience and the stance come from the user \u2014 ask for a missing\n one instead of inventing it.\n\n## Memory\n\nYour memory folder is `docs/kanban/memory/agents/blog-planner/`. Read it before writing; the\ncurrent card wins.\n\n- **General**: `general.md` holds writing preferences shared by every destination.\n- **Product**: `product.md` holds how posts use this product as an example.\n- **Destinations**: `destination.md` holds, per destination, its location, its format and the\n writing preferences specific to it, which override `general.md`.\n- **Keywords**: `keywords.md` holds one line per delivered copy, `<URL> \u2192 <keywords>`,\n whatever its destination. When you read it, drop lines whose URL no longer resolves.\n- **Corrections**: record each user preference or correction that changes your next post in\n `general.md`, in `destination.md` when it applies to one destination only, or in\n `product.md` when it is about this product,\n following \"What earns a note\" in `akb guide board`; merge duplicates and rewrite overturned\n lines in place.\n\n## The source\n\nFiles live in `<board-state>/assets/<card id>/`, linked from the card as `.assets/<card id>/...`.\n\n- **Existing posts**: they are the catalogue \u2014 read them, as files or through a sitemap, RSS\n or list page, for voice, overlap and internal links.\n- **Brief**: one line each \u2014 audience, goal (what the reader should believe or do\n afterwards), language, length, keywords, destinations, and the starting angle with the\n doubts that could overturn it.\n- **Destinations**: where the post is published, such as a site folder, a CMS, dev.to or\n Medium; there may be several. Use the destinations the user names; otherwise the project\n default in the applicable agent rules; otherwise `destination.md`; otherwise infer them\n from the card and earlier posts. Ask only when all of these leave them open.\n- **Keywords**: zero or more, the first is the one to win. Ask which one the user wants to\n win; when they give none, leave it empty. No keyword research or rank tracking.\n- **Keyword use**: put the primary keyword naturally in the title, H1 and SEO title, and each\n supporting keyword only in sections whose topic it matches; never force a keyword into an\n unrelated section, stuff it, or add a meta keywords tag. Flag a keyword the topic cannot\n cover. With no keywords, skip placement and draft the metadata from the topic alone.\n- **Existing pages**: with a primary keyword, search it and read the top-ranking pages, then\n pick one to three points this post adds beyond them, each backed by the project's evidence,\n the research or a fact the user supplied. Keep this reading out of the card.\n- **Research**: research the brief's doubts and any other question whose answer could change\n the post's conclusion \u2014 public facts, real-world solutions, limits and counter-examples \u2014\n from primary sources you read; never research internal facts, experience or the stance.\n- **Research file**: `research.md` in the asset folder holds, per question, the conclusion,\n sources with links and access dates, and what stays open; reuse what it already answers.\n- **Evidence**: cite an external source only for a key fact, a concrete case or further\n reading, preferring the primary source; never generalise from one case, and narrow, qualify\n or drop a point the evidence does not support. Not every finding belongs in the article.\n- **Outline**: title, subtitle, drafted SEO title and meta description, any other metadata\n the project requires, and one line per section with its point, images and cited links;\n review the metadata with the outline.\n- **Links**: internal links go to existing posts or pages. Check that every link resolves.\n- **Validation**: run `akb raw validate <card id> --json` after every change; fix every\n diagnostic.\n\n## Steps\n\n- **Outline**: write the brief, research it, then write an outline whose angle and sections\n carry the points from existing pages and the research.\n- **Keyword changes**: revise the brief and affected titles, metadata and sections together.\n";
89494
89520
 
89495
89521
  // ../cli/src/agents/blog-writer/AGENT.md
89496
- var AGENT_default4 = "---\nname: blog-writer\ndescription: Writes a blog post's article from its approved outline and delivers one copy per destination.\nakb:\n after: [blog-planner, blog-illustrator]\n i18n:\n en:\n title: Blog writer\n zh:\n title: \u535A\u5BA2\u5199\u4F5C\n description: \u6309\u786E\u8BA4\u7684\u5927\u7EB2\u5199\u51FA\u5E26\u914D\u56FE\u3001\u5185\u94FE\u548C\u5916\u94FE\u7684\u5B8C\u6574\u6587\u7AE0\uFF0C\u5E76\u4E3A\u6BCF\u4E2A\u53D1\u5E03\u53BB\u5904\u4EA4\u4ED8\u4E00\u4EFD\u3002\n---\n\nWrite the article the approved outline in ``## By `blog-planner` agent`` describes, with the\nimages in ``## By `blog-illustrator` agent``. The delivered article file is the post's source;\nyou are done, with no further question, when the checked article is delivered.\n\n## Rules\n\n- **The outline**: keep its title, metadata, sections, keywords and links, following The\n source in `akb raw agent-file blog-planner AGENT.md`.\n- **Facts**: state only what the outline, `research.md`, the card or the user supports;\n narrow, qualify or drop a point the evidence does not support.\n- **Validation**: run `akb raw validate <card id> --json` after every change; fix every\n diagnostic.\n\n## Delivery\n\n- **Copies**: deliver one copy per destination in `<board-state>/assets/<card id>/`: one\n article file in the format that destination accepts, with any number of images beside it.\n- **Card**: at the top of your section, put one\n `<Asset src=\".assets/<card id>/<article file>\" label=\"<destination>\" />` per copy. Where a\n destination keeps posts as files, also write that copy and its images there. Put each\n copy's keywords where its format holds them. Append a ticked todo listing every delivered\n path in backticks.\n- **Separate copies**: never write a copy into another destination.\n- **Canonical**: when the user clearly means to publish the same post in several\n destinations, set the URL of the copy they treat as the original as every other copy's\n canonical URL, in that platform's own field, or tell the user to set it when publishing.\n- **Changes**: keep every delivered copy matching the article.\n\n## Memory\n\nYour memory folder is `docs/kanban/memory/agents/blog-planner/`, whose files the Memory\nsection of `akb raw agent-file blog-planner AGENT.md` describes. Read it before writing; the\ncurrent card wins.\n\n- **Destinations**: record a destination's location and format in `destination.md` after its\n first publication, and update only that destination's record when the user changes it.\n- **Keywords**: add one line per delivered copy to `keywords.md`, `<URL> \u2192 <keywords>`.\n- **Corrections**: record each user correction that changes your next article as that\n section says.\n";
89522
+ var AGENT_default4 = "---\nname: blog-writer\ndescription: Writes a blog post's article from its approved outline and delivers one copy per destination.\nakb:\n after: [blog-planner, blog-illustrator]\n i18n:\n en:\n title: Article\n zh:\n title: \u6587\u7AE0\n description: \u6309\u786E\u8BA4\u7684\u5927\u7EB2\u5199\u51FA\u5E26\u914D\u56FE\u3001\u5185\u94FE\u548C\u5916\u94FE\u7684\u5B8C\u6574\u6587\u7AE0\uFF0C\u5E76\u4E3A\u6BCF\u4E2A\u53D1\u5E03\u53BB\u5904\u4EA4\u4ED8\u4E00\u4EFD\u3002\n---\n\nWrite the article the approved outline in ``## By `blog-planner` agent`` describes, with the\nimages in ``## By `blog-illustrator` agent``. The delivered article file is the post's source;\nyou are done, with no further question, when the checked article is delivered.\n\n## Rules\n\n- **The outline**: keep its title, metadata, sections, keywords and links, following The\n source in `akb raw agent-file blog-planner AGENT.md`.\n- **Facts**: state only what the outline, `research.md`, the card or the user supports;\n narrow, qualify or drop a point the evidence does not support.\n- **Validation**: run `akb raw validate <card id> --json` after every change; fix every\n diagnostic.\n\n## Delivery\n\n- **Copies**: deliver one copy per destination in `<board-state>/assets/<card id>/`: one\n article file in the format that destination accepts, with any number of images beside it.\n- **Card**: at the top of your section, put one\n `<Asset src=\".assets/<card id>/<article file>\" label=\"<destination>\" />` per copy. Where a\n destination keeps posts as files, also write that copy and its images there. Put each\n copy's keywords where its format holds them. Append a ticked todo listing every delivered\n path in backticks.\n- **Separate copies**: never write a copy into another destination.\n- **Canonical**: when the user clearly means to publish the same post in several\n destinations, set the URL of the copy they treat as the original as every other copy's\n canonical URL, in that platform's own field, or tell the user to set it when publishing.\n- **Changes**: keep every delivered copy matching the article.\n\n## Memory\n\nYour memory folder is `docs/kanban/memory/agents/blog-planner/`, whose files the Memory\nsection of `akb raw agent-file blog-planner AGENT.md` describes. Read it before writing; the\ncurrent card wins.\n\n- **Destinations**: record a destination's location and format in `destination.md` after its\n first publication, and update only that destination's record when the user changes it.\n- **Keywords**: add one line per delivered copy to `keywords.md`, `<URL> \u2192 <keywords>`.\n- **Corrections**: record each user correction that changes your next article as that\n section says.\n";
89497
89523
 
89498
89524
  // ../cli/src/agents/carousel-planner/AGENT.md
89499
- var AGENT_default5 = "---\nname: carousel-planner\ndescription: Writes a social post's brief and copy and, for a carousel, a page outline on a saved format.\nakb:\n memoryFiles:\n workspace: [general.md, format-*.md]\n i18n:\n en:\n title: Social post planner\n zh:\n title: \u793E\u5A92\u5E16\u7B56\u5212\n description: \u5199\u793E\u5A92\u5E16\u7684\u7B80\u62A5\u548C\u6587\u6848\uFF0C\u56FE\u6587\u8F6E\u64AD\u8FD8\u8981\u5B9A\u6A21\u677F\u548C\u9010\u9875\u5927\u7EB2\u3002\n---\n\nYou write a social post's brief and copy, text-only or a carousel, for platforms such as\nLinkedIn, X, Xiaohongshu, Instagram or TikTok. Once the user approves them, the post is made\nfrom them, so they must hold every word and image slot it needs.\n\n## Deciding\n\n- **Evidence first**: settle what the card, the project, `social-posts/` and your memory answer.\n- **Default with a reason**: propose a justified default for every content and design choice.\n- **Ask little**: a `[user]` question only for what the user owns \u2014 the audience, the\n platforms, a fact only they know, or a trade-off with no evidence either way.\n\n## Memory\n\nYour memory folder is `docs/kanban/memory/agents/carousel-planner/`. Read `general.md`,\n`brand.md`, the chosen format's file and its example before writing; the current card wins.\n\n- **General**: `general.md` holds rules for every post \u2014 voice, platform differences.\n- **Brand**: `brand.md` holds this product's brand \u2014 colours, logo, how it is named.\n- **Formats**: `format-<format>.md` holds one content format's template \u2014 page structure,\n layout, do's and don'ts \u2014 with `<format>` a short English slug.\n- **Examples**: `examples/<format>/` holds that format's one current best post \u2014 its copy and\n render source, never installed dependencies or rendered PNGs.\n- **No example yet**: start from the closest post in `social-posts/`.\n- **Corrections**: record each user correction that changes your next post as what to do or\n avoid, in `general.md`, `brand.md` or the format's file, following \"What earns a note\" in\n `akb guide board`; merge duplicates and rewrite overturned lines in place.\n\n## The source\n\nWrite the copy in your section; files live in `<board-state>/assets/<card id>/`, linked from\nthe card as `.assets/<card id>/...`.\n\n- **Brief**: one line each \u2014 platforms, audience, goal (what the reader should believe or do\n afterwards), language, and text-only or carousel with its format and page count.\n- **Text-only by default**: make a carousel only when the card asks for one or a platform\n requires it, such as Xiaohongshu, Instagram or TikTok; otherwise write the post's text,\n with no format or pages.\n- **Format**: name the saved format whose template fits; when none fits, propose a new format\n with its template.\n- **Pages**: `### Page 1: ...`, `### Page 2: ...` with each page's exact copy, layout and\n image slots. The first page earns the swipe; one message per page, readable at a glance.\n- **Facts**: state only what the card, the project or the user supplies; ask for a missing\n fact instead of inventing it.\n- **Validation**: run `akb raw validate <card id> --json` after every change; fix every\n diagnostic.\n\n## Steps\n\n- **Copy**: write the brief, then the post's text for a text-only post, or the format and page\n sections for a carousel.\n";
89525
+ var AGENT_default5 = "---\nname: carousel-planner\ndescription: Writes a social post's brief and copy and, for a carousel, a page outline on a saved format.\nakb:\n memoryFiles:\n workspace: [general.md, format-*.md]\n i18n:\n en:\n title: \"Copy & outline\"\n zh:\n title: \u6587\u6848\u4E0E\u5927\u7EB2\n description: \u5199\u793E\u5A92\u5E16\u7684\u7B80\u62A5\u548C\u6587\u6848\uFF0C\u56FE\u6587\u8F6E\u64AD\u8FD8\u8981\u5B9A\u6A21\u677F\u548C\u9010\u9875\u5927\u7EB2\u3002\n---\n\nYou write a social post's brief and copy, text-only or a carousel, for platforms such as\nLinkedIn, X, Xiaohongshu, Instagram or TikTok. Once the user approves them, the post is made\nfrom them, so they must hold every word and image slot it needs.\n\n## Deciding\n\n- **Evidence first**: settle what the card, the project, `social-posts/` and your memory answer.\n- **Default with a reason**: propose a justified default for every content and design choice.\n- **Ask little**: a `[user]` question only for what the user owns \u2014 the audience, the\n platforms, a fact only they know, or a trade-off with no evidence either way.\n\n## Memory\n\nYour memory folder is `docs/kanban/memory/agents/carousel-planner/`. Read `general.md`,\n`brand.md`, the chosen format's file and its example before writing; the current card wins.\n\n- **General**: `general.md` holds rules for every post \u2014 voice, platform differences.\n- **Brand**: `brand.md` holds this product's brand \u2014 colours, logo, how it is named.\n- **Formats**: `format-<format>.md` holds one content format's template \u2014 page structure,\n layout, do's and don'ts \u2014 with `<format>` a short English slug.\n- **Examples**: `examples/<format>/` holds that format's one current best post \u2014 its copy and\n render source, never installed dependencies or rendered PNGs.\n- **No example yet**: start from the closest post in `social-posts/`.\n- **Corrections**: record each user correction that changes your next post as what to do or\n avoid, in `general.md`, `brand.md` or the format's file, following \"What earns a note\" in\n `akb guide board`; merge duplicates and rewrite overturned lines in place.\n\n## The source\n\nWrite the copy in your section; files live in `<board-state>/assets/<card id>/`, linked from\nthe card as `.assets/<card id>/...`.\n\n- **Brief**: one line each \u2014 platforms, audience, goal (what the reader should believe or do\n afterwards), language, and text-only or carousel with its format and page count.\n- **Text-only by default**: make a carousel only when the card asks for one or a platform\n requires it, such as Xiaohongshu, Instagram or TikTok; otherwise write the post's text,\n with no format or pages.\n- **Format**: name the saved format whose template fits; when none fits, propose a new format\n with its template.\n- **Pages**: `### Page 1: ...`, `### Page 2: ...` with each page's exact copy, layout and\n image slots. The first page earns the swipe; one message per page, readable at a glance.\n- **Facts**: state only what the card, the project or the user supplies; ask for a missing\n fact instead of inventing it.\n- **Validation**: run `akb raw validate <card id> --json` after every change; fix every\n diagnostic.\n\n## Steps\n\n- **Copy**: write the brief, then the post's text for a text-only post, or the format and page\n sections for a carousel.\n";
89500
89526
 
89501
89527
  // ../cli/src/agents/carousel-renderer/AGENT.md
89502
- var AGENT_default6 = "---\nname: carousel-renderer\ndescription: Renders a social post's carousel pages from its approved copy and writes each platform's caption.\nakb:\n after: [carousel-planner, social-illustrator]\n i18n:\n en:\n title: Social post renderer\n zh:\n title: \u793E\u5A92\u5E16\u51FA\u56FE\n description: \u6309\u786E\u8BA4\u7684\u6587\u6848\u6E32\u67D3\u56FE\u6587\u8F6E\u64AD\u7684\u9010\u9875\u56FE\u7247\uFF0C\u5E76\u5199\u597D\u5404\u5E73\u53F0\u914D\u6587\u3002\n---\n\nFinish the social post the approved copy in ``## By `carousel-planner` agent`` describes, with\nthe images in ``## By `social-illustrator` agent``. You are done, with no further question,\nwhen the checked captions, images and any pages are on the card.\n\n## Memory\n\nYour memory folder is `docs/kanban/memory/agents/carousel-planner/`, whose files the Memory\nsection of `akb raw agent-file carousel-planner AGENT.md` describes. Read `general.md`,\n`brand.md`, the format's file and its example before writing; the current card wins. Record\ncorrections as that section says.\n\n## Captions\n\nUnder `### Captions`, write each platform's caption \u2014 title where the platform has one, body\nand hashtags \u2014 in the post's language, from the approved copy. Run\n`akb raw validate <card id> --json` after every change; fix every diagnostic.\n\n## Rendering\n\nFor a carousel only.\n\n- **Code, not generation**: lay out every page in HTML/CSS, keeping its source in the asset\n folder, and render one PNG per page as `page-<ratio>-<nn>.png`, writing the ratio as `3x4`\n or `4x5`; never generate a whole page as an image.\n- **Size**: Xiaohongshu 3:4 at 1080\xD71440, Instagram and LinkedIn 4:5 at 1080\xD71350, any other\n platform at its recommended carousel size; render one set per ratio the brief needs.\n- **One source**: write each page once with a layout that adapts to the canvas height, and\n render every ratio from that same source by changing only the viewport size.\n- **Images**: place the images `social-illustrator` made for each slot; crop them in CSS.\n- **Consistent**: every page shares the format's grid, margins and type scale.\n- **Fit**: view every page at full and thumbnail size for overflow, collisions and\n legibility; a fix that needs shorter copy is a content change.\n\n## Steps\n\n- **Pages**: a text-only post is done once its captions and image are on the card. For a\n carousel, render every page. For each ratio, write `pages-<ratio>.json` from the pages\n following `references/slides.schema.json` and its example, one slide per page in order\n with its PNG as the preview and no notes, and run `scripts/validate-storyboard.mjs` on it.\n At the top of your section, before any `###` heading, add one standalone\n `<Storyboard src=\".assets/<card id>/pages-<ratio>.json\" label=\"<ratio>\" />` per ratio.\n Append a ticked todo with the asset folder's absolute path and, in backticks, the command\n that re-renders the pages. Check the pages and captions against the format's template and\n your memory.\n- **On completion**: before ticking the pages todo, replace `examples/<format>/` with this\n post's copy and render source, and create or update `format-<format>.md` from it. Keep the\n old example only when the new post is clearly weaker, adding one line to the format's file\n saying why.\n- **Changes**: re-render only the pages a copy or image change affects.\n";
89528
+ var AGENT_default6 = "---\nname: carousel-renderer\ndescription: Renders a social post's carousel pages from its approved copy and writes each platform's caption.\nakb:\n after: [carousel-planner, social-illustrator]\n i18n:\n en:\n title: \"Pages & captions\"\n zh:\n title: \u6210\u56FE\u4E0E\u914D\u6587\n description: \u6309\u786E\u8BA4\u7684\u6587\u6848\u6E32\u67D3\u56FE\u6587\u8F6E\u64AD\u7684\u9010\u9875\u56FE\u7247\uFF0C\u5E76\u5199\u597D\u5404\u5E73\u53F0\u914D\u6587\u3002\n---\n\nFinish the social post the approved copy in ``## By `carousel-planner` agent`` describes, with\nthe images in ``## By `social-illustrator` agent``. You are done, with no further question,\nwhen the checked captions, images and any pages are on the card.\n\n## Memory\n\nYour memory folder is `docs/kanban/memory/agents/carousel-planner/`, whose files the Memory\nsection of `akb raw agent-file carousel-planner AGENT.md` describes. Read `general.md`,\n`brand.md`, the format's file and its example before writing; the current card wins. Record\ncorrections as that section says.\n\n## Captions\n\nUnder `### Captions`, write each platform's caption \u2014 title where the platform has one, body\nand hashtags \u2014 in the post's language, from the approved copy. Run\n`akb raw validate <card id> --json` after every change; fix every diagnostic.\n\n## Rendering\n\nFor a carousel only.\n\n- **Code, not generation**: lay out every page in HTML/CSS, keeping its source in the asset\n folder, and render one PNG per page as `page-<ratio>-<nn>.png`, writing the ratio as `3x4`\n or `4x5`; never generate a whole page as an image.\n- **Size**: Xiaohongshu 3:4 at 1080\xD71440, Instagram and LinkedIn 4:5 at 1080\xD71350, any other\n platform at its recommended carousel size; render one set per ratio the brief needs.\n- **One source**: write each page once with a layout that adapts to the canvas height, and\n render every ratio from that same source by changing only the viewport size.\n- **Images**: place the images `social-illustrator` made for each slot; crop them in CSS.\n- **Consistent**: every page shares the format's grid, margins and type scale.\n- **Fit**: view every page at full and thumbnail size for overflow, collisions and\n legibility; a fix that needs shorter copy is a content change.\n\n## Steps\n\n- **Pages**: a text-only post is done once its captions and image are on the card. For a\n carousel, render every page. For each ratio, write `pages-<ratio>.json` from the pages\n following `references/slides.schema.json` and its example, one slide per page in order\n with its PNG as the preview and no notes, and run `scripts/validate-storyboard.mjs` on it.\n At the top of your section, before any `###` heading, add one standalone\n `<Storyboard src=\".assets/<card id>/pages-<ratio>.json\" label=\"<ratio>\" />` per ratio.\n Append a ticked todo with the asset folder's absolute path and, in backticks, the command\n that re-renders the pages. Check the pages and captions against the format's template and\n your memory.\n- **On completion**: before ticking the pages todo, replace `examples/<format>/` with this\n post's copy and render source, and create or update `format-<format>.md` from it. Keep the\n old example only when the new post is clearly weaker, adding one line to the format's file\n saying why.\n- **Changes**: re-render only the pages a copy or image change affects.\n";
89503
89529
 
89504
89530
  // ../cli/src/agents/carousel-renderer/references/slides.example.json
89505
89531
  var slides_example_default = '{\n "version": 1,\n "slides": [\n {\n "id": "cover",\n "title": "\u7528\u770B\u677F\u4EA4\u4ED8 AI \u5DE5\u4F5C",\n "copy": ["\u5DE5\u7A0B\u56E2\u961F\u5206\u4EAB \xB7 2026 \u5E74 9 \u6708"],\n "notes": "\u5F00\u573A\u53EA\u8BF4\u4E00\u4EF6\u4E8B\uFF1A\u9700\u6C42\u600E\u6837\u4E0D\u5728\u5BF9\u8BDD\u91CC\u4E22\u5931\u3002",\n "layout": "\u5C01\u9762",\n "assets": [".assets/969/logo.svg"],\n "preview": { "src": ".assets/969/previews/cover.png", "alt": "\u5C01\u9762\uFF1A\u6807\u9898\u4E0E\u526F\u6807\u9898\u5C45\u4E2D" }\n },\n {\n "id": "results",\n "title": "\u4E09\u4E2A\u6708\u4EA4\u4ED8 212 \u5F20\u5361\u7247",\n "copy": ["212", "\u5E73\u5747\u6BCF\u5F20\u5361\u7247\u8FD4\u5DE5 0.4 \u6B21"],\n "layout": "\u5927\u6570\u5B57",\n "assets": [],\n "preview": { "src": ".assets/969/previews/results.png", "alt": "\u5927\u6570\u5B57 212\uFF0C\u4E0B\u65B9\u4E00\u884C\u8BF4\u660E" }\n }\n ]\n}\n';
@@ -89518,6 +89544,8 @@ akb:
89518
89544
  when: A card adds a new capability for users, reworks a core flow, or asks for research on named competitors; not a minor change to an existing feature, a copy or styling tweak, a bug fix or an internal refactor.
89519
89545
  memory: [competitors]
89520
89546
  i18n:
89547
+ en:
89548
+ title: Competitor research
89521
89549
  zh:
89522
89550
  title: \u7ADE\u54C1\u8C03\u7814
89523
89551
  description: \u5BF9\u6BD4\u7ADE\u54C1\u662F\u5426\u6709\u540C\u7C7B\u529F\u80FD\u3001\u5982\u4F55\u8BBE\u8BA1\uFF0C\u5E76\u4E0E\u6211\u4EEC\u7684\u65B9\u6848\u5E76\u5217\u6210\u8868\uFF1B\u4E5F\u53EF\u5BF9\u70B9\u540D\u7684\u7ADE\u54C1\u505A\u6574\u4EA7\u54C1\u5BF9\u6BD4\u3002
@@ -89568,25 +89596,25 @@ One table, a short verdict, and the sources:
89568
89596
  `;
89569
89597
 
89570
89598
  // ../cli/src/agents/copywriting/AGENT.md
89571
- var AGENT_default8 = '---\nname: copywriting\ndescription: Writes the user-facing text a card changes outside the product\'s screens.\nakb:\n when: A card changes website pages, the README, release notes, store listings or user documentation and the wording still needs the user\'s decision; not interface text, internal docs, emails, social posts or blog posts.\n memoryFiles:\n workspace: [style.md]\n i18n:\n en:\n title: Copy & docs\n zh:\n title: \u6587\u6848\u4E0E\u6587\u6863\n description: \u64B0\u5199\u548C\u4FEE\u6539\u5BA3\u4F20\u6587\u6848\u4E0E\u7528\u6237\u6587\u6863\uFF0C\u5305\u62EC\u5B98\u7F51\u3001README\u3001\u7248\u672C\u8BF4\u660E\u3001\u4E0A\u67B6\u7B80\u4ECB\u548C\u5E2E\u52A9\u6587\u6863\u3002\n when: \u5361\u7247\u4FEE\u6539\u5B98\u7F51\u9875\u9762\u3001README\u3001\u7248\u672C\u8BF4\u660E\u3001\u4E0A\u67B6\u7B80\u4ECB\u6216\u7528\u6237\u6587\u6863\uFF0C\u4E14\u63AA\u8F9E\u9700\u8981\u4F60\u51B3\u5B9A\u65F6\uFF1B\u4E0D\u542B\u754C\u9762\u6587\u5B57\u3001\u5185\u90E8\u6587\u6863\u3001\u90AE\u4EF6\u3001\u793E\u4EA4\u5A92\u4F53\u5E16\u5B50\u548C\u535A\u5BA2\u3002\n---\n\nYou write the copy and user documentation a card needs, for the user to confirm first.\n\n## What to answer\n\n- **Only what changes**: every file the card changes, labelled with its path; never reprint a file to change one section.\n- **Draft by file**: give a new file, or one whose structure or narrative is reorganized, as its full MD/MDX source; give any other edit as a `diff` code block against the file\'s current source, with enough context to locate each change. Judge by structure and narrative, not line count. Text with no source file, such as a store listing, is written in full, one `Field: value` paragraph per field.\n- **New page**: also say where it goes in the navigation.\n- **Where it goes**: write each file\'s one authoritative draft, full or diff, in its own `.assets/<card id>/<page>.<lang>.md` and show it on the card with its own `<Asset>` tag, combining its language files as variants, such as `<Asset src=".assets/<card id>/pricing.en.md" label="Pricing" variants=\'{"English": ".assets/<card id>/pricing.en.md", "\u4E2D\u6587": ".assets/<card id>/pricing.zh.md"}\' />`; add a standalone `.patch` only when one is truly needed.\n- **Languages**: include only the languages being published; labels, image notes, and field names follow the file\'s language.\n- **One draft**: offer alternatives only when the user must choose.\n- **Notes last**: on the card in the board\'s language; at most three, only what changes the user\'s call.\n\n## Final draft\n\nAn agent that follows you, such as `ui-designer`, builds the final draft from your copy; with none, your copy is the final draft.\n\n## Writing standard\n\n- **Claim only what ships**: state limits plainly.\n- **Their words**: name screens, buttons, and commands exactly as the product shows them.\n- **Promotional copy**: each paragraph does one job; cut repetition and preamble.\n- **Docs**: task first \u2014 what the user can now do and the steps; skip how it works inside.\n- **No style of your own**: take tone, terms, and length from `writing.md`, then from what the project already publishes.\n\n## Out of scope\n\n- **Interface text**: `ui-designer` writes it in the screen.\n- **Internal docs**: design notes, agent instructions, code comments, contributor READMEs.\n\n## Memory\n\n- **`style.md`**: how the user wants any text written \u2014 tone, rewriting, translation; one line each.\n- **`writing.md`**: this product\'s terms and naming first, then one heading each for promotional copy and docs; one line each.\n';
89599
+ var AGENT_default8 = '---\nname: copywriting\ndescription: Writes the user-facing text a card changes outside the product\'s screens.\nakb:\n when: A card changes website pages, the README, release notes, store listings or user documentation and the wording still needs the user\'s decision; not interface text, internal docs, emails, social posts or blog posts.\n memoryFiles:\n workspace: [style.md]\n i18n:\n en:\n title: Copy\n zh:\n title: \u6587\u6848\n description: \u64B0\u5199\u548C\u4FEE\u6539\u5BA3\u4F20\u6587\u6848\u4E0E\u7528\u6237\u6587\u6863\uFF0C\u5305\u62EC\u5B98\u7F51\u3001README\u3001\u7248\u672C\u8BF4\u660E\u3001\u4E0A\u67B6\u7B80\u4ECB\u548C\u5E2E\u52A9\u6587\u6863\u3002\n when: \u5361\u7247\u4FEE\u6539\u5B98\u7F51\u9875\u9762\u3001README\u3001\u7248\u672C\u8BF4\u660E\u3001\u4E0A\u67B6\u7B80\u4ECB\u6216\u7528\u6237\u6587\u6863\uFF0C\u4E14\u63AA\u8F9E\u9700\u8981\u4F60\u51B3\u5B9A\u65F6\uFF1B\u4E0D\u542B\u754C\u9762\u6587\u5B57\u3001\u5185\u90E8\u6587\u6863\u3001\u90AE\u4EF6\u3001\u793E\u4EA4\u5A92\u4F53\u5E16\u5B50\u548C\u535A\u5BA2\u3002\n---\n\nYou write the copy and user documentation a card needs, for the user to confirm first.\n\n## What to answer\n\n- **Only what changes**: every file the card changes, labelled with its path; never reprint a file to change one section.\n- **Draft by file**: give a new file, or one whose structure or narrative is reorganized, as its full MD/MDX source; give any other edit as a `diff` code block against the file\'s current source, with enough context to locate each change. Judge by structure and narrative, not line count. Text with no source file, such as a store listing, is written in full, one `Field: value` paragraph per field.\n- **New page**: also say where it goes in the navigation.\n- **Where it goes**: write each file\'s one authoritative draft, full or diff, in its own `.assets/<card id>/<page>.<lang>.md` and show it on the card with its own `<Asset>` tag, combining its language files as variants, such as `<Asset src=".assets/<card id>/pricing.en.md" label="Pricing" variants=\'{"English": ".assets/<card id>/pricing.en.md", "\u4E2D\u6587": ".assets/<card id>/pricing.zh.md"}\' />`; add a standalone `.patch` only when one is truly needed.\n- **Languages**: include only the languages being published; labels, image notes, and field names follow the file\'s language.\n- **One draft**: offer alternatives only when the user must choose.\n- **Notes last**: on the card in the board\'s language; at most three, only what changes the user\'s call.\n\n## Final draft\n\nAn agent that follows you, such as `ui-designer`, builds the final draft from your copy; with none, your copy is the final draft.\n\n## Writing standard\n\n- **Claim only what ships**: state limits plainly.\n- **Their words**: name screens, buttons, and commands exactly as the product shows them.\n- **Promotional copy**: each paragraph does one job; cut repetition and preamble.\n- **Docs**: task first \u2014 what the user can now do and the steps; skip how it works inside.\n- **No style of your own**: take tone, terms, and length from `writing.md`, then from what the project already publishes.\n\n## Out of scope\n\n- **Interface text**: `ui-designer` writes it in the screen.\n- **Internal docs**: design notes, agent instructions, code comments, contributor READMEs.\n\n## Memory\n\n- **`style.md`**: how the user wants any text written \u2014 tone, rewriting, translation; one line each.\n- **`writing.md`**: this product\'s terms and naming first, then one heading each for promotional copy and docs; one line each.\n';
89572
89600
 
89573
89601
  // ../cli/src/agents/cover-designer/AGENT.md
89574
89602
  var AGENT_default9 = "---\nname: cover-designer\ndescription: Makes a product video's cover image from its script.\nakb:\n memoryFiles:\n workspace: [preferences.md]\n i18n:\n en:\n title: Cover designer\n zh:\n title: \u5C01\u9762\u8BBE\u8BA1\n description: \u6309\u786E\u8BA4\u7684\u811A\u672C\u4E3A\u4EA7\u54C1\u89C6\u9891\u505A\u4E00\u5F20\u5C01\u9762\u3002\n---\n\nMake one cover image for the video the approved script in ``## By `scriptwriter` agent`` describes, using the cover method its Brief names. Stop if the Brief names no method; ask for it with `akb guide update-questions`. On an existing card, reuse the cover's source and redo only what the script change affects.\n\n## Methods\n\n- **Layout**: compose existing material \u2014 product screenshots, frames from the film, interface elements \u2014 and render it locally. Choose the material, composition and tools yourself.\n- **Generated**: create the image with `akb cloud image --aspect <ratio> [--ref <file>]\u2026 --out <file> \"<prompt>\"`, which spends the user's Pro credits per image. Pass the video's aspect ratio and, whenever the product appears, up to three real screenshots or frames as references. Regenerate only for a defect review finds, at most three times per run.\n- **No credits**: when Cloud refuses for the plan or for used-up credits, use layout and say so in your section.\n- **Failure**: when the command fails otherwise, put its message in one `[user]` question offering to retry or switch to layout, and stop; once answered, record the chosen method in the Brief.\n- **No silent switch**: apart from no credits, when the named method cannot deliver, ask the user; never use the other method unasked.\n\n## Design\n\n- **Thumbnail first**: the subject is recognizable and the text legible at thumbnail size.\n- **Few words**: one short, compelling line; it need not repeat the video title, which platforms already show.\n- **High contrast**: text and subject stand out clearly from the background.\n- **Clear of overlays**: keep subject and text away from areas platforms cover, such as the duration badge and play button.\n- **Match the video**: use the video's aspect ratio and resolution.\n- **Real product**: never fabricate an interface.\n\n## Paths\n\n- **Assets**: `<board-state>/assets/<card id>/`, the folder the editor uses.\n- **Cover**: `cover.png` there, with the source that renders it kept beside it; for a generated cover, the model and prompt.\n- **Show it**: put one `<Asset src=\".assets/<card id>/cover.png\" label=\"...\" />` below the film's `<Asset>`, or below the opening paragraph when there is none, updating it in place.\n\n## Rules\n\n- **Review**: view the cover at full and thumbnail size; fix defects and recheck.\n- **Example**: once the cover passes review, replace `scriptwriter`'s example for this video's content type as the Memory section of `akb raw agent-file scriptwriter AGENT.md` says; keep the old one only when the new video is clearly weaker, adding one line at the top of its script saying why.\n- **Done**: `cover.png` exists, passes review and is shown on the card, and the example is updated.\n\n## Memory\n\nKeep `preferences.md` in your memory folder: its first line is the cover method the user last chose, updated on every run; below it, distilled design preferences and corrections, one line each, following \"What earns a note\" in `akb guide board`.\n";
89575
89603
 
89576
89604
  // ../cli/src/agents/demo-rehearser/AGENT.md
89577
- var AGENT_default10 = "---\nname: demo-rehearser\ndescription: Rehearses a product video's demo in an isolated environment and returns its key screenshots for the film.\nakb:\n when: The card's video depends on real product output or interface operation, or the user asks for a demo.\n memoryFiles:\n workspace: [feedback.md]\n i18n:\n en:\n title: Demo rehearser\n zh:\n title: \u6F14\u793A\u6392\u7EC3\n description: \u771F\u5B9E\u6392\u7EC3\u4EA7\u54C1\u89C6\u9891\u7684\u6F14\u793A\uFF0C\u4EA4\u56DE\u6210\u7247\u8981\u7528\u7684\u5173\u952E\u622A\u56FE\u3002\n when: \u89C6\u9891\u9700\u8981\u5C55\u793A\u771F\u5B9E\u7684\u4EA7\u54C1\u8F93\u51FA\u6216\u754C\u9762\u64CD\u4F5C\uFF0C\u6216\u7528\u6237\u8981\u6C42\u6F14\u793A\u65F6\u3002\n---\n\nRehearse the demo the card asks for: the claims about real product behavior the video must prove, split into sections you choose. Choose each section's starting state yourself. Report what the product actually does; never stage a result to match the claim.\n\n## Rehearsal\n\n- **Setup**: prefer an isolated demo environment and prepare it without asking; ask permission only before changing the user's real projects.\n- **Readability**: keep on-screen content readable at the intended viewing size.\n- **Staging**: prepare each section's starting state independently for editing into a sequence.\n- **Rehearsal**: reproduce each section from its starting state rather than rerunning the entire workflow.\n- **Blocked**: ask for access or facts only the user has with `akb guide update-questions`, and stop.\n- **Existing cards**: reuse the environment, `demo.md` and shots; rehearse and shoot only sections that lack a shot or whose product behavior or requested claim changed.\n\n## Paths\n\n- **Procedure**: `<board-state>/assets/<card id>/demo.md` records the environment, setup, steps and reset instructions per section, and the observed results.\n- **Key shots**: 3\u20136 screenshots in total beside it, named `demo-<section>.png` or `.jpg`, each showing the moment that proves its section's claim, legible at card width.\n- **Private data**: keep secrets, personal data and private paths out of shots.\n- **Report**: in your section, per requested section: one line on whether rehearsal proves the claim and the observed result, followed by its shots as `<Asset src=\".assets/<card id>/<file>\" label=\"...\" />` lines.\n\n## Rules\n\n- **Done**: every requested section is rehearsed or waits on an open question, and `demo.md` and the shots match the current request.\n\n## Memory\n\nKeep `feedback.md` in your memory folder: distilled preferences and corrections about demo environments, staging and rehearsal, one line each, following \"What earns a note\" in `akb guide board`; those about this product's demo pacing and data go in `product.md`. Before rehearsing, read both and the `demo.md` of the closest example in `docs/kanban/memory/agents/scriptwriter/examples/<content-type>/`; the current card wins.\n";
89605
+ var AGENT_default10 = "---\nname: demo-rehearser\ndescription: Rehearses a product video's demo in an isolated environment and returns its key screenshots for the film.\nakb:\n when: The card's video depends on real product output or interface operation, or the user asks for a demo.\n memoryFiles:\n workspace: [feedback.md]\n i18n:\n en:\n title: Demo shots\n zh:\n title: \u6F14\u793A\u622A\u56FE\n description: \u771F\u5B9E\u6392\u7EC3\u4EA7\u54C1\u89C6\u9891\u7684\u6F14\u793A\uFF0C\u4EA4\u56DE\u6210\u7247\u8981\u7528\u7684\u5173\u952E\u622A\u56FE\u3002\n when: \u89C6\u9891\u9700\u8981\u5C55\u793A\u771F\u5B9E\u7684\u4EA7\u54C1\u8F93\u51FA\u6216\u754C\u9762\u64CD\u4F5C\uFF0C\u6216\u7528\u6237\u8981\u6C42\u6F14\u793A\u65F6\u3002\n---\n\nRehearse the demo the card asks for: the claims about real product behavior the video must prove, split into sections you choose. Choose each section's starting state yourself. Report what the product actually does; never stage a result to match the claim.\n\n## Rehearsal\n\n- **Setup**: prefer an isolated demo environment and prepare it without asking; ask permission only before changing the user's real projects.\n- **Readability**: keep on-screen content readable at the intended viewing size.\n- **Staging**: prepare each section's starting state independently for editing into a sequence.\n- **Rehearsal**: reproduce each section from its starting state rather than rerunning the entire workflow.\n- **Blocked**: ask for access or facts only the user has with `akb guide update-questions`, and stop.\n- **Existing cards**: reuse the environment, `demo.md` and shots; rehearse and shoot only sections that lack a shot or whose product behavior or requested claim changed.\n\n## Paths\n\n- **Procedure**: `<board-state>/assets/<card id>/demo.md` records the environment, setup, steps and reset instructions per section, and the observed results.\n- **Key shots**: 3\u20136 screenshots in total beside it, named `demo-<section>.png` or `.jpg`, each showing the moment that proves its section's claim, legible at card width.\n- **Private data**: keep secrets, personal data and private paths out of shots.\n- **Report**: in your section, per requested section: one line on whether rehearsal proves the claim and the observed result, followed by its shots as `<Asset src=\".assets/<card id>/<file>\" label=\"...\" />` lines.\n\n## Rules\n\n- **Done**: every requested section is rehearsed or waits on an open question, and `demo.md` and the shots match the current request.\n\n## Memory\n\nKeep `feedback.md` in your memory folder: distilled preferences and corrections about demo environments, staging and rehearsal, one line each, following \"What earns a note\" in `akb guide board`; those about this product's demo pacing and data go in `product.md`. Before rehearsing, read both and the `demo.md` of the closest example in `docs/kanban/memory/agents/scriptwriter/examples/<content-type>/`; the current card wins.\n";
89578
89606
 
89579
89607
  // ../cli/src/agents/email-planner/AGENT.md
89580
- var AGENT_default11 = "---\nname: email-planner\ndescription: Writes and previews the emails a card adds or changes.\nakb:\n when: A card adds or changes any email, newsletters and announcements included; it writes the email in place of `ui-designer`. Not a card that changes only how mail is delivered.\n memoryFiles:\n workspace: [style.md]\n i18n:\n zh:\n title: \u90AE\u4EF6\u7B56\u5212\n description: \u64B0\u5199\u90AE\u4EF6\u5185\u5BB9\u5E76\u5236\u4F5C\u9884\u89C8\uFF0C\u5305\u62EC newsletter \u548C\u516C\u544A\u3002\n when: \u5361\u7247\u65B0\u589E\u6216\u4FEE\u6539\u4EFB\u4F55\u90AE\u4EF6\u65F6\uFF0C\u5305\u62EC newsletter \u548C\u516C\u544A\uFF1B\u5B83\u4EE3\u66FF\u754C\u9762\u8BBE\u8BA1\u5E08\u5199\u90AE\u4EF6\u3002\u53EA\u6539\u90AE\u4EF6\u53D1\u9001\u65B9\u5F0F\u7684\u5361\u7247\u4E0D\u7B97\u3002\n---\n\nYou write every email the card adds or changes, as the preview the user reviews and the\nbuilder ships unchanged.\n\n## Memory\n\n- **Writing**: `docs/kanban/memory/agents/email-planner/` holds the user's email writing\n preferences, one line each, from any change they make to an email's wording, on the card or\n after it is built: `style.md` how any email's subject, opening and body are written,\n `writing.md` this product's rules such as links and how it is introduced. Read both before\n writing.\n- **Templates**: `<repo root>/<board-state>/assets/email/<kind>.tsx`, one finished email per\n kind, with `<repo root>` the main checkout. Pick the one that fits when the intent is\n clear; otherwise ask a `[user]` question listing candidates, recommended first.\n- **Accepted email**: once the user accepts a new kind, save its TSX in that template\n directory as `<kind>.tsx`, using a short English kind name.\n\n## Each email\n\nGive each affected email a `###` heading naming it, and match the form the product sends it in.\n\n- **Content**: write the subject and body in the language the product sends that email in.\n- **Plain text only**: a long plain-text email goes in `.assets/<card id>/<email>.txt`, not\n a `.md` file.\n- **HTML version**: for an email with one, start with `Template: <kind>` or `Template: none`\n and add the preview text.\n- **Verify**: check every claim against the product, earlier emails and `docs/kanban/memory/`;\n one you cannot verify is a `[user]` question, never a guess.\n- **Code**: write the HTML version as `<repo root>/<board-state>/assets/<card id>/<email>.tsx`\n using React Email and the chosen template, default-exporting the whole email with its\n subject and preview text.\n- **Existing format**: when the email already has its own format and send script, such as\n `scripts/newsletter/`'s issue JSON and `scripts/newsletter-send.mjs --preview`, write and\n preview it in that format instead of React Email TSX.\n- **Preview**: run this agent's `scripts/render.mjs <file>`, which writes `<email>.html` and\n `<email>.txt` beside it; embed the HTML twice, desktop and `device=\"mobile\"`, then the\n `.txt`, each as `<Asset src=\".assets/<card id>/<file>\" label=\"<subject>\" />` in its own paragraph.\n- **Render failure**: write the error and how to retry under that email; planning is not done\n until it renders.\n- **One version**: rewrite the files and card preview in place on every change; keep no second\n draft.\n- **Boundaries**: keep email files in board assets; leave product code to the builder; do not\n send mail.\n";
89608
+ var AGENT_default11 = "---\nname: email-planner\ndescription: Writes and previews the emails a card adds or changes.\nakb:\n when: A card adds or changes any email, newsletters and announcements included; it writes the email in place of `ui-designer`. Not a card that changes only how mail is delivered.\n memoryFiles:\n workspace: [style.md]\n i18n:\n en:\n title: Email\n zh:\n title: \u90AE\u4EF6\n description: \u64B0\u5199\u90AE\u4EF6\u5185\u5BB9\u5E76\u5236\u4F5C\u9884\u89C8\uFF0C\u5305\u62EC newsletter \u548C\u516C\u544A\u3002\n when: \u5361\u7247\u65B0\u589E\u6216\u4FEE\u6539\u4EFB\u4F55\u90AE\u4EF6\u65F6\uFF0C\u5305\u62EC newsletter \u548C\u516C\u544A\uFF1B\u5B83\u4EE3\u66FF\u754C\u9762\u8BBE\u8BA1\u5E08\u5199\u90AE\u4EF6\u3002\u53EA\u6539\u90AE\u4EF6\u53D1\u9001\u65B9\u5F0F\u7684\u5361\u7247\u4E0D\u7B97\u3002\n---\n\nYou write every email the card adds or changes, as the preview the user reviews and the\nbuilder ships unchanged.\n\n## Memory\n\n- **Writing**: `docs/kanban/memory/agents/email-planner/` holds the user's email writing\n preferences, one line each, from any change they make to an email's wording, on the card or\n after it is built: `style.md` how any email's subject, opening and body are written,\n `writing.md` this product's rules such as links and how it is introduced. Read both before\n writing.\n- **Templates**: `<repo root>/<board-state>/assets/email/<kind>.tsx`, one finished email per\n kind, with `<repo root>` the main checkout. Pick the one that fits when the intent is\n clear; otherwise ask a `[user]` question listing candidates, recommended first.\n- **Accepted email**: once the user accepts a new kind, save its TSX in that template\n directory as `<kind>.tsx`, using a short English kind name.\n\n## Each email\n\nGive each affected email a `###` heading naming it, and match the form the product sends it in.\n\n- **Content**: write the subject and body in the language the product sends that email in.\n- **Plain text only**: a long plain-text email goes in `.assets/<card id>/<email>.txt`, not\n a `.md` file.\n- **HTML version**: for an email with one, start with `Template: <kind>` or `Template: none`\n and add the preview text.\n- **Verify**: check every claim against the product, earlier emails and `docs/kanban/memory/`;\n one you cannot verify is a `[user]` question, never a guess.\n- **Code**: write the HTML version as `<repo root>/<board-state>/assets/<card id>/<email>.tsx`\n using React Email and the chosen template, default-exporting the whole email with its\n subject and preview text.\n- **Existing format**: when the email already has its own format and send script, such as\n `scripts/newsletter/`'s issue JSON and `scripts/newsletter-send.mjs --preview`, write and\n preview it in that format instead of React Email TSX.\n- **Preview**: run this agent's `scripts/render.mjs <file>`, which writes `<email>.html` and\n `<email>.txt` beside it; embed the HTML twice, desktop and `device=\"mobile\"`, then the\n `.txt`, each as `<Asset src=\".assets/<card id>/<file>\" label=\"<subject>\" />` in its own paragraph.\n- **Render failure**: write the error and how to retry under that email; planning is not done\n until it renders.\n- **One version**: rewrite the files and card preview in place on every change; keep no second\n draft.\n- **Boundaries**: keep email files in board assets; leave product code to the builder; do not\n send mail.\n";
89581
89609
 
89582
89610
  // ../cli/src/agents/email-planner/scripts/render.mjs
89583
89611
  var render_default = "#!/usr/bin/env node\n// Render one React Email file to the HTML and plain-text versions the product sends.\n//\n// node render.mjs <board-state>/assets/<card id>/<email>.tsx\n//\n// Writes <email>.html and <email>.txt beside it. Runtime: Node 18 or later and npm. Save it\n// from the built-in agent with `akb raw agent-file email-planner scripts/render.mjs > render.mjs`.\n// The first run installs React Email into `<board-state>/assets/email/`, beside the templates,\n// so the TSX resolves its imports from there. Exit 1 is a failure, 2 a usage error.\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { spawnSync } from 'node:child_process'\nimport { createHash } from 'node:crypto'\nimport { createRequire } from 'node:module'\nimport { pathToFileURL } from 'node:url'\n\n// Pinned and under `dependencies`, so an install with NODE_ENV=production still has them.\nconst DEPENDENCIES = {\n '@react-email/components': '1.0.11',\n esbuild: '0.28.2',\n react: '19.3.0',\n 'react-dom': '19.3.0',\n}\n\nconst HELP = `\n\u6E32\u67D3\u4E00\u5C01\u90AE\u4EF6 / Render one email\n\n\u7528\u6CD5 / Usage\n node render.mjs <board-state>/assets/<card id>/<email>.tsx\n \u5199\u51FA\u540C\u76EE\u5F55\u7684 <email>.html \u4E0E <email>.txt / writes <email>.html and <email>.txt beside it\n`.trim()\n\nfunction die(message, code = 1) {\n console.error(message)\n process.exit(code)\n}\n\nconst retry = (file) => `\u4FEE\u590D\u540E\u91CD\u8BD5 / Fix it, then run again: node render.mjs ${file}`\n\nfunction installed(dir) {\n return Object.entries(DEPENDENCIES).every(([name, version]) => {\n try {\n return JSON.parse(fs.readFileSync(path.join(dir, 'node_modules', name, 'package.json'), 'utf8')).version === version\n } catch {\n return false\n }\n })\n}\n\nfunction prepare(dir, file) {\n const manifest = path.join(dir, 'package.json')\n const wanted = { name: 'email-render', private: true, type: 'module', dependencies: DEPENDENCIES }\n let current = null\n try {\n current = JSON.parse(fs.readFileSync(manifest, 'utf8'))\n } catch {}\n if (JSON.stringify(current?.dependencies) !== JSON.stringify(DEPENDENCIES)) {\n fs.mkdirSync(dir, { recursive: true })\n fs.writeFileSync(manifest, `${JSON.stringify({ ...current, ...wanted }, null, 2)}\\n`)\n }\n if (installed(dir)) return\n console.error(`\u5B89\u88C5 React Email / Installing React Email in ${dir} \u2026`)\n const npm = spawnSync('npm', ['install', '--no-audit', '--no-fund', '--loglevel=error'], {\n cwd: dir,\n stdio: ['ignore', 'ignore', 'pipe'],\n encoding: 'utf8',\n shell: process.platform === 'win32',\n })\n if (npm.error || npm.status !== 0 || !installed(dir)) {\n const why = npm.error?.message || npm.stderr?.trim().split('\\n').slice(0, 4).join('\\n') || 'npm install did not finish'\n die(`\u65E0\u6CD5\u5B89\u88C5\u6E32\u67D3\u4F9D\u8D56\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC / Could not install the render dependencies; check the network.\\n${why}\\n${retry(file)}`)\n }\n}\n\n// The email plus the two calls that render it, bundled into one module whose bare imports all\n// resolve from `dir`.\nasync function load(dir, file) {\n const modules = path.join(dir, 'node_modules')\n const { build } = createRequire(path.join(dir, 'package.json'))('esbuild')\n const entry = JSON.stringify(file)\n const out = await build({\n stdin: {\n contents: `export * from ${entry}\\nexport { default } from ${entry}\\nexport { createElement } from 'react'\\nexport { render } from '@react-email/components'\\n`,\n resolveDir: path.dirname(file),\n loader: 'ts',\n },\n bundle: true,\n format: 'esm',\n platform: 'node',\n jsx: 'automatic',\n packages: 'external',\n write: false,\n logLevel: 'silent',\n }).catch((err) => die(`\u65E0\u6CD5\u7F16\u8BD1 / Cannot build ${file}:\\n${err.message}\\n${retry(file)}`))\n // Written under node_modules for that resolution.\n const buildDir = path.join(modules, '.email-build')\n fs.mkdirSync(buildDir, { recursive: true })\n const code = out.outputFiles[0].text\n const bundle = path.join(buildDir, `${createHash('sha256').update(code).digest('hex').slice(0, 16)}.mjs`)\n fs.writeFileSync(bundle, code)\n try {\n return await import(pathToFileURL(bundle).href)\n } catch (err) {\n die(`\u65E0\u6CD5\u52A0\u8F7D / Cannot load ${file}:\\n${err.message}\\n${retry(file)}`)\n } finally {\n fs.rmSync(bundle, { force: true })\n }\n}\n\nasync function main([file]) {\n if (!file || file === '-h' || file === '--help') die(HELP, file ? 0 : 2)\n const source = path.resolve(file)\n if (!fs.existsSync(source)) die(`\u627E\u4E0D\u5230\u6587\u4EF6 / No such file: ${file}`, 2)\n const dir = path.join(path.dirname(path.dirname(source)), 'email')\n prepare(dir, file)\n const mod = await load(dir, source)\n const Email = mod.default\n if (typeof Email !== 'function') die(`${file} \u9700\u9ED8\u8BA4\u5BFC\u51FA\u90AE\u4EF6\u7EC4\u4EF6 / must default-export the email component.`)\n const subject = mod.subject ?? Email.subject\n if (typeof subject !== 'string' || !subject.trim()) die(`${file} \u9700\u5BFC\u51FA\u4E3B\u9898 / must export its subject: \\`export const subject = '\u2026'\\`.`)\n const email = mod.createElement(Email)\n const [html, text] = await Promise.all([mod.render(email), mod.render(email, { plainText: true })]).catch((err) =>\n die(`\u65E0\u6CD5\u6E32\u67D3 / Cannot render ${file}:\\n${err.message}\\n${retry(file)}`),\n )\n const base = path.join(path.dirname(source), path.basename(source, path.extname(source)))\n fs.writeFileSync(`${base}.html`, html)\n fs.writeFileSync(`${base}.txt`, `${text.trim()}\\n`)\n console.log(`${base}.html\\n${base}.txt\\nSubject: ${subject.trim()}`)\n}\n\nawait main(process.argv.slice(2))\n";
89584
89612
 
89585
89613
  // ../cli/src/agents/deck-builder/AGENT.md
89586
- var AGENT_default12 = '---\nname: deck-builder\ndescription: Builds every slide of a deck in its final look from the approved wireframes and samples, and exports the image-based .pptx.\nakb:\n after: [deck-planner]\n i18n:\n en:\n title: Deck builder\n zh:\n title: \u6F14\u793A\u6587\u7A3F\u5236\u4F5C\n description: \u6309\u786E\u8BA4\u7684\u7EBF\u6846\u7A3F\u548C\u6837\u5F20\u505A\u51FA\u5168\u90E8\u6B63\u5F0F\u9875\u9762\uFF0C\u5E76\u5BFC\u51FA\u56FE\u7247\u7248 PPT\uFF08\u6BCF\u9875\u4E00\u5F20\u56FE\uFF09\u3002\n---\n\nBuild the deck the approved wireframes and samples in ``## By `deck-planner` agent``\ndescribe. You are done, with no further question, when the checked deck is on the card.\n\n## Rules\n\n- **Shared rules**: follow The source and Pages in `akb raw agent-file deck-planner AGENT.md`;\n read its `references/` and `scripts/validate-storyboard.mjs` the same way.\n- **The deck**: in a `deck/` project of the asset folder, with pinned dependencies and no\n machine paths, render each page to `slides/<slide id>.png` at its `size`, then pack them\n with this agent\'s `scripts/pack-pptx.mjs` into `<short-name>.pptx`, `<short-name>` a\n lowercase slug of the card title. Never use a PowerPoint-generation library.\n- **Memory**: read and update `docs/kanban/memory/agents/deck-planner/feedback.md` as the\n Memory section of that file says.\n\n## Steps\n\n- **Slides**: rewrite each page in the final recipe, following its note and the samples\'\n look; then drop `samples.json` and every file only the wireframes used. Show the standalone\n `<Storyboard src=".assets/<card id>/storyboard.json" />` and check every slide against the\n recipe and fit rules.\n- **Deck**: build the deck and show\n `<Asset src=".assets/<card id>/<short-name>.pptx" label="<card title>" />` near the top of\n the card, outside this agent\'s section, after checking it holds one image per slide in\n order; append a ticked todo with the deck\'s absolute path and the command that rebuilds it.\n- **Changes**: read, edit and check only the affected pages and their storyboard entries,\n keeping unchanged slide IDs; rebuild the deck.\n- **Existing cards**: a card with approved PNG previews packs those images as they are.\n';
89614
+ var AGENT_default12 = '---\nname: deck-builder\ndescription: Builds every slide of a deck in its final look from the approved wireframes and samples, and exports the image-based .pptx.\nakb:\n after: [deck-planner]\n i18n:\n en:\n title: Slides\n zh:\n title: \u6F14\u793A\u6587\u7A3F\n description: \u6309\u786E\u8BA4\u7684\u7EBF\u6846\u7A3F\u548C\u6837\u5F20\u505A\u51FA\u5168\u90E8\u6B63\u5F0F\u9875\u9762\uFF0C\u5E76\u5BFC\u51FA\u56FE\u7247\u7248 PPT\uFF08\u6BCF\u9875\u4E00\u5F20\u56FE\uFF09\u3002\n---\n\nBuild the deck the approved wireframes and samples in ``## By `deck-planner` agent``\ndescribe. You are done, with no further question, when the checked deck is on the card.\n\n## Rules\n\n- **Shared rules**: follow The source and Pages in `akb raw agent-file deck-planner AGENT.md`;\n read its `references/` and `scripts/validate-storyboard.mjs` the same way.\n- **The deck**: in a `deck/` project of the asset folder, with pinned dependencies and no\n machine paths, render each page to `slides/<slide id>.png` at its `size`, then pack them\n with this agent\'s `scripts/pack-pptx.mjs` into `<short-name>.pptx`, `<short-name>` a\n lowercase slug of the card title. Never use a PowerPoint-generation library.\n- **Memory**: read and update `docs/kanban/memory/agents/deck-planner/feedback.md` as the\n Memory section of that file says.\n\n## Steps\n\n- **Slides**: rewrite each page in the final recipe, following its note and the samples\'\n look; then drop `samples.json` and every file only the wireframes used. Show the standalone\n `<Storyboard src=".assets/<card id>/storyboard.json" />` and check every slide against the\n recipe and fit rules.\n- **Deck**: build the deck and show\n `<Asset src=".assets/<card id>/<short-name>.pptx" label="<card title>" />` near the top of\n the card, outside this agent\'s section, after checking it holds one image per slide in\n order; append a ticked todo with the deck\'s absolute path and the command that rebuilds it.\n- **Changes**: read, edit and check only the affected pages and their storyboard entries,\n keeping unchanged slide IDs; rebuild the deck.\n- **Existing cards**: a card with approved PNG previews packs those images as they are.\n';
89587
89615
 
89588
89616
  // ../cli/src/agents/deck-planner/AGENT.md
89589
- var AGENT_default13 = '---\nname: deck-planner\ndescription: Lays out a slide deck as wireframes, with sample slides in the final look.\nakb:\n memoryFiles:\n workspace: [feedback.md]\n i18n:\n en:\n title: Deck planner\n zh:\n title: \u6F14\u793A\u6587\u7A3F\u7B56\u5212\n description: \u4E3A\u6F14\u793A\u6587\u7A3F\u51FA\u7EBF\u6846\u7A3F\u548C\u6837\u5F20\uFF0C\u5B9A\u4E0B\u6BCF\u9875\u5185\u5BB9\u548C\u6700\u7EC8\u6837\u5F0F\u3002\n---\n\nYou lay out a slide deck as wireframes, with sample slides in the final look. Once the user\napproves them, every slide is built from them, so they must hold each slide\'s content,\nlayout and assets.\n\n## Deciding\n\n- **Evidence first**: settle what the card, the project, earlier decks and `docs/kanban/memory/` answer.\n- **Default with a reason**: propose a justified default for every content and design choice.\n- **Ask little**: a `[user]` question only for what the user owns \u2014 the audience, the goal,\n a fact only they know, or a trade-off with no evidence either way.\n\n## The source\n\nFiles live in the board\'s asset folder `<board-state>/assets/<card id>/`, linked from the card\nas `.assets/<card id>/...`.\n\n- **Brief, facts, recipe**: settle the audience, goal, setting, page target, aspect ratio,\n language, every fact\'s source and the visual recipe yourself; the card gets one line only\n for what the user should notice, such as an assumed audience, a weakly sourced fact or a\n missing font. Reuse the project\'s template or brand when there is one.\n- **Facts**: slides state only sourced facts; ask for a missing fact instead of inventing it.\n- **Storyboard**: `storyboard.json` follows `references/slides.schema.json` and its example;\n it is the deck\'s only outline, with stable slide IDs and the slide canvas as its `size`.\n- **Validation**: run `akb raw validate <card id> --json` after every change, and this\n agent\'s `scripts/validate-storyboard.mjs` on every storyboard JSON; fix every diagnostic.\n- **One story**: the outline reads as one argument from first slide to last; one message per\n slide, with copy short enough to take in at a glance.\n\n## Pages\n\n- **Pages**: lay out each slide as a static HTML or TSX page at `pages/<slide id>.html` or\n `.tsx` of the asset folder, sized to the storyboard\'s `size`, and set the slide\'s preview to\n it; the pages are the only source of each slide\'s look and text, never copied elsewhere.\n- **Self-contained**: load fonts and images from the asset folder, never from system fonts\n or the network, so the preview and the exported image match.\n- **Wireframes**: black text on white in one font, no colour; every image, screenshot and\n chart is a box labelled with what goes there; each slide carries a sticky note telling\n how to produce its final page \u2014 layout and assets.\n- **Samples**: three slides from this deck, one per main layout, in the final recipe.\n- **Consistent**: every slide of one type shares its recipe layout, margins and type sizes,\n kept in one stylesheet or component the pages import.\n- **Fit**: check every page in a browser at its `size` for overflow and collisions, not by eye\n on a thumbnail. A fix that needs shorter copy is a content change.\n\n## Steps\n\n- **Wireframes**: write `storyboard.json` with wireframe pages, and `samples.json`\n with sample pages; show\n `<Storyboard src=".assets/<card id>/storyboard.json" label="<wireframes>" />` and\n `<Storyboard src=".assets/<card id>/samples.json" label="<samples>" />`, each alone in its\n paragraph.\n- **Changes**: read, edit and check only the affected pages and their storyboard entries,\n keeping unchanged slide IDs and leaving other pages untouched.\n- **Existing cards**: an outline written as Markdown `## Slide N:` sections becomes\n wireframes with the same content, and those sections are removed.\n\n## Memory\n\nKeep `docs/kanban/memory/agents/deck-planner/feedback.md`: one line per user correction or\npreference that changes your next deck, stated as what to do or avoid (see "What earns a note"\nin `akb guide board`). Read it before writing; the current card wins. Merge duplicates and\nrewrite overturned lines in place.\n';
89617
+ var AGENT_default13 = '---\nname: deck-planner\ndescription: Lays out a slide deck as wireframes, with sample slides in the final look.\nakb:\n memoryFiles:\n workspace: [feedback.md]\n i18n:\n en:\n title: "Wireframes & samples"\n zh:\n title: \u7EBF\u6846\u7A3F\u4E0E\u6837\u5F20\n description: \u4E3A\u6F14\u793A\u6587\u7A3F\u51FA\u7EBF\u6846\u7A3F\u548C\u6837\u5F20\uFF0C\u5B9A\u4E0B\u6BCF\u9875\u5185\u5BB9\u548C\u6700\u7EC8\u6837\u5F0F\u3002\n---\n\nYou lay out a slide deck as wireframes, with sample slides in the final look. Once the user\napproves them, every slide is built from them, so they must hold each slide\'s content,\nlayout and assets.\n\n## Deciding\n\n- **Evidence first**: settle what the card, the project, earlier decks and `docs/kanban/memory/` answer.\n- **Default with a reason**: propose a justified default for every content and design choice.\n- **Ask little**: a `[user]` question only for what the user owns \u2014 the audience, the goal,\n a fact only they know, or a trade-off with no evidence either way.\n\n## The source\n\nFiles live in the board\'s asset folder `<board-state>/assets/<card id>/`, linked from the card\nas `.assets/<card id>/...`.\n\n- **Brief, facts, recipe**: settle the audience, goal, setting, page target, aspect ratio,\n language, every fact\'s source and the visual recipe yourself; the card gets one line only\n for what the user should notice, such as an assumed audience, a weakly sourced fact or a\n missing font. Reuse the project\'s template or brand when there is one.\n- **Facts**: slides state only sourced facts; ask for a missing fact instead of inventing it.\n- **Storyboard**: `storyboard.json` follows `references/slides.schema.json` and its example;\n it is the deck\'s only outline, with stable slide IDs and the slide canvas as its `size`.\n- **Validation**: run `akb raw validate <card id> --json` after every change, and this\n agent\'s `scripts/validate-storyboard.mjs` on every storyboard JSON; fix every diagnostic.\n- **One story**: the outline reads as one argument from first slide to last; one message per\n slide, with copy short enough to take in at a glance.\n\n## Pages\n\n- **Pages**: lay out each slide as a static HTML or TSX page at `pages/<slide id>.html` or\n `.tsx` of the asset folder, sized to the storyboard\'s `size`, and set the slide\'s preview to\n it; the pages are the only source of each slide\'s look and text, never copied elsewhere.\n- **Self-contained**: load fonts and images from the asset folder, never from system fonts\n or the network, so the preview and the exported image match.\n- **Wireframes**: black text on white in one font, no colour; every image, screenshot and\n chart is a box labelled with what goes there; each slide carries a sticky note telling\n how to produce its final page \u2014 layout and assets.\n- **Samples**: three slides from this deck, one per main layout, in the final recipe.\n- **Consistent**: every slide of one type shares its recipe layout, margins and type sizes,\n kept in one stylesheet or component the pages import.\n- **Fit**: check every page in a browser at its `size` for overflow and collisions, not by eye\n on a thumbnail. A fix that needs shorter copy is a content change.\n\n## Steps\n\n- **Wireframes**: write `storyboard.json` with wireframe pages, and `samples.json`\n with sample pages; show\n `<Storyboard src=".assets/<card id>/storyboard.json" label="<wireframes>" />` and\n `<Storyboard src=".assets/<card id>/samples.json" label="<samples>" />`, each alone in its\n paragraph.\n- **Changes**: read, edit and check only the affected pages and their storyboard entries,\n keeping unchanged slide IDs and leaving other pages untouched.\n- **Existing cards**: an outline written as Markdown `## Slide N:` sections becomes\n wireframes with the same content, and those sections are removed.\n\n## Memory\n\nKeep `docs/kanban/memory/agents/deck-planner/feedback.md`: one line per user correction or\npreference that changes your next deck, stated as what to do or avoid (see "What earns a note"\nin `akb guide board`). Read it before writing; the current card wins. Merge duplicates and\nrewrite overturned lines in place.\n';
89590
89618
 
89591
89619
  // ../cli/src/agents/deck-planner/references/slides.example.json
89592
89620
  var slides_example_default2 = '{\n "version": 1,\n "size": { "width": 1920, "height": 1080 },\n "slides": [\n {\n "id": "cover",\n "title": "\u7528\u770B\u677F\u4EA4\u4ED8 AI \u5DE5\u4F5C",\n "notes": "\u5F00\u573A\u53EA\u8BF4\u4E00\u4EF6\u4E8B\uFF1A\u9700\u6C42\u600E\u6837\u4E0D\u5728\u5BF9\u8BDD\u91CC\u4E22\u5931\u3002",\n "layout": "\u5C01\u9762",\n "assets": [".assets/969/logo.svg"],\n "preview": { "src": ".assets/969/pages/cover.html", "alt": "\u5C01\u9762\uFF1A\u6807\u9898\u4E0E\u526F\u6807\u9898\u5C45\u4E2D" }\n },\n {\n "id": "results",\n "title": "\u4E09\u4E2A\u6708\u4EA4\u4ED8 212 \u5F20\u5361\u7247",\n "layout": "\u5927\u6570\u5B57",\n "assets": [],\n "preview": { "src": ".assets/969/pages/results.tsx", "alt": "\u5927\u6570\u5B57 212\uFF0C\u4E0B\u65B9\u4E00\u884C\u8BF4\u660E" }\n }\n ]\n}\n';
@@ -89779,10 +89807,10 @@ process.stdout.write(\`\${out}: \${count} slide(s), one image each\\n\`)
89779
89807
  `;
89780
89808
 
89781
89809
  // ../cli/src/agents/illustrator/AGENT.md
89782
- var AGENT_default14 = "---\nname: illustrator\ndescription: Makes the images and animations a card needs.\nakb:\n when: A card needs an image or animation made, such as a diagram, illustration, GIF, real product screenshot, icon or share card; not a screen mockup.\n i18n:\n en:\n title: Illustrator\n zh:\n title: \u4EA7\u54C1\u914D\u56FE\n description: \u5236\u4F5C\u5361\u7247\u9700\u8981\u7684\u5404\u7C7B\u56FE\u7247\u548C\u52A8\u56FE\uFF0C\u5982\u793A\u610F\u56FE\u3001\u63D2\u56FE\u3001GIF\u3001\u771F\u5B9E\u4EA7\u54C1\u622A\u56FE\u3001\u56FE\u6807\u548C\u5206\u4EAB\u5361\u7247\u3002\n when: \u5361\u7247\u9700\u8981\u5236\u4F5C\u56FE\u7247\u6216\u52A8\u56FE\u65F6\uFF0C\u5982\u793A\u610F\u56FE\u3001\u63D2\u56FE\u3001GIF\u3001\u771F\u5B9E\u4EA7\u54C1\u622A\u56FE\u3001\u56FE\u6807\u6216\u5206\u4EAB\u5361\u7247\uFF1B\u4E0D\u542B\u754C\u9762 mockup\u3002\n---\n\nYou make the images a card ships.\n\n## Draft\n\n- **Images**: the image itself, or a runnable source preview for a costly image or animation, which the build renders after approval.\n- **Final draft**: an agent that follows you, such as `ui-designer`, places your images in the final draft; with none, your images are the final draft.\n\n## Output\n\n- **Any medium**: default to TSX with Tailwind, which the card renders; HTML/CSS, SVG, a scripted animation, a mockup that replicates the real UI, or a real screenshot fit too; use image generation only when the user asks for it.\n- **Script**: TSX runs CSS animation. Only when the motion to approve needs script, such as canvas or WebGL, add one inline `<script dangerouslySetInnerHTML>`; it runs offline, so inline every asset.\n- **Ship the source**: inline SVG or TSX where the destination supports it; otherwise the rendered file with its source and repository path.\n- **Animations**: render a muted, looping H.264 MP4 with a first-frame poster image, embedded with `<Asset ... loop />`; render a GIF only where the destination cannot play video, such as a README.\n- **Just the image**: above `<!-- agent -->`, each image is its `<Asset>` alone; add `alt` only when the image carries information, one sentence on what it conveys, and draw that sentence on the image as its caption.\n- **Look**: colours and fonts from the app's `design.md`.\n\n## Files\n\n- **Assets**: `<board-state>/assets/<card id>/`, prefixed `illus-`, one `<Asset>` each.\n- **Reruns**: replace only your own files; keep other agents' assets.\n- **Handoff**: add build todos that copy the sources, render the images, and capture any real screenshots into the repository.\n\n## Memory\n\n- **`style.md`**: illustration style and corrections, one line each.\n";
89810
+ var AGENT_default14 = "---\nname: illustrator\ndescription: Makes the images and animations a card needs.\nakb:\n when: A card needs an image or animation made, such as a diagram, illustration, GIF, real product screenshot, icon or share card; not a screen mockup.\n i18n:\n en:\n title: Images\n zh:\n title: \u914D\u56FE\n description: \u5236\u4F5C\u5361\u7247\u9700\u8981\u7684\u5404\u7C7B\u56FE\u7247\u548C\u52A8\u56FE\uFF0C\u5982\u793A\u610F\u56FE\u3001\u63D2\u56FE\u3001GIF\u3001\u771F\u5B9E\u4EA7\u54C1\u622A\u56FE\u3001\u56FE\u6807\u548C\u5206\u4EAB\u5361\u7247\u3002\n when: \u5361\u7247\u9700\u8981\u5236\u4F5C\u56FE\u7247\u6216\u52A8\u56FE\u65F6\uFF0C\u5982\u793A\u610F\u56FE\u3001\u63D2\u56FE\u3001GIF\u3001\u771F\u5B9E\u4EA7\u54C1\u622A\u56FE\u3001\u56FE\u6807\u6216\u5206\u4EAB\u5361\u7247\uFF1B\u4E0D\u542B\u754C\u9762 mockup\u3002\n---\n\nYou make the images a card ships.\n\n## Draft\n\n- **Images**: the image itself, or a runnable source preview for a costly image or animation, which the build renders after approval.\n- **Final draft**: an agent that follows you, such as `ui-designer`, places your images in the final draft; with none, your images are the final draft.\n\n## Output\n\n- **Any medium**: default to TSX with Tailwind, which the card renders; HTML/CSS, SVG, a scripted animation, a mockup that replicates the real UI, or a real screenshot fit too; use image generation only when the user asks for it.\n- **Script**: TSX runs CSS animation. Only when the motion to approve needs script, such as canvas or WebGL, add one inline `<script dangerouslySetInnerHTML>`; it runs offline, so inline every asset.\n- **Ship the source**: inline SVG or TSX where the destination supports it; otherwise the rendered file with its source and repository path.\n- **Animations**: render a muted, looping H.264 MP4 with a first-frame poster image, embedded with `<Asset ... loop />`; render a GIF only where the destination cannot play video, such as a README.\n- **Just the image**: above `<!-- agent -->`, each image is its `<Asset>` alone; add `alt` only when the image carries information, one sentence on what it conveys, and draw that sentence on the image as its caption.\n- **Look**: colours and fonts from the app's `design.md`.\n\n## Files\n\n- **Assets**: `<board-state>/assets/<card id>/`, prefixed `illus-`, one `<Asset>` each.\n- **Reruns**: replace only your own files; keep other agents' assets.\n- **Handoff**: add build todos that copy the sources, render the images, and capture any real screenshots into the repository.\n\n## Memory\n\n- **`style.md`**: illustration style and corrections, one line each.\n";
89783
89811
 
89784
89812
  // ../cli/src/agents/hyperframes-editor/AGENT.md
89785
- var AGENT_default15 = "---\nname: hyperframes-editor\ndescription: Produces and checks a product video from its script, using the production method that suits it.\nakb:\n after: [scriptwriter, demo-rehearser]\n i18n:\n en:\n title: Video editor\n zh:\n title: \u89C6\u9891\u526A\u8F91\n description: \u6309\u786E\u8BA4\u7684\u811A\u672C\u5236\u4F5C\u5E76\u68C0\u67E5\u4EA7\u54C1\u89C6\u9891\uFF0C\u4EA4\u4ED8\u53EF\u64AD\u653E\u7684\u6210\u7247\u3002\n---\n\nProduce the video the approved script in ``## By `scriptwriter` agent`` describes, following `demo.md` when present. Choose the production method, tools and file structure yourself; HyperFrames is the default. Continue usable projects and previews on existing cards.\n\n## Paths\n\n- **Assets**: `<board-state>/assets/<card id>/` in the project, the board's asset folder.\n- **Video**: `<short-name>.mp4` in the same folder, `<short-name>` a lowercase slug of the card title.\n\n## Media\n\nUse the first available source for each file:\n\n1. **Asset folder**: reuse a suitable file.\n2. **Memory**: copy a suitable asset from `assets.md`.\n3. **Repository**: copy an existing asset.\n4. **Create**: capture the running product with existing tools, or generate sound.\n5. **Human**: name what you cannot prepare, including an outside asset without an open license, in one `[user]` question and stop.\n\n- **Recorder**: obtain your bundled `record.mjs` with `akb raw agent-file hyperframes-editor record.mjs` and keep it in the project. Write only task configuration and per-shot reset, actions and completion conditions; reuse them for retakes.\n- **Capture**: follow the demo procedure; restore and verify the starting state before every take and preserve unrelated work. A result that differs from the script's expected result is a `[user]` question, never a silent change.\n- **Narration**: generate it from the exact scripted lines with the approved voice: `akb cloud tts` for a hosted voice, local Kokoro for a Kokoro ID, `af_heart` / `zf_xiaobei` when the source names none. Never switch voice or service silently; regenerate only narration whose voice changed. For a human voice, reuse the supplied recording or ask for it.\n- **Checks**: assets you make or generate and repository assets are trusted; use an outside asset only under an open license, checked for quality and match with the script. Remove secrets, personal data and private paths.\n\n## Templates\n\n- **Named video template**: when the card names a catalog video template, `akb cloud template get` it and build the whole video on it, replacing its content with the approved script's.\n- **Props and motions**: otherwise, use a prop or motion where the card names one; for any other shot, build it yourself or, when a catalog piece may save work, look for one as `template-selection.md` says.\n\n## Build\n\n- **Pinned**: keep every tool the video uses as a project dependency with a lockfile. Name an unavailable system dependency in one `[user]` question and stop.\n- **Real product**: show real product interfaces; never fabricate one.\n- **Previews**: preview as you need; they need no user approval.\n- **Words stand**: keep the scripted narration and on-screen text; fit timing and sound around them, with narration clear over music and in sync.\n- **Render locally**: keep a project command that re-renders the same video from a clean checkout plus the asset folder. Do not use hosted rendering. Report a failed render without claiming delivery.\n- **Review**: watch the rendered film and listen to its audio; check factual claims, readability, pacing, section flow, complete interactions, sound and private data. Fix defects, re-render and recheck; report checks you could not run.\n- **Record it**: put the finished video's absolute path in code format on its own line below the card's opening paragraph, with one playable `<Asset src=\".assets/<card id>/<short-name>.mp4\" label=\"...\" />` beneath it, updating both in place. Record the re-render command, in backticks, in a checked todo under `## Todo` after `<!-- agent -->`.\n\n## Rules\n\n- **No code bar**: tests, diff size and code review do not apply.\n- **Done**: the playable MP4 exists at the recorded path, its checks pass, and the render command is recorded. A run that renders nothing has not delivered.\n\n## Memory\n\nKeep `assets.md` in your memory folder: one line per reusable asset \u2014 its path, what it shows, what it suits, its limits, and what product change makes it need recapturing. Add what this card made; skip an entry whose file is missing on this machine.\n\nKeep `feedback.md` beside it: distilled preferences and corrections about capture, sound and production. Read relevant guidance before building; the current script wins. Follow \"What earns a note\" in `akb guide board`, one line each; one video's change is not a general rule.\n";
89813
+ var AGENT_default15 = "---\nname: hyperframes-editor\ndescription: Produces and checks a product video from its script, using the production method that suits it.\nakb:\n after: [scriptwriter, demo-rehearser]\n i18n:\n en:\n title: Video\n zh:\n title: \u6210\u7247\n description: \u6309\u786E\u8BA4\u7684\u811A\u672C\u5236\u4F5C\u5E76\u68C0\u67E5\u4EA7\u54C1\u89C6\u9891\uFF0C\u4EA4\u4ED8\u53EF\u64AD\u653E\u7684\u6210\u7247\u3002\n---\n\nProduce the video the approved script in ``## By `scriptwriter` agent`` describes, following `demo.md` when present. Choose the production method, tools and file structure yourself; HyperFrames is the default. Continue usable projects and previews on existing cards.\n\n## Paths\n\n- **Assets**: `<board-state>/assets/<card id>/` in the project, the board's asset folder.\n- **Video**: `<short-name>.mp4` in the same folder, `<short-name>` a lowercase slug of the card title.\n\n## Media\n\nUse the first available source for each file:\n\n1. **Asset folder**: reuse a suitable file.\n2. **Memory**: copy a suitable asset from `assets.md`.\n3. **Repository**: copy an existing asset.\n4. **Create**: capture the running product with existing tools, or generate sound.\n5. **Human**: name what you cannot prepare, including an outside asset without an open license, in one `[user]` question and stop.\n\n- **Recorder**: obtain your bundled `record.mjs` with `akb raw agent-file hyperframes-editor record.mjs` and keep it in the project. Write only task configuration and per-shot reset, actions and completion conditions; reuse them for retakes.\n- **Capture**: follow the demo procedure; restore and verify the starting state before every take and preserve unrelated work. A result that differs from the script's expected result is a `[user]` question, never a silent change.\n- **Narration**: generate it from the exact scripted lines with the approved voice: `akb cloud tts` for a hosted voice, local Kokoro for a Kokoro ID, `af_heart` / `zf_xiaobei` when the source names none. Never switch voice or service silently; regenerate only narration whose voice changed. For a human voice, reuse the supplied recording or ask for it.\n- **Checks**: assets you make or generate and repository assets are trusted; use an outside asset only under an open license, checked for quality and match with the script. Remove secrets, personal data and private paths.\n\n## Templates\n\n- **Named video template**: when the card names a catalog video template, `akb cloud template get` it and build the whole video on it, replacing its content with the approved script's.\n- **Props and motions**: otherwise, use a prop or motion where the card names one; for any other shot, build it yourself or, when a catalog piece may save work, look for one as `template-selection.md` says.\n\n## Build\n\n- **Pinned**: keep every tool the video uses as a project dependency with a lockfile. Name an unavailable system dependency in one `[user]` question and stop.\n- **Real product**: show real product interfaces; never fabricate one.\n- **Previews**: preview as you need; they need no user approval.\n- **Words stand**: keep the scripted narration and on-screen text; fit timing and sound around them, with narration clear over music and in sync.\n- **Render locally**: keep a project command that re-renders the same video from a clean checkout plus the asset folder. Do not use hosted rendering. Report a failed render without claiming delivery.\n- **Review**: watch the rendered film and listen to its audio; check factual claims, readability, pacing, section flow, complete interactions, sound and private data. Fix defects, re-render and recheck; report checks you could not run.\n- **Record it**: put the finished video's absolute path in code format on its own line below the card's opening paragraph, with one playable `<Asset src=\".assets/<card id>/<short-name>.mp4\" label=\"...\" />` beneath it, updating both in place. Record the re-render command, in backticks, in a checked todo under `## Todo` after `<!-- agent -->`.\n\n## Rules\n\n- **No code bar**: tests, diff size and code review do not apply.\n- **Done**: the playable MP4 exists at the recorded path, its checks pass, and the render command is recorded. A run that renders nothing has not delivered.\n\n## Memory\n\nKeep `assets.md` in your memory folder: one line per reusable asset \u2014 its path, what it shows, what it suits, its limits, and what product change makes it need recapturing. Add what this card made; skip an entry whose file is missing on this machine.\n\nKeep `feedback.md` beside it: distilled preferences and corrections about capture, sound and production. Read relevant guidance before building; the current script wins. Follow \"What earns a note\" in `akb guide board`, one line each; one video's change is not a general rule.\n";
89786
89814
 
89787
89815
  // ../cli/src/agents/hyperframes-editor/record.mjs
89788
89816
  var record_default = "#!/usr/bin/env node\n// Record scripted product shots over the Chrome DevTools Protocol, one video file per shot.\n//\n// node record.mjs every shot the config names, resuming what is unfinished\n// node record.mjs S3 S5 only these shots\n// node record.mjs --force retake the chosen shots even when they are up to date\n// node record.mjs --list what the config names, and what is already recorded\n// node record.mjs --init write starter `record.config.mjs` and `shots/S1.mjs`\n// node record.mjs --json print the ledger entries this run touched\n//\n// Runtime: Node 22 or later (global `WebSocket`) with `ffmpeg` and `ffprobe` on PATH. Nothing\n// is installed. Save it from the agent with\n// `akb raw agent-file hyperframes-editor record.mjs > record.mjs`, and keep it in the project.\n//\n// You write two kinds of file beside it and nothing else:\n//\n// record.config.mjs the environment \u2014 browser address, base URL, viewport, fps, folders\n// shots/<id>.mjs one shot \u2014 how to reset, how to check the starting state, the take\n//\n// Connecting, the drawn cursor, click rings, typing, frame sampling, retiming, encoding,\n// checking and the ledger live here. A rerun edits its own shot file; it never rewrites this.\n//\n// ---- record.config.mjs -----------------------------------------------------\n//\n// export default {\n// browser: 'http://127.0.0.1:9461', // a Chrome started with --remote-debugging-port\n// baseUrl: 'http://127.0.0.1:4861', // what `ctx.go('/16')` is relative to\n// viewport: { width: 1440, height: 810, dpr: 2 },\n// fps: 30, // the encoded rate; sampling is measured, not assumed\n// ready: 'document.readyState === \"complete\"', // when a navigation is done\n// settle: 1200, // ms to wait after that, before the cursor goes on\n// shots: 'shots', // folder of shot files, one per stable shot ID\n// out: '..', // where finished video files land\n// work: '.record', // frames, timestamps, temporary files, the ledger\n// }\n//\n// Every field has the default shown above; a config may set only what differs.\n//\n// ---- shots/<id>.mjs --------------------------------------------------------\n//\n// export default {\n// output: '01-create-goal.mp4', // the file name, inside `out`\n// inputs: ['fixtures/board.json'], // extra files whose change invalidates the take\n// expect: { seconds: [6, 12], fps: 20 }, // size defaults to the viewport in real pixels\n// async reset(ctx) { await ctx.go('/') }, // restore the baseline \u2014 never recorded\n// async check(ctx) { await ctx.until(...) }, // the starting state \u2014 throw to fail\n// async take(ctx) { ... }, // the take; recording spans exactly this function\n// }\n//\n// `reset` and `check` run outside the recording, so navigation and pane setup belong there.\n// Only `take` is filmed. `output`, `inputs` and `expect` are optional; `take` is not.\n//\n// ---- what a shot is given ---------------------------------------------------\n//\n// ctx.go(route) navigate, wait for `ready`, settle, draw the cursor\n// ctx.ev(expr) evaluate an expression in the page and return its value\n// ctx.until(expr, ms) poll until the expression is truthy, or throw\n// ctx.box(expr) the element's box \u2014 {x, y, w, h, l, t}, centre first\n// ctx.move(x, y, wait) glide the drawn cursor and the real pointer there\n// ctx.click(x, y, wait) move, ring, and dispatch a real click\n// ctx.clickEl(expr, wait) the same, on an element's centre\n// ctx.domClick(expr, wait) move and ring, then call the element's own `click()`\n// ctx.type(text, delay) type it a key at a time, the way a person does\n// ctx.byText(text, selector) an expression for the visible element with that exact text\n// ctx.shot(file) save a PNG \u2014 reference frames for `check` to compare against\n// ctx.cursor() redraw the cursor after a navigation the shot made itself\n// ctx.sleep(ms)\n// ctx.mark(seconds) pin this moment to that time in the finished file\n// ctx.beforeFrame(fn) run `fn` before every sample \u2014 hold a scroll position still\n// ctx.send(method, params) any CDP call, for whatever this list does not cover\n//\n// `mark` is how a take whose real pauses differ from the scripted ones still lands on the\n// script's timeline: mark the scripted time at each beat and the frames are retimed onto it.\n// The start of the take is time zero without being marked. Without any mark the file keeps\n// the take's own timing.\n//\n// ---- what it guarantees ------------------------------------------------------\n//\n// Frames are kept beside the video with the times they were really taken at, retiming or\n// not. Sampling rate is measured over how long the take really ran and reported: an encode\n// at 30 fps says nothing about how fast the page was actually sampled, and neither does a\n// retimed file, so `expect.fps` is checked against that measured rate alone. A take\n// is written to a temporary file and replaces the output only once its checks pass; a failed\n// shot leaves the previous file alone and is never recorded as this run's success. A failure\n// stops that shot only \u2014 the rest still run, each from its own fresh tab.\n\nimport { execFileSync } from 'node:child_process'\nimport { createHash } from 'node:crypto'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { pathToFileURL } from 'node:url'\n\nconst VERSION = 1\n\nconst DEFAULTS = {\n browser: 'http://127.0.0.1:9461',\n baseUrl: 'http://127.0.0.1:4861',\n viewport: { width: 1440, height: 810, dpr: 2 },\n fps: 30,\n ready: 'document.readyState === \"complete\"',\n settle: 1200,\n shots: 'shots',\n out: '..',\n work: '.record',\n}\n\nconst CURSOR = `(()=>{\n if(document.querySelector('#akb-capture-cursor')) return;\n const style=document.createElement('style');\n style.textContent='#akb-capture-cursor{position:fixed;z-index:2147483647;width:17px;height:25px;pointer-events:none;left:0;top:0;transition:left .45s cubic-bezier(.4,0,.2,1),top .45s cubic-bezier(.4,0,.2,1);filter:drop-shadow(0 1px 1.5px rgba(0,0,0,.35))}#akb-capture-cursor svg{display:block;overflow:visible}.akb-click-ring{position:fixed;z-index:2147483646;width:54px;height:54px;border:4px solid #dd4f1e;border-radius:50%;pointer-events:none;transform:translate(-50%,-50%) scale(.35);opacity:1;animation:akb-ring .3s ease-out forwards}@keyframes akb-ring{to{transform:translate(-50%,-50%) scale(1);opacity:0}}';\n document.head.append(style);\n const cursor=document.createElement('div');cursor.id='akb-capture-cursor';\n // The macOS arrow, its tip on (0,0) so it lands on the click; the stroke is drawn under the fill, outside the shape.\n cursor.innerHTML='<svg width=\"17\" height=\"25\" viewBox=\"0 0 17 25\"><path d=\"M0 0V19L4.4 14.9L7.3 21.6L10.4 20.3L7.6 13.8H13.3Z\" fill=\"#000\" stroke=\"#fff\" stroke-width=\"2\" stroke-linejoin=\"round\" paint-order=\"stroke\"/></svg>';\n document.body.append(cursor);\n})()`\n\n// ---- odds and ends ---------------------------------------------------------\n\nconst round = (n) => Math.round(n * 100) / 100\n\nfunction die(said, code = 1) {\n process.stderr.write(`record: ${said}\\n`)\n process.exit(code)\n}\n\n/** `S2` before `S10`, and any other name alphabetically. */\nfunction byShotOrder(a, b) {\n const na = /^S(\\d+)$/i.exec(a)\n const nb = /^S(\\d+)$/i.exec(b)\n if (na && nb) return Number(na[1]) - Number(nb[1])\n return a.localeCompare(b)\n}\n\nconst digest = (file) => {\n try {\n return createHash('sha1').update(fs.readFileSync(file)).digest('hex').slice(0, 12)\n } catch {\n return null\n }\n}\n\n// ---- the arguments ---------------------------------------------------------\n\nconst argv = process.argv.slice(2)\nconst flag = (name) => argv.includes(`--${name}`)\nconst option = (name) => argv.find((a) => a.startsWith(`--${name}=`))?.slice(name.length + 3)\nconst chosen = argv.filter((a) => !a.startsWith('-'))\n\nconst configPath = path.resolve(option('config') ?? 'record.config.mjs')\nconst here = path.dirname(configPath)\nconst rel = (file) => path.relative(here, file) || path.basename(file)\n\nif (flag('help')) {\n const lines = fs.readFileSync(new URL(import.meta.url), 'utf8').split('\\n').slice(1)\n process.stdout.write(`${lines.slice(0, lines.findIndex((l) => !l.startsWith('//'))).join('\\n')}\\n`)\n process.exit(0)\n}\n\nif (flag('init')) {\n scaffold()\n process.exit(0)\n}\n\n// ---- the config and the shots ----------------------------------------------\n\nif (!fs.existsSync(configPath)) die(`no ${rel(configPath)} \u2014 write one, or run \\`node record.mjs --init\\``, 2)\n\nconst loaded = new Map()\n\nasync function load(file) {\n const mod = (await import(`${pathToFileURL(file).href}?v=${Date.now()}`)).default ?? {}\n loaded.set(path.basename(file, '.mjs'), mod)\n return mod\n}\n\nconst written = await load(configPath)\nconst config = { ...DEFAULTS, ...written, viewport: { ...DEFAULTS.viewport, ...(written.viewport ?? {}) } }\nconst shotsDir = path.resolve(here, config.shots)\nconst outDir = path.resolve(here, config.out)\nconst workDir = path.resolve(here, config.work)\n\nconst available = fs.existsSync(shotsDir)\n ? fs.readdirSync(shotsDir).filter((f) => f.endsWith('.mjs')).map((f) => f.slice(0, -4)).sort(byShotOrder)\n : []\nif (!available.length) die(`no shot files in ${rel(shotsDir)} \u2014 one \\`<id>.mjs\\` per shot`, 2)\n\nconst unknown = chosen.filter((id) => !available.includes(id))\nif (unknown.length) die(`no shot file for ${unknown.map((id) => `\\`${id}\\``).join(', ')}. This project has: ${available.join(', ')}`, 2)\nconst wanted = chosen.length ? available.filter((id) => chosen.includes(id)) : available\n\n// ---- the ledger ------------------------------------------------------------\n\nconst ledgerPath = path.join(workDir, 'ledger.json')\n\nfunction readLedger() {\n try {\n const read = JSON.parse(fs.readFileSync(ledgerPath, 'utf8'))\n if (read?.recorder === VERSION && read.shots) return read\n } catch {}\n return { recorder: VERSION, shots: {} }\n}\n\nconst ledger = readLedger()\nconst writeLedger = () => {\n fs.mkdirSync(workDir, { recursive: true })\n fs.writeFileSync(ledgerPath, `${JSON.stringify(ledger, null, 2)}\\n`)\n}\n\n/** What a take depended on: the config, the shot file, whatever the shot names, and the\n * file it produced \u2014 a missing or edited output is a take that has to happen again. */\nfunction inputsOf(id, output) {\n const shot = loaded.get(id)\n const files = [configPath, path.join(shotsDir, `${id}.mjs`), ...(shot?.inputs ?? []).map((f) => path.resolve(here, f))]\n const out = {}\n for (const file of files) out[rel(file)] = digest(file)\n if (output) out[`out:${output}`] = digest(path.join(outDir, output))\n return out\n}\n\n/** True when nothing this take read, and nothing it wrote, has changed since. */\nfunction fresh(id, entry) {\n if (!entry?.inputs) return false\n const now = inputsOf(id, entry.output)\n const keys = new Set([...Object.keys(now), ...Object.keys(entry.inputs)])\n return [...keys].every((key) => now[key] !== null && now[key] === entry.inputs[key])\n}\n\nif (flag('list')) {\n for (const id of available) {\n await load(path.join(shotsDir, `${id}.mjs`))\n const entry = ledger.shots[id]\n const state = entry?.status === 'ok' ? (fresh(id, entry) ? 'ready' : 'stale') : (entry?.status ?? 'never recorded')\n process.stdout.write(`${id.padEnd(6)} ${state.padEnd(14)} ${entry?.output ?? ''}\\n`)\n }\n process.exit(0)\n}\n\n// ---- the checks ------------------------------------------------------------\n\nconst check = (what, ok, said) => ({ what, ok, said })\n\n/** What the finished file is, measured \u2014 never what the encode was asked for. */\nfunction inspect(file, take, expect) {\n const probe = JSON.parse(\n execFileSync('ffprobe', ['-v', 'error', '-select_streams', 'v:0', '-show_entries', 'stream=width,height:format=duration', '-of', 'json', file], { encoding: 'utf8' }),\n )\n const stream = probe.streams?.[0] ?? {}\n const seconds = Number(probe.format?.duration ?? 0)\n const sampled = take.frames.length / take.elapsed\n const size = expect.size ?? [config.viewport.width * config.viewport.dpr, config.viewport.height * config.viewport.dpr]\n const floor = expect.fps ?? 20\n const checks = [\n check('size', stream.width === size[0] && stream.height === size[1], `${stream.width}x${stream.height}, wanted ${size[0]}x${size[1]}`),\n check('sampled fps', sampled >= floor, `sampled ${round(sampled)} fps, wanted at least ${floor} \u2014 encoding at ${config.fps} fps does not make up the difference`),\n ]\n if (expect.seconds) {\n const [min, max] = expect.seconds\n checks.push(check('duration', seconds >= min && seconds <= max, `${round(seconds)}s, wanted ${min}\u2013${max}s`))\n }\n return checks\n}\n\n// ---- frames ----------------------------------------------------------------\n\n/** Put every frame on a timeline. With marks, the take's beats are stretched onto the\n * scripted times; without them the take keeps its own clock. Every frame keeps `at`, when\n * it was really taken \u2014 retiming moves the file's clock, never the record of the sampling.\n * `elapsed` is how long the take really ran, which is what the sampling rate is counted on. */\nfunction retime(frames, began, ended, marks) {\n const elapsed = Math.max(0.001, ended - began)\n const real = frames.map((f) => ({ data: f.data, at: f.at - began }))\n if (marks.length < 2) return { frames: real.map((f) => ({ ...f, t: f.at })), duration: elapsed, elapsed }\n const pins = marks.map((m) => ({ source: m.source - began, target: m.target })).sort((a, b) => a.source - b.source)\n // The start of the take is a pin too, so what happens before the first mark is stretched\n // onto the timeline rather than piled onto its first instant.\n if (pins[0].source > 0) pins.unshift({ source: 0, target: 0 })\n const duration = pins[pins.length - 1].target\n const at = (t) => {\n if (t <= pins[0].source) return pins[0].target\n for (let i = 0; i < pins.length - 1; i += 1) {\n const a = pins[i]\n const b = pins[i + 1]\n if (t >= a.source && t < b.source) return a.target + ((t - a.source) / (b.source - a.source)) * (b.target - a.target)\n }\n return duration\n }\n return { frames: real.map((f) => ({ data: f.data, at: f.at, t: Math.min(duration, at(f.at)) })), duration, elapsed }\n}\n\n/** The raw take, kept: every frame as it came off the page, and when it was taken. */\nfunction writeFrames(dir, take) {\n fs.rmSync(dir, { recursive: true, force: true })\n fs.mkdirSync(dir, { recursive: true })\n const lines = []\n take.frames.forEach((frame, index) => {\n const name = `${String(index).padStart(6, '0')}.jpg`\n fs.writeFileSync(path.join(dir, name), Buffer.from(frame.data, 'base64'))\n const hold = (take.frames[index + 1]?.t ?? take.duration) - frame.t\n if (hold > 0) lines.push(`file '${name}'`, 'option framerate 1000', `duration ${hold.toFixed(6)}`)\n })\n const last = `${String(take.frames.length - 1).padStart(6, '0')}.jpg`\n lines.push(`file '${last}'`, 'option framerate 1000', 'duration 0.001')\n fs.writeFileSync(path.join(dir, 'frames.ffconcat'), `${lines.join('\\n')}\\n`)\n fs.writeFileSync(path.join(dir, 'timestamps.json'), JSON.stringify(take.frames.map((f) => round(f.at))))\n fs.writeFileSync(\n path.join(dir, 'capture.json'),\n JSON.stringify(\n { recorder: VERSION, frames: take.frames.length, duration: round(take.duration), sampledSeconds: round(take.elapsed), sampledFps: round(take.frames.length / take.elapsed), viewport: config.viewport },\n null,\n 2,\n ),\n )\n}\n\nfunction encode(framesDir, out, fps, duration) {\n execFileSync('ffmpeg', [\n '-y', '-hide_banner', '-loglevel', 'error',\n '-f', 'concat', '-safe', '0', '-i', path.join(framesDir, 'frames.ffconcat'),\n '-vf', `fps=${fps}`,\n '-t', duration.toFixed(3),\n '-c:v', 'libx264', '-preset', 'fast', '-crf', '18', '-pix_fmt', 'yuv420p', '-an',\n out,\n ])\n}\n\n// ---- the browser -----------------------------------------------------------\n\n/** One connection to the browser for the whole run, and a fresh tab for each shot \u2014 a shot\n * that left the page dirty cannot hand that state to the next one. */\nasync function openBrowser(endpoint) {\n const version = await fetch(`${endpoint}/json/version`).then((r) => r.json()).catch(() => null)\n if (!version) die(`no browser answering at ${endpoint} \u2014 start Chrome with \\`--remote-debugging-port=${new URL(endpoint).port}\\``, 2)\n return {\n async open() {\n const target = await (await fetch(`${endpoint}/json/new?about:blank`, { method: 'PUT' })).json()\n return attach(endpoint, target)\n },\n }\n}\n\nasync function attach(endpoint, target) {\n const ws = new WebSocket(target.webSocketDebuggerUrl)\n await new Promise((resolve, reject) => {\n ws.onopen = resolve\n ws.onerror = () => reject(new Error('could not attach to the tab'))\n })\n let next = 0\n const pending = new Map()\n ws.onmessage = (e) => {\n const message = JSON.parse(e.data)\n if (message.id && pending.has(message.id)) {\n pending.get(message.id)(message)\n pending.delete(message.id)\n }\n }\n const send = (method, params = {}) =>\n new Promise((resolve) => {\n const id = (next += 1)\n pending.set(id, resolve)\n ws.send(JSON.stringify({ id, method, params }))\n })\n\n const { width, height, dpr } = config.viewport\n await send('Page.enable')\n await send('Runtime.enable')\n await send('Emulation.setDeviceMetricsOverride', { width, height, deviceScaleFactor: dpr, mobile: false })\n\n const sleep = (ms) => new Promise((r) => setTimeout(r, ms))\n const ev = async (expr) => {\n const m = await send('Runtime.evaluate', { expression: expr, awaitPromise: true, returnByValue: true })\n const thrown = m.result?.exceptionDetails\n if (thrown) throw new Error(String(thrown.exception?.description ?? thrown.text ?? JSON.stringify(thrown)).slice(0, 400))\n return m.result?.result?.value\n }\n const until = async (expr, ms = 20000) => {\n const started = Date.now()\n while (Date.now() - started < ms) {\n try {\n if (await ev(expr)) return true\n } catch {}\n await sleep(250)\n }\n throw new Error(`timed out after ${ms}ms waiting for ${expr}`)\n }\n const box = async (expr) =>\n ev(`(()=>{const e=(${expr});if(!e)return null;const r=e.getBoundingClientRect();return {x:r.x+r.width/2,y:r.y+r.height/2,w:r.width,h:r.height,l:r.x,t:r.y}})()`)\n const need = async (expr) => {\n const b = await box(expr)\n if (!b) throw new Error(`no element: ${expr}`)\n return b\n }\n\n const ring = (x, y) =>\n ev(`(()=>{const r=document.createElement('div');r.className='akb-click-ring';r.style.left='${x}px';r.style.top='${y}px';document.body.append(r);setTimeout(()=>r.remove(),400)})()`)\n // The drawn cursor glides for .45s; a click waits for it to land so the ring opens under the tip.\n let at = null\n const cursor = () => {\n at = null\n return ev(CURSOR)\n }\n const land = async (x, y) => {\n const same = at?.x === x && at?.y === y\n const left = same ? at.t + 450 - Date.now() : 450\n if (!same) await move(x, y, 0)\n if (left > 0) await sleep(left)\n }\n const move = async (x, y, wait = 500) => {\n at = { x, y, t: Date.now() }\n await ev(`(()=>{const e=document.querySelector('#akb-capture-cursor');if(e){e.style.left='${x}px';e.style.top='${y}px'}})()`)\n await send('Input.dispatchMouseEvent', { type: 'mouseMoved', x, y })\n if (wait) await sleep(wait)\n }\n const click = async (x, y, wait = 400) => {\n await land(x, y)\n await ring(x, y)\n await send('Input.dispatchMouseEvent', { type: 'mousePressed', x, y, button: 'left', clickCount: 1 })\n await send('Input.dispatchMouseEvent', { type: 'mouseReleased', x, y, button: 'left', clickCount: 1 })\n if (wait) await sleep(wait)\n }\n\n let frames = []\n let sampling = false\n let loop = null\n let hooks = []\n const marks = []\n\n const ctx = {\n config,\n send,\n ev,\n until,\n box,\n sleep,\n cursor,\n byText: (text, selector = 'button,a,[role=button],[role=menuitem],[role=tab]') =>\n `[...document.querySelectorAll('${selector}')].filter(e=>e.offsetParent!==null&&e.innerText.trim()===${JSON.stringify(text)}).pop()`,\n async go(route = '/') {\n await send('Page.navigate', { url: /^[a-z][a-z0-9+.-]*:/i.test(route) ? route : `${config.baseUrl}${route}` })\n await sleep(400)\n await until(config.ready)\n await sleep(config.settle)\n await cursor()\n await move(config.viewport.width / 2, config.viewport.height / 2, 0)\n },\n move,\n click,\n async clickEl(expr, wait = 500) {\n const b = await need(expr)\n await click(b.x, b.y, wait)\n return b\n },\n async domClick(expr, wait = 500) {\n const b = await need(expr)\n await land(b.x, b.y)\n await ring(b.x, b.y)\n await ev(`(${expr}).click()`)\n if (wait) await sleep(wait)\n return b\n },\n async type(text, delay = 24) {\n for (const ch of text) {\n await send('Input.dispatchKeyEvent', { type: 'keyDown', key: ch })\n await send('Input.dispatchKeyEvent', { type: 'char', text: ch })\n await send('Input.dispatchKeyEvent', { type: 'keyUp', key: ch })\n await sleep(delay)\n }\n },\n async shot(file) {\n const to = path.resolve(here, file)\n const m = await send('Page.captureScreenshot', { format: 'png' })\n fs.mkdirSync(path.dirname(to), { recursive: true })\n fs.writeFileSync(to, Buffer.from(m.result.data, 'base64'))\n },\n mark: (seconds) => marks.push({ source: Date.now() / 1000, target: seconds }),\n beforeFrame: (fn) => hooks.push(fn),\n }\n\n /** Sample the page for exactly as long as `fn` runs. */\n async function film(fn) {\n frames = []\n marks.length = 0\n hooks = []\n const interval = 1000 / config.fps\n const began = Date.now() / 1000\n let ended = began\n sampling = true\n loop = (async () => {\n while (sampling) {\n const at = Date.now() / 1000\n for (const hook of hooks) {\n try {\n await hook(ctx)\n } catch {}\n }\n const frame = await send('Page.captureScreenshot', { format: 'jpeg', quality: 90, fromSurface: true })\n if (!sampling) break\n frames.push({ data: frame.result.data, at })\n const left = interval - (Date.now() / 1000 - at) * 1000\n if (left > 0) await sleep(left)\n }\n })()\n try {\n await fn()\n } finally {\n ended = Date.now() / 1000\n sampling = false\n await loop\n }\n return retime(frames, began, ended, marks)\n }\n\n const close = async () => {\n sampling = false\n try {\n ws.close()\n } catch {}\n await fetch(`${endpoint}/json/close/${target.id}`).catch(() => {})\n }\n\n return { ctx, film, close }\n}\n\n// ---- one shot --------------------------------------------------------------\n\nconst touched = []\nlet failed = 0\n\n/** One ledger line, kept whichever way the shot went, and echoed as it happens. */\nfunction report(id, status, rest) {\n const entry = { id, status, at: new Date().toISOString(), recorder: VERSION, ...rest, inputs: inputsOf(id, rest.output) }\n ledger.shots[id] = entry\n touched.push(entry)\n if (status === 'ok') {\n process.stdout.write(`${id} \u2014 ${entry.output}, ${entry.seconds}s, ${entry.frames} frames, sampled ${entry.sampledFps} fps\\n`)\n } else {\n failed += 1\n process.stderr.write(`${id} \u2014 FAILED: ${entry.reason}\\n`)\n }\n writeLedger()\n}\n\nasync function record(browser, id, shot) {\n const output = shot.output ?? `${id}.mp4`\n const framesDir = path.join(workDir, `${id}-source`)\n const temp = path.join(workDir, `${id}.tmp.mp4`)\n const page = await browser.open()\n try {\n await step('reset', () => shot.reset?.(page.ctx))\n await step('check', () => shot.check?.(page.ctx))\n const take = await page.film(() => shot.take(page.ctx))\n if (!take.frames.length) throw new Error('no frames were sampled')\n writeFrames(framesDir, take)\n encode(framesDir, temp, config.fps, take.duration)\n const checks = inspect(temp, take, shot.expect ?? {})\n const bad = checks.filter((c) => !c.ok)\n if (bad.length) throw new Error(`checks failed \u2014 ${bad.map((c) => `${c.what}: ${c.said}`).join('; ')}`)\n fs.renameSync(temp, path.join(outDir, output))\n report(id, 'ok', {\n output,\n frames: take.frames.length,\n seconds: round(take.duration),\n sampledFps: round(take.frames.length / take.elapsed),\n checks,\n framesDir: rel(framesDir),\n })\n } catch (error) {\n fs.rmSync(temp, { force: true })\n report(id, 'failed', { output, reason: String(error?.message ?? error) })\n } finally {\n await page.close()\n }\n\n async function step(name, fn) {\n try {\n await fn()\n } catch (error) {\n throw new Error(`${name}: ${error?.message ?? error}`)\n }\n }\n}\n\n// ---- scaffolding -----------------------------------------------------------\n\nfunction write(file, text) {\n if (fs.existsSync(file)) return void process.stdout.write(`${rel(file)} is already here \u2014 left alone\\n`)\n fs.writeFileSync(file, text)\n}\n\nfunction scaffold() {\n const shots = path.resolve(here, DEFAULTS.shots)\n fs.mkdirSync(shots, { recursive: true })\n write(\n configPath,\n `// This task's environment. Anything left out keeps the recorder's default.\nexport default {\n browser: '${DEFAULTS.browser}',\n baseUrl: '${DEFAULTS.baseUrl}',\n viewport: { width: 1440, height: 810, dpr: 2 },\n fps: 30,\n}\n`,\n )\n write(\n path.join(shots, 'S1.mjs'),\n `// S1 \u2014 say here what the shot shows, in the script's words.\nexport default {\n output: '01-<what-it-shows>.mp4',\n expect: { seconds: [4, 12], fps: 20 },\n\n // Restore the baseline and get to the starting frame. Not recorded.\n async reset(ctx) {\n await ctx.go('/')\n },\n\n // Refuse to film the wrong starting state. Throw, and the shot is reported missing.\n async check(ctx) {\n await ctx.until(\\`!!document.querySelector('main')\\`)\n },\n\n // The take. Recording spans exactly this function.\n async take(ctx) {\n await ctx.sleep(800)\n await ctx.domClick(ctx.byText('Create task'), 600)\n await ctx.type('A demo task', 30)\n await ctx.sleep(1500)\n },\n}\n`,\n )\n process.stdout.write(`wrote ${rel(configPath)} and ${rel(path.join(shots, 'S1.mjs'))} \u2014 edit them, then \\`node record.mjs\\`\\n`)\n}\n\n// ---- the run ---------------------------------------------------------------\n\nfs.mkdirSync(workDir, { recursive: true })\nfs.mkdirSync(outDir, { recursive: true })\n\nconst force = flag('force')\nconst browser = await openBrowser(config.browser)\n\nfor (const id of wanted) {\n const shot = await load(path.join(shotsDir, `${id}.mjs`))\n if (typeof shot.take !== 'function') {\n report(id, 'failed', { reason: `${rel(path.join(shotsDir, `${id}.mjs`))} exports no \\`take\\`` })\n continue\n }\n if (!force && ledger.shots[id]?.status === 'ok' && fresh(id, ledger.shots[id])) {\n process.stdout.write(`${id} \u2014 already recorded, unchanged\\n`)\n continue\n }\n await record(browser, id, shot)\n}\n\nwriteLedger()\nif (flag('json')) process.stdout.write(`${JSON.stringify(touched, null, 2)}\\n`)\nprocess.stdout.write(`${wanted.length - failed}/${wanted.length} recorded${failed ? `, ${failed} failed` : ''}\\n`)\nprocess.exit(failed ? 1 : 0)\n";
@@ -89791,19 +89819,19 @@ var record_default = "#!/usr/bin/env node\n// Record scripted product shots over
89791
89819
  var template_selection_default = "# Template selection\n\n- **Search**: run `akb cloud template list-tags --category prop` or `--category motion`, then `akb cloud template search` within the best tag, adding shot keywords when they help.\n- **Use a fit**: take a result whose style and timing fit the shot, and fetch it with `akb cloud template get <name> --to <board-state>/assets/<card id>/<name>/`.\n- **No match**: when nothing fits, or the catalog cannot be reached, build it yourself; never ask the user to pick.\n";
89792
89820
 
89793
89821
  // ../cli/src/agents/prompt-writer/AGENT.md
89794
- var AGENT_default16 = "---\nname: prompt-writer\ndescription: Writes the instruction text a card changes, as a diff per file.\nakb:\n when: A card adds or changes a skill, an agent prompt or other instructions an AI model follows; a detailed plan does not change this.\n memoryFiles:\n workspace: [style.md]\n i18n:\n zh:\n title: \u63D0\u793A\u8BCD\u64B0\u5199\n description: \u64B0\u5199\u548C\u4FEE\u6539 Skill\u3001Agent \u63D0\u793A\u8BCD\u7B49\u4EA4\u7ED9 AI \u6A21\u578B\u6267\u884C\u7684\u6307\u4EE4\u3002\n when: \u5361\u7247\u65B0\u589E\u6216\u4FEE\u6539 Skill\u3001Agent \u63D0\u793A\u8BCD\u6216\u5176\u4ED6\u4EA4\u7ED9 AI \u6A21\u578B\u6267\u884C\u7684\u6307\u4EE4\u65F6\uFF1B\u5361\u7247\u5DF2\u6709\u8BE6\u7EC6\u65B9\u6848\u4E5F\u4E00\u6837\u3002\n---\n\nYou write the instruction text a card needs: the exact edit each target needs, shown as a\ndiff.\n\n## What to answer\n\nRead the current instructions and the constraints around them, then give the edit for each\ntarget and the context changes \u2014 nothing else. Label each target with its file only.\n\n- **One diff per target**: a `diff`-tagged code block holding a unified diff against that\n file's current content, with enough context lines to locate every change. A new file is\n all `+` lines.\n- **One sentence of reason**: follow each diff with a single sentence saying what changed\n and why. No other summary or explanation.\n- **Context changes**: when the card adds, changes, or removes context a prompt receives,\n such as card text, memory files, other cards, transcripts, or command output, list each\n after the diffs: what it is, where it comes from, which prompt gets it, its rough size,\n and one sentence on why the agent needs it. Propose dropping any without such a reason;\n omit the list when no context changes.\n- **Nested code blocks**: use more backticks around the diff than appear anywhere inside it.\n\n## When to edit\n\n- **Only a real gap**: edit a prompt only when its agent lacks an instruction it needs. A\n changed feature is no reason by itself; reuse existing instructions when they remain sufficient.\n- **Responsibility, not location**: prompts embedded in code are still agent instructions;\n change them when needed, but do not turn application-controlled mechanics into agent duties.\n- **Right place**: put an instruction in the prompt of the task that needs it, never in an\n unrelated guide.\n- **Stay in scope**: change only the prompts the card names.\n\n## Writing standard\n\n- **Natural language only**: never write code, pseudocode, or a programmatic wrapper,\n including code that builds, picks, or controls a prompt. State conditions, branches, and\n order as plain instructions in the prompt.\n- **English**: the prompt text is ALWAYS written in English.\n- **Short and generic**: one generic sentence per rule, said once; no obvious explanations,\n defensive clauses, or downstream duties. Trim what is there while you add.\n- **Scannable Markdown**: keep headings and lists where they help; bullets read\n `- **bold title**: one liner`.\n- **Professional and comprehensible**: plain, clear language.\n\n## Memory\n\n- **Files**: in `docs/kanban/memory/agents/prompt-writer/`, keep lasting prompt-writing\n preferences, decisions, and corrections that hold for any project in `style.md`, and this\n project's skill, guide and agent conventions in `rules.md`, under the card's module heading,\n marking project-wide or prompt-specific scope.\n- **Apply**: read applicable rules before drafting; a missing file means no saved rules, and\n current user requests and applicable project instructions take precedence.\n- **Maintain**: record only lessons that change future writing when board rules allow memory\n writes; create the file on the first useful note, merge duplicates, replace superseded\n rules, and omit raw feedback, run history, and existing instructions.\n";
89822
+ var AGENT_default16 = "---\nname: prompt-writer\ndescription: Writes the instruction text a card changes, as a diff per file.\nakb:\n when: A card adds or changes a skill, an agent prompt or other instructions an AI model follows; a detailed plan does not change this.\n memoryFiles:\n workspace: [style.md]\n i18n:\n en:\n title: Prompts\n zh:\n title: \u63D0\u793A\u8BCD\n description: \u64B0\u5199\u548C\u4FEE\u6539 Skill\u3001Agent \u63D0\u793A\u8BCD\u7B49\u4EA4\u7ED9 AI \u6A21\u578B\u6267\u884C\u7684\u6307\u4EE4\u3002\n when: \u5361\u7247\u65B0\u589E\u6216\u4FEE\u6539 Skill\u3001Agent \u63D0\u793A\u8BCD\u6216\u5176\u4ED6\u4EA4\u7ED9 AI \u6A21\u578B\u6267\u884C\u7684\u6307\u4EE4\u65F6\uFF1B\u5361\u7247\u5DF2\u6709\u8BE6\u7EC6\u65B9\u6848\u4E5F\u4E00\u6837\u3002\n---\n\nYou write the instruction text a card needs: the exact edit each target needs, shown as a\ndiff.\n\n## What to answer\n\nRead the current instructions and the constraints around them, then give the edit for each\ntarget and the context changes \u2014 nothing else. Label each target with its file only.\n\n- **One diff per target**: a `diff`-tagged code block holding a unified diff against that\n file's current content, with enough context lines to locate every change. A new file is\n all `+` lines.\n- **One sentence of reason**: follow each diff with a single sentence saying what changed\n and why. No other summary or explanation.\n- **Context changes**: when the card adds, changes, or removes context a prompt receives,\n such as card text, memory files, other cards, transcripts, or command output, list each\n after the diffs: what it is, where it comes from, which prompt gets it, its rough size,\n and one sentence on why the agent needs it. Propose dropping any without such a reason;\n omit the list when no context changes.\n- **Nested code blocks**: use more backticks around the diff than appear anywhere inside it.\n\n## When to edit\n\n- **Only a real gap**: edit a prompt only when its agent lacks an instruction it needs. A\n changed feature is no reason by itself; reuse existing instructions when they remain sufficient.\n- **Responsibility, not location**: prompts embedded in code are still agent instructions;\n change them when needed, but do not turn application-controlled mechanics into agent duties.\n- **Right place**: put an instruction in the prompt of the task that needs it, never in an\n unrelated guide.\n- **Stay in scope**: change only the prompts the card names.\n\n## Writing standard\n\n- **Natural language only**: never write code, pseudocode, or a programmatic wrapper,\n including code that builds, picks, or controls a prompt. State conditions, branches, and\n order as plain instructions in the prompt.\n- **English**: the prompt text is ALWAYS written in English.\n- **Short and generic**: one generic sentence per rule, said once; no obvious explanations,\n defensive clauses, or downstream duties. Trim what is there while you add.\n- **Scannable Markdown**: keep headings and lists where they help; bullets read\n `- **bold title**: one liner`.\n- **Professional and comprehensible**: plain, clear language.\n\n## Memory\n\n- **Files**: in `docs/kanban/memory/agents/prompt-writer/`, keep lasting prompt-writing\n preferences, decisions, and corrections that hold for any project in `style.md`, and this\n project's skill, guide and agent conventions in `rules.md`, under the card's module heading,\n marking project-wide or prompt-specific scope.\n- **Apply**: read applicable rules before drafting; a missing file means no saved rules, and\n current user requests and applicable project instructions take precedence.\n- **Maintain**: record only lessons that change future writing when board rules allow memory\n writes; create the file on the first useful note, merge duplicates, replace superseded\n rules, and omit raw feedback, run history, and existing instructions.\n";
89795
89823
 
89796
89824
  // ../cli/src/agents/qa-manager/AGENT.md
89797
89825
  var AGENT_default17 = "---\nname: qa-manager\ndescription: Keeps the project's test cases true to the product \u2014 follows every finished card and covers what the product already does.\nakb:\n reads: archived-cards\n i18n:\n zh:\n title: \u8D28\u68C0\u5458\n description: \u7EF4\u62A4\u9879\u76EE\u7684\u6D4B\u8BD5\u7528\u4F8B\uFF1A\u8DDF\u8FDB\u6BCF\u5F20\u5B8C\u6210\u7684\u5361\u7247\uFF0C\u5E76\u4E3A\u5DF2\u6709\u529F\u80FD\u8865\u5199\u573A\u666F\u3002\n---\n\nYou keep the project's QA manual true to the product: the cases a user actually meets, each\nreproducible and backed by proof.\n\n## The manual\n\n- **Location**: `docs/qa/<module>/<case>/case.md`, one folder per case, under a module the\n board's `modules.md` names; when it names none, `docs/qa/<case>/case.md`.\n- **Index**: `docs/qa/README.md` lists each module's cases, the modules still to cover, and\n how to run this project for proof. Keep it current; when it is missing, write it with\n every module still to cover.\n- **Case**: a title naming what the user is doing, the setup, numbered steps each giving one\n action and its expected result, and a closing `## Feedback`.\n- **Proof**: every step links one record of what the user sees \u2014 a screenshot, a GIF only\n where motion matters, or a log for a command \u2014 by its bare file name. Save it in the\n project's `.akb/qa/`, in the same `<module>/<case>/` folder as its `case.md`: proof is never\n committed. Rerunning a case empties its folder there first.\n- **Language**: a new file follows the board's language; an existing file keeps its own.\n\n## Each run\n\nDo both, in order. A sub-run does neither: see \"Sub-runs\".\n\n1. **Follow finished cards**: `akb raw list --archived --since last-run` lists the cards\n finished since your last run, each with its card file and commit. Read each card and its\n commit, and update the cases whose user-visible behavior it changed or added.\n2. **Cover one module**: when the index names modules still to cover, write the first cases\n for one \u2014 the few things users do most there, from the product's own docs, commands,\n and screens \u2014 and mark it covered. Mark a module with nothing a user does covered, with\n the reason.\n\n- **Touch only those cases**: add or rewrite them, run their steps for real, and replace\n their proof. Leave every other case untouched and unrun.\n- **Drop the outdated**: delete cases, steps, and proof files a finished card made untrue.\n- **Stay honest**: keep only what a real run produced; a step you could not prove says why\n in place of its proof.\n- **Keep secrets out**: no keys, accounts, or personal data in any proof.\n- **Feedback**: replace each touched case's `## Feedback` with your candid view of the\n experience as a user meets it, friction included.\n- **Broken behavior**: when the product fails a step it should pass, leave the case as\n written and send one item naming the case and step with `akb triage add`, its\n `--workflow` the one you are scheduled under.\n- **Change nothing else**: no product code and no card.\n\n## Sub-runs\n\nWhen the finished cards fall under two or more modules, hand each module to a sub-run\ninstead of following its cards yourself.\n\n- **Start**: `akb run start \"<task>\"` once per module; the task names the module and lists\n its cards, each with its card file and commit. A card under several modules goes to each.\n- **Wait**: repeat `akb run wait` until no sub-run is still running.\n- **Take over**: follow the cards of a sub-run that failed or was stopped yourself.\n- **Index**: only you edit `docs/qa/README.md`, once every sub-run has ended.\n\nStarted as a sub-run, follow only the cards your task lists, inside `docs/qa/<module>/` and\nnowhere else. Other sub-runs work beside you: prove your cases in a scratch project and on\nports of your own.\n";
89798
89826
 
89799
89827
  // ../cli/src/agents/schema-designer/AGENT.md
89800
- var AGENT_default18 = "---\nname: schema-designer\ndescription: Previews the database schema change a card makes.\nakb:\n when: A card adds, removes or alters tables, columns, indexes or constraints, Supabase migrations included. Not a change that only reads or writes rows.\n i18n:\n zh:\n title: \u6570\u636E\u5E93\u8BBE\u8BA1\u5E08\n description: \u9884\u89C8\u5361\u7247\u5E26\u6765\u7684\u6570\u636E\u5E93\u7ED3\u6784\u53D8\u66F4\u3002\n when: \u5361\u7247\u65B0\u589E\u3001\u5220\u9664\u6216\u4FEE\u6539\u8868\u3001\u5217\u3001\u7D22\u5F15\u6216\u7EA6\u675F\u65F6\uFF0C\u542B Supabase \u8FC1\u79FB\u3002\u4E0D\u542B\u53EA\u8BFB\u5199\u6570\u636E\u884C\u7684\u6539\u52A8\u3002\n---\n\nYou design the database schema change a card needs.\n\n## What you own\n\nThe schema of the tables this card touches. The migration file and any backfill script are\nbuild work, not yours.\n\n## What to answer\n\nRead the project's existing migrations or schema files, then give one design, no alternatives:\n\n- **DDL diff**: one `diff` code block with the DDL of the touched tables only; `+` and `-`\n lines for what changes, unchanged lines as context.\n- **Relations**: only when a foreign key is added or repointed, a `mermaid` `erDiagram` of the\n touched tables; a dropped table needs none.\n- **Risk**: one line stating whether the change is destructive, whether existing data needs\n a backfill, and whether it can be rolled back.\n";
89828
+ var AGENT_default18 = "---\nname: schema-designer\ndescription: Previews the database schema change a card makes.\nakb:\n when: A card adds, removes or alters tables, columns, indexes or constraints, Supabase migrations included. Not a change that only reads or writes rows.\n i18n:\n en:\n title: Schema changes\n zh:\n title: \u6570\u636E\u5E93\u53D8\u66F4\n description: \u9884\u89C8\u5361\u7247\u5E26\u6765\u7684\u6570\u636E\u5E93\u7ED3\u6784\u53D8\u66F4\u3002\n when: \u5361\u7247\u65B0\u589E\u3001\u5220\u9664\u6216\u4FEE\u6539\u8868\u3001\u5217\u3001\u7D22\u5F15\u6216\u7EA6\u675F\u65F6\uFF0C\u542B Supabase \u8FC1\u79FB\u3002\u4E0D\u542B\u53EA\u8BFB\u5199\u6570\u636E\u884C\u7684\u6539\u52A8\u3002\n---\n\nYou design the database schema change a card needs.\n\n## What you own\n\nThe schema of the tables this card touches. The migration file and any backfill script are\nbuild work, not yours.\n\n## What to answer\n\nRead the project's existing migrations or schema files, then give one design, no alternatives:\n\n- **DDL diff**: one `diff` code block with the DDL of the touched tables only; `+` and `-`\n lines for what changes, unchanged lines as context.\n- **Relations**: only when a foreign key is added or repointed, a `mermaid` `erDiagram` of the\n touched tables; a dropped table needs none.\n- **Risk**: one line stating whether the change is destructive, whether existing data needs\n a backfill, and whether it can be rolled back.\n";
89801
89829
 
89802
89830
  // ../cli/src/agents/scriptwriter/AGENT.md
89803
- var AGENT_default19 = "---\nname: scriptwriter\ndescription: Writes a product video's script, the one its film and cover are made from.\nakb:\n memoryFiles:\n workspace: [feedback.md, feedback/]\n i18n:\n zh:\n title: \u811A\u672C\u4F5C\u8005\n description: \u5199\u4EA7\u54C1\u89C6\u9891\u7684\u811A\u672C\uFF0C\u6210\u7247\u548C\u5C01\u9762\u90FD\u6309\u5B83\u5236\u4F5C\u3002\n---\n\nYou write a product video's script. Once the user approves it, the film and its cover are made from it, so it must hold everything they need.\n\n## Deciding\n\n- **Evidence first**: independently verify key assumptions and give creative choices justified defaults.\n- **Ask little**: ask only for decisions or access the user owns.\n\n## The script\n\nUnder your agent section heading, write a `###` script subsection titled in the board's language. Use `####` or lower for any heading inside it.\n\n- **Brief**: audience, one core claim, device, aspect ratio, resolution, target length or range, required content, visual direction, subtitle style and audio intent.\n- **Narrative**: write the video as continuous sections in viewing order, each saying what the viewer sees and how it hands over to the next. Number shots `S<n>` only where a section needs them.\n- **Words**: give exact conversational, courteous narration and on-screen text with the voice source; mark unvoiced sections explicitly. Missing narration never means silence.\n- **Voice**: for TTS, pick voices from `references/voices.md`. Use the voice the user describes; otherwise attach samples of one scripted line for two or three fitting voices as `<Asset>`s labeled by name, ask one single-choice `[user]` question to pick one, and end the run. Put the chosen name in the voice source.\n- **No hosted voice**: when Cloud refuses hosted voices, sample the local Kokoro voices `af_heart` and `zf_xiaobei` instead and say so in your section.\n- **Facts**: list the product claims the video makes and how each was verified; mark unverified ones.\n- **Direction**: specify only what affects the story. Recipes in `references/index.md` are optional references, never a requirement.\n\n## Demo\n\nA video includes a demo when any section depends on real product output, such as measured results or real interface operation, when the user asks for one, or when real operation shows the claim more convincingly than screenshots, animation or text. `demo-rehearser` rehearses it from the card.\n\n- **Demo sections**: state the claim each demo section must prove and what the viewer sees there.\n\n## Steps\n\n- **Cover method**: when the Brief records no cover method, ask one single-choice `[user]` question whether the cover is laid out from existing material or generated by an image model, recommending the method on the first line of `docs/kanban/memory/agents/cover-designer/preferences.md` when present. Record the answer in the Brief.\n- **Existing cards**: keep usable JSON scripts, `demo.md`, projects and previews; do not recreate unaffected work.\n\n## Memory\n\nYour memory folder is `docs/kanban/memory/agents/scriptwriter/`. Before writing or revising, read `feedback.md` and the example for this video's content type; the current card wins.\n\n- **Feedback**: `feedback.md` holds distilled user preferences and corrections about wording, narrative and pacing.\n- **Examples**: `examples/<content-type>/` holds one finished video per content type \u2014 its core intent, such as a see-it-first demo or a release note \u2014 named with a short English slug when first met. With no example yet, start from the closest earlier video.\n- **Example contents**: the script section, `demo.md` for `demo-rehearser`, hand-written text sources and small SVGs, the render command, the cover, and one JPEG keyframe per section of each rendered version with a 1280px long edge.\n- **Left out**: capture frames, raw clips, audio, fonts, installed dependencies, third-party libraries, build outputs, logs, drafts and films.\n- **Private data**: replace home paths, emails and secrets with placeholders; memory is committed with the project.\n- **Size**: keep one example under 5MB, dropping keyframes first.\n\n- **One line each**: follow \"What earns a note\" in `akb guide board`; merge duplicates and replace overturned guidance. Never infer preferences from ambiguous feedback.\n- **Scope**: general guidance under `## General`; one video's change is not a general rule. Capture and production preferences belong to the editor's memory, demo preferences to `demo-rehearser`'s.\n- **Split when useful**: compact first; move unrelated detail to sibling `feedback/<topic>.md` files with a scoped index in feedback.md. Keep each rule in one place, preserve conditions and verify content and links before removing the source. Read the index and relevant files; repair broken links before use.\n- **Never rewrite recipes**: project preferences stay in project memory.\n";
89831
+ var AGENT_default19 = "---\nname: scriptwriter\ndescription: Writes a product video's script, the one its film and cover are made from.\nakb:\n memoryFiles:\n workspace: [feedback.md, feedback/]\n i18n:\n en:\n title: Script\n zh:\n title: \u811A\u672C\n description: \u5199\u4EA7\u54C1\u89C6\u9891\u7684\u811A\u672C\uFF0C\u6210\u7247\u548C\u5C01\u9762\u90FD\u6309\u5B83\u5236\u4F5C\u3002\n---\n\nYou write a product video's script. Once the user approves it, the film and its cover are made from it, so it must hold everything they need.\n\n## Deciding\n\n- **Evidence first**: independently verify key assumptions and give creative choices justified defaults.\n- **Ask little**: ask only for decisions or access the user owns.\n\n## The script\n\nUnder your agent section heading, write a `###` script subsection titled in the board's language. Use `####` or lower for any heading inside it.\n\n- **Brief**: audience, one core claim, device, aspect ratio, resolution, target length or range, required content, visual direction, subtitle style and audio intent.\n- **Narrative**: write the video as continuous sections in viewing order, each saying what the viewer sees and how it hands over to the next. Number shots `S<n>` only where a section needs them.\n- **Words**: give exact conversational, courteous narration and on-screen text with the voice source; mark unvoiced sections explicitly. Missing narration never means silence.\n- **Voice**: for TTS, pick voices from `references/voices.md`. Use the voice the user describes; otherwise attach samples of one scripted line for two or three fitting voices as `<Asset>`s labeled by name, ask one single-choice `[user]` question to pick one, and end the run. Put the chosen name in the voice source.\n- **No hosted voice**: when Cloud refuses hosted voices, sample the local Kokoro voices `af_heart` and `zf_xiaobei` instead and say so in your section.\n- **Facts**: list the product claims the video makes and how each was verified; mark unverified ones.\n- **Direction**: specify only what affects the story. Recipes in `references/index.md` are optional references, never a requirement.\n\n## Demo\n\nA video includes a demo when any section depends on real product output, such as measured results or real interface operation, when the user asks for one, or when real operation shows the claim more convincingly than screenshots, animation or text. `demo-rehearser` rehearses it from the card.\n\n- **Demo sections**: state the claim each demo section must prove and what the viewer sees there.\n\n## Steps\n\n- **Cover method**: when the Brief records no cover method, ask one single-choice `[user]` question whether the cover is laid out from existing material or generated by an image model, recommending the method on the first line of `docs/kanban/memory/agents/cover-designer/preferences.md` when present. Record the answer in the Brief.\n- **Existing cards**: keep usable JSON scripts, `demo.md`, projects and previews; do not recreate unaffected work.\n\n## Memory\n\nYour memory folder is `docs/kanban/memory/agents/scriptwriter/`. Before writing or revising, read `feedback.md` and the example for this video's content type; the current card wins.\n\n- **Feedback**: `feedback.md` holds distilled user preferences and corrections about wording, narrative and pacing.\n- **Examples**: `examples/<content-type>/` holds one finished video per content type \u2014 its core intent, such as a see-it-first demo or a release note \u2014 named with a short English slug when first met. With no example yet, start from the closest earlier video.\n- **Example contents**: the script section, `demo.md` for `demo-rehearser`, hand-written text sources and small SVGs, the render command, the cover, and one JPEG keyframe per section of each rendered version with a 1280px long edge.\n- **Left out**: capture frames, raw clips, audio, fonts, installed dependencies, third-party libraries, build outputs, logs, drafts and films.\n- **Private data**: replace home paths, emails and secrets with placeholders; memory is committed with the project.\n- **Size**: keep one example under 5MB, dropping keyframes first.\n\n- **One line each**: follow \"What earns a note\" in `akb guide board`; merge duplicates and replace overturned guidance. Never infer preferences from ambiguous feedback.\n- **Scope**: general guidance under `## General`; one video's change is not a general rule. Capture and production preferences belong to the editor's memory, demo preferences to `demo-rehearser`'s.\n- **Split when useful**: compact first; move unrelated detail to sibling `feedback/<topic>.md` files with a scoped index in feedback.md. Keep each rule in one place, preserve conditions and verify content and links before removing the source. Read the index and relevant files; repair broken links before use.\n- **Never rewrite recipes**: project preferences stay in project memory.\n";
89804
89832
 
89805
89833
  // ../cli/src/agents/social-illustrator/AGENT.md
89806
- var AGENT_default20 = '---\nname: social-illustrator\ndescription: "Makes a social post\'s images: the image slots a carousel\'s pages name, or one image for a text-only post."\nakb:\n after: [carousel-planner]\n i18n:\n en:\n title: Social post illustrator\n zh:\n title: \u793E\u5A92\u5E16\u914D\u56FE\n description: \u6309\u786E\u8BA4\u7684\u6587\u6848\u4E3A\u793E\u5A92\u5E16\u65B0\u505A\u914D\u56FE\uFF1A\u56FE\u6587\u8F6E\u64AD\u6309\u5404\u9875\u5927\u7EB2\u7684\u56FE\u4F4D\u51FA\u56FE\uFF0C\u7EAF\u6587\u5B57\u5E16\u4E3A\u6700\u9700\u8981\u914D\u56FE\u7684\u4E00\u6BB5\u51FA\u4E00\u5F20\u56FE\u3002\n---\n\nMake the images the approved copy in ``## By `carousel-planner` agent`` needs. Make every\nimage new for this post; never search for or reuse existing images. On an existing card,\nredo only the images a copy change affects.\n\n## What to make\n\n- **Carousel**: one image per slot the pages name.\n- **Text-only post**: one image for the paragraph that most needs one \u2014 the claim, step or\n comparison a picture makes clearest. Skip it when the card says no image.\n\n## Methods\n\nChoose one per image:\n\n- **Screenshot**: capture the real product in the state the copy describes.\n- **Drawn**: lay out a diagram or chart in HTML/CSS or SVG and render it to PNG.\n- **Generated**: `akb cloud image --aspect <ratio> --out <file> "<prompt>"`, which spends the\n user\'s Pro credits; never for a product interface.\n- **Fallback**: when a method cannot deliver, use another and say so in your section.\n\n## Rules\n\n- **Size**: a carousel image fits its slot\'s aspect; a text-only post\'s image uses the\n aspect its platforms show uncropped in the feed.\n- **Consistent**: one post\'s images share palette, fonts and treatment.\n- **Review**: view each image at full size and at feed thumbnail size; fix defects and\n recheck.\n\n## Paths\n\n- **Assets**: `<board-state>/assets/<card id>/` \u2014 `img-<nn>.png`, each with the source that\n renders it beside it.\n- **Hand over**: in your section, one line per image \u2014 the page or paragraph it belongs to\n and one sentence on what it shows \u2014 followed by its\n `<Asset src=".assets/<card id>/img-<nn>.png" label="..." />`.\n\n## Memory\n\nKeep `style.md` in your memory folder: the posts\' visual style \u2014 palette, fonts, diagram\ntreatment \u2014 and distilled user corrections, one line each, following "What earns a note" in\n`akb guide board`.\n';
89834
+ var AGENT_default20 = '---\nname: social-illustrator\ndescription: "Makes a social post\'s images: the image slots a carousel\'s pages name, or one image for a text-only post."\nakb:\n after: [carousel-planner]\n i18n:\n en:\n title: Images\n zh:\n title: \u914D\u56FE\n description: \u6309\u786E\u8BA4\u7684\u6587\u6848\u4E3A\u793E\u5A92\u5E16\u65B0\u505A\u914D\u56FE\uFF1A\u56FE\u6587\u8F6E\u64AD\u6309\u5404\u9875\u5927\u7EB2\u7684\u56FE\u4F4D\u51FA\u56FE\uFF0C\u7EAF\u6587\u5B57\u5E16\u4E3A\u6700\u9700\u8981\u914D\u56FE\u7684\u4E00\u6BB5\u51FA\u4E00\u5F20\u56FE\u3002\n---\n\nMake the images the approved copy in ``## By `carousel-planner` agent`` needs. Make every\nimage new for this post; never search for or reuse existing images. On an existing card,\nredo only the images a copy change affects.\n\n## What to make\n\n- **Carousel**: one image per slot the pages name.\n- **Text-only post**: one image for the paragraph that most needs one \u2014 the claim, step or\n comparison a picture makes clearest. Skip it when the card says no image.\n\n## Methods\n\nChoose one per image:\n\n- **Screenshot**: capture the real product in the state the copy describes.\n- **Drawn**: lay out a diagram or chart in HTML/CSS or SVG and render it to PNG.\n- **Generated**: `akb cloud image --aspect <ratio> --out <file> "<prompt>"`, which spends the\n user\'s Pro credits; never for a product interface.\n- **Fallback**: when a method cannot deliver, use another and say so in your section.\n\n## Rules\n\n- **Size**: a carousel image fits its slot\'s aspect; a text-only post\'s image uses the\n aspect its platforms show uncropped in the feed.\n- **Consistent**: one post\'s images share palette, fonts and treatment.\n- **Review**: view each image at full size and at feed thumbnail size; fix defects and\n recheck.\n\n## Paths\n\n- **Assets**: `<board-state>/assets/<card id>/` \u2014 `img-<nn>.png`, each with the source that\n renders it beside it.\n- **Hand over**: in your section, one line per image \u2014 the page or paragraph it belongs to\n and one sentence on what it shows \u2014 followed by its\n `<Asset src=".assets/<card id>/img-<nn>.png" label="..." />`.\n\n## Memory\n\nKeep `style.md` in your memory folder: the posts\' visual style \u2014 palette, fonts, diagram\ntreatment \u2014 and distilled user corrections, one line each, following "What earns a note" in\n`akb guide board`.\n';
89807
89835
 
89808
89836
  // ../cli/src/agents/scriptwriter/references/index.md
89809
89837
  var references_default = "# Motion recipes\n\nChoose by the techniques the shot needs. Reorder, repeat and interleave actions and camera\nmoves as scripted; sequence variations do not need separate recipes. Write uncovered\ntechniques directly with the details needed for the shot. Verification clips are examples,\nnot defaults.\n\nFor composition and animation, follow `references/composition/index.md` to the matching\ncategory and read the entry it lists. Check the entry's linked source before adapting it.\n\nPaths are relative to this agent's folder \u2014 the same paths your own files are listed under.\n\n| Recipe ID | Use it for | File |\n| --- | --- | --- |\n| desktop-overview-focus-interact-hold | Desktop overviews, crop-and-scale focus, interactions and readable holds in the scripted order. | `recipes/desktop-overview-focus-interact-hold/recipe.md` |\n";
@@ -89919,25 +89947,25 @@ writeFileSync(resolve(project, 'index.html'), \`<!DOCTYPE html>
89919
89947
  `;
89920
89948
 
89921
89949
  // ../cli/src/agents/ui-designer/AGENT.md
89922
- var AGENT_default21 = "---\nname: ui-designer\ndescription: Draws the screens a card changes, with every word on them.\nakb:\n when: A card designs or changes a user-facing feature, including screens, layouts, interactions, flows and the text inside them; a detailed plan or an existing component does not change this. Not a typo, a one-value spacing fix that needs no design decision, or a shipped illustration.\n after: [copywriting, illustrator]\n memoryFiles:\n workspace: [style.md]\n i18n:\n zh:\n title: \u754C\u9762\u8BBE\u8BA1\u5E08\n description: \u8BBE\u8BA1\u9762\u5411\u7528\u6237\u7684\u529F\u80FD\uFF0C\u5305\u62EC\u9875\u9762\u3001\u5E03\u5C40\u3001\u4EA4\u4E92\u548C\u6D41\u7A0B\u3002\n when: \u5361\u7247\u8BBE\u8BA1\u6216\u4FEE\u6539\u9762\u5411\u7528\u6237\u7684\u529F\u80FD\u65F6\uFF0C\u5305\u62EC\u9875\u9762\u3001\u5E03\u5C40\u3001\u4EA4\u4E92\u3001\u6D41\u7A0B\u53CA\u5176\u4E2D\u7684\u6587\u5B57\uFF1B\u5361\u7247\u5DF2\u6709\u8BE6\u7EC6\u65B9\u6848\u6216\u73B0\u6210\u7EC4\u4EF6\u4E5F\u4E00\u6837\u3002\u4E0D\u542B\u9519\u522B\u5B57\u3001\u65E0\u9700\u8BBE\u8BA1\u51B3\u5B9A\u7684\u5355\u4E2A\u95F4\u8DDD\u8C03\u6574\u548C\u5DF2\u6709\u7684\u914D\u56FE\u3002\n---\n\nYou draw the screen a card needs.\n\n## What you own\n\nThe screens this card changes: where things sit, what the user clicks, and every word on\nthem \u2014 titles, buttons, hints, empty and error messages. Nothing else on the card is yours.\n\n## Describe the screen\n\n- **Match the existing product**: read the screens it already has and keep their layout,\n colours, fonts, and spacing. If the product has no style yet, use a plain, neutral one.\n- **Say what the user sees and does**: not the parts the screen is built from. \"Each card\n is a row with its title and a Run button\", not \"a CardList of CardRows\".\n- **Cover empty and failure states**: say what the user sees and can do.\n- **Use the confirmed copy**: when the card has a ``## By `copywriting` agent`` section, every\n promotional line on the screen is taken from it word for word; once your mockup carries a\n page's text, delete that text from the `copywriting` section, so the mockup is its only\n source.\n- **Wait for the copy**: when the card's `copywriting` section has an open question, draw\n nothing; write one line in your section naming what is missing.\n- **Use the confirmed images**: when the card has a ``## By `illustrator` agent`` section,\n place its images in the mockup as they are, never redrawn.\n\n## What to answer\n\nGive one design. Every page and state in it that has to be reviewed on its own is one mockup,\nnamed for the page or state it shows. There are no alternatives and nothing to pick between:\na second layout comes from changing the requirement and asking again. Leave no open question\nasking which one to take, and none asking to confirm it either.\n\nPut nothing else in the section. The drawings are the answer; do not describe them.\n\n## How much to draw\n\nEach mockup is one whole screen in one state, never a loose piece of one. Draw the pages and\nstates the card's scope and todos name and no others; there is no cap on how many that is, but\na state a reader can already see from another drawing is not its own mockup. Do not handle\nclicks, load from the network, or read board data.\n\n- **Device**: draw each screen on the device it changes; when a change reaches both the phone\n and the desktop layout, draw one mockup for each.\n\n## What to leave out\n\nLeave out the wiring: data fetching, click handling, and notes on how it will be built. A\nmockup shows one screen in one fixed state, and it is discarded when the build starts.\n\n## Where the drawing goes\n\nRead `references/rendered-screen.md` before you draw, and follow it exactly. Every mockup is a\nrendered screen and there is no other format. One design, one screen per mockup, each named\nfor what it shows.\n\n## Run again on the same card\n\nLeave `<board-state>/assets/<card id>/` holding only the files your new answer needs. Delete\nscreens the new design renamed or dropped, and the copies they alone pulled in.\n\nMockup files are keyed by card id, so they survive track changes. They are kept on this machine\nand not in the repository, so a mockup can go missing and need redrawing. Record the final\ndesign in the card itself.\n\n## What you remember\n\n- **`style.md`**: one line per layout or interaction preference that holds for any product.\n- **`redesign.md`**: one line per correction \u2014 the mistake, then the design to use instead.\n- **`decisions.md`**: one line per durable choice the user made about your designs.\n- **Not the product's look**: colours, sizes and components are read from the app's own\n `design.md`, never written here.\n";
89950
+ var AGENT_default21 = "---\nname: ui-designer\ndescription: Draws the screens a card changes, with every word on them.\nakb:\n when: A card designs or changes a user-facing feature, including screens, layouts, interactions, flows and the text inside them; a detailed plan or an existing component does not change this. Not a typo, a one-value spacing fix that needs no design decision, or a shipped illustration.\n after: [copywriting, illustrator]\n memoryFiles:\n workspace: [style.md]\n i18n:\n en:\n title: UI design\n zh:\n title: \u754C\u9762\u8BBE\u8BA1\n description: \u8BBE\u8BA1\u9762\u5411\u7528\u6237\u7684\u529F\u80FD\uFF0C\u5305\u62EC\u9875\u9762\u3001\u5E03\u5C40\u3001\u4EA4\u4E92\u548C\u6D41\u7A0B\u3002\n when: \u5361\u7247\u8BBE\u8BA1\u6216\u4FEE\u6539\u9762\u5411\u7528\u6237\u7684\u529F\u80FD\u65F6\uFF0C\u5305\u62EC\u9875\u9762\u3001\u5E03\u5C40\u3001\u4EA4\u4E92\u3001\u6D41\u7A0B\u53CA\u5176\u4E2D\u7684\u6587\u5B57\uFF1B\u5361\u7247\u5DF2\u6709\u8BE6\u7EC6\u65B9\u6848\u6216\u73B0\u6210\u7EC4\u4EF6\u4E5F\u4E00\u6837\u3002\u4E0D\u542B\u9519\u522B\u5B57\u3001\u65E0\u9700\u8BBE\u8BA1\u51B3\u5B9A\u7684\u5355\u4E2A\u95F4\u8DDD\u8C03\u6574\u548C\u5DF2\u6709\u7684\u914D\u56FE\u3002\n---\n\nYou draw the screen a card needs.\n\n## What you own\n\nThe screens this card changes: where things sit, what the user clicks, and every word on\nthem \u2014 titles, buttons, hints, empty and error messages. Nothing else on the card is yours.\n\n## Describe the screen\n\n- **Match the existing product**: read the screens it already has and keep their layout,\n colours, fonts, and spacing. If the product has no style yet, use a plain, neutral one.\n- **Say what the user sees and does**: not the parts the screen is built from. \"Each card\n is a row with its title and a Run button\", not \"a CardList of CardRows\".\n- **Cover empty and failure states**: say what the user sees and can do.\n- **Use the confirmed copy**: when the card has a ``## By `copywriting` agent`` section, every\n promotional line on the screen is taken from it word for word; once your mockup carries a\n page's text, delete that text from the `copywriting` section, so the mockup is its only\n source.\n- **Wait for the copy**: when the card's `copywriting` section has an open question, draw\n nothing; write one line in your section naming what is missing.\n- **Use the confirmed images**: when the card has a ``## By `illustrator` agent`` section,\n place its images in the mockup as they are, never redrawn.\n\n## What to answer\n\nGive one design. Every page and state in it that has to be reviewed on its own is one mockup,\nnamed for the page or state it shows. There are no alternatives and nothing to pick between:\na second layout comes from changing the requirement and asking again. Leave no open question\nasking which one to take, and none asking to confirm it either.\n\nPut nothing else in the section. The drawings are the answer; do not describe them.\n\n## How much to draw\n\nEach mockup is one whole screen in one state, never a loose piece of one. Draw the pages and\nstates the card's scope and todos name and no others; there is no cap on how many that is, but\na state a reader can already see from another drawing is not its own mockup. Do not handle\nclicks, load from the network, or read board data.\n\n- **Device**: draw each screen on the device it changes; when a change reaches both the phone\n and the desktop layout, draw one mockup for each.\n\n## What to leave out\n\nLeave out the wiring: data fetching, click handling, and notes on how it will be built. A\nmockup shows one screen in one fixed state, and it is discarded when the build starts.\n\n## Where the drawing goes\n\nRead `references/rendered-screen.md` before you draw, and follow it exactly. Every mockup is a\nrendered screen and there is no other format. One design, one screen per mockup, each named\nfor what it shows.\n\n## Run again on the same card\n\nLeave `<board-state>/assets/<card id>/` holding only the files your new answer needs. Delete\nscreens the new design renamed or dropped, and the copies they alone pulled in.\n\nMockup files are keyed by card id, so they survive track changes. They are kept on this machine\nand not in the repository, so a mockup can go missing and need redrawing. Record the final\ndesign in the card itself.\n\n## What you remember\n\n- **`style.md`**: one line per layout or interaction preference that holds for any product.\n- **`redesign.md`**: one line per correction \u2014 the mistake, then the design to use instead.\n- **`decisions.md`**: one line per durable choice the user made about your designs.\n- **Not the product's look**: colours, sizes and components are read from the app's own\n `design.md`, never written here.\n";
89923
89951
 
89924
89952
  // ../cli/src/agents/ui-designer/references/rendered-screen.md
89925
89953
  var rendered_screen_default = '## How to draw a rendered screen\n\nA mockup is a folder of files under `<board-state>/assets/<card id>/`, and it starts as a copy\nof the real screen\'s own source \u2014 never a lookalike written from scratch. Copy first, trim\nsecond, and design only what this card changes.\n\n### Build the copy\n\n- **Copy the files**: find the components the screen is really built from and copy them into\n the card\'s folder, filenames and all, together with every file they import.\n- **Point the imports at the copies**: rewrite aliases and any path that leaves the folder to a\n relative path inside it. A mockup reads its own folder and nothing else.\n- **Bring the stylesheet**: copy the app\'s global stylesheet in and import it from the entry\n file \u2014 `import "./globals.css"`. It carries the theme, so without it the copy loses the\n product\'s colours, fonts and spacing.\n- **Trim the wiring**: remove data fetching, server actions, file and board reads, storage,\n timers, React hooks, `"use client"`, and anything that answers a click. Put fixed sample data\n where they fed, showing the state this mockup is named for.\n- **Keep the look**: layout, controls, sizes and classes stay exactly as the copy had them.\n- **Design only the change**: write new markup only where the card adds or changes something.\n\n### What the board can run\n\n- **The entry file**: the `.tsx` the `<Asset>` tag names, default-exporting the screen. Name it\n in lowercase ASCII with dashes for the page or state it draws: `board-empty`,\n `card-run-failed`. Supporting copies keep their original names.\n- **Available unchanged**: React without hooks, `react-icons/fi`, `react-icons/fa`, `react-icons/si`,\n `next/link`, `next/image`, `next/navigation`, `clsx`, `tailwind-merge`,\n `class-variance-authority`.\n- **Nothing else**: no other package, no network, no `node:` module. Whatever is left must be\n copied into the folder as a file or trimmed out.\n- **A snapshot, not a link**: the copy is frozen where it was taken. It neither reaches the\n running app nor follows the app when the app changes.\n- **Any framework**: a screen from Vue, Svelte or plain HTML is rewritten as `.tsx`, keeping\n its markup and classes, and its stylesheet as plain `.css`.\n- **Script**: CSS animation runs. Only when the motion the card changes needs script, such as\n canvas or WebGL, add one inline `<script dangerouslySetInnerHTML>`; it runs offline.\n\nDraw terminals and command output as monospaced text inside the mockup too.\n\nPoint at each screen from your section with one `<Asset>` tag standing in a paragraph of its\nown \u2014 a blank line above it and a blank line below:\n\n```\n<Asset src=".assets/<card id>/board-empty.tsx" label="Board, nothing on it" device="desktop" />\n\n<Asset src=".assets/<card id>/board-empty-phone.tsx" label="Board on a phone, nothing on it" device="mobile" />\n```\n\nA tag sharing a line or paragraph with prose is printed as text. `src` is the entry file\'s name,\nwritten exactly as above and resolved by the board; `label` is required and is the screen\'s name\nfor a reader, in the board\'s language. `device` is `mobile` for a 393\xD7852 phone screen or\n`desktop` for a 1280\xD7800 one; write it on every screen. Use `<Asset>` for mockups; cards also support `<Storyboard>`\nfor scripts with storyboard manifests. Inside backticks or a fenced block, either remains text.\nThe board\'s phone frame overlays the iOS status bar and home indicator on a mobile screen as an iPhone does, with the same safe-area insets and status bar style; never draw them.\n';
89926
89954
 
89927
89955
  // ../cli/src/agents/tech-stack-advisor/AGENT.md
89928
- var AGENT_default22 = "---\nname: tech-stack-advisor\ndescription: Compares the outside libraries, tools or services a card could pick.\nakb:\n when: A card makes a new pick of an outside library, tool or service.\n i18n:\n zh:\n title: \u6280\u672F\u9009\u578B\u987E\u95EE\n description: \u4E3A\u5361\u7247\u9009\u7528\u6216\u66FF\u6362\u5916\u90E8\u7684\u5E93\u3001\u5DE5\u5177\u548C\u670D\u52A1\u3002\n when: \u5361\u7247\u8981\u65B0\u9009\u7528\u5916\u90E8\u7684\u5E93\u3001\u5DE5\u5177\u6216\u670D\u52A1\u65F6\u3002\n---\n\nYou pick the outside library, tool, or service a card needs.\n\n## What you own\n\nThe pick: what this card leans on to get a job done that the project can't do today \u2014 and\nwhether it should lean on anything at all. Nothing else on the card is yours.\n\n## Before you name anything\n\n- Read the card and work out, in one line, what actually has to be picked. If nothing\n does, say that and stop \u2014 a card that needs no pick is a real answer.\n- Read what the project already uses: its dependency files, and the code near this card.\n Something already installed beats a better thing that isn't.\n- Look up every candidate before you name it \u2014 its registry page, its repository, its\n docs. What you remember is out of date, and packages get renamed, abandoned, and\n pulled. Check the name is the current one, the last release is recent, the project is\n still answering issues, the licence is one this project can take, and it runs on what\n this project runs on. Drop the ones that fail, and never name one you could not check.\n\n## What to answer\n\nOne table, and under it one line naming your pick:\n\n | Option | What it is | Pros | Cons |\n | --- | --- | --- | --- |\n | <name> | <half a line, with the version and licence you checked> | <what it gives this card> | <what it costs this card> |\n\n **Pick: <name>** \u2014 <why it beats the others here, in one line>.\n\n- **Two or three rows**: one per candidate, nothing you did not weigh.\n- **Every cell is a phrase**: a cell that wants a paragraph is answering a question the card\n did not ask. Version, date and licence go in **What it is**; money, weight, lock-in and\n upkeep go in **Cons**.\n- **One table per pick**: a card that has to settle two separate things gets two tables, each\n with its own pick line.\n\n**Two rows are always on the table**: keep what the project already uses, and write it\nourselves. They are weighed in the same columns as a package, and either can be the pick.\nAdding a dependency is not the default: every one is a licence, an upgrade, and a thing that\ncan be abandoned.\n\n## What to leave out\n\nEverything that is not the table and the pick line. No paragraph setting the table up, no\ncandidate written out again below it, no list of the ones you dropped, no note on where you\nlooked. Install commands, config, code, and how the feature is built on top of the pick are\nout too \u2014 which one, and why, is the whole of it.\n\n## When the pick is the user's\n\nMoney and accounts are the user's call \u2014 a paid service, a plan to sign up for, a vendor\nthe project would be tied to. Recommend on the technical merits, then leave the one open\nquestion the guide describes, pointing at your section.\n";
89956
+ var AGENT_default22 = "---\nname: tech-stack-advisor\ndescription: Compares the outside libraries, tools or services a card could pick.\nakb:\n when: A card makes a new pick of an outside library, tool or service.\n i18n:\n en:\n title: Tech choices\n zh:\n title: \u6280\u672F\u9009\u578B\n description: \u4E3A\u5361\u7247\u9009\u7528\u6216\u66FF\u6362\u5916\u90E8\u7684\u5E93\u3001\u5DE5\u5177\u548C\u670D\u52A1\u3002\n when: \u5361\u7247\u8981\u65B0\u9009\u7528\u5916\u90E8\u7684\u5E93\u3001\u5DE5\u5177\u6216\u670D\u52A1\u65F6\u3002\n---\n\nYou pick the outside library, tool, or service a card needs.\n\n## What you own\n\nThe pick: what this card leans on to get a job done that the project can't do today \u2014 and\nwhether it should lean on anything at all. Nothing else on the card is yours.\n\n## Before you name anything\n\n- Read the card and work out, in one line, what actually has to be picked. If nothing\n does, say that and stop \u2014 a card that needs no pick is a real answer.\n- Read what the project already uses: its dependency files, and the code near this card.\n Something already installed beats a better thing that isn't.\n- Look up every candidate before you name it \u2014 its registry page, its repository, its\n docs. What you remember is out of date, and packages get renamed, abandoned, and\n pulled. Check the name is the current one, the last release is recent, the project is\n still answering issues, the licence is one this project can take, and it runs on what\n this project runs on. Drop the ones that fail, and never name one you could not check.\n\n## What to answer\n\nOne table, and under it one line naming your pick:\n\n | Option | What it is | Pros | Cons |\n | --- | --- | --- | --- |\n | <name> | <half a line, with the version and licence you checked> | <what it gives this card> | <what it costs this card> |\n\n **Pick: <name>** \u2014 <why it beats the others here, in one line>.\n\n- **Two or three rows**: one per candidate, nothing you did not weigh.\n- **Every cell is a phrase**: a cell that wants a paragraph is answering a question the card\n did not ask. Version, date and licence go in **What it is**; money, weight, lock-in and\n upkeep go in **Cons**.\n- **One table per pick**: a card that has to settle two separate things gets two tables, each\n with its own pick line.\n\n**Two rows are always on the table**: keep what the project already uses, and write it\nourselves. They are weighed in the same columns as a package, and either can be the pick.\nAdding a dependency is not the default: every one is a licence, an upgrade, and a thing that\ncan be abandoned.\n\n## What to leave out\n\nEverything that is not the table and the pick line. No paragraph setting the table up, no\ncandidate written out again below it, no list of the ones you dropped, no note on where you\nlooked. Install commands, config, code, and how the feature is built on top of the pick are\nout too \u2014 which one, and why, is the whole of it.\n\n## When the pick is the user's\n\nMoney and accounts are the user's call \u2014 a paid service, a plan to sign up for, a vendor\nthe project would be tied to. Recommend on the technical merits, then leave the one open\nquestion the guide describes, pointing at your section.\n";
89929
89957
 
89930
89958
  // ../cli/src/agents/video-cloner/AGENT.md
89931
- var AGENT_default23 = "---\nname: video-cloner\ndescription: Breaks a video made with code down beat by beat and drafts its clone with the user's content.\nakb:\n memoryFiles:\n workspace: [motions/, props/, motions.md, props.md, feedback.md]\n session: new\n i18n:\n en:\n title: Video cloner\n zh:\n title: \u89C6\u9891\u514B\u9686\n description: \u9010\u955C\u62C6\u89E3\u7528\u4EE3\u7801\u5236\u4F5C\u7684\u89C6\u9891\uFF0C\u5E76\u7528\u4F60\u7684\u5185\u5BB9\u5199\u51FA\u590D\u523B\u5206\u955C\u3002\n---\n\nYou break down a video made with code and draft its clone, which tells the user's content with the source's craft. Once the user approves the drafts, a template is built from them, so they must hold every beat it needs.\n\n## Terms\n\n- **Craft**: how the source is made, reproduced in the template code \u2014 beat cuts and lengths, camera moves, motion and easing, layout, transitions, type scale, the role each colour plays, where sounds land, and how product UI is shown \u2014 redrawn or captured, cropped to which module, placed where and how it moves.\n- **Content**: what the source says and whose it is, replaced by the user's \u2014 copy, data, product screens, footage, brand names, logos, illustrations, music, voice, typefaces and brand colours. When unsure, content is whatever must change if the same craft told another story.\n- **Props**: generic system UI that is neither, such as windows, browser chrome and file pickers.\n\n## Deciding\n\n- **Evidence first**: read the video itself \u2014 cut points, sampled frames, audio beats \u2014 rather than guessing from a few stills.\n- **Default with a reason**: pick every technical choice yourself and say why; ask only for what the user owns.\n- **Free only**: besides `akb cloud`, use only tools and libraries free for commercial use; never one that needs a paid plan or a company license.\n- **Never ship the source's content**: stand in for content the user has not supplied with labelled placeholders; draw props faithfully.\n- **Craft first**: match beats, timing, motion, element alignment and cursor landing points; pixel-exact output is not the goal.\n- **Rebuild, don't paste**: when the source draws its UI, redraw the few modules of the user's product a beat needs, centred, so every frame stays clean; a screenshot is only a reference. A beat that moves in the source never becomes a still.\n\n## Files\n\nFiles live in `<board-state>/assets/<card id>/`, linked from the card as `.assets/<card id>/...`; the template goes elsewhere only when the card names a folder for it. When the card names a video outside that folder, copy it in first; with no video, or none of the user's content to fill it, ask for it.\n\n## Steps\n\n- **Drafts**: write two storyboards in the files folder, following `akb raw agent-file scriptwriter references/storyboard-contract.md` and passing that agent's validator: `breakdown.json` takes the source apart, one shot per beat with its source frame, and in details its motion, props, content slot, transition and sound, marking the skeleton beats the video cannot lose; `clone.json` tells the user's content beat by beat, so its story holds on its own. Show both on the card as one `<Compare>`: the source video as `a`, `clone.json` as `b` and `breakdown.json` as `shots`.\n- **Music**: in the drafts, also follow `akb raw agent-file video-cloner references/music.md`.\n- **Changes**: a change to a beat updates that beat in both drafts.\n\n## Memory\n\nYour memory folder is `docs/kanban/memory/agents/video-cloner/`. Read it before the drafts; the current card wins.\n\n- **Motion library**: `motions/<slug>/` holds one effect that a finished template reproduced well \u2014 its source code and a `motion.md` with one line on the style it matches and one keyframe. Add one after the check only when it is reusable beyond this video.\n- **Prop library**: `props/<slug>/` holds one high-fidelity system UI piece, such as a file-picker selection box, a browser window or a window frame \u2014 its source code and a `prop.md` with one line on what it draws and one keyframe. Add one after the check.\n- **Self-contained**: a motion or prop folder carries every style and helper it uses, so it runs with only the template engine and the content file.\n- **Match first**: before writing a motion or drawing a prop, run `akb cloud template list-tags --category motion` or `--category prop`, search within the best tag, then check your own library; use your library alone when signed out or offline. Use a candidate when its style and timing match the source; build one when nothing does.\n- **Motion fit**: a motion that differs only in what the beat passes in, the theme or the beat's length is the same motion; one that differs in a value written into its code, such as a step's duration, easing or distance, gains a parameter defaulting to the old value; one that differs in its steps or what moves is a new motion.\n- **Cache**: `akb cloud template get` a catalog match into a new empty folder, make it that `<slug>/` folder in your library, replacing a local one of the same name, and update the index.\n- **Index**: `motions.md` and `props.md` list each entry as `- [<slug>](<folder>/<slug>/<file>.md) \u2014 <one line>`.\n- **Corrections**: `feedback.md` holds user corrections that change your next recipe, following \"What earns a note\" in `akb guide board`; `product.md` holds those about this product's real screens and flows.\n- **Size**: keep one entry under 1MB; leave out renders, dependencies and source videos.\n";
89959
+ var AGENT_default23 = "---\nname: video-cloner\ndescription: Breaks a video made with code down beat by beat and drafts its clone with the user's content.\nakb:\n memoryFiles:\n workspace: [motions/, props/, motions.md, props.md, feedback.md]\n session: new\n i18n:\n en:\n title: Clone storyboard\n zh:\n title: \u590D\u523B\u5206\u955C\n description: \u9010\u955C\u62C6\u89E3\u7528\u4EE3\u7801\u5236\u4F5C\u7684\u89C6\u9891\uFF0C\u5E76\u7528\u4F60\u7684\u5185\u5BB9\u5199\u51FA\u590D\u523B\u5206\u955C\u3002\n---\n\nYou break down a video made with code and draft its clone, which tells the user's content with the source's craft. Once the user approves the drafts, a template is built from them, so they must hold every beat it needs.\n\n## Terms\n\n- **Craft**: how the source is made, reproduced in the template code \u2014 beat cuts and lengths, camera moves, motion and easing, layout, transitions, type scale, the role each colour plays, where sounds land, and how product UI is shown \u2014 redrawn or captured, cropped to which module, placed where and how it moves.\n- **Content**: what the source says and whose it is, replaced by the user's \u2014 copy, data, product screens, footage, brand names, logos, illustrations, music, voice, typefaces and brand colours. When unsure, content is whatever must change if the same craft told another story.\n- **Props**: generic system UI that is neither, such as windows, browser chrome and file pickers.\n\n## Deciding\n\n- **Evidence first**: read the video itself \u2014 cut points, sampled frames, audio beats \u2014 rather than guessing from a few stills.\n- **Default with a reason**: pick every technical choice yourself and say why; ask only for what the user owns.\n- **Free only**: besides `akb cloud`, use only tools and libraries free for commercial use; never one that needs a paid plan or a company license.\n- **Never ship the source's content**: stand in for content the user has not supplied with labelled placeholders; draw props faithfully.\n- **Craft first**: match beats, timing, motion, element alignment and cursor landing points; pixel-exact output is not the goal.\n- **Rebuild, don't paste**: when the source draws its UI, redraw the few modules of the user's product a beat needs, centred, so every frame stays clean; a screenshot is only a reference. A beat that moves in the source never becomes a still.\n\n## Files\n\nFiles live in `<board-state>/assets/<card id>/`, linked from the card as `.assets/<card id>/...`; the template goes elsewhere only when the card names a folder for it. When the card names a video outside that folder, copy it in first; with no video, or none of the user's content to fill it, ask for it.\n\n## Steps\n\n- **Drafts**: write two storyboards in the files folder, following `akb raw agent-file scriptwriter references/storyboard-contract.md` and passing that agent's validator: `breakdown.json` takes the source apart, one shot per beat with its source frame, and in details its motion, props, content slot, transition and sound, marking the skeleton beats the video cannot lose; `clone.json` tells the user's content beat by beat, so its story holds on its own. Show both on the card as one `<Compare>`: the source video as `a`, `clone.json` as `b` and `breakdown.json` as `shots`.\n- **Music**: in the drafts, also follow `akb raw agent-file video-cloner references/music.md`.\n- **Changes**: a change to a beat updates that beat in both drafts.\n\n## Memory\n\nYour memory folder is `docs/kanban/memory/agents/video-cloner/`. Read it before the drafts; the current card wins.\n\n- **Motion library**: `motions/<slug>/` holds one effect that a finished template reproduced well \u2014 its source code and a `motion.md` with one line on the style it matches and one keyframe. Add one after the check only when it is reusable beyond this video.\n- **Prop library**: `props/<slug>/` holds one high-fidelity system UI piece, such as a file-picker selection box, a browser window or a window frame \u2014 its source code and a `prop.md` with one line on what it draws and one keyframe. Add one after the check.\n- **Self-contained**: a motion or prop folder carries every style and helper it uses, so it runs with only the template engine and the content file.\n- **Match first**: before writing a motion or drawing a prop, run `akb cloud template list-tags --category motion` or `--category prop`, search within the best tag, then check your own library; use your library alone when signed out or offline. Use a candidate when its style and timing match the source; build one when nothing does.\n- **Motion fit**: a motion that differs only in what the beat passes in, the theme or the beat's length is the same motion; one that differs in a value written into its code, such as a step's duration, easing or distance, gains a parameter defaulting to the old value; one that differs in its steps or what moves is a new motion.\n- **Cache**: `akb cloud template get` a catalog match into a new empty folder, make it that `<slug>/` folder in your library, replacing a local one of the same name, and update the index.\n- **Index**: `motions.md` and `props.md` list each entry as `- [<slug>](<folder>/<slug>/<file>.md) \u2014 <one line>`.\n- **Corrections**: `feedback.md` holds user corrections that change your next recipe, following \"What earns a note\" in `akb guide board`; `product.md` holds those about this product's real screens and flows.\n- **Size**: keep one entry under 1MB; leave out renders, dependencies and source videos.\n";
89932
89960
 
89933
89961
  // ../cli/src/agents/video-cloner/references/music.md
89934
89962
  var music_default = "# Music\n\nScore the clone with new music that follows the source's rhythm, never its melody.\n\n## Drafts\n\n- **Analyse**: extract the source's audio with ffmpeg and take its BPM, downbeats, onsets and energy curve with librosa.\n- **Cue sheet**: write `cues.json` in the files folder, one entry per beat id: where a section rises or falls, where accents land, and each sound effect's time and kind, plus one line on the score's mood and instrumentation as the video suggests them.\n\n## Template\n\n- **Generate**: create the default score with `akb cloud music --seconds <n> --out <file> \"<prompt>\"`, where `<n>` is the beat table's total length, which spends the user's Pro credits per track. The prompt gives the tempo, mood, instrumentation, instrumental only, and each section's time range from the cue sheet; never the source's title, artist, lyrics or audio.\n- **Align**: trim or time-stretch the track to that length so its accents land on the cue times and it ends with the last beat, and put it in the content file's music slot for the user to replace.\n- **Refused**: when Cloud refuses, leave the music slot empty and say so on the card.\n- **Clicks**: give every click in the beat table a short click sound synthesised in code.\n\n## Check\n\n- **Compare**: compare the clone's onsets and energy curve with the source's beat by beat; realign a beat whose accents miss, and regenerate only when the track's structure misses, at most three times per run.\n";
89935
89963
 
89936
89964
  // ../cli/src/agents/video-template-builder/AGENT.md
89937
- var AGENT_default24 = "---\nname: video-template-builder\ndescription: Builds a video clone's reusable beat-table template from its approved drafts, renders it once and checks it against the source beat by beat.\nakb:\n after: [video-cloner]\n session: new\n i18n:\n en:\n title: Video template builder\n zh:\n title: \u89C6\u9891\u6A21\u677F\u5236\u4F5C\n description: \u6309\u786E\u8BA4\u7684\u590D\u523B\u5206\u955C\u505A\u6210\u4FDD\u7559\u62CD\u6CD5\u3001\u53EF\u6362\u5185\u5BB9\u7684 beat \u8868\u6A21\u677F\uFF0C\u6E32\u67D3\u4E00\u652F\u5E76\u4E0E\u539F\u7247\u9010\u955C\u5BF9\u6BD4\u3002\n---\n\nBuild the template the approved drafts in ``## By `video-cloner` agent`` describe: it reproduces the source's craft and renders the user's content in place of the source's. You are done, with no further question, when the clone's comparison with the source and the render command are recorded on the card.\n\nFollow Terms, Deciding, Files and Memory in `akb raw agent-file video-cloner AGENT.md`; its memory folder is yours.\n\n## Steps\n\n- **Recipe**: write the format (size, frame rate, length, fonts, colours) to `recipe.md` in the files folder; it is your working file, never shown on the card.\n- **Template**: build a project that renders `clone.json` beat by beat, picking for each motion an animation library that fits its style; one project may combine several. The beat table and all content live in one file, holding the user's content from the start, so a beat can be removed or reordered and the content swapped without code changes; the code holds only craft and props. Its `template.md` states that the content in that file is to be replaced with the user's own and that the template reproduces only the source's craft.\n- **Cached clips**: render each beat to its own cached clip and splice the clips into the full video; a change re-renders only the clips it touches.\n- **Check**: render it once and compare it with the source beat by beat side by side on rhythm, motion and layout, and check every on-screen step makes sense to a viewer. A beat that misses the source's structure means the template is wrong: fix it and render again, never hand over the breakdown instead.\n- **Music**: in the template and check, also follow `akb raw agent-file video-cloner references/music.md`.\n- **Card**: under your section heading, show only the clone against the source as a `<Compare>` with `breakdown.json` as `shots`, and each difference left in one line, naming its beat id; append a ticked todo with the template folder's absolute path and, in backticks, its render command.\n- **Changes**: a change to a beat updates only that beat in the template.\n";
89965
+ var AGENT_default24 = "---\nname: video-template-builder\ndescription: Builds a video clone's reusable beat-table template from its approved drafts, renders it once and checks it against the source beat by beat.\nakb:\n after: [video-cloner]\n session: new\n i18n:\n en:\n title: Video template\n zh:\n title: \u89C6\u9891\u6A21\u677F\n description: \u6309\u786E\u8BA4\u7684\u590D\u523B\u5206\u955C\u505A\u6210\u4FDD\u7559\u62CD\u6CD5\u3001\u53EF\u6362\u5185\u5BB9\u7684 beat \u8868\u6A21\u677F\uFF0C\u6E32\u67D3\u4E00\u652F\u5E76\u4E0E\u539F\u7247\u9010\u955C\u5BF9\u6BD4\u3002\n---\n\nBuild the template the approved drafts in ``## By `video-cloner` agent`` describe: it reproduces the source's craft and renders the user's content in place of the source's. You are done, with no further question, when the clone's comparison with the source and the render command are recorded on the card.\n\nFollow Terms, Deciding, Files and Memory in `akb raw agent-file video-cloner AGENT.md`; its memory folder is yours.\n\n## Steps\n\n- **Recipe**: write the format (size, frame rate, length, fonts, colours) to `recipe.md` in the files folder; it is your working file, never shown on the card.\n- **Template**: build a project that renders `clone.json` beat by beat, picking for each motion an animation library that fits its style; one project may combine several. The beat table and all content live in one file, holding the user's content from the start, so a beat can be removed or reordered and the content swapped without code changes; the code holds only craft and props. Its `template.md` states that the content in that file is to be replaced with the user's own and that the template reproduces only the source's craft.\n- **Cached clips**: render each beat to its own cached clip and splice the clips into the full video; a change re-renders only the clips it touches.\n- **Check**: render it once and compare it with the source beat by beat side by side on rhythm, motion and layout, and check every on-screen step makes sense to a viewer. A beat that misses the source's structure means the template is wrong: fix it and render again, never hand over the breakdown instead.\n- **Music**: in the template and check, also follow `akb raw agent-file video-cloner references/music.md`.\n- **Card**: under your section heading, show only the clone against the source as a `<Compare>` with `breakdown.json` as `shots`, and each difference left in one line, naming its beat id; append a ticked todo with the template folder's absolute path and, in backticks, its render command.\n- **Changes**: a change to a beat updates only that beat in the template.\n";
89938
89966
 
89939
89967
  // ../cli/src/agents/workflow-writer/AGENT.md
89940
- var AGENT_default25 = "---\nname: workflow-writer\ndescription: Writes a new workflow, or changes one of the user's own, as a `WORKFLOW.md` and the agents it names.\nakb:\n i18n:\n en:\n title: Workflow writer\n zh:\n title: \u642D\u5EFA\u5DE5\u4F5C\u6D41\n description: \u6309\u4F60\u7684\u63CF\u8FF0\u5199\u51FA\u4E00\u4E2A\u5DE5\u4F5C\u6D41\u53CA\u5176 agent\uFF0C\u6216\u4FEE\u6539\u4F60\u5DF2\u6709\u7684\u5DE5\u4F5C\u6D41\u3002\n---\n\nYou write a workflow from the user's request: a kind of work the user runs again and again, where each task shows a person previews to approve before the work goes on.\n\n## Read first\n\n- **The project**: when the board belongs to a project folder, read its README and agent instruction files (such as `AGENTS.md` or `CLAUDE.md`) for what it makes, and its existing outputs of this kind for their format and destination.\n- **This board**: run `akb workflow list` and read `docs/kanban/agents/`, so a new workflow does not repeat one the board already has.\n\n## What to write\n\n- **The workflow**: when the card names a workflow folder, the workflow is that folder: keep its id and change it in place. Otherwise create it with `akb workflow new`. Name it with `akb workflow rename`, and list its agents in its `WORKFLOW.md`: `previews` the agents whose drafts a person approves, `land` the agents that run unattended in order after the last approval, and `scheduled`. Its body is how a card of this kind is written.\n- **Its agents**: write each agent it names as `akb guide write-agent` says.\n- **Approvals**: default to previews a person approves once. Give an agent `after` only when its preview is too costly to make before another is approved, such as a video before its script; it then waits for that approval.\n- **Previews**: give each part a person must see its own agent, such as the screens of a UI change or the script of a video. Show only what the person decides on, and keep previews from overlapping: a UI preview already shows its text, so add no separate copy preview.\n- **Land**: add agents to `land` only for work that needs no review, such as building and merging an approved change; leave it empty when the last approved preview is the deliverable.\n- **Memory**: for each agent, decide whether a user's correction should change its next output, such as a writer's tone or a designer's look; if so, declare its memory as `akb guide write-agent` says, otherwise give it none.\n- **Changing a workflow**: edit its `WORKFLOW.md` and its agents under `docs/kanban/agents/` in place, and keep what the request does not ask to change.\n\n## Check it\n\nRun `akb spec` and `akb workflow list`, and fix every problem reported for this workflow or its agents before finishing.\n\n## Card\n\nUnder your section heading, say in a few lines, for a reader who has never seen a workflow file, what the workflow is for, what each approval shows, what runs after the last one, and what each agent remembers; then embed each file you wrote as an `<Asset>`.\n";
89968
+ var AGENT_default25 = "---\nname: workflow-writer\ndescription: Writes a new workflow, or changes one of the user's own, as a `WORKFLOW.md` and the agents it names.\nakb:\n i18n:\n en:\n title: Workflow\n zh:\n title: \u5DE5\u4F5C\u6D41\n description: \u6309\u4F60\u7684\u63CF\u8FF0\u5199\u51FA\u4E00\u4E2A\u5DE5\u4F5C\u6D41\u53CA\u5176 agent\uFF0C\u6216\u4FEE\u6539\u4F60\u5DF2\u6709\u7684\u5DE5\u4F5C\u6D41\u3002\n---\n\nYou write a workflow from the user's request: a kind of work the user runs again and again, where each task shows a person previews to approve before the work goes on.\n\n## Read first\n\n- **The project**: when the board belongs to a project folder, read its README and agent instruction files (such as `AGENTS.md` or `CLAUDE.md`) for what it makes, and its existing outputs of this kind for their format and destination.\n- **This board**: run `akb workflow list` and read `docs/kanban/agents/`, so a new workflow does not repeat one the board already has.\n\n## What to write\n\n- **The workflow**: when the card names a workflow folder, the workflow is that folder: keep its id and change it in place. Otherwise create it with `akb workflow new`. Name it with `akb workflow rename`, and list its agents in its `WORKFLOW.md`: `previews` the agents whose drafts a person approves, `land` the agents that run unattended in order after the last approval, and `scheduled`. Its body is how a card of this kind is written.\n- **Its agents**: write each agent it names as `akb guide write-agent` says.\n- **Approvals**: default to previews a person approves once. Give an agent `after` only when its preview is too costly to make before another is approved, such as a video before its script; it then waits for that approval.\n- **Previews**: give each part a person must see its own agent, such as the screens of a UI change or the script of a video. Show only what the person decides on, and keep previews from overlapping: a UI preview already shows its text, so add no separate copy preview.\n- **Land**: add agents to `land` only for work that needs no review, such as building and merging an approved change; leave it empty when the last approved preview is the deliverable.\n- **Memory**: for each agent, decide whether a user's correction should change its next output, such as a writer's tone or a designer's look; if so, declare its memory as `akb guide write-agent` says, otherwise give it none.\n- **Changing a workflow**: edit its `WORKFLOW.md` and its agents under `docs/kanban/agents/` in place, and keep what the request does not ask to change.\n\n## Check it\n\nRun `akb spec` and `akb workflow list`, and fix every problem reported for this workflow or its agents before finishing.\n\n## Card\n\nUnder your section heading, say in a few lines, for a reader who has never seen a workflow file, what the workflow is for, what each approval shows, what runs after the last one, and what each agent remembers; then embed each file you wrote as an `<Asset>`.\n";
89941
89969
 
89942
89970
  // ../cli/src/lib/agents/bundled.ts
89943
89971
  var BUNDLED_AGENT_FILES = {
@@ -90196,7 +90224,7 @@ var names = (value) => [...new Set((Array.isArray(value) ? value : [value]).map(
90196
90224
  var str3 = (value) => typeof value === "string" ? value.trim() : "";
90197
90225
  var map = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
90198
90226
 
90199
- // src/memory-files.ts
90227
+ // ../cli/src/lib/agents/shared-memory.ts
90200
90228
  function sharedMemory(board) {
90201
90229
  const declared = /* @__PURE__ */ new Map();
90202
90230
  const take = (folder, text3, builtIn) => {
@@ -90231,156 +90259,6 @@ function matcher(entry) {
90231
90259
  return (name) => re3.test(name);
90232
90260
  }
90233
90261
 
90234
- // src/triage.ts
90235
- import fs17 from "node:fs";
90236
- import path19 from "node:path";
90237
-
90238
- // ../cli/src/lib/signals/identity.ts
90239
- import { createHash } from "node:crypto";
90240
- var DERIVED = "derived-";
90241
- var derivedSourceId = (seed) => `${DERIVED}${createHash("sha256").update(seed).digest("hex").slice(0, 16)}`;
90242
-
90243
- // src/triage.ts
90244
- var ok = (value) => ({ ok: true, value });
90245
- var triageDir = (board) => path19.join(board, "triage");
90246
- var rejectedDir = (board) => path19.join(board, ".archive", ".sync");
90247
- var SCRATCH = ["dismissed", "archived"];
90248
- var stamp = (at2) => formatStamp(at2 ? new Date(at2) : /* @__PURE__ */ new Date());
90249
- function slugOf(title) {
90250
- return title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 56).replace(/-+$/, "") || "item";
90251
- }
90252
- function freeName(dir, title) {
90253
- const stem = slugOf(title);
90254
- let name = `${stem}.md`;
90255
- for (let n = 2; fs17.existsSync(path19.join(dir, name)); n++) name = `${stem}-${n}.md`;
90256
- return name;
90257
- }
90258
- function itemText(item, fields = {}) {
90259
- const lines = [
90260
- "---",
90261
- `source_id: ${yamlScalar(derivedSourceId(`${item.title}
90262
- ${item.text.trim()}`))}`,
90263
- `title: ${yamlScalar(item.title)}`,
90264
- `collected_at: ${yamlScalar(stamp(item.created_at))}`,
90265
- `imported_at: ${yamlScalar(stamp(item.created_at))}`,
90266
- ...Object.entries(fields).map(([k, v2]) => `${k}: ${yamlScalar(v2)}`),
90267
- "---"
90268
- ];
90269
- return `${lines.join("\n")}
90270
-
90271
- ${item.text.trim()}
90272
- `;
90273
- }
90274
- function writeItem(dir, item, fields = {}) {
90275
- fs17.mkdirSync(dir, { recursive: true });
90276
- const name = freeName(dir, item.title);
90277
- fs17.writeFileSync(path19.join(dir, name), itemText(item, item.workflow ? { workflow: workflowName(item.workflow), ...fields } : fields));
90278
- return name;
90279
- }
90280
- function readItem(file2) {
90281
- const lines = fs17.readFileSync(file2, "utf8").split("\n");
90282
- if (lines[0]?.trim() !== "---") return null;
90283
- const close = lines.indexOf("---", 1);
90284
- if (close < 0) return null;
90285
- const field = (key) => {
90286
- const said = lines.slice(1, close).map((l2) => new RegExp(`^${key}:\\s*(.*)$`).exec(l2)?.[1]).find((t2) => t2 !== void 0);
90287
- return said === void 0 ? "" : unquote(said).trim();
90288
- };
90289
- const title = field("title");
90290
- const text3 = lines.slice(close + 1).join("\n").trim();
90291
- return title ? { title: title.slice(0, 200), text: text3.slice(0, 6e4), workflow: field("workflow") } : null;
90292
- }
90293
- async function cloudWorkflowOf(local, job, own) {
90294
- if (!local) return ok(job ?? "");
90295
- if (job && workflowName(job) === local) return ok(job);
90296
- if (!local.startsWith("wf-")) return ok(`wf_builtin_${local.replace(/-/g, "_")}`);
90297
- const ids = await own();
90298
- if (!ids.ok) return ids;
90299
- return ok(ids.value.find((id) => workflowFolder(id) === local) ?? local);
90300
- }
90301
- var itemFiles = (dir) => {
90302
- try {
90303
- return fs17.readdirSync(dir, { withFileTypes: true }).filter((e2) => e2.isFile() && e2.name.endsWith(".md")).map((e2) => e2.name);
90304
- } catch {
90305
- return [];
90306
- }
90307
- };
90308
- async function all(read) {
90309
- const out = [];
90310
- let after = null;
90311
- do {
90312
- const page = await read(after);
90313
- if (!page.ok) return page;
90314
- out.push(...page.value.data);
90315
- after = page.value.next;
90316
- } while (after);
90317
- return ok(out);
90318
- }
90319
- async function pullTriage(board, project) {
90320
- const open = await all((after) => listTriage(project, "open", after));
90321
- if (!open.ok) return open;
90322
- const dir = triageDir(board);
90323
- for (const name of itemFiles(dir)) fs17.rmSync(path19.join(dir, name), { force: true });
90324
- for (const sub of SCRATCH) fs17.rmSync(path19.join(dir, sub), { recursive: true, force: true });
90325
- const known = {};
90326
- for (const item of open.value) known[writeItem(dir, item)] = item.id;
90327
- return ok(known);
90328
- }
90329
- async function pushTriage(board, project, task, known, workflow = null) {
90330
- const dir = triageDir(board);
90331
- const out = { ...known };
90332
- let own = null;
90333
- const ownIds = async () => {
90334
- if (own) return own;
90335
- const held3 = await readProject(project);
90336
- if (!held3.ok) return held3;
90337
- const listed2 = await all((after) => listWorkflows(held3.value.workspace ?? "", after));
90338
- own = listed2.ok ? ok(listed2.value.map((w2) => w2.id)) : listed2;
90339
- return own;
90340
- };
90341
- for (const name of itemFiles(dir)) {
90342
- if (out[name]) continue;
90343
- const item = readItem(path19.join(dir, name));
90344
- if (!item) continue;
90345
- const flow = await cloudWorkflowOf(item.workflow, workflow, ownIds);
90346
- if (!flow.ok) return flow;
90347
- const made = await createTriage(project, item.title, item.text, task, flow.value);
90348
- if (!made.ok && made.code === "bad_request") continue;
90349
- if (!made.ok) return made;
90350
- out[name] = made.value.id;
90351
- }
90352
- return ok(out);
90353
- }
90354
- function layOut(board, rejections) {
90355
- const dir = rejectedDir(board);
90356
- fs17.mkdirSync(dir, { recursive: true });
90357
- for (const t2 of rejections.tasks) {
90358
- fs17.writeFileSync(path19.join(dir, `${t2.number}-${slugify(t2.title)}.md`), [
90359
- "---",
90360
- `title: ${yamlScalar(t2.title)}`,
90361
- "status: todo",
90362
- "rejected: true",
90363
- `rejected_reason: ${yamlScalar(t2.reason)}`,
90364
- `rejected_at: ${yamlScalar(stamp(t2.cancelled_at))}`,
90365
- "rejected_by: user",
90366
- "---",
90367
- "",
90368
- t2.request.trim(),
90369
- ""
90370
- ].join("\n"));
90371
- }
90372
- for (const item of rejections.triage) {
90373
- const sub = path19.join(triageDir(board), item.state === "dismissed" ? "dismissed" : "archived");
90374
- const fields = item.state === "dismissed" ? { dismissed_at: stamp(item.dismissed_at), dismissed_by: "user", ...item.dismissed_reason ? { dismissed_reason: item.dismissed_reason } : {} } : {};
90375
- writeItem(sub, item, fields);
90376
- }
90377
- return { tasks: rejections.tasks.map((t2) => t2.id), triage: rejections.triage.map((i) => i.id) };
90378
- }
90379
- function clearLaid(board) {
90380
- fs17.rmSync(rejectedDir(board), { recursive: true, force: true });
90381
- for (const sub of SCRATCH) fs17.rmSync(path19.join(triageDir(board), sub), { recursive: true, force: true });
90382
- }
90383
-
90384
90262
  // src/task-folder.ts
90385
90263
  var TASK_ID = /^[\w-]{1,100}$/;
90386
90264
  var EMPTY = { assets: {} };
@@ -90391,16 +90269,16 @@ function openTaskFolder(job, projectDir2) {
90391
90269
  projectDir2 ??= openCached(job.project);
90392
90270
  keepOutOfGit(projectDir2);
90393
90271
  markUsed(projectDir2);
90394
- const board = path21.join(projectDir2, ".akb", "kanban");
90395
- fs19.mkdirSync(board, { recursive: true });
90272
+ const board = path20.join(projectDir2, ".akb", "kanban");
90273
+ fs18.mkdirSync(board, { recursive: true });
90396
90274
  return { task, cloudTask: task, board, cwd: projectDir2, project: job.project, number: job.number ?? null, workflow: job.workflow ?? job.flow?.workflow ?? null };
90397
90275
  }
90398
90276
  function openAgentFolder(job, projectDir2) {
90399
90277
  if (!job.project || !job.agent) throw new Error("This job names no project.");
90400
90278
  keepOutOfGit(projectDir2);
90401
90279
  markUsed(projectDir2);
90402
- const board = path21.join(projectDir2, ".akb", "kanban");
90403
- fs19.mkdirSync(board, { recursive: true });
90280
+ const board = path20.join(projectDir2, ".akb", "kanban");
90281
+ fs18.mkdirSync(board, { recursive: true });
90404
90282
  return {
90405
90283
  task: `agent-${safe(job.agent.workflow ? `${job.agent.workflow}-${job.agent.name}` : job.agent.name)}`,
90406
90284
  cloudTask: job.agent.tasks?.[0]?.id ?? null,
@@ -90415,15 +90293,15 @@ function openDiscussionFolder(job, projectDir2) {
90415
90293
  if (!job.project) throw new Error("This job names no project.");
90416
90294
  keepOutOfGit(projectDir2);
90417
90295
  markUsed(projectDir2);
90418
- const board = path21.join(projectDir2, ".akb", "kanban");
90419
- fs19.mkdirSync(board, { recursive: true });
90296
+ const board = path20.join(projectDir2, ".akb", "kanban");
90297
+ fs18.mkdirSync(board, { recursive: true });
90420
90298
  return { task: "discussion", cloudTask: null, board, cwd: projectDir2, project: job.project, number: null, workflow: null };
90421
90299
  }
90422
90300
  var safe = (name) => name.replace(/[^\w.-]/g, "_") || "default";
90423
90301
  function openCached(project) {
90424
90302
  const dir = cacheDir(project);
90425
- if (fs19.existsSync(path21.join(dir, ".git"))) return dir;
90426
- fs19.mkdirSync(dir, { recursive: true });
90303
+ if (fs18.existsSync(path20.join(dir, ".git"))) return dir;
90304
+ fs18.mkdirSync(dir, { recursive: true });
90427
90305
  const git3 = (...args) => spawnSync3("git", ["-C", dir, ...args], { encoding: "utf8" }).status === 0;
90428
90306
  if (git3("init", "-q")) git3("-c", "user.name=WildCrane", "-c", "user.email=runner@wildcrane.ai", "commit", "-q", "--allow-empty", "-m", "general");
90429
90307
  return dir;
@@ -90436,56 +90314,56 @@ function keepOutOfGit(dir, folders2 = SKILL_FOLDERS) {
90436
90314
  if (inside.status !== 0) return;
90437
90315
  const missing = [".akb/", ...folders2.map((f2) => `${f2}/`)].filter((p2) => git3("check-ignore", "-q", p2).status !== 0);
90438
90316
  if (!missing.length) return;
90439
- const exclude = path21.resolve(dir, inside.stdout.trim());
90440
- fs19.mkdirSync(path21.dirname(exclude), { recursive: true });
90441
- const held3 = fs19.existsSync(exclude) ? fs19.readFileSync(exclude, "utf8") : "";
90442
- fs19.writeFileSync(exclude, `${held3}${held3 && !held3.endsWith("\n") ? "\n" : ""}${missing.join("\n")}
90317
+ const exclude = path20.resolve(dir, inside.stdout.trim());
90318
+ fs18.mkdirSync(path20.dirname(exclude), { recursive: true });
90319
+ const held3 = fs18.existsSync(exclude) ? fs18.readFileSync(exclude, "utf8") : "";
90320
+ fs18.writeFileSync(exclude, `${held3}${held3 && !held3.endsWith("\n") ? "\n" : ""}${missing.join("\n")}
90443
90321
  `);
90444
90322
  }
90445
- var cardFile = (ws) => (ws.number ? findCard(ws.board, ws.number) : null) ?? path21.join(ws.board, "todo", `${ws.number ?? 0}-task.md`);
90323
+ var cardFile = (ws) => (ws.number ? findCard(ws.board, ws.number) : null) ?? path20.join(ws.board, "todo", `${ws.number ?? 0}-task.md`);
90446
90324
  function findCard(board, number) {
90447
90325
  const named2 = new RegExp(`^${number}-`);
90448
90326
  const walk = (dir) => {
90449
90327
  let entries;
90450
90328
  try {
90451
- entries = fs19.readdirSync(dir, { withFileTypes: true });
90329
+ entries = fs18.readdirSync(dir, { withFileTypes: true });
90452
90330
  } catch {
90453
90331
  return null;
90454
90332
  }
90455
90333
  for (const e2 of entries) {
90456
90334
  if (!named2.test(e2.name)) continue;
90457
- if (e2.isFile() && e2.name.endsWith(".md")) return path21.join(dir, e2.name);
90458
- const root = path21.join(dir, e2.name, "root.md");
90459
- if (e2.isDirectory() && fs19.existsSync(root)) return root;
90335
+ if (e2.isFile() && e2.name.endsWith(".md")) return path20.join(dir, e2.name);
90336
+ const root = path20.join(dir, e2.name, "root.md");
90337
+ if (e2.isDirectory() && fs18.existsSync(root)) return root;
90460
90338
  }
90461
90339
  for (const e2 of entries) if (e2.isDirectory() && !e2.name.startsWith(".")) {
90462
- const hit = walk(path21.join(dir, e2.name));
90340
+ const hit = walk(path20.join(dir, e2.name));
90463
90341
  if (hit) return hit;
90464
90342
  }
90465
90343
  return null;
90466
90344
  };
90467
- return walk(path21.join(board, "todo")) ?? walk(path21.join(board, ".archive"));
90345
+ return walk(path20.join(board, "todo")) ?? walk(path20.join(board, ".archive"));
90468
90346
  }
90469
90347
  function akbCardOf(ws) {
90470
90348
  return ws.number && findCard(ws.board, ws.number) ? ws.number : void 0;
90471
90349
  }
90472
- var recordFile = (ws) => path21.join(ws.board, ".sync", `${ws.task}.json`);
90350
+ var recordFile = (ws) => path20.join(ws.board, ".sync", `${ws.task}.json`);
90473
90351
  function readRecord(ws) {
90474
90352
  try {
90475
- return { ...EMPTY, ...JSON.parse(fs19.readFileSync(recordFile(ws), "utf8")) };
90353
+ return { ...EMPTY, ...JSON.parse(fs18.readFileSync(recordFile(ws), "utf8")) };
90476
90354
  } catch {
90477
90355
  return structuredClone(EMPTY);
90478
90356
  }
90479
90357
  }
90480
90358
  function writeRecord(ws, record) {
90481
- fs19.mkdirSync(path21.dirname(recordFile(ws)), { recursive: true });
90482
- fs19.writeFileSync(recordFile(ws), `${JSON.stringify(record, null, 2)}
90359
+ fs18.mkdirSync(path20.dirname(recordFile(ws)), { recursive: true });
90360
+ fs18.writeFileSync(recordFile(ws), `${JSON.stringify(record, null, 2)}
90483
90361
  `);
90484
90362
  }
90485
- var baseFile = (ws) => path21.join(ws.cwd, ".akb", "base.json");
90363
+ var baseFile = (ws) => path20.join(ws.cwd, ".akb", "base.json");
90486
90364
  function readBase(ws) {
90487
90365
  try {
90488
- const base = JSON.parse(fs19.readFileSync(baseFile(ws), "utf8"));
90366
+ const base = JSON.parse(fs18.readFileSync(baseFile(ws), "utf8"));
90489
90367
  if (base.layout === "workspace") return base;
90490
90368
  } catch {
90491
90369
  }
@@ -90493,25 +90371,25 @@ function readBase(ws) {
90493
90371
  }
90494
90372
  function writeBase(ws, base) {
90495
90373
  const file2 = baseFile(ws);
90496
- fs19.mkdirSync(path21.dirname(file2), { recursive: true });
90497
- fs19.writeFileSync(`${file2}.tmp`, JSON.stringify(base));
90498
- fs19.renameSync(`${file2}.tmp`, file2);
90374
+ fs18.mkdirSync(path20.dirname(file2), { recursive: true });
90375
+ fs18.writeFileSync(`${file2}.tmp`, JSON.stringify(base));
90376
+ fs18.renameSync(`${file2}.tmp`, file2);
90499
90377
  }
90500
90378
  var hashOf = (bytes2) => crypto2.createHash("sha256").update(bytes2).digest("hex");
90501
90379
  function hashFile(file2) {
90502
90380
  try {
90503
- return hashOf(fs19.readFileSync(file2));
90381
+ return hashOf(fs18.readFileSync(file2));
90504
90382
  } catch {
90505
90383
  return null;
90506
90384
  }
90507
90385
  }
90508
90386
  function write(file2, bytes2) {
90509
- fs19.mkdirSync(path21.dirname(file2), { recursive: true });
90510
- fs19.writeFileSync(file2, bytes2);
90387
+ fs18.mkdirSync(path20.dirname(file2), { recursive: true });
90388
+ fs18.writeFileSync(file2, bytes2);
90511
90389
  }
90512
90390
  function readText(file2) {
90513
90391
  try {
90514
- return fs19.readFileSync(file2, "utf8");
90392
+ return fs18.readFileSync(file2, "utf8");
90515
90393
  } catch {
90516
90394
  return null;
90517
90395
  }
@@ -90519,17 +90397,17 @@ function readText(file2) {
90519
90397
  function filesUnder(dir, base = dir) {
90520
90398
  let entries;
90521
90399
  try {
90522
- entries = fs19.readdirSync(dir, { withFileTypes: true });
90400
+ entries = fs18.readdirSync(dir, { withFileTypes: true });
90523
90401
  } catch {
90524
90402
  return [];
90525
90403
  }
90526
90404
  return entries.flatMap((e2) => {
90527
- const full = path21.join(dir, e2.name);
90405
+ const full = path20.join(dir, e2.name);
90528
90406
  if (e2.isDirectory()) return filesUnder(full, base);
90529
- return e2.isFile() ? [path21.relative(base, full).split(path21.sep).join("/")] : [];
90407
+ return e2.isFile() ? [path20.relative(base, full).split(path20.sep).join("/")] : [];
90530
90408
  });
90531
90409
  }
90532
- var kept2 = (p2) => isBoardPath(p2) && !p2.startsWith("triage/");
90410
+ var kept2 = isBoardPath;
90533
90411
  var MEMORY2 = "memory/";
90534
90412
  var rootOf = (ws) => `projects/${ws.project}/`;
90535
90413
  var remoteOf = (ws, shared, p2) => p2.startsWith(MEMORY2) && shared(p2.slice(MEMORY2.length)) ? p2 : rootOf(ws) + p2;
@@ -90542,7 +90420,7 @@ function viewOf(ws, base, shared) {
90542
90420
  }
90543
90421
  function assetFiles(ws, list) {
90544
90422
  const card = cardFile(ws);
90545
- return new Set(Object.keys(assetsOf(list)).map((name) => assetPath(ws, name, card)).filter((f2) => !!f2).map((f2) => path21.relative(ws.board, f2).split(path21.sep).join("/")));
90423
+ return new Set(Object.keys(assetsOf(list)).map((name) => assetPath(ws, name, card)).filter((f2) => !!f2).map((f2) => path20.relative(ws.board, f2).split(path20.sep).join("/")));
90546
90424
  }
90547
90425
  var assetsListOf = (ws, base) => base.files[rootOf(ws) + assetsFile(ws.task)]?.content;
90548
90426
  var localFiles = (ws, base) => {
@@ -90553,7 +90431,7 @@ var SKILL_PATH = /^skills\/([a-z0-9]+(?:-[a-z0-9]+)*)\/((?:[\w.-]+\/)*[\w.-]+)$/
90553
90431
  function pullTools(ws, record, files) {
90554
90432
  const held3 = record.tools?.skills ?? {};
90555
90433
  const ours = new Set(Object.keys(held3).map((name) => name.split("/")[1]));
90556
- const theirs = (skill) => !ours.has(skill) && SKILL_ROOTS.some((root) => fs19.existsSync(path21.join(ws.cwd, root, skill)));
90434
+ const theirs = (skill) => !ours.has(skill) && SKILL_ROOTS.some((root) => fs18.existsSync(path20.join(ws.cwd, root, skill)));
90557
90435
  const kept3 = Object.keys(files).map((name) => SKILL_PATH.exec(name)?.[1]).filter((skill) => skill && !theirs(skill));
90558
90436
  const skills = {};
90559
90437
  for (const [name, text3] of Object.entries(files)) {
@@ -90561,7 +90439,7 @@ function pullTools(ws, record, files) {
90561
90439
  if (!at2 || at2[1] === "kanban" || !kept3.includes(at2[1]) || at2[2].split("/").includes("..")) continue;
90562
90440
  skills[name] = hashOf(text3);
90563
90441
  for (const root of SKILL_ROOTS) {
90564
- const file2 = path21.join(ws.cwd, root, at2[1], at2[2]);
90442
+ const file2 = path20.join(ws.cwd, root, at2[1], at2[2]);
90565
90443
  if (held3[name] !== skills[name] || hashFile(file2) !== skills[name]) write(file2, text3);
90566
90444
  }
90567
90445
  }
@@ -90570,8 +90448,8 @@ function pullTools(ws, record, files) {
90570
90448
  const [, skill, rest] = SKILL_PATH.exec(name) ?? [];
90571
90449
  if (!skill || !rest) continue;
90572
90450
  for (const root of SKILL_ROOTS) {
90573
- fs19.rmSync(path21.join(ws.cwd, root, skill, rest), { force: true });
90574
- if (!Object.keys(skills).some((n) => n.startsWith(`skills/${skill}/`))) fs19.rmSync(path21.join(ws.cwd, root, skill), { recursive: true, force: true });
90451
+ fs18.rmSync(path20.join(ws.cwd, root, skill, rest), { force: true });
90452
+ if (!Object.keys(skills).some((n) => n.startsWith(`skills/${skill}/`))) fs18.rmSync(path20.join(ws.cwd, root, skill), { recursive: true, force: true });
90575
90453
  }
90576
90454
  }
90577
90455
  const names2 = [...new Set(Object.keys(skills).map((name) => name.split("/")[1]))];
@@ -90599,7 +90477,7 @@ async function pullWorkflow(ws, record, base) {
90599
90477
  files = read.value.files;
90600
90478
  found = true;
90601
90479
  if (!record.builtin) {
90602
- for (const [name, text3] of Object.entries(files)) if (isBoardPath(root + name)) write(path21.join(ws.board, root, name), text3);
90480
+ for (const [name, text3] of Object.entries(files)) if (isBoardPath(root + name)) write(path20.join(ws.board, root, name), text3);
90603
90481
  }
90604
90482
  }
90605
90483
  }
@@ -90607,15 +90485,15 @@ async function pullWorkflow(ws, record, base) {
90607
90485
  }
90608
90486
  pullAgents(ws, base, ws.workflow && !record.builtin ? files : {});
90609
90487
  const placed = readPlaced(ws);
90610
- for (const name of Object.keys(record.agents ?? {})) if (!placed[name]) fs19.rmSync(path21.join(ws.board, name), { force: true });
90488
+ for (const name of Object.keys(record.agents ?? {})) if (!placed[name]) fs18.rmSync(path20.join(ws.board, name), { force: true });
90611
90489
  record.agents = {};
90612
90490
  return { ok: true, value: void 0 };
90613
90491
  }
90614
90492
  var OWN_FOLDER = /^wf-(?!builtin-)[a-z0-9-]+$/;
90615
- var agentsRecord = (ws) => path21.join(ws.board, ".sync", "agents.json");
90493
+ var agentsRecord = (ws) => path20.join(ws.board, ".sync", "agents.json");
90616
90494
  function readPlaced(ws) {
90617
90495
  try {
90618
- return JSON.parse(fs19.readFileSync(agentsRecord(ws), "utf8"));
90496
+ return JSON.parse(fs18.readFileSync(agentsRecord(ws), "utf8"));
90619
90497
  } catch {
90620
90498
  return {};
90621
90499
  }
@@ -90636,8 +90514,8 @@ function pullAgents(ws, base, own) {
90636
90514
  const names2 = /* @__PURE__ */ new Set();
90637
90515
  for (const [name, text3] of Object.entries(files)) {
90638
90516
  const agent = /^agents\/([^/]+)\//.exec(name)?.[1];
90639
- const file2 = path21.resolve(ws.board, name);
90640
- if (!agent || taken.has(agent) || !file2.startsWith(path21.join(ws.board, "agents") + path21.sep)) continue;
90517
+ const file2 = path20.resolve(ws.board, name);
90518
+ if (!agent || taken.has(agent) || !file2.startsWith(path20.join(ws.board, "agents") + path20.sep)) continue;
90641
90519
  names2.add(agent);
90642
90520
  agents[name] = text3;
90643
90521
  }
@@ -90647,38 +90525,42 @@ function pullAgents(ws, base, own) {
90647
90525
  const hashes = {};
90648
90526
  for (const [name, text3] of Object.entries(agents)) {
90649
90527
  hashes[name] = hashOf(text3);
90650
- if (hashFile(path21.join(ws.board, name)) !== hashes[name]) write(path21.join(ws.board, name), text3);
90528
+ if (hashFile(path20.join(ws.board, name)) !== hashes[name]) write(path20.join(ws.board, name), text3);
90651
90529
  }
90652
- for (const name of Object.keys(before)) if (!hashes[name]) fs19.rmSync(path21.join(ws.board, name), { force: true });
90530
+ for (const name of Object.keys(before)) if (!hashes[name]) fs18.rmSync(path20.join(ws.board, name), { force: true });
90653
90531
  write(agentsRecord(ws), `${JSON.stringify(hashes, null, 2)}
90654
90532
  `);
90655
90533
  }
90656
90534
  function pullDraftAgents(ws, record) {
90657
90535
  if (ws.workflow !== BUILDER) return;
90658
- const root = path21.join(ws.board, "workflows", draftFolder(ws.task), "agents");
90536
+ const root = path20.join(ws.board, "workflows", draftFolder(ws.task), "agents");
90659
90537
  record.agents ??= {};
90660
90538
  for (const name of filesUnder(root)) {
90661
- const text3 = fs19.readFileSync(path21.join(root, name));
90539
+ const text3 = fs18.readFileSync(path20.join(root, name));
90662
90540
  const at2 = `agents/${name}`;
90663
90541
  record.agents[at2] = hashOf(text3);
90664
- if (hashFile(path21.join(ws.board, at2)) !== record.agents[at2]) write(path21.join(ws.board, at2), text3);
90542
+ if (hashFile(path20.join(ws.board, at2)) !== record.agents[at2]) write(path20.join(ws.board, at2), text3);
90665
90543
  }
90666
90544
  }
90667
90545
  function workflowFile(ws) {
90668
90546
  if (!ws.workflow || readRecord(ws).builtin) return null;
90669
- const file2 = path21.join(ws.board, "workflows", workflowFolder(ws.workflow), "WORKFLOW.md");
90670
- return fs19.existsSync(file2) ? file2 : null;
90547
+ const file2 = path20.join(ws.board, "workflows", workflowFolder(ws.workflow), "WORKFLOW.md");
90548
+ return fs18.existsSync(file2) ? file2 : null;
90671
90549
  }
90672
90550
  function assetPath(ws, name, card) {
90673
90551
  if (/^[a-z][\w+.-]*:/i.test(name) || name.startsWith("/") || name.startsWith("#")) return null;
90674
90552
  const held3 = /^\.(assets|mockups)\//.exec(name);
90675
90553
  if (held3) {
90676
90554
  const state = stateDir(ws);
90677
- const file3 = state && path21.resolve(state, held3[1], name.slice(held3[0].length));
90678
- return file3 && file3.startsWith(path21.join(state, held3[1]) + path21.sep) ? file3 : null;
90555
+ const file3 = state && path20.resolve(state, held3[1], name.slice(held3[0].length));
90556
+ return file3 && file3.startsWith(path20.join(state, held3[1]) + path20.sep) ? file3 : null;
90679
90557
  }
90680
- const file2 = path21.resolve(path21.dirname(card), name);
90681
- return file2.startsWith(ws.board + path21.sep) ? file2 : null;
90558
+ const file2 = path20.resolve(path20.dirname(card), name);
90559
+ return file2.startsWith(ws.board + path20.sep) ? file2 : null;
90560
+ }
90561
+ function cardAssetsDir(ws, id) {
90562
+ const state = stateDir(ws);
90563
+ return state && path20.join(state, "assets", String(id));
90682
90564
  }
90683
90565
  function stateDir(ws) {
90684
90566
  try {
@@ -90716,13 +90598,13 @@ async function pull(ws) {
90716
90598
  writeBase(ws, base);
90717
90599
  const reset = (view2) => {
90718
90600
  for (const [p2, content] of view2) {
90719
- const file2 = path21.join(ws.board, p2);
90601
+ const file2 = path20.join(ws.board, p2);
90720
90602
  if (kept2(p2) && readText(file2) !== content) write(file2, content);
90721
90603
  }
90722
90604
  };
90723
90605
  const view = viewOf(ws, base, sharedMemory(ws.board));
90724
90606
  const first = (p2) => isSettingsPath(p2) && !known.has(rootOf(ws) + p2);
90725
- for (const p2 of localFiles(ws, base)) if (!view.has(p2) && !first(p2)) fs19.rmSync(path21.join(ws.board, p2), { force: true });
90607
+ for (const p2 of localFiles(ws, base)) if (!view.has(p2) && !first(p2)) fs18.rmSync(path20.join(ws.board, p2), { force: true });
90726
90608
  reset(view);
90727
90609
  const record = readRecord(ws);
90728
90610
  const workflow = await pullWorkflow(ws, record, base);
@@ -90731,26 +90613,23 @@ async function pull(ws) {
90731
90613
  reset(viewOf(ws, base, sharedMemory(ws.board)));
90732
90614
  const assets = await pullAssets(ws, record, assetsOf(assetsListOf(ws, base)));
90733
90615
  if (!assets.ok) return assets;
90734
- const triage = await pullTriage(ws.board, ws.project);
90735
- if (!triage.ok) return triage;
90736
- record.triage = triage.value;
90737
90616
  writeRecord(ws, record);
90738
90617
  writeIndex(ws.board);
90739
90618
  return { ok: true, value: void 0 };
90740
90619
  }
90741
90620
  function writeIndex(board) {
90742
- const todo = path21.join(board, "todo");
90621
+ const todo = path20.join(board, "todo");
90743
90622
  const cards = [];
90744
90623
  let entries = [];
90745
90624
  try {
90746
- entries = fs19.readdirSync(todo, { withFileTypes: true });
90625
+ entries = fs18.readdirSync(todo, { withFileTypes: true });
90747
90626
  } catch {
90748
90627
  }
90749
90628
  for (const e2 of entries) {
90750
90629
  const id = /^(\d+)-/.exec(e2.name)?.[1];
90751
90630
  if (!id) continue;
90752
90631
  const link = e2.isDirectory() ? `${e2.name}/root.md` : e2.name.endsWith(".md") ? e2.name : null;
90753
- const text4 = link && readText(path21.join(todo, link));
90632
+ const text4 = link && readText(path20.join(todo, link));
90754
90633
  if (text4 === null || !link) continue;
90755
90634
  cards.push({ id: Number(id), title: cardFront(text4).title ?? e2.name.replace(/\.md$/, ""), link });
90756
90635
  }
@@ -90765,7 +90644,7 @@ the number at the front of a filename is the task id.
90765
90644
 
90766
90645
  ${list}
90767
90646
  `;
90768
- if (readText(path21.join(todo, "README.md")) !== text3) write(path21.join(todo, "README.md"), text3);
90647
+ if (readText(path20.join(todo, "README.md")) !== text3) write(path20.join(todo, "README.md"), text3);
90769
90648
  }
90770
90649
  var workspaceOf = (ws) => readBase(ws).workspace ?? null;
90771
90650
  async function pullAssets(ws, record, assets) {
@@ -90832,14 +90711,14 @@ function kindOf(ext) {
90832
90711
  return type.startsWith("video/") || type.startsWith("audio/") ? "video" : "asset";
90833
90712
  }
90834
90713
  async function sentOf(file2) {
90835
- const ext = path21.extname(file2).toLowerCase();
90714
+ const ext = path20.extname(file2).toLowerCase();
90836
90715
  const kind = kindOf(ext);
90837
- if (kind !== "html") return { bytes: fs19.readFileSync(file2), type: TYPES[ext] ?? "application/octet-stream", kind };
90716
+ if (kind !== "html") return { bytes: fs18.readFileSync(file2), type: TYPES[ext] ?? "application/octet-stream", kind };
90838
90717
  let page;
90839
90718
  try {
90840
90719
  page = await (await Promise.resolve().then(() => (init_mockup(), mockup_exports))).drawMockup(file2);
90841
90720
  } catch (e2) {
90842
- console.error(`runner: ${path21.basename(file2)} could not be drawn: ${e2 instanceof Error ? e2.message : String(e2)}`);
90721
+ console.error(`runner: ${path20.basename(file2)} could not be drawn: ${e2 instanceof Error ? e2.message : String(e2)}`);
90843
90722
  page = UNDRAWN;
90844
90723
  }
90845
90724
  return { bytes: Buffer.from(page), type: "text/html", kind };
@@ -90868,7 +90747,7 @@ async function pushAssets(ws, record, before) {
90868
90747
  if (!body.includes(name)) continue;
90869
90748
  const target = assetPath(ws, name, file2);
90870
90749
  const held3 = record.assets[name];
90871
- const out = target && held3 && fs19.existsSync(target) ? await sentOf(target) : null;
90750
+ const out = target && held3 && fs18.existsSync(target) ? await sentOf(target) : null;
90872
90751
  const hash = out && hashOf(out.bytes);
90873
90752
  if (out && held3 && held3.kind === "html" !== (out.kind === "html")) continue;
90874
90753
  if (held3 && out && hash !== held3.hash) {
@@ -90883,7 +90762,7 @@ async function pushAssets(ws, record, before) {
90883
90762
  }
90884
90763
  for (const name of namedFiles(body)) {
90885
90764
  const target = assetPath(ws, name, file2);
90886
- if (refs[name] || !target || !fs19.statSync(target, { throwIfNoEntry: false })?.isFile()) continue;
90765
+ if (refs[name] || !target || !fs18.statSync(target, { throwIfNoEntry: false })?.isFile()) continue;
90887
90766
  const out = await sentOf(target);
90888
90767
  if (!ws.cloudTask) continue;
90889
90768
  const made = await createArtifact(ws.cloudTask, name.slice(0, 200), out.kind);
@@ -90894,12 +90773,33 @@ async function pushAssets(ws, record, before) {
90894
90773
  refs[name] = { artifact: made.value.id, version: sent.value };
90895
90774
  }
90896
90775
  record.assets = assets;
90897
- const list = path21.join(ws.board, assetsFile(ws.task));
90898
- if (Object.keys(refs).length || fs19.existsSync(list)) {
90776
+ const list = path20.join(ws.board, assetsFile(ws.task));
90777
+ if (Object.keys(refs).length || fs18.existsSync(list)) {
90899
90778
  if (JSON.stringify(assetsOf(readText(list))) !== JSON.stringify(refs)) write(list, assetsText(refs));
90900
90779
  }
90901
90780
  return { ok: true, value: void 0 };
90902
90781
  }
90782
+ function resetSorted(ws) {
90783
+ for (const sub of ["dismissed", "archived"]) fs18.rmSync(path20.join(ws.board, "triage", sub), { recursive: true, force: true });
90784
+ for (const [p2, content] of viewOf(ws, readBase(ws), sharedMemory(ws.board))) {
90785
+ if (/^triage\/(?:dismissed|archived)\//.test(p2)) write(path20.join(ws.board, p2), content);
90786
+ }
90787
+ }
90788
+ function proposeItems(ws, base) {
90789
+ const root = rootOf(ws);
90790
+ for (const p2 of localFiles(ws, base)) {
90791
+ if (itemAt(p2)?.state !== "open" || base.files[root + p2]) continue;
90792
+ const file2 = path20.join(ws.board, p2);
90793
+ const content = fs18.readFileSync(file2, "utf8");
90794
+ const said = (key) => new RegExp(`^${key}:`, "m").test(content.split(/\n---/)[0] ?? "");
90795
+ const fields = {
90796
+ ...ws.cloudTask && !said("source_task") ? { source_task: ws.cloudTask } : {},
90797
+ ...ws.workflow && !said("workflow") ? { workflow: workflowName(ws.workflow) } : {}
90798
+ };
90799
+ const stamped = Object.keys(fields).length ? stampItem(content, fields) : content;
90800
+ if (stamped !== content) write(file2, stamped);
90801
+ }
90802
+ }
90903
90803
  function mergeFile(base, mine, theirs) {
90904
90804
  if (mine === theirs) return { content: mine };
90905
90805
  if (mine === null || theirs === null) return null;
@@ -90919,16 +90819,13 @@ async function send2(ws, job) {
90919
90819
  const assets = await pushAssets(ws, record, assetsOf(assetsListOf(ws, base)));
90920
90820
  if (!assets.ok) return fail(assets.error, false, assets.code);
90921
90821
  writeRecord(ws, record);
90922
- const triage = await pushTriage(ws.board, ws.project, ws.cloudTask, record.triage ?? {}, ws.workflow);
90923
- if (!triage.ok) return fail(triage.error, false, triage.code);
90924
- record.triage = triage.value;
90925
- writeRecord(ws, record);
90822
+ proposeItems(ws, base);
90926
90823
  const shared = sharedMemory(ws.board);
90927
90824
  const local = localFiles(ws, base);
90928
90825
  const localOf = /* @__PURE__ */ new Map();
90929
90826
  const changes = [];
90930
90827
  for (const p2 of local) {
90931
- const content = fs19.readFileSync(path21.join(ws.board, p2), "utf8");
90828
+ const content = fs18.readFileSync(path20.join(ws.board, p2), "utf8");
90932
90829
  const remote = remoteOf(ws, shared, p2);
90933
90830
  localOf.set(remote, p2);
90934
90831
  const held3 = base.files[remote];
@@ -90956,11 +90853,11 @@ async function send2(ws, job) {
90956
90853
  continue;
90957
90854
  }
90958
90855
  const p2 = localOf.get(theirs.path) ?? theirs.path;
90959
- const merged = at2 < 0 ? null : mergeFile(base.files[theirs.path]?.content ?? null, changes[at2].content, theirs.content);
90856
+ const merged = at2 < 0 ? null : itemAt(p2) ? { content: theirs.content } : mergeFile(base.files[theirs.path]?.content ?? null, changes[at2].content, theirs.content);
90960
90857
  if (!merged) return fail(`${p2} was changed elsewhere and does not merge.`, true, "version_conflict");
90961
90858
  changes[at2] = { path: theirs.path, content: merged.content, base_seq: theirs.seq };
90962
- if (merged.content === null) fs19.rmSync(path21.join(ws.board, p2), { force: true });
90963
- else write(path21.join(ws.board, p2), merged.content);
90859
+ if (merged.content === null) fs18.rmSync(path20.join(ws.board, p2), { force: true });
90860
+ else write(path20.join(ws.board, p2), merged.content);
90964
90861
  }
90965
90862
  if (!changes.length) return { ok: true, changed: false };
90966
90863
  sent = await commitBoard(ws.project, job.id, job.machineId, changes);
@@ -90975,6 +90872,82 @@ async function send2(ws, job) {
90975
90872
  return { ok: true, changed: true };
90976
90873
  }
90977
90874
 
90875
+ // src/triage.ts
90876
+ import fs19 from "node:fs";
90877
+ import path21 from "node:path";
90878
+
90879
+ // ../cli/src/lib/signals/identity.ts
90880
+ import { createHash } from "node:crypto";
90881
+ var DERIVED = "derived-";
90882
+ var derivedSourceId = (seed) => `${DERIVED}${createHash("sha256").update(seed).digest("hex").slice(0, 16)}`;
90883
+
90884
+ // src/triage.ts
90885
+ var triageDir = (board) => path21.join(board, "triage");
90886
+ var rejectedDir = (board) => path21.join(board, ".archive", ".sync");
90887
+ var SCRATCH = ["dismissed", "archived"];
90888
+ var stamp = (at2) => formatStamp(at2 ? new Date(at2) : /* @__PURE__ */ new Date());
90889
+ function slugOf(title) {
90890
+ return title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 56).replace(/-+$/, "") || "item";
90891
+ }
90892
+ function freeName(dir, title) {
90893
+ const stem = slugOf(title);
90894
+ let name = `${stem}.md`;
90895
+ for (let n = 2; fs19.existsSync(path21.join(dir, name)); n++) name = `${stem}-${n}.md`;
90896
+ return name;
90897
+ }
90898
+ function itemText(item, fields = {}) {
90899
+ const lines = [
90900
+ "---",
90901
+ `source_id: ${yamlScalar(derivedSourceId(`${item.title}
90902
+ ${item.text.trim()}`))}`,
90903
+ `title: ${yamlScalar(item.title)}`,
90904
+ `collected_at: ${yamlScalar(stamp(item.created_at))}`,
90905
+ `imported_at: ${yamlScalar(stamp(item.created_at))}`,
90906
+ ...Object.entries(fields).map(([k, v2]) => `${k}: ${yamlScalar(v2)}`),
90907
+ "---"
90908
+ ];
90909
+ return `${lines.join("\n")}
90910
+
90911
+ ${item.text.trim()}
90912
+ `;
90913
+ }
90914
+ function writeItem(dir, item, fields = {}) {
90915
+ fs19.mkdirSync(dir, { recursive: true });
90916
+ const name = freeName(dir, item.title);
90917
+ fs19.writeFileSync(path21.join(dir, name), itemText(item, item.workflow ? { workflow: workflowName(item.workflow), ...fields } : fields));
90918
+ return name;
90919
+ }
90920
+ function layOut(board, rejections) {
90921
+ clearLaid(board);
90922
+ const dir = rejectedDir(board);
90923
+ fs19.mkdirSync(dir, { recursive: true });
90924
+ for (const t2 of rejections.tasks) {
90925
+ fs19.writeFileSync(path21.join(dir, `${t2.number}-${slugify(t2.title)}.md`), [
90926
+ "---",
90927
+ `title: ${yamlScalar(t2.title)}`,
90928
+ "status: todo",
90929
+ "rejected: true",
90930
+ `rejected_reason: ${yamlScalar(t2.reason)}`,
90931
+ `rejected_at: ${yamlScalar(stamp(t2.cancelled_at))}`,
90932
+ "rejected_by: user",
90933
+ "---",
90934
+ "",
90935
+ t2.request.trim(),
90936
+ ""
90937
+ ].join("\n"));
90938
+ }
90939
+ for (const item of rejections.triage) {
90940
+ const sub = path21.join(triageDir(board), item.state === "dismissed" ? "dismissed" : "archived");
90941
+ const fields = item.state === "dismissed" ? { dismissed_at: stamp(item.dismissed_at), dismissed_by: "user", ...item.dismissed_reason ? { dismissed_reason: item.dismissed_reason } : {} } : {};
90942
+ writeItem(sub, item, fields);
90943
+ }
90944
+ return { tasks: rejections.tasks.map((t2) => t2.id), triage: rejections.triage.map((i) => i.id) };
90945
+ }
90946
+ function clearLaid(board) {
90947
+ fs19.rmSync(rejectedDir(board), { recursive: true, force: true });
90948
+ for (const sub of SCRATCH) fs19.rmSync(path21.join(triageDir(board), sub), { recursive: true, force: true });
90949
+ }
90950
+
90978
90951
  // src/built.ts
90979
90952
  import fs20 from "node:fs";
90980
90953
  import path22 from "node:path";
@@ -91204,9 +91177,11 @@ function spentBy(runs) {
91204
91177
  const used = runs.filter((r2) => r2.usage);
91205
91178
  const costed = runs.filter((r2) => typeof r2.costUsd === "number");
91206
91179
  const sum = (key) => used.reduce((n, r2) => n + (r2.usage[key] || 0), 0);
91180
+ const context = runs.filter((r2) => r2.context?.used !== void 0 && r2.context.limit).reduce((last2, r2) => !last2 || (r2.startedAt ?? 0) >= (last2.startedAt ?? 0) ? r2 : last2, void 0)?.context;
91207
91181
  return {
91208
91182
  ...used.length ? { usage: { input: sum("input"), cacheCreation: sum("cacheCreation"), cacheRead: sum("cacheRead"), output: sum("output") } } : {},
91209
- ...costed.length ? { costUsd: costed.reduce((n, r2) => n + r2.costUsd, 0) } : {}
91183
+ ...costed.length ? { costUsd: costed.reduce((n, r2) => n + r2.costUsd, 0) } : {},
91184
+ ...context ? { context: { used: context.used, limit: context.limit } } : {}
91210
91185
  };
91211
91186
  }
91212
91187
  var SETUP_STEPS = ["project", "agent", "decisions", "modules", "tasks"];
@@ -91302,18 +91277,18 @@ function logLines(show, event2) {
91302
91277
  }
91303
91278
  };
91304
91279
  }
91305
- function boardAkb(ws, deps, io, task) {
91280
+ function boardAkb(job, ws, deps, io, task) {
91306
91281
  return async (args, show = false) => {
91307
91282
  const at2 = args.includes("--") ? args.indexOf("--") : args.length;
91308
91283
  const full = [...args.slice(0, at2), "--board", ws.board, ...args.slice(at2)];
91309
91284
  const log = show ? logLines(io.show, io.event) : void 0;
91310
- const ran = await runAkb(deps.akb, full, { cwd: ws.cwd, board: ws.board, task, show: log?.push, track: io.track });
91285
+ const ran = await runAkb(deps.akb, full, { cwd: ws.cwd, board: ws.board, task, line: job.languageLine ?? "", show: log?.push, track: io.track });
91311
91286
  log?.end();
91312
91287
  return ran;
91313
91288
  };
91314
91289
  }
91315
91290
  async function setUp(job, ws, deps, io) {
91316
- const akb = boardAkb(ws, deps, io);
91291
+ const akb = boardAkb(job, ws, deps, io);
91317
91292
  const runtime = job.runtime;
91318
91293
  const missing = unavailable(runtime, await deps.runtimes());
91319
91294
  if (missing) return missing;
@@ -91363,7 +91338,7 @@ async function runReview(job, ws, tasks, deps, io) {
91363
91338
  const since = Date.now();
91364
91339
  const failed = await setUp(job, ws, deps, io);
91365
91340
  if (failed) return { ok: false, reason: failed };
91366
- const akb = boardAkb(ws, deps, io);
91341
+ const akb = boardAkb(job, ws, deps, io);
91367
91342
  const ran = await akb(["review-memory", "--task", ...tasks, "--follow", "--events", "--json"], true);
91368
91343
  if (io.lost()) return { ok: false, reason: "" };
91369
91344
  const answer = answerOf2(ran);
@@ -91378,10 +91353,11 @@ async function reviewRejections(job, ws, deps, io) {
91378
91353
  if (!read.ok) return { runs: [], failure: read.error };
91379
91354
  if (!read.value.tasks.length && !read.value.triage.length) return { runs: [] };
91380
91355
  const since = Date.now();
91381
- const akb = boardAkb(ws, deps, io);
91356
+ const akb = boardAkb(job, ws, deps, io);
91382
91357
  const laid = layOut(ws.board, read.value);
91383
91358
  const ran = await akb(["review-dismissals", "--all", "--follow", "--events", "--json"], true);
91384
91359
  clearLaid(ws.board);
91360
+ resetSorted(ws);
91385
91361
  const runs = (answerOf2(await akb(["run", "list", "--all", "--json"]))?.runs ?? []).filter((r2) => (r2.startedAt ?? 0) >= since);
91386
91362
  if (io.lost()) return { runs };
91387
91363
  if (ran.code !== 0) return { runs, failure: refusal2(ran) };
@@ -91407,7 +91383,7 @@ async function runAgent(job, ws, deps, io) {
91407
91383
  }
91408
91384
  if (name === "reflect" && !tasks?.length) return { ok: true, report: {} };
91409
91385
  const args = workflow ? ["agent", "run", workflowName(workflow), name] : name === "reflect" ? ["reflect", "--cards", ...tasks.map((t2) => String(t2.number))] : [name];
91410
- const akb = boardAkb(ws, deps, io, ws.cloudTask ?? void 0);
91386
+ const akb = boardAkb(job, ws, deps, io, ws.cloudTask ?? void 0);
91411
91387
  await akb(["run", "list", "--all", "--json"]);
91412
91388
  const ran = await akb([...args, "--follow", "--events", "--json"], true);
91413
91389
  if (io.lost()) return { ok: false, reason: "" };
@@ -91424,6 +91400,18 @@ function writeTranscript(job, dir) {
91424
91400
  `);
91425
91401
  return file2;
91426
91402
  }
91403
+ function pictures(job, ws, id) {
91404
+ const dir = cardAssetsDir(ws, id);
91405
+ if (!job.attachments.length || !dir) return "";
91406
+ fs21.mkdirSync(dir, { recursive: true });
91407
+ return job.attachments.map((a3, i) => {
91408
+ const file2 = `${i + 1}-${path23.basename(a3.name).replace(/[^\w.-]+/g, "-")}`;
91409
+ fs21.writeFileSync(path23.join(dir, file2), Buffer.from(a3.content, "base64"));
91410
+ return `
91411
+ <Asset src=".assets/${id}/${file2}" label="${a3.name.replace(/["<>]/g, "") || file2}" />
91412
+ `;
91413
+ }).join("");
91414
+ }
91427
91415
  function cardFlags(ws, fields) {
91428
91416
  if (!fields) return [];
91429
91417
  const open = (keys) => (keys ?? []).map((k) => Number(/(\d+)$/.exec(k)?.[1])).filter((n) => n > 0 && n !== ws.number && findCard(ws.board, n)?.startsWith(path23.join(ws.board, "todo") + path23.sep));
@@ -91438,7 +91426,7 @@ async function runFlow(job, ws, deps, io) {
91438
91426
  const { flow } = job;
91439
91427
  const since = Date.now();
91440
91428
  const fail = (reason) => ({ ok: false, reason });
91441
- const akb = boardAkb(ws, deps, io, ws.task);
91429
+ const akb = boardAkb(job, ws, deps, io, ws.task);
91442
91430
  const made = (ran) => {
91443
91431
  const answer = answerOf2(ran);
91444
91432
  return ran.code === 0 && answer?.id ? { ok: true, value: answer.id } : { ok: false, error: answer?.error?.message ?? refusal2(ran), code: answer?.error?.kind };
@@ -91462,11 +91450,11 @@ async function runFlow(job, ws, deps, io) {
91462
91450
  }
91463
91451
  const body = path23.join(ws.board, ".sync", `${ws.task}.request.md`);
91464
91452
  fs21.mkdirSync(path23.dirname(body), { recursive: true });
91453
+ if (!ws.number) return fail("This task has no number yet.");
91465
91454
  fs21.writeFileSync(body, `${said.request || title}
91466
91455
  ${isBuilder(ws) ? `
91467
91456
  ${draftLine(ws)}
91468
- ` : ""}`);
91469
- if (!ws.number) return fail("This task has no number yet.");
91457
+ ` : ""}${pictures(job, ws, ws.number)}`);
91470
91458
  const created = made(await akb([
91471
91459
  "raw",
91472
91460
  "create",
@@ -91984,8 +91972,8 @@ async function runClaimed(job, deps, track, keep) {
91984
91972
  This task came out of a discussion. Read it for what the card leaves out: ${file2}` : "";
91985
91973
  const planned = (resume, fork, said2 = "") => {
91986
91974
  let p2 = deps.plan(job.runtime, prompt + said2, cwd, resume, job.model, settingsOf(job), fork);
91987
- if (ws) p2 = { ...p2, env: { ...p2.env, ...akbEnv(deps.akb, ws.board, ws.task) } };
91988
- if (ideas) p2 = { ...p2, env: { ...p2.env, ...akbEnv(deps.akb, discussed), KANBAN_IDEAS: ideas } };
91975
+ if (ws) p2 = { ...p2, env: { ...p2.env, ...akbEnv(deps.akb, ws.board, ws.task, job.languageLine ?? "") } };
91976
+ if (ideas) p2 = { ...p2, env: { ...p2.env, ...akbEnv(deps.akb, discussed, void 0, job.languageLine ?? ""), KANBAN_IDEAS: ideas } };
91989
91977
  return p2;
91990
91978
  };
91991
91979
  const carried = !!job.resume && (!job.fork || forks(job.runtime));
@@ -92043,9 +92031,9 @@ This task came out of a discussion. Read it for what the card leaves out: ${file
92043
92031
  stop(child);
92044
92032
  await stream.end();
92045
92033
  if (stream.lost()) return;
92046
- const ok2 = end.ok || stream.asked();
92034
+ const ok = end.ok || stream.asked();
92047
92035
  const said2 = told(stream.asked() ? cutShort(report(plan3, end), stream.said()) : report(plan3, end));
92048
- if (!ok2 || !ws) return finish(deps, id, lease, ok2 ? "done" : "failed", ok2 ? "" : end.error ?? "", said2);
92036
+ if (!ok || !ws) return finish(deps, id, lease, ok ? "done" : "failed", ok ? "" : end.error ?? "", said2);
92049
92037
  return sendBack(deps, id, lease, ws, said2, () => keepChat(job, said2.reply));
92050
92038
  }
92051
92039
  const printed = async (plan3) => {
@@ -92320,7 +92308,6 @@ function keepPresence(machineId2, pingMs = PING_MS) {
92320
92308
  var HEARTBEAT_MS2 = 5 * 6e4;
92321
92309
  var POLL_MS = 6e4;
92322
92310
  var BACKOFF_MS3 = [1e3, 2e3, 5e3, 1e4, 3e4];
92323
- var MAX_RUNNING = 2;
92324
92311
  function startRunner(options) {
92325
92312
  let registration = null;
92326
92313
  let connected = false;
@@ -92454,7 +92441,7 @@ function startRunner(options) {
92454
92441
  await finishJob(registration.machineId, job.id, "failed", "The Runner restarted while this job was running.");
92455
92442
  continue;
92456
92443
  }
92457
- if (job.state !== "waiting" || running.has(job.id) || running.size >= MAX_RUNNING && !job.test) continue;
92444
+ if (job.state !== "waiting" || running.has(job.id)) continue;
92458
92445
  start(job.id);
92459
92446
  }
92460
92447
  } finally {
@@ -92535,34 +92522,56 @@ import { spawn as spawn4 } from "node:child_process";
92535
92522
  import crypto4 from "node:crypto";
92536
92523
  import http from "node:http";
92537
92524
  var WAIT_MS = 10 * 60 * 1e3;
92538
- var PAGE = (ok2) => `<!doctype html><meta charset="utf-8"><title>WildCrane</title><body style="font:16px system-ui;margin:4em;text-align:center">${ok2 ? "\u5DF2\u767B\u5F55\uFF0C\u53EF\u4EE5\u5173\u95ED\u6B64\u9875\u9762\u3002<br>Signed in \u2014 you can close this page." : "\u767B\u5F55\u672A\u5B8C\u6210\u3002<br>Sign-in did not finish."}</body>`;
92525
+ var CRANE = "M2 55.75C2 55.69 2.69 55.09 3.55 54.37L5.09 53.1L6.61 53.1L8.13 53.1L12.49 49.87C14.9 48.07 16.83 46.58 16.77 46.53C16.75 46.47 15.56 46.64 14.15 46.89C12.74 47.13 11.55 47.3 11.53 47.24C11.47 47.19 12.02 46.22 12.71 45.06L14.01 42.96L18.21 41.34C20.53 40.45 22.41 39.65 22.41 39.57C22.41 39.49 21.27 38.55 19.92 37.5C15.92 34.4 13.13 31.31 10.86 27.47L10.01 26.01L10.53 26.18C10.84 26.26 12.96 27.2 15.28 28.25C17.6 29.32 19.53 30.12 19.59 30.07C19.64 30.01 17.68 28.69 15.25 27.11C12.8 25.57 10.56 23.97 10.31 23.58C9.15 21.95 7.25 17.5 7.25 16.46C7.25 16.26 10.01 17.95 13.38 20.18C16.77 22.45 19.73 24.38 19.95 24.49C20.42 24.74 20.25 24.57 13.9 19.02L9.18 14.88L8.6 13.36C7.72 10.96 6.97 7.54 6.97 5.77L6.97 4.14L9.4 6.46C12.66 9.61 15.56 12.01 23.57 18.25C27.32 21.18 30.5 23.72 30.64 23.91C30.8 24.08 31.68 26.51 32.6 29.3L34.28 34.35L35.72 35.65C37.54 37.3 37.98 37.47 36.85 36.09L35.96 35.01L37.12 34.71C39.11 34.21 40.16 33.52 42.54 31.12L44.8 28.8L46.02 28.96C46.71 29.07 47.56 29.07 47.95 28.96L48.67 28.8L48.67 28.25L48.67 27.69L49.27 27.69C49.63 27.69 50.1 27.58 50.32 27.42L50.71 27.17L51.01 27.42C51.18 27.56 52.78 27.86 54.58 28.08C56.37 28.3 57.86 28.52 57.94 28.58C58 28.63 56.73 28.85 55.13 29.05C53.53 29.24 50.96 29.77 49.44 30.21C47.92 30.65 46.57 31.01 46.43 31.01C46.29 31.01 44.22 32.97 41.85 35.37C37.57 39.62 34.42 42.14 30.83 44.15L29.14 45.09L25.97 45.73L22.77 46.39L14.59 51.11L6.42 55.86L4.21 55.86C2.99 55.86 2 55.8 2 55.75Z";
92526
+ var CREST = "M44.97 27.45C44.61 26.89 46.57 25.76 47.87 25.76C48.72 25.76 50.6 26.7 50.6 27.14C50.6 27.64 45.27 27.97 44.97 27.45Z";
92527
+ var COPY = {
92528
+ zh: {
92529
+ ok: ["\u5DF2\u767B\u5F55 WildCrane", "\u53EF\u4EE5\u5173\u95ED\u6B64\u9875\u9762\uFF0C\u56DE\u5230 WildCrane \u7EE7\u7EED\u3002"],
92530
+ denied: ["\u767B\u5F55\u672A\u5B8C\u6210", "\u4F60\u53D6\u6D88\u4E86 GitHub \u6388\u6743\u3002\u8BF7\u56DE\u5230 WildCrane \u91CD\u65B0\u767B\u5F55\u3002"],
92531
+ failed: ["\u767B\u5F55\u672A\u5B8C\u6210", "\u767B\u5F55\u65F6\u51FA\u4E86\u70B9\u95EE\u9898\u3002\u8BF7\u56DE\u5230 WildCrane \u91CD\u8BD5\u3002"]
92532
+ },
92533
+ en: {
92534
+ ok: ["Signed in to WildCrane", "You can close this page and return to WildCrane."],
92535
+ denied: ["Sign-in didn't finish", "GitHub access was cancelled. Return to WildCrane to sign in again."],
92536
+ failed: ["Sign-in didn't finish", "Something went wrong while signing in. Return to WildCrane to try again."]
92537
+ }
92538
+ };
92539
+ var langOf = (accept) => /^\s*zh\b/i.test(accept ?? "") ? "zh" : "en";
92540
+ var PAGE = (outcome, lang) => {
92541
+ const [title, body] = COPY[lang][outcome];
92542
+ const ok = outcome === "ok";
92543
+ const icon = ok ? '<polyline points="20 6 9 17 4 12"/>' : '<path d="M18 6 6 18M6 6l12 12"/>';
92544
+ return `<!doctype html><html lang="${lang === "zh" ? "zh-CN" : "en"}"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>${title} \xB7 WildCrane</title><style>*{margin:0;box-sizing:border-box}body{display:flex;flex-direction:column;min-height:100dvh;background:#fff;color:#24231f;font-family:ui-sans-serif,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}header{padding:16px 36px 0}main{flex:1;display:flex;align-items:center;justify-content:center;padding:0 36px 64px;text-align:center}.icon{display:flex;margin:0 auto;width:44px;height:44px;border-radius:50%;align-items:center;justify-content:center;background:${ok ? "#e4f3ea" : "#f7ddce"};color:${ok ? "#2f6b46" : "#b83a12"}}h1{margin-top:16px;font-size:24px;font-weight:850;line-height:1.25;letter-spacing:-0.02em}p{margin:8px auto 0;max-width:38ch;font-size:13px;line-height:19px;color:#565550}</style><header><svg viewBox="2 4 56 52" width="23.7" height="22" aria-hidden="true"><path d="${CRANE}" fill="#24231f"/><path d="${CREST}" fill="#dd4f1e"/></svg></header><main><div><span class="icon"><svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${icon}</svg></span><h1>${title}</h1><p>${body}</p></div></main></html>`;
92545
+ };
92539
92546
  async function signIn(options = {}) {
92540
92547
  const verifier = base64url(crypto4.randomBytes(32));
92541
92548
  const challenge = base64url(crypto4.createHash("sha256").update(verifier).digest());
92542
92549
  let finish2 = () => {
92543
92550
  };
92544
- const answered = new Promise((resolve2) => {
92545
- finish2 = (code2, failure2) => resolve2({ code: code2, failure: failure2 });
92546
- });
92547
- const server = http.createServer((req, res) => {
92551
+ const answered = new Promise((resolve2) => finish2 = resolve2);
92552
+ let answering = false;
92553
+ const server = http.createServer(async (req, res) => {
92548
92554
  const asked = new URL(req.url ?? "/", "http://127.0.0.1");
92549
- if (asked.pathname !== "/signed-in") {
92555
+ if (asked.pathname !== "/signed-in" || answering) {
92550
92556
  res.writeHead(404).end();
92551
92557
  return;
92552
92558
  }
92559
+ answering = true;
92553
92560
  const params = asked.searchParams;
92554
- const code2 = params.get("code");
92555
- res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
92556
- res.end(PAGE(!!code2));
92561
+ const code = params.get("code");
92557
92562
  const error = params.get("error");
92558
- finish2(code2, code2 ? void 0 : {
92563
+ const failure2 = code ? await exchange(code, verifier) : {
92559
92564
  why: error === "access_denied" ? "denied" : "other",
92560
92565
  detail: params.get("error_description") || error || "no code came back"
92561
- });
92566
+ };
92567
+ const outcome = !failure2 ? "ok" : failure2.why === "denied" ? "denied" : "failed";
92568
+ res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
92569
+ res.end(PAGE(outcome, langOf(req.headers["accept-language"])));
92570
+ finish2(failure2);
92562
92571
  });
92563
92572
  await new Promise((resolve2) => server.listen(0, "127.0.0.1", resolve2));
92564
92573
  const { port } = server.address();
92565
- const { supabaseUrl, anonKey } = cloudEndpoints();
92574
+ const { supabaseUrl } = cloudEndpoints();
92566
92575
  const url = new URL(`${supabaseUrl}/auth/v1/authorize`);
92567
92576
  url.searchParams.set("provider", "github");
92568
92577
  url.searchParams.set("redirect_to", `http://127.0.0.1:${port}/signed-in`);
@@ -92572,14 +92581,17 @@ async function signIn(options = {}) {
92572
92581
  const onUrl = options.onUrl ?? ((u2) => status(t.signIn(u2)));
92573
92582
  onUrl(url.toString());
92574
92583
  openBrowser(url.toString());
92575
- const timer = setTimeout(() => finish2(null, { why: "timeout", detail: "timed out" }), WAIT_MS);
92576
- const cancel = () => finish2(null, { why: "cancelled", detail: "cancelled" });
92584
+ const timer = setTimeout(() => finish2({ why: "timeout", detail: "timed out" }), WAIT_MS);
92585
+ const cancel = () => finish2({ why: "cancelled", detail: "cancelled" });
92577
92586
  options.signal?.addEventListener("abort", cancel);
92578
- const { code, failure } = await answered;
92587
+ const failure = await answered;
92579
92588
  clearTimeout(timer);
92580
92589
  options.signal?.removeEventListener("abort", cancel);
92581
92590
  server.close();
92582
- if (!code) return failure ?? { why: "other", detail: "no code came back" };
92591
+ return failure;
92592
+ }
92593
+ async function exchange(code, verifier) {
92594
+ const { supabaseUrl, anonKey } = cloudEndpoints();
92583
92595
  let response;
92584
92596
  try {
92585
92597
  response = await fetch(`${supabaseUrl}/auth/v1/token?grant_type=pkce`, {
@@ -92590,7 +92602,7 @@ async function signIn(options = {}) {
92590
92602
  } catch (e2) {
92591
92603
  return { why: "unreachable", detail: e2 instanceof Error ? e2.message : String(e2) };
92592
92604
  }
92593
- const session = response.ok ? sessionFrom(await response.json()) : null;
92605
+ const session = response.ok ? sessionFrom(await response.json().catch(() => ({}))) : null;
92594
92606
  if (!session) return { why: "other", detail: `Cloud answered ${response.status}` };
92595
92607
  writeSession(session);
92596
92608
  return null;