@akii09/pdfx-cli 0.1.4 → 0.1.5

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 (2) hide show
  1. package/dist/index.js +662 -235
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -492,8 +492,8 @@ function getErrorMap() {
492
492
 
493
493
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
494
494
  var makeIssue = (params) => {
495
- const { data, path: path11, errorMaps, issueData } = params;
496
- const fullPath = [...path11, ...issueData.path || []];
495
+ const { data, path: path12, errorMaps, issueData } = params;
496
+ const fullPath = [...path12, ...issueData.path || []];
497
497
  const fullIssue = {
498
498
  ...issueData,
499
499
  path: fullPath
@@ -609,11 +609,11 @@ var errorUtil;
609
609
 
610
610
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
611
611
  var ParseInputLazyPath = class {
612
- constructor(parent, value, path11, key) {
612
+ constructor(parent, value, path12, key) {
613
613
  this._cachedPath = [];
614
614
  this.parent = parent;
615
615
  this.data = value;
616
- this._path = path11;
616
+ this._path = path12;
617
617
  this._key = key;
618
618
  }
619
619
  get path() {
@@ -4154,7 +4154,8 @@ var registryFileTypes = [
4154
4154
  "registry:component",
4155
4155
  "registry:lib",
4156
4156
  "registry:style",
4157
- "registry:template"
4157
+ "registry:template",
4158
+ "registry:block"
4158
4159
  ];
4159
4160
  var registryFileSchema = external_exports.object({
4160
4161
  path: external_exports.string().min(1),
@@ -5089,13 +5090,338 @@ async function add(components, options = {}) {
5089
5090
  }
5090
5091
  }
5091
5092
 
5092
- // src/commands/diff.ts
5093
- import fs4 from "fs";
5093
+ // src/commands/block.ts
5094
5094
  import path4 from "path";
5095
5095
  import chalk2 from "chalk";
5096
5096
  import ora2 from "ora";
5097
- var FETCH_TIMEOUT_MS = 1e4;
5098
- async function diff(components) {
5097
+ import prompts2 from "prompts";
5098
+
5099
+ // src/constants.ts
5100
+ var DEFAULTS = {
5101
+ REGISTRY_URL: "https://pdfx.akashpise.dev/r",
5102
+ SCHEMA_URL: "https://pdfx.akashpise.dev/schema.json",
5103
+ COMPONENT_DIR: "./src/components/pdfx",
5104
+ THEME_FILE: "./src/lib/pdfx-theme.ts",
5105
+ TEMPLATE_DIR: "./src/templates/pdfx"
5106
+ };
5107
+ var REGISTRY_SUBPATHS = {
5108
+ TEMPLATES: "templates"
5109
+ };
5110
+
5111
+ // src/commands/block.ts
5112
+ function readConfig2(configPath) {
5113
+ const raw = readJsonFile(configPath);
5114
+ const result = configSchema.safeParse(raw);
5115
+ if (!result.success) {
5116
+ const issues = result.error.issues.map((i) => i.message).join(", ");
5117
+ throw new ConfigError(
5118
+ `Invalid pdfx.json: ${issues}`,
5119
+ `Fix the config or re-run ${chalk2.cyan("pdfx init")}`
5120
+ );
5121
+ }
5122
+ return result.data;
5123
+ }
5124
+ async function fetchBlock(name, registryUrl) {
5125
+ const url = `${registryUrl}/${REGISTRY_SUBPATHS.TEMPLATES}/${name}.json`;
5126
+ let response;
5127
+ try {
5128
+ response = await fetch(url, { signal: AbortSignal.timeout(1e4) });
5129
+ } catch (err) {
5130
+ const isTimeout = err instanceof Error && err.name === "TimeoutError";
5131
+ throw new NetworkError(
5132
+ isTimeout ? "Registry request timed out" : `Could not reach ${registryUrl}`
5133
+ );
5134
+ }
5135
+ if (!response.ok) {
5136
+ throw new RegistryError(
5137
+ response.status === 404 ? `Block "${name}" not found in registry` : `Registry returned HTTP ${response.status}`
5138
+ );
5139
+ }
5140
+ let data;
5141
+ try {
5142
+ data = await response.json();
5143
+ } catch {
5144
+ throw new RegistryError(`Invalid response for "${name}": not valid JSON`);
5145
+ }
5146
+ const result = registryItemSchema.safeParse(data);
5147
+ if (!result.success) {
5148
+ throw new RegistryError(
5149
+ `Invalid registry entry for "${name}": ${result.error.issues[0]?.message}`
5150
+ );
5151
+ }
5152
+ return result.data;
5153
+ }
5154
+ async function fetchComponent2(name, registryUrl) {
5155
+ const url = `${registryUrl}/${name}.json`;
5156
+ let response;
5157
+ try {
5158
+ response = await fetch(url, { signal: AbortSignal.timeout(1e4) });
5159
+ } catch (err) {
5160
+ const isTimeout = err instanceof Error && err.name === "TimeoutError";
5161
+ throw new NetworkError(
5162
+ isTimeout ? "Registry request timed out" : `Could not reach ${registryUrl}`
5163
+ );
5164
+ }
5165
+ if (!response.ok) {
5166
+ throw new RegistryError(
5167
+ response.status === 404 ? `Component "${name}" not found in registry` : `Registry returned HTTP ${response.status}`
5168
+ );
5169
+ }
5170
+ let data;
5171
+ try {
5172
+ data = await response.json();
5173
+ } catch {
5174
+ throw new RegistryError(`Invalid response for "${name}": not valid JSON`);
5175
+ }
5176
+ const result = registryItemSchema.safeParse(data);
5177
+ if (!result.success) {
5178
+ throw new RegistryError(
5179
+ `Invalid registry entry for "${name}": ${result.error.issues[0]?.message}`
5180
+ );
5181
+ }
5182
+ return result.data;
5183
+ }
5184
+ function resolveBlockImports(content, blockName, config) {
5185
+ const cwd = process.cwd();
5186
+ const blockSubdir = path4.resolve(cwd, config.templateDir ?? DEFAULTS.TEMPLATE_DIR, blockName);
5187
+ let result = content.replace(
5188
+ /from '\.\.\/\.\.\/components\/pdfx\/([a-z][a-z0-9-]*)\/pdfx-([a-z][a-z0-9-]*)'/g,
5189
+ (_match, componentName) => {
5190
+ const absCompFile = path4.resolve(
5191
+ cwd,
5192
+ config.componentDir,
5193
+ componentName,
5194
+ `pdfx-${componentName}`
5195
+ );
5196
+ let rel = path4.relative(blockSubdir, absCompFile);
5197
+ if (!rel.startsWith(".")) rel = `./${rel}`;
5198
+ return `from '${rel}'`;
5199
+ }
5200
+ );
5201
+ if (config.theme) {
5202
+ const absThemePath = path4.resolve(cwd, config.theme).replace(/\.tsx?$/, "");
5203
+ let relTheme = path4.relative(blockSubdir, absThemePath);
5204
+ if (!relTheme.startsWith(".")) relTheme = `./${relTheme}`;
5205
+ const absContextPath = path4.join(
5206
+ path4.dirname(path4.resolve(cwd, config.theme)),
5207
+ "pdfx-theme-context"
5208
+ );
5209
+ let relContext = path4.relative(blockSubdir, absContextPath);
5210
+ if (!relContext.startsWith(".")) relContext = `./${relContext}`;
5211
+ result = result.replace(/from '\.\.\/\.\.\/lib\/pdfx-theme'/g, `from '${relTheme}'`);
5212
+ result = result.replace(/from '\.\.\/\.\.\/lib\/pdfx-theme-context'/g, `from '${relContext}'`);
5213
+ }
5214
+ return result;
5215
+ }
5216
+ async function resolveConflict(fileName, currentDecision) {
5217
+ if (currentDecision === "overwrite-all") return "overwrite-all";
5218
+ const { action } = await prompts2({
5219
+ type: "select",
5220
+ name: "action",
5221
+ message: `${chalk2.yellow(fileName)} already exists. What would you like to do?`,
5222
+ choices: [
5223
+ { title: "Skip", value: "skip", description: "Keep the existing file unchanged" },
5224
+ { title: "Overwrite", value: "overwrite", description: "Replace this file only" },
5225
+ {
5226
+ title: "Overwrite all",
5227
+ value: "overwrite-all",
5228
+ description: "Replace all conflicting files"
5229
+ }
5230
+ ],
5231
+ initial: 0
5232
+ });
5233
+ if (!action) throw new ValidationError("Cancelled by user");
5234
+ return action;
5235
+ }
5236
+ async function ensurePeerComponents(block, config, force) {
5237
+ const installedPeers = [];
5238
+ const peerWarnings = [];
5239
+ if (!block.peerComponents || block.peerComponents.length === 0) {
5240
+ return { installedPeers, peerWarnings };
5241
+ }
5242
+ const componentBaseDir = path4.resolve(process.cwd(), config.componentDir);
5243
+ for (const componentName of block.peerComponents) {
5244
+ const componentDir = path4.join(componentBaseDir, componentName);
5245
+ const expectedMain = path4.join(componentDir, `pdfx-${componentName}.tsx`);
5246
+ if (checkFileExists(componentDir)) {
5247
+ if (!checkFileExists(expectedMain)) {
5248
+ peerWarnings.push(
5249
+ `${componentName}: directory exists but expected file missing (${path4.basename(expectedMain)})`
5250
+ );
5251
+ } else {
5252
+ peerWarnings.push(
5253
+ `${componentName}: already exists, skipped install (use "pdfx diff ${componentName}" to verify freshness)`
5254
+ );
5255
+ }
5256
+ continue;
5257
+ }
5258
+ const component = await fetchComponent2(componentName, config.registry);
5259
+ ensureDir(componentDir);
5260
+ const componentRelDir = path4.join(config.componentDir, component.name);
5261
+ for (const file of component.files) {
5262
+ const fileName = path4.basename(file.path);
5263
+ const filePath = safePath(componentDir, fileName);
5264
+ let content = file.content;
5265
+ if (config.theme && (content.includes("pdfx-theme") || content.includes("pdfx-theme-context"))) {
5266
+ content = resolveThemeImport(componentRelDir, config.theme, content);
5267
+ }
5268
+ if (checkFileExists(filePath) && !force) {
5269
+ peerWarnings.push(
5270
+ `${componentName}: skipped writing ${fileName} because it already exists (use --force to overwrite)`
5271
+ );
5272
+ continue;
5273
+ }
5274
+ writeFile(filePath, content);
5275
+ }
5276
+ installedPeers.push(componentName);
5277
+ }
5278
+ return { installedPeers, peerWarnings };
5279
+ }
5280
+ async function installBlock(name, config, force) {
5281
+ const block = await fetchBlock(name, config.registry);
5282
+ const peerResult = await ensurePeerComponents(block, config, force);
5283
+ const blockBaseDir = path4.resolve(process.cwd(), config.templateDir ?? DEFAULTS.TEMPLATE_DIR);
5284
+ const blockDir = path4.join(blockBaseDir, block.name);
5285
+ ensureDir(blockDir);
5286
+ const filesToWrite = [];
5287
+ for (const file of block.files) {
5288
+ const fileName = path4.basename(file.path);
5289
+ const filePath = safePath(blockDir, fileName);
5290
+ let content = file.content;
5291
+ if (/\.(tsx?|jsx?)$/.test(fileName) && content.includes("../../")) {
5292
+ content = resolveBlockImports(content, block.name, config);
5293
+ }
5294
+ filesToWrite.push({ filePath, content });
5295
+ }
5296
+ if (!force) {
5297
+ let globalDecision = null;
5298
+ const resolved = [];
5299
+ for (const file of filesToWrite) {
5300
+ if (checkFileExists(file.filePath)) {
5301
+ const decision = await resolveConflict(path4.basename(file.filePath), globalDecision);
5302
+ if (decision === "overwrite-all") {
5303
+ globalDecision = "overwrite-all";
5304
+ }
5305
+ resolved.push({ ...file, skip: decision === "skip" });
5306
+ } else {
5307
+ resolved.push({ ...file, skip: false });
5308
+ }
5309
+ }
5310
+ for (const file of resolved) {
5311
+ if (!file.skip) {
5312
+ writeFile(file.filePath, file.content);
5313
+ } else {
5314
+ console.log(chalk2.dim(` skipped ${path4.basename(file.filePath)}`));
5315
+ }
5316
+ }
5317
+ } else {
5318
+ for (const file of filesToWrite) {
5319
+ writeFile(file.filePath, file.content);
5320
+ }
5321
+ }
5322
+ if (block.peerComponents && block.peerComponents.length > 0) {
5323
+ const componentBaseDir = path4.resolve(process.cwd(), config.componentDir);
5324
+ const missing = [];
5325
+ for (const comp of block.peerComponents) {
5326
+ const compDir = path4.join(componentBaseDir, comp);
5327
+ if (!checkFileExists(compDir)) {
5328
+ missing.push(comp);
5329
+ }
5330
+ }
5331
+ if (missing.length > 0) {
5332
+ console.log();
5333
+ console.log(chalk2.yellow(" Missing peer components:"));
5334
+ for (const comp of missing) {
5335
+ console.log(chalk2.dim(` ${comp} \u2192 run: ${chalk2.cyan(`pdfx add ${comp}`)}`));
5336
+ }
5337
+ }
5338
+ }
5339
+ if (config.theme) {
5340
+ const absThemePath = path4.resolve(process.cwd(), config.theme);
5341
+ const contextPath = path4.join(path4.dirname(absThemePath), "pdfx-theme-context.tsx");
5342
+ if (!checkFileExists(contextPath)) {
5343
+ ensureDir(path4.dirname(contextPath));
5344
+ writeFile(contextPath, generateThemeContextFile());
5345
+ }
5346
+ }
5347
+ return peerResult;
5348
+ }
5349
+ async function blockAdd(names, options = {}) {
5350
+ const configPath = path4.join(process.cwd(), "pdfx.json");
5351
+ if (!checkFileExists(configPath)) {
5352
+ console.error(chalk2.red("Error: pdfx.json not found"));
5353
+ console.log(chalk2.yellow("Run: pdfx init"));
5354
+ process.exit(1);
5355
+ }
5356
+ let config;
5357
+ try {
5358
+ config = readConfig2(configPath);
5359
+ } catch (error) {
5360
+ if (error instanceof ConfigError) {
5361
+ console.error(chalk2.red(error.message));
5362
+ if (error.suggestion) console.log(chalk2.yellow(` Hint: ${error.suggestion}`));
5363
+ } else {
5364
+ const message = error instanceof Error ? error.message : String(error);
5365
+ console.error(chalk2.red(message));
5366
+ }
5367
+ process.exit(1);
5368
+ }
5369
+ const force = options.force ?? false;
5370
+ const failed = [];
5371
+ for (const blockName of names) {
5372
+ const nameResult = componentNameSchema.safeParse(blockName);
5373
+ if (!nameResult.success) {
5374
+ console.error(chalk2.red(`Invalid block name: "${blockName}"`));
5375
+ console.log(
5376
+ chalk2.dim(' Names must be lowercase alphanumeric with hyphens (e.g., "invoice-classic")')
5377
+ );
5378
+ failed.push(blockName);
5379
+ continue;
5380
+ }
5381
+ const spinner = ora2(`Adding block ${blockName}...`).start();
5382
+ try {
5383
+ const result = await installBlock(blockName, config, force);
5384
+ spinner.succeed(`Added block ${chalk2.cyan(blockName)}`);
5385
+ if (result.installedPeers.length > 0) {
5386
+ console.log(
5387
+ chalk2.green(` Installed required components: ${result.installedPeers.join(", ")}`)
5388
+ );
5389
+ }
5390
+ for (const warning of result.peerWarnings) {
5391
+ console.log(chalk2.yellow(` Warning: ${warning}`));
5392
+ }
5393
+ } catch (error) {
5394
+ if (error instanceof ValidationError && error.message.includes("Cancelled")) {
5395
+ spinner.info("Cancelled");
5396
+ process.exit(0);
5397
+ } else if (error instanceof NetworkError || error instanceof RegistryError || error instanceof ValidationError) {
5398
+ spinner.fail(error.message);
5399
+ if (error.suggestion) {
5400
+ console.log(chalk2.dim(` Hint: ${error.suggestion}`));
5401
+ }
5402
+ } else {
5403
+ spinner.fail(`Failed to add block ${blockName}`);
5404
+ const message = error instanceof Error ? error.message : String(error);
5405
+ console.error(chalk2.dim(` ${message}`));
5406
+ }
5407
+ failed.push(blockName);
5408
+ }
5409
+ }
5410
+ console.log();
5411
+ if (failed.length > 0) {
5412
+ console.log(chalk2.yellow(`Failed: ${failed.join(", ")}`));
5413
+ }
5414
+ if (failed.length < names.length) {
5415
+ const resolvedDir = path4.resolve(process.cwd(), config.templateDir ?? DEFAULTS.TEMPLATE_DIR);
5416
+ console.log(chalk2.green("Done!"));
5417
+ console.log(chalk2.dim(`Blocks installed to: ${resolvedDir}
5418
+ `));
5419
+ }
5420
+ if (failed.length > 0) {
5421
+ process.exit(1);
5422
+ }
5423
+ }
5424
+ async function blockList() {
5099
5425
  const configPath = path4.join(process.cwd(), "pdfx.json");
5100
5426
  if (!checkFileExists(configPath)) {
5101
5427
  console.error(chalk2.red("Error: pdfx.json not found"));
@@ -5109,14 +5435,85 @@ async function diff(components) {
5109
5435
  process.exit(1);
5110
5436
  }
5111
5437
  const config = configResult.data;
5112
- const targetDir = path4.resolve(process.cwd(), config.componentDir);
5438
+ const spinner = ora2("Fetching block list...").start();
5439
+ try {
5440
+ let response;
5441
+ try {
5442
+ response = await fetch(`${config.registry}/index.json`, {
5443
+ signal: AbortSignal.timeout(1e4)
5444
+ });
5445
+ } catch (err) {
5446
+ const isTimeout = err instanceof Error && err.name === "TimeoutError";
5447
+ throw new NetworkError(
5448
+ isTimeout ? "Registry request timed out" : `Could not reach ${config.registry}`
5449
+ );
5450
+ }
5451
+ if (!response.ok) {
5452
+ throw new RegistryError(`Registry returned HTTP ${response.status}`);
5453
+ }
5454
+ const data = await response.json();
5455
+ const result = registrySchema.safeParse(data);
5456
+ if (!result.success) {
5457
+ throw new RegistryError("Invalid registry format");
5458
+ }
5459
+ spinner.stop();
5460
+ const blocks = result.data.items.filter((item) => item.type === "registry:block");
5461
+ if (blocks.length === 0) {
5462
+ console.log(chalk2.dim("\n No blocks available in the registry.\n"));
5463
+ return;
5464
+ }
5465
+ const blockBaseDir = path4.resolve(process.cwd(), config.templateDir ?? DEFAULTS.TEMPLATE_DIR);
5466
+ console.log(chalk2.bold(`
5467
+ Available Blocks (${blocks.length})
5468
+ `));
5469
+ for (const item of blocks) {
5470
+ const blockDir = path4.join(blockBaseDir, item.name);
5471
+ const installed = checkFileExists(blockDir);
5472
+ const status = installed ? chalk2.green("[installed]") : chalk2.dim("[not installed]");
5473
+ console.log(` ${chalk2.cyan(item.name.padEnd(22))} ${item.description ?? ""}`);
5474
+ console.log(` ${"".padEnd(22)} ${status}`);
5475
+ if (item.peerComponents && item.peerComponents.length > 0) {
5476
+ console.log(chalk2.dim(` ${"".padEnd(22)} requires: ${item.peerComponents.join(", ")}`));
5477
+ }
5478
+ console.log();
5479
+ }
5480
+ console.log(chalk2.dim(` Install with: ${chalk2.cyan("pdfx block add <block-name>")}
5481
+ `));
5482
+ } catch (error) {
5483
+ const message = error instanceof Error ? error.message : String(error);
5484
+ spinner.fail(message);
5485
+ process.exit(1);
5486
+ }
5487
+ }
5488
+
5489
+ // src/commands/diff.ts
5490
+ import fs4 from "fs";
5491
+ import path5 from "path";
5492
+ import chalk3 from "chalk";
5493
+ import ora3 from "ora";
5494
+ var FETCH_TIMEOUT_MS = 1e4;
5495
+ async function diff(components) {
5496
+ const configPath = path5.join(process.cwd(), "pdfx.json");
5497
+ if (!checkFileExists(configPath)) {
5498
+ console.error(chalk3.red("Error: pdfx.json not found"));
5499
+ console.log(chalk3.yellow("Run: pdfx init"));
5500
+ process.exit(1);
5501
+ }
5502
+ const raw = readJsonFile(configPath);
5503
+ const configResult = configSchema.safeParse(raw);
5504
+ if (!configResult.success) {
5505
+ console.error(chalk3.red("Invalid pdfx.json"));
5506
+ process.exit(1);
5507
+ }
5508
+ const config = configResult.data;
5509
+ const targetDir = path5.resolve(process.cwd(), config.componentDir);
5113
5510
  for (const componentName of components) {
5114
5511
  const nameResult = componentNameSchema.safeParse(componentName);
5115
5512
  if (!nameResult.success) {
5116
- console.error(chalk2.red(`Invalid component name: "${componentName}"`));
5513
+ console.error(chalk3.red(`Invalid component name: "${componentName}"`));
5117
5514
  continue;
5118
5515
  }
5119
- const spinner = ora2(`Comparing ${componentName}...`).start();
5516
+ const spinner = ora3(`Comparing ${componentName}...`).start();
5120
5517
  try {
5121
5518
  let response;
5122
5519
  try {
@@ -5127,8 +5524,8 @@ async function diff(components) {
5127
5524
  const isTimeout = err instanceof Error && err.name === "TimeoutError";
5128
5525
  throw new NetworkError(
5129
5526
  isTimeout ? `Registry request timed out after 10 seconds.
5130
- ${chalk2.dim("Check your internet connection or try again later.")}` : `Could not reach registry at ${config.registry}
5131
- ${chalk2.dim("Verify the URL is correct and you have internet access.")}`
5527
+ ${chalk3.dim("Check your internet connection or try again later.")}` : `Could not reach registry at ${config.registry}
5528
+ ${chalk3.dim("Verify the URL is correct and you have internet access.")}`
5132
5529
  );
5133
5530
  }
5134
5531
  if (!response.ok) {
@@ -5143,32 +5540,32 @@ async function diff(components) {
5143
5540
  }
5144
5541
  const component = result.data;
5145
5542
  spinner.stop();
5146
- const componentSubDir = path4.join(targetDir, component.name);
5543
+ const componentSubDir = path5.join(targetDir, component.name);
5147
5544
  for (const file of component.files) {
5148
- const fileName = path4.basename(file.path);
5545
+ const fileName = path5.basename(file.path);
5149
5546
  const localPath = safePath(componentSubDir, fileName);
5150
5547
  if (!checkFileExists(localPath)) {
5151
- console.log(chalk2.yellow(` ${fileName}: not installed locally`));
5548
+ console.log(chalk3.yellow(` ${fileName}: not installed locally`));
5152
5549
  continue;
5153
5550
  }
5154
5551
  const localContent = fs4.readFileSync(localPath, "utf-8");
5155
5552
  const registryContent = config.theme && (file.content.includes("pdfx-theme") || file.content.includes("pdfx-theme-context")) ? resolveThemeImport(
5156
- path4.join(config.componentDir, component.name),
5553
+ path5.join(config.componentDir, component.name),
5157
5554
  config.theme,
5158
5555
  file.content
5159
5556
  ) : file.content;
5160
5557
  if (localContent === registryContent) {
5161
- console.log(chalk2.green(` ${fileName}: up to date`));
5558
+ console.log(chalk3.green(` ${fileName}: up to date`));
5162
5559
  } else {
5163
- console.log(chalk2.yellow(` ${fileName}: differs from registry`));
5560
+ console.log(chalk3.yellow(` ${fileName}: differs from registry`));
5164
5561
  const localLines = localContent.split("\n");
5165
5562
  const registryLines = registryContent.split("\n");
5166
5563
  const lineDiff = localLines.length - registryLines.length;
5167
- console.log(chalk2.dim(` Local: ${localLines.length} lines`));
5168
- console.log(chalk2.dim(` Registry: ${registryLines.length} lines`));
5564
+ console.log(chalk3.dim(` Local: ${localLines.length} lines`));
5565
+ console.log(chalk3.dim(` Registry: ${registryLines.length} lines`));
5169
5566
  if (lineDiff !== 0) {
5170
5567
  const diffText = lineDiff > 0 ? `${Math.abs(lineDiff)} line${Math.abs(lineDiff) > 1 ? "s" : ""} added locally` : `${Math.abs(lineDiff)} line${Math.abs(lineDiff) > 1 ? "s" : ""} removed locally`;
5171
- console.log(chalk2.dim(` \u2192 ${diffText}`));
5568
+ console.log(chalk3.dim(` \u2192 ${diffText}`));
5172
5569
  }
5173
5570
  }
5174
5571
  }
@@ -5182,32 +5579,20 @@ async function diff(components) {
5182
5579
 
5183
5580
  // src/commands/init.ts
5184
5581
  import fs7 from "fs";
5185
- import path7 from "path";
5186
- import chalk5 from "chalk";
5187
- import ora4 from "ora";
5188
- import prompts3 from "prompts";
5189
-
5190
- // src/constants.ts
5191
- var DEFAULTS = {
5192
- REGISTRY_URL: "https://pdfx.akashpise.dev/r",
5193
- SCHEMA_URL: "https://pdfx.akashpise.dev/schema.json",
5194
- COMPONENT_DIR: "./src/components/pdfx",
5195
- THEME_FILE: "./src/lib/pdfx-theme.ts",
5196
- TEMPLATE_DIR: "./src/templates/pdfx"
5197
- };
5198
- var REGISTRY_SUBPATHS = {
5199
- TEMPLATES: "templates"
5200
- };
5582
+ import path8 from "path";
5583
+ import chalk6 from "chalk";
5584
+ import ora5 from "ora";
5585
+ import prompts4 from "prompts";
5201
5586
 
5202
5587
  // src/utils/install-dependencies.ts
5203
- import chalk3 from "chalk";
5588
+ import chalk4 from "chalk";
5204
5589
  import { execa } from "execa";
5205
- import ora3 from "ora";
5206
- import prompts2 from "prompts";
5590
+ import ora4 from "ora";
5591
+ import prompts3 from "prompts";
5207
5592
 
5208
5593
  // src/utils/package-manager.ts
5209
5594
  import fs5 from "fs";
5210
- import path5 from "path";
5595
+ import path6 from "path";
5211
5596
  var PACKAGE_MANAGERS = {
5212
5597
  pnpm: {
5213
5598
  name: "pnpm",
@@ -5234,7 +5619,7 @@ function detectPackageManager(cwd = process.cwd()) {
5234
5619
  const managers = ["pnpm", "yarn", "bun", "npm"];
5235
5620
  for (const manager of managers) {
5236
5621
  const info = PACKAGE_MANAGERS[manager];
5237
- const lockfilePath = path5.join(cwd, info.lockfile);
5622
+ const lockfilePath = path6.join(cwd, info.lockfile);
5238
5623
  if (fs5.existsSync(lockfilePath)) {
5239
5624
  return info;
5240
5625
  }
@@ -5258,10 +5643,10 @@ async function promptAndInstallReactPdf(validation, cwd = process.cwd()) {
5258
5643
  const pm = detectPackageManager(cwd);
5259
5644
  const packageName = "@react-pdf/renderer";
5260
5645
  const installCmd = getInstallCommand(pm.name, [packageName]);
5261
- console.log(chalk3.yellow("\n \u26A0 @react-pdf/renderer is required but not installed\n"));
5262
- console.log(chalk3.dim(` This command will run: ${installCmd}
5646
+ console.log(chalk4.yellow("\n \u26A0 @react-pdf/renderer is required but not installed\n"));
5647
+ console.log(chalk4.dim(` This command will run: ${installCmd}
5263
5648
  `));
5264
- const { shouldInstall } = await prompts2({
5649
+ const { shouldInstall } = await prompts3({
5265
5650
  type: "confirm",
5266
5651
  name: "shouldInstall",
5267
5652
  message: "Install @react-pdf/renderer now?",
@@ -5271,10 +5656,10 @@ async function promptAndInstallReactPdf(validation, cwd = process.cwd()) {
5271
5656
  return {
5272
5657
  success: false,
5273
5658
  message: `Installation cancelled. Please install manually:
5274
- ${chalk3.cyan(installCmd)}`
5659
+ ${chalk4.cyan(installCmd)}`
5275
5660
  };
5276
5661
  }
5277
- const spinner = ora3("Installing @react-pdf/renderer...").start();
5662
+ const spinner = ora4("Installing @react-pdf/renderer...").start();
5278
5663
  try {
5279
5664
  await execa(pm.name, ["add", packageName], {
5280
5665
  cwd,
@@ -5291,7 +5676,7 @@ async function promptAndInstallReactPdf(validation, cwd = process.cwd()) {
5291
5676
  return {
5292
5677
  success: false,
5293
5678
  message: `Installation failed: ${message}
5294
- Try manually: ${chalk3.cyan(installCmd)}`
5679
+ Try manually: ${chalk4.cyan(installCmd)}`
5295
5680
  };
5296
5681
  }
5297
5682
  }
@@ -5299,7 +5684,7 @@ async function ensureReactPdfRenderer(validation, cwd = process.cwd()) {
5299
5684
  if (!validation.installed) {
5300
5685
  const result = await promptAndInstallReactPdf(validation, cwd);
5301
5686
  if (!result.success) {
5302
- console.error(chalk3.red(`
5687
+ console.error(chalk4.red(`
5303
5688
  ${result.message}
5304
5689
  `));
5305
5690
  return false;
@@ -5308,10 +5693,10 @@ async function ensureReactPdfRenderer(validation, cwd = process.cwd()) {
5308
5693
  }
5309
5694
  if (!validation.valid) {
5310
5695
  console.log(
5311
- chalk3.yellow(
5696
+ chalk4.yellow(
5312
5697
  `
5313
5698
  \u26A0 ${validation.message}
5314
- ${chalk3.dim("\u2192")} You may encounter compatibility issues
5699
+ ${chalk4.dim("\u2192")} You may encounter compatibility issues
5315
5700
  `
5316
5701
  )
5317
5702
  );
@@ -5320,13 +5705,13 @@ async function ensureReactPdfRenderer(validation, cwd = process.cwd()) {
5320
5705
  }
5321
5706
 
5322
5707
  // src/utils/pre-flight.ts
5323
- import chalk4 from "chalk";
5708
+ import chalk5 from "chalk";
5324
5709
 
5325
5710
  // src/utils/environment-validator.ts
5326
5711
  import fs6 from "fs";
5327
- import path6 from "path";
5712
+ import path7 from "path";
5328
5713
  function validatePackageJson(cwd = process.cwd()) {
5329
- const pkgPath = path6.join(cwd, "package.json");
5714
+ const pkgPath = path7.join(cwd, "package.json");
5330
5715
  const exists = fs6.existsSync(pkgPath);
5331
5716
  return {
5332
5717
  valid: exists,
@@ -5335,7 +5720,7 @@ function validatePackageJson(cwd = process.cwd()) {
5335
5720
  };
5336
5721
  }
5337
5722
  function validateReactProject(cwd = process.cwd()) {
5338
- const pkgPath = path6.join(cwd, "package.json");
5723
+ const pkgPath = path7.join(cwd, "package.json");
5339
5724
  if (!fs6.existsSync(pkgPath)) {
5340
5725
  return {
5341
5726
  valid: false,
@@ -5362,7 +5747,7 @@ function validateReactProject(cwd = process.cwd()) {
5362
5747
  }
5363
5748
  }
5364
5749
  function validatePdfxConfig(cwd = process.cwd()) {
5365
- const configPath = path6.join(cwd, "pdfx.json");
5750
+ const configPath = path7.join(cwd, "pdfx.json");
5366
5751
  const exists = fs6.existsSync(configPath);
5367
5752
  return {
5368
5753
  valid: true,
@@ -5387,43 +5772,43 @@ function runPreFlightChecks(cwd = process.cwd()) {
5387
5772
  if (!environment.hasPackageJson.valid) {
5388
5773
  blockingErrors.push(
5389
5774
  `${environment.hasPackageJson.message}
5390
- ${chalk4.dim("\u2192")} ${environment.hasPackageJson.fixCommand}`
5775
+ ${chalk5.dim("\u2192")} ${environment.hasPackageJson.fixCommand}`
5391
5776
  );
5392
5777
  } else if (!environment.isReactProject.valid) {
5393
5778
  blockingErrors.push(
5394
5779
  `${environment.isReactProject.message}
5395
- ${chalk4.dim("\u2192")} ${environment.isReactProject.fixCommand}`
5780
+ ${chalk5.dim("\u2192")} ${environment.isReactProject.fixCommand}`
5396
5781
  );
5397
5782
  } else {
5398
5783
  if (!dependencies.react.valid && dependencies.react.installed) {
5399
5784
  warnings.push(
5400
5785
  `${dependencies.react.message}
5401
- ${chalk4.dim("\u2192")} Current: ${dependencies.react.currentVersion}, Required: ${dependencies.react.requiredVersion}`
5786
+ ${chalk5.dim("\u2192")} Current: ${dependencies.react.currentVersion}, Required: ${dependencies.react.requiredVersion}`
5402
5787
  );
5403
5788
  } else if (!dependencies.react.installed) {
5404
5789
  blockingErrors.push(
5405
5790
  `${dependencies.react.message}
5406
- ${chalk4.dim("\u2192")} Install React: npm install react react-dom`
5791
+ ${chalk5.dim("\u2192")} Install React: npm install react react-dom`
5407
5792
  );
5408
5793
  }
5409
5794
  }
5410
5795
  if (!dependencies.nodeJs.valid) {
5411
5796
  blockingErrors.push(
5412
5797
  `${dependencies.nodeJs.message}
5413
- ${chalk4.dim("\u2192")} Current: ${dependencies.nodeJs.currentVersion}, Required: ${dependencies.nodeJs.requiredVersion}
5414
- ${chalk4.dim("\u2192")} Visit https://nodejs.org to upgrade`
5798
+ ${chalk5.dim("\u2192")} Current: ${dependencies.nodeJs.currentVersion}, Required: ${dependencies.nodeJs.requiredVersion}
5799
+ ${chalk5.dim("\u2192")} Visit https://nodejs.org to upgrade`
5415
5800
  );
5416
5801
  }
5417
5802
  if (dependencies.reactPdfRenderer.installed && !dependencies.reactPdfRenderer.valid) {
5418
5803
  warnings.push(
5419
5804
  `${dependencies.reactPdfRenderer.message}
5420
- ${chalk4.dim("\u2192")} Consider upgrading: npm install @react-pdf/renderer@latest`
5805
+ ${chalk5.dim("\u2192")} Consider upgrading: npm install @react-pdf/renderer@latest`
5421
5806
  );
5422
5807
  }
5423
5808
  if (dependencies.typescript && !dependencies.typescript.valid) {
5424
5809
  warnings.push(
5425
5810
  `${dependencies.typescript.message}
5426
- ${chalk4.dim("\u2192")} Install types: npm install -D @types/react-pdf`
5811
+ ${chalk5.dim("\u2192")} Install types: npm install -D @types/react-pdf`
5427
5812
  );
5428
5813
  }
5429
5814
  return {
@@ -5435,58 +5820,58 @@ function runPreFlightChecks(cwd = process.cwd()) {
5435
5820
  };
5436
5821
  }
5437
5822
  function displayPreFlightResults(result) {
5438
- console.log(chalk4.bold("\n Pre-flight Checks:\n"));
5823
+ console.log(chalk5.bold("\n Pre-flight Checks:\n"));
5439
5824
  if (result.blockingErrors.length > 0) {
5440
- console.log(chalk4.red(" \u2717 Blocking Issues:\n"));
5825
+ console.log(chalk5.red(" \u2717 Blocking Issues:\n"));
5441
5826
  for (const error of result.blockingErrors) {
5442
- console.log(chalk4.red(` \u2022 ${error}
5827
+ console.log(chalk5.red(` \u2022 ${error}
5443
5828
  `));
5444
5829
  }
5445
5830
  }
5446
5831
  if (result.warnings.length > 0) {
5447
- console.log(chalk4.yellow(" \u26A0 Warnings:\n"));
5832
+ console.log(chalk5.yellow(" \u26A0 Warnings:\n"));
5448
5833
  for (const warning of result.warnings) {
5449
- console.log(chalk4.yellow(` \u2022 ${warning}
5834
+ console.log(chalk5.yellow(` \u2022 ${warning}
5450
5835
  `));
5451
5836
  }
5452
5837
  }
5453
5838
  if (result.blockingErrors.length === 0 && result.warnings.length === 0) {
5454
- console.log(chalk4.green(" \u2713 All checks passed!\n"));
5839
+ console.log(chalk5.green(" \u2713 All checks passed!\n"));
5455
5840
  }
5456
5841
  }
5457
5842
 
5458
5843
  // src/commands/init.ts
5459
5844
  async function init() {
5460
- console.log(chalk5.bold.cyan("\n Welcome to the pdfx cli\n"));
5845
+ console.log(chalk6.bold.cyan("\n Welcome to the pdfx cli\n"));
5461
5846
  const preFlightResult = runPreFlightChecks();
5462
5847
  displayPreFlightResults(preFlightResult);
5463
5848
  if (!preFlightResult.canProceed) {
5464
5849
  console.error(
5465
- chalk5.red("\n Cannot proceed due to blocking issues. Please fix them and try again.\n")
5850
+ chalk6.red("\n Cannot proceed due to blocking issues. Please fix them and try again.\n")
5466
5851
  );
5467
5852
  process.exit(1);
5468
5853
  }
5469
5854
  const hasReactPdf = await ensureReactPdfRenderer(preFlightResult.dependencies.reactPdfRenderer);
5470
5855
  if (!hasReactPdf) {
5471
5856
  console.error(
5472
- chalk5.red("\n @react-pdf/renderer is required. Please install it and try again.\n")
5857
+ chalk6.red("\n @react-pdf/renderer is required. Please install it and try again.\n")
5473
5858
  );
5474
5859
  process.exit(1);
5475
5860
  }
5476
- const existingConfig = path7.join(process.cwd(), "pdfx.json");
5861
+ const existingConfig = path8.join(process.cwd(), "pdfx.json");
5477
5862
  if (fs7.existsSync(existingConfig)) {
5478
- const { overwrite } = await prompts3({
5863
+ const { overwrite } = await prompts4({
5479
5864
  type: "confirm",
5480
5865
  name: "overwrite",
5481
5866
  message: "pdfx.json already exists. Overwrite?",
5482
5867
  initial: false
5483
5868
  });
5484
5869
  if (!overwrite) {
5485
- console.log(chalk5.yellow("Init cancelled \u2014 existing config preserved."));
5870
+ console.log(chalk6.yellow("Init cancelled \u2014 existing config preserved."));
5486
5871
  return;
5487
5872
  }
5488
5873
  }
5489
- const answers = await prompts3(
5874
+ const answers = await prompts4(
5490
5875
  [
5491
5876
  {
5492
5877
  type: "text",
@@ -5497,7 +5882,7 @@ async function init() {
5497
5882
  if (!value || value.trim().length === 0) {
5498
5883
  return "Component directory is required";
5499
5884
  }
5500
- if (path7.isAbsolute(value)) {
5885
+ if (path8.isAbsolute(value)) {
5501
5886
  return "Please use a relative path (e.g., ./src/components/pdfx)";
5502
5887
  }
5503
5888
  if (!value.startsWith(".")) {
@@ -5550,7 +5935,7 @@ async function init() {
5550
5935
  if (!value || value.trim().length === 0) {
5551
5936
  return "Theme path is required";
5552
5937
  }
5553
- if (path7.isAbsolute(value)) {
5938
+ if (path8.isAbsolute(value)) {
5554
5939
  return "Please use a relative path (e.g., ./src/lib/pdfx-theme.ts)";
5555
5940
  }
5556
5941
  if (!value.endsWith(".ts") && !value.endsWith(".tsx")) {
@@ -5562,13 +5947,13 @@ async function init() {
5562
5947
  ],
5563
5948
  {
5564
5949
  onCancel: () => {
5565
- console.log(chalk5.yellow("\nSetup cancelled."));
5950
+ console.log(chalk6.yellow("\nSetup cancelled."));
5566
5951
  process.exit(0);
5567
5952
  }
5568
5953
  }
5569
5954
  );
5570
5955
  if (!answers.componentDir || !answers.registry) {
5571
- console.error(chalk5.red("Missing required fields. Run pdfx init again."));
5956
+ console.error(chalk6.red("Missing required fields. Run pdfx init again."));
5572
5957
  process.exit(1);
5573
5958
  }
5574
5959
  const config = {
@@ -5580,50 +5965,50 @@ async function init() {
5580
5965
  const validation = configSchema.safeParse(config);
5581
5966
  if (!validation.success) {
5582
5967
  const issues = validation.error.issues.map((i) => i.message).join(", ");
5583
- console.error(chalk5.red(`Invalid configuration: ${issues}`));
5968
+ console.error(chalk6.red(`Invalid configuration: ${issues}`));
5584
5969
  process.exit(1);
5585
5970
  }
5586
- const spinner = ora4("Creating config and theme files...").start();
5971
+ const spinner = ora5("Creating config and theme files...").start();
5587
5972
  try {
5588
- const componentDirPath = path7.resolve(process.cwd(), answers.componentDir);
5973
+ const componentDirPath = path8.resolve(process.cwd(), answers.componentDir);
5589
5974
  ensureDir(componentDirPath);
5590
- fs7.writeFileSync(path7.join(process.cwd(), "pdfx.json"), JSON.stringify(config, null, 2));
5975
+ fs7.writeFileSync(path8.join(process.cwd(), "pdfx.json"), JSON.stringify(config, null, 2));
5591
5976
  const presetName = answers.themePreset || "professional";
5592
5977
  const preset = themePresets[presetName];
5593
- const themePath = path7.resolve(process.cwd(), config.theme);
5594
- ensureDir(path7.dirname(themePath));
5978
+ const themePath = path8.resolve(process.cwd(), config.theme);
5979
+ ensureDir(path8.dirname(themePath));
5595
5980
  fs7.writeFileSync(themePath, generateThemeFile(preset), "utf-8");
5596
- const contextPath = path7.join(path7.dirname(themePath), "pdfx-theme-context.tsx");
5981
+ const contextPath = path8.join(path8.dirname(themePath), "pdfx-theme-context.tsx");
5597
5982
  fs7.writeFileSync(contextPath, generateThemeContextFile(), "utf-8");
5598
5983
  spinner.succeed(`Created pdfx.json + ${config.theme} (${presetName} theme)`);
5599
- console.log(chalk5.green("\nSuccess! You can now run:"));
5600
- console.log(chalk5.cyan(" pdfx add heading"));
5601
- console.log(chalk5.dim(`
5602
- Components: ${path7.resolve(process.cwd(), answers.componentDir)}`));
5603
- console.log(chalk5.dim(` Theme: ${path7.resolve(process.cwd(), config.theme)}
5984
+ console.log(chalk6.green("\nSuccess! You can now run:"));
5985
+ console.log(chalk6.cyan(" pdfx add heading"));
5986
+ console.log(chalk6.dim(`
5987
+ Components: ${path8.resolve(process.cwd(), answers.componentDir)}`));
5988
+ console.log(chalk6.dim(` Theme: ${path8.resolve(process.cwd(), config.theme)}
5604
5989
  `));
5605
5990
  } catch (error) {
5606
5991
  spinner.fail("Failed to create config");
5607
5992
  const message = error instanceof Error ? error.message : String(error);
5608
- console.error(chalk5.dim(` ${message}`));
5993
+ console.error(chalk6.dim(` ${message}`));
5609
5994
  process.exit(1);
5610
5995
  }
5611
5996
  }
5612
5997
 
5613
5998
  // src/commands/list.ts
5614
- import path8 from "path";
5615
- import chalk6 from "chalk";
5616
- import ora5 from "ora";
5999
+ import path9 from "path";
6000
+ import chalk7 from "chalk";
6001
+ import ora6 from "ora";
5617
6002
  var FETCH_TIMEOUT_MS2 = 1e4;
5618
6003
  async function list() {
5619
- const configPath = path8.join(process.cwd(), "pdfx.json");
6004
+ const configPath = path9.join(process.cwd(), "pdfx.json");
5620
6005
  let config;
5621
6006
  let hasLocalProject = false;
5622
6007
  if (checkFileExists(configPath)) {
5623
6008
  const raw = readJsonFile(configPath);
5624
6009
  const configResult = configSchema.safeParse(raw);
5625
6010
  if (!configResult.success) {
5626
- console.error(chalk6.red("Invalid pdfx.json"));
6011
+ console.error(chalk7.red("Invalid pdfx.json"));
5627
6012
  process.exit(1);
5628
6013
  }
5629
6014
  config = configResult.data;
@@ -5634,9 +6019,9 @@ async function list() {
5634
6019
  componentDir: "./src/components/pdfx",
5635
6020
  theme: "./src/lib/pdfx-theme.ts"
5636
6021
  };
5637
- console.log(chalk6.dim("No pdfx.json found. Listing components from default registry.\n"));
6022
+ console.log(chalk7.dim("No pdfx.json found. Listing from default registry.\n"));
5638
6023
  }
5639
- const spinner = ora5("Fetching component list...").start();
6024
+ const spinner = ora6("Fetching registry...").start();
5640
6025
  try {
5641
6026
  let response;
5642
6027
  try {
@@ -5647,8 +6032,8 @@ async function list() {
5647
6032
  const isTimeout = err instanceof Error && err.name === "TimeoutError";
5648
6033
  throw new NetworkError(
5649
6034
  isTimeout ? `Registry request timed out after 10 seconds.
5650
- ${chalk6.dim("Check your internet connection or try again later.")}` : `Could not reach registry at ${config.registry}
5651
- ${chalk6.dim("Verify the URL is correct and you have internet access.")}`
6035
+ ${chalk7.dim("Check your internet connection or try again later.")}` : `Could not reach registry at ${config.registry}
6036
+ ${chalk7.dim("Verify the URL is correct and you have internet access.")}`
5652
6037
  );
5653
6038
  }
5654
6039
  if (!response.ok) {
@@ -5661,23 +6046,62 @@ async function list() {
5661
6046
  }
5662
6047
  spinner.stop();
5663
6048
  const components = result.data.items.filter((item) => item.type === "registry:ui");
5664
- console.log(chalk6.bold(`
5665
- Available Components (${components.length})
5666
- `));
6049
+ const templates = result.data.items.filter((item) => item.type === "registry:template");
6050
+ const blocks = result.data.items.filter((item) => item.type === "registry:block");
6051
+ const componentBaseDir = path9.resolve(process.cwd(), config.componentDir);
6052
+ const templateBaseDir = path9.resolve(process.cwd(), config.templateDir ?? "./src/templates");
6053
+ console.log(chalk7.bold(`
6054
+ Components (${components.length})`));
6055
+ console.log(chalk7.dim(" Install with: pdfx add <component>\n"));
5667
6056
  for (const item of components) {
6057
+ const componentSubDir = path9.join(componentBaseDir, item.name);
6058
+ const localPath = safePath(componentSubDir, `pdfx-${item.name}.tsx`);
6059
+ const installed = hasLocalProject && checkFileExists(localPath);
6060
+ const status = installed ? chalk7.green("[installed]") : chalk7.dim("[not installed]");
6061
+ console.log(` ${chalk7.cyan(item.name.padEnd(20))} ${item.description}`);
5668
6062
  if (hasLocalProject) {
5669
- const targetDir = path8.resolve(process.cwd(), config.componentDir);
5670
- const componentSubDir = path8.join(targetDir, item.name);
5671
- const localPath = safePath(componentSubDir, `pdfx-${item.name}.tsx`);
5672
- const installed = checkFileExists(localPath);
5673
- const status = installed ? chalk6.green("[installed]") : chalk6.dim("[not installed]");
5674
- console.log(` ${chalk6.cyan(item.name.padEnd(20))} ${item.description}`);
5675
6063
  console.log(` ${"".padEnd(20)} ${status}`);
5676
- } else {
5677
- console.log(` ${chalk6.cyan(item.name.padEnd(20))} ${item.description}`);
5678
6064
  }
5679
6065
  console.log();
5680
6066
  }
6067
+ console.log(chalk7.bold(` Templates (${templates.length})`));
6068
+ console.log(chalk7.dim(" Data-driven. Install with: pdfx template add <template>\n"));
6069
+ for (const item of templates) {
6070
+ const templateDir = path9.join(templateBaseDir, item.name);
6071
+ const installed = hasLocalProject && checkFileExists(templateDir);
6072
+ const status = installed ? chalk7.green("[installed]") : chalk7.dim("[not installed]");
6073
+ console.log(` ${chalk7.cyan(item.name.padEnd(22))} ${item.description ?? ""}`);
6074
+ if (hasLocalProject) {
6075
+ console.log(` ${"".padEnd(22)} ${status}`);
6076
+ }
6077
+ console.log();
6078
+ }
6079
+ console.log(chalk7.bold(` Blocks (${blocks.length})`));
6080
+ console.log(chalk7.dim(" Copy-paste designs. Install with: pdfx block add <block>\n"));
6081
+ for (const item of blocks) {
6082
+ const blockDir = path9.join(templateBaseDir, item.name);
6083
+ const installed = hasLocalProject && checkFileExists(blockDir);
6084
+ const status = installed ? chalk7.green("[installed]") : chalk7.dim("[not installed]");
6085
+ console.log(` ${chalk7.cyan(item.name.padEnd(22))} ${item.description ?? ""}`);
6086
+ if (hasLocalProject) {
6087
+ console.log(` ${"".padEnd(22)} ${status}`);
6088
+ }
6089
+ if (item.peerComponents && item.peerComponents.length > 0) {
6090
+ console.log(chalk7.dim(` ${"".padEnd(22)} requires: ${item.peerComponents.join(", ")}`));
6091
+ }
6092
+ console.log();
6093
+ }
6094
+ console.log(chalk7.dim(" Quick Start:"));
6095
+ console.log(
6096
+ chalk7.dim(` pdfx add heading table ${chalk7.dim("# Add components")}`)
6097
+ );
6098
+ console.log(
6099
+ chalk7.dim(` pdfx template add invoice-template ${chalk7.dim("# Add data-driven template")}`)
6100
+ );
6101
+ console.log(
6102
+ chalk7.dim(` pdfx block add invoice-classic ${chalk7.dim("# Add copy-paste block")}`)
6103
+ );
6104
+ console.log();
5681
6105
  } catch (error) {
5682
6106
  const message = error instanceof Error ? error.message : String(error);
5683
6107
  spinner.fail(message);
@@ -5686,18 +6110,18 @@ async function list() {
5686
6110
  }
5687
6111
 
5688
6112
  // src/commands/template.ts
5689
- import path9 from "path";
5690
- import chalk7 from "chalk";
5691
- import ora6 from "ora";
5692
- import prompts4 from "prompts";
5693
- function readConfig2(configPath) {
6113
+ import path10 from "path";
6114
+ import chalk8 from "chalk";
6115
+ import ora7 from "ora";
6116
+ import prompts5 from "prompts";
6117
+ function readConfig3(configPath) {
5694
6118
  const raw = readJsonFile(configPath);
5695
6119
  const result = configSchema.safeParse(raw);
5696
6120
  if (!result.success) {
5697
6121
  const issues = result.error.issues.map((i) => i.message).join(", ");
5698
6122
  throw new ConfigError(
5699
6123
  `Invalid pdfx.json: ${issues}`,
5700
- `Fix the config or re-run ${chalk7.cyan("pdfx init")}`
6124
+ `Fix the config or re-run ${chalk8.cyan("pdfx init")}`
5701
6125
  );
5702
6126
  }
5703
6127
  return result.data;
@@ -5732,7 +6156,7 @@ async function fetchTemplate(name, registryUrl) {
5732
6156
  }
5733
6157
  return result.data;
5734
6158
  }
5735
- async function fetchComponent2(name, registryUrl) {
6159
+ async function fetchComponent3(name, registryUrl) {
5736
6160
  const url = `${registryUrl}/${name}.json`;
5737
6161
  let response;
5738
6162
  try {
@@ -5764,7 +6188,7 @@ async function fetchComponent2(name, registryUrl) {
5764
6188
  }
5765
6189
  function resolveTemplateImports(content, templateName, config) {
5766
6190
  const cwd = process.cwd();
5767
- const templateSubdir = path9.resolve(
6191
+ const templateSubdir = path10.resolve(
5768
6192
  cwd,
5769
6193
  config.templateDir ?? DEFAULTS.TEMPLATE_DIR,
5770
6194
  templateName
@@ -5772,38 +6196,38 @@ function resolveTemplateImports(content, templateName, config) {
5772
6196
  let result = content.replace(
5773
6197
  /from '\.\.\/\.\.\/components\/pdfx\/([a-z][a-z0-9-]*)\/pdfx-([a-z][a-z0-9-]*)'/g,
5774
6198
  (_match, componentName) => {
5775
- const absCompFile = path9.resolve(
6199
+ const absCompFile = path10.resolve(
5776
6200
  cwd,
5777
6201
  config.componentDir,
5778
6202
  componentName,
5779
6203
  `pdfx-${componentName}`
5780
6204
  );
5781
- let rel = path9.relative(templateSubdir, absCompFile);
6205
+ let rel = path10.relative(templateSubdir, absCompFile);
5782
6206
  if (!rel.startsWith(".")) rel = `./${rel}`;
5783
6207
  return `from '${rel}'`;
5784
6208
  }
5785
6209
  );
5786
6210
  if (config.theme) {
5787
- const absThemePath = path9.resolve(cwd, config.theme).replace(/\.tsx?$/, "");
5788
- let relTheme = path9.relative(templateSubdir, absThemePath);
6211
+ const absThemePath = path10.resolve(cwd, config.theme).replace(/\.tsx?$/, "");
6212
+ let relTheme = path10.relative(templateSubdir, absThemePath);
5789
6213
  if (!relTheme.startsWith(".")) relTheme = `./${relTheme}`;
5790
- const absContextPath = path9.join(
5791
- path9.dirname(path9.resolve(cwd, config.theme)),
6214
+ const absContextPath = path10.join(
6215
+ path10.dirname(path10.resolve(cwd, config.theme)),
5792
6216
  "pdfx-theme-context"
5793
6217
  );
5794
- let relContext = path9.relative(templateSubdir, absContextPath);
6218
+ let relContext = path10.relative(templateSubdir, absContextPath);
5795
6219
  if (!relContext.startsWith(".")) relContext = `./${relContext}`;
5796
6220
  result = result.replace(/from '\.\.\/\.\.\/lib\/pdfx-theme'/g, `from '${relTheme}'`);
5797
6221
  result = result.replace(/from '\.\.\/\.\.\/lib\/pdfx-theme-context'/g, `from '${relContext}'`);
5798
6222
  }
5799
6223
  return result;
5800
6224
  }
5801
- async function resolveConflict(fileName, currentDecision) {
6225
+ async function resolveConflict2(fileName, currentDecision) {
5802
6226
  if (currentDecision === "overwrite-all") return "overwrite-all";
5803
- const { action } = await prompts4({
6227
+ const { action } = await prompts5({
5804
6228
  type: "select",
5805
6229
  name: "action",
5806
- message: `${chalk7.yellow(fileName)} already exists. What would you like to do?`,
6230
+ message: `${chalk8.yellow(fileName)} already exists. What would you like to do?`,
5807
6231
  choices: [
5808
6232
  { title: "Skip", value: "skip", description: "Keep the existing file unchanged" },
5809
6233
  { title: "Overwrite", value: "overwrite", description: "Replace this file only" },
@@ -5818,20 +6242,20 @@ async function resolveConflict(fileName, currentDecision) {
5818
6242
  if (!action) throw new ValidationError("Cancelled by user");
5819
6243
  return action;
5820
6244
  }
5821
- async function ensurePeerComponents(template, config, force) {
6245
+ async function ensurePeerComponents2(template, config, force) {
5822
6246
  const installedPeers = [];
5823
6247
  const peerWarnings = [];
5824
6248
  if (!template.peerComponents || template.peerComponents.length === 0) {
5825
6249
  return { installedPeers, peerWarnings };
5826
6250
  }
5827
- const componentBaseDir = path9.resolve(process.cwd(), config.componentDir);
6251
+ const componentBaseDir = path10.resolve(process.cwd(), config.componentDir);
5828
6252
  for (const componentName of template.peerComponents) {
5829
- const componentDir = path9.join(componentBaseDir, componentName);
5830
- const expectedMain = path9.join(componentDir, `pdfx-${componentName}.tsx`);
6253
+ const componentDir = path10.join(componentBaseDir, componentName);
6254
+ const expectedMain = path10.join(componentDir, `pdfx-${componentName}.tsx`);
5831
6255
  if (checkFileExists(componentDir)) {
5832
6256
  if (!checkFileExists(expectedMain)) {
5833
6257
  peerWarnings.push(
5834
- `${componentName}: directory exists but expected file missing (${path9.basename(expectedMain)})`
6258
+ `${componentName}: directory exists but expected file missing (${path10.basename(expectedMain)})`
5835
6259
  );
5836
6260
  } else {
5837
6261
  peerWarnings.push(
@@ -5840,11 +6264,11 @@ async function ensurePeerComponents(template, config, force) {
5840
6264
  }
5841
6265
  continue;
5842
6266
  }
5843
- const component = await fetchComponent2(componentName, config.registry);
6267
+ const component = await fetchComponent3(componentName, config.registry);
5844
6268
  ensureDir(componentDir);
5845
- const componentRelDir = path9.join(config.componentDir, component.name);
6269
+ const componentRelDir = path10.join(config.componentDir, component.name);
5846
6270
  for (const file of component.files) {
5847
- const fileName = path9.basename(file.path);
6271
+ const fileName = path10.basename(file.path);
5848
6272
  const filePath = safePath(componentDir, fileName);
5849
6273
  let content = file.content;
5850
6274
  if (config.theme && (content.includes("pdfx-theme") || content.includes("pdfx-theme-context"))) {
@@ -5864,13 +6288,13 @@ async function ensurePeerComponents(template, config, force) {
5864
6288
  }
5865
6289
  async function installTemplate(name, config, force) {
5866
6290
  const template = await fetchTemplate(name, config.registry);
5867
- const peerResult = await ensurePeerComponents(template, config, force);
5868
- const templateBaseDir = path9.resolve(process.cwd(), config.templateDir ?? DEFAULTS.TEMPLATE_DIR);
5869
- const templateDir = path9.join(templateBaseDir, template.name);
6291
+ const peerResult = await ensurePeerComponents2(template, config, force);
6292
+ const templateBaseDir = path10.resolve(process.cwd(), config.templateDir ?? DEFAULTS.TEMPLATE_DIR);
6293
+ const templateDir = path10.join(templateBaseDir, template.name);
5870
6294
  ensureDir(templateDir);
5871
6295
  const filesToWrite = [];
5872
6296
  for (const file of template.files) {
5873
- const fileName = path9.basename(file.path);
6297
+ const fileName = path10.basename(file.path);
5874
6298
  const filePath = safePath(templateDir, fileName);
5875
6299
  let content = file.content;
5876
6300
  if (/\.(tsx?|jsx?)$/.test(fileName) && content.includes("../../")) {
@@ -5883,7 +6307,7 @@ async function installTemplate(name, config, force) {
5883
6307
  const resolved = [];
5884
6308
  for (const file of filesToWrite) {
5885
6309
  if (checkFileExists(file.filePath)) {
5886
- const decision = await resolveConflict(path9.basename(file.filePath), globalDecision);
6310
+ const decision = await resolveConflict2(path10.basename(file.filePath), globalDecision);
5887
6311
  if (decision === "overwrite-all") {
5888
6312
  globalDecision = "overwrite-all";
5889
6313
  }
@@ -5896,7 +6320,7 @@ async function installTemplate(name, config, force) {
5896
6320
  if (!file.skip) {
5897
6321
  writeFile(file.filePath, file.content);
5898
6322
  } else {
5899
- console.log(chalk7.dim(` skipped ${path9.basename(file.filePath)}`));
6323
+ console.log(chalk8.dim(` skipped ${path10.basename(file.filePath)}`));
5900
6324
  }
5901
6325
  }
5902
6326
  } else {
@@ -5905,49 +6329,49 @@ async function installTemplate(name, config, force) {
5905
6329
  }
5906
6330
  }
5907
6331
  if (template.peerComponents && template.peerComponents.length > 0) {
5908
- const componentBaseDir = path9.resolve(process.cwd(), config.componentDir);
6332
+ const componentBaseDir = path10.resolve(process.cwd(), config.componentDir);
5909
6333
  const missing = [];
5910
6334
  for (const comp of template.peerComponents) {
5911
- const compDir = path9.join(componentBaseDir, comp);
6335
+ const compDir = path10.join(componentBaseDir, comp);
5912
6336
  if (!checkFileExists(compDir)) {
5913
6337
  missing.push(comp);
5914
6338
  }
5915
6339
  }
5916
6340
  if (missing.length > 0) {
5917
6341
  console.log();
5918
- console.log(chalk7.yellow(" Missing peer components:"));
6342
+ console.log(chalk8.yellow(" Missing peer components:"));
5919
6343
  for (const comp of missing) {
5920
- console.log(chalk7.dim(` ${comp} \u2192 run: ${chalk7.cyan(`pdfx add ${comp}`)}`));
6344
+ console.log(chalk8.dim(` ${comp} \u2192 run: ${chalk8.cyan(`pdfx add ${comp}`)}`));
5921
6345
  }
5922
6346
  }
5923
6347
  }
5924
6348
  if (config.theme) {
5925
- const absThemePath = path9.resolve(process.cwd(), config.theme);
5926
- const contextPath = path9.join(path9.dirname(absThemePath), "pdfx-theme-context.tsx");
6349
+ const absThemePath = path10.resolve(process.cwd(), config.theme);
6350
+ const contextPath = path10.join(path10.dirname(absThemePath), "pdfx-theme-context.tsx");
5927
6351
  if (!checkFileExists(contextPath)) {
5928
- ensureDir(path9.dirname(contextPath));
6352
+ ensureDir(path10.dirname(contextPath));
5929
6353
  writeFile(contextPath, generateThemeContextFile());
5930
6354
  }
5931
6355
  }
5932
6356
  return peerResult;
5933
6357
  }
5934
6358
  async function templateAdd(names, options = {}) {
5935
- const configPath = path9.join(process.cwd(), "pdfx.json");
6359
+ const configPath = path10.join(process.cwd(), "pdfx.json");
5936
6360
  if (!checkFileExists(configPath)) {
5937
- console.error(chalk7.red("Error: pdfx.json not found"));
5938
- console.log(chalk7.yellow("Run: pdfx init"));
6361
+ console.error(chalk8.red("Error: pdfx.json not found"));
6362
+ console.log(chalk8.yellow("Run: pdfx init"));
5939
6363
  process.exit(1);
5940
6364
  }
5941
6365
  let config;
5942
6366
  try {
5943
- config = readConfig2(configPath);
6367
+ config = readConfig3(configPath);
5944
6368
  } catch (error) {
5945
6369
  if (error instanceof ConfigError) {
5946
- console.error(chalk7.red(error.message));
5947
- if (error.suggestion) console.log(chalk7.yellow(` Hint: ${error.suggestion}`));
6370
+ console.error(chalk8.red(error.message));
6371
+ if (error.suggestion) console.log(chalk8.yellow(` Hint: ${error.suggestion}`));
5948
6372
  } else {
5949
6373
  const message = error instanceof Error ? error.message : String(error);
5950
- console.error(chalk7.red(message));
6374
+ console.error(chalk8.red(message));
5951
6375
  }
5952
6376
  process.exit(1);
5953
6377
  }
@@ -5956,24 +6380,24 @@ async function templateAdd(names, options = {}) {
5956
6380
  for (const templateName of names) {
5957
6381
  const nameResult = componentNameSchema.safeParse(templateName);
5958
6382
  if (!nameResult.success) {
5959
- console.error(chalk7.red(`Invalid template name: "${templateName}"`));
6383
+ console.error(chalk8.red(`Invalid template name: "${templateName}"`));
5960
6384
  console.log(
5961
- chalk7.dim(' Names must be lowercase alphanumeric with hyphens (e.g., "invoice-classic")')
6385
+ chalk8.dim(' Names must be lowercase alphanumeric with hyphens (e.g., "invoice-classic")')
5962
6386
  );
5963
6387
  failed.push(templateName);
5964
6388
  continue;
5965
6389
  }
5966
- const spinner = ora6(`Adding template ${templateName}...`).start();
6390
+ const spinner = ora7(`Adding template ${templateName}...`).start();
5967
6391
  try {
5968
6392
  const result = await installTemplate(templateName, config, force);
5969
- spinner.succeed(`Added template ${chalk7.cyan(templateName)}`);
6393
+ spinner.succeed(`Added template ${chalk8.cyan(templateName)}`);
5970
6394
  if (result.installedPeers.length > 0) {
5971
6395
  console.log(
5972
- chalk7.green(` Installed required components: ${result.installedPeers.join(", ")}`)
6396
+ chalk8.green(` Installed required components: ${result.installedPeers.join(", ")}`)
5973
6397
  );
5974
6398
  }
5975
6399
  for (const warning of result.peerWarnings) {
5976
- console.log(chalk7.yellow(` Warning: ${warning}`));
6400
+ console.log(chalk8.yellow(` Warning: ${warning}`));
5977
6401
  }
5978
6402
  } catch (error) {
5979
6403
  if (error instanceof ValidationError && error.message.includes("Cancelled")) {
@@ -5982,24 +6406,24 @@ async function templateAdd(names, options = {}) {
5982
6406
  } else if (error instanceof NetworkError || error instanceof RegistryError || error instanceof ValidationError) {
5983
6407
  spinner.fail(error.message);
5984
6408
  if (error.suggestion) {
5985
- console.log(chalk7.dim(` Hint: ${error.suggestion}`));
6409
+ console.log(chalk8.dim(` Hint: ${error.suggestion}`));
5986
6410
  }
5987
6411
  } else {
5988
6412
  spinner.fail(`Failed to add template ${templateName}`);
5989
6413
  const message = error instanceof Error ? error.message : String(error);
5990
- console.error(chalk7.dim(` ${message}`));
6414
+ console.error(chalk8.dim(` ${message}`));
5991
6415
  }
5992
6416
  failed.push(templateName);
5993
6417
  }
5994
6418
  }
5995
6419
  console.log();
5996
6420
  if (failed.length > 0) {
5997
- console.log(chalk7.yellow(`Failed: ${failed.join(", ")}`));
6421
+ console.log(chalk8.yellow(`Failed: ${failed.join(", ")}`));
5998
6422
  }
5999
6423
  if (failed.length < names.length) {
6000
- const resolvedDir = path9.resolve(process.cwd(), config.templateDir ?? DEFAULTS.TEMPLATE_DIR);
6001
- console.log(chalk7.green("Done!"));
6002
- console.log(chalk7.dim(`Templates installed to: ${resolvedDir}
6424
+ const resolvedDir = path10.resolve(process.cwd(), config.templateDir ?? DEFAULTS.TEMPLATE_DIR);
6425
+ console.log(chalk8.green("Done!"));
6426
+ console.log(chalk8.dim(`Templates installed to: ${resolvedDir}
6003
6427
  `));
6004
6428
  }
6005
6429
  if (failed.length > 0) {
@@ -6007,20 +6431,20 @@ async function templateAdd(names, options = {}) {
6007
6431
  }
6008
6432
  }
6009
6433
  async function templateList() {
6010
- const configPath = path9.join(process.cwd(), "pdfx.json");
6434
+ const configPath = path10.join(process.cwd(), "pdfx.json");
6011
6435
  if (!checkFileExists(configPath)) {
6012
- console.error(chalk7.red("Error: pdfx.json not found"));
6013
- console.log(chalk7.yellow("Run: pdfx init"));
6436
+ console.error(chalk8.red("Error: pdfx.json not found"));
6437
+ console.log(chalk8.yellow("Run: pdfx init"));
6014
6438
  process.exit(1);
6015
6439
  }
6016
6440
  const raw = readJsonFile(configPath);
6017
6441
  const configResult = configSchema.safeParse(raw);
6018
6442
  if (!configResult.success) {
6019
- console.error(chalk7.red("Invalid pdfx.json"));
6443
+ console.error(chalk8.red("Invalid pdfx.json"));
6020
6444
  process.exit(1);
6021
6445
  }
6022
6446
  const config = configResult.data;
6023
- const spinner = ora6("Fetching template list...").start();
6447
+ const spinner = ora7("Fetching template list...").start();
6024
6448
  try {
6025
6449
  let response;
6026
6450
  try {
@@ -6044,28 +6468,28 @@ async function templateList() {
6044
6468
  spinner.stop();
6045
6469
  const templates = result.data.items.filter((item) => item.type === "registry:template");
6046
6470
  if (templates.length === 0) {
6047
- console.log(chalk7.dim("\n No templates available in the registry.\n"));
6471
+ console.log(chalk8.dim("\n No templates available in the registry.\n"));
6048
6472
  return;
6049
6473
  }
6050
- const templateBaseDir = path9.resolve(
6474
+ const templateBaseDir = path10.resolve(
6051
6475
  process.cwd(),
6052
6476
  config.templateDir ?? DEFAULTS.TEMPLATE_DIR
6053
6477
  );
6054
- console.log(chalk7.bold(`
6478
+ console.log(chalk8.bold(`
6055
6479
  Available Templates (${templates.length})
6056
6480
  `));
6057
6481
  for (const item of templates) {
6058
- const templateDir = path9.join(templateBaseDir, item.name);
6482
+ const templateDir = path10.join(templateBaseDir, item.name);
6059
6483
  const installed = checkFileExists(templateDir);
6060
- const status = installed ? chalk7.green("[installed]") : chalk7.dim("[not installed]");
6061
- console.log(` ${chalk7.cyan(item.name.padEnd(22))} ${item.description ?? ""}`);
6484
+ const status = installed ? chalk8.green("[installed]") : chalk8.dim("[not installed]");
6485
+ console.log(` ${chalk8.cyan(item.name.padEnd(22))} ${item.description ?? ""}`);
6062
6486
  console.log(` ${"".padEnd(22)} ${status}`);
6063
6487
  if (item.peerComponents && item.peerComponents.length > 0) {
6064
- console.log(chalk7.dim(` ${"".padEnd(22)} requires: ${item.peerComponents.join(", ")}`));
6488
+ console.log(chalk8.dim(` ${"".padEnd(22)} requires: ${item.peerComponents.join(", ")}`));
6065
6489
  }
6066
6490
  console.log();
6067
6491
  }
6068
- console.log(chalk7.dim(` Install with: ${chalk7.cyan("pdfx template add <template-name>")}
6492
+ console.log(chalk8.dim(` Install with: ${chalk8.cyan("pdfx template add <template-name>")}
6069
6493
  `));
6070
6494
  } catch (error) {
6071
6495
  const message = error instanceof Error ? error.message : String(error);
@@ -6076,22 +6500,22 @@ async function templateList() {
6076
6500
 
6077
6501
  // src/commands/theme.ts
6078
6502
  import fs8 from "fs";
6079
- import path10 from "path";
6080
- import chalk8 from "chalk";
6081
- import ora7 from "ora";
6082
- import prompts5 from "prompts";
6503
+ import path11 from "path";
6504
+ import chalk9 from "chalk";
6505
+ import ora8 from "ora";
6506
+ import prompts6 from "prompts";
6083
6507
  import ts from "typescript";
6084
6508
  async function themeInit() {
6085
- const configPath = path10.join(process.cwd(), "pdfx.json");
6509
+ const configPath = path11.join(process.cwd(), "pdfx.json");
6086
6510
  if (!fs8.existsSync(configPath)) {
6087
- console.error(chalk8.red("\nError: pdfx.json not found"));
6088
- console.log(chalk8.yellow("\n PDFx is not initialized in this project.\n"));
6089
- console.log(chalk8.cyan(" Run: pdfx init"));
6090
- console.log(chalk8.dim(" This will set up your project configuration and theme.\n"));
6511
+ console.error(chalk9.red("\nError: pdfx.json not found"));
6512
+ console.log(chalk9.yellow("\n PDFx is not initialized in this project.\n"));
6513
+ console.log(chalk9.cyan(" Run: pdfx init"));
6514
+ console.log(chalk9.dim(" This will set up your project configuration and theme.\n"));
6091
6515
  process.exit(1);
6092
6516
  }
6093
- console.log(chalk8.bold.cyan("\n PDFx Theme Setup\n"));
6094
- const answers = await prompts5(
6517
+ console.log(chalk9.bold.cyan("\n PDFx Theme Setup\n"));
6518
+ const answers = await prompts6(
6095
6519
  [
6096
6520
  {
6097
6521
  type: "select",
@@ -6125,27 +6549,27 @@ async function themeInit() {
6125
6549
  ],
6126
6550
  {
6127
6551
  onCancel: () => {
6128
- console.log(chalk8.yellow("\nTheme setup cancelled."));
6552
+ console.log(chalk9.yellow("\nTheme setup cancelled."));
6129
6553
  process.exit(0);
6130
6554
  }
6131
6555
  }
6132
6556
  );
6133
6557
  if (!answers.preset || !answers.themePath) {
6134
- console.error(chalk8.red("Missing required fields."));
6558
+ console.error(chalk9.red("Missing required fields."));
6135
6559
  process.exit(1);
6136
6560
  }
6137
6561
  const presetName = answers.preset;
6138
6562
  const themePath = answers.themePath;
6139
6563
  const preset = themePresets[presetName];
6140
- const spinner = ora7(`Scaffolding ${presetName} theme...`).start();
6564
+ const spinner = ora8(`Scaffolding ${presetName} theme...`).start();
6141
6565
  try {
6142
- const absThemePath = path10.resolve(process.cwd(), themePath);
6143
- ensureDir(path10.dirname(absThemePath));
6566
+ const absThemePath = path11.resolve(process.cwd(), themePath);
6567
+ ensureDir(path11.dirname(absThemePath));
6144
6568
  fs8.writeFileSync(absThemePath, generateThemeFile(preset), "utf-8");
6145
- const contextPath = path10.join(path10.dirname(absThemePath), "pdfx-theme-context.tsx");
6569
+ const contextPath = path11.join(path11.dirname(absThemePath), "pdfx-theme-context.tsx");
6146
6570
  fs8.writeFileSync(contextPath, generateThemeContextFile(), "utf-8");
6147
6571
  spinner.succeed(`Created ${themePath} with ${presetName} theme`);
6148
- const configPath2 = path10.join(process.cwd(), "pdfx.json");
6572
+ const configPath2 = path11.join(process.cwd(), "pdfx.json");
6149
6573
  if (fs8.existsSync(configPath2)) {
6150
6574
  try {
6151
6575
  const rawConfig = readJsonFile(configPath2);
@@ -6153,19 +6577,19 @@ async function themeInit() {
6153
6577
  if (result.success) {
6154
6578
  const updatedConfig = { ...result.data, theme: themePath };
6155
6579
  fs8.writeFileSync(configPath2, JSON.stringify(updatedConfig, null, 2), "utf-8");
6156
- console.log(chalk8.green(" Updated pdfx.json with theme path"));
6580
+ console.log(chalk9.green(" Updated pdfx.json with theme path"));
6157
6581
  }
6158
6582
  } catch {
6159
- console.log(chalk8.yellow(' Could not update pdfx.json \u2014 add "theme" field manually'));
6583
+ console.log(chalk9.yellow(' Could not update pdfx.json \u2014 add "theme" field manually'));
6160
6584
  }
6161
6585
  }
6162
- console.log(chalk8.dim(`
6586
+ console.log(chalk9.dim(`
6163
6587
  Edit ${themePath} to customize your theme.
6164
6588
  `));
6165
6589
  } catch (error) {
6166
6590
  spinner.fail("Failed to create theme file");
6167
6591
  const message = error instanceof Error ? error.message : String(error);
6168
- console.error(chalk8.dim(` ${message}`));
6592
+ console.error(chalk9.dim(` ${message}`));
6169
6593
  process.exit(1);
6170
6594
  }
6171
6595
  }
@@ -6173,56 +6597,56 @@ async function themeSwitch(presetName) {
6173
6597
  const resolvedPreset = presetName === "default" ? "professional" : presetName;
6174
6598
  const validPresets = Object.keys(themePresets);
6175
6599
  if (!validPresets.includes(resolvedPreset)) {
6176
- console.error(chalk8.red(`\u2716 Invalid theme preset: "${presetName}"`));
6177
- console.log(chalk8.dim(` Available presets: ${validPresets.join(", ")}, default
6600
+ console.error(chalk9.red(`\u2716 Invalid theme preset: "${presetName}"`));
6601
+ console.log(chalk9.dim(` Available presets: ${validPresets.join(", ")}, default
6178
6602
  `));
6179
- console.log(chalk8.dim(" Usage: pdfx theme switch <preset>"));
6603
+ console.log(chalk9.dim(" Usage: pdfx theme switch <preset>"));
6180
6604
  process.exit(1);
6181
6605
  }
6182
6606
  const validatedPreset = resolvedPreset;
6183
- const configPath = path10.join(process.cwd(), "pdfx.json");
6607
+ const configPath = path11.join(process.cwd(), "pdfx.json");
6184
6608
  if (!fs8.existsSync(configPath)) {
6185
- console.error(chalk8.red('No pdfx.json found. Run "pdfx init" first.'));
6609
+ console.error(chalk9.red('No pdfx.json found. Run "pdfx init" first.'));
6186
6610
  process.exit(1);
6187
6611
  }
6188
6612
  const rawConfig = readJsonFile(configPath);
6189
6613
  const result = configSchema.safeParse(rawConfig);
6190
6614
  if (!result.success) {
6191
- console.error(chalk8.red("Invalid pdfx.json configuration."));
6615
+ console.error(chalk9.red("Invalid pdfx.json configuration."));
6192
6616
  process.exit(1);
6193
6617
  }
6194
6618
  const config = result.data;
6195
6619
  if (!config.theme) {
6196
6620
  console.error(
6197
- chalk8.red('No theme path in pdfx.json. Run "pdfx theme init" to set up theming.')
6621
+ chalk9.red('No theme path in pdfx.json. Run "pdfx theme init" to set up theming.')
6198
6622
  );
6199
6623
  process.exit(1);
6200
6624
  }
6201
- const answer = await prompts5({
6625
+ const answer = await prompts6({
6202
6626
  type: "confirm",
6203
6627
  name: "confirm",
6204
6628
  message: `This will overwrite ${config.theme} with the ${validatedPreset} preset. Continue?`,
6205
6629
  initial: false
6206
6630
  });
6207
6631
  if (!answer.confirm) {
6208
- console.log(chalk8.yellow("Cancelled."));
6632
+ console.log(chalk9.yellow("Cancelled."));
6209
6633
  return;
6210
6634
  }
6211
- const spinner = ora7(`Switching to ${validatedPreset} theme...`).start();
6635
+ const spinner = ora8(`Switching to ${validatedPreset} theme...`).start();
6212
6636
  try {
6213
6637
  const preset = themePresets[validatedPreset];
6214
- const absThemePath = path10.resolve(process.cwd(), config.theme);
6638
+ const absThemePath = path11.resolve(process.cwd(), config.theme);
6215
6639
  fs8.writeFileSync(absThemePath, generateThemeFile(preset), "utf-8");
6216
- const contextPath = path10.join(path10.dirname(absThemePath), "pdfx-theme-context.tsx");
6640
+ const contextPath = path11.join(path11.dirname(absThemePath), "pdfx-theme-context.tsx");
6217
6641
  if (!fs8.existsSync(contextPath)) {
6218
- ensureDir(path10.dirname(contextPath));
6642
+ ensureDir(path11.dirname(contextPath));
6219
6643
  fs8.writeFileSync(contextPath, generateThemeContextFile(), "utf-8");
6220
6644
  }
6221
6645
  spinner.succeed(`Switched to ${validatedPreset} theme`);
6222
6646
  } catch (error) {
6223
6647
  spinner.fail("Failed to switch theme");
6224
6648
  const message = error instanceof Error ? error.message : String(error);
6225
- console.error(chalk8.dim(` ${message}`));
6649
+ console.error(chalk9.dim(` ${message}`));
6226
6650
  process.exit(1);
6227
6651
  }
6228
6652
  }
@@ -6290,48 +6714,48 @@ function parseThemeObject(themePath) {
6290
6714
  throw new Error("No exported `theme` object found.");
6291
6715
  }
6292
6716
  async function themeValidate() {
6293
- const configPath = path10.join(process.cwd(), "pdfx.json");
6717
+ const configPath = path11.join(process.cwd(), "pdfx.json");
6294
6718
  if (!fs8.existsSync(configPath)) {
6295
- console.error(chalk8.red('No pdfx.json found. Run "pdfx init" first.'));
6719
+ console.error(chalk9.red('No pdfx.json found. Run "pdfx init" first.'));
6296
6720
  process.exit(1);
6297
6721
  }
6298
6722
  const rawConfig = readJsonFile(configPath);
6299
6723
  const configResult = configSchema.safeParse(rawConfig);
6300
6724
  if (!configResult.success) {
6301
- console.error(chalk8.red("Invalid pdfx.json configuration."));
6725
+ console.error(chalk9.red("Invalid pdfx.json configuration."));
6302
6726
  process.exit(1);
6303
6727
  }
6304
6728
  if (!configResult.data.theme) {
6305
6729
  console.error(
6306
- chalk8.red('No theme path in pdfx.json. Run "pdfx theme init" to set up theming.')
6730
+ chalk9.red('No theme path in pdfx.json. Run "pdfx theme init" to set up theming.')
6307
6731
  );
6308
6732
  process.exit(1);
6309
6733
  }
6310
- const absThemePath = path10.resolve(process.cwd(), configResult.data.theme);
6734
+ const absThemePath = path11.resolve(process.cwd(), configResult.data.theme);
6311
6735
  if (!fs8.existsSync(absThemePath)) {
6312
- console.error(chalk8.red(`Theme file not found: ${configResult.data.theme}`));
6736
+ console.error(chalk9.red(`Theme file not found: ${configResult.data.theme}`));
6313
6737
  process.exit(1);
6314
6738
  }
6315
- const spinner = ora7("Validating theme file...").start();
6739
+ const spinner = ora8("Validating theme file...").start();
6316
6740
  try {
6317
6741
  const parsedTheme = parseThemeObject(absThemePath);
6318
6742
  const result = themeSchema.safeParse(parsedTheme);
6319
6743
  if (!result.success) {
6320
- const issues = result.error.issues.map((issue) => ` \u2192 ${chalk8.yellow(issue.path.join("."))}: ${issue.message}`).join("\n");
6744
+ const issues = result.error.issues.map((issue) => ` \u2192 ${chalk9.yellow(issue.path.join("."))}: ${issue.message}`).join("\n");
6321
6745
  spinner.fail("Theme validation failed");
6322
- console.log(chalk8.red("\n Missing or invalid fields:\n"));
6746
+ console.log(chalk9.red("\n Missing or invalid fields:\n"));
6323
6747
  console.log(issues);
6324
- console.log(chalk8.dim("\n Fix these fields in your theme file and run validate again.\n"));
6748
+ console.log(chalk9.dim("\n Fix these fields in your theme file and run validate again.\n"));
6325
6749
  process.exit(1);
6326
6750
  }
6327
6751
  spinner.succeed("Theme file is valid");
6328
- console.log(chalk8.dim(`
6752
+ console.log(chalk9.dim(`
6329
6753
  Validated: ${configResult.data.theme}
6330
6754
  `));
6331
6755
  } catch (error) {
6332
6756
  spinner.fail("Failed to validate theme");
6333
6757
  const message = error instanceof Error ? error.message : String(error);
6334
- console.error(chalk8.dim(` ${message}`));
6758
+ console.error(chalk9.dim(` ${message}`));
6335
6759
  process.exit(1);
6336
6760
  }
6337
6761
  }
@@ -6361,4 +6785,7 @@ themeCmd.command("validate").description("Validate your theme file").action(them
6361
6785
  var templateCmd = program.command("template").description("Manage PDF templates");
6362
6786
  templateCmd.command("add <templates...>").description("Add a template to your project").option("-f, --force", "Overwrite existing files without prompting").action((templates, options) => templateAdd(templates, options));
6363
6787
  templateCmd.command("list").description("List available templates from registry").action(templateList);
6788
+ var blockCmd = program.command("block").description("Manage PDF blocks (copy-paste designs)");
6789
+ blockCmd.command("add <blocks...>").description("Add a block to your project").option("-f, --force", "Overwrite existing files without prompting").action((blocks, options) => blockAdd(blocks, options));
6790
+ blockCmd.command("list").description("List available blocks from registry").action(blockList);
6364
6791
  program.parse();