/** * Typed public CLI registry — sole source for discoverable commands and seats * (ADR 0052 / #105). Model is caller-specified only (#178) — no package candidates. */ import { PACKAGED_ROLE_REGISTRY, type PackagedRole, } from "../packaged-role-registry.ts"; /** Package-relative path of the Internal role entrypoint (explicit load only). */ export const INTERNAL_ROLE_ENTRYPOINT_RELATIVE = "extensions/role-runtime.ts" as const; export const PUBLIC_CALLABLE_ROLES = PACKAGED_ROLE_REGISTRY.map( (entry) => entry.role, ) as readonly PackagedRole[]; export type PublicCallableRole = (typeof PUBLIC_CALLABLE_ROLES)[number]; export type PublicConfigurableSeat = PublicCallableRole; export const PUBLIC_CONFIGURABLE_SEATS = [ ...PUBLIC_CALLABLE_ROLES, ] as const satisfies readonly PublicConfigurableSeat[]; export const PUBLIC_CLI_SUPPORT_COMMANDS = [ "roles", "config", "help", "resume", "new", ] as const; export type PublicCliSupportCommand = (typeof PUBLIC_CLI_SUPPORT_COMMANDS)[number]; /** Opaque thinking level string — pass-through to Pi; no local whitelist (#683). */ export type PublicThinkingLevel = string; export type ModelRef = { provider: string; model: string; /** Absent when invocation passed bare provider/model — pi/model default applies. */ thinking?: PublicThinkingLevel; }; /** * Model-axis projection: incomplete seat row → undefined; else provider/model[/thinking]. * Single implementation for config, institutional resolution, and display (#620). */ export function seatModelOnly( seat: { provider?: string; model?: string; thinking?: PublicThinkingLevel } | undefined, ): ModelRef | undefined { if (seat?.provider === undefined || seat.model === undefined) return undefined; return seat.thinking === undefined ? { provider: seat.provider, model: seat.model } : { provider: seat.provider, model: seat.model, thinking: seat.thinking }; } /** Deterministic public commands — discoverable, never LLM-configurable seats. */ export const PUBLIC_DETERMINISTIC_COMMANDS = ["analyst"] as const; export type PublicDeterministicCommand = (typeof PUBLIC_DETERMINISTIC_COMMANDS)[number]; export type HelpCapability = | { kind: "support"; name: PublicCliSupportCommand; } | { kind: "role"; name: PublicCallableRole; phases: readonly (string | null)[]; defaultPhase: string | null; } | { kind: "deterministic"; name: PublicDeterministicCommand; }; /** * Typed help surface. Presentation formats these facts; tests must not assert * exact help prose or layout (锚定宪法 / ADR 0016 / #105 AC). * analyst is a deterministic analysis command on the public CLI — not an LLM seat. */ export function listHelpCapabilities(): readonly HelpCapability[] { const support: HelpCapability[] = PUBLIC_CLI_SUPPORT_COMMANDS.map((name) => ({ kind: "support" as const, name, })); const roles: HelpCapability[] = PACKAGED_ROLE_REGISTRY.map((entry) => { const phases = entry.phases as readonly (string | null)[]; const defaultPhase = phases.length === 1 && phases[0] === null ? null : phases.includes("apply") ? "apply" : (phases[0] ?? null); return { kind: "role" as const, name: entry.role, phases, defaultPhase, }; }); const deterministic: HelpCapability[] = PUBLIC_DETERMINISTIC_COMMANDS.map( (name) => ({ kind: "deterministic" as const, name, }), ); return [...support, ...roles, ...deterministic]; } export function isPublicCallableRole(value: string): value is PublicCallableRole { return (PUBLIC_CALLABLE_ROLES as readonly string[]).includes(value); } export function isPublicConfigurableSeat( value: string, ): value is PublicConfigurableSeat { return (PUBLIC_CONFIGURABLE_SEATS as readonly string[]).includes(value); } export function isPublicCliSupportCommand( value: string, ): value is PublicCliSupportCommand { return (PUBLIC_CLI_SUPPORT_COMMANDS as readonly string[]).includes(value); }