{"version":3,"file":"pods.d.ts","sourceRoot":"","sources":["../../src/commands/pods.ts"],"names":[],"mappings":"AAUA;;GAEG;AACH,eAAO,MAAM,QAAQ,YAyBpB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,QAAQ;;;;mBAgIpB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,wBAa3B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,wBAU5B,CAAC","sourcesContent":["import chalk from \"chalk\";\nimport { dirname, join } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport { addPod, loadConfig, removePod, setActivePod } from \"../config.js\";\nimport { scpFile, sshExec, sshExecStream } from \"../ssh.js\";\nimport type { GPU, Pod } from \"../types.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * List all pods\n */\nexport const listPods = () => {\n\tconst config = loadConfig();\n\tconst podNames = Object.keys(config.pods);\n\n\tif (podNames.length === 0) {\n\t\tconsole.log(\"No pods configured. Use 'pi pods setup' to add a pod.\");\n\t\treturn;\n\t}\n\n\tconsole.log(\"Configured pods:\");\n\tfor (const name of podNames) {\n\t\tconst pod = config.pods[name];\n\t\tconst isActive = config.active === name;\n\t\tconst marker = isActive ? chalk.green(\"*\") : \" \";\n\t\tconst gpuCount = pod.gpus?.length || 0;\n\t\tconst gpuInfo = gpuCount > 0 ? `${gpuCount}x ${pod.gpus[0].name}` : \"no GPUs detected\";\n\t\tconst vllmInfo = pod.vllmVersion ? ` (vLLM: ${pod.vllmVersion})` : \"\";\n\t\tconsole.log(`${marker} ${chalk.bold(name)} - ${gpuInfo}${vllmInfo} - ${pod.ssh}`);\n\t\tif (pod.modelsPath) {\n\t\t\tconsole.log(`    Models: ${pod.modelsPath}`);\n\t\t}\n\t\tif (pod.vllmVersion === \"gpt-oss\") {\n\t\t\tconsole.log(chalk.yellow(`    ⚠️  GPT-OSS build - only for GPT-OSS models`));\n\t\t}\n\t}\n};\n\n/**\n * Setup a new pod\n */\nexport const setupPod = async (\n\tname: string,\n\tsshCmd: string,\n\toptions: { mount?: string; modelsPath?: string; vllm?: \"release\" | \"nightly\" | \"gpt-oss\" },\n) => {\n\t// Validate environment variables\n\tconst hfToken = process.env.HF_TOKEN;\n\tconst vllmApiKey = process.env.PI_API_KEY;\n\n\tif (!hfToken) {\n\t\tconsole.error(chalk.red(\"ERROR: HF_TOKEN environment variable is required\"));\n\t\tconsole.error(\"Get a token from: https://huggingface.co/settings/tokens\");\n\t\tconsole.error(\"Then run: export HF_TOKEN=your_token_here\");\n\t\tprocess.exit(1);\n\t}\n\n\tif (!vllmApiKey) {\n\t\tconsole.error(chalk.red(\"ERROR: PI_API_KEY environment variable is required\"));\n\t\tconsole.error(\"Set an API key: export PI_API_KEY=your_api_key_here\");\n\t\tprocess.exit(1);\n\t}\n\n\t// Determine models path\n\tlet modelsPath = options.modelsPath;\n\tif (!modelsPath && options.mount) {\n\t\t// Extract path from mount command if not explicitly provided\n\t\t// e.g., \"mount -t nfs ... /mnt/sfs\" -> \"/mnt/sfs\"\n\t\tconst parts = options.mount.split(\" \");\n\t\tmodelsPath = parts[parts.length - 1];\n\t}\n\n\tif (!modelsPath) {\n\t\tconsole.error(chalk.red(\"ERROR: --models-path is required (or must be extractable from --mount)\"));\n\t\tprocess.exit(1);\n\t}\n\n\tconsole.log(chalk.green(`Setting up pod '${name}'...`));\n\tconsole.log(`SSH: ${sshCmd}`);\n\tconsole.log(`Models path: ${modelsPath}`);\n\tconsole.log(\n\t\t`vLLM version: ${options.vllm || \"release\"} ${options.vllm === \"gpt-oss\" ? chalk.yellow(\"(GPT-OSS special build)\") : \"\"}`,\n\t);\n\tif (options.mount) {\n\t\tconsole.log(`Mount command: ${options.mount}`);\n\t}\n\tconsole.log(\"\");\n\n\t// Test SSH connection\n\tconsole.log(\"Testing SSH connection...\");\n\tconst testResult = await sshExec(sshCmd, \"echo 'SSH OK'\");\n\tif (testResult.exitCode !== 0) {\n\t\tconsole.error(chalk.red(\"Failed to connect via SSH\"));\n\t\tconsole.error(testResult.stderr);\n\t\tprocess.exit(1);\n\t}\n\tconsole.log(chalk.green(\"✓ SSH connection successful\"));\n\n\t// Copy setup script\n\tconsole.log(\"Copying setup script...\");\n\tconst scriptPath = join(__dirname, \"../../scripts/pod_setup.sh\");\n\tconst success = await scpFile(sshCmd, scriptPath, \"/tmp/pod_setup.sh\");\n\tif (!success) {\n\t\tconsole.error(chalk.red(\"Failed to copy setup script\"));\n\t\tprocess.exit(1);\n\t}\n\tconsole.log(chalk.green(\"✓ Setup script copied\"));\n\n\t// Build setup command\n\tlet setupCmd = `bash /tmp/pod_setup.sh --models-path '${modelsPath}' --hf-token '${hfToken}' --vllm-api-key '${vllmApiKey}'`;\n\tif (options.mount) {\n\t\tsetupCmd += ` --mount '${options.mount}'`;\n\t}\n\t// Add vLLM version flag\n\tconst vllmVersion = options.vllm || \"release\";\n\tsetupCmd += ` --vllm '${vllmVersion}'`;\n\n\t// Run setup script\n\tconsole.log(\"\");\n\tconsole.log(chalk.yellow(\"Running setup (this will take 2-5 minutes)...\"));\n\tconsole.log(\"\");\n\n\t// Use forceTTY to preserve colors from apt, pip, etc.\n\tconst exitCode = await sshExecStream(sshCmd, setupCmd, { forceTTY: true });\n\tif (exitCode !== 0) {\n\t\tconsole.error(chalk.red(\"\\nSetup failed. Check the output above for errors.\"));\n\t\tprocess.exit(1);\n\t}\n\n\t// Parse GPU info from setup output\n\tconsole.log(\"\");\n\tconsole.log(\"Detecting GPU configuration...\");\n\tconst gpuResult = await sshExec(sshCmd, \"nvidia-smi --query-gpu=index,name,memory.total --format=csv,noheader\");\n\n\tconst gpus: GPU[] = [];\n\tif (gpuResult.exitCode === 0 && gpuResult.stdout) {\n\t\tconst lines = gpuResult.stdout.trim().split(\"\\n\");\n\t\tfor (const line of lines) {\n\t\t\tconst [id, name, memory] = line.split(\",\").map((s) => s.trim());\n\t\t\tif (id !== undefined) {\n\t\t\t\tgpus.push({\n\t\t\t\t\tid: parseInt(id, 10),\n\t\t\t\t\tname: name || \"Unknown\",\n\t\t\t\t\tmemory: memory || \"Unknown\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tconsole.log(chalk.green(`✓ Detected ${gpus.length} GPU(s)`));\n\tfor (const gpu of gpus) {\n\t\tconsole.log(`  GPU ${gpu.id}: ${gpu.name} (${gpu.memory})`);\n\t}\n\n\t// Save pod configuration\n\tconst pod: Pod = {\n\t\tssh: sshCmd,\n\t\tgpus,\n\t\tmodels: {},\n\t\tmodelsPath,\n\t\tvllmVersion: options.vllm || \"release\",\n\t};\n\n\taddPod(name, pod);\n\tconsole.log(\"\");\n\tconsole.log(chalk.green(`✓ Pod '${name}' setup complete and set as active pod`));\n\tconsole.log(\"\");\n\tconsole.log(\"You can now deploy models with:\");\n\tconsole.log(chalk.cyan(`  pi start <model> --name <name>`));\n};\n\n/**\n * Switch active pod\n */\nexport const switchActivePod = (name: string) => {\n\tconst config = loadConfig();\n\tif (!config.pods[name]) {\n\t\tconsole.error(chalk.red(`Pod '${name}' not found`));\n\t\tconsole.log(\"\\nAvailable pods:\");\n\t\tfor (const podName of Object.keys(config.pods)) {\n\t\t\tconsole.log(`  ${podName}`);\n\t\t}\n\t\tprocess.exit(1);\n\t}\n\n\tsetActivePod(name);\n\tconsole.log(chalk.green(`✓ Switched active pod to '${name}'`));\n};\n\n/**\n * Remove a pod from config\n */\nexport const removePodCommand = (name: string) => {\n\tconst config = loadConfig();\n\tif (!config.pods[name]) {\n\t\tconsole.error(chalk.red(`Pod '${name}' not found`));\n\t\tprocess.exit(1);\n\t}\n\n\tremovePod(name);\n\tconsole.log(chalk.green(`✓ Removed pod '${name}' from configuration`));\n\tconsole.log(chalk.yellow(\"Note: This only removes the local configuration. The remote pod is not affected.\"));\n};\n"]}