@mmapp/react-compiler 0.1.0-alpha.17 → 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-GMW45YVD.mjs +868 -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 -656
- 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 -526
- 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 -528
- 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,74 +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';
|
|
15912
15503
|
|
|
15913
|
-
|
|
15914
|
-
|
|
15915
|
-
|
|
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') });
|
|
15916
15507
|
|
|
15917
|
-
|
|
15918
|
-
|
|
15919
|
-
|
|
15920
|
-
|
|
15921
|
-
|
|
15922
|
-
|
|
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;
|
|
15923
15519
|
|
|
15924
|
-
|
|
15925
|
-
|
|
15926
|
-
|
|
15927
|
-
React.createElement('p', { style: { color: '#888', marginTop: 8 } }, 'The engine is running but the API returned an error. This may be an auth issue in SQLite mode.')
|
|
15928
|
-
);
|
|
15520
|
+
const meta = definition.metadata || {};
|
|
15521
|
+
const dataSources = meta.dataSources || [];
|
|
15522
|
+
const mutationTargets = meta.mutationTargets || [];
|
|
15929
15523
|
|
|
15930
|
-
|
|
15931
|
-
|
|
15932
|
-
|
|
15933
|
-
|
|
15934
|
-
|
|
15935
|
-
|
|
15936
|
-
|
|
15937
|
-
|
|
15938
|
-
|
|
15939
|
-
|
|
15940
|
-
|
|
15941
|
-
|
|
15942
|
-
|
|
15943
|
-
|
|
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() {
|
|
15567
|
+
try {
|
|
15568
|
+
const res = await fetch(API_BASE + '/workflow/definitions');
|
|
15569
|
+
const json = await res.json();
|
|
15570
|
+
const items = json.items || json.data || [];
|
|
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
|
+
}
|
|
15599
|
+
} catch (e) {
|
|
15600
|
+
setError(e.message);
|
|
15601
|
+
}
|
|
15944
15602
|
}
|
|
15603
|
+
loadTree();
|
|
15604
|
+
}, []);
|
|
15945
15605
|
|
|
15946
|
-
|
|
15947
|
-
|
|
15948
|
-
|
|
15949
|
-
|
|
15950
|
-
|
|
15951
|
-
|
|
15952
|
-
|
|
15953
|
-
|
|
15954
|
-
|
|
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
|
+
};
|
|
15955
15629
|
let deployInFlight = false;
|
|
15956
15630
|
const compileDeployPlugin = {
|
|
15957
15631
|
name: "mindmatrix-dev-compile-deploy",
|
|
@@ -15982,16 +15656,16 @@ createRoot(document.getElementById('root')).render(React.createElement(App));
|
|
|
15982
15656
|
}
|
|
15983
15657
|
};
|
|
15984
15658
|
const viteConfig = {
|
|
15985
|
-
//
|
|
15986
|
-
root:
|
|
15987
|
-
// 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.
|
|
15988
15662
|
optimizeDeps: { include: ["react", "react-dom/client"] },
|
|
15989
15663
|
server: {
|
|
15990
15664
|
port,
|
|
15991
15665
|
open,
|
|
15992
15666
|
host: true,
|
|
15993
15667
|
// Allow serving files from the real project directory (fs.allow).
|
|
15994
|
-
fs: { allow: [
|
|
15668
|
+
fs: { allow: [process.cwd(), ".."] },
|
|
15995
15669
|
proxy: {
|
|
15996
15670
|
"/api": { target: proxyTarget, changeOrigin: true, secure: true, ws: true },
|
|
15997
15671
|
"/health": { target: proxyTarget, changeOrigin: true, secure: true },
|
|
@@ -16001,6 +15675,7 @@ createRoot(document.getElementById('root')).render(React.createElement(App));
|
|
|
16001
15675
|
plugins: [
|
|
16002
15676
|
mindmatrixReact(pluginOpts),
|
|
16003
15677
|
compileDeployPlugin,
|
|
15678
|
+
devEntryPlugin,
|
|
16004
15679
|
devPlayerPlugin,
|
|
16005
15680
|
{ name: "mindmatrix-error-overlay", configureServer(server) {
|
|
16006
15681
|
server.middlewares.use(errorOverlayMiddleware());
|
|
@@ -16008,8 +15683,8 @@ createRoot(document.getElementById('root')).render(React.createElement(App));
|
|
|
16008
15683
|
],
|
|
16009
15684
|
logLevel: "warn"
|
|
16010
15685
|
};
|
|
16011
|
-
const { createServer
|
|
16012
|
-
const vite = await
|
|
15686
|
+
const { createServer } = await import("vite");
|
|
15687
|
+
const vite = await createServer(viteConfig);
|
|
16013
15688
|
await vite.listen();
|
|
16014
15689
|
const resolvedPort = vite.config.server.port ?? port;
|
|
16015
15690
|
if (enableWs && vite.httpServer) {
|
|
@@ -16027,7 +15702,7 @@ createRoot(document.getElementById('root')).render(React.createElement(App));
|
|
|
16027
15702
|
} catch {
|
|
16028
15703
|
}
|
|
16029
15704
|
}
|
|
16030
|
-
printBanner({ port: resolvedPort, apiUrl
|
|
15705
|
+
printBanner({ port: resolvedPort, apiUrl, src, include, health, token: !!token, compiled: initialCompiled, deployed: initialDeployed, slug: initialSlug, errors: initialErrors });
|
|
16031
15706
|
return {
|
|
16032
15707
|
vite,
|
|
16033
15708
|
port: resolvedPort,
|
|
@@ -16059,14 +15734,6 @@ createRoot(document.getElementById('root')).render(React.createElement(App));
|
|
|
16059
15734
|
clients.clear();
|
|
16060
15735
|
currentErrors = null;
|
|
16061
15736
|
await vite.close();
|
|
16062
|
-
if (localServer) {
|
|
16063
|
-
await localServer.close();
|
|
16064
|
-
}
|
|
16065
|
-
try {
|
|
16066
|
-
const { rmSync } = await import("fs");
|
|
16067
|
-
rmSync(devRoot, { recursive: true, force: true });
|
|
16068
|
-
} catch {
|
|
16069
|
-
}
|
|
16070
15737
|
}
|
|
16071
15738
|
};
|
|
16072
15739
|
}
|
|
@@ -16076,7 +15743,6 @@ var init_dev_server = __esm({
|
|
|
16076
15743
|
"use strict";
|
|
16077
15744
|
init_vite();
|
|
16078
15745
|
init_build();
|
|
16079
|
-
init_local_server();
|
|
16080
15746
|
currentErrors = null;
|
|
16081
15747
|
}
|
|
16082
15748
|
});
|
|
@@ -16385,99 +16051,10 @@ function generateIndexHtml(name) {
|
|
|
16385
16051
|
<meta charset="UTF-8">
|
|
16386
16052
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
16387
16053
|
<title>${title} \u2014 MindMatrix Dev</title>
|
|
16388
|
-
<style>
|
|
16389
|
-
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
16390
|
-
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #fafafa; color: #111; }
|
|
16391
|
-
#root { min-height: 100vh; padding: 40px; max-width: 960px; margin: 0 auto; }
|
|
16392
|
-
h1 { font-size: 24px; margin-bottom: 8px; }
|
|
16393
|
-
.subtitle { color: #666; margin-bottom: 24px; }
|
|
16394
|
-
.card { border: 1px solid #e0e0e0; border-radius: 8px; padding: 16px; margin-bottom: 12px; background: #fff; }
|
|
16395
|
-
.card h3 { font-size: 16px; margin-bottom: 4px; }
|
|
16396
|
-
.card .meta { color: #888; font-size: 13px; }
|
|
16397
|
-
.badge { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 11px; font-weight: 600; }
|
|
16398
|
-
.badge-state { background: #e3f2fd; color: #1565c0; }
|
|
16399
|
-
.empty { text-align: center; padding: 60px 20px; color: #888; }
|
|
16400
|
-
.error { color: #c62828; background: #ffebee; padding: 16px; border-radius: 8px; margin-bottom: 16px; }
|
|
16401
|
-
.actions { display: flex; gap: 8px; margin-top: 8px; }
|
|
16402
|
-
.btn { padding: 6px 12px; border-radius: 4px; border: 1px solid #ddd; background: #fff; cursor: pointer; font-size: 13px; }
|
|
16403
|
-
.btn:hover { background: #f5f5f5; }
|
|
16404
|
-
.btn-primary { background: #1976d2; color: #fff; border-color: #1976d2; }
|
|
16405
|
-
.btn-primary:hover { background: #1565c0; }
|
|
16406
|
-
</style>
|
|
16407
16054
|
</head>
|
|
16408
16055
|
<body>
|
|
16409
|
-
<div id="root">
|
|
16410
|
-
|
|
16411
|
-
<p class="subtitle">Loading...</p>
|
|
16412
|
-
</div>
|
|
16413
|
-
<script type="module">
|
|
16414
|
-
const API = '/api/v1';
|
|
16415
|
-
|
|
16416
|
-
async function api(path, opts) {
|
|
16417
|
-
const res = await fetch(API + path, {
|
|
16418
|
-
headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer dev-local' },
|
|
16419
|
-
...opts,
|
|
16420
|
-
});
|
|
16421
|
-
return res.json();
|
|
16422
|
-
}
|
|
16423
|
-
|
|
16424
|
-
async function render() {
|
|
16425
|
-
const root = document.getElementById('root');
|
|
16426
|
-
try {
|
|
16427
|
-
const defs = await api('/workflow/definitions');
|
|
16428
|
-
const items = defs.items || defs.data || [];
|
|
16429
|
-
|
|
16430
|
-
let html = '<h1>${title}</h1>';
|
|
16431
|
-
html += '<p class="subtitle">' + items.length + ' definition(s) deployed</p>';
|
|
16432
|
-
|
|
16433
|
-
if (items.length === 0) {
|
|
16434
|
-
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>';
|
|
16435
|
-
}
|
|
16436
|
-
|
|
16437
|
-
for (const def of items) {
|
|
16438
|
-
const states = def.states || [];
|
|
16439
|
-
const fields = def.fields || [];
|
|
16440
|
-
const transitions = def.transitions || [];
|
|
16441
|
-
html += '<div class="card">';
|
|
16442
|
-
html += '<h3>' + (def.name || def.slug || 'Unnamed') + '</h3>';
|
|
16443
|
-
html += '<p class="meta">' + states.length + ' states \xB7 ' + fields.length + ' fields \xB7 ' + transitions.length + ' transitions</p>';
|
|
16444
|
-
html += '<div class="actions">';
|
|
16445
|
-
html += '<button class="btn btn-primary" onclick="createInstance(\\'' + def.slug + '\\')">+ Create Instance</button>';
|
|
16446
|
-
html += '</div>';
|
|
16447
|
-
html += '</div>';
|
|
16448
|
-
}
|
|
16449
|
-
|
|
16450
|
-
// Show instances
|
|
16451
|
-
const instances = await api('/workflow/instances');
|
|
16452
|
-
const instItems = instances.items || instances.data || [];
|
|
16453
|
-
if (instItems.length > 0) {
|
|
16454
|
-
html += '<h2 style="margin-top:32px;margin-bottom:12px">Instances (' + instItems.length + ')</h2>';
|
|
16455
|
-
for (const inst of instItems) {
|
|
16456
|
-
html += '<div class="card">';
|
|
16457
|
-
html += '<h3>' + (inst.definition_slug || '?') + ' <span class="badge badge-state">' + (inst.current_state || inst.state || '?') + '</span></h3>';
|
|
16458
|
-
html += '<p class="meta">ID: ' + inst.id + '</p>';
|
|
16459
|
-
html += '</div>';
|
|
16460
|
-
}
|
|
16461
|
-
}
|
|
16462
|
-
|
|
16463
|
-
root.innerHTML = html;
|
|
16464
|
-
} catch (e) {
|
|
16465
|
-
root.innerHTML = '<h1>${title}</h1><div class="error">API Error: ' + e.message + '</div>';
|
|
16466
|
-
}
|
|
16467
|
-
}
|
|
16468
|
-
|
|
16469
|
-
window.createInstance = async function(slug) {
|
|
16470
|
-
await api('/workflow/instances', {
|
|
16471
|
-
method: 'POST',
|
|
16472
|
-
body: JSON.stringify({ definition_slug: slug, state_data: { title: 'New Item', priority: 'medium' } }),
|
|
16473
|
-
});
|
|
16474
|
-
render();
|
|
16475
|
-
};
|
|
16476
|
-
|
|
16477
|
-
render();
|
|
16478
|
-
// Auto-refresh every 3 seconds
|
|
16479
|
-
setInterval(render, 3000);
|
|
16480
|
-
</script>
|
|
16056
|
+
<div id="root"></div>
|
|
16057
|
+
<script type="module" src="/__mm_dev_entry.tsx"></script>
|
|
16481
16058
|
</body>
|
|
16482
16059
|
</html>`;
|
|
16483
16060
|
}
|
|
@@ -16638,35 +16215,46 @@ function generatePage(name) {
|
|
|
16638
16215
|
return `/**
|
|
16639
16216
|
* @workflow slug="${name}-home" version="1.0.0" category="page"
|
|
16640
16217
|
*
|
|
16641
|
-
* Index page \u2014
|
|
16218
|
+
* Index page \u2014 full CRUD with create form, search, transitions, and delete.
|
|
16642
16219
|
*/
|
|
16643
16220
|
|
|
16644
16221
|
import { useState } from 'react';
|
|
16645
16222
|
import itemModel from '../models/item';
|
|
16646
16223
|
import {
|
|
16647
16224
|
useQuery, useMutation, useRouter,
|
|
16648
|
-
Stack, Row, Text, Button, Icon, Card, Show, TextInput, Badge,
|
|
16225
|
+
Stack, Row, Text, Button, Icon, Card, Show, TextInput, Badge, Select,
|
|
16649
16226
|
} from '@mmapp/react';
|
|
16650
16227
|
|
|
16651
|
-
const PRIORITY_COLORS: Record<string, string> = {
|
|
16652
|
-
high: 'token:error',
|
|
16653
|
-
medium: 'token:warning',
|
|
16654
|
-
low: 'token:success',
|
|
16655
|
-
};
|
|
16656
|
-
|
|
16657
16228
|
export default function ${pascal}Home() {
|
|
16658
16229
|
const { data: items, loading } = useQuery(itemModel);
|
|
16659
16230
|
const mutation = useMutation(itemModel);
|
|
16660
16231
|
const router = useRouter();
|
|
16661
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('');
|
|
16662
16239
|
|
|
16663
|
-
const
|
|
16664
|
-
const filtered =
|
|
16665
|
-
i.fields.title.toLowerCase().includes(search.toLowerCase())
|
|
16666
|
-
|
|
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;
|
|
16667
16244
|
|
|
16668
16245
|
const handleCreate = async () => {
|
|
16669
|
-
|
|
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);
|
|
16670
16258
|
};
|
|
16671
16259
|
|
|
16672
16260
|
return (
|
|
@@ -16675,9 +16263,9 @@ export default function ${pascal}Home() {
|
|
|
16675
16263
|
<Row justify="space-between" align="center">
|
|
16676
16264
|
<Stack gap={4}>
|
|
16677
16265
|
<Text variant="h3" weight="bold" value="${title}" />
|
|
16678
|
-
<Text variant="muted" size="sm" value={\`\${
|
|
16266
|
+
<Text variant="muted" size="sm" value={\`\${visibleItems.length} item\${visibleItems.length !== 1 ? 's' : ''}\`} />
|
|
16679
16267
|
</Stack>
|
|
16680
|
-
<Button variant="primary" onPress={
|
|
16268
|
+
<Button variant="primary" onPress={() => setShowCreate(true)}>
|
|
16681
16269
|
<Row gap={6} align="center">
|
|
16682
16270
|
<Icon name="plus" size={16} />
|
|
16683
16271
|
<Text value="Add Item" />
|
|
@@ -16685,6 +16273,42 @@ export default function ${pascal}Home() {
|
|
|
16685
16273
|
</Button>
|
|
16686
16274
|
</Row>
|
|
16687
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
|
+
|
|
16688
16312
|
{/* Search */}
|
|
16689
16313
|
<TextInput
|
|
16690
16314
|
value={search}
|
|
@@ -16706,10 +16330,12 @@ export default function ${pascal}Home() {
|
|
|
16706
16330
|
<Card padding={32}>
|
|
16707
16331
|
<Stack align="center" gap={12}>
|
|
16708
16332
|
<Icon name="inbox" size={40} color="token:muted" />
|
|
16709
|
-
<Text variant="muted" value=
|
|
16710
|
-
<
|
|
16711
|
-
<
|
|
16712
|
-
|
|
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>
|
|
16713
16339
|
</Stack>
|
|
16714
16340
|
</Card>
|
|
16715
16341
|
</Show>
|
|
@@ -16721,13 +16347,48 @@ export default function ${pascal}Home() {
|
|
|
16721
16347
|
<Card key={item.id} padding={12}>
|
|
16722
16348
|
<Row align="center" gap={12}>
|
|
16723
16349
|
<Stack flex={1} gap={2}>
|
|
16724
|
-
<
|
|
16725
|
-
|
|
16726
|
-
|
|
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>
|
|
16727
16374
|
</Show>
|
|
16728
16375
|
</Stack>
|
|
16729
16376
|
<Badge value={item.fields.priority} />
|
|
16730
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>
|
|
16731
16392
|
</Row>
|
|
16732
16393
|
</Card>
|
|
16733
16394
|
))}
|