@batalabs/virlow-mcp-core 3.84.2 → 3.85.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -212,6 +212,9 @@ export declare class MemoryStore {
212
212
  /** The namespace of a memory this session has seen, without a sync;
213
213
  * undefined for a global memory or one not cached yet. */
214
214
  namespaceOfCached(id: string): string | undefined;
215
+ /** One memory as this session has it, without a sync; undefined when it
216
+ * is not cached. */
217
+ cached(id: string): CachedMemory | undefined;
215
218
  /** Requires a prior sync() in the same unlock to have populated the cache. */
216
219
  list(namespace?: string): CachedMemory[];
217
220
  update(id: string, changes: {
@@ -654,6 +654,11 @@ class MemoryStore {
654
654
  namespaceOfCached(id) {
655
655
  return this.cache.get(id)?.namespace;
656
656
  }
657
+ /** One memory as this session has it, without a sync; undefined when it
658
+ * is not cached. */
659
+ cached(id) {
660
+ return this.cache.get(id);
661
+ }
657
662
  /** Requires a prior sync() in the same unlock to have populated the cache. */
658
663
  list(namespace) {
659
664
  this.requireSession();
@@ -1,5 +1,6 @@
1
1
  /**
2
- * Refuses memories that contain credentials, before anything is written.
2
+ * Refuses memories that contain credentials, payment card and bank account
3
+ * numbers, or government ID numbers, before anything is written.
3
4
  *
4
5
  * Memories are captured automatically, so the rule cannot depend on the AI
5
6
  * remembering not to save a key: a memory is encrypted, but it is recalled
@@ -8,7 +9,11 @@
8
9
  * left out instead of retrying with the secret reworded.
9
10
  *
10
11
  * Deliberately narrow: patterns that are credentials with near certainty,
11
- * plus long high-entropy tokens. A false positive costs one memory; a false
12
+ * plus long high-entropy tokens, plus the restricted data that has a shape
13
+ * to match (card numbers and security codes, IBANs and labelled account
14
+ * numbers, US Social Security numbers, labelled passport, licence and
15
+ * national ID numbers). Health information has no such shape; the server
16
+ * instructions tell the model not to save it. A false positive costs one memory; a false
12
17
  * negative puts a live key into every future prompt that recalls it.
13
18
  */
14
19
  /** What secret the text holds, or null when it holds none. */
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  /**
3
- * Refuses memories that contain credentials, before anything is written.
3
+ * Refuses memories that contain credentials, payment card and bank account
4
+ * numbers, or government ID numbers, before anything is written.
4
5
  *
5
6
  * Memories are captured automatically, so the rule cannot depend on the AI
6
7
  * remembering not to save a key: a memory is encrypted, but it is recalled
@@ -9,7 +10,11 @@
9
10
  * left out instead of retrying with the secret reworded.
10
11
  *
11
12
  * Deliberately narrow: patterns that are credentials with near certainty,
12
- * plus long high-entropy tokens. A false positive costs one memory; a false
13
+ * plus long high-entropy tokens, plus the restricted data that has a shape
14
+ * to match (card numbers and security codes, IBANs and labelled account
15
+ * numbers, US Social Security numbers, labelled passport, licence and
16
+ * national ID numbers). Health information has no such shape; the server
17
+ * instructions tell the model not to save it. A false positive costs one memory; a false
13
18
  * negative puts a live key into every future prompt that recalls it.
14
19
  */
15
20
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -31,7 +36,47 @@ const PATTERNS = [
31
36
  test: /\b(password|passwd|pwd|passphrase|api[_ -]?key|secret|token)\s*[:=]\s*\S{6,}/i,
32
37
  },
33
38
  { what: 'a connection string with a password', test: /\b[a-z][a-z0-9+.-]*:\/\/[^\s:/@]+:[^\s@/]{3,}@/i },
39
+ { what: 'a card security code', test: /\b(cvv2?|cvc2?|card security code)\s*[:#=]?\s*\d{3,4}\b/i },
40
+ {
41
+ // The issued format: no 000/666/9xx area, no 00 group, no 0000 serial.
42
+ // Phone numbers (3-3-4) and dates (4-2-2) do not take this shape.
43
+ what: 'a Social Security number',
44
+ test: /\b(?!000|666|9\d\d)\d{3}-(?!00)\d{2}-(?!0000)\d{4}\b/,
45
+ },
46
+ {
47
+ what: 'a Social Security number',
48
+ test: /\b(ssn|social security(\s+(number|no\.?|#))?)\b\D{0,20}\d{3}[ -]?\d{2}[ -]?\d{4}\b/i,
49
+ },
50
+ {
51
+ what: 'a bank account number',
52
+ test: /\b((bank\s+)?account|acct|routing)\s*(number|num|no\.?|#)\s*[:#=]?\s*\d[\d -]{4,}\d\b/i,
53
+ },
54
+ {
55
+ // A labelled ID followed by something with a digit in it, so "passport
56
+ // renewal is due in March" is a fact and "passport no. X1234567" is not.
57
+ what: 'a government ID number',
58
+ test: /\b(passport|driver'?s?\s+licen[cs]e|national\s+(id|insurance)|tax\s+(id|identification)|aadhaar|nino)(\s+(number|num|no\.?|#))?\s*[:#=]?\s*(?=[A-Z0-9-]*\d)[A-Z0-9][A-Z0-9-]{4,}\b/i,
59
+ },
34
60
  ];
61
+ /** An IBAN that passes its ISO 13616 mod-97 check: country code, two check
62
+ * digits, then 11 to 30 letters and digits, spaces allowed in groups of 4. */
63
+ function hasIban(text) {
64
+ for (const [match] of text.matchAll(/\b[A-Z]{2}\d{2}(?: ?[A-Z0-9]){11,30}\b/g)) {
65
+ const iban = match.replace(/ /g, '');
66
+ if (iban.length < 15 || iban.length > 34)
67
+ continue;
68
+ const rearranged = iban.slice(4) + iban.slice(0, 4);
69
+ let remainder = 0;
70
+ for (const ch of rearranged) {
71
+ const value = ch >= 'A' && ch <= 'Z' ? String(ch.charCodeAt(0) - 55) : ch;
72
+ for (const digit of value)
73
+ remainder = (remainder * 10 + Number(digit)) % 97;
74
+ }
75
+ if (remainder === 1)
76
+ return true;
77
+ }
78
+ return false;
79
+ }
35
80
  /** Luhn-valid runs of 13 to 19 digits, spaces or dashes allowed. */
36
81
  function hasCardNumber(text) {
37
82
  for (const match of text.matchAll(/\b(?:\d[ -]?){13,19}\b/g)) {
@@ -87,14 +132,17 @@ function findSecret(text) {
87
132
  }
88
133
  if (hasCardNumber(text))
89
134
  return 'a card number';
135
+ if (hasIban(text))
136
+ return 'a bank account number';
90
137
  if (hasHighEntropyToken(text))
91
138
  return 'what looks like a key or token';
92
139
  return null;
93
140
  }
94
141
  class SecretInMemoryError extends Error {
95
142
  constructor(what) {
96
- super(`Not saved: this memory contains ${what}. Memories are recalled into prompts, so credentials are never ` +
97
- 'stored. Save the fact without the secret (for example "the API key is in 1Password"), not the secret.');
143
+ super(`Not saved: this memory contains ${what}. Memories are recalled into prompts, so credentials, card and ` +
144
+ 'account numbers and ID numbers are never stored. Save the fact without it (for example "the API key ' +
145
+ 'is in 1Password"), not the value itself.');
98
146
  this.name = 'SecretInMemoryError';
99
147
  }
100
148
  }
@@ -0,0 +1,82 @@
1
+ /** The four fields every tool carries. Required, so a missing hint is a
2
+ * compile error rather than an omission a reviewer finds. */
3
+ export interface VirlowToolAnnotations {
4
+ title: string;
5
+ readOnlyHint: boolean;
6
+ destructiveHint: boolean;
7
+ openWorldHint: boolean;
8
+ }
9
+ export declare const TOOL_ANNOTATIONS: {
10
+ readonly unlock: VirlowToolAnnotations;
11
+ readonly lock: VirlowToolAnnotations;
12
+ readonly status: VirlowToolAnnotations;
13
+ readonly add_memory: VirlowToolAnnotations;
14
+ readonly search_memory: VirlowToolAnnotations;
15
+ readonly list_memories: VirlowToolAnnotations;
16
+ readonly recall_entity: VirlowToolAnnotations;
17
+ readonly link_memory: VirlowToolAnnotations;
18
+ readonly merge_entities: VirlowToolAnnotations;
19
+ readonly memory_context: VirlowToolAnnotations;
20
+ readonly memory_health: VirlowToolAnnotations;
21
+ readonly describe_entity: VirlowToolAnnotations;
22
+ readonly untyped_entities: VirlowToolAnnotations;
23
+ readonly update_memory: VirlowToolAnnotations;
24
+ readonly delete_memory: VirlowToolAnnotations;
25
+ readonly search_notes: VirlowToolAnnotations;
26
+ readonly list_notes: VirlowToolAnnotations;
27
+ readonly list_folders: VirlowToolAnnotations;
28
+ readonly read_note: VirlowToolAnnotations;
29
+ readonly create_note: VirlowToolAnnotations;
30
+ readonly update_note: VirlowToolAnnotations;
31
+ readonly get_backlinks: VirlowToolAnnotations;
32
+ readonly list_folder_view: VirlowToolAnnotations;
33
+ readonly list_properties: VirlowToolAnnotations;
34
+ readonly define_property: VirlowToolAnnotations;
35
+ readonly read_dashboard: VirlowToolAnnotations;
36
+ readonly set_dashboard: VirlowToolAnnotations;
37
+ readonly set_properties: VirlowToolAnnotations;
38
+ readonly move_note: VirlowToolAnnotations;
39
+ readonly set_star: VirlowToolAnnotations;
40
+ readonly archive_note: VirlowToolAnnotations;
41
+ readonly trash_note: VirlowToolAnnotations;
42
+ readonly create_folder: VirlowToolAnnotations;
43
+ readonly list_attachments: VirlowToolAnnotations;
44
+ readonly add_attachment: VirlowToolAnnotations;
45
+ readonly read_attachment: VirlowToolAnnotations;
46
+ readonly rename_attachment: VirlowToolAnnotations;
47
+ readonly move_attachment: VirlowToolAnnotations;
48
+ readonly delete_attachment: VirlowToolAnnotations;
49
+ readonly restore_attachment: VirlowToolAnnotations;
50
+ };
51
+ export type ToolName = keyof typeof TOOL_ANNOTATIONS;
52
+ /**
53
+ * A tool's annotations for this host. Only read_attachment varies: with file
54
+ * access its `save_to` / `overwrite` can replace a file on the user's disk.
55
+ * A fresh object each call, so nothing downstream can mutate the table.
56
+ */
57
+ export declare function toolAnnotations(name: ToolName, opts?: {
58
+ fileAccess?: boolean;
59
+ }): VirlowToolAnnotations;
60
+ /**
61
+ * Short status lines ChatGPT shows while a tool runs and once it returns
62
+ * (`openai/toolInvocation/invoking` and `.../invoked`, 64 characters at most).
63
+ * Other clients ignore `_meta`. Only the tools a user sees most often in a
64
+ * conversation carry them.
65
+ */
66
+ export declare const INVOCATION_STATUS: Partial<Record<ToolName, {
67
+ invoking: string;
68
+ invoked: string;
69
+ }>>;
70
+ /**
71
+ * Everything registerTool takes besides the description, schema and handler:
72
+ * the display title, the annotations and, where there are any, the `_meta`
73
+ * keys: the status line, and the inline card for the tools that have one
74
+ * (see widgets.ts). Spread into each registerTool config.
75
+ */
76
+ export declare function toolConfig(name: ToolName, opts?: {
77
+ fileAccess?: boolean;
78
+ }): {
79
+ title: string;
80
+ annotations: VirlowToolAnnotations;
81
+ _meta?: Record<string, unknown>;
82
+ };
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.INVOCATION_STATUS = exports.TOOL_ANNOTATIONS = void 0;
4
+ exports.toolAnnotations = toolAnnotations;
5
+ exports.toolConfig = toolConfig;
6
+ /**
7
+ * MCP tool annotations for every tool the server registers.
8
+ *
9
+ * Clients use these to decide when to ask the user before a call: ChatGPT,
10
+ * for one, confirms a write and asks again for anything marked destructive,
11
+ * and its plugin review requires all three hints to be explicit booleans on
12
+ * every tool. They live in one table, rather than inline at each
13
+ * registerTool call, so the whole surface can be read and reviewed at once
14
+ * and a test can hold every registered tool to it.
15
+ *
16
+ * The rules applied:
17
+ *
18
+ * - readOnlyHint: true only when the call changes nothing the user owns
19
+ * (retrieval, search, listings, status). Refreshing this process's own
20
+ * cache does not count as a change.
21
+ * - destructiveHint: true when the call can overwrite, remove, hide, move or
22
+ * rewrite something the user already has, even when the app can undo it
23
+ * (Trash, version history, a kept previous dashboard). false only for
24
+ * additive writes and for state changes that lose nothing.
25
+ * - openWorldHint: false everywhere. Every tool acts on the user's own
26
+ * private Virlow workspace; none searches the web or writes to an arbitrary
27
+ * destination.
28
+ *
29
+ * Judgment calls, so the next reader does not have to rediscover them:
30
+ *
31
+ * - add_memory and link_memory are not destructive. add_memory only folds
32
+ * into an existing memory when it is a near-identical restatement
33
+ * (similarity at or above DEDUPE_UPDATE_THRESHOLD) and never when the new
34
+ * fact contradicts the old one; superseded facts get an end date and are
35
+ * kept as history, never removed. link_memory only adds entities and
36
+ * relations, ending superseded facts the same way.
37
+ * - describe_entity is destructive: a kind or note given there replaces the
38
+ * one stored, and an empty note clears it.
39
+ * - set_star is not destructive: a star is a reversible marker with nothing
40
+ * behind it. archive_note is: it takes the note out of the user's lists.
41
+ * - unlock and lock change session state, not data, so neither is read-only
42
+ * and neither is destructive. lock only discards this session's in-memory
43
+ * key and caches; nothing stored is touched and unlock restores access.
44
+ * - read_attachment depends on the host. Without file access it only returns
45
+ * the file. With it (local CLI, desktop app) `save_to` writes to the user's
46
+ * disk and `overwrite: true` replaces an existing file, so it is a
47
+ * destructive write there.
48
+ */
49
+ const widgets_js_1 = require("./widgets.js");
50
+ const read = (title) => ({
51
+ title,
52
+ readOnlyHint: true,
53
+ destructiveHint: false,
54
+ openWorldHint: false,
55
+ });
56
+ const additive = (title) => ({
57
+ title,
58
+ readOnlyHint: false,
59
+ destructiveHint: false,
60
+ openWorldHint: false,
61
+ });
62
+ const destructive = (title) => ({
63
+ title,
64
+ readOnlyHint: false,
65
+ destructiveHint: true,
66
+ openWorldHint: false,
67
+ });
68
+ exports.TOOL_ANNOTATIONS = {
69
+ // vault lifecycle
70
+ unlock: additive('Unlock Virlow'),
71
+ lock: additive('Lock Virlow'),
72
+ status: read('Check Virlow status'),
73
+ // memories
74
+ add_memory: additive('Save a memory'),
75
+ search_memory: read('Search memories'),
76
+ list_memories: read('List memories'),
77
+ recall_entity: read('Recall a person or project'),
78
+ link_memory: additive('Link a memory to entities'),
79
+ merge_entities: destructive('Merge two entities'),
80
+ memory_context: read('Get memory briefing'),
81
+ memory_health: read('Check memory health'),
82
+ describe_entity: destructive('Describe an entity'),
83
+ untyped_entities: read('List entities without a kind'),
84
+ update_memory: destructive('Update a memory'),
85
+ delete_memory: destructive('Delete a memory'),
86
+ // notes
87
+ search_notes: read('Search notes'),
88
+ list_notes: read('List notes'),
89
+ list_folders: read('List folders'),
90
+ read_note: read('Read a note'),
91
+ create_note: additive('Create a note'),
92
+ update_note: destructive('Update a note'),
93
+ get_backlinks: read('Get backlinks'),
94
+ list_folder_view: read('Read folder table view'),
95
+ list_properties: read('List folder properties'),
96
+ define_property: additive('Define a folder property'),
97
+ read_dashboard: read('Read a dashboard'),
98
+ set_dashboard: destructive('Replace a dashboard'),
99
+ set_properties: destructive('Set note properties'),
100
+ move_note: destructive('Move a note'),
101
+ set_star: additive('Star or unstar a note'),
102
+ archive_note: destructive('Archive or unarchive a note'),
103
+ trash_note: destructive('Move a note to the trash'),
104
+ create_folder: additive('Create a folder'),
105
+ // attachments
106
+ list_attachments: read('List attachments'),
107
+ add_attachment: additive('Attach a file'),
108
+ read_attachment: read('Read an attachment'),
109
+ rename_attachment: destructive('Rename an attachment'),
110
+ move_attachment: destructive('Move an attachment'),
111
+ delete_attachment: destructive('Delete an attachment'),
112
+ restore_attachment: additive('Restore an attachment'),
113
+ };
114
+ /**
115
+ * A tool's annotations for this host. Only read_attachment varies: with file
116
+ * access its `save_to` / `overwrite` can replace a file on the user's disk.
117
+ * A fresh object each call, so nothing downstream can mutate the table.
118
+ */
119
+ function toolAnnotations(name, opts = {}) {
120
+ if (name === 'read_attachment' && opts.fileAccess === true) {
121
+ return destructive('Read or save an attachment');
122
+ }
123
+ return { ...exports.TOOL_ANNOTATIONS[name] };
124
+ }
125
+ /**
126
+ * Short status lines ChatGPT shows while a tool runs and once it returns
127
+ * (`openai/toolInvocation/invoking` and `.../invoked`, 64 characters at most).
128
+ * Other clients ignore `_meta`. Only the tools a user sees most often in a
129
+ * conversation carry them.
130
+ */
131
+ exports.INVOCATION_STATUS = {
132
+ add_memory: { invoking: 'Saving to Virlow…', invoked: 'Saved to Virlow' },
133
+ update_memory: { invoking: 'Updating Virlow…', invoked: 'Updated Virlow' },
134
+ search_memory: { invoking: 'Checking Virlow…', invoked: 'Checked Virlow' },
135
+ memory_context: { invoking: 'Checking Virlow…', invoked: 'Checked Virlow' },
136
+ recall_entity: { invoking: 'Checking Virlow…', invoked: 'Checked Virlow' },
137
+ };
138
+ /**
139
+ * Everything registerTool takes besides the description, schema and handler:
140
+ * the display title, the annotations and, where there are any, the `_meta`
141
+ * keys: the status line, and the inline card for the tools that have one
142
+ * (see widgets.ts). Spread into each registerTool config.
143
+ */
144
+ function toolConfig(name, opts = {}) {
145
+ const annotations = toolAnnotations(name, opts);
146
+ const status = exports.INVOCATION_STATUS[name];
147
+ const widget = (0, widgets_js_1.widgetToolMeta)(name);
148
+ const meta = {
149
+ ...(status && {
150
+ 'openai/toolInvocation/invoking': status.invoking,
151
+ 'openai/toolInvocation/invoked': status.invoked,
152
+ }),
153
+ ...widget,
154
+ };
155
+ return {
156
+ title: annotations.title,
157
+ annotations,
158
+ ...(Object.keys(meta).length > 0 && { _meta: meta }),
159
+ };
160
+ }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Inline cards for hosts that render MCP Apps UI: ChatGPT (Apps SDK) and any
3
+ * other client that implements the MCP Apps extension.
4
+ *
5
+ * Two cards, each one self-contained HTML document served as a `ui://`
6
+ * resource:
7
+ *
8
+ * - saved-memory: shown after add_memory and update_memory. "Saved to
9
+ * Virlow" (or "Updated in Virlow"), the label, the fact, the entities as
10
+ * kind-coloured chips, and at most two actions: Undo (a fresh save only)
11
+ * and Open in Virlow.
12
+ * - memory-context: shown after memory_context. "What Virlow knows": a few
13
+ * recent facts and the people and projects they are about, with one
14
+ * action, Open in Virlow.
15
+ *
16
+ * Why it is registered for every deployment, not only the hosted connector:
17
+ *
18
+ * - Nothing changes for a client that does not render UI. The text `content`
19
+ * every tool returned before is returned unchanged; `structuredContent` and
20
+ * `_meta` are extra fields such a client ignores, and a client that never
21
+ * reads a `ui://` resource never sees the HTML.
22
+ * - "Hosted only" would not mean "ChatGPT only": the hosted connector also
23
+ * serves claude.ai, and Claude Desktop (the local CLI's main host) renders
24
+ * MCP Apps too. So the card has to be right in every host anyway, which is
25
+ * why it speaks both bridges (window.openai and the MCP Apps postMessage
26
+ * protocol) rather than ChatGPT's alone.
27
+ * - One tool surface for both deployments is the rule this package exists
28
+ * for (see tools.ts); a host-specific `_meta` would be the first exception.
29
+ *
30
+ * The page loads nothing from the network: inline CSS and script, system
31
+ * fonts, the brand mark as inline SVG. Its only way out is the host's own
32
+ * bridge (callTool, openExternal), so its CSP declares no domains at all.
33
+ * Data is written with textContent, never as markup: a memory's text is
34
+ * whatever a model or a person typed.
35
+ */
36
+ import type { EntityKind } from './memory-graph.js';
37
+ /** The MCP Apps resource type. ChatGPT reads it too. */
38
+ export declare const WIDGET_MIME_TYPE = "text/html;profile=mcp-app";
39
+ export declare const SAVED_MEMORY_URI = "ui://widget/saved-memory.html";
40
+ export declare const MEMORY_CONTEXT_URI = "ui://widget/memory-context.html";
41
+ /** Where "Open in Virlow" goes. The web app has no per-memory route, so it
42
+ * opens the app itself. */
43
+ export declare const VIRLOW_APP_URL = "https://app.virlow.com";
44
+ /**
45
+ * The thirteen kind colours, light and dark. A copy of KIND_COLORS in the
46
+ * web app (src/lib/entityKinds.ts), which cannot be imported here: that
47
+ * module pulls in lucide-react. A test holds the two to the same values.
48
+ */
49
+ export declare const KIND_COLORS: Record<EntityKind, {
50
+ light: string;
51
+ dark: string;
52
+ }>;
53
+ export interface CardEntity {
54
+ name: string;
55
+ kind: EntityKind;
56
+ }
57
+ /** structuredContent of add_memory and update_memory. */
58
+ export interface SavedMemoryContent {
59
+ id: string;
60
+ label: string;
61
+ text: string;
62
+ /** The project it was saved under; null for a memory that applies everywhere. */
63
+ namespace: string | null;
64
+ entities: CardEntity[];
65
+ /** True when an existing memory changed (update_memory, or add_memory
66
+ * folding a near-identical restatement into one), false for a new one. */
67
+ updated: boolean;
68
+ }
69
+ /** structuredContent of memory_context. */
70
+ export interface MemoryContextContent {
71
+ namespace: string | null;
72
+ /** Saving is paused for the account or this project (recall still works). */
73
+ paused: boolean;
74
+ /** The most recent current facts, newest first. */
75
+ facts: Array<{
76
+ id: string;
77
+ label: string;
78
+ text: string;
79
+ }>;
80
+ /** The entities these memories name most, most first. */
81
+ entities: Array<CardEntity & {
82
+ facts: number;
83
+ }>;
84
+ }
85
+ /** How many facts the context card shows; the text result keeps them all. */
86
+ export declare const CONTEXT_CARD_FACTS = 5;
87
+ type WidgetView = 'saved' | 'context';
88
+ /** Which tools show which card. Tools not named here have no UI. */
89
+ export declare const TOOL_WIDGETS: Partial<Record<string, WidgetView>>;
90
+ /** The tool-side `_meta` linking a tool to its card: the MCP Apps key and
91
+ * ChatGPT's alias for it. add_memory's card calls delete_memory (Undo), so
92
+ * it is marked as allowed to call tools. */
93
+ export declare function widgetToolMeta(tool: string): Record<string, unknown> | undefined;
94
+ /** Everything the server needs to list and serve the two resources. */
95
+ export declare const WIDGET_RESOURCES: Array<{
96
+ name: string;
97
+ uri: string;
98
+ title: string;
99
+ description: string;
100
+ view: WidgetView;
101
+ }>;
102
+ /** A `resources/read` result for one card. */
103
+ export declare function readWidget(view: WidgetView): {
104
+ contents: {
105
+ uri: string;
106
+ mimeType: string;
107
+ text: string;
108
+ _meta: Record<string, unknown>;
109
+ }[];
110
+ };
111
+ /** The whole page for one card. */
112
+ export declare function widgetHtml(view: WidgetView): string;
113
+ /** The pieces, for the widget tests: they run the script against the page
114
+ * body in jsdom without a host. */
115
+ export declare const WIDGET_PARTS: {
116
+ css: string;
117
+ script: string;
118
+ };
119
+ export {};