nxds-cli 0.5.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +118 -37
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -4543,7 +4543,7 @@ async function fetchRelease(registry, version) {
|
|
|
4543
4543
|
if (isNewerSchema(value)) {
|
|
4544
4544
|
const release = version === "latest" ? "The latest nxds release" : `nxds ${version}`;
|
|
4545
4545
|
throw new CliError(
|
|
4546
|
-
`${release} needs a newer nxds-cli than ${"0.
|
|
4546
|
+
`${release} needs a newer nxds-cli than ${"0.6.1"}. Run \`${CLI_COMMAND}\` to get the newest one.`
|
|
4547
4547
|
);
|
|
4548
4548
|
}
|
|
4549
4549
|
const invalid2 = (problems) => new CliError(
|
|
@@ -6295,7 +6295,7 @@ function localPackage(source) {
|
|
|
6295
6295
|
function assertWritable(out, overwrite) {
|
|
6296
6296
|
if (!existsSync9(out) || readdirSync(out).length === 0 || overwrite) return;
|
|
6297
6297
|
throw new UsageError(
|
|
6298
|
-
`${out} already has files. Pass --overwrite to replace
|
|
6298
|
+
`${out} already has files. Pass --overwrite to replace the export in it, or choose another --out.`
|
|
6299
6299
|
);
|
|
6300
6300
|
}
|
|
6301
6301
|
function readPaths(file) {
|
|
@@ -6310,6 +6310,12 @@ function readPaths(file) {
|
|
|
6310
6310
|
function stalePaths(existing, exported) {
|
|
6311
6311
|
return existing.filter((file) => file.startsWith("project/")).filter((file) => !isPageGenerated(file.slice("project/".length))).filter((file) => !exported.has(file)).sort();
|
|
6312
6312
|
}
|
|
6313
|
+
var EXPORT_NAMES = /* @__PURE__ */ new Set(["project", "files.json", "removed.json"]);
|
|
6314
|
+
var isRootName = (name) => name !== "" && name !== "." && name !== ".." && path10.basename(name) === name && !EXPORT_NAMES.has(name);
|
|
6315
|
+
var sha256 = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
|
6316
|
+
var isEntryList = (value) => Array.isArray(value) && value.every(
|
|
6317
|
+
(entry) => typeof entry?.path === "string" && typeof entry.sha256 === "string"
|
|
6318
|
+
);
|
|
6313
6319
|
function readManifest(root) {
|
|
6314
6320
|
const file = path10.join(root, "files.json");
|
|
6315
6321
|
if (!existsSync9(file)) {
|
|
@@ -6318,39 +6324,99 @@ function readManifest(root) {
|
|
|
6318
6324
|
);
|
|
6319
6325
|
}
|
|
6320
6326
|
const value = readJson(file);
|
|
6321
|
-
if (!
|
|
6322
|
-
(entry) => typeof entry?.path === "string" && typeof entry.sha256 === "string"
|
|
6323
|
-
)) {
|
|
6327
|
+
if (!isEntryList(value?.project) || !isEntryList(value.root)) {
|
|
6324
6328
|
throw new CliError(
|
|
6325
|
-
`${file} must
|
|
6329
|
+
`${file} must hold project and root, each a JSON array of { path, sha256 } entries.`
|
|
6326
6330
|
);
|
|
6327
6331
|
}
|
|
6328
|
-
return value;
|
|
6332
|
+
return { project: value.project, root: value.root };
|
|
6329
6333
|
}
|
|
6330
|
-
function
|
|
6331
|
-
const projectDir = path10.join(root, "project");
|
|
6334
|
+
function readEntries(dir, entries, prefix) {
|
|
6332
6335
|
const files = /* @__PURE__ */ new Map();
|
|
6333
|
-
for (const entry of
|
|
6334
|
-
const file = path10.join(
|
|
6335
|
-
const relative = path10.relative(projectDir, file);
|
|
6336
|
-
if (relative.split(path10.sep)[0] === ".." || path10.isAbsolute(relative)) {
|
|
6337
|
-
throw new CliError(`files.json lists ${entry.path}, outside project/.`);
|
|
6338
|
-
}
|
|
6336
|
+
for (const entry of entries) {
|
|
6337
|
+
const file = path10.join(dir, entry.path);
|
|
6339
6338
|
if (!existsSync9(file) || !lstatSync(file).isFile()) {
|
|
6340
6339
|
throw new CliError(
|
|
6341
|
-
|
|
6340
|
+
`${prefix}${entry.path} is missing from the release, or isn't a regular file.`
|
|
6342
6341
|
);
|
|
6343
6342
|
}
|
|
6344
6343
|
const bytes = readFileSync5(file);
|
|
6345
|
-
if (
|
|
6344
|
+
if (sha256(bytes) !== entry.sha256) {
|
|
6346
6345
|
throw new CliError(
|
|
6347
|
-
|
|
6346
|
+
`${prefix}${entry.path} doesn't match the release's files.json, so nothing was written.`
|
|
6348
6347
|
);
|
|
6349
6348
|
}
|
|
6350
6349
|
files.set(entry.path, bytes);
|
|
6351
6350
|
}
|
|
6352
6351
|
return files;
|
|
6353
6352
|
}
|
|
6353
|
+
function readRelease(root) {
|
|
6354
|
+
const manifest = readManifest(root);
|
|
6355
|
+
const projectDir = path10.join(root, "project");
|
|
6356
|
+
for (const { path: file } of manifest.project) {
|
|
6357
|
+
const relative = path10.relative(projectDir, path10.join(projectDir, file));
|
|
6358
|
+
if (relative.split(path10.sep)[0] === ".." || path10.isAbsolute(relative)) {
|
|
6359
|
+
throw new CliError(`files.json lists ${file}, outside project/.`);
|
|
6360
|
+
}
|
|
6361
|
+
}
|
|
6362
|
+
for (const { path: file } of manifest.root) {
|
|
6363
|
+
if (!isRootName(file)) {
|
|
6364
|
+
throw new CliError(
|
|
6365
|
+
`files.json lists ${file || "an empty path"} as a root file. A root file is one name beside project/, other than project, files.json and removed.json.`
|
|
6366
|
+
);
|
|
6367
|
+
}
|
|
6368
|
+
}
|
|
6369
|
+
if (!manifest.root.some((entry) => entry.path === "SETUP.md")) {
|
|
6370
|
+
throw new CliError(
|
|
6371
|
+
"The release's files.json lists no SETUP.md, so there's no guide to follow."
|
|
6372
|
+
);
|
|
6373
|
+
}
|
|
6374
|
+
return {
|
|
6375
|
+
files: readEntries(projectDir, manifest.project, "project/"),
|
|
6376
|
+
rootFiles: readEntries(root, manifest.root, "")
|
|
6377
|
+
};
|
|
6378
|
+
}
|
|
6379
|
+
function droppedRootFiles(out, rootFiles) {
|
|
6380
|
+
const file = path10.join(out, "files.json");
|
|
6381
|
+
if (!existsSync9(file)) return [];
|
|
6382
|
+
const value = readJson(file);
|
|
6383
|
+
if (!isEntryList(value?.root)) {
|
|
6384
|
+
throw new UsageError(
|
|
6385
|
+
`${file} must hold root, a JSON array of { path, sha256 } entries. Delete it, then run the command again.`
|
|
6386
|
+
);
|
|
6387
|
+
}
|
|
6388
|
+
return value.root.filter(
|
|
6389
|
+
(entry) => isRootName(entry.path) && !rootFiles.has(entry.path)
|
|
6390
|
+
);
|
|
6391
|
+
}
|
|
6392
|
+
function removeDroppedRootFiles(out, dropped) {
|
|
6393
|
+
const edited = [];
|
|
6394
|
+
for (const entry of dropped) {
|
|
6395
|
+
const file = path10.join(out, entry.path);
|
|
6396
|
+
if (!existsSync9(file)) continue;
|
|
6397
|
+
const unchanged = lstatSync(file).isFile() && sha256(readFileSync5(file)) === entry.sha256;
|
|
6398
|
+
if (unchanged) rmSync(file);
|
|
6399
|
+
else edited.push(entry.path);
|
|
6400
|
+
}
|
|
6401
|
+
return edited;
|
|
6402
|
+
}
|
|
6403
|
+
function writeRootFiles(out, rootFiles) {
|
|
6404
|
+
for (const [name, bytes] of rootFiles) {
|
|
6405
|
+
writeFileSync3(path10.join(out, name), bytes);
|
|
6406
|
+
}
|
|
6407
|
+
}
|
|
6408
|
+
var entriesOf = (files) => [...files].map(([file, bytes]) => ({ path: file, sha256: sha256(bytes) }));
|
|
6409
|
+
function writeManifest(out, files, rootFiles) {
|
|
6410
|
+
const manifest = {
|
|
6411
|
+
project: entriesOf(files),
|
|
6412
|
+
root: entriesOf(rootFiles)
|
|
6413
|
+
};
|
|
6414
|
+
writeFileSync3(
|
|
6415
|
+
path10.join(out, "files.json"),
|
|
6416
|
+
`${JSON.stringify(manifest, null, 2)}
|
|
6417
|
+
`
|
|
6418
|
+
);
|
|
6419
|
+
}
|
|
6354
6420
|
function mergeIndex(files, currentFile) {
|
|
6355
6421
|
const exported = files.get("design-system.json");
|
|
6356
6422
|
if (!exported) throw new CliError("The release has no design-system.json.");
|
|
@@ -6426,42 +6492,57 @@ async function exportClaudeDesign(cwd, options) {
|
|
|
6426
6492
|
options.release ?? "latest"
|
|
6427
6493
|
);
|
|
6428
6494
|
try {
|
|
6429
|
-
const files =
|
|
6495
|
+
const { files, rootFiles } = readRelease(pkg.root);
|
|
6430
6496
|
if (options.index) mergeIndex(files, path10.resolve(cwd, options.index));
|
|
6431
6497
|
const exported = new Set(
|
|
6432
6498
|
[...files.keys()].map((file) => `project/${file}`)
|
|
6433
6499
|
);
|
|
6434
6500
|
const removed = options.existing ? stalePaths(readPaths(path10.resolve(cwd, options.existing)), exported) : [];
|
|
6435
|
-
const
|
|
6436
|
-
const coverage = existsSync9(coverageFile) ? readFileSync5(coverageFile) : void 0;
|
|
6501
|
+
const dropped = droppedRootFiles(out, rootFiles);
|
|
6437
6502
|
writeProject(out, files);
|
|
6438
|
-
|
|
6503
|
+
const kept = removeDroppedRootFiles(out, dropped);
|
|
6504
|
+
writeRootFiles(out, rootFiles);
|
|
6505
|
+
writeManifest(out, files, rootFiles);
|
|
6506
|
+
const removedFile = path10.join(out, "removed.json");
|
|
6439
6507
|
if (options.existing) {
|
|
6440
|
-
writeFileSync3(
|
|
6441
|
-
|
|
6442
|
-
|
|
6443
|
-
|
|
6444
|
-
);
|
|
6508
|
+
writeFileSync3(removedFile, `${JSON.stringify(removed, null, 2)}
|
|
6509
|
+
`);
|
|
6510
|
+
} else {
|
|
6511
|
+
rmSync(removedFile, { force: true });
|
|
6445
6512
|
}
|
|
6446
6513
|
const relative = path10.relative(cwd, out) || ".";
|
|
6447
6514
|
const lines2 = [
|
|
6448
|
-
`Exported nxds ${pkg.version} as a Claude Design System: ${files.size} files in ${path10.join(relative, "project")}
|
|
6449
|
-
`Publish ${relative} as a Design System artifact in Claude, with ${relative} as the root.`
|
|
6515
|
+
`Exported nxds ${pkg.version} as a Claude Design System: ${files.size} files in ${path10.join(relative, "project")}.`
|
|
6450
6516
|
];
|
|
6451
|
-
if (
|
|
6517
|
+
if (rootFiles.has("coverage.md")) {
|
|
6452
6518
|
lines2.push(
|
|
6453
|
-
`
|
|
6519
|
+
`The props the canvas can't set are in ${path10.join(relative, "coverage.md")}.`
|
|
6454
6520
|
);
|
|
6455
6521
|
}
|
|
6456
|
-
|
|
6522
|
+
for (const name of kept) {
|
|
6457
6523
|
lines2.push(
|
|
6458
|
-
`
|
|
6524
|
+
`Kept ${path10.join(relative, name)}: this release doesn't ship it, and you edited it.`
|
|
6525
|
+
);
|
|
6526
|
+
}
|
|
6527
|
+
if (removed.length > 0) {
|
|
6528
|
+
lines2.push(
|
|
6529
|
+
`Remove the ${removed.length} files the system has and this release doesn't: they're listed in ${path10.join(relative, "removed.json")}.`
|
|
6459
6530
|
);
|
|
6460
6531
|
}
|
|
6532
|
+
lines2.push(
|
|
6533
|
+
`Read ${path10.join(relative, "SETUP.md")} and follow it. It publishes the system, installs it on a canvas and checks it.`
|
|
6534
|
+
);
|
|
6461
6535
|
return {
|
|
6462
|
-
ok:
|
|
6536
|
+
ok: kept.length === 0,
|
|
6463
6537
|
lines: lines2,
|
|
6464
|
-
data: {
|
|
6538
|
+
data: {
|
|
6539
|
+
version: pkg.version,
|
|
6540
|
+
out,
|
|
6541
|
+
files: files.size,
|
|
6542
|
+
removed,
|
|
6543
|
+
kept: kept.map((name) => path10.join(out, name)),
|
|
6544
|
+
root: [...rootFiles.keys()].map((name) => path10.join(out, name))
|
|
6545
|
+
}
|
|
6465
6546
|
};
|
|
6466
6547
|
} finally {
|
|
6467
6548
|
pkg.cleanup();
|
|
@@ -6895,7 +6976,7 @@ function program(done, write) {
|
|
|
6895
6976
|
// Errors are printed once, by `main`, as text or JSON.
|
|
6896
6977
|
outputError: () => {
|
|
6897
6978
|
}
|
|
6898
|
-
}).exitOverride().name(CLI_COMMAND).description("Add nxds to your app.").version("0.
|
|
6979
|
+
}).exitOverride().name(CLI_COMMAND).description("Add nxds to your app.").version("0.6.1", "-v, --version", "print the version").helpOption("-h, --help", "show help").helpCommand("help [command]", "show help for a command").option("--json", "print machine-readable JSON").option("--cwd <path>", "run in another folder").addOption(
|
|
6899
6980
|
new Option(
|
|
6900
6981
|
"--registry <url|path>",
|
|
6901
6982
|
"where to get nxds releases (default: https://nxds.dev/r)"
|
|
@@ -6987,7 +7068,7 @@ Docs: https://nxds.dev/getting-started/install`
|
|
|
6987
7068
|
).option(
|
|
6988
7069
|
"--existing <path>",
|
|
6989
7070
|
"a JSON list of the system's current file paths, to list the ones this release removes"
|
|
6990
|
-
).option("--overwrite", "replace the
|
|
7071
|
+
).option("--overwrite", "replace the export in --out", false).option(
|
|
6991
7072
|
"--source <path>",
|
|
6992
7073
|
"a built @nxds/claude-design dist folder, instead of the npm release"
|
|
6993
7074
|
).addOption(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nxds-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Install nxds components, blocks and setup into your app.",
|
|
6
6
|
"keywords": [
|
|
@@ -45,9 +45,9 @@
|
|
|
45
45
|
"@types/semver": "^7.8.0",
|
|
46
46
|
"tsup": "^8.5.1",
|
|
47
47
|
"typescript": "^5.9.3",
|
|
48
|
-
"@nxds/
|
|
49
|
-
"@nxds/
|
|
50
|
-
"@nxds/
|
|
48
|
+
"@nxds/catalog": "0.0.1",
|
|
49
|
+
"@nxds/claude-design": "0.13.2",
|
|
50
|
+
"@nxds/core": "0.12.0"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
53
|
"build": "tsup",
|