lopebase 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +94 -2
  2. package/dist/lopebase.js +1883 -0
  3. package/package.json +57 -4
@@ -0,0 +1,1883 @@
1
+ #!/usr/bin/env node
2
+ var __create = Object.create;
3
+ var { getPrototypeOf: __getProtoOf, defineProperty: __defProp, getOwnPropertyNames: __getOwnPropNames } = Object;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ function __accessProp(key) {
6
+ return this[key];
7
+ }
8
+ var __toESMCache_node, __toESMCache_esm, __toESM = (mod, isNodeMode, target) => {
9
+ var canCache = mod != null && typeof mod === "object";
10
+ if (canCache) {
11
+ var cache = isNodeMode ? __toESMCache_node ??= /* @__PURE__ */ new WeakMap : __toESMCache_esm ??= /* @__PURE__ */ new WeakMap, cached = cache.get(mod);
12
+ if (cached)
13
+ return cached;
14
+ }
15
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
16
+ let to = isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", { value: mod, enumerable: !0 }) : target;
17
+ if (mod && typeof mod === "object" || typeof mod === "function") {
18
+ for (let key of __getOwnPropNames(mod))
19
+ if (!__hasOwnProp.call(to, key))
20
+ __defProp(to, key, {
21
+ get: __accessProp.bind(mod, key),
22
+ enumerable: !0
23
+ });
24
+ }
25
+ if (canCache)
26
+ cache.set(mod, to);
27
+ return to;
28
+ };
29
+ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
30
+
31
+ // ../../node_modules/.bun/sisteransi@1.0.5/node_modules/sisteransi/src/index.js
32
+ var require_src = __commonJS(function(exports, module) {
33
+ var cursor = {
34
+ to(x, y) {
35
+ if (!y)
36
+ return `\x1B[${x + 1}G`;
37
+ return `\x1B[${y + 1};${x + 1}H`;
38
+ },
39
+ move(x, y) {
40
+ let ret = "";
41
+ if (x < 0)
42
+ ret += `\x1B[${-x}D`;
43
+ else if (x > 0)
44
+ ret += `\x1B[${x}C`;
45
+ if (y < 0)
46
+ ret += `\x1B[${-y}A`;
47
+ else if (y > 0)
48
+ ret += `\x1B[${y}B`;
49
+ return ret;
50
+ },
51
+ up: (count = 1) => `\x1B[${count}A`,
52
+ down: (count = 1) => `\x1B[${count}B`,
53
+ forward: (count = 1) => `\x1B[${count}C`,
54
+ backward: (count = 1) => `\x1B[${count}D`,
55
+ nextLine: (count = 1) => "\x1B[E".repeat(count),
56
+ prevLine: (count = 1) => "\x1B[F".repeat(count),
57
+ left: "\x1B[G",
58
+ hide: "\x1B[?25l",
59
+ show: "\x1B[?25h",
60
+ save: "\x1B7",
61
+ restore: "\x1B8"
62
+ }, scroll = {
63
+ up: (count = 1) => "\x1B[S".repeat(count),
64
+ down: (count = 1) => "\x1B[T".repeat(count)
65
+ }, erase = {
66
+ screen: "\x1B[2J",
67
+ up: (count = 1) => "\x1B[1J".repeat(count),
68
+ down: (count = 1) => "\x1B[J".repeat(count),
69
+ line: "\x1B[2K",
70
+ lineEnd: "\x1B[K",
71
+ lineStart: "\x1B[1K",
72
+ lines(count) {
73
+ let clear = "";
74
+ for (let i = 0;i < count; i++)
75
+ clear += this.line + (i < count - 1 ? cursor.up() : "");
76
+ if (count)
77
+ clear += cursor.left;
78
+ return clear;
79
+ }
80
+ };
81
+ module.exports = { cursor, scroll, erase, beep: "\x07" };
82
+ });
83
+
84
+ // ../../node_modules/.bun/picocolors@1.1.1/node_modules/picocolors/picocolors.js
85
+ var require_picocolors = __commonJS(function(exports, module) {
86
+ var p = process || {}, argv = p.argv || [], env = p.env || {}, isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI), formatter = (open, close, replace = open) => (input) => {
87
+ let string = "" + input, index = string.indexOf(close, open.length);
88
+ return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
89
+ }, replaceClose = (string, close, replace, index) => {
90
+ let result = "", cursor = 0;
91
+ do
92
+ result += string.substring(cursor, index) + replace, cursor = index + close.length, index = string.indexOf(close, cursor);
93
+ while (~index);
94
+ return result + string.substring(cursor);
95
+ }, createColors = (enabled = isColorSupported) => {
96
+ let f = enabled ? formatter : () => String;
97
+ return {
98
+ isColorSupported: enabled,
99
+ reset: f("\x1B[0m", "\x1B[0m"),
100
+ bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
101
+ dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
102
+ italic: f("\x1B[3m", "\x1B[23m"),
103
+ underline: f("\x1B[4m", "\x1B[24m"),
104
+ inverse: f("\x1B[7m", "\x1B[27m"),
105
+ hidden: f("\x1B[8m", "\x1B[28m"),
106
+ strikethrough: f("\x1B[9m", "\x1B[29m"),
107
+ black: f("\x1B[30m", "\x1B[39m"),
108
+ red: f("\x1B[31m", "\x1B[39m"),
109
+ green: f("\x1B[32m", "\x1B[39m"),
110
+ yellow: f("\x1B[33m", "\x1B[39m"),
111
+ blue: f("\x1B[34m", "\x1B[39m"),
112
+ magenta: f("\x1B[35m", "\x1B[39m"),
113
+ cyan: f("\x1B[36m", "\x1B[39m"),
114
+ white: f("\x1B[37m", "\x1B[39m"),
115
+ gray: f("\x1B[90m", "\x1B[39m"),
116
+ bgBlack: f("\x1B[40m", "\x1B[49m"),
117
+ bgRed: f("\x1B[41m", "\x1B[49m"),
118
+ bgGreen: f("\x1B[42m", "\x1B[49m"),
119
+ bgYellow: f("\x1B[43m", "\x1B[49m"),
120
+ bgBlue: f("\x1B[44m", "\x1B[49m"),
121
+ bgMagenta: f("\x1B[45m", "\x1B[49m"),
122
+ bgCyan: f("\x1B[46m", "\x1B[49m"),
123
+ bgWhite: f("\x1B[47m", "\x1B[49m"),
124
+ blackBright: f("\x1B[90m", "\x1B[39m"),
125
+ redBright: f("\x1B[91m", "\x1B[39m"),
126
+ greenBright: f("\x1B[92m", "\x1B[39m"),
127
+ yellowBright: f("\x1B[93m", "\x1B[39m"),
128
+ blueBright: f("\x1B[94m", "\x1B[39m"),
129
+ magentaBright: f("\x1B[95m", "\x1B[39m"),
130
+ cyanBright: f("\x1B[96m", "\x1B[39m"),
131
+ whiteBright: f("\x1B[97m", "\x1B[39m"),
132
+ bgBlackBright: f("\x1B[100m", "\x1B[49m"),
133
+ bgRedBright: f("\x1B[101m", "\x1B[49m"),
134
+ bgGreenBright: f("\x1B[102m", "\x1B[49m"),
135
+ bgYellowBright: f("\x1B[103m", "\x1B[49m"),
136
+ bgBlueBright: f("\x1B[104m", "\x1B[49m"),
137
+ bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
138
+ bgCyanBright: f("\x1B[106m", "\x1B[49m"),
139
+ bgWhiteBright: f("\x1B[107m", "\x1B[49m")
140
+ };
141
+ };
142
+ module.exports = createColors();
143
+ module.exports.createColors = createColors;
144
+ });
145
+
146
+ // bin/lopebase.ts
147
+ import { spawn, spawnSync as spawnSync2 } from "node:child_process";
148
+
149
+ // ../../node_modules/.bun/@clack+prompts@0.11.0/node_modules/@clack/prompts/dist/index.mjs
150
+ import { stripVTControlCharacters as S2 } from "node:util";
151
+
152
+ // ../../node_modules/.bun/@clack+core@0.5.0/node_modules/@clack/core/dist/index.mjs
153
+ var import_sisteransi = __toESM(require_src(), 1), import_picocolors = __toESM(require_picocolors(), 1);
154
+ import { stdin as j, stdout as M } from "node:process";
155
+ import * as g from "node:readline";
156
+ import O from "node:readline";
157
+ import { Writable as X } from "node:stream";
158
+ function DD({ onlyFirst: e = !1 } = {}) {
159
+ let t = ["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?(?:\\u0007|\\u001B\\u005C|\\u009C))", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"].join("|");
160
+ return new RegExp(t, e ? void 0 : "g");
161
+ }
162
+ var uD = DD();
163
+ function P(e) {
164
+ if (typeof e != "string")
165
+ throw TypeError(`Expected a \`string\`, got \`${typeof e}\``);
166
+ return e.replace(uD, "");
167
+ }
168
+ function L(e) {
169
+ return e && e.__esModule && Object.prototype.hasOwnProperty.call(e, "default") ? e.default : e;
170
+ }
171
+ var W = { exports: {} };
172
+ (function(e) {
173
+ var u = {};
174
+ e.exports = u, u.eastAsianWidth = function(F) {
175
+ var s = F.charCodeAt(0), i = F.length == 2 ? F.charCodeAt(1) : 0, D = s;
176
+ return 55296 <= s && s <= 56319 && 56320 <= i && i <= 57343 && (s &= 1023, i &= 1023, D = s << 10 | i, D += 65536), D == 12288 || 65281 <= D && D <= 65376 || 65504 <= D && D <= 65510 ? "F" : D == 8361 || 65377 <= D && D <= 65470 || 65474 <= D && D <= 65479 || 65482 <= D && D <= 65487 || 65490 <= D && D <= 65495 || 65498 <= D && D <= 65500 || 65512 <= D && D <= 65518 ? "H" : 4352 <= D && D <= 4447 || 4515 <= D && D <= 4519 || 4602 <= D && D <= 4607 || 9001 <= D && D <= 9002 || 11904 <= D && D <= 11929 || 11931 <= D && D <= 12019 || 12032 <= D && D <= 12245 || 12272 <= D && D <= 12283 || 12289 <= D && D <= 12350 || 12353 <= D && D <= 12438 || 12441 <= D && D <= 12543 || 12549 <= D && D <= 12589 || 12593 <= D && D <= 12686 || 12688 <= D && D <= 12730 || 12736 <= D && D <= 12771 || 12784 <= D && D <= 12830 || 12832 <= D && D <= 12871 || 12880 <= D && D <= 13054 || 13056 <= D && D <= 19903 || 19968 <= D && D <= 42124 || 42128 <= D && D <= 42182 || 43360 <= D && D <= 43388 || 44032 <= D && D <= 55203 || 55216 <= D && D <= 55238 || 55243 <= D && D <= 55291 || 63744 <= D && D <= 64255 || 65040 <= D && D <= 65049 || 65072 <= D && D <= 65106 || 65108 <= D && D <= 65126 || 65128 <= D && D <= 65131 || 110592 <= D && D <= 110593 || 127488 <= D && D <= 127490 || 127504 <= D && D <= 127546 || 127552 <= D && D <= 127560 || 127568 <= D && D <= 127569 || 131072 <= D && D <= 194367 || 177984 <= D && D <= 196605 || 196608 <= D && D <= 262141 ? "W" : 32 <= D && D <= 126 || 162 <= D && D <= 163 || 165 <= D && D <= 166 || D == 172 || D == 175 || 10214 <= D && D <= 10221 || 10629 <= D && D <= 10630 ? "Na" : D == 161 || D == 164 || 167 <= D && D <= 168 || D == 170 || 173 <= D && D <= 174 || 176 <= D && D <= 180 || 182 <= D && D <= 186 || 188 <= D && D <= 191 || D == 198 || D == 208 || 215 <= D && D <= 216 || 222 <= D && D <= 225 || D == 230 || 232 <= D && D <= 234 || 236 <= D && D <= 237 || D == 240 || 242 <= D && D <= 243 || 247 <= D && D <= 250 || D == 252 || D == 254 || D == 257 || D == 273 || D == 275 || D == 283 || 294 <= D && D <= 295 || D == 299 || 305 <= D && D <= 307 || D == 312 || 319 <= D && D <= 322 || D == 324 || 328 <= D && D <= 331 || D == 333 || 338 <= D && D <= 339 || 358 <= D && D <= 359 || D == 363 || D == 462 || D == 464 || D == 466 || D == 468 || D == 470 || D == 472 || D == 474 || D == 476 || D == 593 || D == 609 || D == 708 || D == 711 || 713 <= D && D <= 715 || D == 717 || D == 720 || 728 <= D && D <= 731 || D == 733 || D == 735 || 768 <= D && D <= 879 || 913 <= D && D <= 929 || 931 <= D && D <= 937 || 945 <= D && D <= 961 || 963 <= D && D <= 969 || D == 1025 || 1040 <= D && D <= 1103 || D == 1105 || D == 8208 || 8211 <= D && D <= 8214 || 8216 <= D && D <= 8217 || 8220 <= D && D <= 8221 || 8224 <= D && D <= 8226 || 8228 <= D && D <= 8231 || D == 8240 || 8242 <= D && D <= 8243 || D == 8245 || D == 8251 || D == 8254 || D == 8308 || D == 8319 || 8321 <= D && D <= 8324 || D == 8364 || D == 8451 || D == 8453 || D == 8457 || D == 8467 || D == 8470 || 8481 <= D && D <= 8482 || D == 8486 || D == 8491 || 8531 <= D && D <= 8532 || 8539 <= D && D <= 8542 || 8544 <= D && D <= 8555 || 8560 <= D && D <= 8569 || D == 8585 || 8592 <= D && D <= 8601 || 8632 <= D && D <= 8633 || D == 8658 || D == 8660 || D == 8679 || D == 8704 || 8706 <= D && D <= 8707 || 8711 <= D && D <= 8712 || D == 8715 || D == 8719 || D == 8721 || D == 8725 || D == 8730 || 8733 <= D && D <= 8736 || D == 8739 || D == 8741 || 8743 <= D && D <= 8748 || D == 8750 || 8756 <= D && D <= 8759 || 8764 <= D && D <= 8765 || D == 8776 || D == 8780 || D == 8786 || 8800 <= D && D <= 8801 || 8804 <= D && D <= 8807 || 8810 <= D && D <= 8811 || 8814 <= D && D <= 8815 || 8834 <= D && D <= 8835 || 8838 <= D && D <= 8839 || D == 8853 || D == 8857 || D == 8869 || D == 8895 || D == 8978 || 9312 <= D && D <= 9449 || 9451 <= D && D <= 9547 || 9552 <= D && D <= 9587 || 9600 <= D && D <= 9615 || 9618 <= D && D <= 9621 || 9632 <= D && D <= 9633 || 9635 <= D && D <= 9641 || 9650 <= D && D <= 9651 || 9654 <= D && D <= 9655 || 9660 <= D && D <= 9661 || 9664 <= D && D <= 9665 || 9670 <= D && D <= 9672 || D == 9675 || 9678 <= D && D <= 9681 || 9698 <= D && D <= 9701 || D == 9711 || 9733 <= D && D <= 9734 || D == 9737 || 9742 <= D && D <= 9743 || 9748 <= D && D <= 9749 || D == 9756 || D == 9758 || D == 9792 || D == 9794 || 9824 <= D && D <= 9825 || 9827 <= D && D <= 9829 || 9831 <= D && D <= 9834 || 9836 <= D && D <= 9837 || D == 9839 || 9886 <= D && D <= 9887 || 9918 <= D && D <= 9919 || 9924 <= D && D <= 9933 || 9935 <= D && D <= 9953 || D == 9955 || 9960 <= D && D <= 9983 || D == 10045 || D == 10071 || 10102 <= D && D <= 10111 || 11093 <= D && D <= 11097 || 12872 <= D && D <= 12879 || 57344 <= D && D <= 63743 || 65024 <= D && D <= 65039 || D == 65533 || 127232 <= D && D <= 127242 || 127248 <= D && D <= 127277 || 127280 <= D && D <= 127337 || 127344 <= D && D <= 127386 || 917760 <= D && D <= 917999 || 983040 <= D && D <= 1048573 || 1048576 <= D && D <= 1114109 ? "A" : "N";
177
+ }, u.characterLength = function(F) {
178
+ var s = this.eastAsianWidth(F);
179
+ return s == "F" || s == "W" || s == "A" ? 2 : 1;
180
+ };
181
+ function t(F) {
182
+ return F.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[^\uD800-\uDFFF]/g) || [];
183
+ }
184
+ u.length = function(F) {
185
+ for (var s = t(F), i = 0, D = 0;D < s.length; D++)
186
+ i = i + this.characterLength(s[D]);
187
+ return i;
188
+ }, u.slice = function(F, s, i) {
189
+ textLen = u.length(F), s = s || 0, i = i || 1, s < 0 && (s = textLen + s), i < 0 && (i = textLen + i);
190
+ for (var D = "", C = 0, n = t(F), E = 0;E < n.length; E++) {
191
+ var a = n[E], o = u.length(a);
192
+ if (C >= s - (o == 2 ? 1 : 0))
193
+ if (C + o <= i)
194
+ D += a;
195
+ else
196
+ break;
197
+ C += o;
198
+ }
199
+ return D;
200
+ };
201
+ })(W);
202
+ var tD = W.exports, eD = L(tD), FD = function() {
203
+ return /\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67)\uDB40\uDC7F|(?:\uD83E\uDDD1\uD83C\uDFFF\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFD\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFC-\uDFFF])|\uD83D\uDC68(?:\uD83C\uDFFB(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))?|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])\uFE0F|\u200D(?:(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D[\uDC66\uDC67])|\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC)?|(?:\uD83D\uDC69(?:\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69]))|\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC69(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83E\uDDD1(?:\u200D(?:\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDE36\u200D\uD83C\uDF2B|\uD83C\uDFF3\uFE0F\u200D\u26A7|\uD83D\uDC3B\u200D\u2744|(?:(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\uD83C\uDFF4\u200D\u2620|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])\u200D[\u2640\u2642]|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u2600-\u2604\u260E\u2611\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26B0\u26B1\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0\u26F1\u26F4\u26F7\u26F8\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u3030\u303D\u3297\u3299]|\uD83C[\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]|\uD83D[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3])\uFE0F|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83D\uDE35\u200D\uD83D\uDCAB|\uD83D\uDE2E\u200D\uD83D\uDCA8|\uD83D\uDC15\u200D\uD83E\uDDBA|\uD83E\uDDD1(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83D\uDC69(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF4\uD83C\uDDF2|\uD83D\uDC08\u200D\u2B1B|\u2764\uFE0F\u200D(?:\uD83D\uDD25|\uD83E\uDE79)|\uD83D\uDC41\uFE0F|\uD83C\uDFF3\uFE0F|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|[#\*0-9]\uFE0F\u20E3|\u2764\uFE0F|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|\uD83C\uDFF4|(?:[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270C\u270D]|\uD83D[\uDD74\uDD90])(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC08\uDC15\uDC3B\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE2E\uDE35\uDE36\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5]|\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD]|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF]|[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0D\uDD0E\uDD10-\uDD17\uDD1D\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78\uDD7A-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCB\uDDD0\uDDE0-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6]|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26A7\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDED5-\uDED7\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])\uFE0F|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDC8F\uDC91\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1F\uDD26\uDD30-\uDD39\uDD3C-\uDD3E\uDD77\uDDB5\uDDB6\uDDB8\uDDB9\uDDBB\uDDCD-\uDDCF\uDDD1-\uDDDD])/g;
204
+ }, sD = L(FD);
205
+ function p(e, u = {}) {
206
+ if (typeof e != "string" || e.length === 0 || (u = { ambiguousIsNarrow: !0, ...u }, e = P(e), e.length === 0))
207
+ return 0;
208
+ e = e.replace(sD(), " ");
209
+ let t = u.ambiguousIsNarrow ? 1 : 2, F = 0;
210
+ for (let s of e) {
211
+ let i = s.codePointAt(0);
212
+ if (i <= 31 || i >= 127 && i <= 159 || i >= 768 && i <= 879)
213
+ continue;
214
+ switch (eD.eastAsianWidth(s)) {
215
+ case "F":
216
+ case "W":
217
+ F += 2;
218
+ break;
219
+ case "A":
220
+ F += t;
221
+ break;
222
+ default:
223
+ F += 1;
224
+ }
225
+ }
226
+ return F;
227
+ }
228
+ var w = 10, N = (e = 0) => (u) => `\x1B[${u + e}m`, I = (e = 0) => (u) => `\x1B[${38 + e};5;${u}m`, R = (e = 0) => (u, t, F) => `\x1B[${38 + e};2;${u};${t};${F}m`, r = { modifier: { reset: [0, 0], bold: [1, 22], dim: [2, 22], italic: [3, 23], underline: [4, 24], overline: [53, 55], inverse: [7, 27], hidden: [8, 28], strikethrough: [9, 29] }, color: { black: [30, 39], red: [31, 39], green: [32, 39], yellow: [33, 39], blue: [34, 39], magenta: [35, 39], cyan: [36, 39], white: [37, 39], blackBright: [90, 39], gray: [90, 39], grey: [90, 39], redBright: [91, 39], greenBright: [92, 39], yellowBright: [93, 39], blueBright: [94, 39], magentaBright: [95, 39], cyanBright: [96, 39], whiteBright: [97, 39] }, bgColor: { bgBlack: [40, 49], bgRed: [41, 49], bgGreen: [42, 49], bgYellow: [43, 49], bgBlue: [44, 49], bgMagenta: [45, 49], bgCyan: [46, 49], bgWhite: [47, 49], bgBlackBright: [100, 49], bgGray: [100, 49], bgGrey: [100, 49], bgRedBright: [101, 49], bgGreenBright: [102, 49], bgYellowBright: [103, 49], bgBlueBright: [104, 49], bgMagentaBright: [105, 49], bgCyanBright: [106, 49], bgWhiteBright: [107, 49] } };
229
+ Object.keys(r.modifier);
230
+ var iD = Object.keys(r.color), CD = Object.keys(r.bgColor);
231
+ [...iD, ...CD];
232
+ function rD() {
233
+ let e = /* @__PURE__ */ new Map;
234
+ for (let [u, t] of Object.entries(r)) {
235
+ for (let [F, s] of Object.entries(t))
236
+ r[F] = { open: `\x1B[${s[0]}m`, close: `\x1B[${s[1]}m` }, t[F] = r[F], e.set(s[0], s[1]);
237
+ Object.defineProperty(r, u, { value: t, enumerable: !1 });
238
+ }
239
+ return Object.defineProperty(r, "codes", { value: e, enumerable: !1 }), r.color.close = "\x1B[39m", r.bgColor.close = "\x1B[49m", r.color.ansi = N(), r.color.ansi256 = I(), r.color.ansi16m = R(), r.bgColor.ansi = N(w), r.bgColor.ansi256 = I(w), r.bgColor.ansi16m = R(w), Object.defineProperties(r, { rgbToAnsi256: { value: (u, t, F) => u === t && t === F ? u < 8 ? 16 : u > 248 ? 231 : Math.round((u - 8) / 247 * 24) + 232 : 16 + 36 * Math.round(u / 255 * 5) + 6 * Math.round(t / 255 * 5) + Math.round(F / 255 * 5), enumerable: !1 }, hexToRgb: { value: (u) => {
240
+ let t = /[a-f\d]{6}|[a-f\d]{3}/i.exec(u.toString(16));
241
+ if (!t)
242
+ return [0, 0, 0];
243
+ let [F] = t;
244
+ F.length === 3 && (F = [...F].map((i) => i + i).join(""));
245
+ let s = Number.parseInt(F, 16);
246
+ return [s >> 16 & 255, s >> 8 & 255, s & 255];
247
+ }, enumerable: !1 }, hexToAnsi256: { value: (u) => r.rgbToAnsi256(...r.hexToRgb(u)), enumerable: !1 }, ansi256ToAnsi: { value: (u) => {
248
+ if (u < 8)
249
+ return 30 + u;
250
+ if (u < 16)
251
+ return 90 + (u - 8);
252
+ let t, F, s;
253
+ if (u >= 232)
254
+ t = ((u - 232) * 10 + 8) / 255, F = t, s = t;
255
+ else {
256
+ u -= 16;
257
+ let C = u % 36;
258
+ t = Math.floor(u / 36) / 5, F = Math.floor(C / 6) / 5, s = C % 6 / 5;
259
+ }
260
+ let i = Math.max(t, F, s) * 2;
261
+ if (i === 0)
262
+ return 30;
263
+ let D = 30 + (Math.round(s) << 2 | Math.round(F) << 1 | Math.round(t));
264
+ return i === 2 && (D += 60), D;
265
+ }, enumerable: !1 }, rgbToAnsi: { value: (u, t, F) => r.ansi256ToAnsi(r.rgbToAnsi256(u, t, F)), enumerable: !1 }, hexToAnsi: { value: (u) => r.ansi256ToAnsi(r.hexToAnsi256(u)), enumerable: !1 } }), r;
266
+ }
267
+ var ED = rD(), d = /* @__PURE__ */ new Set(["\x1B", "›"]), oD = 39, y = "\x07", V = "[", nD = "]", G = "m", _ = `${nD}8;;`, z = (e) => `${d.values().next().value}${V}${e}${G}`, K = (e) => `${d.values().next().value}${_}${e}${y}`, aD = (e) => e.split(" ").map((u) => p(u)), k = (e, u, t) => {
268
+ let F = [...u], s = !1, i = !1, D = p(P(e[e.length - 1]));
269
+ for (let [C, n] of F.entries()) {
270
+ let E = p(n);
271
+ if (D + E <= t ? e[e.length - 1] += n : (e.push(n), D = 0), d.has(n) && (s = !0, i = F.slice(C + 1).join("").startsWith(_)), s) {
272
+ i ? n === y && (s = !1, i = !1) : n === G && (s = !1);
273
+ continue;
274
+ }
275
+ D += E, D === t && C < F.length - 1 && (e.push(""), D = 0);
276
+ }
277
+ !D && e[e.length - 1].length > 0 && e.length > 1 && (e[e.length - 2] += e.pop());
278
+ }, hD = (e) => {
279
+ let u = e.split(" "), t = u.length;
280
+ for (;t > 0 && !(p(u[t - 1]) > 0); )
281
+ t--;
282
+ return t === u.length ? e : u.slice(0, t).join(" ") + u.slice(t).join("");
283
+ }, lD = (e, u, t = {}) => {
284
+ if (t.trim !== !1 && e.trim() === "")
285
+ return "";
286
+ let F = "", s, i, D = aD(e), C = [""];
287
+ for (let [E, a] of e.split(" ").entries()) {
288
+ t.trim !== !1 && (C[C.length - 1] = C[C.length - 1].trimStart());
289
+ let o = p(C[C.length - 1]);
290
+ if (E !== 0 && (o >= u && (t.wordWrap === !1 || t.trim === !1) && (C.push(""), o = 0), (o > 0 || t.trim === !1) && (C[C.length - 1] += " ", o++)), t.hard && D[E] > u) {
291
+ let c = u - o, f = 1 + Math.floor((D[E] - c - 1) / u);
292
+ Math.floor((D[E] - 1) / u) < f && C.push(""), k(C, a, u);
293
+ continue;
294
+ }
295
+ if (o + D[E] > u && o > 0 && D[E] > 0) {
296
+ if (t.wordWrap === !1 && o < u) {
297
+ k(C, a, u);
298
+ continue;
299
+ }
300
+ C.push("");
301
+ }
302
+ if (o + D[E] > u && t.wordWrap === !1) {
303
+ k(C, a, u);
304
+ continue;
305
+ }
306
+ C[C.length - 1] += a;
307
+ }
308
+ t.trim !== !1 && (C = C.map((E) => hD(E)));
309
+ let n = [...C.join(`
310
+ `)];
311
+ for (let [E, a] of n.entries()) {
312
+ if (F += a, d.has(a)) {
313
+ let { groups: c } = new RegExp(`(?:\\${V}(?<code>\\d+)m|\\${_}(?<uri>.*)${y})`).exec(n.slice(E).join("")) || { groups: {} };
314
+ if (c.code !== void 0) {
315
+ let f = Number.parseFloat(c.code);
316
+ s = f === oD ? void 0 : f;
317
+ } else
318
+ c.uri !== void 0 && (i = c.uri.length === 0 ? void 0 : c.uri);
319
+ }
320
+ let o = ED.codes.get(Number(s));
321
+ n[E + 1] === `
322
+ ` ? (i && (F += K("")), s && o && (F += z(o))) : a === `
323
+ ` && (s && o && (F += z(s)), i && (F += K(i)));
324
+ }
325
+ return F;
326
+ };
327
+ function Y(e, u, t) {
328
+ return String(e).normalize().replace(/\r\n/g, `
329
+ `).split(`
330
+ `).map((F) => lD(F, u, t)).join(`
331
+ `);
332
+ }
333
+ var xD = ["up", "down", "left", "right", "space", "enter", "cancel"], B = { actions: new Set(xD), aliases: /* @__PURE__ */ new Map([["k", "up"], ["j", "down"], ["h", "left"], ["l", "right"], ["\x03", "cancel"], ["escape", "cancel"]]) };
334
+ function $(e, u) {
335
+ if (typeof e == "string")
336
+ return B.aliases.get(e) === u;
337
+ for (let t of e)
338
+ if (t !== void 0 && $(t, u))
339
+ return !0;
340
+ return !1;
341
+ }
342
+ function BD(e, u) {
343
+ if (e === u)
344
+ return;
345
+ let t = e.split(`
346
+ `), F = u.split(`
347
+ `), s = [];
348
+ for (let i = 0;i < Math.max(t.length, F.length); i++)
349
+ t[i] !== F[i] && s.push(i);
350
+ return s;
351
+ }
352
+ var AD = globalThis.process.platform.startsWith("win"), S = Symbol("clack:cancel");
353
+ function pD(e) {
354
+ return e === S;
355
+ }
356
+ function m(e, u) {
357
+ let t = e;
358
+ t.isTTY && t.setRawMode(u);
359
+ }
360
+ function fD({ input: e = j, output: u = M, overwrite: t = !0, hideCursor: F = !0 } = {}) {
361
+ let s = g.createInterface({ input: e, output: u, prompt: "", tabSize: 1 });
362
+ g.emitKeypressEvents(e, s), e.isTTY && e.setRawMode(!0);
363
+ let i = (D, { name: C, sequence: n }) => {
364
+ let E = String(D);
365
+ if ($([E, C, n], "cancel")) {
366
+ F && u.write(import_sisteransi.cursor.show), process.exit(0);
367
+ return;
368
+ }
369
+ if (!t)
370
+ return;
371
+ g.moveCursor(u, C === "return" ? 0 : -1, C === "return" ? -1 : 0, () => {
372
+ g.clearLine(u, 1, () => {
373
+ e.once("keypress", i);
374
+ });
375
+ });
376
+ };
377
+ return F && u.write(import_sisteransi.cursor.hide), e.once("keypress", i), () => {
378
+ e.off("keypress", i), F && u.write(import_sisteransi.cursor.show), e.isTTY && !AD && e.setRawMode(!1), s.terminal = !1, s.close();
379
+ };
380
+ }
381
+ var gD = Object.defineProperty, vD = (e, u, t) => (u in e) ? gD(e, u, { enumerable: !0, configurable: !0, writable: !0, value: t }) : e[u] = t, h = (e, u, t) => (vD(e, typeof u != "symbol" ? u + "" : u, t), t);
382
+
383
+ class x {
384
+ constructor(u, t = !0) {
385
+ h(this, "input"), h(this, "output"), h(this, "_abortSignal"), h(this, "rl"), h(this, "opts"), h(this, "_render"), h(this, "_track", !1), h(this, "_prevFrame", ""), h(this, "_subscribers", /* @__PURE__ */ new Map), h(this, "_cursor", 0), h(this, "state", "initial"), h(this, "error", ""), h(this, "value");
386
+ let { input: F = j, output: s = M, render: i, signal: D, ...C } = u;
387
+ this.opts = C, this.onKeypress = this.onKeypress.bind(this), this.close = this.close.bind(this), this.render = this.render.bind(this), this._render = i.bind(this), this._track = t, this._abortSignal = D, this.input = F, this.output = s;
388
+ }
389
+ unsubscribe() {
390
+ this._subscribers.clear();
391
+ }
392
+ setSubscriber(u, t) {
393
+ let F = this._subscribers.get(u) ?? [];
394
+ F.push(t), this._subscribers.set(u, F);
395
+ }
396
+ on(u, t) {
397
+ this.setSubscriber(u, { cb: t });
398
+ }
399
+ once(u, t) {
400
+ this.setSubscriber(u, { cb: t, once: !0 });
401
+ }
402
+ emit(u, ...t) {
403
+ let F = this._subscribers.get(u) ?? [], s = [];
404
+ for (let i of F)
405
+ i.cb(...t), i.once && s.push(() => F.splice(F.indexOf(i), 1));
406
+ for (let i of s)
407
+ i();
408
+ }
409
+ prompt() {
410
+ return new Promise((u, t) => {
411
+ if (this._abortSignal) {
412
+ if (this._abortSignal.aborted)
413
+ return this.state = "cancel", this.close(), u(S);
414
+ this._abortSignal.addEventListener("abort", () => {
415
+ this.state = "cancel", this.close();
416
+ }, { once: !0 });
417
+ }
418
+ let F = new X;
419
+ F._write = (s, i, D) => {
420
+ this._track && (this.value = this.rl?.line.replace(/\t/g, ""), this._cursor = this.rl?.cursor ?? 0, this.emit("value", this.value)), D();
421
+ }, this.input.pipe(F), this.rl = O.createInterface({ input: this.input, output: F, tabSize: 2, prompt: "", escapeCodeTimeout: 50, terminal: !0 }), O.emitKeypressEvents(this.input, this.rl), this.rl.prompt(), this.opts.initialValue !== void 0 && this._track && this.rl.write(this.opts.initialValue), this.input.on("keypress", this.onKeypress), m(this.input, !0), this.output.on("resize", this.render), this.render(), this.once("submit", () => {
422
+ this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), m(this.input, !1), u(this.value);
423
+ }), this.once("cancel", () => {
424
+ this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), m(this.input, !1), u(S);
425
+ });
426
+ });
427
+ }
428
+ onKeypress(u, t) {
429
+ if (this.state === "error" && (this.state = "active"), t?.name && (!this._track && B.aliases.has(t.name) && this.emit("cursor", B.aliases.get(t.name)), B.actions.has(t.name) && this.emit("cursor", t.name)), u && (u.toLowerCase() === "y" || u.toLowerCase() === "n") && this.emit("confirm", u.toLowerCase() === "y"), u === "\t" && this.opts.placeholder && (this.value || (this.rl?.write(this.opts.placeholder), this.emit("value", this.opts.placeholder))), u && this.emit("key", u.toLowerCase()), t?.name === "return") {
430
+ if (this.opts.validate) {
431
+ let F = this.opts.validate(this.value);
432
+ F && (this.error = F instanceof Error ? F.message : F, this.state = "error", this.rl?.write(this.value));
433
+ }
434
+ this.state !== "error" && (this.state = "submit");
435
+ }
436
+ $([u, t?.name, t?.sequence], "cancel") && (this.state = "cancel"), (this.state === "submit" || this.state === "cancel") && this.emit("finalize"), this.render(), (this.state === "submit" || this.state === "cancel") && this.close();
437
+ }
438
+ close() {
439
+ this.input.unpipe(), this.input.removeListener("keypress", this.onKeypress), this.output.write(`
440
+ `), m(this.input, !1), this.rl?.close(), this.rl = void 0, this.emit(`${this.state}`, this.value), this.unsubscribe();
441
+ }
442
+ restoreCursor() {
443
+ let u = Y(this._prevFrame, process.stdout.columns, { hard: !0 }).split(`
444
+ `).length - 1;
445
+ this.output.write(import_sisteransi.cursor.move(-999, u * -1));
446
+ }
447
+ render() {
448
+ let u = Y(this._render(this) ?? "", process.stdout.columns, { hard: !0 });
449
+ if (u !== this._prevFrame) {
450
+ if (this.state === "initial")
451
+ this.output.write(import_sisteransi.cursor.hide);
452
+ else {
453
+ let t = BD(this._prevFrame, u);
454
+ if (this.restoreCursor(), t && t?.length === 1) {
455
+ let F = t[0];
456
+ this.output.write(import_sisteransi.cursor.move(0, F)), this.output.write(import_sisteransi.erase.lines(1));
457
+ let s = u.split(`
458
+ `);
459
+ this.output.write(s[F]), this._prevFrame = u, this.output.write(import_sisteransi.cursor.move(0, s.length - F - 1));
460
+ return;
461
+ }
462
+ if (t && t?.length > 1) {
463
+ let F = t[0];
464
+ this.output.write(import_sisteransi.cursor.move(0, F)), this.output.write(import_sisteransi.erase.down());
465
+ let s = u.split(`
466
+ `).slice(F);
467
+ this.output.write(s.join(`
468
+ `)), this._prevFrame = u;
469
+ return;
470
+ }
471
+ this.output.write(import_sisteransi.erase.down());
472
+ }
473
+ this.output.write(u), this.state === "initial" && (this.state = "active"), this._prevFrame = u;
474
+ }
475
+ }
476
+ }
477
+ var A;
478
+ A = /* @__PURE__ */ new WeakMap;
479
+ var kD = Object.defineProperty, $D = (e, u, t) => (u in e) ? kD(e, u, { enumerable: !0, configurable: !0, writable: !0, value: t }) : e[u] = t, H = (e, u, t) => ($D(e, typeof u != "symbol" ? u + "" : u, t), t), SD = class extends x {
480
+ constructor(u) {
481
+ super(u, !1), H(this, "options"), H(this, "cursor", 0), this.options = u.options, this.value = [...u.initialValues ?? []], this.cursor = Math.max(this.options.findIndex(({ value: t }) => t === u.cursorAt), 0), this.on("key", (t) => {
482
+ t === "a" && this.toggleAll();
483
+ }), this.on("cursor", (t) => {
484
+ switch (t) {
485
+ case "left":
486
+ case "up":
487
+ this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
488
+ break;
489
+ case "down":
490
+ case "right":
491
+ this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
492
+ break;
493
+ case "space":
494
+ this.toggleValue();
495
+ break;
496
+ }
497
+ });
498
+ }
499
+ get _value() {
500
+ return this.options[this.cursor].value;
501
+ }
502
+ toggleAll() {
503
+ let u = this.value.length === this.options.length;
504
+ this.value = u ? [] : this.options.map((t) => t.value);
505
+ }
506
+ toggleValue() {
507
+ let u = this.value.includes(this._value);
508
+ this.value = u ? this.value.filter((t) => t !== this._value) : [...this.value, this._value];
509
+ }
510
+ }, TD = Object.defineProperty, jD = (e, u, t) => (u in e) ? TD(e, u, { enumerable: !0, configurable: !0, writable: !0, value: t }) : e[u] = t, U = (e, u, t) => (jD(e, typeof u != "symbol" ? u + "" : u, t), t);
511
+
512
+ class MD extends x {
513
+ constructor({ mask: u, ...t }) {
514
+ super(t), U(this, "valueWithCursor", ""), U(this, "_mask", "•"), this._mask = u ?? "•", this.on("finalize", () => {
515
+ this.valueWithCursor = this.masked;
516
+ }), this.on("value", () => {
517
+ if (this.cursor >= this.value.length)
518
+ this.valueWithCursor = `${this.masked}${import_picocolors.default.inverse(import_picocolors.default.hidden("_"))}`;
519
+ else {
520
+ let F = this.masked.slice(0, this.cursor), s = this.masked.slice(this.cursor);
521
+ this.valueWithCursor = `${F}${import_picocolors.default.inverse(s[0])}${s.slice(1)}`;
522
+ }
523
+ });
524
+ }
525
+ get cursor() {
526
+ return this._cursor;
527
+ }
528
+ get masked() {
529
+ return this.value.replaceAll(/./g, this._mask);
530
+ }
531
+ }
532
+ var OD = Object.defineProperty, PD = (e, u, t) => (u in e) ? OD(e, u, { enumerable: !0, configurable: !0, writable: !0, value: t }) : e[u] = t, J = (e, u, t) => (PD(e, typeof u != "symbol" ? u + "" : u, t), t);
533
+
534
+ class LD extends x {
535
+ constructor(u) {
536
+ super(u, !1), J(this, "options"), J(this, "cursor", 0), this.options = u.options, this.cursor = this.options.findIndex(({ value: t }) => t === u.initialValue), this.cursor === -1 && (this.cursor = 0), this.changeValue(), this.on("cursor", (t) => {
537
+ switch (t) {
538
+ case "left":
539
+ case "up":
540
+ this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
541
+ break;
542
+ case "down":
543
+ case "right":
544
+ this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
545
+ break;
546
+ }
547
+ this.changeValue();
548
+ });
549
+ }
550
+ get _value() {
551
+ return this.options[this.cursor];
552
+ }
553
+ changeValue() {
554
+ this.value = this._value.value;
555
+ }
556
+ }
557
+ class RD extends x {
558
+ get valueWithCursor() {
559
+ if (this.state === "submit")
560
+ return this.value;
561
+ if (this.cursor >= this.value.length)
562
+ return `${this.value}█`;
563
+ let u = this.value.slice(0, this.cursor), [t, ...F] = this.value.slice(this.cursor);
564
+ return `${u}${import_picocolors.default.inverse(t)}${F.join("")}`;
565
+ }
566
+ get cursor() {
567
+ return this._cursor;
568
+ }
569
+ constructor(u) {
570
+ super(u), this.on("finalize", () => {
571
+ this.value || (this.value = u.defaultValue);
572
+ });
573
+ }
574
+ }
575
+
576
+ // ../../node_modules/.bun/@clack+prompts@0.11.0/node_modules/@clack/prompts/dist/index.mjs
577
+ var import_picocolors2 = __toESM(require_picocolors(), 1), import_sisteransi2 = __toESM(require_src(), 1);
578
+ import y2 from "node:process";
579
+ function ce() {
580
+ return y2.platform !== "win32" ? y2.env.TERM !== "linux" : !!y2.env.CI || !!y2.env.WT_SESSION || !!y2.env.TERMINUS_SUBLIME || y2.env.ConEmuTask === "{cmd::Cmder}" || y2.env.TERM_PROGRAM === "Terminus-Sublime" || y2.env.TERM_PROGRAM === "vscode" || y2.env.TERM === "xterm-256color" || y2.env.TERM === "alacritty" || y2.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
581
+ }
582
+ var V2 = ce(), u = (t, n) => V2 ? t : n, le = u("◆", "*"), L2 = u("■", "x"), W2 = u("▲", "x"), C = u("◇", "o"), ue = u("┌", "T"), o = u("│", "|"), d2 = u("└", "—"), k2 = u("●", ">"), P2 = u("○", " "), A2 = u("◻", "[•]"), T = u("◼", "[+]"), F = u("◻", "[ ]"), $e = u("▪", "•"), _2 = u("─", "-"), me = u("╮", "+"), de = u("├", "+"), pe = u("╯", "+"), q = u("●", "•"), D = u("◆", "*"), U2 = u("▲", "!"), K2 = u("■", "x"), b2 = (t) => {
583
+ switch (t) {
584
+ case "initial":
585
+ case "active":
586
+ return import_picocolors2.default.cyan(le);
587
+ case "cancel":
588
+ return import_picocolors2.default.red(L2);
589
+ case "error":
590
+ return import_picocolors2.default.yellow(W2);
591
+ case "submit":
592
+ return import_picocolors2.default.green(C);
593
+ }
594
+ }, G2 = (t) => {
595
+ let { cursor: n, options: r, style: i } = t, s = t.maxItems ?? Number.POSITIVE_INFINITY, c = Math.max(process.stdout.rows - 4, 0), a = Math.min(c, Math.max(s, 5)), l = 0;
596
+ n >= l + a - 3 ? l = Math.max(Math.min(n - a + 3, r.length - a), 0) : n < l + 2 && (l = Math.max(n - 2, 0));
597
+ let $ = a < r.length && l > 0, g = a < r.length && l + a < r.length;
598
+ return r.slice(l, l + a).map((p, v, f) => {
599
+ let j = v === 0 && $, E = v === f.length - 1 && g;
600
+ return j || E ? import_picocolors2.default.dim("...") : i(p, v + l === n);
601
+ });
602
+ }, he = (t) => new RD({ validate: t.validate, placeholder: t.placeholder, defaultValue: t.defaultValue, initialValue: t.initialValue, render() {
603
+ let n = `${import_picocolors2.default.gray(o)}
604
+ ${b2(this.state)} ${t.message}
605
+ `, r = t.placeholder ? import_picocolors2.default.inverse(t.placeholder[0]) + import_picocolors2.default.dim(t.placeholder.slice(1)) : import_picocolors2.default.inverse(import_picocolors2.default.hidden("_")), i = this.value ? this.valueWithCursor : r;
606
+ switch (this.state) {
607
+ case "error":
608
+ return `${n.trim()}
609
+ ${import_picocolors2.default.yellow(o)} ${i}
610
+ ${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(this.error)}
611
+ `;
612
+ case "submit":
613
+ return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(this.value || t.placeholder)}`;
614
+ case "cancel":
615
+ return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(this.value ?? ""))}${this.value?.trim() ? `
616
+ ${import_picocolors2.default.gray(o)}` : ""}`;
617
+ default:
618
+ return `${n}${import_picocolors2.default.cyan(o)} ${i}
619
+ ${import_picocolors2.default.cyan(d2)}
620
+ `;
621
+ }
622
+ } }).prompt(), ge = (t) => new MD({ validate: t.validate, mask: t.mask ?? $e, render() {
623
+ let n = `${import_picocolors2.default.gray(o)}
624
+ ${b2(this.state)} ${t.message}
625
+ `, r = this.valueWithCursor, i = this.masked;
626
+ switch (this.state) {
627
+ case "error":
628
+ return `${n.trim()}
629
+ ${import_picocolors2.default.yellow(o)} ${i}
630
+ ${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(this.error)}
631
+ `;
632
+ case "submit":
633
+ return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(i)}`;
634
+ case "cancel":
635
+ return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(i ?? ""))}${i ? `
636
+ ${import_picocolors2.default.gray(o)}` : ""}`;
637
+ default:
638
+ return `${n}${import_picocolors2.default.cyan(o)} ${r}
639
+ ${import_picocolors2.default.cyan(d2)}
640
+ `;
641
+ }
642
+ } }).prompt();
643
+ var ve = (t) => {
644
+ let n = (r, i) => {
645
+ let s = r.label ?? String(r.value);
646
+ switch (i) {
647
+ case "selected":
648
+ return `${import_picocolors2.default.dim(s)}`;
649
+ case "active":
650
+ return `${import_picocolors2.default.green(k2)} ${s} ${r.hint ? import_picocolors2.default.dim(`(${r.hint})`) : ""}`;
651
+ case "cancelled":
652
+ return `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}`;
653
+ default:
654
+ return `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(s)}`;
655
+ }
656
+ };
657
+ return new LD({ options: t.options, initialValue: t.initialValue, render() {
658
+ let r = `${import_picocolors2.default.gray(o)}
659
+ ${b2(this.state)} ${t.message}
660
+ `;
661
+ switch (this.state) {
662
+ case "submit":
663
+ return `${r}${import_picocolors2.default.gray(o)} ${n(this.options[this.cursor], "selected")}`;
664
+ case "cancel":
665
+ return `${r}${import_picocolors2.default.gray(o)} ${n(this.options[this.cursor], "cancelled")}
666
+ ${import_picocolors2.default.gray(o)}`;
667
+ default:
668
+ return `${r}${import_picocolors2.default.cyan(o)} ${G2({ cursor: this.cursor, options: this.options, maxItems: t.maxItems, style: (i, s) => n(i, s ? "active" : "inactive") }).join(`
669
+ ${import_picocolors2.default.cyan(o)} `)}
670
+ ${import_picocolors2.default.cyan(d2)}
671
+ `;
672
+ }
673
+ } }).prompt();
674
+ };
675
+ var fe = (t) => {
676
+ let n = (r, i) => {
677
+ let s = r.label ?? String(r.value);
678
+ return i === "active" ? `${import_picocolors2.default.cyan(A2)} ${s} ${r.hint ? import_picocolors2.default.dim(`(${r.hint})`) : ""}` : i === "selected" ? `${import_picocolors2.default.green(T)} ${import_picocolors2.default.dim(s)} ${r.hint ? import_picocolors2.default.dim(`(${r.hint})`) : ""}` : i === "cancelled" ? `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}` : i === "active-selected" ? `${import_picocolors2.default.green(T)} ${s} ${r.hint ? import_picocolors2.default.dim(`(${r.hint})`) : ""}` : i === "submitted" ? `${import_picocolors2.default.dim(s)}` : `${import_picocolors2.default.dim(F)} ${import_picocolors2.default.dim(s)}`;
679
+ };
680
+ return new SD({ options: t.options, initialValues: t.initialValues, required: t.required ?? !0, cursorAt: t.cursorAt, validate(r) {
681
+ if (this.required && r.length === 0)
682
+ return `Please select at least one option.
683
+ ${import_picocolors2.default.reset(import_picocolors2.default.dim(`Press ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" space ")))} to select, ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" enter ")))} to submit`))}`;
684
+ }, render() {
685
+ let r = `${import_picocolors2.default.gray(o)}
686
+ ${b2(this.state)} ${t.message}
687
+ `, i = (s, c) => {
688
+ let a = this.value.includes(s.value);
689
+ return c && a ? n(s, "active-selected") : a ? n(s, "selected") : n(s, c ? "active" : "inactive");
690
+ };
691
+ switch (this.state) {
692
+ case "submit":
693
+ return `${r}${import_picocolors2.default.gray(o)} ${this.options.filter(({ value: s }) => this.value.includes(s)).map((s) => n(s, "submitted")).join(import_picocolors2.default.dim(", ")) || import_picocolors2.default.dim("none")}`;
694
+ case "cancel": {
695
+ let s = this.options.filter(({ value: c }) => this.value.includes(c)).map((c) => n(c, "cancelled")).join(import_picocolors2.default.dim(", "));
696
+ return `${r}${import_picocolors2.default.gray(o)} ${s.trim() ? `${s}
697
+ ${import_picocolors2.default.gray(o)}` : ""}`;
698
+ }
699
+ case "error": {
700
+ let s = this.error.split(`
701
+ `).map((c, a) => a === 0 ? `${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(c)}` : ` ${c}`).join(`
702
+ `);
703
+ return `${r + import_picocolors2.default.yellow(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
704
+ ${import_picocolors2.default.yellow(o)} `)}
705
+ ${s}
706
+ `;
707
+ }
708
+ default:
709
+ return `${r}${import_picocolors2.default.cyan(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
710
+ ${import_picocolors2.default.cyan(o)} `)}
711
+ ${import_picocolors2.default.cyan(d2)}
712
+ `;
713
+ }
714
+ } }).prompt();
715
+ };
716
+ var Me = (t = "", n = "") => {
717
+ let r = `
718
+ ${t}
719
+ `.split(`
720
+ `), i = S2(n).length, s = Math.max(r.reduce((a, l) => {
721
+ let $ = S2(l);
722
+ return $.length > a ? $.length : a;
723
+ }, 0), i) + 2, c = r.map((a) => `${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(a)}${" ".repeat(s - S2(a).length)}${import_picocolors2.default.gray(o)}`).join(`
724
+ `);
725
+ process.stdout.write(`${import_picocolors2.default.gray(o)}
726
+ ${import_picocolors2.default.green(C)} ${import_picocolors2.default.reset(n)} ${import_picocolors2.default.gray(_2.repeat(Math.max(s - i - 1, 1)) + me)}
727
+ ${c}
728
+ ${import_picocolors2.default.gray(de + _2.repeat(s + 2) + pe)}
729
+ `);
730
+ }, xe = (t = "") => {
731
+ process.stdout.write(`${import_picocolors2.default.gray(d2)} ${import_picocolors2.default.red(t)}
732
+
733
+ `);
734
+ }, Ie = (t = "") => {
735
+ process.stdout.write(`${import_picocolors2.default.gray(ue)} ${t}
736
+ `);
737
+ }, Se = (t = "") => {
738
+ process.stdout.write(`${import_picocolors2.default.gray(o)}
739
+ ${import_picocolors2.default.gray(d2)} ${t}
740
+
741
+ `);
742
+ }, M2 = { message: (t = "", { symbol: n = import_picocolors2.default.gray(o) } = {}) => {
743
+ let r = [`${import_picocolors2.default.gray(o)}`];
744
+ if (t) {
745
+ let [i, ...s] = t.split(`
746
+ `);
747
+ r.push(`${n} ${i}`, ...s.map((c) => `${import_picocolors2.default.gray(o)} ${c}`));
748
+ }
749
+ process.stdout.write(`${r.join(`
750
+ `)}
751
+ `);
752
+ }, info: (t) => {
753
+ M2.message(t, { symbol: import_picocolors2.default.blue(q) });
754
+ }, success: (t) => {
755
+ M2.message(t, { symbol: import_picocolors2.default.green(D) });
756
+ }, step: (t) => {
757
+ M2.message(t, { symbol: import_picocolors2.default.green(C) });
758
+ }, warn: (t) => {
759
+ M2.message(t, { symbol: import_picocolors2.default.yellow(U2) });
760
+ }, warning: (t) => {
761
+ M2.warn(t);
762
+ }, error: (t) => {
763
+ M2.message(t, { symbol: import_picocolors2.default.red(K2) });
764
+ } }, J2 = `${import_picocolors2.default.gray(o)} `;
765
+ var Y2 = ({ indicator: t = "dots" } = {}) => {
766
+ let n = V2 ? ["◒", "◐", "◓", "◑"] : ["•", "o", "O", "0"], r = V2 ? 80 : 120, i = process.env.CI === "true", s, c, a = !1, l = "", $, g = performance.now(), p = (m) => {
767
+ let h = m > 1 ? "Something went wrong" : "Canceled";
768
+ a && N(h, m);
769
+ }, v = () => p(2), f = () => p(1), j = () => {
770
+ process.on("uncaughtExceptionMonitor", v), process.on("unhandledRejection", v), process.on("SIGINT", f), process.on("SIGTERM", f), process.on("exit", p);
771
+ }, E = () => {
772
+ process.removeListener("uncaughtExceptionMonitor", v), process.removeListener("unhandledRejection", v), process.removeListener("SIGINT", f), process.removeListener("SIGTERM", f), process.removeListener("exit", p);
773
+ }, B = () => {
774
+ if ($ === void 0)
775
+ return;
776
+ i && process.stdout.write(`
777
+ `);
778
+ let m = $.split(`
779
+ `);
780
+ process.stdout.write(import_sisteransi2.cursor.move(-999, m.length - 1)), process.stdout.write(import_sisteransi2.erase.down(m.length));
781
+ }, R = (m) => m.replace(/\.+$/, ""), O = (m) => {
782
+ let h = (performance.now() - m) / 1000, w = Math.floor(h / 60), I = Math.floor(h % 60);
783
+ return w > 0 ? `[${w}m ${I}s]` : `[${I}s]`;
784
+ }, H = (m = "") => {
785
+ a = !0, s = fD(), l = R(m), g = performance.now(), process.stdout.write(`${import_picocolors2.default.gray(o)}
786
+ `);
787
+ let h = 0, w = 0;
788
+ j(), c = setInterval(() => {
789
+ if (i && l === $)
790
+ return;
791
+ B(), $ = l;
792
+ let I = import_picocolors2.default.magenta(n[h]);
793
+ if (i)
794
+ process.stdout.write(`${I} ${l}...`);
795
+ else if (t === "timer")
796
+ process.stdout.write(`${I} ${l} ${O(g)}`);
797
+ else {
798
+ let z = ".".repeat(Math.floor(w)).slice(0, 3);
799
+ process.stdout.write(`${I} ${l}${z}`);
800
+ }
801
+ h = h + 1 < n.length ? h + 1 : 0, w = w < n.length ? w + 0.125 : 0;
802
+ }, r);
803
+ }, N = (m = "", h = 0) => {
804
+ a = !1, clearInterval(c), B();
805
+ let w = h === 0 ? import_picocolors2.default.green(C) : h === 1 ? import_picocolors2.default.red(L2) : import_picocolors2.default.red(W2);
806
+ l = R(m ?? l), t === "timer" ? process.stdout.write(`${w} ${l} ${O(g)}
807
+ `) : process.stdout.write(`${w} ${l}
808
+ `), E(), s();
809
+ };
810
+ return { start: H, stop: N, message: (m = "") => {
811
+ l = R(m ?? l);
812
+ } };
813
+ };
814
+
815
+ // ../admin-adapter/src/security.ts
816
+ var SIGNATURE_HEADER = "lopebase-signature";
817
+ var enc = /* @__PURE__ */ new TextEncoder;
818
+ function hex(bytes) {
819
+ return [...new Uint8Array(bytes)].map((b) => b.toString(16).padStart(2, "0")).join("");
820
+ }
821
+ async function sha256Hex(data) {
822
+ return hex(await crypto.subtle.digest("SHA-256", data));
823
+ }
824
+ async function hmacHex(secret, message) {
825
+ let key = await crypto.subtle.importKey("raw", enc.encode(secret), { name: "HMAC", hash: "SHA-256" }, !1, ["sign"]);
826
+ return hex(await crypto.subtle.sign("HMAC", key, enc.encode(message)));
827
+ }
828
+ function newSigningSecret() {
829
+ let bytes = crypto.getRandomValues(new Uint8Array(32)), bin = "";
830
+ for (let b of bytes)
831
+ bin += String.fromCharCode(b);
832
+ return "lbs_" + btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
833
+ }
834
+ function payload(t, method, pathAndQuery, bodyHash) {
835
+ return `${t}.${method.toUpperCase()}.${pathAndQuery}.${bodyHash}`;
836
+ }
837
+ async function signRequest(input) {
838
+ let t = input.timestamp ?? Math.floor(Date.now() / 1000), body = typeof input.body === "string" ? enc.encode(input.body) : input.body ?? new Uint8Array, sig = await hmacHex(input.secret, payload(t, input.method, input.pathAndQuery, await sha256Hex(body)));
839
+ return `t=${t},v1=${sig}`;
840
+ }
841
+ var SENSITIVE_PARTS = /* @__PURE__ */ new Set([
842
+ "password",
843
+ "passwd",
844
+ "passcode",
845
+ "pwd",
846
+ "hash",
847
+ "hashed",
848
+ "salt",
849
+ "secret",
850
+ "secrets",
851
+ "token",
852
+ "tokens",
853
+ "credential",
854
+ "credentials",
855
+ "ssn",
856
+ "card",
857
+ "cvv",
858
+ "cvc",
859
+ "iban",
860
+ "otp",
861
+ "mfa",
862
+ "totp",
863
+ "session",
864
+ "cookie"
865
+ ]), SENSITIVE_JOINED = /apikey|privatekey|secretkey|accesskey|accountnumber|routingnumber|stripecustomer|paymentmethod|recoverycode/;
866
+ function isSensitiveFieldName(name) {
867
+ let parts = name.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase().split(/[^a-z0-9]+/).filter(Boolean);
868
+ if (parts.some((p) => SENSITIVE_PARTS.has(p)))
869
+ return !0;
870
+ return SENSITIVE_JOINED.test(parts.join(""));
871
+ }
872
+
873
+ // ../admin-adapter/src/adapter.ts
874
+ var DEFAULT_BASE_PATH = "/api/lopebase";
875
+ // ../admin-adapter/src/conformance.ts
876
+ import { strict as assert } from "node:assert";
877
+ async function body(res) {
878
+ return await res.json();
879
+ }
880
+ function conformanceChecks(opts) {
881
+ if (!opts.adapter && !opts.baseUrl)
882
+ throw Error("conformanceChecks needs an adapter or a baseUrl");
883
+ let remote = !opts.adapter, base = opts.baseUrl ? opts.baseUrl.replace(/\/$/, "") : `${opts.origin ?? "https://property.test"}${(opts.basePath ?? opts.adapter?.config.basePath ?? DEFAULT_BASE_PATH).replace(/\/$/, "")}`, send = (req) => opts.adapter ? opts.adapter.handle(req) : fetch(req);
884
+ async function signedHeaders(url, method, bodyText, timestamp) {
885
+ if (opts.secret) {
886
+ let u = new URL(url);
887
+ return {
888
+ [SIGNATURE_HEADER]: await signRequest({
889
+ secret: opts.secret,
890
+ method,
891
+ pathAndQuery: u.pathname + u.search,
892
+ body: bodyText,
893
+ timestamp
894
+ })
895
+ };
896
+ }
897
+ return opts.token ? { authorization: `Bearer ${opts.token}` } : {};
898
+ }
899
+ let authed = async (path, init) => {
900
+ let url = base + path, method = init?.method ?? "GET", bodyText = typeof init?.body === "string" ? init.body : void 0;
901
+ return send(new Request(url, {
902
+ ...init,
903
+ headers: {
904
+ "content-type": "application/json",
905
+ ...await signedHeaders(url, method, bodyText),
906
+ ...init?.headers
907
+ }
908
+ }));
909
+ }, resources = () => authed("/resources").then((r) => body(r));
910
+ return [
911
+ {
912
+ name: "GET /health returns { ok } without auth",
913
+ async run() {
914
+ let res = await send(new Request(`${base}/health`));
915
+ assert.equal(res.status, 200);
916
+ let b = await body(res);
917
+ assert.equal(typeof b.ok, "boolean");
918
+ }
919
+ },
920
+ {
921
+ name: "requests without a valid token get 401",
922
+ async run() {
923
+ let res = await send(new Request(`${base}/resources`));
924
+ assert.equal(res.status, 401);
925
+ }
926
+ },
927
+ {
928
+ name: "GET /resources returns a catalog with field metadata",
929
+ async run() {
930
+ let res = await authed("/resources");
931
+ assert.equal(res.status, 200);
932
+ let b = await body(res);
933
+ assert.ok(Array.isArray(b.resources));
934
+ for (let r of b.resources)
935
+ assert.ok(r.name && r.label && r.readCapability), assert.ok(Array.isArray(r.fields));
936
+ }
937
+ },
938
+ {
939
+ name: "GET /actions returns a catalog with param specs",
940
+ async run() {
941
+ let res = await authed("/actions");
942
+ assert.equal(res.status, 200);
943
+ let b = await body(res);
944
+ assert.ok(Array.isArray(b.actions));
945
+ for (let a of b.actions)
946
+ assert.ok(a.name && a.label && a.capability), assert.ok(Array.isArray(a.params));
947
+ }
948
+ },
949
+ {
950
+ name: "GET /resources/:name paginates ({ rows, total? })",
951
+ async run() {
952
+ let cat = await resources(), name = opts.sampleResource ?? cat.resources[0]?.name;
953
+ if (!name)
954
+ return;
955
+ let res = await authed(`/resources/${name}?limit=5`);
956
+ assert.equal(res.status, 200);
957
+ let page = await body(res);
958
+ assert.ok(Array.isArray(page.rows));
959
+ }
960
+ },
961
+ {
962
+ name: "GET /resources/:name/:id returns a row or 404-null",
963
+ async run() {
964
+ let cat = await resources(), meta = opts.sampleResource ? cat.resources.find((r) => r.name === opts.sampleResource) : cat.resources[0];
965
+ if (!meta)
966
+ return;
967
+ let first = (await body(await authed(`/resources/${meta.name}?limit=1`))).rows[0];
968
+ if (!first)
969
+ return;
970
+ let idField = meta.fields[0]?.name ?? "id", res = await authed(`/resources/${meta.name}/${encodeURIComponent(String(first[idField]))}`);
971
+ assert.ok(res.status === 200 || res.status === 404);
972
+ }
973
+ },
974
+ {
975
+ name: "GET /audit returns { rows: AuditEvent[] }",
976
+ async run() {
977
+ let res = await authed("/audit");
978
+ assert.equal(res.status, 200);
979
+ let b = await body(res);
980
+ assert.ok(Array.isArray(b.rows));
981
+ }
982
+ },
983
+ {
984
+ name: "an unknown route returns 404",
985
+ async run() {
986
+ let res = await authed("/does-not-exist");
987
+ assert.equal(res.status, 404);
988
+ }
989
+ },
990
+ {
991
+ name: "no field in the catalog looks like a secret unless marked safe",
992
+ async run() {
993
+ let cat = await resources();
994
+ for (let r of cat.resources)
995
+ for (let f of r.fields)
996
+ assert.ok(!isSensitiveFieldName(f.name) || f.sensitive === "allow", `${r.name}.${f.name} looks sensitive`);
997
+ }
998
+ },
999
+ {
1000
+ name: "rows contain only declared fields, and a page is at most 100",
1001
+ async run() {
1002
+ let cat = await resources();
1003
+ for (let r of cat.resources) {
1004
+ let res = await authed(`/resources/${r.name}?limit=1000`);
1005
+ assert.equal(res.status, 200);
1006
+ let page = await body(res);
1007
+ assert.ok(page.rows.length <= 100, `${r.name} returned ${page.rows.length} rows`);
1008
+ let declared = /* @__PURE__ */ new Set(["id", ...r.fields.map((f) => f.name)]);
1009
+ for (let row of page.rows)
1010
+ for (let k of Object.keys(row))
1011
+ assert.ok(declared.has(k), `${r.name} returned undeclared field ${k}`);
1012
+ }
1013
+ }
1014
+ },
1015
+ ...opts.secret ? [
1016
+ {
1017
+ name: "a stale or tampered signature gets 401",
1018
+ async run() {
1019
+ let url = `${base}/resources`, stale = await signedHeaders(url, "GET", void 0, Math.floor(Date.now() / 1000) - 3600);
1020
+ assert.equal((await send(new Request(url, { headers: stale }))).status, 401);
1021
+ let good = await signedHeaders(url, "GET", void 0), tampered = `${url}?limit=1`;
1022
+ assert.equal((await send(new Request(tampered, { headers: good }))).status, 401);
1023
+ }
1024
+ }
1025
+ ] : [],
1026
+ {
1027
+ name: "a mutation writes an audit row (PATCH round-trips into /audit)",
1028
+ async run() {
1029
+ let writable = (await resources()).resources.find((r) => r.writeCapability && r.fields.some((f) => f.editable));
1030
+ if (!writable || remote)
1031
+ return;
1032
+ let row = (await body(await authed(`/resources/${writable.name}?limit=1`))).rows[0];
1033
+ if (!row)
1034
+ return;
1035
+ let idField = writable.fields[0]?.name ?? "id", editField = writable.fields.find((f) => f.editable)?.name;
1036
+ if (!editField)
1037
+ return;
1038
+ let before = await body(await authed("/audit")), res = await authed(`/resources/${writable.name}/${encodeURIComponent(String(row[idField]))}`, {
1039
+ method: "PATCH",
1040
+ body: JSON.stringify({ patch: { [editField]: row[editField] } })
1041
+ });
1042
+ assert.equal(res.status, 200);
1043
+ let after = await body(await authed("/audit"));
1044
+ assert.ok(after.rows.length > before.rows.length, "expected a new audit row");
1045
+ }
1046
+ }
1047
+ ];
1048
+ }
1049
+ // bin/lopebase.ts
1050
+ var import_picocolors3 = __toESM(require_picocolors(), 1);
1051
+
1052
+ // src/adapter-check.ts
1053
+ async function checkAdapter(input) {
1054
+ let log = input.log ?? (() => {}), failed = [], passed = 0, base = input.baseUrl.replace(/\/$/, ""), url = new URL(`${base}/resources`), status;
1055
+ try {
1056
+ let headers = input.secret ? {
1057
+ [SIGNATURE_HEADER]: await signRequest({
1058
+ secret: input.secret,
1059
+ method: "GET",
1060
+ pathAndQuery: url.pathname + url.search
1061
+ })
1062
+ } : { authorization: `Bearer ${input.token ?? ""}` };
1063
+ status = (await fetch(url, { headers })).status;
1064
+ } catch (e) {
1065
+ let error = `Could not reach ${base} (${e instanceof Error ? e.message : String(e)}).`;
1066
+ return log(`FAIL ${error}`), { passed, failed: [{ name: "reachable", error }] };
1067
+ }
1068
+ if (status === 401) {
1069
+ let error = input.secret ? "The adapter refused the signature. The secret here does not match the app's LOPEBASE_SIGNING_SECRET, or the two clocks are more than 5 minutes apart." : "The adapter refused the token.";
1070
+ return log(`FAIL ${error}`), { passed, failed: [{ name: "authenticated", error }] };
1071
+ }
1072
+ if (status === 404) {
1073
+ let error = `Nothing at ${base}/resources. Check the base URL, usually https://your-app/api/lopebase.`;
1074
+ return log(`FAIL ${error}`), { passed, failed: [{ name: "found", error }] };
1075
+ }
1076
+ for (let c of conformanceChecks({
1077
+ baseUrl: input.baseUrl,
1078
+ secret: input.secret,
1079
+ token: input.token
1080
+ }))
1081
+ try {
1082
+ await c.run(), passed++, log(`pass ${c.name}`);
1083
+ } catch (e) {
1084
+ let error = e instanceof Error ? e.message.split(`
1085
+ `)[0] : String(e);
1086
+ failed.push({ name: c.name, error }), log(`FAIL ${c.name}: ${error}`);
1087
+ }
1088
+ return { passed, failed };
1089
+ }
1090
+
1091
+ // src/agents.ts
1092
+ import { spawnSync } from "node:child_process";
1093
+ var AGENTS = [
1094
+ {
1095
+ id: "claude",
1096
+ label: "Claude Code",
1097
+ bin: "claude",
1098
+ args: (p) => [p],
1099
+ mcpAdd: (argv) => [
1100
+ "mcp",
1101
+ "add",
1102
+ "--scope",
1103
+ "local",
1104
+ "lopebase",
1105
+ "--",
1106
+ ...argv
1107
+ ]
1108
+ },
1109
+ {
1110
+ id: "codex",
1111
+ label: "Codex",
1112
+ bin: "codex",
1113
+ args: (p) => [p],
1114
+ mcpAdd: (argv) => ["mcp", "add", "lopebase", "--", ...argv]
1115
+ },
1116
+ {
1117
+ id: "gemini",
1118
+ label: "Gemini CLI",
1119
+ bin: "gemini",
1120
+ args: (p) => ["-i", p],
1121
+ mcpAdd: (argv) => ["mcp", "add", "lopebase", ...argv]
1122
+ },
1123
+ {
1124
+ id: "opencode",
1125
+ label: "opencode",
1126
+ bin: "opencode",
1127
+ args: (p) => ["--prompt", p]
1128
+ },
1129
+ {
1130
+ id: "cursor-agent",
1131
+ label: "Cursor Agent",
1132
+ bin: "cursor-agent",
1133
+ args: (p) => [p]
1134
+ }
1135
+ ];
1136
+ function isInstalled(bin) {
1137
+ let probe = process.platform === "win32" ? "where" : "which";
1138
+ return spawnSync(probe, [bin], { stdio: "ignore" }).status === 0;
1139
+ }
1140
+ function installedAgents() {
1141
+ return AGENTS.filter((a) => isInstalled(a.bin));
1142
+ }
1143
+
1144
+ // src/config.ts
1145
+ import {
1146
+ chmodSync,
1147
+ existsSync,
1148
+ mkdirSync,
1149
+ readFileSync,
1150
+ writeFileSync
1151
+ } from "node:fs";
1152
+ import os from "node:os";
1153
+ import path from "node:path";
1154
+ var DEFAULT_URL = "https://app.lopebase.com";
1155
+ function configDir() {
1156
+ let base = process.env.XDG_CONFIG_HOME || path.join(os.homedir(), ".config");
1157
+ return path.join(base, "lopebase");
1158
+ }
1159
+ var authFile = () => path.join(configDir(), "auth.json");
1160
+ function loadAuth() {
1161
+ let envToken = process.env.LOPEBASE_TOKEN?.trim(), envUrl = process.env.LOPEBASE_URL?.trim();
1162
+ if (envToken)
1163
+ return { url: envUrl || DEFAULT_URL, token: envToken };
1164
+ if (!existsSync(authFile()))
1165
+ return null;
1166
+ try {
1167
+ let a = JSON.parse(readFileSync(authFile(), "utf8"));
1168
+ if (!a.token)
1169
+ return null;
1170
+ return { url: envUrl || a.url || DEFAULT_URL, token: a.token };
1171
+ } catch {
1172
+ return null;
1173
+ }
1174
+ }
1175
+ function saveAuth(auth) {
1176
+ return mkdirSync(configDir(), { recursive: !0, mode: 448 }), writeFileSync(authFile(), `${JSON.stringify(auth, null, 2)}
1177
+ `, {
1178
+ mode: 384
1179
+ }), chmodSync(authFile(), 384), authFile();
1180
+ }
1181
+ var mcpEndpoint = (url) => `${url.replace(/\/+$/, "")}/api/mcp`;
1182
+
1183
+ // src/detect.ts
1184
+ var APP_SIDE_ENV = /^(NEXT_PUBLIC_|PUBLIC_|VITE_|NUXT_PUBLIC_|EXPO_PUBLIC_)|_DSN$/;
1185
+ function evidenceFor(facts, rule) {
1186
+ let out = [], weak = [];
1187
+ for (let re of rule.deps ?? []) {
1188
+ let hit = facts.dependencies.find((d) => re.test(d));
1189
+ if (hit)
1190
+ out.push(`uses ${hit}`);
1191
+ }
1192
+ for (let re of rule.files ?? []) {
1193
+ let hit = facts.files.find((f) => re.test(f));
1194
+ if (hit)
1195
+ out.push(`has ${hit}`);
1196
+ }
1197
+ for (let re of rule.env ?? []) {
1198
+ let hit = facts.envKeys.find((k) => re.test(k));
1199
+ if (hit)
1200
+ (APP_SIDE_ENV.test(hit) ? out : weak).push(`env ${hit}`);
1201
+ }
1202
+ return { strong: [...new Set(out)], weak: [...new Set(weak)] };
1203
+ }
1204
+ var SOURCE_RULES = {
1205
+ posthog: {
1206
+ label: "PostHog",
1207
+ rule: { deps: [/^posthog-(js|node)$/], env: [/POSTHOG/] },
1208
+ why: "Signups, active users, and funnels on your dashboard."
1209
+ },
1210
+ ga4: {
1211
+ label: "Google Analytics",
1212
+ rule: {
1213
+ deps: [/^@next\/third-parties$/, /^react-ga4$/, /^vue-gtag/],
1214
+ env: [
1215
+ /^(NEXT_PUBLIC_|PUBLIC_|VITE_)?GA(4)?_(MEASUREMENT_)?ID$/,
1216
+ /GTM_ID/
1217
+ ]
1218
+ },
1219
+ why: "Traffic and sources on your dashboard."
1220
+ },
1221
+ sentry: {
1222
+ label: "Sentry",
1223
+ rule: {
1224
+ deps: [/^@sentry\//],
1225
+ files: [/sentry\.(client|server|edge)\.config/],
1226
+ env: [/SENTRY_DSN/]
1227
+ },
1228
+ why: "Error counts next to your traffic, so a bad deploy shows up."
1229
+ },
1230
+ stripe: {
1231
+ label: "Stripe",
1232
+ rule: { deps: [/^stripe$/, /^@stripe\//], env: [/^STRIPE_/] },
1233
+ why: "Revenue, new customers, and churn per product."
1234
+ }
1235
+ }, STACK_RULES = [
1236
+ { kind: "framework", name: "Next.js", rule: { deps: [/^next$/] } },
1237
+ { kind: "framework", name: "Astro", rule: { deps: [/^astro$/] } },
1238
+ {
1239
+ kind: "framework",
1240
+ name: "SvelteKit",
1241
+ rule: { deps: [/^@sveltejs\/kit$/] }
1242
+ },
1243
+ {
1244
+ kind: "framework",
1245
+ name: "Remix",
1246
+ rule: { deps: [/^@remix-run\//, /^react-router$/] }
1247
+ },
1248
+ { kind: "framework", name: "Nuxt", rule: { deps: [/^nuxt$/] } },
1249
+ { kind: "framework", name: "Hono", rule: { deps: [/^hono$/] } },
1250
+ {
1251
+ kind: "hosting",
1252
+ name: "Cloudflare Workers",
1253
+ rule: {
1254
+ files: [/(^|\/)wrangler\.(toml|jsonc?)$/],
1255
+ deps: [/^@opennextjs\/cloudflare$/]
1256
+ }
1257
+ },
1258
+ { kind: "hosting", name: "Vercel", rule: { files: [/(^|\/)vercel\.json$/] } },
1259
+ {
1260
+ kind: "hosting",
1261
+ name: "Netlify",
1262
+ rule: { files: [/(^|\/)netlify\.toml$/] }
1263
+ },
1264
+ { kind: "hosting", name: "Fly.io", rule: { files: [/(^|\/)fly\.toml$/] } },
1265
+ {
1266
+ kind: "database",
1267
+ name: "Supabase",
1268
+ rule: { deps: [/^@supabase\//], files: [/(^|\/)supabase\/config\.toml$/] }
1269
+ },
1270
+ {
1271
+ kind: "database",
1272
+ name: "Convex",
1273
+ rule: { deps: [/^convex$/], files: [/(^|\/)convex\/schema\.ts$/] }
1274
+ },
1275
+ {
1276
+ kind: "database",
1277
+ name: "Neon",
1278
+ rule: { deps: [/^@neondatabase\//, /^@neon\/(env|config)$/] }
1279
+ },
1280
+ {
1281
+ kind: "database",
1282
+ name: "Postgres",
1283
+ rule: { deps: [/^postgres$/, /^pg$/] }
1284
+ },
1285
+ { kind: "database", name: "Prisma", rule: { deps: [/^@prisma\/client$/] } },
1286
+ { kind: "database", name: "Drizzle", rule: { deps: [/^drizzle-orm$/] } },
1287
+ {
1288
+ kind: "database",
1289
+ name: "Cloudflare D1",
1290
+ rule: { files: [/(^|\/)wrangler\.(toml|jsonc?)#d1$/] }
1291
+ },
1292
+ {
1293
+ kind: "email",
1294
+ name: "Resend",
1295
+ rule: { deps: [/^resend$/], env: [/^RESEND_/] }
1296
+ },
1297
+ {
1298
+ kind: "billing",
1299
+ name: "Polar",
1300
+ rule: { deps: [/^@polar-sh\//], env: [/^POLAR_/] }
1301
+ },
1302
+ { kind: "auth", name: "Clerk", rule: { deps: [/^@clerk\//] } },
1303
+ { kind: "auth", name: "WorkOS", rule: { deps: [/^@workos-inc\//] } },
1304
+ { kind: "auth", name: "Better Auth", rule: { deps: [/^better-auth$/] } }
1305
+ ];
1306
+ function detectStack(facts) {
1307
+ let stack = [];
1308
+ for (let s of STACK_RULES) {
1309
+ let { strong, weak } = evidenceFor(facts, s.rule), ev = [...strong, ...weak];
1310
+ if (ev.length)
1311
+ stack.push({ kind: s.kind, name: s.name, evidence: ev[0] });
1312
+ }
1313
+ let sources = [];
1314
+ for (let [id, s] of Object.entries(SOURCE_RULES)) {
1315
+ let { strong, weak } = evidenceFor(facts, s.rule);
1316
+ if (strong.length || weak.length)
1317
+ sources.push({
1318
+ source: id,
1319
+ label: s.label,
1320
+ status: strong.length ? "found" : "possible",
1321
+ evidence: [...strong, ...weak],
1322
+ why: s.why
1323
+ });
1324
+ }
1325
+ let has = (id) => sources.some((s) => s.source === id && s.status === "found"), listed = (id) => sources.some((s) => s.source === id), isWebsite = stack.some((s) => s.kind === "framework") || !!facts.siteUrl, gaps = [];
1326
+ if (isWebsite)
1327
+ sources.push({
1328
+ source: "gsc",
1329
+ label: "Google Search Console",
1330
+ status: "suggested",
1331
+ evidence: [],
1332
+ why: "What people search to find you. No code change, only a verified domain."
1333
+ }, {
1334
+ source: "bing",
1335
+ label: "Bing Webmaster Tools",
1336
+ status: "suggested",
1337
+ evidence: [],
1338
+ why: "Bing and ChatGPT search traffic. Imports from Search Console in one click."
1339
+ });
1340
+ if (!has("posthog") && !has("ga4")) {
1341
+ if (gaps.push("No product analytics found. Add PostHog (free tier, one snippet) so LopeBase can show signups and active users."), !listed("posthog"))
1342
+ sources.push({
1343
+ source: "posthog",
1344
+ label: "PostHog",
1345
+ status: "suggested",
1346
+ evidence: [],
1347
+ why: SOURCE_RULES.posthog.why
1348
+ });
1349
+ }
1350
+ if (!has("sentry")) {
1351
+ if (gaps.push("No error tracking found. Sentry lets LopeBase flag a spike in errors after a deploy."), !listed("sentry"))
1352
+ sources.push({
1353
+ source: "sentry",
1354
+ label: "Sentry",
1355
+ status: "suggested",
1356
+ evidence: [],
1357
+ why: SOURCE_RULES.sentry.why
1358
+ });
1359
+ }
1360
+ return { stack, sources, gaps };
1361
+ }
1362
+
1363
+ // src/device-login.ts
1364
+ async function startDeviceLogin(url, opts = {}) {
1365
+ let f = opts.fetchImpl ?? fetch;
1366
+ try {
1367
+ let res = await f(`${url}/api/oauth/device`, {
1368
+ method: "POST",
1369
+ headers: { "content-type": "application/x-www-form-urlencoded" },
1370
+ body: new URLSearchParams({
1371
+ client_name: opts.clientName ?? "lopebase CLI",
1372
+ scope: opts.scope ?? "setup read"
1373
+ }).toString()
1374
+ });
1375
+ if (!res.ok)
1376
+ return null;
1377
+ let b = await res.json();
1378
+ if (typeof b.device_code !== "string" || typeof b.user_code !== "string")
1379
+ return null;
1380
+ return {
1381
+ deviceCode: b.device_code,
1382
+ userCode: b.user_code,
1383
+ verifyUrl: String(b.verification_uri_complete ?? b.verification_uri),
1384
+ interval: Number(b.interval) || 5,
1385
+ expiresIn: Number(b.expires_in) || 600
1386
+ };
1387
+ } catch {
1388
+ return null;
1389
+ }
1390
+ }
1391
+ async function pollDeviceLogin(url, start, opts = {}) {
1392
+ let f = opts.fetchImpl ?? fetch, sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms))), interval = start.interval, deadline = Date.now() + start.expiresIn * 1000;
1393
+ while (Date.now() < deadline) {
1394
+ await sleep(interval * 1000);
1395
+ let body;
1396
+ try {
1397
+ body = await (await f(`${url}/api/oauth/token`, {
1398
+ method: "POST",
1399
+ headers: { "content-type": "application/x-www-form-urlencoded" },
1400
+ body: new URLSearchParams({
1401
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
1402
+ device_code: start.deviceCode
1403
+ }).toString()
1404
+ })).json();
1405
+ } catch {
1406
+ continue;
1407
+ }
1408
+ if (typeof body.access_token === "string")
1409
+ return {
1410
+ ok: !0,
1411
+ token: body.access_token,
1412
+ url: typeof body.workspace_url === "string" ? body.workspace_url : url,
1413
+ scope: String(body.scope ?? "")
1414
+ };
1415
+ switch (body.error) {
1416
+ case "authorization_pending":
1417
+ continue;
1418
+ case "slow_down":
1419
+ interval += 5;
1420
+ continue;
1421
+ case "access_denied":
1422
+ return {
1423
+ ok: !1,
1424
+ reason: "denied",
1425
+ message: "The request was denied in the browser."
1426
+ };
1427
+ case "expired_token":
1428
+ return {
1429
+ ok: !1,
1430
+ reason: "expired",
1431
+ message: "The code expired. Run lopebase login again."
1432
+ };
1433
+ default:
1434
+ return {
1435
+ ok: !1,
1436
+ reason: "error",
1437
+ message: String(body.error_description ?? body.error ?? "Sign-in failed.")
1438
+ };
1439
+ }
1440
+ }
1441
+ return {
1442
+ ok: !1,
1443
+ reason: "expired",
1444
+ message: "The code expired. Run lopebase login again."
1445
+ };
1446
+ }
1447
+
1448
+ // src/mcp-proxy.ts
1449
+ import { createInterface as createInterface2 } from "node:readline";
1450
+ async function runMcpProxy(auth, fetchImpl = fetch) {
1451
+ let endpoint = mcpEndpoint(auth.url), write = (msg) => process.stdout.write(`${JSON.stringify(msg)}
1452
+ `), rl = createInterface2({
1453
+ input: process.stdin,
1454
+ crlfDelay: Number.POSITIVE_INFINITY
1455
+ }), pending = [];
1456
+ for await (let line of rl) {
1457
+ if (!line.trim())
1458
+ continue;
1459
+ pending.push(forward(line));
1460
+ }
1461
+ await Promise.all(pending);
1462
+ async function forward(line) {
1463
+ let id = null;
1464
+ try {
1465
+ id = JSON.parse(line).id ?? null;
1466
+ } catch {}
1467
+ try {
1468
+ let res = await fetchImpl(endpoint, {
1469
+ method: "POST",
1470
+ headers: {
1471
+ "content-type": "application/json",
1472
+ accept: "application/json, text/event-stream",
1473
+ authorization: `Bearer ${auth.token}`
1474
+ },
1475
+ body: line
1476
+ });
1477
+ if (res.status === 202)
1478
+ return;
1479
+ if (res.status === 401) {
1480
+ if (id !== null)
1481
+ write({
1482
+ jsonrpc: "2.0",
1483
+ id,
1484
+ error: {
1485
+ code: -32001,
1486
+ message: "LopeBase rejected the saved agent token (expired or revoked). Ask the human to run: npx lopebase login"
1487
+ }
1488
+ });
1489
+ return;
1490
+ }
1491
+ let text = (await res.text()).trim();
1492
+ if (!text.startsWith("{") && !text.startsWith("[")) {
1493
+ if (id !== null)
1494
+ write({
1495
+ jsonrpc: "2.0",
1496
+ id,
1497
+ error: {
1498
+ code: -32000,
1499
+ message: `No LopeBase workspace answered at ${endpoint} (HTTP ${res.status}). Check the workspace address with: npx lopebase login`
1500
+ }
1501
+ });
1502
+ return;
1503
+ }
1504
+ process.stdout.write(`${text}
1505
+ `);
1506
+ } catch (e) {
1507
+ if (id === null)
1508
+ return;
1509
+ write({
1510
+ jsonrpc: "2.0",
1511
+ id,
1512
+ error: {
1513
+ code: -32000,
1514
+ message: `Could not reach LopeBase at ${endpoint}: ${String(e)}`
1515
+ }
1516
+ });
1517
+ }
1518
+ }
1519
+ }
1520
+
1521
+ // src/prompt.ts
1522
+ function onboardingPrompt(input) {
1523
+ let { facts, detection, chosen } = input, stack = detection.stack.map((s) => `${s.name} (${s.kind})`).join(", ") || "not detected", found = detection.sources.filter((s) => s.status === "found");
1524
+ return [
1525
+ "Set up this project in LopeBase using the lopebase MCP tools.",
1526
+ "",
1527
+ "What a scan of this repo found:",
1528
+ `- Product: ${input.productName ?? facts.name ?? "unknown"}${facts.siteUrl ? ` at ${facts.siteUrl}` : ""}`,
1529
+ `- Stack: ${stack}`,
1530
+ `- Already in use: ${found.map((s) => s.label).join(", ") || "none of the sources LopeBase reads"}`,
1531
+ `- The human wants connected: ${chosen.join(", ") || "whatever get_onboarding_status recommends"}`,
1532
+ "",
1533
+ "How to work:",
1534
+ "1. Call get_onboarding_status first, and again after every step. Do the step it marks next.",
1535
+ "2. Pass the scan above to detect_stack if the product has no stack on file.",
1536
+ "3. Do the work yourself where you can: read code, install packages, run CLIs the human is signed in to (wrangler, gh, stripe, supabase), and create least-privilege keys.",
1537
+ "4. When a step needs the human (a browser sign-in, a payment, a permission, a key you cannot create), call request_human_action, tell them in one or two plain sentences what to do and why, and wait for them.",
1538
+ "5. Never print a secret in chat or write one to a tracked file. Pass keys straight to connect_source.",
1539
+ "6. For a source the project does not use yet (for example analytics), explain what it adds, ask before installing it, then add it the way this codebase does things.",
1540
+ "7. Finish when get_onboarding_status says done. Summarize what is connected and anything left for later."
1541
+ ].join(`
1542
+ `);
1543
+ }
1544
+
1545
+ // src/scan.ts
1546
+ import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync2 } from "node:fs";
1547
+ import path2 from "node:path";
1548
+ var MONOREPO_DIRS = ["apps", "packages", "services", "web", "site"], MARKER_FILES = [
1549
+ "wrangler.toml",
1550
+ "wrangler.json",
1551
+ "wrangler.jsonc",
1552
+ "vercel.json",
1553
+ "netlify.toml",
1554
+ "fly.toml",
1555
+ "supabase/config.toml",
1556
+ "convex/schema.ts",
1557
+ "sentry.client.config.ts",
1558
+ "sentry.server.config.ts",
1559
+ "sentry.edge.config.ts",
1560
+ "instrumentation.ts"
1561
+ ], EXAMPLE_ENV = [
1562
+ ".env.example",
1563
+ ".env.sample",
1564
+ ".env.template",
1565
+ ".dev.vars.example"
1566
+ ];
1567
+ function readJson(file) {
1568
+ try {
1569
+ return JSON.parse(readFileSync2(file, "utf8"));
1570
+ } catch {
1571
+ return null;
1572
+ }
1573
+ }
1574
+ function packageDirs(root) {
1575
+ let dirs = [root];
1576
+ for (let group of MONOREPO_DIRS) {
1577
+ let g = path2.join(root, group);
1578
+ if (!existsSync2(g))
1579
+ continue;
1580
+ if (existsSync2(path2.join(g, "package.json")))
1581
+ dirs.push(g);
1582
+ try {
1583
+ for (let entry of readdirSync(g, { withFileTypes: !0 }))
1584
+ if (entry.isDirectory() && existsSync2(path2.join(g, entry.name, "package.json")))
1585
+ dirs.push(path2.join(g, entry.name));
1586
+ } catch {}
1587
+ }
1588
+ return dirs;
1589
+ }
1590
+ function siteFromWrangler(text) {
1591
+ let first = [
1592
+ ...text.matchAll(/(?:pattern|route)["']?\s*[:=]\s*["']([^"'*/\s]+)/g),
1593
+ ...text.matchAll(/custom_domain["']?\s*[:=]\s*["']([^"'*/\s]+)/g)
1594
+ ].map((m) => m[1].toLowerCase()).filter((h) => h.includes(".") && !h.endsWith("workers.dev"))[0];
1595
+ if (!first)
1596
+ return;
1597
+ return `https://${first.replace(/^(app|www|api|console)\./, "")}`;
1598
+ }
1599
+ function envKeyNames(text) {
1600
+ let out = [];
1601
+ for (let line of text.split(/\r?\n/)) {
1602
+ let m = /^\s*(?:#\s*)?(?:export\s+)?([A-Z][A-Z0-9_]*)\s*=/.exec(line);
1603
+ if (m)
1604
+ out.push(m[1]);
1605
+ }
1606
+ return out;
1607
+ }
1608
+ function scanProject(root) {
1609
+ let deps = /* @__PURE__ */ new Set, files = /* @__PURE__ */ new Set, envKeys = /* @__PURE__ */ new Set, name, siteUrl;
1610
+ for (let dir of packageDirs(root)) {
1611
+ let rel = (f) => path2.relative(root, path2.join(dir, f)) || f, pkg = readJson(path2.join(dir, "package.json"));
1612
+ if (pkg) {
1613
+ if (dir === root && typeof pkg.name === "string")
1614
+ name = pkg.name;
1615
+ if (!siteUrl && typeof pkg.homepage === "string")
1616
+ siteUrl = pkg.homepage;
1617
+ for (let k of ["dependencies", "devDependencies"]) {
1618
+ let d = pkg[k];
1619
+ if (d && typeof d === "object")
1620
+ for (let n of Object.keys(d))
1621
+ deps.add(n);
1622
+ }
1623
+ }
1624
+ for (let f of MARKER_FILES) {
1625
+ if (!existsSync2(path2.join(dir, f)))
1626
+ continue;
1627
+ if (files.add(rel(f)), f.startsWith("wrangler."))
1628
+ try {
1629
+ let text = readFileSync2(path2.join(dir, f), "utf8");
1630
+ if (/d1_databases/.test(text))
1631
+ files.add(`${rel(f)}#d1`);
1632
+ if (!siteUrl)
1633
+ siteUrl = siteFromWrangler(text);
1634
+ } catch {}
1635
+ }
1636
+ for (let f of EXAMPLE_ENV)
1637
+ try {
1638
+ for (let k of envKeyNames(readFileSync2(path2.join(dir, f), "utf8")))
1639
+ envKeys.add(k);
1640
+ } catch {}
1641
+ }
1642
+ return {
1643
+ name,
1644
+ siteUrl,
1645
+ dependencies: [...deps].sort(),
1646
+ files: [...files].sort(),
1647
+ envKeys: [...envKeys].sort()
1648
+ };
1649
+ }
1650
+
1651
+ // bin/lopebase.ts
1652
+ var [command = "init", ...rest] = process.argv.slice(2), HELP = `
1653
+ ${import_picocolors3.default.bgYellow(import_picocolors3.default.black(" LopeBase "))} Set up LopeBase from this project's folder.
1654
+
1655
+ ${import_picocolors3.default.bold("Usage")}
1656
+ npx lopebase scan, connect, and hand over to your agent
1657
+ npx lopebase login connect this computer (--paste for a token)
1658
+ npx lopebase scan [--json] show what the scan found
1659
+ npx lopebase prompt print the setup prompt instead
1660
+ npx lopebase mcp run the LopeBase tools as a stdio MCP server
1661
+ npx lopebase adapter secret print a new @lopebase/adapter signing secret
1662
+ npx lopebase adapter check <url> test a running adapter (reads LOPEBASE_SIGNING_SECRET)
1663
+
1664
+ ${import_picocolors3.default.bold("Learn more")}
1665
+ ${import_picocolors3.default.cyan("https://lopebase.com")}
1666
+ Help: contact@jackalope.digital
1667
+ `, flag = (name) => rest.includes(`--${name}`), option = (name) => {
1668
+ let i = rest.indexOf(`--${name}`);
1669
+ return i >= 0 ? rest[i + 1] : rest.find((a) => a.startsWith(`--${name}=`))?.split("=")[1];
1670
+ }, cwd = process.cwd();
1671
+ function bail(message) {
1672
+ xe(message), process.exit(1);
1673
+ }
1674
+ function guard(value) {
1675
+ if (pD(value))
1676
+ bail("Stopped. Run lopebase again any time.");
1677
+ return value;
1678
+ }
1679
+ function openBrowser(url) {
1680
+ let cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
1681
+ spawn(cmd, [url], { stdio: "ignore", detached: !0 }).unref();
1682
+ }
1683
+ async function checkToken(auth) {
1684
+ try {
1685
+ let res = await fetch(mcpEndpoint(auth.url), {
1686
+ method: "POST",
1687
+ headers: {
1688
+ "content-type": "application/json",
1689
+ authorization: `Bearer ${auth.token}`
1690
+ },
1691
+ body: JSON.stringify({
1692
+ jsonrpc: "2.0",
1693
+ id: 1,
1694
+ method: "tools/call",
1695
+ params: { name: "list_products", arguments: {} }
1696
+ })
1697
+ });
1698
+ if (res.status === 401)
1699
+ return { ok: !1, message: "That token is not valid or has expired." };
1700
+ let body = await res.json();
1701
+ return { ok: !0, products: JSON.parse(body.result?.content?.[0]?.text ?? "[]").length };
1702
+ } catch (e) {
1703
+ return {
1704
+ ok: !1,
1705
+ message: `Could not reach ${auth.url} (${String(e)}).`
1706
+ };
1707
+ }
1708
+ }
1709
+ async function login() {
1710
+ let url = guard(await he({
1711
+ message: "Your LopeBase workspace address",
1712
+ placeholder: "https://yourteam.lopebase.com",
1713
+ initialValue: option("url") ?? loadAuth()?.url ?? DEFAULT_URL,
1714
+ validate: (v) => /^https?:\/\/\S+$/.test(v ?? "") ? void 0 : "Starts with https://"
1715
+ })).replace(/\/+$/, "");
1716
+ if (!flag("paste")) {
1717
+ let device = await startDeviceLogin(url);
1718
+ if (device) {
1719
+ Me([
1720
+ `Your code: ${import_picocolors3.default.bold(import_picocolors3.default.yellow(device.userCode))}`,
1721
+ "",
1722
+ "We opened your workspace in the browser. Sign in if asked,",
1723
+ "check the code matches, and press Connect."
1724
+ ].join(`
1725
+ `), "Connect this computer"), openBrowser(device.verifyUrl), M2.info(import_picocolors3.default.dim(device.verifyUrl));
1726
+ let s = Y2();
1727
+ s.start("Waiting for you to approve in the browser");
1728
+ let res = await pollDeviceLogin(url, device);
1729
+ if (res.ok) {
1730
+ let file = saveAuth({ url: res.url, token: res.token });
1731
+ return s.stop(`Connected (${res.scope}). Saved to ${import_picocolors3.default.dim(file)}`), { url: res.url, token: res.token };
1732
+ }
1733
+ if (s.stop(import_picocolors3.default.red(res.message)), res.reason === "denied")
1734
+ bail("Nothing was connected.");
1735
+ M2.warn("Falling back to pasting a token.");
1736
+ }
1737
+ }
1738
+ return pasteLogin(url);
1739
+ }
1740
+ async function pasteLogin(url) {
1741
+ let settings = `${url}/settings#agent-access`;
1742
+ Me([
1743
+ "1. Sign in (or sign up) in the browser tab we open.",
1744
+ `2. Under Settings, Agent access, press ${import_picocolors3.default.bold("Create agent access")}.`,
1745
+ "3. Copy the token and paste it here. It is saved on this computer only."
1746
+ ].join(`
1747
+ `), "Get an agent token"), openBrowser(settings), M2.info(import_picocolors3.default.dim(settings));
1748
+ for (;; ) {
1749
+ let token = guard(await ge({
1750
+ message: "Paste the agent token",
1751
+ validate: (v) => v?.startsWith("lb_agent_") ? void 0 : "Tokens start with lb_agent_"
1752
+ })).trim(), s = Y2();
1753
+ s.start("Checking the token");
1754
+ let check = await checkToken({ url, token });
1755
+ if (check.ok) {
1756
+ let file = saveAuth({ url, token });
1757
+ return s.stop(`Signed in. ${check.products} product(s) in this workspace. Saved to ${import_picocolors3.default.dim(file)}`), { url, token };
1758
+ }
1759
+ s.stop(import_picocolors3.default.red(check.message ?? "That did not work."));
1760
+ }
1761
+ }
1762
+ function printDetection(d) {
1763
+ let stack = d.stack.map((s) => `${import_picocolors3.default.bold(s.name)} ${import_picocolors3.default.dim(s.kind)}`).join(`
1764
+ `) || import_picocolors3.default.dim("Nothing recognised");
1765
+ Me(stack, "Your stack");
1766
+ let found = d.sources.filter((s) => s.status === "found");
1767
+ if (found.length)
1768
+ Me(found.map((s) => `${import_picocolors3.default.green("●")} ${import_picocolors3.default.bold(s.label)} ${import_picocolors3.default.dim(s.evidence.join(", "))}`).join(`
1769
+ `), "Already in your code, ready to connect");
1770
+ let possible = d.sources.filter((s) => s.status === "possible");
1771
+ if (possible.length)
1772
+ Me(possible.map((s) => `${import_picocolors3.default.yellow("?")} ${import_picocolors3.default.bold(s.label)} ${import_picocolors3.default.dim(`only ${s.evidence.join(", ")}`)}`).join(`
1773
+ `), "Maybe in use, your agent will check");
1774
+ for (let gap of d.gaps)
1775
+ M2.warn(gap);
1776
+ }
1777
+ function selfCommand() {
1778
+ let self = process.argv[1] ?? "";
1779
+ return self.includes("node_modules") || !self ? ["npx", "-y", "lopebase", "mcp"] : [process.execPath, self, "mcp"];
1780
+ }
1781
+ function registerMcp(agent) {
1782
+ if (!agent.mcpAdd)
1783
+ return !1;
1784
+ let argv = agent.mcpAdd(selfCommand()), res = spawnSync2(agent.bin, argv, {
1785
+ stdio: "pipe",
1786
+ cwd,
1787
+ encoding: "utf8"
1788
+ });
1789
+ return res.status === 0 || /already exists/i.test(`${res.stderr}${res.stdout}`);
1790
+ }
1791
+ async function init() {
1792
+ console.clear(), Ie(`${import_picocolors3.default.bgYellow(import_picocolors3.default.black(" LopeBase "))} set up this project`);
1793
+ let s = Y2();
1794
+ s.start("Scanning this folder");
1795
+ let facts = scanProject(cwd), detection = detectStack(facts);
1796
+ s.stop(`Scanned ${facts.dependencies.length} dependencies and ${facts.files.length} config files`), printDetection(detection);
1797
+ let auth = loadAuth() ?? await login();
1798
+ if (!(await checkToken(auth)).ok)
1799
+ M2.warn("Your saved token no longer works. Let's get a new one."), await login();
1800
+ let productName = guard(await he({
1801
+ message: "What is this product called?",
1802
+ initialValue: facts.name?.replace(/^@[^/]+\//, "") ?? ""
1803
+ })), chosen = guard(await fe({
1804
+ message: "What should we connect? (space to toggle)",
1805
+ options: detection.sources.map((src) => ({
1806
+ value: src.label,
1807
+ label: src.status === "found" ? src.label : src.status === "possible" ? `${src.label} ${import_picocolors3.default.dim("(maybe in use, we'll check)")}` : `${src.label} ${import_picocolors3.default.dim("(not set up yet, we'll help)")}`,
1808
+ hint: src.why
1809
+ })),
1810
+ initialValues: detection.sources.filter((src) => src.status === "found" || src.source === "gsc").map((src) => src.label),
1811
+ required: !1
1812
+ })), prompt = onboardingPrompt({ facts, detection, chosen, productName }), agents = installedAgents();
1813
+ if (!agents.length || flag("print")) {
1814
+ Me(prompt, "Paste this into your coding agent"), Se(`Add the MCP server first: ${import_picocolors3.default.cyan("npx lopebase mcp")} (stdio)`);
1815
+ return;
1816
+ }
1817
+ let agentId = guard(await ve({
1818
+ message: "Which agent should do the steps? It will ask you when it needs you.",
1819
+ options: [
1820
+ ...agents.map((a) => ({ value: a.id, label: a.label })),
1821
+ { value: "print", label: "None, print the prompt" }
1822
+ ]
1823
+ }));
1824
+ if (agentId === "print") {
1825
+ Me(prompt, "Paste this into your coding agent"), Se("Done.");
1826
+ return;
1827
+ }
1828
+ let agent = agents.find((a) => a.id === agentId);
1829
+ if (registerMcp(agent))
1830
+ M2.success(`Added LopeBase tools to ${agent.label} for this folder.`);
1831
+ else
1832
+ M2.warn(`Add an MCP server to ${agent.label} that runs: npx -y lopebase mcp`);
1833
+ Se(`Handing over to ${agent.label}. You stay in the loop for anything that needs you.`), spawn(agent.bin, agent.args(prompt), { stdio: "inherit", cwd }).on("exit", (code) => process.exit(code ?? 0));
1834
+ }
1835
+ async function main() {
1836
+ switch (command) {
1837
+ case "init":
1838
+ return init();
1839
+ case "login":
1840
+ return Ie(`${import_picocolors3.default.bgYellow(import_picocolors3.default.black(" LopeBase "))} sign in`), await login(), Se("Ready. Run lopebase in any project.");
1841
+ case "scan": {
1842
+ let facts = scanProject(cwd), detection = detectStack(facts);
1843
+ if (flag("json"))
1844
+ return console.log(JSON.stringify({ facts, detection }, null, 2));
1845
+ return printDetection(detection);
1846
+ }
1847
+ case "prompt": {
1848
+ let facts = scanProject(cwd), detection = detectStack(facts);
1849
+ return console.log(onboardingPrompt({ facts, detection, chosen: [] }));
1850
+ }
1851
+ case "adapter": {
1852
+ let sub = rest[0];
1853
+ if (sub === "secret")
1854
+ return process.stdout.write(`${newSigningSecret()}
1855
+ `);
1856
+ if (sub === "check" && rest[1]) {
1857
+ let envName = option("secret-env") ?? "LOPEBASE_SIGNING_SECRET", secret = process.env[envName]?.trim(), token = process.env.LOPEBASE_ADAPTER_TOKEN?.trim();
1858
+ if (!secret && !token)
1859
+ console.error(`Set ${envName} to the adapter's signing secret (or LOPEBASE_ADAPTER_TOKEN for an older bearer adapter).`), process.exit(1);
1860
+ console.log(`Checking ${rest[1]}`);
1861
+ let res = await checkAdapter({
1862
+ baseUrl: rest[1],
1863
+ secret,
1864
+ token: secret ? void 0 : token,
1865
+ log: (l) => console.log(l.startsWith("FAIL") ? import_picocolors3.default.red(l) : import_picocolors3.default.green(l))
1866
+ });
1867
+ console.log(res.failed.length ? import_picocolors3.default.red(`${res.failed.length} failed, ${res.passed} passed`) : import_picocolors3.default.green(`All ${res.passed} checks passed. Ready to connect.`)), process.exit(res.failed.length ? 1 : 0);
1868
+ }
1869
+ return console.log(`Usage:
1870
+ lopebase adapter secret print a new signing secret
1871
+ lopebase adapter check <base-url> test a running adapter (reads LOPEBASE_SIGNING_SECRET)`), process.exit(sub ? 1 : 0);
1872
+ }
1873
+ case "mcp": {
1874
+ let auth = loadAuth();
1875
+ if (!auth)
1876
+ console.error("Not signed in. Run: npx lopebase login"), process.exit(1);
1877
+ return runMcpProxy(auth);
1878
+ }
1879
+ default:
1880
+ console.log(HELP), process.exit(command === "--help" || command === "-h" || command === "help" ? 0 : 1);
1881
+ }
1882
+ }
1883
+ main();