@doodle-engine/cli 0.0.16 → 0.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/cli.js +293 -232
  3. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # @doodle-engine/cli
2
2
 
3
+ ## 0.0.17
4
+
5
+ ### Patch Changes
6
+
7
+ - 07107df: fix bluff checks
8
+ - Updated dependencies [07107df]
9
+ - @doodle-engine/core@0.0.17
10
+ - @doodle-engine/react@0.0.17
11
+
3
12
  ## 0.0.16
4
13
 
5
14
  ### Patch Changes
package/dist/cli.js CHANGED
@@ -1,84 +1,84 @@
1
1
  #!/usr/bin/env node
2
- import { Command as q } from "commander";
3
- import { crayon as i } from "crayon.js";
4
- import { createServer as G, build as $ } from "vite";
2
+ import { Command as x } from "commander";
3
+ import { crayon as s } from "crayon.js";
4
+ import { createServer as q, build as $ } from "vite";
5
5
  import S from "@vitejs/plugin-react";
6
6
  import { watch as H } from "chokidar";
7
- import { readdir as p, readFile as f, mkdir as D, writeFile as k } from "fs/promises";
8
- import { join as h, extname as g, relative as b, dirname as M } from "path";
9
- import { parse as y } from "yaml";
10
- import { parseDialogue as E } from "@doodle-engine/core";
7
+ import { readdir as p, readFile as f, mkdir as D, writeFile as w } from "fs/promises";
8
+ import { join as h, extname as g, relative as y, dirname as M } from "path";
9
+ import { parse as b } from "yaml";
10
+ import { parseDialogue as k } from "@doodle-engine/core";
11
11
  import F from "prompts";
12
- function I(t, a) {
12
+ function N(n, a) {
13
13
  const r = [];
14
- for (const o of Object.values(t.dialogues)) {
15
- const n = a.get(o.id) || `dialogue:${o.id}`;
16
- r.push(...P(o, n));
14
+ for (const o of Object.values(n.dialogues)) {
15
+ const t = a.get(o.id) || `dialogue:${o.id}`;
16
+ r.push(...B(o, t));
17
17
  }
18
- for (const o of Object.values(t.characters))
19
- if (o.dialogue && !t.dialogues[o.dialogue]) {
20
- const n = a.get(o.id) || `character:${o.id}`;
18
+ for (const o of Object.values(n.characters))
19
+ if (o.dialogue && !n.dialogues[o.dialogue]) {
20
+ const t = a.get(o.id) || `character:${o.id}`;
21
21
  r.push({
22
- file: n,
22
+ file: t,
23
23
  message: `Character "${o.id}" references non-existent dialogue "${o.dialogue}"`,
24
24
  suggestion: `Create dialogue "${o.dialogue}" or fix the reference`
25
25
  });
26
26
  }
27
- return r.push(...W(t, a)), r;
27
+ return r.push(...W(n, a)), r;
28
28
  }
29
- function P(t, a) {
29
+ function B(n, a) {
30
30
  const r = [], o = /* @__PURE__ */ new Set();
31
- for (const n of t.nodes)
32
- o.has(n.id) && r.push({
31
+ for (const t of n.nodes)
32
+ o.has(t.id) && r.push({
33
33
  file: a,
34
- message: `Duplicate node ID "${n.id}"`,
34
+ message: `Duplicate node ID "${t.id}"`,
35
35
  suggestion: "Node IDs must be unique within a dialogue"
36
- }), o.add(n.id);
37
- o.has(t.startNode) || r.push({
36
+ }), o.add(t.id);
37
+ o.has(n.startNode) || r.push({
38
38
  file: a,
39
- message: `Start node "${t.startNode}" not found`,
40
- suggestion: `Add a NODE ${t.startNode} or fix the startNode reference`
39
+ message: `Start node "${n.startNode}" not found`,
40
+ suggestion: `Add a NODE ${n.startNode} or fix the startNode reference`
41
41
  });
42
- for (const n of t.nodes)
43
- r.push(...B(n, o, a));
42
+ for (const t of n.nodes)
43
+ r.push(...L(t, o, a));
44
44
  return r;
45
45
  }
46
- function B(t, a, r) {
46
+ function L(n, a, r) {
47
47
  const o = [];
48
- if (t.next && !a.has(t.next) && o.push({
48
+ if (n.next && !a.has(n.next) && o.push({
49
49
  file: r,
50
- message: `Node "${t.id}" GOTO "${t.next}" points to non-existent node`,
51
- suggestion: `Add NODE ${t.next} or fix the GOTO target`
52
- }), t.conditionalNext)
53
- for (const n of t.conditionalNext)
54
- a.has(n.next) || o.push({
50
+ message: `Node "${n.id}" GOTO "${n.next}" points to non-existent node`,
51
+ suggestion: `Add NODE ${n.next} or fix the GOTO target`
52
+ }), n.conditionalNext)
53
+ for (const t of n.conditionalNext)
54
+ a.has(t.next) || o.push({
55
55
  file: r,
56
- message: `Node "${t.id}" IF block GOTO "${n.next}" points to non-existent node`,
57
- suggestion: `Add NODE ${n.next} or fix the GOTO target`
58
- }), o.push(...v(n.condition, t.id, r));
59
- for (const n of t.choices) {
60
- if (!n.effects?.some(
56
+ message: `Node "${n.id}" IF block GOTO "${t.next}" points to non-existent node`,
57
+ suggestion: `Add NODE ${t.next} or fix the GOTO target`
58
+ }), o.push(...v(t.condition, n.id, r));
59
+ for (const t of n.choices) {
60
+ if (!t.effects?.some(
61
61
  (e) => e.type === "endDialogue" || e.type === "goToLocation" || e.type === "startDialogue"
62
- ) && n.next && !a.has(n.next) && o.push({
62
+ ) && t.next && !a.has(t.next) && o.push({
63
63
  file: r,
64
- message: `Node "${t.id}" choice "${n.id}" GOTO "${n.next}" points to non-existent node`,
65
- suggestion: `Add NODE ${n.next} or fix the GOTO target`
66
- }), n.conditions)
67
- for (const e of n.conditions)
68
- o.push(...v(e, t.id, r));
69
- if (n.effects)
70
- for (const e of n.effects)
71
- o.push(...C(e, t.id, r));
64
+ message: `Node "${n.id}" choice "${t.id}" GOTO "${t.next}" points to non-existent node`,
65
+ suggestion: `Add NODE ${t.next} or fix the GOTO target`
66
+ }), t.conditions)
67
+ for (const e of t.conditions)
68
+ o.push(...v(e, n.id, r));
69
+ if (t.effects)
70
+ for (const e of t.effects)
71
+ o.push(...C(e, n.id, r));
72
72
  }
73
- if (t.conditions)
74
- for (const n of t.conditions)
75
- o.push(...v(n, t.id, r));
76
- if (t.effects)
77
- for (const n of t.effects)
78
- o.push(...C(n, t.id, r));
73
+ if (n.conditions)
74
+ for (const t of n.conditions)
75
+ o.push(...v(t, n.id, r));
76
+ if (n.effects)
77
+ for (const t of n.effects)
78
+ o.push(...C(t, n.id, r));
79
79
  return o;
80
80
  }
81
- const L = {
81
+ const P = {
82
82
  hasFlag: ["flag"],
83
83
  notFlag: ["flag"],
84
84
  hasItem: ["itemId"],
@@ -123,51 +123,51 @@ const L = {
123
123
  showInterlude: ["interludeId"],
124
124
  roll: ["variable", "min", "max"]
125
125
  };
126
- function v(t, a, r) {
126
+ function v(n, a, r) {
127
127
  const o = [];
128
- if (!t.type)
128
+ if (!n.type)
129
129
  return o.push({
130
130
  file: r,
131
131
  message: `Node "${a}" has condition with missing type`
132
132
  }), o;
133
- if (t.type === "timeIs")
134
- return t.hour === void 0 && t.day === void 0 && o.push({
133
+ if (n.type === "timeIs")
134
+ return n.hour === void 0 && n.day === void 0 && o.push({
135
135
  file: r,
136
136
  message: `Node "${a}" condition "timeIs" must have at least one of "hour" or "day" argument`
137
137
  }), o;
138
- const n = L[t.type];
139
- if (!n)
138
+ const t = P[n.type];
139
+ if (!t)
140
140
  return o;
141
- for (const s of n)
142
- (t[s] === void 0 || t[s] === null || t[s] === "") && o.push({
141
+ for (const i of t)
142
+ (n[i] === void 0 || n[i] === null || n[i] === "") && o.push({
143
143
  file: r,
144
- message: `Node "${a}" condition "${t.type}" missing required "${s}" argument`
144
+ message: `Node "${a}" condition "${n.type}" missing required "${i}" argument`
145
145
  });
146
146
  return o;
147
147
  }
148
- function C(t, a, r) {
148
+ function C(n, a, r) {
149
149
  const o = [];
150
- if (!t.type)
150
+ if (!n.type)
151
151
  return o.push({
152
152
  file: r,
153
153
  message: `Node "${a}" has effect with missing type`
154
154
  }), o;
155
- const n = U[t.type];
156
- if (!n)
155
+ const t = U[n.type];
156
+ if (!t)
157
157
  return o;
158
- for (const s of n)
159
- (t[s] === void 0 || t[s] === null || t[s] === "") && o.push({
158
+ for (const i of t)
159
+ (n[i] === void 0 || n[i] === null || n[i] === "") && o.push({
160
160
  file: r,
161
- message: `Node "${a}" effect "${t.type}" missing required "${s}" argument`
161
+ message: `Node "${a}" effect "${n.type}" missing required "${i}" argument`
162
162
  });
163
163
  return o;
164
164
  }
165
- function W(t, a) {
165
+ function W(n, a) {
166
166
  const r = [], o = /* @__PURE__ */ new Set();
167
- for (const e of Object.values(t.locales))
167
+ for (const e of Object.values(n.locales))
168
168
  for (const c of Object.keys(e))
169
169
  o.add(c);
170
- const n = (e) => e.startsWith("@"), s = (e, c, l) => {
170
+ const t = (e) => e.startsWith("@"), i = (e, c, l) => {
171
171
  const d = e.slice(1);
172
172
  if (!o.has(d)) {
173
173
  const u = a.get(c) || `${l}:${c}`;
@@ -178,86 +178,86 @@ function W(t, a) {
178
178
  });
179
179
  }
180
180
  };
181
- for (const e of Object.values(t.locations))
182
- n(e.name) && s(e.name, e.id, "location"), n(e.description) && s(e.description, e.id, "location");
183
- for (const e of Object.values(t.characters))
184
- n(e.name) && s(e.name, e.id, "character"), n(e.biography) && s(e.biography, e.id, "character");
185
- for (const e of Object.values(t.items))
186
- n(e.name) && s(e.name, e.id, "item"), n(e.description) && s(e.description, e.id, "item");
187
- for (const e of Object.values(t.quests)) {
188
- n(e.name) && s(e.name, e.id, "quest"), n(e.description) && s(e.description, e.id, "quest");
181
+ for (const e of Object.values(n.locations))
182
+ t(e.name) && i(e.name, e.id, "location"), t(e.description) && i(e.description, e.id, "location");
183
+ for (const e of Object.values(n.characters))
184
+ t(e.name) && i(e.name, e.id, "character"), t(e.biography) && i(e.biography, e.id, "character");
185
+ for (const e of Object.values(n.items))
186
+ t(e.name) && i(e.name, e.id, "item"), t(e.description) && i(e.description, e.id, "item");
187
+ for (const e of Object.values(n.quests)) {
188
+ t(e.name) && i(e.name, e.id, "quest"), t(e.description) && i(e.description, e.id, "quest");
189
189
  for (const c of e.stages)
190
- n(c.description) && s(c.description, e.id, "quest");
190
+ t(c.description) && i(c.description, e.id, "quest");
191
191
  }
192
- for (const e of Object.values(t.journalEntries))
193
- n(e.title) && s(e.title, e.id, "journal"), n(e.text) && s(e.text, e.id, "journal");
194
- for (const e of Object.values(t.dialogues))
192
+ for (const e of Object.values(n.journalEntries))
193
+ t(e.title) && i(e.title, e.id, "journal"), t(e.text) && i(e.text, e.id, "journal");
194
+ for (const e of Object.values(n.dialogues))
195
195
  for (const c of e.nodes) {
196
- n(c.text) && s(c.text, e.id, "dialogue");
196
+ t(c.text) && i(c.text, e.id, "dialogue");
197
197
  for (const l of c.choices)
198
- n(l.text) && s(l.text, e.id, "dialogue");
198
+ t(l.text) && i(l.text, e.id, "dialogue");
199
199
  }
200
- for (const e of Object.values(t.interludes))
201
- n(e.text) && s(e.text, e.id, "interlude");
200
+ for (const e of Object.values(n.interludes))
201
+ t(e.text) && i(e.text, e.id, "interlude");
202
202
  return r;
203
203
  }
204
- function N(t) {
205
- if (t.length === 0) {
206
- console.log(i.green("✓ No validation errors"));
204
+ function I(n) {
205
+ if (n.length === 0) {
206
+ console.log(s.green("✓ No validation errors"));
207
207
  return;
208
208
  }
209
- console.log(i.red(`
210
- ✗ Found ${t.length} validation error${t.length === 1 ? "" : "s"}:
209
+ console.log(s.red(`
210
+ ✗ Found ${n.length} validation error${n.length === 1 ? "" : "s"}:
211
211
  `));
212
- for (const a of t)
213
- console.log(i.bold(a.file) + (a.line ? `:${a.line}` : "")), console.log(" " + i.red(a.message)), a.suggestion && console.log(" " + i.dim(a.suggestion)), console.log();
212
+ for (const a of n)
213
+ console.log(s.bold(a.file) + (a.line ? `:${a.line}` : "")), console.log(" " + s.red(a.message)), a.suggestion && console.log(" " + s.dim(a.suggestion)), console.log();
214
214
  }
215
215
  const R = "ðŸū", J = "âœĻ", Q = "✏ïļ", Y = "➕";
216
216
  async function V() {
217
- const t = process.cwd(), a = h(t, "content");
218
- console.log(""), console.log(i.bold.magenta(` ${R} Doodle Engine Dev Server ${R}`)), console.log("");
217
+ const n = process.cwd(), a = h(n, "content");
218
+ console.log(""), console.log(s.bold.magenta(` ${R} Doodle Engine Dev Server ${R}`)), console.log("");
219
219
  const r = {
220
220
  name: "doodle-content-loader",
221
- configureServer(n) {
222
- n.middlewares.use("/api/content", async (d, u) => {
221
+ configureServer(t) {
222
+ t.middlewares.use("/api/content", async (d, u) => {
223
223
  try {
224
224
  const m = await K(a);
225
225
  u.setHeader("Content-Type", "application/json"), u.end(JSON.stringify(m));
226
226
  } catch (m) {
227
- console.error(i.red(" Error loading content:"), m), u.statusCode = 500, u.end(JSON.stringify({ error: "Failed to load content" }));
227
+ console.error(s.red(" Error loading content:"), m), u.statusCode = 500, u.end(JSON.stringify({ error: "Failed to load content" }));
228
228
  }
229
229
  });
230
- const s = H(a, {
230
+ const i = H(a, {
231
231
  ignored: /(^|[\/\\])\../,
232
232
  persistent: !0
233
233
  });
234
234
  let e = !1;
235
- s.on("ready", () => {
235
+ i.on("ready", () => {
236
236
  e = !0;
237
237
  });
238
238
  let c = null;
239
239
  const l = (d) => {
240
240
  c && clearTimeout(c), c = setTimeout(async () => {
241
- c = null, console.log(d), await z(a), n.ws.send({ type: "full-reload", path: "*" });
241
+ c = null, console.log(d), await z(a), t.ws.send({ type: "full-reload", path: "*" });
242
242
  }, 50);
243
243
  };
244
- s.on("change", (d) => {
245
- l(i.yellow(` ${Q} Content changed: ${d}`));
246
- }), s.on("add", (d) => {
247
- e && l(i.green(` ${Y} Content added: ${d}`));
244
+ i.on("change", (d) => {
245
+ l(s.yellow(` ${Q} Content changed: ${d}`));
246
+ }), i.on("add", (d) => {
247
+ e && l(s.green(` ${Y} Content added: ${d}`));
248
248
  });
249
249
  }
250
- }, o = await G({
251
- root: t,
250
+ }, o = await q({
251
+ root: n,
252
252
  plugins: [S(), r],
253
253
  server: {
254
254
  port: 3e3,
255
255
  open: !0
256
256
  }
257
257
  });
258
- await o.listen(), o.printUrls(), console.log(""), console.log(i.dim(` ${J} Watching content files for changes...`)), console.log("");
258
+ await o.listen(), o.printUrls(), console.log(""), console.log(s.dim(` ${J} Watching content files for changes...`)), console.log("");
259
259
  }
260
- async function K(t) {
260
+ async function K(n) {
261
261
  const a = {
262
262
  locations: {},
263
263
  characters: {},
@@ -279,41 +279,41 @@ async function K(t) {
279
279
  { dir: "journal", key: "journalEntries" },
280
280
  { dir: "interludes", key: "interludes" }
281
281
  ];
282
- for (const { dir: n, key: s } of o) {
283
- const e = h(t, n);
282
+ for (const { dir: t, key: i } of o) {
283
+ const e = h(n, t);
284
284
  try {
285
285
  const c = await p(e);
286
286
  for (const l of c)
287
287
  if (g(l) === ".yaml" || g(l) === ".yml") {
288
- const d = h(e, l), u = await f(d, "utf-8"), m = y(u);
289
- m && m.id && (a[s][m.id] = m);
288
+ const d = h(e, l), u = await f(d, "utf-8"), m = b(u);
289
+ m && m.id && (a[i][m.id] = m);
290
290
  }
291
291
  } catch {
292
292
  }
293
293
  }
294
294
  try {
295
- const n = h(t, "locales"), s = await p(n);
296
- for (const e of s)
295
+ const t = h(n, "locales"), i = await p(t);
296
+ for (const e of i)
297
297
  if (g(e) === ".yaml" || g(e) === ".yml") {
298
- const c = h(n, e), l = await f(c, "utf-8"), d = y(l), u = e.replace(/\.(yaml|yml)$/, "");
298
+ const c = h(t, e), l = await f(c, "utf-8"), d = b(l), u = e.replace(/\.(yaml|yml)$/, "");
299
299
  a.locales[u] = d ?? {};
300
300
  }
301
301
  } catch {
302
302
  }
303
303
  try {
304
- const n = h(t, "dialogues"), s = await p(n);
305
- for (const e of s)
304
+ const t = h(n, "dialogues"), i = await p(t);
305
+ for (const e of i)
306
306
  if (g(e) === ".dlg") {
307
- const c = h(n, e), l = await f(c, "utf-8"), d = e.replace(".dlg", ""), u = E(l, d);
307
+ const c = h(t, e), l = await f(c, "utf-8"), d = e.replace(".dlg", ""), u = k(l, d);
308
308
  a.dialogues[u.id] = u;
309
309
  }
310
310
  } catch {
311
311
  }
312
312
  try {
313
- const n = h(t, "game.yaml"), s = await f(n, "utf-8");
314
- r = y(s);
313
+ const t = h(n, "game.yaml"), i = await f(t, "utf-8");
314
+ r = b(i);
315
315
  } catch {
316
- console.warn(i.yellow(" No game.yaml found, using defaults")), r = {
316
+ console.warn(s.yellow(" No game.yaml found, using defaults")), r = {
317
317
  startLocation: "tavern",
318
318
  startTime: { day: 1, hour: 8 },
319
319
  startFlags: {},
@@ -323,15 +323,15 @@ async function K(t) {
323
323
  }
324
324
  return { registry: a, config: r };
325
325
  }
326
- async function z(t) {
326
+ async function z(n) {
327
327
  try {
328
- const { registry: a, fileMap: r } = await X(t), o = I(a, r);
329
- o.length > 0 && (console.log(""), N(o), console.log(""));
328
+ const { registry: a, fileMap: r } = await X(n), o = N(a, r);
329
+ o.length > 0 && (console.log(""), I(o), console.log(""));
330
330
  } catch (a) {
331
- console.error(i.red(" Error running validation:"), a);
331
+ console.error(s.red(" Error running validation:"), a);
332
332
  }
333
333
  }
334
- async function X(t) {
334
+ async function X(n) {
335
335
  const a = {
336
336
  locations: {},
337
337
  characters: {},
@@ -351,65 +351,65 @@ async function X(t) {
351
351
  { dir: "journal", key: "journalEntries" },
352
352
  { dir: "interludes", key: "interludes" }
353
353
  ];
354
- for (const { dir: n, key: s } of o) {
355
- const e = h(t, n);
354
+ for (const { dir: t, key: i } of o) {
355
+ const e = h(n, t);
356
356
  try {
357
357
  const c = await p(e);
358
358
  for (const l of c)
359
359
  if (g(l) === ".yaml" || g(l) === ".yml") {
360
- const d = h(e, l), u = await f(d, "utf-8"), m = y(u);
361
- m && m.id && (a[s][m.id] = m, r.set(m.id, b(process.cwd(), d)));
360
+ const d = h(e, l), u = await f(d, "utf-8"), m = b(u);
361
+ m && m.id && (a[i][m.id] = m, r.set(m.id, y(process.cwd(), d)));
362
362
  }
363
363
  } catch {
364
364
  }
365
365
  }
366
366
  try {
367
- const n = h(t, "locales"), s = await p(n);
368
- for (const e of s)
367
+ const t = h(n, "locales"), i = await p(t);
368
+ for (const e of i)
369
369
  if (g(e) === ".yaml" || g(e) === ".yml") {
370
- const c = h(n, e), l = await f(c, "utf-8"), d = y(l), u = e.replace(/\.(yaml|yml)$/, "");
370
+ const c = h(t, e), l = await f(c, "utf-8"), d = b(l), u = e.replace(/\.(yaml|yml)$/, "");
371
371
  a.locales[u] = d ?? {};
372
372
  }
373
373
  } catch {
374
374
  }
375
375
  try {
376
- const n = h(t, "dialogues"), s = await p(n);
377
- for (const e of s)
376
+ const t = h(n, "dialogues"), i = await p(t);
377
+ for (const e of i)
378
378
  if (g(e) === ".dlg") {
379
- const c = h(n, e), l = await f(c, "utf-8"), d = e.replace(".dlg", ""), u = E(l, d);
380
- a.dialogues[u.id] = u, r.set(u.id, b(process.cwd(), c));
379
+ const c = h(t, e), l = await f(c, "utf-8"), d = e.replace(".dlg", ""), u = k(l, d);
380
+ a.dialogues[u.id] = u, r.set(u.id, y(process.cwd(), c));
381
381
  }
382
382
  } catch {
383
383
  }
384
384
  return { registry: a, fileMap: r };
385
385
  }
386
386
  async function Z() {
387
- const t = process.cwd(), a = h(t, "content");
388
- console.log(""), console.log(i.bold.magenta("🐕 Building Doodle Engine game...")), console.log(""), console.log(i.dim("Validating content..."));
387
+ const n = process.cwd(), a = h(n, "content");
388
+ console.log(""), console.log(s.bold.magenta("🐕 Building Doodle Engine game...")), console.log(""), console.log(s.dim("Validating content..."));
389
389
  let r;
390
390
  try {
391
- const { registry: o, fileMap: n, config: s } = await ee(a), e = I(o, n);
392
- N(e), e.length > 0 && (console.log(i.red("Build failed due to validation errors.")), console.log(""), process.exit(1)), r = { registry: o, config: s };
391
+ const { registry: o, fileMap: t, config: i } = await ee(a), e = N(o, t);
392
+ I(e), e.length > 0 && (console.log(s.red("Build failed due to validation errors.")), console.log(""), process.exit(1)), r = { registry: o, config: i };
393
393
  } catch (o) {
394
- console.error(i.red("Error loading content:"), o), process.exit(1);
394
+ console.error(s.red("Error loading content:"), o), process.exit(1);
395
395
  }
396
396
  console.log("");
397
397
  try {
398
398
  await $({
399
- root: t,
399
+ root: n,
400
400
  plugins: [S()],
401
401
  build: {
402
402
  outDir: "dist",
403
403
  emptyOutDir: !0
404
404
  }
405
405
  });
406
- const o = h(t, "dist", "api");
407
- await D(o, { recursive: !0 }), await k(h(o, "content"), JSON.stringify(r)), console.log(""), console.log(i.green("✅ Build complete! Output in dist/")), console.log(""), console.log("To preview the build:"), console.log(i.dim(" yarn preview")), console.log("");
406
+ const o = h(n, "dist", "api");
407
+ await D(o, { recursive: !0 }), await w(h(o, "content"), JSON.stringify(r)), console.log(""), console.log(s.green("✅ Build complete! Output in dist/")), console.log(""), console.log("To preview the build:"), console.log(s.dim(" yarn preview")), console.log("");
408
408
  } catch (o) {
409
- console.error(i.red("Build failed:"), o), process.exit(1);
409
+ console.error(s.red("Build failed:"), o), process.exit(1);
410
410
  }
411
411
  }
412
- async function ee(t) {
412
+ async function ee(n) {
413
413
  const a = {
414
414
  locations: {},
415
415
  characters: {},
@@ -429,56 +429,56 @@ async function ee(t) {
429
429
  { dir: "journal", key: "journalEntries" },
430
430
  { dir: "interludes", key: "interludes" }
431
431
  ];
432
- for (const { dir: s, key: e } of o) {
433
- const c = h(t, s);
432
+ for (const { dir: i, key: e } of o) {
433
+ const c = h(n, i);
434
434
  try {
435
435
  const l = await p(c);
436
436
  for (const d of l)
437
437
  if (g(d) === ".yaml" || g(d) === ".yml") {
438
- const u = h(c, d), m = await f(u, "utf-8"), w = y(m);
439
- w && w.id && (a[e][w.id] = w, r.set(w.id, b(process.cwd(), u)));
438
+ const u = h(c, d), m = await f(u, "utf-8"), E = b(m);
439
+ E && E.id && (a[e][E.id] = E, r.set(E.id, y(process.cwd(), u)));
440
440
  }
441
441
  } catch {
442
442
  }
443
443
  }
444
444
  try {
445
- const s = h(t, "locales"), e = await p(s);
445
+ const i = h(n, "locales"), e = await p(i);
446
446
  for (const c of e)
447
447
  if (g(c) === ".yaml" || g(c) === ".yml") {
448
- const l = h(s, c), d = await f(l, "utf-8"), u = y(d), m = c.replace(/\.(yaml|yml)$/, "");
448
+ const l = h(i, c), d = await f(l, "utf-8"), u = b(d), m = c.replace(/\.(yaml|yml)$/, "");
449
449
  a.locales[m] = u ?? {};
450
450
  }
451
451
  } catch {
452
452
  }
453
453
  try {
454
- const s = h(t, "dialogues"), e = await p(s);
454
+ const i = h(n, "dialogues"), e = await p(i);
455
455
  for (const c of e)
456
456
  if (g(c) === ".dlg") {
457
- const l = h(s, c), d = await f(l, "utf-8"), u = c.replace(".dlg", ""), m = E(d, u);
458
- a.dialogues[m.id] = m, r.set(m.id, b(process.cwd(), l));
457
+ const l = h(i, c), d = await f(l, "utf-8"), u = c.replace(".dlg", ""), m = k(d, u);
458
+ a.dialogues[m.id] = m, r.set(m.id, y(process.cwd(), l));
459
459
  }
460
460
  } catch {
461
461
  }
462
- let n = null;
462
+ let t = null;
463
463
  try {
464
- const s = h(t, "game.yaml"), e = await f(s, "utf-8");
465
- n = y(e);
464
+ const i = h(n, "game.yaml"), e = await f(i, "utf-8");
465
+ t = b(e);
466
466
  } catch {
467
- n = { id: "game", startLocation: "", startTime: { day: 1, hour: 8 }, startFlags: {}, startVariables: {}, startInventory: [] };
467
+ t = { id: "game", startLocation: "", startTime: { day: 1, hour: 8 }, startFlags: {}, startVariables: {}, startInventory: [] };
468
468
  }
469
- return { registry: a, fileMap: r, config: n };
469
+ return { registry: a, fileMap: r, config: t };
470
470
  }
471
- async function te() {
472
- const t = process.cwd(), a = h(t, "content");
473
- console.log(""), console.log(i.bold.magenta("ðŸū Validating Doodle Engine content...")), console.log("");
471
+ async function ne() {
472
+ const n = process.cwd(), a = h(n, "content");
473
+ console.log(""), console.log(s.bold.magenta("ðŸū Validating Doodle Engine content...")), console.log("");
474
474
  try {
475
- const { registry: r, fileMap: o } = await ne(a), n = I(r, o);
476
- N(n), n.length > 0 && process.exit(1);
475
+ const { registry: r, fileMap: o } = await te(a), t = N(r, o);
476
+ I(t), t.length > 0 && process.exit(1);
477
477
  } catch (r) {
478
- console.error(i.red("Error loading content:"), r), process.exit(1);
478
+ console.error(s.red("Error loading content:"), r), process.exit(1);
479
479
  }
480
480
  }
481
- async function ne(t) {
481
+ async function te(n) {
482
482
  const a = {
483
483
  locations: {},
484
484
  characters: {},
@@ -496,33 +496,33 @@ async function ne(t) {
496
496
  { dir: "quests", key: "quests" },
497
497
  { dir: "journal", key: "journalEntries" }
498
498
  ];
499
- for (const { dir: n, key: s } of o) {
500
- const e = h(t, n);
499
+ for (const { dir: t, key: i } of o) {
500
+ const e = h(n, t);
501
501
  try {
502
502
  const c = await p(e);
503
503
  for (const l of c)
504
504
  if (g(l) === ".yaml" || g(l) === ".yml") {
505
- const d = h(e, l), u = await f(d, "utf-8"), m = y(u);
506
- m && m.id && (a[s][m.id] = m, r.set(m.id, b(process.cwd(), d)));
505
+ const d = h(e, l), u = await f(d, "utf-8"), m = b(u);
506
+ m && m.id && (a[i][m.id] = m, r.set(m.id, y(process.cwd(), d)));
507
507
  }
508
508
  } catch {
509
509
  }
510
510
  }
511
511
  try {
512
- const n = h(t, "locales"), s = await p(n);
513
- for (const e of s)
512
+ const t = h(n, "locales"), i = await p(t);
513
+ for (const e of i)
514
514
  if (g(e) === ".yaml" || g(e) === ".yml") {
515
- const c = h(n, e), l = await f(c, "utf-8"), d = y(l), u = e.replace(/\.(yaml|yml)$/, "");
515
+ const c = h(t, e), l = await f(c, "utf-8"), d = b(l), u = e.replace(/\.(yaml|yml)$/, "");
516
516
  a.locales[u] = d ?? {};
517
517
  }
518
518
  } catch {
519
519
  }
520
520
  try {
521
- const n = h(t, "dialogues"), s = await p(n);
522
- for (const e of s)
521
+ const t = h(n, "dialogues"), i = await p(t);
522
+ for (const e of i)
523
523
  if (g(e) === ".dlg") {
524
- const c = h(n, e), l = await f(c, "utf-8"), d = e.replace(".dlg", ""), u = E(l, d);
525
- a.dialogues[u.id] = u, r.set(u.id, b(process.cwd(), c));
524
+ const c = h(t, e), l = await f(c, "utf-8"), d = e.replace(".dlg", ""), u = k(l, d);
525
+ a.dialogues[u.id] = u, r.set(u.id, y(process.cwd(), c));
526
526
  }
527
527
  } catch {
528
528
  }
@@ -561,14 +561,14 @@ dist
561
561
  },
562
562
  "include": ["src"]
563
563
  }
564
- `, se = `id: bartender
564
+ `, ie = `id: bartender
565
565
  name: "@character.bartender.name"
566
566
  biography: "@character.bartender.bio"
567
567
  portrait: ""
568
568
  location: tavern
569
569
  dialogue: bartender_greeting
570
570
  stats: {}
571
- `, ie = `id: merchant
571
+ `, se = `id: merchant
572
572
  name: "@character.merchant.name"
573
573
  biography: "@character.merchant.bio"
574
574
  portrait: ""
@@ -652,9 +652,9 @@ NODE order_drink
652
652
  GOTO after_drink
653
653
  END
654
654
 
655
- # Try to bluff a free drink — launches the skill check dialogue (demonstrates: START dialogue)
655
+ # Try to bluff a free drink — rolls dice inline (demonstrates: ROLL + GOTO within one dialogue)
656
656
  CHOICE @bartender.choice.try_bluff
657
- START dialogue bluff_check
657
+ GOTO bluff_attempt
658
658
  END
659
659
 
660
660
  # Always available as an out
@@ -662,6 +662,41 @@ NODE order_drink
662
662
  GOTO start
663
663
  END
664
664
 
665
+ NODE bluff_attempt
666
+ # Roll happens immediately on entering this node — auto-advances to success or failure
667
+ ROLL bluffRoll 1 20
668
+ IF variableGreaterThan bluffRoll 14
669
+ GOTO bluff_success
670
+ END
671
+ GOTO bluff_failure
672
+
673
+ NODE bluff_success
674
+ BARTENDER: @bluff.success.bartender
675
+ ADD relationship bartender 2
676
+ SET flag bluffedMarcus
677
+
678
+ CHOICE @bluff.choice.cheers
679
+ GOTO start
680
+ END
681
+
682
+ NODE bluff_failure
683
+ BARTENDER: @bluff.failure.bartender
684
+
685
+ CHOICE @bluff.choice.fine_pay
686
+ REQUIRE variableGreaterThan gold 4
687
+ ADD variable gold -5
688
+ ADD variable _drinksBought 1
689
+ ADD variable reputation 1
690
+ SET flag hadDrink
691
+ ADD relationship bartender 1
692
+ NOTIFY @notification.bought_drink
693
+ GOTO start
694
+ END
695
+
696
+ CHOICE @bluff.choice.walk_away
697
+ GOTO start
698
+ END
699
+
665
700
  NODE after_drink
666
701
  BARTENDER: @bartender.after_drink
667
702
 
@@ -722,13 +757,17 @@ NODE work_done
722
757
  NODE farewell
723
758
  BARTENDER: @bartender.farewell
724
759
  END dialogue
725
- `, le = `# Skill check example — demonstrates dice rolling and variable interpolation.
760
+ `, le = `# Standalone skill-check demo — demonstrates dice syntax in isolation.
726
761
  #
727
762
  # ROLL <variable> <min> <max> — rolls a random integer and stores it in a variable.
728
763
  # {varName} — in dialogue text, replaced with the variable's value.
729
764
  # roll <min> <max> <threshold> — condition: rolls and returns true if result >= threshold.
730
765
  #
731
- # This dialogue is NOT auto-triggered — start it from another node with:
766
+ # The actual bluff check in this scaffold is inlined into bartender_greeting.dlg
767
+ # so it can flow back into the bartender conversation (GOTO after_drink, GOTO start).
768
+ #
769
+ # Use START dialogue to launch a self-contained dialogue that doesn't need to
770
+ # return to the caller. For example, from a CHOICE in another dialogue:
732
771
  # START dialogue bluff_check
733
772
 
734
773
  NODE start
@@ -757,14 +796,31 @@ NODE resolve
757
796
  GOTO failure
758
797
 
759
798
  NODE success
760
- NARRATOR: @bluff.success
799
+ NARRATOR: @bluff.success.narration
800
+ BARTENDER: @bluff.success.bartender
761
801
  ADD relationship bartender 2
762
802
  SET flag bluffedMarcus
763
- END dialogue
803
+
804
+ CHOICE @bluff.choice.cheers
805
+ END dialogue
806
+ END
764
807
 
765
808
  NODE failure
766
- NARRATOR: @bluff.failure
767
- END dialogue
809
+ NARRATOR: @bluff.failure.narration
810
+ BARTENDER: @bluff.failure.bartender
811
+
812
+ # Still have to pay — or just walk away
813
+ CHOICE @bluff.choice.fine_pay
814
+ REQUIRE variableGreaterThan gold 4
815
+ ADD variable gold -5
816
+ SET flag hadDrink
817
+ NOTIFY @notification.bought_drink
818
+ END dialogue
819
+ END
820
+
821
+ CHOICE @bluff.choice.walk_away
822
+ END dialogue
823
+ END
768
824
  `, de = `# One-time narrator intro for the market. Same pattern as tavern_intro.dlg.
769
825
 
770
826
  TRIGGER market
@@ -962,11 +1018,11 @@ stats: {}
962
1018
  title: "@journal.market_square.title"
963
1019
  text: "@journal.market_square.text"
964
1020
  category: places
965
- `, ye = `id: odd_jobs_accepted
1021
+ `, be = `id: odd_jobs_accepted
966
1022
  title: "@journal.odd_jobs_accepted.title"
967
1023
  text: "@journal.odd_jobs_accepted.text"
968
1024
  category: quests
969
- `, be = `id: tavern_discovery
1025
+ `, ye = `id: tavern_discovery
970
1026
  title: "@journal.tavern_discovery.title"
971
1027
  text: "@journal.tavern_discovery.text"
972
1028
  category: places
@@ -1108,21 +1164,26 @@ bluff.choice.attempt: "Try to bluff him."
1108
1164
  bluff.choice.back_down: "Actually, never mind."
1109
1165
  bluff.backed_down: "Some fights aren't worth picking."
1110
1166
  bluff.rolled: "You spin the tale with {bluffRoll} on your roll — and Marcus listens carefully."
1111
- bluff.success: "The story lands perfectly. Marcus laughs and slides a free drink across the bar. Not bad at all, he admits."
1112
- bluff.failure: "Marcus raises an eyebrow, entirely unconvinced. That will be five gold, he says flatly."
1113
- `, we = `id: market
1167
+ bluff.success.narration: "The story lands perfectly. Marcus laughs and slides a free drink across the bar."
1168
+ bluff.success.bartender: "Sure, this one's on the house."
1169
+ bluff.failure.narration: "Marcus raises an eyebrow, entirely unconvinced."
1170
+ bluff.failure.bartender: "Nope. That'll be five gold."
1171
+ bluff.choice.cheers: "Cheers!"
1172
+ bluff.choice.fine_pay: "Fine. Here's five gold."
1173
+ bluff.choice.walk_away: "Never mind then."
1174
+ `, Ee = `id: market
1114
1175
  name: "@location.market.name"
1115
1176
  description: "@location.market.description"
1116
1177
  banner: ""
1117
1178
  music: ""
1118
1179
  ambient: ""
1119
- `, ke = `id: tavern
1180
+ `, we = `id: tavern
1120
1181
  name: "@location.tavern.name"
1121
1182
  description: "@location.tavern.description"
1122
1183
  banner: ""
1123
1184
  music: ""
1124
1185
  ambient: ""
1125
- `, Ee = `id: town
1186
+ `, ke = `id: town
1126
1187
  name: "@map.town.name"
1127
1188
  image: ""
1128
1189
  scale: 1
@@ -1272,7 +1333,7 @@ export function App() {
1272
1333
  -webkit-font-smoothing: antialiased;
1273
1334
  -moz-osx-font-smoothing: grayscale;
1274
1335
  }
1275
- `, Ie = `import { StrictMode } from 'react'
1336
+ `, Ne = `import { StrictMode } from 'react'
1276
1337
  import { createRoot } from 'react-dom/client'
1277
1338
  import { App } from './App'
1278
1339
  import './index.css'
@@ -1282,12 +1343,12 @@ createRoot(document.getElementById('root')!).render(
1282
1343
  <App />
1283
1344
  </StrictMode>,
1284
1345
  )
1285
- `, O = "ðŸū", Ne = "🐕", j = "ðŸĶī", Ce = "âœĻ", x = "📁", T = "✅", Re = "🚀", A = /* @__PURE__ */ Object.assign({
1346
+ `, O = "ðŸū", Ie = "🐕", j = "ðŸĶī", Ce = "âœĻ", G = "📁", T = "✅", Re = "🚀", A = /* @__PURE__ */ Object.assign({
1286
1347
  "./templates/_root/_gitignore": oe,
1287
1348
  "./templates/_root/index.html": ae,
1288
1349
  "./templates/_root/tsconfig.json": re,
1289
- "./templates/content/characters/bartender.yaml": se,
1290
- "./templates/content/characters/merchant.yaml": ie,
1350
+ "./templates/content/characters/bartender.yaml": ie,
1351
+ "./templates/content/characters/merchant.yaml": se,
1291
1352
  "./templates/content/dialogues/bartender_greeting.dlg": ce,
1292
1353
  "./templates/content/dialogues/bluff_check.dlg": le,
1293
1354
  "./templates/content/dialogues/market_intro.dlg": de,
@@ -1297,20 +1358,20 @@ createRoot(document.getElementById('root')!).render(
1297
1358
  "./templates/content/interludes/chapter_one.yaml": ge,
1298
1359
  "./templates/content/items/old_coin.yaml": fe,
1299
1360
  "./templates/content/journal/market_square.yaml": pe,
1300
- "./templates/content/journal/odd_jobs_accepted.yaml": ye,
1301
- "./templates/content/journal/tavern_discovery.yaml": be,
1361
+ "./templates/content/journal/odd_jobs_accepted.yaml": be,
1362
+ "./templates/content/journal/tavern_discovery.yaml": ye,
1302
1363
  "./templates/content/locales/en.yaml": _e,
1303
- "./templates/content/locations/market.yaml": we,
1304
- "./templates/content/locations/tavern.yaml": ke,
1305
- "./templates/content/maps/town.yaml": Ee,
1364
+ "./templates/content/locations/market.yaml": Ee,
1365
+ "./templates/content/locations/tavern.yaml": we,
1366
+ "./templates/content/maps/town.yaml": ke,
1306
1367
  "./templates/content/quests/odd_jobs.yaml": ve,
1307
1368
  "./templates/src/App.custom.tsx": Oe,
1308
1369
  "./templates/src/App.default.tsx": De,
1309
1370
  "./templates/src/index.css": Te,
1310
- "./templates/src/main.tsx": Ie
1371
+ "./templates/src/main.tsx": Ne
1311
1372
  });
1312
- function Ae(t) {
1313
- const a = t.replace("./templates/", "");
1373
+ function Ae(n) {
1374
+ const a = n.replace("./templates/", "");
1314
1375
  if (a === "src/App.default.tsx" || a === "src/App.custom.tsx") return null;
1315
1376
  if (a.startsWith("_root/")) {
1316
1377
  const r = a.slice(6);
@@ -1318,19 +1379,19 @@ function Ae(t) {
1318
1379
  }
1319
1380
  return a;
1320
1381
  }
1321
- async function Se(t) {
1322
- const a = h(process.cwd(), t);
1323
- console.log(""), console.log(i.bold.magenta(` ${O} Doodle Engine ${O}`)), console.log(i.dim(" Text-based RPG and Adventure Game Scaffolder")), console.log(""), console.log(` ${Ne} Creating new game: ${i.bold.cyan(t)}`), console.log("");
1382
+ async function Se(n) {
1383
+ const a = h(process.cwd(), n);
1384
+ console.log(""), console.log(s.bold.magenta(` ${O} Doodle Engine ${O}`)), console.log(s.dim(" Text-based RPG and Adventure Game Scaffolder")), console.log(""), console.log(` ${Ie} Creating new game: ${s.bold.cyan(n)}`), console.log("");
1324
1385
  const { useDefaultRenderer: r } = await F({
1325
1386
  type: "confirm",
1326
1387
  name: "useDefaultRenderer",
1327
1388
  message: "Use default renderer?",
1328
1389
  initial: !0
1329
1390
  });
1330
- r === void 0 && (console.log(i.yellow(`
1331
- ${j} No worries, maybe next time! Woof!`)), process.exit(0)), console.log(""), await je(a, t, r), console.log(""), console.log(i.bold.green(` ${T} Project created successfully!`)), console.log(""), console.log(i.dim(` ${x} ${a}`)), console.log(""), console.log(i.bold(" Next steps:")), console.log(i.cyan(` cd ${t}`)), console.log(i.cyan(" npm install ") + i.dim("# or: yarn install / pnpm install")), console.log(i.cyan(" npm run dev ") + i.dim("# or: yarn dev / pnpm dev")), console.log(""), console.log(i.dim(` ${Re} Happy game making! ${O}`)), console.log("");
1391
+ r === void 0 && (console.log(s.yellow(`
1392
+ ${j} No worries, maybe next time! Woof!`)), process.exit(0)), console.log(""), await je(a, n, r), console.log(""), console.log(s.bold.green(` ${T} Project created successfully!`)), console.log(""), console.log(s.dim(` ${G} ${a}`)), console.log(""), console.log(s.bold(" Next steps:")), console.log(s.cyan(` cd ${n}`)), console.log(s.cyan(" npm install ") + s.dim("# or: yarn install / pnpm install")), console.log(s.cyan(" npm run dev ") + s.dim("# or: yarn dev / pnpm dev")), console.log(""), console.log(s.dim(` ${Re} Happy game making! ${O}`)), console.log("");
1332
1393
  }
1333
- async function je(t, a, r) {
1394
+ async function je(n, a, r) {
1334
1395
  const o = [
1335
1396
  "content/locations",
1336
1397
  "content/characters",
@@ -1350,11 +1411,11 @@ async function je(t, a, r) {
1350
1411
  "assets/audio/voice",
1351
1412
  "src"
1352
1413
  ];
1353
- console.log(` ${x} ${i.bold("Creating directories...")}`);
1414
+ console.log(` ${G} ${s.bold("Creating directories...")}`);
1354
1415
  for (const e of o)
1355
- await D(h(t, e), { recursive: !0 });
1356
- console.log(i.green(` ${T} Directories created`)), console.log("");
1357
- const n = {
1416
+ await D(h(n, e), { recursive: !0 });
1417
+ console.log(s.green(` ${T} Directories created`)), console.log("");
1418
+ const t = {
1358
1419
  name: a,
1359
1420
  version: "0.1.0",
1360
1421
  type: "module",
@@ -1378,20 +1439,20 @@ async function je(t, a, r) {
1378
1439
  vite: "^6.0.0"
1379
1440
  }
1380
1441
  };
1381
- console.log(` ${Ce} ${i.bold("Writing project files...")}`), await k(h(t, "package.json"), JSON.stringify(n, null, 2));
1442
+ console.log(` ${Ce} ${s.bold("Writing project files...")}`), await w(h(n, "package.json"), JSON.stringify(t, null, 2));
1382
1443
  for (const [e, c] of Object.entries(A)) {
1383
1444
  const l = Ae(e);
1384
1445
  if (l === null) continue;
1385
- const d = h(t, l);
1386
- await D(M(d), { recursive: !0 }), await k(d, c);
1446
+ const d = h(n, l);
1447
+ await D(M(d), { recursive: !0 }), await w(d, c);
1387
1448
  }
1388
- const s = r ? "./templates/src/App.default.tsx" : "./templates/src/App.custom.tsx";
1389
- await k(h(t, "src/App.tsx"), A[s]), console.log(i.green(` ${T} Source files created`)), console.log(""), console.log(` ${j} ${i.bold("Starter content written")}`), console.log(""), console.log(i.dim(" Content includes:")), console.log(i.dim(" 2 locations (tavern, market)")), console.log(i.dim(" 2 characters (bartender, merchant)")), console.log(i.dim(" 1 item (old coin)")), console.log(i.dim(" 1 map (town with 2 locations)")), console.log(i.dim(" 1 quest (odd jobs, 3 stages)")), console.log(i.dim(" 3 journal entries")), console.log(i.dim(" 1 interlude (chapter one, auto-triggers at tavern)")), console.log(i.dim(" 5 dialogues (2 narrator intros, 2 NPC conversations, 1 skill check)")), console.log(i.dim(" English locale with all strings"));
1449
+ const i = r ? "./templates/src/App.default.tsx" : "./templates/src/App.custom.tsx";
1450
+ await w(h(n, "src/App.tsx"), A[i]), console.log(s.green(` ${T} Source files created`)), console.log(""), console.log(` ${j} ${s.bold("Starter content written")}`), console.log(""), console.log(s.dim(" Content includes:")), console.log(s.dim(" 2 locations (tavern, market)")), console.log(s.dim(" 2 characters (bartender, merchant)")), console.log(s.dim(" 1 item (old coin)")), console.log(s.dim(" 1 map (town with 2 locations)")), console.log(s.dim(" 1 quest (odd jobs, 3 stages)")), console.log(s.dim(" 3 journal entries")), console.log(s.dim(" 1 interlude (chapter one, auto-triggers at tavern)")), console.log(s.dim(" 5 dialogues (2 narrator intros, 2 NPC conversations, 1 skill check)")), console.log(s.dim(" English locale with all strings"));
1390
1451
  }
1391
- const _ = new q();
1392
- _.name("doodle").description(i.magenta("ðŸū Doodle Engine") + i.dim(" — Narrative RPG development tools")).version("0.0.1");
1393
- _.command("create <project-name>").description("Scaffold a new Doodle Engine game project").action(async (t) => {
1394
- await Se(t);
1452
+ const _ = new x();
1453
+ _.name("doodle").description(s.magenta("ðŸū Doodle Engine") + s.dim(" — Narrative RPG development tools")).version("0.0.1");
1454
+ _.command("create <project-name>").description("Scaffold a new Doodle Engine game project").action(async (n) => {
1455
+ await Se(n);
1395
1456
  });
1396
1457
  _.command("dev").description("Start development server with hot reload").action(async () => {
1397
1458
  await V();
@@ -1400,6 +1461,6 @@ _.command("build").description("Build game for production").action(async () => {
1400
1461
  await Z();
1401
1462
  });
1402
1463
  _.command("validate").description("Validate game content").action(async () => {
1403
- await te();
1464
+ await ne();
1404
1465
  });
1405
1466
  _.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doodle-engine/cli",
3
- "version": "0.0.16",
3
+ "version": "0.0.17",
4
4
  "type": "module",
5
5
  "description": "CLI tools for Doodle Engine game development",
6
6
  "bin": {
@@ -15,8 +15,8 @@
15
15
  "test": "echo no tests"
16
16
  },
17
17
  "dependencies": {
18
- "@doodle-engine/core": "0.0.16",
19
- "@doodle-engine/react": "0.0.16",
18
+ "@doodle-engine/core": "0.0.17",
19
+ "@doodle-engine/react": "0.0.17",
20
20
  "@vitejs/plugin-react": "^4.3.0",
21
21
  "chokidar": "^4.0.0",
22
22
  "commander": "^12.0.0",