@aspects-ai/workspace-cli 0.1.13 → 0.1.15
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/README.md +9 -10
- package/dist/index.js +344 -332
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -105,34 +105,33 @@ Generate a `remotion-entry.tsx` file for server-side rendering of Remotion compo
|
|
|
105
105
|
```bash
|
|
106
106
|
workspace-cli create-remotion-entry
|
|
107
107
|
```
|
|
108
|
-
|
|
109
108
|
Options:
|
|
110
109
|
- `-o, --output <path>` - Output path for remotion-entry.tsx (default: `remotion-entry.tsx`)
|
|
111
|
-
- `-f, --
|
|
110
|
+
- `-f, --compositions-dir <path>` - Path to compositions directory (default: `compositions`)
|
|
112
111
|
|
|
113
112
|
This command will:
|
|
114
|
-
1. Scan the
|
|
115
|
-
2. Validate that each
|
|
116
|
-
3. Generate a `remotion-entry.tsx` file with all
|
|
117
|
-
4. Display the list of registered
|
|
113
|
+
1. Scan the compositions directory for all composition subdirectories
|
|
114
|
+
2. Validate that each composition has a `main.tsx` file
|
|
115
|
+
3. Generate a `remotion-entry.tsx` file with all compositions imported and registered
|
|
116
|
+
4. Display the list of registered compositions
|
|
118
117
|
|
|
119
118
|
Example output:
|
|
120
119
|
```
|
|
121
|
-
[INFO] Scanning
|
|
120
|
+
[INFO] Scanning compositions in: compositions
|
|
122
121
|
[SUCCESS] Created remotion entry file: /path/to/remotion-entry.tsx
|
|
123
122
|
|
|
124
|
-
Registered 3
|
|
123
|
+
Registered 3 compositions(s):
|
|
125
124
|
• example
|
|
126
125
|
• healthee
|
|
127
126
|
• peregrine
|
|
128
127
|
|
|
129
128
|
Next steps:
|
|
130
|
-
Render a
|
|
129
|
+
Render a composition: ANIMATION_SSR_MODE=true npx remotion render remotion-entry.tsx <composition-id> output.mp4
|
|
131
130
|
```
|
|
132
131
|
|
|
133
132
|
The generated file can be used with Remotion CLI for server-side rendering:
|
|
134
133
|
```bash
|
|
135
|
-
# Render a specific
|
|
134
|
+
# Render a specific composition
|
|
136
135
|
ANIMATION_SSR_MODE=true npx remotion render remotion-entry.tsx example output.mp4
|
|
137
136
|
|
|
138
137
|
# List available compositions
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,45 @@
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { Command as Command8 } from "commander";
|
|
5
5
|
|
|
6
|
-
//
|
|
6
|
+
// package.json
|
|
7
|
+
var package_default = {
|
|
8
|
+
name: "@aspects-ai/workspace-cli",
|
|
9
|
+
version: "0.1.15",
|
|
10
|
+
private: false,
|
|
11
|
+
description: "Lightweight CLI for installing libraries into workspaces",
|
|
12
|
+
type: "module",
|
|
13
|
+
bin: {
|
|
14
|
+
"workspace-cli": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
scripts: {
|
|
17
|
+
build: "tsup src/index.ts --format esm --dts --clean && npm run copy:registry",
|
|
18
|
+
"copy:registry": "mkdir -p dist/registry && cp src/registry/libraries.json dist/registry/",
|
|
19
|
+
dev: "tsup src/index.ts --format esm --watch",
|
|
20
|
+
typecheck: "tsc --noEmit"
|
|
21
|
+
},
|
|
22
|
+
files: [
|
|
23
|
+
"dist",
|
|
24
|
+
"src/registry"
|
|
25
|
+
],
|
|
26
|
+
dependencies: {
|
|
27
|
+
chalk: "^5.3.0",
|
|
28
|
+
commander: "^12.0.0",
|
|
29
|
+
execa: "^8.0.0",
|
|
30
|
+
"fs-extra": "^11.2.0",
|
|
31
|
+
zod: "^3.22.0"
|
|
32
|
+
},
|
|
33
|
+
devDependencies: {
|
|
34
|
+
"@types/fs-extra": "^11.0.0",
|
|
35
|
+
"@types/node": "^20",
|
|
36
|
+
tsup: "^8.0.0",
|
|
37
|
+
typescript: "^5"
|
|
38
|
+
},
|
|
39
|
+
engines: {
|
|
40
|
+
node: ">=18.0.0"
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// src/commands/add.ts
|
|
7
45
|
import { Command } from "commander";
|
|
8
46
|
|
|
9
47
|
// src/utils/fs.ts
|
|
@@ -114,128 +152,6 @@ function getConfigPath(workspaceRoot) {
|
|
|
114
152
|
return path2.join(workspaceRoot, CONFIG_FILE_NAME);
|
|
115
153
|
}
|
|
116
154
|
|
|
117
|
-
// src/utils/logger.ts
|
|
118
|
-
import chalk from "chalk";
|
|
119
|
-
var logger = {
|
|
120
|
-
info(message) {
|
|
121
|
-
console.log(chalk.blue("[INFO]"), message);
|
|
122
|
-
},
|
|
123
|
-
success(message) {
|
|
124
|
-
console.log(chalk.green("[SUCCESS]"), message);
|
|
125
|
-
},
|
|
126
|
-
error(message) {
|
|
127
|
-
console.error(chalk.red("[ERROR]"), message);
|
|
128
|
-
},
|
|
129
|
-
warn(message) {
|
|
130
|
-
console.warn(chalk.yellow("[WARN]"), message);
|
|
131
|
-
},
|
|
132
|
-
log(message) {
|
|
133
|
-
console.log(message);
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
// src/commands/init.ts
|
|
138
|
-
function createInitCommand() {
|
|
139
|
-
return new Command("init").description("Initialize workspace configuration").action(async () => {
|
|
140
|
-
try {
|
|
141
|
-
const workspaceRoot = await ensureWorkspaceRoot();
|
|
142
|
-
const existing = await loadWorkspaceConfig(workspaceRoot);
|
|
143
|
-
if (existing) {
|
|
144
|
-
logger.warn("workspace.config.json already exists");
|
|
145
|
-
logger.info(`Config file: ${getConfigPath(workspaceRoot)}`);
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
await createDefaultConfig(workspaceRoot);
|
|
149
|
-
logger.success("Created workspace.config.json");
|
|
150
|
-
logger.log("\nNext steps:");
|
|
151
|
-
logger.log(" workspace-cli list # View available libraries");
|
|
152
|
-
logger.log(" workspace-cli add <library> # Install a library");
|
|
153
|
-
} catch (error) {
|
|
154
|
-
logger.error(error.message);
|
|
155
|
-
process.exit(1);
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// src/commands/list.ts
|
|
161
|
-
import { Command as Command2 } from "commander";
|
|
162
|
-
|
|
163
|
-
// src/core/registry.ts
|
|
164
|
-
import { z as z2 } from "zod";
|
|
165
|
-
var RepositorySchema = z2.object({
|
|
166
|
-
url: z2.string(),
|
|
167
|
-
directory: z2.string(),
|
|
168
|
-
branch: z2.string(),
|
|
169
|
-
packageJsonPath: z2.string().optional()
|
|
170
|
-
// Path to package.json in repo (e.g., "noodle-animate-core/package.json")
|
|
171
|
-
});
|
|
172
|
-
var LibrarySchema = z2.object({
|
|
173
|
-
name: z2.string(),
|
|
174
|
-
description: z2.string(),
|
|
175
|
-
version: z2.string().optional(),
|
|
176
|
-
// Optional - if not provided, will be read from package.json in repo
|
|
177
|
-
repository: RepositorySchema,
|
|
178
|
-
installPath: z2.string(),
|
|
179
|
-
dependencies: z2.record(z2.string()).optional()
|
|
180
|
-
// Optional - if not provided, will be read from package.json in repo
|
|
181
|
-
});
|
|
182
|
-
var RegistrySchema = z2.object({
|
|
183
|
-
libraries: z2.record(LibrarySchema)
|
|
184
|
-
});
|
|
185
|
-
var cachedRegistry = null;
|
|
186
|
-
async function loadRegistry() {
|
|
187
|
-
if (cachedRegistry) {
|
|
188
|
-
return cachedRegistry;
|
|
189
|
-
}
|
|
190
|
-
const registryPath = getRegistryPath();
|
|
191
|
-
const data = await readJsonFile(registryPath);
|
|
192
|
-
cachedRegistry = RegistrySchema.parse(data);
|
|
193
|
-
return cachedRegistry;
|
|
194
|
-
}
|
|
195
|
-
async function getLibrary(libraryName) {
|
|
196
|
-
const registry = await loadRegistry();
|
|
197
|
-
const library = registry.libraries[libraryName];
|
|
198
|
-
if (!library) {
|
|
199
|
-
throw new Error(
|
|
200
|
-
`Library '${libraryName}' not found in registry.
|
|
201
|
-
Available libraries: ${Object.keys(registry.libraries).join(", ")}`
|
|
202
|
-
);
|
|
203
|
-
}
|
|
204
|
-
return library;
|
|
205
|
-
}
|
|
206
|
-
async function listLibraries() {
|
|
207
|
-
const registry = await loadRegistry();
|
|
208
|
-
return Object.entries(registry.libraries).map(([name, library]) => ({
|
|
209
|
-
name,
|
|
210
|
-
library
|
|
211
|
-
}));
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// src/commands/list.ts
|
|
215
|
-
import chalk2 from "chalk";
|
|
216
|
-
function createListCommand() {
|
|
217
|
-
return new Command2("list").description("List available libraries").action(async () => {
|
|
218
|
-
try {
|
|
219
|
-
const libraries = await listLibraries();
|
|
220
|
-
logger.log(chalk2.bold("\nAvailable libraries:\n"));
|
|
221
|
-
for (const { name, library } of libraries) {
|
|
222
|
-
const versionStr = library.version ? ` @${library.version}` : " @latest";
|
|
223
|
-
logger.log(chalk2.cyan(` ${name}`) + chalk2.gray(versionStr));
|
|
224
|
-
logger.log(` ${library.description}`);
|
|
225
|
-
logger.log("");
|
|
226
|
-
}
|
|
227
|
-
logger.log(`Total: ${libraries.length} ${libraries.length === 1 ? "library" : "libraries"}
|
|
228
|
-
`);
|
|
229
|
-
} catch (error) {
|
|
230
|
-
logger.error(error.message);
|
|
231
|
-
process.exit(1);
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// src/commands/add.ts
|
|
237
|
-
import { Command as Command3 } from "commander";
|
|
238
|
-
|
|
239
155
|
// src/core/installer.ts
|
|
240
156
|
import path4 from "path";
|
|
241
157
|
import fs4 from "fs-extra";
|
|
@@ -321,6 +237,77 @@ function getToken() {
|
|
|
321
237
|
return token;
|
|
322
238
|
}
|
|
323
239
|
|
|
240
|
+
// src/core/registry.ts
|
|
241
|
+
import { z as z2 } from "zod";
|
|
242
|
+
var RepositorySchema = z2.object({
|
|
243
|
+
url: z2.string(),
|
|
244
|
+
directory: z2.string(),
|
|
245
|
+
branch: z2.string(),
|
|
246
|
+
packageJsonPath: z2.string().optional()
|
|
247
|
+
// Path to package.json in repo (e.g., "noodle-animate-core/package.json")
|
|
248
|
+
});
|
|
249
|
+
var LibrarySchema = z2.object({
|
|
250
|
+
name: z2.string(),
|
|
251
|
+
description: z2.string(),
|
|
252
|
+
version: z2.string().optional(),
|
|
253
|
+
// Optional - if not provided, will be read from package.json in repo
|
|
254
|
+
repository: RepositorySchema,
|
|
255
|
+
installPath: z2.string(),
|
|
256
|
+
dependencies: z2.record(z2.string()).optional()
|
|
257
|
+
// Optional - if not provided, will be read from package.json in repo
|
|
258
|
+
});
|
|
259
|
+
var RegistrySchema = z2.object({
|
|
260
|
+
libraries: z2.record(LibrarySchema)
|
|
261
|
+
});
|
|
262
|
+
var cachedRegistry = null;
|
|
263
|
+
async function loadRegistry() {
|
|
264
|
+
if (cachedRegistry) {
|
|
265
|
+
return cachedRegistry;
|
|
266
|
+
}
|
|
267
|
+
const registryPath = getRegistryPath();
|
|
268
|
+
const data = await readJsonFile(registryPath);
|
|
269
|
+
cachedRegistry = RegistrySchema.parse(data);
|
|
270
|
+
return cachedRegistry;
|
|
271
|
+
}
|
|
272
|
+
async function getLibrary(libraryName) {
|
|
273
|
+
const registry = await loadRegistry();
|
|
274
|
+
const library = registry.libraries[libraryName];
|
|
275
|
+
if (!library) {
|
|
276
|
+
throw new Error(
|
|
277
|
+
`Library '${libraryName}' not found in registry.
|
|
278
|
+
Available libraries: ${Object.keys(registry.libraries).join(", ")}`
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
return library;
|
|
282
|
+
}
|
|
283
|
+
async function listLibraries() {
|
|
284
|
+
const registry = await loadRegistry();
|
|
285
|
+
return Object.entries(registry.libraries).map(([name, library]) => ({
|
|
286
|
+
name,
|
|
287
|
+
library
|
|
288
|
+
}));
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// src/utils/logger.ts
|
|
292
|
+
import chalk from "chalk";
|
|
293
|
+
var logger = {
|
|
294
|
+
info(message) {
|
|
295
|
+
console.log(chalk.blue("[INFO]"), message);
|
|
296
|
+
},
|
|
297
|
+
success(message) {
|
|
298
|
+
console.log(chalk.green("[SUCCESS]"), message);
|
|
299
|
+
},
|
|
300
|
+
error(message) {
|
|
301
|
+
console.error(chalk.red("[ERROR]"), message);
|
|
302
|
+
},
|
|
303
|
+
warn(message) {
|
|
304
|
+
console.warn(chalk.yellow("[WARN]"), message);
|
|
305
|
+
},
|
|
306
|
+
log(message) {
|
|
307
|
+
console.log(message);
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
|
|
324
311
|
// src/core/installer.ts
|
|
325
312
|
async function installLibrary(workspaceRoot, libraryName, options = {}) {
|
|
326
313
|
if (!options.force && await isLibraryInstalled(workspaceRoot, libraryName)) {
|
|
@@ -382,16 +369,16 @@ async function updatePackageDependencies(workspaceRoot, dependencies) {
|
|
|
382
369
|
}
|
|
383
370
|
|
|
384
371
|
// src/commands/add.ts
|
|
385
|
-
import
|
|
372
|
+
import chalk2 from "chalk";
|
|
386
373
|
function createAddCommand() {
|
|
387
|
-
return new
|
|
374
|
+
return new Command("add").description("Add a library to the workspace").argument("<library>", "Name of the library to add").option("-f, --force", "Force reinstall if already installed").action(async (libraryName, options) => {
|
|
388
375
|
try {
|
|
389
376
|
const workspaceRoot = await ensureWorkspaceRoot();
|
|
390
377
|
await getOrCreateConfig(workspaceRoot);
|
|
391
378
|
await installLibrary(workspaceRoot, libraryName, { force: options.force });
|
|
392
|
-
logger.log("\n" +
|
|
393
|
-
logger.log(` ${
|
|
394
|
-
logger.log(` ${
|
|
379
|
+
logger.log("\n" + chalk2.bold("Next steps:"));
|
|
380
|
+
logger.log(` ${chalk2.gray("Import components:")} import { ... } from '@/core/${libraryName.replace("animate-", "")}'`);
|
|
381
|
+
logger.log(` ${chalk2.gray("Install dependencies:")} npm install`);
|
|
395
382
|
logger.log("");
|
|
396
383
|
} catch (error) {
|
|
397
384
|
logger.error(error.message);
|
|
@@ -400,40 +387,9 @@ function createAddCommand() {
|
|
|
400
387
|
});
|
|
401
388
|
}
|
|
402
389
|
|
|
403
|
-
// src/commands/
|
|
404
|
-
import
|
|
405
|
-
import
|
|
406
|
-
function createUpdateCommand() {
|
|
407
|
-
return new Command4("update").description("Update an installed library to the latest version").argument("<library>", "Name of the library to update").action(async (libraryName) => {
|
|
408
|
-
try {
|
|
409
|
-
const workspaceRoot = await ensureWorkspaceRoot();
|
|
410
|
-
await getOrCreateConfig(workspaceRoot);
|
|
411
|
-
if (!await isLibraryInstalled(workspaceRoot, libraryName)) {
|
|
412
|
-
throw new Error(
|
|
413
|
-
`Library '${libraryName}' is not installed.
|
|
414
|
-
Use 'workspace-cli add ${libraryName}' to install it first.`
|
|
415
|
-
);
|
|
416
|
-
}
|
|
417
|
-
const config = await loadWorkspaceConfig(workspaceRoot);
|
|
418
|
-
const currentVersion = config?.libraries[libraryName]?.version || "unknown";
|
|
419
|
-
const currentCommit = config?.libraries[libraryName]?.commit || "unknown";
|
|
420
|
-
logger.info(`Current version: ${currentVersion} (commit: ${currentCommit.substring(0, 7)})`);
|
|
421
|
-
logger.info(`Updating ${libraryName}...`);
|
|
422
|
-
await installLibrary(workspaceRoot, libraryName, { force: true });
|
|
423
|
-
logger.log("\n" + chalk4.bold("Next steps:"));
|
|
424
|
-
logger.log(` ${chalk4.gray("Review changes:")} git diff ./core/${libraryName.replace("animate-", "")}`);
|
|
425
|
-
logger.log(` ${chalk4.gray("Install updated dependencies:")} npm install`);
|
|
426
|
-
logger.log("");
|
|
427
|
-
} catch (error) {
|
|
428
|
-
logger.error(error.message);
|
|
429
|
-
process.exit(1);
|
|
430
|
-
}
|
|
431
|
-
});
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
// src/commands/create-frame.ts
|
|
435
|
-
import chalk5 from "chalk";
|
|
436
|
-
import { Command as Command5 } from "commander";
|
|
390
|
+
// src/commands/create-composition.ts
|
|
391
|
+
import chalk3 from "chalk";
|
|
392
|
+
import { Command as Command2 } from "commander";
|
|
437
393
|
import fs5 from "fs-extra";
|
|
438
394
|
import path5 from "path";
|
|
439
395
|
function generateId() {
|
|
@@ -446,77 +402,77 @@ function parseManifestOption(manifestStr) {
|
|
|
446
402
|
throw new Error(`Invalid manifest JSON: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
447
403
|
}
|
|
448
404
|
}
|
|
449
|
-
function validateAndFixManifest(manifest, toolName,
|
|
405
|
+
function validateAndFixManifest(manifest, toolName, compositionName) {
|
|
450
406
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
451
407
|
const validatedManifest = {
|
|
452
|
-
id:
|
|
408
|
+
id: compositionName,
|
|
453
409
|
// Always match the directory name
|
|
454
410
|
projectId: manifest.projectId || "default-project",
|
|
455
|
-
title: manifest.title ||
|
|
456
|
-
description: manifest.description || `
|
|
411
|
+
title: manifest.title || compositionName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" "),
|
|
412
|
+
description: manifest.description || `Composition for ${toolName}`,
|
|
457
413
|
createdAt: now,
|
|
458
414
|
// Always update createdAt
|
|
459
|
-
|
|
415
|
+
compositionType: manifest.compositionType || "animationComposition",
|
|
460
416
|
width: manifest.width,
|
|
461
417
|
height: manifest.height
|
|
462
418
|
};
|
|
463
419
|
if (toolName === "animate-core") {
|
|
464
|
-
validatedManifest.
|
|
420
|
+
validatedManifest.compositionType = "animationComposition";
|
|
465
421
|
if (!validatedManifest.width) validatedManifest.width = 1920;
|
|
466
422
|
if (!validatedManifest.height) validatedManifest.height = 1080;
|
|
467
423
|
}
|
|
468
424
|
return validatedManifest;
|
|
469
425
|
}
|
|
470
|
-
async function
|
|
471
|
-
let
|
|
426
|
+
async function getNextCompositionName(compositionsDir, customName) {
|
|
427
|
+
let compositionName;
|
|
472
428
|
if (customName) {
|
|
473
429
|
const truncatedName = customName.slice(0, 20);
|
|
474
430
|
const uniqueId = generateId();
|
|
475
|
-
|
|
431
|
+
compositionName = `${truncatedName}-${uniqueId}`;
|
|
476
432
|
} else {
|
|
477
|
-
|
|
433
|
+
compositionName = generateId();
|
|
478
434
|
}
|
|
479
|
-
while (await fs5.pathExists(path5.join(
|
|
435
|
+
while (await fs5.pathExists(path5.join(compositionsDir, compositionName))) {
|
|
480
436
|
const uniqueId = generateId();
|
|
481
|
-
|
|
437
|
+
compositionName = customName ? `${customName.slice(0, 20)}-${uniqueId}` : uniqueId;
|
|
482
438
|
}
|
|
483
|
-
return
|
|
439
|
+
return compositionName;
|
|
484
440
|
}
|
|
485
|
-
async function
|
|
441
|
+
async function fetchExampleComposition(toolName, targetPath) {
|
|
486
442
|
const library = await getLibrary(toolName);
|
|
487
443
|
const token = getToken();
|
|
488
|
-
logger.info(`Fetching example
|
|
489
|
-
const
|
|
444
|
+
logger.info(`Fetching example composition from ${chalk3.cyan(library.repository.url)}`);
|
|
445
|
+
const exampleCompositionDirectory = library.repository.directory.replace("/src", "/starter-composition-123");
|
|
490
446
|
await fetchDirectory({
|
|
491
447
|
repository: library.repository.url,
|
|
492
|
-
directory:
|
|
448
|
+
directory: exampleCompositionDirectory,
|
|
493
449
|
branch: library.repository.branch,
|
|
494
450
|
token,
|
|
495
451
|
targetPath
|
|
496
452
|
});
|
|
497
453
|
}
|
|
498
|
-
function
|
|
499
|
-
return new
|
|
454
|
+
function createCreateCompositionCommand() {
|
|
455
|
+
return new Command2("create-composition").description("Create a new composition for a given tool").argument("<tool>", "Name of the tool (e.g., animate-core)").argument("<manifest>", "Manifest data as JSON string").option("-n, --name <name>", "Name for the new composition", "new-composition").action(async (toolName, manifestStr, options) => {
|
|
500
456
|
try {
|
|
501
457
|
const workspaceRoot = await ensureWorkspaceRoot();
|
|
502
|
-
const
|
|
503
|
-
await fs5.ensureDir(
|
|
504
|
-
const customName = options.name && options.name !== "new-
|
|
505
|
-
const
|
|
506
|
-
const
|
|
507
|
-
logger.info(`Creating
|
|
508
|
-
await
|
|
458
|
+
const compositionsDir = path5.join(workspaceRoot, "compositions");
|
|
459
|
+
await fs5.ensureDir(compositionsDir);
|
|
460
|
+
const customName = options.name && options.name !== "new-composition" ? options.name : void 0;
|
|
461
|
+
const compositionName = await getNextCompositionName(compositionsDir, customName);
|
|
462
|
+
const compositionDir = path5.join(compositionsDir, compositionName);
|
|
463
|
+
logger.info(`Creating composition: ${chalk3.cyan(compositionName)} for ${chalk3.cyan(toolName)}`);
|
|
464
|
+
await fetchExampleComposition(toolName, compositionDir);
|
|
509
465
|
const manifestData = parseManifestOption(manifestStr);
|
|
510
|
-
const validatedManifest = validateAndFixManifest(manifestData, toolName,
|
|
511
|
-
const manifestPath = path5.join(
|
|
466
|
+
const validatedManifest = validateAndFixManifest(manifestData, toolName, compositionName);
|
|
467
|
+
const manifestPath = path5.join(compositionDir, "manifest.json");
|
|
512
468
|
await fs5.writeJson(manifestPath, validatedManifest, { spaces: 4 });
|
|
513
|
-
logger.success(`
|
|
469
|
+
logger.success(`Composition created at: ${chalk3.green(path5.relative(workspaceRoot, compositionDir))}`);
|
|
514
470
|
logger.log("");
|
|
515
|
-
logger.log(
|
|
471
|
+
logger.log(chalk3.bold("Manifest:"));
|
|
516
472
|
logger.log(JSON.stringify(validatedManifest, null, 2));
|
|
517
473
|
logger.log("");
|
|
518
|
-
logger.log(
|
|
519
|
-
logger.log(` ${
|
|
474
|
+
logger.log(chalk3.bold("Next steps:"));
|
|
475
|
+
logger.log(` ${chalk3.gray("Edit composition:")} ${path5.relative(workspaceRoot, path5.join(compositionDir, "main.tsx"))}`);
|
|
520
476
|
logger.log("");
|
|
521
477
|
} catch (error) {
|
|
522
478
|
logger.error(error.message);
|
|
@@ -525,10 +481,170 @@ function createCreateFrameCommand() {
|
|
|
525
481
|
});
|
|
526
482
|
}
|
|
527
483
|
|
|
484
|
+
// src/commands/create-remotion-entry.ts
|
|
485
|
+
import chalk4 from "chalk";
|
|
486
|
+
import { Command as Command3 } from "commander";
|
|
487
|
+
import fs6 from "fs-extra";
|
|
488
|
+
import path6 from "path";
|
|
489
|
+
async function createRemotionEntry(compositionsDir, outputPath, animateCorePath) {
|
|
490
|
+
if (!await fs6.pathExists(compositionsDir)) {
|
|
491
|
+
throw new Error(`Compositions directory not found: ${compositionsDir}`);
|
|
492
|
+
}
|
|
493
|
+
const entries = await fs6.readdir(compositionsDir, { withFileTypes: true });
|
|
494
|
+
const compositionDirs = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
495
|
+
if (compositionDirs.length === 0) {
|
|
496
|
+
throw new Error(`No composition directories found in ${compositionsDir}`);
|
|
497
|
+
}
|
|
498
|
+
const validCompositions = [];
|
|
499
|
+
for (const compositionDir of compositionDirs) {
|
|
500
|
+
const mainPath = path6.join(compositionsDir, compositionDir, "main.tsx");
|
|
501
|
+
if (await fs6.pathExists(mainPath)) {
|
|
502
|
+
validCompositions.push(compositionDir);
|
|
503
|
+
} else {
|
|
504
|
+
logger.warn(`Skipping ${compositionDir}: main.tsx not found`);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
if (validCompositions.length === 0) {
|
|
508
|
+
throw new Error("No valid compositions found (compositions must contain main.tsx)");
|
|
509
|
+
}
|
|
510
|
+
const imports = validCompositions.map((compositionDir, index) => {
|
|
511
|
+
const varName = `Composition${index}`;
|
|
512
|
+
const defName = `composition${index}Def`;
|
|
513
|
+
return {
|
|
514
|
+
compositionDir,
|
|
515
|
+
varName,
|
|
516
|
+
defName,
|
|
517
|
+
statement: `import ${varName}, { compositionDefinition as ${defName} } from './compositions/${compositionDir}/main';`
|
|
518
|
+
};
|
|
519
|
+
});
|
|
520
|
+
const compositionsObject = imports.map(({ compositionDir, varName, defName }) => {
|
|
521
|
+
return ` '${compositionDir}': { component: ${varName}, compositionDefinition: ${defName} },`;
|
|
522
|
+
}).join("\n");
|
|
523
|
+
const stylesheetLoader = `// Load stylesheet - try compiled.css first, fall back to Tailwind CDN
|
|
524
|
+
(async () => {
|
|
525
|
+
try {
|
|
526
|
+
await import('./styles/compiled.css');
|
|
527
|
+
} catch (error) {
|
|
528
|
+
// If compiled.css doesn't exist, inject Tailwind CDN as fallback
|
|
529
|
+
console.error("Failed to load compiled styles");
|
|
530
|
+
if (typeof document !== 'undefined') {
|
|
531
|
+
const script = document.createElement('script');
|
|
532
|
+
script.src = 'https://cdn.tailwindcss.com';
|
|
533
|
+
document.head.appendChild(script);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
})();`;
|
|
537
|
+
const content = `/**
|
|
538
|
+
* Auto-generated Remotion SSR Entry Point
|
|
539
|
+
*
|
|
540
|
+
* Generated by: @aspects-ai/workspace-cli create-remotion-entry
|
|
541
|
+
* DO NOT EDIT THIS FILE MANUALLY - it will be overwritten
|
|
542
|
+
*
|
|
543
|
+
* This file serves as the entry point for server-side rendering with Remotion.
|
|
544
|
+
* It automatically registers all compositions in the ./compositions directory.
|
|
545
|
+
*
|
|
546
|
+
* Usage:
|
|
547
|
+
* ANIMATION_SSR_MODE=true npx remotion render remotion-entry.tsx <composition-id> output.mp4
|
|
548
|
+
*
|
|
549
|
+
* To regenerate this file:
|
|
550
|
+
* npx @aspects-ai/workspace-cli create-remotion-entry
|
|
551
|
+
*/
|
|
552
|
+
|
|
553
|
+
${stylesheetLoader}
|
|
554
|
+
|
|
555
|
+
import { registerRoot } from 'remotion';
|
|
556
|
+
import { createRemotionRoot } from '${animateCorePath}/remotion';
|
|
557
|
+
|
|
558
|
+
// Composition imports
|
|
559
|
+
${imports.map((i) => i.statement).join("\n")}
|
|
560
|
+
|
|
561
|
+
// Register all compositions with Remotion
|
|
562
|
+
const Root = createRemotionRoot({
|
|
563
|
+
${compositionsObject}
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
registerRoot(Root);
|
|
567
|
+
`;
|
|
568
|
+
await fs6.writeFile(outputPath, content, "utf-8");
|
|
569
|
+
logger.success(`Created remotion entry file: ${chalk4.green(outputPath)}`);
|
|
570
|
+
logger.log("");
|
|
571
|
+
logger.log(chalk4.bold(`Registered ${validCompositions.length} composition(s):`));
|
|
572
|
+
validCompositions.forEach((composition) => {
|
|
573
|
+
logger.log(` ${chalk4.cyan("\u2022")} ${composition}`);
|
|
574
|
+
});
|
|
575
|
+
logger.log("");
|
|
576
|
+
logger.log(chalk4.bold("Next steps:"));
|
|
577
|
+
logger.log(` ${chalk4.gray("Render a composition:")} ANIMATION_SSR_MODE=true npx remotion render remotion-entry.tsx <composition-id> output.mp4`);
|
|
578
|
+
logger.log("");
|
|
579
|
+
}
|
|
580
|
+
function createCreateRemotionEntryCommand() {
|
|
581
|
+
return new Command3("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, --compositions-dir <path>", "Path to compositions directory", "compositions").option("-a, --animate-core-path <path>", "Path to animate-core (e.g., ./core/animate-core or @aspects-ai/noodle-animate-core)", "./core/animate-core").action(async (options) => {
|
|
582
|
+
try {
|
|
583
|
+
const workspaceRoot = await ensureWorkspaceRoot();
|
|
584
|
+
const compositionsDir = path6.resolve(workspaceRoot, options.compositionsDir || "compositions");
|
|
585
|
+
const outputPath = path6.resolve(workspaceRoot, options.output || "remotion-entry.tsx");
|
|
586
|
+
const animateCorePath = options.animateCorePath || "./core/animate-core";
|
|
587
|
+
logger.info(`Scanning compositions in: ${chalk4.cyan(path6.relative(workspaceRoot, compositionsDir))}`);
|
|
588
|
+
logger.info(`Using animate-core from: ${chalk4.cyan(animateCorePath)}`);
|
|
589
|
+
await createRemotionEntry(compositionsDir, outputPath, animateCorePath);
|
|
590
|
+
} catch (error) {
|
|
591
|
+
logger.error(error.message);
|
|
592
|
+
process.exit(1);
|
|
593
|
+
}
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// src/commands/init.ts
|
|
598
|
+
import { Command as Command4 } from "commander";
|
|
599
|
+
function createInitCommand() {
|
|
600
|
+
return new Command4("init").description("Initialize workspace configuration").action(async () => {
|
|
601
|
+
try {
|
|
602
|
+
const workspaceRoot = await ensureWorkspaceRoot();
|
|
603
|
+
const existing = await loadWorkspaceConfig(workspaceRoot);
|
|
604
|
+
if (existing) {
|
|
605
|
+
logger.warn("workspace.config.json already exists");
|
|
606
|
+
logger.info(`Config file: ${getConfigPath(workspaceRoot)}`);
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
609
|
+
await createDefaultConfig(workspaceRoot);
|
|
610
|
+
logger.success("Created workspace.config.json");
|
|
611
|
+
logger.log("\nNext steps:");
|
|
612
|
+
logger.log(" workspace-cli list # View available libraries");
|
|
613
|
+
logger.log(" workspace-cli add <library> # Install a library");
|
|
614
|
+
} catch (error) {
|
|
615
|
+
logger.error(error.message);
|
|
616
|
+
process.exit(1);
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// src/commands/list.ts
|
|
622
|
+
import { Command as Command5 } from "commander";
|
|
623
|
+
import chalk5 from "chalk";
|
|
624
|
+
function createListCommand() {
|
|
625
|
+
return new Command5("list").description("List available libraries").action(async () => {
|
|
626
|
+
try {
|
|
627
|
+
const libraries = await listLibraries();
|
|
628
|
+
logger.log(chalk5.bold("\nAvailable libraries:\n"));
|
|
629
|
+
for (const { name, library } of libraries) {
|
|
630
|
+
const versionStr = library.version ? ` @${library.version}` : " @latest";
|
|
631
|
+
logger.log(chalk5.cyan(` ${name}`) + chalk5.gray(versionStr));
|
|
632
|
+
logger.log(` ${library.description}`);
|
|
633
|
+
logger.log("");
|
|
634
|
+
}
|
|
635
|
+
logger.log(`Total: ${libraries.length} ${libraries.length === 1 ? "library" : "libraries"}
|
|
636
|
+
`);
|
|
637
|
+
} catch (error) {
|
|
638
|
+
logger.error(error.message);
|
|
639
|
+
process.exit(1);
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
|
|
528
644
|
// src/commands/update-template.ts
|
|
529
645
|
import { Command as Command6 } from "commander";
|
|
530
|
-
import
|
|
531
|
-
import
|
|
646
|
+
import path7 from "path";
|
|
647
|
+
import fs7 from "fs-extra";
|
|
532
648
|
import { execa as execa2 } from "execa";
|
|
533
649
|
import os2 from "os";
|
|
534
650
|
import chalk6 from "chalk";
|
|
@@ -539,9 +655,9 @@ function createUpdateTemplateCommand() {
|
|
|
539
655
|
return new Command6("update-template").description("Update EDITING.md file from noodle-base template").action(async () => {
|
|
540
656
|
try {
|
|
541
657
|
const workspaceRoot = await ensureWorkspaceRoot();
|
|
542
|
-
const targetFile =
|
|
658
|
+
const targetFile = path7.join(workspaceRoot, "EDITING.md");
|
|
543
659
|
const token = getToken();
|
|
544
|
-
const targetExists = await
|
|
660
|
+
const targetExists = await fs7.pathExists(targetFile);
|
|
545
661
|
if (targetExists) {
|
|
546
662
|
logger.info("Existing EDITING.md found, it will be overwritten.");
|
|
547
663
|
}
|
|
@@ -552,7 +668,7 @@ function createUpdateTemplateCommand() {
|
|
|
552
668
|
branch: NOODLE_BASE_BRANCH,
|
|
553
669
|
token
|
|
554
670
|
});
|
|
555
|
-
await
|
|
671
|
+
await fs7.writeFile(targetFile, content, "utf-8");
|
|
556
672
|
logger.success(
|
|
557
673
|
`Successfully ${targetExists ? "updated" : "copied"} EDITING.md to workspace`
|
|
558
674
|
);
|
|
@@ -566,7 +682,7 @@ function createUpdateTemplateCommand() {
|
|
|
566
682
|
});
|
|
567
683
|
}
|
|
568
684
|
async function fetchFileFromGit(options) {
|
|
569
|
-
const tempDir = await
|
|
685
|
+
const tempDir = await fs7.mkdtemp(path7.join(os2.tmpdir(), "workspace-cli-"));
|
|
570
686
|
try {
|
|
571
687
|
const repoUrl = options.repository.replace(
|
|
572
688
|
"https://github.com/",
|
|
@@ -575,18 +691,18 @@ async function fetchFileFromGit(options) {
|
|
|
575
691
|
await execa2("git", ["init"], { cwd: tempDir });
|
|
576
692
|
await execa2("git", ["remote", "add", "origin", repoUrl], { cwd: tempDir });
|
|
577
693
|
await execa2("git", ["config", "core.sparseCheckout", "true"], { cwd: tempDir });
|
|
578
|
-
const sparseFile =
|
|
579
|
-
await
|
|
694
|
+
const sparseFile = path7.join(tempDir, ".git", "info", "sparse-checkout");
|
|
695
|
+
await fs7.writeFile(sparseFile, `${options.filePath}
|
|
580
696
|
`);
|
|
581
697
|
await execa2("git", ["pull", "origin", options.branch, "--depth=1"], {
|
|
582
698
|
cwd: tempDir,
|
|
583
699
|
stderr: "pipe"
|
|
584
700
|
});
|
|
585
|
-
const sourceFile =
|
|
586
|
-
if (!await
|
|
701
|
+
const sourceFile = path7.join(tempDir, options.filePath);
|
|
702
|
+
if (!await fs7.pathExists(sourceFile)) {
|
|
587
703
|
throw new Error(`File '${options.filePath}' not found in repository`);
|
|
588
704
|
}
|
|
589
|
-
return await
|
|
705
|
+
return await fs7.readFile(sourceFile, "utf-8");
|
|
590
706
|
} catch (error) {
|
|
591
707
|
if (error.stderr && error.stderr.includes("Authentication failed")) {
|
|
592
708
|
throw new Error(
|
|
@@ -595,100 +711,34 @@ async function fetchFileFromGit(options) {
|
|
|
595
711
|
}
|
|
596
712
|
throw new Error(`Failed to fetch file from git: ${error.message}`);
|
|
597
713
|
} finally {
|
|
598
|
-
await
|
|
714
|
+
await fs7.remove(tempDir);
|
|
599
715
|
}
|
|
600
716
|
}
|
|
601
717
|
|
|
602
|
-
// src/commands/
|
|
603
|
-
import chalk7 from "chalk";
|
|
718
|
+
// src/commands/update.ts
|
|
604
719
|
import { Command as Command7 } from "commander";
|
|
605
|
-
import
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
if (!await fs7.pathExists(framesDir)) {
|
|
609
|
-
throw new Error(`Frames directory not found: ${framesDir}`);
|
|
610
|
-
}
|
|
611
|
-
const entries = await fs7.readdir(framesDir, { withFileTypes: true });
|
|
612
|
-
const frameDirs = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
613
|
-
if (frameDirs.length === 0) {
|
|
614
|
-
throw new Error(`No frame directories found in ${framesDir}`);
|
|
615
|
-
}
|
|
616
|
-
const validFrames = [];
|
|
617
|
-
for (const frameDir of frameDirs) {
|
|
618
|
-
const mainPath = path7.join(framesDir, frameDir, "main.tsx");
|
|
619
|
-
if (await fs7.pathExists(mainPath)) {
|
|
620
|
-
validFrames.push(frameDir);
|
|
621
|
-
} else {
|
|
622
|
-
logger.warn(`Skipping ${frameDir}: main.tsx not found`);
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
if (validFrames.length === 0) {
|
|
626
|
-
throw new Error("No valid frames found (frames must contain main.tsx)");
|
|
627
|
-
}
|
|
628
|
-
const imports = validFrames.map((frameDir, index) => {
|
|
629
|
-
const varName = `Frame${index}`;
|
|
630
|
-
const defName = `frame${index}Def`;
|
|
631
|
-
return {
|
|
632
|
-
frameDir,
|
|
633
|
-
varName,
|
|
634
|
-
defName,
|
|
635
|
-
statement: `import ${varName}, { compositionDefinition as ${defName} } from './frames/${frameDir}/main';`
|
|
636
|
-
};
|
|
637
|
-
});
|
|
638
|
-
const framesObject = imports.map(({ frameDir, varName, defName }) => {
|
|
639
|
-
return ` '${frameDir}': { component: ${varName}, compositionDefinition: ${defName} },`;
|
|
640
|
-
}).join("\n");
|
|
641
|
-
const content = `/**
|
|
642
|
-
* Auto-generated Remotion SSR Entry Point
|
|
643
|
-
*
|
|
644
|
-
* Generated by: @aspects-ai/workspace-cli create-remotion-entry
|
|
645
|
-
* DO NOT EDIT THIS FILE MANUALLY - it will be overwritten
|
|
646
|
-
*
|
|
647
|
-
* This file serves as the entry point for server-side rendering with Remotion.
|
|
648
|
-
* It automatically registers all frames in the ./frames directory.
|
|
649
|
-
*
|
|
650
|
-
* Usage:
|
|
651
|
-
* ANIMATION_SSR_MODE=true npx remotion render remotion-entry.tsx <frame-id> output.mp4
|
|
652
|
-
*
|
|
653
|
-
* To regenerate this file:
|
|
654
|
-
* npx @aspects-ai/workspace-cli create-remotion-entry
|
|
655
|
-
*/
|
|
656
|
-
|
|
657
|
-
import { registerRoot } from 'remotion';
|
|
658
|
-
import { createRemotionRoot } from '${animateCorePath}/remotion';
|
|
659
|
-
|
|
660
|
-
// Frame imports
|
|
661
|
-
${imports.map((i) => i.statement).join("\n")}
|
|
662
|
-
|
|
663
|
-
// Register all frames with Remotion
|
|
664
|
-
const Root = createRemotionRoot({
|
|
665
|
-
${framesObject}
|
|
666
|
-
});
|
|
667
|
-
|
|
668
|
-
registerRoot(Root);
|
|
669
|
-
`;
|
|
670
|
-
await fs7.writeFile(outputPath, content, "utf-8");
|
|
671
|
-
logger.success(`Created remotion entry file: ${chalk7.green(outputPath)}`);
|
|
672
|
-
logger.log("");
|
|
673
|
-
logger.log(chalk7.bold(`Registered ${validFrames.length} frame(s):`));
|
|
674
|
-
validFrames.forEach((frame) => {
|
|
675
|
-
logger.log(` ${chalk7.cyan("\u2022")} ${frame}`);
|
|
676
|
-
});
|
|
677
|
-
logger.log("");
|
|
678
|
-
logger.log(chalk7.bold("Next steps:"));
|
|
679
|
-
logger.log(` ${chalk7.gray("Render a frame:")} ANIMATION_SSR_MODE=true npx remotion render remotion-entry.tsx <frame-id> output.mp4`);
|
|
680
|
-
logger.log("");
|
|
681
|
-
}
|
|
682
|
-
function createCreateRemotionEntryCommand() {
|
|
683
|
-
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").option("-a, --animate-core-path <path>", "Path to animate-core (e.g., ./core/animate-core or @aspects-ai/noodle-animate-core)", "./core/animate-core").action(async (options) => {
|
|
720
|
+
import chalk7 from "chalk";
|
|
721
|
+
function createUpdateCommand() {
|
|
722
|
+
return new Command7("update").description("Update an installed library to the latest version").argument("<library>", "Name of the library to update").action(async (libraryName) => {
|
|
684
723
|
try {
|
|
685
724
|
const workspaceRoot = await ensureWorkspaceRoot();
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
725
|
+
await getOrCreateConfig(workspaceRoot);
|
|
726
|
+
if (!await isLibraryInstalled(workspaceRoot, libraryName)) {
|
|
727
|
+
throw new Error(
|
|
728
|
+
`Library '${libraryName}' is not installed.
|
|
729
|
+
Use 'workspace-cli add ${libraryName}' to install it first.`
|
|
730
|
+
);
|
|
731
|
+
}
|
|
732
|
+
const config = await loadWorkspaceConfig(workspaceRoot);
|
|
733
|
+
const currentVersion = config?.libraries[libraryName]?.version || "unknown";
|
|
734
|
+
const currentCommit = config?.libraries[libraryName]?.commit || "unknown";
|
|
735
|
+
logger.info(`Current version: ${currentVersion} (commit: ${currentCommit.substring(0, 7)})`);
|
|
736
|
+
logger.info(`Updating ${libraryName}...`);
|
|
737
|
+
await installLibrary(workspaceRoot, libraryName, { force: true });
|
|
738
|
+
logger.log("\n" + chalk7.bold("Next steps:"));
|
|
739
|
+
logger.log(` ${chalk7.gray("Review changes:")} git diff ./core/${libraryName.replace("animate-", "")}`);
|
|
740
|
+
logger.log(` ${chalk7.gray("Install updated dependencies:")} npm install`);
|
|
741
|
+
logger.log("");
|
|
692
742
|
} catch (error) {
|
|
693
743
|
logger.error(error.message);
|
|
694
744
|
process.exit(1);
|
|
@@ -696,44 +746,6 @@ function createCreateRemotionEntryCommand() {
|
|
|
696
746
|
});
|
|
697
747
|
}
|
|
698
748
|
|
|
699
|
-
// package.json
|
|
700
|
-
var package_default = {
|
|
701
|
-
name: "@aspects-ai/workspace-cli",
|
|
702
|
-
version: "0.1.13",
|
|
703
|
-
private: false,
|
|
704
|
-
description: "Lightweight CLI for installing libraries into workspaces",
|
|
705
|
-
type: "module",
|
|
706
|
-
bin: {
|
|
707
|
-
"workspace-cli": "./dist/index.js"
|
|
708
|
-
},
|
|
709
|
-
scripts: {
|
|
710
|
-
build: "tsup src/index.ts --format esm --dts --clean && npm run copy:registry",
|
|
711
|
-
"copy:registry": "mkdir -p dist/registry && cp src/registry/libraries.json dist/registry/",
|
|
712
|
-
dev: "tsup src/index.ts --format esm --watch",
|
|
713
|
-
typecheck: "tsc --noEmit"
|
|
714
|
-
},
|
|
715
|
-
files: [
|
|
716
|
-
"dist",
|
|
717
|
-
"src/registry"
|
|
718
|
-
],
|
|
719
|
-
dependencies: {
|
|
720
|
-
chalk: "^5.3.0",
|
|
721
|
-
commander: "^12.0.0",
|
|
722
|
-
execa: "^8.0.0",
|
|
723
|
-
"fs-extra": "^11.2.0",
|
|
724
|
-
zod: "^3.22.0"
|
|
725
|
-
},
|
|
726
|
-
devDependencies: {
|
|
727
|
-
"@types/fs-extra": "^11.0.0",
|
|
728
|
-
"@types/node": "^20",
|
|
729
|
-
tsup: "^8.0.0",
|
|
730
|
-
typescript: "^5"
|
|
731
|
-
},
|
|
732
|
-
engines: {
|
|
733
|
-
node: ">=18.0.0"
|
|
734
|
-
}
|
|
735
|
-
};
|
|
736
|
-
|
|
737
749
|
// src/index.ts
|
|
738
750
|
var program = new Command8();
|
|
739
751
|
program.name("workspace-cli").description("Lightweight CLI for installing libraries into workspaces").version(package_default.version);
|
|
@@ -741,7 +753,7 @@ program.addCommand(createInitCommand());
|
|
|
741
753
|
program.addCommand(createListCommand());
|
|
742
754
|
program.addCommand(createAddCommand());
|
|
743
755
|
program.addCommand(createUpdateCommand());
|
|
744
|
-
program.addCommand(
|
|
756
|
+
program.addCommand(createCreateCompositionCommand());
|
|
745
757
|
program.addCommand(createUpdateTemplateCommand());
|
|
746
758
|
program.addCommand(createCreateRemotionEntryCommand());
|
|
747
759
|
program.parse(process.argv);
|