{"version":3,"file":"config.mjs","names":[],"sources":["../../src/schemas/config.ts"],"sourcesContent":["/**\n * Configuration surfaces, contributed by every extension that owns settings.\n *\n * Doom settings live in one YAML file but are owned by many extensions, and for\n * a long time the only way to change any of them was to edit that file by hand.\n * The one exception, an editor-command prompt, asked for a value with no way to\n * see what a valid one looked like.\n *\n * So configuration is published rather than centralised: an extension describes\n * its own fields, one renderer draws them all, and the extension still performs\n * every write. Nothing here knows what a voice model or an editor command is.\n *\n * Deliberately the same shape as the mode and footer contracts next door, since\n * the problem is the same one: several extensions sharing one surface. The UI\n * hub invokes an owner's registered action directly, because unlike a status\n * strip this surface is written to as well as read.\n */\n\nimport { type Static, Type } from 'typebox';\n\n/** Canonical Cordis key for the session-owned Doom configuration service. */\nexport const DOOM_CONFIG_SERVICE = 'doom/config';\n\n/**\n * Cross-package service contract for the immutable configuration snapshot.\n *\n * The provider supplies the concrete snapshot and file-config types. Keeping\n * this contract generic lets independently bundled consumers share the Cordis\n * service definition without making the contracts package depend on config.\n */\nexport interface IDoomConfigService<TSnapshot = unknown, TFileConfig = unknown> {\n  /** Identifies the currently published session service for stale-work fencing. */\n  readonly generation: string;\n  /** Returns the immutable snapshot currently visible to consumers. */\n  getSnapshot(): TSnapshot;\n  /** Atomically replaces the immutable live snapshot after a successful transition. */\n  replaceSnapshot(snapshot: TSnapshot): TSnapshot;\n  /** Loads the package's file configuration outside the live session snapshot. */\n  load(repoRoot: string, homeDirectory?: string): TFileConfig;\n}\n\n/** Matches the leader contract's source rule: package names, addressable and spoof-checkable. */\nexport const ConfigSourceSchema = Type.String({\n  minLength: 1,\n  maxLength: 128,\n  pattern: '^[A-Za-z0-9@][A-Za-z0-9@/._:-]*$',\n});\n\nconst ConfigIdSchema = Type.String({ minLength: 1, maxLength: 128, pattern: '^[a-z0-9][a-z0-9._:-]*$' });\n\n/**\n * How ready a value is to be used, as opposed to whether it is merely set.\n * `blocked` covers a choice that needs something else first, such as a model\n * whose engine is not installed.\n */\nexport const ConfigStatusSchema = Type.Union([\n  Type.Literal('ready'),\n  Type.Literal('available'),\n  Type.Literal('blocked'),\n]);\nexport type ConfigStatus = Static<typeof ConfigStatusSchema>;\n\nexport const ConfigFieldKindSchema = Type.Union([\n  /** Free text, edited in place. */\n  Type.Literal('text'),\n  /** A short closed set, cycled in place. */\n  Type.Literal('enum'),\n  /** A long set worth its own screen, with per-entry status and actions. */\n  Type.Literal('choice'),\n  /** Read-only. Resolution results, derived values, preflight checks. */\n  Type.Literal('info'),\n]);\nexport type ConfigFieldKind = Static<typeof ConfigFieldKindSchema>;\n\n/**\n * A key the renderer offers on the focused field, sent back verbatim as an\n * action. Owners use this for confirmations, so the pending question survives a\n * panel that is closed and reopened.\n */\nexport const ConfigActionSchema = Type.Object(\n  {\n    key: Type.String({ minLength: 1, maxLength: 1 }),\n    label: Type.String({ minLength: 1, maxLength: 24 }),\n    action: ConfigIdSchema,\n  },\n  { additionalProperties: false },\n);\nexport type ConfigAction = Static<typeof ConfigActionSchema>;\n\nexport const ConfigChoiceSchema = Type.Object(\n  {\n    id: Type.String({ minLength: 1, maxLength: 256 }),\n    label: Type.String({ minLength: 1, maxLength: 96 }),\n    /** Right-aligned by the renderer. Sizes, ids, anything narrow. */\n    detail: Type.Optional(Type.String({ minLength: 1, maxLength: 96 })),\n    /** Groups entries under a heading the cursor skips over. */\n    group: Type.Optional(Type.String({ minLength: 1, maxLength: 48 })),\n    status: Type.Optional(ConfigStatusSchema),\n    statusText: Type.Optional(Type.String({ minLength: 1, maxLength: 96 })),\n    /**\n     * What enter does on this entry. Carrying it per-entry is what lets one list\n     * hold both an installed model that only needs selecting and an absent one\n     * that needs fetching, without the renderer knowing the difference.\n     */\n    action: Type.Optional(ConfigIdSchema),\n  },\n  { additionalProperties: false },\n);\nexport type ConfigChoice = Static<typeof ConfigChoiceSchema>;\n\n/**\n * One line of a multi-step operation.\n *\n * Published as a list rather than a single \"current step\" string so the panel can\n * show what already ran alongside what is left. During an install that is the\n * difference between \"something is happening\" and knowing a package manager\n * already finished and a download is now underway.\n */\nexport const ConfigStepSchema = Type.Object(\n  {\n    label: Type.String({ minLength: 1, maxLength: 96 }),\n    state: Type.Union([\n      Type.Literal('pending'),\n      /** Already true of this machine, so nothing will run for it. */\n      Type.Literal('satisfied'),\n      Type.Literal('running'),\n      Type.Literal('done'),\n      Type.Literal('failed'),\n    ]),\n    detail: Type.Optional(Type.String({ minLength: 1, maxLength: 160 })),\n  },\n  { additionalProperties: false },\n);\nexport type ConfigStep = Static<typeof ConfigStepSchema>;\n\nexport const ConfigProgressSchema = Type.Object(\n  {\n    label: Type.String({ minLength: 1, maxLength: 96 }),\n    /** 0 to 1. Omitted when the work has no measurable total. */\n    ratio: Type.Optional(Type.Number({ minimum: 0, maximum: 1 })),\n  },\n  { additionalProperties: false },\n);\nexport type ConfigProgress = Static<typeof ConfigProgressSchema>;\n\nexport const ConfigFieldSchema = Type.Object(\n  {\n    id: ConfigIdSchema,\n    label: Type.String({ minLength: 1, maxLength: 48 }),\n    kind: ConfigFieldKindSchema,\n    /** Absent means unset; the renderer shows `placeholder` instead. */\n    value: Type.Optional(Type.String({ minLength: 1, maxLength: 4096 })),\n    placeholder: Type.Optional(Type.String({ minLength: 1, maxLength: 96 })),\n    /** One line of help for the focused field. */\n    detail: Type.Optional(Type.String({ minLength: 1, maxLength: 240 })),\n    /** The config key this writes, shown under the focused field so the file stays legible. */\n    keyPath: Type.Optional(Type.String({ minLength: 1, maxLength: 128 })),\n    status: Type.Optional(ConfigStatusSchema),\n    /** Doubles as the error line: a rejected edit comes back as the old value plus this. */\n    statusText: Type.Optional(Type.String({ minLength: 1, maxLength: 240 })),\n    choices: Type.Optional(Type.Array(ConfigChoiceSchema, { maxItems: 128 })),\n    actions: Type.Optional(Type.Array(ConfigActionSchema, { maxItems: 4 })),\n    /** Work is running; the renderer dims the field and offers abort. */\n    busy: Type.Optional(Type.Boolean()),\n    progress: Type.Optional(ConfigProgressSchema),\n    steps: Type.Optional(Type.Array(ConfigStepSchema, { maxItems: 24 })),\n    /**\n     * The tail of a running command's terminal output.\n     *\n     * A tail rather than the whole scrollback: the field is a few rows of a\n     * shared pane, and what matters is the question a package manager just\n     * asked, not what it printed a minute ago.\n     */\n    output: Type.Optional(Type.Array(Type.String({ maxLength: 512 }), { maxItems: 64 })),\n    /**\n     * The command is waiting on the user. The renderer offers a line to type\n     * into, which comes back as an owner-defined action carrying the text.\n     */\n    awaitingInput: Type.Optional(Type.Boolean()),\n  },\n  { additionalProperties: false },\n);\nexport type ConfigField = Static<typeof ConfigFieldSchema>;\n\nexport const ConfigSectionSchema = Type.Object(\n  {\n    id: ConfigIdSchema,\n    title: Type.String({ minLength: 1, maxLength: 32 }),\n    detail: Type.Optional(Type.String({ minLength: 1, maxLength: 96 })),\n    order: Type.Integer({ minimum: 0, maximum: 1000 }),\n    /** Section-wide state: readiness, or why a write failed. */\n    notice: Type.Optional(Type.String({ minLength: 1, maxLength: 240 })),\n    noticeLevel: Type.Optional(Type.Union([Type.Literal('info'), Type.Literal('error')])),\n    fields: Type.Array(ConfigFieldSchema, { maxItems: 64 }),\n  },\n  { additionalProperties: false },\n);\nexport type ConfigSection = Static<typeof ConfigSectionSchema>;\n\nconst ConfigSourceRefSchema = Type.Object(\n  { source: ConfigSourceSchema, generation: Type.String({ minLength: 1 }) },\n  { additionalProperties: false },\n);\n\nconst ConfigSnapshotSchema = Type.Object(\n  { ...ConfigSourceRefSchema.properties, sections: Type.Array(ConfigSectionSchema, { maxItems: 32 }) },\n  { additionalProperties: false },\n);\nexport type ConfigSnapshot = Static<typeof ConfigSnapshotSchema>;\nexport type ConfigSourceRef = Static<typeof ConfigSourceRefSchema>;\n\nexport const CONFIG_ACTION = {\n  set: 'set',\n  clear: 'clear',\n} as const;\n\nexport interface DoomExtensionContext {\n  sessionManager: { getSessionId(): string };\n}\n\nexport interface DoomConfigSectionView extends ConfigSection {\n  source: string;\n}\n\nexport interface DoomConfigInvocation {\n  source: string;\n  sectionId: string;\n  fieldId: string;\n  action: string;\n  value?: string;\n}\n\nexport interface DoomConfigActionInput<Context extends DoomExtensionContext = DoomExtensionContext> {\n  ctx: Context;\n  sectionId: string;\n  fieldId: string;\n  value?: string;\n}\n\nexport interface DoomConfigContributionOptions<Context extends DoomExtensionContext = DoomExtensionContext> {\n  source: string;\n  listSections: () => readonly ConfigSection[];\n  handlers: Readonly<Record<string, (input: DoomConfigActionInput<Context>) => void | Promise<void>>>;\n  onError: (error: unknown, actionName: string, ctx: Context) => void;\n}\n\nexport interface DoomConfigContributionHandle {\n  update(): void;\n  dispose(): void;\n}\n"],"mappings":"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"}