@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.
- package/dist/babel/index.d.mts +1 -1
- package/dist/babel/index.d.ts +1 -1
- package/dist/babel/index.js +9 -6
- package/dist/babel/index.mjs +1 -1
- package/dist/chunk-26U577GB.mjs +3465 -0
- package/dist/chunk-2FBDFAX6.mjs +2362 -0
- package/dist/chunk-2REDFOER.mjs +931 -0
- package/dist/{chunk-FPAMQXKB.mjs → chunk-2UTXM2QX.mjs} +10 -20
- package/dist/chunk-2YDQTFAL.mjs +879 -0
- package/dist/chunk-2ZRKQE74.mjs +175 -0
- package/dist/chunk-3QHG2JWV.mjs +154 -0
- package/dist/chunk-466OWSTT.mjs +186 -0
- package/dist/chunk-467SFYOD.mjs +3127 -0
- package/dist/chunk-4AIJO7DZ.mjs +214 -0
- package/dist/chunk-4D43TZYL.mjs +7495 -0
- package/dist/chunk-4HX4PI4R.mjs +734 -0
- package/dist/chunk-4VU56NTZ.mjs +544 -0
- package/dist/chunk-4XHK6FWL.mjs +2058 -0
- package/dist/chunk-52C2JKH2.mjs +186 -0
- package/dist/chunk-52XHYD2V.mjs +214 -0
- package/dist/chunk-5GUFFFGL.mjs +148 -0
- package/dist/chunk-5N2FDDS6.mjs +214 -0
- package/dist/chunk-5ZSJXWZT.mjs +1646 -0
- package/dist/chunk-6CQOAAMV.mjs +1803 -0
- package/dist/chunk-6SEVAAVT.mjs +3516 -0
- package/dist/chunk-6YLR5ZDA.mjs +2829 -0
- package/dist/chunk-77UJB356.mjs +244 -0
- package/dist/chunk-7QOAJPQF.mjs +774 -0
- package/dist/chunk-A5RCMIBP.mjs +1795 -0
- package/dist/chunk-A63R3GKH.mjs +1803 -0
- package/dist/chunk-ABNTZXF5.mjs +951 -0
- package/dist/chunk-ADHWW56I.mjs +214 -0
- package/dist/chunk-AOGY2GK6.mjs +3292 -0
- package/dist/chunk-AXXUXRNA.mjs +1434 -0
- package/dist/chunk-BZLU5YK5.mjs +1025 -0
- package/dist/chunk-C7XCDDBH.mjs +1802 -0
- package/dist/chunk-CHLVKMQW.mjs +175 -0
- package/dist/chunk-CKGOZAB7.mjs +939 -0
- package/dist/chunk-CSXYDIVC.mjs +214 -0
- package/dist/chunk-CXTV4VGG.mjs +148 -0
- package/dist/chunk-D34RAZUX.mjs +2223 -0
- package/dist/chunk-DDIC7WM6.mjs +3127 -0
- package/dist/chunk-DPUQOBU6.mjs +4810 -0
- package/dist/chunk-E6MDVTGT.mjs +148 -0
- package/dist/chunk-EGKMUEM6.mjs +544 -0
- package/dist/chunk-EO6SYNCG.mjs +175 -0
- package/dist/chunk-EQGA6A6D.mjs +121 -0
- package/dist/chunk-EY2CSXYA.mjs +822 -0
- package/dist/chunk-FF5BQVII.mjs +148 -0
- package/dist/chunk-FIQ65CDR.mjs +925 -0
- package/dist/chunk-FOZXJFAR.mjs +186 -0
- package/dist/chunk-G2IAZ5Q6.mjs +148 -0
- package/dist/chunk-G7SMOWOL.mjs +828 -0
- package/dist/chunk-GK7NU6DO.mjs +214 -0
- package/dist/chunk-HDSCPEHY.mjs +4061 -0
- package/dist/chunk-HJELFNEA.mjs +186 -0
- package/dist/chunk-HOIUP6IF.mjs +690 -0
- package/dist/chunk-HRJGDPNE.mjs +148 -0
- package/dist/chunk-I3AU7GRD.mjs +120 -0
- package/dist/chunk-I3VQQJZ6.mjs +2843 -0
- package/dist/chunk-IPTX5MJU.mjs +3223 -0
- package/dist/chunk-ITGUSH2Z.mjs +2783 -0
- package/dist/chunk-IXHBCAMF.mjs +3306 -0
- package/dist/chunk-J7JUAHS4.mjs +186 -0
- package/dist/chunk-J7TWJ3TM.mjs +2784 -0
- package/dist/chunk-JDPLDGVF.mjs +4810 -0
- package/dist/chunk-JK72MQ4N.mjs +877 -0
- package/dist/chunk-K2HHCAS2.mjs +148 -0
- package/dist/chunk-K5HX2SVL.mjs +1902 -0
- package/dist/chunk-KAUEQ2F3.mjs +148 -0
- package/dist/chunk-KFVVOS5N.mjs +925 -0
- package/dist/chunk-KIH4AN3Y.mjs +154 -0
- package/dist/chunk-KPDMN5IX.mjs +175 -0
- package/dist/chunk-LZL2IRCH.mjs +186 -0
- package/dist/chunk-MIZV3TAN.mjs +3293 -0
- package/dist/chunk-MRH4J7IX.mjs +2846 -0
- package/dist/chunk-NKBL5GUC.mjs +186 -0
- package/dist/chunk-NQCNSCF6.mjs +148 -0
- package/dist/chunk-NRP5J3BR.mjs +4811 -0
- package/dist/chunk-NTB7OEX2.mjs +2918 -0
- package/dist/chunk-NUPJYPFU.mjs +801 -0
- package/dist/chunk-NVQUTSQX.mjs +3128 -0
- package/dist/chunk-OGMG64EY.mjs +148 -0
- package/dist/chunk-OL5B2HTH.mjs +175 -0
- package/dist/chunk-OPJKP747.mjs +7506 -0
- package/dist/chunk-OQLGGBNE.mjs +2918 -0
- package/dist/chunk-OW4AQUDL.mjs +544 -0
- package/dist/chunk-OWI6XWCD.mjs +3375 -0
- package/dist/chunk-OZT2EAF2.mjs +2776 -0
- package/dist/chunk-PBRBRKIQ.mjs +175 -0
- package/dist/chunk-PRUMNNDI.mjs +3192 -0
- package/dist/chunk-QPNHDTSM.mjs +4839 -0
- package/dist/chunk-RNEIAJDR.mjs +897 -0
- package/dist/chunk-RY7POBNT.mjs +3127 -0
- package/dist/chunk-S6FJ4DXL.mjs +1813 -0
- package/dist/chunk-SU4E6E7B.mjs +3153 -0
- package/dist/chunk-SYUUKW5A.mjs +3379 -0
- package/dist/chunk-THB5SX2S.mjs +113 -0
- package/dist/chunk-THFYE5ZX.mjs +244 -0
- package/dist/chunk-TK3QMXIP.mjs +2921 -0
- package/dist/chunk-TRR2NPAV.mjs +248 -0
- package/dist/chunk-TTTTOT7P.mjs +1803 -0
- package/dist/chunk-TXONBY6A.mjs +7509 -0
- package/dist/chunk-U2PX3JSY.mjs +1933 -0
- package/dist/chunk-UASOWKDI.mjs +186 -0
- package/dist/chunk-UDDTWG5J.mjs +734 -0
- package/dist/chunk-UIWLAQCL.mjs +175 -0
- package/dist/chunk-UL2XZEMA.mjs +3128 -0
- package/dist/chunk-US3AVDAI.mjs +3456 -0
- package/dist/chunk-V5DIDOTT.mjs +148 -0
- package/dist/chunk-VLTKQDJ3.mjs +244 -0
- package/dist/chunk-VVC42PTS.mjs +175 -0
- package/dist/chunk-VX3T3NIR.mjs +897 -0
- package/dist/chunk-WBYMW4NQ.mjs +3450 -0
- package/dist/chunk-XMWUHQVV.mjs +939 -0
- package/dist/chunk-Y6FXYEAI.mjs +10 -0
- package/dist/chunk-YCWC2SCO.mjs +148 -0
- package/dist/chunk-YFS6JMYO.mjs +3342 -0
- package/dist/chunk-ZE67HOSN.mjs +148 -0
- package/dist/chunk-ZSK5TPIV.mjs +148 -0
- package/dist/cli/index.js +317 -645
- package/dist/cli/index.mjs +8 -8
- package/dist/config-PL24KEWL.mjs +219 -0
- package/dist/dev-server-Bs_sz2DG.d.mts +111 -0
- package/dist/dev-server-Bs_sz2DG.d.ts +111 -0
- package/dist/dev-server-RmGHIntF.d.mts +113 -0
- package/dist/dev-server-RmGHIntF.d.ts +113 -0
- package/dist/dev-server.js +194 -515
- package/dist/dev-server.mjs +4 -4
- package/dist/engine-binary-KQB23JDR.mjs +97 -0
- package/dist/envelope-DD7v0v6E.d.mts +265 -0
- package/dist/envelope-DD7v0v6E.d.ts +265 -0
- package/dist/envelope.js +9 -6
- package/dist/envelope.mjs +2 -2
- package/dist/index-B5gSgvnd.d.mts +44 -0
- package/dist/index-B5gSgvnd.d.ts +44 -0
- package/dist/index-Bs0MnR54.d.mts +103 -0
- package/dist/index-Bs0MnR54.d.ts +103 -0
- package/dist/index-DR0nNc_f.d.mts +101 -0
- package/dist/index-DR0nNc_f.d.ts +101 -0
- package/dist/index-revho_gS.d.mts +104 -0
- package/dist/index-revho_gS.d.ts +104 -0
- package/dist/index-vQjwYekL.d.mts +104 -0
- package/dist/index-vQjwYekL.d.ts +104 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +198 -517
- package/dist/index.mjs +9 -8
- package/dist/init-2XLTUF7O.mjs +407 -0
- package/dist/init-7FJENUDK.mjs +407 -0
- package/dist/init-DQDX3QK6.mjs +369 -0
- package/dist/init-K3GVM4JS.mjs +538 -0
- package/dist/init-NXS5BJN3.mjs +454 -0
- package/dist/init-UC3FWPIW.mjs +367 -0
- package/dist/init-UNV5XIDE.mjs +367 -0
- package/dist/project-compiler-2HOPO7GC.mjs +10 -0
- package/dist/project-compiler-D245L5QR.mjs +10 -0
- package/dist/project-compiler-FUQRMB4X.mjs +10 -0
- package/dist/project-compiler-LA5OBI5P.mjs +10 -0
- package/dist/project-compiler-OP2VVGJQ.mjs +10 -0
- package/dist/project-compiler-PZNFE6AH.mjs +10 -0
- package/dist/project-compiler-QBVF6MFI.mjs +10 -0
- package/dist/project-compiler-VFR6CSDX.mjs +10 -0
- package/dist/project-compiler-WMJZA4UH.mjs +10 -0
- package/dist/project-compiler-XXS27TZT.mjs +10 -0
- package/dist/project-compiler-YYGDSHY5.mjs +10 -0
- package/dist/project-decompiler-5GY2KSG4.mjs +7 -0
- package/dist/project-decompiler-7I2OMUVY.mjs +7 -0
- package/dist/project-decompiler-US7GAVIC.mjs +7 -0
- package/dist/pull-2Q53HF3H.mjs +107 -0
- package/dist/pull-5AFHD3QG.mjs +109 -0
- package/dist/pull-65GUSX6F.mjs +109 -0
- package/dist/pull-6LVI4LMM.mjs +109 -0
- package/dist/pull-A2QUHW4K.mjs +109 -0
- package/dist/pull-B6T5BUKV.mjs +109 -0
- package/dist/pull-CKHWZT33.mjs +109 -0
- package/dist/pull-GM74ERRT.mjs +109 -0
- package/dist/pull-JBEQWVPE.mjs +109 -0
- package/dist/pull-P44LDRWB.mjs +109 -0
- package/dist/pull-W2US3T3E.mjs +109 -0
- package/dist/testing/index.js +9 -6
- package/dist/testing/index.mjs +1 -1
- package/dist/verify-3PPS4XAM.mjs +1833 -0
- package/dist/verify-GKEH5FZQ.mjs +1833 -0
- package/dist/verify-HDKUNHZ4.mjs +1833 -0
- package/dist/verify-SEIXUGN4.mjs +1833 -0
- package/dist/vite/index.js +10 -7
- package/dist/vite/index.mjs +2 -2
- package/package.json +2 -2
package/dist/cli/index.js
CHANGED
|
@@ -6469,7 +6469,8 @@ function convertOnEvent(sub) {
|
|
|
6469
6469
|
};
|
|
6470
6470
|
}
|
|
6471
6471
|
function emitIR(extracted) {
|
|
6472
|
-
const { slug, name, version, description, category, fields, states, transitions } = extracted;
|
|
6472
|
+
const { slug, name, version, description, category: rawCategory, fields, states, transitions } = extracted;
|
|
6473
|
+
const category = Array.isArray(rawCategory) ? rawCategory : [rawCategory];
|
|
6473
6474
|
const stateArray = Array.from(states.values());
|
|
6474
6475
|
if (stateArray.length === 0) {
|
|
6475
6476
|
stateArray.push({
|
|
@@ -6857,13 +6858,15 @@ function emitCanonical(extracted, sourceFilename) {
|
|
|
6857
6858
|
}
|
|
6858
6859
|
]
|
|
6859
6860
|
});
|
|
6860
|
-
const
|
|
6861
|
+
const rawCat = extracted.category;
|
|
6861
6862
|
let categoryArray;
|
|
6862
|
-
if (
|
|
6863
|
-
|
|
6863
|
+
if (Array.isArray(rawCat)) {
|
|
6864
|
+
categoryArray = rawCat;
|
|
6865
|
+
} else if (rawCat.includes("/")) {
|
|
6866
|
+
const [primary, ...tags] = rawCat.split("/");
|
|
6864
6867
|
categoryArray = (0, import_player_core.normalizeCategory)(primary, ...tags);
|
|
6865
6868
|
} else {
|
|
6866
|
-
categoryArray = [
|
|
6869
|
+
categoryArray = [rawCat];
|
|
6867
6870
|
}
|
|
6868
6871
|
return {
|
|
6869
6872
|
slug: ir.slug,
|
|
@@ -7010,7 +7013,7 @@ function compilerStateToWorkflow(state, metadata) {
|
|
|
7010
7013
|
name: metadata.name || "Workflow",
|
|
7011
7014
|
version: metadata.version || "0.1.0",
|
|
7012
7015
|
description: metadata.description,
|
|
7013
|
-
category: metadata.category || "workflow",
|
|
7016
|
+
category: metadata.categoryArray ? metadata.categoryArray : [metadata.category || "workflow"],
|
|
7014
7017
|
fields: state.fields || [],
|
|
7015
7018
|
states: state.states || /* @__PURE__ */ new Map(),
|
|
7016
7019
|
transitions: state.transitions || [],
|
|
@@ -7954,7 +7957,7 @@ function extractRouterWorkflow(pages, options = {}) {
|
|
|
7954
7957
|
name: "Router",
|
|
7955
7958
|
version: "1.0.0",
|
|
7956
7959
|
description: "Auto-derived router workflow from file-based routing",
|
|
7957
|
-
category: "router",
|
|
7960
|
+
category: ["router"],
|
|
7958
7961
|
fields,
|
|
7959
7962
|
states,
|
|
7960
7963
|
transitions,
|
|
@@ -8053,7 +8056,8 @@ function compileModel(filename, source, options = {}) {
|
|
|
8053
8056
|
parserOpts: { plugins: parserPlugins, attachComment: true }
|
|
8054
8057
|
});
|
|
8055
8058
|
const ir = babelResult?.metadata?.mindmatrixIR ?? createEmptyModelIR(interfaceName);
|
|
8056
|
-
|
|
8059
|
+
const catOverride = options.categoryOverride || annotation.category || "data";
|
|
8060
|
+
ir.category = Array.isArray(catOverride) ? catOverride : [catOverride];
|
|
8057
8061
|
if (options.slugOverride) {
|
|
8058
8062
|
ir.slug = options.slugOverride;
|
|
8059
8063
|
}
|
|
@@ -8117,7 +8121,7 @@ function createEmptyModelIR(interfaceName) {
|
|
|
8117
8121
|
name: interfaceName,
|
|
8118
8122
|
version: "1.0.0",
|
|
8119
8123
|
description: "Data model: " + interfaceName,
|
|
8120
|
-
category: "data",
|
|
8124
|
+
category: ["data"],
|
|
8121
8125
|
fields: [],
|
|
8122
8126
|
states: [{
|
|
8123
8127
|
name: "draft",
|
|
@@ -8285,7 +8289,7 @@ function buildRouterIR(routes, layouts, allParams, slugPrefix) {
|
|
|
8285
8289
|
name: "Router",
|
|
8286
8290
|
version: "1.0.0",
|
|
8287
8291
|
description: "Auto-generated router from app/ directory structure",
|
|
8288
|
-
category: "router",
|
|
8292
|
+
category: ["router"],
|
|
8289
8293
|
fields,
|
|
8290
8294
|
states,
|
|
8291
8295
|
transitions,
|
|
@@ -8534,7 +8538,7 @@ function extractAction(source, filename) {
|
|
|
8534
8538
|
slug,
|
|
8535
8539
|
name: humanName,
|
|
8536
8540
|
version: "0.1.0",
|
|
8537
|
-
category: "action",
|
|
8541
|
+
category: ["action"],
|
|
8538
8542
|
fields,
|
|
8539
8543
|
states: states2,
|
|
8540
8544
|
transitions: transitions2,
|
|
@@ -8586,7 +8590,7 @@ function extractAction(source, filename) {
|
|
|
8586
8590
|
slug,
|
|
8587
8591
|
name: humanName,
|
|
8588
8592
|
version: "0.1.0",
|
|
8589
|
-
category: "action",
|
|
8593
|
+
category: ["action"],
|
|
8590
8594
|
fields,
|
|
8591
8595
|
states,
|
|
8592
8596
|
transitions,
|
|
@@ -10023,7 +10027,7 @@ function applyConfig(ir, config) {
|
|
|
10023
10027
|
if (config.name) ir.name = config.name;
|
|
10024
10028
|
if (config.version) ir.version = config.version;
|
|
10025
10029
|
if (config.description !== void 0) ir.description = config.description;
|
|
10026
|
-
if (config.category) ir.category = config.category;
|
|
10030
|
+
if (config.category) ir.category = Array.isArray(config.category) ? config.category : [config.category];
|
|
10027
10031
|
if (!ir.metadata) ir.metadata = {};
|
|
10028
10032
|
ir.metadata.stable_id = "def-" + ir.slug;
|
|
10029
10033
|
ir.metadata.provenance = {
|
|
@@ -10039,7 +10043,7 @@ function createEmptyIR(config) {
|
|
|
10039
10043
|
name: config.name || "Project",
|
|
10040
10044
|
version: config.version || "0.1.0",
|
|
10041
10045
|
description: config.description,
|
|
10042
|
-
category: config.category || "workflow",
|
|
10046
|
+
category: Array.isArray(config.category) ? config.category : [config.category || "workflow"],
|
|
10043
10047
|
fields: [],
|
|
10044
10048
|
states: [{
|
|
10045
10049
|
name: "draft",
|
|
@@ -10197,8 +10201,10 @@ function buildComposedResult(files, fileIRs, config, errors, warnings, options =
|
|
|
10197
10201
|
if (isWorkflowFile(filename)) {
|
|
10198
10202
|
workflowIRs.push(ir);
|
|
10199
10203
|
} else if (isModelFile2(filename)) {
|
|
10200
|
-
|
|
10201
|
-
|
|
10204
|
+
const cat = ir.category;
|
|
10205
|
+
const isDefault = !cat || cat === "workflow" || Array.isArray(cat) && cat.length === 1 && cat[0] === "workflow";
|
|
10206
|
+
if (isDefault) {
|
|
10207
|
+
ir.category = ["data"];
|
|
10202
10208
|
}
|
|
10203
10209
|
modelIRs.push(ir);
|
|
10204
10210
|
} else if (isServerActionFile2(filename)) {
|
|
@@ -12187,7 +12193,8 @@ function determineSplitStrategy(def) {
|
|
|
12187
12193
|
const stateCount = def.states.length;
|
|
12188
12194
|
const hasExperience = !!def.experience || !!def.views?.default;
|
|
12189
12195
|
const hasChildren = Array.isArray(def.metadata?.childSlugs) && def.metadata.childSlugs.length > 0;
|
|
12190
|
-
|
|
12196
|
+
const catArr = Array.isArray(def.category) ? def.category : [def.category];
|
|
12197
|
+
if (catArr.includes("blueprint") || hasChildren) {
|
|
12191
12198
|
return {
|
|
12192
12199
|
tier: "large",
|
|
12193
12200
|
emitModels: fieldCount > 0,
|
|
@@ -12474,6 +12481,10 @@ var project_decompiler_exports = {};
|
|
|
12474
12481
|
__export(project_decompiler_exports, {
|
|
12475
12482
|
decompileProjectEnhanced: () => decompileProjectEnhanced
|
|
12476
12483
|
});
|
|
12484
|
+
function hasCategory(cat, target) {
|
|
12485
|
+
if (!cat) return false;
|
|
12486
|
+
return Array.isArray(cat) ? cat.includes(target) : cat === target;
|
|
12487
|
+
}
|
|
12477
12488
|
function pascalCase3(slug) {
|
|
12478
12489
|
return slug.split(/[-_]/).map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()).join("");
|
|
12479
12490
|
}
|
|
@@ -12945,7 +12956,7 @@ function generateLayoutFile(slug, roles) {
|
|
|
12945
12956
|
function extractRouteTable(childDefinitions) {
|
|
12946
12957
|
if (!childDefinitions) return [];
|
|
12947
12958
|
const router = childDefinitions.find(
|
|
12948
|
-
(c) => c.slug.endsWith("-router") || c.category
|
|
12959
|
+
(c) => c.slug.endsWith("-router") || hasCategory(c.category, "router")
|
|
12949
12960
|
);
|
|
12950
12961
|
if (!router?.states) return [];
|
|
12951
12962
|
return router.states.filter((s) => s.description?.startsWith("Route:")).map((s) => {
|
|
@@ -13073,7 +13084,7 @@ function extractPageSections(experience, childDefinitions) {
|
|
|
13073
13084
|
if (routerExtracted) return routerExtracted;
|
|
13074
13085
|
const routeTable = extractRouteTable(childDefinitions);
|
|
13075
13086
|
const childSlugs = new Set(
|
|
13076
|
-
(childDefinitions || []).filter((c) => !c.slug.endsWith("-router") && c.category
|
|
13087
|
+
(childDefinitions || []).filter((c) => !c.slug.endsWith("-router") && !hasCategory(c.category, "router")).map((c) => c.slug)
|
|
13077
13088
|
);
|
|
13078
13089
|
const pages = [];
|
|
13079
13090
|
const childViews = [];
|
|
@@ -13242,7 +13253,7 @@ function generatePageFileFromSection(page, modelSlugToPath) {
|
|
|
13242
13253
|
slug: page.slug,
|
|
13243
13254
|
name: page.componentName,
|
|
13244
13255
|
version: "1.0.0",
|
|
13245
|
-
category: "page",
|
|
13256
|
+
category: ["page"],
|
|
13246
13257
|
states: [],
|
|
13247
13258
|
transitions: [],
|
|
13248
13259
|
fields,
|
|
@@ -13497,7 +13508,7 @@ function generateComponentFromDefinition(name, experience, props) {
|
|
|
13497
13508
|
slug: name.toLowerCase(),
|
|
13498
13509
|
name,
|
|
13499
13510
|
version: "1.0.0",
|
|
13500
|
-
category: "component",
|
|
13511
|
+
category: ["component"],
|
|
13501
13512
|
states: [],
|
|
13502
13513
|
transitions: [],
|
|
13503
13514
|
fields: [],
|
|
@@ -13734,7 +13745,7 @@ function decompileProjectEnhanced(definition) {
|
|
|
13734
13745
|
if (definition.childDefinitions) {
|
|
13735
13746
|
for (const child of definition.childDefinitions) {
|
|
13736
13747
|
const cs = child.slug;
|
|
13737
|
-
if (!cs.endsWith("-router") && child.category
|
|
13748
|
+
if (!cs.endsWith("-router") && !hasCategory(child.category, "router")) {
|
|
13738
13749
|
modelSlugToPath.set(cs, `models/${cs}.ts`);
|
|
13739
13750
|
}
|
|
13740
13751
|
}
|
|
@@ -13755,7 +13766,7 @@ function decompileProjectEnhanced(definition) {
|
|
|
13755
13766
|
for (const child of definition.childDefinitions) {
|
|
13756
13767
|
const childSlug = child.slug;
|
|
13757
13768
|
if (childSlug === slug) continue;
|
|
13758
|
-
const isRouter = childSlug.endsWith("-router") || child.category
|
|
13769
|
+
const isRouter = childSlug.endsWith("-router") || hasCategory(child.category, "router");
|
|
13759
13770
|
if (isRouter && routerIsCompilerGenerated) continue;
|
|
13760
13771
|
if (!mergedChildren.has(childSlug)) {
|
|
13761
13772
|
mergedChildren.set(childSlug, { ...child });
|
|
@@ -13810,7 +13821,7 @@ function decompileProjectEnhanced(definition) {
|
|
|
13810
13821
|
if (child.version && child.version !== "0.1.0" && (!existing.version || existing.version === "0.1.0")) {
|
|
13811
13822
|
existing.version = child.version;
|
|
13812
13823
|
}
|
|
13813
|
-
if (child.category && child.category
|
|
13824
|
+
if (child.category && !hasCategory(child.category, "data") && (!existing.category || hasCategory(existing.category, "data"))) {
|
|
13814
13825
|
existing.category = child.category;
|
|
13815
13826
|
}
|
|
13816
13827
|
if (child.description && !existing.description) {
|
|
@@ -13820,8 +13831,8 @@ function decompileProjectEnhanced(definition) {
|
|
|
13820
13831
|
}
|
|
13821
13832
|
}
|
|
13822
13833
|
for (const [childSlug, child] of mergedChildren) {
|
|
13823
|
-
const isRouter = childSlug.endsWith("-router") || child.category
|
|
13824
|
-
const isAction = child.category
|
|
13834
|
+
const isRouter = childSlug.endsWith("-router") || hasCategory(child.category, "router");
|
|
13835
|
+
const isAction = hasCategory(child.category, "action");
|
|
13825
13836
|
const childTransitions = isRouter ? reduceRouterTransitions(child.transitions, child.states) : child.transitions;
|
|
13826
13837
|
if (isAction) {
|
|
13827
13838
|
const actionFilePath = `actions/${childSlug}.ts`;
|
|
@@ -14883,7 +14894,7 @@ function mindmatrixReact(options) {
|
|
|
14883
14894
|
slug: ir.slug,
|
|
14884
14895
|
name: ir.name,
|
|
14885
14896
|
version: ir.version,
|
|
14886
|
-
category: ir.category || "workflow",
|
|
14897
|
+
category: ir.category || ["workflow"],
|
|
14887
14898
|
fields: ir.fields || [],
|
|
14888
14899
|
states: ir.states || [],
|
|
14889
14900
|
transitions: ir.transitions || [],
|
|
@@ -15033,431 +15044,6 @@ var init_vite = __esm({
|
|
|
15033
15044
|
}
|
|
15034
15045
|
});
|
|
15035
15046
|
|
|
15036
|
-
// src/cli/local-server.ts
|
|
15037
|
-
async function startLocalServer(options = {}) {
|
|
15038
|
-
const { port = 4200, noAuth = true } = options;
|
|
15039
|
-
const store = new MemoryStore();
|
|
15040
|
-
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
15041
|
-
function json(res, status, body) {
|
|
15042
|
-
const data = JSON.stringify(body);
|
|
15043
|
-
res.writeHead(status, {
|
|
15044
|
-
"Content-Type": "application/json",
|
|
15045
|
-
"Access-Control-Allow-Origin": "*",
|
|
15046
|
-
"Access-Control-Allow-Methods": "GET, POST, PATCH, PUT, DELETE, OPTIONS",
|
|
15047
|
-
"Access-Control-Allow-Headers": "Content-Type, Authorization",
|
|
15048
|
-
"Content-Length": Buffer.byteLength(data)
|
|
15049
|
-
});
|
|
15050
|
-
res.end(data);
|
|
15051
|
-
}
|
|
15052
|
-
function readBody(req) {
|
|
15053
|
-
return new Promise((resolve7, reject) => {
|
|
15054
|
-
const chunks = [];
|
|
15055
|
-
req.on("data", (chunk) => chunks.push(chunk));
|
|
15056
|
-
req.on("end", () => resolve7(Buffer.concat(chunks).toString()));
|
|
15057
|
-
req.on("error", reject);
|
|
15058
|
-
});
|
|
15059
|
-
}
|
|
15060
|
-
function parseQuery(url) {
|
|
15061
|
-
const idx = url.indexOf("?");
|
|
15062
|
-
if (idx === -1) return {};
|
|
15063
|
-
const params = {};
|
|
15064
|
-
const qs = url.slice(idx + 1);
|
|
15065
|
-
for (const pair of qs.split("&")) {
|
|
15066
|
-
const [k, v] = pair.split("=");
|
|
15067
|
-
if (k) params[decodeURIComponent(k)] = decodeURIComponent(v ?? "");
|
|
15068
|
-
}
|
|
15069
|
-
return params;
|
|
15070
|
-
}
|
|
15071
|
-
const server = http.createServer(async (req, res) => {
|
|
15072
|
-
const method = req.method?.toUpperCase() ?? "GET";
|
|
15073
|
-
const rawUrl = req.url ?? "/";
|
|
15074
|
-
const queryStart = rawUrl.indexOf("?");
|
|
15075
|
-
const path = queryStart >= 0 ? rawUrl.slice(0, queryStart) : rawUrl;
|
|
15076
|
-
const query = parseQuery(rawUrl);
|
|
15077
|
-
if (method === "OPTIONS") {
|
|
15078
|
-
res.writeHead(204, {
|
|
15079
|
-
"Access-Control-Allow-Origin": "*",
|
|
15080
|
-
"Access-Control-Allow-Methods": "GET, POST, PATCH, PUT, DELETE, OPTIONS",
|
|
15081
|
-
"Access-Control-Allow-Headers": "Content-Type, Authorization",
|
|
15082
|
-
"Access-Control-Max-Age": "86400"
|
|
15083
|
-
});
|
|
15084
|
-
res.end();
|
|
15085
|
-
return;
|
|
15086
|
-
}
|
|
15087
|
-
try {
|
|
15088
|
-
if (path === "/health" && method === "GET") {
|
|
15089
|
-
return json(res, 200, {
|
|
15090
|
-
status: "ok",
|
|
15091
|
-
service: "mm-local-dev",
|
|
15092
|
-
mode: "in-memory",
|
|
15093
|
-
started_at: startedAt,
|
|
15094
|
-
definitions: store.definitions.size,
|
|
15095
|
-
instances: store.instances.size
|
|
15096
|
-
});
|
|
15097
|
-
}
|
|
15098
|
-
if (path === "/api/v1/auth/login" && (method === "POST" || method === "GET")) {
|
|
15099
|
-
return json(res, 200, {
|
|
15100
|
-
token: "dev-token-local",
|
|
15101
|
-
user: {
|
|
15102
|
-
id: "dev-user-001",
|
|
15103
|
-
email: "dev@localhost",
|
|
15104
|
-
role: "admin",
|
|
15105
|
-
name: "Local Developer"
|
|
15106
|
-
}
|
|
15107
|
-
});
|
|
15108
|
-
}
|
|
15109
|
-
if (path === "/api/v1/workflow/definitions" && method === "GET") {
|
|
15110
|
-
const result = store.listDefinitions({
|
|
15111
|
-
category: query.category,
|
|
15112
|
-
limit: query.limit ? parseInt(query.limit, 10) : void 0,
|
|
15113
|
-
offset: query.offset ? parseInt(query.offset, 10) : void 0
|
|
15114
|
-
});
|
|
15115
|
-
if (query.slug) {
|
|
15116
|
-
const def = store.getDefinition(query.slug);
|
|
15117
|
-
return json(res, 200, { items: def ? [def] : [], total: def ? 1 : 0 });
|
|
15118
|
-
}
|
|
15119
|
-
return json(res, 200, result);
|
|
15120
|
-
}
|
|
15121
|
-
const defMatch = path.match(/^\/api\/v1\/workflow\/definitions\/([^/]+)$/);
|
|
15122
|
-
if (defMatch && method === "GET") {
|
|
15123
|
-
const def = store.getDefinition(defMatch[1]);
|
|
15124
|
-
if (!def) return json(res, 404, { error: "Not found" });
|
|
15125
|
-
return json(res, 200, def);
|
|
15126
|
-
}
|
|
15127
|
-
if (path === "/api/v1/workflow/definitions" && method === "POST") {
|
|
15128
|
-
const body = JSON.parse(await readBody(req));
|
|
15129
|
-
const def = store.createDefinition(body);
|
|
15130
|
-
return json(res, 201, def);
|
|
15131
|
-
}
|
|
15132
|
-
if (defMatch && method === "PATCH") {
|
|
15133
|
-
const body = JSON.parse(await readBody(req));
|
|
15134
|
-
const updated = store.patchDefinition(defMatch[1], body);
|
|
15135
|
-
if (!updated) return json(res, 404, { error: "Not found" });
|
|
15136
|
-
return json(res, 200, updated);
|
|
15137
|
-
}
|
|
15138
|
-
if (defMatch && method === "DELETE") {
|
|
15139
|
-
const deleted = store.deleteDefinition(defMatch[1]);
|
|
15140
|
-
if (!deleted) return json(res, 404, { error: "Not found" });
|
|
15141
|
-
return json(res, 204, null);
|
|
15142
|
-
}
|
|
15143
|
-
if (path === "/api/v1/workflow/instances" && method === "GET") {
|
|
15144
|
-
const result = store.listInstances({
|
|
15145
|
-
definition_id: query.definition_id,
|
|
15146
|
-
limit: query.limit ? parseInt(query.limit, 10) : void 0,
|
|
15147
|
-
offset: query.offset ? parseInt(query.offset, 10) : void 0
|
|
15148
|
-
});
|
|
15149
|
-
return json(res, 200, result);
|
|
15150
|
-
}
|
|
15151
|
-
if (path === "/api/v1/workflow/instances" && method === "POST") {
|
|
15152
|
-
const body = JSON.parse(await readBody(req));
|
|
15153
|
-
const inst = store.createInstance(body);
|
|
15154
|
-
if (!inst) return json(res, 404, { error: "Definition not found" });
|
|
15155
|
-
return json(res, 201, inst);
|
|
15156
|
-
}
|
|
15157
|
-
const instMatch = path.match(/^\/api\/v1\/workflow\/instances\/([^/]+)$/);
|
|
15158
|
-
if (instMatch && method === "GET") {
|
|
15159
|
-
const inst = store.getInstance(instMatch[1]);
|
|
15160
|
-
if (!inst) return json(res, 404, { error: "Not found" });
|
|
15161
|
-
return json(res, 200, inst);
|
|
15162
|
-
}
|
|
15163
|
-
if (path === "/api/v1/workflow/execute-action" && method === "POST") {
|
|
15164
|
-
const body = JSON.parse(await readBody(req));
|
|
15165
|
-
const result = store.executeAction(body);
|
|
15166
|
-
return json(res, 200, result);
|
|
15167
|
-
}
|
|
15168
|
-
const dataMatch = path.match(/^\/api\/v1\/data\/([^/]+)$/);
|
|
15169
|
-
if (dataMatch && method === "GET") {
|
|
15170
|
-
const def = store.getDefinition(dataMatch[1]);
|
|
15171
|
-
if (!def) return json(res, 404, { error: "Not found" });
|
|
15172
|
-
const instances = store.listInstances({ definition_id: def.id });
|
|
15173
|
-
return json(res, 200, instances);
|
|
15174
|
-
}
|
|
15175
|
-
if (path.startsWith("/api/v1/")) {
|
|
15176
|
-
return json(res, 501, { error: "Not implemented in local dev mode", path, method });
|
|
15177
|
-
}
|
|
15178
|
-
return json(res, 404, { error: "Not found", path });
|
|
15179
|
-
} catch (err) {
|
|
15180
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
15181
|
-
console.error(`[mm-local] ${method} ${path} \u2014 Error: ${message}`);
|
|
15182
|
-
return json(res, 500, { error: message });
|
|
15183
|
-
}
|
|
15184
|
-
});
|
|
15185
|
-
return new Promise((resolve7, reject) => {
|
|
15186
|
-
server.on("error", (err) => {
|
|
15187
|
-
if (err.code === "EADDRINUSE") {
|
|
15188
|
-
reject(new Error(`Port ${port} is already in use. Is another server running?`));
|
|
15189
|
-
} else {
|
|
15190
|
-
reject(err);
|
|
15191
|
-
}
|
|
15192
|
-
});
|
|
15193
|
-
server.listen(port, () => {
|
|
15194
|
-
console.log(`[mm-local] Local API server running at http://localhost:${port}`);
|
|
15195
|
-
console.log(`[mm-local] Mode: in-memory (data lost on restart)`);
|
|
15196
|
-
console.log(`[mm-local] Auth: disabled (all requests accepted)`);
|
|
15197
|
-
resolve7({
|
|
15198
|
-
server,
|
|
15199
|
-
port,
|
|
15200
|
-
store,
|
|
15201
|
-
async close() {
|
|
15202
|
-
return new Promise((res) => {
|
|
15203
|
-
server.close(() => {
|
|
15204
|
-
console.log("[mm-local] Local API server stopped");
|
|
15205
|
-
res();
|
|
15206
|
-
});
|
|
15207
|
-
});
|
|
15208
|
-
}
|
|
15209
|
-
});
|
|
15210
|
-
});
|
|
15211
|
-
});
|
|
15212
|
-
}
|
|
15213
|
-
var http, import_node_crypto, MemoryStore;
|
|
15214
|
-
var init_local_server = __esm({
|
|
15215
|
-
"src/cli/local-server.ts"() {
|
|
15216
|
-
"use strict";
|
|
15217
|
-
http = __toESM(require("http"));
|
|
15218
|
-
import_node_crypto = require("crypto");
|
|
15219
|
-
MemoryStore = class {
|
|
15220
|
-
constructor() {
|
|
15221
|
-
this.definitions = /* @__PURE__ */ new Map();
|
|
15222
|
-
this.instances = /* @__PURE__ */ new Map();
|
|
15223
|
-
this.slugIndex = /* @__PURE__ */ new Map();
|
|
15224
|
-
}
|
|
15225
|
-
// slug → id
|
|
15226
|
-
// ── Definitions ──────────────────────────────────────────────────────
|
|
15227
|
-
createDefinition(input) {
|
|
15228
|
-
if (this.slugIndex.has(input.slug)) {
|
|
15229
|
-
const existing = this.definitions.get(this.slugIndex.get(input.slug));
|
|
15230
|
-
if (existing) return existing;
|
|
15231
|
-
}
|
|
15232
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
15233
|
-
const def = {
|
|
15234
|
-
id: input.id ?? (0, import_node_crypto.randomUUID)(),
|
|
15235
|
-
slug: input.slug,
|
|
15236
|
-
name: input.name,
|
|
15237
|
-
version: input.version ?? "1.0.0",
|
|
15238
|
-
description: input.description ?? null,
|
|
15239
|
-
category: input.category ?? "workflow",
|
|
15240
|
-
fields: input.fields ?? [],
|
|
15241
|
-
states: input.states ?? [],
|
|
15242
|
-
transitions: input.transitions ?? [],
|
|
15243
|
-
roles: input.roles ?? [],
|
|
15244
|
-
experience: input.experience ?? null,
|
|
15245
|
-
metadata: input.metadata ?? {},
|
|
15246
|
-
child_definitions: input.child_definitions ?? [],
|
|
15247
|
-
is_immutable: input.is_immutable ?? false,
|
|
15248
|
-
tags: input.tags ?? [],
|
|
15249
|
-
inline_tags: input.inline_tags ?? [],
|
|
15250
|
-
created_at: now,
|
|
15251
|
-
updated_at: now
|
|
15252
|
-
};
|
|
15253
|
-
this.definitions.set(def.id, def);
|
|
15254
|
-
this.slugIndex.set(def.slug, def.id);
|
|
15255
|
-
return def;
|
|
15256
|
-
}
|
|
15257
|
-
getDefinition(idOrSlug) {
|
|
15258
|
-
const byId = this.definitions.get(idOrSlug);
|
|
15259
|
-
if (byId) return byId;
|
|
15260
|
-
const id = this.slugIndex.get(idOrSlug);
|
|
15261
|
-
if (id) return this.definitions.get(id);
|
|
15262
|
-
return void 0;
|
|
15263
|
-
}
|
|
15264
|
-
listDefinitions(opts) {
|
|
15265
|
-
let items = Array.from(this.definitions.values());
|
|
15266
|
-
if (opts?.category) {
|
|
15267
|
-
items = items.filter((d) => d.category === opts.category);
|
|
15268
|
-
}
|
|
15269
|
-
const total = items.length;
|
|
15270
|
-
const offset = opts?.offset ?? 0;
|
|
15271
|
-
const limit = opts?.limit ?? 50;
|
|
15272
|
-
items = items.slice(offset, offset + limit);
|
|
15273
|
-
return { items, total };
|
|
15274
|
-
}
|
|
15275
|
-
patchDefinition(id, patch) {
|
|
15276
|
-
const def = this.definitions.get(id);
|
|
15277
|
-
if (!def) return void 0;
|
|
15278
|
-
Object.assign(def, patch, { updated_at: (/* @__PURE__ */ new Date()).toISOString() });
|
|
15279
|
-
return def;
|
|
15280
|
-
}
|
|
15281
|
-
deleteDefinition(id) {
|
|
15282
|
-
const def = this.definitions.get(id);
|
|
15283
|
-
if (!def) return false;
|
|
15284
|
-
this.slugIndex.delete(def.slug);
|
|
15285
|
-
this.definitions.delete(id);
|
|
15286
|
-
return true;
|
|
15287
|
-
}
|
|
15288
|
-
// ── Instances ────────────────────────────────────────────────────────
|
|
15289
|
-
createInstance(input) {
|
|
15290
|
-
const def = this.getDefinition(input.definition_id) ?? this.getDefinition(input.definition_slug);
|
|
15291
|
-
if (!def) return null;
|
|
15292
|
-
const initialState = def.states.find((s) => s.type === "START" || s.type === "initial");
|
|
15293
|
-
const stateName = initialState?.name ?? "initial";
|
|
15294
|
-
const stateData = {};
|
|
15295
|
-
for (const field of def.fields) {
|
|
15296
|
-
if (field.default_value !== void 0) {
|
|
15297
|
-
stateData[field.name] = field.default_value;
|
|
15298
|
-
}
|
|
15299
|
-
}
|
|
15300
|
-
Object.assign(stateData, input.state_data ?? {});
|
|
15301
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
15302
|
-
const inst = {
|
|
15303
|
-
id: (0, import_node_crypto.randomUUID)(),
|
|
15304
|
-
definition_id: def.id,
|
|
15305
|
-
definition_slug: def.slug,
|
|
15306
|
-
current_state: stateName,
|
|
15307
|
-
state_data: stateData,
|
|
15308
|
-
execution_lock_version: 0,
|
|
15309
|
-
event_log: [{
|
|
15310
|
-
event_type: "transition",
|
|
15311
|
-
message: `Instance created in state '${stateName}'`,
|
|
15312
|
-
timestamp: now
|
|
15313
|
-
}],
|
|
15314
|
-
created_at: now,
|
|
15315
|
-
updated_at: now
|
|
15316
|
-
};
|
|
15317
|
-
this.instances.set(inst.id, inst);
|
|
15318
|
-
return inst;
|
|
15319
|
-
}
|
|
15320
|
-
getInstance(id) {
|
|
15321
|
-
return this.instances.get(id);
|
|
15322
|
-
}
|
|
15323
|
-
listInstances(opts) {
|
|
15324
|
-
let items = Array.from(this.instances.values());
|
|
15325
|
-
if (opts?.definition_id) {
|
|
15326
|
-
items = items.filter((i) => i.definition_id === opts.definition_id);
|
|
15327
|
-
}
|
|
15328
|
-
const total = items.length;
|
|
15329
|
-
const offset = opts?.offset ?? 0;
|
|
15330
|
-
const limit = opts?.limit ?? 50;
|
|
15331
|
-
items = items.slice(offset, offset + limit);
|
|
15332
|
-
return { items, total };
|
|
15333
|
-
}
|
|
15334
|
-
// ── Execute Action (Transition) ──────────────────────────────────────
|
|
15335
|
-
executeAction(input) {
|
|
15336
|
-
const def = this.getDefinition(input.definition_id);
|
|
15337
|
-
if (!def) return { success: false, error: "Definition not found" };
|
|
15338
|
-
let inst;
|
|
15339
|
-
if (input.instance_id) {
|
|
15340
|
-
const existing = this.instances.get(input.instance_id);
|
|
15341
|
-
if (!existing) return { success: false, error: "Instance not found" };
|
|
15342
|
-
inst = existing;
|
|
15343
|
-
} else {
|
|
15344
|
-
const created = this.createInstance({
|
|
15345
|
-
definition_id: def.id,
|
|
15346
|
-
definition_slug: def.slug,
|
|
15347
|
-
state_data: input.payload
|
|
15348
|
-
});
|
|
15349
|
-
if (!created) return { success: false, error: "Failed to create instance" };
|
|
15350
|
-
inst = created;
|
|
15351
|
-
}
|
|
15352
|
-
if (input.payload && input.instance_id) {
|
|
15353
|
-
Object.assign(inst.state_data, input.payload);
|
|
15354
|
-
}
|
|
15355
|
-
const transition = def.transitions.find((t27) => t27.name === input.action_name && t27.from.includes(inst.current_state));
|
|
15356
|
-
if (!transition) {
|
|
15357
|
-
return {
|
|
15358
|
-
success: false,
|
|
15359
|
-
instance_id: inst.id,
|
|
15360
|
-
from_state: inst.current_state,
|
|
15361
|
-
to_state: null,
|
|
15362
|
-
state_data: inst.state_data,
|
|
15363
|
-
error: `No transition '${input.action_name}' from state '${inst.current_state}'`
|
|
15364
|
-
};
|
|
15365
|
-
}
|
|
15366
|
-
const fromState = inst.current_state;
|
|
15367
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
15368
|
-
const events = [];
|
|
15369
|
-
let lastEvalResult = null;
|
|
15370
|
-
events.push({ event_type: "transition", message: `Transition '${transition.name}' started: ${fromState} \u2192 ${transition.to}`, timestamp: now });
|
|
15371
|
-
for (const action of transition.actions ?? []) {
|
|
15372
|
-
try {
|
|
15373
|
-
if (action.type === "set_field") {
|
|
15374
|
-
const field = action.config?.field;
|
|
15375
|
-
if (action.config?.expression) {
|
|
15376
|
-
const expr = action.config.expression;
|
|
15377
|
-
const result = this.evaluateSimpleExpression(expr, inst.state_data);
|
|
15378
|
-
inst.state_data[field] = result;
|
|
15379
|
-
} else if (action.config?.value !== void 0) {
|
|
15380
|
-
inst.state_data[field] = action.config.value;
|
|
15381
|
-
}
|
|
15382
|
-
events.push({ event_type: "action_executed", message: `transition action 'set_field' succeeded`, timestamp: now });
|
|
15383
|
-
} else if (action.type === "eval") {
|
|
15384
|
-
const expr = action.config?.expression;
|
|
15385
|
-
lastEvalResult = this.evaluateSimpleExpression(expr, inst.state_data);
|
|
15386
|
-
events.push({ event_type: "action_executed", message: `transition action 'eval' succeeded`, timestamp: now });
|
|
15387
|
-
} else {
|
|
15388
|
-
events.push({ event_type: "action_executed", message: `transition action '${action.type}' succeeded (no-op in local mode)`, timestamp: now });
|
|
15389
|
-
}
|
|
15390
|
-
} catch (err) {
|
|
15391
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
15392
|
-
events.push({ event_type: "action_failed", message: `transition action '${action.type}' failed: ${msg}`, timestamp: now });
|
|
15393
|
-
return {
|
|
15394
|
-
success: false,
|
|
15395
|
-
instance_id: inst.id,
|
|
15396
|
-
from_state: fromState,
|
|
15397
|
-
to_state: null,
|
|
15398
|
-
state_data: inst.state_data,
|
|
15399
|
-
event_log: events,
|
|
15400
|
-
error: `transition action failed: ${msg}`
|
|
15401
|
-
};
|
|
15402
|
-
}
|
|
15403
|
-
}
|
|
15404
|
-
inst.current_state = transition.to;
|
|
15405
|
-
inst.execution_lock_version++;
|
|
15406
|
-
inst.updated_at = now;
|
|
15407
|
-
events.push({ event_type: "transition", message: `State changed: ${fromState} \u2192 ${transition.to}`, timestamp: now });
|
|
15408
|
-
inst.event_log.push(...events);
|
|
15409
|
-
return {
|
|
15410
|
-
success: true,
|
|
15411
|
-
instance_id: inst.id,
|
|
15412
|
-
from_state: fromState,
|
|
15413
|
-
to_state: transition.to,
|
|
15414
|
-
state_data: inst.state_data,
|
|
15415
|
-
result: lastEvalResult,
|
|
15416
|
-
event_log: events
|
|
15417
|
-
};
|
|
15418
|
-
}
|
|
15419
|
-
/**
|
|
15420
|
-
* Minimal expression evaluator for local dev mode.
|
|
15421
|
-
* Handles: field references, arithmetic, string literals, simple comparisons.
|
|
15422
|
-
* Does NOT handle: while loops, if/else, function calls, multi-statement blocks.
|
|
15423
|
-
* For full evaluation, use mm-napi when available.
|
|
15424
|
-
*/
|
|
15425
|
-
evaluateSimpleExpression(expr, context) {
|
|
15426
|
-
if (context[expr] !== void 0) return context[expr];
|
|
15427
|
-
const arithMatch = expr.match(/^(\w+)\s*([+\-*/])\s*(\d+(?:\.\d+)?)$/);
|
|
15428
|
-
if (arithMatch) {
|
|
15429
|
-
const [, field, op, numStr] = arithMatch;
|
|
15430
|
-
const left = Number(context[field] ?? 0);
|
|
15431
|
-
const right = Number(numStr);
|
|
15432
|
-
switch (op) {
|
|
15433
|
-
case "+":
|
|
15434
|
-
return left + right;
|
|
15435
|
-
case "-":
|
|
15436
|
-
return left - right;
|
|
15437
|
-
case "*":
|
|
15438
|
-
return left * right;
|
|
15439
|
-
case "/":
|
|
15440
|
-
return right !== 0 ? left / right : 0;
|
|
15441
|
-
}
|
|
15442
|
-
}
|
|
15443
|
-
if (/^\d+(\.\d+)?$/.test(expr.trim())) {
|
|
15444
|
-
return Number(expr.trim());
|
|
15445
|
-
}
|
|
15446
|
-
const strMatch = expr.match(/^["'](.*)["']$/);
|
|
15447
|
-
if (strMatch) return strMatch[1];
|
|
15448
|
-
try {
|
|
15449
|
-
const keys = Object.keys(context);
|
|
15450
|
-
const values = Object.values(context);
|
|
15451
|
-
const fn = new Function(...keys, `"use strict"; return (${expr});`);
|
|
15452
|
-
return fn(...values);
|
|
15453
|
-
} catch {
|
|
15454
|
-
return null;
|
|
15455
|
-
}
|
|
15456
|
-
}
|
|
15457
|
-
};
|
|
15458
|
-
}
|
|
15459
|
-
});
|
|
15460
|
-
|
|
15461
15047
|
// src/cli/seed.ts
|
|
15462
15048
|
var seed_exports = {};
|
|
15463
15049
|
__export(seed_exports, {
|
|
@@ -15797,34 +15383,33 @@ async function createDevServer(options = {}) {
|
|
|
15797
15383
|
open = false
|
|
15798
15384
|
} = options;
|
|
15799
15385
|
const clients = /* @__PURE__ */ new Set();
|
|
15800
|
-
let localServer = null;
|
|
15801
15386
|
let apiUrl;
|
|
15802
|
-
|
|
15803
|
-
|
|
15804
|
-
|
|
15805
|
-
|
|
15806
|
-
|
|
15807
|
-
|
|
15808
|
-
|
|
15809
|
-
|
|
15810
|
-
|
|
15811
|
-
apiUrl = defaultRemote;
|
|
15812
|
-
} else {
|
|
15813
|
-
const localHealth = await checkBackendHealth("http://localhost:4200/api/v1");
|
|
15814
|
-
if (localHealth.ok) {
|
|
15815
|
-
apiUrl = "http://localhost:4200/api/v1";
|
|
15387
|
+
if (rawApiUrl === "local" || rawApiUrl === "auto") {
|
|
15388
|
+
const localHealth = await checkBackendHealth("http://localhost:4200/api/v1");
|
|
15389
|
+
if (localHealth.ok) {
|
|
15390
|
+
apiUrl = "http://localhost:4200/api/v1";
|
|
15391
|
+
} else if (rawApiUrl === "auto") {
|
|
15392
|
+
const defaultRemote = "https://dev.mindmatrix.club/api/v1";
|
|
15393
|
+
const remoteHealth = await checkBackendHealth(defaultRemote);
|
|
15394
|
+
if (remoteHealth.ok) {
|
|
15395
|
+
apiUrl = defaultRemote;
|
|
15816
15396
|
} else {
|
|
15817
|
-
console.
|
|
15818
|
-
|
|
15397
|
+
console.error("[mm-dev] No backend detected. Start the engine first:");
|
|
15398
|
+
console.error(" mmrc dev (auto-starts engine)");
|
|
15399
|
+
console.error(" mmrc engine start (manual start)");
|
|
15400
|
+
console.error("[mm-dev] Or specify a remote API: mmrc dev --api-url https://...");
|
|
15819
15401
|
apiUrl = "http://localhost:4200/api/v1";
|
|
15820
|
-
isLocalMode = true;
|
|
15821
15402
|
}
|
|
15403
|
+
} else {
|
|
15404
|
+
console.error("[mm-dev] Local engine not running on port 4200.");
|
|
15405
|
+
console.error(" Start it with: mmrc dev (or mmrc engine start)");
|
|
15406
|
+
apiUrl = "http://localhost:4200/api/v1";
|
|
15822
15407
|
}
|
|
15823
15408
|
} else {
|
|
15824
15409
|
apiUrl = rawApiUrl;
|
|
15825
15410
|
}
|
|
15826
|
-
const token =
|
|
15827
|
-
const health =
|
|
15411
|
+
const token = await resolveDevToken(apiUrl, explicitToken);
|
|
15412
|
+
const health = await checkBackendHealth(apiUrl);
|
|
15828
15413
|
let initialSlug, initialCompiled = 0, initialDeployed = false, initialErrors = 0;
|
|
15829
15414
|
if (token && health.ok) {
|
|
15830
15415
|
const r = await initialBuildDeploy(src, outDir, mode, apiUrl, token);
|
|
@@ -15884,63 +15469,163 @@ createRoot(document.getElementById('root')).render(React.createElement(App));
|
|
|
15884
15469
|
`;
|
|
15885
15470
|
}
|
|
15886
15471
|
};
|
|
15887
|
-
const
|
|
15472
|
+
const { existsSync: fsExists } = await import("fs");
|
|
15473
|
+
const projectIndexPath = require("path").join(process.cwd(), "index.html");
|
|
15474
|
+
const hasProjectIndex = fsExists(projectIndexPath);
|
|
15475
|
+
if (!hasProjectIndex) {
|
|
15476
|
+
const { writeFileSync: fsWrite } = await import("fs");
|
|
15477
|
+
fsWrite(projectIndexPath, `<!DOCTYPE html>
|
|
15888
15478
|
<html lang="en">
|
|
15889
15479
|
<head>
|
|
15890
15480
|
<meta charset="UTF-8">
|
|
15891
15481
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
15892
15482
|
<title>MindMatrix Dev</title>
|
|
15893
|
-
<style>
|
|
15894
|
-
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
15895
|
-
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #fafafa; color: #111; }
|
|
15896
|
-
#root { min-height: 100vh; }
|
|
15897
|
-
.mm-loading { display: flex; align-items: center; justify-content: center; min-height: 100vh; flex-direction: column; gap: 12px; }
|
|
15898
|
-
.mm-loading h1 { font-size: 20px; font-weight: 600; color: #333; }
|
|
15899
|
-
.mm-loading p { color: #888; font-size: 14px; }
|
|
15900
|
-
</style>
|
|
15901
15483
|
</head>
|
|
15902
15484
|
<body>
|
|
15903
|
-
<div id="root">
|
|
15904
|
-
|
|
15905
|
-
|
|
15906
|
-
|
|
15907
|
-
|
|
15908
|
-
|
|
15909
|
-
|
|
15910
|
-
|
|
15911
|
-
|
|
15485
|
+
<div id="root"></div>
|
|
15486
|
+
<script type="module" src="/__mm_dev_entry.tsx"></script>
|
|
15487
|
+
</body>
|
|
15488
|
+
</html>`, "utf-8");
|
|
15489
|
+
}
|
|
15490
|
+
const devEntryPlugin = {
|
|
15491
|
+
name: "mindmatrix-dev-entry",
|
|
15492
|
+
resolveId(id) {
|
|
15493
|
+
if (id === "/__mm_dev_entry.tsx") return id;
|
|
15494
|
+
return null;
|
|
15495
|
+
},
|
|
15496
|
+
load(id) {
|
|
15497
|
+
if (id !== "/__mm_dev_entry.tsx") return null;
|
|
15498
|
+
return `
|
|
15499
|
+
import React, { useState, useEffect } from 'react';
|
|
15500
|
+
import { createRoot } from 'react-dom/client';
|
|
15501
|
+
import { DevPlayer } from '@mmapp/react/player';
|
|
15502
|
+
import { PlayerProvider, ExperienceRenderer, createApiResolver } from '@mmapp/react/player';
|
|
15503
|
+
|
|
15504
|
+
// Detect API base URL \u2014 proxy through dev server or use direct URL
|
|
15505
|
+
const API_BASE = window.location.origin + '/api/v1';
|
|
15506
|
+
const resolver = createApiResolver({ baseUrl: API_BASE, token: () => localStorage.getItem('auth_token') });
|
|
15507
|
+
|
|
15508
|
+
/**
|
|
15509
|
+
* Prepare experience tree for rendering.
|
|
15510
|
+
* Attaches metadata.dataSources to the root node and remaps
|
|
15511
|
+
* dataSource slugs to use definition-relative naming.
|
|
15512
|
+
*
|
|
15513
|
+
* @param definition - The main blueprint definition
|
|
15514
|
+
* @param allDefinitions - ALL definitions from the API (used for slug resolution)
|
|
15515
|
+
*/
|
|
15516
|
+
function prepareTree(definition, allDefinitions) {
|
|
15517
|
+
const exp = definition.experience;
|
|
15518
|
+
if (!exp || typeof exp !== 'object') return null;
|
|
15519
|
+
|
|
15520
|
+
const meta = definition.metadata || {};
|
|
15521
|
+
const dataSources = meta.dataSources || [];
|
|
15522
|
+
const mutationTargets = meta.mutationTargets || [];
|
|
15523
|
+
|
|
15524
|
+
// Build a slug map from ALL deployed definitions
|
|
15525
|
+
// This resolves bare model names (e.g. "item") to full slugs (e.g. "tutorial-1-item")
|
|
15526
|
+
const blueprintSlug = definition.slug || '';
|
|
15527
|
+
const allSlugs = (allDefinitions || []).map(d => d.slug).filter(Boolean);
|
|
15528
|
+
|
|
15529
|
+
function resolveSlug(bareSlug) {
|
|
15530
|
+
if (!bareSlug) return bareSlug;
|
|
15531
|
+
// Already a full slug (contains hyphen matching a known definition)
|
|
15532
|
+
if (allSlugs.includes(bareSlug)) return bareSlug;
|
|
15533
|
+
// Try blueprint-prefixed slug: "item" \u2192 "tutorial-1-item"
|
|
15534
|
+
const prefixed = blueprintSlug + '-' + bareSlug;
|
|
15535
|
+
if (allSlugs.includes(prefixed)) return prefixed;
|
|
15536
|
+
// Try matching by suffix across all definitions
|
|
15537
|
+
const match = allSlugs.find(s => s.endsWith('-' + bareSlug));
|
|
15538
|
+
if (match) return match;
|
|
15539
|
+
// Return original (will attempt as-is)
|
|
15540
|
+
return bareSlug;
|
|
15541
|
+
}
|
|
15542
|
+
|
|
15543
|
+
// Clone root node and attach dataSources
|
|
15544
|
+
const root = { ...exp };
|
|
15545
|
+
if (dataSources.length > 0 && !root.dataSources) {
|
|
15546
|
+
root.dataSources = dataSources.map(ds => ({
|
|
15547
|
+
...ds,
|
|
15548
|
+
slug: resolveSlug(ds.slug),
|
|
15549
|
+
}));
|
|
15550
|
+
}
|
|
15551
|
+
|
|
15552
|
+
// Remap mutation targets the same way
|
|
15553
|
+
if (mutationTargets.length > 0) {
|
|
15554
|
+
const resolvedTargets = mutationTargets.map(t => resolveSlug(t));
|
|
15555
|
+
root.config = { ...(root.config || {}), _mutationTargets: resolvedTargets };
|
|
15556
|
+
}
|
|
15557
|
+
|
|
15558
|
+
return root;
|
|
15559
|
+
}
|
|
15560
|
+
|
|
15561
|
+
function App() {
|
|
15562
|
+
const [tree, setTree] = useState(null);
|
|
15563
|
+
const [error, setError] = useState(null);
|
|
15564
|
+
|
|
15565
|
+
useEffect(() => {
|
|
15566
|
+
async function loadTree() {
|
|
15912
15567
|
try {
|
|
15913
|
-
const res = await fetch('/
|
|
15568
|
+
const res = await fetch(API_BASE + '/workflow/definitions');
|
|
15914
15569
|
const json = await res.json();
|
|
15915
15570
|
const items = json.items || json.data || [];
|
|
15916
|
-
|
|
15917
|
-
|
|
15918
|
-
|
|
15919
|
-
|
|
15920
|
-
|
|
15921
|
-
|
|
15922
|
-
|
|
15923
|
-
|
|
15924
|
-
|
|
15925
|
-
|
|
15926
|
-
|
|
15927
|
-
|
|
15928
|
-
|
|
15929
|
-
|
|
15571
|
+
// Find the main blueprint definition (has experience tree)
|
|
15572
|
+
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];
|
|
15573
|
+
if (main?.experience) {
|
|
15574
|
+
const prepared = prepareTree(main, items);
|
|
15575
|
+
if (prepared) {
|
|
15576
|
+
setTree(prepared);
|
|
15577
|
+
return;
|
|
15578
|
+
}
|
|
15579
|
+
}
|
|
15580
|
+
if (main) {
|
|
15581
|
+
// No experience tree \u2014 show definition info
|
|
15582
|
+
setTree({
|
|
15583
|
+
type: 'Stack',
|
|
15584
|
+
props: { style: { padding: 40, gap: 16 } },
|
|
15585
|
+
children: [
|
|
15586
|
+
{ type: 'Text', props: { children: main.name || main.slug, style: { fontSize: 24, fontWeight: 'bold' } } },
|
|
15587
|
+
{ type: 'Text', props: { children: (main.states?.length || 0) + ' states, ' + (main.fields?.length || 0) + ' fields', style: { color: '#666' } } },
|
|
15588
|
+
...items.map((d, i) => ({
|
|
15589
|
+
type: 'Card',
|
|
15590
|
+
props: { key: i, style: { padding: 16, border: '1px solid #ddd', borderRadius: 8 } },
|
|
15591
|
+
children: [
|
|
15592
|
+
{ type: 'Text', props: { children: d.name || d.slug, style: { fontWeight: 600 } } },
|
|
15593
|
+
{ type: 'Text', props: { children: 'slug: ' + d.slug + ' | ' + (d.states?.length || 0) + ' states', style: { fontSize: 13, color: '#888' } } },
|
|
15594
|
+
],
|
|
15595
|
+
})),
|
|
15596
|
+
],
|
|
15597
|
+
});
|
|
15598
|
+
}
|
|
15930
15599
|
} catch (e) {
|
|
15931
|
-
|
|
15600
|
+
setError(e.message);
|
|
15932
15601
|
}
|
|
15933
15602
|
}
|
|
15934
|
-
|
|
15935
|
-
|
|
15936
|
-
|
|
15937
|
-
|
|
15938
|
-
|
|
15939
|
-
|
|
15940
|
-
|
|
15941
|
-
|
|
15942
|
-
|
|
15943
|
-
|
|
15603
|
+
loadTree();
|
|
15604
|
+
}, []);
|
|
15605
|
+
|
|
15606
|
+
if (error) return React.createElement('div', { style: { padding: 40 } },
|
|
15607
|
+
React.createElement('h1', null, 'MindMatrix Dev'),
|
|
15608
|
+
React.createElement('p', { style: { color: '#c00' } }, 'Error: ' + error)
|
|
15609
|
+
);
|
|
15610
|
+
|
|
15611
|
+
if (!tree) return React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh' } },
|
|
15612
|
+
React.createElement('p', null, 'Loading...')
|
|
15613
|
+
);
|
|
15614
|
+
|
|
15615
|
+
// If tree has 'component' field, use ExperienceRenderer; otherwise legacy DevPlayer
|
|
15616
|
+
if (tree.component) {
|
|
15617
|
+
return React.createElement(PlayerProvider, { resolver },
|
|
15618
|
+
React.createElement(ExperienceRenderer, { tree, className: 'mm-experience-root' })
|
|
15619
|
+
);
|
|
15620
|
+
}
|
|
15621
|
+
|
|
15622
|
+
return React.createElement(DevPlayer, { tree, title: document.title || 'MindMatrix Dev' });
|
|
15623
|
+
}
|
|
15624
|
+
|
|
15625
|
+
createRoot(document.getElementById('root')).render(React.createElement(App));
|
|
15626
|
+
`;
|
|
15627
|
+
}
|
|
15628
|
+
};
|
|
15944
15629
|
let deployInFlight = false;
|
|
15945
15630
|
const compileDeployPlugin = {
|
|
15946
15631
|
name: "mindmatrix-dev-compile-deploy",
|
|
@@ -15971,16 +15656,16 @@ createRoot(document.getElementById('root')).render(React.createElement(App));
|
|
|
15971
15656
|
}
|
|
15972
15657
|
};
|
|
15973
15658
|
const viteConfig = {
|
|
15974
|
-
//
|
|
15975
|
-
root:
|
|
15976
|
-
// Pre-bundle React
|
|
15659
|
+
// Use the blueprint directory as Vite root (has node_modules with React).
|
|
15660
|
+
root: process.cwd(),
|
|
15661
|
+
// Pre-bundle React and the player for fast dev startup.
|
|
15977
15662
|
optimizeDeps: { include: ["react", "react-dom/client"] },
|
|
15978
15663
|
server: {
|
|
15979
15664
|
port,
|
|
15980
15665
|
open,
|
|
15981
15666
|
host: true,
|
|
15982
15667
|
// Allow serving files from the real project directory (fs.allow).
|
|
15983
|
-
fs: { allow: [
|
|
15668
|
+
fs: { allow: [process.cwd(), ".."] },
|
|
15984
15669
|
proxy: {
|
|
15985
15670
|
"/api": { target: proxyTarget, changeOrigin: true, secure: true, ws: true },
|
|
15986
15671
|
"/health": { target: proxyTarget, changeOrigin: true, secure: true },
|
|
@@ -15990,6 +15675,7 @@ createRoot(document.getElementById('root')).render(React.createElement(App));
|
|
|
15990
15675
|
plugins: [
|
|
15991
15676
|
mindmatrixReact(pluginOpts),
|
|
15992
15677
|
compileDeployPlugin,
|
|
15678
|
+
devEntryPlugin,
|
|
15993
15679
|
devPlayerPlugin,
|
|
15994
15680
|
{ name: "mindmatrix-error-overlay", configureServer(server) {
|
|
15995
15681
|
server.middlewares.use(errorOverlayMiddleware());
|
|
@@ -15997,8 +15683,8 @@ createRoot(document.getElementById('root')).render(React.createElement(App));
|
|
|
15997
15683
|
],
|
|
15998
15684
|
logLevel: "warn"
|
|
15999
15685
|
};
|
|
16000
|
-
const { createServer
|
|
16001
|
-
const vite = await
|
|
15686
|
+
const { createServer } = await import("vite");
|
|
15687
|
+
const vite = await createServer(viteConfig);
|
|
16002
15688
|
await vite.listen();
|
|
16003
15689
|
const resolvedPort = vite.config.server.port ?? port;
|
|
16004
15690
|
if (enableWs && vite.httpServer) {
|
|
@@ -16016,7 +15702,7 @@ createRoot(document.getElementById('root')).render(React.createElement(App));
|
|
|
16016
15702
|
} catch {
|
|
16017
15703
|
}
|
|
16018
15704
|
}
|
|
16019
|
-
printBanner({ port: resolvedPort, apiUrl
|
|
15705
|
+
printBanner({ port: resolvedPort, apiUrl, src, include, health, token: !!token, compiled: initialCompiled, deployed: initialDeployed, slug: initialSlug, errors: initialErrors });
|
|
16020
15706
|
return {
|
|
16021
15707
|
vite,
|
|
16022
15708
|
port: resolvedPort,
|
|
@@ -16048,14 +15734,6 @@ createRoot(document.getElementById('root')).render(React.createElement(App));
|
|
|
16048
15734
|
clients.clear();
|
|
16049
15735
|
currentErrors = null;
|
|
16050
15736
|
await vite.close();
|
|
16051
|
-
if (localServer) {
|
|
16052
|
-
await localServer.close();
|
|
16053
|
-
}
|
|
16054
|
-
try {
|
|
16055
|
-
const { rmSync } = await import("fs");
|
|
16056
|
-
rmSync(devRoot, { recursive: true, force: true });
|
|
16057
|
-
} catch {
|
|
16058
|
-
}
|
|
16059
15737
|
}
|
|
16060
15738
|
};
|
|
16061
15739
|
}
|
|
@@ -16065,7 +15743,6 @@ var init_dev_server = __esm({
|
|
|
16065
15743
|
"use strict";
|
|
16066
15744
|
init_vite();
|
|
16067
15745
|
init_build();
|
|
16068
|
-
init_local_server();
|
|
16069
15746
|
currentErrors = null;
|
|
16070
15747
|
}
|
|
16071
15748
|
});
|
|
@@ -16374,99 +16051,10 @@ function generateIndexHtml(name) {
|
|
|
16374
16051
|
<meta charset="UTF-8">
|
|
16375
16052
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
16376
16053
|
<title>${title} \u2014 MindMatrix Dev</title>
|
|
16377
|
-
<style>
|
|
16378
|
-
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
16379
|
-
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #fafafa; color: #111; }
|
|
16380
|
-
#root { min-height: 100vh; padding: 40px; max-width: 960px; margin: 0 auto; }
|
|
16381
|
-
h1 { font-size: 24px; margin-bottom: 8px; }
|
|
16382
|
-
.subtitle { color: #666; margin-bottom: 24px; }
|
|
16383
|
-
.card { border: 1px solid #e0e0e0; border-radius: 8px; padding: 16px; margin-bottom: 12px; background: #fff; }
|
|
16384
|
-
.card h3 { font-size: 16px; margin-bottom: 4px; }
|
|
16385
|
-
.card .meta { color: #888; font-size: 13px; }
|
|
16386
|
-
.badge { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 11px; font-weight: 600; }
|
|
16387
|
-
.badge-state { background: #e3f2fd; color: #1565c0; }
|
|
16388
|
-
.empty { text-align: center; padding: 60px 20px; color: #888; }
|
|
16389
|
-
.error { color: #c62828; background: #ffebee; padding: 16px; border-radius: 8px; margin-bottom: 16px; }
|
|
16390
|
-
.actions { display: flex; gap: 8px; margin-top: 8px; }
|
|
16391
|
-
.btn { padding: 6px 12px; border-radius: 4px; border: 1px solid #ddd; background: #fff; cursor: pointer; font-size: 13px; }
|
|
16392
|
-
.btn:hover { background: #f5f5f5; }
|
|
16393
|
-
.btn-primary { background: #1976d2; color: #fff; border-color: #1976d2; }
|
|
16394
|
-
.btn-primary:hover { background: #1565c0; }
|
|
16395
|
-
</style>
|
|
16396
16054
|
</head>
|
|
16397
16055
|
<body>
|
|
16398
|
-
<div id="root">
|
|
16399
|
-
|
|
16400
|
-
<p class="subtitle">Loading...</p>
|
|
16401
|
-
</div>
|
|
16402
|
-
<script type="module">
|
|
16403
|
-
const API = '/api/v1';
|
|
16404
|
-
|
|
16405
|
-
async function api(path, opts) {
|
|
16406
|
-
const res = await fetch(API + path, {
|
|
16407
|
-
headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer dev-local' },
|
|
16408
|
-
...opts,
|
|
16409
|
-
});
|
|
16410
|
-
return res.json();
|
|
16411
|
-
}
|
|
16412
|
-
|
|
16413
|
-
async function render() {
|
|
16414
|
-
const root = document.getElementById('root');
|
|
16415
|
-
try {
|
|
16416
|
-
const defs = await api('/workflow/definitions');
|
|
16417
|
-
const items = defs.items || defs.data || [];
|
|
16418
|
-
|
|
16419
|
-
let html = '<h1>${title}</h1>';
|
|
16420
|
-
html += '<p class="subtitle">' + items.length + ' definition(s) deployed</p>';
|
|
16421
|
-
|
|
16422
|
-
if (items.length === 0) {
|
|
16423
|
-
html += '<div class="empty"><p>No definitions deployed yet.</p><p style="margin-top:8px;font-size:13px">Edit your model files and save \u2014 mmrc dev will auto-compile and deploy.</p></div>';
|
|
16424
|
-
}
|
|
16425
|
-
|
|
16426
|
-
for (const def of items) {
|
|
16427
|
-
const states = def.states || [];
|
|
16428
|
-
const fields = def.fields || [];
|
|
16429
|
-
const transitions = def.transitions || [];
|
|
16430
|
-
html += '<div class="card">';
|
|
16431
|
-
html += '<h3>' + (def.name || def.slug || 'Unnamed') + '</h3>';
|
|
16432
|
-
html += '<p class="meta">' + states.length + ' states \xB7 ' + fields.length + ' fields \xB7 ' + transitions.length + ' transitions</p>';
|
|
16433
|
-
html += '<div class="actions">';
|
|
16434
|
-
html += '<button class="btn btn-primary" onclick="createInstance(\\'' + def.slug + '\\')">+ Create Instance</button>';
|
|
16435
|
-
html += '</div>';
|
|
16436
|
-
html += '</div>';
|
|
16437
|
-
}
|
|
16438
|
-
|
|
16439
|
-
// Show instances
|
|
16440
|
-
const instances = await api('/workflow/instances');
|
|
16441
|
-
const instItems = instances.items || instances.data || [];
|
|
16442
|
-
if (instItems.length > 0) {
|
|
16443
|
-
html += '<h2 style="margin-top:32px;margin-bottom:12px">Instances (' + instItems.length + ')</h2>';
|
|
16444
|
-
for (const inst of instItems) {
|
|
16445
|
-
html += '<div class="card">';
|
|
16446
|
-
html += '<h3>' + (inst.definition_slug || '?') + ' <span class="badge badge-state">' + (inst.current_state || inst.state || '?') + '</span></h3>';
|
|
16447
|
-
html += '<p class="meta">ID: ' + inst.id + '</p>';
|
|
16448
|
-
html += '</div>';
|
|
16449
|
-
}
|
|
16450
|
-
}
|
|
16451
|
-
|
|
16452
|
-
root.innerHTML = html;
|
|
16453
|
-
} catch (e) {
|
|
16454
|
-
root.innerHTML = '<h1>${title}</h1><div class="error">API Error: ' + e.message + '</div>';
|
|
16455
|
-
}
|
|
16456
|
-
}
|
|
16457
|
-
|
|
16458
|
-
window.createInstance = async function(slug) {
|
|
16459
|
-
await api('/workflow/instances', {
|
|
16460
|
-
method: 'POST',
|
|
16461
|
-
body: JSON.stringify({ definition_slug: slug, state_data: { title: 'New Item', priority: 'medium' } }),
|
|
16462
|
-
});
|
|
16463
|
-
render();
|
|
16464
|
-
};
|
|
16465
|
-
|
|
16466
|
-
render();
|
|
16467
|
-
// Auto-refresh every 3 seconds
|
|
16468
|
-
setInterval(render, 3000);
|
|
16469
|
-
</script>
|
|
16056
|
+
<div id="root"></div>
|
|
16057
|
+
<script type="module" src="/__mm_dev_entry.tsx"></script>
|
|
16470
16058
|
</body>
|
|
16471
16059
|
</html>`;
|
|
16472
16060
|
}
|
|
@@ -16627,35 +16215,46 @@ function generatePage(name) {
|
|
|
16627
16215
|
return `/**
|
|
16628
16216
|
* @workflow slug="${name}-home" version="1.0.0" category="page"
|
|
16629
16217
|
*
|
|
16630
|
-
* Index page \u2014
|
|
16218
|
+
* Index page \u2014 full CRUD with create form, search, transitions, and delete.
|
|
16631
16219
|
*/
|
|
16632
16220
|
|
|
16633
16221
|
import { useState } from 'react';
|
|
16634
16222
|
import itemModel from '../models/item';
|
|
16635
16223
|
import {
|
|
16636
16224
|
useQuery, useMutation, useRouter,
|
|
16637
|
-
Stack, Row, Text, Button, Icon, Card, Show, TextInput, Badge,
|
|
16225
|
+
Stack, Row, Text, Button, Icon, Card, Show, TextInput, Badge, Select,
|
|
16638
16226
|
} from '@mmapp/react';
|
|
16639
16227
|
|
|
16640
|
-
const PRIORITY_COLORS: Record<string, string> = {
|
|
16641
|
-
high: 'token:error',
|
|
16642
|
-
medium: 'token:warning',
|
|
16643
|
-
low: 'token:success',
|
|
16644
|
-
};
|
|
16645
|
-
|
|
16646
16228
|
export default function ${pascal}Home() {
|
|
16647
16229
|
const { data: items, loading } = useQuery(itemModel);
|
|
16648
16230
|
const mutation = useMutation(itemModel);
|
|
16649
16231
|
const router = useRouter();
|
|
16650
16232
|
const [search, setSearch] = useState('');
|
|
16233
|
+
const [showCreate, setShowCreate] = useState(false);
|
|
16234
|
+
const [newTitle, setNewTitle] = useState('');
|
|
16235
|
+
const [newDescription, setNewDescription] = useState('');
|
|
16236
|
+
const [newPriority, setNewPriority] = useState('medium');
|
|
16237
|
+
const [editingId, setEditingId] = useState<string | null>(null);
|
|
16238
|
+
const [editTitle, setEditTitle] = useState('');
|
|
16651
16239
|
|
|
16652
|
-
const
|
|
16653
|
-
const filtered =
|
|
16654
|
-
i.fields.title.toLowerCase().includes(search.toLowerCase())
|
|
16655
|
-
|
|
16240
|
+
const visibleItems = items.filter(i => i.state !== 'archived');
|
|
16241
|
+
const filtered = search
|
|
16242
|
+
? visibleItems.filter(i => i.fields.title.toLowerCase().includes(search.toLowerCase()))
|
|
16243
|
+
: visibleItems;
|
|
16656
16244
|
|
|
16657
16245
|
const handleCreate = async () => {
|
|
16658
|
-
|
|
16246
|
+
if (!newTitle.trim()) return;
|
|
16247
|
+
await mutation.create({ title: newTitle.trim(), description: newDescription, priority: newPriority });
|
|
16248
|
+
setNewTitle('');
|
|
16249
|
+
setNewDescription('');
|
|
16250
|
+
setNewPriority('medium');
|
|
16251
|
+
setShowCreate(false);
|
|
16252
|
+
};
|
|
16253
|
+
|
|
16254
|
+
const handleUpdate = async (id: string) => {
|
|
16255
|
+
if (!editTitle.trim()) return;
|
|
16256
|
+
await mutation.update(id, { title: editTitle.trim() });
|
|
16257
|
+
setEditingId(null);
|
|
16659
16258
|
};
|
|
16660
16259
|
|
|
16661
16260
|
return (
|
|
@@ -16664,9 +16263,9 @@ export default function ${pascal}Home() {
|
|
|
16664
16263
|
<Row justify="space-between" align="center">
|
|
16665
16264
|
<Stack gap={4}>
|
|
16666
16265
|
<Text variant="h3" weight="bold" value="${title}" />
|
|
16667
|
-
<Text variant="muted" size="sm" value={\`\${
|
|
16266
|
+
<Text variant="muted" size="sm" value={\`\${visibleItems.length} item\${visibleItems.length !== 1 ? 's' : ''}\`} />
|
|
16668
16267
|
</Stack>
|
|
16669
|
-
<Button variant="primary" onPress={
|
|
16268
|
+
<Button variant="primary" onPress={() => setShowCreate(true)}>
|
|
16670
16269
|
<Row gap={6} align="center">
|
|
16671
16270
|
<Icon name="plus" size={16} />
|
|
16672
16271
|
<Text value="Add Item" />
|
|
@@ -16674,6 +16273,42 @@ export default function ${pascal}Home() {
|
|
|
16674
16273
|
</Button>
|
|
16675
16274
|
</Row>
|
|
16676
16275
|
|
|
16276
|
+
{/* Create form */}
|
|
16277
|
+
<Show when={showCreate}>
|
|
16278
|
+
<Card padding={16}>
|
|
16279
|
+
<Stack gap={12}>
|
|
16280
|
+
<Text weight="bold" value="New Item" />
|
|
16281
|
+
<TextInput
|
|
16282
|
+
value={newTitle}
|
|
16283
|
+
onChange={setNewTitle}
|
|
16284
|
+
placeholder="Item title (required)"
|
|
16285
|
+
/>
|
|
16286
|
+
<TextInput
|
|
16287
|
+
value={newDescription}
|
|
16288
|
+
onChange={setNewDescription}
|
|
16289
|
+
placeholder="Description (optional)"
|
|
16290
|
+
/>
|
|
16291
|
+
<Select
|
|
16292
|
+
value={newPriority}
|
|
16293
|
+
onChange={setNewPriority}
|
|
16294
|
+
options={[
|
|
16295
|
+
{ label: 'Low', value: 'low' },
|
|
16296
|
+
{ label: 'Medium', value: 'medium' },
|
|
16297
|
+
{ label: 'High', value: 'high' },
|
|
16298
|
+
]}
|
|
16299
|
+
/>
|
|
16300
|
+
<Row gap={8} justify="flex-end">
|
|
16301
|
+
<Button variant="ghost" onPress={() => setShowCreate(false)}>
|
|
16302
|
+
<Text value="Cancel" />
|
|
16303
|
+
</Button>
|
|
16304
|
+
<Button variant="primary" onPress={handleCreate}>
|
|
16305
|
+
<Text value="Create" />
|
|
16306
|
+
</Button>
|
|
16307
|
+
</Row>
|
|
16308
|
+
</Stack>
|
|
16309
|
+
</Card>
|
|
16310
|
+
</Show>
|
|
16311
|
+
|
|
16677
16312
|
{/* Search */}
|
|
16678
16313
|
<TextInput
|
|
16679
16314
|
value={search}
|
|
@@ -16695,10 +16330,12 @@ export default function ${pascal}Home() {
|
|
|
16695
16330
|
<Card padding={32}>
|
|
16696
16331
|
<Stack align="center" gap={12}>
|
|
16697
16332
|
<Icon name="inbox" size={40} color="token:muted" />
|
|
16698
|
-
<Text variant="muted" value=
|
|
16699
|
-
<
|
|
16700
|
-
<
|
|
16701
|
-
|
|
16333
|
+
<Text variant="muted" value={search ? 'No items match your search' : 'No items yet'} />
|
|
16334
|
+
<Show when={!search}>
|
|
16335
|
+
<Button variant="outline" onPress={() => setShowCreate(true)}>
|
|
16336
|
+
<Text value="Create your first item" />
|
|
16337
|
+
</Button>
|
|
16338
|
+
</Show>
|
|
16702
16339
|
</Stack>
|
|
16703
16340
|
</Card>
|
|
16704
16341
|
</Show>
|
|
@@ -16710,13 +16347,48 @@ export default function ${pascal}Home() {
|
|
|
16710
16347
|
<Card key={item.id} padding={12}>
|
|
16711
16348
|
<Row align="center" gap={12}>
|
|
16712
16349
|
<Stack flex={1} gap={2}>
|
|
16713
|
-
<
|
|
16714
|
-
|
|
16715
|
-
|
|
16350
|
+
<Show when={editingId === item.id}>
|
|
16351
|
+
<Row gap={8}>
|
|
16352
|
+
<TextInput
|
|
16353
|
+
value={editTitle}
|
|
16354
|
+
onChange={setEditTitle}
|
|
16355
|
+
placeholder="Title"
|
|
16356
|
+
/>
|
|
16357
|
+
<Button variant="primary" size="sm" onPress={() => handleUpdate(item.id)}>
|
|
16358
|
+
<Text value="Save" />
|
|
16359
|
+
</Button>
|
|
16360
|
+
<Button variant="ghost" size="sm" onPress={() => setEditingId(null)}>
|
|
16361
|
+
<Text value="Cancel" />
|
|
16362
|
+
</Button>
|
|
16363
|
+
</Row>
|
|
16364
|
+
</Show>
|
|
16365
|
+
<Show when={editingId !== item.id}>
|
|
16366
|
+
<Text
|
|
16367
|
+
weight="medium"
|
|
16368
|
+
value={item.fields.title}
|
|
16369
|
+
onPress={() => { setEditingId(item.id); setEditTitle(item.fields.title); }}
|
|
16370
|
+
/>
|
|
16371
|
+
<Show when={!!item.fields.description}>
|
|
16372
|
+
<Text size="sm" variant="muted" value={item.fields.description} />
|
|
16373
|
+
</Show>
|
|
16716
16374
|
</Show>
|
|
16717
16375
|
</Stack>
|
|
16718
16376
|
<Badge value={item.fields.priority} />
|
|
16719
16377
|
<Badge value={item.state} variant={item.state === 'active' ? 'success' : 'default'} />
|
|
16378
|
+
{/* Transition buttons */}
|
|
16379
|
+
<Show when={item.state === 'draft'}>
|
|
16380
|
+
<Button variant="outline" size="sm" onPress={() => mutation.transition(item.id, 'activate')}>
|
|
16381
|
+
<Text value="Activate" />
|
|
16382
|
+
</Button>
|
|
16383
|
+
</Show>
|
|
16384
|
+
<Show when={item.state === 'active'}>
|
|
16385
|
+
<Button variant="ghost" size="sm" onPress={() => mutation.transition(item.id, 'archive')}>
|
|
16386
|
+
<Text value="Archive" />
|
|
16387
|
+
</Button>
|
|
16388
|
+
</Show>
|
|
16389
|
+
<Button variant="ghost" size="sm" onPress={() => mutation.remove(item.id)}>
|
|
16390
|
+
<Icon name="trash" size={14} color="token:error" />
|
|
16391
|
+
</Button>
|
|
16720
16392
|
</Row>
|
|
16721
16393
|
</Card>
|
|
16722
16394
|
))}
|