marvelous-ui-library 1.0.0 → 1.0.2

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 CHANGED
@@ -7,9 +7,9 @@ npx marvelous-ui-library@latest init
7
7
  npx marvelous-ui-library@latest add dialog tabs toast
8
8
  ```
9
9
 
10
- `init` detects the project and supported agent configuration. In an interactive terminal it asks whether to install the Pack in this project or in your user profile, then asks for Free or Pro. For automation, use `--scope project|user --edition free|pro`. A noninteractive invocation defaults to Free in the current project.
10
+ `init` detects the project and supported agent configuration. In an interactive terminal it asks whether to install the Pack in this project or in your user profile. Enter a Polar license key in the hidden prompt for Pro, or press Enter for Free. User setup then asks which agents to connect and registers Codex and Claude Code directly. For automation, set `MARVELOUS_LICENSE_KEY` for Pro and use `--scope user --clients codex,claude` to choose agents; `--clients none` installs only the shared Pack. Rerunning user setup removes a previously selected plugin when you deselect that agent. A noninteractive invocation without a key defaults to Free in the current project. `--edition free|pro` remains available for existing scripts. Other agents can use project setup or the manual instructions in the Pack's `docs/MCP.md`.
11
11
 
12
- The Pro Pack requires a Polar license key. Enter it when prompted or pass it through the `MARVELOUS_LICENSE_KEY` environment variable. The key is not written to a project file. A project Pack remains at its installed version until you run:
12
+ The Pro Pack requires a Polar license key for the first download and for newer releases. A supplied invalid key causes an error. The key is not written to a project file. A project Pack remains at its installed version until you run:
13
13
 
14
14
  ```bash
15
15
  npx marvelous-ui-library@latest update
@@ -17,4 +17,12 @@ npx marvelous-ui-library@latest update
17
17
 
18
18
  `update` compares installed component hashes before replacing files. Locally customized files are reported and preserved. A Pack installed in your user profile does not change copies already installed in other projects. A current Pro license key, including a key from an active yearly Renewal, is required to fetch a newer Pro Pack. For a private Renewal link, contact hello@marvelous-ui.com.
19
19
 
20
+ Every verified Pro ZIP is saved under `~/.marvelous-ui/archives`, including when the Pack is installed in a project. Keep a backup of this folder if you want to preserve your downloaded releases. To restore a saved release without contacting Polar or the download service:
21
+
22
+ ```bash
23
+ npx marvelous-ui-library@latest restore --version 1.0.0
24
+ ```
25
+
26
+ Run `restore` without `--version` in an interactive terminal to choose from the saved releases. Use `--scope project|user` to choose the target. Restoration compares managed component hashes and preserves customized files. A saved release remains usable after the key expires; fetching a release that was never saved still requires an active key.
27
+
20
28
  The Free Pack is MIT licensed. The Pro Pack is subject to the commercial license shipped in its `LICENSE.md`.
package/bin.mjs CHANGED
@@ -3,19 +3,22 @@ import { execFileSync } from "node:child_process";
3
3
  import { existsSync } from "node:fs";
4
4
  import { join, resolve } from "node:path";
5
5
  import { createInterface } from "node:readline/promises";
6
- import { locations, readState, latestRelease, downloadRelease, installPack, addComponents, detectFramework } from "./lib/installer.mjs";
6
+ import { Writable } from "node:stream";
7
+ import { locations, readState, latestRelease, downloadRelease, installPack, addComponents, detectFramework, listProArchives, readProArchive } from "./lib/installer.mjs";
8
+ import { checkUserAgents, configureUserAgents, parseUserAgents, readUserAgents } from "./lib/agents.mjs";
7
9
 
8
10
  const HELP = `Marvelous UI
9
11
 
10
- npx marvelous-ui-library@latest init [--scope project|user] [--edition free|pro]
12
+ npx marvelous-ui-library@latest init [--scope project|user]
11
13
  npx marvelous-ui-library@latest add <component...> [--scope project|user] [--out path]
12
14
  npx marvelous-ui-library@latest update [--scope project|user]
15
+ npx marvelous-ui-library@latest restore [--scope project|user] [--version 1.1.0]
13
16
 
14
- Options: --project path, --clients names. For Pro, set MARVELOUS_LICENSE_KEY or enter the Polar key when prompted.
17
+ Options: --project path, --clients names. User setup supports codex,claude,none. At init, press Enter for Free or enter a Polar key for Pro. In automation, set MARVELOUS_LICENSE_KEY for Pro.
15
18
  `;
16
19
 
17
20
  function options(args) {
18
- const values = new Set(["scope", "edition", "project", "out", "clients"]);
21
+ const values = new Set(["scope", "edition", "project", "out", "clients", "version"]);
19
22
  const parsed = { slugs: [] };
20
23
  for (let i = 0; i < args.length; i++) {
21
24
  const arg = args[i];
@@ -36,12 +39,21 @@ async function ask(question, fallback = "") {
36
39
  finally { rl.close(); }
37
40
  }
38
41
 
42
+ async function askSecret(question) {
43
+ if (!process.stdin.isTTY) return "";
44
+ const muted = new Writable({ write(_chunk, _encoding, done) { done(); } });
45
+ const rl = createInterface({ input: process.stdin, output: muted, terminal: true });
46
+ process.stdout.write(question);
47
+ try { return (await rl.question("")).trim(); }
48
+ finally { rl.close(); process.stdout.write("\n"); }
49
+ }
50
+
39
51
  function existingScope(project) {
40
52
  return readState(locations("project", project).state) ? "project" : readState(locations("user", project).state) ? "user" : null;
41
53
  }
42
54
 
43
55
  async function licenseKey() {
44
- const key = process.env.MARVELOUS_LICENSE_KEY?.trim() || await ask("Polar license key: ");
56
+ const key = process.env.MARVELOUS_LICENSE_KEY?.trim() || await askSecret("Polar license key: ");
45
57
  if (!key) throw new Error("A Pro license key is required. Set MARVELOUS_LICENSE_KEY or run interactively.");
46
58
  return key;
47
59
  }
@@ -58,33 +70,110 @@ function chosenOut(project, supplied, componentState) {
58
70
  }
59
71
 
60
72
  function pluginRefresh(place) {
61
- console.log("If your agent installed a copy of the plugin, register the updated Pack again:");
62
- execFileSync(process.execPath, [join(place.pack, "scripts", "init-agent.mjs"), "--plugin"], { stdio: "inherit" });
73
+ if (place.scope !== "user") return;
74
+ const agents = readUserAgents(place);
75
+ if (agents.length) {
76
+ const names = configureUserAgents(place, agents);
77
+ console.log(`Updated agent plugins: ${names.join(", ")}.`);
78
+ }
79
+ }
80
+
81
+ function defaultUserAgents(place) {
82
+ const previous = readUserAgents(place);
83
+ if (existsSync(join(place.base, "agents.json"))) return previous.length ? previous.join(",") : "none";
84
+ for (const name of ["codex", "claude"]) {
85
+ try { execFileSync(name, ["--version"], { stdio: "ignore" }); return name; }
86
+ catch {}
87
+ }
88
+ return "none";
63
89
  }
64
90
 
65
91
  async function init(opts, project) {
66
92
  const scope = opts.scope ?? existingScope(project) ?? await ask("Install in this project or for this user? [project/user] ", "project");
67
93
  const place = locations(scope, project);
68
94
  const current = readState(place.state);
69
- const edition = opts.edition ?? current?.edition ?? await ask("Free or Pro Pack? [free/pro] ", "free");
95
+ let key = process.env.MARVELOUS_LICENSE_KEY?.trim() ?? "";
96
+ if (!opts.edition && !key && current?.edition !== "pro") key = await askSecret("Polar license key (optional, press Enter for Free): ");
97
+ const edition = opts.edition ?? (key || current?.edition === "pro" ? "pro" : "free");
70
98
  if (!["project", "user"].includes(scope) || !["free", "pro"].includes(edition)) throw new Error("Choose --scope project|user and --edition free|pro.");
71
- console.log(`Marvelous UI: ${edition} Pack, ${scope} scope, ${detectFramework(project)} project`);
99
+ if (opts.edition === "free" && key) throw new Error("A Polar key was provided with --edition free. Remove the key or choose Pro.");
100
+ let selectedAgents = null;
101
+ if (scope === "user") {
102
+ const choice = opts.clients ?? (process.stdin.isTTY
103
+ ? await ask("Which agents should be connected? [codex,claude,none] (comma-separated) ", defaultUserAgents(place))
104
+ : existsSync(join(place.base, "agents.json")) ? defaultUserAgents(place) : "none");
105
+ selectedAgents = parseUserAgents(choice);
106
+ }
107
+ if (selectedAgents) checkUserAgents(selectedAgents);
108
+ const componentState = readState(place.components);
109
+ const hasComponents = !!(current && componentState?.slugs?.length && componentState.sourceScope === scope);
110
+ console.log(`Marvelous UI: ${edition} Pack, ${scope === "user" ? "user profile" : `${detectFramework(project)} project`}${key ? ", Polar key received" : ""}.`);
72
111
  if (!current || current.edition !== edition) {
73
112
  const meta = await latestRelease(edition);
74
- const bytes = await downloadRelease(edition, meta, edition === "pro" ? await licenseKey() : "");
75
- installPack(bytes, edition, meta, place);
113
+ const bytes = await downloadRelease(edition, meta, edition === "pro" ? key || await licenseKey() : "");
114
+ installPack(bytes, edition, meta, place, {
115
+ beforeCommit(stagedPack) {
116
+ if (!hasComponents) return;
117
+ const preview = addComponents({ place: { ...place, pack: stagedPack }, project, slugs: componentState.slugs, out: componentState.out, dryRun: true, useCurrentPack: true });
118
+ console.log("Project component changes:");
119
+ report(preview);
120
+ if (preview.conflicts.length) console.log("Customized files will be preserved. Merge those files manually if you want the new edition.");
121
+ },
122
+ });
123
+ if (hasComponents) report(addComponents({ place, project, slugs: componentState.slugs, out: componentState.out, useCurrentPack: true }));
76
124
  console.log(`Pack ${meta.version} installed in ${place.pack}`);
77
- } else console.log(`Pack ${current.version} is installed. Run update to fetch a newer version.`);
125
+ } else {
126
+ if (edition === "pro" && key) await downloadRelease("pro", await latestRelease("pro"), key);
127
+ console.log(`Pack ${current.version} is installed. Run update to fetch a newer version.`);
128
+ }
78
129
  if (scope === "project") {
79
130
  const out = chosenOut(project, opts.out, readState(place.components));
80
131
  const args = [join(place.pack, "scripts", "init-agent.mjs"), project, "--out", out];
81
132
  if (opts.clients) args.push("--clients", opts.clients);
82
133
  execFileSync(process.execPath, args, { stdio: "inherit" });
83
134
  } else {
84
- console.log("Register the user Pack with your agent using these commands:");
85
- execFileSync(process.execPath, [join(place.pack, "scripts", "init-agent.mjs"), "--plugin"], { stdio: "inherit" });
135
+ const names = configureUserAgents(place, selectedAgents);
136
+ console.log(names.length ? `Connected for all projects: ${names.join(", ")}.` : "No agent connected by choice.");
137
+ }
138
+ console.log(scope === "user" && !selectedAgents.length ? "Pack installed." : "Ready. Restart your agent to load Marvelous UI.");
139
+ }
140
+
141
+ async function restore(opts, project) {
142
+ const scope = opts.scope ?? existingScope(project) ?? "project";
143
+ const place = locations(scope, project);
144
+ const archives = listProArchives(place);
145
+ let version = opts.version;
146
+ if (!version) {
147
+ if (!process.stdin.isTTY) throw new Error("Specify --version to restore a saved Pro ZIP noninteractively.");
148
+ if (!archives.length) throw new Error("No saved Pro ZIP found. A new download requires an active key.");
149
+ console.log("Saved Pro ZIPs:");
150
+ archives.forEach((item, index) => console.log(` ${index + 1}. ${item.version} (${item.sha256.slice(0, 12)})`));
151
+ const choice = Number(await ask("Choose a version [1]: ", "1"));
152
+ if (!Number.isSafeInteger(choice) || choice < 1 || choice > archives.length) throw new Error("Choose a listed Pro version.");
153
+ version = archives[choice - 1].version;
86
154
  }
87
- console.log("Ready. Ask your coding agent to build a UI with Marvelous UI.");
155
+ const { bytes, meta } = readProArchive(place, version);
156
+ const current = readState(place.state);
157
+ const componentState = readState(place.components);
158
+ const hasComponents = !!(current && componentState?.slugs?.length && componentState.sourceScope === scope);
159
+ console.log(`Restoring Pro Pack ${meta.version} from the verified local ZIP.`);
160
+ installPack(bytes, "pro", meta, place, {
161
+ beforeCommit(stagedPack) {
162
+ if (!hasComponents) return;
163
+ const preview = addComponents({ place: { ...place, pack: stagedPack }, project, slugs: componentState.slugs, out: componentState.out, dryRun: true, useCurrentPack: true });
164
+ console.log("Project component changes:");
165
+ report(preview);
166
+ if (preview.conflicts.length) console.log("Customized files will be preserved. Merge those files manually if you want the restored version.");
167
+ },
168
+ });
169
+ if (hasComponents) report(addComponents({ place, project, slugs: componentState.slugs, out: componentState.out, useCurrentPack: true }));
170
+ if (!current && scope === "project") {
171
+ const out = chosenOut(project, opts.out, componentState);
172
+ const args = [join(place.pack, "scripts", "init-agent.mjs"), project, "--out", out];
173
+ if (opts.clients) args.push("--clients", opts.clients);
174
+ execFileSync(process.execPath, args, { stdio: "inherit" });
175
+ } else pluginRefresh(place);
176
+ console.log(`Pro Pack ${meta.version} restored without contacting the download service.`);
88
177
  }
89
178
 
90
179
  async function add(opts, project) {
@@ -142,11 +231,12 @@ async function run(args = process.argv.slice(2)) {
142
231
  if (command === "--help" || command === "-h") return console.log(HELP);
143
232
  const opts = options(args.slice(1));
144
233
  if (!command || opts.help || command === "help") return console.log(HELP);
145
- if (!["init", "add", "update"].includes(command)) throw new Error(`Unknown command: ${command}\n${HELP}`);
234
+ if (!["init", "add", "update", "restore"].includes(command)) throw new Error(`Unknown command: ${command}\n${HELP}`);
146
235
  const project = resolve(opts.project ?? process.cwd());
147
236
  if (!existsSync(project)) throw new Error(`Project does not exist: ${project}`);
148
237
  if (command === "init") return init(opts, project);
149
238
  if (command === "add") return add(opts, project);
239
+ if (command === "restore") return restore(opts, project);
150
240
  return update(opts, project);
151
241
  }
152
242
 
package/lib/agents.mjs ADDED
@@ -0,0 +1,69 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+
5
+ const SUPPORTED = ["codex", "claude"];
6
+ const LABELS = { codex: "Codex", claude: "Claude Code" };
7
+
8
+ export function parseUserAgents(value) {
9
+ const names = [...new Set(value.toLowerCase().split(",").map((name) => name.trim()).filter(Boolean))];
10
+ if (names.length === 1 && names[0] === "none") return [];
11
+ const unsupported = names.filter((name) => !SUPPORTED.includes(name));
12
+ if (unsupported.length) throw new Error(`User setup supports Codex and Claude Code. Unsupported choice: ${unsupported.join(", ")}. Other agents can use project setup or the manual guide.`);
13
+ if (!names.length) throw new Error("Choose codex, claude, both, or none.");
14
+ return names;
15
+ }
16
+
17
+ export function readUserAgents(place) {
18
+ const file = join(place.base, "agents.json");
19
+ if (!existsSync(file)) return [];
20
+ const state = JSON.parse(readFileSync(file, "utf8"));
21
+ if (state.schema !== 1 || !Array.isArray(state.clients) || state.clients.some((name) => !SUPPORTED.includes(name))) {
22
+ throw new Error(`Unsupported Marvelous UI agent state: ${file}`);
23
+ }
24
+ return state.clients;
25
+ }
26
+
27
+ function runAgent(command, args, runner) {
28
+ try { runner(command, args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }); }
29
+ catch (error) {
30
+ const detail = String(error.stderr ?? error.message ?? "").trim().split(/\r?\n/).at(-1);
31
+ throw new Error(`${LABELS[command]} setup failed${detail ? `: ${detail}` : "."} The Pack remains installed. Rerun init to retry agent setup.`);
32
+ }
33
+ }
34
+
35
+ export function checkUserAgents(clients, runner = execFileSync) {
36
+ for (const client of clients) runAgent(client, ["--version"], runner);
37
+ }
38
+
39
+ export function configureUserAgents(place, clients, runner = execFileSync) {
40
+ const prior = readUserAgents(place);
41
+ for (const client of clients) {
42
+ if (client === "codex") {
43
+ runAgent("codex", ["plugin", "marketplace", "add", place.pack], runner);
44
+ runAgent("codex", ["plugin", "add", "marvelous-ui@marvelous-ui"], runner);
45
+ } else {
46
+ if (prior.includes("claude")) {
47
+ runAgent("claude", ["plugin", "marketplace", "update", "marvelous-ui"], runner);
48
+ runAgent("claude", ["plugin", "update", "marvelous-ui@marvelous-ui"], runner);
49
+ } else {
50
+ runAgent("claude", ["plugin", "marketplace", "add", place.pack], runner);
51
+ runAgent("claude", ["plugin", "install", "marvelous-ui@marvelous-ui", "--scope", "user"], runner);
52
+ }
53
+ }
54
+ }
55
+ for (const client of prior.filter((name) => !clients.includes(name))) {
56
+ if (client === "codex") runAgent("codex", ["plugin", "remove", "marvelous-ui@marvelous-ui"], runner);
57
+ else runAgent("claude", ["plugin", "uninstall", "marvelous-ui@marvelous-ui", "--scope", "user"], runner);
58
+ }
59
+ saveUserAgents(place, clients);
60
+ return clients.map((name) => LABELS[name]);
61
+ }
62
+
63
+ function saveUserAgents(place, clients) {
64
+ const file = join(place.base, "agents.json");
65
+ mkdirSync(place.base, { recursive: true });
66
+ const temporary = `${file}.${process.pid}.tmp`;
67
+ writeFileSync(temporary, JSON.stringify({ schema: 1, clients }, null, 2) + "\n", { mode: 0o600 });
68
+ renameSync(temporary, file);
69
+ }
package/lib/installer.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { execFileSync } from "node:child_process";
1
+ import { execFileSync, execSync } from "node:child_process";
2
2
  import { existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
3
3
  import { homedir, tmpdir } from "node:os";
4
4
  import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
@@ -17,7 +17,7 @@ export function locations(scope, project = process.cwd(), home = homedir()) {
17
17
  try { if (lstatSync(projectBase).isSymbolicLink()) throw new Error("The project Pack directory cannot be a symbolic link."); }
18
18
  catch (error) { if (error.code !== "ENOENT") throw error; }
19
19
  const base = scope === "user" ? join(home, ".marvelous-ui") : projectBase;
20
- return { scope, base, pack: join(base, "pack"), state: join(base, "install.json"), components: join(projectBase, "components.json") };
20
+ return { scope, base, pack: join(base, "pack"), state: join(base, "install.json"), components: join(projectBase, "components.json"), archives: join(home, ".marvelous-ui", "archives") };
21
21
  }
22
22
 
23
23
  export function readState(file) {
@@ -114,6 +114,72 @@ function validPack(dir, edition, version) {
114
114
  if (edition === "free" && !existsSync(join(dir, "LICENSE"))) throw new Error("The Free license is missing from the Pack.");
115
115
  }
116
116
 
117
+ function archiveName(meta) { return `pro-${meta.version}-${meta.sha256}.zip`; }
118
+
119
+ function safeArchiveDirectory(directory) {
120
+ const parent = dirname(directory);
121
+ for (const path of [parent, directory]) {
122
+ try { if (lstatSync(path).isSymbolicLink()) throw new Error("The Pro archive directory cannot be a symbolic link."); }
123
+ catch (error) { if (error.code !== "ENOENT") throw error; }
124
+ }
125
+ }
126
+
127
+ /** Keep a verified release outside the project before replacing its installed Pack. */
128
+ export function saveProArchive(bytes, meta, place) {
129
+ validMeta(meta);
130
+ if (bytes.length !== meta.bytes || hash(bytes) !== meta.sha256) throw new Error("The Pro archive failed its size or SHA-256 check.");
131
+ const directory = place.archives ?? join(homedir(), ".marvelous-ui", "archives");
132
+ const target = join(directory, archiveName(meta));
133
+ let temporary;
134
+ try {
135
+ safeArchiveDirectory(directory);
136
+ mkdirSync(directory, { recursive: true });
137
+ const conflicting = readdirSync(directory).find((name) => {
138
+ const match = /^pro-(\d+\.\d+\.\d+)-([a-f0-9]{64})\.zip$/.exec(name);
139
+ return match && match[1] === meta.version && match[2] !== meta.sha256;
140
+ });
141
+ if (conflicting) throw new Error(`Pro Pack ${meta.version} is already saved with a different SHA-256. Pack versions must be immutable.`);
142
+ if (existsSync(target)) {
143
+ if (!lstatSync(target).isFile()) throw new Error("The Pro archive path is not a regular file.");
144
+ const prior = readFileSync(target);
145
+ if (prior.length !== meta.bytes || hash(prior) !== meta.sha256) throw new Error("An existing Pro archive is corrupt. Remove or move it, then retry.");
146
+ return target;
147
+ }
148
+ temporary = join(directory, `.${archiveName(meta)}.${process.pid}.${Math.random().toString(16).slice(2)}.tmp`);
149
+ writeFileSync(temporary, bytes, { flag: "wx", mode: 0o600 });
150
+ renameSync(temporary, target);
151
+ return target;
152
+ } catch (error) {
153
+ throw new Error(`The verified Pro ZIP could not be saved to ${target}: ${error.message}`);
154
+ } finally { if (temporary && existsSync(temporary)) rmSync(temporary, { force: true }); }
155
+ }
156
+
157
+ export function listProArchives(place) {
158
+ const directory = place.archives ?? join(homedir(), ".marvelous-ui", "archives");
159
+ safeArchiveDirectory(directory);
160
+ if (!existsSync(directory)) return [];
161
+ return readdirSync(directory).flatMap((name) => {
162
+ const match = /^pro-(\d+\.\d+\.\d+)-([a-f0-9]{64})\.zip$/.exec(name);
163
+ if (!match) return [];
164
+ const path = join(directory, name);
165
+ if (!lstatSync(path).isFile()) return [];
166
+ return [{ version: match[1], sha256: match[2], path }];
167
+ }).sort((a, b) => b.version.localeCompare(a.version, undefined, { numeric: true }) || a.sha256.localeCompare(b.sha256));
168
+ }
169
+
170
+ export function readProArchive(place, version) {
171
+ if (version && !VERSION.test(version)) throw new Error("Specify a valid Pack version, for example 1.1.0.");
172
+ const matches = listProArchives(place).filter((item) => !version || item.version === version);
173
+ if (!matches.length) throw new Error(`No saved Pro ZIP found${version ? ` for ${version}` : ""}. A new download requires an active key.`);
174
+ if (matches.length !== 1) throw new Error("Several Pro ZIPs match. Specify a unique version or move the duplicate archive.");
175
+ const item = matches[0];
176
+ const bytes = readFileSync(item.path);
177
+ const meta = { version: item.version, sha256: item.sha256, bytes: bytes.length };
178
+ validMeta(meta);
179
+ if (hash(bytes) !== meta.sha256) throw new Error(`The saved Pro ZIP for ${item.version} failed its SHA-256 check.`);
180
+ return { bytes, meta, path: item.path };
181
+ }
182
+
117
183
  /** Install a verified ZIP atomically so a failed download or npm install keeps the prior Pack. */
118
184
  export function installPack(bytes, edition, meta, place, { installDependencies = true, beforeCommit } = {}) {
119
185
  validMeta(meta);
@@ -125,10 +191,17 @@ export function installPack(bytes, edition, meta, place, { installDependencies =
125
191
  try {
126
192
  extractPack(bytes, stage, `marvelous-ui-${edition}`);
127
193
  validPack(stage, edition, meta.version);
194
+ if (edition === "pro") saveProArchive(bytes, meta, place);
128
195
  if (installDependencies) {
129
- const npmArgs = ["ci", "--omit=dev", "--ignore-scripts", "--no-audit"];
130
- if (process.env.npm_execpath?.endsWith(".js")) execFileSync(process.execPath, [process.env.npm_execpath, ...npmArgs], { cwd: stage, stdio: "inherit" });
131
- else execFileSync("npm", npmArgs, { cwd: stage, stdio: "inherit", shell: process.platform === "win32" });
196
+ const npmArgs = ["ci", "--omit=dev", "--ignore-scripts", "--no-audit", "--no-fund", "--silent"];
197
+ try {
198
+ if (process.env.npm_execpath?.endsWith(".js")) execFileSync(process.execPath, [process.env.npm_execpath, ...npmArgs], { cwd: stage, stdio: ["ignore", "pipe", "pipe"] });
199
+ else if (process.platform === "win32") execSync(`npm ${npmArgs.join(" ")}`, { cwd: stage, stdio: ["ignore", "pipe", "pipe"] });
200
+ else execFileSync("npm", npmArgs, { cwd: stage, stdio: ["ignore", "pipe", "pipe"] });
201
+ } catch (error) {
202
+ const detail = String(error.stderr ?? error.message ?? "").trim().split(/\r?\n/).at(-1);
203
+ throw new Error(`The Pack dependencies could not be installed${detail ? `: ${detail}` : "."}`);
204
+ }
132
205
  }
133
206
  beforeCommit?.(stage);
134
207
  if (existsSync(backup)) throw new Error("A previous installation is still being recovered.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "marvelous-ui-library",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Install and update the Marvelous UI component Pack for coding agents",
5
5
  "type": "module",
6
6
  "license": "MIT",