|
| 1 | +#!/usr/bin/env node |
| 2 | + |
| 3 | +import { readFileSync } from 'node:fs'; |
| 4 | +import path from 'node:path'; |
| 5 | +import { fileURLToPath, pathToFileURL } from 'node:url'; |
| 6 | + |
| 7 | +const __filename = fileURLToPath(import.meta.url); |
| 8 | +const __dirname = path.dirname(__filename); |
| 9 | +const packagePath = path.resolve(__dirname, '..', 'package.json'); |
| 10 | +const packageJson = JSON.parse(readFileSync(packagePath, 'utf8')); |
| 11 | + |
| 12 | +const HELP = `skill-publish CLI |
| 13 | +
|
| 14 | +Usage: |
| 15 | + npx skill-publish --api-key <key> --skill-dir <dir> [options] |
| 16 | +
|
| 17 | +Required: |
| 18 | + --api-key <key> Registry Broker API key (or use RB_API_KEY env var) |
| 19 | + --skill-dir <dir> Skill package directory containing SKILL.md + skill.json |
| 20 | +
|
| 21 | +Options: |
| 22 | + --api-base-url <url> Broker API base URL (default: https://hol.org/registry/api/v1) |
| 23 | + --account-id <id> Optional Hedera account ID |
| 24 | + --name <name> Optional skill name override |
| 25 | + --version <version> Optional skill version override |
| 26 | + --annotate <bool> Enable GitHub annotation behavior (default: false for CLI) |
| 27 | + --no-annotate Disable GitHub annotations |
| 28 | + --github-token <token> GitHub token for annotations |
| 29 | + --stamp-repo-commit <bool> Stamp repo/commit fields (default: true) |
| 30 | + --no-stamp-repo-commit Disable repo/commit stamping |
| 31 | + --poll-timeout-ms <ms> Publish poll timeout (default: 720000) |
| 32 | + --poll-interval-ms <ms> Publish poll interval (default: 4000) |
| 33 | + --help Show this help |
| 34 | + -v Show CLI version |
| 35 | +
|
| 36 | +Examples: |
| 37 | + RB_API_KEY=rbk_xxx npx skill-publish --skill-dir ./skills/my-skill |
| 38 | + npx skill-publish --api-key rbk_xxx --skill-dir ./skills/my-skill --version 1.2.3 |
| 39 | +`; |
| 40 | + |
| 41 | +const FLAG_ENV_MAP = new Map([ |
| 42 | + ['--api-base-url', 'INPUT_API_BASE_URL'], |
| 43 | + ['--api-key', 'INPUT_API_KEY'], |
| 44 | + ['--account-id', 'INPUT_ACCOUNT_ID'], |
| 45 | + ['--skill-dir', 'INPUT_SKILL_DIR'], |
| 46 | + ['--name', 'INPUT_NAME'], |
| 47 | + ['--version', 'INPUT_VERSION'], |
| 48 | + ['--stamp-repo-commit', 'INPUT_STAMP_REPO_COMMIT'], |
| 49 | + ['--poll-timeout-ms', 'INPUT_POLL_TIMEOUT_MS'], |
| 50 | + ['--poll-interval-ms', 'INPUT_POLL_INTERVAL_MS'], |
| 51 | + ['--annotate', 'INPUT_ANNOTATE'], |
| 52 | + ['--github-token', 'INPUT_GITHUB_TOKEN'], |
| 53 | +]); |
| 54 | + |
| 55 | +const BOOLEAN_FLAGS = new Set(['--annotate', '--stamp-repo-commit']); |
| 56 | + |
| 57 | +function fail(message) { |
| 58 | + process.stderr.write(`Error: ${message}\n`); |
| 59 | + process.stderr.write('Run `npx skill-publish --help` for usage.\n'); |
| 60 | + process.exit(1); |
| 61 | +} |
| 62 | + |
| 63 | +function parseArgs(args) { |
| 64 | + for (let index = 0; index < args.length; index += 1) { |
| 65 | + const arg = args[index]; |
| 66 | + |
| 67 | + if (arg === '--help' || arg === '-h') { |
| 68 | + process.stdout.write(`${HELP}\n`); |
| 69 | + process.exit(0); |
| 70 | + } |
| 71 | + |
| 72 | + if (arg === '-v') { |
| 73 | + process.stdout.write(`${String(packageJson.version)}\n`); |
| 74 | + process.exit(0); |
| 75 | + } |
| 76 | + |
| 77 | + if (arg === '--version') { |
| 78 | + const next = args[index + 1]; |
| 79 | + if (!next || next.startsWith('--')) { |
| 80 | + process.stdout.write(`${String(packageJson.version)}\n`); |
| 81 | + process.exit(0); |
| 82 | + } |
| 83 | + } |
| 84 | + |
| 85 | + if (arg.startsWith('--no-')) { |
| 86 | + const positive = `--${arg.slice(5)}`; |
| 87 | + if (!BOOLEAN_FLAGS.has(positive)) { |
| 88 | + fail(`Unknown flag: ${arg}`); |
| 89 | + } |
| 90 | + process.env[FLAG_ENV_MAP.get(positive)] = 'false'; |
| 91 | + continue; |
| 92 | + } |
| 93 | + |
| 94 | + let key = arg; |
| 95 | + let value = ''; |
| 96 | + if (arg.startsWith('--') && arg.includes('=')) { |
| 97 | + const splitIndex = arg.indexOf('='); |
| 98 | + key = arg.slice(0, splitIndex); |
| 99 | + value = arg.slice(splitIndex + 1); |
| 100 | + } |
| 101 | + |
| 102 | + if (!FLAG_ENV_MAP.has(key)) { |
| 103 | + fail(`Unknown flag: ${key}`); |
| 104 | + } |
| 105 | + |
| 106 | + if (arg.includes('=')) { |
| 107 | + process.env[FLAG_ENV_MAP.get(key)] = value; |
| 108 | + continue; |
| 109 | + } |
| 110 | + |
| 111 | + const next = args[index + 1]; |
| 112 | + if (next && !next.startsWith('--')) { |
| 113 | + process.env[FLAG_ENV_MAP.get(key)] = next; |
| 114 | + index += 1; |
| 115 | + continue; |
| 116 | + } |
| 117 | + |
| 118 | + if (BOOLEAN_FLAGS.has(key)) { |
| 119 | + process.env[FLAG_ENV_MAP.get(key)] = 'true'; |
| 120 | + continue; |
| 121 | + } |
| 122 | + |
| 123 | + fail(`Missing value for ${key}`); |
| 124 | + } |
| 125 | +} |
| 126 | + |
| 127 | +function applyDefaults() { |
| 128 | + if (!process.env.INPUT_API_KEY && process.env.RB_API_KEY) { |
| 129 | + process.env.INPUT_API_KEY = process.env.RB_API_KEY; |
| 130 | + } |
| 131 | + if (!process.env.INPUT_SKILL_DIR) { |
| 132 | + process.env.INPUT_SKILL_DIR = '.'; |
| 133 | + } |
| 134 | + if (!process.env.INPUT_ANNOTATE) { |
| 135 | + process.env.INPUT_ANNOTATE = 'false'; |
| 136 | + } |
| 137 | + if (!process.env.INPUT_STAMP_REPO_COMMIT) { |
| 138 | + process.env.INPUT_STAMP_REPO_COMMIT = 'true'; |
| 139 | + } |
| 140 | + if (!process.env.INPUT_POLL_TIMEOUT_MS) { |
| 141 | + process.env.INPUT_POLL_TIMEOUT_MS = '720000'; |
| 142 | + } |
| 143 | + if (!process.env.INPUT_POLL_INTERVAL_MS) { |
| 144 | + process.env.INPUT_POLL_INTERVAL_MS = '4000'; |
| 145 | + } |
| 146 | +} |
| 147 | + |
| 148 | +async function run() { |
| 149 | + parseArgs(process.argv.slice(2)); |
| 150 | + applyDefaults(); |
| 151 | + |
| 152 | + if (!process.env.INPUT_API_KEY) { |
| 153 | + fail('Missing API key. Pass --api-key or set RB_API_KEY.'); |
| 154 | + } |
| 155 | + |
| 156 | + const entrypointUrl = pathToFileURL( |
| 157 | + path.resolve(__dirname, '..', 'entrypoint.mjs'), |
| 158 | + ).href; |
| 159 | + await import(entrypointUrl); |
| 160 | +} |
| 161 | + |
| 162 | +run().catch((error) => { |
| 163 | + const message = error instanceof Error ? error.message : String(error); |
| 164 | + process.stderr.write(`Error: ${message}\n`); |
| 165 | + process.exit(1); |
| 166 | +}); |
0 commit comments