@ncukondo/slide-generation 0.2.2 → 0.2.4

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.2";
1518
+ var VERSION = "0.2.4";
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 } from "path";
4810
+ import { existsSync as existsSync2 } from "fs";
4811
+ import { execSync, spawnSync } from "child_process";
4812
+ import { createInterface } from "readline";
4813
+ import { 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";
@@ -6034,10 +6073,10 @@ function generateSlideThemeCommand() {
6034
6073
  // src/cli/commands/init.ts
6035
6074
  function getPackageRoot() {
6036
6075
  const __dirname = dirname6(fileURLToPath(import.meta.url));
6037
- if (__dirname.includes("/src/")) {
6038
- return join15(__dirname, "..", "..", "..");
6076
+ if (__dirname.includes(`${sep}src${sep}`) || __dirname.includes("/src/")) {
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,139 @@ 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 promptYesNo(question, defaultYes = true) {
6234
+ if (!process.stdin.isTTY) {
6235
+ return defaultYes;
6236
+ }
6237
+ const rl = createInterface({
6238
+ input: process.stdin,
6239
+ output: process.stdout
6240
+ });
6241
+ const hint = defaultYes ? "(Y/n)" : "(y/N)";
6242
+ const prompt = `${question} ${hint} `;
6243
+ return new Promise((resolve7) => {
6244
+ rl.question(prompt, (answer) => {
6245
+ rl.close();
6246
+ const normalized = answer.trim().toLowerCase();
6247
+ if (normalized === "") {
6248
+ resolve7(defaultYes);
6249
+ } else {
6250
+ resolve7(normalized === "y" || normalized === "yes");
6251
+ }
6252
+ });
6253
+ });
6254
+ }
6255
+ function installMarpCli(targetDir) {
6256
+ const pm = detectPackageManager(targetDir);
6257
+ const installCmd = getMarpInstallCommand(pm);
6258
+ const spinner = ora3(`Installing Marp CLI with ${pm}...`).start();
6259
+ try {
6260
+ const result = spawnSync(pm, ["add", "-D", "@marp-team/marp-cli"], {
6261
+ cwd: targetDir,
6262
+ stdio: "pipe",
6263
+ shell: true,
6264
+ timeout: 12e4
6265
+ // 2 minutes timeout
6266
+ });
6267
+ if (result.status === 0) {
6268
+ spinner.succeed("Marp CLI installed successfully");
6269
+ return true;
6270
+ } else {
6271
+ const stderr = result.stderr?.toString() || "Unknown error";
6272
+ spinner.fail(`Failed to install Marp CLI: ${stderr}`);
6273
+ console.log(chalk6.dim(`You can install it manually with: ${installCmd}`));
6274
+ return false;
6275
+ }
6276
+ } catch (error) {
6277
+ const message = error instanceof Error ? error.message : "Unknown error";
6278
+ spinner.fail(`Failed to install Marp CLI: ${message}`);
6279
+ console.log(chalk6.dim(`You can install it manually with: ${installCmd}`));
6280
+ return false;
6281
+ }
6282
+ }
6283
+ async function showMarpCliInfo(targetDir) {
6284
+ if (isMarpCliInstalledGlobally() || isMarpCliInstalledLocally(targetDir)) {
6285
+ console.log("");
6286
+ console.log(chalk6.green("\u2713") + " Marp CLI is available");
6287
+ return true;
6182
6288
  }
6183
6289
  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";
6290
+ const installCmd = getMarpInstallCommand(pm);
6185
6291
  console.log("");
6292
+ console.log(chalk6.dim("\u2500".repeat(45)));
6186
6293
  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");
6294
+ console.log(" \u2022 Preview slides in browser");
6295
+ console.log(" \u2022 Take screenshots for AI review");
6296
+ console.log(" \u2022 Export to PDF/HTML/PPTX");
6190
6297
  console.log("");
6191
- console.log(chalk6.dim("Install with:"));
6192
- console.log(` ${chalk6.cyan(installCmd)}`);
6298
+ console.log(chalk6.dim("Marp CLI is not currently installed."));
6299
+ console.log(chalk6.dim("\u2500".repeat(45)));
6300
+ console.log("");
6301
+ const packageJsonPath = join16(targetDir, "package.json");
6302
+ const hasPackageJson = existsSync2(packageJsonPath);
6303
+ if (!hasPackageJson) {
6304
+ console.log(chalk6.dim("No package.json found. You can install Marp CLI globally:"));
6305
+ console.log(` ${chalk6.cyan("npm install -g @marp-team/marp-cli")}`);
6306
+ return false;
6307
+ }
6308
+ const shouldInstall = await promptYesNo("Install Marp CLI now?", true);
6309
+ if (shouldInstall) {
6310
+ const success = installMarpCli(targetDir);
6311
+ return success;
6312
+ } else {
6313
+ console.log("");
6314
+ console.log(chalk6.dim("You can install it later with:"));
6315
+ console.log(` ${chalk6.cyan(installCmd)}`);
6316
+ return false;
6317
+ }
6193
6318
  }
6194
6319
  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 });
6320
+ await mkdir7(join16(targetDir, ".skills", "slide-assistant", "references"), { recursive: true });
6321
+ await mkdir7(join16(targetDir, ".skills", "slide-assistant", "scripts"), { recursive: true });
6322
+ await mkdir7(join16(targetDir, ".claude", "commands"), { recursive: true });
6323
+ await mkdir7(join16(targetDir, ".opencode", "agent"), { recursive: true });
6199
6324
  await writeFileIfNotExists(
6200
- join15(targetDir, ".skills", "slide-assistant", "SKILL.md"),
6325
+ join16(targetDir, ".skills", "slide-assistant", "SKILL.md"),
6201
6326
  generateSkillMd()
6202
6327
  );
6203
6328
  await writeFileIfNotExists(
6204
- join15(targetDir, ".skills", "slide-assistant", "references", "templates.md"),
6329
+ join16(targetDir, ".skills", "slide-assistant", "references", "templates.md"),
6205
6330
  generateTemplatesRef()
6206
6331
  );
6207
6332
  await writeFileIfNotExists(
6208
- join15(targetDir, ".skills", "slide-assistant", "references", "workflows.md"),
6333
+ join16(targetDir, ".skills", "slide-assistant", "references", "workflows.md"),
6209
6334
  generateWorkflowsRef()
6210
6335
  );
6211
- await writeFileIfNotExists(join15(targetDir, "CLAUDE.md"), generateClaudeMd());
6336
+ await writeFileIfNotExists(join16(targetDir, "CLAUDE.md"), generateClaudeMd());
6212
6337
  const commandGenerators = {
6213
6338
  "slide-create": generateSlideCreateCommand,
6214
6339
  "slide-validate": generateSlideValidateCommand,
@@ -6218,16 +6343,16 @@ async function generateAiConfig(targetDir) {
6218
6343
  };
6219
6344
  for (const [name, generator] of Object.entries(commandGenerators)) {
6220
6345
  await writeFileIfNotExists(
6221
- join15(targetDir, ".claude", "commands", `${name}.md`),
6346
+ join16(targetDir, ".claude", "commands", `${name}.md`),
6222
6347
  generator()
6223
6348
  );
6224
6349
  }
6225
- await writeFileIfNotExists(join15(targetDir, "AGENTS.md"), generateAgentsMd());
6350
+ await writeFileIfNotExists(join16(targetDir, "AGENTS.md"), generateAgentsMd());
6226
6351
  await writeFileIfNotExists(
6227
- join15(targetDir, ".opencode", "agent", "slide.md"),
6352
+ join16(targetDir, ".opencode", "agent", "slide.md"),
6228
6353
  generateOpenCodeAgent()
6229
6354
  );
6230
- await writeFileIfNotExists(join15(targetDir, ".cursorrules"), generateAgentsMd());
6355
+ await writeFileIfNotExists(join16(targetDir, ".cursorrules"), generateAgentsMd());
6231
6356
  }
6232
6357
  function generateConfigContent() {
6233
6358
  return `# slide-gen configuration
@@ -6325,7 +6450,7 @@ slides:
6325
6450
  // src/cli/commands/watch.ts
6326
6451
  import { Command as Command7 } from "commander";
6327
6452
  import { access as access11 } from "fs/promises";
6328
- import { basename as basename7, dirname as dirname7, join as join16 } from "path";
6453
+ import { basename as basename7, dirname as dirname7, join as join17 } from "path";
6329
6454
  import chalk7 from "chalk";
6330
6455
  import { watch as chokidarWatch2 } from "chokidar";
6331
6456
  var WatchState = class {
@@ -6360,7 +6485,7 @@ var WatchState = class {
6360
6485
  function getDefaultOutputPath2(inputPath) {
6361
6486
  const dir = dirname7(inputPath);
6362
6487
  const base = basename7(inputPath, ".yaml");
6363
- return join16(dir, `${base}.md`);
6488
+ return join17(dir, `${base}.md`);
6364
6489
  }
6365
6490
  function formatTime() {
6366
6491
  const now = /* @__PURE__ */ new Date();
@@ -6504,7 +6629,7 @@ async function executeWatch(inputPath, options) {
6504
6629
  // src/cli/commands/images.ts
6505
6630
  import { Command as Command8 } from "commander";
6506
6631
  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";
6632
+ import { dirname as dirname8, basename as basename8, join as join18 } from "path";
6508
6633
  import chalk8 from "chalk";
6509
6634
  import { stringify as stringifyYaml3 } from "yaml";
6510
6635
  function createImagesCommand() {
@@ -6792,7 +6917,7 @@ async function executeImagesProcess(inputPath, options) {
6792
6917
  }
6793
6918
  async function processDirectory(dirPath, options) {
6794
6919
  if (options.fromMeta) {
6795
- const outputDir = join17(dirPath, options.output);
6920
+ const outputDir = join18(dirPath, options.output);
6796
6921
  const pipeline = new ImageProcessingPipeline(dirPath, { outputDir });
6797
6922
  const result = await pipeline.processDirectory();
6798
6923
  console.log("");
@@ -6829,9 +6954,9 @@ async function processSingleFile(filePath, options) {
6829
6954
  const processor = new ImageProcessor();
6830
6955
  const dir = dirname8(filePath);
6831
6956
  const filename = basename8(filePath);
6832
- const outputDir = join17(dir, options.output);
6957
+ const outputDir = join18(dir, options.output);
6833
6958
  await mkdir8(outputDir, { recursive: true });
6834
- const outputPath = join17(outputDir, filename);
6959
+ const outputPath = join18(outputDir, filename);
6835
6960
  let success = false;
6836
6961
  if (options.crop) {
6837
6962
  const edges = parseCropSpec(options.crop);
@@ -6926,14 +7051,13 @@ function parseBlurSpec(spec) {
6926
7051
  // src/cli/commands/screenshot.ts
6927
7052
  import { Command as Command9 } from "commander";
6928
7053
  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";
7054
+ import { basename as basename9, dirname as dirname9, join as join19 } from "path";
6931
7055
  import chalk9 from "chalk";
6932
7056
  import ora4 from "ora";
6933
7057
  async function filterToSpecificSlide(outputDir, baseName, slideNumber, format) {
6934
7058
  const slideStr = slideNumber.toString().padStart(3, "0");
6935
7059
  const targetFileName = `${baseName}.${slideStr}.${format}`;
6936
- const targetPath = join18(outputDir, targetFileName);
7060
+ const targetPath = join19(outputDir, targetFileName);
6937
7061
  try {
6938
7062
  await access12(targetPath);
6939
7063
  } catch {
@@ -6948,7 +7072,7 @@ async function filterToSpecificSlide(outputDir, baseName, slideNumber, format) {
6948
7072
  );
6949
7073
  for (const file of slideFiles) {
6950
7074
  if (file !== targetFileName) {
6951
- await unlink3(join18(outputDir, file));
7075
+ await unlink3(join19(outputDir, file));
6952
7076
  }
6953
7077
  }
6954
7078
  return {
@@ -6956,17 +7080,12 @@ async function filterToSpecificSlide(outputDir, baseName, slideNumber, format) {
6956
7080
  keptFile: targetFileName
6957
7081
  };
6958
7082
  }
6959
- function checkMarpCliAvailable2() {
6960
- try {
6961
- execSync3("marp --version", { stdio: "ignore", timeout: 5e3 });
6962
- return true;
6963
- } catch {
6964
- return false;
6965
- }
7083
+ function checkMarpCliAvailable2(projectDir) {
7084
+ return isMarpAvailable(projectDir);
6966
7085
  }
6967
7086
  function buildMarpCommandArgs(markdownPath, outputDir, options) {
6968
7087
  const format = options.format || "png";
6969
- const args = ["marp", "--images", format];
7088
+ const args = ["--images", format];
6970
7089
  if (options.width && options.width !== 1280) {
6971
7090
  const scale = options.width / 1280;
6972
7091
  args.push("--image-scale", String(scale));
@@ -7001,9 +7120,9 @@ async function executeScreenshot(inputPath, options) {
7001
7120
  return { success: false, errors };
7002
7121
  }
7003
7122
  spinner?.start("Checking for Marp CLI...");
7004
- if (!checkMarpCliAvailable2()) {
7123
+ if (!checkMarpCliAvailable2(dirname9(inputPath))) {
7005
7124
  spinner?.fail("Marp CLI not found");
7006
- const message = "Marp CLI not found. Install it with: npm install -g @marp-team/marp-cli";
7125
+ const message = "Marp CLI not found. Install it with: npm install -D @marp-team/marp-cli";
7007
7126
  console.error(chalk9.red(`Error: ${message}`));
7008
7127
  errors.push(message);
7009
7128
  process.exitCode = ExitCode.GeneralError;
@@ -7063,10 +7182,13 @@ async function executeScreenshot(inputPath, options) {
7063
7182
  spinner?.start("Taking screenshots...");
7064
7183
  const marpArgs = buildMarpCommandArgs(tempMdPath, outputDir, options);
7065
7184
  if (options.verbose) {
7066
- console.log(`Running: npx ${marpArgs.join(" ")}`);
7185
+ console.log(`Running: marp ${marpArgs.join(" ")}`);
7067
7186
  }
7068
7187
  try {
7069
- execFileSync3("npx", marpArgs, { stdio: options.verbose ? "inherit" : "pipe" });
7188
+ runMarp(marpArgs, {
7189
+ projectDir: dirname9(inputPath),
7190
+ stdio: options.verbose ? "inherit" : "pipe"
7191
+ });
7070
7192
  spinner?.succeed(`Screenshots saved to ${outputDir}`);
7071
7193
  } catch (error) {
7072
7194
  spinner?.fail("Failed to take screenshots");