@aspects-ai/workspace-cli 0.1.0 → 0.1.2

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 CHANGED
@@ -83,6 +83,21 @@ The command will:
83
83
  3. Update `workspace.config.json`
84
84
  4. Add dependencies to `package.json`
85
85
 
86
+ ### `update <library>`
87
+
88
+ Update an installed library to the latest version from the repository.
89
+
90
+ ```bash
91
+ WORKSPACE_CLI_TOKEN=ghp_xxx workspace-cli update animate-core
92
+ ```
93
+
94
+ This command will:
95
+ 1. Check the currently installed version
96
+ 2. Fetch the latest version from the git repository
97
+ 3. Overwrite the existing files
98
+ 4. Update `workspace.config.json` with the new version and commit hash
99
+ 5. Update dependencies in `package.json` if they changed
100
+
86
101
  ## Usage Examples
87
102
 
88
103
  ### Basic Workflow
@@ -176,28 +191,27 @@ Libraries are defined in `src/registry/libraries.json`:
176
191
  "animate-core": {
177
192
  "name": "@aspects-ai/noodle-animate-core",
178
193
  "description": "Core animation components for Noodle videos",
179
- "version": "0.1.3",
180
194
  "repository": {
181
195
  "url": "https://github.com/aspects-ai/noodle-templates.git",
182
196
  "directory": "noodle-animate-core/src",
183
- "branch": "main"
197
+ "branch": "main",
198
+ "packageJsonPath": "noodle-animate-core/package.json"
184
199
  },
185
- "installPath": "animate-core",
186
- "dependencies": {
187
- "react": "19.1.0",
188
- "remotion": "4.0.356"
189
- }
200
+ "installPath": "animate-core"
190
201
  }
191
202
  }
192
203
  }
193
204
  ```
194
205
 
206
+ **Automatic Detection**: The CLI automatically reads both the `version` and `dependencies` from the library's `package.json` in the git repository. You don't need to hardcode these values in the registry - they're always fetched from the source of truth.
207
+
195
208
  ## How It Works
196
209
 
197
210
  1. **Git Sparse Checkout**: The CLI uses git sparse checkout to efficiently fetch only the required directory from the repository
198
- 2. **Local Installation**: Files are copied to `./core/<library-name>/` in your workspace
199
- 3. **Dependency Management**: Required dependencies are automatically added to your `package.json`
200
- 4. **Version Tracking**: The exact git commit hash is stored for reproducibility
211
+ 2. **Automatic Metadata Detection**: Both version and dependencies are read from the library's `package.json` in the repository, so they're always up-to-date
212
+ 3. **Local Installation**: Files are copied to `./core/<library-name>/` in your workspace
213
+ 4. **Dependency Management**: Required dependencies are automatically added to your `package.json`
214
+ 5. **Version Tracking**: The exact git commit hash and detected version are stored for reproducibility
201
215
 
202
216
  ## Error Handling
203
217
 
@@ -249,20 +263,19 @@ Example:
249
263
  "my-library": {
250
264
  "name": "@aspects-ai/my-library",
251
265
  "description": "Description of the library",
252
- "version": "1.0.0",
253
266
  "repository": {
254
267
  "url": "https://github.com/org/repo.git",
255
268
  "directory": "path/to/library/src",
256
- "branch": "main"
269
+ "branch": "main",
270
+ "packageJsonPath": "path/to/library/package.json"
257
271
  },
258
- "installPath": "my-library",
259
- "dependencies": {
260
- "react": "^18.0.0"
261
- }
272
+ "installPath": "my-library"
262
273
  }
263
274
  }
264
275
  ```
265
276
 
277
+ **Note**: Both `version` and `dependencies` fields are optional. If you provide `packageJsonPath`, the CLI will automatically read these from the library's `package.json` in the repository. This keeps the registry minimal and ensures values are always current.
278
+
266
279
  ## License
267
280
 
268
281
  ISC
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 Command4 } from "commander";
4
+ import { Command as Command5 } from "commander";
5
5
 
6
6
  // src/commands/init.ts
7
7
  import { Command } from "commander";
@@ -165,15 +165,19 @@ import { z as z2 } from "zod";
165
165
  var RepositorySchema = z2.object({
166
166
  url: z2.string(),
167
167
  directory: z2.string(),
168
- branch: 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")
169
171
  });
170
172
  var LibrarySchema = z2.object({
171
173
  name: z2.string(),
172
174
  description: z2.string(),
173
- version: z2.string(),
175
+ version: z2.string().optional(),
176
+ // Optional - if not provided, will be read from package.json in repo
174
177
  repository: RepositorySchema,
175
178
  installPath: z2.string(),
176
- dependencies: z2.record(z2.string())
179
+ dependencies: z2.record(z2.string()).optional()
180
+ // Optional - if not provided, will be read from package.json in repo
177
181
  });
178
182
  var RegistrySchema = z2.object({
179
183
  libraries: z2.record(LibrarySchema)
@@ -215,7 +219,8 @@ function createListCommand() {
215
219
  const libraries = await listLibraries();
216
220
  logger.log(chalk2.bold("\nAvailable libraries:\n"));
217
221
  for (const { name, library } of libraries) {
218
- logger.log(chalk2.cyan(` ${name}`) + chalk2.gray(` @${library.version}`));
222
+ const versionStr = library.version ? ` @${library.version}` : " @latest";
223
+ logger.log(chalk2.cyan(` ${name}`) + chalk2.gray(versionStr));
219
224
  logger.log(` ${library.description}`);
220
225
  logger.log("");
221
226
  }
@@ -251,8 +256,13 @@ async function fetchDirectory(options) {
251
256
  await execa("git", ["remote", "add", "origin", repoUrl], { cwd: tempDir });
252
257
  await execa("git", ["config", "core.sparseCheckout", "true"], { cwd: tempDir });
253
258
  const sparseFile = path3.join(tempDir, ".git", "info", "sparse-checkout");
254
- await fs3.writeFile(sparseFile, `${options.directory}/*
255
- `);
259
+ let sparsePaths = `${options.directory}/*
260
+ `;
261
+ if (options.packageJsonPath) {
262
+ sparsePaths += `${options.packageJsonPath}
263
+ `;
264
+ }
265
+ await fs3.writeFile(sparseFile, sparsePaths);
256
266
  await execa("git", ["pull", "origin", options.branch, "--depth=1"], {
257
267
  cwd: tempDir,
258
268
  stderr: "pipe"
@@ -267,7 +277,26 @@ async function fetchDirectory(options) {
267
277
  overwrite: true,
268
278
  errorOnExist: false
269
279
  });
270
- return commit.trim();
280
+ let version = null;
281
+ let dependencies = {};
282
+ if (options.packageJsonPath) {
283
+ const packageJsonFullPath = path3.join(tempDir, options.packageJsonPath);
284
+ if (await fs3.pathExists(packageJsonFullPath)) {
285
+ try {
286
+ const packageJson = await fs3.readJson(packageJsonFullPath);
287
+ version = packageJson.version || null;
288
+ dependencies = packageJson.dependencies || {};
289
+ } catch (error) {
290
+ version = null;
291
+ dependencies = {};
292
+ }
293
+ }
294
+ }
295
+ return {
296
+ commit: commit.trim(),
297
+ version,
298
+ dependencies
299
+ };
271
300
  } catch (error) {
272
301
  if (error.stderr && error.stderr.includes("Authentication failed")) {
273
302
  throw new Error(
@@ -305,20 +334,24 @@ Use --force to reinstall.`
305
334
  const config = await loadWorkspaceConfig(workspaceRoot);
306
335
  const coreDir = config?.coreDir || "./core";
307
336
  const targetPath = path4.join(workspaceRoot, coreDir, library.installPath);
308
- logger.info(`Fetching ${libraryName}@${library.version} from git...`);
309
- const commit = await fetchDirectory({
337
+ const versionDisplay = library.version || "latest";
338
+ logger.info(`Fetching ${libraryName}@${versionDisplay} from git...`);
339
+ const result = await fetchDirectory({
310
340
  repository: library.repository.url,
311
341
  directory: library.repository.directory,
312
342
  branch: library.repository.branch,
313
343
  token,
314
- targetPath
344
+ targetPath,
345
+ packageJsonPath: library.repository.packageJsonPath
315
346
  });
347
+ const actualVersion = result.version || library.version || "unknown";
348
+ const actualDependencies = Object.keys(result.dependencies).length > 0 ? result.dependencies : library.dependencies || {};
316
349
  logger.info(`Installed to ${path4.relative(workspaceRoot, targetPath)}`);
317
350
  logger.info(`Updating workspace.config.json...`);
318
- await addLibraryToConfig(workspaceRoot, libraryName, library.version, commit);
319
- await updatePackageDependencies(workspaceRoot, library.dependencies);
351
+ await addLibraryToConfig(workspaceRoot, libraryName, actualVersion, result.commit);
352
+ await updatePackageDependencies(workspaceRoot, actualDependencies);
320
353
  logger.success(
321
- `Installed ${libraryName}@${library.version} (commit: ${commit.substring(0, 7)})`
354
+ `Installed ${libraryName}@${actualVersion} (commit: ${result.commit.substring(0, 7)})`
322
355
  );
323
356
  }
324
357
  async function updatePackageDependencies(workspaceRoot, dependencies) {
@@ -364,10 +397,42 @@ function createAddCommand() {
364
397
  });
365
398
  }
366
399
 
400
+ // src/commands/update.ts
401
+ import { Command as Command4 } from "commander";
402
+ import chalk4 from "chalk";
403
+ function createUpdateCommand() {
404
+ return new Command4("update").description("Update an installed library to the latest version").argument("<library>", "Name of the library to update").action(async (libraryName) => {
405
+ try {
406
+ const workspaceRoot = await ensureWorkspaceRoot();
407
+ await getOrCreateConfig(workspaceRoot);
408
+ if (!await isLibraryInstalled(workspaceRoot, libraryName)) {
409
+ throw new Error(
410
+ `Library '${libraryName}' is not installed.
411
+ Use 'workspace-cli add ${libraryName}' to install it first.`
412
+ );
413
+ }
414
+ const config = await loadWorkspaceConfig(workspaceRoot);
415
+ const currentVersion = config?.libraries[libraryName]?.version || "unknown";
416
+ const currentCommit = config?.libraries[libraryName]?.commit || "unknown";
417
+ logger.info(`Current version: ${currentVersion} (commit: ${currentCommit.substring(0, 7)})`);
418
+ logger.info(`Updating ${libraryName}...`);
419
+ await installLibrary(workspaceRoot, libraryName, { force: true });
420
+ logger.log("\n" + chalk4.bold("Next steps:"));
421
+ logger.log(` ${chalk4.gray("Review changes:")} git diff ./core/${libraryName.replace("animate-", "")}`);
422
+ logger.log(` ${chalk4.gray("Install updated dependencies:")} npm install`);
423
+ logger.log("");
424
+ } catch (error) {
425
+ logger.error(error.message);
426
+ process.exit(1);
427
+ }
428
+ });
429
+ }
430
+
367
431
  // src/index.ts
368
- var program = new Command4();
432
+ var program = new Command5();
369
433
  program.name("workspace-cli").description("Lightweight CLI for installing libraries into workspaces").version("0.1.0");
370
434
  program.addCommand(createInitCommand());
371
435
  program.addCommand(createListCommand());
372
436
  program.addCommand(createAddCommand());
437
+ program.addCommand(createUpdateCommand());
373
438
  program.parse(process.argv);
@@ -3,29 +3,13 @@
3
3
  "animate-core": {
4
4
  "name": "@aspects-ai/noodle-animate-core",
5
5
  "description": "Core animation components for Noodle videos",
6
- "version": "0.1.3",
7
6
  "repository": {
8
7
  "url": "https://github.com/aspects-ai/noodle-templates.git",
9
8
  "directory": "noodle-animate-core/src",
10
- "branch": "main"
9
+ "branch": "main",
10
+ "packageJsonPath": "noodle-animate-core/package.json"
11
11
  },
12
- "installPath": "animate-core",
13
- "dependencies": {
14
- "react": "19.1.0",
15
- "react-dom": "19.1.0",
16
- "remotion": "4.0.356",
17
- "react-rnd": "^10.5.2",
18
- "class-variance-authority": "^0.7.1",
19
- "clsx": "^2.1.1",
20
- "cmdk": "^1.1.1",
21
- "date-fns": "^4.1.0",
22
- "embla-carousel-react": "^8.6.0",
23
- "input-otp": "^1.4.2",
24
- "lucide-react": "^0.542.0",
25
- "tailwind-merge": "^3.3.1",
26
- "tailwindcss-animate": "^1.0.7",
27
- "vaul": "^1.1.2"
28
- }
12
+ "installPath": "animate-core"
29
13
  }
30
14
  }
31
- }
15
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aspects-ai/workspace-cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
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
+ }
@@ -3,29 +3,13 @@
3
3
  "animate-core": {
4
4
  "name": "@aspects-ai/noodle-animate-core",
5
5
  "description": "Core animation components for Noodle videos",
6
- "version": "0.1.3",
7
6
  "repository": {
8
7
  "url": "https://github.com/aspects-ai/noodle-templates.git",
9
8
  "directory": "noodle-animate-core/src",
10
- "branch": "main"
9
+ "branch": "main",
10
+ "packageJsonPath": "noodle-animate-core/package.json"
11
11
  },
12
- "installPath": "animate-core",
13
- "dependencies": {
14
- "react": "19.1.0",
15
- "react-dom": "19.1.0",
16
- "remotion": "4.0.356",
17
- "react-rnd": "^10.5.2",
18
- "class-variance-authority": "^0.7.1",
19
- "clsx": "^2.1.1",
20
- "cmdk": "^1.1.1",
21
- "date-fns": "^4.1.0",
22
- "embla-carousel-react": "^8.6.0",
23
- "input-otp": "^1.4.2",
24
- "lucide-react": "^0.542.0",
25
- "tailwind-merge": "^3.3.1",
26
- "tailwindcss-animate": "^1.0.7",
27
- "vaul": "^1.1.2"
28
- }
12
+ "installPath": "animate-core"
29
13
  }
30
14
  }
31
- }
15
+ }