/** * CoeditingRegistry — the INV-10 activation gate (spec §6.4). Holds the set of * documents the writer has explicitly entered into coediting; every surface * (SCM/QuickDiff, comments, preview annotations, edit commands, decorations) * checks membership before attaching. Persisted in workspaceState so a reload * restores the set (the durable sidecar carries the artifacts; this carries * only the mode). */ import * as vscode from "vscode"; const STATE_KEY = "cowriting.coeditingSet"; export class CoeditingRegistry implements vscode.Disposable { private readonly set: Set; private readonly emitter = new vscode.EventEmitter<{ uri: string; coediting: boolean }>(); readonly onDidChange = this.emitter.event; /** Set by the SCM surface (Task 3) so syncContext can expose the baseline mode. */ baselineModeOf: ((uri: vscode.Uri) => "head" | "snapshot" | undefined) | undefined; constructor(private readonly state: vscode.Memento) { this.set = new Set(state.get(STATE_KEY, [])); } enter(uri: vscode.Uri): void { const key = uri.toString(); if (this.set.has(key)) return; this.set.add(key); void this.state.update(STATE_KEY, [...this.set]); this.emitter.fire({ uri: key, coediting: true }); } exit(uri: vscode.Uri): void { const key = uri.toString(); if (!this.set.delete(key)) return; void this.state.update(STATE_KEY, [...this.set]); this.emitter.fire({ uri: key, coediting: false }); } isCoediting(uri: vscode.Uri): boolean { return this.set.has(uri.toString()); } list(): string[] { return [...this.set]; } syncContext(editor: vscode.TextEditor | undefined): void { const coediting = !!editor && this.isCoediting(editor.document.uri); void vscode.commands.executeCommand("setContext", "cowriting.isCoediting", coediting); const mode = coediting && editor ? this.baselineModeOf?.(editor.document.uri) : undefined; void vscode.commands.executeCommand("setContext", "cowriting.baselineMode", mode ?? ""); } dispose(): void { this.emitter.dispose(); } }