@stdout-design/cli 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.
Files changed (2) hide show
  1. package/dist/index.mjs +165 -3
  2. package/package.json +2 -2
package/dist/index.mjs CHANGED
@@ -4,10 +4,11 @@ import { Command } from "commander";
4
4
  import { AppError, ErrorCode, importTemplateForBatch, loadConfig, openCache, runBatch, zodToJsonSchemaShape } from "@stdout-design/core";
5
5
  import path from "node:path";
6
6
  import { execSync, spawnSync } from "node:child_process";
7
- import { existsSync } from "node:fs";
7
+ import { existsSync, readFileSync } from "node:fs";
8
8
  import { resolveCommand } from "package-manager-detector/commands";
9
9
  import { detect } from "package-manager-detector/detect";
10
10
  import { cp, mkdir, writeFile } from "node:fs/promises";
11
+ import { pathToFileURL } from "node:url";
11
12
  //#region src/lib/display.ts
12
13
  const formatBytes = (bytes) => {
13
14
  if (bytes < 1024) return `${bytes} B`;
@@ -3221,6 +3222,24 @@ const getScaffoldVersion = () => {
3221
3222
  };
3222
3223
  //#endregion
3223
3224
  //#region src/commands/init/scaffold.ts
3225
+ const getDefaults = () => ({
3226
+ defaultPreset: "instagram-square",
3227
+ presets: [{
3228
+ height: 1080,
3229
+ id: "instagram-square",
3230
+ platform: "instagram",
3231
+ width: 1080
3232
+ }, {
3233
+ height: 1200,
3234
+ id: "x-card",
3235
+ platform: "x",
3236
+ width: 1200
3237
+ }],
3238
+ templates: { "bento-feature": {
3239
+ componentPath: "./templates/bento-feature",
3240
+ description: "Apple-style bento feature card."
3241
+ } }
3242
+ });
3224
3243
  const getConfigTemplate = (version) => `import type { StudioConfig } from "@stdout-design/cli";
3225
3244
 
3226
3245
  const config: StudioConfig = {
@@ -3505,6 +3524,146 @@ const render = async (templateId, propArgs, options) => {
3505
3524
  if (manifest.failed.length > 0) process.exit(1);
3506
3525
  };
3507
3526
  //#endregion
3527
+ //#region src/commands/init/deps.ts
3528
+ const updatePackageJsonDeps = (contents, currentVersion) => {
3529
+ const pkg = JSON.parse(contents);
3530
+ const deps = pkg.dependencies ??= {};
3531
+ const currentRange = `^${currentVersion}`;
3532
+ if (deps["@stdout-design/cli"] === currentRange) return {
3533
+ changed: false,
3534
+ updated: contents
3535
+ };
3536
+ deps["@stdout-design/cli"] = currentRange;
3537
+ return {
3538
+ changed: true,
3539
+ updated: JSON.stringify(pkg, null, 2)
3540
+ };
3541
+ };
3542
+ //#endregion
3543
+ //#region src/commands/init/merge-config.ts
3544
+ const mergePresets = (existing, defaults, deprecatedPresetIds) => {
3545
+ const existingIds = new Set(existing.presets.map((p) => p.id));
3546
+ const addedPresets = [];
3547
+ const presets = [...existing.presets];
3548
+ for (const defaultPreset of defaults.presets) if (!existingIds.has(defaultPreset.id)) {
3549
+ const marked = deprecatedPresetIds.has(defaultPreset.id) ? {
3550
+ ...defaultPreset,
3551
+ deprecated: true
3552
+ } : { ...defaultPreset };
3553
+ presets.push(marked);
3554
+ addedPresets.push(defaultPreset.id);
3555
+ }
3556
+ const presetsWithDeprecation = presets.map((p) => deprecatedPresetIds.has(p.id) && !p.deprecated ? {
3557
+ ...p,
3558
+ deprecated: true
3559
+ } : p);
3560
+ return {
3561
+ addedPresets,
3562
+ deprecatedPresets: [...new Set(presetsWithDeprecation.filter((p) => p.deprecated).map((p) => p.id))],
3563
+ presets: presetsWithDeprecation
3564
+ };
3565
+ };
3566
+ const mergeTemplates = (existing, defaults) => {
3567
+ const addedTemplates = [];
3568
+ const templates = { ...existing.templates };
3569
+ for (const [key, template] of Object.entries(defaults.templates)) if (!(key in templates)) {
3570
+ templates[key] = { ...template };
3571
+ addedTemplates.push(key);
3572
+ }
3573
+ return {
3574
+ addedTemplates,
3575
+ templates
3576
+ };
3577
+ };
3578
+ const resolveDefaultPreset = (presets, existing, defaults) => {
3579
+ const mergedIds = new Set(presets.map((p) => p.id));
3580
+ const current = existing.defaultPreset;
3581
+ if (current && mergedIds.has(current)) return current;
3582
+ return defaults.defaultPreset ?? defaults.presets[0]?.id;
3583
+ };
3584
+ const mergeConfig = (existing, defaults, currentVersion, deprecatedPresetIds) => {
3585
+ const oldVersion = existing.scaffoldVersion ?? null;
3586
+ const { presets, addedPresets, deprecatedPresets } = mergePresets(existing, defaults, deprecatedPresetIds);
3587
+ const { templates, addedTemplates } = mergeTemplates(existing, defaults);
3588
+ return {
3589
+ config: {
3590
+ ...existing,
3591
+ defaultPreset: resolveDefaultPreset(presets, existing, defaults),
3592
+ presets,
3593
+ scaffoldVersion: currentVersion,
3594
+ templates
3595
+ },
3596
+ summary: {
3597
+ addedPresets,
3598
+ addedTemplates,
3599
+ deprecatedPresets,
3600
+ newVersion: currentVersion,
3601
+ oldVersion
3602
+ }
3603
+ };
3604
+ };
3605
+ //#endregion
3606
+ //#region src/commands/update.ts
3607
+ const DEPRECATED_PRESET_IDS = /* @__PURE__ */ new Set();
3608
+ const serializeConfig = (config) => `import type { StudioConfig } from "@stdout-design/cli";
3609
+
3610
+ const config: StudioConfig = ${JSON.stringify(config, null, 2)};
3611
+
3612
+ export default config;
3613
+ `;
3614
+ const update = async (projectDir, options) => {
3615
+ const cwd = process.cwd();
3616
+ const dir = path.resolve(cwd, projectDir ?? ".");
3617
+ const configPath = path.resolve(dir, "studio.config.ts");
3618
+ if (!existsSync(configPath)) throw new Error("No studio project found. Run `studio init` first.");
3619
+ const existingModule = await import(pathToFileURL(configPath).href);
3620
+ const existing = existingModule.default ?? existingModule;
3621
+ const existingConfig = {
3622
+ defaultPreset: existing.defaultPreset,
3623
+ outDir: existing.outDir,
3624
+ presets: existing.presets ?? [],
3625
+ scaffoldVersion: existing.scaffoldVersion,
3626
+ templates: existing.templates ?? {}
3627
+ };
3628
+ const defaults = getDefaults();
3629
+ const currentVersion = getScaffoldVersion();
3630
+ const { config: merged, summary } = mergeConfig(existingConfig, defaults, currentVersion, DEPRECATED_PRESET_IDS);
3631
+ const { intro, outro, confirm } = await import("@clack/prompts");
3632
+ intro("studio update");
3633
+ if (!(summary.addedPresets.length > 0 || summary.deprecatedPresets.length > 0 || summary.addedTemplates.length > 0 || summary.oldVersion !== summary.newVersion)) {
3634
+ console.log("Project is already up to date.");
3635
+ outro("Done");
3636
+ return;
3637
+ }
3638
+ console.log("");
3639
+ if (summary.oldVersion !== summary.newVersion) console.log(` scaffoldVersion ${summary.oldVersion ?? "(none)"} -> ${summary.newVersion}`);
3640
+ for (const id of summary.addedPresets) console.log(` presets +${id}`);
3641
+ for (const id of summary.deprecatedPresets) console.log(` presets ! ${id} (deprecated)`);
3642
+ for (const id of summary.addedTemplates) console.log(` templates +${id}`);
3643
+ console.log(" assets tsconfig.json, .gitignore, types.d.ts (overwrite)");
3644
+ console.log(` deps @stdout-design/cli ^x -> ^${currentVersion}`);
3645
+ console.log("");
3646
+ if (!options?.yes) {
3647
+ if (!await confirm({
3648
+ initialValue: true,
3649
+ message: "Apply these changes?"
3650
+ })) {
3651
+ console.log("Cancelled.");
3652
+ outro("Done");
3653
+ return;
3654
+ }
3655
+ }
3656
+ await writeFile(configPath, serializeConfig(merged));
3657
+ await copyStaticAssets(dir);
3658
+ const pkgPath = path.resolve(dir, "package.json");
3659
+ if (existsSync(pkgPath)) {
3660
+ const { updated, changed } = updatePackageJsonDeps(readFileSync(pkgPath, "utf-8"), currentVersion);
3661
+ if (changed) await writeFile(pkgPath, updated);
3662
+ }
3663
+ console.log("");
3664
+ outro("Done");
3665
+ };
3666
+ //#endregion
3508
3667
  //#region src/lib/runner.ts
3509
3668
  const handlers = {
3510
3669
  cache: cacheStats,
@@ -3513,7 +3672,8 @@ const handlers = {
3513
3672
  dev,
3514
3673
  init,
3515
3674
  lint,
3516
- render
3675
+ render,
3676
+ update
3517
3677
  };
3518
3678
  const run = (moduleName, handlerName) => async (...args) => {
3519
3679
  try {
@@ -3527,8 +3687,9 @@ const run = (moduleName, handlerName) => async (...args) => {
3527
3687
  };
3528
3688
  //#endregion
3529
3689
  //#region src/index.ts
3690
+ const pkg = createRequire(import.meta.url)("../package.json");
3530
3691
  const program = new Command().allowExcessArguments(true);
3531
- program.name("studio").description("Social media design tool — render, preview, batch").version("0.0.0");
3692
+ program.name("studio").description("Social media design tool — render, preview, batch").version(pkg.version, "-v, -V, --version");
3532
3693
  program.command("dev").description("Start the studio dev server with live preview").argument("[rootDir]", "Project root directory (default: cwd)").option("-p, --port <number>", "Port to run on", "3000").option("--open", "Open browser on start").action(run("dev"));
3533
3694
  program.command("render").description("Render a template — single or batch with --data").argument("<template>", "Template ID from studio.config.ts").argument("[props...]", "Props as key=value pairs (e.g. title=\"Hello\")").option("--data <path>", "CSV or JSON data file for batch rendering").option("--preset <ids>", "Comma-separated preset IDs").option("--locale <locales>", "Comma-separated locale codes").option("--out-dir <path>", "Output directory").option("--concurrency <n>", "Max concurrent renders in batch mode", "4").option("--fail-fast", "Stop batch on first error").option("--json", "Output results as JSON").action(run("render"));
3534
3695
  const cacheCmd = program.command("cache").description("Manage the render cache");
@@ -3536,6 +3697,7 @@ cacheCmd.command("stats").description("Show cache statistics").option("--json",
3536
3697
  cacheCmd.command("clean").description("Clear the render cache").option("--json", "Output as JSON").argument("[rootDir]", "Project root directory (default: cwd)").action(run("cache", "cacheClean"));
3537
3698
  program.command("lint").description("Check templates for compatibility (coming soon)").argument("[rootDir]", "Project root directory (default: cwd)").action(run("lint"));
3538
3699
  program.command("init").description("Scaffold a new studio project").argument("[projectDir]", "Project directory (default: cwd)").option("-y, --yes", "Skip prompts, use defaults").action(run("init"));
3700
+ program.command("update").description("Update an existing studio project to the latest CLI version").argument("[projectDir]", "Project directory (default: cwd)").option("-y, --yes", "Skip confirmation prompts").action(run("update"));
3539
3701
  program.parse();
3540
3702
  //#endregion
3541
3703
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stdout-design/cli",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "stdout-design CLI — shallow front door to @stdout-design/core and @stdout-design/dev-server",
5
5
  "keywords": [
6
6
  "cli",
@@ -62,7 +62,7 @@
62
62
  "package-manager-detector": "^1.8.0"
63
63
  },
64
64
  "devDependencies": {
65
- "@stdout-design/config": "0.0.0",
65
+ "@stdout-design/config": "workspace:*",
66
66
  "tsdown": "^0.22.5",
67
67
  "typescript": "^7.0.2"
68
68
  },