fix: harden Pi management readiness
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { execFile as nodeExecFile } from "node:child_process";
|
||||
import { promisify } from "node:util";
|
||||
import type { AppConfig } from "../config.js";
|
||||
import { secretValue } from "../config/secret-bundle.js";
|
||||
import {
|
||||
loadSettings,
|
||||
saveSettings,
|
||||
@@ -12,6 +13,11 @@ import {
|
||||
isPiManagedConfigError,
|
||||
} from "./managed-config.js";
|
||||
import { createPiProviderSmoke, type PiProviderSmoke } from "./provider-smoke.js";
|
||||
import { loadPiAuthProviders } from "./auth-providers.js";
|
||||
import {
|
||||
piProviderCredentialStatus,
|
||||
type PiCredentialStatus,
|
||||
} from "./provider-credentials.js";
|
||||
|
||||
const execFile = promisify(nodeExecFile);
|
||||
const REASONING_CHOICES = ["low", "medium", "high"] as const;
|
||||
@@ -31,6 +37,7 @@ export interface PiInstallationConfig {
|
||||
export interface PiStatus {
|
||||
version?: string;
|
||||
ready: boolean;
|
||||
credentials: PiCredentialStatus;
|
||||
config: PiInstallationConfig;
|
||||
checkedAt: string;
|
||||
message?: string;
|
||||
@@ -89,6 +96,7 @@ interface PiManagementDeps {
|
||||
readSettings?: () => Settings;
|
||||
saveSettings?: (settings: Settings) => Settings;
|
||||
readLogs?: () => string | Promise<string>;
|
||||
credentialStatus?: (provider: string | undefined) => PiCredentialStatus;
|
||||
now?: () => Date;
|
||||
}
|
||||
|
||||
@@ -104,6 +112,18 @@ export function createPiManagement(config: AppConfig, deps: PiManagementDeps): P
|
||||
const persistSettings = deps.saveSettings ?? ((settings) => saveSettings(config, settings));
|
||||
const readLogs = deps.readLogs ?? (() => diagnostics.join("\n"));
|
||||
const smokeProvider = deps.smokeProvider ?? createPiProviderSmoke(config);
|
||||
const credentialStatus = deps.credentialStatus ?? ((provider: string | undefined) => {
|
||||
try {
|
||||
return piProviderCredentialStatus({
|
||||
provider,
|
||||
authProviders: loadPiAuthProviders(),
|
||||
credentialValue: secretValue(config, "THT_MODEL_API_KEY"),
|
||||
credentialFile: config.modelApiKeyFile,
|
||||
});
|
||||
} catch {
|
||||
return "missing";
|
||||
}
|
||||
});
|
||||
|
||||
const closedOptions = async (): Promise<Omit<PiOptions, "checkedAt">> => {
|
||||
let listed: PiModel[];
|
||||
@@ -168,14 +188,15 @@ export function createPiManagement(config: AppConfig, deps: PiManagementDeps): P
|
||||
async status(): Promise<PiStatus> {
|
||||
const checkedAt = now().toISOString();
|
||||
const current = installationConfig();
|
||||
const credentials = credentialStatus(current.provider);
|
||||
try {
|
||||
const currentVersion = await version();
|
||||
addDiagnostic("Pi version probe succeeded");
|
||||
return { version: currentVersion, ready: true, config: current, checkedAt };
|
||||
return { version: currentVersion, ready: true, credentials, config: current, checkedAt };
|
||||
} catch (error) {
|
||||
const message = stableMessage(error, "Pi runtime is unavailable");
|
||||
addDiagnostic(message);
|
||||
return { ready: false, config: current, checkedAt, message };
|
||||
return { ready: false, credentials, config: current, checkedAt, message };
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -53,6 +53,8 @@ export function canonicalPiProvider(provider: string | undefined): string | unde
|
||||
return value;
|
||||
}
|
||||
|
||||
export type PiCredentialStatus = "present" | "missing";
|
||||
|
||||
export interface CredentialFsOps {
|
||||
lstat(path: string): Stats;
|
||||
open(path: string, flags: number): number;
|
||||
@@ -172,3 +174,22 @@ export function buildPiChildEnv(opts: {
|
||||
}
|
||||
return env;
|
||||
}
|
||||
|
||||
/** Report only whether the selected hosted provider has a usable credential source. */
|
||||
export function piProviderCredentialStatus(opts: {
|
||||
provider?: string;
|
||||
credentialFile?: string;
|
||||
credentialValue?: string;
|
||||
authProviders?: ReadonlySet<string>;
|
||||
fsOps?: CredentialFsOps;
|
||||
}): PiCredentialStatus {
|
||||
const provider = canonicalPiProvider(opts.provider);
|
||||
if (!provider || LOCAL_PROVIDERS.has(provider)) return "missing";
|
||||
if (opts.authProviders?.has(provider)) return "present";
|
||||
try {
|
||||
buildPiChildEnv({ ...opts, ambient: {} });
|
||||
return "present";
|
||||
} catch {
|
||||
return "missing";
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user