/** * Edit-approval settings: this plugin entry's flat document fields, the * resolved per-feature settings the guards consume, and the adapter between * them. * * Kept free of host wiring so the defaults, the fallbacks, and the * clear-when-default write rule stay unit-testable in isolation; `src/index.ts` * is the only consumer. * * DSH 0.1.7 removed the settings-namespace registry (`settings.register`), so * this plugin's two former namespaces (`edit-approval`, `bash-approval`) * collapsed into ONE profile entry's `Config`. The fields the config page edits * are `.volatile()` on that schema: the host resolves them into live references * before `apply` runs, so a config-page write is visible at the next `.get()` * without a remount. Every other field stays ordinary config — excluded from * the form and editable only in the profile file, exactly as before. * * Field names carry a feature prefix on purpose: this entry's own `disabled:` * flag sits beside them in the same document, so a bare `enabled` would read as * the plugin switch rather than as one feature's master switch. * * @module dsh-edit-approval/config */ import type { Volatile } from '@deepseek-ai/cordis'; import type { EditApprovalSettings } from './guard.ts'; import type { BashApprovalSettings } from './bash-guard.ts'; /** * Tool names the edit-approval feature intercepts by default. * * `str_replace_editor` is deliberately ABSENT even though the package still * ships: it stopped being a DEFAULT tool in DSH 0.1.3, so a default install * can never see it. The guard branches that handle it are kept (and unit * tested) because adding the name to `editTools` makes them live again. */ export declare const DEFAULT_TOOLS: readonly string[]; /** Tool names the bash-approval feature intercepts by default. */ export declare const DEFAULT_BASH_TOOLS: readonly string[]; /** Command prefixes the bash-approval feature always passes, by default. */ export declare const DEFAULT_BASH_ALLOW: readonly string[]; /** The edit-approval defaults: schema defaults and the resolved fallbacks. */ export declare const DEFAULT_EDIT_APPROVAL: EditApprovalSettings; /** The bash-approval defaults: schema defaults and the resolved fallbacks. */ export declare const DEFAULT_BASH_APPROVAL: BashApprovalSettings; /** * The document field names the config page edits. They MUST equal the * `.volatile()` fields of the `Config` schema in `src/index.ts` — a name here * that is not volatile makes the Host refuse the write with * `Config field "…" is not volatile`, and a volatile field missing here is * simply invisible in the UI. `tests/config.spec.ts` pins the pairing. */ export declare const APPROVAL_SWITCH_FIELDS: readonly ['editEnabled', 'bashEnabled']; /** One switch field name the config page edits. */ export type ApprovalSwitchField = (typeof APPROVAL_SWITCH_FIELDS)[number]; /** * The live configuration this plugin reads: the two master switches the config * page edits (`.volatile()`, so they update without a remount) plus the * ordinary fields, which are plain values resolved once when the entry loads. * * The volatile/ordinary split is deliberate: a `.volatile()` field is the only * kind a settings write may address AND the only kind whose value can change * while the plugin is mounted, so marking a field volatile makes it a form * field by construction. Only what the config page shows is volatile. */ export interface ApprovalConfig { /** Edit-approval master switch. */ readonly editEnabled: Volatile; /** Bash-approval master switch. */ readonly bashEnabled: Volatile; /** Intercepted edit-tool names. */ readonly editTools: string[]; /** Ask only when a change touches at least this many lines. */ readonly editMinDiffLines: number; /** Whether creating a new file asks. */ readonly editIncludeCreate: boolean; /** Whether clearing/emptying a file asks. */ readonly editIncludeDelete: boolean; /** Intercepted command-tool names. */ readonly bashTools: string[]; /** Always-allow command prefixes; matched after whitespace normalization. */ readonly bashAllow: string[]; } /** * The host settings service's entry write port. * * A write is a revision-fenced document mutation, so *clearing* a field is what * lets it re-inherit the schema default instead of pinning a copy of it. */ export interface ApprovalConfigWriter { /** Profile entry id the write addresses (the bundle patch's row id). */ readonly entryId: string; /** Merge field values into the entry's user layer. */ update(entryId: string, patch: Record): Promise; /** Remove fields from the entry's user layer, restoring the inherited value. */ clear(entryId: string, fields: readonly string[]): Promise; } /** The resolved settings read/write port the guards and the commands use. */ export interface ApprovalConfigStore { /** The resolved edit-approval settings (always schema-valid). */ loadEdit(): EditApprovalSettings; /** The resolved bash-approval settings. */ loadBash(): BashApprovalSettings; /** Persist one master switch; rejects without a configurable entry. */ saveSwitch(field: ApprovalSwitchField, next: boolean): Promise; } /** * Adapter over the entry's live `Config` and the host's write port. * * Reads re-read the volatile references, so a config-page write is visible at * the next read with no remount and no cache to invalidate — which is why the * guards call `load()` per interception rather than capturing a snapshot. * * Writes apply the clear-when-default rule: a value equal to the schema default * is UNSET rather than pinned. That keeps the profile patch to what the user * actually changed and lets a later default change still reach them — pinning a * copy of today's default would silently opt the user out of it forever. * * @param config - the resolved entry configuration (live references). * @param writer - the entry write port; absent for an entry-less mount, which * makes every write reject instead of silently doing nothing. * @returns the store the commands and the interception read. */ export declare function volatileApprovalStore(config: ApprovalConfig, writer: ApprovalConfigWriter | undefined): ApprovalConfigStore;