@skillport/cli 0.1.0 → 0.1.2
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/dist/index.js +70 -28
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2496,46 +2496,89 @@ import { createServer } from "node:http";
|
|
|
2496
2496
|
import { randomBytes } from "node:crypto";
|
|
2497
2497
|
import chalk9 from "chalk";
|
|
2498
2498
|
import inquirer4 from "inquirer";
|
|
2499
|
-
|
|
2499
|
+
function listenOnPort(server, port) {
|
|
2500
|
+
return new Promise((resolve, reject) => {
|
|
2501
|
+
server.once("error", reject);
|
|
2502
|
+
server.listen(port, () => {
|
|
2503
|
+
server.removeListener("error", reject);
|
|
2504
|
+
const addr = server.address();
|
|
2505
|
+
resolve(addr.port);
|
|
2506
|
+
});
|
|
2507
|
+
});
|
|
2508
|
+
}
|
|
2509
|
+
async function loginCommand(options) {
|
|
2500
2510
|
const config = loadConfig();
|
|
2501
2511
|
console.log(chalk9.bold("SkillPort Market Login"));
|
|
2502
2512
|
console.log(chalk9.dim(`Marketplace: ${config.marketplace_url}`));
|
|
2503
2513
|
console.log();
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2514
|
+
let method = options.method;
|
|
2515
|
+
if (options.token) {
|
|
2516
|
+
method = "token";
|
|
2517
|
+
}
|
|
2518
|
+
if (!options.yes && method === "browser" && !options.token) {
|
|
2519
|
+
const answer = await inquirer4.prompt([
|
|
2520
|
+
{
|
|
2521
|
+
type: "list",
|
|
2522
|
+
name: "method",
|
|
2523
|
+
message: "Login method:",
|
|
2524
|
+
choices: [
|
|
2525
|
+
{ name: "Browser (GitHub OAuth)", value: "browser" },
|
|
2526
|
+
{ name: "Paste API token", value: "token" }
|
|
2527
|
+
]
|
|
2528
|
+
}
|
|
2518
2529
|
]);
|
|
2530
|
+
method = answer.method;
|
|
2531
|
+
}
|
|
2532
|
+
if (method === "token") {
|
|
2533
|
+
let token2 = options.token;
|
|
2534
|
+
if (!token2) {
|
|
2535
|
+
const answer = await inquirer4.prompt([
|
|
2536
|
+
{ type: "password", name: "token", message: "Enter your API token:" }
|
|
2537
|
+
]);
|
|
2538
|
+
token2 = answer.token;
|
|
2539
|
+
}
|
|
2519
2540
|
config.auth_token = token2;
|
|
2520
2541
|
saveConfig(config);
|
|
2521
2542
|
console.log(chalk9.green("Login successful! Token saved."));
|
|
2522
2543
|
return;
|
|
2523
2544
|
}
|
|
2524
2545
|
const state = randomBytes(16).toString("hex");
|
|
2525
|
-
const
|
|
2526
|
-
const
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2546
|
+
const requestedPort = options.port !== void 0 ? parseInt(options.port, 10) : 9876;
|
|
2547
|
+
const userExplicitPort = options.port !== void 0;
|
|
2548
|
+
const server = createServer();
|
|
2549
|
+
let actualPort;
|
|
2550
|
+
try {
|
|
2551
|
+
actualPort = await listenOnPort(server, requestedPort);
|
|
2552
|
+
} catch (err) {
|
|
2553
|
+
const code = err.code;
|
|
2554
|
+
if (code === "EADDRINUSE" && !userExplicitPort) {
|
|
2555
|
+
console.log(chalk9.yellow(`Port ${requestedPort} in use, selecting a free port...`));
|
|
2556
|
+
actualPort = await listenOnPort(server, 0);
|
|
2557
|
+
} else {
|
|
2558
|
+
throw err;
|
|
2559
|
+
}
|
|
2560
|
+
}
|
|
2561
|
+
const authUrl = `${config.marketplace_url}/auth/cli?state=${state}&port=${actualPort}`;
|
|
2562
|
+
if (options.browser === false) {
|
|
2563
|
+
console.log(chalk9.bold("Open this URL in your browser to authenticate:"));
|
|
2564
|
+
console.log();
|
|
2565
|
+
console.log(` ${authUrl}`);
|
|
2566
|
+
console.log();
|
|
2567
|
+
console.log(chalk9.dim("Waiting for authentication callback..."));
|
|
2568
|
+
} else {
|
|
2569
|
+
console.log(chalk9.dim(`Opening browser to: ${authUrl}`));
|
|
2570
|
+
console.log(chalk9.dim("Waiting for authentication..."));
|
|
2571
|
+
const { exec } = await import("node:child_process");
|
|
2572
|
+
const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
2573
|
+
exec(`${openCmd} "${authUrl}"`);
|
|
2574
|
+
}
|
|
2532
2575
|
const token = await new Promise((resolve, reject) => {
|
|
2533
2576
|
const timeout = setTimeout(() => {
|
|
2534
2577
|
server.close();
|
|
2535
|
-
reject(new Error("Authentication timed out (60s)"));
|
|
2578
|
+
reject(new Error("Authentication timed out (60s). Try again or use: skillport login --method token --token <your-token>"));
|
|
2536
2579
|
}, 6e4);
|
|
2537
|
-
|
|
2538
|
-
const url = new URL(req.url || "", `http://localhost:${
|
|
2580
|
+
server.on("request", (req, res) => {
|
|
2581
|
+
const url = new URL(req.url || "", `http://localhost:${actualPort}`);
|
|
2539
2582
|
if (url.pathname === "/callback") {
|
|
2540
2583
|
const callbackState = url.searchParams.get("state");
|
|
2541
2584
|
const accessToken = url.searchParams.get("token");
|
|
@@ -2556,7 +2599,6 @@ async function loginCommand() {
|
|
|
2556
2599
|
resolve(accessToken);
|
|
2557
2600
|
}
|
|
2558
2601
|
});
|
|
2559
|
-
server.listen(port);
|
|
2560
2602
|
});
|
|
2561
2603
|
try {
|
|
2562
2604
|
const response = await fetch(`${config.marketplace_url}/v1/auth/cli-token`, {
|
|
@@ -2678,7 +2720,7 @@ async function publishCommand(sspPath) {
|
|
|
2678
2720
|
|
|
2679
2721
|
// src/index.ts
|
|
2680
2722
|
var program = new Command();
|
|
2681
|
-
program.name("skillport").description("SkillPort \u2014 secure skill distribution for OpenClaw").version("0.1.
|
|
2723
|
+
program.name("skillport").description("SkillPort \u2014 secure skill distribution for OpenClaw").version("0.1.2");
|
|
2682
2724
|
program.command("init").description("Generate Ed25519 key pair for signing").action(initCommand);
|
|
2683
2725
|
program.command("scan <path>").description("Run security scan on a skill directory or .ssp file").action(scanCommand);
|
|
2684
2726
|
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);
|
|
@@ -2687,6 +2729,6 @@ program.command("verify <ssp>").description("Verify SkillPort package signatures
|
|
|
2687
2729
|
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);
|
|
2688
2730
|
program.command("dry-run <ssp>").description("Run installation diagnostics without installing").action(dryRunCommand);
|
|
2689
2731
|
program.command("uninstall <id>").description("Uninstall an installed skill").action(uninstallCommand);
|
|
2690
|
-
program.command("login").description("Authenticate with SkillPort Market").action(loginCommand);
|
|
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);
|
|
2691
2733
|
program.command("publish <ssp>").description("Publish a SkillPort package to the marketplace").action(publishCommand);
|
|
2692
2734
|
program.parse();
|
package/package.json
CHANGED