@ncukondo/slide-generation 0.2.3 → 0.2.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.
package/dist/cli/index.js CHANGED
@@ -1515,7 +1515,7 @@ var Pipeline = class {
1515
1515
  };
1516
1516
 
1517
1517
  // src/index.ts
1518
- var VERSION = "0.2.3";
1518
+ var VERSION = "0.2.5";
1519
1519
 
1520
1520
  // src/cli/commands/convert.ts
1521
1521
  import { Command } from "commander";
@@ -2947,20 +2947,60 @@ import { Command as Command4 } from "commander";
2947
2947
  import chalk4 from "chalk";
2948
2948
  import * as yaml2 from "yaml";
2949
2949
  import { mkdir as mkdir3, writeFile as writeFile3, rm as rm2 } from "fs/promises";
2950
- import { join as join9, basename as basename5 } from "path";
2950
+ import { join as join10, basename as basename5 } from "path";
2951
2951
  import { tmpdir as tmpdir2 } from "os";
2952
- import { execFileSync as execFileSync2 } from "child_process";
2953
2952
 
2954
2953
  // src/cli/commands/preview.ts
2955
2954
  import { Command as Command3 } from "commander";
2956
2955
  import { access as access6, unlink as unlink2, readdir as readdir4, mkdir as mkdir2, writeFile as writeFile2, readFile as readFile10, rm } from "fs/promises";
2957
- import { basename as basename4, dirname as dirname4, join as join8, extname as extname2 } from "path";
2956
+ import { basename as basename4, dirname as dirname4, join as join9, extname as extname2 } from "path";
2958
2957
  import * as path6 from "path";
2959
2958
  import { tmpdir } from "os";
2960
- import { spawn, execSync, execFileSync } from "child_process";
2961
2959
  import { createServer } from "http";
2962
2960
  import chalk3 from "chalk";
2963
2961
  import { watch as chokidarWatch } from "chokidar";
2962
+
2963
+ // src/cli/utils/marp-runner.ts
2964
+ import { existsSync } from "fs";
2965
+ import { join as join8 } from "path";
2966
+ import {
2967
+ execFileSync,
2968
+ spawn
2969
+ } from "child_process";
2970
+ function getMarpCommand(projectDir) {
2971
+ const dir = projectDir ?? process.cwd();
2972
+ const localMarp = join8(dir, "node_modules", ".bin", "marp");
2973
+ if (existsSync(localMarp)) {
2974
+ return localMarp;
2975
+ }
2976
+ try {
2977
+ execFileSync("marp", ["--version"], { stdio: "ignore", timeout: 5e3 });
2978
+ return "marp";
2979
+ } catch {
2980
+ return null;
2981
+ }
2982
+ }
2983
+ function isMarpAvailable(projectDir) {
2984
+ return getMarpCommand(projectDir) !== null;
2985
+ }
2986
+ function runMarp(args, options = {}) {
2987
+ const { projectDir, ...execOptions } = options;
2988
+ const marpCmd = getMarpCommand(projectDir);
2989
+ if (!marpCmd) {
2990
+ throw new Error("Marp CLI not found. Install it with: npm install -D @marp-team/marp-cli");
2991
+ }
2992
+ execFileSync(marpCmd, args, execOptions);
2993
+ }
2994
+ function spawnMarp(args, options = {}) {
2995
+ const { projectDir, ...spawnOptions } = options;
2996
+ const marpCmd = getMarpCommand(projectDir);
2997
+ if (!marpCmd) {
2998
+ throw new Error("Marp CLI not found. Install it with: npm install -D @marp-team/marp-cli");
2999
+ }
3000
+ return spawn(marpCmd, args, spawnOptions);
3001
+ }
3002
+
3003
+ // src/cli/commands/preview.ts
2964
3004
  function escapeHtml(str) {
2965
3005
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
2966
3006
  }
@@ -3074,7 +3114,7 @@ async function collectSlideInfo(dir, baseName, format) {
3074
3114
  if (match) {
3075
3115
  const index = parseInt(match[1], 10);
3076
3116
  slides.push({
3077
- path: join8(dir, file),
3117
+ path: join9(dir, file),
3078
3118
  title: `Slide ${index}`,
3079
3119
  index
3080
3120
  });
@@ -3085,20 +3125,15 @@ async function collectSlideInfo(dir, baseName, format) {
3085
3125
  return [];
3086
3126
  }
3087
3127
  }
3088
- async function checkMarpCliAvailable() {
3089
- try {
3090
- execSync("marp --version", { stdio: "ignore", timeout: 5e3 });
3091
- return true;
3092
- } catch {
3093
- return false;
3094
- }
3128
+ async function checkMarpCliAvailable(projectDir) {
3129
+ return isMarpAvailable(projectDir);
3095
3130
  }
3096
3131
  function getTempOutputPath(inputPath) {
3097
3132
  const base = basename4(inputPath, ".yaml");
3098
- return join8(tmpdir(), `slide-gen-preview-${base}-${Date.now()}.md`);
3133
+ return join9(tmpdir(), `slide-gen-preview-${base}-${Date.now()}.md`);
3099
3134
  }
3100
3135
  function buildMarpCommand(markdownPath, options) {
3101
- const parts = ["npx", "marp", "--preview"];
3136
+ const parts = ["marp", "--preview"];
3102
3137
  if (options.port) {
3103
3138
  parts.push("-p", String(options.port));
3104
3139
  }
@@ -3153,7 +3188,7 @@ function startStaticServer(baseDir, port, options = {}) {
3153
3188
  async function executeGalleryPreview(inputPath, options) {
3154
3189
  const errors = [];
3155
3190
  const port = Number(options.port) || 8080;
3156
- const galleryDir = join8(tmpdir(), `slide-gen-gallery-${Date.now()}`);
3191
+ const galleryDir = join9(tmpdir(), `slide-gen-gallery-${Date.now()}`);
3157
3192
  try {
3158
3193
  await access6(inputPath);
3159
3194
  } catch {
@@ -3163,11 +3198,12 @@ async function executeGalleryPreview(inputPath, options) {
3163
3198
  return { success: false, errors };
3164
3199
  }
3165
3200
  console.log("Checking for Marp CLI...");
3166
- const marpAvailable = await checkMarpCliAvailable();
3201
+ const projectDir = dirname4(inputPath);
3202
+ const marpAvailable = await checkMarpCliAvailable(projectDir);
3167
3203
  if (!marpAvailable) {
3168
3204
  console.error(
3169
3205
  chalk3.red(
3170
- "Error: Marp CLI not found. Install it with: npm install -g @marp-team/marp-cli"
3206
+ "Error: Marp CLI not found. Install it with: npm install -D @marp-team/marp-cli"
3171
3207
  )
3172
3208
  );
3173
3209
  errors.push("Marp CLI not available");
@@ -3194,7 +3230,7 @@ async function executeGalleryPreview(inputPath, options) {
3194
3230
  await rm(galleryDir, { recursive: true, force: true });
3195
3231
  return { success: false, errors };
3196
3232
  }
3197
- const tempMdPath = join8(galleryDir, "slides.md");
3233
+ const tempMdPath = join9(galleryDir, "slides.md");
3198
3234
  console.log(`Converting ${chalk3.cyan(inputPath)}...`);
3199
3235
  try {
3200
3236
  await pipeline.runWithResult(inputPath, { outputPath: tempMdPath });
@@ -3209,7 +3245,8 @@ async function executeGalleryPreview(inputPath, options) {
3209
3245
  }
3210
3246
  console.log("Taking screenshots...");
3211
3247
  try {
3212
- execFileSync("npx", ["marp", "--images", "png", "-o", galleryDir, tempMdPath], {
3248
+ runMarp(["--images", "png", "-o", galleryDir, tempMdPath], {
3249
+ projectDir,
3213
3250
  stdio: options.verbose ? "inherit" : "pipe"
3214
3251
  });
3215
3252
  console.log(chalk3.green("\u2713") + " Screenshots generated");
@@ -3234,7 +3271,7 @@ async function executeGalleryPreview(inputPath, options) {
3234
3271
  path: basename4(s.path)
3235
3272
  }));
3236
3273
  const galleryHtml = generateGalleryHtml(relativeSlides);
3237
- await writeFile2(join8(galleryDir, "index.html"), galleryHtml);
3274
+ await writeFile2(join9(galleryDir, "index.html"), galleryHtml);
3238
3275
  console.log(`
3239
3276
  Starting gallery server on port ${chalk3.cyan(port)}...`);
3240
3277
  let server;
@@ -3314,11 +3351,11 @@ async function executePreview(inputPath, options) {
3314
3351
  return { success: false, errors };
3315
3352
  }
3316
3353
  console.log("Checking for Marp CLI...");
3317
- const marpAvailable = await checkMarpCliAvailable();
3354
+ const marpAvailable = await checkMarpCliAvailable(dirname4(inputPath));
3318
3355
  if (!marpAvailable) {
3319
3356
  console.error(
3320
3357
  chalk3.red(
3321
- "Error: Marp CLI not found. Install it with: npm install -g @marp-team/marp-cli"
3358
+ "Error: Marp CLI not found. Install it with: npm install -D @marp-team/marp-cli"
3322
3359
  )
3323
3360
  );
3324
3361
  errors.push("Marp CLI not available");
@@ -3366,9 +3403,9 @@ Starting preview server on port ${chalk3.cyan(port)}...`);
3366
3403
  if (verbose) {
3367
3404
  console.log(`Running: ${marpCommand}`);
3368
3405
  }
3369
- const marpProcess = spawn("npx", ["marp", "--preview", "-p", String(port), tempMarkdownPath], {
3370
- stdio: "inherit",
3371
- shell: true
3406
+ const marpProcess = spawnMarp(["--preview", "-p", String(port), tempMarkdownPath], {
3407
+ projectDir: dirname4(inputPath),
3408
+ stdio: "inherit"
3372
3409
  });
3373
3410
  let watcher = null;
3374
3411
  let debounceTimer = null;
@@ -3849,7 +3886,7 @@ async function executeTemplatePreview(name, options) {
3849
3886
  return;
3850
3887
  }
3851
3888
  const port = Number(options.port) || 8080;
3852
- const previewDir = join9(tmpdir2(), `slide-gen-template-preview-${Date.now()}`);
3889
+ const previewDir = join10(tmpdir2(), `slide-gen-template-preview-${Date.now()}`);
3853
3890
  console.log("Checking for Marp CLI...");
3854
3891
  const marpAvailable = await checkMarpCliAvailable();
3855
3892
  if (!marpAvailable) {
@@ -3902,9 +3939,9 @@ async function executeTemplatePreview(name, options) {
3902
3939
  for (const template of templates) {
3903
3940
  console.log(`Processing template: ${chalk4.cyan(template.name)}...`);
3904
3941
  const sampleYaml = generateSampleYaml(template);
3905
- const yamlPath = join9(previewDir, `${template.name}.yaml`);
3942
+ const yamlPath = join10(previewDir, `${template.name}.yaml`);
3906
3943
  await writeFile3(yamlPath, sampleYaml);
3907
- const mdPath = join9(previewDir, `${template.name}.md`);
3944
+ const mdPath = join10(previewDir, `${template.name}.md`);
3908
3945
  try {
3909
3946
  await pipeline.runWithResult(yamlPath, { outputPath: mdPath });
3910
3947
  } catch (error) {
@@ -3913,7 +3950,8 @@ async function executeTemplatePreview(name, options) {
3913
3950
  continue;
3914
3951
  }
3915
3952
  try {
3916
- execFileSync2("npx", ["marp", "--images", "png", "-o", previewDir, mdPath], {
3953
+ runMarp(["--images", "png", "-o", previewDir, mdPath], {
3954
+ projectDir: process.cwd(),
3917
3955
  stdio: "pipe"
3918
3956
  });
3919
3957
  } catch {
@@ -3936,7 +3974,7 @@ async function executeTemplatePreview(name, options) {
3936
3974
  return;
3937
3975
  }
3938
3976
  const previewHtml = generateTemplatePreviewHtml(templatePreviews);
3939
- await writeFile3(join9(previewDir, "index.html"), previewHtml);
3977
+ await writeFile3(join10(previewDir, "index.html"), previewHtml);
3940
3978
  console.log(`
3941
3979
  Starting preview server on port ${chalk4.cyan(port)}...`);
3942
3980
  let server;
@@ -4769,9 +4807,10 @@ function createIconsCommand() {
4769
4807
  // src/cli/commands/init.ts
4770
4808
  import { Command as Command6 } from "commander";
4771
4809
  import { mkdir as mkdir7, writeFile as writeFile7, access as access10, readdir as readdir6, cp } from "fs/promises";
4772
- import { existsSync } from "fs";
4773
- import { execSync as execSync2 } from "child_process";
4774
- import { dirname as dirname6, join as join15, resolve as resolve5, sep } from "path";
4810
+ import { existsSync as existsSync2 } from "fs";
4811
+ import { execSync, spawnSync } from "child_process";
4812
+ import { createInterface } from "readline";
4813
+ import { basename as basename7, dirname as dirname6, join as join16, resolve as resolve5, sep } from "path";
4775
4814
  import { fileURLToPath } from "url";
4776
4815
  import chalk6 from "chalk";
4777
4816
  import ora3 from "ora";
@@ -6035,9 +6074,9 @@ function generateSlideThemeCommand() {
6035
6074
  function getPackageRoot() {
6036
6075
  const __dirname = dirname6(fileURLToPath(import.meta.url));
6037
6076
  if (__dirname.includes(`${sep}src${sep}`) || __dirname.includes("/src/")) {
6038
- return join15(__dirname, "..", "..", "..");
6077
+ return join16(__dirname, "..", "..", "..");
6039
6078
  }
6040
- return join15(__dirname, "..", "..");
6079
+ return join16(__dirname, "..", "..");
6041
6080
  }
6042
6081
  function createInitCommand() {
6043
6082
  return new Command6("init").description("Initialize a new project").argument("[directory]", "Target directory", ".").option("--template <name>", "Initial template").option("--no-examples", "Do not create sample files").option("--no-ai-config", "Do not create AI assistant config files").option("--no-sources", "Do not create sources directory").option("--from-directory <path>", "Import materials from directory").option("--skip-marp-install", "Skip Marp CLI installation prompt").action(async (directory, options) => {
@@ -6061,29 +6100,29 @@ async function executeInit(directory, options) {
6061
6100
  } catch {
6062
6101
  }
6063
6102
  await mkdir7(targetDir, { recursive: true });
6064
- await mkdir7(join15(targetDir, "themes"), { recursive: true });
6065
- await mkdir7(join15(targetDir, "icons", "custom"), { recursive: true });
6103
+ await mkdir7(join16(targetDir, "themes"), { recursive: true });
6104
+ await mkdir7(join16(targetDir, "icons", "custom"), { recursive: true });
6066
6105
  const packageRoot = getPackageRoot();
6067
- const sourceTemplatesDir = join15(packageRoot, "templates");
6068
- const targetTemplatesDir = join15(targetDir, "templates");
6106
+ const sourceTemplatesDir = join16(packageRoot, "templates");
6107
+ const targetTemplatesDir = join16(targetDir, "templates");
6069
6108
  try {
6070
6109
  await access10(targetTemplatesDir);
6071
6110
  } catch {
6072
6111
  await cp(sourceTemplatesDir, targetTemplatesDir, { recursive: true });
6073
6112
  }
6074
- const sourceIconsRegistry = join15(packageRoot, "icons", "registry.yaml");
6075
- const targetIconsRegistry = join15(targetDir, "icons", "registry.yaml");
6113
+ const sourceIconsRegistry = join16(packageRoot, "icons", "registry.yaml");
6114
+ const targetIconsRegistry = join16(targetDir, "icons", "registry.yaml");
6076
6115
  await copyFileIfNotExists(sourceIconsRegistry, targetIconsRegistry);
6077
- const sourceDefaultTheme = join15(packageRoot, "themes", "default.css");
6078
- const targetDefaultTheme = join15(targetDir, "themes", "default.css");
6116
+ const sourceDefaultTheme = join16(packageRoot, "themes", "default.css");
6117
+ const targetDefaultTheme = join16(targetDir, "themes", "default.css");
6079
6118
  await copyFileIfNotExists(sourceDefaultTheme, targetDefaultTheme);
6080
6119
  const configContent = generateConfigContent();
6081
- await writeFileIfNotExists(join15(targetDir, "config.yaml"), configContent);
6120
+ await writeFileIfNotExists(join16(targetDir, "config.yaml"), configContent);
6082
6121
  const customCssContent = generateCustomCssContent();
6083
- await writeFileIfNotExists(join15(targetDir, "themes", "custom.css"), customCssContent);
6122
+ await writeFileIfNotExists(join16(targetDir, "themes", "custom.css"), customCssContent);
6084
6123
  if (includeExamples) {
6085
6124
  const presentationContent = generatePresentationContent(options.template);
6086
- await writeFileIfNotExists(join15(targetDir, "presentation.yaml"), presentationContent);
6125
+ await writeFileIfNotExists(join16(targetDir, "presentation.yaml"), presentationContent);
6087
6126
  }
6088
6127
  if (includeAiConfig) {
6089
6128
  await generateAiConfig(targetDir);
@@ -6138,7 +6177,7 @@ async function executeInit(directory, options) {
6138
6177
  console.log(` 1. Edit ${chalk6.yellow("presentation.yaml")} to add your slides`);
6139
6178
  console.log(` 2. Run ${chalk6.yellow("slide-gen convert presentation.yaml")} to generate markdown`);
6140
6179
  if (options.skipMarpInstall !== true) {
6141
- showMarpCliInfo(targetDir);
6180
+ await showMarpCliInfo(targetDir);
6142
6181
  }
6143
6182
  } catch (error) {
6144
6183
  spinner.fail("Failed to initialize project");
@@ -6162,53 +6201,186 @@ async function copyFileIfNotExists(source, dest) {
6162
6201
  await cp(source, dest);
6163
6202
  }
6164
6203
  }
6165
- function isMarpCliInstalled() {
6204
+ function isMarpCliInstalledGlobally() {
6166
6205
  try {
6167
- execSync2("marp --version", { stdio: "pipe", timeout: 5e3 });
6206
+ execSync("marp --version", { stdio: "pipe", timeout: 5e3 });
6168
6207
  return true;
6169
6208
  } catch {
6170
6209
  return false;
6171
6210
  }
6172
6211
  }
6212
+ function isMarpCliInstalledLocally(targetDir) {
6213
+ const dir = targetDir ?? process.cwd();
6214
+ const marpBinPath = join16(dir, "node_modules", ".bin", "marp");
6215
+ return existsSync2(marpBinPath);
6216
+ }
6173
6217
  function detectPackageManager(targetDir) {
6174
6218
  const dir = targetDir ?? process.cwd();
6175
- if (existsSync(join15(dir, "pnpm-lock.yaml"))) return "pnpm";
6176
- if (existsSync(join15(dir, "yarn.lock"))) return "yarn";
6219
+ if (existsSync2(join16(dir, "pnpm-lock.yaml"))) return "pnpm";
6220
+ if (existsSync2(join16(dir, "yarn.lock"))) return "yarn";
6177
6221
  return "npm";
6178
6222
  }
6179
- function showMarpCliInfo(targetDir) {
6180
- if (isMarpCliInstalled()) {
6181
- return;
6223
+ function getMarpInstallCommand(pm) {
6224
+ switch (pm) {
6225
+ case "pnpm":
6226
+ return "pnpm add -D @marp-team/marp-cli";
6227
+ case "yarn":
6228
+ return "yarn add -D @marp-team/marp-cli";
6229
+ default:
6230
+ return "npm install -D @marp-team/marp-cli";
6231
+ }
6232
+ }
6233
+ async function promptMarpInstallChoice() {
6234
+ if (!process.stdin.isTTY) {
6235
+ return "skip";
6182
6236
  }
6237
+ const rl = createInterface({
6238
+ input: process.stdin,
6239
+ output: process.stdout
6240
+ });
6241
+ console.log("How would you like to install Marp CLI?");
6242
+ console.log(` ${chalk6.cyan("1)")} Global install ${chalk6.dim("(recommended - works everywhere)")}`);
6243
+ console.log(` ${chalk6.cyan("2)")} Local install ${chalk6.dim("(creates package.json)")}`);
6244
+ console.log(` ${chalk6.cyan("3)")} Skip ${chalk6.dim("(I'll install it later)")}`);
6245
+ console.log("");
6246
+ return new Promise((resolve7) => {
6247
+ rl.question("Choice [1]: ", (answer) => {
6248
+ rl.close();
6249
+ const normalized = answer.trim();
6250
+ if (normalized === "" || normalized === "1") {
6251
+ resolve7("global");
6252
+ } else if (normalized === "2") {
6253
+ resolve7("local");
6254
+ } else {
6255
+ resolve7("skip");
6256
+ }
6257
+ });
6258
+ });
6259
+ }
6260
+ function installMarpCliGlobally() {
6261
+ const spinner = ora3("Installing Marp CLI globally...").start();
6262
+ try {
6263
+ const result = spawnSync("npm", ["install", "-g", "@marp-team/marp-cli"], {
6264
+ stdio: "pipe",
6265
+ shell: true,
6266
+ timeout: 12e4
6267
+ // 2 minutes timeout
6268
+ });
6269
+ if (result.status === 0) {
6270
+ spinner.succeed("Marp CLI installed globally");
6271
+ return true;
6272
+ } else {
6273
+ const stderr = result.stderr?.toString() || "Unknown error";
6274
+ spinner.fail(`Failed to install Marp CLI: ${stderr}`);
6275
+ console.log(chalk6.dim("You can install it manually with: npm install -g @marp-team/marp-cli"));
6276
+ return false;
6277
+ }
6278
+ } catch (error) {
6279
+ const message = error instanceof Error ? error.message : "Unknown error";
6280
+ spinner.fail(`Failed to install Marp CLI: ${message}`);
6281
+ console.log(chalk6.dim("You can install it manually with: npm install -g @marp-team/marp-cli"));
6282
+ return false;
6283
+ }
6284
+ }
6285
+ async function installMarpCliLocally(targetDir) {
6183
6286
  const pm = detectPackageManager(targetDir);
6184
- const installCmd = pm === "pnpm" ? "pnpm add -D @marp-team/marp-cli" : pm === "yarn" ? "yarn add -D @marp-team/marp-cli" : "npm install -D @marp-team/marp-cli";
6287
+ const installCmd = getMarpInstallCommand(pm);
6288
+ const packageJsonPath = join16(targetDir, "package.json");
6289
+ if (!existsSync2(packageJsonPath)) {
6290
+ const packageJsonContent = generatePackageJsonContent(targetDir);
6291
+ await writeFile7(packageJsonPath, packageJsonContent, "utf-8");
6292
+ }
6293
+ const spinner = ora3(`Installing Marp CLI locally with ${pm}...`).start();
6294
+ try {
6295
+ const result = spawnSync(pm, ["add", "-D", "@marp-team/marp-cli"], {
6296
+ cwd: targetDir,
6297
+ stdio: "pipe",
6298
+ shell: true,
6299
+ timeout: 12e4
6300
+ // 2 minutes timeout
6301
+ });
6302
+ if (result.status === 0) {
6303
+ spinner.succeed("Marp CLI installed locally");
6304
+ return true;
6305
+ } else {
6306
+ const stderr = result.stderr?.toString() || "Unknown error";
6307
+ spinner.fail(`Failed to install Marp CLI: ${stderr}`);
6308
+ console.log(chalk6.dim(`You can install it manually with: ${installCmd}`));
6309
+ return false;
6310
+ }
6311
+ } catch (error) {
6312
+ const message = error instanceof Error ? error.message : "Unknown error";
6313
+ spinner.fail(`Failed to install Marp CLI: ${message}`);
6314
+ console.log(chalk6.dim(`You can install it manually with: ${installCmd}`));
6315
+ return false;
6316
+ }
6317
+ }
6318
+ function generatePackageJsonContent(targetDir) {
6319
+ const projectName = basename7(targetDir) || "my-presentation";
6320
+ return JSON.stringify(
6321
+ {
6322
+ name: projectName,
6323
+ version: "1.0.0",
6324
+ private: true,
6325
+ description: "Presentation project created with slide-gen",
6326
+ scripts: {
6327
+ preview: "slide-gen preview presentation.yaml",
6328
+ build: "slide-gen convert presentation.yaml"
6329
+ }
6330
+ },
6331
+ null,
6332
+ 2
6333
+ );
6334
+ }
6335
+ async function showMarpCliInfo(targetDir) {
6336
+ if (isMarpCliInstalledGlobally() || isMarpCliInstalledLocally(targetDir)) {
6337
+ console.log("");
6338
+ console.log(chalk6.green("\u2713") + " Marp CLI is available");
6339
+ return true;
6340
+ }
6185
6341
  console.log("");
6342
+ console.log(chalk6.dim("\u2500".repeat(45)));
6186
6343
  console.log(chalk6.yellow("Marp CLI is recommended for full features:"));
6187
- console.log(" - Preview slides in browser");
6188
- console.log(" - Take screenshots for AI review");
6189
- console.log(" - Export to PDF/HTML/PPTX");
6344
+ console.log(" \u2022 Preview slides in browser");
6345
+ console.log(" \u2022 Take screenshots for AI review");
6346
+ console.log(" \u2022 Export to PDF/HTML/PPTX");
6190
6347
  console.log("");
6191
- console.log(chalk6.dim("Install with:"));
6192
- console.log(` ${chalk6.cyan(installCmd)}`);
6348
+ console.log(chalk6.dim("Marp CLI is not currently installed."));
6349
+ console.log(chalk6.dim("\u2500".repeat(45)));
6350
+ console.log("");
6351
+ const choice = await promptMarpInstallChoice();
6352
+ switch (choice) {
6353
+ case "global":
6354
+ return installMarpCliGlobally();
6355
+ case "local":
6356
+ return await installMarpCliLocally(targetDir);
6357
+ case "skip":
6358
+ default:
6359
+ console.log("");
6360
+ console.log(chalk6.dim("You can install Marp CLI later with:"));
6361
+ console.log(` ${chalk6.cyan("npm install -g @marp-team/marp-cli")} ${chalk6.dim("(global)")}`);
6362
+ console.log(` ${chalk6.cyan("npm install -D @marp-team/marp-cli")} ${chalk6.dim("(local)")}`);
6363
+ return false;
6364
+ }
6193
6365
  }
6194
6366
  async function generateAiConfig(targetDir) {
6195
- await mkdir7(join15(targetDir, ".skills", "slide-assistant", "references"), { recursive: true });
6196
- await mkdir7(join15(targetDir, ".skills", "slide-assistant", "scripts"), { recursive: true });
6197
- await mkdir7(join15(targetDir, ".claude", "commands"), { recursive: true });
6198
- await mkdir7(join15(targetDir, ".opencode", "agent"), { recursive: true });
6367
+ await mkdir7(join16(targetDir, ".skills", "slide-assistant", "references"), { recursive: true });
6368
+ await mkdir7(join16(targetDir, ".skills", "slide-assistant", "scripts"), { recursive: true });
6369
+ await mkdir7(join16(targetDir, ".claude", "commands"), { recursive: true });
6370
+ await mkdir7(join16(targetDir, ".opencode", "agent"), { recursive: true });
6199
6371
  await writeFileIfNotExists(
6200
- join15(targetDir, ".skills", "slide-assistant", "SKILL.md"),
6372
+ join16(targetDir, ".skills", "slide-assistant", "SKILL.md"),
6201
6373
  generateSkillMd()
6202
6374
  );
6203
6375
  await writeFileIfNotExists(
6204
- join15(targetDir, ".skills", "slide-assistant", "references", "templates.md"),
6376
+ join16(targetDir, ".skills", "slide-assistant", "references", "templates.md"),
6205
6377
  generateTemplatesRef()
6206
6378
  );
6207
6379
  await writeFileIfNotExists(
6208
- join15(targetDir, ".skills", "slide-assistant", "references", "workflows.md"),
6380
+ join16(targetDir, ".skills", "slide-assistant", "references", "workflows.md"),
6209
6381
  generateWorkflowsRef()
6210
6382
  );
6211
- await writeFileIfNotExists(join15(targetDir, "CLAUDE.md"), generateClaudeMd());
6383
+ await writeFileIfNotExists(join16(targetDir, "CLAUDE.md"), generateClaudeMd());
6212
6384
  const commandGenerators = {
6213
6385
  "slide-create": generateSlideCreateCommand,
6214
6386
  "slide-validate": generateSlideValidateCommand,
@@ -6218,16 +6390,16 @@ async function generateAiConfig(targetDir) {
6218
6390
  };
6219
6391
  for (const [name, generator] of Object.entries(commandGenerators)) {
6220
6392
  await writeFileIfNotExists(
6221
- join15(targetDir, ".claude", "commands", `${name}.md`),
6393
+ join16(targetDir, ".claude", "commands", `${name}.md`),
6222
6394
  generator()
6223
6395
  );
6224
6396
  }
6225
- await writeFileIfNotExists(join15(targetDir, "AGENTS.md"), generateAgentsMd());
6397
+ await writeFileIfNotExists(join16(targetDir, "AGENTS.md"), generateAgentsMd());
6226
6398
  await writeFileIfNotExists(
6227
- join15(targetDir, ".opencode", "agent", "slide.md"),
6399
+ join16(targetDir, ".opencode", "agent", "slide.md"),
6228
6400
  generateOpenCodeAgent()
6229
6401
  );
6230
- await writeFileIfNotExists(join15(targetDir, ".cursorrules"), generateAgentsMd());
6402
+ await writeFileIfNotExists(join16(targetDir, ".cursorrules"), generateAgentsMd());
6231
6403
  }
6232
6404
  function generateConfigContent() {
6233
6405
  return `# slide-gen configuration
@@ -6325,7 +6497,7 @@ slides:
6325
6497
  // src/cli/commands/watch.ts
6326
6498
  import { Command as Command7 } from "commander";
6327
6499
  import { access as access11 } from "fs/promises";
6328
- import { basename as basename7, dirname as dirname7, join as join16 } from "path";
6500
+ import { basename as basename8, dirname as dirname7, join as join17 } from "path";
6329
6501
  import chalk7 from "chalk";
6330
6502
  import { watch as chokidarWatch2 } from "chokidar";
6331
6503
  var WatchState = class {
@@ -6359,8 +6531,8 @@ var WatchState = class {
6359
6531
  };
6360
6532
  function getDefaultOutputPath2(inputPath) {
6361
6533
  const dir = dirname7(inputPath);
6362
- const base = basename7(inputPath, ".yaml");
6363
- return join16(dir, `${base}.md`);
6534
+ const base = basename8(inputPath, ".yaml");
6535
+ return join17(dir, `${base}.md`);
6364
6536
  }
6365
6537
  function formatTime() {
6366
6538
  const now = /* @__PURE__ */ new Date();
@@ -6504,7 +6676,7 @@ async function executeWatch(inputPath, options) {
6504
6676
  // src/cli/commands/images.ts
6505
6677
  import { Command as Command8 } from "commander";
6506
6678
  import { readFile as readFile15, stat as stat2, mkdir as mkdir8 } from "fs/promises";
6507
- import { dirname as dirname8, basename as basename8, join as join17 } from "path";
6679
+ import { dirname as dirname8, basename as basename9, join as join18 } from "path";
6508
6680
  import chalk8 from "chalk";
6509
6681
  import { stringify as stringifyYaml3 } from "yaml";
6510
6682
  function createImagesCommand() {
@@ -6792,7 +6964,7 @@ async function executeImagesProcess(inputPath, options) {
6792
6964
  }
6793
6965
  async function processDirectory(dirPath, options) {
6794
6966
  if (options.fromMeta) {
6795
- const outputDir = join17(dirPath, options.output);
6967
+ const outputDir = join18(dirPath, options.output);
6796
6968
  const pipeline = new ImageProcessingPipeline(dirPath, { outputDir });
6797
6969
  const result = await pipeline.processDirectory();
6798
6970
  console.log("");
@@ -6828,10 +7000,10 @@ async function processSingleFile(filePath, options) {
6828
7000
  }
6829
7001
  const processor = new ImageProcessor();
6830
7002
  const dir = dirname8(filePath);
6831
- const filename = basename8(filePath);
6832
- const outputDir = join17(dir, options.output);
7003
+ const filename = basename9(filePath);
7004
+ const outputDir = join18(dir, options.output);
6833
7005
  await mkdir8(outputDir, { recursive: true });
6834
- const outputPath = join17(outputDir, filename);
7006
+ const outputPath = join18(outputDir, filename);
6835
7007
  let success = false;
6836
7008
  if (options.crop) {
6837
7009
  const edges = parseCropSpec(options.crop);
@@ -6926,14 +7098,13 @@ function parseBlurSpec(spec) {
6926
7098
  // src/cli/commands/screenshot.ts
6927
7099
  import { Command as Command9 } from "commander";
6928
7100
  import { access as access12, mkdir as mkdir9, readdir as readdir7, unlink as unlink3 } from "fs/promises";
6929
- import { basename as basename9, dirname as dirname9, join as join18 } from "path";
6930
- import { execSync as execSync3, execFileSync as execFileSync3 } from "child_process";
7101
+ import { basename as basename10, dirname as dirname9, join as join19 } from "path";
6931
7102
  import chalk9 from "chalk";
6932
7103
  import ora4 from "ora";
6933
7104
  async function filterToSpecificSlide(outputDir, baseName, slideNumber, format) {
6934
7105
  const slideStr = slideNumber.toString().padStart(3, "0");
6935
7106
  const targetFileName = `${baseName}.${slideStr}.${format}`;
6936
- const targetPath = join18(outputDir, targetFileName);
7107
+ const targetPath = join19(outputDir, targetFileName);
6937
7108
  try {
6938
7109
  await access12(targetPath);
6939
7110
  } catch {
@@ -6948,7 +7119,7 @@ async function filterToSpecificSlide(outputDir, baseName, slideNumber, format) {
6948
7119
  );
6949
7120
  for (const file of slideFiles) {
6950
7121
  if (file !== targetFileName) {
6951
- await unlink3(join18(outputDir, file));
7122
+ await unlink3(join19(outputDir, file));
6952
7123
  }
6953
7124
  }
6954
7125
  return {
@@ -6956,17 +7127,12 @@ async function filterToSpecificSlide(outputDir, baseName, slideNumber, format) {
6956
7127
  keptFile: targetFileName
6957
7128
  };
6958
7129
  }
6959
- function checkMarpCliAvailable2() {
6960
- try {
6961
- execSync3("marp --version", { stdio: "ignore", timeout: 5e3 });
6962
- return true;
6963
- } catch {
6964
- return false;
6965
- }
7130
+ function checkMarpCliAvailable2(projectDir) {
7131
+ return isMarpAvailable(projectDir);
6966
7132
  }
6967
7133
  function buildMarpCommandArgs(markdownPath, outputDir, options) {
6968
7134
  const format = options.format || "png";
6969
- const args = ["marp", "--images", format];
7135
+ const args = ["--images", format];
6970
7136
  if (options.width && options.width !== 1280) {
6971
7137
  const scale = options.width / 1280;
6972
7138
  args.push("--image-scale", String(scale));
@@ -7001,9 +7167,9 @@ async function executeScreenshot(inputPath, options) {
7001
7167
  return { success: false, errors };
7002
7168
  }
7003
7169
  spinner?.start("Checking for Marp CLI...");
7004
- if (!checkMarpCliAvailable2()) {
7170
+ if (!checkMarpCliAvailable2(dirname9(inputPath))) {
7005
7171
  spinner?.fail("Marp CLI not found");
7006
- const message = "Marp CLI not found. Install it with: npm install -g @marp-team/marp-cli";
7172
+ const message = "Marp CLI not found. Install it with: npm install -D @marp-team/marp-cli";
7007
7173
  console.error(chalk9.red(`Error: ${message}`));
7008
7174
  errors.push(message);
7009
7175
  process.exitCode = ExitCode.GeneralError;
@@ -7063,10 +7229,13 @@ async function executeScreenshot(inputPath, options) {
7063
7229
  spinner?.start("Taking screenshots...");
7064
7230
  const marpArgs = buildMarpCommandArgs(tempMdPath, outputDir, options);
7065
7231
  if (options.verbose) {
7066
- console.log(`Running: npx ${marpArgs.join(" ")}`);
7232
+ console.log(`Running: marp ${marpArgs.join(" ")}`);
7067
7233
  }
7068
7234
  try {
7069
- execFileSync3("npx", marpArgs, { stdio: options.verbose ? "inherit" : "pipe" });
7235
+ runMarp(marpArgs, {
7236
+ projectDir: dirname9(inputPath),
7237
+ stdio: options.verbose ? "inherit" : "pipe"
7238
+ });
7070
7239
  spinner?.succeed(`Screenshots saved to ${outputDir}`);
7071
7240
  } catch (error) {
7072
7241
  spinner?.fail("Failed to take screenshots");
@@ -7079,7 +7248,7 @@ async function executeScreenshot(inputPath, options) {
7079
7248
  }
7080
7249
  if (options.slide !== void 0) {
7081
7250
  spinner?.start(`Filtering to slide ${options.slide}...`);
7082
- const mdBaseName = basename9(tempMdPath, ".md");
7251
+ const mdBaseName = basename10(tempMdPath, ".md");
7083
7252
  const format = options.format || "png";
7084
7253
  const filterResult = await filterToSpecificSlide(
7085
7254
  outputDir,