refactor(cli): split install.ts and model-fallback.ts into focused modules
Install pipeline: - cli-installer.ts, tui-installer.ts, tui-install-prompts.ts - install-validators.ts Model fallback: - model-fallback-types.ts, fallback-chain-resolution.ts - provider-availability.ts, provider-model-id-transform.ts
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
import * as p from "@clack/prompts"
|
||||
import type { Option } from "@clack/prompts"
|
||||
import type {
|
||||
ClaudeSubscription,
|
||||
DetectedConfig,
|
||||
InstallConfig,
|
||||
} from "./types"
|
||||
import { detectedToInitialValues } from "./install-validators"
|
||||
|
||||
async function selectOrCancel<TValue extends Readonly<string | boolean | number>>(params: {
|
||||
message: string
|
||||
options: Option<TValue>[]
|
||||
initialValue: TValue
|
||||
}): Promise<TValue | null> {
|
||||
const value = await p.select<TValue>({
|
||||
message: params.message,
|
||||
options: params.options,
|
||||
initialValue: params.initialValue,
|
||||
})
|
||||
if (p.isCancel(value)) {
|
||||
p.cancel("Installation cancelled.")
|
||||
return null
|
||||
}
|
||||
return value as TValue
|
||||
}
|
||||
|
||||
export async function promptInstallConfig(detected: DetectedConfig): Promise<InstallConfig | null> {
|
||||
const initial = detectedToInitialValues(detected)
|
||||
|
||||
const claude = await selectOrCancel<ClaudeSubscription>({
|
||||
message: "Do you have a Claude Pro/Max subscription?",
|
||||
options: [
|
||||
{ value: "no", label: "No", hint: "Will use opencode/glm-4.7-free as fallback" },
|
||||
{ value: "yes", label: "Yes (standard)", hint: "Claude Opus 4.5 for orchestration" },
|
||||
{ value: "max20", label: "Yes (max20 mode)", hint: "Full power with Claude Sonnet 4.5 for Librarian" },
|
||||
],
|
||||
initialValue: initial.claude,
|
||||
})
|
||||
if (!claude) return null
|
||||
|
||||
const openai = await selectOrCancel({
|
||||
message: "Do you have an OpenAI/ChatGPT Plus subscription?",
|
||||
options: [
|
||||
{ value: "no", label: "No", hint: "Oracle will use fallback models" },
|
||||
{ value: "yes", label: "Yes", hint: "GPT-5.2 for Oracle (high-IQ debugging)" },
|
||||
],
|
||||
initialValue: initial.openai,
|
||||
})
|
||||
if (!openai) return null
|
||||
|
||||
const gemini = await selectOrCancel({
|
||||
message: "Will you integrate Google Gemini?",
|
||||
options: [
|
||||
{ value: "no", label: "No", hint: "Frontend/docs agents will use fallback" },
|
||||
{ value: "yes", label: "Yes", hint: "Beautiful UI generation with Gemini 3 Pro" },
|
||||
],
|
||||
initialValue: initial.gemini,
|
||||
})
|
||||
if (!gemini) return null
|
||||
|
||||
const copilot = await selectOrCancel({
|
||||
message: "Do you have a GitHub Copilot subscription?",
|
||||
options: [
|
||||
{ value: "no", label: "No", hint: "Only native providers will be used" },
|
||||
{ value: "yes", label: "Yes", hint: "Fallback option when native providers unavailable" },
|
||||
],
|
||||
initialValue: initial.copilot,
|
||||
})
|
||||
if (!copilot) return null
|
||||
|
||||
const opencodeZen = await selectOrCancel({
|
||||
message: "Do you have access to OpenCode Zen (opencode/ models)?",
|
||||
options: [
|
||||
{ value: "no", label: "No", hint: "Will use other configured providers" },
|
||||
{ value: "yes", label: "Yes", hint: "opencode/claude-opus-4-6, opencode/gpt-5.2, etc." },
|
||||
],
|
||||
initialValue: initial.opencodeZen,
|
||||
})
|
||||
if (!opencodeZen) return null
|
||||
|
||||
const zaiCodingPlan = await selectOrCancel({
|
||||
message: "Do you have a Z.ai Coding Plan subscription?",
|
||||
options: [
|
||||
{ value: "no", label: "No", hint: "Will use other configured providers" },
|
||||
{ value: "yes", label: "Yes", hint: "Fallback for Librarian and Multimodal Looker" },
|
||||
],
|
||||
initialValue: initial.zaiCodingPlan,
|
||||
})
|
||||
if (!zaiCodingPlan) return null
|
||||
|
||||
const kimiForCoding = await selectOrCancel({
|
||||
message: "Do you have a Kimi For Coding subscription?",
|
||||
options: [
|
||||
{ value: "no", label: "No", hint: "Will use other configured providers" },
|
||||
{ value: "yes", label: "Yes", hint: "Kimi K2.5 for Sisyphus/Prometheus fallback" },
|
||||
],
|
||||
initialValue: initial.kimiForCoding,
|
||||
})
|
||||
if (!kimiForCoding) return null
|
||||
|
||||
return {
|
||||
hasClaude: claude !== "no",
|
||||
isMax20: claude === "max20",
|
||||
hasOpenAI: openai === "yes",
|
||||
hasGemini: gemini === "yes",
|
||||
hasCopilot: copilot === "yes",
|
||||
hasOpencodeZen: opencodeZen === "yes",
|
||||
hasZaiCodingPlan: zaiCodingPlan === "yes",
|
||||
hasKimiForCoding: kimiForCoding === "yes",
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user