@mmapp/react-compiler 0.1.0-alpha.18 → 0.1.0-alpha.20

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 (199) hide show
  1. package/dist/babel/index.d.mts +1 -1
  2. package/dist/babel/index.d.ts +1 -1
  3. package/dist/babel/index.js +9 -6
  4. package/dist/babel/index.mjs +1 -1
  5. package/dist/chunk-26U577GB.mjs +3465 -0
  6. package/dist/chunk-2FBDFAX6.mjs +2362 -0
  7. package/dist/chunk-2REDFOER.mjs +931 -0
  8. package/dist/{chunk-FPAMQXKB.mjs → chunk-2UTXM2QX.mjs} +10 -20
  9. package/dist/chunk-2YDQTFAL.mjs +879 -0
  10. package/dist/chunk-2ZRKQE74.mjs +175 -0
  11. package/dist/chunk-3QHG2JWV.mjs +154 -0
  12. package/dist/chunk-466OWSTT.mjs +186 -0
  13. package/dist/chunk-467SFYOD.mjs +3127 -0
  14. package/dist/chunk-4AIJO7DZ.mjs +214 -0
  15. package/dist/chunk-4D43TZYL.mjs +7495 -0
  16. package/dist/chunk-4FP5DXY4.mjs +3456 -0
  17. package/dist/chunk-4HX4PI4R.mjs +734 -0
  18. package/dist/chunk-4VU56NTZ.mjs +544 -0
  19. package/dist/chunk-4XHK6FWL.mjs +2058 -0
  20. package/dist/chunk-52C2JKH2.mjs +186 -0
  21. package/dist/chunk-52XHYD2V.mjs +214 -0
  22. package/dist/chunk-5GUFFFGL.mjs +148 -0
  23. package/dist/chunk-5N2FDDS6.mjs +214 -0
  24. package/dist/chunk-5ZSJXWZT.mjs +1646 -0
  25. package/dist/chunk-6CQOAAMV.mjs +1803 -0
  26. package/dist/chunk-6SEVAAVT.mjs +3516 -0
  27. package/dist/chunk-6YLR5ZDA.mjs +2829 -0
  28. package/dist/chunk-77UJB356.mjs +244 -0
  29. package/dist/chunk-7QOAJPQF.mjs +774 -0
  30. package/dist/chunk-A5RCMIBP.mjs +1795 -0
  31. package/dist/chunk-A63R3GKH.mjs +1803 -0
  32. package/dist/chunk-ABNTZXF5.mjs +951 -0
  33. package/dist/chunk-ADHWW56I.mjs +214 -0
  34. package/dist/chunk-AOGY2GK6.mjs +3292 -0
  35. package/dist/chunk-AXXUXRNA.mjs +1434 -0
  36. package/dist/chunk-BZLU5YK5.mjs +1025 -0
  37. package/dist/chunk-C7XCDDBH.mjs +1802 -0
  38. package/dist/chunk-CHLVKMQW.mjs +175 -0
  39. package/dist/chunk-CKGOZAB7.mjs +939 -0
  40. package/dist/chunk-CSXYDIVC.mjs +214 -0
  41. package/dist/chunk-CXTV4VGG.mjs +148 -0
  42. package/dist/chunk-D34RAZUX.mjs +2223 -0
  43. package/dist/chunk-DDIC7WM6.mjs +3127 -0
  44. package/dist/chunk-DPUQOBU6.mjs +4810 -0
  45. package/dist/chunk-E6MDVTGT.mjs +148 -0
  46. package/dist/chunk-EGKMUEM6.mjs +544 -0
  47. package/dist/chunk-EO6SYNCG.mjs +175 -0
  48. package/dist/chunk-EQGA6A6D.mjs +121 -0
  49. package/dist/chunk-EY2CSXYA.mjs +822 -0
  50. package/dist/chunk-EYLOSECJ.mjs +544 -0
  51. package/dist/chunk-FF5BQVII.mjs +148 -0
  52. package/dist/chunk-FIQ65CDR.mjs +925 -0
  53. package/dist/chunk-FOZXJFAR.mjs +186 -0
  54. package/dist/chunk-G2IAZ5Q6.mjs +148 -0
  55. package/dist/chunk-G7SMOWOL.mjs +828 -0
  56. package/dist/chunk-GK7NU6DO.mjs +214 -0
  57. package/dist/chunk-HDSCPEHY.mjs +4061 -0
  58. package/dist/chunk-HJELFNEA.mjs +186 -0
  59. package/dist/chunk-HOIUP6IF.mjs +690 -0
  60. package/dist/chunk-HRJGDPNE.mjs +148 -0
  61. package/dist/chunk-I3AU7GRD.mjs +120 -0
  62. package/dist/chunk-I3VQQJZ6.mjs +2843 -0
  63. package/dist/chunk-I6SSPILI.mjs +550 -0
  64. package/dist/chunk-IPTX5MJU.mjs +3223 -0
  65. package/dist/chunk-ITGUSH2Z.mjs +2783 -0
  66. package/dist/chunk-IXHBCAMF.mjs +3306 -0
  67. package/dist/chunk-J7JUAHS4.mjs +186 -0
  68. package/dist/chunk-J7TWJ3TM.mjs +2784 -0
  69. package/dist/chunk-JDPLDGVF.mjs +4810 -0
  70. package/dist/chunk-JK72MQ4N.mjs +877 -0
  71. package/dist/chunk-K2HHCAS2.mjs +148 -0
  72. package/dist/chunk-K5HX2SVL.mjs +1902 -0
  73. package/dist/chunk-KAUEQ2F3.mjs +148 -0
  74. package/dist/chunk-KFVVOS5N.mjs +925 -0
  75. package/dist/chunk-KIH4AN3Y.mjs +154 -0
  76. package/dist/chunk-KPDMN5IX.mjs +175 -0
  77. package/dist/chunk-LZL2IRCH.mjs +186 -0
  78. package/dist/chunk-MIZV3TAN.mjs +3293 -0
  79. package/dist/chunk-MRH4J7IX.mjs +2846 -0
  80. package/dist/chunk-NKBL5GUC.mjs +186 -0
  81. package/dist/chunk-NQCNSCF6.mjs +148 -0
  82. package/dist/chunk-NRP5J3BR.mjs +4811 -0
  83. package/dist/chunk-NTB7OEX2.mjs +2918 -0
  84. package/dist/chunk-NUPJYPFU.mjs +801 -0
  85. package/dist/chunk-NVQUTSQX.mjs +3128 -0
  86. package/dist/chunk-OGMG64EY.mjs +148 -0
  87. package/dist/chunk-OL5B2HTH.mjs +175 -0
  88. package/dist/chunk-OPJKP747.mjs +7506 -0
  89. package/dist/chunk-OQLGGBNE.mjs +2918 -0
  90. package/dist/chunk-OW4AQUDL.mjs +544 -0
  91. package/dist/chunk-OWI6XWCD.mjs +3375 -0
  92. package/dist/chunk-OZT2EAF2.mjs +2776 -0
  93. package/dist/chunk-PBRBRKIQ.mjs +175 -0
  94. package/dist/chunk-PRUMNNDI.mjs +3192 -0
  95. package/dist/chunk-QPNHDTSM.mjs +4839 -0
  96. package/dist/chunk-RNEIAJDR.mjs +897 -0
  97. package/dist/chunk-RY7POBNT.mjs +3127 -0
  98. package/dist/chunk-S6FJ4DXL.mjs +1813 -0
  99. package/dist/chunk-SU4E6E7B.mjs +3153 -0
  100. package/dist/chunk-SYUUKW5A.mjs +3379 -0
  101. package/dist/chunk-THB5SX2S.mjs +113 -0
  102. package/dist/chunk-THFYE5ZX.mjs +244 -0
  103. package/dist/chunk-TK3QMXIP.mjs +2921 -0
  104. package/dist/chunk-TRR2NPAV.mjs +248 -0
  105. package/dist/chunk-TTTTOT7P.mjs +1803 -0
  106. package/dist/chunk-TXONBY6A.mjs +7509 -0
  107. package/dist/chunk-U2PX3JSY.mjs +1933 -0
  108. package/dist/chunk-U6F7CTHK.mjs +550 -0
  109. package/dist/chunk-UASOWKDI.mjs +186 -0
  110. package/dist/chunk-UDDTWG5J.mjs +734 -0
  111. package/dist/chunk-UIWLAQCL.mjs +175 -0
  112. package/dist/chunk-UL2XZEMA.mjs +3128 -0
  113. package/dist/chunk-US3AVDAI.mjs +3456 -0
  114. package/dist/chunk-V5DIDOTT.mjs +148 -0
  115. package/dist/chunk-VLTKQDJ3.mjs +244 -0
  116. package/dist/chunk-VVC42PTS.mjs +175 -0
  117. package/dist/chunk-VX3T3NIR.mjs +897 -0
  118. package/dist/chunk-WBYMW4NQ.mjs +3450 -0
  119. package/dist/chunk-XMWUHQVV.mjs +939 -0
  120. package/dist/chunk-XUQ5R6F3.mjs +213 -0
  121. package/dist/chunk-Y6FXYEAI.mjs +10 -0
  122. package/dist/chunk-YCWC2SCO.mjs +148 -0
  123. package/dist/chunk-YFS6JMYO.mjs +3342 -0
  124. package/dist/chunk-ZE67HOSN.mjs +148 -0
  125. package/dist/chunk-ZSK5TPIV.mjs +148 -0
  126. package/dist/cli/index.js +329 -653
  127. package/dist/cli/index.mjs +9 -9
  128. package/dist/config-PL24KEWL.mjs +219 -0
  129. package/dist/deploy-VAHWALWB.mjs +9 -0
  130. package/dist/dev-server-Bs_sz2DG.d.mts +111 -0
  131. package/dist/dev-server-Bs_sz2DG.d.ts +111 -0
  132. package/dist/dev-server-RmGHIntF.d.mts +113 -0
  133. package/dist/dev-server-RmGHIntF.d.ts +113 -0
  134. package/dist/dev-server.js +205 -522
  135. package/dist/dev-server.mjs +4 -4
  136. package/dist/engine-binary-KQB23JDR.mjs +97 -0
  137. package/dist/envelope-DD7v0v6E.d.mts +265 -0
  138. package/dist/envelope-DD7v0v6E.d.ts +265 -0
  139. package/dist/envelope.js +9 -6
  140. package/dist/envelope.mjs +2 -2
  141. package/dist/index-B5gSgvnd.d.mts +44 -0
  142. package/dist/index-B5gSgvnd.d.ts +44 -0
  143. package/dist/index-Bs0MnR54.d.mts +103 -0
  144. package/dist/index-Bs0MnR54.d.ts +103 -0
  145. package/dist/index-DR0nNc_f.d.mts +101 -0
  146. package/dist/index-DR0nNc_f.d.ts +101 -0
  147. package/dist/index-revho_gS.d.mts +104 -0
  148. package/dist/index-revho_gS.d.ts +104 -0
  149. package/dist/index-vQjwYekL.d.mts +104 -0
  150. package/dist/index-vQjwYekL.d.ts +104 -0
  151. package/dist/index.d.mts +2 -2
  152. package/dist/index.d.ts +2 -2
  153. package/dist/index.js +210 -525
  154. package/dist/index.mjs +10 -9
  155. package/dist/init-2XLTUF7O.mjs +407 -0
  156. package/dist/init-7FJENUDK.mjs +407 -0
  157. package/dist/init-AVZJHZYY.mjs +538 -0
  158. package/dist/init-DQDX3QK6.mjs +369 -0
  159. package/dist/init-K3GVM4JS.mjs +538 -0
  160. package/dist/init-NXS5BJN3.mjs +454 -0
  161. package/dist/init-UC3FWPIW.mjs +367 -0
  162. package/dist/init-UNV5XIDE.mjs +367 -0
  163. package/dist/project-compiler-2HOPO7GC.mjs +10 -0
  164. package/dist/project-compiler-D245L5QR.mjs +10 -0
  165. package/dist/project-compiler-FUQRMB4X.mjs +10 -0
  166. package/dist/project-compiler-LA5OBI5P.mjs +10 -0
  167. package/dist/project-compiler-OP2VVGJQ.mjs +10 -0
  168. package/dist/project-compiler-PZNFE6AH.mjs +10 -0
  169. package/dist/project-compiler-QBVF6MFI.mjs +10 -0
  170. package/dist/project-compiler-VFR6CSDX.mjs +10 -0
  171. package/dist/project-compiler-WMJZA4UH.mjs +10 -0
  172. package/dist/project-compiler-XXS27TZT.mjs +10 -0
  173. package/dist/project-compiler-YYGDSHY5.mjs +10 -0
  174. package/dist/project-decompiler-5GY2KSG4.mjs +7 -0
  175. package/dist/project-decompiler-7I2OMUVY.mjs +7 -0
  176. package/dist/project-decompiler-QCZYY4TW.mjs +7 -0
  177. package/dist/project-decompiler-US7GAVIC.mjs +7 -0
  178. package/dist/pull-2Q53HF3H.mjs +107 -0
  179. package/dist/pull-5AFHD3QG.mjs +109 -0
  180. package/dist/pull-5WJ4LW4U.mjs +109 -0
  181. package/dist/pull-65GUSX6F.mjs +109 -0
  182. package/dist/pull-6LVI4LMM.mjs +109 -0
  183. package/dist/pull-A2QUHW4K.mjs +109 -0
  184. package/dist/pull-B6T5BUKV.mjs +109 -0
  185. package/dist/pull-CKHWZT33.mjs +109 -0
  186. package/dist/pull-GM74ERRT.mjs +109 -0
  187. package/dist/pull-JBEQWVPE.mjs +109 -0
  188. package/dist/pull-P44LDRWB.mjs +109 -0
  189. package/dist/pull-W2US3T3E.mjs +109 -0
  190. package/dist/testing/index.js +9 -6
  191. package/dist/testing/index.mjs +1 -1
  192. package/dist/verify-3PPS4XAM.mjs +1833 -0
  193. package/dist/verify-GKEH5FZQ.mjs +1833 -0
  194. package/dist/verify-HDKUNHZ4.mjs +1833 -0
  195. package/dist/verify-SEIXUGN4.mjs +1833 -0
  196. package/dist/vite/index.js +10 -7
  197. package/dist/vite/index.mjs +2 -2
  198. package/mm-dev.db +0 -0
  199. package/package.json +2 -2
@@ -6468,7 +6468,8 @@ function convertOnEvent(sub) {
6468
6468
  };
6469
6469
  }
6470
6470
  function emitIR(extracted) {
6471
- const { slug, name, version, description, category, fields, states, transitions } = extracted;
6471
+ const { slug, name, version, description, category: rawCategory, fields, states, transitions } = extracted;
6472
+ const category = Array.isArray(rawCategory) ? rawCategory : [rawCategory];
6472
6473
  const stateArray = Array.from(states.values());
6473
6474
  if (stateArray.length === 0) {
6474
6475
  stateArray.push({
@@ -6856,13 +6857,15 @@ function emitCanonical(extracted, sourceFilename) {
6856
6857
  }
6857
6858
  ]
6858
6859
  });
6859
- const category = extracted.category;
6860
+ const rawCat = extracted.category;
6860
6861
  let categoryArray;
6861
- if (category.includes("/")) {
6862
- const [primary, ...tags] = category.split("/");
6862
+ if (Array.isArray(rawCat)) {
6863
+ categoryArray = rawCat;
6864
+ } else if (rawCat.includes("/")) {
6865
+ const [primary, ...tags] = rawCat.split("/");
6863
6866
  categoryArray = (0, import_player_core.normalizeCategory)(primary, ...tags);
6864
6867
  } else {
6865
- categoryArray = [category];
6868
+ categoryArray = [rawCat];
6866
6869
  }
6867
6870
  return {
6868
6871
  slug: ir.slug,
@@ -7009,7 +7012,7 @@ function compilerStateToWorkflow(state, metadata) {
7009
7012
  name: metadata.name || "Workflow",
7010
7013
  version: metadata.version || "0.1.0",
7011
7014
  description: metadata.description,
7012
- category: metadata.category || "workflow",
7015
+ category: metadata.categoryArray ? metadata.categoryArray : [metadata.category || "workflow"],
7013
7016
  fields: state.fields || [],
7014
7017
  states: state.states || /* @__PURE__ */ new Map(),
7015
7018
  transitions: state.transitions || [],
@@ -7787,7 +7790,7 @@ function extractRouterWorkflow(pages, options = {}) {
7787
7790
  name: "Router",
7788
7791
  version: "1.0.0",
7789
7792
  description: "Auto-derived router workflow from file-based routing",
7790
- category: "router",
7793
+ category: ["router"],
7791
7794
  fields,
7792
7795
  states,
7793
7796
  transitions,
@@ -7886,7 +7889,8 @@ function compileModel(filename, source, options = {}) {
7886
7889
  parserOpts: { plugins: parserPlugins, attachComment: true }
7887
7890
  });
7888
7891
  const ir = babelResult?.metadata?.mindmatrixIR ?? createEmptyModelIR(interfaceName);
7889
- ir.category = options.categoryOverride || annotation.category || "data";
7892
+ const catOverride = options.categoryOverride || annotation.category || "data";
7893
+ ir.category = Array.isArray(catOverride) ? catOverride : [catOverride];
7890
7894
  if (options.slugOverride) {
7891
7895
  ir.slug = options.slugOverride;
7892
7896
  }
@@ -7950,7 +7954,7 @@ function createEmptyModelIR(interfaceName) {
7950
7954
  name: interfaceName,
7951
7955
  version: "1.0.0",
7952
7956
  description: "Data model: " + interfaceName,
7953
- category: "data",
7957
+ category: ["data"],
7954
7958
  fields: [],
7955
7959
  states: [{
7956
7960
  name: "draft",
@@ -8118,7 +8122,7 @@ function buildRouterIR(routes, layouts, allParams, slugPrefix) {
8118
8122
  name: "Router",
8119
8123
  version: "1.0.0",
8120
8124
  description: "Auto-generated router from app/ directory structure",
8121
- category: "router",
8125
+ category: ["router"],
8122
8126
  fields,
8123
8127
  states,
8124
8128
  transitions,
@@ -8367,7 +8371,7 @@ function extractAction(source, filename) {
8367
8371
  slug,
8368
8372
  name: humanName,
8369
8373
  version: "0.1.0",
8370
- category: "action",
8374
+ category: ["action"],
8371
8375
  fields,
8372
8376
  states: states2,
8373
8377
  transitions: transitions2,
@@ -8419,7 +8423,7 @@ function extractAction(source, filename) {
8419
8423
  slug,
8420
8424
  name: humanName,
8421
8425
  version: "0.1.0",
8422
- category: "action",
8426
+ category: ["action"],
8423
8427
  fields,
8424
8428
  states,
8425
8429
  transitions,
@@ -9856,7 +9860,7 @@ function applyConfig(ir, config) {
9856
9860
  if (config.name) ir.name = config.name;
9857
9861
  if (config.version) ir.version = config.version;
9858
9862
  if (config.description !== void 0) ir.description = config.description;
9859
- if (config.category) ir.category = config.category;
9863
+ if (config.category) ir.category = Array.isArray(config.category) ? config.category : [config.category];
9860
9864
  if (!ir.metadata) ir.metadata = {};
9861
9865
  ir.metadata.stable_id = "def-" + ir.slug;
9862
9866
  ir.metadata.provenance = {
@@ -9872,7 +9876,7 @@ function createEmptyIR(config) {
9872
9876
  name: config.name || "Project",
9873
9877
  version: config.version || "0.1.0",
9874
9878
  description: config.description,
9875
- category: config.category || "workflow",
9879
+ category: Array.isArray(config.category) ? config.category : [config.category || "workflow"],
9876
9880
  fields: [],
9877
9881
  states: [{
9878
9882
  name: "draft",
@@ -10030,8 +10034,10 @@ function buildComposedResult(files, fileIRs, config, errors, warnings, options =
10030
10034
  if (isWorkflowFile(filename)) {
10031
10035
  workflowIRs.push(ir);
10032
10036
  } else if (isModelFile2(filename)) {
10033
- if (!ir.category || ir.category === "workflow") {
10034
- ir.category = "data";
10037
+ const cat = ir.category;
10038
+ const isDefault = !cat || cat === "workflow" || Array.isArray(cat) && cat.length === 1 && cat[0] === "workflow";
10039
+ if (isDefault) {
10040
+ ir.category = ["data"];
10035
10041
  }
10036
10042
  modelIRs.push(ir);
10037
10043
  } else if (isServerActionFile2(filename)) {
@@ -10843,14 +10849,12 @@ async function deploy(options) {
10843
10849
  }
10844
10850
  async function fetchExistingDefinition(apiUrl, token, slug) {
10845
10851
  try {
10846
- const res = await fetch(`${apiUrl}/workflow/definitions?slug=${encodeURIComponent(slug)}`, {
10852
+ const res = await fetch(`${apiUrl}/workflow/definitions/${encodeURIComponent(slug)}`, {
10847
10853
  headers: { Authorization: `Bearer ${token}` }
10848
10854
  });
10849
10855
  if (!res.ok) return null;
10850
- const data = await res.json();
10851
- const definitions = Array.isArray(data) ? data : data.items ?? data.data;
10852
- if (!definitions || definitions.length === 0) return null;
10853
- const def = definitions[0];
10856
+ const def = await res.json();
10857
+ if (!def || !def.id) return null;
10854
10858
  return {
10855
10859
  id: def.id,
10856
10860
  slug: def.slug,
@@ -10868,7 +10872,7 @@ async function createDefinition(apiUrl, token, ir) {
10868
10872
  "Content-Type": "application/json",
10869
10873
  Authorization: `Bearer ${token}`
10870
10874
  },
10871
- body: JSON.stringify(ir)
10875
+ body: JSON.stringify({ ...ir, visibility: "PUBLIC" })
10872
10876
  });
10873
10877
  if (!res.ok) {
10874
10878
  const errorText = await res.text();
@@ -11171,7 +11175,7 @@ function mindmatrixReact(options) {
11171
11175
  slug: ir.slug,
11172
11176
  name: ir.name,
11173
11177
  version: ir.version,
11174
- category: ir.category || "workflow",
11178
+ category: ir.category || ["workflow"],
11175
11179
  fields: ir.fields || [],
11176
11180
  states: ir.states || [],
11177
11181
  transitions: ir.transitions || [],
@@ -11705,425 +11709,6 @@ async function startWatchMode(options) {
11705
11709
  });
11706
11710
  }
11707
11711
 
11708
- // src/cli/local-server.ts
11709
- var http = __toESM(require("http"));
11710
- var import_node_crypto = require("crypto");
11711
- var MemoryStore = class {
11712
- constructor() {
11713
- this.definitions = /* @__PURE__ */ new Map();
11714
- this.instances = /* @__PURE__ */ new Map();
11715
- this.slugIndex = /* @__PURE__ */ new Map();
11716
- }
11717
- // slug → id
11718
- // ── Definitions ──────────────────────────────────────────────────────
11719
- createDefinition(input) {
11720
- if (this.slugIndex.has(input.slug)) {
11721
- const existing = this.definitions.get(this.slugIndex.get(input.slug));
11722
- if (existing) return existing;
11723
- }
11724
- const now = (/* @__PURE__ */ new Date()).toISOString();
11725
- const def = {
11726
- id: input.id ?? (0, import_node_crypto.randomUUID)(),
11727
- slug: input.slug,
11728
- name: input.name,
11729
- version: input.version ?? "1.0.0",
11730
- description: input.description ?? null,
11731
- category: input.category ?? "workflow",
11732
- fields: input.fields ?? [],
11733
- states: input.states ?? [],
11734
- transitions: input.transitions ?? [],
11735
- roles: input.roles ?? [],
11736
- experience: input.experience ?? null,
11737
- metadata: input.metadata ?? {},
11738
- child_definitions: input.child_definitions ?? [],
11739
- is_immutable: input.is_immutable ?? false,
11740
- tags: input.tags ?? [],
11741
- inline_tags: input.inline_tags ?? [],
11742
- created_at: now,
11743
- updated_at: now
11744
- };
11745
- this.definitions.set(def.id, def);
11746
- this.slugIndex.set(def.slug, def.id);
11747
- return def;
11748
- }
11749
- getDefinition(idOrSlug) {
11750
- const byId = this.definitions.get(idOrSlug);
11751
- if (byId) return byId;
11752
- const id = this.slugIndex.get(idOrSlug);
11753
- if (id) return this.definitions.get(id);
11754
- return void 0;
11755
- }
11756
- listDefinitions(opts) {
11757
- let items = Array.from(this.definitions.values());
11758
- if (opts?.category) {
11759
- items = items.filter((d) => d.category === opts.category);
11760
- }
11761
- const total = items.length;
11762
- const offset = opts?.offset ?? 0;
11763
- const limit = opts?.limit ?? 50;
11764
- items = items.slice(offset, offset + limit);
11765
- return { items, total };
11766
- }
11767
- patchDefinition(id, patch) {
11768
- const def = this.definitions.get(id);
11769
- if (!def) return void 0;
11770
- Object.assign(def, patch, { updated_at: (/* @__PURE__ */ new Date()).toISOString() });
11771
- return def;
11772
- }
11773
- deleteDefinition(id) {
11774
- const def = this.definitions.get(id);
11775
- if (!def) return false;
11776
- this.slugIndex.delete(def.slug);
11777
- this.definitions.delete(id);
11778
- return true;
11779
- }
11780
- // ── Instances ────────────────────────────────────────────────────────
11781
- createInstance(input) {
11782
- const def = this.getDefinition(input.definition_id) ?? this.getDefinition(input.definition_slug);
11783
- if (!def) return null;
11784
- const initialState = def.states.find((s) => s.type === "START" || s.type === "initial");
11785
- const stateName = initialState?.name ?? "initial";
11786
- const stateData = {};
11787
- for (const field of def.fields) {
11788
- if (field.default_value !== void 0) {
11789
- stateData[field.name] = field.default_value;
11790
- }
11791
- }
11792
- Object.assign(stateData, input.state_data ?? {});
11793
- const now = (/* @__PURE__ */ new Date()).toISOString();
11794
- const inst = {
11795
- id: (0, import_node_crypto.randomUUID)(),
11796
- definition_id: def.id,
11797
- definition_slug: def.slug,
11798
- current_state: stateName,
11799
- state_data: stateData,
11800
- execution_lock_version: 0,
11801
- event_log: [{
11802
- event_type: "transition",
11803
- message: `Instance created in state '${stateName}'`,
11804
- timestamp: now
11805
- }],
11806
- created_at: now,
11807
- updated_at: now
11808
- };
11809
- this.instances.set(inst.id, inst);
11810
- return inst;
11811
- }
11812
- getInstance(id) {
11813
- return this.instances.get(id);
11814
- }
11815
- listInstances(opts) {
11816
- let items = Array.from(this.instances.values());
11817
- if (opts?.definition_id) {
11818
- items = items.filter((i) => i.definition_id === opts.definition_id);
11819
- }
11820
- const total = items.length;
11821
- const offset = opts?.offset ?? 0;
11822
- const limit = opts?.limit ?? 50;
11823
- items = items.slice(offset, offset + limit);
11824
- return { items, total };
11825
- }
11826
- // ── Execute Action (Transition) ──────────────────────────────────────
11827
- executeAction(input) {
11828
- const def = this.getDefinition(input.definition_id);
11829
- if (!def) return { success: false, error: "Definition not found" };
11830
- let inst;
11831
- if (input.instance_id) {
11832
- const existing = this.instances.get(input.instance_id);
11833
- if (!existing) return { success: false, error: "Instance not found" };
11834
- inst = existing;
11835
- } else {
11836
- const created = this.createInstance({
11837
- definition_id: def.id,
11838
- definition_slug: def.slug,
11839
- state_data: input.payload
11840
- });
11841
- if (!created) return { success: false, error: "Failed to create instance" };
11842
- inst = created;
11843
- }
11844
- if (input.payload && input.instance_id) {
11845
- Object.assign(inst.state_data, input.payload);
11846
- }
11847
- const transition = def.transitions.find((t23) => t23.name === input.action_name && t23.from.includes(inst.current_state));
11848
- if (!transition) {
11849
- return {
11850
- success: false,
11851
- instance_id: inst.id,
11852
- from_state: inst.current_state,
11853
- to_state: null,
11854
- state_data: inst.state_data,
11855
- error: `No transition '${input.action_name}' from state '${inst.current_state}'`
11856
- };
11857
- }
11858
- const fromState = inst.current_state;
11859
- const now = (/* @__PURE__ */ new Date()).toISOString();
11860
- const events = [];
11861
- let lastEvalResult = null;
11862
- events.push({ event_type: "transition", message: `Transition '${transition.name}' started: ${fromState} \u2192 ${transition.to}`, timestamp: now });
11863
- for (const action of transition.actions ?? []) {
11864
- try {
11865
- if (action.type === "set_field") {
11866
- const field = action.config?.field;
11867
- if (action.config?.expression) {
11868
- const expr = action.config.expression;
11869
- const result = this.evaluateSimpleExpression(expr, inst.state_data);
11870
- inst.state_data[field] = result;
11871
- } else if (action.config?.value !== void 0) {
11872
- inst.state_data[field] = action.config.value;
11873
- }
11874
- events.push({ event_type: "action_executed", message: `transition action 'set_field' succeeded`, timestamp: now });
11875
- } else if (action.type === "eval") {
11876
- const expr = action.config?.expression;
11877
- lastEvalResult = this.evaluateSimpleExpression(expr, inst.state_data);
11878
- events.push({ event_type: "action_executed", message: `transition action 'eval' succeeded`, timestamp: now });
11879
- } else {
11880
- events.push({ event_type: "action_executed", message: `transition action '${action.type}' succeeded (no-op in local mode)`, timestamp: now });
11881
- }
11882
- } catch (err) {
11883
- const msg = err instanceof Error ? err.message : String(err);
11884
- events.push({ event_type: "action_failed", message: `transition action '${action.type}' failed: ${msg}`, timestamp: now });
11885
- return {
11886
- success: false,
11887
- instance_id: inst.id,
11888
- from_state: fromState,
11889
- to_state: null,
11890
- state_data: inst.state_data,
11891
- event_log: events,
11892
- error: `transition action failed: ${msg}`
11893
- };
11894
- }
11895
- }
11896
- inst.current_state = transition.to;
11897
- inst.execution_lock_version++;
11898
- inst.updated_at = now;
11899
- events.push({ event_type: "transition", message: `State changed: ${fromState} \u2192 ${transition.to}`, timestamp: now });
11900
- inst.event_log.push(...events);
11901
- return {
11902
- success: true,
11903
- instance_id: inst.id,
11904
- from_state: fromState,
11905
- to_state: transition.to,
11906
- state_data: inst.state_data,
11907
- result: lastEvalResult,
11908
- event_log: events
11909
- };
11910
- }
11911
- /**
11912
- * Minimal expression evaluator for local dev mode.
11913
- * Handles: field references, arithmetic, string literals, simple comparisons.
11914
- * Does NOT handle: while loops, if/else, function calls, multi-statement blocks.
11915
- * For full evaluation, use mm-napi when available.
11916
- */
11917
- evaluateSimpleExpression(expr, context) {
11918
- if (context[expr] !== void 0) return context[expr];
11919
- const arithMatch = expr.match(/^(\w+)\s*([+\-*/])\s*(\d+(?:\.\d+)?)$/);
11920
- if (arithMatch) {
11921
- const [, field, op, numStr] = arithMatch;
11922
- const left = Number(context[field] ?? 0);
11923
- const right = Number(numStr);
11924
- switch (op) {
11925
- case "+":
11926
- return left + right;
11927
- case "-":
11928
- return left - right;
11929
- case "*":
11930
- return left * right;
11931
- case "/":
11932
- return right !== 0 ? left / right : 0;
11933
- }
11934
- }
11935
- if (/^\d+(\.\d+)?$/.test(expr.trim())) {
11936
- return Number(expr.trim());
11937
- }
11938
- const strMatch = expr.match(/^["'](.*)["']$/);
11939
- if (strMatch) return strMatch[1];
11940
- try {
11941
- const keys = Object.keys(context);
11942
- const values = Object.values(context);
11943
- const fn = new Function(...keys, `"use strict"; return (${expr});`);
11944
- return fn(...values);
11945
- } catch {
11946
- return null;
11947
- }
11948
- }
11949
- };
11950
- async function startLocalServer(options = {}) {
11951
- const { port = 4200, noAuth = true } = options;
11952
- const store = new MemoryStore();
11953
- const startedAt = (/* @__PURE__ */ new Date()).toISOString();
11954
- function json(res, status, body) {
11955
- const data = JSON.stringify(body);
11956
- res.writeHead(status, {
11957
- "Content-Type": "application/json",
11958
- "Access-Control-Allow-Origin": "*",
11959
- "Access-Control-Allow-Methods": "GET, POST, PATCH, PUT, DELETE, OPTIONS",
11960
- "Access-Control-Allow-Headers": "Content-Type, Authorization",
11961
- "Content-Length": Buffer.byteLength(data)
11962
- });
11963
- res.end(data);
11964
- }
11965
- function readBody(req) {
11966
- return new Promise((resolve2, reject) => {
11967
- const chunks = [];
11968
- req.on("data", (chunk) => chunks.push(chunk));
11969
- req.on("end", () => resolve2(Buffer.concat(chunks).toString()));
11970
- req.on("error", reject);
11971
- });
11972
- }
11973
- function parseQuery(url) {
11974
- const idx = url.indexOf("?");
11975
- if (idx === -1) return {};
11976
- const params = {};
11977
- const qs = url.slice(idx + 1);
11978
- for (const pair of qs.split("&")) {
11979
- const [k, v] = pair.split("=");
11980
- if (k) params[decodeURIComponent(k)] = decodeURIComponent(v ?? "");
11981
- }
11982
- return params;
11983
- }
11984
- const server = http.createServer(async (req, res) => {
11985
- const method = req.method?.toUpperCase() ?? "GET";
11986
- const rawUrl = req.url ?? "/";
11987
- const queryStart = rawUrl.indexOf("?");
11988
- const path = queryStart >= 0 ? rawUrl.slice(0, queryStart) : rawUrl;
11989
- const query = parseQuery(rawUrl);
11990
- if (method === "OPTIONS") {
11991
- res.writeHead(204, {
11992
- "Access-Control-Allow-Origin": "*",
11993
- "Access-Control-Allow-Methods": "GET, POST, PATCH, PUT, DELETE, OPTIONS",
11994
- "Access-Control-Allow-Headers": "Content-Type, Authorization",
11995
- "Access-Control-Max-Age": "86400"
11996
- });
11997
- res.end();
11998
- return;
11999
- }
12000
- try {
12001
- if (path === "/health" && method === "GET") {
12002
- return json(res, 200, {
12003
- status: "ok",
12004
- service: "mm-local-dev",
12005
- mode: "in-memory",
12006
- started_at: startedAt,
12007
- definitions: store.definitions.size,
12008
- instances: store.instances.size
12009
- });
12010
- }
12011
- if (path === "/api/v1/auth/login" && (method === "POST" || method === "GET")) {
12012
- return json(res, 200, {
12013
- token: "dev-token-local",
12014
- user: {
12015
- id: "dev-user-001",
12016
- email: "dev@localhost",
12017
- role: "admin",
12018
- name: "Local Developer"
12019
- }
12020
- });
12021
- }
12022
- if (path === "/api/v1/workflow/definitions" && method === "GET") {
12023
- const result = store.listDefinitions({
12024
- category: query.category,
12025
- limit: query.limit ? parseInt(query.limit, 10) : void 0,
12026
- offset: query.offset ? parseInt(query.offset, 10) : void 0
12027
- });
12028
- if (query.slug) {
12029
- const def = store.getDefinition(query.slug);
12030
- return json(res, 200, { items: def ? [def] : [], total: def ? 1 : 0 });
12031
- }
12032
- return json(res, 200, result);
12033
- }
12034
- const defMatch = path.match(/^\/api\/v1\/workflow\/definitions\/([^/]+)$/);
12035
- if (defMatch && method === "GET") {
12036
- const def = store.getDefinition(defMatch[1]);
12037
- if (!def) return json(res, 404, { error: "Not found" });
12038
- return json(res, 200, def);
12039
- }
12040
- if (path === "/api/v1/workflow/definitions" && method === "POST") {
12041
- const body = JSON.parse(await readBody(req));
12042
- const def = store.createDefinition(body);
12043
- return json(res, 201, def);
12044
- }
12045
- if (defMatch && method === "PATCH") {
12046
- const body = JSON.parse(await readBody(req));
12047
- const updated = store.patchDefinition(defMatch[1], body);
12048
- if (!updated) return json(res, 404, { error: "Not found" });
12049
- return json(res, 200, updated);
12050
- }
12051
- if (defMatch && method === "DELETE") {
12052
- const deleted = store.deleteDefinition(defMatch[1]);
12053
- if (!deleted) return json(res, 404, { error: "Not found" });
12054
- return json(res, 204, null);
12055
- }
12056
- if (path === "/api/v1/workflow/instances" && method === "GET") {
12057
- const result = store.listInstances({
12058
- definition_id: query.definition_id,
12059
- limit: query.limit ? parseInt(query.limit, 10) : void 0,
12060
- offset: query.offset ? parseInt(query.offset, 10) : void 0
12061
- });
12062
- return json(res, 200, result);
12063
- }
12064
- if (path === "/api/v1/workflow/instances" && method === "POST") {
12065
- const body = JSON.parse(await readBody(req));
12066
- const inst = store.createInstance(body);
12067
- if (!inst) return json(res, 404, { error: "Definition not found" });
12068
- return json(res, 201, inst);
12069
- }
12070
- const instMatch = path.match(/^\/api\/v1\/workflow\/instances\/([^/]+)$/);
12071
- if (instMatch && method === "GET") {
12072
- const inst = store.getInstance(instMatch[1]);
12073
- if (!inst) return json(res, 404, { error: "Not found" });
12074
- return json(res, 200, inst);
12075
- }
12076
- if (path === "/api/v1/workflow/execute-action" && method === "POST") {
12077
- const body = JSON.parse(await readBody(req));
12078
- const result = store.executeAction(body);
12079
- return json(res, 200, result);
12080
- }
12081
- const dataMatch = path.match(/^\/api\/v1\/data\/([^/]+)$/);
12082
- if (dataMatch && method === "GET") {
12083
- const def = store.getDefinition(dataMatch[1]);
12084
- if (!def) return json(res, 404, { error: "Not found" });
12085
- const instances = store.listInstances({ definition_id: def.id });
12086
- return json(res, 200, instances);
12087
- }
12088
- if (path.startsWith("/api/v1/")) {
12089
- return json(res, 501, { error: "Not implemented in local dev mode", path, method });
12090
- }
12091
- return json(res, 404, { error: "Not found", path });
12092
- } catch (err) {
12093
- const message = err instanceof Error ? err.message : String(err);
12094
- console.error(`[mm-local] ${method} ${path} \u2014 Error: ${message}`);
12095
- return json(res, 500, { error: message });
12096
- }
12097
- });
12098
- return new Promise((resolve2, reject) => {
12099
- server.on("error", (err) => {
12100
- if (err.code === "EADDRINUSE") {
12101
- reject(new Error(`Port ${port} is already in use. Is another server running?`));
12102
- } else {
12103
- reject(err);
12104
- }
12105
- });
12106
- server.listen(port, () => {
12107
- console.log(`[mm-local] Local API server running at http://localhost:${port}`);
12108
- console.log(`[mm-local] Mode: in-memory (data lost on restart)`);
12109
- console.log(`[mm-local] Auth: disabled (all requests accepted)`);
12110
- resolve2({
12111
- server,
12112
- port,
12113
- store,
12114
- async close() {
12115
- return new Promise((res) => {
12116
- server.close(() => {
12117
- console.log("[mm-local] Local API server stopped");
12118
- res();
12119
- });
12120
- });
12121
- }
12122
- });
12123
- });
12124
- });
12125
- }
12126
-
12127
11712
  // src/dev-server.ts
12128
11713
  var currentErrors = null;
12129
11714
  function escapeHtml(s) {
@@ -12300,34 +11885,33 @@ async function createDevServer(options = {}) {
12300
11885
  open = false
12301
11886
  } = options;
12302
11887
  const clients = /* @__PURE__ */ new Set();
12303
- let localServer = null;
12304
11888
  let apiUrl;
12305
- let isLocalMode = false;
12306
- if (rawApiUrl === "local") {
12307
- localServer = await startLocalServer({ port: 4200 });
12308
- apiUrl = "http://localhost:4200/api/v1";
12309
- isLocalMode = true;
12310
- } else if (rawApiUrl === "auto") {
12311
- const defaultRemote = "https://dev.mindmatrix.club/api/v1";
12312
- const remoteHealth = await checkBackendHealth(defaultRemote);
12313
- if (remoteHealth.ok) {
12314
- apiUrl = defaultRemote;
12315
- } else {
12316
- const localHealth = await checkBackendHealth("http://localhost:4200/api/v1");
12317
- if (localHealth.ok) {
12318
- apiUrl = "http://localhost:4200/api/v1";
11889
+ if (rawApiUrl === "local" || rawApiUrl === "auto") {
11890
+ const localHealth = await checkBackendHealth("http://localhost:4200/api/v1");
11891
+ if (localHealth.ok) {
11892
+ apiUrl = "http://localhost:4200/api/v1";
11893
+ } else if (rawApiUrl === "auto") {
11894
+ const defaultRemote = "https://dev.mindmatrix.club/api/v1";
11895
+ const remoteHealth = await checkBackendHealth(defaultRemote);
11896
+ if (remoteHealth.ok) {
11897
+ apiUrl = defaultRemote;
12319
11898
  } else {
12320
- console.log("[mm-dev] No backend detected \u2014 starting local in-memory API server...");
12321
- localServer = await startLocalServer({ port: 4200 });
11899
+ console.error("[mm-dev] No backend detected. Start the engine first:");
11900
+ console.error(" mmrc dev (auto-starts engine)");
11901
+ console.error(" mmrc engine start (manual start)");
11902
+ console.error("[mm-dev] Or specify a remote API: mmrc dev --api-url https://...");
12322
11903
  apiUrl = "http://localhost:4200/api/v1";
12323
- isLocalMode = true;
12324
11904
  }
11905
+ } else {
11906
+ console.error("[mm-dev] Local engine not running on port 4200.");
11907
+ console.error(" Start it with: mmrc dev (or mmrc engine start)");
11908
+ apiUrl = "http://localhost:4200/api/v1";
12325
11909
  }
12326
11910
  } else {
12327
11911
  apiUrl = rawApiUrl;
12328
11912
  }
12329
- const token = isLocalMode ? "dev-token-local" : await resolveDevToken(apiUrl, explicitToken);
12330
- const health = isLocalMode ? { ok: true, version: "local", db: "in-memory" } : await checkBackendHealth(apiUrl);
11913
+ const token = await resolveDevToken(apiUrl, explicitToken);
11914
+ const health = await checkBackendHealth(apiUrl);
12331
11915
  let initialSlug, initialCompiled = 0, initialDeployed = false, initialErrors = 0;
12332
11916
  if (token && health.ok) {
12333
11917
  const r = await initialBuildDeploy(src, outDir, mode, apiUrl, token);
@@ -12387,63 +11971,169 @@ createRoot(document.getElementById('root')).render(React.createElement(App));
12387
11971
  `;
12388
11972
  }
12389
11973
  };
12390
- const devHtml = `<!DOCTYPE html>
11974
+ const { existsSync: fsExists } = await import("fs");
11975
+ const projectIndexPath = require("path").join(process.cwd(), "index.html");
11976
+ const hasProjectIndex = fsExists(projectIndexPath);
11977
+ if (!hasProjectIndex) {
11978
+ const { writeFileSync: fsWrite } = await import("fs");
11979
+ fsWrite(projectIndexPath, `<!DOCTYPE html>
12391
11980
  <html lang="en">
12392
11981
  <head>
12393
11982
  <meta charset="UTF-8">
12394
11983
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
12395
11984
  <title>MindMatrix Dev</title>
12396
- <style>
12397
- * { margin: 0; padding: 0; box-sizing: border-box; }
12398
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #fafafa; color: #111; }
12399
- #root { min-height: 100vh; }
12400
- .mm-loading { display: flex; align-items: center; justify-content: center; min-height: 100vh; flex-direction: column; gap: 12px; }
12401
- .mm-loading h1 { font-size: 20px; font-weight: 600; color: #333; }
12402
- .mm-loading p { color: #888; font-size: 14px; }
12403
- </style>
12404
11985
  </head>
12405
11986
  <body>
12406
- <div id="root">
12407
- <div class="mm-loading">
12408
- <h1>MindMatrix Dev</h1>
12409
- <p>Loading...</p>
12410
- </div>
12411
- </div>
12412
- <script>
12413
- async function render() {
12414
- const root = document.getElementById('root');
11987
+ <div id="root"></div>
11988
+ <script type="module" src="/__mm_dev_entry.tsx"></script>
11989
+ </body>
11990
+ </html>`, "utf-8");
11991
+ }
11992
+ const devEntryPlugin = {
11993
+ name: "mindmatrix-dev-entry",
11994
+ resolveId(id) {
11995
+ if (id === "/__mm_dev_entry.tsx") return id;
11996
+ return null;
11997
+ },
11998
+ load(id) {
11999
+ if (id !== "/__mm_dev_entry.tsx") return null;
12000
+ return `
12001
+ import React, { useState, useEffect } from 'react';
12002
+ import { createRoot } from 'react-dom/client';
12003
+ import { DevPlayer } from '@mmapp/react/player';
12004
+ import { PlayerProvider, ExperienceRenderer, createApiResolver } from '@mmapp/react/player';
12005
+
12006
+ // Detect API base URL \u2014 proxy through dev server or use direct URL
12007
+ const API_BASE = window.location.origin + '/api/v1';
12008
+ const resolver = createApiResolver({ baseUrl: API_BASE, token: () => localStorage.getItem('auth_token') });
12009
+
12010
+ /**
12011
+ * Prepare experience tree for rendering.
12012
+ * Attaches metadata.dataSources to the root node and remaps
12013
+ * dataSource slugs to use definition-relative naming.
12014
+ *
12015
+ * @param definition - The main blueprint definition
12016
+ * @param allDefinitions - ALL definitions from the API (used for slug resolution)
12017
+ */
12018
+ function prepareTree(definition, allDefinitions) {
12019
+ const exp = definition.experience;
12020
+ if (!exp || typeof exp !== 'object') return null;
12021
+
12022
+ const meta = definition.metadata || {};
12023
+ const dataSources = meta.dataSources || [];
12024
+ const mutationTargets = meta.mutationTargets || [];
12025
+
12026
+ // Build a slug map from ALL deployed definitions
12027
+ // This resolves bare model names (e.g. "item") to full slugs (e.g. "tutorial-1-item")
12028
+ const blueprintSlug = definition.slug || '';
12029
+ const allSlugs = (allDefinitions || []).map(d => d.slug).filter(Boolean);
12030
+
12031
+ function resolveSlug(bareSlug) {
12032
+ if (!bareSlug) return bareSlug;
12033
+ // Already a full slug (contains hyphen matching a known definition)
12034
+ if (allSlugs.includes(bareSlug)) return bareSlug;
12035
+ // Try blueprint-prefixed slug: "item" \u2192 "tutorial-1-item"
12036
+ const prefixed = blueprintSlug + '-' + bareSlug;
12037
+ if (allSlugs.includes(prefixed)) return prefixed;
12038
+ // Try matching by suffix across all definitions
12039
+ const match = allSlugs.find(s => s.endsWith('-' + bareSlug));
12040
+ if (match) return match;
12041
+ // Return original (will attempt as-is)
12042
+ return bareSlug;
12043
+ }
12044
+
12045
+ // Clone root node and attach dataSources
12046
+ const root = { ...exp };
12047
+ if (dataSources.length > 0 && !root.dataSources) {
12048
+ root.dataSources = dataSources.map(ds => ({
12049
+ ...ds,
12050
+ slug: resolveSlug(ds.slug),
12051
+ }));
12052
+ }
12053
+
12054
+ // Remap mutation targets the same way
12055
+ if (mutationTargets.length > 0) {
12056
+ const resolvedTargets = mutationTargets.map(t => resolveSlug(t));
12057
+ root.config = { ...(root.config || {}), _mutationTargets: resolvedTargets };
12058
+ }
12059
+
12060
+ return root;
12061
+ }
12062
+
12063
+ function App() {
12064
+ const [tree, setTree] = useState(null);
12065
+ const [error, setError] = useState(null);
12066
+
12067
+ useEffect(() => {
12068
+ async function loadTree() {
12415
12069
  try {
12416
- const res = await fetch('/api/v1/workflow/definitions');
12070
+ const res = await fetch(API_BASE + '/workflow/definitions');
12417
12071
  const json = await res.json();
12418
- const items = json.items || json.data || [];
12419
- let html = '<div style="padding:40px;max-width:960px;margin:0 auto;font-family:-apple-system,BlinkMacSystemFont,sans-serif">';
12420
- html += '<h1 style="margin-bottom:8px">MindMatrix Dev</h1>';
12421
- html += '<p style="color:#666;margin-bottom:24px">' + items.length + ' definition(s) deployed</p>';
12422
- if (items.length === 0) {
12423
- html += '<div style="text-align:center;padding:60px 20px;color:#888"><p>No definitions yet.</p><p style="margin-top:8px;font-size:13px">Edit your model files and save.</p></div>';
12424
- }
12425
- for (const def of items) {
12426
- html += '<div style="border:1px solid #e0e0e0;border-radius:8px;padding:16px;margin-bottom:12px;background:#fff">';
12427
- html += '<h3 style="margin-bottom:4px">' + (def.name || def.slug || 'Unnamed') + '</h3>';
12428
- html += '<p style="color:#888;font-size:13px">slug: ' + (def.slug || '?') + ' | states: ' + (def.states?.length || 0) + ' | fields: ' + (def.fields?.length || 0) + '</p>';
12429
- html += '</div>';
12430
- }
12431
- html += '</div>';
12432
- root.innerHTML = html;
12072
+ const rawItems = json.items || json.data || [];
12073
+ // Flatten: API returns { id, slug, definition: { experience, ... } }
12074
+ // Merge definition fields up to the top level for easier access
12075
+ const items = rawItems.map(d => {
12076
+ const def = d.definition || {};
12077
+ return { ...d, ...def, definition: undefined };
12078
+ });
12079
+ // Find the main blueprint definition (has experience tree)
12080
+ const main = items.find(d => d.experience && !(Array.isArray(d.category) ? d.category.includes('data') : d.category === 'data')) || items.find(d => d.experience) || items[0];
12081
+ if (main?.experience) {
12082
+ const prepared = prepareTree(main, items);
12083
+ if (prepared) {
12084
+ setTree(prepared);
12085
+ return;
12086
+ }
12087
+ }
12088
+ if (main) {
12089
+ // No experience tree \u2014 show definition info
12090
+ setTree({
12091
+ type: 'Stack',
12092
+ props: { style: { padding: 40, gap: 16 } },
12093
+ children: [
12094
+ { type: 'Text', props: { children: main.name || main.slug, style: { fontSize: 24, fontWeight: 'bold' } } },
12095
+ { type: 'Text', props: { children: (main.states?.length || 0) + ' states, ' + (main.fields?.length || 0) + ' fields', style: { color: '#666' } } },
12096
+ ...items.map((d, i) => ({
12097
+ type: 'Card',
12098
+ props: { key: i, style: { padding: 16, border: '1px solid #ddd', borderRadius: 8 } },
12099
+ children: [
12100
+ { type: 'Text', props: { children: d.name || d.slug, style: { fontWeight: 600 } } },
12101
+ { type: 'Text', props: { children: 'slug: ' + d.slug + ' | ' + (d.states?.length || 0) + ' states', style: { fontSize: 13, color: '#888' } } },
12102
+ ],
12103
+ })),
12104
+ ],
12105
+ });
12106
+ }
12433
12107
  } catch (e) {
12434
- root.innerHTML = '<div style="padding:40px"><h1>MindMatrix Dev</h1><p style="color:#c00;margin-top:8px">API Error: ' + e.message + '</p></div>';
12108
+ setError(e.message);
12435
12109
  }
12436
12110
  }
12437
- render();
12438
- setInterval(render, 3000);
12439
- </script>
12440
- </body>
12441
- </html>`;
12442
- const { mkdtempSync, writeFileSync: writeFileSync5 } = await import("fs");
12443
- const { join: join4 } = await import("path");
12444
- const { tmpdir } = await import("os");
12445
- const devRoot = mkdtempSync(join4(tmpdir(), "mm-dev-"));
12446
- writeFileSync5(join4(devRoot, "index.html"), devHtml, "utf-8");
12111
+ loadTree();
12112
+ }, []);
12113
+
12114
+ if (error) return React.createElement('div', { style: { padding: 40 } },
12115
+ React.createElement('h1', null, 'MindMatrix Dev'),
12116
+ React.createElement('p', { style: { color: '#c00' } }, 'Error: ' + error)
12117
+ );
12118
+
12119
+ if (!tree) return React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh' } },
12120
+ React.createElement('p', null, 'Loading...')
12121
+ );
12122
+
12123
+ // If tree has 'component' field, use ExperienceRenderer; otherwise legacy DevPlayer
12124
+ if (tree.component) {
12125
+ return React.createElement(PlayerProvider, { resolver },
12126
+ React.createElement(ExperienceRenderer, { tree, className: 'mm-experience-root' })
12127
+ );
12128
+ }
12129
+
12130
+ return React.createElement(DevPlayer, { tree, title: document.title || 'MindMatrix Dev' });
12131
+ }
12132
+
12133
+ createRoot(document.getElementById('root')).render(React.createElement(App));
12134
+ `;
12135
+ }
12136
+ };
12447
12137
  let deployInFlight = false;
12448
12138
  const compileDeployPlugin = {
12449
12139
  name: "mindmatrix-dev-compile-deploy",
@@ -12474,16 +12164,16 @@ createRoot(document.getElementById('root')).render(React.createElement(App));
12474
12164
  }
12475
12165
  };
12476
12166
  const viteConfig = {
12477
- // Physical index.html lives in a temp dir so Vite serves it natively.
12478
- root: devRoot,
12479
- // Pre-bundle React so Vite doesn't warn about missing entry point.
12167
+ // Use the blueprint directory as Vite root (has node_modules with React).
12168
+ root: process.cwd(),
12169
+ // Pre-bundle React and the player for fast dev startup.
12480
12170
  optimizeDeps: { include: ["react", "react-dom/client"] },
12481
12171
  server: {
12482
12172
  port,
12483
12173
  open,
12484
12174
  host: true,
12485
12175
  // Allow serving files from the real project directory (fs.allow).
12486
- fs: { allow: [devRoot, process.cwd(), ".."] },
12176
+ fs: { allow: [process.cwd(), ".."] },
12487
12177
  proxy: {
12488
12178
  "/api": { target: proxyTarget, changeOrigin: true, secure: true, ws: true },
12489
12179
  "/health": { target: proxyTarget, changeOrigin: true, secure: true },
@@ -12493,6 +12183,7 @@ createRoot(document.getElementById('root')).render(React.createElement(App));
12493
12183
  plugins: [
12494
12184
  mindmatrixReact(pluginOpts),
12495
12185
  compileDeployPlugin,
12186
+ devEntryPlugin,
12496
12187
  devPlayerPlugin,
12497
12188
  { name: "mindmatrix-error-overlay", configureServer(server) {
12498
12189
  server.middlewares.use(errorOverlayMiddleware());
@@ -12500,8 +12191,8 @@ createRoot(document.getElementById('root')).render(React.createElement(App));
12500
12191
  ],
12501
12192
  logLevel: "warn"
12502
12193
  };
12503
- const { createServer: createServer2 } = await import("vite");
12504
- const vite = await createServer2(viteConfig);
12194
+ const { createServer } = await import("vite");
12195
+ const vite = await createServer(viteConfig);
12505
12196
  await vite.listen();
12506
12197
  const resolvedPort = vite.config.server.port ?? port;
12507
12198
  if (enableWs && vite.httpServer) {
@@ -12519,7 +12210,7 @@ createRoot(document.getElementById('root')).render(React.createElement(App));
12519
12210
  } catch {
12520
12211
  }
12521
12212
  }
12522
- printBanner({ port: resolvedPort, apiUrl: isLocalMode ? `${apiUrl} (local in-memory)` : apiUrl, src, include, health, token: !!token, compiled: initialCompiled, deployed: initialDeployed, slug: initialSlug, errors: initialErrors });
12213
+ printBanner({ port: resolvedPort, apiUrl, src, include, health, token: !!token, compiled: initialCompiled, deployed: initialDeployed, slug: initialSlug, errors: initialErrors });
12523
12214
  return {
12524
12215
  vite,
12525
12216
  port: resolvedPort,
@@ -12551,14 +12242,6 @@ createRoot(document.getElementById('root')).render(React.createElement(App));
12551
12242
  clients.clear();
12552
12243
  currentErrors = null;
12553
12244
  await vite.close();
12554
- if (localServer) {
12555
- await localServer.close();
12556
- }
12557
- try {
12558
- const { rmSync } = await import("fs");
12559
- rmSync(devRoot, { recursive: true, force: true });
12560
- } catch {
12561
- }
12562
12245
  }
12563
12246
  };
12564
12247
  }