sgiant-ai-widget 1.0.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.
Files changed (93) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +155 -0
  3. package/dist/ai-invalidation.d.ts +29 -0
  4. package/dist/ai-invalidation.d.ts.map +1 -0
  5. package/dist/ai-invalidation.js +121 -0
  6. package/dist/ai-invalidation.js.map +1 -0
  7. package/dist/contrast.d.ts +87 -0
  8. package/dist/contrast.d.ts.map +1 -0
  9. package/dist/contrast.js +151 -0
  10. package/dist/contrast.js.map +1 -0
  11. package/dist/directive.d.ts +37 -0
  12. package/dist/directive.d.ts.map +1 -0
  13. package/dist/directive.js +87 -0
  14. package/dist/directive.js.map +1 -0
  15. package/dist/dom.d.ts +83 -0
  16. package/dist/dom.d.ts.map +1 -0
  17. package/dist/dom.js +146 -0
  18. package/dist/dom.js.map +1 -0
  19. package/dist/host-actions.d.ts +192 -0
  20. package/dist/host-actions.d.ts.map +1 -0
  21. package/dist/host-actions.js +443 -0
  22. package/dist/host-actions.js.map +1 -0
  23. package/dist/icons.d.ts +21 -0
  24. package/dist/icons.d.ts.map +1 -0
  25. package/dist/icons.js +84 -0
  26. package/dist/icons.js.map +1 -0
  27. package/dist/index.d.ts +600 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +4833 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/labels.d.ts +187 -0
  32. package/dist/labels.d.ts.map +1 -0
  33. package/dist/labels.js +232 -0
  34. package/dist/labels.js.map +1 -0
  35. package/dist/limits.d.ts +43 -0
  36. package/dist/limits.d.ts.map +1 -0
  37. package/dist/limits.js +48 -0
  38. package/dist/limits.js.map +1 -0
  39. package/dist/markdown.d.ts +23 -0
  40. package/dist/markdown.d.ts.map +1 -0
  41. package/dist/markdown.js +0 -0
  42. package/dist/markdown.js.map +1 -0
  43. package/dist/message-chrome.d.ts +45 -0
  44. package/dist/message-chrome.d.ts.map +1 -0
  45. package/dist/message-chrome.js +101 -0
  46. package/dist/message-chrome.js.map +1 -0
  47. package/dist/pane-follow.d.ts +67 -0
  48. package/dist/pane-follow.d.ts.map +1 -0
  49. package/dist/pane-follow.js +61 -0
  50. package/dist/pane-follow.js.map +1 -0
  51. package/dist/prefix.d.ts +9 -0
  52. package/dist/prefix.d.ts.map +1 -0
  53. package/dist/prefix.js +9 -0
  54. package/dist/prefix.js.map +1 -0
  55. package/dist/proposal-summary.d.ts +19 -0
  56. package/dist/proposal-summary.d.ts.map +1 -0
  57. package/dist/proposal-summary.js +73 -0
  58. package/dist/proposal-summary.js.map +1 -0
  59. package/dist/replay.d.ts +125 -0
  60. package/dist/replay.d.ts.map +1 -0
  61. package/dist/replay.js +172 -0
  62. package/dist/replay.js.map +1 -0
  63. package/dist/safe-url.d.ts +47 -0
  64. package/dist/safe-url.d.ts.map +1 -0
  65. package/dist/safe-url.js +80 -0
  66. package/dist/safe-url.js.map +1 -0
  67. package/dist/sgiant-ai-widget.global.js +778 -0
  68. package/dist/sgiant-ai-widget.global.js.map +7 -0
  69. package/dist/specs.d.ts +173 -0
  70. package/dist/specs.d.ts.map +1 -0
  71. package/dist/specs.js +231 -0
  72. package/dist/specs.js.map +1 -0
  73. package/dist/storage.d.ts +77 -0
  74. package/dist/storage.d.ts.map +1 -0
  75. package/dist/storage.js +124 -0
  76. package/dist/storage.js.map +1 -0
  77. package/dist/styles.d.ts +29 -0
  78. package/dist/styles.d.ts.map +1 -0
  79. package/dist/styles.js +876 -0
  80. package/dist/styles.js.map +1 -0
  81. package/dist/ui-control.d.ts +8 -0
  82. package/dist/ui-control.d.ts.map +1 -0
  83. package/dist/ui-control.js +8 -0
  84. package/dist/ui-control.js.map +1 -0
  85. package/dist/ui-render.d.ts +75 -0
  86. package/dist/ui-render.d.ts.map +1 -0
  87. package/dist/ui-render.js +617 -0
  88. package/dist/ui-render.js.map +1 -0
  89. package/dist/ui-spec.d.ts +143 -0
  90. package/dist/ui-spec.d.ts.map +1 -0
  91. package/dist/ui-spec.js +288 -0
  92. package/dist/ui-spec.js.map +1 -0
  93. package/package.json +61 -0
@@ -0,0 +1,443 @@
1
+ /**
2
+ * Shared host protocol for Copilot — the ONE definition of the page context the
3
+ * assistant receives and the in-app actions it may take, reused by every
4
+ * surface (org, admin, marketing, onboarding). Keeping this in one place means
5
+ * adding a surface is a few lines, and the action allow-list can't drift between
6
+ * apps.
7
+ *
8
+ * SECURITY: the AI only ever NAMES an action; the host owns the name→effect
9
+ * mapping below. The model never receives a raw URL or endpoint.
10
+ */
11
+ import { isUiControlAction, runUiControl, isOperateAction, runOperateAction, } from "./ui-control.js";
12
+ /**
13
+ * The locale segments the site actually serves.
14
+ *
15
+ * "Any two lowercase letters" is NOT a locale test: `/ai` is a real marketing
16
+ * page, and treating its first segment as a locale rewrote that entry to `/`,
17
+ * which then matched every path with the same segment count. Mirrors
18
+ * a host's i18n config; the host's `Locale` union types it, so
19
+ * a locale that is renamed there fails to compile here.
20
+ */
21
+ const LOCALE_SEGMENTS = ["en", "tr"];
22
+ function isLocaleSegment(seg) {
23
+ return LOCALE_SEGMENTS.includes(seg);
24
+ }
25
+ /** Normalize a path for manifest matching: drop a leading locale segment
26
+ * (marketing "/en/network" → "/network") and any trailing slash. */
27
+ function normalizePath(path) {
28
+ let p = path.replace(/\/+$/, "") || "/";
29
+ const m = p.match(/^\/([a-z]{2})(\/|$)/);
30
+ if (m && isLocaleSegment(m[1]))
31
+ p = p.slice(m[1].length + 1) || "/";
32
+ return p;
33
+ }
34
+ /** Manifest entries are ours and locale-neutral by contract (see
35
+ * `PageManifestEntry.path`), so they get a trailing-slash trim and nothing
36
+ * else — no locale strip, no decoding. */
37
+ function entrySegments(path) {
38
+ return path.replace(/\/+$/, "").split("/").filter(Boolean);
39
+ }
40
+ /**
41
+ * Percent-decode until the result stops changing, so a doubly-encoded segment
42
+ * (`%252e`) is judged by what it finally says rather than by its first layer.
43
+ * Malformed encoding, and nesting past any plausible depth, are refusals —
44
+ * there is no legitimate route we would be rejecting.
45
+ */
46
+ function decodeFully(raw) {
47
+ let cur = raw;
48
+ for (let i = 0; i < 6; i++) {
49
+ if (!cur.includes("%"))
50
+ return cur;
51
+ let next;
52
+ try {
53
+ next = decodeURIComponent(cur);
54
+ }
55
+ catch {
56
+ return null;
57
+ }
58
+ if (next === cur)
59
+ return cur;
60
+ cur = next;
61
+ }
62
+ return null;
63
+ }
64
+ /**
65
+ * Decode ONE raw path segment into the thing a browser will finally resolve it
66
+ * to, or null when it is not a plain segment at all.
67
+ *
68
+ * This is the half of the gate that has to come FIRST. Judging the raw spelling
69
+ * is a blocklist — it refuses `..` and admits `%2e%2e`, `%2E%2E`, `.%2e` and
70
+ * `%252e%252e`, every one of which the URL parser resolves as a double-dot
71
+ * segment (or resolves after one more decode hop on the server).
72
+ */
73
+ function decodeSegment(raw) {
74
+ const decoded = decodeFully(raw);
75
+ if (decoded === null)
76
+ return null;
77
+ // Compatibility forms fold into ASCII: U+FF0E FULLWIDTH FULL STOP twice is
78
+ // `..` after NFKC, and U+FF0F folds to a solidus.
79
+ const seg = decoded.normalize("NFKC");
80
+ // A segment that decodes into a SEPARATOR smuggled structure past the split:
81
+ // `%2f` and `%5c` are both "/" once the URL is parsed.
82
+ if (/[/\\]/.test(seg))
83
+ return null;
84
+ // C0 controls and DEL. Tab/LF/CR matter most — the URL parser STRIPS them, so
85
+ // `.%09.` arrives as `..`.
86
+ if (/[\u0000-\u001f\u007f]/.test(seg))
87
+ return null;
88
+ return seg;
89
+ }
90
+ /**
91
+ * Decode an AI-supplied path into the segments the browser will actually
92
+ * resolve, or null if it is not a root-relative in-app path at all.
93
+ *
94
+ * Decode first, then validate. The caller matches what comes back against the
95
+ * manifest, which is an ALLOW-list; nothing downstream re-inspects spellings.
96
+ */
97
+ function navPathSegments(path) {
98
+ if (typeof path !== "string")
99
+ return null;
100
+ // The URL parser strips leading/trailing C0-and-space before it parses.
101
+ if (path !== path.trim())
102
+ return null;
103
+ if (!path.startsWith("/"))
104
+ return null;
105
+ const bare = path.split(/[?#]/)[0] ?? "";
106
+ // A backslash is a path separator to the URL parser, so `/\evil.example.com`
107
+ // is protocol-relative. No route needs one.
108
+ if (bare.includes("\\"))
109
+ return null;
110
+ // Protocol-relative (`//host`), or an empty interior segment.
111
+ if (bare.includes("//"))
112
+ return null;
113
+ const out = [];
114
+ for (const raw of bare.split("/")) {
115
+ if (!raw)
116
+ continue; // the leading "/" and one trailing "/"
117
+ const seg = decodeSegment(raw);
118
+ if (seg === null)
119
+ return null;
120
+ // Dot segments are relative MOVES, not names. The host prefixes the account
121
+ // after this runs, so `/reports/../../accounts/<them>/x` climbs straight
122
+ // back out of the account it was just given.
123
+ if (seg === "." || seg === "..")
124
+ return null;
125
+ out.push(seg);
126
+ }
127
+ if (out.length && isLocaleSegment(out[0]))
128
+ out.shift();
129
+ return out;
130
+ }
131
+ /**
132
+ * Find the manifest entry that best describes the current path — the entry
133
+ * whose `path` is the longest suffix of the (normalized) current path.
134
+ *
135
+ * A segment written as `:name` matches ANY one segment, so a detail page can
136
+ * be declared once ("/reports/:reportId") instead of being undescribable.
137
+ * Without this a concrete `/reports/<uuid>` matched nothing at all — not even
138
+ * the list page above it, since the uuid is a further segment and the
139
+ * comparison was a plain suffix test — so the assistant silently lost all
140
+ * knowledge of which page the user was standing on.
141
+ *
142
+ * Matching is done per SEGMENT rather than by string, because a suffix test
143
+ * cannot tell a parameter from a literal. The longest match still wins, which
144
+ * keeps a specific entry ahead of a general one.
145
+ */
146
+ export function matchManifest(path, manifest) {
147
+ const segs = (p) => p.split("/").filter(Boolean);
148
+ const pathSegs = segs(normalizePath(path));
149
+ let best;
150
+ let bestLen = -1;
151
+ for (const e of manifest) {
152
+ const entrySegs = segs(e.path);
153
+ // The root entry ("/") describes only the root.
154
+ if (!entrySegs.length) {
155
+ if (!pathSegs.length && bestLen < 0) {
156
+ best = e;
157
+ bestLen = 0;
158
+ }
159
+ continue;
160
+ }
161
+ if (entrySegs.length > pathSegs.length)
162
+ continue;
163
+ const off = pathSegs.length - entrySegs.length;
164
+ const hit = entrySegs.every((seg, i) => seg.startsWith(":") || seg === pathSegs[off + i]);
165
+ if (hit && entrySegs.length > bestLen) {
166
+ best = e;
167
+ bestLen = entrySegs.length;
168
+ }
169
+ }
170
+ return best;
171
+ }
172
+ /**
173
+ * Is this AI-supplied path one of the pages the manifest actually DECLARES?
174
+ *
175
+ * The manifest is the whole security surface for navigation, and until now it
176
+ * was only ever advice: it went into the prompt as "Pages you can open (use
177
+ * ONLY these to navigate)" and nothing checked the answer. The only real gate
178
+ * was a shape test — starts with one `/`, not `//` or `/\` — which every
179
+ * cross-tenant path also passes. `/accounts/<someone-else>/settings` is a
180
+ * root-relative in-app route by that definition, and `orgPath` returns an
181
+ * already-`/accounts/`-prefixed path untouched, so a model that emitted one got
182
+ * it loaded into the deliberately un-sandboxed, same-origin advanced frame.
183
+ *
184
+ * Matched from the START, per segment, unlike `matchManifest` — which matches a
185
+ * SUFFIX because it is handed a full SPA route and has to find the entry that
186
+ * describes it. Here the input is the account-relative path the model wrote, so
187
+ * the manifest's namespace has to be its PREFIX or the check is no gate at all:
188
+ * a suffix test admits `/accounts/<someone-else>/dashboards` on the strength of
189
+ * the `/dashboards` entry. Extra trailing segments ARE allowed — that is how a
190
+ * detail page under a declared list ("/reports/<uuid>") stays reachable — and
191
+ * `:param` segments match any one segment, as in the manifest itself.
192
+ *
193
+ * DECODE FIRST, THEN VALIDATE. The first cut of this refused a literal `..`
194
+ * segment by comparing the raw spelling, which is a blocklist — and a blocklist
195
+ * of shapes is exactly what produced the hole above. `%2e%2e`, `%2E%2E`, `.%2e`
196
+ * and `%252e%252e` all survive a literal comparison and all mean `..` by the
197
+ * time the URL is parsed, so `/reports/%2e%2e/%2e%2e/%2e%2e/accounts/<them>/x`
198
+ * walked straight through it and into the frame. `navPathSegments` resolves the
199
+ * path to what the browser will actually see — percent-decoded to a fixed
200
+ * point, NFKC-folded, backslashes and protocol-relative forms refused — and
201
+ * only then is each segment matched against the manifest.
202
+ *
203
+ * A dot segment is refused rather than resolved: the host prefixes the account
204
+ * AFTER this runs, so resolving here would judge a different path than the one
205
+ * the browser resolves, and no real route contains one.
206
+ *
207
+ * NO MANIFEST MEANS NO NAVIGATION. A host that declares no pages has declared
208
+ * nothing the model may open, and falling back to "any root-relative path" here
209
+ * would restore exactly the hole this closes.
210
+ */
211
+ export function isKnownNavTarget(path, targets) {
212
+ const segs = navPathSegments(path);
213
+ if (segs === null)
214
+ return false;
215
+ if (!targets?.length)
216
+ return false;
217
+ for (const t of targets) {
218
+ if (!t.path)
219
+ continue;
220
+ const entry = entrySegments(t.path);
221
+ // The root entry describes the root, never everything beneath it.
222
+ if (!entry.length) {
223
+ if (!segs.length)
224
+ return true;
225
+ continue;
226
+ }
227
+ if (entry.length > segs.length)
228
+ continue;
229
+ if (entry.every((s, i) => s.startsWith(":") || s === segs[i]))
230
+ return true;
231
+ }
232
+ return false;
233
+ }
234
+ /** Build a standard PageContext from a path (derives `page`, caps the trail).
235
+ * Pass the app's page `manifest` to also attach the current page's descriptor
236
+ * and the navigable-page catalog. */
237
+ export function makePageContext(app, path, recentPages = [], manifest) {
238
+ const page = path.split("/").filter(Boolean).slice(-1)[0] || "home";
239
+ const ctx = {
240
+ app,
241
+ path,
242
+ page,
243
+ recentPages: recentPages.slice(-8),
244
+ };
245
+ if (manifest?.length) {
246
+ ctx.pageInfo = matchManifest(path, manifest);
247
+ ctx.navTargets = manifest.map((e) => ({
248
+ path: e.path,
249
+ title: e.title,
250
+ purpose: e.purpose,
251
+ ...(e.action ? { action: e.action } : {}),
252
+ }));
253
+ }
254
+ return ctx;
255
+ }
256
+ // NOTE: `formatPageContext` and `STANDARD_ACTIONS` lived here and were deleted
257
+ // 2026-08-05 with zero callers. Both were client-side twins of things that moved
258
+ // server-side: prompt assembly runs on the SERVER (a formatPageContextHint in
259
+ // lib/page-context.ts) and the permitted action set is stated in
260
+ // the backend's prompt builder). Don't rebuild a client catalogue — it drifted
261
+ // from the live one (12 actions vs 5) the whole time it sat unused.
262
+ /**
263
+ * Account-relative path each named standard action opens. Single source of truth
264
+ * shared by `createHostActions` (which navigates the parent app there) and the
265
+ * widget's advanced view (which navigates the iframe there via `resolveActionPath`),
266
+ * so the two can't drift.
267
+ */
268
+ export const STANDARD_ACTION_PATHS = {
269
+ "open-dashboards": "/dashboards",
270
+ "open-dashboard-builder": "/dashboards/new/edit",
271
+ "open-billing": "/billing",
272
+ "open-assets": "/assets",
273
+ };
274
+ /** Human confirmation text for each named standard action (post-navigation). */
275
+ const STANDARD_ACTION_DONE = {
276
+ "open-dashboards": "Opened dashboards",
277
+ "open-dashboard-builder": "Opened the dashboard builder",
278
+ "open-billing": "Opened billing",
279
+ "open-assets": "Opened assets",
280
+ };
281
+ /**
282
+ * Is this action PURE NAVIGATION — moving the user to a page and nothing else?
283
+ *
284
+ * The auto-navigate option promises exactly this and nothing more. It used to
285
+ * decide by asking whether the model had attached a `confirm` to its own action,
286
+ * which put the safety decision in the model's hands: an action it emitted
287
+ * without one ran instantly and unattended — and a confirm-less action can
288
+ * spend metered credit, so "auto-navigate" could buy things. Navigation is a
289
+ * closed set — enumerate it, and let everything else wait for the user to
290
+ * press the button.
291
+ */
292
+ export function isNavigationAction(name) {
293
+ // `show-assets` is navigation too — it opens a folder/file and nothing else,
294
+ // buys nothing and changes nothing. It is listed explicitly rather than via
295
+ // STANDARD_ACTION_PATHS because it carries a target, so it has no fixed path.
296
+ return (name === "navigate" ||
297
+ name === "show-assets" ||
298
+ name in STANDARD_ACTION_PATHS);
299
+ }
300
+ /** Said instead of "Opened …" when the user is ALREADY on that page. */
301
+ const STANDARD_ACTION_ALREADY = {
302
+ "open-dashboards": "Already on dashboards",
303
+ "open-dashboard-builder": "Already in the dashboard builder",
304
+ "open-billing": "Already on billing",
305
+ "open-assets": "Already on assets",
306
+ };
307
+ /**
308
+ * Are we already looking at this route?
309
+ *
310
+ * Navigating to the page you are standing on is not a helpful action, it is
311
+ * noise — and worse, it reads as a broken one, because nothing visibly happens.
312
+ * Compared on pathname only: a query string or hash is a filter or an anchor
313
+ * within the same page, not a different destination.
314
+ */
315
+ /** Where an account-relative path really lands, mirroring the hosts' own
316
+ * `orgPath`/`adminPath`: already absolute stays put, anything else is prefixed
317
+ * with the account. Kept in step with those two by construction — they are
318
+ * idempotent for a path that already carries the prefix. */
319
+ function resolveTarget(base, path) {
320
+ return path.startsWith("/accounts/") ? path : `${base}${path}`;
321
+ }
322
+ function alreadyThere(path) {
323
+ if (typeof window === "undefined")
324
+ return false;
325
+ const strip = (p) => p.length > 1 && p.endsWith("/") ? p.slice(0, -1) : p;
326
+ // The QUERY has to count, not just the path (#134). "Open the Rooms folder"
327
+ // is `/assets?folder=…`: judged on pathname alone that is "already there"
328
+ // whenever the user happens to be on /assets, so the one navigation most
329
+ // likely to be requested was the one guaranteed to be refused.
330
+ const [targetPath = "", targetQuery = ""] = path.split("?");
331
+ if (strip(window.location.pathname) !== strip(targetPath))
332
+ return false;
333
+ const current = new URLSearchParams(window.location.search);
334
+ const wanted = new URLSearchParams(targetQuery);
335
+ for (const [k, v] of wanted)
336
+ if (current.get(k) !== v)
337
+ return false;
338
+ return true;
339
+ }
340
+ /**
341
+ * Build the `onWidgetAction(name, data)` handler from the standard allow-listed
342
+ * actions + any app-specific handlers. Pass to `createAiChatWidget`.
343
+ */
344
+ export function createHostActions(cfg) {
345
+ const base = cfg.accountId ? `/accounts/${cfg.accountId}` : "";
346
+ const tr = cfg.t ?? ((_k, d) => d);
347
+ const standard = {
348
+ // Deep-link INTO the library: a folder and/or one file's preview.
349
+ //
350
+ // Two steps on purpose. If the user is elsewhere, the host router has to
351
+ // open /assets first; if they are already there, a same-route push fires no
352
+ // popstate and does not remount, so the library would never hear it — hence
353
+ // showAssetsAt, which writes the query AND announces it (#134).
354
+ "show-assets": (data) => {
355
+ const folderId = data.folderId || null;
356
+ const assetId = data.assetId || null;
357
+ if (!folderId && !assetId)
358
+ return;
359
+ const query = new URLSearchParams();
360
+ if (folderId)
361
+ query.set("folder", folderId);
362
+ if (assetId)
363
+ query.set("asset", assetId);
364
+ const path = `${STANDARD_ACTION_PATHS["open-assets"]}?${query}`;
365
+ if (!alreadyThere(resolveTarget(base, path)))
366
+ cfg.navigate(path);
367
+ cfg.showAssets?.({ folderId, assetId });
368
+ return assetId
369
+ ? tr("aiAssistant.action.actionOpenedFile", "Opened the file")
370
+ : tr("aiAssistant.action.actionOpenedFolder", "Opened the folder");
371
+ },
372
+ navigate: (data) => {
373
+ if (data.path) {
374
+ // The manifest decides, not the path's shape. Floating mode hands the
375
+ // path to the host's own router, which is the same session and the same
376
+ // origin as the advanced frame — so it needs the same gate, refused out
377
+ // loud rather than by returning undefined (an undefined return resolves
378
+ // as success and the chip ticks green over a path we declined).
379
+ if (!isKnownNavTarget(data.path, cfg.pages))
380
+ return tr("aiAssistant.action.actionNotAPage", "That is not a page I can open");
381
+ // Compare what the host will ACTUALLY open, not what the model wrote.
382
+ // The AI emits account-relative paths ("/assets"); the host prefixes
383
+ // the account before routing. Testing the bare path against the real
384
+ // location never matched, so "you are already here" could not fire on
385
+ // the one action most likely to be aimed at the current page.
386
+ if (alreadyThere(resolveTarget(base, data.path)))
387
+ return tr("aiAssistant.action.actionAlreadyThere", "Already there");
388
+ cfg.navigate(data.path);
389
+ return tr("aiAssistant.action.actionOpened", "Opened");
390
+ }
391
+ },
392
+ };
393
+ // The named "open-*" actions all resolve to a fixed account-relative path (see
394
+ // STANDARD_ACTION_PATHS) — generate their handlers so the paths live in ONE
395
+ // place the advanced-view resolver also reads.
396
+ for (const [name, path] of Object.entries(STANDARD_ACTION_PATHS)) {
397
+ standard[name] = () => {
398
+ const target = `${base}${path}`;
399
+ if (alreadyThere(target))
400
+ return tr(`aiAssistant.action.actionAlready_${name.replace(/-/g, "_")}`, STANDARD_ACTION_ALREADY[name] ?? "Already there");
401
+ cfg.navigate(target);
402
+ return tr(`aiAssistant.action.actionDone_${name.replace(/-/g, "_")}`, STANDARD_ACTION_DONE[name] ?? "Opened");
403
+ };
404
+ }
405
+ const map = {
406
+ ...standard,
407
+ ...(cfg.handlers ?? {}),
408
+ };
409
+ return async (action, data) => {
410
+ // Read-only UI control (highlight / scroll-to / focus-field) works on EVERY
411
+ // surface via the pure-DOM twin — no per-app wiring, no confirm (reversible).
412
+ if (isUiControlAction(action)) {
413
+ const ok = runUiControl(action, data.target ?? "");
414
+ // A target that isn't on this page is a FAILURE. Returning undefined
415
+ // resolved the widget's promise and rendered a tick, so "show me where"
416
+ // ticked green while nothing was highlighted.
417
+ if (!ok)
418
+ throw new Error(`no such control on this page: ${data.target}`);
419
+ return tr("aiAssistant.action.actionShownOnPage", "Shown on the page");
420
+ }
421
+ // State-changing UI control (fill / click). The widget has already forced a
422
+ // Confirm step before we get here (renderAction), so this runs post-approval.
423
+ if (isOperateAction(action)) {
424
+ const ok = runOperateAction(action, data.target ?? "", data.value);
425
+ // Same as above, and worse here: the user APPROVED this one. Telling them
426
+ // a fill or a click succeeded when the control was never found means they
427
+ // walk away believing a value was entered.
428
+ if (!ok)
429
+ throw new Error(`no such control on this page: ${data.target}`);
430
+ return tr("aiAssistant.action.actionDoneOnPage", "Done on the page");
431
+ }
432
+ const fn = map[action];
433
+ // THROW, don't shrug. Returning undefined here resolved the widget's
434
+ // promise, and a resolved promise is rendered as "<label> ✓" — so an action
435
+ // this app cannot perform reported itself as done. That is how "Opening
436
+ // Open Assets…" turned into a tick next to a page that never opened. An
437
+ // action we do not have is a failure, and the chip must say so.
438
+ if (!fn)
439
+ throw new Error(`unsupported action: ${action}`);
440
+ return await fn(data);
441
+ };
442
+ }
443
+ //# sourceMappingURL=host-actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-actions.js","sourceRoot":"","sources":["../src/host-actions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export declare const AVATAR_DEFS = "<svg width=\"0\" height=\"0\" style=\"position:absolute\" aria-hidden=\"true\"><defs>\n<linearGradient id=\"sgiant-aiw-av-sweep\" x1=\"0\" y1=\"1\" x2=\"1\" y2=\"0\">\n<stop offset=\"0%\" stop-color=\"#60C7C8\"/><stop offset=\"55%\" stop-color=\"#FBAA34\"/><stop offset=\"100%\" stop-color=\"#FA712D\"/>\n</linearGradient></defs></svg>";
2
+ export declare const AVATAR_SVG = "<svg viewBox=\"0 0 24 24\" class=\"sgiant-aiw-ayca\" aria-hidden=\"true\"><path class=\"sgiant-aiw-av-mark\" d=\"M20.4 14.5A8.6 8.6 0 0 1 9.5 3.6 8.6 8.6 0 1 0 20.4 14.5Z\"/></svg>";
3
+ export declare const ICON_HISTORY = "<svg viewBox=\"0 0 24 24\" width=\"17\" height=\"17\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M3 3v5h5\"/><path d=\"M3.05 13A9 9 0 1 0 6 5.3L3 8\"/><path d=\"M12 7v5l3 2\"/></svg>";
4
+ export declare const ICON_EXPAND = "<svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M15 3h6v6\"/><path d=\"M9 21H3v-6\"/><path d=\"M21 3l-7 7\"/><path d=\"M3 21l7-7\"/></svg>";
5
+ export declare const ICON_COLLAPSE = "<svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M4 14h6v6\"/><path d=\"M20 10h-6V4\"/><path d=\"M14 10l7-7\"/><path d=\"M3 21l7-7\"/></svg>";
6
+ export declare const ICON_COMPASS = "<svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"9\"/><polygon points=\"16.2 7.8 13.4 13.4 7.8 16.2 10.6 10.6 16.2 7.8\"/></svg>";
7
+ export declare const ICON_ADVANCED = "<svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><rect x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"2\"/><line x1=\"10\" y1=\"4\" x2=\"10\" y2=\"20\"/></svg>";
8
+ export declare const ICON_CHEVRON_R = "<svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><polyline points=\"9 18 15 12 9 6\"/></svg>";
9
+ export declare const ICON_DOWNLOAD = "<svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"/><polyline points=\"7 10 12 15 17 10\"/><line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\"/></svg>";
10
+ export declare const ICON_FLAG = "<svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z\"/><line x1=\"4\" y1=\"22\" x2=\"4\" y2=\"15\"/></svg>";
11
+ export declare const ICON_BELL = "<svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9\"/><path d=\"M10.3 21a1.94 1.94 0 0 0 3.4 0\"/></svg>";
12
+ export declare const ICON_BELL_OFF = "<svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/><path d=\"M18.63 13A17.9 17.9 0 0 1 18 8\"/><path d=\"M6.26 6.26A6 6 0 0 0 6 8c0 7-3 9-3 9h14\"/><path d=\"M18 8a6 6 0 0 0-9.33-5\"/><line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"/></svg>";
13
+ export declare const ICON_MORE = "<svg viewBox=\"0 0 24 24\" width=\"17\" height=\"17\" fill=\"currentColor\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"5\" r=\"1.7\"/><circle cx=\"12\" cy=\"12\" r=\"1.7\"/><circle cx=\"12\" cy=\"19\" r=\"1.7\"/></svg>";
14
+ export declare const ICON_ATTACH = "<svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M21.44 11.05l-9.19 9.19a5.5 5.5 0 0 1-7.78-7.78l9.19-9.19a3.5 3.5 0 0 1 4.95 4.95l-9.2 9.19a1.5 1.5 0 0 1-2.12-2.12l8.49-8.49\"/></svg>";
15
+ export declare const ICON_EDIT = "<svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M12 20h9\"/><path d=\"M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z\"/></svg>";
16
+ export declare const ICON_REGEN = "<svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M3 2v6h6\"/><path d=\"M3.51 15a9 9 0 1 0 2.13-9.36L3 8\"/></svg>";
17
+ export declare const ICON_CHEV_L = "<svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><polyline points=\"15 18 9 12 15 6\"/></svg>";
18
+ export declare const ICON_CHEV_R = "<svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><polyline points=\"9 18 15 12 9 6\"/></svg>";
19
+ export declare const ICON_THUMB_UP = "<svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M7 10v12\"/><path d=\"M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z\"/></svg>";
20
+ export declare const ICON_THUMB_DOWN = "<svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M17 14V2\"/><path d=\"M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22a3.13 3.13 0 0 1-3-3.88Z\"/></svg>";
21
+ //# sourceMappingURL=icons.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../src/icons.ts"],"names":[],"mappings":"AA0CA,eAAO,MAAM,WAAW,oVAGO,CAAC;AAQhC,eAAO,MAAM,UAAU,yLAA6K,CAAC;AAGrM,eAAO,MAAM,YAAY,2RAAmQ,CAAC;AAC7R,eAAO,MAAM,WAAW,gSAAsQ,CAAC;AAC/R,eAAO,MAAM,aAAa,iSAAuQ,CAAC;AAElS,eAAO,MAAM,YAAY,2SAAiR,CAAC;AAE3S,eAAO,MAAM,aAAa,2SAAuQ,CAAC;AAClS,eAAO,MAAM,cAAc,uOAAmN,CAAC;AAE/O,eAAO,MAAM,aAAa,8UAAgT,CAAC;AAE3U,eAAO,MAAM,SAAS,sTAA0R,CAAC;AAEjT,eAAO,MAAM,SAAS,qSAA+Q,CAAC;AACtS,eAAO,MAAM,aAAa,4ZAA0X,CAAC;AAGrZ,eAAO,MAAM,SAAS,gOAAoM,CAAC;AAG3N,eAAO,MAAM,WAAW,6UAAyT,CAAC;AAGlV,eAAO,MAAM,SAAS,kRAA4P,CAAC;AACnR,eAAO,MAAM,UAAU,sQAAgP,CAAC;AACxQ,eAAO,MAAM,WAAW,0OAAsN,CAAC;AAC/O,eAAO,MAAM,WAAW,yOAAqN,CAAC;AAE9O,eAAO,MAAM,aAAa,8XAAwW,CAAC;AACnY,eAAO,MAAM,eAAe,6XAAuW,CAAC"}
package/dist/icons.js ADDED
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Every SVG the widget draws: the Copilot mark, its gradient defs, and the
3
+ * chrome icons.
4
+ *
5
+ * Extracted from index.ts (#320). Pure data — one import and no behaviour —
6
+ * which is what makes it the cheapest region to move, and the reason to move
7
+ * it first.
8
+ *
9
+ * It also answers something #306 asks for and #305 warned about. The mark's
10
+ * only escape hatch is `avatarUrl`, which swaps in an `<img>`: an embedder
11
+ * either uses our moon or supplies a BITMAP, with no way to pass a vector.
12
+ * #305 asked that the redraw land "as something replaceable, not a second
13
+ * constant" — and it landed as a constant, here. Making the mark themeable
14
+ * starts by having a file to point at.
15
+ */
16
+ import { PREFIX } from "./prefix.js";
17
+ // Copilot — the CRESCENT (#305). "Copilot = moonlight (tr)" is already the
18
+ // comment on the ASSISTANT design token, and this file's own avatar fallback
19
+ // was documented as "else a crescent glyph" — describing a mark nobody had
20
+ // drawn. This draws it.
21
+ //
22
+ // What it replaces: a morphing SVG blob, an feGaussianBlur+feColorMatrix goo
23
+ // filter, two orbiting metaballs with three <animate> tracks each, a float
24
+ // loop, a blink loop, an orange glow, a gradient ring and a two-layer shadow —
25
+ // EIGHT simultaneous effects to say one thing, "there is a chat here". Each was
26
+ // added for a reason and none was ever taken away, so the launcher was loud at
27
+ // rest and had nothing left to say when a reply was actually waiting.
28
+ //
29
+ // It is ONE path with no filter and no SMIL. That is not only simplicity: a CSS
30
+ // `animation:none` cannot reach a SMIL <animate>, so a reader who asked their OS
31
+ // for stillness got a permanently moving blob in the corner of every page (#308
32
+ // recorded that as unreachable from CSS; this is the fix).
33
+ //
34
+ // THE GROUND RULE, measured rather than chosen. Contrast over the brand sweep:
35
+ // white fails on every stop (teal 2.00, amber 1.93, orange 2.81) and navy
36
+ // clears all of them (8.41 / 8.73 / 5.98); on cream, teal is 1.86 and navy is
37
+ // 15.66. Navy is the only value that survives the whole sweep and cream is the
38
+ // only value that survives navy — so THE MARK AND ITS DISC ALWAYS STRADDLE
39
+ // NAVY. Light ground: navy disc, gradient mark. Ink ground: the whole object
40
+ // inverts to a cream disc with a navy mark. The gradient never makes that
41
+ // second trip, which is why there is no third variant.
42
+ export const AVATAR_DEFS = `<svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs>
43
+ <linearGradient id="${PREFIX}-av-sweep" x1="0" y1="1" x2="1" y2="0">
44
+ <stop offset="0%" stop-color="#60C7C8"/><stop offset="55%" stop-color="#FBAA34"/><stop offset="100%" stop-color="#FA712D"/>
45
+ </linearGradient></defs></svg>`;
46
+ // The mark, taken from the resolved specimen rather than re-derived: two arcs
47
+ // of the SAME radius, which is what makes a crescent read as a MOON. My first
48
+ // attempt used a shallower second arc (r19 against r15) with the tips at top
49
+ // and bottom — geometrically a crescent, but standing straight up. It read as
50
+ // 90 degrees, which is a shape and not a moon. This one is tilted, and the
51
+ // tilt is the whole difference.
52
+ export const AVATAR_SVG = `<svg viewBox="0 0 24 24" class="${PREFIX}-ayca" aria-hidden="true"><path class="${PREFIX}-av-mark" d="M20.4 14.5A8.6 8.6 0 0 1 9.5 3.6 8.6 8.6 0 1 0 20.4 14.5Z"/></svg>`;
53
+ // Small line icons for the header controls (currentColor, 18px).
54
+ export const ICON_HISTORY = `<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 3v5h5"/><path d="M3.05 13A9 9 0 1 0 6 5.3L3 8"/><path d="M12 7v5l3 2"/></svg>`;
55
+ export const ICON_EXPAND = `<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 3h6v6"/><path d="M9 21H3v-6"/><path d="M21 3l-7 7"/><path d="M3 21l7-7"/></svg>`;
56
+ export const ICON_COLLAPSE = `<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 14h6v6"/><path d="M20 10h-6V4"/><path d="M14 10l7-7"/><path d="M3 21l7-7"/></svg>`;
57
+ // Compass — the auto-navigate ("drive me there") toggle.
58
+ export const ICON_COMPASS = `<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><polygon points="16.2 7.8 13.4 13.4 7.8 16.2 10.6 10.6 16.2 7.8"/></svg>`;
59
+ // Advanced view: a panel split into a sidebar + main area (Copilot ⇆ live app).
60
+ export const ICON_ADVANCED = `<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2"/><line x1="10" y1="4" x2="10" y2="20"/></svg>`;
61
+ export const ICON_CHEVRON_R = `<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="9 18 15 12 9 6"/></svg>`;
62
+ // Download — export the current conversation as a .txt transcript.
63
+ export const ICON_DOWNLOAD = `<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>`;
64
+ // Flag — agent/admin oversight: flag the current conversation with a reason.
65
+ export const ICON_FLAG = `<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/><line x1="4" y1="22" x2="4" y2="15"/></svg>`;
66
+ // Bell — toggle a soft chime when a reply arrives.
67
+ export const ICON_BELL = `<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg>`;
68
+ export const ICON_BELL_OFF = `<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M13.73 21a2 2 0 0 1-3.46 0"/><path d="M18.63 13A17.9 17.9 0 0 1 18 8"/><path d="M6.26 6.26A6 6 0 0 0 6 8c0 7-3 9-3 9h14"/><path d="M18 8a6 6 0 0 0-9.33-5"/><line x1="1" y1="1" x2="23" y2="23"/></svg>`;
69
+ // Kebab (vertical dots) — the "More" overflow menu that collects the secondary
70
+ // header controls so they no longer crowd the title bar side-by-side.
71
+ export const ICON_MORE = `<svg viewBox="0 0 24 24" width="17" height="17" fill="currentColor" aria-hidden="true"><circle cx="12" cy="5" r="1.7"/><circle cx="12" cy="12" r="1.7"/><circle cx="12" cy="19" r="1.7"/></svg>`;
72
+ // Paperclip — the composer's attach-a-file control. A crisp line icon replaces
73
+ // the flat 📎 emoji so the button reads as part of the widget, not an OS glyph.
74
+ export const ICON_ATTACH = `<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21.44 11.05l-9.19 9.19a5.5 5.5 0 0 1-7.78-7.78l9.19-9.19a3.5 3.5 0 0 1 4.95 4.95l-9.2 9.19a1.5 1.5 0 0 1-2.12-2.12l8.49-8.49"/></svg>`;
75
+ // Branching controls: edit a user turn, regenerate an assistant reply, and the
76
+ // ‹n/m› sibling switcher arrows.
77
+ export const ICON_EDIT = `<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 20h9"/><path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z"/></svg>`;
78
+ export const ICON_REGEN = `<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 2v6h6"/><path d="M3.51 15a9 9 0 1 0 2.13-9.36L3 8"/></svg>`;
79
+ export const ICON_CHEV_L = `<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="15 18 9 12 15 6"/></svg>`;
80
+ export const ICON_CHEV_R = `<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="9 18 15 12 9 6"/></svg>`;
81
+ // Per-message quality vote (thumbs up/down) — mirrors the React panel's VoteButtons.
82
+ export const ICON_THUMB_UP = `<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 10v12"/><path d="M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z"/></svg>`;
83
+ export const ICON_THUMB_DOWN = `<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M17 14V2"/><path d="M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22a3.13 3.13 0 0 1-3-3.88Z"/></svg>`;
84
+ //# sourceMappingURL=icons.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icons.js","sourceRoot":"","sources":["../src/icons.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,2EAA2E;AAC3E,6EAA6E;AAC7E,2EAA2E;AAC3E,wBAAwB;AACxB,EAAE;AACF,6EAA6E;AAC7E,2EAA2E;AAC3E,+EAA+E;AAC/E,gFAAgF;AAChF,+EAA+E;AAC/E,sEAAsE;AACtE,EAAE;AACF,gFAAgF;AAChF,iFAAiF;AACjF,gFAAgF;AAChF,2DAA2D;AAC3D,EAAE;AACF,+EAA+E;AAC/E,0EAA0E;AAC1E,8EAA8E;AAC9E,+EAA+E;AAC/E,2EAA2E;AAC3E,6EAA6E;AAC7E,0EAA0E;AAC1E,uDAAuD;AACvD,MAAM,CAAC,MAAM,WAAW,GAAG;sBACL,MAAM;;+BAEG,CAAC;AAEhC,8EAA8E;AAC9E,8EAA8E;AAC9E,6EAA6E;AAC7E,8EAA8E;AAC9E,2EAA2E;AAC3E,gCAAgC;AAChC,MAAM,CAAC,MAAM,UAAU,GAAG,mCAAmC,MAAM,0CAA0C,MAAM,iFAAiF,CAAC;AAErM,iEAAiE;AACjE,MAAM,CAAC,MAAM,YAAY,GAAG,gQAAgQ,CAAC;AAC7R,MAAM,CAAC,MAAM,WAAW,GAAG,mQAAmQ,CAAC;AAC/R,MAAM,CAAC,MAAM,aAAa,GAAG,oQAAoQ,CAAC;AAClS,yDAAyD;AACzD,MAAM,CAAC,MAAM,YAAY,GAAG,8QAA8Q,CAAC;AAC3S,gFAAgF;AAChF,MAAM,CAAC,MAAM,aAAa,GAAG,oQAAoQ,CAAC;AAClS,MAAM,CAAC,MAAM,cAAc,GAAG,gNAAgN,CAAC;AAC/O,mEAAmE;AACnE,MAAM,CAAC,MAAM,aAAa,GAAG,6SAA6S,CAAC;AAC3U,6EAA6E;AAC7E,MAAM,CAAC,MAAM,SAAS,GAAG,uRAAuR,CAAC;AACjT,mDAAmD;AACnD,MAAM,CAAC,MAAM,SAAS,GAAG,4QAA4Q,CAAC;AACtS,MAAM,CAAC,MAAM,aAAa,GAAG,uXAAuX,CAAC;AACrZ,+EAA+E;AAC/E,sEAAsE;AACtE,MAAM,CAAC,MAAM,SAAS,GAAG,iMAAiM,CAAC;AAC3N,+EAA+E;AAC/E,gFAAgF;AAChF,MAAM,CAAC,MAAM,WAAW,GAAG,sTAAsT,CAAC;AAClV,+EAA+E;AAC/E,iCAAiC;AACjC,MAAM,CAAC,MAAM,SAAS,GAAG,yPAAyP,CAAC;AACnR,MAAM,CAAC,MAAM,UAAU,GAAG,6OAA6O,CAAC;AACxQ,MAAM,CAAC,MAAM,WAAW,GAAG,mNAAmN,CAAC;AAC/O,MAAM,CAAC,MAAM,WAAW,GAAG,kNAAkN,CAAC;AAC9O,qFAAqF;AACrF,MAAM,CAAC,MAAM,aAAa,GAAG,qWAAqW,CAAC;AACnY,MAAM,CAAC,MAAM,eAAe,GAAG,oWAAoW,CAAC"}