mirror of
https://github.com/backnotprop/plannotator.git
synced 2026-09-14 14:17:26 +08:00
6903d7a3dd
Phase 1 of WebMCP support: a zero-dependency, feature-detected engine in packages/ui/webmcp plus a read-and-comment tool catalog for plan review and annotate (read_document, add_comments, update_comment, remove_comments, reveal, nudge_user, list_documents). No decision tools; the human approves. Zero footprint in browsers without document.modelContext (DOM, network, console, timers, and cookies identical to main), idle until called where the API exists, and never registered inside the annotate iframes. Adds an optional inReplyTo field on annotations for threaded replies. Client-only; no server changes. AI-assisted (Claude) under maintainer direction.
47 lines
1.4 KiB
TypeScript
47 lines
1.4 KiB
TypeScript
/**
|
|
* "An agent has acted" signal for the indicator policy: NOTHING visible may
|
|
* appear merely because `document.modelContext` exists. Only after the first
|
|
* successful tool call in a session does the header show its unobtrusive
|
|
* affordance, which subscribes here.
|
|
*
|
|
* Module-level and dependency-free; a browser without WebMCP never records a
|
|
* call, so subscribers render nothing and the store never changes.
|
|
*/
|
|
import { useSyncExternalStore } from 'react';
|
|
|
|
export interface WebMcpActivity {
|
|
/** Successful tool calls in this page load. */
|
|
calls: number;
|
|
/** Prefixed name of the last successful tool call. */
|
|
lastTool: string | null;
|
|
}
|
|
|
|
let activity: WebMcpActivity = { calls: 0, lastTool: null };
|
|
const listeners = new Set<() => void>();
|
|
|
|
export function recordToolCall(tool: string): void {
|
|
activity = { calls: activity.calls + 1, lastTool: tool };
|
|
for (const listener of listeners) listener();
|
|
}
|
|
|
|
export function getWebMcpActivity(): WebMcpActivity {
|
|
return activity;
|
|
}
|
|
|
|
export function subscribeWebMcpActivity(listener: () => void): () => void {
|
|
listeners.add(listener);
|
|
return () => {
|
|
listeners.delete(listener);
|
|
};
|
|
}
|
|
|
|
/** Mainly for tests. */
|
|
export function resetWebMcpActivity(): void {
|
|
activity = { calls: 0, lastTool: null };
|
|
for (const listener of listeners) listener();
|
|
}
|
|
|
|
export function useWebMcpActivity(): WebMcpActivity {
|
|
return useSyncExternalStore(subscribeWebMcpActivity, getWebMcpActivity, getWebMcpActivity);
|
|
}
|