import { createInterface } from "readline"; import chalk from "chalk"; import { writeConfig, readConfig, getRegistryUrl } from "../lib/config.js"; export async function loginCommand(options: { credential?: string; registryUrl?: string; }): Promise { const registryUrl = options.registryUrl ?? getRegistryUrl(); let credential = options.credential; if (!credential) { credential = await promptHidden( "Enter your publish credential (psk_ns_*): " ); } if (!credential || credential.trim().length === 0) { console.error(chalk.red("Error: credential cannot be empty.")); process.exit(1); } credential = credential.trim(); if (!credential.startsWith("psk_ns_")) { console.error( chalk.red( "Error: credential must start with psk_ns_.\n" + " Get yours at https://www.paperclipskills.com/publisher" ) ); process.exit(1); } writeConfig({ token: credential, registryUrl: options.registryUrl ?? registryUrl, savedAt: new Date().toISOString(), }); console.log( chalk.green("✓ Credential saved to ~/.paperclip-skills/config.json") ); console.log( chalk.dim( " Run `npx paperclip-skills publish` to publish your first skill." ) ); } function promptHidden(question: string): Promise { return new Promise((resolve) => { const rl = createInterface({ input: process.stdin, output: process.stdout, }); if (process.stdout.isTTY) { process.stdout.write(question); process.stdin.setRawMode?.(true); let chars = ""; process.stdin.resume(); process.stdin.setEncoding("utf8"); process.stdin.on("data", function onData(char: string) { if (char === "\r" || char === "\n") { process.stdin.setRawMode?.(false); process.stdin.removeListener("data", onData); process.stdout.write("\n"); rl.close(); resolve(chars); } else if (char === "\u0003") { process.exit(); } else if (char === "\u007f") { chars = chars.slice(0, -1); } else { chars += char; } }); } else { rl.question(question, (answer) => { rl.close(); resolve(answer); }); } }); }