// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 const fs = require("fs"); const path = require("path"); const readline = require("readline"); const { execSync } = require("child_process"); const CREDS_DIR = path.join(process.env.HOME || "/tmp", ".iniclaw"); const CREDS_FILE = path.join(CREDS_DIR, "credentials.json"); function loadCredentials() { try { if (fs.existsSync(CREDS_FILE)) { return JSON.parse(fs.readFileSync(CREDS_FILE, "utf-8")); } } catch {} return {}; } function saveCredential(key, value) { fs.mkdirSync(CREDS_DIR, { recursive: true, mode: 0o700 }); const creds = loadCredentials(); creds[key] = value; fs.writeFileSync(CREDS_FILE, JSON.stringify(creds, null, 2), { mode: 0o600 }); } function getCredential(key) { if (process.env[key]) return process.env[key]; const creds = loadCredentials(); return creds[key] || null; } function prompt(question) { return new Promise((resolve) => { const rl = readline.createInterface({ input: process.stdin, output: process.stderr }); rl.question(question, (answer) => { rl.close(); resolve(answer.trim()); }); }); } async function ensureApiKey() { let key = getCredential("NVIDIA_API_KEY"); if (key) { process.env.NVIDIA_API_KEY = key; return; } console.log(""); console.log(" ┌─────────────────────────────────────────────────────────────────┐"); console.log(" │ API Key required │"); console.log(" │ │"); console.log(" │ 1. Go to your AI provider's dashboard │"); console.log(" │ 2. Generate or copy your API key │"); console.log(" │ 3. Paste the key below │"); console.log(" └─────────────────────────────────────────────────────────────────┘"); console.log(""); key = await prompt(" API Key: "); if (!key) { console.error(" Invalid key. Key cannot be empty."); process.exit(1); } saveCredential("NVIDIA_API_KEY", key); process.env.NVIDIA_API_KEY = key; console.log(""); console.log(" Key saved to ~/.iniclaw/credentials.json (mode 600)"); console.log(""); } function isRepoPrivate(repo) { try { const json = execSync(`gh api repos/${repo} --jq .private 2>/dev/null`, { encoding: "utf-8" }).trim(); return json === "true"; } catch { return false; } } async function ensureGithubToken() { let token = getCredential("GITHUB_TOKEN"); if (token) { process.env.GITHUB_TOKEN = token; return; } try { token = execSync("gh auth token 2>/dev/null", { encoding: "utf-8" }).trim(); if (token) { process.env.GITHUB_TOKEN = token; return; } } catch {} console.log(""); console.log(" ┌──────────────────────────────────────────────────┐"); console.log(" │ GitHub token required (private repo detected) │"); console.log(" │ │"); console.log(" │ Option A: gh auth login (if you have gh CLI) │"); console.log(" │ Option B: Paste a PAT with read:packages scope │"); console.log(" └──────────────────────────────────────────────────┘"); console.log(""); token = await prompt(" GitHub Token: "); if (!token) { console.error(" Token required for deploy (repo is private)."); process.exit(1); } saveCredential("GITHUB_TOKEN", token); process.env.GITHUB_TOKEN = token; console.log(""); console.log(" Token saved to ~/.iniclaw/credentials.json (mode 600)"); console.log(""); } module.exports = { CREDS_DIR, CREDS_FILE, loadCredentials, saveCredential, getCredential, prompt, ensureApiKey, ensureGithubToken, isRepoPrivate, };