import type { RuntimeConfig } from "../config/validate.js"; import { type ReportItem } from "./report.js"; import { type ClusterTopology } from "../ssh/nodeRouter.js"; import { type AccessTier } from "./bootstrap.js"; export type SetupOptions = { proxmoxHost?: string; proxmoxPort?: number; proxmoxUser?: string; proxmoxRealm?: string; tokenName?: string; tokenSecret?: string; allowInsecureTls?: boolean; sshHost?: string; sshPort?: number; sshUser?: string; sshKeyPath?: string; skipConnectivity?: boolean; /** Which client configs to write. Defaults to Claude Code + VS Code. */ clients?: string; /** Emitted into the client config env block; the server defaults to `full`. */ accessTier?: string; moduleMode?: string; /** Print a paste-ready config to stdout and write nothing. */ printConfig?: boolean; /** * Instance name. One instance per Proxmox: run setup once per server and each * gets its own credentials file and its own entry in the client config. * Defaults to the discovered cluster or node name. */ name?: string; /** `project` writes into the current directory, `user` into the home directory. */ scope?: string; }; /** * The slice of readline the wizard uses. * * Declared as an interface rather than taken from `createInterface` so the flow * can be driven by a test. Piping a file into the real interface does not work: * readline flushes every line at once and the ones that arrive between two * questions are dropped, after which the process exits cleanly having answered * nothing -- which looks exactly like a hang that isn't one. */ export type Prompt = { question: (text: string) => Promise; close: () => void; }; export type WizardResult = { config: RuntimeConfig; accessTier: AccessTier; }; /** * The guided path. * * Rewritten around one observation: the hard part of this setup is not typing * the answers, it is knowing what the questions mean and what to do when the * answer is rejected. So every question carries one line of context, the two * decisions with real consequences (how much power to grant, and whether SSH is * needed at all) are asked explicitly instead of defaulted silently, and a * failed connection is retried in place with the fix on screen rather than * printed as a red report after everything has already been written. */ export type WizardDeps = { prompt?: Prompt; /** Returns the number of nodes Proxmox reports, or throws. Injectable for tests. */ probe?: (config: RuntimeConfig) => Promise; }; export declare const ask: (options: SetupOptions, deps?: WizardDeps) => Promise; /** * Whether the caller supplied connection details, i.e. wants the scripted path. * * This used to ask whether *any* option was defined, which silently disabled * the interactive wizard entirely: commander fills in defaults for * `--proxmox-realm` and `--scope`, so the answer was always yes and a bare * `nandi-proxmox-mcp setup` -- the command the docs hand to newcomers -- failed * with "missing required options" instead of asking anything. * * Only the four values that carry actual connection data can imply that intent. */ export declare const hasCliOverrides: (options: SetupOptions) => boolean; export declare const resolveSetupConfig: (options: SetupOptions) => RuntimeConfig; /** * Turns ssh's multi-line failures into one actionable line. * * A changed host key prints a 15-line banner that tells a non-expert nothing * about what to do; it happens whenever a node is reinstalled or its key * rotates, which is common enough to be worth handling explicitly. */ export declare const summarizeSshFailure: (stderr: string) => string; /** * The API-side twin of `summarizeSshFailure`. * * The 401 case is the one that matters. Proxmox returns it both for a wrong * secret and for a token created with privilege separation left on -- the web * UI's default -- and those need opposite fixes. A token with `privsep 1` * starts with no permissions at all, so a perfectly correct user, role and * secret still fails, and the operator reasonably concludes they mistyped the * secret and retypes it forever. */ export declare const summarizeProxmoxFailure: (error: unknown, account: string, tokenName: string) => string; export type Discovery = { topology?: ClusterTopology; /** Which node `sshHost` is, asked of the node itself. */ sshNodeName?: string; report: ReportItem[]; }; export declare const runSetup: (options?: SetupOptions) => Promise; //# sourceMappingURL=setup.d.ts.map