@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.
Files changed (314) hide show
  1. package/README.md +107 -0
  2. package/compile-blueprint-chat.mjs +99 -0
  3. package/compile-blueprint-glass-console.mjs +98 -0
  4. package/compile-chat-defs.mjs +92 -0
  5. package/dist/babel/index.d.mts +3 -0
  6. package/dist/babel/index.d.ts +3 -0
  7. package/dist/babel/index.js +4851 -0
  8. package/dist/babel/index.mjs +7 -0
  9. package/dist/chunk-26U577GB.mjs +3465 -0
  10. package/dist/chunk-2FBDFAX6.mjs +2362 -0
  11. package/dist/chunk-2L4QSMXG.mjs +175 -0
  12. package/dist/chunk-2REDFOER.mjs +931 -0
  13. package/dist/chunk-46YKSHQR.mjs +175 -0
  14. package/dist/chunk-4XHK6FWL.mjs +2058 -0
  15. package/dist/chunk-5M7DKKBC.mjs +215 -0
  16. package/dist/chunk-5VNJ7C6N.mjs +154 -0
  17. package/dist/chunk-6CQOAAMV.mjs +1803 -0
  18. package/dist/chunk-6SEVAAVT.mjs +3516 -0
  19. package/dist/chunk-6YLR5ZDA.mjs +2829 -0
  20. package/dist/chunk-AOGY2GK6.mjs +3292 -0
  21. package/dist/chunk-AXXUXRNA.mjs +1434 -0
  22. package/dist/chunk-CHLVKMQW.mjs +175 -0
  23. package/dist/chunk-CKGOZAB7.mjs +939 -0
  24. package/dist/chunk-D34RAZUX.mjs +2223 -0
  25. package/dist/chunk-EQGA6A6D.mjs +121 -0
  26. package/dist/chunk-EY2CSXYA.mjs +822 -0
  27. package/dist/chunk-FIQ65CDR.mjs +925 -0
  28. package/dist/chunk-FOZXJFAR.mjs +186 -0
  29. package/dist/chunk-FX6URXWN.mjs +186 -0
  30. package/dist/chunk-G7SMOWOL.mjs +828 -0
  31. package/dist/chunk-GGB4G5YY.mjs +175 -0
  32. package/dist/chunk-HLRGCCIL.mjs +4839 -0
  33. package/dist/chunk-HOIUP6IF.mjs +690 -0
  34. package/dist/chunk-I3AU7GRD.mjs +120 -0
  35. package/dist/chunk-ILFGMUVD.mjs +1933 -0
  36. package/dist/chunk-IPTX5MJU.mjs +3223 -0
  37. package/dist/chunk-ITGUSH2Z.mjs +2783 -0
  38. package/dist/chunk-IXHBCAMF.mjs +3306 -0
  39. package/dist/chunk-J7TWJ3TM.mjs +2784 -0
  40. package/dist/chunk-JDPLDGVF.mjs +4810 -0
  41. package/dist/chunk-K53XP2DL.mjs +148 -0
  42. package/dist/chunk-K5HX2SVL.mjs +1902 -0
  43. package/dist/chunk-KFGYOOVS.mjs +214 -0
  44. package/dist/chunk-KFVVOS5N.mjs +925 -0
  45. package/dist/chunk-L2OZ4CDV.mjs +113 -0
  46. package/dist/chunk-MIZV3TAN.mjs +3293 -0
  47. package/dist/chunk-NKKLQE5V.mjs +148 -0
  48. package/dist/chunk-NOW23XFZ.mjs +186 -0
  49. package/dist/chunk-NRXQKQ74.mjs +148 -0
  50. package/dist/chunk-OWI6XWCD.mjs +3375 -0
  51. package/dist/chunk-PRUMNNDI.mjs +3192 -0
  52. package/dist/chunk-QTBD5B3F.mjs +148 -0
  53. package/dist/chunk-SKSDPPNT.mjs +3788 -0
  54. package/dist/chunk-SP2YUS33.mjs +186 -0
  55. package/dist/chunk-SU4E6E7B.mjs +3153 -0
  56. package/dist/chunk-SYUUKW5A.mjs +3379 -0
  57. package/dist/chunk-UL2XZEMA.mjs +3128 -0
  58. package/dist/chunk-XMWUHQVV.mjs +939 -0
  59. package/dist/chunk-XZNEDRGN.mjs +3876 -0
  60. package/dist/chunk-Y6FXYEAI.mjs +10 -0
  61. package/dist/chunk-YFS6JMYO.mjs +3342 -0
  62. package/dist/chunk-Z6AIQ4KL.mjs +113 -0
  63. package/dist/cli/index.d.mts +1 -0
  64. package/dist/cli/index.d.ts +1 -0
  65. package/dist/cli/index.js +11585 -0
  66. package/dist/cli/index.mjs +701 -0
  67. package/dist/codemod/cli.d.mts +1 -0
  68. package/dist/codemod/cli.d.ts +1 -0
  69. package/dist/codemod/cli.js +1104 -0
  70. package/dist/codemod/cli.mjs +157 -0
  71. package/dist/codemod/index.d.mts +148 -0
  72. package/dist/codemod/index.d.ts +148 -0
  73. package/dist/codemod/index.js +981 -0
  74. package/dist/codemod/index.mjs +25 -0
  75. package/dist/dev-server-Bs_sz2DG.d.mts +111 -0
  76. package/dist/dev-server-Bs_sz2DG.d.ts +111 -0
  77. package/dist/dev-server-CjoufJ-u.d.mts +109 -0
  78. package/dist/dev-server-CjoufJ-u.d.ts +109 -0
  79. package/dist/dev-server.d.mts +3 -0
  80. package/dist/dev-server.d.ts +3 -0
  81. package/dist/dev-server.js +7603 -0
  82. package/dist/dev-server.mjs +11 -0
  83. package/dist/envelope-DD7v0v6E.d.mts +265 -0
  84. package/dist/envelope-DD7v0v6E.d.ts +265 -0
  85. package/dist/envelope-vCVjrHlo.d.mts +265 -0
  86. package/dist/envelope-vCVjrHlo.d.ts +265 -0
  87. package/dist/envelope.d.mts +2 -0
  88. package/dist/envelope.d.ts +2 -0
  89. package/dist/envelope.js +5184 -0
  90. package/dist/envelope.mjs +9 -0
  91. package/dist/index-B5gSgvnd.d.mts +44 -0
  92. package/dist/index-B5gSgvnd.d.ts +44 -0
  93. package/dist/index-Bs0MnR54.d.mts +103 -0
  94. package/dist/index-Bs0MnR54.d.ts +103 -0
  95. package/dist/index-DR0nNc_f.d.mts +101 -0
  96. package/dist/index-DR0nNc_f.d.ts +101 -0
  97. package/dist/index-revho_gS.d.mts +104 -0
  98. package/dist/index-revho_gS.d.ts +104 -0
  99. package/dist/index.d.mts +1099 -0
  100. package/dist/index.d.ts +1099 -0
  101. package/dist/index.js +10162 -0
  102. package/dist/index.mjs +372 -0
  103. package/dist/init-IXEE2RCF.mjs +340 -0
  104. package/dist/project-compiler-EGJUTAJU.mjs +10 -0
  105. package/dist/project-compiler-VFR6CSDX.mjs +10 -0
  106. package/dist/project-decompiler-5GY2KSG4.mjs +7 -0
  107. package/dist/pull-A2QUHW4K.mjs +109 -0
  108. package/dist/pull-JBEQWVPE.mjs +109 -0
  109. package/dist/testing/index.d.mts +211 -0
  110. package/dist/testing/index.d.ts +211 -0
  111. package/dist/testing/index.js +5106 -0
  112. package/dist/testing/index.mjs +247 -0
  113. package/dist/vite/index.d.mts +59 -0
  114. package/dist/vite/index.d.ts +59 -0
  115. package/dist/vite/index.js +5023 -0
  116. package/dist/vite/index.mjs +8 -0
  117. package/examples/README.md +72 -0
  118. package/examples/authentication/main.workflow.tsx +139 -0
  119. package/examples/authentication/mm.config.ts +22 -0
  120. package/examples/authentication/models/auth.ts +45 -0
  121. package/examples/authentication/pages/LoginPage.tsx +79 -0
  122. package/examples/authentication/pages/SignupPage.tsx +87 -0
  123. package/examples/counter.workflow.tsx +65 -0
  124. package/examples/dashboard.workflow.tsx +419 -0
  125. package/examples/invoice-approval/actions/invoice.server.ts +72 -0
  126. package/examples/invoice-approval/main.workflow.tsx +168 -0
  127. package/examples/invoice-approval/mm.config.ts +18 -0
  128. package/examples/invoice-approval/models/invoice.ts +46 -0
  129. package/examples/invoice-approval/pages/InvoiceDetailPage.tsx +175 -0
  130. package/examples/invoice-approval/pages/InvoiceFormPage.tsx +198 -0
  131. package/examples/invoice-approval/pages/InvoiceListPage.tsx +141 -0
  132. package/examples/todo-app.workflow.tsx +131 -0
  133. package/examples/uber-app/actions/matching.server.ts +177 -0
  134. package/examples/uber-app/actions/notifications.server.ts +176 -0
  135. package/examples/uber-app/actions/payments.server.ts +184 -0
  136. package/examples/uber-app/actions/pricing.server.ts +176 -0
  137. package/examples/uber-app/app/admin/analytics.tsx +102 -0
  138. package/examples/uber-app/app/admin/fleet.tsx +102 -0
  139. package/examples/uber-app/app/admin/surge-pricing.tsx +95 -0
  140. package/examples/uber-app/app/driver/dashboard.tsx +87 -0
  141. package/examples/uber-app/app/driver/earnings.tsx +101 -0
  142. package/examples/uber-app/app/driver/navigation.tsx +94 -0
  143. package/examples/uber-app/app/driver/ride-acceptance.tsx +103 -0
  144. package/examples/uber-app/app/rider/home.tsx +109 -0
  145. package/examples/uber-app/app/rider/payment-methods.tsx +134 -0
  146. package/examples/uber-app/app/rider/ride-history.tsx +90 -0
  147. package/examples/uber-app/app/rider/ride-tracking.tsx +108 -0
  148. package/examples/uber-app/components/DriverCard.tsx +176 -0
  149. package/examples/uber-app/components/MapView.tsx +216 -0
  150. package/examples/uber-app/components/RatingStars.tsx +227 -0
  151. package/examples/uber-app/components/RideCard.tsx +167 -0
  152. package/examples/uber-app/mm.config.ts +30 -0
  153. package/examples/uber-app/models/location.model.ts +70 -0
  154. package/examples/uber-app/models/payment.model.ts +87 -0
  155. package/examples/uber-app/models/rating.model.ts +54 -0
  156. package/examples/uber-app/models/ride.model.ts +118 -0
  157. package/examples/uber-app/models/user.model.ts +66 -0
  158. package/examples/uber-app/models/vehicle.model.ts +63 -0
  159. package/examples/uber-app/tests/payment.test.tsx +129 -0
  160. package/examples/uber-app/tests/ride-flow.test.tsx +123 -0
  161. package/examples/uber-app/workflows/dispute-resolution.workflow.tsx +205 -0
  162. package/examples/uber-app/workflows/driver-onboarding.workflow.tsx +227 -0
  163. package/examples/uber-app/workflows/payment-processing.workflow.tsx +223 -0
  164. package/examples/uber-app/workflows/ride-request.workflow.tsx +194 -0
  165. package/package.json +77 -0
  166. package/package.json.backup +86 -0
  167. package/scripts/decompile.ts +226 -0
  168. package/scripts/seed-auth.ts +267 -0
  169. package/scripts/seed-uber.ts +248 -0
  170. package/scripts/validate-uber.ts +119 -0
  171. package/seed-blueprint-chat.mjs +444 -0
  172. package/seed-blueprint-glass-console.mjs +445 -0
  173. package/seed-compiled.mjs +318 -0
  174. package/src/RoundTripValidator.ts +400 -0
  175. package/src/__tests__/atom-rendering-coverage.test.ts +680 -0
  176. package/src/__tests__/auth-module-compilation.test.ts +247 -0
  177. package/src/__tests__/auth-template-compilation.test.ts +589 -0
  178. package/src/__tests__/change-extractor.test.ts +142 -0
  179. package/src/__tests__/cli-pull.test.ts +73 -0
  180. package/src/__tests__/cli-test.test.ts +72 -0
  181. package/src/__tests__/component-extractor.test.ts +331 -0
  182. package/src/__tests__/context-extractor.test.ts +145 -0
  183. package/src/__tests__/decompiler.test.ts +718 -0
  184. package/src/__tests__/define-blueprint.test.ts +133 -0
  185. package/src/__tests__/definition-validator.test.ts +519 -0
  186. package/src/__tests__/during-extractor.test.ts +152 -0
  187. package/src/__tests__/effect-extractor.test.ts +107 -0
  188. package/src/__tests__/event-emission.test.ts +127 -0
  189. package/src/__tests__/examples.test.ts +236 -0
  190. package/src/__tests__/full-blueprint-coverage.test.ts +1221 -0
  191. package/src/__tests__/golden-suite.test.ts +403 -0
  192. package/src/__tests__/grammar-island-extractor.test.ts +289 -0
  193. package/src/__tests__/instance-key.test.ts +82 -0
  194. package/src/__tests__/ir-migration.test.ts +255 -0
  195. package/src/__tests__/lock-file.test.ts +117 -0
  196. package/src/__tests__/model-extractor.test.ts +195 -0
  197. package/src/__tests__/model-field-acl.test.ts +237 -0
  198. package/src/__tests__/model-hooks.test.ts +130 -0
  199. package/src/__tests__/model-ref-resolution.test.ts +268 -0
  200. package/src/__tests__/model-roundtrip.test.ts +502 -0
  201. package/src/__tests__/model-runtime.test.ts +112 -0
  202. package/src/__tests__/model-transitions.test.ts +183 -0
  203. package/src/__tests__/nrt-action-trace.test.ts +391 -0
  204. package/src/__tests__/pipeline-hardening.test.ts +413 -0
  205. package/src/__tests__/project-compiler.test.ts +546 -0
  206. package/src/__tests__/project-decompiler.test.ts +343 -0
  207. package/src/__tests__/query-compilation.test.ts +145 -0
  208. package/src/__tests__/round-trip/PLAN.md +158 -0
  209. package/src/__tests__/round-trip/README.md +52 -0
  210. package/src/__tests__/round-trip/RESULTS.md +86 -0
  211. package/src/__tests__/round-trip/fixtures/data-heavy/main.workflow.tsx +55 -0
  212. package/src/__tests__/round-trip/fixtures/data-heavy/mm.config.ts +11 -0
  213. package/src/__tests__/round-trip/fixtures/data-heavy/models/contact.ts +54 -0
  214. package/src/__tests__/round-trip/fixtures/full-workflow/main.workflow.tsx +79 -0
  215. package/src/__tests__/round-trip/fixtures/full-workflow/mm.config.ts +12 -0
  216. package/src/__tests__/round-trip/fixtures/full-workflow/models/order.ts +50 -0
  217. package/src/__tests__/round-trip/fixtures/simple-crud/main.workflow.tsx +25 -0
  218. package/src/__tests__/round-trip/fixtures/simple-crud/mm.config.ts +11 -0
  219. package/src/__tests__/round-trip/fixtures/simple-crud/models/task.ts +32 -0
  220. package/src/__tests__/round-trip/fixtures/view-heavy/main.workflow.tsx +79 -0
  221. package/src/__tests__/round-trip/fixtures/view-heavy/mm.config.ts +10 -0
  222. package/src/__tests__/round-trip/round-trip.test.ts +2598 -0
  223. package/src/__tests__/round-trip-ir.test.ts +300 -0
  224. package/src/__tests__/round-trip.test.ts +1212 -0
  225. package/src/__tests__/route-merging.test.ts +372 -0
  226. package/src/__tests__/router-composition.test.ts +489 -0
  227. package/src/__tests__/router-extractor.test.ts +176 -0
  228. package/src/__tests__/server-action-extractor.test.ts +128 -0
  229. package/src/__tests__/smart-type-inference.test.ts +365 -0
  230. package/src/__tests__/source-envelope.test.ts +284 -0
  231. package/src/__tests__/source-fidelity.test.ts +516 -0
  232. package/src/__tests__/state-extractor.test.ts +115 -0
  233. package/src/__tests__/strict-mode.test.ts +227 -0
  234. package/src/__tests__/transition-effect-extractor.test.ts +119 -0
  235. package/src/__tests__/transition-extractor.test.ts +68 -0
  236. package/src/__tests__/ts-to-expression.test.ts +462 -0
  237. package/src/__tests__/type-generator.test.ts +201 -0
  238. package/src/__tests__/uber-validation.test.ts +502 -0
  239. package/src/action-compiler.ts +361 -0
  240. package/src/babel/emitters/experience-transform.ts +199 -0
  241. package/src/babel/emitters/ir-to-tsx-emitter.ts +110 -0
  242. package/src/babel/emitters/pure-form-emitter.ts +1023 -0
  243. package/src/babel/emitters/runtime-glue-emitter.ts +39 -0
  244. package/src/babel/extractors/change-extractor.ts +199 -0
  245. package/src/babel/extractors/component-extractor.ts +907 -0
  246. package/src/babel/extractors/computed-extractor.ts +262 -0
  247. package/src/babel/extractors/context-extractor.ts +277 -0
  248. package/src/babel/extractors/during-extractor.ts +295 -0
  249. package/src/babel/extractors/effect-extractor.ts +340 -0
  250. package/src/babel/extractors/event-extractor.ts +235 -0
  251. package/src/babel/extractors/grammar-island-extractor.ts +302 -0
  252. package/src/babel/extractors/model-extractor.ts +1018 -0
  253. package/src/babel/extractors/router-extractor.ts +303 -0
  254. package/src/babel/extractors/server-action-extractor.ts +173 -0
  255. package/src/babel/extractors/server-action-hook-extractor.ts +72 -0
  256. package/src/babel/extractors/server-state-extractor.ts +88 -0
  257. package/src/babel/extractors/state-extractor.ts +214 -0
  258. package/src/babel/extractors/transition-effect-extractor.ts +176 -0
  259. package/src/babel/extractors/transition-extractor.ts +143 -0
  260. package/src/babel/index.ts +24 -0
  261. package/src/babel/transpilers/ts-to-expression.ts +674 -0
  262. package/src/babel/visitor.ts +807 -0
  263. package/src/cli/auth.ts +255 -0
  264. package/src/cli/build.ts +288 -0
  265. package/src/cli/deploy.ts +206 -0
  266. package/src/cli/index.ts +328 -0
  267. package/src/cli/init.ts +388 -0
  268. package/src/cli/installer.ts +261 -0
  269. package/src/cli/lock-file.ts +94 -0
  270. package/src/cli/mmrc.ts +22 -0
  271. package/src/cli/pull.ts +172 -0
  272. package/src/cli/registry-client.ts +175 -0
  273. package/src/cli/test.ts +397 -0
  274. package/src/cli/type-generator.ts +243 -0
  275. package/src/codemod/__tests__/forward.test.ts +239 -0
  276. package/src/codemod/__tests__/reverse.test.ts +145 -0
  277. package/src/codemod/__tests__/round-trip.test.ts +137 -0
  278. package/src/codemod/annotation.ts +97 -0
  279. package/src/codemod/classify.ts +197 -0
  280. package/src/codemod/cli.ts +207 -0
  281. package/src/codemod/control-flow.ts +409 -0
  282. package/src/codemod/forward.ts +244 -0
  283. package/src/codemod/import-manager.ts +171 -0
  284. package/src/codemod/index.ts +120 -0
  285. package/src/codemod/reverse.ts +197 -0
  286. package/src/codemod/rules.ts +174 -0
  287. package/src/codemod/state-transform.ts +126 -0
  288. package/src/decompiler/ast-builder.ts +538 -0
  289. package/src/decompiler/config-generator.ts +151 -0
  290. package/src/decompiler/index.ts +315 -0
  291. package/src/decompiler/project-decompiler.ts +1776 -0
  292. package/src/decompiler/project.ts +862 -0
  293. package/src/decompiler/split-strategy.ts +140 -0
  294. package/src/decompiler/state-emitter.ts +1053 -0
  295. package/src/decompiler/sx-emitter.ts +318 -0
  296. package/src/decompiler/workspace-hydrator.ts +189 -0
  297. package/src/dev-server.ts +238 -0
  298. package/src/envelope/fs-tree.ts +217 -0
  299. package/src/envelope/source-envelope.ts +264 -0
  300. package/src/envelope.ts +315 -0
  301. package/src/incremental-compiler.ts +401 -0
  302. package/src/index.ts +99 -0
  303. package/src/model-compiler.ts +277 -0
  304. package/src/project-compiler.ts +1629 -0
  305. package/src/route-extractor.ts +333 -0
  306. package/src/testing/index.ts +32 -0
  307. package/src/testing/snapshot.ts +252 -0
  308. package/src/testing/test-utils.ts +226 -0
  309. package/src/types.ts +68 -0
  310. package/src/vite/index.ts +288 -0
  311. package/test-compile.mjs +142 -0
  312. package/tsconfig.json +25 -0
  313. package/tsup.config.ts +23 -0
  314. 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
+ }
@@ -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';
@@ -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
+ }