ply-ui-cli 1.1.118

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.
@@ -0,0 +1,432 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/commands/add.ts
31
+ var add_exports = {};
32
+ __export(add_exports, {
33
+ add: () => add
34
+ });
35
+ module.exports = __toCommonJS(add_exports);
36
+ var import_fs4 = __toESM(require("fs"));
37
+ var import_path5 = __toESM(require("path"));
38
+ var import_vendor2 = require("../vendor");
39
+ var import_registry = require("../registry");
40
+
41
+ // src/lockfile.ts
42
+ var import_fs = __toESM(require("fs"));
43
+ var import_path = __toESM(require("path"));
44
+ var import_crypto = __toESM(require("crypto"));
45
+ var LOCKFILE_NAME = "base-ui-lock.json";
46
+ var LOCKFILE_VERSION = 1;
47
+ function hashContent(content) {
48
+ return import_crypto.default.createHash("sha256").update(content, "utf8").digest("hex");
49
+ }
50
+ function lockfilePath() {
51
+ return import_path.default.resolve(process.cwd(), LOCKFILE_NAME);
52
+ }
53
+ function readLockFile() {
54
+ const p = lockfilePath();
55
+ if (!import_fs.default.existsSync(p)) {
56
+ return { version: LOCKFILE_VERSION, components: {} };
57
+ }
58
+ try {
59
+ const parsed = JSON.parse(import_fs.default.readFileSync(p, "utf8"));
60
+ if (parsed && typeof parsed === "object" && parsed.components) {
61
+ return { version: parsed.version ?? LOCKFILE_VERSION, components: parsed.components };
62
+ }
63
+ } catch {
64
+ }
65
+ return { version: LOCKFILE_VERSION, components: {} };
66
+ }
67
+ function writeLockFile(lock) {
68
+ import_fs.default.writeFileSync(lockfilePath(), JSON.stringify(lock, null, 2) + "\n", "utf8");
69
+ }
70
+ function recordComponent(lock, name, tier, files) {
71
+ const fileHashes = {};
72
+ for (const f of files) {
73
+ fileHashes[f.name] = hashContent(f.content);
74
+ }
75
+ lock.components[name] = {
76
+ tier,
77
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
78
+ files: fileHashes
79
+ };
80
+ }
81
+
82
+ // src/config.ts
83
+ var import_fs2 = __toESM(require("fs"));
84
+ var import_path2 = __toESM(require("path"));
85
+
86
+ // src/brand.ts
87
+ var CLI_BIN = "ply-ui-cli";
88
+ var CLI_NPX = `npx ${CLI_BIN}`;
89
+ var MCP_PACKAGE = "ply-ui-mcp";
90
+ var MCP_NPX = `npx -y ${MCP_PACKAGE}`;
91
+
92
+ // src/config.ts
93
+ function readConfig() {
94
+ const configPath = import_path2.default.resolve(process.cwd(), "base-ui.json");
95
+ if (!import_fs2.default.existsSync(configPath)) {
96
+ console.error(`base-ui.json not found. Please run "${CLI_NPX} init" first.`);
97
+ return null;
98
+ }
99
+ try {
100
+ const config = JSON.parse(import_fs2.default.readFileSync(configPath, "utf8"));
101
+ if (!config || !config.aliases || !config.aliases.components) {
102
+ throw new Error("Missing aliases.components in base-ui.json");
103
+ }
104
+ return config;
105
+ } catch (err) {
106
+ console.error(`Error reading base-ui.json: ${err.message}`);
107
+ return null;
108
+ }
109
+ }
110
+
111
+ // src/path-safety.ts
112
+ var import_path3 = __toESM(require("path"));
113
+ function isSafeFileName(name) {
114
+ if (import_path3.default.isAbsolute(name) || /^[a-zA-Z]:[\\/]/.test(name)) return false;
115
+ const segments = name.split(/[\\/]/);
116
+ return segments.every((s) => s !== "" && s !== "..");
117
+ }
118
+
119
+ // src/integrity.ts
120
+ function isSafeNpmDependency(spec) {
121
+ return /^(?:@[a-z0-9][a-z0-9-._~]*\/)?[a-z0-9][a-z0-9-._~]*$/.test(spec) && spec.length <= 214;
122
+ }
123
+
124
+ // src/commands/pick-components.ts
125
+ var import_vendor = require("../vendor");
126
+
127
+ // src/categories.ts
128
+ var CATEGORY_TITLES = {
129
+ application: "Applications",
130
+ "page-layout": "Page layouts",
131
+ block: "Blocks",
132
+ widget: "Widgets",
133
+ shell: "Shells",
134
+ component: "Components"
135
+ };
136
+ var CATEGORY_ORDER = [
137
+ "application",
138
+ "page-layout",
139
+ "block",
140
+ "widget",
141
+ "shell",
142
+ "component"
143
+ ];
144
+ function categoryTitle(category) {
145
+ const key = category || "component";
146
+ return CATEGORY_TITLES[key] || key;
147
+ }
148
+
149
+ // src/commands/pick-components.ts
150
+ var ADD_NEEDS_NAME = `Pass a component name: ${CLI_NPX} add <name>
151
+ Or run without --yes in a terminal to pick from the catalog.`;
152
+ function canPromptInteractively(options, tty = Boolean(process.stdin.isTTY && process.stdout.isTTY)) {
153
+ return !options.yes && tty;
154
+ }
155
+ function filterCatalog(index, filter) {
156
+ if (filter === "all") return index;
157
+ if (filter === "free" || filter === "pro") {
158
+ return index.filter((item) => item.tier === filter);
159
+ }
160
+ if (filter.startsWith("category:")) {
161
+ const category = filter.slice("category:".length);
162
+ return index.filter((item) => (item.category || "component") === category);
163
+ }
164
+ return index;
165
+ }
166
+ function catalogFilterChoices(index) {
167
+ const count = (pred) => index.filter(pred).length;
168
+ const choices = [
169
+ { title: `All (${index.length})`, value: "all" },
170
+ { title: `Free (${count((item) => item.tier === "free")})`, value: "free" },
171
+ { title: `Pro (${count((item) => item.tier === "pro")})`, value: "pro" }
172
+ ];
173
+ for (const category of CATEGORY_ORDER) {
174
+ const n = count((item) => (item.category || "component") === category);
175
+ if (!n) continue;
176
+ choices.push({
177
+ title: `${CATEGORY_TITLES[category]} (${n})`,
178
+ value: `category:${category}`
179
+ });
180
+ }
181
+ return choices;
182
+ }
183
+ function pickerTitle(item) {
184
+ const keywords = (item.keywords || []).slice(0, 6).join(" ");
185
+ const label = `${item.name} (${item.tier} \xB7 ${categoryTitle(item.category)})`;
186
+ return keywords ? `${label} ${keywords}` : label;
187
+ }
188
+ function toPickerChoices(index) {
189
+ return [...index].sort((a, b) => a.name.localeCompare(b.name)).map((item) => ({
190
+ title: pickerTitle(item),
191
+ value: item.name
192
+ }));
193
+ }
194
+ async function pickComponents(index) {
195
+ const filterRes = await (0, import_vendor.prompts)({
196
+ type: "select",
197
+ name: "filter",
198
+ message: "Filter the catalog",
199
+ choices: catalogFilterChoices(index)
200
+ });
201
+ if (!filterRes.filter) return [];
202
+ const filtered = filterCatalog(index, String(filterRes.filter));
203
+ if (!filtered.length) {
204
+ console.error("No components in that filter.");
205
+ return [];
206
+ }
207
+ const picked = await (0, import_vendor.prompts)({
208
+ type: "autocompleteMultiselect",
209
+ name: "components",
210
+ message: "Select components to add",
211
+ hint: "- Type to filter. Space to select. Enter to confirm",
212
+ instructions: false,
213
+ min: 1,
214
+ choices: toPickerChoices(filtered)
215
+ });
216
+ const selected = picked.components;
217
+ if (!Array.isArray(selected) || selected.length === 0) return [];
218
+ return selected.map(String);
219
+ }
220
+
221
+ // src/aliases.ts
222
+ var COMPONENT_ALIASES = {
223
+ sheet: "drawer",
224
+ "side-sheet": "drawer",
225
+ carousel: "slider",
226
+ gallery: "slider",
227
+ "image-slider": "slider",
228
+ range: "range-slider",
229
+ "slider-input": "range-slider",
230
+ "input-slider": "range-slider"
231
+ };
232
+ function canonicalComponentName(name) {
233
+ const key = name.trim().toLowerCase();
234
+ return COMPONENT_ALIASES[key] ?? name.trim();
235
+ }
236
+
237
+ // src/snapshot.ts
238
+ var import_fs3 = __toESM(require("fs"));
239
+ var import_path4 = __toESM(require("path"));
240
+ var SNAPSHOT_ROOT = ".base-ui/snapshots";
241
+ function snapshotPath(component, file) {
242
+ return import_path4.default.resolve(process.cwd(), SNAPSHOT_ROOT, component, file);
243
+ }
244
+ function writeSnapshot(component, file, content) {
245
+ if (!isSafeFileName(file) || !isSafeFileName(component)) return;
246
+ const dest = snapshotPath(component, file);
247
+ import_fs3.default.mkdirSync(import_path4.default.dirname(dest), { recursive: true });
248
+ import_fs3.default.writeFileSync(dest, content, "utf8");
249
+ }
250
+
251
+ // src/commands/add.ts
252
+ function detectPackageManager(cwd) {
253
+ if (import_fs4.default.existsSync(import_path5.default.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
254
+ if (import_fs4.default.existsSync(import_path5.default.join(cwd, "yarn.lock"))) return "yarn";
255
+ if (import_fs4.default.existsSync(import_path5.default.join(cwd, "bun.lockb")) || import_fs4.default.existsSync(import_path5.default.join(cwd, "bun.lock"))) return "bun";
256
+ return "npm";
257
+ }
258
+ function installedNpmDeps(cwd) {
259
+ try {
260
+ const pkg = JSON.parse(import_fs4.default.readFileSync(import_path5.default.join(cwd, "package.json"), "utf8"));
261
+ return /* @__PURE__ */ new Set([
262
+ ...Object.keys(pkg.dependencies || {}),
263
+ ...Object.keys(pkg.devDependencies || {})
264
+ ]);
265
+ } catch {
266
+ return /* @__PURE__ */ new Set();
267
+ }
268
+ }
269
+ async function add(components, options = {}) {
270
+ let names = (components || []).map((name) => name.trim()).filter(Boolean);
271
+ names = names.map((name) => {
272
+ const canonical = canonicalComponentName(name);
273
+ if (canonical !== name) {
274
+ console.log(`\u2139 ${name} \u2192 ${canonical}`);
275
+ }
276
+ return canonical;
277
+ });
278
+ names = [...new Set(names)];
279
+ if (names.length === 0 && !canPromptInteractively(options)) {
280
+ console.error(ADD_NEEDS_NAME);
281
+ process.exitCode = 1;
282
+ return;
283
+ }
284
+ const config = readConfig();
285
+ if (!config) {
286
+ process.exitCode = 1;
287
+ return;
288
+ }
289
+ const componentsRoot = import_path5.default.resolve(process.cwd(), config.aliases.components);
290
+ const indexSpinner = (0, import_vendor2.ora)("Loading registry index...").start();
291
+ let index;
292
+ try {
293
+ index = await (0, import_registry.fetchIndex)();
294
+ indexSpinner.succeed("Registry index loaded.");
295
+ } catch (err) {
296
+ indexSpinner.fail(err.message);
297
+ process.exitCode = 1;
298
+ return;
299
+ }
300
+ if (names.length === 0) {
301
+ names = await pickComponents(index);
302
+ if (names.length === 0) {
303
+ console.log("Nothing to install.");
304
+ return;
305
+ }
306
+ }
307
+ const byName = new Map(index.map((i) => [i.name, i]));
308
+ let hadError = false;
309
+ for (const name of names) {
310
+ if (!(0, import_registry.isSafeItemName)(name) || !byName.has(name)) {
311
+ hadError = true;
312
+ const suggestions = (0, import_registry.suggestNames)(name, index.map((i) => i.name));
313
+ console.error(`\u2716 Unknown component: '${name}'.`);
314
+ if (suggestions.length) {
315
+ console.error(` Did you mean: ${suggestions.join(", ")}?`);
316
+ }
317
+ console.error(` Run "${CLI_NPX} list" to see every available component.`);
318
+ }
319
+ }
320
+ if (hadError) {
321
+ process.exitCode = 1;
322
+ return;
323
+ }
324
+ const requested = new Set(names);
325
+ const toInstall = /* @__PURE__ */ new Map();
326
+ const queue = [...names];
327
+ while (queue.length) {
328
+ const name = queue.shift();
329
+ if (toInstall.has(name)) continue;
330
+ const entry = byName.get(name);
331
+ if (!entry) {
332
+ console.error(`\u2716 Registry index is missing dependency '${name}'. Aborting.`);
333
+ process.exitCode = 1;
334
+ return;
335
+ }
336
+ const targetDir = import_path5.default.join(componentsRoot, name);
337
+ if (!requested.has(name) && import_fs4.default.existsSync(targetDir)) continue;
338
+ toInstall.set(name, entry);
339
+ queue.push(...entry.registryDependencies);
340
+ }
341
+ const proItems = [...toInstall.values()].filter((i) => i.tier === "pro");
342
+ if (proItems.length && !(0, import_registry.getLicenseKey)()) {
343
+ console.error(`\u2716 The following components require a Ply Pro license: ${proItems.map((i) => i.name).join(", ")}`);
344
+ console.error(` Set the PLY_LICENSE_KEY environment variable to your license key.`);
345
+ console.error(` (BASE_UI_LICENSE_KEY is still accepted.)`);
346
+ console.error(` Get a license at ${import_registry.SITE_URL}/pricing.`);
347
+ process.exitCode = 1;
348
+ return;
349
+ }
350
+ for (const name of requested) {
351
+ const targetDir = import_path5.default.join(componentsRoot, name);
352
+ if (!import_fs4.default.existsSync(targetDir)) continue;
353
+ if (options.overwrite || options.yes) continue;
354
+ const res = await (0, import_vendor2.prompts)({
355
+ type: "confirm",
356
+ name: "overwrite",
357
+ message: `${import_path5.default.relative(process.cwd(), targetDir)} already exists. Overwrite it?`,
358
+ initial: false
359
+ });
360
+ if (!res.overwrite) {
361
+ toInstall.delete(name);
362
+ console.log(` Skipped ${name}.`);
363
+ }
364
+ }
365
+ if (toInstall.size === 0) {
366
+ console.log("Nothing to install.");
367
+ return;
368
+ }
369
+ const npmDeps = /* @__PURE__ */ new Set();
370
+ const installedItems = [];
371
+ const lock = readLockFile();
372
+ for (const [name, entry] of toInstall) {
373
+ const spinner = (0, import_vendor2.ora)(`Fetching ${name}...`).start();
374
+ let item;
375
+ try {
376
+ item = await (0, import_registry.fetchItem)(name, entry.tier, entry.digest);
377
+ } catch (err) {
378
+ spinner.fail(`Failed to fetch ${name}: ${err.code === "NOT_FOUND" ? "not found in registry." : err.message}`);
379
+ process.exitCode = 1;
380
+ return;
381
+ }
382
+ const unsafeFile = item.files.find((f) => !isSafeFileName(f.name));
383
+ if (unsafeFile) {
384
+ spinner.fail(`Registry payload for ${name} contains an unsafe file path ('${unsafeFile.name}') \u2014 nothing was written.`);
385
+ process.exitCode = 1;
386
+ return;
387
+ }
388
+ const unsafeDep = item.dependencies.find((d) => !isSafeNpmDependency(d));
389
+ if (unsafeDep) {
390
+ spinner.fail(`Registry payload for ${name} lists an invalid npm dependency ('${unsafeDep}') \u2014 nothing was written.`);
391
+ process.exitCode = 1;
392
+ return;
393
+ }
394
+ const targetDir = import_path5.default.join(componentsRoot, name);
395
+ try {
396
+ for (const file of item.files) {
397
+ const filePath = import_path5.default.join(targetDir, file.name);
398
+ import_fs4.default.mkdirSync(import_path5.default.dirname(filePath), { recursive: true });
399
+ import_fs4.default.writeFileSync(filePath, file.content, "utf8");
400
+ writeSnapshot(name, file.name, file.content);
401
+ }
402
+ } catch (err) {
403
+ spinner.fail(`Failed to write ${name}: ${err.message}`);
404
+ process.exitCode = 1;
405
+ return;
406
+ }
407
+ item.dependencies.forEach((d) => npmDeps.add(d));
408
+ installedItems.push(name);
409
+ recordComponent(lock, name, entry.tier, item.files);
410
+ spinner.succeed(`${name} \u2192 ${import_path5.default.relative(process.cwd(), targetDir)}${entry.tier === "pro" ? " (pro)" : ""}`);
411
+ }
412
+ if (installedItems.length) {
413
+ writeLockFile(lock);
414
+ }
415
+ const existing = installedNpmDeps(process.cwd());
416
+ const missingDeps = [...npmDeps].filter((d) => !existing.has(d));
417
+ if (missingDeps.length) {
418
+ const pm = detectPackageManager(process.cwd());
419
+ const cmd = pm === "npm" ? `npm install ${missingDeps.join(" ")}` : `${pm} add ${missingDeps.join(" ")}`;
420
+ console.log(
421
+ `
422
+ Install missing npm ${missingDeps.length === 1 ? "dependency" : "dependencies"}:
423
+ ${cmd}`
424
+ );
425
+ }
426
+ console.log(`
427
+ \u2714 Added ${installedItems.length} ${installedItems.length === 1 ? "component" : "components"}: ${installedItems.join(", ")}`);
428
+ }
429
+ // Annotate the CommonJS export names for ESM import in node:
430
+ 0 && (module.exports = {
431
+ add
432
+ });
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/commands/changelog.ts
21
+ var changelog_exports = {};
22
+ __export(changelog_exports, {
23
+ changelog: () => changelog
24
+ });
25
+ module.exports = __toCommonJS(changelog_exports);
26
+ var import_registry = require("../registry");
27
+
28
+ // src/brand.ts
29
+ var CLI_BIN = "ply-ui-cli";
30
+ var CLI_NPX = `npx ${CLI_BIN}`;
31
+ var MCP_PACKAGE = "ply-ui-mcp";
32
+ var MCP_NPX = `npx -y ${MCP_PACKAGE}`;
33
+
34
+ // src/commands/changelog.ts
35
+ var CHANGELOG_URL = process.env.PLY_CHANGELOG_URL?.trim() || process.env.BASE_UI_CHANGELOG_URL?.trim() || `${import_registry.SITE_URL}/assets/changelog.json`;
36
+ function flattenEntries(payload) {
37
+ const out = [];
38
+ for (const month of payload.months ?? []) {
39
+ if (!month || typeof month !== "object") continue;
40
+ const block = month;
41
+ const entries = block.entries?.length ? block.entries : (block.sections ?? []).flatMap((section) => section.entries ?? []);
42
+ out.push(...entries);
43
+ }
44
+ return out;
45
+ }
46
+ function matchesName(entry, name) {
47
+ if (entry.scope === name) return true;
48
+ return Array.isArray(entry.components) && entry.components.includes(name);
49
+ }
50
+ async function changelog(names) {
51
+ const name = names[0]?.trim();
52
+ if (!name || names.length !== 1) {
53
+ console.error(`Usage: ${CLI_NPX} changelog <name>`);
54
+ process.exitCode = 1;
55
+ return;
56
+ }
57
+ if (!(0, import_registry.isSafeItemName)(name)) {
58
+ console.error(`\u2716 Invalid component name: '${name}'.`);
59
+ process.exitCode = 1;
60
+ return;
61
+ }
62
+ let payload;
63
+ try {
64
+ const res = await fetch(CHANGELOG_URL);
65
+ if (!res.ok) {
66
+ throw new Error(`HTTP ${res.status}`);
67
+ }
68
+ payload = await res.json();
69
+ } catch (err) {
70
+ const message = err instanceof Error ? err.message : String(err);
71
+ console.error(`\u2716 Could not load changelog (${message}).`);
72
+ console.error(` ${import_registry.SITE_URL}/changelog`);
73
+ process.exitCode = 1;
74
+ return;
75
+ }
76
+ const hits = flattenEntries(payload).filter((entry) => matchesName(entry, name));
77
+ if (!hits.length) {
78
+ try {
79
+ const index = await (0, import_registry.fetchIndex)();
80
+ const known = index.some((item) => item.name === name) || name === "cli" || name === "mcp";
81
+ if (!known) {
82
+ const suggestions = (0, import_registry.suggestNames)(
83
+ name,
84
+ index.map((item) => item.name)
85
+ );
86
+ console.error(`\u2716 Unknown component: '${name}'.`);
87
+ if (suggestions.length) {
88
+ console.error(` Did you mean: ${suggestions.join(", ")}`);
89
+ }
90
+ process.exitCode = 1;
91
+ return;
92
+ }
93
+ } catch {
94
+ }
95
+ console.log(`No changelog entries for '${name}' yet.`);
96
+ console.log(`Full history: ${import_registry.SITE_URL}/changelog`);
97
+ return;
98
+ }
99
+ console.log(`${name} \u2014 ${hits.length} matching update${hits.length === 1 ? "" : "s"}
100
+ `);
101
+ for (const entry of hits) {
102
+ const type = (entry.type || "other").padEnd(8);
103
+ const bang = entry.breaking ? " BREAKING" : "";
104
+ console.log(`${entry.date} ${type} ${entry.hash}${bang} ${entry.description}`);
105
+ }
106
+ console.log(`
107
+ Full history: ${import_registry.SITE_URL}/changelog`);
108
+ }
109
+ // Annotate the CommonJS export names for ESM import in node:
110
+ 0 && (module.exports = {
111
+ changelog
112
+ });