dreamboard 0.1.7 → 0.1.8

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 (92) hide show
  1. package/LICENSE +89 -0
  2. package/NOTICE +1 -0
  3. package/README.md +22 -178
  4. package/dist/{chunk-MP7IBNWW.js → chunk-BMYC6772.js} +577 -38
  5. package/dist/chunk-BMYC6772.js.map +1 -0
  6. package/dist/chunk-D4HDZEJT.js +37 -0
  7. package/dist/chunk-EM7NOFFC.js +19072 -0
  8. package/dist/chunk-EM7NOFFC.js.map +1 -0
  9. package/dist/chunk-SET56RVA.js +435 -0
  10. package/dist/chunk-SET56RVA.js.map +1 -0
  11. package/dist/{dist-B3R64F6G.js → dist-WJRJNFLI.js} +3 -3
  12. package/dist/global-config-VQJZ3JOA.js +15 -0
  13. package/dist/global-config-VQJZ3JOA.js.map +1 -0
  14. package/dist/index.js +23993 -24387
  15. package/dist/index.js.map +1 -1
  16. package/dist/keychain-backend-2DL3C6BS.js +125 -0
  17. package/dist/keychain-backend-2DL3C6BS.js.map +1 -0
  18. package/dist/{prompt-GMZABCJC.js → prompt-IV67HSPU.js} +2 -2
  19. package/dist/scaffold/assets/static/app/tsconfig.framework.json +24 -0
  20. package/dist/scaffold/assets/static/app/tsconfig.json +3 -0
  21. package/dist/scaffold/assets/static/ui/App.tsx +22 -0
  22. package/dist/scaffold/assets/static/ui/index.tsx +12 -0
  23. package/dist/scaffold/assets/static/ui/style.css +4 -0
  24. package/dist/scaffold/assets/static/ui/tsconfig.framework.json +31 -0
  25. package/dist/scaffold/assets/static/ui/tsconfig.json +5 -0
  26. package/dist/src-K2NK3A4P.js +626 -0
  27. package/dist/src-K2NK3A4P.js.map +1 -0
  28. package/package.json +41 -4
  29. package/skills/dreamboard/SKILL.md +126 -59
  30. package/skills/dreamboard/references/authoring-lifecycle.md +102 -0
  31. package/skills/dreamboard/references/board-surfaces.md +36 -0
  32. package/skills/dreamboard/references/board-topology.md +443 -0
  33. package/skills/dreamboard/references/boards-and-topology.md +100 -0
  34. package/skills/dreamboard/references/card-actions.md +107 -0
  35. package/skills/dreamboard/references/cli.md +120 -0
  36. package/skills/dreamboard/references/core-concepts.md +514 -0
  37. package/skills/dreamboard/references/custom-renderers.md +26 -0
  38. package/skills/dreamboard/references/derived-values.md +55 -0
  39. package/skills/dreamboard/references/effects.md +111 -0
  40. package/skills/dreamboard/references/game-contract.md +89 -0
  41. package/skills/dreamboard/references/game-definition.md +89 -0
  42. package/skills/dreamboard/references/game-shell.md +80 -0
  43. package/skills/dreamboard/references/hand-surfaces.md +33 -0
  44. package/skills/dreamboard/references/index.md +112 -0
  45. package/skills/dreamboard/references/inputs-and-targets.md +160 -0
  46. package/skills/dreamboard/references/interactions.md +158 -0
  47. package/skills/dreamboard/references/manifest-fields.md +137 -0
  48. package/skills/dreamboard/references/manifest.md +81 -0
  49. package/skills/dreamboard/references/package-surfaces.md +69 -0
  50. package/skills/dreamboard/references/phases.md +145 -0
  51. package/skills/dreamboard/references/prompts-and-choices.md +55 -0
  52. package/skills/dreamboard/references/quickstart.md +71 -0
  53. package/skills/dreamboard/references/rule-authoring.md +81 -77
  54. package/skills/dreamboard/references/setup-bootstrap.md +78 -0
  55. package/skills/dreamboard/references/stages-and-zones.md +59 -0
  56. package/skills/dreamboard/references/static-views.md +67 -0
  57. package/skills/dreamboard/references/table-queries-and-ops.md +103 -0
  58. package/skills/dreamboard/references/testing-bases.md +147 -0
  59. package/skills/dreamboard/references/testing-generated-contracts.md +142 -0
  60. package/skills/dreamboard/references/testing-runtime-assertions.md +124 -0
  61. package/skills/dreamboard/references/testing-scenarios.md +148 -0
  62. package/skills/dreamboard/references/testing-ui-tests.md +174 -0
  63. package/skills/dreamboard/references/testing.md +161 -0
  64. package/skills/dreamboard/references/ui-architecture.md +137 -0
  65. package/skills/dreamboard/references/ui-components.md +34 -0
  66. package/skills/dreamboard/references/views.md +72 -0
  67. package/skills/dreamboard/references/workspace-layout.md +136 -0
  68. package/dist/chunk-2H7UOFLK.js +0 -11
  69. package/dist/chunk-MP7IBNWW.js.map +0 -1
  70. package/dist/chunk-WM7TY7DV.js +0 -2328
  71. package/dist/chunk-WM7TY7DV.js.map +0 -1
  72. package/dist/embedded-harness-IHP7A2ZX.js +0 -344
  73. package/dist/embedded-harness-IHP7A2ZX.js.map +0 -1
  74. package/skills/dreamboard/references/adversarial-testing.md +0 -113
  75. package/skills/dreamboard/references/all-players-tracking.md +0 -75
  76. package/skills/dreamboard/references/api-reference.md +0 -197
  77. package/skills/dreamboard/references/app-best-practices.md +0 -98
  78. package/skills/dreamboard/references/building-your-first-game.md +0 -49
  79. package/skills/dreamboard/references/hands-vs-decks.md +0 -124
  80. package/skills/dreamboard/references/manifest-authoring.md +0 -328
  81. package/skills/dreamboard/references/phase-handlers.md +0 -134
  82. package/skills/dreamboard/references/scenario-format.md +0 -99
  83. package/skills/dreamboard/references/test-harness.md +0 -225
  84. package/skills/dreamboard/references/ui-best-practices.md +0 -156
  85. package/skills/dreamboard/references/ui-genre-resource-management.md +0 -187
  86. package/skills/dreamboard/references/ui-genre-trick-taking.md +0 -110
  87. package/skills/dreamboard/references/ui-genre-worker-placement.md +0 -143
  88. package/skills/dreamboard/references/ui-style-guide.md +0 -54
  89. package/skills/dreamboard/scripts/events-extract.mjs +0 -218
  90. /package/dist/{chunk-2H7UOFLK.js.map → chunk-D4HDZEJT.js.map} +0 -0
  91. /package/dist/{dist-B3R64F6G.js.map → dist-WJRJNFLI.js.map} +0 -0
  92. /package/dist/{prompt-GMZABCJC.js.map → prompt-IV67HSPU.js.map} +0 -0
@@ -1,2328 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // ../../node_modules/.pnpm/consola@3.4.2/node_modules/consola/dist/core.mjs
4
- var LogLevels = {
5
- silent: Number.NEGATIVE_INFINITY,
6
- fatal: 0,
7
- error: 0,
8
- warn: 1,
9
- log: 2,
10
- info: 3,
11
- success: 3,
12
- fail: 3,
13
- ready: 3,
14
- start: 3,
15
- box: 3,
16
- debug: 4,
17
- trace: 5,
18
- verbose: Number.POSITIVE_INFINITY
19
- };
20
- var LogTypes = {
21
- // Silent
22
- silent: {
23
- level: -1
24
- },
25
- // Level 0
26
- fatal: {
27
- level: LogLevels.fatal
28
- },
29
- error: {
30
- level: LogLevels.error
31
- },
32
- // Level 1
33
- warn: {
34
- level: LogLevels.warn
35
- },
36
- // Level 2
37
- log: {
38
- level: LogLevels.log
39
- },
40
- // Level 3
41
- info: {
42
- level: LogLevels.info
43
- },
44
- success: {
45
- level: LogLevels.success
46
- },
47
- fail: {
48
- level: LogLevels.fail
49
- },
50
- ready: {
51
- level: LogLevels.info
52
- },
53
- start: {
54
- level: LogLevels.info
55
- },
56
- box: {
57
- level: LogLevels.info
58
- },
59
- // Level 4
60
- debug: {
61
- level: LogLevels.debug
62
- },
63
- // Level 5
64
- trace: {
65
- level: LogLevels.trace
66
- },
67
- // Verbose
68
- verbose: {
69
- level: LogLevels.verbose
70
- }
71
- };
72
- function isPlainObject$1(value) {
73
- if (value === null || typeof value !== "object") {
74
- return false;
75
- }
76
- const prototype = Object.getPrototypeOf(value);
77
- if (prototype !== null && prototype !== Object.prototype && Object.getPrototypeOf(prototype) !== null) {
78
- return false;
79
- }
80
- if (Symbol.iterator in value) {
81
- return false;
82
- }
83
- if (Symbol.toStringTag in value) {
84
- return Object.prototype.toString.call(value) === "[object Module]";
85
- }
86
- return true;
87
- }
88
- function _defu(baseObject, defaults, namespace = ".", merger) {
89
- if (!isPlainObject$1(defaults)) {
90
- return _defu(baseObject, {}, namespace, merger);
91
- }
92
- const object = Object.assign({}, defaults);
93
- for (const key in baseObject) {
94
- if (key === "__proto__" || key === "constructor") {
95
- continue;
96
- }
97
- const value = baseObject[key];
98
- if (value === null || value === void 0) {
99
- continue;
100
- }
101
- if (merger && merger(object, key, value, namespace)) {
102
- continue;
103
- }
104
- if (Array.isArray(value) && Array.isArray(object[key])) {
105
- object[key] = [...value, ...object[key]];
106
- } else if (isPlainObject$1(value) && isPlainObject$1(object[key])) {
107
- object[key] = _defu(
108
- value,
109
- object[key],
110
- (namespace ? `${namespace}.` : "") + key.toString(),
111
- merger
112
- );
113
- } else {
114
- object[key] = value;
115
- }
116
- }
117
- return object;
118
- }
119
- function createDefu(merger) {
120
- return (...arguments_) => (
121
- // eslint-disable-next-line unicorn/no-array-reduce
122
- arguments_.reduce((p, c2) => _defu(p, c2, "", merger), {})
123
- );
124
- }
125
- var defu = createDefu();
126
- function isPlainObject(obj) {
127
- return Object.prototype.toString.call(obj) === "[object Object]";
128
- }
129
- function isLogObj(arg) {
130
- if (!isPlainObject(arg)) {
131
- return false;
132
- }
133
- if (!arg.message && !arg.args) {
134
- return false;
135
- }
136
- if (arg.stack) {
137
- return false;
138
- }
139
- return true;
140
- }
141
- var paused = false;
142
- var queue = [];
143
- var Consola = class _Consola {
144
- options;
145
- _lastLog;
146
- _mockFn;
147
- /**
148
- * Creates an instance of Consola with specified options or defaults.
149
- *
150
- * @param {Partial<ConsolaOptions>} [options={}] - Configuration options for the Consola instance.
151
- */
152
- constructor(options = {}) {
153
- const types = options.types || LogTypes;
154
- this.options = defu(
155
- {
156
- ...options,
157
- defaults: { ...options.defaults },
158
- level: _normalizeLogLevel(options.level, types),
159
- reporters: [...options.reporters || []]
160
- },
161
- {
162
- types: LogTypes,
163
- throttle: 1e3,
164
- throttleMin: 5,
165
- formatOptions: {
166
- date: true,
167
- colors: false,
168
- compact: true
169
- }
170
- }
171
- );
172
- for (const type in types) {
173
- const defaults = {
174
- type,
175
- ...this.options.defaults,
176
- ...types[type]
177
- };
178
- this[type] = this._wrapLogFn(defaults);
179
- this[type].raw = this._wrapLogFn(
180
- defaults,
181
- true
182
- );
183
- }
184
- if (this.options.mockFn) {
185
- this.mockTypes();
186
- }
187
- this._lastLog = {};
188
- }
189
- /**
190
- * Gets the current log level of the Consola instance.
191
- *
192
- * @returns {number} The current log level.
193
- */
194
- get level() {
195
- return this.options.level;
196
- }
197
- /**
198
- * Sets the minimum log level that will be output by the instance.
199
- *
200
- * @param {number} level - The new log level to set.
201
- */
202
- set level(level) {
203
- this.options.level = _normalizeLogLevel(
204
- level,
205
- this.options.types,
206
- this.options.level
207
- );
208
- }
209
- /**
210
- * Displays a prompt to the user and returns the response.
211
- * Throw an error if `prompt` is not supported by the current configuration.
212
- *
213
- * @template T
214
- * @param {string} message - The message to display in the prompt.
215
- * @param {T} [opts] - Optional options for the prompt. See {@link PromptOptions}.
216
- * @returns {promise<T>} A promise that infer with the prompt options. See {@link PromptOptions}.
217
- */
218
- prompt(message, opts) {
219
- if (!this.options.prompt) {
220
- throw new Error("prompt is not supported!");
221
- }
222
- return this.options.prompt(message, opts);
223
- }
224
- /**
225
- * Creates a new instance of Consola, inheriting options from the current instance, with possible overrides.
226
- *
227
- * @param {Partial<ConsolaOptions>} options - Optional overrides for the new instance. See {@link ConsolaOptions}.
228
- * @returns {ConsolaInstance} A new Consola instance. See {@link ConsolaInstance}.
229
- */
230
- create(options) {
231
- const instance = new _Consola({
232
- ...this.options,
233
- ...options
234
- });
235
- if (this._mockFn) {
236
- instance.mockTypes(this._mockFn);
237
- }
238
- return instance;
239
- }
240
- /**
241
- * Creates a new Consola instance with the specified default log object properties.
242
- *
243
- * @param {InputLogObject} defaults - Default properties to include in any log from the new instance. See {@link InputLogObject}.
244
- * @returns {ConsolaInstance} A new Consola instance. See {@link ConsolaInstance}.
245
- */
246
- withDefaults(defaults) {
247
- return this.create({
248
- ...this.options,
249
- defaults: {
250
- ...this.options.defaults,
251
- ...defaults
252
- }
253
- });
254
- }
255
- /**
256
- * Creates a new Consola instance with a specified tag, which will be included in every log.
257
- *
258
- * @param {string} tag - The tag to include in each log of the new instance.
259
- * @returns {ConsolaInstance} A new Consola instance. See {@link ConsolaInstance}.
260
- */
261
- withTag(tag) {
262
- return this.withDefaults({
263
- tag: this.options.defaults.tag ? this.options.defaults.tag + ":" + tag : tag
264
- });
265
- }
266
- /**
267
- * Adds a custom reporter to the Consola instance.
268
- * Reporters will be called for each log message, depending on their implementation and log level.
269
- *
270
- * @param {ConsolaReporter} reporter - The reporter to add. See {@link ConsolaReporter}.
271
- * @returns {Consola} The current Consola instance.
272
- */
273
- addReporter(reporter) {
274
- this.options.reporters.push(reporter);
275
- return this;
276
- }
277
- /**
278
- * Removes a custom reporter from the Consola instance.
279
- * If no reporter is specified, all reporters will be removed.
280
- *
281
- * @param {ConsolaReporter} reporter - The reporter to remove. See {@link ConsolaReporter}.
282
- * @returns {Consola} The current Consola instance.
283
- */
284
- removeReporter(reporter) {
285
- if (reporter) {
286
- const i2 = this.options.reporters.indexOf(reporter);
287
- if (i2 !== -1) {
288
- return this.options.reporters.splice(i2, 1);
289
- }
290
- } else {
291
- this.options.reporters.splice(0);
292
- }
293
- return this;
294
- }
295
- /**
296
- * Replaces all reporters of the Consola instance with the specified array of reporters.
297
- *
298
- * @param {ConsolaReporter[]} reporters - The new reporters to set. See {@link ConsolaReporter}.
299
- * @returns {Consola} The current Consola instance.
300
- */
301
- setReporters(reporters) {
302
- this.options.reporters = Array.isArray(reporters) ? reporters : [reporters];
303
- return this;
304
- }
305
- wrapAll() {
306
- this.wrapConsole();
307
- this.wrapStd();
308
- }
309
- restoreAll() {
310
- this.restoreConsole();
311
- this.restoreStd();
312
- }
313
- /**
314
- * Overrides console methods with Consola logging methods for consistent logging.
315
- */
316
- wrapConsole() {
317
- for (const type in this.options.types) {
318
- if (!console["__" + type]) {
319
- console["__" + type] = console[type];
320
- }
321
- console[type] = this[type].raw;
322
- }
323
- }
324
- /**
325
- * Restores the original console methods, removing Consola overrides.
326
- */
327
- restoreConsole() {
328
- for (const type in this.options.types) {
329
- if (console["__" + type]) {
330
- console[type] = console["__" + type];
331
- delete console["__" + type];
332
- }
333
- }
334
- }
335
- /**
336
- * Overrides standard output and error streams to redirect them through Consola.
337
- */
338
- wrapStd() {
339
- this._wrapStream(this.options.stdout, "log");
340
- this._wrapStream(this.options.stderr, "log");
341
- }
342
- _wrapStream(stream, type) {
343
- if (!stream) {
344
- return;
345
- }
346
- if (!stream.__write) {
347
- stream.__write = stream.write;
348
- }
349
- stream.write = (data) => {
350
- this[type].raw(String(data).trim());
351
- };
352
- }
353
- /**
354
- * Restores the original standard output and error streams, removing the Consola redirection.
355
- */
356
- restoreStd() {
357
- this._restoreStream(this.options.stdout);
358
- this._restoreStream(this.options.stderr);
359
- }
360
- _restoreStream(stream) {
361
- if (!stream) {
362
- return;
363
- }
364
- if (stream.__write) {
365
- stream.write = stream.__write;
366
- delete stream.__write;
367
- }
368
- }
369
- /**
370
- * Pauses logging, queues incoming logs until resumed.
371
- */
372
- pauseLogs() {
373
- paused = true;
374
- }
375
- /**
376
- * Resumes logging, processing any queued logs.
377
- */
378
- resumeLogs() {
379
- paused = false;
380
- const _queue = queue.splice(0);
381
- for (const item of _queue) {
382
- item[0]._logFn(item[1], item[2]);
383
- }
384
- }
385
- /**
386
- * Replaces logging methods with mocks if a mock function is provided.
387
- *
388
- * @param {ConsolaOptions["mockFn"]} mockFn - The function to use for mocking logging methods. See {@link ConsolaOptions["mockFn"]}.
389
- */
390
- mockTypes(mockFn) {
391
- const _mockFn = mockFn || this.options.mockFn;
392
- this._mockFn = _mockFn;
393
- if (typeof _mockFn !== "function") {
394
- return;
395
- }
396
- for (const type in this.options.types) {
397
- this[type] = _mockFn(type, this.options.types[type]) || this[type];
398
- this[type].raw = this[type];
399
- }
400
- }
401
- _wrapLogFn(defaults, isRaw) {
402
- return (...args) => {
403
- if (paused) {
404
- queue.push([this, defaults, args, isRaw]);
405
- return;
406
- }
407
- return this._logFn(defaults, args, isRaw);
408
- };
409
- }
410
- _logFn(defaults, args, isRaw) {
411
- if ((defaults.level || 0) > this.level) {
412
- return false;
413
- }
414
- const logObj = {
415
- date: /* @__PURE__ */ new Date(),
416
- args: [],
417
- ...defaults,
418
- level: _normalizeLogLevel(defaults.level, this.options.types)
419
- };
420
- if (!isRaw && args.length === 1 && isLogObj(args[0])) {
421
- Object.assign(logObj, args[0]);
422
- } else {
423
- logObj.args = [...args];
424
- }
425
- if (logObj.message) {
426
- logObj.args.unshift(logObj.message);
427
- delete logObj.message;
428
- }
429
- if (logObj.additional) {
430
- if (!Array.isArray(logObj.additional)) {
431
- logObj.additional = logObj.additional.split("\n");
432
- }
433
- logObj.args.push("\n" + logObj.additional.join("\n"));
434
- delete logObj.additional;
435
- }
436
- logObj.type = typeof logObj.type === "string" ? logObj.type.toLowerCase() : "log";
437
- logObj.tag = typeof logObj.tag === "string" ? logObj.tag : "";
438
- const resolveLog = (newLog = false) => {
439
- const repeated = (this._lastLog.count || 0) - this.options.throttleMin;
440
- if (this._lastLog.object && repeated > 0) {
441
- const args2 = [...this._lastLog.object.args];
442
- if (repeated > 1) {
443
- args2.push(`(repeated ${repeated} times)`);
444
- }
445
- this._log({ ...this._lastLog.object, args: args2 });
446
- this._lastLog.count = 1;
447
- }
448
- if (newLog) {
449
- this._lastLog.object = logObj;
450
- this._log(logObj);
451
- }
452
- };
453
- clearTimeout(this._lastLog.timeout);
454
- const diffTime = this._lastLog.time && logObj.date ? logObj.date.getTime() - this._lastLog.time.getTime() : 0;
455
- this._lastLog.time = logObj.date;
456
- if (diffTime < this.options.throttle) {
457
- try {
458
- const serializedLog = JSON.stringify([
459
- logObj.type,
460
- logObj.tag,
461
- logObj.args
462
- ]);
463
- const isSameLog = this._lastLog.serialized === serializedLog;
464
- this._lastLog.serialized = serializedLog;
465
- if (isSameLog) {
466
- this._lastLog.count = (this._lastLog.count || 0) + 1;
467
- if (this._lastLog.count > this.options.throttleMin) {
468
- this._lastLog.timeout = setTimeout(
469
- resolveLog,
470
- this.options.throttle
471
- );
472
- return;
473
- }
474
- }
475
- } catch {
476
- }
477
- }
478
- resolveLog(true);
479
- }
480
- _log(logObj) {
481
- for (const reporter of this.options.reporters) {
482
- reporter.log(logObj, {
483
- options: this.options
484
- });
485
- }
486
- }
487
- };
488
- function _normalizeLogLevel(input, types = {}, defaultLevel = 3) {
489
- if (input === void 0) {
490
- return defaultLevel;
491
- }
492
- if (typeof input === "number") {
493
- return input;
494
- }
495
- if (types[input] && types[input].level !== void 0) {
496
- return types[input].level;
497
- }
498
- return defaultLevel;
499
- }
500
- Consola.prototype.add = Consola.prototype.addReporter;
501
- Consola.prototype.remove = Consola.prototype.removeReporter;
502
- Consola.prototype.clear = Consola.prototype.removeReporter;
503
- Consola.prototype.withScope = Consola.prototype.withTag;
504
- Consola.prototype.mock = Consola.prototype.mockTypes;
505
- Consola.prototype.pause = Consola.prototype.pauseLogs;
506
- Consola.prototype.resume = Consola.prototype.resumeLogs;
507
- function createConsola(options = {}) {
508
- return new Consola(options);
509
- }
510
-
511
- // ../../node_modules/.pnpm/consola@3.4.2/node_modules/consola/dist/shared/consola.DRwqZj3T.mjs
512
- import { formatWithOptions } from "util";
513
- import { sep } from "path";
514
- function parseStack(stack, message) {
515
- const cwd = process.cwd() + sep;
516
- const lines = stack.split("\n").splice(message.split("\n").length).map((l2) => l2.trim().replace("file://", "").replace(cwd, ""));
517
- return lines;
518
- }
519
- function writeStream(data, stream) {
520
- const write = stream.__write || stream.write;
521
- return write.call(stream, data);
522
- }
523
- var bracket = (x) => x ? `[${x}]` : "";
524
- var BasicReporter = class {
525
- formatStack(stack, message, opts) {
526
- const indent = " ".repeat((opts?.errorLevel || 0) + 1);
527
- return indent + parseStack(stack, message).join(`
528
- ${indent}`);
529
- }
530
- formatError(err, opts) {
531
- const message = err.message ?? formatWithOptions(opts, err);
532
- const stack = err.stack ? this.formatStack(err.stack, message, opts) : "";
533
- const level = opts?.errorLevel || 0;
534
- const causedPrefix = level > 0 ? `${" ".repeat(level)}[cause]: ` : "";
535
- const causedError = err.cause ? "\n\n" + this.formatError(err.cause, { ...opts, errorLevel: level + 1 }) : "";
536
- return causedPrefix + message + "\n" + stack + causedError;
537
- }
538
- formatArgs(args, opts) {
539
- const _args = args.map((arg) => {
540
- if (arg && typeof arg.stack === "string") {
541
- return this.formatError(arg, opts);
542
- }
543
- return arg;
544
- });
545
- return formatWithOptions(opts, ..._args);
546
- }
547
- formatDate(date, opts) {
548
- return opts.date ? date.toLocaleTimeString() : "";
549
- }
550
- filterAndJoin(arr) {
551
- return arr.filter(Boolean).join(" ");
552
- }
553
- formatLogObj(logObj, opts) {
554
- const message = this.formatArgs(logObj.args, opts);
555
- if (logObj.type === "box") {
556
- return "\n" + [
557
- bracket(logObj.tag),
558
- logObj.title && logObj.title,
559
- ...message.split("\n")
560
- ].filter(Boolean).map((l2) => " > " + l2).join("\n") + "\n";
561
- }
562
- return this.filterAndJoin([
563
- bracket(logObj.type),
564
- bracket(logObj.tag),
565
- message
566
- ]);
567
- }
568
- log(logObj, ctx) {
569
- const line = this.formatLogObj(logObj, {
570
- columns: ctx.options.stdout.columns || 0,
571
- ...ctx.options.formatOptions
572
- });
573
- return writeStream(
574
- line + "\n",
575
- logObj.level < 2 ? ctx.options.stderr || process.stderr : ctx.options.stdout || process.stdout
576
- );
577
- }
578
- };
579
-
580
- // ../../node_modules/.pnpm/consola@3.4.2/node_modules/consola/dist/index.mjs
581
- import g$1 from "process";
582
-
583
- // ../../node_modules/.pnpm/consola@3.4.2/node_modules/consola/dist/shared/consola.DXBYu-KD.mjs
584
- import * as tty from "tty";
585
- var {
586
- env = {},
587
- argv = [],
588
- platform = ""
589
- } = typeof process === "undefined" ? {} : process;
590
- var isDisabled = "NO_COLOR" in env || argv.includes("--no-color");
591
- var isForced = "FORCE_COLOR" in env || argv.includes("--color");
592
- var isWindows = platform === "win32";
593
- var isDumbTerminal = env.TERM === "dumb";
594
- var isCompatibleTerminal = tty && tty.isatty && tty.isatty(1) && env.TERM && !isDumbTerminal;
595
- var isCI = "CI" in env && ("GITHUB_ACTIONS" in env || "GITLAB_CI" in env || "CIRCLECI" in env);
596
- var isColorSupported = !isDisabled && (isForced || isWindows && !isDumbTerminal || isCompatibleTerminal || isCI);
597
- function replaceClose(index, string, close, replace, head = string.slice(0, Math.max(0, index)) + replace, tail = string.slice(Math.max(0, index + close.length)), next = tail.indexOf(close)) {
598
- return head + (next < 0 ? tail : replaceClose(next, tail, close, replace));
599
- }
600
- function clearBleed(index, string, open, close, replace) {
601
- return index < 0 ? open + string + close : open + replaceClose(index, string, close, replace) + close;
602
- }
603
- function filterEmpty(open, close, replace = open, at = open.length + 1) {
604
- return (string) => string || !(string === "" || string === void 0) ? clearBleed(
605
- ("" + string).indexOf(close, at),
606
- string,
607
- open,
608
- close,
609
- replace
610
- ) : "";
611
- }
612
- function init(open, close, replace) {
613
- return filterEmpty(`\x1B[${open}m`, `\x1B[${close}m`, replace);
614
- }
615
- var colorDefs = {
616
- reset: init(0, 0),
617
- bold: init(1, 22, "\x1B[22m\x1B[1m"),
618
- dim: init(2, 22, "\x1B[22m\x1B[2m"),
619
- italic: init(3, 23),
620
- underline: init(4, 24),
621
- inverse: init(7, 27),
622
- hidden: init(8, 28),
623
- strikethrough: init(9, 29),
624
- black: init(30, 39),
625
- red: init(31, 39),
626
- green: init(32, 39),
627
- yellow: init(33, 39),
628
- blue: init(34, 39),
629
- magenta: init(35, 39),
630
- cyan: init(36, 39),
631
- white: init(37, 39),
632
- gray: init(90, 39),
633
- bgBlack: init(40, 49),
634
- bgRed: init(41, 49),
635
- bgGreen: init(42, 49),
636
- bgYellow: init(43, 49),
637
- bgBlue: init(44, 49),
638
- bgMagenta: init(45, 49),
639
- bgCyan: init(46, 49),
640
- bgWhite: init(47, 49),
641
- blackBright: init(90, 39),
642
- redBright: init(91, 39),
643
- greenBright: init(92, 39),
644
- yellowBright: init(93, 39),
645
- blueBright: init(94, 39),
646
- magentaBright: init(95, 39),
647
- cyanBright: init(96, 39),
648
- whiteBright: init(97, 39),
649
- bgBlackBright: init(100, 49),
650
- bgRedBright: init(101, 49),
651
- bgGreenBright: init(102, 49),
652
- bgYellowBright: init(103, 49),
653
- bgBlueBright: init(104, 49),
654
- bgMagentaBright: init(105, 49),
655
- bgCyanBright: init(106, 49),
656
- bgWhiteBright: init(107, 49)
657
- };
658
- function createColors(useColor = isColorSupported) {
659
- return useColor ? colorDefs : Object.fromEntries(Object.keys(colorDefs).map((key) => [key, String]));
660
- }
661
- var colors = createColors();
662
- function getColor(color, fallback = "reset") {
663
- return colors[color] || colors[fallback];
664
- }
665
- var ansiRegex = [
666
- String.raw`[\u001B\u009B][[\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\d\/#&.:=?%@~_]+)*|[a-zA-Z\d]+(?:;[-a-zA-Z\d\/#&.:=?%@~_]*)*)?\u0007)`,
667
- String.raw`(?:(?:\d{1,4}(?:;\d{0,4})*)?[\dA-PR-TZcf-nq-uy=><~]))`
668
- ].join("|");
669
- function stripAnsi(text) {
670
- return text.replace(new RegExp(ansiRegex, "g"), "");
671
- }
672
- var boxStylePresets = {
673
- solid: {
674
- tl: "\u250C",
675
- tr: "\u2510",
676
- bl: "\u2514",
677
- br: "\u2518",
678
- h: "\u2500",
679
- v: "\u2502"
680
- },
681
- double: {
682
- tl: "\u2554",
683
- tr: "\u2557",
684
- bl: "\u255A",
685
- br: "\u255D",
686
- h: "\u2550",
687
- v: "\u2551"
688
- },
689
- doubleSingle: {
690
- tl: "\u2553",
691
- tr: "\u2556",
692
- bl: "\u2559",
693
- br: "\u255C",
694
- h: "\u2500",
695
- v: "\u2551"
696
- },
697
- doubleSingleRounded: {
698
- tl: "\u256D",
699
- tr: "\u256E",
700
- bl: "\u2570",
701
- br: "\u256F",
702
- h: "\u2500",
703
- v: "\u2551"
704
- },
705
- singleThick: {
706
- tl: "\u250F",
707
- tr: "\u2513",
708
- bl: "\u2517",
709
- br: "\u251B",
710
- h: "\u2501",
711
- v: "\u2503"
712
- },
713
- singleDouble: {
714
- tl: "\u2552",
715
- tr: "\u2555",
716
- bl: "\u2558",
717
- br: "\u255B",
718
- h: "\u2550",
719
- v: "\u2502"
720
- },
721
- singleDoubleRounded: {
722
- tl: "\u256D",
723
- tr: "\u256E",
724
- bl: "\u2570",
725
- br: "\u256F",
726
- h: "\u2550",
727
- v: "\u2502"
728
- },
729
- rounded: {
730
- tl: "\u256D",
731
- tr: "\u256E",
732
- bl: "\u2570",
733
- br: "\u256F",
734
- h: "\u2500",
735
- v: "\u2502"
736
- }
737
- };
738
- var defaultStyle = {
739
- borderColor: "white",
740
- borderStyle: "rounded",
741
- valign: "center",
742
- padding: 2,
743
- marginLeft: 1,
744
- marginTop: 1,
745
- marginBottom: 1
746
- };
747
- function box(text, _opts = {}) {
748
- const opts = {
749
- ..._opts,
750
- style: {
751
- ...defaultStyle,
752
- ..._opts.style
753
- }
754
- };
755
- const textLines = text.split("\n");
756
- const boxLines = [];
757
- const _color = getColor(opts.style.borderColor);
758
- const borderStyle = {
759
- ...typeof opts.style.borderStyle === "string" ? boxStylePresets[opts.style.borderStyle] || boxStylePresets.solid : opts.style.borderStyle
760
- };
761
- if (_color) {
762
- for (const key in borderStyle) {
763
- borderStyle[key] = _color(
764
- borderStyle[key]
765
- );
766
- }
767
- }
768
- const paddingOffset = opts.style.padding % 2 === 0 ? opts.style.padding : opts.style.padding + 1;
769
- const height = textLines.length + paddingOffset;
770
- const width = Math.max(
771
- ...textLines.map((line) => stripAnsi(line).length),
772
- opts.title ? stripAnsi(opts.title).length : 0
773
- ) + paddingOffset;
774
- const widthOffset = width + paddingOffset;
775
- const leftSpace = opts.style.marginLeft > 0 ? " ".repeat(opts.style.marginLeft) : "";
776
- if (opts.style.marginTop > 0) {
777
- boxLines.push("".repeat(opts.style.marginTop));
778
- }
779
- if (opts.title) {
780
- const title = _color ? _color(opts.title) : opts.title;
781
- const left = borderStyle.h.repeat(
782
- Math.floor((width - stripAnsi(opts.title).length) / 2)
783
- );
784
- const right = borderStyle.h.repeat(
785
- width - stripAnsi(opts.title).length - stripAnsi(left).length + paddingOffset
786
- );
787
- boxLines.push(
788
- `${leftSpace}${borderStyle.tl}${left}${title}${right}${borderStyle.tr}`
789
- );
790
- } else {
791
- boxLines.push(
792
- `${leftSpace}${borderStyle.tl}${borderStyle.h.repeat(widthOffset)}${borderStyle.tr}`
793
- );
794
- }
795
- const valignOffset = opts.style.valign === "center" ? Math.floor((height - textLines.length) / 2) : opts.style.valign === "top" ? height - textLines.length - paddingOffset : height - textLines.length;
796
- for (let i2 = 0; i2 < height; i2++) {
797
- if (i2 < valignOffset || i2 >= valignOffset + textLines.length) {
798
- boxLines.push(
799
- `${leftSpace}${borderStyle.v}${" ".repeat(widthOffset)}${borderStyle.v}`
800
- );
801
- } else {
802
- const line = textLines[i2 - valignOffset];
803
- const left = " ".repeat(paddingOffset);
804
- const right = " ".repeat(width - stripAnsi(line).length);
805
- boxLines.push(
806
- `${leftSpace}${borderStyle.v}${left}${line}${right}${borderStyle.v}`
807
- );
808
- }
809
- }
810
- boxLines.push(
811
- `${leftSpace}${borderStyle.bl}${borderStyle.h.repeat(widthOffset)}${borderStyle.br}`
812
- );
813
- if (opts.style.marginBottom > 0) {
814
- boxLines.push("".repeat(opts.style.marginBottom));
815
- }
816
- return boxLines.join("\n");
817
- }
818
-
819
- // ../../node_modules/.pnpm/consola@3.4.2/node_modules/consola/dist/index.mjs
820
- import "util";
821
- import "path";
822
- import "tty";
823
- var r = /* @__PURE__ */ Object.create(null);
824
- var i = (e) => globalThis.process?.env || import.meta.env || globalThis.Deno?.env.toObject() || globalThis.__env__ || (e ? r : globalThis);
825
- var o = new Proxy(r, { get(e, s2) {
826
- return i()[s2] ?? r[s2];
827
- }, has(e, s2) {
828
- const E = i();
829
- return s2 in E || s2 in r;
830
- }, set(e, s2, E) {
831
- const B = i(true);
832
- return B[s2] = E, true;
833
- }, deleteProperty(e, s2) {
834
- if (!s2) return false;
835
- const E = i(true);
836
- return delete E[s2], true;
837
- }, ownKeys() {
838
- const e = i(true);
839
- return Object.keys(e);
840
- } });
841
- var t = typeof process < "u" && process.env && process.env.NODE_ENV || "";
842
- var f = [["APPVEYOR"], ["AWS_AMPLIFY", "AWS_APP_ID", { ci: true }], ["AZURE_PIPELINES", "SYSTEM_TEAMFOUNDATIONCOLLECTIONURI"], ["AZURE_STATIC", "INPUT_AZURE_STATIC_WEB_APPS_API_TOKEN"], ["APPCIRCLE", "AC_APPCIRCLE"], ["BAMBOO", "bamboo_planKey"], ["BITBUCKET", "BITBUCKET_COMMIT"], ["BITRISE", "BITRISE_IO"], ["BUDDY", "BUDDY_WORKSPACE_ID"], ["BUILDKITE"], ["CIRCLE", "CIRCLECI"], ["CIRRUS", "CIRRUS_CI"], ["CLOUDFLARE_PAGES", "CF_PAGES", { ci: true }], ["CODEBUILD", "CODEBUILD_BUILD_ARN"], ["CODEFRESH", "CF_BUILD_ID"], ["DRONE"], ["DRONE", "DRONE_BUILD_EVENT"], ["DSARI"], ["GITHUB_ACTIONS"], ["GITLAB", "GITLAB_CI"], ["GITLAB", "CI_MERGE_REQUEST_ID"], ["GOCD", "GO_PIPELINE_LABEL"], ["LAYERCI"], ["HUDSON", "HUDSON_URL"], ["JENKINS", "JENKINS_URL"], ["MAGNUM"], ["NETLIFY"], ["NETLIFY", "NETLIFY_LOCAL", { ci: false }], ["NEVERCODE"], ["RENDER"], ["SAIL", "SAILCI"], ["SEMAPHORE"], ["SCREWDRIVER"], ["SHIPPABLE"], ["SOLANO", "TDDIUM"], ["STRIDER"], ["TEAMCITY", "TEAMCITY_VERSION"], ["TRAVIS"], ["VERCEL", "NOW_BUILDER"], ["VERCEL", "VERCEL", { ci: false }], ["VERCEL", "VERCEL_ENV", { ci: false }], ["APPCENTER", "APPCENTER_BUILD_ID"], ["CODESANDBOX", "CODESANDBOX_SSE", { ci: false }], ["CODESANDBOX", "CODESANDBOX_HOST", { ci: false }], ["STACKBLITZ"], ["STORMKIT"], ["CLEAVR"], ["ZEABUR"], ["CODESPHERE", "CODESPHERE_APP_ID", { ci: true }], ["RAILWAY", "RAILWAY_PROJECT_ID"], ["RAILWAY", "RAILWAY_SERVICE_ID"], ["DENO-DEPLOY", "DENO_DEPLOYMENT_ID"], ["FIREBASE_APP_HOSTING", "FIREBASE_APP_HOSTING", { ci: true }]];
843
- function b() {
844
- if (globalThis.process?.env) for (const e of f) {
845
- const s2 = e[1] || e[0];
846
- if (globalThis.process?.env[s2]) return { name: e[0].toLowerCase(), ...e[2] };
847
- }
848
- return globalThis.process?.env?.SHELL === "/bin/jsh" && globalThis.process?.versions?.webcontainer ? { name: "stackblitz", ci: false } : { name: "", ci: false };
849
- }
850
- var l = b();
851
- l.name;
852
- function n(e) {
853
- return e ? e !== "false" : false;
854
- }
855
- var I = globalThis.process?.platform || "";
856
- var T = n(o.CI) || l.ci !== false;
857
- var a = n(globalThis.process?.stdout && globalThis.process?.stdout.isTTY);
858
- var g = n(o.DEBUG);
859
- var R = t === "test" || n(o.TEST);
860
- n(o.MINIMAL) || T || R || !a;
861
- var A = /^win/i.test(I);
862
- !n(o.NO_COLOR) && (n(o.FORCE_COLOR) || (a || A) && o.TERM !== "dumb" || T);
863
- var C = (globalThis.process?.versions?.node || "").replace(/^v/, "") || null;
864
- Number(C?.split(".")[0]) || null;
865
- var y = globalThis.process || /* @__PURE__ */ Object.create(null);
866
- var _ = { versions: {} };
867
- new Proxy(y, { get(e, s2) {
868
- if (s2 === "env") return o;
869
- if (s2 in e) return e[s2];
870
- if (s2 in _) return _[s2];
871
- } });
872
- var c = globalThis.process?.release?.name === "node";
873
- var O = !!globalThis.Bun || !!globalThis.process?.versions?.bun;
874
- var D = !!globalThis.Deno;
875
- var L = !!globalThis.fastly;
876
- var S = !!globalThis.Netlify;
877
- var u = !!globalThis.EdgeRuntime;
878
- var N = globalThis.navigator?.userAgent === "Cloudflare-Workers";
879
- var F = [[S, "netlify"], [u, "edge-light"], [N, "workerd"], [L, "fastly"], [D, "deno"], [O, "bun"], [c, "node"]];
880
- function G() {
881
- const e = F.find((s2) => s2[0]);
882
- if (e) return { name: e[1] };
883
- }
884
- var P = G();
885
- P?.name || "";
886
- function ansiRegex2({ onlyFirst = false } = {}) {
887
- const ST = "(?:\\u0007|\\u001B\\u005C|\\u009C)";
888
- const pattern = [
889
- `[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?${ST})`,
890
- "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"
891
- ].join("|");
892
- return new RegExp(pattern, onlyFirst ? void 0 : "g");
893
- }
894
- var regex = ansiRegex2();
895
- function stripAnsi2(string) {
896
- if (typeof string !== "string") {
897
- throw new TypeError(`Expected a \`string\`, got \`${typeof string}\``);
898
- }
899
- return string.replace(regex, "");
900
- }
901
- function isAmbiguous(x) {
902
- return x === 161 || x === 164 || x === 167 || x === 168 || x === 170 || x === 173 || x === 174 || x >= 176 && x <= 180 || x >= 182 && x <= 186 || x >= 188 && x <= 191 || x === 198 || x === 208 || x === 215 || x === 216 || x >= 222 && x <= 225 || x === 230 || x >= 232 && x <= 234 || x === 236 || x === 237 || x === 240 || x === 242 || x === 243 || x >= 247 && x <= 250 || x === 252 || x === 254 || x === 257 || x === 273 || x === 275 || x === 283 || x === 294 || x === 295 || x === 299 || x >= 305 && x <= 307 || x === 312 || x >= 319 && x <= 322 || x === 324 || x >= 328 && x <= 331 || x === 333 || x === 338 || x === 339 || x === 358 || x === 359 || x === 363 || x === 462 || x === 464 || x === 466 || x === 468 || x === 470 || x === 472 || x === 474 || x === 476 || x === 593 || x === 609 || x === 708 || x === 711 || x >= 713 && x <= 715 || x === 717 || x === 720 || x >= 728 && x <= 731 || x === 733 || x === 735 || x >= 768 && x <= 879 || x >= 913 && x <= 929 || x >= 931 && x <= 937 || x >= 945 && x <= 961 || x >= 963 && x <= 969 || x === 1025 || x >= 1040 && x <= 1103 || x === 1105 || x === 8208 || x >= 8211 && x <= 8214 || x === 8216 || x === 8217 || x === 8220 || x === 8221 || x >= 8224 && x <= 8226 || x >= 8228 && x <= 8231 || x === 8240 || x === 8242 || x === 8243 || x === 8245 || x === 8251 || x === 8254 || x === 8308 || x === 8319 || x >= 8321 && x <= 8324 || x === 8364 || x === 8451 || x === 8453 || x === 8457 || x === 8467 || x === 8470 || x === 8481 || x === 8482 || x === 8486 || x === 8491 || x === 8531 || x === 8532 || x >= 8539 && x <= 8542 || x >= 8544 && x <= 8555 || x >= 8560 && x <= 8569 || x === 8585 || x >= 8592 && x <= 8601 || x === 8632 || x === 8633 || x === 8658 || x === 8660 || x === 8679 || x === 8704 || x === 8706 || x === 8707 || x === 8711 || x === 8712 || x === 8715 || x === 8719 || x === 8721 || x === 8725 || x === 8730 || x >= 8733 && x <= 8736 || x === 8739 || x === 8741 || x >= 8743 && x <= 8748 || x === 8750 || x >= 8756 && x <= 8759 || x === 8764 || x === 8765 || x === 8776 || x === 8780 || x === 8786 || x === 8800 || x === 8801 || x >= 8804 && x <= 8807 || x === 8810 || x === 8811 || x === 8814 || x === 8815 || x === 8834 || x === 8835 || x === 8838 || x === 8839 || x === 8853 || x === 8857 || x === 8869 || x === 8895 || x === 8978 || x >= 9312 && x <= 9449 || x >= 9451 && x <= 9547 || x >= 9552 && x <= 9587 || x >= 9600 && x <= 9615 || x >= 9618 && x <= 9621 || x === 9632 || x === 9633 || x >= 9635 && x <= 9641 || x === 9650 || x === 9651 || x === 9654 || x === 9655 || x === 9660 || x === 9661 || x === 9664 || x === 9665 || x >= 9670 && x <= 9672 || x === 9675 || x >= 9678 && x <= 9681 || x >= 9698 && x <= 9701 || x === 9711 || x === 9733 || x === 9734 || x === 9737 || x === 9742 || x === 9743 || x === 9756 || x === 9758 || x === 9792 || x === 9794 || x === 9824 || x === 9825 || x >= 9827 && x <= 9829 || x >= 9831 && x <= 9834 || x === 9836 || x === 9837 || x === 9839 || x === 9886 || x === 9887 || x === 9919 || x >= 9926 && x <= 9933 || x >= 9935 && x <= 9939 || x >= 9941 && x <= 9953 || x === 9955 || x === 9960 || x === 9961 || x >= 9963 && x <= 9969 || x === 9972 || x >= 9974 && x <= 9977 || x === 9979 || x === 9980 || x === 9982 || x === 9983 || x === 10045 || x >= 10102 && x <= 10111 || x >= 11094 && x <= 11097 || x >= 12872 && x <= 12879 || x >= 57344 && x <= 63743 || x >= 65024 && x <= 65039 || x === 65533 || x >= 127232 && x <= 127242 || x >= 127248 && x <= 127277 || x >= 127280 && x <= 127337 || x >= 127344 && x <= 127373 || x === 127375 || x === 127376 || x >= 127387 && x <= 127404 || x >= 917760 && x <= 917999 || x >= 983040 && x <= 1048573 || x >= 1048576 && x <= 1114109;
903
- }
904
- function isFullWidth(x) {
905
- return x === 12288 || x >= 65281 && x <= 65376 || x >= 65504 && x <= 65510;
906
- }
907
- function isWide(x) {
908
- return x >= 4352 && x <= 4447 || x === 8986 || x === 8987 || x === 9001 || x === 9002 || x >= 9193 && x <= 9196 || x === 9200 || x === 9203 || x === 9725 || x === 9726 || x === 9748 || x === 9749 || x >= 9776 && x <= 9783 || x >= 9800 && x <= 9811 || x === 9855 || x >= 9866 && x <= 9871 || x === 9875 || x === 9889 || x === 9898 || x === 9899 || x === 9917 || x === 9918 || x === 9924 || x === 9925 || x === 9934 || x === 9940 || x === 9962 || x === 9970 || x === 9971 || x === 9973 || x === 9978 || x === 9981 || x === 9989 || x === 9994 || x === 9995 || x === 10024 || x === 10060 || x === 10062 || x >= 10067 && x <= 10069 || x === 10071 || x >= 10133 && x <= 10135 || x === 10160 || x === 10175 || x === 11035 || x === 11036 || x === 11088 || x === 11093 || x >= 11904 && x <= 11929 || x >= 11931 && x <= 12019 || x >= 12032 && x <= 12245 || x >= 12272 && x <= 12287 || x >= 12289 && x <= 12350 || x >= 12353 && x <= 12438 || x >= 12441 && x <= 12543 || x >= 12549 && x <= 12591 || x >= 12593 && x <= 12686 || x >= 12688 && x <= 12773 || x >= 12783 && x <= 12830 || x >= 12832 && x <= 12871 || x >= 12880 && x <= 42124 || x >= 42128 && x <= 42182 || x >= 43360 && x <= 43388 || x >= 44032 && x <= 55203 || x >= 63744 && x <= 64255 || x >= 65040 && x <= 65049 || x >= 65072 && x <= 65106 || x >= 65108 && x <= 65126 || x >= 65128 && x <= 65131 || x >= 94176 && x <= 94180 || x === 94192 || x === 94193 || x >= 94208 && x <= 100343 || x >= 100352 && x <= 101589 || x >= 101631 && x <= 101640 || x >= 110576 && x <= 110579 || x >= 110581 && x <= 110587 || x === 110589 || x === 110590 || x >= 110592 && x <= 110882 || x === 110898 || x >= 110928 && x <= 110930 || x === 110933 || x >= 110948 && x <= 110951 || x >= 110960 && x <= 111355 || x >= 119552 && x <= 119638 || x >= 119648 && x <= 119670 || x === 126980 || x === 127183 || x === 127374 || x >= 127377 && x <= 127386 || x >= 127488 && x <= 127490 || x >= 127504 && x <= 127547 || x >= 127552 && x <= 127560 || x === 127568 || x === 127569 || x >= 127584 && x <= 127589 || x >= 127744 && x <= 127776 || x >= 127789 && x <= 127797 || x >= 127799 && x <= 127868 || x >= 127870 && x <= 127891 || x >= 127904 && x <= 127946 || x >= 127951 && x <= 127955 || x >= 127968 && x <= 127984 || x === 127988 || x >= 127992 && x <= 128062 || x === 128064 || x >= 128066 && x <= 128252 || x >= 128255 && x <= 128317 || x >= 128331 && x <= 128334 || x >= 128336 && x <= 128359 || x === 128378 || x === 128405 || x === 128406 || x === 128420 || x >= 128507 && x <= 128591 || x >= 128640 && x <= 128709 || x === 128716 || x >= 128720 && x <= 128722 || x >= 128725 && x <= 128727 || x >= 128732 && x <= 128735 || x === 128747 || x === 128748 || x >= 128756 && x <= 128764 || x >= 128992 && x <= 129003 || x === 129008 || x >= 129292 && x <= 129338 || x >= 129340 && x <= 129349 || x >= 129351 && x <= 129535 || x >= 129648 && x <= 129660 || x >= 129664 && x <= 129673 || x >= 129679 && x <= 129734 || x >= 129742 && x <= 129756 || x >= 129759 && x <= 129769 || x >= 129776 && x <= 129784 || x >= 131072 && x <= 196605 || x >= 196608 && x <= 262141;
909
- }
910
- function validate(codePoint) {
911
- if (!Number.isSafeInteger(codePoint)) {
912
- throw new TypeError(`Expected a code point, got \`${typeof codePoint}\`.`);
913
- }
914
- }
915
- function eastAsianWidth(codePoint, { ambiguousAsWide = false } = {}) {
916
- validate(codePoint);
917
- if (isFullWidth(codePoint) || isWide(codePoint) || ambiguousAsWide && isAmbiguous(codePoint)) {
918
- return 2;
919
- }
920
- return 1;
921
- }
922
- var emojiRegex = () => {
923
- return /[#*0-9]\uFE0F?\u20E3|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26AA\u26B0\u26B1\u26BD\u26BE\u26C4\u26C8\u26CF\u26D1\u26E9\u26F0-\u26F5\u26F7\u26F8\u26FA\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B55\u3030\u303D\u3297\u3299]\uFE0F?|[\u261D\u270C\u270D](?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?|[\u270A\u270B](?:\uD83C[\uDFFB-\uDFFF])?|[\u23E9-\u23EC\u23F0\u23F3\u25FD\u2693\u26A1\u26AB\u26C5\u26CE\u26D4\u26EA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2795-\u2797\u27B0\u27BF\u2B50]|\u26D3\uFE0F?(?:\u200D\uD83D\uDCA5)?|\u26F9(?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?(?:\u200D[\u2640\u2642]\uFE0F?)?|\u2764\uFE0F?(?:\u200D(?:\uD83D\uDD25|\uD83E\uDE79))?|\uD83C(?:[\uDC04\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]\uFE0F?|[\uDF85\uDFC2\uDFC7](?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC4\uDFCA](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDFCB\uDFCC](?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF43\uDF45-\uDF4A\uDF4C-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF7\uDDFA-\uDDFF]|\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF]|\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uDDFC\uD83C[\uDDEB\uDDF8]|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C[\uDDEA\uDDF9]|\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uDF44(?:\u200D\uD83D\uDFEB)?|\uDF4B(?:\u200D\uD83D\uDFE9)?|\uDFC3(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?|\uDFF3\uFE0F?(?:\u200D(?:\u26A7\uFE0F?|\uD83C\uDF08))?|\uDFF4(?:\u200D\u2620\uFE0F?|\uDB40\uDC67\uDB40\uDC62\uDB40(?:\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDC73\uDB40\uDC63\uDB40\uDC74|\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F)?)|\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?|[\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](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4\uDEB5](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD74\uDD90](?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?|[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC25\uDC27-\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-\uDE41\uDE43\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEDC-\uDEDF\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB\uDFF0]|\uDC08(?:\u200D\u2B1B)?|\uDC15(?:\u200D\uD83E\uDDBA)?|\uDC26(?:\u200D(?:\u2B1B|\uD83D\uDD25))?|\uDC3B(?:\u200D\u2744\uFE0F?)?|\uDC41\uFE0F?(?:\u200D\uD83D\uDDE8\uFE0F?)?|\uDC68(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDC68\uDC69]\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE])))?))?|\uDC69(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?[\uDC68\uDC69]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|\uDC69\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?))|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFE])))?))?|\uDC6F(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDD75(?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDE2E(?:\u200D\uD83D\uDCA8)?|\uDE35(?:\u200D\uD83D\uDCAB)?|\uDE36(?:\u200D\uD83C\uDF2B\uFE0F?)?|\uDE42(?:\u200D[\u2194\u2195]\uFE0F?)?|\uDEB6(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?)|\uD83E(?:[\uDD0C\uDD0F\uDD18-\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5\uDEC3-\uDEC5\uDEF0\uDEF2-\uDEF8](?:\uD83C[\uDFFB-\uDFFF])?|[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD\uDDCF\uDDD4\uDDD6-\uDDDD](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDDDE\uDDDF](?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD0D\uDD0E\uDD10-\uDD17\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCC\uDDD0\uDDE0-\uDDFF\uDE70-\uDE7C\uDE80-\uDE89\uDE8F-\uDEC2\uDEC6\uDECE-\uDEDC\uDEDF-\uDEE9]|\uDD3C(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF])?|\uDDCE(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?|\uDDD1(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1|\uDDD1\u200D\uD83E\uDDD2(?:\u200D\uD83E\uDDD2)?|\uDDD2(?:\u200D\uD83E\uDDD2)?))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?))?|\uDEF1(?:\uD83C(?:\uDFFB(?:\u200D\uD83E\uDEF2\uD83C[\uDFFC-\uDFFF])?|\uDFFC(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFD-\uDFFF])?|\uDFFD(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])?|\uDFFE(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFD\uDFFF])?|\uDFFF(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFE])?))?)/g;
924
- };
925
- var segmenter = globalThis.Intl?.Segmenter ? new Intl.Segmenter() : { segment: (str) => str.split("") };
926
- var defaultIgnorableCodePointRegex = new RegExp("^\\p{Default_Ignorable_Code_Point}$", "u");
927
- function stringWidth$1(string, options = {}) {
928
- if (typeof string !== "string" || string.length === 0) {
929
- return 0;
930
- }
931
- const {
932
- ambiguousIsNarrow = true,
933
- countAnsiEscapeCodes = false
934
- } = options;
935
- if (!countAnsiEscapeCodes) {
936
- string = stripAnsi2(string);
937
- }
938
- if (string.length === 0) {
939
- return 0;
940
- }
941
- let width = 0;
942
- const eastAsianWidthOptions = { ambiguousAsWide: !ambiguousIsNarrow };
943
- for (const { segment: character } of segmenter.segment(string)) {
944
- const codePoint = character.codePointAt(0);
945
- if (codePoint <= 31 || codePoint >= 127 && codePoint <= 159) {
946
- continue;
947
- }
948
- if (codePoint >= 8203 && codePoint <= 8207 || codePoint === 65279) {
949
- continue;
950
- }
951
- if (codePoint >= 768 && codePoint <= 879 || codePoint >= 6832 && codePoint <= 6911 || codePoint >= 7616 && codePoint <= 7679 || codePoint >= 8400 && codePoint <= 8447 || codePoint >= 65056 && codePoint <= 65071) {
952
- continue;
953
- }
954
- if (codePoint >= 55296 && codePoint <= 57343) {
955
- continue;
956
- }
957
- if (codePoint >= 65024 && codePoint <= 65039) {
958
- continue;
959
- }
960
- if (defaultIgnorableCodePointRegex.test(character)) {
961
- continue;
962
- }
963
- if (emojiRegex().test(character)) {
964
- width += 2;
965
- continue;
966
- }
967
- width += eastAsianWidth(codePoint, eastAsianWidthOptions);
968
- }
969
- return width;
970
- }
971
- function isUnicodeSupported() {
972
- const { env: env2 } = g$1;
973
- const { TERM, TERM_PROGRAM } = env2;
974
- if (g$1.platform !== "win32") {
975
- return TERM !== "linux";
976
- }
977
- return Boolean(env2.WT_SESSION) || Boolean(env2.TERMINUS_SUBLIME) || env2.ConEmuTask === "{cmd::Cmder}" || TERM_PROGRAM === "Terminus-Sublime" || TERM_PROGRAM === "vscode" || TERM === "xterm-256color" || TERM === "alacritty" || TERM === "rxvt-unicode" || TERM === "rxvt-unicode-256color" || env2.TERMINAL_EMULATOR === "JetBrains-JediTerm";
978
- }
979
- var TYPE_COLOR_MAP = {
980
- info: "cyan",
981
- fail: "red",
982
- success: "green",
983
- ready: "green",
984
- start: "magenta"
985
- };
986
- var LEVEL_COLOR_MAP = {
987
- 0: "red",
988
- 1: "yellow"
989
- };
990
- var unicode = isUnicodeSupported();
991
- var s = (c2, fallback) => unicode ? c2 : fallback;
992
- var TYPE_ICONS = {
993
- error: s("\u2716", "\xD7"),
994
- fatal: s("\u2716", "\xD7"),
995
- ready: s("\u2714", "\u221A"),
996
- warn: s("\u26A0", "\u203C"),
997
- info: s("\u2139", "i"),
998
- success: s("\u2714", "\u221A"),
999
- debug: s("\u2699", "D"),
1000
- trace: s("\u2192", "\u2192"),
1001
- fail: s("\u2716", "\xD7"),
1002
- start: s("\u25D0", "o"),
1003
- log: ""
1004
- };
1005
- function stringWidth(str) {
1006
- const hasICU = typeof Intl === "object";
1007
- if (!hasICU || !Intl.Segmenter) {
1008
- return stripAnsi(str).length;
1009
- }
1010
- return stringWidth$1(str);
1011
- }
1012
- var FancyReporter = class extends BasicReporter {
1013
- formatStack(stack, message, opts) {
1014
- const indent = " ".repeat((opts?.errorLevel || 0) + 1);
1015
- return `
1016
- ${indent}` + parseStack(stack, message).map(
1017
- (line) => " " + line.replace(/^at +/, (m) => colors.gray(m)).replace(/\((.+)\)/, (_2, m) => `(${colors.cyan(m)})`)
1018
- ).join(`
1019
- ${indent}`);
1020
- }
1021
- formatType(logObj, isBadge, opts) {
1022
- const typeColor = TYPE_COLOR_MAP[logObj.type] || LEVEL_COLOR_MAP[logObj.level] || "gray";
1023
- if (isBadge) {
1024
- return getBgColor(typeColor)(
1025
- colors.black(` ${logObj.type.toUpperCase()} `)
1026
- );
1027
- }
1028
- const _type = typeof TYPE_ICONS[logObj.type] === "string" ? TYPE_ICONS[logObj.type] : logObj.icon || logObj.type;
1029
- return _type ? getColor2(typeColor)(_type) : "";
1030
- }
1031
- formatLogObj(logObj, opts) {
1032
- const [message, ...additional] = this.formatArgs(logObj.args, opts).split(
1033
- "\n"
1034
- );
1035
- if (logObj.type === "box") {
1036
- return box(
1037
- characterFormat(
1038
- message + (additional.length > 0 ? "\n" + additional.join("\n") : "")
1039
- ),
1040
- {
1041
- title: logObj.title ? characterFormat(logObj.title) : void 0,
1042
- style: logObj.style
1043
- }
1044
- );
1045
- }
1046
- const date = this.formatDate(logObj.date, opts);
1047
- const coloredDate = date && colors.gray(date);
1048
- const isBadge = logObj.badge ?? logObj.level < 2;
1049
- const type = this.formatType(logObj, isBadge, opts);
1050
- const tag = logObj.tag ? colors.gray(logObj.tag) : "";
1051
- let line;
1052
- const left = this.filterAndJoin([type, characterFormat(message)]);
1053
- const right = this.filterAndJoin(opts.columns ? [tag, coloredDate] : [tag]);
1054
- const space = (opts.columns || 0) - stringWidth(left) - stringWidth(right) - 2;
1055
- line = space > 0 && (opts.columns || 0) >= 80 ? left + " ".repeat(space) + right : (right ? `${colors.gray(`[${right}]`)} ` : "") + left;
1056
- line += characterFormat(
1057
- additional.length > 0 ? "\n" + additional.join("\n") : ""
1058
- );
1059
- if (logObj.type === "trace") {
1060
- const _err = new Error("Trace: " + logObj.message);
1061
- line += this.formatStack(_err.stack || "", _err.message);
1062
- }
1063
- return isBadge ? "\n" + line + "\n" : line;
1064
- }
1065
- };
1066
- function characterFormat(str) {
1067
- return str.replace(/`([^`]+)`/gm, (_2, m) => colors.cyan(m)).replace(/\s+_([^_]+)_\s+/gm, (_2, m) => ` ${colors.underline(m)} `);
1068
- }
1069
- function getColor2(color = "white") {
1070
- return colors[color] || colors.white;
1071
- }
1072
- function getBgColor(color = "bgWhite") {
1073
- return colors[`bg${color[0].toUpperCase()}${color.slice(1)}`] || colors.bgWhite;
1074
- }
1075
- function createConsola2(options = {}) {
1076
- let level = _getDefaultLogLevel();
1077
- if (process.env.CONSOLA_LEVEL) {
1078
- level = Number.parseInt(process.env.CONSOLA_LEVEL) ?? level;
1079
- }
1080
- const consola2 = createConsola({
1081
- level,
1082
- defaults: { level },
1083
- stdout: process.stdout,
1084
- stderr: process.stderr,
1085
- prompt: (...args) => import("./prompt-GMZABCJC.js").then((m) => m.prompt(...args)),
1086
- reporters: options.reporters || [
1087
- options.fancy ?? !(T || R) ? new FancyReporter() : new BasicReporter()
1088
- ],
1089
- ...options
1090
- });
1091
- return consola2;
1092
- }
1093
- function _getDefaultLogLevel() {
1094
- if (g) {
1095
- return LogLevels.debug;
1096
- }
1097
- if (R) {
1098
- return LogLevels.warn;
1099
- }
1100
- return LogLevels.info;
1101
- }
1102
- var consola = createConsola2();
1103
-
1104
- // ../../packages/api-client/src/core/bodySerializer.gen.ts
1105
- var jsonBodySerializer = {
1106
- bodySerializer: (body) => JSON.stringify(
1107
- body,
1108
- (_key, value) => typeof value === "bigint" ? value.toString() : value
1109
- )
1110
- };
1111
-
1112
- // ../../packages/api-client/src/core/params.gen.ts
1113
- var extraPrefixesMap = {
1114
- $body_: "body",
1115
- $headers_: "headers",
1116
- $path_: "path",
1117
- $query_: "query"
1118
- };
1119
- var extraPrefixes = Object.entries(extraPrefixesMap);
1120
-
1121
- // ../../packages/api-client/src/core/serverSentEvents.gen.ts
1122
- var createSseClient = ({
1123
- onRequest,
1124
- onSseError,
1125
- onSseEvent,
1126
- responseTransformer,
1127
- responseValidator,
1128
- sseDefaultRetryDelay,
1129
- sseMaxRetryAttempts,
1130
- sseMaxRetryDelay,
1131
- sseSleepFn,
1132
- url,
1133
- ...options
1134
- }) => {
1135
- let lastEventId;
1136
- const sleep = sseSleepFn ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
1137
- const createStream = async function* () {
1138
- let retryDelay = sseDefaultRetryDelay ?? 3e3;
1139
- let attempt = 0;
1140
- const signal = options.signal ?? new AbortController().signal;
1141
- while (true) {
1142
- if (signal.aborted) break;
1143
- attempt++;
1144
- const headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers);
1145
- if (lastEventId !== void 0) {
1146
- headers.set("Last-Event-ID", lastEventId);
1147
- }
1148
- try {
1149
- const requestInit = {
1150
- redirect: "follow",
1151
- ...options,
1152
- body: options.serializedBody,
1153
- headers,
1154
- signal
1155
- };
1156
- let request = new Request(url, requestInit);
1157
- if (onRequest) {
1158
- request = await onRequest(url, requestInit);
1159
- }
1160
- const _fetch = options.fetch ?? globalThis.fetch;
1161
- const response = await _fetch(request);
1162
- if (!response.ok)
1163
- throw new Error(
1164
- `SSE failed: ${response.status} ${response.statusText}`
1165
- );
1166
- if (!response.body) throw new Error("No body in SSE response");
1167
- const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
1168
- let buffer = "";
1169
- const abortHandler = () => {
1170
- try {
1171
- reader.cancel();
1172
- } catch {
1173
- }
1174
- };
1175
- signal.addEventListener("abort", abortHandler);
1176
- try {
1177
- while (true) {
1178
- const { done, value } = await reader.read();
1179
- if (done) break;
1180
- buffer += value;
1181
- const chunks = buffer.split("\r\n");
1182
- buffer = chunks.pop() ?? "";
1183
- for (const chunk of chunks) {
1184
- const lines = chunk.split("\n");
1185
- const dataLines = [];
1186
- let eventName;
1187
- for (const line of lines) {
1188
- if (line.startsWith("data:")) {
1189
- dataLines.push(line.replace(/^data:\s*/, ""));
1190
- } else if (line.startsWith("event:")) {
1191
- eventName = line.replace(/^event:\s*/, "");
1192
- } else if (line.startsWith("id:")) {
1193
- lastEventId = line.replace(/^id:\s*/, "");
1194
- } else if (line.startsWith("retry:")) {
1195
- const parsed = Number.parseInt(
1196
- line.replace(/^retry:\s*/, ""),
1197
- 10
1198
- );
1199
- if (!Number.isNaN(parsed)) {
1200
- retryDelay = parsed;
1201
- }
1202
- }
1203
- }
1204
- let data;
1205
- let parsedJson = false;
1206
- if (dataLines.length) {
1207
- const rawData = dataLines.join("\n");
1208
- try {
1209
- data = JSON.parse(rawData);
1210
- parsedJson = true;
1211
- } catch {
1212
- data = rawData;
1213
- }
1214
- }
1215
- if (parsedJson) {
1216
- if (responseValidator) {
1217
- await responseValidator(data);
1218
- }
1219
- if (responseTransformer) {
1220
- data = await responseTransformer(data);
1221
- }
1222
- }
1223
- onSseEvent?.({
1224
- data,
1225
- event: eventName,
1226
- id: lastEventId,
1227
- retry: retryDelay
1228
- });
1229
- if (dataLines.length) {
1230
- yield data;
1231
- }
1232
- }
1233
- }
1234
- } finally {
1235
- signal.removeEventListener("abort", abortHandler);
1236
- reader.releaseLock();
1237
- }
1238
- break;
1239
- } catch (error) {
1240
- onSseError?.(error);
1241
- if (sseMaxRetryAttempts !== void 0 && attempt >= sseMaxRetryAttempts) {
1242
- break;
1243
- }
1244
- const backoff = Math.min(
1245
- retryDelay * 2 ** (attempt - 1),
1246
- sseMaxRetryDelay ?? 3e4
1247
- );
1248
- await sleep(backoff);
1249
- }
1250
- }
1251
- };
1252
- const stream = createStream();
1253
- return { stream };
1254
- };
1255
-
1256
- // ../../packages/api-client/src/core/pathSerializer.gen.ts
1257
- var separatorArrayExplode = (style) => {
1258
- switch (style) {
1259
- case "label":
1260
- return ".";
1261
- case "matrix":
1262
- return ";";
1263
- case "simple":
1264
- return ",";
1265
- default:
1266
- return "&";
1267
- }
1268
- };
1269
- var separatorArrayNoExplode = (style) => {
1270
- switch (style) {
1271
- case "form":
1272
- return ",";
1273
- case "pipeDelimited":
1274
- return "|";
1275
- case "spaceDelimited":
1276
- return "%20";
1277
- default:
1278
- return ",";
1279
- }
1280
- };
1281
- var separatorObjectExplode = (style) => {
1282
- switch (style) {
1283
- case "label":
1284
- return ".";
1285
- case "matrix":
1286
- return ";";
1287
- case "simple":
1288
- return ",";
1289
- default:
1290
- return "&";
1291
- }
1292
- };
1293
- var serializeArrayParam = ({
1294
- allowReserved,
1295
- explode,
1296
- name,
1297
- style,
1298
- value
1299
- }) => {
1300
- if (!explode) {
1301
- const joinedValues2 = (allowReserved ? value : value.map((v) => encodeURIComponent(v))).join(separatorArrayNoExplode(style));
1302
- switch (style) {
1303
- case "label":
1304
- return `.${joinedValues2}`;
1305
- case "matrix":
1306
- return `;${name}=${joinedValues2}`;
1307
- case "simple":
1308
- return joinedValues2;
1309
- default:
1310
- return `${name}=${joinedValues2}`;
1311
- }
1312
- }
1313
- const separator = separatorArrayExplode(style);
1314
- const joinedValues = value.map((v) => {
1315
- if (style === "label" || style === "simple") {
1316
- return allowReserved ? v : encodeURIComponent(v);
1317
- }
1318
- return serializePrimitiveParam({
1319
- allowReserved,
1320
- name,
1321
- value: v
1322
- });
1323
- }).join(separator);
1324
- return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
1325
- };
1326
- var serializePrimitiveParam = ({
1327
- allowReserved,
1328
- name,
1329
- value
1330
- }) => {
1331
- if (value === void 0 || value === null) {
1332
- return "";
1333
- }
1334
- if (typeof value === "object") {
1335
- throw new Error(
1336
- "Deeply-nested arrays/objects aren\u2019t supported. Provide your own `querySerializer()` to handle these."
1337
- );
1338
- }
1339
- return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
1340
- };
1341
- var serializeObjectParam = ({
1342
- allowReserved,
1343
- explode,
1344
- name,
1345
- style,
1346
- value,
1347
- valueOnly
1348
- }) => {
1349
- if (value instanceof Date) {
1350
- return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`;
1351
- }
1352
- if (style !== "deepObject" && !explode) {
1353
- let values = [];
1354
- Object.entries(value).forEach(([key, v]) => {
1355
- values = [
1356
- ...values,
1357
- key,
1358
- allowReserved ? v : encodeURIComponent(v)
1359
- ];
1360
- });
1361
- const joinedValues2 = values.join(",");
1362
- switch (style) {
1363
- case "form":
1364
- return `${name}=${joinedValues2}`;
1365
- case "label":
1366
- return `.${joinedValues2}`;
1367
- case "matrix":
1368
- return `;${name}=${joinedValues2}`;
1369
- default:
1370
- return joinedValues2;
1371
- }
1372
- }
1373
- const separator = separatorObjectExplode(style);
1374
- const joinedValues = Object.entries(value).map(
1375
- ([key, v]) => serializePrimitiveParam({
1376
- allowReserved,
1377
- name: style === "deepObject" ? `${name}[${key}]` : key,
1378
- value: v
1379
- })
1380
- ).join(separator);
1381
- return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
1382
- };
1383
-
1384
- // ../../packages/api-client/src/core/utils.gen.ts
1385
- var PATH_PARAM_RE = /\{[^{}]+\}/g;
1386
- var defaultPathSerializer = ({ path: path3, url: _url }) => {
1387
- let url = _url;
1388
- const matches = _url.match(PATH_PARAM_RE);
1389
- if (matches) {
1390
- for (const match of matches) {
1391
- let explode = false;
1392
- let name = match.substring(1, match.length - 1);
1393
- let style = "simple";
1394
- if (name.endsWith("*")) {
1395
- explode = true;
1396
- name = name.substring(0, name.length - 1);
1397
- }
1398
- if (name.startsWith(".")) {
1399
- name = name.substring(1);
1400
- style = "label";
1401
- } else if (name.startsWith(";")) {
1402
- name = name.substring(1);
1403
- style = "matrix";
1404
- }
1405
- const value = path3[name];
1406
- if (value === void 0 || value === null) {
1407
- continue;
1408
- }
1409
- if (Array.isArray(value)) {
1410
- url = url.replace(
1411
- match,
1412
- serializeArrayParam({ explode, name, style, value })
1413
- );
1414
- continue;
1415
- }
1416
- if (typeof value === "object") {
1417
- url = url.replace(
1418
- match,
1419
- serializeObjectParam({
1420
- explode,
1421
- name,
1422
- style,
1423
- value,
1424
- valueOnly: true
1425
- })
1426
- );
1427
- continue;
1428
- }
1429
- if (style === "matrix") {
1430
- url = url.replace(
1431
- match,
1432
- `;${serializePrimitiveParam({
1433
- name,
1434
- value
1435
- })}`
1436
- );
1437
- continue;
1438
- }
1439
- const replaceValue = encodeURIComponent(
1440
- style === "label" ? `.${value}` : value
1441
- );
1442
- url = url.replace(match, replaceValue);
1443
- }
1444
- }
1445
- return url;
1446
- };
1447
- var getUrl = ({
1448
- baseUrl,
1449
- path: path3,
1450
- query,
1451
- querySerializer,
1452
- url: _url
1453
- }) => {
1454
- const pathUrl = _url.startsWith("/") ? _url : `/${_url}`;
1455
- let url = (baseUrl ?? "") + pathUrl;
1456
- if (path3) {
1457
- url = defaultPathSerializer({ path: path3, url });
1458
- }
1459
- let search = query ? querySerializer(query) : "";
1460
- if (search.startsWith("?")) {
1461
- search = search.substring(1);
1462
- }
1463
- if (search) {
1464
- url += `?${search}`;
1465
- }
1466
- return url;
1467
- };
1468
- function getValidRequestBody(options) {
1469
- const hasBody = options.body !== void 0;
1470
- const isSerializedBody = hasBody && options.bodySerializer;
1471
- if (isSerializedBody) {
1472
- if ("serializedBody" in options) {
1473
- const hasSerializedBody = options.serializedBody !== void 0 && options.serializedBody !== "";
1474
- return hasSerializedBody ? options.serializedBody : null;
1475
- }
1476
- return options.body !== "" ? options.body : null;
1477
- }
1478
- if (hasBody) {
1479
- return options.body;
1480
- }
1481
- return void 0;
1482
- }
1483
-
1484
- // ../../packages/api-client/src/core/auth.gen.ts
1485
- var getAuthToken = async (auth, callback) => {
1486
- const token = typeof callback === "function" ? await callback(auth) : callback;
1487
- if (!token) {
1488
- return;
1489
- }
1490
- if (auth.scheme === "bearer") {
1491
- return `Bearer ${token}`;
1492
- }
1493
- if (auth.scheme === "basic") {
1494
- return `Basic ${btoa(token)}`;
1495
- }
1496
- return token;
1497
- };
1498
-
1499
- // ../../packages/api-client/src/client/utils.gen.ts
1500
- var createQuerySerializer = ({
1501
- parameters = {},
1502
- ...args
1503
- } = {}) => {
1504
- const querySerializer = (queryParams) => {
1505
- const search = [];
1506
- if (queryParams && typeof queryParams === "object") {
1507
- for (const name in queryParams) {
1508
- const value = queryParams[name];
1509
- if (value === void 0 || value === null) {
1510
- continue;
1511
- }
1512
- const options = parameters[name] || args;
1513
- if (Array.isArray(value)) {
1514
- const serializedArray = serializeArrayParam({
1515
- allowReserved: options.allowReserved,
1516
- explode: true,
1517
- name,
1518
- style: "form",
1519
- value,
1520
- ...options.array
1521
- });
1522
- if (serializedArray) search.push(serializedArray);
1523
- } else if (typeof value === "object") {
1524
- const serializedObject = serializeObjectParam({
1525
- allowReserved: options.allowReserved,
1526
- explode: true,
1527
- name,
1528
- style: "deepObject",
1529
- value,
1530
- ...options.object
1531
- });
1532
- if (serializedObject) search.push(serializedObject);
1533
- } else {
1534
- const serializedPrimitive = serializePrimitiveParam({
1535
- allowReserved: options.allowReserved,
1536
- name,
1537
- value
1538
- });
1539
- if (serializedPrimitive) search.push(serializedPrimitive);
1540
- }
1541
- }
1542
- }
1543
- return search.join("&");
1544
- };
1545
- return querySerializer;
1546
- };
1547
- var getParseAs = (contentType) => {
1548
- if (!contentType) {
1549
- return "stream";
1550
- }
1551
- const cleanContent = contentType.split(";")[0]?.trim();
1552
- if (!cleanContent) {
1553
- return;
1554
- }
1555
- if (cleanContent.startsWith("application/json") || cleanContent.endsWith("+json")) {
1556
- return "json";
1557
- }
1558
- if (cleanContent === "multipart/form-data") {
1559
- return "formData";
1560
- }
1561
- if (["application/", "audio/", "image/", "video/"].some(
1562
- (type) => cleanContent.startsWith(type)
1563
- )) {
1564
- return "blob";
1565
- }
1566
- if (cleanContent.startsWith("text/")) {
1567
- return "text";
1568
- }
1569
- return;
1570
- };
1571
- var checkForExistence = (options, name) => {
1572
- if (!name) {
1573
- return false;
1574
- }
1575
- if (options.headers.has(name) || options.query?.[name] || options.headers.get("Cookie")?.includes(`${name}=`)) {
1576
- return true;
1577
- }
1578
- return false;
1579
- };
1580
- var setAuthParams = async ({
1581
- security,
1582
- ...options
1583
- }) => {
1584
- for (const auth of security) {
1585
- if (checkForExistence(options, auth.name)) {
1586
- continue;
1587
- }
1588
- const token = await getAuthToken(auth, options.auth);
1589
- if (!token) {
1590
- continue;
1591
- }
1592
- const name = auth.name ?? "Authorization";
1593
- switch (auth.in) {
1594
- case "query":
1595
- if (!options.query) {
1596
- options.query = {};
1597
- }
1598
- options.query[name] = token;
1599
- break;
1600
- case "cookie":
1601
- options.headers.append("Cookie", `${name}=${token}`);
1602
- break;
1603
- case "header":
1604
- default:
1605
- options.headers.set(name, token);
1606
- break;
1607
- }
1608
- }
1609
- };
1610
- var buildUrl = (options) => getUrl({
1611
- baseUrl: options.baseUrl,
1612
- path: options.path,
1613
- query: options.query,
1614
- querySerializer: typeof options.querySerializer === "function" ? options.querySerializer : createQuerySerializer(options.querySerializer),
1615
- url: options.url
1616
- });
1617
- var mergeConfigs = (a2, b2) => {
1618
- const config = { ...a2, ...b2 };
1619
- if (config.baseUrl?.endsWith("/")) {
1620
- config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1);
1621
- }
1622
- config.headers = mergeHeaders(a2.headers, b2.headers);
1623
- return config;
1624
- };
1625
- var headersEntries = (headers) => {
1626
- const entries = [];
1627
- headers.forEach((value, key) => {
1628
- entries.push([key, value]);
1629
- });
1630
- return entries;
1631
- };
1632
- var mergeHeaders = (...headers) => {
1633
- const mergedHeaders = new Headers();
1634
- for (const header of headers) {
1635
- if (!header) {
1636
- continue;
1637
- }
1638
- const iterator = header instanceof Headers ? headersEntries(header) : Object.entries(header);
1639
- for (const [key, value] of iterator) {
1640
- if (value === null) {
1641
- mergedHeaders.delete(key);
1642
- } else if (Array.isArray(value)) {
1643
- for (const v of value) {
1644
- mergedHeaders.append(key, v);
1645
- }
1646
- } else if (value !== void 0) {
1647
- mergedHeaders.set(
1648
- key,
1649
- typeof value === "object" ? JSON.stringify(value) : value
1650
- );
1651
- }
1652
- }
1653
- }
1654
- return mergedHeaders;
1655
- };
1656
- var Interceptors = class {
1657
- fns = [];
1658
- clear() {
1659
- this.fns = [];
1660
- }
1661
- eject(id) {
1662
- const index = this.getInterceptorIndex(id);
1663
- if (this.fns[index]) {
1664
- this.fns[index] = null;
1665
- }
1666
- }
1667
- exists(id) {
1668
- const index = this.getInterceptorIndex(id);
1669
- return Boolean(this.fns[index]);
1670
- }
1671
- getInterceptorIndex(id) {
1672
- if (typeof id === "number") {
1673
- return this.fns[id] ? id : -1;
1674
- }
1675
- return this.fns.indexOf(id);
1676
- }
1677
- update(id, fn) {
1678
- const index = this.getInterceptorIndex(id);
1679
- if (this.fns[index]) {
1680
- this.fns[index] = fn;
1681
- return id;
1682
- }
1683
- return false;
1684
- }
1685
- use(fn) {
1686
- this.fns.push(fn);
1687
- return this.fns.length - 1;
1688
- }
1689
- };
1690
- var createInterceptors = () => ({
1691
- error: new Interceptors(),
1692
- request: new Interceptors(),
1693
- response: new Interceptors()
1694
- });
1695
- var defaultQuerySerializer = createQuerySerializer({
1696
- allowReserved: false,
1697
- array: {
1698
- explode: true,
1699
- style: "form"
1700
- },
1701
- object: {
1702
- explode: true,
1703
- style: "deepObject"
1704
- }
1705
- });
1706
- var defaultHeaders = {
1707
- "Content-Type": "application/json"
1708
- };
1709
- var createConfig = (override = {}) => ({
1710
- ...jsonBodySerializer,
1711
- headers: defaultHeaders,
1712
- parseAs: "auto",
1713
- querySerializer: defaultQuerySerializer,
1714
- ...override
1715
- });
1716
-
1717
- // ../../packages/api-client/src/client/client.gen.ts
1718
- var createClient = (config = {}) => {
1719
- let _config = mergeConfigs(createConfig(), config);
1720
- const getConfig = () => ({ ..._config });
1721
- const setConfig = (config2) => {
1722
- _config = mergeConfigs(_config, config2);
1723
- return getConfig();
1724
- };
1725
- const interceptors = createInterceptors();
1726
- const beforeRequest = async (options) => {
1727
- const opts = {
1728
- ..._config,
1729
- ...options,
1730
- fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
1731
- headers: mergeHeaders(_config.headers, options.headers),
1732
- serializedBody: void 0
1733
- };
1734
- if (opts.security) {
1735
- await setAuthParams({
1736
- ...opts,
1737
- security: opts.security
1738
- });
1739
- }
1740
- if (opts.requestValidator) {
1741
- await opts.requestValidator(opts);
1742
- }
1743
- if (opts.body !== void 0 && opts.bodySerializer) {
1744
- opts.serializedBody = opts.bodySerializer(opts.body);
1745
- }
1746
- if (opts.body === void 0 || opts.serializedBody === "") {
1747
- opts.headers.delete("Content-Type");
1748
- }
1749
- const url = buildUrl(opts);
1750
- return { opts, url };
1751
- };
1752
- const request = async (options) => {
1753
- const { opts, url } = await beforeRequest(options);
1754
- const requestInit = {
1755
- redirect: "follow",
1756
- ...opts,
1757
- body: getValidRequestBody(opts)
1758
- };
1759
- let request2 = new Request(url, requestInit);
1760
- for (const fn of interceptors.request.fns) {
1761
- if (fn) {
1762
- request2 = await fn(request2, opts);
1763
- }
1764
- }
1765
- const _fetch = opts.fetch;
1766
- let response;
1767
- try {
1768
- response = await _fetch(request2);
1769
- } catch (error2) {
1770
- let finalError2 = error2;
1771
- for (const fn of interceptors.error.fns) {
1772
- if (fn) {
1773
- finalError2 = await fn(
1774
- error2,
1775
- void 0,
1776
- request2,
1777
- opts
1778
- );
1779
- }
1780
- }
1781
- finalError2 = finalError2 || {};
1782
- if (opts.throwOnError) {
1783
- throw finalError2;
1784
- }
1785
- return opts.responseStyle === "data" ? void 0 : {
1786
- error: finalError2,
1787
- request: request2,
1788
- response: void 0
1789
- };
1790
- }
1791
- for (const fn of interceptors.response.fns) {
1792
- if (fn) {
1793
- response = await fn(response, request2, opts);
1794
- }
1795
- }
1796
- const result = {
1797
- request: request2,
1798
- response
1799
- };
1800
- if (response.ok) {
1801
- const parseAs = (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json";
1802
- if (response.status === 204 || response.headers.get("Content-Length") === "0") {
1803
- let emptyData;
1804
- switch (parseAs) {
1805
- case "arrayBuffer":
1806
- case "blob":
1807
- case "text":
1808
- emptyData = await response[parseAs]();
1809
- break;
1810
- case "formData":
1811
- emptyData = new FormData();
1812
- break;
1813
- case "stream":
1814
- emptyData = response.body;
1815
- break;
1816
- case "json":
1817
- default:
1818
- emptyData = {};
1819
- break;
1820
- }
1821
- return opts.responseStyle === "data" ? emptyData : {
1822
- data: emptyData,
1823
- ...result
1824
- };
1825
- }
1826
- let data;
1827
- switch (parseAs) {
1828
- case "arrayBuffer":
1829
- case "blob":
1830
- case "formData":
1831
- case "json":
1832
- case "text":
1833
- data = await response[parseAs]();
1834
- break;
1835
- case "stream":
1836
- return opts.responseStyle === "data" ? response.body : {
1837
- data: response.body,
1838
- ...result
1839
- };
1840
- }
1841
- if (parseAs === "json") {
1842
- if (opts.responseValidator) {
1843
- await opts.responseValidator(data);
1844
- }
1845
- if (opts.responseTransformer) {
1846
- data = await opts.responseTransformer(data);
1847
- }
1848
- }
1849
- return opts.responseStyle === "data" ? data : {
1850
- data,
1851
- ...result
1852
- };
1853
- }
1854
- const textError = await response.text();
1855
- let jsonError;
1856
- try {
1857
- jsonError = JSON.parse(textError);
1858
- } catch {
1859
- }
1860
- const error = jsonError ?? textError;
1861
- let finalError = error;
1862
- for (const fn of interceptors.error.fns) {
1863
- if (fn) {
1864
- finalError = await fn(error, response, request2, opts);
1865
- }
1866
- }
1867
- finalError = finalError || {};
1868
- if (opts.throwOnError) {
1869
- throw finalError;
1870
- }
1871
- return opts.responseStyle === "data" ? void 0 : {
1872
- error: finalError,
1873
- ...result
1874
- };
1875
- };
1876
- const makeMethodFn = (method) => (options) => request({ ...options, method });
1877
- const makeSseFn = (method) => async (options) => {
1878
- const { opts, url } = await beforeRequest(options);
1879
- return createSseClient({
1880
- ...opts,
1881
- body: opts.body,
1882
- headers: opts.headers,
1883
- method,
1884
- onRequest: async (url2, init2) => {
1885
- let request2 = new Request(url2, init2);
1886
- for (const fn of interceptors.request.fns) {
1887
- if (fn) {
1888
- request2 = await fn(request2, opts);
1889
- }
1890
- }
1891
- return request2;
1892
- },
1893
- serializedBody: getValidRequestBody(opts),
1894
- url
1895
- });
1896
- };
1897
- return {
1898
- buildUrl,
1899
- connect: makeMethodFn("CONNECT"),
1900
- delete: makeMethodFn("DELETE"),
1901
- get: makeMethodFn("GET"),
1902
- getConfig,
1903
- head: makeMethodFn("HEAD"),
1904
- interceptors,
1905
- options: makeMethodFn("OPTIONS"),
1906
- patch: makeMethodFn("PATCH"),
1907
- post: makeMethodFn("POST"),
1908
- put: makeMethodFn("PUT"),
1909
- request,
1910
- setConfig,
1911
- sse: {
1912
- connect: makeSseFn("CONNECT"),
1913
- delete: makeSseFn("DELETE"),
1914
- get: makeSseFn("GET"),
1915
- head: makeSseFn("HEAD"),
1916
- options: makeSseFn("OPTIONS"),
1917
- patch: makeSseFn("PATCH"),
1918
- post: makeSseFn("POST"),
1919
- put: makeSseFn("PUT"),
1920
- trace: makeSseFn("TRACE")
1921
- },
1922
- trace: makeMethodFn("TRACE")
1923
- };
1924
- };
1925
-
1926
- // ../../packages/api-client/src/client.gen.ts
1927
- var client = createClient(createConfig({ baseUrl: "https://dreamboard.games" }));
1928
-
1929
- // src/utils/fs.ts
1930
- import { mkdir, readFile, stat, writeFile } from "fs/promises";
1931
- import path from "path";
1932
-
1933
- // src/generated/skill-content.generated.ts
1934
- var SKILL_ASSET_FILES = {
1935
- "references/adversarial-testing.md": "# Adversarial Testing\n\nAdversarial testing uses scenario files to intentionally stress game rules, turn gating, and edge conditions.\n\nUse this guide with `dreamboard run --scenario <file>`.\n\nThis file is about adversarial coverage strategy, not JSON schema.\n\n- For the JSON step format itself, see [scenario-format.md](scenario-format.md).\n- For TypeScript regression tests, see [test-harness.md](test-harness.md).\n\n## Goals\n\n1. Validate that illegal or out-of-sequence actions are rejected.\n2. Validate that legal actions still work after edge-state pressure.\n3. Catch flaky behavior by running with deterministic seeds.\n\n## Core Workflow\n\n1. Start from a known state:\n\n```bash\ndreamboard run --new-session --seed 1337 --players <playerCount>\n```\n\n2. Inspect `.dreamboard/run/latest-your-turn.json` to identify:\n\n - Current controllable player(s)\n - Available actions and parameter shapes\n - Turn/phase context\n\n3. Write a focused scenario file that targets one adversarial behavior.\n4. Execute the scenario:\n\n```bash\ndreamboard run --players <playerCount> --scenario scenario-for-<case>.json\n```\n\n5. Validate outcomes using:\n - CLI exit result (`scenario_completed` vs `scenario_rejected`)\n - `.dreamboard/run/events.ndjson`\n - `.dreamboard/run/last-run-summary.json`\n\nFor deeper inspection, extract specific fields from events:\n\n```bash\nnode .agents/skills/dreamboard/scripts/events-extract.mjs --type ACTION_REJECTED --field message.reason\nnode .agents/skills/dreamboard/scripts/events-extract.mjs --type YOUR_TURN --field message.availableActions --limit 1\n```\n\n## Progression Strategy\n\n1. Start simple first:\n - Begin with 1-step or 2-step scenarios.\n - Use a single player (`player-1`) and one expected behavior per file.\n - Confirm your action names and parameter shapes are correct before scaling up.\n2. Then move to complex simulations:\n - Create multi-step scenarios that chain several turns.\n - Include multiple players across steps (for example `player-1`, `player-2`, `player-3`).\n - Combine normal and adversarial actions in the same flow to test resilience after state transitions.\n3. Create scenario that fully tests a round (e.g. all players played their hand, or all players placed their workers)\n4. Ensure AUTO phase transitions are correct.\n5. Keep deterministic inputs (`--new-session --seed 1337`) while increasing complexity so failures stay reproducible.\n\nBuild scenario files using the contract in [scenario-format.md](scenario-format.md), then use the patterns below to decide what to test.\n\n## Adversarial Patterns\n\nCreate one scenario per pattern so failures are easy to triage.\n\n1. Invalid parameters: missing required input, invalid enum, or out-of-range values.\n2. Wrong player: action submitted by a non-active/non-controllable player.\n3. Order violation: execute actions in a sequence that should be illegal.\n4. Resource exhaustion: repeat actions until resources/cards/slots are depleted.\n5. Duplicate or replay behavior: attempt the same step repeatedly in one turn.\n6. Boundary transitions: move through end-of-round/end-of-game boundaries and attempt one extra action.\n\n## Practical Conventions\n\n1. Keep each scenario small and single-purpose.\n2. Name files by expected behavior, for example:\n - `scenario-reject-invalid-params.json`\n - `scenario-reject-wrong-player.json`\n - `scenario-endgame-boundary.json`\n3. Prefer `--new-session --seed 1337` while authoring/debugging to avoid random drift.\n4. If turn context is missing, `dreamboard run --scenario ...` will wait for the first `YOUR_TURN` automatically.\n5. API scenarios are strict: if a step gets `ACTION_REJECTED`, the run stops with `scenario_rejected`.\n6. Use `events-extract.mjs` to quickly inspect rejection reasons, available actions, and player transitions before editing scenarios.\n\n### Error: `Card is not in your hand`\n\nWhen this rejection appears, verify the target player's hand state across turns before and after each scenario step.\n\n1. Extract rejection events first:\n\n```bash\nnode .agents/skills/dreamboard/scripts/events-extract.mjs --type ACTION_REJECTED --field message.reason\n```\n\n2. Inspect hand snapshots from turn events for the target player (example: `player-2`):\n\n```bash\nnode .agents/skills/dreamboard/scripts/events-extract.mjs --type YOUR_TURN --player player-2 --field message.gameState.hands\n```\n\n3. Compare entries by `index` in output to see how the player's hand changes between turns.\n4. Confirm the `cardId` in your scenario step exists in the target player's hand at the turn where the action is submitted.\n5. If the card disappears earlier than expected, inspect preceding steps for draws/discards/transfers that changed ownership.\n\n## Optional UI Driver\n\nUse `--scenario-driver ui` only for browser input-path coverage (click targets, interaction wiring).\nKeep most adversarial rule tests on the API driver for reliability and speed.\n",
1936
- "references/all-players-tracking.md": '# ALL_PLAYERS Phase - Tracking Who Has Acted\n\nThe engine automatically tracks action progress in `ALL_PLAYERS` (`MultiplePlayer`) phases through `ctx.phase`. Do not implement manual KV tracking for this.\n\n## Built-in phase tracking API\n\nUse `ctx.phase` in `validateAction` and `checkCompletion`:\n\n- `ctx.phase.hasPlayerActed(playerId)` - has this player already submitted an action?\n- `ctx.phase.haveAllExpectedPlayersActed()` - are all currently expected players done?\n- `ctx.phase.getPlayersStillWaiting()` - which players are still pending?\n- `ctx.phase.getExpectedPlayers()` - who is expected to act this phase?\n- `ctx.phase.getPlayersWhoActed()` - who has already acted?\n\n## Recommended pattern\n\n```typescript\nimport type { MultiplePlayerPhaseDefinition } from "../sdk/phaseHandlers";\nimport { createMultiplePlayerPhase } from "../sdk/phaseHandlers";\nimport { validationSuccess, validationError } from "../sdk/validation.js";\n\ntype PhaseAction = "revealCard";\n\nconst phaseDefinition = {\n onEnter(ctx) {\n const { state, apis } = ctx;\n apis.gameApi.setActivePlayers(state.player.getOrder());\n // No manual tracking setup required.\n },\n\n validateAction(ctx, playerId, actionType, parameters) {\n if (ctx.phase.hasPlayerActed(playerId)) {\n return validationError("already-acted", "You already acted this phase");\n }\n return validationSuccess();\n },\n\n onPlayerAction(ctx, playerId, actionType, parameters) {\n const { apis } = ctx;\n // ... process action ...\n // Engine tracking updates automatically after accepted actions.\n },\n\n checkCompletion(ctx) {\n if (ctx.phase.haveAllExpectedPlayersActed()) {\n return "nextPhase";\n }\n return null;\n },\n\n onComplete(ctx) {\n // Optional cleanup only. No action-tracking cleanup required.\n },\n\n getUIArgs(ctx, playerId) {\n return {\n waitingOn: ctx.phase.getPlayersStillWaiting(),\n };\n },\n} satisfies MultiplePlayerPhaseDefinition<"revealCards", PhaseAction>;\n\nexport const phase = createMultiplePlayerPhase(phaseDefinition);\n```\n\n## If UI needs progress data\n\n`ctx.phase` is available in app logic. For UI, pass derived values via `getUIArgs()` (for example `waitingOn`), or write explicit UI-facing values via global/player state APIs.\n\n## Checklist for ALL_PLAYERS phases\n\n1. Call `apis.gameApi.setActivePlayers(state.player.getOrder())` in `onEnter`.\n2. Block duplicate actions with `ctx.phase.hasPlayerActed(playerId)` in `validateAction`.\n3. Process each action in `onPlayerAction` without manual tracking writes.\n4. Transition from `checkCompletion` when `ctx.phase.haveAllExpectedPlayersActed()` is true.\n5. Use `ctx.phase.getPlayersStillWaiting()` / `getPlayersWhoActed()` for logs or UI args as needed.\n',
1937
- "references/api-reference.md": '# State & API Reference\n\nUse this page as a lookup while writing `app/phases/*.ts`.\n\nThis is a reference-first document, not a modeling guide. For schema design, use [manifest-authoring.md](manifest-authoring.md). For hand-vs-deck decisions, use [hands-vs-decks.md](hands-vs-decks.md).\n\n## Read APIs (`ctx.state.*`)\n\n### `state.player`\n\n| Method | Returns | Description |\n| -------------------------------------- | ------------- | ------------------------------------- |\n| `.getOrder()` | `PlayerId[]` | All players in turn order |\n| `.getCurrentIds()` | `PlayerId[]` | Currently active player IDs |\n| `.get(playerId)` | `Player` | Player data: `{ id, name, score }` |\n| `.getState(playerId)` | `PlayerState` | Player variables from manifest schema |\n| `.getHand(playerId, handId)` | `CardId[]` | Cards in a specific hand |\n| `.getAllHands(playerId)` | `CardId[]` | All cards across all hands |\n| `.isInHand(playerId, cardId, handId?)` | `boolean` | Check if card is in hand |\n| `.isActive(playerId)` | `boolean` | Is player currently active |\n\n### `state.deck`\n\n| Method | Returns | Description |\n| --------------------- | ---------------- | ---------------------- |\n| `.getCards(deckId)` | `CardId[]` | Cards in a shared deck |\n| `.getTopCard(deckId)` | `CardId \\| null` | Top card of deck |\n\n### `state.card`\n\n| Method | Returns | Description |\n| -------------------------------- | ------------------ | ---------------------------------------------------- |\n| `.get(cardId)` | `Card` | Full card data |\n| `.getProperties(cardId)` | Typed properties | Card-specific props (rank, suit, etc.) |\n| `.getLocation(cardId)` | `Location` | Where the card is (InHand, InDeck, InZone, Detached) |\n| `.getPlayedBy(cardId)` | `PlayerId \\| null` | Who played this card to a deck/zone |\n| `.getOwner(cardId)` | `PlayerId \\| null` | Card owner |\n| `.isVisibleTo(cardId, playerId)` | `boolean` | Visibility check |\n| `.getOwnedBy(playerId)` | `CardId[]` | All cards owned by player |\n\n### `state.game`\n\n| Method | Returns | Description |\n| -------------------- | ------------- | ------------------------------------- |\n| `.getGlobalState()` | `GlobalState` | Global variables from manifest schema |\n| `.getCurrentState()` | `StateName` | Current state machine state |\n\n## Mutation APIs (`ctx.apis.*`)\n\n### `apis.cardApi`\n\n| Method | Description |\n| --------------------------------------------------------------------------- | ------------------------------ |\n| `.moveCardsFromHandToDeck(playerId, handId, cardIds, deckId)` | Hand \u2192 Deck |\n| `.moveCardsFromHandToHand(fromPlayer, fromHand, toPlayer, toHand, cardIds)` | Hand \u2192 Hand |\n| `.moveCardsToPlayer(cardIds, toPlayerId, handId)` | Any \u2192 Hand |\n| `.flip(deckId, cardId)` | Flip card face up/down |\n| `.detachCard(cardId)` | Remove card from all locations |\n| `.transferOwnership(cardId, toPlayer)` | Change card owner |\n\n#### Card movement semantics\n\n- `moveCardsFromHandToHand(fromPlayer, fromHand, toPlayer, toHand, cardIds)` is **additive** at destination.\n- Destination cards are preserved; moved cards are added to the destination hand.\n- This API does **not** replace/overwrite the destination hand.\n- For pass/rotate mechanics where each player should receive exactly one other player\'s hand, avoid in-place cyclic moves. Snapshot source hands first, then move via a temporary location (or other two-phase transfer pattern).\n\n### `apis.deckApi`\n\n| Method | Description |\n| ------------------------------------------------------------- | ------------------------- |\n| `.moveCardsFromDeckToPlayer(deckId, playerId, handId, count)` | Deck \u2192 Hand (deal) |\n| `.moveCardsFromDeckToDeck(fromDeckId, toDeckId)` | Deck \u2192 Deck |\n| `.shuffle(deckId)` | Shuffle a deck |\n| `.addCards(deckId, cardIds)` | Add cards to a deck |\n| `.removeCard(deckId, cardId)` | Remove a card from a deck |\n\n### `apis.gameApi`\n\n| Method | Description |\n| ---------------------------------- | ---------------------------------------------- |\n| `.setActivePlayers(playerIds)` | Set who can act (use in ALL_PLAYERS `onEnter`) |\n| `.setNextPlayer(playerId)` | Set single active player |\n| `.advanceTurn()` | Move to next player in order |\n| `.declareWinner(playerId, reason)` | Declare game winner |\n| `.endGame()` | End the game |\n\n### `apis.globalStateApi`\n\n| Method | Description |\n| ------------------------------------- | ---------------------------- |\n| `.setGlobalState(newState)` | Replace all global variables |\n| `.setPlayerState(playerId, newState)` | Replace a player\'s variables |\n\n### `apis.kvApi`\n\nInternal-only key-value store. **UI cannot access these values.**\n\n| Method | Returns | Description |\n| ------------------ | ---------------- | ----------------------------------- |\n| `.set(key, value)` | `KvSetResult` | Store a JSON value |\n| `.get(key)` | `KvGetResult` | Read a value (`.success`, `.value`) |\n| `.delete(key)` | `KvDeleteResult` | Remove a key |\n| `.has(key)` | `boolean` | Check existence |\n| `.keys()` | `string[]` | List all keys |\n\n### `apis.resourceApi`\n\n| Method | Description |\n| ------------------------- | -------------------------- |\n| `.add(playerId, cost)` | Give resources to player |\n| `.deduct(playerId, cost)` | Take resources from player |\n\n### `apis.dieApi`\n\n| Method | Description |\n| -------------------------- | ------------------------- |\n| `.roll(dieId)` | Roll a die |\n| `.setValue(dieId, value?)` | Set die to specific value |\n\n## Typed KV Store\n\nUse `createTypedKv` from `sdk/stateApi.js` for type-safe KV access:\n\n```typescript\nimport { createTypedKv } from "../sdk/stateApi.js";\n\ninterface MyKv {\n playersActed: PlayerId[];\n roundData: { scores: number[] };\n}\n\nconst kv = createTypedKv<MyKv>(apis.kvApi);\nkv.set("playersActed", ["player-1"]); // Type-checked key and value\nconst acted = kv.get("playersActed"); // PlayerId[] | null\nkv.has("playersActed"); // boolean\nkv.delete("playersActed"); // boolean (existed)\n```\n\n## Card `playedBy` Tracking\n\nWhen cards move from a Hand to a Deck via `moveCardsFromHandToDeck()`, the engine automatically records `playedBy` on each card:\n\n```typescript\n// Move card from player\'s hand to a shared deck\napis.cardApi.moveCardsFromHandToDeck(\n playerId,\n "main-hand",\n [cardId],\n "play-area",\n);\n\n// Later, check who played a specific card\nconst whoPlayed = state.card.getPlayedBy(cardId); // PlayerId | null\n```\n\n## Location Type\n\nCards have a location discriminated union:\n\n```typescript\ntype Location =\n | { type: "Detached" }\n | {\n type: "InDeck";\n deckId: DeckId;\n playedBy: PlayerId | null;\n position: number | null;\n }\n | {\n type: "InHand";\n handId: HandId;\n playerId: PlayerId;\n position: number | null;\n }\n | {\n type: "InZone";\n zoneId: string;\n playedBy: PlayerId | null;\n position: number | null;\n };\n```\n\n## Validation Helpers\n\n```typescript\nimport { validationSuccess, validationError } from "../sdk/validation.js";\n\n// Valid action\nreturn validationSuccess();\n\n// Invalid action \u2014 errorCode should be kebab-case\nreturn validationError(\n "must-play-valid-combination",\n "You must play a valid card combination",\n);\n```\n',
1938
- "references/app-best-practices.md": '# App Best Practices\n\nUse this guide when implementing `app/phases/*.ts`.\n\nThis page is about phase logic and engine APIs. If you are still deciding the game model itself, fix `rule.md` or `manifest.json` first.\n\n## Before Writing Code\n\n1. Read `shared/manifest.ts` so you know the actual generated IDs and types.\n2. Read every file in `app/phases/` to understand the current flow.\n3. Review the generated SDK types in `app/sdk/`.\n\nIf the card model is still unclear, stop and revisit [hands-vs-decks.md](hands-vs-decks.md) and [manifest-authoring.md](manifest-authoring.md).\n\n## Core Principles\n\n1. **The app is authoritative**\n All gameplay mutations must go through `ctx.apis.*`. Do not assume the UI moved cards or tracked state correctly.\n2. **Prefer mutation results inside the current transaction**\n Values returned by mutation APIs are safer than immediately rereading `ctx.state.*`, which may still reflect the previous snapshot.\n3. **Use the right active-player API**\n Use `setActivePlayers()` for `ALL_PLAYERS` phases and `setNextPlayer()` for `SINGLE_PLAYER` phases.\n4. **All card movement goes through move APIs**\n Never hand-edit card locations in your own state.\n5. **Use generated IDs exactly**\n Deck IDs, hand IDs, resource IDs, board IDs, and action names should come from `shared/manifest.ts`.\n6. **KV is internal-only**\n `kvApi` is for app logic, not UI data. Pass UI-facing data through `getUIArgs()` or stored state.\n7. **Keep player-visible outcomes around long enough to render**\n If an `AUTO` phase resolves a trick, round, or reveal, preserve that result until the next player-facing phase can show it.\n\n## Validation\n\n- Implement `validateAction` for `SINGLE_PLAYER` and `ALL_PLAYERS` phases.\n- Return `validationSuccess()` for valid actions.\n- Return `validationError(code, message)` for invalid actions.\n- Keep error codes stable and kebab-case, for example `must-play-valid-combination`.\n\n## UI Args Contract\n\n- Define UI arg interfaces in `shared/ui-args.ts`.\n- Implement `getUIArgs(ctx, playerId)` for each player-facing phase.\n- Send only the data the UI actually needs.\n- Prefer computed values over forcing the UI to recompute them.\n\nExample:\n\n- better: `canPlayCard: boolean`\n- worse: raw state fragments that force the UI to rebuild game rules\n\n## Safety Habits\n\n- Check array length before indexing.\n- Use generated guards from `../generated/guards` for typed ID checks.\n- Avoid `any`.\n- Log compact payloads with `ctx.logger`, not giant arrays or full state dumps.\n\n## Common Patterns\n\n### Typed KV store\n\n```typescript\nimport { createTypedKv } from "../sdk/stateApi.js";\n\ninterface PhaseKv {\n playersActed: PlayerId[];\n roundNumber: number;\n}\n\nconst kv = createTypedKv<PhaseKv>(apis.kvApi);\nkv.set("playersActed", []);\nconst acted = kv.get("playersActed"); // PlayerId[] | null\n```\n\n### Card `playedBy` tracking\n\n```typescript\napis.cardApi.moveCardsFromHandToDeck(\n playerId,\n "main-hand",\n [cardId],\n "play-area",\n);\n\nconst whoPlayed = state.card.getPlayedBy(cardId); // PlayerId | null\n```\n\n### Turn advancement\n\n```typescript\nonAfterAction(ctx, playerId, actionType) {\n ctx.apis.gameApi.advanceTurn();\n},\n```\n\n### ALL_PLAYERS progress tracking\n\nUse the engine-managed helpers in [all-players-tracking.md](all-players-tracking.md) instead of building your own action-tracking store.\n',
1939
- "references/building-your-first-game.md": '# Building Your First Game\n\nUse this as the default end-to-end workflow for a new Dreamboard game. The goal is not just "something renders"; the goal is a complete, playable game with rules, app logic, UI, and tests all aligned.\n\n## Core Workflow\n\n1. Create a game: `dreamboard new <slug> --description "<<short description>>"`\n2. Author `rule.md` and `manifest.json`\n Quality bar: define the full game loop up front, including setup, turn structure, win/loss conditions, scoring, tie behavior, hidden/public information, and every player action the app must support. `manifest.json` should reflect the real player counts, entities, zones, and controls needed by the rules, not a partial guess.\n Refer to\n - [references/rule-authoring.md](rule-authoring.md),\n - [references/manifest-authoring.md](manifest-authoring.md)\n3. Run `dreamboard sync` after every manifest or rule change\n Quality bar: do this immediately after each rule or manifest edit so generated scaffold, types, and remote authored state stay in sync. Do not keep coding against stale generated files.\n4. Implement rules in `app/phases/*.ts` and UI data in `shared/ui-args.ts`\n Quality bar: every gameplay phase must be implemented end to end. Cover all rule branches, all legal player actions, all transitions, all round-resolution logic, and all game-end paths. `shared/ui-args.ts` must provide enough data for the UI to render every playable state without guessing or reconstructing hidden game logic in React.\n Refer to\n - [references/phase-handlers.md](phase-handlers.md),\n - [references/api-reference.md](api-reference.md),\n - [references/hands-vs-decks.md](hands-vs-decks.md),\n - [references/all-players-tracking.md](all-players-tracking.md),\n - [references/app-best-practices.md](app-best-practices.md)\n5. Implement UI in `ui/App.tsx` and `ui/components/*`\n Quality bar: the entire game must be playable through the UI, including setup, core turns, confirmations, resolution states, errors and disabled states, and end-of-game feedback. Follow the styling requirements in [ui-style-guide.md](ui-style-guide.md). Avoid half-finished interfaces such as raw debug JSON, missing controls, placeholder labels, or flows that require reading logs to understand what to do next.\n Refer to\n - [references/ui-best-practices.md](ui-best-practices.md)\n6. Typecheck from the game root: `npm install && npm run typecheck`\n Quality bar: typecheck must pass cleanly from the game root with no ignored errors and no dead code left behind from iteration.\n7. Compile the current authored state: `dreamboard compile`\n Quality bar: the compiled build should reflect the same rules and UI you validated locally, with no pending local-only fixes or known desync between authored files and the remote authored state.\n8. Generate deterministic bases for testing: `dreamboard test generate`\n Quality bar: regenerate bases whenever initial setup, compiled behavior, or game identity changes. The generated bases should be stable enough that regressions are easy to spot.\n9. Run regression scenarios: `dreamboard test run`\n Quality bar: cover the happy path, invalid actions, boundary conditions, phase transitions, simultaneous or multi-player interactions where relevant, and every game-ending outcome. All scenario statuses should be green.\n Refer to\n - [references/test-harness.md](test-harness.md)\n10. Validate the runtime behavior and live UI with `dreamboard run --scenario <scenario_file>` and `dreamboard run --screenshot`\n Quality bar: if Playwright is installed locally, screenshot verification is required. Confirm the UI looks complete and usable in real runtime states, including the initial view, an active turn, resolution moments, and the end-game state. Fix any broken layout, missing affordances, or styling drift before considering the game done.\n Refer to\n - [references/adversarial-testing.md](adversarial-testing.md)\n\nDo not treat UI, rules, and tests as separate finish-later tracks. A game is only complete when the authored rules, app logic, UI flow, compiled build, and regression coverage all agree on the same behavior.\n\n## What "Done" Means\n\n- App and logic are complete: all phases are implemented, all rule branches are covered, and no required gameplay path is left as a TODO or inferred only in the UI.\n- UI is complete: the full game is playable without relying on logs, debug panels, or manual backend intervention.\n- Styling is complete: the game follows [ui-style-guide.md](ui-style-guide.md) rather than shipping a generic or half-finished interface.\n- Verification is complete: typecheck passes, regression scenarios are green, and runtime screenshot verification has been performed when Playwright is available.\n',
1940
- "references/hands-vs-decks.md": '# Hands vs Decks\n\nUse this guide when you are deciding how to model a card container in `manifest.json`.\n\nDreamboard separates three ideas that are easy to blur together in tabletop rules:\n\n- `cardSets`: what cards exist\n- `decks`: shared card containers\n- `playerHandDefinitions`: per-player card containers\n\nFor the full manifest schema, see [manifest-authoring.md](manifest-authoring.md).\n\n## Quick Decision Rule\n\n1. If you are defining the cards themselves, use a `cardSet`.\n2. If the whole table shares one container, use a `deck`.\n3. If each player gets their own copy of the container, use a `playerHandDefinition`.\n\n## Canonical Meanings\n\n| Concept | Manifest key | Runtime ID | Use it for |\n| -------- | ----------------------- | ------------- | --------------------------------- |\n| Card set | `cardSets` | none directly | Card content and card schema |\n| Hand | `playerHandDefinitions` | `HandId` | Cards each player owns separately |\n| Deck | `decks` | `DeckId` | Shared piles or shared card areas |\n\n## Naming Rule\n\nUse the Dreamboard meaning, not the tabletop nickname.\n\nIf a real-world game says each player has a "deck", but each player owns a separate pile, model it as a hand.\n\nExamples:\n\n- a player\'s draw pile in War is a hand\n- a player\'s scored pile is a hand\n- the shared draw pile in Poker is a deck\n- the shared discard pile is a deck\n- a shared trick area is a deck\n\n## Common Mistakes\n\n- Do not use a deck just because cards are face-down.\n- Do not use a deck for something every player owns separately.\n- Do not use a hand for a communal area just because cards stay there for a while.\n\nVisibility is separate from ownership:\n\n- if each player has their own container, it is still a hand\n- set `visibility: "public"` if other players should be able to see that hand\n\n## Example\n\n```json\n{\n "cardSets": [\n {\n "type": "preset",\n "id": "standard_52_deck",\n "name": "Standard 52-Card Deck"\n }\n ],\n "decks": [\n {\n "id": "main-deck",\n "name": "Main Deck",\n "cardSetId": "standard_52_deck"\n },\n {\n "id": "battle-zone",\n "name": "Battle Zone",\n "cardSetId": "standard_52_deck"\n }\n ],\n "playerHandDefinitions": [\n {\n "id": "player-deck",\n "displayName": "Your Deck",\n "visibility": "ownerOnly",\n "cardSetIds": ["standard_52_deck"]\n },\n {\n "id": "won-pile",\n "displayName": "Won Cards",\n "visibility": "public",\n "cardSetIds": ["standard_52_deck"]\n }\n ]\n}\n```\n\nIn that example:\n\n- `standard_52_deck` defines the cards\n- `main-deck` and `battle-zone` are shared decks\n- `player-deck` and `won-pile` are per-player hands\n\n## Related Move APIs\n\n```typescript\n// Hand -> Deck\napis.cardApi.moveCardsFromHandToDeck(playerId, handId, cardIds, deckId);\n\n// Deck -> Hand\napis.deckApi.moveCardsFromDeckToPlayer(deckId, playerId, handId, count);\n\n// Hand -> Hand\napis.cardApi.moveCardsFromHandToHand(\n fromPlayer,\n fromHand,\n toPlayer,\n toHand,\n cardIds,\n);\n\n// Deck -> Deck\napis.deckApi.moveCardsFromDeckToDeck(fromDeckId, toDeckId);\n```\n\n## Rule Of Thumb\n\n- shared container: `deck`\n- per-player container: `playerHandDefinition`\n- card blueprint: `cardSet`\n',
1941
- "references/manifest-authoring.md": '# Manifest Authoring Guide\n\nUse this guide when editing `manifest.json`.\n\n`manifest.json` describes the runtime shape of the game:\n\n- who can play\n- what cards, resources, dice, and boards exist\n- what actions players can submit\n- what phases and stored state the engine needs\n\nKeep the full game explanation in `rule.md`. Use the manifest to turn that explanation into typed runtime data.\n\nAfter editing the manifest, run `dreamboard sync` to regenerate scaffolded files such as `shared/manifest.ts` and `app/phases/`.\n\nIf you are still deciding whether something is a hand, a deck, or a card set, read [hands-vs-decks.md](hands-vs-decks.md) alongside this guide.\n\n## Supported Top-Level Shape\n\n```json\n{\n "playerConfig": { ... },\n "cardSets": [ ... ],\n "playerHandDefinitions": [ ... ],\n "decks": [ ... ],\n "dice": [ ... ],\n "resources": [ ... ],\n "boardDefinitions": [ ... ],\n "availableActions": [ ... ],\n "stateMachine": { ... },\n "variableSchema": { ... }\n}\n```\n\n| Field | Required | Purpose |\n| ----------------------- | -------- | -------------------------------------------- |\n| `playerConfig` | \u2705 | Supported player counts |\n| `cardSets` | \u2705 | Card blueprints and card property schemas |\n| `playerHandDefinitions` | \u2705 | Per-player card containers |\n| `decks` | \u274C | Shared card containers |\n| `dice` | \u274C | Shared dice |\n| `resources` | \u274C | Typed resource economy |\n| `boardDefinitions` | \u274C | Structured boards such as hex, square, track |\n| `availableActions` | \u2705 | Player-submittable actions |\n| `stateMachine` | \u2705 | Game phases and transitions |\n| `variableSchema` | \u2705 | Global and per-player stored state |\n\n## Authoring Rules\n\n- Only use documented schema fields. If a key is not described in this guide, do not invent it in `manifest.json`.\n- Optional list fields should be omitted or set to `[]`. Do not use `null`.\n- Keep the manifest about runtime structure. Put presentation choices in UI code or `shared/ui-args.ts`.\n- There is no top-level `version` field in the manifest schema.\n- A deck entry is structural data only. Use `id`, `name`, and `cardSetId`.\n\n## Recommended Authoring Order\n\n1. Start from `rule.md`.\n2. Define the game\'s containers and content: players, card sets, hands, decks, resources, dice, and boards.\n3. Define the actions players can submit.\n4. Define the phase flow in `stateMachine`.\n5. Add only the stored state that cannot be derived from the rest of the game state.\n\n## 1. `playerConfig`\n\nUse `playerConfig` to declare the supported player counts.\n\n```json\n{\n "playerConfig": {\n "minPlayers": 2,\n "maxPlayers": 4,\n "optimalPlayers": 4\n }\n}\n```\n\n## 2. `cardSets`\n\n`cardSets` define the cards that exist in the game. They do not describe where those cards live during play.\n\nThere are two card set styles:\n\n- `preset` for built-in sets such as a standard 52-card deck\n- `manual` for authored card content and custom card schemas\n\n### Preset card set\n\n```json\n{\n "cardSets": [\n {\n "type": "preset",\n "id": "standard_52_deck",\n "name": "Standard 52-Card Deck"\n }\n ]\n}\n```\n\n### Manual card set\n\n```json\n{\n "type": "manual",\n "id": "resource-cards",\n "name": "Resource Cards",\n "cardSchema": {\n "properties": {\n "value": { "type": "integer", "description": "Point value" },\n "category": { "type": "string", "description": "Resource category" }\n }\n },\n "cards": [\n {\n "type": "lumber",\n "name": "Lumber",\n "count": 4,\n "properties": { "value": "1", "category": "wood" }\n }\n ]\n}\n```\n\nCard authoring reminders:\n\n- `type` is the manifest-level card type.\n- `count` is the number of copies to create.\n- runtime card IDs are derived from `type` and `count` (`lumber`, `lumber-2`, `lumber-3`, ...)\n- `properties` must match `cardSchema`\n- `name` and `text` are worth keeping because they help scaffolding, debugging, and agent reasoning\n\n## 3. `playerHandDefinitions`\n\nEach `playerHandDefinition` creates one container per player.\n\nUse a hand for anything each player owns separately, even if the tabletop rules call it a "deck", "reserve", or "scored pile".\n\n```json\n{\n "playerHandDefinitions": [\n {\n "id": "main-hand",\n "displayName": "Hand",\n "visibility": "ownerOnly",\n "maxCards": 7,\n "cardSetIds": ["standard_52_deck"]\n }\n ]\n}\n```\n\n| Field | Required | Purpose |\n| ------------- | -------- | ----------------------------------------------- |\n| `id` | \u2705 | Stable hand ID (`HandId`) |\n| `displayName` | \u2705 | Human-readable name |\n| `visibility` | \u274C | `ownerOnly`, `public`, or `hidden` |\n| `maxCards` | \u274C | Maximum allowed card count |\n| `minCards` | \u274C | Minimum required card count |\n| `cardSetIds` | \u274C | Allowed card sets; omit for any compatible card |\n| `description` | \u274C | Explanation for authors and tools |\n\n## 4. `decks`\n\n`decks` are shared card containers.\n\nUse a deck for any card location the whole table shares: a draw pile, discard pile, market row, trick area, or communal play area.\n\n```json\n{\n "decks": [\n {\n "id": "draw-pile",\n "name": "Draw Pile",\n "cardSetId": "standard_52_deck"\n },\n {\n "id": "discard-pile",\n "name": "Discard Pile",\n "cardSetId": "standard_52_deck"\n }\n ]\n}\n```\n\n| Field | Required | Purpose |\n| ----------- | -------- | -------------------------------------- |\n| `id` | \u2705 | Stable deck ID (`DeckId`) |\n| `name` | \u2705 | Human-readable name |\n| `cardSetId` | \u2705 | Card set used by this shared container |\n\n## 5. `dice`, `resources`, and `boardDefinitions`\n\nAdd these sections only if the game needs them.\n\n- `dice` define shared dice such as `d6` or custom dice.\n- `resources` define typed player economies such as coins, food, or energy.\n- `boardDefinitions` define structured boards such as hex maps, square grids, tracks, or networks.\n\nExample:\n\n```json\n{\n "dice": [{ "id": "d6", "name": "Six-Sided Die", "sides": 6 }],\n "resources": [{ "id": "coins", "displayName": "Coins" }]\n}\n```\n\n## 6. `availableActions`\n\nActions describe what players may submit to the engine.\n\nThink of actions as structured intent, not UI clicks. The UI gathers selections, then submits those values through action parameters.\n\n```json\n{\n "availableActions": [\n {\n "actionType": "playCard",\n "displayName": "Play Card",\n "description": "Play the selected card",\n "parameters": [\n {\n "name": "cardId",\n "type": "cardId",\n "required": true,\n "cardSetId": "standard_52_deck"\n }\n ],\n "errorCodes": ["NOT_YOUR_TURN", "INVALID_CARD"]\n }\n ]\n}\n```\n\nAction authoring reminders:\n\n- use stable, readable IDs\n- use `cardSetId` when a `cardId` or `cardType` parameter should be limited to one card set\n- use `array: true` with `minLength` and `maxLength` when an action takes multiple values\n\n## 7. `stateMachine`\n\n`stateMachine` defines the phase flow of the game.\n\nUse it to name phases, describe who can act, and define how the game moves from one phase to the next.\n\nState types:\n\n- `AUTO`: engine-driven phase\n- `SINGLE_PLAYER`: one active player acts\n- `ALL_PLAYERS`: multiple players may act in parallel\n\n```json\n{\n "stateMachine": {\n "initialState": "dealCards",\n "states": [\n {\n "name": "dealCards",\n "type": "AUTO",\n "description": "Shuffle and deal cards.",\n "transitions": [{ "targetState": "playTurn" }]\n },\n {\n "name": "playTurn",\n "type": "SINGLE_PLAYER",\n "description": "Active player plays a card.",\n "availableActions": ["playCard"],\n "transitions": [{ "targetState": "playTurn" }]\n }\n ]\n }\n}\n```\n\n## 8. `variableSchema`\n\n`variableSchema` is for state that must be stored explicitly.\n\nKeep it small. If something can be derived from card locations, resources, board state, or the current phase, it usually does not belong here.\n\nGood candidates:\n\n- running scores across rounds\n- round number, trump suit, current bid\n- flags that affect future legal moves\n\nAvoid storing:\n\n- counts that can be derived from hands or decks\n- phase flow already represented by `stateMachine`\n- duplicated resource totals\n\n```json\n{\n "variableSchema": {\n "globalVariableSchema": {\n "properties": {\n "roundNumber": { "type": "integer", "description": "Current round" }\n }\n },\n "playerVariableSchema": {\n "properties": {\n "score": {\n "type": "integer",\n "description": "Accumulated score"\n }\n }\n }\n }\n}\n```\n\n## Final Checklist\n\nBefore running `dreamboard sync`, check that:\n\n- every referenced `cardSetId`, `handId`, `deckId`, resource ID, board ID, and action name exists\n- the manifest only uses documented schema fields\n- `variableSchema` stores only non-derivable state\n- optional list fields are omitted or `[]`, not `null`\n\nThen run:\n\n```bash\ndreamboard sync\n```\n',
1942
- "references/phase-handlers.md": '# Phase Handlers\n\nPhase handlers are the core abstraction for implementing game logic. Each state in the manifest\'s `stateMachine` maps to a phase handler file in `app/phases/`.\n\n## Phase Types\n\n| Type | File Import | When to use |\n| --------------- | --------------------------- | ------------------------------------------------------------ |\n| `AUTO` | `createAutoPhase` | No player input needed (deal, resolve, score) |\n| `SINGLE_PLAYER` | `createSinglePlayerPhase` | One player acts at a time (play a card, roll dice) |\n| `ALL_PLAYERS` | `createMultiplePlayerPhase` | All players act simultaneously (reveal, pass cards, discard) |\n\n## Phase Lifecycle\n\n**AUTO**: `execute(ctx)` \u2192 returns next state name\n\n**SINGLE_PLAYER / ALL_PLAYERS**:\n\n1. `onEnter(ctx)` \u2014 initialize phase state, set active players\n2. `validateAction(ctx, playerId, actionType, parameters)` \u2014 validate before execution\n3. `onPlayerAction(ctx, playerId, actionType, parameters)` \u2014 process the action (mutate state)\n4. `onAfterAction(ctx, playerId, actionType)` \u2014 per-action side effects (e.g., advance turn)\n5. `checkCompletion(ctx)` \u2014 return `null` if not done, or the next state name if done\n6. `onComplete(ctx)` \u2014 cleanup after transition decision\n\n## PhaseContext (`ctx`)\n\n```typescript\ninterface PhaseContext {\n readonly state: StateApi; // Read game state\n readonly apis: GameApis; // Mutate game state\n readonly logger: Logger; // Log messages\n}\n```\n\n## AUTO Phase Example\n\n```typescript\nimport type { AutoPhaseDefinition } from "../sdk/phaseHandlers";\nimport { createAutoPhase } from "../sdk/phaseHandlers";\n\nconst phaseDefinition = {\n execute(ctx) {\n const { state, apis, logger } = ctx;\n apis.deckApi.shuffle("main-deck");\n for (const playerId of state.player.getOrder()) {\n apis.deckApi.moveCardsFromDeckToPlayer(\n "main-deck",\n playerId,\n "main-hand",\n 5,\n );\n }\n return "playPhase";\n },\n} satisfies AutoPhaseDefinition<"dealCards">;\n\nexport const phase = createAutoPhase(phaseDefinition);\n```\n\n## SINGLE_PLAYER Phase Example\n\n```typescript\nimport type { SinglePlayerPhaseDefinition } from "../sdk/phaseHandlers";\nimport { createSinglePlayerPhase } from "../sdk/phaseHandlers";\nimport { validationSuccess, validationError } from "../sdk/validation.js";\n\nconst phaseDefinition = {\n onEnter(ctx) {\n const { state, apis } = ctx;\n const firstPlayer = state.player.getOrder()[0];\n apis.gameApi.setNextPlayer(firstPlayer);\n },\n\n validateAction(ctx, playerId, actionType, parameters) {\n return validationSuccess();\n },\n\n onPlayerAction(ctx, playerId, actionType, parameters) {\n const { apis } = ctx;\n // Process action...\n },\n\n onAfterAction(ctx, playerId, actionType) {\n const { apis } = ctx;\n apis.gameApi.advanceTurn(); // Move to next player\n },\n\n checkCompletion(ctx) {\n // Return null to keep playing, or next state name to transition\n return null;\n },\n\n getUIArgs(ctx, playerId) {\n return {};\n },\n} satisfies SinglePlayerPhaseDefinition<"playPhase", "playCard">;\n\nexport const phase = createSinglePlayerPhase(phaseDefinition);\n```\n\n## ALL_PLAYERS Phase Example\n\nSee [all-players-tracking.md](all-players-tracking.md) for the recommended tracking pattern.\n\n## Terminal Phase (Game End)\n\nFor states with no transitions (game end), use `TerminalPhaseDefinition`:\n\n```typescript\nimport type { TerminalPhaseDefinition } from "../sdk/phaseHandlers";\nimport { createTerminalPhase } from "../sdk/phaseHandlers";\n\nconst phaseDefinition = {\n execute(ctx) {\n const { state, apis } = ctx;\n // Optionally declare winner\n apis.gameApi.declareWinner("player-1", "Most points");\n apis.gameApi.endGame();\n return "endGame";\n },\n} satisfies TerminalPhaseDefinition<"endGame">;\n\nexport const phase = createTerminalPhase(phaseDefinition);\n```\n\n## Type Safety\n\nPhase definitions use `satisfies` for type checking:\n\n- `AutoPhaseDefinition<\'stateName\'>` \u2014 state name from manifest\n- `SinglePlayerPhaseDefinition<\'stateName\', \'actionName\'>` \u2014 with action type union\n- `MultiplePlayerPhaseDefinition<\'stateName\', \'actionName\'>` \u2014 for ALL_PLAYERS\n- Union multiple actions: `\'playCard\' | \'drawCard\'`\n',
1943
- "references/rule-authoring.md": '# Rule Authoring Guide\n\nUse this guide when creating or rewriting `rule.md`.\n\n`rule.md` should explain how the game works in plain language. It is the source of intent for the game. `manifest.json` comes later and turns that intent into runtime structure.\n\nKeep the jobs separate:\n\n- `rule.md` explains the rules\n- `manifest.json` defines the runtime model\n- `app/phases/*.ts` implements the rules\n\nIf you need schema details, use [manifest-authoring.md](manifest-authoring.md). If you need help deciding between hands and decks, use [hands-vs-decks.md](hands-vs-decks.md).\n\n## Recommended Document Structure\n\nUse this section order in `rule.md`.\n\n1. **Overview**\n\n - Game premise and objective\n - Player count\n - Match length target\n\n2. **Components**\n\n - Cards, hands, decks, tokens, dice, boards, resources\n - Public vs hidden information\n - Limits such as hand size or token caps\n\n3. **Setup**\n\n - Starting layout\n - Starting player and turn order\n - Initial cards, resources, and other player state\n\n4. **Gameplay**\n\n - Turn or phase loop in order\n - Available actions in each phase\n - Validation constraints\n - Transition conditions between phases\n\n5. **Scoring and Progression**\n\n - How points or progress are gained or lost\n - When scoring happens\n - Tie-breakers\n\n6. **Winning Conditions**\n\n - Exact end-game triggers\n - Winner resolution rules\n\n7. **Special Rules and Edge Cases**\n\n - Simultaneous actions\n - Empty deck behavior\n - Invalid or no-op actions\n - What happens when a player cannot act\n\n## Writing Rules That Map Cleanly To The Engine\n\n- **Phase model**\n State whether a phase is automatic, single-player, or all-players, and say how it ends.\n- **Action model**\n Name each action, say what it does, and list required inputs and constraints.\n- **State model**\n Separate stored state from derived state. If something can be computed from cards, resources, or the current phase, call that out.\n- **Visibility model**\n Say who can see what, when hidden information becomes public, and when reveals happen.\n- **Determinism**\n Resolve ambiguous cases with explicit priority order. Define random events precisely.\n\n## Writing Style\n\n- Use `must` for mandatory behavior.\n- Use `may` only for optional player choices.\n- Define terms once, then reuse the same words consistently.\n- Avoid UI-specific verbs such as "click" or "drag".\n\n## High-Signal Template\n\nUse this template when creating or rewriting `rule.md`:\n\n```markdown\n# <Game Name>\n\n## Overview\n\n- Players: <min-max> (optimal: <n>)\n- Objective: <how to win>\n- Duration: <target minutes>\n\n## Components\n\n- Card sets:\n- Shared decks:\n- Player hands:\n- Boards:\n- Resources, tokens, or dice:\n- Public vs hidden information:\n\n## Setup\n\n1. ...\n2. ...\n3. ...\n\n## Gameplay\n\n### Phase 1: <name> (<AUTO|SINGLE_PLAYER|ALL_PLAYERS>)\n\n- Entry:\n- Allowed actions:\n- Validation:\n- Completion -> Next phase:\n\n### Phase 2: <name>\n\n- ...\n\n## Scoring and Progression\n\n- ...\n\n## Winning Conditions\n\n- End trigger:\n- Winner determination:\n- Tie-breaker:\n```\n\n## Iteration Workflow\n\n1. Edit `rule.md` first.\n2. Align `manifest.json` to the updated rules.\n3. Run `dreamboard sync`.\n4. Implement or refine `app/phases/*.ts`.\n5. Validate the flow with `dreamboard run`, `dreamboard test generate`, and `dreamboard test run` as needed.\n',
1944
- "references/scenario-format.md": '# Scenario Format\n\nScenarios are JSON files used with `dreamboard run --scenario <file>` to automate gameplay actions.\n\nUse this file for the JSON runtime-scenario contract.\n\n- For TypeScript regression tests with `dreamboard test generate` / `dreamboard test run`, see [test-harness.md](test-harness.md).\n- For what adversarial cases to write with these JSON scenarios, see [adversarial-testing.md](adversarial-testing.md).\n\n`dreamboard run` is now a single command flow:\n\n1. Without `--scenario`, it observes SSE until a stop condition (default `YOUR_TURN`).\n2. With `--scenario`, it executes scenario steps (default `--max-steps 1`).\n3. Scenario driver defaults to `api` (no Playwright required).\n4. Playwright is used only for `--scenario-driver ui` or `--screenshot`.\n\n## Default Structure (API Driver)\n\n```json\n{\n "steps": [\n {\n "playerId": "player-1",\n "actionType": "playCard",\n "parameters": { "cardId": "hearts-7" },\n "turns": 1\n },\n {\n "playerId": "player-1",\n "actionType": "endTurn",\n "parameters": {},\n "turns": 1\n }\n ]\n}\n```\n\n## API Step Fields (Default)\n\n| Field | Type | Description |\n| ------------ | ------------------------- | ----------------------------------------------------------------- |\n| `playerId` | `string` | Player ID this step applies to (required) |\n| `actionType` | `string` | Action type submitted to runtime API (required) |\n| `parameters` | `Record<string, unknown>` | Action parameters object (optional, default `{}`) |\n| `turns` | `number` | Number of turns to wait after this action (optional, default `1`) |\n\n## UI Step Fields (`--scenario-driver ui`)\n\n| Field | Type | Description |\n| ---------- | ---------- | --------------------------------------------------------------------------- |\n| `playerId` | `string` | Player ID this step applies to (required) |\n| `buttons` | `string[]` | Mouse/keyboard buttons to simulate (`"left_mouse_button"`, `"right"`, etc.) |\n| `turns` | `number` | Number of turns to apply this step |\n| `mouse_x` | `number` | X coordinate of the simulated click (optional) |\n| `mouse_y` | `number` | Y coordinate of the simulated click (optional) |\n\n## Conventions\n\n1. `playerId` is required on every step.\n2. Run one acting step per invocation for deterministic agent loops:\n - `dreamboard run` (observe turn context)\n - `dreamboard run --scenario ... --max-steps 1` (act once)\n3. All steps executed in one invocation must target the same `playerId`.\n4. The step `playerId` must be eligible for the latest `YOUR_TURN` context.\n\n## Observe Artifacts\n\nWhen running without `--scenario`, the CLI writes:\n\n1. `.dreamboard/run/session.json`\n2. `.dreamboard/run/events.ndjson`\n3. `.dreamboard/run/latest-your-turn.json`\n4. `.dreamboard/run/last-run-summary.json`\n\nBy default, `events.ndjson` stores only `YOUR_TURN` messages.\n\n## Usage\n\n```bash\n# Observe until actionable state (default: until YOUR_TURN)\ndreamboard run\n\n# Observe stream behavior\ndreamboard run --until GAME_ENDED\ndreamboard run --observe-events all\ndreamboard run --timeout-ms 15000\ndreamboard run --screenshot\n\n# Execute API scenario steps (default driver, no Playwright required)\ndreamboard run --scenario path/to/scenario.json\ndreamboard run --scenario path/to/scenario.json --max-steps 1\n\n# Execute UI scenario steps (Playwright driver)\ndreamboard run --scenario path/to/scenario.json --scenario-driver ui --max-steps 1\ndreamboard run --scenario path/to/scenario.json --scenario-driver ui --max-steps 1 --screenshot\n\n# Start a fresh session instead of resuming\ndreamboard run --new-session --players 4\n```\n',
1945
- "references/test-harness.md": '# Test Harness\n\nTypeScript scenario tests run against the Dreamboard backend API using deterministic base snapshots.\n\nUse this file for the TypeScript regression harness:\n\n- `dreamboard test generate`\n- `dreamboard test run`\n\nThis is not the same system as `dreamboard run --scenario <file>.json`.\n\n- For JSON runtime scenarios, see [scenario-format.md](scenario-format.md).\n- For rejection-focused runtime coverage, see [adversarial-testing.md](adversarial-testing.md).\n\n## Workspace Layout\n\nThe harness expects this structure in the game project:\n\n- `test/base-scenarios.json`\n- `test/scenarios/*.scenario.ts`\n- `test/generated/*` (generated by `dreamboard test generate`)\n\nCurrent canonical example workspace (`examples/things-in-rings`) includes bases like `initial-turn` and `after-first-placement`, plus scenarios under `test/scenarios/`.\n\n## Commands\n\nGenerate deterministic bases:\n\n```bash\ndreamboard test generate\n```\n\nRun all scenarios:\n\n```bash\ndreamboard test run\n```\n\nRun one scenario file:\n\n```bash\ndreamboard test run --scenario test/scenarios/reject-card-not-in-hand.scenario.ts\n```\n\nSource-checkout builds may expose internal environment overrides for harness work, but those flags are not part of the published CLI contract.\n\nRegenerate whenever any fingerprint input changes: base definition (`seed`, `players`, `steps`), game manifest hash, compiled result ID, or game ID.\n\n## Base Definitions\n\n`test/base-scenarios.json` is required and must explicitly include `initial-turn`.\n\nEach base entry has:\n\n- `seed: number`\n- `players: number`\n- `steps: ApiScenarioStep[]`\n\n`steps` may be empty. Use an empty-step base plus an empty-step scenario to assert opening-state invariants without inventing fake actions.\n\nExample:\n\n```json\n{\n "initial-turn": {\n "seed": 1337,\n "players": 4,\n "steps": []\n },\n "after-first-placement": {\n "seed": 1337,\n "players": 4,\n "steps": [\n {\n "playerId": "player-2",\n "actionType": "placeThing",\n "parameters": { "cardId": "a-shadow", "ringId": "ring-1" }\n }\n ]\n }\n}\n```\n\nGeneration flow for each used base:\n\n1. Create session with deterministic seed/player count.\n2. Start game.\n3. Wait for first `YOUR_TURN`.\n4. Execute base setup steps.\n5. Save snapshot + fingerprint metadata.\n\nBase setup events are not counted in test assertions. `events` in `then.assert` only reflects actions from `when.steps`, so zero-step scenarios start with an empty event history.\n\n## Generated Artifacts\n\n`dreamboard test generate` writes:\n\n- `test/generated/base-states.generated.ts`\n- `test/generated/base-states.generated.d.ts`\n- `test/generated/scenario-manifest.generated.ts`\n- `test/generated/.generation-meta.json`\n\nThese files are generated and should not be edited manually.\n\n## Scenario Contract\n\nScenarios are loaded from `test/scenarios/**/*.scenario.ts` and validated strictly (unknown fields are rejected).\n\nIn current projects, scenario files typically import from `../testing-types`:\n\n```ts\nimport { AssertContext, defineScenario } from "../testing-types";\n\nexport default defineScenario({\n meta: {\n id: "reject-card-not-in-hand",\n description: "Player tries to place a card they don\'t hold",\n },\n given: {\n base: "initial-turn",\n },\n when: {\n steps: [\n {\n playerId: "player-2",\n actionType: "placeThing",\n parameters: { cardId: "a-dog", ringId: "ring-1" },\n },\n ],\n },\n then: {\n assert: ({ gameState, events, expect }: AssertContext) => {\n expect(events.count("ACTION_REJECTED")).toBe(1);\n expect(events.last("ACTION_REJECTED")?.errorCode).toBe(\n "CARD_NOT_IN_HAND",\n );\n expect(gameState.currentState).toBe("placeThing");\n },\n },\n});\n```\n\n`given.base` must exist in `test/base-scenarios.json`, or the run fails with an available-base list.\n\nFor invariant coverage, add at least one zero-step scenario:\n\n```ts\nimport {\n AssertContext,\n defineScenario,\n getNormalizedHands,\n} from "../testing-types";\n\nexport default defineScenario({\n meta: {\n id: "initial-state",\n description: "Opening hands are dealt to the correct players",\n },\n given: {\n base: "initial-turn",\n },\n when: {\n steps: [],\n },\n then: {\n assert: ({ gameState, expect }: AssertContext) => {\n const hands = getNormalizedHands(gameState);\n expect(hands["player-1"]?.hand).toEqual([\n "seat-1-flower-1",\n "seat-1-flower-2",\n "seat-1-flower-3",\n "seat-1-skull",\n ]);\n },\n },\n});\n```\n\n## Runtime Assertion Surface\n\n`then.assert` receives `{ gameState, events, expect }`.\n\n- `events.count(type)` returns number of matching events.\n- `events.last(type)` returns the latest matching event.\n- `events.all(type)` returns all matching events.\n- `expect(actual)` supports `toBe`, `toEqual`, `toBeDefined`, `toContain`, and `toBeGreaterThanOrEqual`.\n\nDuring scenario assertions, event history includes only scenario steps (base-step events are cleared before scenario execution).\n\n`gameState.globalVariables` and `gameState.playerVariables` are JSON-parsed for assertions.\n\n`testing-types` also exports:\n\n- `getNormalizedHands(gameState)` to read each player hand with sorted card IDs.\n- `getNormalizedDecks(gameState)` to read deck contents with sorted card IDs.\n\n## Failure And Staleness Signals\n\nCommon failures indicate stale generated bases:\n\n- `Missing test/generated/base-states.generated.ts. Run \'dreamboard test generate\' first.`\n- `Fingerprint mismatch: base setup changed (...). Run \'dreamboard test generate\' to refresh deterministic bases.`\n- `Fingerprint mismatch: compiled result changed (...). Run \'dreamboard test generate\' to refresh deterministic bases.`\n- `Fingerprint mismatch: base setup changed (...); compiled result changed (...). Run \'dreamboard test generate\' to refresh deterministic bases.`\n- Unknown `given.base` values.\n\n## Common edge cases\n\nWhen testing out-of-turn behavior in any turn-based game, include these checks:\n\n- Wrong actor attempts a valid action: choose a base where the active player is known, send a normal action from a different player, and assert a turn-violation error (for example `NOT_YOUR_TURN`).\n- Unauthorized role attempts an action: if your game has role-restricted actions, attempt the action from an actor without permission and assert the appropriate authorization error.\n- Correct actor, wrong phase/state: attempt an action that is valid in one phase/state while the game is in another, and assert a deterministic phase/state rejection.\n- Consecutive out-of-turn attempts: send multiple invalid actions from different non-active players and verify each is rejected independently.\n- No state mutation on rejection: assert no successful action event was emitted, the game phase/state is unchanged, and the active player pointer is unchanged.\n\nRecommended assertion template:\n\n```ts\nexpect(events.count("ACTION_REJECTED")).toBe(1);\nexpect(events.count("ACTION_EXECUTED")).toBe(0);\nexpect(events.last("ACTION_REJECTED")?.errorCode).toBe("NOT_YOUR_TURN");\nexpect(gameState.currentState).toBe(expectedState);\nexpect(gameState.currentPlayerIds[0]).toBe(expectedActivePlayerId);\n```\n',
1946
- "references/ui-best-practices.md": '# UI Best Practices\n\nUse this guide when implementing `ui/App.tsx` and `ui/components/*`.\n\nThis page is about rendering, interaction, and UI data flow. Keep rules in `rule.md`, runtime structure in `manifest.json`, and phase-specific UI data in `getUIArgs()`.\n\n## Core Principles\n\n1. **Start with SDK components**\n Prefer `./sdk/components/` and customize them with render props before building custom replacements.\n2. **Design mobile-first**\n Mobile is the baseline. Desktop can add polish, but the primary layout should work on smaller screens first.\n3. **Do not duplicate authoritative game state**\n Use hooks such as `useGameState`, `useUIArgs`, and `useAction` instead of mirroring shared state in local React state.\n4. **Wrap actions in error handling**\n Show feedback through `useToast` or another clear error surface.\n5. **Keep types intact**\n Use the generated hook and action types. Avoid `any`.\n6. **Reserve a persistent feedback area**\n Players should always be able to see the current phase, turn ownership, latest meaningful result, and end-of-game summary.\n\n## SDK Hooks\n\nUse these from `./sdk/hooks/`.\n\n| Hook | Returns | When to use |\n| ------------------------ | ------------------------------------------------------------------------- | ---------------------------------- |\n| `useGameState` | Full game state (`currentPlayerIds`, `decks`, `currentState`, `isMyTurn`) | Core session state |\n| `useCard(cardId)` | `CardItem \\| undefined` | Resolve one card |\n| `useCards(cardIds)` | `CardItem[]` | Resolve multiple cards |\n| `useMyHand(handId)` | Current player\'s cards for one hand | Private or public per-player cards |\n| `useMyResources()` | Current player\'s resources | Resource display |\n| `useMe()` | `{ playerId, name, isHost }` | Current player identity |\n| `usePlayerInfo()` | All players keyed by ID | Player labels and scoreboards |\n| `useAction()` | Phase-specific action submitters | Submitting actions |\n| `useUIArgs()` | Phase-specific UI args | Data returned from `getUIArgs()` |\n| `useGameNotifications()` | Event listeners | Turn prompts, rejections, game end |\n| `useLobby()` | Lobby state | Seating and pre-game UI |\n| `useDice(dieIds)` | Dice values and roll function | Dice mechanics |\n\n## SDK Components\n\nUse these from `./sdk/components/`.\n\n### Core display\n\n| Component | Purpose |\n| --------------- | ---------------------------------------------- |\n| `Card` | Display a card with animation support |\n| `ConnectedCard` | Resolve card data from context automatically |\n| `Hand` | Render a player\'s hand with custom card layout |\n| `PlayArea` | Render a shared card area |\n| `PlayerInfo` | Show player name, score, and turn state |\n\n### Actions and status\n\n| Component | Purpose |\n| ----------------- | ---------------------------------------- |\n| `ActionButton` | Action button with optional cost display |\n| `ActionPanel` | Container for related actions |\n| `ActionGroup` | Group actions inside a panel |\n| `PhaseIndicator` | Show current phase and turn state |\n| `ResourceCounter` | Display typed resources |\n| `CostDisplay` | Show affordability |\n| `DiceRoller` | Show die values |\n| `GameEndDisplay` | Show final results |\n| `Drawer` | Mobile overflow surface |\n\n### Board components\n\n| Component | Use case | Hook |\n| -------------- | ----------------------------- | --------------------------------- |\n| `SquareGrid` | Chess, checkers, grid tactics | `useSquareBoard(boardId)` |\n| `HexGrid` | Hex maps and wargames | `useHexBoard(boardId)` |\n| `TrackBoard` | Race tracks and score tracks | `useTrackBoard(boardId)` |\n| `NetworkGraph` | Connected-node boards | `useNetworkBoard(boardId)` |\n| `ZoneMap` | Area-control boards | `useZoneMap(zones, pieces)` |\n| `SlotSystem` | Worker placement | `useSlotSystem(slots, occupants)` |\n\n## Layout Guidelines\n\n- Use Tailwind CSS for styling.\n- Use `clsx` for conditional class composition.\n- Use `framer-motion` for meaningful motion, not motion everywhere.\n- Keep touch targets large and spacing readable on mobile.\n- Use `useIsMobile()` when behavior must differ by device.\n\n## Persistent Feedback Region\n\nReserve a visible area near the top of the layout for status that should survive subview changes.\n\nThat region should be able to show:\n\n- the current phase\n- whether it is the local player\'s turn\n- the latest meaningful status message\n- round or trick resolution results\n- game-over state and winner summary\n\nIf your game uses `AUTO` phases, do not let those transitions erase the only copy of round-resolution feedback before the next interactive view appears.\n\n## Common Patterns\n\n### Phase-based rendering\n\n```tsx\nconst { currentState } = useGameState();\nconst uiArgs = useUIArgs();\nconst actions = useAction();\n\nif (currentState === "playCards") {\n const phaseArgs = uiArgs.playCards;\n const phaseActions = actions.playCardsActions;\n return <PlayCardsView args={phaseArgs} actions={phaseActions} />;\n}\n```\n\n### Action submission with error handling\n\n```tsx\nconst { toast } = useToast();\n\nconst handlePlay = async () => {\n try {\n await actions.playCardsActions.playCard({ cardIds: selectedCards });\n } catch (err) {\n toast.error(err instanceof Error ? err.message : "Action failed");\n }\n};\n```\n\n### Public hands in UI\n\nFor per-player containers that should be visible to everyone, prefer the built-in public-hand hook instead of duplicating that data in `getUIArgs()`.\n\n```ts\nimport { useMyHand, usePublicHands } from "@dreamboard/ui-sdk";\n\nconst myHand = useMyHand("hand");\nconst scoredByPlayer = usePublicHands("scored-area");\nconst player2Scored = scoredByPlayer["player-2"] ?? [];\n```\n\nNotes:\n\n- `useMyHand(handId)` reads the current player\'s copy of that hand\n- `usePublicHands(handId)` reads all players\' copies, keyed by `playerId`\n- `usePublicHands()` only works for hands marked `visibility: "public"`\n\n## Genre-Specific Guides\n\nUse these when the game matches one of the built-in patterns:\n\n- [ui-genre-trick-taking.md](ui-genre-trick-taking.md)\n- [ui-genre-worker-placement.md](ui-genre-worker-placement.md)\n- [ui-genre-resource-management.md](ui-genre-resource-management.md)\n',
1947
- "references/ui-genre-resource-management.md": '# UI Guide: Resource Management Games\n\nPatterns for Catan, Splendor, engine builders, trading games, and similar resource-centric games.\n\n## Game characteristics\n\n- Players **collect, spend, and trade resources** to build structures, buy cards, or score points.\n- May involve a shared board (hex grid, network, market row) plus personal tableaux.\n- Key UI signals: resource pools, affordability, available purchases, trade offers, build options.\n\n## Recommended SDK components\n\n### Primary\n\n| Component | Usage |\n| ----------------------------- | -------------------------------------------------------------------------- |\n| `ResourceCounter` | Display each player\'s resource pool with icons and animated count changes. |\n| `CostDisplay` | Show build/purchase costs with green/red affordability feedback. |\n| `ActionButton` | "Build", "Buy", "Trade" buttons with integrated cost display. |\n| `ActionPanel` / `ActionGroup` | Organize actions by type (Build, Trade, End Turn). |\n| `Card` / `Hand` | Display purchasable cards or player tableau cards. |\n\n### Board components (pick based on game)\n\n| Component | Use case | Hook |\n| -------------- | ----------------------------------------- | -------------------------- |\n| `HexGrid` | Catan-style resource hex boards | `useHexBoard(boardId)` |\n| `NetworkGraph` | Trade route networks | `useNetworkBoard(boardId)` |\n| `SquareGrid` | Grid-based markets or tableaux | `useSquareBoard(boardId)` |\n| `PlayArea` | Market row / available cards for purchase | \u2014 |\n\n### Supporting\n\n| Component | Usage |\n| ---------------- | -------------------------------------------------------- |\n| `PlayerInfo` | Player name, score, and victory point tracker. |\n| `PhaseIndicator` | Current phase (roll, trade, build, etc.). |\n| `DiceRoller` | For dice-based resource generation (e.g., Catan). |\n| `GameEndDisplay` | Final scores with score breakdown. |\n| `Drawer` | Mobile drawer for trade interface or detailed card view. |\n\n### Hooks\n\n| Hook | Usage |\n| -------------------------- | ----------------------------------------------------- |\n| `useMyResources()` | Current player\'s resource counts. |\n| `useHexBoard(boardId)` | Hex board state for Catan-style games. |\n| `useNetworkBoard(boardId)` | Network/route state. |\n| `useSquareBoard(boardId)` | Grid board state. |\n| `useDice(dieIds)` | Dice rolling mechanics. |\n| `useGameState` | Turn order, current phase, active players. |\n| `useAction` | Submit build, trade, end-turn actions. |\n| `useUIArgs` | Phase-specific data (available builds, trade offers). |\n| `usePlayerInfo` | All player info for scoreboards. |\n\n## Key patterns\n\n### Resource display with affordability\n\n```tsx\nconst resources = useMyResources();\nconst resourceDefs: ResourceDefinition[] = [\n { type: "brick", label: "Brick", icon: Blocks, color: "text-red-600" },\n { type: "lumber", label: "Lumber", icon: TreePine, color: "text-green-700" },\n { type: "ore", label: "Ore", icon: Mountain, color: "text-slate-500" },\n { type: "grain", label: "Grain", icon: Wheat, color: "text-yellow-500" },\n { type: "wool", label: "Wool", icon: Cloud, color: "text-green-400" },\n];\n\n<ResourceCounter\n resources={resourceDefs.map((d) => ({\n ...d,\n iconColor: d.color,\n bgColor: "bg-slate-800",\n }))}\n counts={resources}\n layout="row"\n/>;\n```\n\n### Build actions with costs\n\n```tsx\nconst { buildPhase } = useUIArgs();\nconst resources = useMyResources();\n\n<ActionPanel title="Build" state="buildPhase">\n <ActionGroup title="Structures">\n <ActionButton\n label="Build Road"\n cost={{ brick: 1, lumber: 1 }}\n currentResources={resources}\n resourceDefs={resourceDefs}\n available={buildPhase?.canBuildRoad}\n onClick={() => actions.buildActions.build({ type: "road" })}\n />\n <ActionButton\n label="Build Settlement"\n cost={{ brick: 1, lumber: 1, grain: 1, wool: 1 }}\n currentResources={resources}\n resourceDefs={resourceDefs}\n available={buildPhase?.canBuildSettlement}\n onClick={() => actions.buildActions.build({ type: "settlement" })}\n />\n </ActionGroup>\n</ActionPanel>;\n```\n\n### Hex board for Catan-style games\n\n```tsx\nconst { tiles, edges, vertices } = useHexBoard("catan-board");\n\n<HexGrid\n tiles={tiles}\n edges={edges}\n vertices={vertices}\n hexSize={50}\n renderTile={(tile) => (\n <DefaultHexTile\n size={50}\n fill={terrainColors[tile.typeId]}\n label={tile.data?.diceNumber}\n />\n )}\n renderEdge={(edge, pos) => (\n <DefaultHexEdge position={pos} color={playerColors[edge.owner]} />\n )}\n renderVertex={(vertex, pos) => (\n <DefaultHexVertex position={pos} color={playerColors[vertex.owner]} />\n )}\n interactiveVertices={placementMode === "settlement"}\n interactiveEdges={placementMode === "road"}\n onInteractiveVertexClick={(v) => handlePlacement("settlement", v.id)}\n onInteractiveEdgeClick={(e) => handlePlacement("road", e.id)}\n/>;\n```\n\n### Market row (purchasable cards)\n\n```tsx\n<PlayArea\n cards={marketCards}\n layout="row"\n interactive\n onCardClick={(cardId) => handlePurchase(cardId)}\n renderCard={(card) => (\n <div className="relative">\n <DefaultCardContent card={card} />\n <CostDisplay\n cost={card.properties.cost}\n currentResources={resources}\n resourceDefs={resourceDefs}\n layout="inline"\n />\n </div>\n )}\n/>\n```\n\n## UIArgs recommendations\n\n```typescript\n// shared/ui-args.ts\nexport interface BuildPhaseUIArgs {\n canBuildRoad: boolean;\n canBuildSettlement: boolean;\n canBuildCity: boolean;\n canBuyCard: boolean;\n availableBuildLocations?: string[]; // Board positions where building is allowed\n}\n\nexport interface TradePhaseUIArgs {\n canTrade: boolean;\n tradeOffers?: {\n from: string;\n offering: Record<string, number>;\n requesting: Record<string, number>;\n }[];\n bankTradeRatios?: Record<string, number>; // e.g., { brick: 4, lumber: 3 } for ports\n}\n\nexport interface DicePhaseUIArgs {\n diceValues?: number[];\n resourcesGained?: Record<string, number>;\n}\n```\n',
1948
- "references/ui-genre-trick-taking.md": '# UI Guide: Trick-Taking Games\n\nPatterns for Hearts, Spades, Bridge, Big Two, and similar card-based trick-taking games.\n\n## Game characteristics\n\n- Players hold a **hand of cards** and play them to a shared **trick area**.\n- One trick is resolved at a time; the winner collects cards.\n- Turn order matters \u2014 typically clockwise from the trick leader.\n- Key UI signals: whose turn it is, which cards are legal to play, current trick, scores.\n\n## Recommended SDK components\n\n### Primary\n\n| Component | Usage |\n| ------------ | --------------------------------------------------------------------------------------------------- |\n| `Hand` | Display the current player\'s hand. Use `renderCard` to highlight playable cards. |\n| `Card` | Render individual cards in the hand and trick area. Use `renderContent` for custom suit/rank faces. |\n| `PlayArea` | Display the current trick \u2014 cards played by each player. Use `layout="row"`. |\n| `PlayerInfo` | Show each player\'s name, score, and turn indicator around the table. |\n\n### Supporting\n\n| Component | Usage |\n| ---------------- | ----------------------------------------------------------- |\n| `PhaseIndicator` | Show current phase (dealing, passing, playing, scoring). |\n| `GameEndDisplay` | Final scoreboard at game end. |\n| `useToast` | Feedback for invalid plays (e.g., "Must follow suit"). |\n| `Drawer` | Overflow drawer when the hand has too many cards on mobile. |\n\n### Hooks\n\n| Hook | Usage |\n| -------------------- | -------------------------------------------------------------------------- |\n| `useMyHand(handId)` | Get the current player\'s cards. |\n| `useCard / useCards` | Resolve card data for display. |\n| `useGameState` | Get `currentPlayerIds`, `isMyTurn`, `currentState`. |\n| `useAction` | Submit play-card action. |\n| `useUIArgs` | Get phase-specific data (e.g., legal card IDs, trick cards, trick winner). |\n| `usePlayerInfo` | Map player IDs to names for trick display. |\n\n## Key patterns\n\n### Card selection for play\n\n```tsx\nconst [selectedCards, setSelectedCards] = useState<string[]>([]);\nconst { playCards } = useUIArgs();\nconst legalCardIds = new Set(playCards?.legalCardIds ?? []);\n\n<Hand\n cards={myCards}\n selectedIds={selectedCards}\n renderCard={({ card, isSelected, ...pos }) => (\n <Card\n card={card}\n selected={isSelected}\n disabled={!legalCardIds.has(card.id)}\n onCardClick={(id) => toggleSelection(id)}\n style={{\n position: "absolute",\n left: pos.x,\n transform: `translateY(${pos.y}px)`,\n zIndex: pos.zIndex,\n }}\n />\n )}\n renderDrawer={({ cards }) => <DrawerContent cards={cards} />}\n renderEmpty={() => <p>No cards</p>}\n/>;\n```\n\n### Trick display with player labels\n\n```tsx\nconst playerInfo = usePlayerInfo();\nconst { playCards } = useUIArgs();\nconst trickCards = playCards?.trickCards ?? []; // { cardId, playerId }[]\n\n<PlayArea\n cards={resolvedCards}\n layout="row"\n renderCard={(card) => (\n <div className="flex flex-col items-center gap-1">\n <span className="text-xs text-slate-400">\n {playerInfo[card.properties?.playedBy]?.name}\n </span>\n <SuitRankCard card={card} />\n </div>\n )}\n/>;\n```\n\n## UIArgs recommendations\n\n```typescript\n// shared/ui-args.ts\nexport interface PlayCardsUIArgs {\n legalCardIds: string[]; // Cards the player can legally play\n trickCards: { cardId: string; playerId: string }[]; // Cards in the current trick\n trickLeader: string | null; // Who led the trick\n trumpSuit?: string; // Trump suit if applicable\n}\n\nexport interface ScoringUIArgs {\n roundScores: Record<string, number>;\n totalScores: Record<string, number>;\n}\n```\n',
1949
- "references/ui-genre-worker-placement.md": '# UI Guide: Worker Placement Games\n\nPatterns for Agricola, Viticulture, Lords of Waterdeep, Caverna, and similar euro-style worker placement games.\n\n## Game characteristics\n\n- Players place **worker tokens** on shared **action slots** to gain resources or take actions.\n- Slots may be exclusive (one player per round) or shared.\n- Phases typically include: placement, resolution/harvest, and cleanup.\n- Key UI signals: available slots, slot costs/rewards, number of workers remaining, resource counts.\n\n## Recommended SDK components\n\n### Primary\n\n| Component | Usage |\n| --------------------- | ----------------------------------------------------------------------------------------------------- |\n| `SlotSystem` | Core board \u2014 renders all action slots with occupants. Use `layout="grouped"` to organize by category. |\n| `DefaultSlotItem` | Pre-built slot renderer showing name, description, capacity, cost/reward labels. |\n| `DefaultSlotOccupant` | Pre-built worker token display with player color. |\n| `ResourceCounter` | Display each player\'s resource pool (wood, stone, food, etc.). |\n| `ActionButton` | "Place Worker" button with integrated cost display and affordability check. |\n\n### Supporting\n\n| Component | Usage |\n| ----------------------------- | ------------------------------------------------------------ |\n| `ActionPanel` / `ActionGroup` | Group available actions (e.g., "Place Worker", "End Turn"). |\n| `CostDisplay` | Show resource costs on slot details. |\n| `PlayerInfo` | Show each player\'s name, workers remaining, and turn status. |\n| `PhaseIndicator` | Distinguish placement phase from harvest/scoring phases. |\n| `GameEndDisplay` | Final scoring with detailed breakdown. |\n| `Drawer` | Mobile drawer for detailed slot inspection. |\n\n### Hooks\n\n| Hook | Usage |\n| --------------------------------- | ---------------------------------------------------------------------------------------------- |\n| `useSlotSystem(slots, occupants)` | Utility for slot lookups: `getSlot`, `isFull`, `getRemainingCapacity`, `getOccupantsByPlayer`. |\n| `useMyResources()` | Current player\'s resource pool. |\n| `useGameState` | Get `isMyTurn`, `currentState`, `currentPlayerIds`. |\n| `useAction` | Submit place-worker or end-turn actions. |\n| `useUIArgs` | Get phase-specific data (available slots, worker count, etc.). |\n| `usePlayerInfo` | Map player IDs to names and colors. |\n\n## Key patterns\n\n### Slot board with placement\n\n```tsx\nconst { placementPhase } = useUIArgs();\nconst slots = placementPhase?.slots ?? [];\nconst occupants = placementPhase?.occupants ?? [];\nconst availableSlotIds = new Set(placementPhase?.availableSlotIds ?? []);\nconst slotApi = useSlotSystem(slots, occupants);\n\n<SlotSystem\n slots={slots}\n occupants={occupants}\n layout="grouped"\n renderSlot={(slot, slotOccupants) => (\n <DefaultSlotItem\n name={slot.name}\n description={slot.description}\n capacity={slot.capacity}\n occupantCount={slotOccupants.length}\n isExclusive={slot.exclusive}\n isAvailable={availableSlotIds.has(slot.id)}\n costLabel={formatCost(slot.cost)}\n rewardLabel={formatReward(slot.reward)}\n onClick={() => handlePlaceWorker(slot.id)}\n renderOccupants={() => (\n <div className="flex gap-1">\n {slotOccupants.map((o) => (\n <DefaultSlotOccupant\n key={o.pieceId}\n color={playerColors[o.playerId]}\n label={playerInfo[o.playerId]?.name}\n />\n ))}\n </div>\n )}\n />\n )}\n/>;\n```\n\n### Resource display\n\n```tsx\nconst resources = useMyResources();\n\n<ResourceCounter\n resources={[\n {\n type: "wood",\n label: "Wood",\n icon: TreePine,\n iconColor: "text-amber-700",\n },\n {\n type: "stone",\n label: "Stone",\n icon: Mountain,\n iconColor: "text-slate-400",\n },\n { type: "food", label: "Food", icon: Apple, iconColor: "text-red-400" },\n { type: "gold", label: "Gold", icon: Coins, iconColor: "text-yellow-400" },\n ]}\n counts={resources}\n layout="row"\n/>;\n```\n\n### Action buttons with costs\n\n```tsx\n<ActionButton\n label="Build Farm"\n cost={{ wood: 2, stone: 1 }}\n currentResources={resources}\n resourceDefs={resourceDefinitions}\n icon={Home}\n onClick={() => actions.buildActions.build({ buildingType: "farm" })}\n/>\n```\n\n## UIArgs recommendations\n\n```typescript\n// shared/ui-args.ts\nexport interface PlacementPhaseUIArgs {\n slots: SlotDefinition[];\n occupants: SlotOccupant[];\n availableSlotIds: string[]; // Slots the current player can legally place on\n workersRemaining: number;\n}\n\nexport interface HarvestPhaseUIArgs {\n feedingRequired: number; // Food needed\n currentFood: number;\n}\n```\n',
1950
- "references/ui-style-guide.md": '# UI Style Guide\n\nThis style guide details the design philosophy, visual tokens, and core components for the Dreamboard.games UI SDK. The framework uses a **Hand-Drawn** aesthetic that emphasizes human creativity over corporate polish.\n\n## Design Philosophy\n\nThe Hand-Drawn design style celebrates authentic imperfection and human touch in a digital world. It rejects clinical precision in favor of organic, playful irregularity that evokes sketches on paper, sticky notes on a wall, and napkin diagrams from a brainstorming session.\n\n### Core Principles\n\n- **No Straight Lines**: Every border, shape, and container uses irregular border-radius values to create wobbly, hand-drawn edges that reject geometric perfection.\n- **Authentic Texture**: The design layer paper grain, dot patterns, and subtle background textures to simulate physical media (notebook paper, post-its, sketch pads).\n- **Playful Rotation**: Elements are deliberately tilted using small rotation transforms (`-rotate-1`, `rotate-2`) to break rigid grid alignment and create casual energy.\n- **Hard Offset Shadows**: Reject soft blur shadows entirely. Use solid, offset box-shadows (like `4px 4px 0px`) to create a cut-paper, layered collage aesthetic.\n- **Handwritten Typography**: Use exclusively handwritten or marker-style fonts (like Kalam for headings and Patrick Hand for body text) that feel human and approachable.\n- **Limited Color Palette**: Stick to pencil blacks (`#2d2d2d`), paper whites (`#fdfbf7`), correction marker red (`#ff4d4d`), post-it yellow (`#fff9c4`), and ballpoint blue (`#2d5da1`).\n- **Intentional Messiness**: Embrace overlap, asymmetry, and visual "mistakes" that make the design feel spontaneous.\n\n## CSS Tokens & Utilities\n\nThe platform provides several global CSS utilities designed for this aesthetic:\n\n- **Borders**: `.wobbly-border`, `.wobbly-border-md`, `.wobbly-border-lg` apply the irregular `border-radius` shapes. Used with `border-2`, `border-[3px]`, or `border-[4px]`.\n- **Shadows**: `.hard-shadow`, `.hard-shadow-md`, `.hard-shadow-lg` apply the solid offset shadows. Use `.hard-shadow-sm` for active states (buttons pressing flat).\n\n## Implementing in Components\n\nWhen writing or modifying UI components in `ui/` or `ui-sdk/`:\n\n### Containers & Cards\n\n- Add `wobbly-border-md` or `wobbly-border-lg`.\n- Use `border-[3px] border-border` to give it a thick pencil-like stroke.\n- Apply `bg-[#fdfbf7]` (warm paper) or `bg-white`.\n- Add a solid shadow with `hard-shadow` or `hard-shadow-lg`.\n- Slightly rotate the element with `rotate-1` or `-rotate-1`.\n\n### Buttons\n\n- Use `wobbly-border`.\n- Normal state: `border-[3px] border-border bg-[#fdfbf7] text-foreground hard-shadow`.\n- Hover state: `hover:bg-primary hover:text-white hover:hard-shadow-sm hover:-translate-y-1`.\n- Active state: `active:shadow-none active:translate-y-1 active:translate-x-1`.\n- Secondary variants can use `bg-[#e5e0d8]` or `bg-[#fff9c4]`.\n\n### Typography\n\n- Add `font-sans` for standard handwritten text or `font-display` for bold marker headings.\n- Make things bold! `font-bold` works well with handwritten fonts to make them legible.\n\n### Decoration\n\n- For emphasis, wrap text in a post-it styling: `bg-[#fff9c4] px-2 py-1 border-2 border-border wobbly-border rotate-2 inline-block`.\n- Add "tape" to tops of containers: `<div className="absolute top-2 left-1/2 -translate-x-1/2 w-24 h-6 bg-[#e5e0d8] border border-border opacity-80 backdrop-blur-sm -rotate-2 z-10" />`.\n',
1951
- "scripts/events-extract.mjs": '#!/usr/bin/env node\n\nimport { access, readFile } from "node:fs/promises";\n\nconst DEFAULT_EVENTS_PATH = ".dreamboard/run/events.ndjson";\n\nfunction printHelp() {\n console.log(`Extract fields from dreamboard run artifacts.\n\nUsage:\n node .agents/skills/dreamboard/scripts/events-extract.mjs [options]\n\nOptions:\n --file, -f <path> NDJSON file path (default: ${DEFAULT_EVENTS_PATH})\n --type <eventType> Filter by event type (repeatable)\n --field <path> Dot path to extract (e.g. message.reason)\n --player <playerId> Filter by player ID across common message fields\n --limit <number> Limit output records\n --no-index Omit line index in output\n --help, -h Show this help\n\nExamples:\n node .agents/skills/dreamboard/scripts/events-extract.mjs --type YOUR_TURN\n node .agents/skills/dreamboard/scripts/events-extract.mjs --type ACTION_REJECTED --field message.reason\n node .agents/skills/dreamboard/scripts/events-extract.mjs --player player-2 --field message.availableActions\n`);\n}\n\nfunction parseCliArgs(argv) {\n const options = {\n filePath: DEFAULT_EVENTS_PATH,\n types: new Set(),\n includeIndex: true,\n };\n\n for (let index = 0; index < argv.length; index += 1) {\n const token = argv[index];\n const nextToken = argv[index + 1];\n\n if (token === "--help" || token === "-h") {\n printHelp();\n process.exit(0);\n }\n if (token === "--no-index") {\n options.includeIndex = false;\n continue;\n }\n if (token === "--file" || token === "-f") {\n if (!nextToken) {\n throw new Error("--file requires a value");\n }\n options.filePath = nextToken;\n index += 1;\n continue;\n }\n if (token === "--type") {\n if (!nextToken) {\n throw new Error("--type requires a value");\n }\n options.types.add(nextToken);\n index += 1;\n continue;\n }\n if (token === "--field") {\n if (!nextToken) {\n throw new Error("--field requires a value");\n }\n options.fieldPath = nextToken;\n index += 1;\n continue;\n }\n if (token === "--player") {\n if (!nextToken) {\n throw new Error("--player requires a value");\n }\n options.playerId = nextToken;\n index += 1;\n continue;\n }\n if (token === "--limit") {\n if (!nextToken) {\n throw new Error("--limit requires a value");\n }\n const parsed = Number.parseInt(nextToken, 10);\n if (!Number.isFinite(parsed) || parsed <= 0) {\n throw new Error("--limit must be a positive integer");\n }\n options.limit = parsed;\n index += 1;\n continue;\n }\n\n throw new Error(`Unknown argument: ${token}`);\n }\n\n return options;\n}\n\nfunction getByPath(value, path) {\n const segments = path.split(".").filter(Boolean);\n let current = value;\n\n for (const segment of segments) {\n if (current === null || current === undefined) {\n return undefined;\n }\n if (typeof current !== "object") {\n return undefined;\n }\n current = current[segment];\n }\n\n return current;\n}\n\nfunction extractPlayerCandidates(record) {\n const message = record.message ?? {};\n const players = new Set();\n\n const singleCandidates = [\n message.playerId,\n message.targetPlayer,\n message.toUser,\n ];\n for (const candidate of singleCandidates) {\n if (typeof candidate === "string") {\n players.add(candidate);\n }\n }\n\n const listCandidates = [\n message.activePlayers,\n message.previousPlayers,\n message.currentPlayers,\n message.controllablePlayerIds,\n message.eligiblePlayerIds,\n ];\n for (const candidate of listCandidates) {\n if (!Array.isArray(candidate)) {\n continue;\n }\n for (const item of candidate) {\n if (typeof item === "string") {\n players.add(item);\n }\n }\n }\n\n return [...players];\n}\n\nfunction toOutputRecord(record, lineIndex, options) {\n const output = {};\n\n if (options.includeIndex) {\n output.index = lineIndex;\n }\n output.observedAt = record.observedAt ?? null;\n output.sessionId = record.sessionId ?? null;\n output.eventId = record.eventId ?? null;\n output.type = record.type ?? null;\n\n if (options.fieldPath) {\n output.field = options.fieldPath;\n output.value = getByPath(record, options.fieldPath);\n } else {\n output.message = record.message ?? null;\n }\n\n return output;\n}\n\nasync function main() {\n const options = parseCliArgs(process.argv.slice(2));\n await access(options.filePath);\n\n const text = await readFile(options.filePath, "utf8");\n const lines = text\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line.length > 0);\n\n let emitted = 0;\n for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {\n const line = lines[lineIndex];\n let record;\n try {\n record = JSON.parse(line);\n } catch {\n continue;\n }\n\n if (options.types.size > 0 && !options.types.has(record.type ?? "")) {\n continue;\n }\n\n if (options.playerId) {\n const players = extractPlayerCandidates(record);\n if (!players.includes(options.playerId)) {\n continue;\n }\n }\n\n const output = toOutputRecord(record, lineIndex + 1, options);\n console.log(JSON.stringify(output));\n emitted += 1;\n\n if (options.limit !== undefined && emitted >= options.limit) {\n break;\n }\n }\n}\n\nmain().catch((error) => {\n const message = error instanceof Error ? error.message : String(error);\n console.error(`events-extract failed: ${message}`);\n process.exit(1);\n});\n',
1952
- "SKILL.md": "---\nname: dreamboard\ndescription: Create multiplayer, rule-enforced, turn-based board game on Dreamboard.games platform.\nmetadata:\n short-description: Dreamboard Game Development Workflow\n tags: [dreamboard, cli, game-dev, board-game, turn-based, multiplayer]\n---\n\n# Dreamboard\n\n## Goal\n\nCreate and iterate on a Dreamboard game locally, then sync rules, scaffold, UI, and tests back to the platform.\n\n## Why Dreamboard\n\nDreamboard exists to turn a board-game idea into a playable digital prototype quickly.\n\n- Describe the game instead of hand-building every primitive first.\n- Generate rules scaffolding, components, and UI structure faster.\n- Playtest with real players without repeated print-and-play friction.\n- Iterate live while Dreamboard handles turns, hands, and multiplayer plumbing.\n\n## Prereqs\n\n- Dreamboard CLI installed and available as `dreamboard`\n Install with `npm install -g dreamboard`\n- Authenticated via `dreamboard login`\n\n## Building Your First Game\n\nRead [references/building-your-first-game.md](references/building-your-first-game.md)\n\n## References\n\n- Rules and manifest:\n [references/rule-authoring.md](references/rule-authoring.md),\n [references/manifest-authoring.md](references/manifest-authoring.md)\n- App logic and engine concepts:\n [references/phase-handlers.md](references/phase-handlers.md),\n [references/api-reference.md](references/api-reference.md),\n [references/hands-vs-decks.md](references/hands-vs-decks.md),\n [references/all-players-tracking.md](references/all-players-tracking.md),\n [references/app-best-practices.md](references/app-best-practices.md)\n- UI and UX:\n [references/ui-best-practices.md](references/ui-best-practices.md),\n [references/ui-style-guide.md](references/ui-style-guide.md),\n genre references under `references/ui-genre-*.md`\n- TypeScript regression harness (`dreamboard test generate/run`):\n [references/test-harness.md](references/test-harness.md)\n- JSON runtime scenarios (`dreamboard run --scenario ...`):\n [references/scenario-format.md](references/scenario-format.md)\n- Rejection and edge-case pressure using JSON runtime scenarios:\n [references/adversarial-testing.md](references/adversarial-testing.md)\n\n## Testing Modes\n\nThere are two different scenario systems:\n\n- `dreamboard test generate` / `dreamboard test run`\n TypeScript scenario files in `test/scenarios/*.scenario.ts` against deterministic generated base snapshots. Use this for regression coverage.\n- `dreamboard run --scenario path/to/file.json`\n JSON action scripts that drive a live session. Use this for debugging flows, reproductions, and adversarial experiments.\n\n## Guardrails\n\n- `manifest.json` and `rule.md` are the source of truth for scaffolding.\n- Run `dreamboard sync` after manifest or rule changes to keep generated files in sync and advance the remote authoring head.\n- Run `dreamboard compile` when you want a new runnable build for the current authored state.\n- Use `dreamboard pull` only when you explicitly need to reconcile unexpected remote authored changes into the workspace.\n- `dreamboard test generate` should be re-run after base changes, compiled-result changes, or game identity changes.\n- Add at least one zero-step `initial-state` scenario so setup invariants fail before action tests begin.\n- Keep `scripts/events-extract.mjs` as a debugging helper for `.dreamboard/run/events.ndjson`; assertions belong in test scenarios.\n\n## Editable Surface\n\nEdit:\n\n- `app/phases/*.ts`\n- `shared/ui-args.ts`\n- `ui/App.tsx`\n- `ui/components/*`\n- `ui/sdk/components/*`\n\nDo not edit framework-owned files such as:\n\n- `app/index.ts`\n- `app/sdk/*`\n- `app/generated/*`\n- `ui/index.tsx`\n- `ui/sdk/context/*`\n- `ui/sdk/hooks/*`\n- `ui/sdk/types/*`\n\n## Framework Feedback\n\nUse `feedback.md` in the game project root to record framework issues, missing features, or workflow friction. Include reproduction steps, expected behavior, and actual behavior when possible.\n"
1953
- };
1954
- var SKILL_MD_CONTENT = SKILL_ASSET_FILES["SKILL.md"];
1955
-
1956
- // src/utils/fs.ts
1957
- async function ensureDir(dirPath) {
1958
- await mkdir(dirPath, { recursive: true });
1959
- }
1960
- async function installSkillFile(projectRoot) {
1961
- const skillRoot = path.join(projectRoot, ".agents", "skills", "dreamboard");
1962
- for (const [relativePath, content] of Object.entries(SKILL_ASSET_FILES)) {
1963
- const targetPath = path.join(skillRoot, relativePath);
1964
- await ensureDir(path.dirname(targetPath));
1965
- await writeFile(targetPath, content, "utf8");
1966
- }
1967
- }
1968
- async function exists(filePath) {
1969
- try {
1970
- await stat(filePath);
1971
- return true;
1972
- } catch {
1973
- return false;
1974
- }
1975
- }
1976
- async function readTextFile(filePath) {
1977
- return readFile(filePath, "utf8");
1978
- }
1979
- async function readTextFileIfExists(filePath) {
1980
- try {
1981
- return await readFile(filePath, "utf8");
1982
- } catch {
1983
- return null;
1984
- }
1985
- }
1986
- async function writeTextFile(filePath, content) {
1987
- await ensureDir(path.dirname(filePath));
1988
- await writeFile(filePath, content, "utf8");
1989
- }
1990
- async function readJsonFile(filePath) {
1991
- const data = await readTextFile(filePath);
1992
- return JSON.parse(data);
1993
- }
1994
- async function writeJsonFile(filePath, data) {
1995
- await writeTextFile(filePath, `${JSON.stringify(data, null, 2)}
1996
- `);
1997
- }
1998
-
1999
- // src/utils/crypto.ts
2000
- import crypto from "crypto";
2001
- function hashContent(content) {
2002
- return crypto.createHash("sha256").update(content, "utf8").digest("hex");
2003
- }
2004
-
2005
- // src/services/project/local-files.ts
2006
- import { readdir, unlink } from "fs/promises";
2007
- import path2 from "path";
2008
-
2009
- // src/constants.ts
2010
- var DEFAULT_API_BASE_URL = "https://api.dreamboard.games";
2011
- var DEFAULT_WEB_BASE_URL = "https://dreamboard.games";
2012
- var PROD_SUPABASE_URL = "https://upsjrgzihskmqporuaye.supabase.co";
2013
- var PROD_SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InVwc2pyZ3ppaHNrbXFwb3J1YXllIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjAwOTM1MjQsImV4cCI6MjA3NTY2OTUyNH0.9IZZ9Jmtqk4OzhQnkU7pApVx-IfdNjAt55ZKjOBjBB4";
2014
- var PROJECT_DIR_NAME = ".dreamboard";
2015
- var ENVIRONMENT_CONFIGS = {
2016
- local: {
2017
- apiBaseUrl: "http://localhost:8080",
2018
- webBaseUrl: "http://localhost:5173",
2019
- supabaseUrl: "http://127.0.0.1:54321",
2020
- supabaseAnonKey: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0"
2021
- },
2022
- dev: {
2023
- apiBaseUrl: "https://dev-dreamboard.fly.dev",
2024
- webBaseUrl: "https://dev.dreamboard.games",
2025
- supabaseUrl: "https://dev-supabase.dreamboard.games",
2026
- supabaseAnonKey: process.env.SUPABASE_DEV_ANON_KEY || ""
2027
- },
2028
- prod: {
2029
- apiBaseUrl: "https://api.dreamboard.games",
2030
- webBaseUrl: "https://dreamboard.games",
2031
- supabaseUrl: PROD_SUPABASE_URL,
2032
- supabaseAnonKey: PROD_SUPABASE_ANON_KEY
2033
- }
2034
- };
2035
- var PROJECT_CONFIG_FILE = "project.json";
2036
- var SNAPSHOT_FILE = "snapshot.json";
2037
- var MANIFEST_FILE = "manifest.json";
2038
- var RULE_FILE = "rule.md";
2039
- var DEFAULT_LOGIN_TIMEOUT_MS = 5 * 60 * 1e3;
2040
- var DEFAULT_TURN_DELAY_MS = 250;
2041
- var LOCAL_IGNORE_DIRS = /* @__PURE__ */ new Set([
2042
- ".dreamboard",
2043
- ".git",
2044
- "node_modules",
2045
- "dist"
2046
- ]);
2047
-
2048
- // src/services/project/scaffold-ownership.generated.ts
2049
- var SCAFFOLD_OWNERSHIP = {
2050
- version: 2,
2051
- allowedPaths: {
2052
- rootFiles: ["package.json", "manifest.json", "rule.md"],
2053
- directoryPrefixes: ["app/", "ui/", "shared/", "test/"]
2054
- },
2055
- dynamic: {
2056
- generatedFiles: [
2057
- "shared/manifest.ts",
2058
- "app/generated/guards.ts",
2059
- "app/index.ts"
2060
- ],
2061
- seedFiles: ["shared/ui-args.ts", "ui/App.tsx"],
2062
- seedFilePatterns: [
2063
- {
2064
- prefix: "app/phases/",
2065
- suffix: ".ts"
2066
- }
2067
- ]
2068
- },
2069
- cliStatic: {
2070
- exactFiles: [
2071
- "package.json",
2072
- "shared/game-message.d.ts",
2073
- "shared/index.ts",
2074
- "app/tsconfig.json",
2075
- "ui/index.tsx",
2076
- "ui/tsconfig.json",
2077
- "ui/package.json"
2078
- ],
2079
- directoryPrefixes: ["app/sdk/", "ui/sdk/"]
2080
- },
2081
- preservedUserFiles: ["shared/ui-args.ts"]
2082
- };
2083
-
2084
- // src/services/project/scaffold-ownership.ts
2085
- function normalizeProjectPath(filePath) {
2086
- return filePath.replace(/^\.\//, "").replace(/^\/+/, "").replace(/\\/g, "/");
2087
- }
2088
- function isAllowedGamePath(filePath) {
2089
- const path3 = normalizeProjectPath(filePath);
2090
- if (SCAFFOLD_OWNERSHIP.allowedPaths.rootFiles.includes(path3)) return true;
2091
- return SCAFFOLD_OWNERSHIP.allowedPaths.directoryPrefixes.some(
2092
- (prefix) => path3.startsWith(prefix)
2093
- );
2094
- }
2095
- function isDynamicGeneratedPath(filePath) {
2096
- const path3 = normalizeProjectPath(filePath);
2097
- return SCAFFOLD_OWNERSHIP.dynamic.generatedFiles.includes(path3);
2098
- }
2099
- function isDynamicSeedPath(filePath) {
2100
- const path3 = normalizeProjectPath(filePath);
2101
- if (SCAFFOLD_OWNERSHIP.dynamic.seedFiles.includes(path3)) return true;
2102
- return SCAFFOLD_OWNERSHIP.dynamic.seedFilePatterns.some(
2103
- (pattern) => path3.startsWith(pattern.prefix) && path3.endsWith(pattern.suffix)
2104
- );
2105
- }
2106
- function isCliStaticPath(filePath) {
2107
- const path3 = normalizeProjectPath(filePath);
2108
- if (SCAFFOLD_OWNERSHIP.cliStatic.exactFiles.includes(path3)) return true;
2109
- return SCAFFOLD_OWNERSHIP.cliStatic.directoryPrefixes.some(
2110
- (prefix) => path3.startsWith(prefix)
2111
- );
2112
- }
2113
- function isLibraryPath(filePath) {
2114
- return isDynamicGeneratedPath(filePath) || isCliStaticPath(filePath);
2115
- }
2116
- var PRESERVED_USER_FILES = new Set(
2117
- SCAFFOLD_OWNERSHIP.preservedUserFiles
2118
- );
2119
-
2120
- // src/services/project/local-files.ts
2121
- function isAllowedGamePath2(filePath) {
2122
- return isAllowedGamePath(filePath);
2123
- }
2124
- function isLibraryPath2(filePath) {
2125
- return isLibraryPath(filePath);
2126
- }
2127
- function shouldWriteScaffoldFile(filePath, existingContent) {
2128
- if (isLibraryPath2(filePath)) return "write";
2129
- const hasContent = existingContent !== null && existingContent.trim().length > 0;
2130
- return hasContent ? "skip" : "write";
2131
- }
2132
- async function writeSourceFiles(rootDir, files) {
2133
- for (const [relativePath, content] of Object.entries(files)) {
2134
- if (content === null || content === void 0) continue;
2135
- const filePath = path2.join(rootDir, relativePath);
2136
- await writeTextFile(filePath, content);
2137
- }
2138
- }
2139
- async function writeScaffoldFiles(rootDir, files) {
2140
- const written = [];
2141
- const skipped = [];
2142
- for (const [relativePath, content] of Object.entries(files)) {
2143
- if (content === null || content === void 0) continue;
2144
- const fullPath = path2.join(rootDir, relativePath);
2145
- const existingContent = await readTextFileIfExists(fullPath);
2146
- const decision = shouldWriteScaffoldFile(relativePath, existingContent);
2147
- if (decision === "skip") {
2148
- skipped.push(relativePath);
2149
- continue;
2150
- }
2151
- await writeTextFile(fullPath, content);
2152
- if (existingContent !== content) {
2153
- written.push(relativePath);
2154
- }
2155
- }
2156
- written.sort();
2157
- skipped.sort();
2158
- return { written, skipped };
2159
- }
2160
- async function removeExtraneousFiles(rootDir, keep) {
2161
- const localFiles = await collectLocalFiles(rootDir);
2162
- for (const filePath of Object.keys(localFiles)) {
2163
- if (filePath === MANIFEST_FILE || filePath === RULE_FILE) continue;
2164
- if (!keep.has(filePath)) {
2165
- await unlink(path2.join(rootDir, filePath));
2166
- }
2167
- }
2168
- }
2169
- async function collectLocalFiles(rootDir) {
2170
- const result = {};
2171
- await walkDir(rootDir, rootDir, result);
2172
- return result;
2173
- }
2174
- async function walkDir(rootDir, currentDir, result) {
2175
- const entries = await readdir(currentDir, { withFileTypes: true });
2176
- for (const entry of entries) {
2177
- if (entry.isDirectory()) {
2178
- if (LOCAL_IGNORE_DIRS.has(entry.name)) continue;
2179
- await walkDir(rootDir, path2.join(currentDir, entry.name), result);
2180
- } else if (entry.isFile()) {
2181
- const filePath = path2.join(currentDir, entry.name);
2182
- const relativePath = path2.relative(rootDir, filePath);
2183
- result[relativePath] = await readTextFile(filePath);
2184
- }
2185
- }
2186
- }
2187
- async function writeManifest(rootDir, manifest) {
2188
- const filePath = path2.join(rootDir, MANIFEST_FILE);
2189
- await writeTextFile(filePath, `${JSON.stringify(manifest, null, 2)}
2190
- `);
2191
- }
2192
- async function writeRule(rootDir, ruleText) {
2193
- const filePath = path2.join(rootDir, RULE_FILE);
2194
- await writeTextFile(filePath, ruleText);
2195
- }
2196
- async function loadManifest(rootDir) {
2197
- const filePath = path2.join(rootDir, MANIFEST_FILE);
2198
- return readJsonFile(filePath);
2199
- }
2200
- async function loadRule(rootDir) {
2201
- const filePath = path2.join(rootDir, RULE_FILE);
2202
- return readTextFile(filePath);
2203
- }
2204
- async function writeSnapshot(rootDir) {
2205
- const files = await collectLocalFiles(rootDir);
2206
- await writeSnapshotFromFiles(rootDir, files);
2207
- }
2208
- async function writeSnapshotFromFiles(rootDir, files) {
2209
- const snapshot = {
2210
- files: {}
2211
- };
2212
- for (const [filePath, content] of Object.entries(files)) {
2213
- if (filePath.startsWith(`${PROJECT_DIR_NAME}/`)) continue;
2214
- snapshot.files[filePath] = hashContent(content);
2215
- }
2216
- const snapshotPath = path2.join(rootDir, PROJECT_DIR_NAME, SNAPSHOT_FILE);
2217
- await writeJsonFile(snapshotPath, snapshot);
2218
- }
2219
- async function getLocalDiff(rootDir) {
2220
- const snapshotPath = path2.join(rootDir, PROJECT_DIR_NAME, SNAPSHOT_FILE);
2221
- const snapshot = await readJsonFile(snapshotPath).catch(() => null);
2222
- if (!snapshot) {
2223
- return { modified: [], added: [], deleted: [] };
2224
- }
2225
- const files = await collectLocalFiles(rootDir);
2226
- const currentHashes = {};
2227
- for (const [filePath, content] of Object.entries(files)) {
2228
- if (filePath.startsWith(`${PROJECT_DIR_NAME}/`)) continue;
2229
- currentHashes[filePath] = hashContent(content);
2230
- }
2231
- const modified = [];
2232
- const added = [];
2233
- const deleted = [];
2234
- for (const [filePath, hash] of Object.entries(currentHashes)) {
2235
- const prevHash = snapshot.files[filePath];
2236
- if (!prevHash) {
2237
- added.push(filePath);
2238
- } else if (prevHash !== hash) {
2239
- modified.push(filePath);
2240
- }
2241
- }
2242
- for (const filePath of Object.keys(snapshot.files)) {
2243
- if (!currentHashes[filePath]) {
2244
- deleted.push(filePath);
2245
- }
2246
- }
2247
- return { modified, added, deleted };
2248
- }
2249
-
2250
- // src/services/project/project-state.ts
2251
- function getProjectAuthoringState(projectConfig) {
2252
- return projectConfig.authoring ?? {};
2253
- }
2254
- function getProjectCompileState(projectConfig) {
2255
- return projectConfig.compile ?? {};
2256
- }
2257
- function updateProjectAuthoringState(projectConfig, authoring) {
2258
- return {
2259
- ...projectConfig,
2260
- authoring: {
2261
- ...getProjectAuthoringState(projectConfig),
2262
- ...authoring
2263
- }
2264
- };
2265
- }
2266
- function updateProjectCompileState(projectConfig, compile) {
2267
- return {
2268
- ...projectConfig,
2269
- compile: {
2270
- ...getProjectCompileState(projectConfig),
2271
- ...compile
2272
- }
2273
- };
2274
- }
2275
- function setLatestCompileAttempt(projectConfig, attempt) {
2276
- return updateProjectCompileState(projectConfig, {
2277
- ...getProjectCompileState(projectConfig),
2278
- latestAttempt: attempt,
2279
- latestSuccessful: attempt.status === "successful" && attempt.resultId ? {
2280
- resultId: attempt.resultId,
2281
- authoringStateId: attempt.authoringStateId
2282
- } : getProjectCompileState(projectConfig).latestSuccessful
2283
- });
2284
- }
2285
-
2286
- export {
2287
- consola,
2288
- client,
2289
- DEFAULT_API_BASE_URL,
2290
- DEFAULT_WEB_BASE_URL,
2291
- PROJECT_DIR_NAME,
2292
- ENVIRONMENT_CONFIGS,
2293
- PROJECT_CONFIG_FILE,
2294
- MANIFEST_FILE,
2295
- RULE_FILE,
2296
- DEFAULT_LOGIN_TIMEOUT_MS,
2297
- DEFAULT_TURN_DELAY_MS,
2298
- ensureDir,
2299
- installSkillFile,
2300
- exists,
2301
- readTextFile,
2302
- readTextFileIfExists,
2303
- writeTextFile,
2304
- readJsonFile,
2305
- writeJsonFile,
2306
- hashContent,
2307
- isAllowedGamePath,
2308
- isDynamicGeneratedPath,
2309
- isDynamicSeedPath,
2310
- isLibraryPath,
2311
- isAllowedGamePath2,
2312
- writeSourceFiles,
2313
- writeScaffoldFiles,
2314
- removeExtraneousFiles,
2315
- collectLocalFiles,
2316
- writeManifest,
2317
- writeRule,
2318
- loadManifest,
2319
- loadRule,
2320
- writeSnapshot,
2321
- writeSnapshotFromFiles,
2322
- getLocalDiff,
2323
- getProjectAuthoringState,
2324
- getProjectCompileState,
2325
- updateProjectAuthoringState,
2326
- setLatestCompileAttempt
2327
- };
2328
- //# sourceMappingURL=chunk-WM7TY7DV.js.map