@aspects-ai/workspace-cli 0.1.6 → 0.1.8

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.js +67 -26
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -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);
@@ -518,29 +525,30 @@ function createCreateFrameCommand() {
518
525
  import { Command as Command6 } from "commander";
519
526
  import path6 from "path";
520
527
  import fs6 from "fs-extra";
528
+ import { execa as execa2 } from "execa";
529
+ import os2 from "os";
521
530
  import chalk6 from "chalk";
522
- import { fileURLToPath as fileURLToPath2 } from "url";
523
- var __filename2 = fileURLToPath2(import.meta.url);
524
- var __dirname2 = path6.dirname(__filename2);
531
+ var NOODLE_BASE_REPO = "https://github.com/aspects-ai/noodle-templates";
532
+ var NOODLE_BASE_BRANCH = "main";
533
+ var EDITING_FILE_PATH = "noodle-base/EDITING.md";
525
534
  function createUpdateTemplateCommand() {
526
535
  return new Command6("update-template").description("Update EDITING.md file from noodle-base template").action(async () => {
527
536
  try {
528
537
  const workspaceRoot = await ensureWorkspaceRoot();
529
- const noodleBasePath = path6.resolve(__dirname2, "../../../noodle-base");
530
- const sourceFile = path6.join(noodleBasePath, "EDITING.md");
531
538
  const targetFile = path6.join(workspaceRoot, "EDITING.md");
532
- if (!await fs6.pathExists(sourceFile)) {
533
- throw new Error(
534
- `Template file not found at: ${sourceFile}
535
- Make sure noodle-base is available in the monorepo.`
536
- );
537
- }
539
+ const token = getToken();
538
540
  const targetExists = await fs6.pathExists(targetFile);
539
541
  if (targetExists) {
540
542
  logger.info("Existing EDITING.md found, it will be overwritten.");
541
543
  }
542
- logger.info(`Copying EDITING.md from noodle-base...`);
543
- await fs6.copy(sourceFile, targetFile, { overwrite: true });
544
+ logger.info("Fetching EDITING.md from noodle-base...");
545
+ const content = await fetchFileFromGit({
546
+ repository: NOODLE_BASE_REPO,
547
+ filePath: EDITING_FILE_PATH,
548
+ branch: NOODLE_BASE_BRANCH,
549
+ token
550
+ });
551
+ await fs6.writeFile(targetFile, content, "utf-8");
544
552
  logger.success(
545
553
  `Successfully ${targetExists ? "updated" : "copied"} EDITING.md to workspace`
546
554
  );
@@ -553,11 +561,44 @@ Make sure noodle-base is available in the monorepo.`
553
561
  }
554
562
  });
555
563
  }
564
+ async function fetchFileFromGit(options) {
565
+ const tempDir = await fs6.mkdtemp(path6.join(os2.tmpdir(), "workspace-cli-"));
566
+ try {
567
+ const repoUrl = options.repository.replace(
568
+ "https://github.com/",
569
+ `https://${options.token}@github.com/`
570
+ );
571
+ await execa2("git", ["init"], { cwd: tempDir });
572
+ await execa2("git", ["remote", "add", "origin", repoUrl], { cwd: tempDir });
573
+ await execa2("git", ["config", "core.sparseCheckout", "true"], { cwd: tempDir });
574
+ const sparseFile = path6.join(tempDir, ".git", "info", "sparse-checkout");
575
+ await fs6.writeFile(sparseFile, `${options.filePath}
576
+ `);
577
+ await execa2("git", ["pull", "origin", options.branch, "--depth=1"], {
578
+ cwd: tempDir,
579
+ stderr: "pipe"
580
+ });
581
+ const sourceFile = path6.join(tempDir, options.filePath);
582
+ if (!await fs6.pathExists(sourceFile)) {
583
+ throw new Error(`File '${options.filePath}' not found in repository`);
584
+ }
585
+ return await fs6.readFile(sourceFile, "utf-8");
586
+ } catch (error) {
587
+ if (error.stderr && error.stderr.includes("Authentication failed")) {
588
+ throw new Error(
589
+ "Git authentication failed. Please check your WORKSPACE_CLI_TOKEN.\nThe token must have access to the repository."
590
+ );
591
+ }
592
+ throw new Error(`Failed to fetch file from git: ${error.message}`);
593
+ } finally {
594
+ await fs6.remove(tempDir);
595
+ }
596
+ }
556
597
 
557
598
  // package.json
558
599
  var package_default = {
559
600
  name: "@aspects-ai/workspace-cli",
560
- version: "0.1.5",
601
+ version: "0.1.7",
561
602
  private: false,
562
603
  description: "Lightweight CLI for installing libraries into workspaces",
563
604
  type: "module",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aspects-ai/workspace-cli",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "private": false,
5
5
  "description": "Lightweight CLI for installing libraries into workspaces",
6
6
  "type": "module",