@aspects-ai/workspace-cli 0.1.7 → 0.1.10

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 (3) hide show
  1. package/README.md +41 -0
  2. package/dist/index.js +118 -15
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -98,6 +98,47 @@ This command will:
98
98
  4. Update `workspace.config.json` with the new version and commit hash
99
99
  5. Update dependencies in `package.json` if they changed
100
100
 
101
+ ### `create-remotion-entry`
102
+
103
+ Generate a `remotion-entry.tsx` file for server-side rendering of Remotion compositions.
104
+
105
+ ```bash
106
+ workspace-cli create-remotion-entry
107
+ ```
108
+
109
+ Options:
110
+ - `-o, --output <path>` - Output path for remotion-entry.tsx (default: `remotion-entry.tsx`)
111
+ - `-f, --frames-dir <path>` - Path to frames directory (default: `frames`)
112
+
113
+ This command will:
114
+ 1. Scan the frames directory for all frame subdirectories
115
+ 2. Validate that each frame has a `main.tsx` file
116
+ 3. Generate a `remotion-entry.tsx` file with all frames imported and registered
117
+ 4. Display the list of registered frames
118
+
119
+ Example output:
120
+ ```
121
+ [INFO] Scanning frames in: frames
122
+ [SUCCESS] Created remotion entry file: /path/to/remotion-entry.tsx
123
+
124
+ Registered 3 frame(s):
125
+ • example
126
+ • healthee
127
+ • peregrine
128
+
129
+ Next steps:
130
+ Render a frame: ANIMATION_SSR_MODE=true npx remotion render remotion-entry.tsx <frame-id> output.mp4
131
+ ```
132
+
133
+ The generated file can be used with Remotion CLI for server-side rendering:
134
+ ```bash
135
+ # Render a specific frame
136
+ ANIMATION_SSR_MODE=true npx remotion render remotion-entry.tsx example output.mp4
137
+
138
+ # List available compositions
139
+ ANIMATION_SSR_MODE=true npx remotion compositions remotion-entry.tsx
140
+ ```
141
+
101
142
  ## Usage Examples
102
143
 
103
144
  ### Basic Workflow
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { Command as Command7 } from "commander";
4
+ import { Command as Command8 } from "commander";
5
5
 
6
6
  // src/commands/init.ts
7
7
  import { Command } from "commander";
@@ -436,6 +436,9 @@ import chalk5 from "chalk";
436
436
  import { Command as Command5 } from "commander";
437
437
  import fs5 from "fs-extra";
438
438
  import path5 from "path";
439
+ function generateId() {
440
+ return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString();
441
+ }
439
442
  function parseManifestOption(manifestStr) {
440
443
  try {
441
444
  return JSON.parse(manifestStr);
@@ -446,7 +449,8 @@ function parseManifestOption(manifestStr) {
446
449
  function validateAndFixManifest(manifest, toolName, frameName) {
447
450
  const now = (/* @__PURE__ */ new Date()).toISOString();
448
451
  const validatedManifest = {
449
- id: manifest.id || frameName,
452
+ id: frameName,
453
+ // Always match the directory name
450
454
  projectId: manifest.projectId || "default-project",
451
455
  title: manifest.title || frameName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" "),
452
456
  description: manifest.description || `Frame for ${toolName}`,
@@ -459,17 +463,20 @@ function validateAndFixManifest(manifest, toolName, frameName) {
459
463
  }
460
464
  return validatedManifest;
461
465
  }
462
- async function getNextFrameName(framesDir, baseName) {
463
- if (!await fs5.pathExists(path5.join(framesDir, baseName))) {
464
- return baseName;
466
+ async function getNextFrameName(framesDir, customName) {
467
+ let frameName;
468
+ if (customName) {
469
+ const truncatedName = customName.slice(0, 20);
470
+ const uniqueId = generateId();
471
+ frameName = `${truncatedName}-${uniqueId}`;
472
+ } else {
473
+ frameName = generateId();
465
474
  }
466
- let counter = 1;
467
- let nextName = `${baseName}-${counter}`;
468
- while (await fs5.pathExists(path5.join(framesDir, nextName))) {
469
- counter++;
470
- nextName = `${baseName}-${counter}`;
475
+ while (await fs5.pathExists(path5.join(framesDir, frameName))) {
476
+ const uniqueId = generateId();
477
+ frameName = customName ? `${customName.slice(0, 20)}-${uniqueId}` : uniqueId;
471
478
  }
472
- return nextName;
479
+ return frameName;
473
480
  }
474
481
  async function fetchExampleFrame(toolName, targetPath) {
475
482
  const library = await getLibrary(toolName);
@@ -490,8 +497,8 @@ function createCreateFrameCommand() {
490
497
  const workspaceRoot = await ensureWorkspaceRoot();
491
498
  const framesDir = path5.join(workspaceRoot, "frames");
492
499
  await fs5.ensureDir(framesDir);
493
- const baseName = options.name || "new-frame";
494
- const frameName = await getNextFrameName(framesDir, baseName);
500
+ const customName = options.name && options.name !== "new-frame" ? options.name : void 0;
501
+ const frameName = await getNextFrameName(framesDir, customName);
495
502
  const frameDir = path5.join(framesDir, frameName);
496
503
  logger.info(`Creating frame: ${chalk5.cyan(frameName)} for ${chalk5.cyan(toolName)}`);
497
504
  await fetchExampleFrame(toolName, frameDir);
@@ -588,10 +595,105 @@ async function fetchFileFromGit(options) {
588
595
  }
589
596
  }
590
597
 
598
+ // src/commands/create-remotion-entry.ts
599
+ import chalk7 from "chalk";
600
+ import { Command as Command7 } from "commander";
601
+ import fs7 from "fs-extra";
602
+ import path7 from "path";
603
+ async function createRemotionEntry(framesDir, outputPath) {
604
+ if (!await fs7.pathExists(framesDir)) {
605
+ throw new Error(`Frames directory not found: ${framesDir}`);
606
+ }
607
+ const entries = await fs7.readdir(framesDir, { withFileTypes: true });
608
+ const frameDirs = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);
609
+ if (frameDirs.length === 0) {
610
+ throw new Error(`No frame directories found in ${framesDir}`);
611
+ }
612
+ const validFrames = [];
613
+ for (const frameDir of frameDirs) {
614
+ const mainPath = path7.join(framesDir, frameDir, "main.tsx");
615
+ if (await fs7.pathExists(mainPath)) {
616
+ validFrames.push(frameDir);
617
+ } else {
618
+ logger.warn(`Skipping ${frameDir}: main.tsx not found`);
619
+ }
620
+ }
621
+ if (validFrames.length === 0) {
622
+ throw new Error("No valid frames found (frames must contain main.tsx)");
623
+ }
624
+ const imports = validFrames.map((frameDir, index) => {
625
+ const varName = `Frame${index}`;
626
+ const defName = `frame${index}Def`;
627
+ return {
628
+ frameDir,
629
+ varName,
630
+ defName,
631
+ statement: `import ${varName}, { compositionDefinition as ${defName} } from './frames/${frameDir}/main';`
632
+ };
633
+ });
634
+ const framesObject = imports.map(({ frameDir, varName, defName }) => {
635
+ return ` '${frameDir}': { component: ${varName}, compositionDefinition: ${defName} },`;
636
+ }).join("\n");
637
+ const content = `/**
638
+ * Auto-generated Remotion SSR Entry Point
639
+ *
640
+ * Generated by: @aspects-ai/workspace-cli create-remotion-entry
641
+ * DO NOT EDIT THIS FILE MANUALLY - it will be overwritten
642
+ *
643
+ * This file serves as the entry point for server-side rendering with Remotion.
644
+ * It automatically registers all frames in the ./frames directory.
645
+ *
646
+ * Usage:
647
+ * ANIMATION_SSR_MODE=true npx remotion render remotion-entry.tsx <frame-id> output.mp4
648
+ *
649
+ * To regenerate this file:
650
+ * npx @aspects-ai/workspace-cli create-remotion-entry
651
+ */
652
+
653
+ import { registerRoot } from 'remotion';
654
+ import { createRemotionRoot } from '@aspects-ai/noodle-animate-core/remotion';
655
+
656
+ // Frame imports
657
+ ${imports.map((i) => i.statement).join("\n")}
658
+
659
+ // Register all frames with Remotion
660
+ const Root = createRemotionRoot({
661
+ ${framesObject}
662
+ });
663
+
664
+ registerRoot(Root);
665
+ `;
666
+ await fs7.writeFile(outputPath, content, "utf-8");
667
+ logger.success(`Created remotion entry file: ${chalk7.green(outputPath)}`);
668
+ logger.log("");
669
+ logger.log(chalk7.bold(`Registered ${validFrames.length} frame(s):`));
670
+ validFrames.forEach((frame) => {
671
+ logger.log(` ${chalk7.cyan("\u2022")} ${frame}`);
672
+ });
673
+ logger.log("");
674
+ logger.log(chalk7.bold("Next steps:"));
675
+ logger.log(` ${chalk7.gray("Render a frame:")} ANIMATION_SSR_MODE=true npx remotion render remotion-entry.tsx <frame-id> output.mp4`);
676
+ logger.log("");
677
+ }
678
+ function createCreateRemotionEntryCommand() {
679
+ return new Command7("create-remotion-entry").description("Create a remotion-entry.tsx file for server-side rendering").option("-o, --output <path>", "Output path for remotion-entry.tsx", "remotion-entry.tsx").option("-f, --frames-dir <path>", "Path to frames directory", "frames").action(async (options) => {
680
+ try {
681
+ const workspaceRoot = await ensureWorkspaceRoot();
682
+ const framesDir = path7.resolve(workspaceRoot, options.framesDir || "frames");
683
+ const outputPath = path7.resolve(workspaceRoot, options.output || "remotion-entry.tsx");
684
+ logger.info(`Scanning frames in: ${chalk7.cyan(path7.relative(workspaceRoot, framesDir))}`);
685
+ await createRemotionEntry(framesDir, outputPath);
686
+ } catch (error) {
687
+ logger.error(error.message);
688
+ process.exit(1);
689
+ }
690
+ });
691
+ }
692
+
591
693
  // package.json
592
694
  var package_default = {
593
695
  name: "@aspects-ai/workspace-cli",
594
- version: "0.1.6",
696
+ version: "0.1.9",
595
697
  private: false,
596
698
  description: "Lightweight CLI for installing libraries into workspaces",
597
699
  type: "module",
@@ -627,7 +729,7 @@ var package_default = {
627
729
  };
628
730
 
629
731
  // src/index.ts
630
- var program = new Command7();
732
+ var program = new Command8();
631
733
  program.name("workspace-cli").description("Lightweight CLI for installing libraries into workspaces").version(package_default.version);
632
734
  program.addCommand(createInitCommand());
633
735
  program.addCommand(createListCommand());
@@ -635,4 +737,5 @@ program.addCommand(createAddCommand());
635
737
  program.addCommand(createUpdateCommand());
636
738
  program.addCommand(createCreateFrameCommand());
637
739
  program.addCommand(createUpdateTemplateCommand());
740
+ program.addCommand(createCreateRemotionEntryCommand());
638
741
  program.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aspects-ai/workspace-cli",
3
- "version": "0.1.7",
3
+ "version": "0.1.10",
4
4
  "private": false,
5
5
  "description": "Lightweight CLI for installing libraries into workspaces",
6
6
  "type": "module",
@@ -33,4 +33,4 @@
33
33
  "engines": {
34
34
  "node": ">=18.0.0"
35
35
  }
36
- }
36
+ }