@skillport/cli 0.1.2 → 0.1.4

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 +33 -14
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ var __export = (target, all) => {
10
10
  };
11
11
 
12
12
  // ../../packages/shared/dist/constants.js
13
- var SP_VERSION, SP_CONFIG_DIR, SP_KEYS_DIR, SP_AUDIT_DIR, SP_CONFIG_FILE, SP_REGISTRY_FILE, OPENCLAW_SKILLS_DIR, DEFAULT_MARKETPLACE_URL;
13
+ var SP_VERSION, SP_CONFIG_DIR, SP_KEYS_DIR, SP_AUDIT_DIR, SP_CONFIG_FILE, SP_REGISTRY_FILE, OPENCLAW_SKILLS_DIR, DEFAULT_MARKETPLACE_URL, DEFAULT_MARKETPLACE_WEB_URL;
14
14
  var init_constants = __esm({
15
15
  "../../packages/shared/dist/constants.js"() {
16
16
  "use strict";
@@ -22,6 +22,7 @@ var init_constants = __esm({
22
22
  SP_REGISTRY_FILE = "installed/registry.json";
23
23
  OPENCLAW_SKILLS_DIR = ".openclaw/skills";
24
24
  DEFAULT_MARKETPLACE_URL = "https://api.skillport.market";
25
+ DEFAULT_MARKETPLACE_WEB_URL = "https://skillport.market";
25
26
  }
26
27
  });
27
28
 
@@ -77,9 +78,16 @@ function registryPath() {
77
78
  function loadConfig() {
78
79
  const path = configPath();
79
80
  if (!existsSync(path)) {
80
- return { marketplace_url: DEFAULT_MARKETPLACE_URL };
81
+ return {
82
+ marketplace_url: DEFAULT_MARKETPLACE_URL,
83
+ marketplace_web_url: DEFAULT_MARKETPLACE_WEB_URL
84
+ };
81
85
  }
82
- return JSON.parse(readFileSync(path, "utf-8"));
86
+ const raw = JSON.parse(readFileSync(path, "utf-8"));
87
+ if (!raw.marketplace_web_url) {
88
+ raw.marketplace_web_url = DEFAULT_MARKETPLACE_WEB_URL;
89
+ }
90
+ return raw;
83
91
  }
84
92
  function saveConfig(config) {
85
93
  ensureConfigDirs();
@@ -2496,10 +2504,11 @@ import { createServer } from "node:http";
2496
2504
  import { randomBytes } from "node:crypto";
2497
2505
  import chalk9 from "chalk";
2498
2506
  import inquirer4 from "inquirer";
2499
- function listenOnPort(server, port) {
2507
+ var DEFAULT_HOST = "127.0.0.1";
2508
+ function listenOnPort(server, port, host) {
2500
2509
  return new Promise((resolve, reject) => {
2501
2510
  server.once("error", reject);
2502
- server.listen(port, () => {
2511
+ server.listen(port, host, () => {
2503
2512
  server.removeListener("error", reject);
2504
2513
  const addr = server.address();
2505
2514
  resolve(addr.port);
@@ -2509,7 +2518,7 @@ function listenOnPort(server, port) {
2509
2518
  async function loginCommand(options) {
2510
2519
  const config = loadConfig();
2511
2520
  console.log(chalk9.bold("SkillPort Market Login"));
2512
- console.log(chalk9.dim(`Marketplace: ${config.marketplace_url}`));
2521
+ console.log(chalk9.dim(`Marketplace: ${config.marketplace_web_url}`));
2513
2522
  console.log();
2514
2523
  let method = options.method;
2515
2524
  if (options.token) {
@@ -2545,28 +2554,32 @@ async function loginCommand(options) {
2545
2554
  const state = randomBytes(16).toString("hex");
2546
2555
  const requestedPort = options.port !== void 0 ? parseInt(options.port, 10) : 9876;
2547
2556
  const userExplicitPort = options.port !== void 0;
2557
+ const bindHost = options.host || DEFAULT_HOST;
2548
2558
  const server = createServer();
2549
2559
  let actualPort;
2550
2560
  try {
2551
- actualPort = await listenOnPort(server, requestedPort);
2561
+ actualPort = await listenOnPort(server, requestedPort, bindHost);
2552
2562
  } catch (err) {
2553
2563
  const code = err.code;
2554
2564
  if (code === "EADDRINUSE" && !userExplicitPort) {
2555
2565
  console.log(chalk9.yellow(`Port ${requestedPort} in use, selecting a free port...`));
2556
- actualPort = await listenOnPort(server, 0);
2566
+ actualPort = await listenOnPort(server, 0, bindHost);
2557
2567
  } else {
2558
2568
  throw err;
2559
2569
  }
2560
2570
  }
2561
- const authUrl = `${config.marketplace_url}/auth/cli?state=${state}&port=${actualPort}`;
2571
+ const callbackHost = bindHost === "::1" ? "[::1]" : bindHost;
2572
+ const authUrl = `${config.marketplace_web_url}/auth/cli?state=${state}&port=${actualPort}&host=${encodeURIComponent(callbackHost)}`;
2562
2573
  if (options.browser === false) {
2563
2574
  console.log(chalk9.bold("Open this URL in your browser to authenticate:"));
2564
2575
  console.log();
2565
2576
  console.log(` ${authUrl}`);
2566
2577
  console.log();
2578
+ console.log(chalk9.dim(`Listening on ${callbackHost}:${actualPort}`));
2567
2579
  console.log(chalk9.dim("Waiting for authentication callback..."));
2568
2580
  } else {
2569
2581
  console.log(chalk9.dim(`Opening browser to: ${authUrl}`));
2582
+ console.log(chalk9.dim(`Listening on ${callbackHost}:${actualPort}`));
2570
2583
  console.log(chalk9.dim("Waiting for authentication..."));
2571
2584
  const { exec } = await import("node:child_process");
2572
2585
  const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
@@ -2575,10 +2588,16 @@ async function loginCommand(options) {
2575
2588
  const token = await new Promise((resolve, reject) => {
2576
2589
  const timeout = setTimeout(() => {
2577
2590
  server.close();
2578
- reject(new Error("Authentication timed out (60s). Try again or use: skillport login --method token --token <your-token>"));
2591
+ reject(new Error(
2592
+ `Authentication timed out (60s).
2593
+ Listened on: ${callbackHost}:${actualPort}
2594
+ Self-test: curl http://${callbackHost}:${actualPort}/callback?state=test\\&token=test
2595
+ Retry: skillport login --yes --no-browser --port 0 --host 127.0.0.1
2596
+ Or use: skillport login --method token --token <your-token>`
2597
+ ));
2579
2598
  }, 6e4);
2580
2599
  server.on("request", (req, res) => {
2581
- const url = new URL(req.url || "", `http://localhost:${actualPort}`);
2600
+ const url = new URL(req.url || "", `http://${callbackHost}:${actualPort}`);
2582
2601
  if (url.pathname === "/callback") {
2583
2602
  const callbackState = url.searchParams.get("state");
2584
2603
  const accessToken = url.searchParams.get("token");
@@ -2710,7 +2729,7 @@ async function publishCommand(sspPath) {
2710
2729
  console.log(` ${chalk10.bold("Scan:")} ${result.scan_passed ? chalk10.green("PASSED") : chalk10.red("FAILED")}`);
2711
2730
  console.log(` ${chalk10.bold("Risk Score:")} ${result.risk_score}/100`);
2712
2731
  console.log();
2713
- console.log(chalk10.dim(` URL: ${config.marketplace_url}/skills/${result.id}`));
2732
+ console.log(chalk10.dim(` URL: ${config.marketplace_web_url}/skills/${result.id}`));
2714
2733
  console.log(chalk10.dim(` Install: skillport install ${result.ssp_id}@${result.version}`));
2715
2734
  } catch (error) {
2716
2735
  console.log(chalk10.red(`Upload failed: ${error.message}`));
@@ -2720,7 +2739,7 @@ async function publishCommand(sspPath) {
2720
2739
 
2721
2740
  // src/index.ts
2722
2741
  var program = new Command();
2723
- program.name("skillport").description("SkillPort \u2014 secure skill distribution for OpenClaw").version("0.1.2");
2742
+ program.name("skillport").description("SkillPort \u2014 secure skill distribution for OpenClaw").version("0.1.4");
2724
2743
  program.command("init").description("Generate Ed25519 key pair for signing").action(initCommand);
2725
2744
  program.command("scan <path>").description("Run security scan on a skill directory or .ssp file").action(scanCommand);
2726
2745
  program.command("export <path>").description("Export a skill directory as a SkillPort package (.ssp)").option("-o, --output <file>", "Output file path").option("-y, --yes", "Non-interactive mode (include all, skip prompts)").option("--id <id>", "Skill ID (author-slug/skill-slug)").option("--name <name>", "Skill name").option("--description <desc>", "Skill description").option("--skill-version <ver>", "Skill version (semver)").option("--author <name>", "Author name").option("--openclaw-compat <range>", "OpenClaw compatibility range").option("--os <os...>", "Compatible OS (macos, linux, windows)").action(exportCommand);
@@ -2729,6 +2748,6 @@ program.command("verify <ssp>").description("Verify SkillPort package signatures
2729
2748
  program.command("install <target>").description("Install a SkillPort package").option("--accept-risk", "Accept high-risk permissions (shell, critical flags)").option("-y, --yes", "Non-interactive mode (auto-approve, use defaults)").action(installCommand);
2730
2749
  program.command("dry-run <ssp>").description("Run installation diagnostics without installing").action(dryRunCommand);
2731
2750
  program.command("uninstall <id>").description("Uninstall an installed skill").action(uninstallCommand);
2732
- program.command("login").description("Authenticate with SkillPort Market").option("--method <method>", "Login method: browser or token", "browser").option("--token <token>", "API token (for --method token)").option("-y, --yes", "Non-interactive mode (skip prompts)").option("--no-browser", "Print auth URL instead of opening browser").option("--port <port>", "Callback port (default: 9876, use 0 for auto)").action(loginCommand);
2751
+ program.command("login").description("Authenticate with SkillPort Market").option("--method <method>", "Login method: browser or token", "browser").option("--token <token>", "API token (for --method token)").option("-y, --yes", "Non-interactive mode (skip prompts)").option("--no-browser", "Print auth URL instead of opening browser").option("--port <port>", "Callback port (default: 9876, use 0 for auto)").option("--host <host>", "Callback host (default: 127.0.0.1)").action(loginCommand);
2733
2752
  program.command("publish <ssp>").description("Publish a SkillPort package to the marketplace").action(publishCommand);
2734
2753
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skillport/cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "SkillPort CLI — secure skill distribution for OpenClaw. Export, scan, sign, and install AI skill packages.",
5
5
  "type": "module",
6
6
  "license": "MIT",