@orth/cli 0.2.0 → 0.2.3

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
@@ -2,7 +2,7 @@
2
2
 
3
3
  CLI to access all APIs and agent skills on the Orthogonal platform.
4
4
 
5
- ![Demo](demos/demo.gif)
5
+ ![Demo](https://raw.githubusercontent.com/orthogonal-sh/cli/main/demos/demo.gif)
6
6
 
7
7
  ## Installation
8
8
 
@@ -33,7 +33,7 @@ async function whoamiCommand() {
33
33
  const key = (0, config_js_1.getApiKey)();
34
34
  if (!key) {
35
35
  console.log(chalk_1.default.yellow("Not authenticated"));
36
- console.log(chalk_1.default.gray("Run 'orth login' to authenticate"));
36
+ console.log(chalk_1.default.gray("Run 'ortho login' to authenticate"));
37
37
  return;
38
38
  }
39
39
  console.log(chalk_1.default.green("✓ Authenticated"));
@@ -36,8 +36,8 @@ async function searchCommand(query, options) {
36
36
  }
37
37
  console.log();
38
38
  }
39
- console.log(chalk_1.default.gray(`Run 'orth api <slug>' to see all endpoints for an API`));
40
- console.log(chalk_1.default.gray(`Run 'orth run <api> <path>' to call an endpoint`));
39
+ console.log(chalk_1.default.gray(`Run 'ortho api <slug>' to see all endpoints for an API`));
40
+ console.log(chalk_1.default.gray(`Run 'ortho run <api> <path>' to call an endpoint`));
41
41
  }
42
42
  catch (error) {
43
43
  spinner.stop();
@@ -21,6 +21,10 @@ export declare function skillsSubmitCommand(inputPath: string | undefined, optio
21
21
  name?: string;
22
22
  tags?: string;
23
23
  }): Promise<void>;
24
+ export declare function skillsUpdateCommand(slug: string, inputPath: string | undefined, options: {
25
+ name?: string;
26
+ tags?: string;
27
+ }): Promise<void>;
24
28
  export declare function skillsRequestVerificationCommand(slug: string): Promise<void>;
25
29
  export declare function skillsPublishCommand(slug: string, options: {
26
30
  unpublish?: boolean;
@@ -43,6 +43,7 @@ exports.skillsCreateCommand = skillsCreateCommand;
43
43
  exports.skillsInstallCommand = skillsInstallCommand;
44
44
  exports.skillsInitCommand = skillsInitCommand;
45
45
  exports.skillsSubmitCommand = skillsSubmitCommand;
46
+ exports.skillsUpdateCommand = skillsUpdateCommand;
46
47
  exports.skillsRequestVerificationCommand = skillsRequestVerificationCommand;
47
48
  exports.skillsPublishCommand = skillsPublishCommand;
48
49
  exports.skillsRequestCommand = skillsRequestCommand;
@@ -576,6 +577,87 @@ async function skillsSubmitCommand(inputPath, options) {
576
577
  }
577
578
  }
578
579
  // ─────────────────────────────────────────────────────────────────────────────
580
+ // orth skills update <slug> [path]
581
+ // ─────────────────────────────────────────────────────────────────────────────
582
+ async function skillsUpdateCommand(slug, inputPath, options) {
583
+ const dirPath = inputPath ? path.resolve(inputPath) : process.cwd();
584
+ const spinner = (0, ora_1.default)("Reading skill files...").start();
585
+ try {
586
+ // Validate directory exists
587
+ if (!fs.existsSync(dirPath) || !fs.statSync(dirPath).isDirectory()) {
588
+ spinner.stop();
589
+ console.error(chalk_1.default.red(`Error: ${dirPath} is not a directory`));
590
+ process.exit(1);
591
+ }
592
+ // Read all files
593
+ const files = readFilesRecursive(dirPath);
594
+ if (files.length === 0) {
595
+ spinner.stop();
596
+ console.error(chalk_1.default.red("Error: No files found in the directory"));
597
+ process.exit(1);
598
+ }
599
+ // Validate SKILL.md exists
600
+ const primaryFile = files.find((f) => f.isPrimary);
601
+ if (!primaryFile) {
602
+ spinner.stop();
603
+ console.error(chalk_1.default.red("Error: No SKILL.md found in the root of the directory"));
604
+ process.exit(1);
605
+ }
606
+ // Parse frontmatter
607
+ // Note: Unlike submit, name/description are optional for updates
608
+ // We only send them if provided (to allow partial updates)
609
+ const frontmatter = parseFrontmatter(primaryFile.content);
610
+ const skillName = options.name || frontmatter.name;
611
+ const skillDescription = frontmatter.description;
612
+ // Check size limits
613
+ const totalSize = files.reduce((acc, f) => acc + f.content.length, 0);
614
+ if (files.length > 50) {
615
+ spinner.stop();
616
+ console.error(chalk_1.default.red("Error: Too many files (max 50)"));
617
+ process.exit(1);
618
+ }
619
+ if (totalSize > 1024 * 1024) {
620
+ spinner.stop();
621
+ console.error(chalk_1.default.red("Error: Total content too large (max 1MB)"));
622
+ process.exit(1);
623
+ }
624
+ spinner.text = "Updating skill...";
625
+ const tags = options.tags
626
+ ? options.tags.split(",").map((t) => t.trim())
627
+ : undefined;
628
+ const updatePayload = {
629
+ files: files.map((f) => ({
630
+ filePath: f.filePath,
631
+ content: f.content,
632
+ isPrimary: f.isPrimary,
633
+ })),
634
+ };
635
+ if (skillName)
636
+ updatePayload.name = skillName;
637
+ if (skillDescription)
638
+ updatePayload.description = skillDescription;
639
+ if (tags)
640
+ updatePayload.tags = tags;
641
+ const data = await (0, api_js_1.apiRequest)(`/skills/${slug}`, {
642
+ method: "PUT",
643
+ body: updatePayload,
644
+ });
645
+ spinner.stop();
646
+ console.log(chalk_1.default.green(`\n✓ Skill updated successfully`));
647
+ console.log(chalk_1.default.bold(`\n${data.skill.name}`));
648
+ console.log(chalk_1.default.gray(` Slug: ${data.skill.slug}`));
649
+ console.log(chalk_1.default.gray(` Files: ${files.length}`));
650
+ if (data.skill.description) {
651
+ console.log(chalk_1.default.gray(` ${data.skill.description.slice(0, 100)}`));
652
+ }
653
+ }
654
+ catch (error) {
655
+ spinner.stop();
656
+ console.error(chalk_1.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
657
+ process.exit(1);
658
+ }
659
+ }
660
+ // ─────────────────────────────────────────────────────────────────────────────
579
661
  // orth skills request-verification <slug>
580
662
  // ─────────────────────────────────────────────────────────────────────────────
581
663
  async function skillsRequestVerificationCommand(slug) {
package/dist/config.js CHANGED
@@ -29,7 +29,7 @@ function clearApiKey() {
29
29
  function requireApiKey() {
30
30
  const key = getApiKey();
31
31
  if (!key) {
32
- console.error("Error: Not authenticated. Run 'orth login' first or set ORTHOGONAL_API_KEY.");
32
+ console.error("Error: Not authenticated. Run 'ortho login' first or set ORTHOGONAL_API_KEY.");
33
33
  process.exit(1);
34
34
  }
35
35
  return key;
package/dist/index.js CHANGED
@@ -175,6 +175,15 @@ skillsGroup
175
175
  (0, analytics_js_1.trackEvent)("skills.submit", { path: inputPath });
176
176
  await (0, skills_js_1.skillsSubmitCommand)(inputPath, options);
177
177
  }));
178
+ skillsGroup
179
+ .command("update <slug> [path]")
180
+ .description("Update an existing skill with local files")
181
+ .option("-n, --name <name>", "Override skill name from frontmatter")
182
+ .option("-t, --tags <tags>", "Comma-separated tags")
183
+ .action(asyncAction(async (slug, inputPath, options) => {
184
+ (0, analytics_js_1.trackEvent)("skills.update", { slug, path: inputPath });
185
+ await (0, skills_js_1.skillsUpdateCommand)(slug, inputPath, options);
186
+ }));
178
187
  skillsGroup
179
188
  .command("request-verification <slug>")
180
189
  .description("Request verification for your skill (required before discoverability)")
@@ -220,7 +229,7 @@ skillsGroup
220
229
  // ─────────────────────────────────────────────────────────────────────────────
221
230
  program
222
231
  .command("search <query>")
223
- .description("Search for APIs (alias for 'orth api search')")
232
+ .description("Search for APIs (alias for 'ortho api search')")
224
233
  .option("-l, --limit <number>", "Max results", "10")
225
234
  .action(asyncAction(async (query, options) => {
226
235
  (0, analytics_js_1.trackEvent)("search", { query });
@@ -228,7 +237,7 @@ program
228
237
  }));
229
238
  program
230
239
  .command("run <api> <path>")
231
- .description("Call an API endpoint (alias for 'orth api run')")
240
+ .description("Call an API endpoint (alias for 'ortho api run')")
232
241
  .option("-X, --method <method>", "HTTP method", "GET")
233
242
  .option("-q, --query <params...>", "Query params (key=value)")
234
243
  .option("-b, --body <json>", "Request body JSON")
@@ -240,7 +249,7 @@ program
240
249
  }));
241
250
  program
242
251
  .command("code <api> <path>")
243
- .description("Generate integration code (alias for 'orth api code')")
252
+ .description("Generate integration code (alias for 'ortho api code')")
244
253
  .option("-l, --lang <language>", "Language: typescript, python, curl", "typescript")
245
254
  .action(asyncAction(async (api, path, options) => {
246
255
  (0, analytics_js_1.trackEvent)("code", { api, path });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orth/cli",
3
- "version": "0.2.0",
3
+ "version": "0.2.3",
4
4
  "description": "CLI to access all APIs and skills on the Orthogonal platform",
5
5
  "main": "dist/index.js",
6
6
  "bin": {