@multiplatform.one/cli 7.11.0 → 7.16.0

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 (163) hide show
  1. package/README.md +121 -111
  2. package/bin/createMultiplatformApp.mjs +39 -37
  3. package/lib/bin/multiplatformOne.mjs +65 -75
  4. package/lib/commands/addApp.mjs +78 -0
  5. package/lib/commands/adoptApp.mjs +11 -7
  6. package/lib/commands/doctypeTypes.mjs +148 -0
  7. package/lib/commands/e2e.mjs +2 -2
  8. package/lib/commands/init.mjs +142 -459
  9. package/lib/commands/merge.mjs +359 -0
  10. package/lib/commands/pieces.mjs +236 -0
  11. package/lib/commands/provenance.mjs +108 -0
  12. package/lib/commands/scaffold.mjs +105 -0
  13. package/lib/commands/updateApp.mjs +211 -528
  14. package/lib/source.json +5 -0
  15. package/lib/source.mjs +63 -0
  16. package/package.json +6 -6
  17. package/scripts/frappe-bootstrap.sh +29 -3
  18. package/scripts/frappe-dev.sh +1 -2
  19. package/scripts/frappe-helpers.sh +50 -2
  20. package/scripts/frappe.sh +5 -0
  21. package/scripts/scaffold.sh +937 -0
  22. package/scripts/stamp-source.mjs +51 -0
  23. package/scripts/stamp-source.spec.ts +86 -0
  24. package/src/bin/multiplatformOne.ts +116 -226
  25. package/src/commands/addApp.ts +102 -0
  26. package/src/commands/adoptApp.spec.ts +5 -1
  27. package/src/commands/adoptApp.ts +15 -10
  28. package/src/commands/doctypeTypes.spec.ts +155 -0
  29. package/src/commands/doctypeTypes.ts +214 -0
  30. package/src/commands/init.spec.ts +66 -0
  31. package/src/commands/init.ts +201 -643
  32. package/src/commands/merge.spec.ts +81 -0
  33. package/src/commands/merge.ts +411 -0
  34. package/src/commands/pieces.spec.ts +62 -0
  35. package/src/commands/pieces.ts +340 -0
  36. package/src/commands/provenance.spec.ts +92 -0
  37. package/src/commands/provenance.ts +169 -0
  38. package/src/commands/scaffold.ts +131 -0
  39. package/src/commands/updateApp.spec.ts +540 -331
  40. package/src/commands/updateApp.ts +255 -668
  41. package/src/source.spec.ts +45 -0
  42. package/src/source.ts +88 -0
  43. package/templates/AGENTS.md +161 -0
  44. package/templates/README.md +62 -0
  45. package/templates/pieces/frappe/universal/README.md.partial +7 -32
  46. package/templates/pieces/frappe/universal/env.example.partial +3 -3
  47. package/templates/pieces/frappe-bench/universal/README.md.partial +28 -0
  48. package/templates/pieces/{frappe → frappe-bench}/universal/docker/compose.frappe.yaml +2 -2
  49. package/templates/pieces/tauri/universal/README.md.partial +7 -5
  50. package/templates/pieces/tauri/universal/apps/__NAME__/src-tauri/src/dev.rs +463 -0
  51. package/templates/pieces/tauri/universal/apps/__NAME__/src-tauri/src/lib.rs +6 -0
  52. package/templates/pieces/tauri/universal/apps/__NAME__/src-tauri/tauri.conf.json +2 -1
  53. package/templates/pieces/webext/universal/apps/__NAME__/package.json.partial +1 -0
  54. package/templates/pieces/webext/universal/apps/__NAME__/vite.config.webext.ts +6 -2
  55. package/types/bin/multiplatformOne.d.ts.map +1 -1
  56. package/types/commands/addApp.d.ts +20 -0
  57. package/types/commands/addApp.d.ts.map +1 -0
  58. package/types/commands/adoptApp.d.ts +4 -3
  59. package/types/commands/adoptApp.d.ts.map +1 -1
  60. package/types/commands/doctypeTypes.d.ts +40 -0
  61. package/types/commands/doctypeTypes.d.ts.map +1 -0
  62. package/types/commands/init.d.ts +30 -13
  63. package/types/commands/init.d.ts.map +1 -1
  64. package/types/commands/merge.d.ts +54 -0
  65. package/types/commands/merge.d.ts.map +1 -0
  66. package/types/commands/pieces.d.ts +54 -0
  67. package/types/commands/pieces.d.ts.map +1 -0
  68. package/types/commands/provenance.d.ts +52 -0
  69. package/types/commands/provenance.d.ts.map +1 -0
  70. package/types/commands/scaffold.d.ts +43 -0
  71. package/types/commands/scaffold.d.ts.map +1 -0
  72. package/types/commands/updateApp.d.ts +19 -27
  73. package/types/commands/updateApp.d.ts.map +1 -1
  74. package/types/source.d.ts +35 -0
  75. package/types/source.d.ts.map +1 -0
  76. package/lib/commands/initApp.mjs +0 -431
  77. package/lib/generateVscode.mjs +0 -184
  78. package/scripts/clone.sh +0 -17
  79. package/scripts/update.sh +0 -46
  80. package/src/commands/initApp.spec.ts +0 -720
  81. package/src/commands/initApp.ts +0 -706
  82. package/src/generateVscode.ts +0 -238
  83. package/templates/app/AGENTS.md +0 -142
  84. package/templates/app/README.md +0 -62
  85. package/templates/app/apps/__NAME__/index.html +0 -36
  86. package/templates/app/apps/__NAME__/package.json +0 -31
  87. package/templates/app/apps/__NAME__/public/fonts/inter-400.woff2 +0 -0
  88. package/templates/app/apps/__NAME__/public/fonts/inter-700.woff2 +0 -0
  89. package/templates/app/apps/__NAME__/src/App.tsx +0 -9
  90. package/templates/app/apps/__NAME__/src/main.tsx +0 -14
  91. package/templates/app/apps/__NAME__/tsconfig.json +0 -8
  92. package/templates/app/apps/__NAME__/vite.config.ts +0 -17
  93. package/templates/app/features/__NAME__/package.json +0 -34
  94. package/templates/app/features/__NAME__/src/HomeScreen.tsx +0 -70
  95. package/templates/app/features/__NAME__/src/index.ts +0 -1
  96. package/templates/app/features/__NAME__/tsconfig.json +0 -5
  97. package/templates/app/gitignore +0 -9
  98. package/templates/app/npmrc +0 -2
  99. package/templates/app/oxlintrc.json +0 -39
  100. package/templates/app/package.json +0 -38
  101. package/templates/app/packages/config/config.json +0 -4
  102. package/templates/app/packages/config/index.ts +0 -5
  103. package/templates/app/packages/config/package.json +0 -17
  104. package/templates/app/packages/config/tsconfig.json +0 -5
  105. package/templates/app/pnpm-workspace.yaml +0 -4
  106. package/templates/app/tsconfig.base.json +0 -16
  107. package/templates/universal/AGENTS.md +0 -142
  108. package/templates/universal/README.md +0 -97
  109. package/templates/universal/apps/__NAME__/app.config.js +0 -31
  110. package/templates/universal/apps/__NAME__/config/tamagui.config.ts +0 -4
  111. package/templates/universal/apps/__NAME__/package.json +0 -62
  112. package/templates/universal/apps/__NAME__/polyfills.native.ts +0 -23
  113. package/templates/universal/apps/__NAME__/polyfills.ts +0 -3
  114. package/templates/universal/apps/__NAME__/public/fonts/inter-400.woff2 +0 -0
  115. package/templates/universal/apps/__NAME__/public/fonts/inter-700.woff2 +0 -0
  116. package/templates/universal/apps/__NAME__/routes/_layout.tsx +0 -22
  117. package/templates/universal/apps/__NAME__/routes/_layout.web.tsx +0 -21
  118. package/templates/universal/apps/__NAME__/routes/about.tsx +0 -3
  119. package/templates/universal/apps/__NAME__/routes/index.tsx +0 -3
  120. package/templates/universal/apps/__NAME__/src/app.ts +0 -10
  121. package/templates/universal/apps/__NAME__/tamagui.css +0 -3
  122. package/templates/universal/apps/__NAME__/tsconfig.json +0 -8
  123. package/templates/universal/apps/__NAME__/types.d.ts +0 -9
  124. package/templates/universal/apps/__NAME__/vite.config.ts +0 -20
  125. package/templates/universal/features/__NAME__/package.json +0 -35
  126. package/templates/universal/features/__NAME__/src/AboutScreen.tsx +0 -27
  127. package/templates/universal/features/__NAME__/src/AppLayout.tsx +0 -50
  128. package/templates/universal/features/__NAME__/src/ContactForm.spec.tsx +0 -22
  129. package/templates/universal/features/__NAME__/src/ContactForm.tsx +0 -55
  130. package/templates/universal/features/__NAME__/src/HomeScreen.tsx +0 -40
  131. package/templates/universal/features/__NAME__/src/index.ts +0 -4
  132. package/templates/universal/features/__NAME__/src/screens.spec.ts +0 -12
  133. package/templates/universal/features/__NAME__/tsconfig.json +0 -5
  134. package/templates/universal/features/__NAME__/vitest.config.mjs +0 -7
  135. package/templates/universal/gitignore +0 -14
  136. package/templates/universal/npmrc +0 -3
  137. package/templates/universal/oxlintrc.json +0 -39
  138. package/templates/universal/package.json +0 -51
  139. package/templates/universal/packages/config/config.json +0 -4
  140. package/templates/universal/packages/config/index.ts +0 -5
  141. package/templates/universal/packages/config/package.json +0 -17
  142. package/templates/universal/packages/config/tsconfig.json +0 -5
  143. package/templates/universal/packages/i18n/en/common.json +0 -30
  144. package/templates/universal/packages/i18n/es/common.json +0 -30
  145. package/templates/universal/packages/i18n/i18n.d.ts +0 -16
  146. package/templates/universal/packages/i18n/index.ts +0 -26
  147. package/templates/universal/packages/i18n/package.json +0 -20
  148. package/templates/universal/packages/i18n/resources.ts +0 -13
  149. package/templates/universal/packages/i18n/tsconfig.json +0 -5
  150. package/templates/universal/packages/themes/accent.ts +0 -32
  151. package/templates/universal/packages/themes/base.ts +0 -50
  152. package/templates/universal/packages/themes/fonts.ts +0 -8
  153. package/templates/universal/packages/themes/index.ts +0 -33
  154. package/templates/universal/packages/themes/package.json +0 -23
  155. package/templates/universal/packages/themes/tamagui.config.ts +0 -14
  156. package/templates/universal/packages/themes/tsconfig.json +0 -5
  157. package/templates/universal/pnpm-workspace.yaml +0 -4
  158. package/templates/universal/tsconfig.base.json +0 -21
  159. package/templates/universal/types/env.d.ts +0 -9
  160. package/types/commands/initApp.d.ts +0 -114
  161. package/types/commands/initApp.d.ts.map +0 -1
  162. package/types/generateVscode.d.ts +0 -7
  163. package/types/generateVscode.d.ts.map +0 -1
@@ -0,0 +1,108 @@
1
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { dirname, join, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ //#region src/commands/provenance.ts
6
+ const PROVENANCE_FILE = ".mpo.json";
7
+ function validateName(name) {
8
+ const trimmed = name.trim();
9
+ if (!trimmed) throw new Error("Project name is required");
10
+ if (!/^[a-z][a-z0-9-]*$/.test(trimmed)) throw new Error(`Invalid project name "${trimmed}". Use lowercase letters, numbers, and hyphens (e.g. my-app).`);
11
+ return trimmed;
12
+ }
13
+ /** Root package.json name with any @scope/ prefix stripped (adopt derives the project name from it). */
14
+ function packageJsonName(projectDir) {
15
+ try {
16
+ return JSON.parse(readFileSync(join(projectDir, "package.json"), "utf-8")).name?.replace(/^@[^/]+\//u, "");
17
+ } catch {
18
+ return;
19
+ }
20
+ }
21
+ function cliRoot() {
22
+ return resolve(dirname(fileURLToPath(import.meta.url)), "../..");
23
+ }
24
+ function cliVersion() {
25
+ try {
26
+ return JSON.parse(readFileSync(join(cliRoot(), "package.json"), "utf-8")).version;
27
+ } catch {
28
+ return;
29
+ }
30
+ }
31
+ /** `^x.y.z` for a bare version; explicit ranges pass through. */
32
+ function mpoRange(explicit, fallbackVersion = cliVersion()) {
33
+ if (explicit) return explicit.startsWith("^") || explicit.startsWith("~") || explicit === "*" ? explicit : `^${explicit}`;
34
+ return fallbackVersion ? `^${fallbackVersion}` : "^0.0.0";
35
+ }
36
+ function writeProvenance(targetDir, provenance) {
37
+ const pieces = [...provenance.pieces].sort();
38
+ const record = provenance.source ? {
39
+ cliVersion: provenance.cliVersion,
40
+ source: provenance.source,
41
+ apps: provenance.apps,
42
+ services: [...provenance.services].sort(),
43
+ pieces
44
+ } : {
45
+ template: provenance.template ?? "none",
46
+ cliVersion: provenance.cliVersion,
47
+ name: provenance.name,
48
+ mpoVersion: provenance.mpoVersion ?? `^${provenance.cliVersion}`,
49
+ pieces,
50
+ ...provenance.reconciled === false ? { reconciled: false } : {}
51
+ };
52
+ writeFileSync(join(targetDir, PROVENANCE_FILE), `${JSON.stringify(record, null, 2)}\n`);
53
+ }
54
+ /**
55
+ * Reads both shapes: the clone-derived record ({cliVersion, source, apps,
56
+ * services, pieces}) and the older {template, name} record written by
57
+ * `mpo adopt` and the retired template scaffolder.
58
+ */
59
+ function readProvenance(projectDir) {
60
+ const file = join(projectDir, PROVENANCE_FILE);
61
+ if (!existsSync(file)) return void 0;
62
+ let raw;
63
+ try {
64
+ raw = JSON.parse(readFileSync(file, "utf-8"));
65
+ } catch {
66
+ return;
67
+ }
68
+ if (typeof raw.cliVersion !== "string") return void 0;
69
+ const strings = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
70
+ const pieces = strings(raw.pieces).sort();
71
+ const source = raw.source;
72
+ if (source && typeof source.sha === "string") return {
73
+ cliVersion: raw.cliVersion,
74
+ source: {
75
+ sha: source.sha,
76
+ ...typeof source.url === "string" ? { url: source.url } : {}
77
+ },
78
+ apps: strings(raw.apps),
79
+ services: strings(raw.services).sort(),
80
+ pieces
81
+ };
82
+ const template = raw.template;
83
+ if (template !== "none" && template !== "universal" && template !== "app") {
84
+ if (Array.isArray(raw.apps)) return {
85
+ cliVersion: raw.cliVersion,
86
+ apps: strings(raw.apps),
87
+ services: strings(raw.services).sort(),
88
+ pieces,
89
+ template: "universal",
90
+ name: strings(raw.apps)[0]
91
+ };
92
+ return;
93
+ }
94
+ if (typeof raw.name !== "string") return void 0;
95
+ return {
96
+ cliVersion: raw.cliVersion,
97
+ apps: template === "none" ? [] : [raw.name],
98
+ services: [],
99
+ pieces,
100
+ template,
101
+ name: raw.name,
102
+ mpoVersion: typeof raw.mpoVersion === "string" ? raw.mpoVersion : `^${raw.cliVersion}`,
103
+ ...raw.reconciled === false ? { reconciled: false } : {}
104
+ };
105
+ }
106
+
107
+ //#endregion
108
+ export { PROVENANCE_FILE, cliRoot, cliVersion, mpoRange, packageJsonName, readProvenance, validateName, writeProvenance };
@@ -0,0 +1,105 @@
1
+ import { cliRoot, readProvenance } from "./provenance.mjs";
2
+ import { mkdtempSync, rmSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import spawn from "nano-spawn";
5
+ import { tmpdir } from "node:os";
6
+
7
+ //#region src/commands/scaffold.ts
8
+ /** The scaffold itself: POSIX sh, runs standalone. The TS commands only call it. */
9
+ function scaffoldScript() {
10
+ return join(cliRoot(), "scripts/scaffold.sh");
11
+ }
12
+ var ScaffoldError = class extends Error {
13
+ constructor(message, request) {
14
+ super(message);
15
+ this.request = request;
16
+ }
17
+ };
18
+ /** --into keeps every path the target already had; name them, since mpo update will not touch them. */
19
+ function reportKept(stdout) {
20
+ const prefix = "skipped (exists): ";
21
+ const kept = stdout.split("\n").filter((line) => line.startsWith(prefix)).map((line) => line.slice(18));
22
+ if (!kept.length) return;
23
+ console.log(`\nKept ${kept.length} path(s) already here, pinned in .updateignore:`);
24
+ for (const path of kept) console.log(` ${path}`);
25
+ }
26
+ /** Run scaffold.sh and return the provenance it wrote. */
27
+ async function runScaffold(request) {
28
+ const args = [scaffoldScript()];
29
+ for (const app of request.apps) args.push("--app", app);
30
+ for (const service of request.services) args.push("--service", service);
31
+ if (request.mpoVersion) args.push("--mpo-version", request.mpoVersion);
32
+ if (request.into) args.push("--into");
33
+ if (request.sourceUrl) args.push("--source-url", request.sourceUrl);
34
+ if (request.name) args.push("--name", request.name);
35
+ args.push("--", request.source, request.ref, request.target);
36
+ let stdout = "";
37
+ try {
38
+ stdout = (await spawn("sh", args, { stdio: request.verbose ? "inherit" : [
39
+ "ignore",
40
+ "pipe",
41
+ "pipe"
42
+ ] })).stdout;
43
+ } catch (err) {
44
+ throw new ScaffoldError(((err.stderr ?? "").trim().split("\n").filter(Boolean).pop() ?? err.message).replace(/^scaffold: /, ""), request);
45
+ }
46
+ if (request.into && !request.verbose) reportKept(stdout);
47
+ const provenance = readProvenance(request.target);
48
+ if (!provenance?.source) throw new ScaffoldError(`scaffold.sh wrote no provenance into ${request.target}`, request);
49
+ return provenance;
50
+ }
51
+ /** A scaffold in a temp dir (merge baselines). */
52
+ async function scaffoldToTemp(request) {
53
+ const parent = mkdtempSync(join(tmpdir(), "mpo-scaffold-"));
54
+ const dir = join(parent, "project");
55
+ const cleanup = () => rmSync(parent, {
56
+ recursive: true,
57
+ force: true
58
+ });
59
+ try {
60
+ return {
61
+ dir,
62
+ provenance: await runScaffold({
63
+ ...request,
64
+ target: dir
65
+ }),
66
+ cleanup
67
+ };
68
+ } catch (err) {
69
+ cleanup();
70
+ throw err;
71
+ }
72
+ }
73
+ /**
74
+ * One subtree of the monorepo at a ref, extracted into `dest` (the piece
75
+ * templates of an older CLI version, for adopted-project merge bases).
76
+ */
77
+ async function archiveSubtree(source, ref, subtree, dest) {
78
+ await spawn("sh", [
79
+ "-c",
80
+ [
81
+ "set -eu",
82
+ "SOURCE=\"$1\"; REF=\"$2\"; SUBTREE=\"$3\"; DEST=\"$4\"",
83
+ "if [ -d \"$SOURCE\" ]; then REPO=\"$SOURCE\"; else",
84
+ " REPO=\"$(mktemp -d \"${TMPDIR:-/tmp}/mpo-archive.XXXXXX\")\"",
85
+ " trap 'rm -rf \"$REPO\"' EXIT",
86
+ " git clone -q --depth 1 --no-checkout --branch \"$REF\" \"$SOURCE\" \"$REPO\"",
87
+ " REF=HEAD",
88
+ "fi",
89
+ "mkdir -p \"$DEST\"",
90
+ "git -C \"$REPO\" archive --format=tar \"$REF\" \"$SUBTREE\" | tar -xf - -C \"$DEST\""
91
+ ].join("\n"),
92
+ "sh",
93
+ source,
94
+ ref,
95
+ subtree,
96
+ dest
97
+ ], { stdio: [
98
+ "ignore",
99
+ "ignore",
100
+ "pipe"
101
+ ] });
102
+ }
103
+
104
+ //#endregion
105
+ export { ScaffoldError, archiveSubtree, runScaffold, scaffoldScript, scaffoldToTemp };