Files
Michael Ramos f532a149a6 feat(webmcp): change tracker, nudges, useToolset hook and the configure seam
changes.ts assigns a per-annotation seq, keeps tombstones, and holds the
per-tab watermark with an explicit since override; claimOwn makes the
agent's own writes never new to it while a later human edit is.
nudges.ts computes the twelve codes synchronously from page state with
static messages that never embed document or comment text. useToolset
attaches a named set to the document registry, resolves the provider
once per mount, and reconciles rebuilt tool lists in place so a
re-render never touches registerTool; active false aborts the set.
configurePlannotatorUI gains the optional webmcp policy and the package
exports ./webmcp.
2026-08-26 13:46:33 -07:00

89 lines
4.4 KiB
TypeScript

import { setImageSrcResolver, type ImageSrcResolver } from './components/ImageThumbnail';
import { setDocPreviewFetcher, type DocPreviewFetcher, type DocPreviewResult } from './components/InlineMarkdown';
import { setStorageBackend, type StorageBackend } from './utils/storage';
import { setUploadTransport, type UploadTransport, type UploadResult } from './utils/upload';
import { setIdentityProvider, type IdentityProvider } from './utils/identity';
import { setFileTreeBackend, type FileTreeBackend } from './hooks/useFileBrowser';
import { setDraftTransport, type DraftTransport } from './hooks/useAnnotationDraft';
import { setExternalAnnotationTransport, type ExternalAnnotationTransport } from './hooks/useExternalAnnotations';
import { setAITransport, type AITransport } from './hooks/useAIChat';
import { setSkillCatalogTransport, setSkillContentTransport, type SkillCatalogTransport, type SkillContentTransport } from './utils/skillCatalog';
import { setWebMcpPolicy, type WebMcpPolicy } from './webmcp/policy';
import { configStore } from './config';
import type { ServerSyncFn } from './config/configStore';
import type { ExternalAnnotationEvent, VaultNode } from './types';
// One-stop type barrel: every seam contract a host implements is importable
// from this module, next to configurePlannotatorUI itself.
export type {
ImageSrcResolver,
DocPreviewFetcher,
DocPreviewResult,
StorageBackend,
UploadTransport,
UploadResult,
IdentityProvider,
FileTreeBackend,
VaultNode,
DraftTransport,
ExternalAnnotationTransport,
ExternalAnnotationEvent,
AITransport,
SkillCatalogTransport,
SkillContentTransport,
ServerSyncFn,
WebMcpPolicy,
};
type ExternalAnnotationBase = { id: string; source?: string };
export interface PlannotatorUIConfig {
imageSrcResolver?: ImageSrcResolver;
storageBackend?: StorageBackend;
uploadTransport?: UploadTransport;
docPreviewFetcher?: DocPreviewFetcher;
fileTreeBackend?: FileTreeBackend;
identityProvider?: IdentityProvider;
draftTransport?: DraftTransport;
/**
* Base-constraint transport. If your annotation type extends the base
* constraint ({ id: string; source?: string }) with extra fields, call
* setExternalAnnotationTransport<YourType>() directly for full type safety —
* this front-door field intentionally pins the base constraint for ergonomics.
*/
externalAnnotationTransport?: ExternalAnnotationTransport<ExternalAnnotationBase>;
aiTransport?: AITransport;
/** Skill-reference catalog request. Default: `GET /api/skills` on the page origin. */
skillCatalogTransport?: SkillCatalogTransport;
/** Human-only skill contents request for feedback injection. Default: `GET /api/skills/content?name=` on the page origin. */
skillContentTransport?: SkillContentTransport;
serverSync?: ServerSyncFn;
/**
* WebMCP provider policy: `{ enabled, namePrefix }`. Default: enabled
* whenever the browser exposes `document.modelContext`, with the
* `plannotator.` prefix. There is no confirmation seam because the catalog
* exposes nothing consequential: no tool decides, submits or closes.
*/
webmcp?: WebMcpPolicy;
/** Re-hydrate settings from the installed (SYNCHRONOUS) storageBackend after install. */
loadSettingsFromBackend?: boolean;
}
export function configurePlannotatorUI(config: PlannotatorUIConfig): void {
if (config.imageSrcResolver) setImageSrcResolver(config.imageSrcResolver);
if (config.storageBackend) setStorageBackend(config.storageBackend);
if (config.uploadTransport) setUploadTransport(config.uploadTransport);
if (config.docPreviewFetcher) setDocPreviewFetcher(config.docPreviewFetcher);
if (config.fileTreeBackend) setFileTreeBackend(config.fileTreeBackend);
if (config.identityProvider) setIdentityProvider(config.identityProvider);
if (config.draftTransport) setDraftTransport(config.draftTransport);
if (config.externalAnnotationTransport) setExternalAnnotationTransport(config.externalAnnotationTransport);
if (config.aiTransport) setAITransport(config.aiTransport);
if (config.skillCatalogTransport) setSkillCatalogTransport(config.skillCatalogTransport);
if (config.skillContentTransport) setSkillContentTransport(config.skillContentTransport);
if (config.serverSync) configStore.setServerSync(config.serverSync);
if (config.webmcp) setWebMcpPolicy(config.webmcp);
// Re-hydrate AFTER storageBackend is installed (load-bearing order — gated last).
if (config.loadSettingsFromBackend) configStore.loadFromBackend();
}