pith-ui 0.1.1 → 0.1.4

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 (110) hide show
  1. package/AI.md +12 -1
  2. package/API.md +347 -192
  3. package/README.md +3 -1
  4. package/dist/composer.d.ts.map +1 -1
  5. package/dist/composer.js +37 -27
  6. package/dist/composer.js.map +1 -1
  7. package/dist/content/conversation-reader.d.ts.map +1 -1
  8. package/dist/content/conversation-reader.js +8 -1
  9. package/dist/content/conversation-reader.js.map +1 -1
  10. package/dist/content/conversation-view.d.ts.map +1 -1
  11. package/dist/content/conversation-view.js +34 -8
  12. package/dist/content/conversation-view.js.map +1 -1
  13. package/dist/content/image-viewer.d.ts.map +1 -1
  14. package/dist/content/image-viewer.js +11 -3
  15. package/dist/content/image-viewer.js.map +1 -1
  16. package/dist/content/paged-preview.d.ts +1 -1
  17. package/dist/content/paged-preview.d.ts.map +1 -1
  18. package/dist/content/paged-preview.js +4 -2
  19. package/dist/content/paged-preview.js.map +1 -1
  20. package/dist/content/views.d.ts +3 -0
  21. package/dist/content/views.d.ts.map +1 -1
  22. package/dist/content/views.js +110 -41
  23. package/dist/content/views.js.map +1 -1
  24. package/dist/content/welcome.d.ts.map +1 -1
  25. package/dist/content/welcome.js +5 -2
  26. package/dist/content/welcome.js.map +1 -1
  27. package/dist/dom.js +1 -1
  28. package/dist/dom.js.map +1 -1
  29. package/dist/files/panels.d.ts +2 -0
  30. package/dist/files/panels.d.ts.map +1 -1
  31. package/dist/files/panels.js +202 -128
  32. package/dist/files/panels.js.map +1 -1
  33. package/dist/files/systems.d.ts.map +1 -1
  34. package/dist/files/systems.js +37 -64
  35. package/dist/files/systems.js.map +1 -1
  36. package/dist/forms/actions.d.ts +23 -2
  37. package/dist/forms/actions.d.ts.map +1 -1
  38. package/dist/forms/actions.js +53 -25
  39. package/dist/forms/actions.js.map +1 -1
  40. package/dist/forms/custom-connection.d.ts.map +1 -1
  41. package/dist/forms/custom-connection.js +3 -2
  42. package/dist/forms/custom-connection.js.map +1 -1
  43. package/dist/forms/history.d.ts +1 -1
  44. package/dist/forms/history.d.ts.map +1 -1
  45. package/dist/forms/history.js +78 -15
  46. package/dist/forms/history.js.map +1 -1
  47. package/dist/forms/identity.d.ts.map +1 -1
  48. package/dist/forms/identity.js +9 -25
  49. package/dist/forms/identity.js.map +1 -1
  50. package/dist/forms/model-editor.js +3 -3
  51. package/dist/forms/model-editor.js.map +1 -1
  52. package/dist/forms/panels.d.ts +9 -2
  53. package/dist/forms/panels.d.ts.map +1 -1
  54. package/dist/forms/panels.js +79 -88
  55. package/dist/forms/panels.js.map +1 -1
  56. package/dist/forms/provider-login.d.ts.map +1 -1
  57. package/dist/forms/provider-login.js +20 -36
  58. package/dist/forms/provider-login.js.map +1 -1
  59. package/dist/forms/resource-editor.js +5 -4
  60. package/dist/forms/resource-editor.js.map +1 -1
  61. package/dist/foundations.d.ts +1 -1
  62. package/dist/foundations.d.ts.map +1 -1
  63. package/dist/foundations.js +22 -38
  64. package/dist/foundations.js.map +1 -1
  65. package/dist/navigation/context-menu.d.ts +7 -1
  66. package/dist/navigation/context-menu.d.ts.map +1 -1
  67. package/dist/navigation/context-menu.js +60 -57
  68. package/dist/navigation/context-menu.js.map +1 -1
  69. package/dist/navigation/navigation.d.ts +13 -0
  70. package/dist/navigation/navigation.d.ts.map +1 -1
  71. package/dist/navigation/navigation.js +96 -130
  72. package/dist/navigation/navigation.js.map +1 -1
  73. package/dist/operation.d.ts +12 -0
  74. package/dist/operation.d.ts.map +1 -0
  75. package/dist/operation.js +49 -0
  76. package/dist/operation.js.map +1 -0
  77. package/dist/primitives.d.ts +8 -1
  78. package/dist/primitives.d.ts.map +1 -1
  79. package/dist/primitives.js +114 -143
  80. package/dist/primitives.js.map +1 -1
  81. package/dist/reconcile.d.ts +11 -0
  82. package/dist/reconcile.d.ts.map +1 -0
  83. package/dist/reconcile.js +36 -0
  84. package/dist/reconcile.js.map +1 -0
  85. package/dist/select.d.ts +14 -0
  86. package/dist/select.d.ts.map +1 -0
  87. package/dist/select.js +304 -0
  88. package/dist/select.js.map +1 -0
  89. package/dist/styles.css +435 -369
  90. package/dist/surface.d.ts +31 -0
  91. package/dist/surface.d.ts.map +1 -1
  92. package/dist/surface.js +193 -3
  93. package/dist/surface.js.map +1 -1
  94. package/dist/tasks/approval.d.ts.map +1 -1
  95. package/dist/tasks/approval.js +83 -45
  96. package/dist/tasks/approval.js.map +1 -1
  97. package/dist/tasks/permission-element.d.ts +3 -0
  98. package/dist/tasks/permission-element.d.ts.map +1 -0
  99. package/dist/tasks/permission-element.js +10 -0
  100. package/dist/tasks/permission-element.js.map +1 -0
  101. package/dist/tasks/permission.d.ts.map +1 -1
  102. package/dist/tasks/permission.js +37 -18
  103. package/dist/tasks/permission.js.map +1 -1
  104. package/dist/tasks/runtime.d.ts.map +1 -1
  105. package/dist/tasks/runtime.js +30 -13
  106. package/dist/tasks/runtime.js.map +1 -1
  107. package/dist/workspace.d.ts.map +1 -1
  108. package/dist/workspace.js +93 -40
  109. package/dist/workspace.js.map +1 -1
  110. package/package.json +1 -1
package/README.md CHANGED
@@ -4,6 +4,8 @@ Native TypeScript UI building blocks for AI-assisted application development. Ch
4
4
 
5
5
  The source is TypeScript and CSS. The package contains compiled ESM, declarations and a separate stylesheet. It uses browser DOM APIs, native controls and system fonts; no UI framework or animation runtime is required.
6
6
 
7
+ Presentation is fixed rather than assembled from style choices: system UI and monospace code fonts, small/medium/large text at 12/14/16 CSS px, regular/strong weights at 400/600, a shared 1.5 line height, and 4/8/12/16/24 CSS px spacing. Blocks choose the appropriate role automatically. Applications supply their own branding.
8
+
7
9
  ## Try the components
8
10
 
9
11
  The [interactive showroom](https://minifish-org.github.io/pith-ui/) groups **design foundations → base components → product blocks → composed pages**. It exposes real controls, theme and state comparisons, CSS-pixel measurements, spacing rulers and motion playback. Showroom data and actions are simulated and labelled accordingly. Automated checks do not substitute for human acceptance.
@@ -18,7 +20,7 @@ npm run dev
18
20
  ## Use the package
19
21
 
20
22
  ```sh
21
- npm install --save-exact pith-ui@0.1.1
23
+ npm install --save-exact pith-ui@0.1.4
22
24
  ```
23
25
 
24
26
  ```ts
@@ -1 +1 @@
1
- {"version":3,"file":"composer.d.ts","sourceRoot":"","sources":["../src/composer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIzC,MAAM,WAAW,cAAc;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAAE;AAChG,MAAM,WAAW,oBAAoB;IAAG,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;CAAE;AAC5G,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACtE;AACD,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAyCzG;AAED,MAAM,WAAW,cAAc;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;CAAE;AAE1E,wBAAgB,kBAAkB,CAAC,OAAO,EAAE;IAAE,SAAS,EAAE,WAAW,CAAA;CAAE,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAQxH;AACD,MAAM,WAAW,gBAAgB;IAAG,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAAE;AAC3F,wBAAgB,iBAAiB,CAAC,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAA;CAAO,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA2BnL"}
1
+ {"version":3,"file":"composer.d.ts","sourceRoot":"","sources":["../src/composer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,MAAM,WAAW,cAAc;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAAE;AAChG,MAAM,WAAW,oBAAoB;IAAG,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;CAAE;AAC5G,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACtE;AACD,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAyCzG;AAED,MAAM,WAAW,cAAc;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;CAAE;AAE1E,wBAAgB,kBAAkB,CAAC,OAAO,EAAE;IAAE,SAAS,EAAE,WAAW,CAAA;CAAE,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAQxH;AACD,MAAM,WAAW,gBAAgB;IAAG,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAAE;AAC3F,wBAAgB,iBAAiB,CAAC,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAA;CAAO,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAgCnL"}
package/dist/composer.js CHANGED
@@ -1,5 +1,6 @@
1
- import { escape, icon } from './dom.js';
1
+ import { icon, setText } from './dom.js';
2
2
  import { adoptProductParts } from './foundations.js';
3
+ import { reconcileKeyed } from './reconcile.js';
3
4
  export function createPendingMessages(options = {}) {
4
5
  const element = options.container ?? document.createElement('section');
5
6
  element.classList.add('pui-queued-messages');
@@ -79,45 +80,54 @@ export function createAttachments(options = {}) {
79
80
  element.setAttribute('aria-label', 'Image attachments');
80
81
  const parts = adoptProductParts(element);
81
82
  let destroyed = false;
83
+ const figures = new Map([...element.querySelectorAll('[data-attachment-id]')].map(node => [node.dataset.attachmentId, node]));
82
84
  const click = (event) => {
83
85
  const target = event.target;
84
86
  const button = target.closest('[data-remove-image]');
85
- if (button && !button.disabled)
86
- options.onRemove?.(button.dataset.removeImage);
87
- if (target instanceof HTMLImageElement)
88
- options.onOpen?.(target);
87
+ if (button && !button.disabled && options.onRemove) {
88
+ event.stopPropagation();
89
+ options.onRemove(button.dataset.removeImage);
90
+ }
91
+ if (target instanceof HTMLImageElement && options.onOpen) {
92
+ event.stopPropagation();
93
+ options.onOpen(target);
94
+ }
95
+ };
96
+ const keydown = (event) => {
97
+ if (!options.onOpen || !(event.target instanceof HTMLImageElement) || event.isComposing || !['Enter', ' '].includes(event.key))
98
+ return;
99
+ event.preventDefault();
100
+ event.stopPropagation();
101
+ if (!event.repeat)
102
+ options.onOpen(event.target);
89
103
  };
90
104
  element.addEventListener('click', click);
105
+ element.addEventListener('keydown', keydown);
91
106
  return { element, update(state) {
92
107
  if (destroyed)
93
108
  return;
94
109
  element.hidden = !state.items.length;
95
- const keys = new Set(state.items.map(item => item.id));
96
- for (const node of element.querySelectorAll('[data-attachment-id]'))
97
- if (!keys.has(node.dataset.attachmentId))
98
- node.remove();
99
- for (const item of state.items) {
100
- let figure = [...element.children].find(node => node.dataset.attachmentId === item.id);
101
- if (!figure) {
102
- figure = document.createElement('figure');
110
+ reconcileKeyed(element, figures, state.items, { key: item => item.id, element: figure => figure,
111
+ create(item) {
112
+ const figure = document.createElement('figure');
103
113
  figure.className = 'pui-draft-image';
104
114
  figure.dataset.attachmentId = item.id;
105
115
  figure.innerHTML = `<img role="button" tabindex="0" title="Click to enlarge" /><figcaption></figcaption><button type="button" class="pui-remove-image">${icon('close')}</button>`;
106
- }
107
- const image = figure.querySelector('img');
108
- if (image.getAttribute('src') !== item.url)
109
- image.src = item.url;
110
- image.alt = item.name;
111
- figure.querySelector('figcaption').textContent = item.name;
112
- const button = figure.querySelector('button');
113
- button.dataset.removeImage = item.id;
114
- button.setAttribute('aria-label', 'Remove ' + item.name);
115
- parts.action(button).update({ disabled: !!state.disabled });
116
- if (element.children[state.items.indexOf(item)] !== figure)
117
- element.insertBefore(figure, element.children[state.items.indexOf(item)] ?? null);
118
- }
116
+ return figure;
117
+ },
118
+ update(figure, item) {
119
+ const image = figure.querySelector('img');
120
+ if (image.getAttribute('src') !== item.url)
121
+ image.src = item.url;
122
+ image.alt = item.name;
123
+ setText(figure.querySelector('figcaption'), item.name);
124
+ const button = figure.querySelector('button');
125
+ button.dataset.removeImage = item.id;
126
+ button.setAttribute('aria-label', 'Remove ' + item.name);
127
+ parts.action(button).update({ disabled: !!state.disabled });
128
+ }, destroy() { }, });
119
129
  parts.update();
120
130
  }, destroy() { if (destroyed)
121
- return; destroyed = true; parts.destroy(); element.removeEventListener('click', click); element.replaceChildren(); } };
131
+ return; destroyed = true; parts.destroy(); element.removeEventListener('click', click); element.removeEventListener('keydown', keydown); figures.clear(); element.replaceChildren(); } };
122
132
  }
123
133
  //# sourceMappingURL=composer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"composer.js","sourceRoot":"","sources":["../src/composer.ts"],"names":[],"mappings":"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","sourcesContent":["import type { UIBlock } from './core.js';\nimport { escape, icon } from './dom.js';\nimport { adoptProductParts } from './foundations.js';\n\nexport interface PendingMessage { id: string; text: string; mode: string; imageCount?: number; }\nexport interface PendingMessagesState { items: readonly PendingMessage[]; running: boolean; busy: boolean; }\nexport interface PendingMessagesOptions {\n container?: HTMLElement;\n onAction?: (action: 'edit' | 'delete' | 'steer', id: string) => void;\n}\nexport function createPendingMessages(options: PendingMessagesOptions = {}): UIBlock<PendingMessagesState> {\n const element = options.container ?? document.createElement('section');\n element.classList.add('pui-queued-messages'); element.setAttribute('aria-label', 'Pending messages');\n const parts = adoptProductParts(element);\n let destroyed = false;\n const rows = new Map<string, HTMLElement>();\n const heading = document.createElement('div'); heading.className = 'pui-section-heading'; heading.textContent = 'Pending messages';\n element.append(heading);\n const click = (event: Event) => {\n const button = (event.target as Element).closest<HTMLButtonElement>('[data-queue-action]');\n if (button && !button.disabled) options.onAction?.(button.dataset.queueAction as 'edit' | 'delete' | 'steer', button.dataset.queuedMessage!);\n };\n element.addEventListener('click', click);\n return { element, update(state) {\n if (destroyed) return;\n element.hidden = !state.items.length;\n const keep = new Set(state.items.map(item => item.id));\n for (const [key, row] of rows) if (!keep.has(key)) { row.remove(); rows.delete(key); }\n let cursor: Element | null = heading.nextElementSibling;\n for (const item of state.items) {\n let row = rows.get(item.id);\n if (!row) {\n row = document.createElement('div'); row.className = 'pui-queued-message';\n row.innerHTML = `<span class=\"pui-queue-badge\">Instruction</span><div class=\"pui-queued-message-content\"><span class=\"pui-queued-message-text\"></span><small class=\"pui-queue-image-count\"></small></div><div class=\"pui-queued-message-actions\"><button type=\"button\" class=\"pui-quiet-icon pui-queue-steer\" data-queue-action=\"steer\" title=\"Steer the current task at its next turn\">${icon('steer')}<span>Steer</span></button><button type=\"button\" class=\"pui-quiet-icon\" data-queue-action=\"edit\" aria-label=\"Edit pending message\" title=\"Edit message\">${icon('edit')}</button><button type=\"button\" class=\"pui-quiet-icon\" data-queue-action=\"delete\" aria-label=\"Delete pending message\" title=\"Delete message\">${icon('trash')}</button></div>`;\n rows.set(item.id, row);\n }\n row.querySelector<HTMLElement>('.pui-queue-badge')!.hidden = item.mode !== 'steer';\n const text = row.querySelector<HTMLElement>('.pui-queued-message-text')!;\n const value = item.text || 'Image attachment'; if (text.textContent !== value) text.textContent = value; text.title = item.text;\n const count = row.querySelector<HTMLElement>('.pui-queue-image-count')!;\n const label = item.imageCount ? `${item.imageCount} image${item.imageCount === 1 ? '' : 's'}` : '';\n if (count.textContent !== label) count.textContent = label; count.hidden = !item.imageCount;\n for (const button of row.querySelectorAll<HTMLButtonElement>('[data-queue-action]')) {\n button.dataset.queuedMessage = item.id; parts.action(button).update({ disabled: state.busy });\n if (button.dataset.queueAction === 'steer') button.hidden = item.mode !== 'follow-up' || !state.running;\n }\n if (row !== cursor) element.insertBefore(row, cursor);\n cursor = row.nextElementSibling;\n }\n parts.update();\n }, destroy() { if (destroyed) return; destroyed = true; parts.destroy(); element.removeEventListener('click', click); rows.clear(); element.replaceChildren(); } };\n}\n\nexport interface AttachmentItem { id: string; url: string; name: string; }\n\nexport function createDropFeedback(options: { container: HTMLElement }): UIBlock<{ active: boolean; disabled?: boolean }> {\n const element = options.container;\n let destroyed = false;\n return { element, update(state) {\n if (destroyed) return;\n if (state.active && !state.disabled) element.classList.add('pui-drag-images');\n else element.classList.remove('pui-drag-images');\n }, destroy() { destroyed = true; element.classList.remove('pui-drag-images'); } };\n}\nexport interface AttachmentsState { items: readonly AttachmentItem[]; disabled?: boolean; }\nexport function createAttachments(options: { container?: HTMLElement; onRemove?: (id: string) => void; onOpen?: (image: HTMLImageElement) => void } = {}): UIBlock<AttachmentsState> {\n const element = options.container ?? document.createElement('div'); element.classList.add('pui-draft-images'); element.setAttribute('aria-label', 'Image attachments');\n const parts = adoptProductParts(element);\n let destroyed = false;\n const click = (event: Event) => {\n const target = event.target as Element;\n const button = target.closest<HTMLButtonElement>('[data-remove-image]');\n if (button && !button.disabled) options.onRemove?.(button.dataset.removeImage!);\n if (target instanceof HTMLImageElement) options.onOpen?.(target);\n };\n element.addEventListener('click', click);\n return { element, update(state) {\n if (destroyed) return;\n element.hidden = !state.items.length;\n const keys = new Set(state.items.map(item => item.id));\n for (const node of element.querySelectorAll<HTMLElement>('[data-attachment-id]')) if (!keys.has(node.dataset.attachmentId!)) node.remove();\n for (const item of state.items) {\n let figure = [...element.children].find(node => (node as HTMLElement).dataset.attachmentId === item.id) as HTMLElement | undefined;\n if (!figure) { figure = document.createElement('figure'); figure.className = 'pui-draft-image'; figure.dataset.attachmentId = item.id;\n figure.innerHTML = `<img role=\"button\" tabindex=\"0\" title=\"Click to enlarge\" /><figcaption></figcaption><button type=\"button\" class=\"pui-remove-image\">${icon('close')}</button>`; }\n const image = figure.querySelector('img')!; if (image.getAttribute('src') !== item.url) image.src = item.url; image.alt = item.name;\n figure.querySelector('figcaption')!.textContent = item.name;\n const button = figure.querySelector('button')!; button.dataset.removeImage = item.id; button.setAttribute('aria-label', 'Remove ' + item.name); parts.action(button).update({ disabled: !!state.disabled });\n if (element.children[state.items.indexOf(item)] !== figure) element.insertBefore(figure, element.children[state.items.indexOf(item)] ?? null);\n }\n parts.update();\n }, destroy() { if (destroyed) return; destroyed = true; parts.destroy(); element.removeEventListener('click', click); element.replaceChildren(); } };\n}\n"]}
1
+ {"version":3,"file":"composer.js","sourceRoot":"","sources":["../src/composer.ts"],"names":[],"mappings":"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","sourcesContent":["import type { UIBlock } from './core.js';\nimport { icon, setText } from './dom.js';\nimport { adoptProductParts } from './foundations.js';\nimport { reconcileKeyed } from './reconcile.js';\n\nexport interface PendingMessage { id: string; text: string; mode: string; imageCount?: number; }\nexport interface PendingMessagesState { items: readonly PendingMessage[]; running: boolean; busy: boolean; }\nexport interface PendingMessagesOptions {\n container?: HTMLElement;\n onAction?: (action: 'edit' | 'delete' | 'steer', id: string) => void;\n}\nexport function createPendingMessages(options: PendingMessagesOptions = {}): UIBlock<PendingMessagesState> {\n const element = options.container ?? document.createElement('section');\n element.classList.add('pui-queued-messages'); element.setAttribute('aria-label', 'Pending messages');\n const parts = adoptProductParts(element);\n let destroyed = false;\n const rows = new Map<string, HTMLElement>();\n const heading = document.createElement('div'); heading.className = 'pui-section-heading'; heading.textContent = 'Pending messages';\n element.append(heading);\n const click = (event: Event) => {\n const button = (event.target as Element).closest<HTMLButtonElement>('[data-queue-action]');\n if (button && !button.disabled) options.onAction?.(button.dataset.queueAction as 'edit' | 'delete' | 'steer', button.dataset.queuedMessage!);\n };\n element.addEventListener('click', click);\n return { element, update(state) {\n if (destroyed) return;\n element.hidden = !state.items.length;\n const keep = new Set(state.items.map(item => item.id));\n for (const [key, row] of rows) if (!keep.has(key)) { row.remove(); rows.delete(key); }\n let cursor: Element | null = heading.nextElementSibling;\n for (const item of state.items) {\n let row = rows.get(item.id);\n if (!row) {\n row = document.createElement('div'); row.className = 'pui-queued-message';\n row.innerHTML = `<span class=\"pui-queue-badge\">Instruction</span><div class=\"pui-queued-message-content\"><span class=\"pui-queued-message-text\"></span><small class=\"pui-queue-image-count\"></small></div><div class=\"pui-queued-message-actions\"><button type=\"button\" class=\"pui-quiet-icon pui-queue-steer\" data-queue-action=\"steer\" title=\"Steer the current task at its next turn\">${icon('steer')}<span>Steer</span></button><button type=\"button\" class=\"pui-quiet-icon\" data-queue-action=\"edit\" aria-label=\"Edit pending message\" title=\"Edit message\">${icon('edit')}</button><button type=\"button\" class=\"pui-quiet-icon\" data-queue-action=\"delete\" aria-label=\"Delete pending message\" title=\"Delete message\">${icon('trash')}</button></div>`;\n rows.set(item.id, row);\n }\n row.querySelector<HTMLElement>('.pui-queue-badge')!.hidden = item.mode !== 'steer';\n const text = row.querySelector<HTMLElement>('.pui-queued-message-text')!;\n const value = item.text || 'Image attachment'; if (text.textContent !== value) text.textContent = value; text.title = item.text;\n const count = row.querySelector<HTMLElement>('.pui-queue-image-count')!;\n const label = item.imageCount ? `${item.imageCount} image${item.imageCount === 1 ? '' : 's'}` : '';\n if (count.textContent !== label) count.textContent = label; count.hidden = !item.imageCount;\n for (const button of row.querySelectorAll<HTMLButtonElement>('[data-queue-action]')) {\n button.dataset.queuedMessage = item.id; parts.action(button).update({ disabled: state.busy });\n if (button.dataset.queueAction === 'steer') button.hidden = item.mode !== 'follow-up' || !state.running;\n }\n if (row !== cursor) element.insertBefore(row, cursor);\n cursor = row.nextElementSibling;\n }\n parts.update();\n }, destroy() { if (destroyed) return; destroyed = true; parts.destroy(); element.removeEventListener('click', click); rows.clear(); element.replaceChildren(); } };\n}\n\nexport interface AttachmentItem { id: string; url: string; name: string; }\n\nexport function createDropFeedback(options: { container: HTMLElement }): UIBlock<{ active: boolean; disabled?: boolean }> {\n const element = options.container;\n let destroyed = false;\n return { element, update(state) {\n if (destroyed) return;\n if (state.active && !state.disabled) element.classList.add('pui-drag-images');\n else element.classList.remove('pui-drag-images');\n }, destroy() { destroyed = true; element.classList.remove('pui-drag-images'); } };\n}\nexport interface AttachmentsState { items: readonly AttachmentItem[]; disabled?: boolean; }\nexport function createAttachments(options: { container?: HTMLElement; onRemove?: (id: string) => void; onOpen?: (image: HTMLImageElement) => void } = {}): UIBlock<AttachmentsState> {\n const element = options.container ?? document.createElement('div'); element.classList.add('pui-draft-images'); element.setAttribute('aria-label', 'Image attachments');\n const parts = adoptProductParts(element);\n let destroyed = false;\n const figures = new Map([...element.querySelectorAll<HTMLElement>('[data-attachment-id]')].map(node => [node.dataset.attachmentId!, node]));\n const click = (event: Event) => {\n const target = event.target as Element;\n const button = target.closest<HTMLButtonElement>('[data-remove-image]');\n if (button && !button.disabled && options.onRemove) {event.stopPropagation(); options.onRemove(button.dataset.removeImage!);}\n if (target instanceof HTMLImageElement && options.onOpen) {event.stopPropagation(); options.onOpen(target);}\n };\n const keydown = (event: KeyboardEvent) => {\n if (!options.onOpen || !(event.target instanceof HTMLImageElement) || event.isComposing || !['Enter',' '].includes(event.key)) return;\n event.preventDefault(); event.stopPropagation();\n if (!event.repeat) options.onOpen(event.target);\n };\n element.addEventListener('click', click);\n element.addEventListener('keydown', keydown);\n return { element, update(state) {\n if (destroyed) return;\n element.hidden = !state.items.length;\n reconcileKeyed(element,figures,state.items,{key:item=>item.id,element:figure=>figure,\n create(item) {const figure = document.createElement('figure'); figure.className = 'pui-draft-image'; figure.dataset.attachmentId = item.id;\n figure.innerHTML = `<img role=\"button\" tabindex=\"0\" title=\"Click to enlarge\" /><figcaption></figcaption><button type=\"button\" class=\"pui-remove-image\">${icon('close')}</button>`;return figure;},\n update(figure,item) {\n const image = figure.querySelector('img')!; if (image.getAttribute('src') !== item.url) image.src = item.url; image.alt = item.name;\n setText(figure.querySelector('figcaption')!,item.name);\n const button = figure.querySelector('button')!; button.dataset.removeImage = item.id; button.setAttribute('aria-label', 'Remove ' + item.name); parts.action(button).update({ disabled: !!state.disabled });\n },destroy() {},\n });\n parts.update();\n }, destroy() { if (destroyed) return; destroyed = true; parts.destroy(); element.removeEventListener('click', click); element.removeEventListener('keydown', keydown); figures.clear(); element.replaceChildren(); } };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-reader.d.ts","sourceRoot":"","sources":["../../src/content/conversation-reader.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IAAG,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE;AAGzD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,CAInE;AAKD,MAAM,WAAW,yBAAyB;IACxC,cAAc,CAAC,EAAE,WAAW,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC;CACnC;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,iBAAiB,EAAE,OAAO,GAAE,yBAA8B;qBA2LrJ,MAAM,GAAG,IAAI;mBAQf,IAAI;eAYR,MAAM,EAAE,GAAG,IAAI;wBArJH,IAAI;oBAiFR,IAAI;qBAMH,IAAI;eAkEb,IAAI;EAYlB"}
1
+ {"version":3,"file":"conversation-reader.d.ts","sourceRoot":"","sources":["../../src/content/conversation-reader.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IAAG,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE;AAGzD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,CAInE;AAKD,MAAM,WAAW,yBAAyB;IACxC,cAAc,CAAC,EAAE,WAAW,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC;CACnC;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,iBAAiB,EAAE,OAAO,GAAE,yBAA8B;qBA8LrJ,MAAM,GAAG,IAAI;mBAQf,IAAI;eAYR,MAAM,EAAE,GAAG,IAAI;wBAxJH,IAAI;oBAkFR,IAAI;qBAOH,IAAI;eAmEb,IAAI;EAYlB"}
@@ -66,6 +66,8 @@ export function installConversationReader(scroll, messages, bar, latest, options
66
66
  updateLatest();
67
67
  }
68
68
  function followLatest() {
69
+ if (destroyed)
70
+ return;
69
71
  const position = { top: 0, follow: true };
70
72
  if (pendingPosition)
71
73
  pendingPosition = position;
@@ -161,12 +163,16 @@ export function installConversationReader(scroll, messages, bar, latest, options
161
163
  reveal();
162
164
  }
163
165
  function openFind() {
166
+ if (destroyed)
167
+ return;
164
168
  bar.hidden = false;
165
169
  markMatches();
166
170
  field.focus();
167
171
  field.select();
168
172
  }
169
173
  function closeFind() {
174
+ if (destroyed)
175
+ return;
170
176
  bar.hidden = true;
171
177
  clearMarks();
172
178
  matches = [];
@@ -257,7 +263,8 @@ export function installConversationReader(scroll, messages, bar, latest, options
257
263
  updateLatest();
258
264
  });
259
265
  },
260
- prune(ids) { const keep = new Set(ids); for (const id of positions.keys())
266
+ prune(ids) { if (destroyed)
267
+ return; const keep = new Set(ids); for (const id of positions.keys())
261
268
  if (!keep.has(id))
262
269
  positions.delete(id); },
263
270
  followLatest,
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-reader.js","sourceRoot":"","sources":["../../src/content/conversation-reader.ts"],"names":[],"mappings":"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","sourcesContent":["export interface TextRange { start: number; end: number }\n\n// Literal, case-insensitive matches, with offsets into the original text.\nexport function findRanges(text: string, query: string): TextRange[] {\n if (!query) return [];\n const pattern = new RegExp(query.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'giu');\n return [...text.matchAll(pattern)].map((match) => ({ start: match.index!, end: match.index! + match[0].length }));\n}\n\ninterface ReadingPosition { top: number; follow: boolean; anchor?: string; offset?: number }\ninterface Match { key: string; parts: HTMLElement[] }\n\nexport interface ConversationReaderOptions {\n keyboardTarget?: EventTarget;\n isKeyboardBlocked?: () => boolean;\n}\n\nexport function installConversationReader(scroll: HTMLElement, messages: HTMLElement, bar: HTMLElement, latest: HTMLButtonElement, options: ConversationReaderOptions = {}) {\n let destroyed = false;\n const removals: Array<() => void> = [];\n function listen<T extends Event>(target: EventTarget, type: string, listener: (event: T) => void, settings?: AddEventListenerOptions): void {\n target.addEventListener(type, listener as EventListener, settings);\n removals.push(() => target.removeEventListener?.(type, listener as EventListener, settings));\n }\n const field = bar.querySelector<HTMLInputElement>('input')!;\n const count = bar.querySelector<HTMLElement>('[data-find-count]')!;\n const previous = bar.querySelector<HTMLButtonElement>('[data-find-previous]')!;\n const next = bar.querySelector<HTMLButtonElement>('[data-find-next]')!;\n const close = bar.querySelector<HTMLButtonElement>('[data-find-close]')!;\n const positions = new Map<string, ReadingPosition>();\n let activeID = '';\n let matches: Match[] = [];\n let selected = -1;\n let frame = 0;\n let pendingPosition: ReadingPosition | undefined;\n let restoring = false;\n let searchSignature = '';\n let contentHeight = scroll.scrollHeight;\n let viewportHeight = scroll.clientHeight;\n let viewportWidth = scroll.clientWidth;\n\n const nearBottom = () => scroll.scrollHeight - scroll.scrollTop - scroll.clientHeight < 80;\n const layoutChanged = () => contentHeight !== scroll.scrollHeight || viewportHeight !== scroll.clientHeight || viewportWidth !== scroll.clientWidth;\n function recordLayout(): void {\n contentHeight = scroll.scrollHeight;\n viewportHeight = scroll.clientHeight;\n viewportWidth = scroll.clientWidth;\n }\n function capture(follow = nearBottom()): ReadingPosition {\n const top = scroll.getBoundingClientRect().top;\n const anchor = [...messages.querySelectorAll<HTMLElement>('[data-reading-id]')].find((element) => element.getBoundingClientRect().bottom > top);\n return { top: scroll.scrollTop, follow, anchor: anchor?.dataset.readingId, offset: anchor ? anchor.getBoundingClientRect().top - top : undefined };\n }\n function updateLatest(): void { latest.hidden = !messages.childElementCount || nearBottom(); }\n function remember(): void {\n if (activeID && !restoring && !pendingPosition) positions.set(activeID, capture());\n recordLayout();\n updateLatest();\n }\n function restore(position: ReadingPosition): void {\n restoring = true;\n if (position.follow) scroll.scrollTop = scroll.scrollHeight;\n else {\n const anchor = [...messages.querySelectorAll<HTMLElement>('[data-reading-id]')].find((element) => element.dataset.readingId === position.anchor);\n scroll.scrollTop = anchor && position.offset !== undefined\n ? scroll.scrollTop + anchor.getBoundingClientRect().top - scroll.getBoundingClientRect().top - position.offset\n : position.top;\n }\n restoring = false;\n // Following is user intent. Layout changes (including image decoding) must\n // not turn it off, or turn a history reader back into a follower.\n if (activeID) positions.set(activeID, capture(position.follow));\n recordLayout();\n updateLatest();\n }\n function followLatest(): void {\n const position = { top: 0, follow: true };\n if (pendingPosition) pendingPosition = position;\n restore(position);\n }\n\n let cachedMatches = new WeakMap<HTMLElement, { query: string; version?: string; matches: typeof matches }>();\n function clearMarks(root: HTMLElement = messages): void {\n for (const mark of root.querySelectorAll('mark[data-find-match]')) mark.replaceWith(document.createTextNode(mark.textContent || ''));\n root.normalize();\n if (root === messages) cachedMatches = new WeakMap();\n else cachedMatches.delete(root);\n }\n function markMatches(): void {\n const previousKey = matches[selected]?.key;\n matches = [];\n const query = field.value;\n if (!bar.hidden && query) {\n for (const root of messages.querySelectorAll<HTMLElement>('[data-reading-id]')) {\n const cached = cachedMatches.get(root);\n if (cached?.query === query && cached.version === root.dataset.renderVersion) { matches.push(...cached.matches); continue; }\n clearMarks(root);\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {\n acceptNode: (node) => node.parentElement?.closest('button, summary, script, style, [data-find-ignore]') ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT,\n });\n const nodes: { node: Text; start: number; end: number }[] = [];\n let text = '', block: Element | null = null;\n while (walker.nextNode()) {\n const node = walker.currentNode as Text;\n const parent = node.parentElement?.closest('p, pre, li, h1, h2, h3, h4, h5, h6, .pui-user-text, .pui-system-message') || root;\n if (text && parent !== block) text += '\\n';\n block = parent;\n const start = text.length;\n text += node.data;\n nodes.push({ node, start, end: text.length });\n }\n const ranges = findRanges(text, query);\n const base = matches.length;\n matches.push(...ranges.map((range) => ({ key: `${root.dataset.readingId}:${range.start}`, parts: [] })));\n for (const { node, start, end } of nodes) {\n const intersections = ranges.map((range, index) => ({ start: Math.max(start, range.start) - start, end: Math.min(end, range.end) - start, index: base + index })).filter((range) => range.end > range.start);\n if (!intersections.length) continue;\n const fragment = document.createDocumentFragment();\n let offset = 0;\n for (const range of intersections) {\n fragment.append(document.createTextNode(node.data.slice(offset, range.start)));\n const mark = document.createElement('mark');\n mark.dataset.findMatch = String(range.index);\n mark.textContent = node.data.slice(range.start, range.end);\n matches[range.index].parts.push(mark);\n fragment.append(mark);\n offset = range.end;\n }\n fragment.append(document.createTextNode(node.data.slice(offset)));\n node.replaceWith(fragment);\n }\n cachedMatches.set(root, { query, version: root.dataset.renderVersion, matches: matches.slice(base) });\n }\n } else clearMarks();\n const kept = matches.findIndex((match) => match.key === previousKey);\n selected = matches.length ? kept >= 0 ? kept : Math.max(0, Math.min(selected, matches.length - 1)) : -1;\n updateSelection();\n }\n function updateSelection(): void {\n matches.forEach((match, index) => match.parts.forEach((part) => part.classList.toggle('pui-find-current', index === selected)));\n count.textContent = field.value ? matches.length ? `${selected + 1} / ${matches.length}` : 'No matches' : '';\n previous.disabled = next.disabled = !matches.length;\n }\n function reveal(): void {\n const target = matches[selected]?.parts[0];\n if (!target) return;\n for (let parent = target.parentElement; parent && parent !== messages; parent = parent.parentElement) if (parent instanceof HTMLDetailsElement) parent.open = true;\n scroll.scrollTop += target.getBoundingClientRect().top - scroll.getBoundingClientRect().top - scroll.clientHeight / 3;\n remember();\n }\n function move(direction: number): void {\n if (!matches.length) return;\n selected = (selected + direction + matches.length) % matches.length;\n updateSelection();\n reveal();\n }\n function openFind(): void {\n bar.hidden = false;\n markMatches();\n field.focus();\n field.select();\n }\n function closeFind(): void {\n bar.hidden = true;\n clearMarks();\n matches = [];\n selected = -1;\n scroll.focus({ preventScroll: true });\n updateLatest();\n }\n listen(field, 'input', () => { selected = -1; matches = []; markMatches(); reveal(); });\n listen<KeyboardEvent>(field, 'keydown', (event) => {\n if (event.key === 'Enter' && !event.isComposing) { event.preventDefault(); move(event.shiftKey ? -1 : 1); }\n });\n listen(previous, 'click', () => move(-1));\n listen(next, 'click', () => move(1));\n listen(close, 'click', closeFind);\n listen<KeyboardEvent>(options.keyboardTarget || document, 'keydown', (event) => {\n if (event.isComposing || options.isKeyboardBlocked?.()) return;\n if ((event.metaKey || event.ctrlKey) && !event.altKey && event.key.toLowerCase() === 'f') { event.preventDefault(); openFind(); }\n else if (event.key === 'Escape' && !bar.hidden) { event.preventDefault(); closeFind(); }\n });\n listen(latest, 'click', followLatest);\n listen(scroll, 'scroll', () => {\n if (restoring || pendingPosition) return;\n const saved = positions.get(activeID);\n // A resize can clamp scrollTop and dispatch a scroll before ResizeObserver.\n // Only scrolling within a stable layout changes the following preference.\n if (saved && layoutChanged()) restore(saved);\n else if (!saved || Math.abs(scroll.scrollTop - saved.top) > 1) remember();\n else updateLatest();\n }, { passive: true });\n // Async image decoding and resizing must not displace an existing anchor.\n const observer = new ResizeObserver(() => {\n if (destroyed) return;\n if (!pendingPosition && activeID) {\n const saved = positions.get(activeID);\n if (saved) restore(saved);\n }\n updateLatest();\n });\n observer.observe(messages);\n observer.observe(scroll);\n return {\n beforeRender(id: string): void {\n if (destroyed) return;\n if (activeID && !positions.has(activeID)) positions.set(activeID, capture());\n pendingPosition = id === activeID ? pendingPosition || positions.get(activeID) || capture() : positions.get(id) || { top: 0, follow: true };\n if (id !== activeID) { selected = -1; matches = []; searchSignature = ''; }\n activeID = id;\n cancelAnimationFrame(frame);\n },\n afterRender(): void {\n if (destroyed) return;\n const signature = messages.innerHTML;\n if (!bar.hidden && signature !== searchSignature) { markMatches(); searchSignature = messages.innerHTML; }\n frame = requestAnimationFrame(() => {\n if (destroyed) return;\n const position = pendingPosition;\n pendingPosition = undefined;\n if (position) restore(position);\n else updateLatest();\n });\n },\n prune(ids: string[]): void { const keep = new Set(ids); for (const id of positions.keys()) if (!keep.has(id)) positions.delete(id); },\n followLatest,\n openFind,\n closeFind,\n destroy(): void {\n if (destroyed) return;\n destroyed = true;\n cancelAnimationFrame(frame);\n observer.disconnect();\n removals.splice(0).forEach((remove) => remove());\n clearMarks();\n positions.clear();\n matches = [];\n pendingPosition = undefined;\n },\n };\n}\n"]}
1
+ {"version":3,"file":"conversation-reader.js","sourceRoot":"","sources":["../../src/content/conversation-reader.ts"],"names":[],"mappings":"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","sourcesContent":["export interface TextRange { start: number; end: number }\n\n// Literal, case-insensitive matches, with offsets into the original text.\nexport function findRanges(text: string, query: string): TextRange[] {\n if (!query) return [];\n const pattern = new RegExp(query.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'giu');\n return [...text.matchAll(pattern)].map((match) => ({ start: match.index!, end: match.index! + match[0].length }));\n}\n\ninterface ReadingPosition { top: number; follow: boolean; anchor?: string; offset?: number }\ninterface Match { key: string; parts: HTMLElement[] }\n\nexport interface ConversationReaderOptions {\n keyboardTarget?: EventTarget;\n isKeyboardBlocked?: () => boolean;\n}\n\nexport function installConversationReader(scroll: HTMLElement, messages: HTMLElement, bar: HTMLElement, latest: HTMLButtonElement, options: ConversationReaderOptions = {}) {\n let destroyed = false;\n const removals: Array<() => void> = [];\n function listen<T extends Event>(target: EventTarget, type: string, listener: (event: T) => void, settings?: AddEventListenerOptions): void {\n target.addEventListener(type, listener as EventListener, settings);\n removals.push(() => target.removeEventListener?.(type, listener as EventListener, settings));\n }\n const field = bar.querySelector<HTMLInputElement>('input')!;\n const count = bar.querySelector<HTMLElement>('[data-find-count]')!;\n const previous = bar.querySelector<HTMLButtonElement>('[data-find-previous]')!;\n const next = bar.querySelector<HTMLButtonElement>('[data-find-next]')!;\n const close = bar.querySelector<HTMLButtonElement>('[data-find-close]')!;\n const positions = new Map<string, ReadingPosition>();\n let activeID = '';\n let matches: Match[] = [];\n let selected = -1;\n let frame = 0;\n let pendingPosition: ReadingPosition | undefined;\n let restoring = false;\n let searchSignature = '';\n let contentHeight = scroll.scrollHeight;\n let viewportHeight = scroll.clientHeight;\n let viewportWidth = scroll.clientWidth;\n\n const nearBottom = () => scroll.scrollHeight - scroll.scrollTop - scroll.clientHeight < 80;\n const layoutChanged = () => contentHeight !== scroll.scrollHeight || viewportHeight !== scroll.clientHeight || viewportWidth !== scroll.clientWidth;\n function recordLayout(): void {\n contentHeight = scroll.scrollHeight;\n viewportHeight = scroll.clientHeight;\n viewportWidth = scroll.clientWidth;\n }\n function capture(follow = nearBottom()): ReadingPosition {\n const top = scroll.getBoundingClientRect().top;\n const anchor = [...messages.querySelectorAll<HTMLElement>('[data-reading-id]')].find((element) => element.getBoundingClientRect().bottom > top);\n return { top: scroll.scrollTop, follow, anchor: anchor?.dataset.readingId, offset: anchor ? anchor.getBoundingClientRect().top - top : undefined };\n }\n function updateLatest(): void { latest.hidden = !messages.childElementCount || nearBottom(); }\n function remember(): void {\n if (activeID && !restoring && !pendingPosition) positions.set(activeID, capture());\n recordLayout();\n updateLatest();\n }\n function restore(position: ReadingPosition): void {\n restoring = true;\n if (position.follow) scroll.scrollTop = scroll.scrollHeight;\n else {\n const anchor = [...messages.querySelectorAll<HTMLElement>('[data-reading-id]')].find((element) => element.dataset.readingId === position.anchor);\n scroll.scrollTop = anchor && position.offset !== undefined\n ? scroll.scrollTop + anchor.getBoundingClientRect().top - scroll.getBoundingClientRect().top - position.offset\n : position.top;\n }\n restoring = false;\n // Following is user intent. Layout changes (including image decoding) must\n // not turn it off, or turn a history reader back into a follower.\n if (activeID) positions.set(activeID, capture(position.follow));\n recordLayout();\n updateLatest();\n }\n function followLatest(): void {\n if (destroyed) return;\n const position = { top: 0, follow: true };\n if (pendingPosition) pendingPosition = position;\n restore(position);\n }\n\n let cachedMatches = new WeakMap<HTMLElement, { query: string; version?: string; matches: typeof matches }>();\n function clearMarks(root: HTMLElement = messages): void {\n for (const mark of root.querySelectorAll('mark[data-find-match]')) mark.replaceWith(document.createTextNode(mark.textContent || ''));\n root.normalize();\n if (root === messages) cachedMatches = new WeakMap();\n else cachedMatches.delete(root);\n }\n function markMatches(): void {\n const previousKey = matches[selected]?.key;\n matches = [];\n const query = field.value;\n if (!bar.hidden && query) {\n for (const root of messages.querySelectorAll<HTMLElement>('[data-reading-id]')) {\n const cached = cachedMatches.get(root);\n if (cached?.query === query && cached.version === root.dataset.renderVersion) { matches.push(...cached.matches); continue; }\n clearMarks(root);\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {\n acceptNode: (node) => node.parentElement?.closest('button, summary, script, style, [data-find-ignore]') ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT,\n });\n const nodes: { node: Text; start: number; end: number }[] = [];\n let text = '', block: Element | null = null;\n while (walker.nextNode()) {\n const node = walker.currentNode as Text;\n const parent = node.parentElement?.closest('p, pre, li, h1, h2, h3, h4, h5, h6, .pui-user-text, .pui-system-message') || root;\n if (text && parent !== block) text += '\\n';\n block = parent;\n const start = text.length;\n text += node.data;\n nodes.push({ node, start, end: text.length });\n }\n const ranges = findRanges(text, query);\n const base = matches.length;\n matches.push(...ranges.map((range) => ({ key: `${root.dataset.readingId}:${range.start}`, parts: [] })));\n for (const { node, start, end } of nodes) {\n const intersections = ranges.map((range, index) => ({ start: Math.max(start, range.start) - start, end: Math.min(end, range.end) - start, index: base + index })).filter((range) => range.end > range.start);\n if (!intersections.length) continue;\n const fragment = document.createDocumentFragment();\n let offset = 0;\n for (const range of intersections) {\n fragment.append(document.createTextNode(node.data.slice(offset, range.start)));\n const mark = document.createElement('mark');\n mark.dataset.findMatch = String(range.index);\n mark.textContent = node.data.slice(range.start, range.end);\n matches[range.index].parts.push(mark);\n fragment.append(mark);\n offset = range.end;\n }\n fragment.append(document.createTextNode(node.data.slice(offset)));\n node.replaceWith(fragment);\n }\n cachedMatches.set(root, { query, version: root.dataset.renderVersion, matches: matches.slice(base) });\n }\n } else clearMarks();\n const kept = matches.findIndex((match) => match.key === previousKey);\n selected = matches.length ? kept >= 0 ? kept : Math.max(0, Math.min(selected, matches.length - 1)) : -1;\n updateSelection();\n }\n function updateSelection(): void {\n matches.forEach((match, index) => match.parts.forEach((part) => part.classList.toggle('pui-find-current', index === selected)));\n count.textContent = field.value ? matches.length ? `${selected + 1} / ${matches.length}` : 'No matches' : '';\n previous.disabled = next.disabled = !matches.length;\n }\n function reveal(): void {\n const target = matches[selected]?.parts[0];\n if (!target) return;\n for (let parent = target.parentElement; parent && parent !== messages; parent = parent.parentElement) if (parent instanceof HTMLDetailsElement) parent.open = true;\n scroll.scrollTop += target.getBoundingClientRect().top - scroll.getBoundingClientRect().top - scroll.clientHeight / 3;\n remember();\n }\n function move(direction: number): void {\n if (!matches.length) return;\n selected = (selected + direction + matches.length) % matches.length;\n updateSelection();\n reveal();\n }\n function openFind(): void {\n if (destroyed) return;\n bar.hidden = false;\n markMatches();\n field.focus();\n field.select();\n }\n function closeFind(): void {\n if (destroyed) return;\n bar.hidden = true;\n clearMarks();\n matches = [];\n selected = -1;\n scroll.focus({ preventScroll: true });\n updateLatest();\n }\n listen(field, 'input', () => { selected = -1; matches = []; markMatches(); reveal(); });\n listen<KeyboardEvent>(field, 'keydown', (event) => {\n if (event.key === 'Enter' && !event.isComposing) { event.preventDefault(); move(event.shiftKey ? -1 : 1); }\n });\n listen(previous, 'click', () => move(-1));\n listen(next, 'click', () => move(1));\n listen(close, 'click', closeFind);\n listen<KeyboardEvent>(options.keyboardTarget || document, 'keydown', (event) => {\n if (event.isComposing || options.isKeyboardBlocked?.()) return;\n if ((event.metaKey || event.ctrlKey) && !event.altKey && event.key.toLowerCase() === 'f') { event.preventDefault(); openFind(); }\n else if (event.key === 'Escape' && !bar.hidden) { event.preventDefault(); closeFind(); }\n });\n listen(latest, 'click', followLatest);\n listen(scroll, 'scroll', () => {\n if (restoring || pendingPosition) return;\n const saved = positions.get(activeID);\n // A resize can clamp scrollTop and dispatch a scroll before ResizeObserver.\n // Only scrolling within a stable layout changes the following preference.\n if (saved && layoutChanged()) restore(saved);\n else if (!saved || Math.abs(scroll.scrollTop - saved.top) > 1) remember();\n else updateLatest();\n }, { passive: true });\n // Async image decoding and resizing must not displace an existing anchor.\n const observer = new ResizeObserver(() => {\n if (destroyed) return;\n if (!pendingPosition && activeID) {\n const saved = positions.get(activeID);\n if (saved) restore(saved);\n }\n updateLatest();\n });\n observer.observe(messages);\n observer.observe(scroll);\n return {\n beforeRender(id: string): void {\n if (destroyed) return;\n if (activeID && !positions.has(activeID)) positions.set(activeID, capture());\n pendingPosition = id === activeID ? pendingPosition || positions.get(activeID) || capture() : positions.get(id) || { top: 0, follow: true };\n if (id !== activeID) { selected = -1; matches = []; searchSignature = ''; }\n activeID = id;\n cancelAnimationFrame(frame);\n },\n afterRender(): void {\n if (destroyed) return;\n const signature = messages.innerHTML;\n if (!bar.hidden && signature !== searchSignature) { markMatches(); searchSignature = messages.innerHTML; }\n frame = requestAnimationFrame(() => {\n if (destroyed) return;\n const position = pendingPosition;\n pendingPosition = undefined;\n if (position) restore(position);\n else updateLatest();\n });\n },\n prune(ids: string[]): void { if (destroyed) return; const keep = new Set(ids); for (const id of positions.keys()) if (!keep.has(id)) positions.delete(id); },\n followLatest,\n openFind,\n closeFind,\n destroy(): void {\n if (destroyed) return;\n destroyed = true;\n cancelAnimationFrame(frame);\n observer.disconnect();\n removals.splice(0).forEach((remove) => remove());\n clearMarks();\n positions.clear();\n matches = [];\n pendingPosition = undefined;\n },\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-view.d.ts","sourceRoot":"","sources":["../../src/content/conversation-view.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAE3D,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAGrE,kFAAkF;AAClF,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrD,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3D,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;CACjG;AACD,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACzC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AACD,MAAM,WAAW,kBAAkB;IAAG,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE;AACjH,MAAM,WAAW,8BAA8B;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAC;AAClG,MAAM,MAAM,sBAAsB,GAAG;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAC,GAAG;IAAC,MAAM,EAAE,aAAa,CAAA;CAAC,CAAC;AAC9F,MAAM,WAAW,qBAAsB,SAAQ,OAAO,CAAC,qBAAqB,CAAC;IAC3E,4EAA4E;IAC5E,wBAAwB,CAAC,QAAQ,EAAE,QAAQ,CAAC,8BAA8B,CAAC,GAAG,IAAI,CAAC;IACnF,MAAM,IAAI,SAAS,gBAAgB,EAAE,CAAC;IACtC,aAAa,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,sBAAsB,GAAG,IAAI,CAAC;CAC7E;AACD,MAAM,WAAW,uBAAuB;IACtC,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,eAAe,CAAC;IACvD,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,EAAE,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC3E,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAChE;AAGD,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,uBAA4B,GAAG,qBAAqB,CAuEnG"}
1
+ {"version":3,"file":"conversation-view.d.ts","sourceRoot":"","sources":["../../src/content/conversation-view.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAE3D,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAGrE,kFAAkF;AAClF,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrD,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3D,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;CACjG;AACD,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACzC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AACD,MAAM,WAAW,kBAAkB;IAAG,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE;AACjH,MAAM,WAAW,8BAA8B;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAC;AAClG,MAAM,MAAM,sBAAsB,GAAG;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAC,GAAG;IAAC,MAAM,EAAE,aAAa,CAAA;CAAC,CAAC;AAC9F,MAAM,WAAW,qBAAsB,SAAQ,OAAO,CAAC,qBAAqB,CAAC;IAC3E,4EAA4E;IAC5E,wBAAwB,CAAC,QAAQ,EAAE,QAAQ,CAAC,8BAA8B,CAAC,GAAG,IAAI,CAAC;IACnF,MAAM,IAAI,SAAS,gBAAgB,EAAE,CAAC;IACtC,aAAa,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,sBAAsB,GAAG,IAAI,CAAC;CAC7E;AACD,MAAM,WAAW,uBAAuB;IACtC,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,eAAe,CAAC;IACvD,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,EAAE,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC3E,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAChE;AAGD,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,uBAA4B,GAAG,qBAAqB,CA0FnG"}
@@ -31,17 +31,22 @@ export function createConversationView(options = {}) {
31
31
  };
32
32
  container.addEventListener('click', click);
33
33
  let activeId = '';
34
+ let groups = new Map();
34
35
  function update(id, messages, working, folds) {
35
36
  if (destroyed)
36
37
  return;
37
38
  if (id !== activeId) {
38
39
  clearViews(container);
40
+ groups.clear();
39
41
  activeId = id;
40
42
  }
41
43
  const views = [];
42
- const messageView = (message, key = message.id, foldKey = '') => ({
43
- key, signature: JSON.stringify(message), html: () => renderMessage(id, message, folds.get(foldKey), foldKey, (text, conversationId) => renderMarkdown(text, options.markdown?.(conversationId))),
44
+ const aliases = new Map();
45
+ const expanded = (key, legacy = '') => folds?.get(key) ?? folds?.get(legacy) ?? false;
46
+ const messageView = (message, key = `message:${message.id}`, foldKey = '', legacyFoldKey = '') => ({
47
+ key, signature: JSON.stringify(message), html: () => renderMessage(id, message, expanded(foldKey, legacyFoldKey), foldKey, (text, conversationId) => renderMarkdown(text, options.markdown?.(conversationId))),
44
48
  });
49
+ const nextGroups = new Map();
45
50
  let groupIndex = 0;
46
51
  for (let index = 0; index < messages.length;) {
47
52
  if (messages[index].role !== 'tool') {
@@ -51,18 +56,39 @@ export function createConversationView(options = {}) {
51
56
  const start = index;
52
57
  while (index < messages.length && messages[index].role === 'tool')
53
58
  index++;
54
- const tools = messages.slice(start, index), key = `group-${groupIndex++}`;
59
+ const tools = messages.slice(start, index), members = new Set(tools.map(tool => tool.id));
60
+ // A group can gain results or have earlier history inserted. Reuse its
61
+ // identity through an existing member instead of its current list index.
62
+ const retained = [...groups].find(([key, previous]) => !nextGroups.has(key) && [...members].some(id => previous.has(id)));
63
+ const baseKey = `group-${tools[0].id}`;
64
+ let key = retained?.[0] ?? baseKey;
65
+ // A retained group's first member may no longer be present. A newly
66
+ // inserted group using that member must not take its still-owned key.
67
+ if (!retained)
68
+ for (let suffix = 2; groups.has(key) || nextGroups.has(key); suffix++)
69
+ key = `${baseKey}-${suffix}`;
70
+ const legacyKey = `group-${groupIndex++}`;
71
+ nextGroups.set(key, members);
72
+ aliases.set(key, legacyKey);
55
73
  const running = tools.filter((tool) => tool.status === 'running').length;
56
74
  const failed = tools.filter((tool) => tool.status === 'error').length;
57
75
  const label = toolGroupLabel(tools);
58
- views.push({ key, signature: JSON.stringify([label, tools.length, failed, running]),
59
- html: () => `<details class="pui-tool-group" data-tool-fold="${key}" ${folds.get(key) ? 'open' : ''}><summary>${icon('terminal')}<span class="pui-tool-group-label">${label}</span><span class="pui-tool-group-count">${tools.length} ${tools.length === 1 ? 'call' : 'calls'}</span>${failed ? `<span class="pui-tool-group-failed">${failed} failed</span>` : ''}${running ? `<span class="pui-tool-group-running">${running} running</span>` : ''}${icon('down')}</summary><div class="pui-tool-group-content" data-view-children></div></details>`,
60
- children: tools.map((tool) => { const toolKey = `${key}-tool-${tool.toolCallId || tool.id}`; return messageView(tool, toolKey, toolKey); }),
76
+ views.push({ key: `tools:${key}`, signature: JSON.stringify([label, tools.length, failed, running]),
77
+ html: () => `<details class="pui-tool-group" data-tool-fold="${escape(key)}" ${expanded(key, legacyKey) ? 'open' : ''}><summary>${icon('terminal')}<span class="pui-tool-group-label">${label}</span><span class="pui-tool-group-count">${tools.length} ${tools.length === 1 ? 'call' : 'calls'}</span>${failed ? `<span class="pui-tool-group-failed">${failed} failed</span>` : ''}${running ? `<span class="pui-tool-group-running">${running} running</span>` : ''}${icon('down')}</summary><div class="pui-tool-group-content" data-view-children></div></details>`,
78
+ children: tools.map((tool) => { const toolKey = `${key}-tool-${tool.toolCallId || tool.id}`, legacyToolKey = `${legacyKey}-tool-${tool.toolCallId || tool.id}`; aliases.set(toolKey, legacyToolKey); return messageView(tool, `tool:${tool.id}`, toolKey, legacyToolKey); }),
61
79
  });
62
80
  }
63
81
  if (working)
64
82
  views.push({ key: 'working', signature: 'working', html: () => '<div class="pui-agent-working" role="status"><span class="pui-working-dots" aria-hidden="true"><i></i><i></i><i></i></span><span>Working…</span></div>' });
65
83
  reconcileViews(container, views);
84
+ groups = nextGroups;
85
+ if (folds)
86
+ for (const details of container.querySelectorAll('[data-tool-fold]')) {
87
+ const key = details.dataset.toolFold, legacy = aliases.get(key);
88
+ const value = folds.get(key) ?? (legacy ? folds.get(legacy) : undefined);
89
+ if (value !== undefined && details.open !== value)
90
+ details.open = value;
91
+ }
66
92
  actionButtons = [...container.querySelectorAll('[data-message-action]')];
67
93
  parts.update();
68
94
  syncAvailability();
@@ -70,8 +96,7 @@ export function createConversationView(options = {}) {
70
96
  return {
71
97
  element: container,
72
98
  update(state) {
73
- const folds = state.folds || new Map(Array.from(container.querySelectorAll('[data-tool-fold]'), (element) => [element.dataset.toolFold, element.open]));
74
- update(state.id, state.messages, state.working, folds);
99
+ update(state.id, state.messages, state.working, state.folds);
75
100
  },
76
101
  updateActionAvailability(disabled) {
77
102
  if (destroyed || (disabled.copy === disabledActions.copy && disabled.edit === disabledActions.edit && disabled.branch === disabledActions.branch))
@@ -96,6 +121,7 @@ export function createConversationView(options = {}) {
96
121
  clearViews(container);
97
122
  parts.destroy();
98
123
  actionButtons = [];
124
+ groups.clear();
99
125
  },
100
126
  };
101
127
  }
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-view.js","sourceRoot":"","sources":["../../src/content/conversation-view.ts"],"names":[],"mappings":"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","sourcesContent":["import { escape, icon } from '../dom.js';\nimport { controlDisabled, type UIBlock } from '../core.js';\nimport { adoptProductParts } from '../foundations.js';\nimport { renderMarkdown, type MarkdownOptions } from './markdown.js';\nimport { reconcileViews, clearViews, type View } from './views.js';\n\n/** UI data only. Hosts decide copy/edit/branch eligibility and resolve images. */\nexport interface ConversationMessage {\n id: string;\n role: string;\n text: string;\n timestamp?: number;\n toolName?: string;\n toolCallId?: string;\n status?: string;\n images?: Array<{ index: number; mimeType?: string }>;\n command?: { text: string; cwd: string; exitCode?: number };\n actions?: { copy?: boolean | string; edit?: boolean; branch?: { key: string; label?: string } };\n}\nexport interface ConversationViewState {\n id: string;\n messages: readonly ConversationMessage[];\n working: boolean;\n folds?: ReadonlyMap<string, boolean>;\n}\nexport interface ConversationAction { action: 'copy' | 'edit' | 'branch'; messageId: string; branchKey?: string }\nexport interface ConversationActionAvailability {copy?: boolean; edit?: boolean; branch?: boolean}\nexport type ConversationImageState = {status: 'ready'; src: string} | {status: 'unavailable'};\nexport interface ConversationViewBlock extends UIBlock<ConversationViewState> {\n /** Disabled state, separate from whether an action exists for a message. */\n updateActionAvailability(disabled: Readonly<ConversationActionAvailability>): void;\n images(): readonly HTMLImageElement[];\n setImageState(image: HTMLImageElement, state: ConversationImageState): void;\n}\nexport interface ConversationViewOptions {\n container?: HTMLElement;\n markdown?: (conversationId: string) => MarkdownOptions;\n onAction?: (action: ConversationAction, button: HTMLButtonElement) => void;\n onCopyCode?: (text: string, button: HTMLButtonElement) => void;\n}\n\n\nexport function createConversationView(options: ConversationViewOptions = {}): ConversationViewBlock {\n const container = options.container || document.createElement('div');\n container.classList.add('pui-conversation-messages');\n const parts = adoptProductParts(container);\n let actionButtons: HTMLButtonElement[] = [];\n let disabledActions: Readonly<ConversationActionAvailability> = {};\n const syncAvailability = () => {for (const button of actionButtons) parts.action(button).update({disabled: controlDisabled(button, !!disabledActions[button.dataset.messageAction as ConversationAction['action']])});};\n let destroyed = false;\n const click = (event: Event) => {\n const target = (event.target as Element).closest<HTMLButtonElement>('[data-message-action], [data-copy-code]');\n if (!target || !container.contains(target) || target.disabled) return;\n if (target.hasAttribute('data-copy-code')) {\n const text = target.closest('.pui-code-block')?.querySelector('pre > code')?.textContent || '';\n if (options.onCopyCode) {event.stopPropagation(); options.onCopyCode(text, target);}\n return;\n }\n if (options.onAction) {event.stopPropagation(); options.onAction({ action: target.dataset.messageAction as ConversationAction['action'], messageId: target.dataset.messageActionId!, branchKey: target.dataset.branchKey }, target);}\n };\n container.addEventListener('click', click);\n let activeId = '';\n function update(id: string, messages: readonly ConversationMessage[], working: boolean, folds: ReadonlyMap<string, boolean>): void {\n if (destroyed) return;\n if (id !== activeId) { clearViews(container); activeId = id; }\n const views: View[] = [];\n const messageView = (message: ConversationMessage, key = message.id, foldKey = ''): View => ({\n key, signature: JSON.stringify(message), html: () => renderMessage(id, message, folds.get(foldKey), foldKey, (text, conversationId) => renderMarkdown(text, options.markdown?.(conversationId))),\n });\n let groupIndex = 0;\n for (let index = 0; index < messages.length;) {\n if (messages[index].role !== 'tool') { views.push(messageView(messages[index++])); continue; }\n const start = index;\n while (index < messages.length && messages[index].role === 'tool') index++;\n const tools = messages.slice(start, index), key = `group-${groupIndex++}`;\n const running = tools.filter((tool) => tool.status === 'running').length;\n const failed = tools.filter((tool) => tool.status === 'error').length;\n const label = toolGroupLabel(tools);\n views.push({ key, signature: JSON.stringify([label, tools.length, failed, running]),\n html: () => `<details class=\"pui-tool-group\" data-tool-fold=\"${key}\" ${folds.get(key) ? 'open' : ''}><summary>${icon('terminal')}<span class=\"pui-tool-group-label\">${label}</span><span class=\"pui-tool-group-count\">${tools.length} ${tools.length === 1 ? 'call' : 'calls'}</span>${failed ? `<span class=\"pui-tool-group-failed\">${failed} failed</span>` : ''}${running ? `<span class=\"pui-tool-group-running\">${running} running</span>` : ''}${icon('down')}</summary><div class=\"pui-tool-group-content\" data-view-children></div></details>`,\n children: tools.map((tool) => { const toolKey = `${key}-tool-${tool.toolCallId || tool.id}`; return messageView(tool, toolKey, toolKey); }),\n });\n }\n if (working) views.push({ key: 'working', signature: 'working', html: () => '<div class=\"pui-agent-working\" role=\"status\"><span class=\"pui-working-dots\" aria-hidden=\"true\"><i></i><i></i><i></i></span><span>Working…</span></div>' });\n reconcileViews(container, views);\n actionButtons = [...container.querySelectorAll<HTMLButtonElement>('[data-message-action]')];\n parts.update(); syncAvailability();\n }\n return {\n element: container,\n update(state): void {\n const folds = state.folds || new Map(Array.from(container.querySelectorAll<HTMLDetailsElement>('[data-tool-fold]'), (element) => [element.dataset.toolFold!, element.open] as const));\n update(state.id, state.messages, state.working, folds);\n },\n updateActionAvailability(disabled): void {\n if (destroyed || (disabled.copy === disabledActions.copy && disabled.edit === disabledActions.edit && disabled.branch === disabledActions.branch)) return;\n disabledActions = {...disabled}; syncAvailability();\n },\n images: () => destroyed ? [] : [...container.querySelectorAll<HTMLImageElement>('img[data-image-key]')],\n setImageState(image, state): void {\n if (destroyed || !container.contains(image)) return;\n image.classList.toggle('pui-image-unavailable', state.status === 'unavailable');\n image.alt = state.status === 'unavailable' ? 'Image unavailable' : `Image ${Number(image.dataset.imageIndex) + 1}`;\n if (state.status === 'ready') image.src = state.src;\n },\n destroy(): void {\n if (destroyed) return;\n destroyed = true;\n container.removeEventListener('click', click);\n clearViews(container);\n parts.destroy(); actionButtons = [];\n },\n };\n}\n\nfunction toolGroupLabel(tools: readonly ConversationMessage[]): string {\n if (tools.length === 1) return ({ list_files: 'Listed files', read_file: 'Read a file', run_command: 'Ran a command', write_file: 'Wrote a file', edit_file: 'Edited a file', tool_search: 'Searched tools', codemode: 'Ran code' } as Record<string, string>)[tools[0].toolName || ''] || 'Used a tool';\n const hasCommands = tools.some((tool) => tool.toolName === 'run_command');\n const exploredFiles = tools.every((tool) => ['list_files', 'read_file', 'grep', 'find', 'ls', 'run_command'].includes(tool.toolName || ''));\n if (tools.every((tool) => tool.toolName === 'run_command')) return 'Ran commands';\n if (exploredFiles) return hasCommands ? 'Ran commands and explored files' : 'Explored files';\n return 'Used tools';\n}\n\nfunction renderMessage(conversationId: string, message: ConversationMessage, expanded = false, foldKey = '', markdown: (value: string, conversationId: string) => string = (text) => renderMarkdown(text)): string {\n const text = message.text ?? '';\n const images = (message.images || []).map((image) => `<img class=\"pui-history-image\" data-image-key=\"${escape(`${conversationId}/${message.id}/${image.index}`)}\" data-message-id=\"${escape(message.id)}\" data-image-index=\"${image.index}\" alt=\"Image ${image.index + 1}\" role=\"button\" tabindex=\"0\" title=\"Click to enlarge\" loading=\"lazy\" />`).join('');\n const gallery = images ? `<div class=\"pui-message-images\">${images}</div>` : '';\n const copyLabel = typeof message.actions?.copy === 'string' ? message.actions.copy : 'Copy message';\n const copy = message.actions?.copy ? `<button type=\"button\" class=\"pui-quiet-icon pui-message-action\" data-message-action=\"copy\" data-message-action-id=\"${escape(message.id)}\" data-copy-message=\"${escape(message.id)}\" title=\"${escape(copyLabel)}\" aria-label=\"${escape(copyLabel)}\">${icon('copy')}</button>` : '';\n const edit = message.actions?.edit ? `<button type=\"button\" class=\"pui-quiet-icon pui-message-action\" data-message-action=\"edit\" data-message-action-id=\"${escape(message.id)}\" data-edit-message=\"${escape(message.id)}\" title=\"Edit message\" aria-label=\"Edit message\">${icon('edit')}</button>` : '';\n const branchAction = message.actions?.branch;\n const branch = branchAction ? `<button type=\"button\" class=\"pui-quiet-icon pui-message-action\" data-message-action=\"branch\" data-message-action-id=\"${escape(message.id)}\" data-branch-key=\"${escape(branchAction.key)}\" data-node=\"${escape(branchAction.key)}\" title=\"${escape(branchAction.label || 'Branch from this message')}\" aria-label=\"${escape(branchAction.label || 'Branch from this message')}\">${icon('branch')}</button>` : '';\n const actions = copy || edit || branch ? `<div class=\"pui-message-actions\">${copy}${edit}${branch}</div>` : '';\n const date = new Date(message.timestamp || NaN);\n const time = Number.isFinite(date.getTime()) ? `<time class=\"pui-message-time\" datetime=\"${date.toISOString()}\" title=\"${escape(date.toLocaleString())}\">${escape(date.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' }))}</time>` : '';\n const footer = time || actions ? `<div class=\"pui-message-footer\">${time}${actions}</div>` : '';\n if (message.role === 'tool') {\n const command = message.command;\n const details = command ? `<div class=\"pui-command-details\"><span class=\"pui-tool-field-label\">Command</span><pre class=\"pui-command-text\">${escape(command.text)}</pre><div class=\"pui-command-directory\"><span class=\"pui-tool-field-label\">Directory</span><code>${escape(command.cwd)}</code></div></div>` : '';\n const status = command ? ({ running: 'Running', done: 'Completed', error: 'Failed' } as Record<string, string>)[message.status || ''] || message.status || 'Result' : message.status || 'Result';\n const exit = command?.exitCode !== undefined ? ` · Exit ${command.exitCode}` : '';\n const output = command ? `<div class=\"pui-command-output\"><span class=\"pui-tool-field-label\">Output</span><pre>${escape(text)}</pre></div>` : `<pre>${escape(text)}</pre>`;\n return `<details class=\"pui-tool-message\" data-reading-id=\"${escape(message.id)}\" data-tool-fold=\"${escape(foldKey)}\" ${expanded ? 'open' : ''}><summary>${icon('terminal')}<span>${command ? 'Command' : escape(message.toolName || 'Tool result')}</span><span class=\"pui-tool-status${message.status === 'error' ? ' pui-tool-status-error' : ''}\">${escape(status + exit)}</span>${icon('down')}</summary>${details}${output}${gallery}</details>`;\n }\n if (message.role === 'user') return `<article class=\"pui-message pui-user-message\" data-reading-id=\"${escape(message.id)}\" aria-label=\"Your message\"><div class=\"pui-message-content\">${gallery}${text ? `<div class=\"pui-user-text\">${escape(text)}</div>` : ''}${footer}</div></article>`;\n if (message.role === 'system') return `<div class=\"pui-system-message\" data-reading-id=\"${escape(message.id)}\">${escape(text)}</div>`;\n return `<article class=\"pui-message pui-assistant-message\" data-reading-id=\"${escape(message.id)}\" aria-label=\"Agent response\"><div class=\"pui-message-content\"><div class=\"pui-markdown\">${markdown(text, conversationId)}</div>${message.status === 'error' ? '<span class=\"pui-message-error-label\">Response interrupted</span>' : ''}${footer}</div></article>`;\n}\n"]}
1
+ {"version":3,"file":"conversation-view.js","sourceRoot":"","sources":["../../src/content/conversation-view.ts"],"names":[],"mappings":"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","sourcesContent":["import { escape, icon } from '../dom.js';\nimport { controlDisabled, type UIBlock } from '../core.js';\nimport { adoptProductParts } from '../foundations.js';\nimport { renderMarkdown, type MarkdownOptions } from './markdown.js';\nimport { reconcileViews, clearViews, type View } from './views.js';\n\n/** UI data only. Hosts decide copy/edit/branch eligibility and resolve images. */\nexport interface ConversationMessage {\n id: string;\n role: string;\n text: string;\n timestamp?: number;\n toolName?: string;\n toolCallId?: string;\n status?: string;\n images?: Array<{ index: number; mimeType?: string }>;\n command?: { text: string; cwd: string; exitCode?: number };\n actions?: { copy?: boolean | string; edit?: boolean; branch?: { key: string; label?: string } };\n}\nexport interface ConversationViewState {\n id: string;\n messages: readonly ConversationMessage[];\n working: boolean;\n folds?: ReadonlyMap<string, boolean>;\n}\nexport interface ConversationAction { action: 'copy' | 'edit' | 'branch'; messageId: string; branchKey?: string }\nexport interface ConversationActionAvailability {copy?: boolean; edit?: boolean; branch?: boolean}\nexport type ConversationImageState = {status: 'ready'; src: string} | {status: 'unavailable'};\nexport interface ConversationViewBlock extends UIBlock<ConversationViewState> {\n /** Disabled state, separate from whether an action exists for a message. */\n updateActionAvailability(disabled: Readonly<ConversationActionAvailability>): void;\n images(): readonly HTMLImageElement[];\n setImageState(image: HTMLImageElement, state: ConversationImageState): void;\n}\nexport interface ConversationViewOptions {\n container?: HTMLElement;\n markdown?: (conversationId: string) => MarkdownOptions;\n onAction?: (action: ConversationAction, button: HTMLButtonElement) => void;\n onCopyCode?: (text: string, button: HTMLButtonElement) => void;\n}\n\n\nexport function createConversationView(options: ConversationViewOptions = {}): ConversationViewBlock {\n const container = options.container || document.createElement('div');\n container.classList.add('pui-conversation-messages');\n const parts = adoptProductParts(container);\n let actionButtons: HTMLButtonElement[] = [];\n let disabledActions: Readonly<ConversationActionAvailability> = {};\n const syncAvailability = () => {for (const button of actionButtons) parts.action(button).update({disabled: controlDisabled(button, !!disabledActions[button.dataset.messageAction as ConversationAction['action']])});};\n let destroyed = false;\n const click = (event: Event) => {\n const target = (event.target as Element).closest<HTMLButtonElement>('[data-message-action], [data-copy-code]');\n if (!target || !container.contains(target) || target.disabled) return;\n if (target.hasAttribute('data-copy-code')) {\n const text = target.closest('.pui-code-block')?.querySelector('pre > code')?.textContent || '';\n if (options.onCopyCode) {event.stopPropagation(); options.onCopyCode(text, target);}\n return;\n }\n if (options.onAction) {event.stopPropagation(); options.onAction({ action: target.dataset.messageAction as ConversationAction['action'], messageId: target.dataset.messageActionId!, branchKey: target.dataset.branchKey }, target);}\n };\n container.addEventListener('click', click);\n let activeId = '';\n let groups = new Map<string, Set<string>>();\n function update(id: string, messages: readonly ConversationMessage[], working: boolean, folds?: ReadonlyMap<string, boolean>): void {\n if (destroyed) return;\n if (id !== activeId) { clearViews(container); groups.clear(); activeId = id; }\n const views: View[] = [];\n const aliases = new Map<string, string>();\n const expanded = (key: string, legacy = '') => folds?.get(key) ?? folds?.get(legacy) ?? false;\n const messageView = (message: ConversationMessage, key = `message:${message.id}`, foldKey = '', legacyFoldKey = ''): View => ({\n key, signature: JSON.stringify(message), html: () => renderMessage(id, message, expanded(foldKey, legacyFoldKey), foldKey, (text, conversationId) => renderMarkdown(text, options.markdown?.(conversationId))),\n });\n const nextGroups = new Map<string, Set<string>>();\n let groupIndex = 0;\n for (let index = 0; index < messages.length;) {\n if (messages[index].role !== 'tool') { views.push(messageView(messages[index++])); continue; }\n const start = index;\n while (index < messages.length && messages[index].role === 'tool') index++;\n const tools = messages.slice(start, index), members = new Set(tools.map(tool => tool.id));\n // A group can gain results or have earlier history inserted. Reuse its\n // identity through an existing member instead of its current list index.\n const retained = [...groups].find(([key, previous]) => !nextGroups.has(key) && [...members].some(id => previous.has(id)));\n const baseKey = `group-${tools[0].id}`;\n let key = retained?.[0] ?? baseKey;\n // A retained group's first member may no longer be present. A newly\n // inserted group using that member must not take its still-owned key.\n if (!retained) for (let suffix = 2; groups.has(key) || nextGroups.has(key); suffix++) key = `${baseKey}-${suffix}`;\n const legacyKey = `group-${groupIndex++}`;\n nextGroups.set(key, members); aliases.set(key, legacyKey);\n const running = tools.filter((tool) => tool.status === 'running').length;\n const failed = tools.filter((tool) => tool.status === 'error').length;\n const label = toolGroupLabel(tools);\n views.push({ key:`tools:${key}`, signature: JSON.stringify([label, tools.length, failed, running]),\n html: () => `<details class=\"pui-tool-group\" data-tool-fold=\"${escape(key)}\" ${expanded(key, legacyKey) ? 'open' : ''}><summary>${icon('terminal')}<span class=\"pui-tool-group-label\">${label}</span><span class=\"pui-tool-group-count\">${tools.length} ${tools.length === 1 ? 'call' : 'calls'}</span>${failed ? `<span class=\"pui-tool-group-failed\">${failed} failed</span>` : ''}${running ? `<span class=\"pui-tool-group-running\">${running} running</span>` : ''}${icon('down')}</summary><div class=\"pui-tool-group-content\" data-view-children></div></details>`,\n children: tools.map((tool) => { const toolKey = `${key}-tool-${tool.toolCallId || tool.id}`, legacyToolKey = `${legacyKey}-tool-${tool.toolCallId || tool.id}`; aliases.set(toolKey, legacyToolKey); return messageView(tool, `tool:${tool.id}`, toolKey, legacyToolKey); }),\n });\n }\n if (working) views.push({ key: 'working', signature: 'working', html: () => '<div class=\"pui-agent-working\" role=\"status\"><span class=\"pui-working-dots\" aria-hidden=\"true\"><i></i><i></i><i></i></span><span>Working…</span></div>' });\n reconcileViews(container, views);\n groups = nextGroups;\n if (folds) for (const details of container.querySelectorAll<HTMLDetailsElement>('[data-tool-fold]')) {\n const key = details.dataset.toolFold!, legacy = aliases.get(key);\n const value = folds.get(key) ?? (legacy ? folds.get(legacy) : undefined);\n if (value !== undefined && details.open !== value) details.open = value;\n }\n actionButtons = [...container.querySelectorAll<HTMLButtonElement>('[data-message-action]')];\n parts.update(); syncAvailability();\n }\n return {\n element: container,\n update(state): void {\n update(state.id, state.messages, state.working, state.folds);\n },\n updateActionAvailability(disabled): void {\n if (destroyed || (disabled.copy === disabledActions.copy && disabled.edit === disabledActions.edit && disabled.branch === disabledActions.branch)) return;\n disabledActions = {...disabled}; syncAvailability();\n },\n images: () => destroyed ? [] : [...container.querySelectorAll<HTMLImageElement>('img[data-image-key]')],\n setImageState(image, state): void {\n if (destroyed || !container.contains(image)) return;\n image.classList.toggle('pui-image-unavailable', state.status === 'unavailable');\n image.alt = state.status === 'unavailable' ? 'Image unavailable' : `Image ${Number(image.dataset.imageIndex) + 1}`;\n if (state.status === 'ready') image.src = state.src;\n },\n destroy(): void {\n if (destroyed) return;\n destroyed = true;\n container.removeEventListener('click', click);\n clearViews(container);\n parts.destroy(); actionButtons = []; groups.clear();\n },\n };\n}\n\nfunction toolGroupLabel(tools: readonly ConversationMessage[]): string {\n if (tools.length === 1) return ({ list_files: 'Listed files', read_file: 'Read a file', run_command: 'Ran a command', write_file: 'Wrote a file', edit_file: 'Edited a file', tool_search: 'Searched tools', codemode: 'Ran code' } as Record<string, string>)[tools[0].toolName || ''] || 'Used a tool';\n const hasCommands = tools.some((tool) => tool.toolName === 'run_command');\n const exploredFiles = tools.every((tool) => ['list_files', 'read_file', 'grep', 'find', 'ls', 'run_command'].includes(tool.toolName || ''));\n if (tools.every((tool) => tool.toolName === 'run_command')) return 'Ran commands';\n if (exploredFiles) return hasCommands ? 'Ran commands and explored files' : 'Explored files';\n return 'Used tools';\n}\n\nfunction renderMessage(conversationId: string, message: ConversationMessage, expanded = false, foldKey = '', markdown: (value: string, conversationId: string) => string = (text) => renderMarkdown(text)): string {\n const text = message.text ?? '';\n const images = (message.images || []).map((image) => `<img class=\"pui-history-image\" data-image-key=\"${escape(`${conversationId}/${message.id}/${image.index}`)}\" data-message-id=\"${escape(message.id)}\" data-image-index=\"${image.index}\" alt=\"Image ${image.index + 1}\" role=\"button\" tabindex=\"0\" title=\"Click to enlarge\" loading=\"lazy\" />`).join('');\n const gallery = images ? `<div class=\"pui-message-images\">${images}</div>` : '';\n const copyLabel = typeof message.actions?.copy === 'string' ? message.actions.copy : 'Copy message';\n const copy = message.actions?.copy ? `<button type=\"button\" class=\"pui-quiet-icon pui-message-action\" data-message-action=\"copy\" data-message-action-id=\"${escape(message.id)}\" data-copy-message=\"${escape(message.id)}\" title=\"${escape(copyLabel)}\" aria-label=\"${escape(copyLabel)}\">${icon('copy')}</button>` : '';\n const edit = message.actions?.edit ? `<button type=\"button\" class=\"pui-quiet-icon pui-message-action\" data-message-action=\"edit\" data-message-action-id=\"${escape(message.id)}\" data-edit-message=\"${escape(message.id)}\" title=\"Edit message\" aria-label=\"Edit message\">${icon('edit')}</button>` : '';\n const branchAction = message.actions?.branch;\n const branch = branchAction ? `<button type=\"button\" class=\"pui-quiet-icon pui-message-action\" data-message-action=\"branch\" data-message-action-id=\"${escape(message.id)}\" data-branch-key=\"${escape(branchAction.key)}\" data-node=\"${escape(branchAction.key)}\" title=\"${escape(branchAction.label || 'Branch from this message')}\" aria-label=\"${escape(branchAction.label || 'Branch from this message')}\">${icon('branch')}</button>` : '';\n const actions = copy || edit || branch ? `<div class=\"pui-message-actions\">${copy}${edit}${branch}</div>` : '';\n const date = new Date(message.timestamp || NaN);\n const time = Number.isFinite(date.getTime()) ? `<time class=\"pui-message-time\" datetime=\"${date.toISOString()}\" title=\"${escape(date.toLocaleString())}\">${escape(date.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' }))}</time>` : '';\n const footer = time || actions ? `<div class=\"pui-message-footer\">${time}${actions}</div>` : '';\n if (message.role === 'tool') {\n const command = message.command;\n const details = command ? `<div class=\"pui-command-details\"><span class=\"pui-tool-field-label\">Command</span><pre class=\"pui-command-text\">${escape(command.text)}</pre><div class=\"pui-command-directory\"><span class=\"pui-tool-field-label\">Directory</span><code>${escape(command.cwd)}</code></div></div>` : '';\n const status = command ? ({ running: 'Running', done: 'Completed', error: 'Failed' } as Record<string, string>)[message.status || ''] || message.status || 'Result' : message.status || 'Result';\n const exit = command?.exitCode !== undefined ? ` · Exit ${command.exitCode}` : '';\n const output = command ? `<div class=\"pui-command-output\"><span class=\"pui-tool-field-label\">Output</span><pre>${escape(text)}</pre></div>` : `<pre>${escape(text)}</pre>`;\n return `<details class=\"pui-tool-message\" data-reading-id=\"${escape(message.id)}\" data-tool-fold=\"${escape(foldKey)}\" ${expanded ? 'open' : ''}><summary>${icon('terminal')}<span>${command ? 'Command' : escape(message.toolName || 'Tool result')}</span><span class=\"pui-tool-status${message.status === 'error' ? ' pui-tool-status-error' : ''}\">${escape(status + exit)}</span>${icon('down')}</summary>${details}${output}${gallery}</details>`;\n }\n if (message.role === 'user') return `<article class=\"pui-message pui-user-message\" data-reading-id=\"${escape(message.id)}\" aria-label=\"Your message\"><div class=\"pui-message-content\">${gallery}${text ? `<div class=\"pui-user-text\">${escape(text)}</div>` : ''}${footer}</div></article>`;\n if (message.role === 'system') return `<div class=\"pui-system-message\" data-reading-id=\"${escape(message.id)}\">${escape(text)}</div>`;\n return `<article class=\"pui-message pui-assistant-message\" data-reading-id=\"${escape(message.id)}\" aria-label=\"Agent response\"><div class=\"pui-message-content\"><div class=\"pui-markdown\">${markdown(text, conversationId)}</div>${message.status === 'error' ? '<span class=\"pui-message-error-label\">Response interrupted</span>' : ''}${footer}</div></article>`;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"image-viewer.d.ts","sourceRoot":"","sources":["../../src/content/image-viewer.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,kBAAkB;IAAG,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE;AACtF,MAAM,WAAW,gBAAgB;IAAG,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,WAAW,CAAA;CAAE;AAG1F,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,kBAAuB;;iBA6CjD,gBAAgB,GAAG,gBAAgB,GAAG,IAAI;iBAHvC,IAAI;eAqBT,IAAI;EAclB;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,iBAAiB,EAAE,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,WAAW,CAAA;CAAO;;;iBAlCxF,gBAAgB,GAAG,gBAAgB,GAAG,IAAI;iBAHvC,IAAI;EAkDvB"}
1
+ {"version":3,"file":"image-viewer.d.ts","sourceRoot":"","sources":["../../src/content/image-viewer.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,kBAAkB;IAAG,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE;AACtF,MAAM,WAAW,gBAAgB;IAAG,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,WAAW,CAAA;CAAE;AAG1F,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,kBAAuB;;iBAgDjD,gBAAgB,GAAG,gBAAgB,GAAG,IAAI;iBAHvC,IAAI;eAqBT,IAAI;EAgBlB;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,iBAAiB,EAAE,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,WAAW,CAAA;CAAO;;;iBApCxF,gBAAgB,GAAG,gBAAgB,GAAG,IAAI;iBAHvC,IAAI;EAoDvB"}