@mmapp/react-compiler 0.1.0-alpha.1
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/README.md +107 -0
- package/compile-blueprint-chat.mjs +99 -0
- package/compile-blueprint-glass-console.mjs +98 -0
- package/compile-chat-defs.mjs +92 -0
- package/dist/babel/index.d.mts +3 -0
- package/dist/babel/index.d.ts +3 -0
- package/dist/babel/index.js +4851 -0
- package/dist/babel/index.mjs +7 -0
- package/dist/chunk-26U577GB.mjs +3465 -0
- package/dist/chunk-2FBDFAX6.mjs +2362 -0
- package/dist/chunk-2L4QSMXG.mjs +175 -0
- package/dist/chunk-2REDFOER.mjs +931 -0
- package/dist/chunk-46YKSHQR.mjs +175 -0
- package/dist/chunk-4XHK6FWL.mjs +2058 -0
- package/dist/chunk-5M7DKKBC.mjs +215 -0
- package/dist/chunk-5VNJ7C6N.mjs +154 -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-AOGY2GK6.mjs +3292 -0
- package/dist/chunk-AXXUXRNA.mjs +1434 -0
- package/dist/chunk-CHLVKMQW.mjs +175 -0
- package/dist/chunk-CKGOZAB7.mjs +939 -0
- package/dist/chunk-D34RAZUX.mjs +2223 -0
- package/dist/chunk-EQGA6A6D.mjs +121 -0
- package/dist/chunk-EY2CSXYA.mjs +822 -0
- package/dist/chunk-FIQ65CDR.mjs +925 -0
- package/dist/chunk-FOZXJFAR.mjs +186 -0
- package/dist/chunk-FX6URXWN.mjs +186 -0
- package/dist/chunk-G7SMOWOL.mjs +828 -0
- package/dist/chunk-GGB4G5YY.mjs +175 -0
- package/dist/chunk-HLRGCCIL.mjs +4839 -0
- package/dist/chunk-HOIUP6IF.mjs +690 -0
- package/dist/chunk-I3AU7GRD.mjs +120 -0
- package/dist/chunk-ILFGMUVD.mjs +1933 -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-J7TWJ3TM.mjs +2784 -0
- package/dist/chunk-JDPLDGVF.mjs +4810 -0
- package/dist/chunk-K53XP2DL.mjs +148 -0
- package/dist/chunk-K5HX2SVL.mjs +1902 -0
- package/dist/chunk-KFGYOOVS.mjs +214 -0
- package/dist/chunk-KFVVOS5N.mjs +925 -0
- package/dist/chunk-L2OZ4CDV.mjs +113 -0
- package/dist/chunk-MIZV3TAN.mjs +3293 -0
- package/dist/chunk-NKKLQE5V.mjs +148 -0
- package/dist/chunk-NOW23XFZ.mjs +186 -0
- package/dist/chunk-NRXQKQ74.mjs +148 -0
- package/dist/chunk-OWI6XWCD.mjs +3375 -0
- package/dist/chunk-PRUMNNDI.mjs +3192 -0
- package/dist/chunk-QTBD5B3F.mjs +148 -0
- package/dist/chunk-SKSDPPNT.mjs +3788 -0
- package/dist/chunk-SP2YUS33.mjs +186 -0
- package/dist/chunk-SU4E6E7B.mjs +3153 -0
- package/dist/chunk-SYUUKW5A.mjs +3379 -0
- package/dist/chunk-UL2XZEMA.mjs +3128 -0
- package/dist/chunk-XMWUHQVV.mjs +939 -0
- package/dist/chunk-XZNEDRGN.mjs +3876 -0
- package/dist/chunk-Y6FXYEAI.mjs +10 -0
- package/dist/chunk-YFS6JMYO.mjs +3342 -0
- package/dist/chunk-Z6AIQ4KL.mjs +113 -0
- package/dist/cli/index.d.mts +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +11585 -0
- package/dist/cli/index.mjs +701 -0
- package/dist/codemod/cli.d.mts +1 -0
- package/dist/codemod/cli.d.ts +1 -0
- package/dist/codemod/cli.js +1104 -0
- package/dist/codemod/cli.mjs +157 -0
- package/dist/codemod/index.d.mts +148 -0
- package/dist/codemod/index.d.ts +148 -0
- package/dist/codemod/index.js +981 -0
- package/dist/codemod/index.mjs +25 -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-CjoufJ-u.d.mts +109 -0
- package/dist/dev-server-CjoufJ-u.d.ts +109 -0
- package/dist/dev-server.d.mts +3 -0
- package/dist/dev-server.d.ts +3 -0
- package/dist/dev-server.js +7603 -0
- package/dist/dev-server.mjs +11 -0
- package/dist/envelope-DD7v0v6E.d.mts +265 -0
- package/dist/envelope-DD7v0v6E.d.ts +265 -0
- package/dist/envelope-vCVjrHlo.d.mts +265 -0
- package/dist/envelope-vCVjrHlo.d.ts +265 -0
- package/dist/envelope.d.mts +2 -0
- package/dist/envelope.d.ts +2 -0
- package/dist/envelope.js +5184 -0
- package/dist/envelope.mjs +9 -0
- 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.d.mts +1099 -0
- package/dist/index.d.ts +1099 -0
- package/dist/index.js +10162 -0
- package/dist/index.mjs +372 -0
- package/dist/init-IXEE2RCF.mjs +340 -0
- package/dist/project-compiler-EGJUTAJU.mjs +10 -0
- package/dist/project-compiler-VFR6CSDX.mjs +10 -0
- package/dist/project-decompiler-5GY2KSG4.mjs +7 -0
- package/dist/pull-A2QUHW4K.mjs +109 -0
- package/dist/pull-JBEQWVPE.mjs +109 -0
- package/dist/testing/index.d.mts +211 -0
- package/dist/testing/index.d.ts +211 -0
- package/dist/testing/index.js +5106 -0
- package/dist/testing/index.mjs +247 -0
- package/dist/vite/index.d.mts +59 -0
- package/dist/vite/index.d.ts +59 -0
- package/dist/vite/index.js +5023 -0
- package/dist/vite/index.mjs +8 -0
- package/examples/README.md +72 -0
- package/examples/authentication/main.workflow.tsx +139 -0
- package/examples/authentication/mm.config.ts +22 -0
- package/examples/authentication/models/auth.ts +45 -0
- package/examples/authentication/pages/LoginPage.tsx +79 -0
- package/examples/authentication/pages/SignupPage.tsx +87 -0
- package/examples/counter.workflow.tsx +65 -0
- package/examples/dashboard.workflow.tsx +419 -0
- package/examples/invoice-approval/actions/invoice.server.ts +72 -0
- package/examples/invoice-approval/main.workflow.tsx +168 -0
- package/examples/invoice-approval/mm.config.ts +18 -0
- package/examples/invoice-approval/models/invoice.ts +46 -0
- package/examples/invoice-approval/pages/InvoiceDetailPage.tsx +175 -0
- package/examples/invoice-approval/pages/InvoiceFormPage.tsx +198 -0
- package/examples/invoice-approval/pages/InvoiceListPage.tsx +141 -0
- package/examples/todo-app.workflow.tsx +131 -0
- package/examples/uber-app/actions/matching.server.ts +177 -0
- package/examples/uber-app/actions/notifications.server.ts +176 -0
- package/examples/uber-app/actions/payments.server.ts +184 -0
- package/examples/uber-app/actions/pricing.server.ts +176 -0
- package/examples/uber-app/app/admin/analytics.tsx +102 -0
- package/examples/uber-app/app/admin/fleet.tsx +102 -0
- package/examples/uber-app/app/admin/surge-pricing.tsx +95 -0
- package/examples/uber-app/app/driver/dashboard.tsx +87 -0
- package/examples/uber-app/app/driver/earnings.tsx +101 -0
- package/examples/uber-app/app/driver/navigation.tsx +94 -0
- package/examples/uber-app/app/driver/ride-acceptance.tsx +103 -0
- package/examples/uber-app/app/rider/home.tsx +109 -0
- package/examples/uber-app/app/rider/payment-methods.tsx +134 -0
- package/examples/uber-app/app/rider/ride-history.tsx +90 -0
- package/examples/uber-app/app/rider/ride-tracking.tsx +108 -0
- package/examples/uber-app/components/DriverCard.tsx +176 -0
- package/examples/uber-app/components/MapView.tsx +216 -0
- package/examples/uber-app/components/RatingStars.tsx +227 -0
- package/examples/uber-app/components/RideCard.tsx +167 -0
- package/examples/uber-app/mm.config.ts +30 -0
- package/examples/uber-app/models/location.model.ts +70 -0
- package/examples/uber-app/models/payment.model.ts +87 -0
- package/examples/uber-app/models/rating.model.ts +54 -0
- package/examples/uber-app/models/ride.model.ts +118 -0
- package/examples/uber-app/models/user.model.ts +66 -0
- package/examples/uber-app/models/vehicle.model.ts +63 -0
- package/examples/uber-app/tests/payment.test.tsx +129 -0
- package/examples/uber-app/tests/ride-flow.test.tsx +123 -0
- package/examples/uber-app/workflows/dispute-resolution.workflow.tsx +205 -0
- package/examples/uber-app/workflows/driver-onboarding.workflow.tsx +227 -0
- package/examples/uber-app/workflows/payment-processing.workflow.tsx +223 -0
- package/examples/uber-app/workflows/ride-request.workflow.tsx +194 -0
- package/package.json +77 -0
- package/package.json.backup +86 -0
- package/scripts/decompile.ts +226 -0
- package/scripts/seed-auth.ts +267 -0
- package/scripts/seed-uber.ts +248 -0
- package/scripts/validate-uber.ts +119 -0
- package/seed-blueprint-chat.mjs +444 -0
- package/seed-blueprint-glass-console.mjs +445 -0
- package/seed-compiled.mjs +318 -0
- package/src/RoundTripValidator.ts +400 -0
- package/src/__tests__/atom-rendering-coverage.test.ts +680 -0
- package/src/__tests__/auth-module-compilation.test.ts +247 -0
- package/src/__tests__/auth-template-compilation.test.ts +589 -0
- package/src/__tests__/change-extractor.test.ts +142 -0
- package/src/__tests__/cli-pull.test.ts +73 -0
- package/src/__tests__/cli-test.test.ts +72 -0
- package/src/__tests__/component-extractor.test.ts +331 -0
- package/src/__tests__/context-extractor.test.ts +145 -0
- package/src/__tests__/decompiler.test.ts +718 -0
- package/src/__tests__/define-blueprint.test.ts +133 -0
- package/src/__tests__/definition-validator.test.ts +519 -0
- package/src/__tests__/during-extractor.test.ts +152 -0
- package/src/__tests__/effect-extractor.test.ts +107 -0
- package/src/__tests__/event-emission.test.ts +127 -0
- package/src/__tests__/examples.test.ts +236 -0
- package/src/__tests__/full-blueprint-coverage.test.ts +1221 -0
- package/src/__tests__/golden-suite.test.ts +403 -0
- package/src/__tests__/grammar-island-extractor.test.ts +289 -0
- package/src/__tests__/instance-key.test.ts +82 -0
- package/src/__tests__/ir-migration.test.ts +255 -0
- package/src/__tests__/lock-file.test.ts +117 -0
- package/src/__tests__/model-extractor.test.ts +195 -0
- package/src/__tests__/model-field-acl.test.ts +237 -0
- package/src/__tests__/model-hooks.test.ts +130 -0
- package/src/__tests__/model-ref-resolution.test.ts +268 -0
- package/src/__tests__/model-roundtrip.test.ts +502 -0
- package/src/__tests__/model-runtime.test.ts +112 -0
- package/src/__tests__/model-transitions.test.ts +183 -0
- package/src/__tests__/nrt-action-trace.test.ts +391 -0
- package/src/__tests__/pipeline-hardening.test.ts +413 -0
- package/src/__tests__/project-compiler.test.ts +546 -0
- package/src/__tests__/project-decompiler.test.ts +343 -0
- package/src/__tests__/query-compilation.test.ts +145 -0
- package/src/__tests__/round-trip/PLAN.md +158 -0
- package/src/__tests__/round-trip/README.md +52 -0
- package/src/__tests__/round-trip/RESULTS.md +86 -0
- package/src/__tests__/round-trip/fixtures/data-heavy/main.workflow.tsx +55 -0
- package/src/__tests__/round-trip/fixtures/data-heavy/mm.config.ts +11 -0
- package/src/__tests__/round-trip/fixtures/data-heavy/models/contact.ts +54 -0
- package/src/__tests__/round-trip/fixtures/full-workflow/main.workflow.tsx +79 -0
- package/src/__tests__/round-trip/fixtures/full-workflow/mm.config.ts +12 -0
- package/src/__tests__/round-trip/fixtures/full-workflow/models/order.ts +50 -0
- package/src/__tests__/round-trip/fixtures/simple-crud/main.workflow.tsx +25 -0
- package/src/__tests__/round-trip/fixtures/simple-crud/mm.config.ts +11 -0
- package/src/__tests__/round-trip/fixtures/simple-crud/models/task.ts +32 -0
- package/src/__tests__/round-trip/fixtures/view-heavy/main.workflow.tsx +79 -0
- package/src/__tests__/round-trip/fixtures/view-heavy/mm.config.ts +10 -0
- package/src/__tests__/round-trip/round-trip.test.ts +2598 -0
- package/src/__tests__/round-trip-ir.test.ts +300 -0
- package/src/__tests__/round-trip.test.ts +1212 -0
- package/src/__tests__/route-merging.test.ts +372 -0
- package/src/__tests__/router-composition.test.ts +489 -0
- package/src/__tests__/router-extractor.test.ts +176 -0
- package/src/__tests__/server-action-extractor.test.ts +128 -0
- package/src/__tests__/smart-type-inference.test.ts +365 -0
- package/src/__tests__/source-envelope.test.ts +284 -0
- package/src/__tests__/source-fidelity.test.ts +516 -0
- package/src/__tests__/state-extractor.test.ts +115 -0
- package/src/__tests__/strict-mode.test.ts +227 -0
- package/src/__tests__/transition-effect-extractor.test.ts +119 -0
- package/src/__tests__/transition-extractor.test.ts +68 -0
- package/src/__tests__/ts-to-expression.test.ts +462 -0
- package/src/__tests__/type-generator.test.ts +201 -0
- package/src/__tests__/uber-validation.test.ts +502 -0
- package/src/action-compiler.ts +361 -0
- package/src/babel/emitters/experience-transform.ts +199 -0
- package/src/babel/emitters/ir-to-tsx-emitter.ts +110 -0
- package/src/babel/emitters/pure-form-emitter.ts +1023 -0
- package/src/babel/emitters/runtime-glue-emitter.ts +39 -0
- package/src/babel/extractors/change-extractor.ts +199 -0
- package/src/babel/extractors/component-extractor.ts +907 -0
- package/src/babel/extractors/computed-extractor.ts +262 -0
- package/src/babel/extractors/context-extractor.ts +277 -0
- package/src/babel/extractors/during-extractor.ts +295 -0
- package/src/babel/extractors/effect-extractor.ts +340 -0
- package/src/babel/extractors/event-extractor.ts +235 -0
- package/src/babel/extractors/grammar-island-extractor.ts +302 -0
- package/src/babel/extractors/model-extractor.ts +1018 -0
- package/src/babel/extractors/router-extractor.ts +303 -0
- package/src/babel/extractors/server-action-extractor.ts +173 -0
- package/src/babel/extractors/server-action-hook-extractor.ts +72 -0
- package/src/babel/extractors/server-state-extractor.ts +88 -0
- package/src/babel/extractors/state-extractor.ts +214 -0
- package/src/babel/extractors/transition-effect-extractor.ts +176 -0
- package/src/babel/extractors/transition-extractor.ts +143 -0
- package/src/babel/index.ts +24 -0
- package/src/babel/transpilers/ts-to-expression.ts +674 -0
- package/src/babel/visitor.ts +807 -0
- package/src/cli/auth.ts +255 -0
- package/src/cli/build.ts +288 -0
- package/src/cli/deploy.ts +206 -0
- package/src/cli/index.ts +328 -0
- package/src/cli/init.ts +388 -0
- package/src/cli/installer.ts +261 -0
- package/src/cli/lock-file.ts +94 -0
- package/src/cli/mmrc.ts +22 -0
- package/src/cli/pull.ts +172 -0
- package/src/cli/registry-client.ts +175 -0
- package/src/cli/test.ts +397 -0
- package/src/cli/type-generator.ts +243 -0
- package/src/codemod/__tests__/forward.test.ts +239 -0
- package/src/codemod/__tests__/reverse.test.ts +145 -0
- package/src/codemod/__tests__/round-trip.test.ts +137 -0
- package/src/codemod/annotation.ts +97 -0
- package/src/codemod/classify.ts +197 -0
- package/src/codemod/cli.ts +207 -0
- package/src/codemod/control-flow.ts +409 -0
- package/src/codemod/forward.ts +244 -0
- package/src/codemod/import-manager.ts +171 -0
- package/src/codemod/index.ts +120 -0
- package/src/codemod/reverse.ts +197 -0
- package/src/codemod/rules.ts +174 -0
- package/src/codemod/state-transform.ts +126 -0
- package/src/decompiler/ast-builder.ts +538 -0
- package/src/decompiler/config-generator.ts +151 -0
- package/src/decompiler/index.ts +315 -0
- package/src/decompiler/project-decompiler.ts +1776 -0
- package/src/decompiler/project.ts +862 -0
- package/src/decompiler/split-strategy.ts +140 -0
- package/src/decompiler/state-emitter.ts +1053 -0
- package/src/decompiler/sx-emitter.ts +318 -0
- package/src/decompiler/workspace-hydrator.ts +189 -0
- package/src/dev-server.ts +238 -0
- package/src/envelope/fs-tree.ts +217 -0
- package/src/envelope/source-envelope.ts +264 -0
- package/src/envelope.ts +315 -0
- package/src/incremental-compiler.ts +401 -0
- package/src/index.ts +99 -0
- package/src/model-compiler.ts +277 -0
- package/src/project-compiler.ts +1629 -0
- package/src/route-extractor.ts +333 -0
- package/src/testing/index.ts +32 -0
- package/src/testing/snapshot.ts +252 -0
- package/src/testing/test-utils.ts +226 -0
- package/src/types.ts +68 -0
- package/src/vite/index.ts +288 -0
- package/test-compile.mjs +142 -0
- package/tsconfig.json +25 -0
- package/tsup.config.ts +23 -0
- package/vitest.config.ts +9 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mm.lock — Lock file management for installed workflow packages.
|
|
3
|
+
*
|
|
4
|
+
* Simple JSON lock file that tracks installed packages, versions, and modes.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
import { createHash } from 'crypto';
|
|
10
|
+
|
|
11
|
+
export interface LockEntry {
|
|
12
|
+
slug: string;
|
|
13
|
+
version: string;
|
|
14
|
+
installedAt: string;
|
|
15
|
+
mode: 'type-only' | 'full';
|
|
16
|
+
hash: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type LockData = Record<string, LockEntry>;
|
|
20
|
+
|
|
21
|
+
const LOCK_FILENAME = 'mm.lock';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Read the lock file from the given directory.
|
|
25
|
+
* Returns an empty object if the lock file doesn't exist.
|
|
26
|
+
*/
|
|
27
|
+
export function readLockFile(dir: string): LockData {
|
|
28
|
+
const lockPath = join(dir, LOCK_FILENAME);
|
|
29
|
+
if (!existsSync(lockPath)) {
|
|
30
|
+
return {};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
const content = readFileSync(lockPath, 'utf-8');
|
|
35
|
+
return JSON.parse(content) as LockData;
|
|
36
|
+
} catch {
|
|
37
|
+
// Corrupted lock file — start fresh
|
|
38
|
+
return {};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Write the lock file to the given directory.
|
|
44
|
+
*/
|
|
45
|
+
export function writeLockFile(dir: string, entries: LockData): void {
|
|
46
|
+
const lockPath = join(dir, LOCK_FILENAME);
|
|
47
|
+
|
|
48
|
+
// Sort keys for deterministic output
|
|
49
|
+
const sorted: LockData = {};
|
|
50
|
+
for (const key of Object.keys(entries).sort()) {
|
|
51
|
+
sorted[key] = entries[key];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
writeFileSync(lockPath, JSON.stringify(sorted, null, 2) + '\n', 'utf-8');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Add or update a lock entry.
|
|
59
|
+
*/
|
|
60
|
+
export function upsertLockEntry(
|
|
61
|
+
dir: string,
|
|
62
|
+
slug: string,
|
|
63
|
+
version: string,
|
|
64
|
+
mode: 'type-only' | 'full',
|
|
65
|
+
content: string,
|
|
66
|
+
): void {
|
|
67
|
+
const entries = readLockFile(dir);
|
|
68
|
+
entries[slug] = {
|
|
69
|
+
slug,
|
|
70
|
+
version,
|
|
71
|
+
installedAt: new Date().toISOString(),
|
|
72
|
+
mode,
|
|
73
|
+
hash: computeHash(content),
|
|
74
|
+
};
|
|
75
|
+
writeLockFile(dir, entries);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Remove a lock entry.
|
|
80
|
+
*/
|
|
81
|
+
export function removeLockEntry(dir: string, slug: string): boolean {
|
|
82
|
+
const entries = readLockFile(dir);
|
|
83
|
+
if (!(slug in entries)) return false;
|
|
84
|
+
delete entries[slug];
|
|
85
|
+
writeLockFile(dir, entries);
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Compute a content hash for change detection.
|
|
91
|
+
*/
|
|
92
|
+
export function computeHash(content: string): string {
|
|
93
|
+
return createHash('sha256').update(content).digest('hex').slice(0, 16);
|
|
94
|
+
}
|
package/src/cli/mmrc.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* mmrc — MindMatrix React Compiler CLI
|
|
4
|
+
*
|
|
5
|
+
* This is an alias entry point. The actual CLI logic lives in ./index.ts.
|
|
6
|
+
*
|
|
7
|
+
* Commands:
|
|
8
|
+
* mmrc dev Start dev server with hot reload
|
|
9
|
+
* mmrc build Compile workflow files to Pure Form IR
|
|
10
|
+
* mmrc test Run workflow test files
|
|
11
|
+
* mmrc deploy Compile + upload workflows to backend DB
|
|
12
|
+
* mmrc pull Fetch a definition from DB and scaffold local project
|
|
13
|
+
* mmrc install <slug> Install a workflow definition (type-only by default)
|
|
14
|
+
* mmrc install <slug> --full Install with full source code
|
|
15
|
+
* mmrc list List installed workflow packages
|
|
16
|
+
* mmrc update Update all installed packages
|
|
17
|
+
* mmrc remove <slug> Remove an installed package
|
|
18
|
+
* mmrc search <query> Search available definitions
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
// Re-export from main CLI entry point
|
|
22
|
+
import './index';
|
package/src/cli/pull.ts
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Pull Command — fetches a workflow definition from DB and scaffolds
|
|
3
|
+
* a local React framework project.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* mmrc pull <slug> --api-url http://... --token TOKEN --out ./my-project
|
|
7
|
+
*
|
|
8
|
+
* Pipeline:
|
|
9
|
+
* GET /api/v1/workflow/definitions?slug=<slug>
|
|
10
|
+
* → IRWorkflowDefinition
|
|
11
|
+
* → project-decompiler
|
|
12
|
+
* → local files (mm.config.ts, main.workflow.tsx, pages/, models/)
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { mkdirSync, writeFileSync } from 'fs';
|
|
16
|
+
import { join, dirname } from 'path';
|
|
17
|
+
import { decompileProjectEnhanced as decompileProject } from '../decompiler/project-decompiler';
|
|
18
|
+
import type { IRWorkflowDefinition } from '@mindmatrix/player-core';
|
|
19
|
+
|
|
20
|
+
export interface PullOptions {
|
|
21
|
+
slug: string;
|
|
22
|
+
apiUrl: string;
|
|
23
|
+
token: string;
|
|
24
|
+
outDir?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface PullResult {
|
|
28
|
+
slug: string;
|
|
29
|
+
filesWritten: string[];
|
|
30
|
+
outDir: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function pull(options: PullOptions): Promise<PullResult> {
|
|
34
|
+
const { slug, apiUrl, token } = options;
|
|
35
|
+
const outDir = options.outDir ?? slug;
|
|
36
|
+
|
|
37
|
+
console.log(`[mmrc pull] Fetching "${slug}" from ${apiUrl}...`);
|
|
38
|
+
|
|
39
|
+
// 1. Fetch the definition from the API
|
|
40
|
+
const ir = await fetchDefinition(apiUrl, token, slug);
|
|
41
|
+
if (!ir) {
|
|
42
|
+
throw new Error(`Definition "${slug}" not found`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
console.log(` Found: ${ir.name || ir.slug} (${ir.category || 'workflow'}, v${ir.version || '1.0.0'})`);
|
|
46
|
+
console.log(` Fields: ${ir.fields?.length ?? 0}, States: ${ir.states?.length ?? 0}, Transitions: ${ir.transitions?.length ?? 0}`);
|
|
47
|
+
|
|
48
|
+
// 2. Decompile to project files
|
|
49
|
+
const result = decompileProject(ir);
|
|
50
|
+
|
|
51
|
+
// 3. Write files to disk
|
|
52
|
+
mkdirSync(outDir, { recursive: true });
|
|
53
|
+
const filesWritten: string[] = [];
|
|
54
|
+
|
|
55
|
+
for (const file of result.files) {
|
|
56
|
+
const filePath = join(outDir, file.path);
|
|
57
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
58
|
+
writeFileSync(filePath, file.content, 'utf-8');
|
|
59
|
+
filesWritten.push(file.path);
|
|
60
|
+
console.log(` + ${file.path}`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
console.log(`\n[mmrc pull] Scaffolded ${filesWritten.length} files in ${outDir}/`);
|
|
64
|
+
console.log(` Entry: ${result.entryFile}`);
|
|
65
|
+
console.log(`\n Next steps:`);
|
|
66
|
+
console.log(` cd ${outDir}`);
|
|
67
|
+
console.log(` mmrc dev --src .`);
|
|
68
|
+
console.log(` # Edit files, then deploy back:`);
|
|
69
|
+
console.log(` mmrc deploy --src . --api-url ${apiUrl} --token <token>`);
|
|
70
|
+
|
|
71
|
+
return { slug, filesWritten, outDir };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// =============================================================================
|
|
75
|
+
// API fetch
|
|
76
|
+
// =============================================================================
|
|
77
|
+
|
|
78
|
+
async function fetchDefinition(
|
|
79
|
+
apiUrl: string,
|
|
80
|
+
token: string,
|
|
81
|
+
slug: string,
|
|
82
|
+
): Promise<IRWorkflowDefinition | null> {
|
|
83
|
+
// Try by slug first
|
|
84
|
+
const bySlug = await tryFetch(`${apiUrl}/workflow/definitions?slug=${encodeURIComponent(slug)}`, token);
|
|
85
|
+
if (bySlug) return bySlug;
|
|
86
|
+
|
|
87
|
+
// Try the definitions endpoint with search
|
|
88
|
+
const bySearch = await tryFetch(`${apiUrl}/workflow/catalog/search?q=${encodeURIComponent(slug)}`, token);
|
|
89
|
+
if (bySearch) return bySearch;
|
|
90
|
+
|
|
91
|
+
// Try modules endpoint (for category=module definitions)
|
|
92
|
+
const modulesRes = await fetch(`${apiUrl}/modules`, {
|
|
93
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
94
|
+
});
|
|
95
|
+
if (modulesRes.ok) {
|
|
96
|
+
const modules = await modulesRes.json() as any[];
|
|
97
|
+
const mod = modules.find((m: any) => m.module_id === slug || m.name?.toLowerCase() === slug.toLowerCase());
|
|
98
|
+
if (mod) {
|
|
99
|
+
// Re-fetch the full definition by ID
|
|
100
|
+
const fullRes = await fetch(`${apiUrl}/workflow/definitions/${mod.module_id}`, {
|
|
101
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
102
|
+
});
|
|
103
|
+
if (fullRes.ok) {
|
|
104
|
+
return normalizeApiResponse(await fullRes.json());
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function tryFetch(url: string, token: string): Promise<IRWorkflowDefinition | null> {
|
|
113
|
+
try {
|
|
114
|
+
const res = await fetch(url, {
|
|
115
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
116
|
+
});
|
|
117
|
+
if (!res.ok) return null;
|
|
118
|
+
|
|
119
|
+
const data = await res.json() as any;
|
|
120
|
+
|
|
121
|
+
// Handle array responses (search/list endpoints)
|
|
122
|
+
if (Array.isArray(data)) {
|
|
123
|
+
if (data.length === 0) return null;
|
|
124
|
+
return normalizeApiResponse(data[0]);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Handle paginated responses (items or data key)
|
|
128
|
+
const items = data.items ?? data.data;
|
|
129
|
+
if (items && Array.isArray(items)) {
|
|
130
|
+
if (items.length === 0) return null;
|
|
131
|
+
return normalizeApiResponse(items[0]);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Direct object
|
|
135
|
+
return normalizeApiResponse(data);
|
|
136
|
+
} catch {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Normalize API response to IRWorkflowDefinition shape.
|
|
143
|
+
* Backend uses `view` for experience tree, IR uses `metadata.experience`.
|
|
144
|
+
*/
|
|
145
|
+
function normalizeApiResponse(def: any): IRWorkflowDefinition {
|
|
146
|
+
const ir: any = {
|
|
147
|
+
slug: def.slug,
|
|
148
|
+
name: def.name,
|
|
149
|
+
version: def.version || '1.0.0',
|
|
150
|
+
description: def.description || '',
|
|
151
|
+
category: def.category || 'workflow',
|
|
152
|
+
fields: def.fields || [],
|
|
153
|
+
states: def.states || [],
|
|
154
|
+
transitions: def.transitions || [],
|
|
155
|
+
roles: def.roles || [],
|
|
156
|
+
on_event: def.on_event || [],
|
|
157
|
+
metadata: {
|
|
158
|
+
...(def.metadata || {}),
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// The experience tree may be in `view`, `experience`, or `metadata.experience`
|
|
163
|
+
// Must set ir.experience at top level — the decompiler checks definition.experience
|
|
164
|
+
const experience = def.view || def.experience || def.metadata?.experience;
|
|
165
|
+
if (experience) {
|
|
166
|
+
ir.experience = experience;
|
|
167
|
+
ir.metadata.experience = experience;
|
|
168
|
+
ir.view = experience;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return ir as IRWorkflowDefinition;
|
|
172
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry client — fetches workflow definitions from the MindMatrix API.
|
|
3
|
+
* Uses native fetch (Node 18+). No external dependencies.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface RegistryConfig {
|
|
7
|
+
apiUrl: string;
|
|
8
|
+
authToken?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface WorkflowDefinitionResponse {
|
|
12
|
+
id?: string;
|
|
13
|
+
slug: string;
|
|
14
|
+
name: string;
|
|
15
|
+
version: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
category: string;
|
|
18
|
+
fields: Array<{
|
|
19
|
+
name: string;
|
|
20
|
+
type: string;
|
|
21
|
+
typeVersion?: string;
|
|
22
|
+
baseType?: string;
|
|
23
|
+
label?: string;
|
|
24
|
+
required?: boolean;
|
|
25
|
+
default_value?: unknown;
|
|
26
|
+
computed?: string;
|
|
27
|
+
computed_deps?: string[];
|
|
28
|
+
validation?: {
|
|
29
|
+
enum?: string[];
|
|
30
|
+
min?: number;
|
|
31
|
+
max?: number;
|
|
32
|
+
pattern?: string;
|
|
33
|
+
};
|
|
34
|
+
}>;
|
|
35
|
+
states: Array<{
|
|
36
|
+
name: string;
|
|
37
|
+
type: string;
|
|
38
|
+
description?: string;
|
|
39
|
+
}>;
|
|
40
|
+
transitions: Array<{
|
|
41
|
+
name: string;
|
|
42
|
+
from: string[];
|
|
43
|
+
to: string;
|
|
44
|
+
description?: string;
|
|
45
|
+
roles?: string[];
|
|
46
|
+
auto?: boolean;
|
|
47
|
+
required_fields?: string[];
|
|
48
|
+
}>;
|
|
49
|
+
roles?: Array<{ name: string; description?: string }>;
|
|
50
|
+
metadata?: Record<string, unknown>;
|
|
51
|
+
experience?: unknown;
|
|
52
|
+
view?: unknown;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function buildHeaders(config: RegistryConfig): Record<string, string> {
|
|
56
|
+
const headers: Record<string, string> = {
|
|
57
|
+
'Content-Type': 'application/json',
|
|
58
|
+
};
|
|
59
|
+
if (config.authToken) {
|
|
60
|
+
headers['Authorization'] = `Bearer ${config.authToken}`;
|
|
61
|
+
}
|
|
62
|
+
return headers;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function extractDefinition(data: unknown): WorkflowDefinitionResponse | null {
|
|
66
|
+
if (!data || typeof data !== 'object') return null;
|
|
67
|
+
|
|
68
|
+
// Handle array responses
|
|
69
|
+
if (Array.isArray(data)) {
|
|
70
|
+
return data.length > 0 ? (data[0] as WorkflowDefinitionResponse) : null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const obj = data as Record<string, unknown>;
|
|
74
|
+
|
|
75
|
+
// Handle paginated responses
|
|
76
|
+
const items = obj.items ?? obj.data;
|
|
77
|
+
if (items && Array.isArray(items)) {
|
|
78
|
+
return items.length > 0 ? (items[0] as WorkflowDefinitionResponse) : null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Direct object — must have slug
|
|
82
|
+
if ('slug' in obj) {
|
|
83
|
+
return obj as unknown as WorkflowDefinitionResponse;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function extractDefinitions(data: unknown): WorkflowDefinitionResponse[] {
|
|
90
|
+
if (!data || typeof data !== 'object') return [];
|
|
91
|
+
|
|
92
|
+
if (Array.isArray(data)) {
|
|
93
|
+
return data as WorkflowDefinitionResponse[];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const obj = data as Record<string, unknown>;
|
|
97
|
+
const items = obj.items ?? obj.data;
|
|
98
|
+
if (items && Array.isArray(items)) {
|
|
99
|
+
return items as WorkflowDefinitionResponse[];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if ('slug' in obj) {
|
|
103
|
+
return [obj as unknown as WorkflowDefinitionResponse];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Fetch a single workflow definition by slug.
|
|
111
|
+
*/
|
|
112
|
+
export async function fetchDefinition(
|
|
113
|
+
slug: string,
|
|
114
|
+
config: RegistryConfig,
|
|
115
|
+
): Promise<WorkflowDefinitionResponse> {
|
|
116
|
+
const url = `${config.apiUrl}/workflow/definitions?slug=${encodeURIComponent(slug)}`;
|
|
117
|
+
|
|
118
|
+
let res: Response;
|
|
119
|
+
try {
|
|
120
|
+
res = await fetch(url, { headers: buildHeaders(config) });
|
|
121
|
+
} catch (err) {
|
|
122
|
+
throw new Error(
|
|
123
|
+
`Failed to connect to registry at ${config.apiUrl}. ` +
|
|
124
|
+
`Is the API server running? (${err instanceof Error ? err.message : String(err)})`,
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (!res.ok) {
|
|
129
|
+
if (res.status === 401) {
|
|
130
|
+
throw new Error('Authentication required. Provide --token or set MM_AUTH_TOKEN.');
|
|
131
|
+
}
|
|
132
|
+
if (res.status === 404) {
|
|
133
|
+
throw new Error(`Definition "${slug}" not found in registry.`);
|
|
134
|
+
}
|
|
135
|
+
throw new Error(`Registry returned ${res.status}: ${res.statusText}`);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const data = await res.json();
|
|
139
|
+
const def = extractDefinition(data);
|
|
140
|
+
if (!def) {
|
|
141
|
+
throw new Error(`Definition "${slug}" not found in registry.`);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return def;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Search definitions by query string.
|
|
149
|
+
*/
|
|
150
|
+
export async function searchDefinitions(
|
|
151
|
+
query: string,
|
|
152
|
+
config: RegistryConfig,
|
|
153
|
+
): Promise<WorkflowDefinitionResponse[]> {
|
|
154
|
+
const url = `${config.apiUrl}/workflow/catalog/definitions?search=${encodeURIComponent(query)}`;
|
|
155
|
+
|
|
156
|
+
let res: Response;
|
|
157
|
+
try {
|
|
158
|
+
res = await fetch(url, { headers: buildHeaders(config) });
|
|
159
|
+
} catch (err) {
|
|
160
|
+
throw new Error(
|
|
161
|
+
`Failed to connect to registry at ${config.apiUrl}. ` +
|
|
162
|
+
`Is the API server running? (${err instanceof Error ? err.message : String(err)})`,
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (!res.ok) {
|
|
167
|
+
if (res.status === 401) {
|
|
168
|
+
throw new Error('Authentication required. Provide --token or set MM_AUTH_TOKEN.');
|
|
169
|
+
}
|
|
170
|
+
throw new Error(`Registry returned ${res.status}: ${res.statusText}`);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const data = await res.json();
|
|
174
|
+
return extractDefinitions(data);
|
|
175
|
+
}
|