/** * Installation-scoped host operations that must not impersonate an HTTP administrator. * This command runs only through `docker compose exec core`; it never accepts credentials, * headers, paths, or arbitrary code from the caller. */ import { pathToFileURL } from "node:url"; import { join } from "node:path"; import { loadConfig, type AppConfig } from "./config.js"; import { rolesToPermissions } from "./auth/config.js"; import type { PrincipalContext } from "./auth/principal.js"; import { createPiModelLister } from "./pi/list-models.js"; import { createPiManagement } from "./pi/management.js"; import { effectiveSettings } from "./routes/settings.js"; import { MaintenanceBarrier } from "./runtime/maintenance-gate.js"; import { loadSettings } from "./settings/settings-store.js"; import { ThtRunner, type SessionRow } from "./tht/tht-runner.js"; import { WorkspaceRegistry } from "./workspaces/registry.js"; import { WorkspaceSecretStore } from "./workspaces/secret-store.js"; type OperatorAction = "maintenance-activate" | "maintenance-deactivate" | "maintenance-status" | "session-inventory" | "workflow-doctor" | "workspace-integrity" | "pi-options" | "pi-test" | "effective-settings"; const lifecyclePrincipal: PrincipalContext = { issuer: "tht-operator-command", subject: "installation-lifecycle", displayName: "Installation lifecycle", roles: ["admin"], permissions: rolesToPermissions(["admin"]), isAdmin: true, }; function operatorRunner(config: AppConfig): ThtRunner { const workspaceSecretStore = new WorkspaceSecretStore({ root: config.workspaceSecretStoreRoot, runtimeRoot: config.workspaceSecretRuntimeRoot, installationId: config.workspaceRegistry.installationId, }); return new ThtRunner({ thtBin: config.thtBin, harnessDir: config.harnessDir, configPath: process.env.THT_CONFIG ?? "config/tht.yaml", dataRoot: config.dataRoot, runtimeSnapshotRoot: join(config.workspaceRegistry.root, "snapshots", "runtime"), secretRoots: config.workspaceRegistry.secretRoots, secretsFile: config.secretsFile, secretFiles: config.secretFiles, workspaceSecretStore, semanticRuntime: { internalQdrantUrl: config.internalQdrantUrl, internalEmbeddingUrl: config.internalEmbeddingUrl, internalEmbeddingModel: config.internalEmbeddingModel, internalEmbeddingDimensions: config.internalEmbeddingDimensions, }, }).withPrincipal(lifecyclePrincipal); } async function sessionInventory(config: AppConfig): Promise>> { const registry = new WorkspaceRegistry(config.workspaceRegistry); const revisions = await registry.listRetainedSnapshots(); const runner = operatorRunner(config); const sessions = new Map(); for (const revision of revisions) { for (const session of await runner.sessionList(revision.snapshotPath)) sessions.set(session.id, session); } return [...sessions.values()].map(({ status, archived }) => ({ status, archived: archived === true })); } async function workflowDiagnostics(config: AppConfig): Promise<{ ready: true; workspaces: number }> { const registry = new WorkspaceRegistry(config.workspaceRegistry); const revisions = await registry.listRetainedSnapshots(); if (revisions.length === 0) throw new Error("workflow diagnostics unavailable"); const runner = operatorRunner(config); for (const revision of revisions) { const result = await runner.run(["doctor", "--json"], revision.snapshotPath); let payload: unknown; try { payload = JSON.parse(result.stdout); } catch { throw new Error("workflow diagnostics failed"); } if ( result.code !== 0 || !payload || typeof payload !== "object" || (payload as { ok?: unknown }).ok !== true ) throw new Error("workflow diagnostics failed"); } return { ready: true, workspaces: revisions.length }; } async function workspaceIntegrity(config: AppConfig): Promise<{ ready: true; state: "uninitialized" | "active"; workspaces: number; fingerprint: string; }> { const integrity = await new WorkspaceRegistry(config.workspaceRegistry).verifyStoredState(); return { ready: true, ...integrity }; } export async function runOperatorAction( action: OperatorAction, config: AppConfig, ): Promise { if (action.startsWith("maintenance-")) { const barrier = new MaintenanceBarrier(config.maintenanceFile); if (action === "maintenance-activate") await barrier.activate(); if (action === "maintenance-deactivate") barrier.deactivate(); return barrier.status(); } if (action === "session-inventory") return await sessionInventory(config); if (action === "workflow-doctor") return await workflowDiagnostics(config); if (action === "workspace-integrity") return await workspaceIntegrity(config); if (action === "effective-settings") return effectiveSettings(config, loadSettings(config)); const service = createPiManagement(config, { listModels: createPiModelLister(config) }); if (action === "pi-options") return await service.options(); if (action === "pi-test") return await service.test(); throw new Error("unsupported operator action"); } async function main(): Promise { const action = process.argv[2] as OperatorAction | undefined; if (!action || ![ "maintenance-activate", "maintenance-deactivate", "maintenance-status", "session-inventory", "workflow-doctor", "workspace-integrity", "pi-options", "pi-test", "effective-settings", ].includes(action)) throw new Error("invalid operator action"); const result = await runOperatorAction(action, loadConfig(process.env)); process.stdout.write(`${JSON.stringify(result)}\n`); } if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { void main().catch(() => { process.stderr.write("operator command failed\n"); process.exitCode = 2; }); }