@orth/cli 0.2.2 → 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.
@@ -36,7 +36,7 @@ async function apiCommand(slug, path, options) {
36
36
  chalk_1.default.white(api.name || "") +
37
37
  chalk_1.default.gray(` (${api.endpoints?.length || 0} endpoints)`));
38
38
  }
39
- console.log(chalk_1.default.gray("\nRun 'ortho api <slug>' to see endpoints for an API"));
39
+ console.log(chalk_1.default.gray("\nRun 'orth api <slug>' to see endpoints for an API"));
40
40
  return;
41
41
  }
42
42
  if (path) {
@@ -127,7 +127,7 @@ async function apiCommand(slug, path, options) {
127
127
  const api = data.results.find((a) => a.slug === slug);
128
128
  if (!api) {
129
129
  console.log(chalk_1.default.yellow(`API '${slug}' not found.`));
130
- console.log(chalk_1.default.gray("Run 'ortho api' to see available APIs"));
130
+ console.log(chalk_1.default.gray("Run 'orth api' to see available APIs"));
131
131
  return;
132
132
  }
133
133
  console.log(chalk_1.default.bold(`\n${chalk_1.default.cyan(api.name)} (${api.slug})\n`));
@@ -139,8 +139,8 @@ async function apiCommand(slug, path, options) {
139
139
  console.log(chalk_1.default.gray(` ${endpoint.description.slice(0, 80)}${endpoint.description.length > 80 ? "..." : ""}`));
140
140
  }
141
141
  }
142
- console.log(chalk_1.default.gray("\nRun 'ortho api " + slug + " <path>' for endpoint details"));
143
- console.log(chalk_1.default.gray("Run 'ortho run " + slug + " <path>' to call an endpoint"));
142
+ console.log(chalk_1.default.gray("\nRun 'orth api " + slug + " <path>' for endpoint details"));
143
+ console.log(chalk_1.default.gray("Run 'orth run " + slug + " <path>' to call an endpoint"));
144
144
  }
145
145
  catch (error) {
146
146
  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;
@@ -63,7 +64,7 @@ const AGENT_DIRS = {
63
64
  openclaw: path.join(os.homedir(), ".openclaw", "skills"),
64
65
  };
65
66
  // ─────────────────────────────────────────────────────────────────────────────
66
- // ortho skills list
67
+ // orth skills list
67
68
  // ─────────────────────────────────────────────────────────────────────────────
68
69
  async function skillsListCommand(options) {
69
70
  const spinner = (0, ora_1.default)("Loading skills...").start();
@@ -93,8 +94,8 @@ async function skillsListCommand(options) {
93
94
  console.log(chalk_1.default.gray(` Slug: ${skill.slug}`));
94
95
  console.log();
95
96
  }
96
- console.log(chalk_1.default.gray("Run 'ortho skills show <slug>' to see skill details"));
97
- console.log(chalk_1.default.gray("Run 'ortho skills add <slug>' to add a skill locally"));
97
+ console.log(chalk_1.default.gray("Run 'orth skills show <slug>' to see skill details"));
98
+ console.log(chalk_1.default.gray("Run 'orth skills add <slug>' to add a skill locally"));
98
99
  }
99
100
  catch (error) {
100
101
  spinner.stop();
@@ -103,7 +104,7 @@ async function skillsListCommand(options) {
103
104
  }
104
105
  }
105
106
  // ─────────────────────────────────────────────────────────────────────────────
106
- // ortho skills search <query>
107
+ // orth skills search <query>
107
108
  // ─────────────────────────────────────────────────────────────────────────────
108
109
  async function skillsSearchCommand(query, options) {
109
110
  const spinner = (0, ora_1.default)("Searching skills...").start();
@@ -128,7 +129,7 @@ async function skillsSearchCommand(query, options) {
128
129
  console.log(chalk_1.default.gray(` Slug: ${skill.slug}`));
129
130
  console.log();
130
131
  }
131
- console.log(chalk_1.default.gray("Run 'ortho skills show <slug>' for full details"));
132
+ console.log(chalk_1.default.gray("Run 'orth skills show <slug>' for full details"));
132
133
  }
133
134
  catch (error) {
134
135
  spinner.stop();
@@ -137,7 +138,7 @@ async function skillsSearchCommand(query, options) {
137
138
  }
138
139
  }
139
140
  // ─────────────────────────────────────────────────────────────────────────────
140
- // ortho skills show <slug>
141
+ // orth skills show <slug>
141
142
  // ─────────────────────────────────────────────────────────────────────────────
142
143
  async function skillsShowCommand(slug) {
143
144
  const spinner = (0, ora_1.default)("Loading skill...").start();
@@ -191,7 +192,7 @@ async function skillsShowCommand(slug) {
191
192
  console.log(chalk_1.default.bold("Install:"));
192
193
  console.log(chalk_1.default.white(` ${skill.installCommand}`));
193
194
  }
194
- console.log(chalk_1.default.gray(`\nRun 'ortho skills add ${skill.slug}' to add locally`));
195
+ console.log(chalk_1.default.gray(`\nRun 'orth skills add ${skill.slug}' to add locally`));
195
196
  }
196
197
  catch (error) {
197
198
  spinner.stop();
@@ -200,7 +201,7 @@ async function skillsShowCommand(slug) {
200
201
  }
201
202
  }
202
203
  // ─────────────────────────────────────────────────────────────────────────────
203
- // ortho skills create <githubRepo>
204
+ // orth skills create <githubRepo>
204
205
  // ─────────────────────────────────────────────────────────────────────────────
205
206
  async function skillsCreateCommand(githubRepo, options) {
206
207
  const spinner = (0, ora_1.default)("Creating skill from GitHub...").start();
@@ -242,7 +243,7 @@ async function skillsCreateCommand(githubRepo, options) {
242
243
  console.log(chalk_1.default.gray(` ${data.skill.description}`));
243
244
  }
244
245
  console.log(chalk_1.default.bold("\nYour skill is on the platform but not yet verified."));
245
- console.log(chalk_1.default.white(`To request verification: ${chalk_1.default.cyan(`ortho skills request-verification ${data.skill.slug}`)}`));
246
+ console.log(chalk_1.default.white(`To request verification: ${chalk_1.default.cyan(`orth skills request-verification ${data.skill.slug}`)}`));
246
247
  console.log(chalk_1.default.gray("Once verified, you can toggle discoverability anytime."));
247
248
  }
248
249
  catch (error) {
@@ -252,7 +253,7 @@ async function skillsCreateCommand(githubRepo, options) {
252
253
  }
253
254
  }
254
255
  // ─────────────────────────────────────────────────────────────────────────────
255
- // ortho skills add <slug>
256
+ // orth skills add <slug>
256
257
  // ─────────────────────────────────────────────────────────────────────────────
257
258
  async function skillsInstallCommand(slug, options) {
258
259
  const spinner = (0, ora_1.default)("Fetching skill...").start();
@@ -333,7 +334,7 @@ async function skillsInstallCommand(slug, options) {
333
334
  }
334
335
  }
335
336
  // ─────────────────────────────────────────────────────────────────────────────
336
- // ortho skills init [name]
337
+ // orth skills init [name]
337
338
  // ─────────────────────────────────────────────────────────────────────────────
338
339
  // Known binary/large file extensions to skip when reading local files
339
340
  const SKIP_EXTENSIONS = new Set([
@@ -419,7 +420,7 @@ Describe the next step.
419
420
  console.log(chalk_1.default.bold("\nNext steps:"));
420
421
  console.log(chalk_1.default.white(" 1. Edit SKILL.md with your skill's instructions"));
421
422
  console.log(chalk_1.default.white(" 2. Add any supporting files to scripts/, references/, or assets/"));
422
- console.log(chalk_1.default.white(` 3. Submit to Orthogonal: ${chalk_1.default.cyan(`ortho skills submit ${dirPath}`)}`));
423
+ console.log(chalk_1.default.white(` 3. Submit to Orthogonal: ${chalk_1.default.cyan(`orth skills submit ${dirPath}`)}`));
423
424
  }
424
425
  catch (error) {
425
426
  console.error(chalk_1.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
@@ -427,7 +428,7 @@ Describe the next step.
427
428
  }
428
429
  }
429
430
  // ─────────────────────────────────────────────────────────────────────────────
430
- // ortho skills submit [path]
431
+ // orth skills submit [path]
431
432
  // ─────────────────────────────────────────────────────────────────────────────
432
433
  function readFilesRecursive(dirPath, basePath = "") {
433
434
  const files = [];
@@ -508,7 +509,7 @@ async function skillsSubmitCommand(inputPath, options) {
508
509
  if (!primaryFile) {
509
510
  spinner.stop();
510
511
  console.error(chalk_1.default.red("Error: No SKILL.md found in the root of the directory"));
511
- console.log(chalk_1.default.gray("Run 'ortho skills init' to create a skill template"));
512
+ console.log(chalk_1.default.gray("Run 'orth skills init' to create a skill template"));
512
513
  process.exit(1);
513
514
  }
514
515
  // Parse frontmatter
@@ -565,7 +566,7 @@ async function skillsSubmitCommand(inputPath, options) {
565
566
  console.log(chalk_1.default.gray(` ${data.skill.description.slice(0, 100)}`));
566
567
  }
567
568
  console.log(chalk_1.default.bold("\nYour skill is on the platform but not yet verified."));
568
- console.log(chalk_1.default.white(`To request verification: ${chalk_1.default.cyan(`ortho skills request-verification ${data.skill.slug}`)}`));
569
+ console.log(chalk_1.default.white(`To request verification: ${chalk_1.default.cyan(`orth skills request-verification ${data.skill.slug}`)}`));
569
570
  console.log(chalk_1.default.gray("Once verified, you can toggle discoverability anytime."));
570
571
  console.log(chalk_1.default.gray(`Dashboard: https://orthogonal.com/dashboard/skills`));
571
572
  }
@@ -576,7 +577,88 @@ async function skillsSubmitCommand(inputPath, options) {
576
577
  }
577
578
  }
578
579
  // ─────────────────────────────────────────────────────────────────────────────
579
- // ortho skills request-verification <slug>
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
+ // ─────────────────────────────────────────────────────────────────────────────
661
+ // orth skills request-verification <slug>
580
662
  // ─────────────────────────────────────────────────────────────────────────────
581
663
  async function skillsRequestVerificationCommand(slug) {
582
664
  const spinner = (0, ora_1.default)("Submitting verification request...").start();
@@ -604,16 +686,16 @@ async function skillsRequestVerificationCommand(slug) {
604
686
  }
605
687
  }
606
688
  // ─────────────────────────────────────────────────────────────────────────────
607
- // ortho skills publish <slug> (deprecated - redirects to request-verification)
689
+ // orth skills publish <slug> (deprecated - redirects to request-verification)
608
690
  // ─────────────────────────────────────────────────────────────────────────────
609
691
  async function skillsPublishCommand(slug, options) {
610
692
  console.log(chalk_1.default.yellow("Note: Direct publishing has been replaced with a verification workflow."));
611
- console.log(chalk_1.default.white(`\nTo request your skill to be verified, run:\n ${chalk_1.default.cyan(`ortho skills request-verification ${slug}`)}`));
693
+ console.log(chalk_1.default.white(`\nTo request your skill to be verified, run:\n ${chalk_1.default.cyan(`orth skills request-verification ${slug}`)}`));
612
694
  console.log(chalk_1.default.white("Once verified, you can toggle discoverability from your dashboard."));
613
695
  console.log(chalk_1.default.gray("\nOr manage from the dashboard: https://orthogonal.com/dashboard/skills"));
614
696
  }
615
697
  // ─────────────────────────────────────────────────────────────────────────────
616
- // ortho skills request <input>
698
+ // orth skills request <input>
617
699
  // ─────────────────────────────────────────────────────────────────────────────
618
700
  async function skillsRequestCommand(input) {
619
701
  const spinner = (0, ora_1.default)("Submitting skill request...").start();
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)")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orth/cli",
3
- "version": "0.2.2",
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": {