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

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 (189) 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-4HX4PI4R.mjs +734 -0
  17. package/dist/chunk-4VU56NTZ.mjs +544 -0
  18. package/dist/chunk-4XHK6FWL.mjs +2058 -0
  19. package/dist/chunk-52C2JKH2.mjs +186 -0
  20. package/dist/chunk-52XHYD2V.mjs +214 -0
  21. package/dist/chunk-5GUFFFGL.mjs +148 -0
  22. package/dist/chunk-5N2FDDS6.mjs +214 -0
  23. package/dist/chunk-5ZSJXWZT.mjs +1646 -0
  24. package/dist/chunk-6CQOAAMV.mjs +1803 -0
  25. package/dist/chunk-6SEVAAVT.mjs +3516 -0
  26. package/dist/chunk-6YLR5ZDA.mjs +2829 -0
  27. package/dist/chunk-77UJB356.mjs +244 -0
  28. package/dist/chunk-7QOAJPQF.mjs +774 -0
  29. package/dist/chunk-A5RCMIBP.mjs +1795 -0
  30. package/dist/chunk-A63R3GKH.mjs +1803 -0
  31. package/dist/chunk-ABNTZXF5.mjs +951 -0
  32. package/dist/chunk-ADHWW56I.mjs +214 -0
  33. package/dist/chunk-AOGY2GK6.mjs +3292 -0
  34. package/dist/chunk-AXXUXRNA.mjs +1434 -0
  35. package/dist/chunk-BZLU5YK5.mjs +1025 -0
  36. package/dist/chunk-C7XCDDBH.mjs +1802 -0
  37. package/dist/chunk-CHLVKMQW.mjs +175 -0
  38. package/dist/chunk-CKGOZAB7.mjs +939 -0
  39. package/dist/chunk-CSXYDIVC.mjs +214 -0
  40. package/dist/chunk-CXTV4VGG.mjs +148 -0
  41. package/dist/chunk-D34RAZUX.mjs +2223 -0
  42. package/dist/chunk-DDIC7WM6.mjs +3127 -0
  43. package/dist/chunk-DPUQOBU6.mjs +4810 -0
  44. package/dist/chunk-E6MDVTGT.mjs +148 -0
  45. package/dist/chunk-EGKMUEM6.mjs +544 -0
  46. package/dist/chunk-EO6SYNCG.mjs +175 -0
  47. package/dist/chunk-EQGA6A6D.mjs +121 -0
  48. package/dist/chunk-EY2CSXYA.mjs +822 -0
  49. package/dist/chunk-FF5BQVII.mjs +148 -0
  50. package/dist/chunk-FIQ65CDR.mjs +925 -0
  51. package/dist/chunk-FOZXJFAR.mjs +186 -0
  52. package/dist/chunk-G2IAZ5Q6.mjs +148 -0
  53. package/dist/chunk-G7SMOWOL.mjs +828 -0
  54. package/dist/chunk-GK7NU6DO.mjs +214 -0
  55. package/dist/chunk-HDSCPEHY.mjs +4061 -0
  56. package/dist/chunk-HJELFNEA.mjs +186 -0
  57. package/dist/chunk-HOIUP6IF.mjs +690 -0
  58. package/dist/chunk-HRJGDPNE.mjs +148 -0
  59. package/dist/chunk-I3AU7GRD.mjs +120 -0
  60. package/dist/chunk-I3VQQJZ6.mjs +2843 -0
  61. package/dist/chunk-IPTX5MJU.mjs +3223 -0
  62. package/dist/chunk-ITGUSH2Z.mjs +2783 -0
  63. package/dist/chunk-IXHBCAMF.mjs +3306 -0
  64. package/dist/chunk-J7JUAHS4.mjs +186 -0
  65. package/dist/chunk-J7TWJ3TM.mjs +2784 -0
  66. package/dist/chunk-JDPLDGVF.mjs +4810 -0
  67. package/dist/chunk-JK72MQ4N.mjs +877 -0
  68. package/dist/chunk-K2HHCAS2.mjs +148 -0
  69. package/dist/chunk-K5HX2SVL.mjs +1902 -0
  70. package/dist/chunk-KAUEQ2F3.mjs +148 -0
  71. package/dist/chunk-KFVVOS5N.mjs +925 -0
  72. package/dist/chunk-KIH4AN3Y.mjs +154 -0
  73. package/dist/chunk-KPDMN5IX.mjs +175 -0
  74. package/dist/chunk-LZL2IRCH.mjs +186 -0
  75. package/dist/chunk-MIZV3TAN.mjs +3293 -0
  76. package/dist/chunk-MRH4J7IX.mjs +2846 -0
  77. package/dist/chunk-NKBL5GUC.mjs +186 -0
  78. package/dist/chunk-NQCNSCF6.mjs +148 -0
  79. package/dist/chunk-NRP5J3BR.mjs +4811 -0
  80. package/dist/chunk-NTB7OEX2.mjs +2918 -0
  81. package/dist/chunk-NUPJYPFU.mjs +801 -0
  82. package/dist/chunk-NVQUTSQX.mjs +3128 -0
  83. package/dist/chunk-OGMG64EY.mjs +148 -0
  84. package/dist/chunk-OL5B2HTH.mjs +175 -0
  85. package/dist/chunk-OPJKP747.mjs +7506 -0
  86. package/dist/chunk-OQLGGBNE.mjs +2918 -0
  87. package/dist/chunk-OW4AQUDL.mjs +544 -0
  88. package/dist/chunk-OWI6XWCD.mjs +3375 -0
  89. package/dist/chunk-OZT2EAF2.mjs +2776 -0
  90. package/dist/chunk-PBRBRKIQ.mjs +175 -0
  91. package/dist/chunk-PRUMNNDI.mjs +3192 -0
  92. package/dist/chunk-QPNHDTSM.mjs +4839 -0
  93. package/dist/chunk-RNEIAJDR.mjs +897 -0
  94. package/dist/chunk-RY7POBNT.mjs +3127 -0
  95. package/dist/chunk-S6FJ4DXL.mjs +1813 -0
  96. package/dist/chunk-SU4E6E7B.mjs +3153 -0
  97. package/dist/chunk-SYUUKW5A.mjs +3379 -0
  98. package/dist/chunk-THB5SX2S.mjs +113 -0
  99. package/dist/chunk-THFYE5ZX.mjs +244 -0
  100. package/dist/chunk-TK3QMXIP.mjs +2921 -0
  101. package/dist/chunk-TRR2NPAV.mjs +248 -0
  102. package/dist/chunk-TTTTOT7P.mjs +1803 -0
  103. package/dist/chunk-TXONBY6A.mjs +7509 -0
  104. package/dist/chunk-U2PX3JSY.mjs +1933 -0
  105. package/dist/chunk-UASOWKDI.mjs +186 -0
  106. package/dist/chunk-UDDTWG5J.mjs +734 -0
  107. package/dist/chunk-UIWLAQCL.mjs +175 -0
  108. package/dist/chunk-UL2XZEMA.mjs +3128 -0
  109. package/dist/chunk-US3AVDAI.mjs +3456 -0
  110. package/dist/chunk-V5DIDOTT.mjs +148 -0
  111. package/dist/chunk-VLTKQDJ3.mjs +244 -0
  112. package/dist/chunk-VVC42PTS.mjs +175 -0
  113. package/dist/chunk-VX3T3NIR.mjs +897 -0
  114. package/dist/chunk-WBYMW4NQ.mjs +3450 -0
  115. package/dist/chunk-XMWUHQVV.mjs +939 -0
  116. package/dist/chunk-Y6FXYEAI.mjs +10 -0
  117. package/dist/chunk-YCWC2SCO.mjs +148 -0
  118. package/dist/chunk-YFS6JMYO.mjs +3342 -0
  119. package/dist/chunk-ZE67HOSN.mjs +148 -0
  120. package/dist/chunk-ZSK5TPIV.mjs +148 -0
  121. package/dist/cli/index.js +317 -645
  122. package/dist/cli/index.mjs +8 -8
  123. package/dist/config-PL24KEWL.mjs +219 -0
  124. package/dist/dev-server-Bs_sz2DG.d.mts +111 -0
  125. package/dist/dev-server-Bs_sz2DG.d.ts +111 -0
  126. package/dist/dev-server-RmGHIntF.d.mts +113 -0
  127. package/dist/dev-server-RmGHIntF.d.ts +113 -0
  128. package/dist/dev-server.js +194 -515
  129. package/dist/dev-server.mjs +4 -4
  130. package/dist/engine-binary-KQB23JDR.mjs +97 -0
  131. package/dist/envelope-DD7v0v6E.d.mts +265 -0
  132. package/dist/envelope-DD7v0v6E.d.ts +265 -0
  133. package/dist/envelope.js +9 -6
  134. package/dist/envelope.mjs +2 -2
  135. package/dist/index-B5gSgvnd.d.mts +44 -0
  136. package/dist/index-B5gSgvnd.d.ts +44 -0
  137. package/dist/index-Bs0MnR54.d.mts +103 -0
  138. package/dist/index-Bs0MnR54.d.ts +103 -0
  139. package/dist/index-DR0nNc_f.d.mts +101 -0
  140. package/dist/index-DR0nNc_f.d.ts +101 -0
  141. package/dist/index-revho_gS.d.mts +104 -0
  142. package/dist/index-revho_gS.d.ts +104 -0
  143. package/dist/index-vQjwYekL.d.mts +104 -0
  144. package/dist/index-vQjwYekL.d.ts +104 -0
  145. package/dist/index.d.mts +2 -2
  146. package/dist/index.d.ts +2 -2
  147. package/dist/index.js +198 -517
  148. package/dist/index.mjs +9 -8
  149. package/dist/init-2XLTUF7O.mjs +407 -0
  150. package/dist/init-7FJENUDK.mjs +407 -0
  151. package/dist/init-DQDX3QK6.mjs +369 -0
  152. package/dist/init-K3GVM4JS.mjs +538 -0
  153. package/dist/init-NXS5BJN3.mjs +454 -0
  154. package/dist/init-UC3FWPIW.mjs +367 -0
  155. package/dist/init-UNV5XIDE.mjs +367 -0
  156. package/dist/project-compiler-2HOPO7GC.mjs +10 -0
  157. package/dist/project-compiler-D245L5QR.mjs +10 -0
  158. package/dist/project-compiler-FUQRMB4X.mjs +10 -0
  159. package/dist/project-compiler-LA5OBI5P.mjs +10 -0
  160. package/dist/project-compiler-OP2VVGJQ.mjs +10 -0
  161. package/dist/project-compiler-PZNFE6AH.mjs +10 -0
  162. package/dist/project-compiler-QBVF6MFI.mjs +10 -0
  163. package/dist/project-compiler-VFR6CSDX.mjs +10 -0
  164. package/dist/project-compiler-WMJZA4UH.mjs +10 -0
  165. package/dist/project-compiler-XXS27TZT.mjs +10 -0
  166. package/dist/project-compiler-YYGDSHY5.mjs +10 -0
  167. package/dist/project-decompiler-5GY2KSG4.mjs +7 -0
  168. package/dist/project-decompiler-7I2OMUVY.mjs +7 -0
  169. package/dist/project-decompiler-US7GAVIC.mjs +7 -0
  170. package/dist/pull-2Q53HF3H.mjs +107 -0
  171. package/dist/pull-5AFHD3QG.mjs +109 -0
  172. package/dist/pull-65GUSX6F.mjs +109 -0
  173. package/dist/pull-6LVI4LMM.mjs +109 -0
  174. package/dist/pull-A2QUHW4K.mjs +109 -0
  175. package/dist/pull-B6T5BUKV.mjs +109 -0
  176. package/dist/pull-CKHWZT33.mjs +109 -0
  177. package/dist/pull-GM74ERRT.mjs +109 -0
  178. package/dist/pull-JBEQWVPE.mjs +109 -0
  179. package/dist/pull-P44LDRWB.mjs +109 -0
  180. package/dist/pull-W2US3T3E.mjs +109 -0
  181. package/dist/testing/index.js +9 -6
  182. package/dist/testing/index.mjs +1 -1
  183. package/dist/verify-3PPS4XAM.mjs +1833 -0
  184. package/dist/verify-GKEH5FZQ.mjs +1833 -0
  185. package/dist/verify-HDKUNHZ4.mjs +1833 -0
  186. package/dist/verify-SEIXUGN4.mjs +1833 -0
  187. package/dist/vite/index.js +10 -7
  188. package/dist/vite/index.mjs +2 -2
  189. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -2115,7 +2115,8 @@ function convertOnEvent(sub) {
2115
2115
  };
2116
2116
  }
2117
2117
  function emitIR(extracted) {
2118
- const { slug, name, version, description, category, fields, states, transitions } = extracted;
2118
+ const { slug, name, version, description, category: rawCategory, fields, states, transitions } = extracted;
2119
+ const category = Array.isArray(rawCategory) ? rawCategory : [rawCategory];
2119
2120
  const stateArray = Array.from(states.values());
2120
2121
  if (stateArray.length === 0) {
2121
2122
  stateArray.push({
@@ -2503,13 +2504,15 @@ function emitCanonical(extracted, sourceFilename) {
2503
2504
  }
2504
2505
  ]
2505
2506
  });
2506
- const category = extracted.category;
2507
+ const rawCat = extracted.category;
2507
2508
  let categoryArray;
2508
- if (category.includes("/")) {
2509
- const [primary, ...tags] = category.split("/");
2509
+ if (Array.isArray(rawCat)) {
2510
+ categoryArray = rawCat;
2511
+ } else if (rawCat.includes("/")) {
2512
+ const [primary, ...tags] = rawCat.split("/");
2510
2513
  categoryArray = (0, import_player_core.normalizeCategory)(primary, ...tags);
2511
2514
  } else {
2512
- categoryArray = [category];
2515
+ categoryArray = [rawCat];
2513
2516
  }
2514
2517
  return {
2515
2518
  slug: ir.slug,
@@ -2662,7 +2665,7 @@ function compilerStateToWorkflow(state, metadata) {
2662
2665
  name: metadata.name || "Workflow",
2663
2666
  version: metadata.version || "0.1.0",
2664
2667
  description: metadata.description,
2665
- category: metadata.category || "workflow",
2668
+ category: metadata.categoryArray ? metadata.categoryArray : [metadata.category || "workflow"],
2666
2669
  fields: state.fields || [],
2667
2670
  states: state.states || /* @__PURE__ */ new Map(),
2668
2671
  transitions: state.transitions || [],
@@ -7794,7 +7797,7 @@ function extractRouterWorkflow(pages, options = {}) {
7794
7797
  name: "Router",
7795
7798
  version: "1.0.0",
7796
7799
  description: "Auto-derived router workflow from file-based routing",
7797
- category: "router",
7800
+ category: ["router"],
7798
7801
  fields,
7799
7802
  states,
7800
7803
  transitions,
@@ -7893,7 +7896,8 @@ function compileModel(filename, source, options = {}) {
7893
7896
  parserOpts: { plugins: parserPlugins, attachComment: true }
7894
7897
  });
7895
7898
  const ir = babelResult?.metadata?.mindmatrixIR ?? createEmptyModelIR(interfaceName);
7896
- ir.category = options.categoryOverride || annotation.category || "data";
7899
+ const catOverride = options.categoryOverride || annotation.category || "data";
7900
+ ir.category = Array.isArray(catOverride) ? catOverride : [catOverride];
7897
7901
  if (options.slugOverride) {
7898
7902
  ir.slug = options.slugOverride;
7899
7903
  }
@@ -7957,7 +7961,7 @@ function createEmptyModelIR(interfaceName) {
7957
7961
  name: interfaceName,
7958
7962
  version: "1.0.0",
7959
7963
  description: "Data model: " + interfaceName,
7960
- category: "data",
7964
+ category: ["data"],
7961
7965
  fields: [],
7962
7966
  states: [{
7963
7967
  name: "draft",
@@ -8125,7 +8129,7 @@ function buildRouterIR(routes, layouts, allParams, slugPrefix) {
8125
8129
  name: "Router",
8126
8130
  version: "1.0.0",
8127
8131
  description: "Auto-generated router from app/ directory structure",
8128
- category: "router",
8132
+ category: ["router"],
8129
8133
  fields,
8130
8134
  states,
8131
8135
  transitions,
@@ -8394,7 +8398,7 @@ function extractAction(source, filename) {
8394
8398
  slug,
8395
8399
  name: humanName,
8396
8400
  version: "0.1.0",
8397
- category: "action",
8401
+ category: ["action"],
8398
8402
  fields,
8399
8403
  states: states2,
8400
8404
  transitions: transitions2,
@@ -8446,7 +8450,7 @@ function extractAction(source, filename) {
8446
8450
  slug,
8447
8451
  name: humanName,
8448
8452
  version: "0.1.0",
8449
- category: "action",
8453
+ category: ["action"],
8450
8454
  fields,
8451
8455
  states,
8452
8456
  transitions,
@@ -9883,7 +9887,7 @@ function applyConfig(ir, config) {
9883
9887
  if (config.name) ir.name = config.name;
9884
9888
  if (config.version) ir.version = config.version;
9885
9889
  if (config.description !== void 0) ir.description = config.description;
9886
- if (config.category) ir.category = config.category;
9890
+ if (config.category) ir.category = Array.isArray(config.category) ? config.category : [config.category];
9887
9891
  if (!ir.metadata) ir.metadata = {};
9888
9892
  ir.metadata.stable_id = "def-" + ir.slug;
9889
9893
  ir.metadata.provenance = {
@@ -9899,7 +9903,7 @@ function createEmptyIR(config) {
9899
9903
  name: config.name || "Project",
9900
9904
  version: config.version || "0.1.0",
9901
9905
  description: config.description,
9902
- category: config.category || "workflow",
9906
+ category: Array.isArray(config.category) ? config.category : [config.category || "workflow"],
9903
9907
  fields: [],
9904
9908
  states: [{
9905
9909
  name: "draft",
@@ -10057,8 +10061,10 @@ function buildComposedResult(files, fileIRs, config, errors, warnings, options =
10057
10061
  if (isWorkflowFile(filename)) {
10058
10062
  workflowIRs.push(ir);
10059
10063
  } else if (isModelFile2(filename)) {
10060
- if (!ir.category || ir.category === "workflow") {
10061
- ir.category = "data";
10064
+ const cat = ir.category;
10065
+ const isDefault = !cat || cat === "workflow" || Array.isArray(cat) && cat.length === 1 && cat[0] === "workflow";
10066
+ if (isDefault) {
10067
+ ir.category = ["data"];
10062
10068
  }
10063
10069
  modelIRs.push(ir);
10064
10070
  } else if (isServerActionFile2(filename)) {
@@ -12856,7 +12862,8 @@ function decompileProject(definition, options) {
12856
12862
  ...child,
12857
12863
  experience: child.views?.default
12858
12864
  };
12859
- if (child.category === "data" && child.fields.length > 0 && !options?.skipModels) {
12865
+ const childCatArr = Array.isArray(child.category) ? child.category : [child.category];
12866
+ if (childCatArr.includes("data") && child.fields.length > 0 && !options?.skipModels) {
12860
12867
  let childModelContent = generateModelFile(childSlug, child.fields);
12861
12868
  if (child.states.length > 0) {
12862
12869
  childModelContent += generateStateEnum(childSlug, child.states);
@@ -13117,7 +13124,8 @@ function compareIR(original, roundTripped) {
13117
13124
  const diffs = [];
13118
13125
  comparePrimitive(diffs, "slug", original.slug, roundTripped.slug);
13119
13126
  comparePrimitive(diffs, "version", original.version, roundTripped.version);
13120
- comparePrimitive(diffs, "category", original.category, roundTripped.category);
13127
+ const normCat = (c) => JSON.stringify(Array.isArray(c) ? c : c ? [c] : []);
13128
+ comparePrimitive(diffs, "category", normCat(original.category), normCat(roundTripped.category));
13121
13129
  compareFields(diffs, original.fields, roundTripped.fields);
13122
13130
  compareStates(diffs, original.states, roundTripped.states);
13123
13131
  compareTransitions(diffs, original.transitions, roundTripped.transitions);
@@ -13334,7 +13342,7 @@ function mindmatrixReact(options) {
13334
13342
  slug: ir.slug,
13335
13343
  name: ir.name,
13336
13344
  version: ir.version,
13337
- category: ir.category || "workflow",
13345
+ category: ir.category || ["workflow"],
13338
13346
  fields: ir.fields || [],
13339
13347
  states: ir.states || [],
13340
13348
  transitions: ir.transitions || [],
@@ -13919,425 +13927,6 @@ async function startWatchMode(options) {
13919
13927
  });
13920
13928
  }
13921
13929
 
13922
- // src/cli/local-server.ts
13923
- var http = __toESM(require("http"));
13924
- var import_node_crypto = require("crypto");
13925
- var MemoryStore = class {
13926
- constructor() {
13927
- this.definitions = /* @__PURE__ */ new Map();
13928
- this.instances = /* @__PURE__ */ new Map();
13929
- this.slugIndex = /* @__PURE__ */ new Map();
13930
- }
13931
- // slug → id
13932
- // ── Definitions ──────────────────────────────────────────────────────
13933
- createDefinition(input) {
13934
- if (this.slugIndex.has(input.slug)) {
13935
- const existing = this.definitions.get(this.slugIndex.get(input.slug));
13936
- if (existing) return existing;
13937
- }
13938
- const now = (/* @__PURE__ */ new Date()).toISOString();
13939
- const def = {
13940
- id: input.id ?? (0, import_node_crypto.randomUUID)(),
13941
- slug: input.slug,
13942
- name: input.name,
13943
- version: input.version ?? "1.0.0",
13944
- description: input.description ?? null,
13945
- category: input.category ?? "workflow",
13946
- fields: input.fields ?? [],
13947
- states: input.states ?? [],
13948
- transitions: input.transitions ?? [],
13949
- roles: input.roles ?? [],
13950
- experience: input.experience ?? null,
13951
- metadata: input.metadata ?? {},
13952
- child_definitions: input.child_definitions ?? [],
13953
- is_immutable: input.is_immutable ?? false,
13954
- tags: input.tags ?? [],
13955
- inline_tags: input.inline_tags ?? [],
13956
- created_at: now,
13957
- updated_at: now
13958
- };
13959
- this.definitions.set(def.id, def);
13960
- this.slugIndex.set(def.slug, def.id);
13961
- return def;
13962
- }
13963
- getDefinition(idOrSlug) {
13964
- const byId = this.definitions.get(idOrSlug);
13965
- if (byId) return byId;
13966
- const id = this.slugIndex.get(idOrSlug);
13967
- if (id) return this.definitions.get(id);
13968
- return void 0;
13969
- }
13970
- listDefinitions(opts) {
13971
- let items = Array.from(this.definitions.values());
13972
- if (opts?.category) {
13973
- items = items.filter((d) => d.category === opts.category);
13974
- }
13975
- const total = items.length;
13976
- const offset = opts?.offset ?? 0;
13977
- const limit = opts?.limit ?? 50;
13978
- items = items.slice(offset, offset + limit);
13979
- return { items, total };
13980
- }
13981
- patchDefinition(id, patch) {
13982
- const def = this.definitions.get(id);
13983
- if (!def) return void 0;
13984
- Object.assign(def, patch, { updated_at: (/* @__PURE__ */ new Date()).toISOString() });
13985
- return def;
13986
- }
13987
- deleteDefinition(id) {
13988
- const def = this.definitions.get(id);
13989
- if (!def) return false;
13990
- this.slugIndex.delete(def.slug);
13991
- this.definitions.delete(id);
13992
- return true;
13993
- }
13994
- // ── Instances ────────────────────────────────────────────────────────
13995
- createInstance(input) {
13996
- const def = this.getDefinition(input.definition_id) ?? this.getDefinition(input.definition_slug);
13997
- if (!def) return null;
13998
- const initialState = def.states.find((s) => s.type === "START" || s.type === "initial");
13999
- const stateName = initialState?.name ?? "initial";
14000
- const stateData = {};
14001
- for (const field of def.fields) {
14002
- if (field.default_value !== void 0) {
14003
- stateData[field.name] = field.default_value;
14004
- }
14005
- }
14006
- Object.assign(stateData, input.state_data ?? {});
14007
- const now = (/* @__PURE__ */ new Date()).toISOString();
14008
- const inst = {
14009
- id: (0, import_node_crypto.randomUUID)(),
14010
- definition_id: def.id,
14011
- definition_slug: def.slug,
14012
- current_state: stateName,
14013
- state_data: stateData,
14014
- execution_lock_version: 0,
14015
- event_log: [{
14016
- event_type: "transition",
14017
- message: `Instance created in state '${stateName}'`,
14018
- timestamp: now
14019
- }],
14020
- created_at: now,
14021
- updated_at: now
14022
- };
14023
- this.instances.set(inst.id, inst);
14024
- return inst;
14025
- }
14026
- getInstance(id) {
14027
- return this.instances.get(id);
14028
- }
14029
- listInstances(opts) {
14030
- let items = Array.from(this.instances.values());
14031
- if (opts?.definition_id) {
14032
- items = items.filter((i) => i.definition_id === opts.definition_id);
14033
- }
14034
- const total = items.length;
14035
- const offset = opts?.offset ?? 0;
14036
- const limit = opts?.limit ?? 50;
14037
- items = items.slice(offset, offset + limit);
14038
- return { items, total };
14039
- }
14040
- // ── Execute Action (Transition) ──────────────────────────────────────
14041
- executeAction(input) {
14042
- const def = this.getDefinition(input.definition_id);
14043
- if (!def) return { success: false, error: "Definition not found" };
14044
- let inst;
14045
- if (input.instance_id) {
14046
- const existing = this.instances.get(input.instance_id);
14047
- if (!existing) return { success: false, error: "Instance not found" };
14048
- inst = existing;
14049
- } else {
14050
- const created = this.createInstance({
14051
- definition_id: def.id,
14052
- definition_slug: def.slug,
14053
- state_data: input.payload
14054
- });
14055
- if (!created) return { success: false, error: "Failed to create instance" };
14056
- inst = created;
14057
- }
14058
- if (input.payload && input.instance_id) {
14059
- Object.assign(inst.state_data, input.payload);
14060
- }
14061
- const transition = def.transitions.find((t27) => t27.name === input.action_name && t27.from.includes(inst.current_state));
14062
- if (!transition) {
14063
- return {
14064
- success: false,
14065
- instance_id: inst.id,
14066
- from_state: inst.current_state,
14067
- to_state: null,
14068
- state_data: inst.state_data,
14069
- error: `No transition '${input.action_name}' from state '${inst.current_state}'`
14070
- };
14071
- }
14072
- const fromState = inst.current_state;
14073
- const now = (/* @__PURE__ */ new Date()).toISOString();
14074
- const events = [];
14075
- let lastEvalResult = null;
14076
- events.push({ event_type: "transition", message: `Transition '${transition.name}' started: ${fromState} \u2192 ${transition.to}`, timestamp: now });
14077
- for (const action of transition.actions ?? []) {
14078
- try {
14079
- if (action.type === "set_field") {
14080
- const field = action.config?.field;
14081
- if (action.config?.expression) {
14082
- const expr = action.config.expression;
14083
- const result = this.evaluateSimpleExpression(expr, inst.state_data);
14084
- inst.state_data[field] = result;
14085
- } else if (action.config?.value !== void 0) {
14086
- inst.state_data[field] = action.config.value;
14087
- }
14088
- events.push({ event_type: "action_executed", message: `transition action 'set_field' succeeded`, timestamp: now });
14089
- } else if (action.type === "eval") {
14090
- const expr = action.config?.expression;
14091
- lastEvalResult = this.evaluateSimpleExpression(expr, inst.state_data);
14092
- events.push({ event_type: "action_executed", message: `transition action 'eval' succeeded`, timestamp: now });
14093
- } else {
14094
- events.push({ event_type: "action_executed", message: `transition action '${action.type}' succeeded (no-op in local mode)`, timestamp: now });
14095
- }
14096
- } catch (err) {
14097
- const msg = err instanceof Error ? err.message : String(err);
14098
- events.push({ event_type: "action_failed", message: `transition action '${action.type}' failed: ${msg}`, timestamp: now });
14099
- return {
14100
- success: false,
14101
- instance_id: inst.id,
14102
- from_state: fromState,
14103
- to_state: null,
14104
- state_data: inst.state_data,
14105
- event_log: events,
14106
- error: `transition action failed: ${msg}`
14107
- };
14108
- }
14109
- }
14110
- inst.current_state = transition.to;
14111
- inst.execution_lock_version++;
14112
- inst.updated_at = now;
14113
- events.push({ event_type: "transition", message: `State changed: ${fromState} \u2192 ${transition.to}`, timestamp: now });
14114
- inst.event_log.push(...events);
14115
- return {
14116
- success: true,
14117
- instance_id: inst.id,
14118
- from_state: fromState,
14119
- to_state: transition.to,
14120
- state_data: inst.state_data,
14121
- result: lastEvalResult,
14122
- event_log: events
14123
- };
14124
- }
14125
- /**
14126
- * Minimal expression evaluator for local dev mode.
14127
- * Handles: field references, arithmetic, string literals, simple comparisons.
14128
- * Does NOT handle: while loops, if/else, function calls, multi-statement blocks.
14129
- * For full evaluation, use mm-napi when available.
14130
- */
14131
- evaluateSimpleExpression(expr, context) {
14132
- if (context[expr] !== void 0) return context[expr];
14133
- const arithMatch = expr.match(/^(\w+)\s*([+\-*/])\s*(\d+(?:\.\d+)?)$/);
14134
- if (arithMatch) {
14135
- const [, field, op, numStr] = arithMatch;
14136
- const left = Number(context[field] ?? 0);
14137
- const right = Number(numStr);
14138
- switch (op) {
14139
- case "+":
14140
- return left + right;
14141
- case "-":
14142
- return left - right;
14143
- case "*":
14144
- return left * right;
14145
- case "/":
14146
- return right !== 0 ? left / right : 0;
14147
- }
14148
- }
14149
- if (/^\d+(\.\d+)?$/.test(expr.trim())) {
14150
- return Number(expr.trim());
14151
- }
14152
- const strMatch = expr.match(/^["'](.*)["']$/);
14153
- if (strMatch) return strMatch[1];
14154
- try {
14155
- const keys = Object.keys(context);
14156
- const values = Object.values(context);
14157
- const fn = new Function(...keys, `"use strict"; return (${expr});`);
14158
- return fn(...values);
14159
- } catch {
14160
- return null;
14161
- }
14162
- }
14163
- };
14164
- async function startLocalServer(options = {}) {
14165
- const { port = 4200, noAuth = true } = options;
14166
- const store = new MemoryStore();
14167
- const startedAt = (/* @__PURE__ */ new Date()).toISOString();
14168
- function json(res, status, body) {
14169
- const data = JSON.stringify(body);
14170
- res.writeHead(status, {
14171
- "Content-Type": "application/json",
14172
- "Access-Control-Allow-Origin": "*",
14173
- "Access-Control-Allow-Methods": "GET, POST, PATCH, PUT, DELETE, OPTIONS",
14174
- "Access-Control-Allow-Headers": "Content-Type, Authorization",
14175
- "Content-Length": Buffer.byteLength(data)
14176
- });
14177
- res.end(data);
14178
- }
14179
- function readBody(req) {
14180
- return new Promise((resolve3, reject) => {
14181
- const chunks = [];
14182
- req.on("data", (chunk) => chunks.push(chunk));
14183
- req.on("end", () => resolve3(Buffer.concat(chunks).toString()));
14184
- req.on("error", reject);
14185
- });
14186
- }
14187
- function parseQuery(url) {
14188
- const idx = url.indexOf("?");
14189
- if (idx === -1) return {};
14190
- const params = {};
14191
- const qs = url.slice(idx + 1);
14192
- for (const pair of qs.split("&")) {
14193
- const [k, v] = pair.split("=");
14194
- if (k) params[decodeURIComponent(k)] = decodeURIComponent(v ?? "");
14195
- }
14196
- return params;
14197
- }
14198
- const server = http.createServer(async (req, res) => {
14199
- const method = req.method?.toUpperCase() ?? "GET";
14200
- const rawUrl = req.url ?? "/";
14201
- const queryStart = rawUrl.indexOf("?");
14202
- const path = queryStart >= 0 ? rawUrl.slice(0, queryStart) : rawUrl;
14203
- const query = parseQuery(rawUrl);
14204
- if (method === "OPTIONS") {
14205
- res.writeHead(204, {
14206
- "Access-Control-Allow-Origin": "*",
14207
- "Access-Control-Allow-Methods": "GET, POST, PATCH, PUT, DELETE, OPTIONS",
14208
- "Access-Control-Allow-Headers": "Content-Type, Authorization",
14209
- "Access-Control-Max-Age": "86400"
14210
- });
14211
- res.end();
14212
- return;
14213
- }
14214
- try {
14215
- if (path === "/health" && method === "GET") {
14216
- return json(res, 200, {
14217
- status: "ok",
14218
- service: "mm-local-dev",
14219
- mode: "in-memory",
14220
- started_at: startedAt,
14221
- definitions: store.definitions.size,
14222
- instances: store.instances.size
14223
- });
14224
- }
14225
- if (path === "/api/v1/auth/login" && (method === "POST" || method === "GET")) {
14226
- return json(res, 200, {
14227
- token: "dev-token-local",
14228
- user: {
14229
- id: "dev-user-001",
14230
- email: "dev@localhost",
14231
- role: "admin",
14232
- name: "Local Developer"
14233
- }
14234
- });
14235
- }
14236
- if (path === "/api/v1/workflow/definitions" && method === "GET") {
14237
- const result = store.listDefinitions({
14238
- category: query.category,
14239
- limit: query.limit ? parseInt(query.limit, 10) : void 0,
14240
- offset: query.offset ? parseInt(query.offset, 10) : void 0
14241
- });
14242
- if (query.slug) {
14243
- const def = store.getDefinition(query.slug);
14244
- return json(res, 200, { items: def ? [def] : [], total: def ? 1 : 0 });
14245
- }
14246
- return json(res, 200, result);
14247
- }
14248
- const defMatch = path.match(/^\/api\/v1\/workflow\/definitions\/([^/]+)$/);
14249
- if (defMatch && method === "GET") {
14250
- const def = store.getDefinition(defMatch[1]);
14251
- if (!def) return json(res, 404, { error: "Not found" });
14252
- return json(res, 200, def);
14253
- }
14254
- if (path === "/api/v1/workflow/definitions" && method === "POST") {
14255
- const body = JSON.parse(await readBody(req));
14256
- const def = store.createDefinition(body);
14257
- return json(res, 201, def);
14258
- }
14259
- if (defMatch && method === "PATCH") {
14260
- const body = JSON.parse(await readBody(req));
14261
- const updated = store.patchDefinition(defMatch[1], body);
14262
- if (!updated) return json(res, 404, { error: "Not found" });
14263
- return json(res, 200, updated);
14264
- }
14265
- if (defMatch && method === "DELETE") {
14266
- const deleted = store.deleteDefinition(defMatch[1]);
14267
- if (!deleted) return json(res, 404, { error: "Not found" });
14268
- return json(res, 204, null);
14269
- }
14270
- if (path === "/api/v1/workflow/instances" && method === "GET") {
14271
- const result = store.listInstances({
14272
- definition_id: query.definition_id,
14273
- limit: query.limit ? parseInt(query.limit, 10) : void 0,
14274
- offset: query.offset ? parseInt(query.offset, 10) : void 0
14275
- });
14276
- return json(res, 200, result);
14277
- }
14278
- if (path === "/api/v1/workflow/instances" && method === "POST") {
14279
- const body = JSON.parse(await readBody(req));
14280
- const inst = store.createInstance(body);
14281
- if (!inst) return json(res, 404, { error: "Definition not found" });
14282
- return json(res, 201, inst);
14283
- }
14284
- const instMatch = path.match(/^\/api\/v1\/workflow\/instances\/([^/]+)$/);
14285
- if (instMatch && method === "GET") {
14286
- const inst = store.getInstance(instMatch[1]);
14287
- if (!inst) return json(res, 404, { error: "Not found" });
14288
- return json(res, 200, inst);
14289
- }
14290
- if (path === "/api/v1/workflow/execute-action" && method === "POST") {
14291
- const body = JSON.parse(await readBody(req));
14292
- const result = store.executeAction(body);
14293
- return json(res, 200, result);
14294
- }
14295
- const dataMatch = path.match(/^\/api\/v1\/data\/([^/]+)$/);
14296
- if (dataMatch && method === "GET") {
14297
- const def = store.getDefinition(dataMatch[1]);
14298
- if (!def) return json(res, 404, { error: "Not found" });
14299
- const instances = store.listInstances({ definition_id: def.id });
14300
- return json(res, 200, instances);
14301
- }
14302
- if (path.startsWith("/api/v1/")) {
14303
- return json(res, 501, { error: "Not implemented in local dev mode", path, method });
14304
- }
14305
- return json(res, 404, { error: "Not found", path });
14306
- } catch (err) {
14307
- const message = err instanceof Error ? err.message : String(err);
14308
- console.error(`[mm-local] ${method} ${path} \u2014 Error: ${message}`);
14309
- return json(res, 500, { error: message });
14310
- }
14311
- });
14312
- return new Promise((resolve3, reject) => {
14313
- server.on("error", (err) => {
14314
- if (err.code === "EADDRINUSE") {
14315
- reject(new Error(`Port ${port} is already in use. Is another server running?`));
14316
- } else {
14317
- reject(err);
14318
- }
14319
- });
14320
- server.listen(port, () => {
14321
- console.log(`[mm-local] Local API server running at http://localhost:${port}`);
14322
- console.log(`[mm-local] Mode: in-memory (data lost on restart)`);
14323
- console.log(`[mm-local] Auth: disabled (all requests accepted)`);
14324
- resolve3({
14325
- server,
14326
- port,
14327
- store,
14328
- async close() {
14329
- return new Promise((res) => {
14330
- server.close(() => {
14331
- console.log("[mm-local] Local API server stopped");
14332
- res();
14333
- });
14334
- });
14335
- }
14336
- });
14337
- });
14338
- });
14339
- }
14340
-
14341
13930
  // src/dev-server.ts
14342
13931
  var currentErrors = null;
14343
13932
  function escapeHtml(s) {
@@ -14514,34 +14103,33 @@ async function createDevServer(options = {}) {
14514
14103
  open = false
14515
14104
  } = options;
14516
14105
  const clients = /* @__PURE__ */ new Set();
14517
- let localServer = null;
14518
14106
  let apiUrl;
14519
- let isLocalMode = false;
14520
- if (rawApiUrl === "local") {
14521
- localServer = await startLocalServer({ port: 4200 });
14522
- apiUrl = "http://localhost:4200/api/v1";
14523
- isLocalMode = true;
14524
- } else if (rawApiUrl === "auto") {
14525
- const defaultRemote = "https://dev.mindmatrix.club/api/v1";
14526
- const remoteHealth = await checkBackendHealth(defaultRemote);
14527
- if (remoteHealth.ok) {
14528
- apiUrl = defaultRemote;
14529
- } else {
14530
- const localHealth = await checkBackendHealth("http://localhost:4200/api/v1");
14531
- if (localHealth.ok) {
14532
- apiUrl = "http://localhost:4200/api/v1";
14107
+ if (rawApiUrl === "local" || rawApiUrl === "auto") {
14108
+ const localHealth = await checkBackendHealth("http://localhost:4200/api/v1");
14109
+ if (localHealth.ok) {
14110
+ apiUrl = "http://localhost:4200/api/v1";
14111
+ } else if (rawApiUrl === "auto") {
14112
+ const defaultRemote = "https://dev.mindmatrix.club/api/v1";
14113
+ const remoteHealth = await checkBackendHealth(defaultRemote);
14114
+ if (remoteHealth.ok) {
14115
+ apiUrl = defaultRemote;
14533
14116
  } else {
14534
- console.log("[mm-dev] No backend detected \u2014 starting local in-memory API server...");
14535
- localServer = await startLocalServer({ port: 4200 });
14117
+ console.error("[mm-dev] No backend detected. Start the engine first:");
14118
+ console.error(" mmrc dev (auto-starts engine)");
14119
+ console.error(" mmrc engine start (manual start)");
14120
+ console.error("[mm-dev] Or specify a remote API: mmrc dev --api-url https://...");
14536
14121
  apiUrl = "http://localhost:4200/api/v1";
14537
- isLocalMode = true;
14538
14122
  }
14123
+ } else {
14124
+ console.error("[mm-dev] Local engine not running on port 4200.");
14125
+ console.error(" Start it with: mmrc dev (or mmrc engine start)");
14126
+ apiUrl = "http://localhost:4200/api/v1";
14539
14127
  }
14540
14128
  } else {
14541
14129
  apiUrl = rawApiUrl;
14542
14130
  }
14543
- const token = isLocalMode ? "dev-token-local" : await resolveDevToken(apiUrl, explicitToken);
14544
- const health = isLocalMode ? { ok: true, version: "local", db: "in-memory" } : await checkBackendHealth(apiUrl);
14131
+ const token = await resolveDevToken(apiUrl, explicitToken);
14132
+ const health = await checkBackendHealth(apiUrl);
14545
14133
  let initialSlug, initialCompiled = 0, initialDeployed = false, initialErrors = 0;
14546
14134
  if (token && health.ok) {
14547
14135
  const r = await initialBuildDeploy(src, outDir, mode, apiUrl, token);
@@ -14601,63 +14189,163 @@ createRoot(document.getElementById('root')).render(React.createElement(App));
14601
14189
  `;
14602
14190
  }
14603
14191
  };
14604
- const devHtml = `<!DOCTYPE html>
14192
+ const { existsSync: fsExists } = await import("fs");
14193
+ const projectIndexPath = require("path").join(process.cwd(), "index.html");
14194
+ const hasProjectIndex = fsExists(projectIndexPath);
14195
+ if (!hasProjectIndex) {
14196
+ const { writeFileSync: fsWrite } = await import("fs");
14197
+ fsWrite(projectIndexPath, `<!DOCTYPE html>
14605
14198
  <html lang="en">
14606
14199
  <head>
14607
14200
  <meta charset="UTF-8">
14608
14201
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
14609
14202
  <title>MindMatrix Dev</title>
14610
- <style>
14611
- * { margin: 0; padding: 0; box-sizing: border-box; }
14612
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #fafafa; color: #111; }
14613
- #root { min-height: 100vh; }
14614
- .mm-loading { display: flex; align-items: center; justify-content: center; min-height: 100vh; flex-direction: column; gap: 12px; }
14615
- .mm-loading h1 { font-size: 20px; font-weight: 600; color: #333; }
14616
- .mm-loading p { color: #888; font-size: 14px; }
14617
- </style>
14618
14203
  </head>
14619
14204
  <body>
14620
- <div id="root">
14621
- <div class="mm-loading">
14622
- <h1>MindMatrix Dev</h1>
14623
- <p>Loading...</p>
14624
- </div>
14625
- </div>
14626
- <script>
14627
- async function render() {
14628
- const root = document.getElementById('root');
14205
+ <div id="root"></div>
14206
+ <script type="module" src="/__mm_dev_entry.tsx"></script>
14207
+ </body>
14208
+ </html>`, "utf-8");
14209
+ }
14210
+ const devEntryPlugin = {
14211
+ name: "mindmatrix-dev-entry",
14212
+ resolveId(id) {
14213
+ if (id === "/__mm_dev_entry.tsx") return id;
14214
+ return null;
14215
+ },
14216
+ load(id) {
14217
+ if (id !== "/__mm_dev_entry.tsx") return null;
14218
+ return `
14219
+ import React, { useState, useEffect } from 'react';
14220
+ import { createRoot } from 'react-dom/client';
14221
+ import { DevPlayer } from '@mmapp/react/player';
14222
+ import { PlayerProvider, ExperienceRenderer, createApiResolver } from '@mmapp/react/player';
14223
+
14224
+ // Detect API base URL \u2014 proxy through dev server or use direct URL
14225
+ const API_BASE = window.location.origin + '/api/v1';
14226
+ const resolver = createApiResolver({ baseUrl: API_BASE, token: () => localStorage.getItem('auth_token') });
14227
+
14228
+ /**
14229
+ * Prepare experience tree for rendering.
14230
+ * Attaches metadata.dataSources to the root node and remaps
14231
+ * dataSource slugs to use definition-relative naming.
14232
+ *
14233
+ * @param definition - The main blueprint definition
14234
+ * @param allDefinitions - ALL definitions from the API (used for slug resolution)
14235
+ */
14236
+ function prepareTree(definition, allDefinitions) {
14237
+ const exp = definition.experience;
14238
+ if (!exp || typeof exp !== 'object') return null;
14239
+
14240
+ const meta = definition.metadata || {};
14241
+ const dataSources = meta.dataSources || [];
14242
+ const mutationTargets = meta.mutationTargets || [];
14243
+
14244
+ // Build a slug map from ALL deployed definitions
14245
+ // This resolves bare model names (e.g. "item") to full slugs (e.g. "tutorial-1-item")
14246
+ const blueprintSlug = definition.slug || '';
14247
+ const allSlugs = (allDefinitions || []).map(d => d.slug).filter(Boolean);
14248
+
14249
+ function resolveSlug(bareSlug) {
14250
+ if (!bareSlug) return bareSlug;
14251
+ // Already a full slug (contains hyphen matching a known definition)
14252
+ if (allSlugs.includes(bareSlug)) return bareSlug;
14253
+ // Try blueprint-prefixed slug: "item" \u2192 "tutorial-1-item"
14254
+ const prefixed = blueprintSlug + '-' + bareSlug;
14255
+ if (allSlugs.includes(prefixed)) return prefixed;
14256
+ // Try matching by suffix across all definitions
14257
+ const match = allSlugs.find(s => s.endsWith('-' + bareSlug));
14258
+ if (match) return match;
14259
+ // Return original (will attempt as-is)
14260
+ return bareSlug;
14261
+ }
14262
+
14263
+ // Clone root node and attach dataSources
14264
+ const root = { ...exp };
14265
+ if (dataSources.length > 0 && !root.dataSources) {
14266
+ root.dataSources = dataSources.map(ds => ({
14267
+ ...ds,
14268
+ slug: resolveSlug(ds.slug),
14269
+ }));
14270
+ }
14271
+
14272
+ // Remap mutation targets the same way
14273
+ if (mutationTargets.length > 0) {
14274
+ const resolvedTargets = mutationTargets.map(t => resolveSlug(t));
14275
+ root.config = { ...(root.config || {}), _mutationTargets: resolvedTargets };
14276
+ }
14277
+
14278
+ return root;
14279
+ }
14280
+
14281
+ function App() {
14282
+ const [tree, setTree] = useState(null);
14283
+ const [error, setError] = useState(null);
14284
+
14285
+ useEffect(() => {
14286
+ async function loadTree() {
14629
14287
  try {
14630
- const res = await fetch('/api/v1/workflow/definitions');
14288
+ const res = await fetch(API_BASE + '/workflow/definitions');
14631
14289
  const json = await res.json();
14632
14290
  const items = json.items || json.data || [];
14633
- let html = '<div style="padding:40px;max-width:960px;margin:0 auto;font-family:-apple-system,BlinkMacSystemFont,sans-serif">';
14634
- html += '<h1 style="margin-bottom:8px">MindMatrix Dev</h1>';
14635
- html += '<p style="color:#666;margin-bottom:24px">' + items.length + ' definition(s) deployed</p>';
14636
- if (items.length === 0) {
14637
- 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>';
14638
- }
14639
- for (const def of items) {
14640
- html += '<div style="border:1px solid #e0e0e0;border-radius:8px;padding:16px;margin-bottom:12px;background:#fff">';
14641
- html += '<h3 style="margin-bottom:4px">' + (def.name || def.slug || 'Unnamed') + '</h3>';
14642
- html += '<p style="color:#888;font-size:13px">slug: ' + (def.slug || '?') + ' | states: ' + (def.states?.length || 0) + ' | fields: ' + (def.fields?.length || 0) + '</p>';
14643
- html += '</div>';
14644
- }
14645
- html += '</div>';
14646
- root.innerHTML = html;
14291
+ // Find the main blueprint definition (has experience tree)
14292
+ 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];
14293
+ if (main?.experience) {
14294
+ const prepared = prepareTree(main, items);
14295
+ if (prepared) {
14296
+ setTree(prepared);
14297
+ return;
14298
+ }
14299
+ }
14300
+ if (main) {
14301
+ // No experience tree \u2014 show definition info
14302
+ setTree({
14303
+ type: 'Stack',
14304
+ props: { style: { padding: 40, gap: 16 } },
14305
+ children: [
14306
+ { type: 'Text', props: { children: main.name || main.slug, style: { fontSize: 24, fontWeight: 'bold' } } },
14307
+ { type: 'Text', props: { children: (main.states?.length || 0) + ' states, ' + (main.fields?.length || 0) + ' fields', style: { color: '#666' } } },
14308
+ ...items.map((d, i) => ({
14309
+ type: 'Card',
14310
+ props: { key: i, style: { padding: 16, border: '1px solid #ddd', borderRadius: 8 } },
14311
+ children: [
14312
+ { type: 'Text', props: { children: d.name || d.slug, style: { fontWeight: 600 } } },
14313
+ { type: 'Text', props: { children: 'slug: ' + d.slug + ' | ' + (d.states?.length || 0) + ' states', style: { fontSize: 13, color: '#888' } } },
14314
+ ],
14315
+ })),
14316
+ ],
14317
+ });
14318
+ }
14647
14319
  } catch (e) {
14648
- root.innerHTML = '<div style="padding:40px"><h1>MindMatrix Dev</h1><p style="color:#c00;margin-top:8px">API Error: ' + e.message + '</p></div>';
14320
+ setError(e.message);
14649
14321
  }
14650
14322
  }
14651
- render();
14652
- setInterval(render, 3000);
14653
- </script>
14654
- </body>
14655
- </html>`;
14656
- const { mkdtempSync, writeFileSync: writeFileSync5 } = await import("fs");
14657
- const { join: join4 } = await import("path");
14658
- const { tmpdir } = await import("os");
14659
- const devRoot = mkdtempSync(join4(tmpdir(), "mm-dev-"));
14660
- writeFileSync5(join4(devRoot, "index.html"), devHtml, "utf-8");
14323
+ loadTree();
14324
+ }, []);
14325
+
14326
+ if (error) return React.createElement('div', { style: { padding: 40 } },
14327
+ React.createElement('h1', null, 'MindMatrix Dev'),
14328
+ React.createElement('p', { style: { color: '#c00' } }, 'Error: ' + error)
14329
+ );
14330
+
14331
+ if (!tree) return React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh' } },
14332
+ React.createElement('p', null, 'Loading...')
14333
+ );
14334
+
14335
+ // If tree has 'component' field, use ExperienceRenderer; otherwise legacy DevPlayer
14336
+ if (tree.component) {
14337
+ return React.createElement(PlayerProvider, { resolver },
14338
+ React.createElement(ExperienceRenderer, { tree, className: 'mm-experience-root' })
14339
+ );
14340
+ }
14341
+
14342
+ return React.createElement(DevPlayer, { tree, title: document.title || 'MindMatrix Dev' });
14343
+ }
14344
+
14345
+ createRoot(document.getElementById('root')).render(React.createElement(App));
14346
+ `;
14347
+ }
14348
+ };
14661
14349
  let deployInFlight = false;
14662
14350
  const compileDeployPlugin = {
14663
14351
  name: "mindmatrix-dev-compile-deploy",
@@ -14688,16 +14376,16 @@ createRoot(document.getElementById('root')).render(React.createElement(App));
14688
14376
  }
14689
14377
  };
14690
14378
  const viteConfig = {
14691
- // Physical index.html lives in a temp dir so Vite serves it natively.
14692
- root: devRoot,
14693
- // Pre-bundle React so Vite doesn't warn about missing entry point.
14379
+ // Use the blueprint directory as Vite root (has node_modules with React).
14380
+ root: process.cwd(),
14381
+ // Pre-bundle React and the player for fast dev startup.
14694
14382
  optimizeDeps: { include: ["react", "react-dom/client"] },
14695
14383
  server: {
14696
14384
  port,
14697
14385
  open,
14698
14386
  host: true,
14699
14387
  // Allow serving files from the real project directory (fs.allow).
14700
- fs: { allow: [devRoot, process.cwd(), ".."] },
14388
+ fs: { allow: [process.cwd(), ".."] },
14701
14389
  proxy: {
14702
14390
  "/api": { target: proxyTarget, changeOrigin: true, secure: true, ws: true },
14703
14391
  "/health": { target: proxyTarget, changeOrigin: true, secure: true },
@@ -14707,6 +14395,7 @@ createRoot(document.getElementById('root')).render(React.createElement(App));
14707
14395
  plugins: [
14708
14396
  mindmatrixReact(pluginOpts),
14709
14397
  compileDeployPlugin,
14398
+ devEntryPlugin,
14710
14399
  devPlayerPlugin,
14711
14400
  { name: "mindmatrix-error-overlay", configureServer(server) {
14712
14401
  server.middlewares.use(errorOverlayMiddleware());
@@ -14714,8 +14403,8 @@ createRoot(document.getElementById('root')).render(React.createElement(App));
14714
14403
  ],
14715
14404
  logLevel: "warn"
14716
14405
  };
14717
- const { createServer: createServer2 } = await import("vite");
14718
- const vite = await createServer2(viteConfig);
14406
+ const { createServer } = await import("vite");
14407
+ const vite = await createServer(viteConfig);
14719
14408
  await vite.listen();
14720
14409
  const resolvedPort = vite.config.server.port ?? port;
14721
14410
  if (enableWs && vite.httpServer) {
@@ -14733,7 +14422,7 @@ createRoot(document.getElementById('root')).render(React.createElement(App));
14733
14422
  } catch {
14734
14423
  }
14735
14424
  }
14736
- printBanner({ port: resolvedPort, apiUrl: isLocalMode ? `${apiUrl} (local in-memory)` : apiUrl, src, include, health, token: !!token, compiled: initialCompiled, deployed: initialDeployed, slug: initialSlug, errors: initialErrors });
14425
+ printBanner({ port: resolvedPort, apiUrl, src, include, health, token: !!token, compiled: initialCompiled, deployed: initialDeployed, slug: initialSlug, errors: initialErrors });
14737
14426
  return {
14738
14427
  vite,
14739
14428
  port: resolvedPort,
@@ -14765,14 +14454,6 @@ createRoot(document.getElementById('root')).render(React.createElement(App));
14765
14454
  clients.clear();
14766
14455
  currentErrors = null;
14767
14456
  await vite.close();
14768
- if (localServer) {
14769
- await localServer.close();
14770
- }
14771
- try {
14772
- const { rmSync } = await import("fs");
14773
- rmSync(devRoot, { recursive: true, force: true });
14774
- } catch {
14775
- }
14776
14457
  }
14777
14458
  };
14778
14459
  }