@ncukondo/slide-generation 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -1688,7 +1688,7 @@ var Pipeline = class {
1688
1688
  };
1689
1689
 
1690
1690
  // src/index.ts
1691
- var VERSION = "0.5.0";
1691
+ var VERSION = "0.6.0";
1692
1692
 
1693
1693
  // src/cli/commands/convert.ts
1694
1694
  import { Command } from "commander";
@@ -3376,6 +3376,48 @@ function getMarpCommand(projectDir) {
3376
3376
  function isMarpAvailable(projectDir) {
3377
3377
  return getMarpCommand(projectDir) !== null;
3378
3378
  }
3379
+ function parseMarpBrowserError(errorOutput) {
3380
+ const output = errorOutput.toLowerCase();
3381
+ if (output.includes("no suitable browser found")) {
3382
+ return {
3383
+ type: "browser_not_found",
3384
+ message: "No browser found for taking screenshots",
3385
+ suggestion: `Install a browser using one of these methods:
3386
+ 1. Run: npx puppeteer browsers install chrome
3387
+ 2. Install Chrome/Chromium system-wide
3388
+ 3. Set CHROME_PATH environment variable to your browser path`
3389
+ };
3390
+ }
3391
+ if (output.includes("snap to be installed") || output.includes("requires the chromium snap")) {
3392
+ return {
3393
+ type: "snap_not_available",
3394
+ message: "Snap packages are not available in this environment (Docker/devcontainer)",
3395
+ suggestion: `Use Puppeteer's bundled Chrome instead:
3396
+ 1. Run: npx puppeteer browsers install chrome
3397
+ 2. Set: export PUPPETEER_ARGS="--no-sandbox --disable-setuid-sandbox"`
3398
+ };
3399
+ }
3400
+ if (output.includes("error while loading shared libraries") || output.includes("cannot open shared object file")) {
3401
+ const libMatch = errorOutput.match(/lib[\w.-]+\.so[\d.]*/i);
3402
+ const libName = libMatch ? libMatch[0] : "unknown library";
3403
+ return {
3404
+ type: "missing_libraries",
3405
+ message: `Missing Chrome dependency: ${libName}`,
3406
+ suggestion: `Install required libraries:
3407
+ sudo apt-get install -y libnss3 libatk-bridge2.0-0 libdrm2 libxkbcommon0 \\
3408
+ libgbm1 libasound2t64 libxfixes3 fonts-noto-cjk`
3409
+ };
3410
+ }
3411
+ if (output.includes("target closed") || output.includes("targetcloseerror") || output.includes("no-sandbox")) {
3412
+ return {
3413
+ type: "sandbox_error",
3414
+ message: "Chrome sandbox error (common in container environments)",
3415
+ suggestion: `Disable sandbox mode:
3416
+ export PUPPETEER_ARGS="--no-sandbox --disable-setuid-sandbox"`
3417
+ };
3418
+ }
3419
+ return null;
3420
+ }
3379
3421
  function runMarp(args, options = {}) {
3380
3422
  const { projectDir, ...execOptions } = options;
3381
3423
  const marpCmd = getMarpCommand(projectDir);
@@ -8191,7 +8233,7 @@ function parseBlurSpec(spec) {
8191
8233
 
8192
8234
  // src/cli/commands/screenshot.ts
8193
8235
  import { Command as Command9 } from "commander";
8194
- import { access as access12, mkdir as mkdir9, readdir as readdir7, unlink as unlink2 } from "fs/promises";
8236
+ import { access as access12, mkdir as mkdir9, readdir as readdir7, rename as rename2, unlink as unlink2 } from "fs/promises";
8195
8237
  import { basename as basename10, dirname as dirname10, extname as extname5, join as join19 } from "path";
8196
8238
  import chalk9 from "chalk";
8197
8239
  import ora4 from "ora";
@@ -8225,6 +8267,20 @@ async function filterToSpecificSlide(outputDir, baseName, slideNumber, format) {
8225
8267
  function checkMarpCliAvailable2(projectDir) {
8226
8268
  return isMarpAvailable(projectDir);
8227
8269
  }
8270
+ async function ensureFileExtensions(outputDir, baseName, format) {
8271
+ const files = await readdir7(outputDir);
8272
+ const slidePattern = /\.(\d{3})$/;
8273
+ const renamedFiles = [];
8274
+ for (const file of files) {
8275
+ if (file.startsWith(baseName) && slidePattern.test(file)) {
8276
+ const oldPath = join19(outputDir, file);
8277
+ const newPath = join19(outputDir, `${file}.${format}`);
8278
+ await rename2(oldPath, newPath);
8279
+ renamedFiles.push(`${file}.${format}`);
8280
+ }
8281
+ }
8282
+ return renamedFiles;
8283
+ }
8228
8284
  function estimateTokens(width, height) {
8229
8285
  return Math.ceil(width * height / 750);
8230
8286
  }
@@ -8437,9 +8493,19 @@ async function executeScreenshot(inputPath, options) {
8437
8493
  spinner?.succeed(`Screenshots saved to ${outputDir}`);
8438
8494
  } catch (error) {
8439
8495
  spinner?.fail("Failed to take screenshots");
8440
- const message = error instanceof Error ? error.message : "Marp CLI failed";
8441
- console.error(chalk9.red(`Error: ${message}`));
8442
- errors.push(message);
8496
+ const errorOutput = error instanceof Error ? error.message : String(error);
8497
+ const browserError = parseMarpBrowserError(errorOutput);
8498
+ if (browserError) {
8499
+ console.error(chalk9.red(`
8500
+ Error: ${browserError.message}
8501
+ `));
8502
+ console.error(chalk9.yellow(browserError.suggestion));
8503
+ errors.push(browserError.message);
8504
+ } else {
8505
+ const message = error instanceof Error ? error.message : "Marp CLI failed";
8506
+ console.error(chalk9.red(`Error: ${message}`));
8507
+ errors.push(message);
8508
+ }
8443
8509
  process.exitCode = ExitCode.GeneralError;
8444
8510
  await cleanupTempFile();
8445
8511
  return { success: false, errors };
@@ -8448,12 +8514,13 @@ async function executeScreenshot(inputPath, options) {
8448
8514
  const actualFormat = isAiFormat ? "jpeg" : options.format || "png";
8449
8515
  let actualWidth = isAiFormat ? 640 : options.width || 1280;
8450
8516
  let actualHeight = Math.round(actualWidth * 9 / 16);
8517
+ const mdBaseName = basename10(tempMdPath, ".md");
8518
+ await ensureFileExtensions(outputDir, mdBaseName, actualFormat);
8451
8519
  if (options.slide !== void 0) {
8452
8520
  spinner?.start(`Filtering to slide ${options.slide}...`);
8453
- const mdBaseName2 = basename10(tempMdPath, ".md");
8454
8521
  const filterResult = await filterToSpecificSlide(
8455
8522
  outputDir,
8456
- mdBaseName2,
8523
+ mdBaseName,
8457
8524
  options.slide,
8458
8525
  actualFormat
8459
8526
  );
@@ -8468,7 +8535,6 @@ async function executeScreenshot(inputPath, options) {
8468
8535
  spinner?.succeed(`Kept slide ${options.slide}: ${filterResult.keptFile}`);
8469
8536
  }
8470
8537
  const allFiles = await readdir7(outputDir);
8471
- const mdBaseName = basename10(tempMdPath, ".md");
8472
8538
  const generatedFiles = allFiles.filter((f) => f.startsWith(mdBaseName) && f.endsWith(`.${actualFormat}`)).sort();
8473
8539
  if (generatedFiles.length > 0) {
8474
8540
  try {