slicc-cdp-client 1.41.21

Shared CDP connection for slicc-cdp CLIs
Documentation
(() => {
  if (
    !isSecureContext ||
    'modelContext' in Document.prototype ||
    'modelContext' in document ||
    'modelContext' in navigator
  )
    return;
  const apply = Reflect.apply;
  const define = Object.defineProperty;
  const descriptor = Object.getOwnPropertyDescriptor;
  const parse = JSON.parse;
  const stringify = JSON.stringify;
  const isArray = Array.isArray;
  const then = Promise.prototype.then;
  const StringValue = String;
  const ErrorValue = DOMException;
  const Controller = AbortController;
  const PromiseValue = Promise;
  const resolve = Promise.resolve.bind(Promise);
  const mapGet = Map.prototype.get;
  const mapSet = Map.prototype.set;
  const mapDelete = Map.prototype.delete;
  const mapValues = Map.prototype.values;
  const iteratorNext = Object.getPrototypeOf(new Map().values()).next;
  const push = Array.prototype.push;
  const sort = Array.prototype.sort;
  const slice = String.prototype.slice;
  const add = EventTarget.prototype.addEventListener;
  const remove = EventTarget.prototype.removeEventListener;
  const dispatch = EventTarget.prototype.dispatchEvent;
  const EventValue = Event;
  const abort = AbortController.prototype.abort;
  const ownOrigin = location.origin;
  const registry = new Map();
  const context = new EventTarget();
  const cap = 65536;
  let changes = 0;
  const bounded = (value) => apply(slice, StringValue(value), [0, cap]);
  const copy = (value) => parse(stringify(value));
  const entries = () => {
    const result = [];
    const iterator = apply(mapValues, registry, []);
    for (;;) {
      const entry = apply(iteratorNext, iterator, []);
      if (entry.done) break;
      apply(push, result, [entry.value]);
    }
    return result;
  };
  const changed = () => {
    changes += 1;
    const event = new EventValue('toolchange');
    apply(dispatch, context, [event]);
    if (typeof context.ontoolchange === 'function') context.ontoolchange(event);
  };
  const metadata = (entry, bridge) => {
    const tool = copy(entry.metadata);
    if (bridge) tool.exposedTo = copy(entry.exposedTo);
    else tool.window = window;
    return tool;
  };
  const localTools = (bridge) => {
    const tools = [];
    const records = entries();
    for (let index = 0; index < records.length; index += 1)
      apply(push, tools, [metadata(records[index], bridge)]);
    apply(sort, tools, [(a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0)]);
    return tools;
  };
  const unregister = (name, entry) => {
    if (apply(mapGet, registry, [name]) !== entry) return;
    apply(mapDelete, registry, [name]);
    if (entry.signal) apply(remove, entry.signal, ['abort', entry.onabort]);
    changed();
  };
  const registerTool = (tool, options = {}) => {
    if (!tool || typeof tool.name !== 'string' || !tool.name || typeof tool.execute !== 'function')
      throw new TypeError('A tool needs a name and execute function');
    if (apply(mapGet, registry, [tool.name]))
      throw new ErrorValue('Duplicate tool name', 'InvalidStateError');
    if (options.signal?.aborted) return;
    const schema = tool.inputSchema ?? { type: 'object' };
    if (typeof schema !== 'object' || schema === null || isArray(schema))
      throw new TypeError('inputSchema must be an object');
    const annotations = copy(tool.annotations ?? {});
    if (annotations.readOnly !== undefined) annotations.readOnlyHint = annotations.readOnly;
    if (annotations.consequential !== undefined)
      annotations.consequentialHint = annotations.consequential;
    if (annotations.untrustedContent !== undefined)
      annotations.untrustedContentHint = annotations.untrustedContent;
    const entry = {
      execute: tool.execute,
      metadata: {
        name: tool.name,
        title: tool.title ?? null,
        description: tool.description ?? '',
        inputSchema: copy(schema),
        annotations,
        origin: ownOrigin,
      },
      exposedTo: copy(tool.exposedTo ?? []),
      signal: options.signal,
    };
    entry.onabort = () => unregister(entry.metadata.name, entry);
    if (entry.signal) apply(add, entry.signal, ['abort', entry.onabort, { once: true }]);
    apply(mapSet, registry, [entry.metadata.name, entry]);
    changed();
  };
  const getTools = async () => {
    const tools = localTools(false);
    for (let index = 0; index < window.frames.length; index += 1) {
      try {
        const child = window.frames[index];
        if (child.location.origin !== ownOrigin || !child.document.modelContext) continue;
        const nested = await child.document.modelContext.getTools();
        for (let at = 0; at < nested.length; at += 1) apply(push, tools, [nested[at]]);
      } catch {}
    }
    apply(sort, tools, [(a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0)]);
    return tools;
  };
  const executeTool = async (tool, input, options = {}) => {
    if (tool?.window && tool.window !== window) {
      if (tool.window.location.origin !== ownOrigin)
        throw new ErrorValue('Cross-origin tool access is not allowed', 'SecurityError');
      return tool.window.document.modelContext.executeTool(tool, input, options);
    }
    const name = typeof tool === 'string' ? tool : tool?.name;
    const entry = apply(mapGet, registry, [name]);
    if (!entry) throw new ErrorValue('Unknown tool', 'NotFoundError');
    const signal = options.signal;
    if (signal?.aborted) throw new ErrorValue('Tool invocation aborted', 'AbortError');
    const controller = new Controller();
    let onabort;
    try {
      return await new PromiseValue((fulfill, reject) => {
        onabort = () => {
          apply(abort, controller, []);
          reject(new ErrorValue('Tool invocation aborted', 'AbortError'));
        };
        if (signal) apply(add, signal, ['abort', onabort, { once: true }]);
        const parsed = typeof input === 'string' ? parse(input) : input;
        if (!parsed || typeof parsed !== 'object' || isArray(parsed))
          throw new TypeError('Tool input must be an object');
        apply(then, resolve(entry.execute(parsed, { signal: controller.signal })), [
          (result) => fulfill(typeof result === 'string' ? result : stringify(result ?? null)),
          (error) => reject(new ErrorValue(bounded(error), 'UnknownError')),
        ]);
      });
    } catch (error) {
      if (error?.name === 'AbortError' || error?.name === 'UnknownError') throw error;
      throw new ErrorValue(bounded(error), 'UnknownError');
    } finally {
      if (signal && onabort) apply(remove, signal, ['abort', onabort]);
    }
  };
  define(context, '__slicc_webmcp_shim', { value: true });
  define(context, Symbol.toStringTag, { value: 'ModelContext' });
  define(context, 'registerTool', { value: registerTool });
  define(context, 'getTools', { value: getTools });
  define(context, 'executeTool', { value: executeTool });
  context.ontoolchange = null;
  const alias = (owner, prototype) => {
    define(owner, 'modelContext', {
      configurable: true,
      get() {
        const native = descriptor(prototype, 'modelContext');
        return native?.get ? apply(native.get, this, []) : context;
      },
      set(value) {
        define(owner, 'modelContext', { configurable: true, writable: true, value });
      },
    });
  };
  alias(document, Document.prototype);
  alias(navigator, Navigator.prototype);
  return {
    list() {
      const tools = stringify(localTools(true));
      if (tools.length > cap) return { error: 'limit' };
      return { toolsJson: tools, changes, replaced: document.modelContext !== context };
    },
    async call(name, input, allowConsequential) {
      const entry = apply(mapGet, registry, [name]);
      if (!entry) return { __webmcp_error: 'unknown' };
      if (!allowConsequential && entry.metadata.annotations.consequentialHint)
        return {
          __webmcp_error: 'consequential',
          description: bounded(entry.metadata.description),
        };
      try {
        return { __webmcp_result: bounded(await executeTool(name, input)) };
      } catch (error) {
        return { __webmcp_error: 'threw', message: bounded(error) };
      }
    },
  };
})();