import type { SourceStore } from '../source-store.js'; import type { ResolvedWorkspace } from '../workspace.js'; import type { VisualDiagnostic } from '../adapters/visual/protocol-contract.js'; import type { EditorHost } from './editor-host.js'; /** * The editor with no server behind it (#252). * * The session server answers three of the seven browser inputs itself, inline, * without ever waking an agent: a filter, a commit and a layout save are * questions for the ENGINE. The other four - a chat message, a choice, a * navigation, an end - are questions for an AGENT. This host answers the * engine's three over a store the embedder owns, and says plainly that it * cannot answer the rest. * * That split is why the issue says chat is the section a host leaves out. It is * not a feature withheld: with no agent there is nobody to talk to and nothing * to hand control back to. * * SYNCHRONOUS, per ADR 0100. An embedder whose backing store is asynchronous - * D1, S3 - fetches its sources, builds a store over what it fetched, and writes * back what `writeAll` is given. That is the shape the ADR chose over an async * interface, and it is the shape this host is built for. */ export interface LocalHostOptions { /** Where the sources come from and where a commit lands (ADR 0100). */ readonly store: SourceStore; /** * The manifest, already resolved. Resolving one means expanding globs * against a filesystem, which is the one part of the engine that cannot run * here - so the embedder resolves and hands over the result. */ readonly workspace: ResolvedWorkspace; /** What the editor calls this model. Cosmetic; nothing is derived from it. */ readonly title?: string; readonly description?: string; /** Told after every landed commit, so a host can persist what it was given. */ readonly onCommit?: (documents: readonly string[]) => void; /** * The question catalogue the questions section evaluates, or the shipped * `core-enrichment` one when absent (#328). * * The engine is yarramate's and so is the UI; the QUESTIONS belong to * whoever adopted it. `core-enrichment` is a general modelling interview, * right for this repository's own CLI and for a host with no domain of its * own, and wrong for a product whose interview is about its own subject * matter. Until this existed a host could have the questions UI only by * also running yarramate's catalogue, so a product with its own interview * had to omit the section and show its questions on a separate surface, * away from the model they are about. * * Bytes rather than a parsed catalogue, matching what the seam beneath * already takes: a catalogue that does not load leaves the overlay absent * rather than failing the mount, because the overlay is a garnish on the * model and a model frame must not be blocked by it. * * One catalogue, or the composed SET a workspace carries (#369). The * overlay beneath has taken the array since ADR 0129 made composition the * qualification point; this option was the last single-width seam between * a host's composed interview and the pane, and a pane evaluating fewer * catalogues than the host's own question surfaces is a disagreement with * no symptom. A single source stays source-compatible. */ readonly catalogue?: { readonly path: string; readonly source: string; } | readonly { readonly path: string; readonly source: string; }[]; /** * Questions this host has already dealt with and does not want asked again * (#328). * * A host-supplied catalogue alone does not close this: the editor evaluates * the catalogue itself and cannot know that a reviewer set a question aside, * with a reason, recorded somewhere the editor cannot see. Without this the * pane would go on asking a question its own product had answered. * * `subject` absent dismisses the question wherever it appears - the * workspace-scoped entry and every subject's - which is "stop asking this". * `subject` present dismisses it for that subject alone, which is "not for * this one". Dismissal hides a question from the pane and changes nothing * about the model or about what `ask --open` reports; the interview is not * the editor's to settle. */ readonly dismissed?: readonly { readonly questionId: string; readonly subject?: string; }[]; } /** * What a `refresh` did, or why it did nothing (#444). * * A result rather than a boolean, because the caller needs to tell three * different situations apart and act differently on each: it worked, the * workspace will not compile, or the reviewer has staged work against content * that has since moved. `setDecorations` answers with a bare boolean because * decorating is reading and the only failure is a not-there window; refreshing * can fail for reasons a host must be able to explain to a person. */ export type RefreshOutcome = { readonly applied: true; } | { /** * Staged operations pin content this refresh would replace. Nothing was * delivered and the canvas is unchanged, so the reviewer's work is * exactly where they left it; the named documents are what a host should * put in front of them. */ readonly applied: false; readonly reason: 'staged-against-changed-documents'; readonly documents: readonly string[]; } | { /** The store's current contents do not compile; the last good model stands. */ readonly applied: false; readonly reason: 'refused'; readonly diagnostics: readonly VisualDiagnostic[]; }; /** A local host, plus the refresh only a store-owning host can perform. */ export type LocalEditorHost = EditorHost & { readonly refresh: (stagedPins: Readonly>) => RefreshOutcome; }; export declare const createLocalHost: (options: LocalHostOptions) => LocalEditorHost;