@design.estate/dees-catalog 3.93.0 → 3.95.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.
- package/dist_bundle/bundle.js +2868 -1376
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.d.ts +6 -3
- package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.demo.js +34 -4
- package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.js +49 -45
- package/dist_ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.d.ts +13 -0
- package/dist_ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.demo.js +5 -2
- package/dist_ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.js +118 -3
- package/dist_ts_web/elements/00group-harness/dees-harness-message-list/dees-harness-message-list.d.ts +25 -3
- package/dist_ts_web/elements/00group-harness/dees-harness-message-list/dees-harness-message-list.js +156 -48
- package/dist_ts_web/elements/00group-harness/dees-harness-permission-card/dees-harness-permission-card.d.ts +2 -0
- package/dist_ts_web/elements/00group-harness/dees-harness-permission-card/dees-harness-permission-card.js +9 -5
- package/dist_ts_web/elements/00group-harness/dees-harness-question-card/dees-harness-question-card.d.ts +31 -0
- package/dist_ts_web/elements/00group-harness/dees-harness-question-card/dees-harness-question-card.demo.d.ts +1 -0
- package/dist_ts_web/elements/00group-harness/dees-harness-question-card/dees-harness-question-card.demo.js +69 -0
- package/dist_ts_web/elements/00group-harness/dees-harness-question-card/dees-harness-question-card.js +382 -0
- package/dist_ts_web/elements/00group-harness/dees-harness-question-card/index.d.ts +1 -0
- package/dist_ts_web/elements/00group-harness/dees-harness-question-card/index.js +2 -0
- package/dist_ts_web/elements/00group-harness/index.d.ts +1 -0
- package/dist_ts_web/elements/00group-harness/index.js +2 -1
- package/dist_ts_web/elements/00group-harness/interfaces.d.ts +33 -0
- package/dist_ts_web/elements/00group-harness/toolregistry.js +9 -1
- package/dist_ts_web/elements/00group-layout/dees-mosaic/dees-mosaic.d.ts +49 -0
- package/dist_ts_web/elements/00group-layout/dees-mosaic/dees-mosaic.demo.d.ts +1 -0
- package/dist_ts_web/elements/00group-layout/dees-mosaic/dees-mosaic.demo.js +82 -0
- package/dist_ts_web/elements/00group-layout/dees-mosaic/dees-mosaic.js +622 -0
- package/dist_ts_web/elements/00group-layout/dees-mosaic/index.d.ts +3 -0
- package/dist_ts_web/elements/00group-layout/dees-mosaic/index.js +4 -0
- package/dist_ts_web/elements/00group-layout/dees-mosaic/interaction.d.ts +37 -0
- package/dist_ts_web/elements/00group-layout/dees-mosaic/interaction.js +174 -0
- package/dist_ts_web/elements/00group-layout/dees-mosaic/tree.d.ts +33 -0
- package/dist_ts_web/elements/00group-layout/dees-mosaic/tree.js +199 -0
- package/dist_ts_web/elements/00group-layout/dees-mosaic/types.d.ts +52 -0
- package/dist_ts_web/elements/00group-layout/dees-mosaic/types.js +8 -0
- package/dist_ts_web/elements/00group-layout/index.d.ts +1 -0
- package/dist_ts_web/elements/00group-layout/index.js +2 -1
- package/dist_ts_web/elements/00theme.js +6 -1
- package/dist_watch/bundle.js +2869 -1377
- package/dist_watch/bundle.js.map +4 -4
- package/package.json +1 -1
- package/readme.md +41 -6
- package/readme.playbook.md +1 -1
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.demo.ts +37 -3
- package/ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.ts +31 -44
- package/ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.demo.ts +4 -1
- package/ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.ts +99 -0
- package/ts_web/elements/00group-harness/dees-harness-message-list/dees-harness-message-list.ts +148 -46
- package/ts_web/elements/00group-harness/dees-harness-permission-card/dees-harness-permission-card.ts +9 -4
- package/ts_web/elements/00group-harness/dees-harness-question-card/dees-harness-question-card.demo.ts +70 -0
- package/ts_web/elements/00group-harness/dees-harness-question-card/dees-harness-question-card.ts +319 -0
- package/ts_web/elements/00group-harness/dees-harness-question-card/index.ts +1 -0
- package/ts_web/elements/00group-harness/index.ts +1 -0
- package/ts_web/elements/00group-harness/interfaces.ts +36 -0
- package/ts_web/elements/00group-harness/toolregistry.ts +8 -0
- package/ts_web/elements/00group-layout/dees-mosaic/dees-mosaic.demo.ts +87 -0
- package/ts_web/elements/00group-layout/dees-mosaic/dees-mosaic.ts +562 -0
- package/ts_web/elements/00group-layout/dees-mosaic/index.ts +3 -0
- package/ts_web/elements/00group-layout/dees-mosaic/interaction.ts +187 -0
- package/ts_web/elements/00group-layout/dees-mosaic/tree.ts +239 -0
- package/ts_web/elements/00group-layout/dees-mosaic/types.ts +63 -0
- package/ts_web/elements/00group-layout/index.ts +1 -0
- package/ts_web/elements/00theme.ts +7 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@design.estate/dees-catalog",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.95.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.",
|
|
6
6
|
"main": "dist_ts_web/index.js",
|
package/readme.md
CHANGED
|
@@ -57,14 +57,14 @@ For developers working on this library, please refer to the [UI Components Playb
|
|
|
57
57
|
|----------|------------|
|
|
58
58
|
| **Core UI** | [`DeesButton`](#deesbutton), [`DeesButtonExit`](#deesbuttonexit), [`DeesButtonGroup`](#deesbuttongroup), [`DeesBadge`](#deesbadge), [`DeesChips`](#deeschips), [`DeesHeading`](#deesheading), [`DeesHint`](#deeshint), [`DeesIcon`](#deesicon), [`DeesLabel`](#deeslabel), [`DeesPanel`](#deespanel), [`DeesSearchbar`](#deessearchbar), [`DeesSpinner`](#deesspinner), [`DeesToast`](#deestoast), [`DeesWindowcontrols`](#deeswindowcontrols), [`DeesActionbar`](#deesactionbar) |
|
|
59
59
|
| **Forms** | [`DeesForm`](#deesform), [`DeesInputText`](#deesinputtext), [`DeesInputCheckbox`](#deesinputcheckbox), [`DeesInputDropdown`](#deesinputdropdown), [`DeesInputRadiogroup`](#deesinputradiogroup), [`DeesInputFileupload`](#deesinputfileupload), [`DeesInputIban`](#deesinputiban), [`DeesInputPhone`](#deesinputphone), [`DeesInputQuantitySelector`](#deesinputquantityselector), [`DeesInputMultitoggle`](#deesinputmultitoggle), [`DeesInputToggle`](#deesinputtoggle), [`DeesInputTags`](#deesinputtags), [`DeesInputTypelist`](#deesinputtypelist), [`DeesInputList`](#deesinputlist), [`DeesInputProfilepicture`](#deesinputprofilepicture), [`DeesInputRichtext`](#deesinputrichtext), [`DeesInputWysiwyg`](#deesinputwysiwyg), [`DeesInputDatepicker`](#deesinputdatepicker), [`DeesInputSearchselect`](#deesinputsearchselect), [`DeesInputCode`](#deesinputcode), [`DeesFormSubmit`](#deesformsubmit) |
|
|
60
|
-
| **App Shell (Layout)** | [`DeesAppui`](#deesappui-️), [`DeesAppuiMainmenu`](#deesappuimainmenu), [`DeesAppuiSecondarymenu`](#deesappuisecondarymenu), [`DeesAppuiMaincontent`](#deesappuimaincontent), [`DeesAppuiAppbar`](#deesappuiappbar), [`DeesAppuiActivitylog`](#deesappuiactivitylog), [`DeesAppuiBottombar`](#deesappuibottombar), [`DeesAppuiProfiledropdown`](#deesappuiprofiledropdown), [`DeesAppuiTabs`](#deesappuitabs), [`DeesMobileNavigation`](#deesmobilenavigation), [`DeesDashboardGrid`](#deesdashboardgrid) |
|
|
60
|
+
| **App Shell (Layout)** | [`DeesMosaic`](#deesmosaic), [`DeesAppui`](#deesappui-️), [`DeesAppuiMainmenu`](#deesappuimainmenu), [`DeesAppuiSecondarymenu`](#deesappuisecondarymenu), [`DeesAppuiMaincontent`](#deesappuimaincontent), [`DeesAppuiAppbar`](#deesappuiappbar), [`DeesAppuiActivitylog`](#deesappuiactivitylog), [`DeesAppuiBottombar`](#deesappuibottombar), [`DeesAppuiProfiledropdown`](#deesappuiprofiledropdown), [`DeesAppuiTabs`](#deesappuitabs), [`DeesMobileNavigation`](#deesmobilenavigation), [`DeesDashboardGrid`](#deesdashboardgrid) |
|
|
61
61
|
| **Data Display** | [`DeesTable`](#deestable), [`DeesDataviewCodebox`](#deesdataviewcodebox), [`DeesDataviewStatusobject`](#deesdataviewstatusobject), [`DeesPdf`](#deespdf), [`DeesStatsGrid`](#deesstatsgrid), [`DeesPagination`](#deespagination), [`DeesStorageBrowser`](#deesstorgebrowser) |
|
|
62
62
|
| **Media & Thumbnails** | [`DeesThumbnailPdf`](#deesthumbnailpdf), [`DeesThumbnailImage`](#deesthumbnailimage), [`DeesThumbnailAudio`](#deesthumbnailaudio), [`DeesThumbnailVideo`](#deesthumbnalvideo), [`DeesThumbnailNote`](#deesthumbnailnote), [`DeesThumbnailFolder`](#deesthumbnailfolder), [`DeesPreview`](#deespreview), [`DeesPdfViewer`](#deespdfviewer), [`DeesImageViewer`](#deesimageviewer), [`DeesAudioViewer`](#deesaudioviewer), [`DeesVideoViewer`](#deesvideoviewer) |
|
|
63
63
|
| **Visualization** | [`DeesChartArea`](#deeschartarea), [`DeesChartBar`](#deeschartbar), [`DeesChartDonut`](#deeschartdonut), [`DeesChartGauge`](#deeschartgauge), [`DeesChartRadar`](#deeschartradar), [`DeesChartLog`](#deeschartlog) |
|
|
64
64
|
| **Dialogs & Overlays** | [`DeesModal`](#deesmodal), [`DeesContextmenu`](#deescontextmenu), [`DeesSpeechbubble`](#deesspeechbubble), [`DeesWindowlayer`](#deeswindowlayer) |
|
|
65
65
|
| **Navigation** | [`DeesStepper`](#deesstepper), [`DeesProgressbar`](#deesprogressbar) |
|
|
66
66
|
| **Workspace / IDE** | [`DeesWorkspace`](#deesworkspace), [`DeesWorkspaceMonaco`](#deesworkspacemonaco), [`DeesWorkspaceDiffEditor`](#deesworkspacediffeditor), [`DeesWorkspaceFiletree`](#deesworkspacefiletree), [`DeesWorkspaceTerminal`](#deesworkspaceterminal), [`DeesWorkspaceTerminalPreview`](#deesworkspaceterminalpreview), [`DeesWorkspaceMarkdown`](#deesworkspacemarkdown), [`DeesWorkspaceMarkdownoutlet`](#deesworkspacemarkdownoutlet), [`DeesWorkspaceBottombar`](#deesworkspacebottombar) |
|
|
67
|
-
| **Agentic Chat** | [`DeesHarnessChat`](#deesharnesschat), [`DeesHarnessMessageList`](#deesharnessmessagelist), [`DeesHarnessMessage`](#deesharnessmessage), [`DeesHarnessReasoning`](#deesharnessreasoning), [`DeesHarnessToolCard`](#deesharnesstoolcard), [`DeesHarnessContentBlocks`](#deesharnesscontentblocks), [`DeesHarnessPermissionCard`](#deesharnesspermissioncard), [`DeesHarnessComposer`](#deesharnesscomposer), [`DeesHarnessStatus`](#deesharnessstatus), [`DeesHarnessTodos`](#deesharnesstodos), [`DeesHarnessUsage`](#deesharnessusage), [`DeesHarnessSessionList`](#deesharnesssessionlist) |
|
|
67
|
+
| **Agentic Chat** | [`DeesHarnessChat`](#deesharnesschat), [`DeesHarnessMessageList`](#deesharnessmessagelist), [`DeesHarnessMessage`](#deesharnessmessage), [`DeesHarnessReasoning`](#deesharnessreasoning), [`DeesHarnessToolCard`](#deesharnesstoolcard), [`DeesHarnessContentBlocks`](#deesharnesscontentblocks), [`DeesHarnessPermissionCard`](#deesharnesspermissioncard), [`DeesHarnessQuestionCard`](#deesharnessquestioncard), [`DeesHarnessComposer`](#deesharnesscomposer), [`DeesHarnessStatus`](#deesharnessstatus), [`DeesHarnessTodos`](#deesharnesstodos), [`DeesHarnessUsage`](#deesharnessusage), [`DeesHarnessSessionList`](#deesharnesssessionlist) |
|
|
68
68
|
| **Theming** | [`DeesTheme`](#deestheme), [`DeesUpdater`](#deesupdater) |
|
|
69
69
|
| **Pre-built Templates** | [`DeesSimpleAppdash`](#deessimpleappdash), [`DeesSimpleLogin`](#deessimplelogin) |
|
|
70
70
|
| **Shopping** | [`DeesShoppingProductcard`](#deesshoppingproductcard) |
|
|
@@ -713,6 +713,33 @@ Submit button component specifically designed for `DeesForm`.
|
|
|
713
713
|
|
|
714
714
|
### App Shell (Layout) Components
|
|
715
715
|
|
|
716
|
+
#### `DeesMosaic`
|
|
717
|
+
|
|
718
|
+
Sway-like tiling workspace: a controlled split-tree layout where tiles resize against each other, drag by a slim tilebar (which also closes them), and dock onto any edge of another tile with a live drop preview. Content projects through named slots, so hosts keep light-DOM ownership — Electron `<webview>` content survives every layout change because slot reassignment never moves the light-DOM node.
|
|
719
|
+
|
|
720
|
+
```typescript
|
|
721
|
+
import { createMosaicLeaf, mosaicInsert, type IMosaicLayout } from '@design.estate/dees-catalog';
|
|
722
|
+
|
|
723
|
+
let layout: IMosaicLayout = mosaicInsert({ root: null }, null, 'right', createMosaicLeaf('editor', 'l-editor'));
|
|
724
|
+
layout = mosaicInsert(layout, 'l-editor', 'right', createMosaicLeaf('chat', 'l-chat'));
|
|
725
|
+
layout = mosaicInsert(layout, null, 'bottom', createMosaicLeaf('terminal', 'l-term'));
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
```html
|
|
729
|
+
<dees-mosaic
|
|
730
|
+
.layout=${layout}
|
|
731
|
+
.surfaces=${{ editor: { title: 'Editor', icon: 'lucide:Code' }, chat: { title: 'AI Chat' }, terminal: { title: 'Terminal' } }}
|
|
732
|
+
@mosaic-layout-change=${(e) => { layout = e.detail.layout; /* persist */ }}
|
|
733
|
+
>
|
|
734
|
+
<my-editor slot="tile-l-editor"></my-editor>
|
|
735
|
+
<my-chat slot="tile-l-chat"></my-chat>
|
|
736
|
+
<my-terminal slot="tile-l-term"></my-terminal>
|
|
737
|
+
<div slot="empty">Workspace is empty.</div>
|
|
738
|
+
</dees-mosaic>
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
The component is controlled: apply `e.detail.layout` back (and persist it) on every `mosaic-layout-change` (`reason: 'resize' | 'drop' | 'close' | 'equalize'`). Other events: cancelable `mosaic-tile-close`, `mosaic-tile-focus`, throttled `mosaic-resizing` (re-measure embedded content), `mosaic-drag-state`. Methods: `getLeafRects()` (viewport rect per leaf content area), `equalize(splitId?)`, `focusTile(id)`. Pure helpers (`mosaicInsert/mosaicRemove/mosaicMove/mosaicResize/mosaicEqualize/mosaicNormalize/mosaicLeaves`) are exported for host-side layout logic. Splitters are keyboard-accessible (`role="separator"`, arrow keys resize, double-click equalizes); Escape cancels drags.
|
|
742
|
+
|
|
716
743
|
#### `DeesAppui` 🏗️
|
|
717
744
|
A comprehensive application shell component providing a complete UI framework with navigation, menus, activity logging, bottom bar, and view management.
|
|
718
745
|
|
|
@@ -1699,7 +1726,7 @@ The `00group-harness` family renders what an agent harness produces — streamin
|
|
|
1699
1726
|
|
|
1700
1727
|
#### `DeesHarnessChat`
|
|
1701
1728
|
|
|
1702
|
-
The assembled chat: optional toolbar (heading, usage chip, history/new-session buttons), streaming message list
|
|
1729
|
+
The assembled chat: optional toolbar (heading, usage chip, history/new-session buttons), streaming message list with inline permission cards, transcript status line, and docked composer.
|
|
1703
1730
|
|
|
1704
1731
|
```typescript
|
|
1705
1732
|
const chat = document.querySelector('dees-harness-chat');
|
|
@@ -1721,13 +1748,13 @@ chat.applyDelta({ type: 'text', messageId: 'm1', delta: 'chunk' });
|
|
|
1721
1748
|
chat.applyDelta({ type: 'message-end', messageId: 'm1', usage: { totalTokens: 1200 } });
|
|
1722
1749
|
```
|
|
1723
1750
|
|
|
1724
|
-
Key props: `messages`, `permissions`, `status`, `usage`, `todos`/`showTodosPanel`, `heading`, `subheading`, `showToolbar`, `busy`, `queuedCount`, `disabled`, `model`/`modelOptions`, `reasoningEffort`/`effortOptions`, `toolRegistry`.
|
|
1751
|
+
Key props: `messages`, `permissions`, `questions`, `status`, `usage`, `todos`/`showTodosPanel`, `heading`, `subheading`, `showToolbar`, `busy`, `queuedCount`, `disabled`, `model`/`modelOptions`, `reasoningEffort`/`effortOptions`, `mode`/`modeOptions`, `toolRegistry`. The status line renders inside the transcript column (it never pushes between the Tasks panel and the composer), and both the toolbar and the docked composer cast a subtle shadow over the scrolling messages.
|
|
1725
1752
|
|
|
1726
|
-
A **Tasks side panel** (OpenCode-style) shows the current todo list next to the transcript: set `.todos` explicitly, or leave it empty and the chat derives it from the newest todo tool call in `messages`. The panel hides itself in narrow containers (< 520px) where the transcript's todo cards carry the same information; `showTodosPanel={false}` disables it entirely. Methods: `applyDelta()`, `focusComposer()`, `clearComposer()`, `scrollToBottom()`. Events (also from children, all composed): `harness-send`, `harness-steer`, `harness-abort`, `harness-input`, `harness-attachments-change`, `harness-attachment-error`, `harness-model-change`, `harness-permission-response`, `harness-new-session`, `harness-open-sessions`.
|
|
1753
|
+
A **Tasks side panel** (OpenCode-style) shows the current todo list next to the transcript: set `.todos` explicitly, or leave it empty and the chat derives it from the newest todo tool call in `messages`. The panel hides itself in narrow containers (< 520px) where the transcript's todo cards carry the same information; `showTodosPanel={false}` disables it entirely. Methods: `applyDelta()`, `focusComposer()`, `clearComposer()`, `scrollToBottom()`. Events (also from children, all composed): `harness-send`, `harness-steer`, `harness-abort`, `harness-input`, `harness-attachments-change`, `harness-attachment-error`, `harness-model-change`, `harness-mode-change`, `harness-permission-response`, `harness-question-response`, `harness-new-session`, `harness-open-sessions`.
|
|
1727
1754
|
|
|
1728
1755
|
#### `DeesHarnessMessageList`
|
|
1729
1756
|
|
|
1730
|
-
Scrollable streaming-safe log. Keyed repeat
|
|
1757
|
+
Scrollable streaming-safe log. Keyed repeat keeps DOM identity stable; `applyDelta()` routes updates to the affected message element only. Auto-follows the bottom while pinned; otherwise raises a "Jump to latest" chip instead of yanking the scroll. Permission requests and agent questions render inline in the flow, and while pinned the list follows content growth frame-by-frame (ResizeObserver), so a new box growing into place and the scroll move as one motion. Props: `messages`, `permissions`/`permissionsBusy`, `questions`, `status`, `autoFollow`, `showRoles`, `showTimestamps`, `emptyTitle`/`emptyText` (+ `slot="empty"`).
|
|
1731
1758
|
|
|
1732
1759
|
#### `DeesHarnessMessage`
|
|
1733
1760
|
|
|
@@ -1764,12 +1791,20 @@ Renders MCP `CallToolResult` content structurally: text, base64 images, audio wi
|
|
|
1764
1791
|
|
|
1765
1792
|
Permission prompt: title, type badge (shell/delete → error tone, write/browser → warning), metadata key/values, Allow Once / Always Allow / Reject, and a "remember" checkbox (`always` implies remember). Emits `harness-permission-response`; disables itself once answered or while `busy`.
|
|
1766
1793
|
|
|
1794
|
+
Inside the chat, permission cards render **inline with the messages**: pending requests pin to the end of the transcript (action required), and answered ones freeze at their response time in the flow. Set `response`/`respondedAt` on the request after handling it and keep it in the array — the card stays in the transcript showing what was granted or rejected.
|
|
1795
|
+
|
|
1796
|
+
#### `DeesHarnessQuestionCard`
|
|
1797
|
+
|
|
1798
|
+
A question the agent asks mid-run: option buttons with descriptions (single-select answers on click; `multiSelect` collects then confirms) plus an optional free-text answer (`allowCustom`, default on — Enter or "Send Answer" submits, combining selections with the text). Emits `harness-question-response` with `{ requestId, answers, request }`. Questions flow through `dees-harness-chat`'s `questions` property and render inline like permissions: pending ones pin to the end of the transcript, and answered ones persist showing the chosen answers once the host sets `response`/`respondedAt`.
|
|
1799
|
+
|
|
1767
1800
|
#### `DeesHarnessComposer`
|
|
1768
1801
|
|
|
1769
1802
|
Prompt input: autogrow textarea, attachment picker/paste/drag-drop with per-file (10 MB) and total (30 MB) limits and MIME allowlist, optional model + reasoning-effort dropdowns, Cmd/Ctrl+Enter to send. Controlled component — the host owns `value` and `attachments`.
|
|
1770
1803
|
|
|
1771
1804
|
While `busy`, Stop renders as an additional button and Send stays available so hosts can queue messages. With an empty prompt and `queuedCount > 0`, the primary action becomes **Steer now** (`harness-steer` event) to force the agent to continue with the queued messages immediately.
|
|
1772
1805
|
|
|
1806
|
+
Set `modeOptions` (e.g. `['Planning', 'Building']`) to render a segmented **mode switcher**; the active `mode` changes on click — or **Shift+Tab** inside the prompt cycles it — and emits `harness-mode-change`. Inside `dees-harness-chat` the composer renders `docked` — flush edge-to-edge with a top border and an upward shadow (`--dees-shadow-up-sm`) so it meets the transcript and the Tasks panel like the toolbar does; standalone composers keep the floating-card chrome.
|
|
1807
|
+
|
|
1773
1808
|
#### `DeesHarnessTodos`
|
|
1774
1809
|
|
|
1775
1810
|
Agent task list for `IHarnessTodoItem[]` — completed items dim with a check and strikethrough, the in-progress item leads with a pulsing accent marker, and an optional heading shows `completed/total` progress. Used automatically as the todo tool-card body (`harnessParseTodos` normalizes tool input shapes) and standalone for a "current tasks" sidebar panel fed from the latest `todowrite` call.
|
package/readme.playbook.md
CHANGED
|
@@ -439,7 +439,7 @@ Components that render continuously arriving data (agent chat, logs) follow the
|
|
|
439
439
|
- **Props are the source of truth; deltas are the fast path.** The host owns the array (e.g. `.messages`). Incremental updates go through `applyDelta()`, which mutates the same object instance held in the array and calls `requestUpdate()` on the one affected child element. A later wholesale re-assignment of the array is therefore idempotent — no divergence between streamed and re-set state.
|
|
440
440
|
- **Keyed `repeat` for identity.** List children render via `directives.repeat` keyed by a stable id so streaming never recreates sibling DOM (which would drop scroll position, expansion state, and selection).
|
|
441
441
|
- **Cheap while streaming, rich when done.** While `streaming` is set, text renders as pre-wrap with a cursor; expensive work (markdown parse) is throttled (≥150 ms, token-guarded like the codebox highlight pattern) and syntax highlighting waits for the final parse.
|
|
442
|
-
- **Scroll follow with user override.** Auto-scroll only when the user is already pinned to the bottom (`scrollHeight - scrollTop - clientHeight < threshold`); otherwise show a "jump to latest" chip.
|
|
442
|
+
- **Scroll follow with user override.** Auto-scroll only when the user is already pinned to the bottom (`scrollHeight - scrollTop - clientHeight < threshold`); otherwise show a "jump to latest" chip. While pinned, a content change opens a short follow window and a `ResizeObserver` on the scroll content re-pins the bottom on every layout change (post-layout, pre-paint), so a growing box and the scroll move as one motion; an external upward scroll ends the window before the next pin so following never fights the user. Disconnect the observer in `disconnectedCallback`.
|
|
443
443
|
- **Interaction state lives on the child.** Expand/collapse (reasoning, tool cards) is element-local state seeded from data (`expanded ?? isStreaming`), so parent re-renders can't reset what the user opened.
|
|
444
444
|
|
|
445
445
|
## Performance Optimization
|
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@design.estate/dees-catalog',
|
|
6
|
-
version: '3.
|
|
6
|
+
version: '3.95.0',
|
|
7
7
|
description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.'
|
|
8
8
|
}
|
|
@@ -223,6 +223,23 @@ const simulate = (event: MouseEvent) => {
|
|
|
223
223
|
});
|
|
224
224
|
};
|
|
225
225
|
|
|
226
|
+
const askQuestion = (event: MouseEvent) => {
|
|
227
|
+
const chat = chatOf(event);
|
|
228
|
+
if (!chat) return;
|
|
229
|
+
chat.questions = [
|
|
230
|
+
...chat.questions,
|
|
231
|
+
{
|
|
232
|
+
id: `question-${Date.now()}`,
|
|
233
|
+
question: 'Which cache-key strategy should I roll out?',
|
|
234
|
+
createdAt: Date.now(),
|
|
235
|
+
options: [
|
|
236
|
+
{ label: 'Route manifest hash', description: 'Deterministic, invalidates on route changes' },
|
|
237
|
+
{ label: 'Content hash', description: 'Fine-grained, more churn' },
|
|
238
|
+
],
|
|
239
|
+
},
|
|
240
|
+
];
|
|
241
|
+
};
|
|
242
|
+
|
|
226
243
|
const askPermission = (event: MouseEvent) => {
|
|
227
244
|
const chat = chatOf(event);
|
|
228
245
|
if (!chat) return;
|
|
@@ -274,9 +291,23 @@ export const demoFunc = () => html`
|
|
|
274
291
|
console.log('harness-permission-response', event.detail);
|
|
275
292
|
const chat = (event.target as HTMLElement).closest('.chatDemo')?.querySelector('dees-harness-chat');
|
|
276
293
|
if (chat) {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
294
|
+
// answered cards stay in the transcript showing the outcome
|
|
295
|
+
chat.permissions = chat.permissions.map((request) =>
|
|
296
|
+
request.id === event.detail.requestId
|
|
297
|
+
? { ...request, response: event.detail.response, respondedAt: Date.now() }
|
|
298
|
+
: request,
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
}}
|
|
302
|
+
@harness-question-response=${(event: CustomEvent) => {
|
|
303
|
+
console.log('harness-question-response', event.detail);
|
|
304
|
+
const chat = (event.target as HTMLElement).closest('.chatDemo')?.querySelector('dees-harness-chat');
|
|
305
|
+
if (chat) {
|
|
306
|
+
chat.questions = chat.questions.map((request) =>
|
|
307
|
+
request.id === event.detail.requestId
|
|
308
|
+
? { ...request, response: event.detail.answers, respondedAt: Date.now() }
|
|
309
|
+
: request,
|
|
310
|
+
);
|
|
280
311
|
}
|
|
281
312
|
}}
|
|
282
313
|
@harness-new-session=${() => console.log('harness-new-session')}
|
|
@@ -289,6 +320,7 @@ export const demoFunc = () => html`
|
|
|
289
320
|
<div class="controls">
|
|
290
321
|
<dees-button type="accent" @clicked=${simulate}>Simulate streaming</dees-button>
|
|
291
322
|
<dees-button @clicked=${askPermission}>Ask permission</dees-button>
|
|
323
|
+
<dees-button @clicked=${askQuestion}>Ask a question</dees-button>
|
|
292
324
|
<dees-button @clicked=${toggleError}>Toggle error status</dees-button>
|
|
293
325
|
<dees-button type="ghost" @clicked=${resetChat}>Reset</dees-button>
|
|
294
326
|
</div>
|
|
@@ -297,6 +329,8 @@ export const demoFunc = () => html`
|
|
|
297
329
|
subheading="acme-app · main · connected"
|
|
298
330
|
model="gpt-5.5"
|
|
299
331
|
reasoningEffort="high"
|
|
332
|
+
mode="Building"
|
|
333
|
+
.modeOptions=${['Planning', 'Building']}
|
|
300
334
|
.modelOptions=${['gpt-5.5', 'gpt-5', 'o4-mini']}
|
|
301
335
|
.effortOptions=${['xhigh', 'high', 'medium', 'low']}
|
|
302
336
|
.usage=${{ inputTokens: 18_400, outputTokens: 3_100, totalTokens: 21_500 }}
|
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
IHarnessAttachment,
|
|
14
14
|
IHarnessMessage,
|
|
15
15
|
IHarnessPermissionRequest,
|
|
16
|
+
IHarnessQuestionRequest,
|
|
16
17
|
IHarnessStatus,
|
|
17
18
|
IHarnessTodoItem,
|
|
18
19
|
IHarnessUsage,
|
|
@@ -22,8 +23,6 @@ import { harnessParseTodos } from '../harness.helpers.js';
|
|
|
22
23
|
import { DeesHarnessToolRegistry } from '../toolregistry.js';
|
|
23
24
|
import { DeesHarnessMessageList } from '../dees-harness-message-list/dees-harness-message-list.js';
|
|
24
25
|
import { DeesHarnessComposer } from '../dees-harness-composer/dees-harness-composer.js';
|
|
25
|
-
import '../dees-harness-permission-card/dees-harness-permission-card.js';
|
|
26
|
-
import '../dees-harness-status/dees-harness-status.js';
|
|
27
26
|
import '../dees-harness-todos/dees-harness-todos.js';
|
|
28
27
|
import '../dees-harness-usage/dees-harness-usage.js';
|
|
29
28
|
import '../../00group-button/dees-button/dees-button.js';
|
|
@@ -35,9 +34,6 @@ declare global {
|
|
|
35
34
|
}
|
|
36
35
|
}
|
|
37
36
|
|
|
38
|
-
// stable idle binding for the embedded list — a fresh object literal per
|
|
39
|
-
// render would re-trigger its follow logic on every chat render
|
|
40
|
-
const idleStatus: IHarnessStatus = { type: 'idle' };
|
|
41
37
|
|
|
42
38
|
/**
|
|
43
39
|
* The assembled agent chat: optional toolbar, streaming message list,
|
|
@@ -58,6 +54,10 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
58
54
|
@property({ attribute: false })
|
|
59
55
|
accessor permissions: IHarnessPermissionRequest[] = [];
|
|
60
56
|
|
|
57
|
+
/** agent questions render inline like permissions; answered ones persist */
|
|
58
|
+
@property({ attribute: false })
|
|
59
|
+
accessor questions: IHarnessQuestionRequest[] = [];
|
|
60
|
+
|
|
61
61
|
@property({ attribute: false })
|
|
62
62
|
accessor status: IHarnessStatus = { type: 'idle' };
|
|
63
63
|
|
|
@@ -115,6 +115,13 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
115
115
|
@property({ attribute: false })
|
|
116
116
|
accessor effortOptions: string[] = [];
|
|
117
117
|
|
|
118
|
+
/** agent mode switcher (e.g. Planning / Building); empty hides it */
|
|
119
|
+
@property()
|
|
120
|
+
accessor mode: string = '';
|
|
121
|
+
|
|
122
|
+
@property({ attribute: false })
|
|
123
|
+
accessor modeOptions: string[] = [];
|
|
124
|
+
|
|
118
125
|
@property({ attribute: false })
|
|
119
126
|
accessor toolRegistry: DeesHarnessToolRegistry = DeesHarnessToolRegistry.default;
|
|
120
127
|
|
|
@@ -166,6 +173,10 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
166
173
|
padding: var(--dees-spacing-sm) var(--dees-spacing-md);
|
|
167
174
|
border-bottom: 1px solid var(--dees-color-border-subtle);
|
|
168
175
|
background: var(--dees-color-bg-secondary);
|
|
176
|
+
/* chrome floats above the scrolling transcript */
|
|
177
|
+
position: relative;
|
|
178
|
+
z-index: 1;
|
|
179
|
+
box-shadow: var(--dees-shadow-sm);
|
|
169
180
|
}
|
|
170
181
|
|
|
171
182
|
.headingBlock {
|
|
@@ -203,32 +214,13 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
203
214
|
min-height: 0;
|
|
204
215
|
}
|
|
205
216
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
padding: 0 var(--dees-spacing-md);
|
|
210
|
-
max-height: 40%;
|
|
211
|
-
overflow-y: auto;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
.permissionQueue > * + * {
|
|
215
|
-
margin-top: var(--dees-spacing-xs);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/* always mounted so the status leave transition can play; the status
|
|
219
|
-
element renders empty when idle, collapsing the row to zero height */
|
|
220
|
-
.statusRow {
|
|
221
|
-
flex: 0 0 auto;
|
|
222
|
-
padding: 0 var(--dees-spacing-md);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
.statusRow dees-harness-status {
|
|
226
|
-
margin: 0;
|
|
227
|
-
}
|
|
228
|
-
|
|
217
|
+
/* the composer docks edge-to-edge like the toolbar, so the tasks
|
|
218
|
+
panel's border meets its top border cleanly; z-order keeps its
|
|
219
|
+
upward shadow above the transcript */
|
|
229
220
|
.composerRow {
|
|
230
221
|
flex: 0 0 auto;
|
|
231
|
-
|
|
222
|
+
position: relative;
|
|
223
|
+
z-index: 1;
|
|
232
224
|
}
|
|
233
225
|
`,
|
|
234
226
|
];
|
|
@@ -285,7 +277,10 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
285
277
|
<div class="chatBody">
|
|
286
278
|
<dees-harness-message-list
|
|
287
279
|
.messages=${this.messages}
|
|
288
|
-
.
|
|
280
|
+
.permissions=${this.permissions}
|
|
281
|
+
.permissionsBusy=${this.disabled}
|
|
282
|
+
.questions=${this.questions}
|
|
283
|
+
.status=${this.status}
|
|
289
284
|
.showRoles=${this.showRoles}
|
|
290
285
|
.toolRegistry=${this.toolRegistry}
|
|
291
286
|
></dees-harness-message-list>
|
|
@@ -297,22 +292,9 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
297
292
|
`
|
|
298
293
|
: ''}
|
|
299
294
|
</div>
|
|
300
|
-
${this.permissions.length
|
|
301
|
-
? html`
|
|
302
|
-
<div class="permissionQueue">
|
|
303
|
-
${this.permissions.map(
|
|
304
|
-
(request) => html`
|
|
305
|
-
<dees-harness-permission-card .request=${request} .busy=${this.disabled}></dees-harness-permission-card>
|
|
306
|
-
`,
|
|
307
|
-
)}
|
|
308
|
-
</div>
|
|
309
|
-
`
|
|
310
|
-
: ''}
|
|
311
|
-
<div class="statusRow">
|
|
312
|
-
<dees-harness-status .status=${this.status}></dees-harness-status>
|
|
313
|
-
</div>
|
|
314
295
|
<div class="composerRow">
|
|
315
296
|
<dees-harness-composer
|
|
297
|
+
docked
|
|
316
298
|
.value=${this.composerValue}
|
|
317
299
|
.attachments=${this.attachments}
|
|
318
300
|
.disabled=${this.disabled}
|
|
@@ -322,6 +304,8 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
322
304
|
.modelOptions=${this.modelOptions}
|
|
323
305
|
.reasoningEffort=${this.reasoningEffort}
|
|
324
306
|
.effortOptions=${this.effortOptions}
|
|
307
|
+
.mode=${this.mode}
|
|
308
|
+
.modeOptions=${this.modeOptions}
|
|
325
309
|
@harness-input=${(event: CustomEvent<{ value: string }>) => {
|
|
326
310
|
this.composerValue = event.detail?.value ?? '';
|
|
327
311
|
}}
|
|
@@ -332,6 +316,9 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
332
316
|
if (event.detail?.model) this.model = event.detail.model;
|
|
333
317
|
if (event.detail?.reasoningEffort) this.reasoningEffort = event.detail.reasoningEffort;
|
|
334
318
|
}}
|
|
319
|
+
@harness-mode-change=${(event: CustomEvent<{ mode?: string }>) => {
|
|
320
|
+
if (event.detail?.mode) this.mode = event.detail.mode;
|
|
321
|
+
}}
|
|
335
322
|
></dees-harness-composer>
|
|
336
323
|
</div>
|
|
337
324
|
`;
|
|
@@ -30,11 +30,14 @@ export const demoFunc = () => html`
|
|
|
30
30
|
@harness-attachments-change=${logEvent}
|
|
31
31
|
@harness-attachment-error=${logEvent}
|
|
32
32
|
@harness-model-change=${logEvent}
|
|
33
|
+
@harness-mode-change=${logEvent}
|
|
33
34
|
>
|
|
34
|
-
<div class="label">default with model controls (events log to console)</div>
|
|
35
|
+
<div class="label">default with mode switcher + model controls (events log to console)</div>
|
|
35
36
|
<dees-harness-composer
|
|
36
37
|
model="gpt-5.5"
|
|
37
38
|
reasoningEffort="high"
|
|
39
|
+
mode="Planning"
|
|
40
|
+
.modeOptions=${['Planning', 'Building']}
|
|
38
41
|
.modelOptions=${['gpt-5.5', 'gpt-5', 'o4-mini']}
|
|
39
42
|
.effortOptions=${['xhigh', 'high', 'medium', 'low']}
|
|
40
43
|
></dees-harness-composer>
|
|
@@ -57,6 +57,15 @@ export class DeesHarnessComposer extends DeesElement {
|
|
|
57
57
|
@property()
|
|
58
58
|
accessor placeholder: string = 'Message the agent — drop or paste files to attach…';
|
|
59
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Docked composers sit flush against their container edge-to-edge (a
|
|
62
|
+
* top border instead of the floating card chrome) — used by
|
|
63
|
+
* dees-harness-chat so the bar meets the transcript and the tasks panel
|
|
64
|
+
* without a gap.
|
|
65
|
+
*/
|
|
66
|
+
@property({ type: Boolean, reflect: true })
|
|
67
|
+
accessor docked: boolean = false;
|
|
68
|
+
|
|
60
69
|
@property({ type: Boolean })
|
|
61
70
|
accessor disabled: boolean = false;
|
|
62
71
|
|
|
@@ -94,6 +103,16 @@ export class DeesHarnessComposer extends DeesElement {
|
|
|
94
103
|
@property({ attribute: false })
|
|
95
104
|
accessor effortOptions: string[] = [];
|
|
96
105
|
|
|
106
|
+
/**
|
|
107
|
+
* Agent mode switcher (e.g. Planning / Building). Renders a segmented
|
|
108
|
+
* control when modeOptions is set; emits harness-mode-change.
|
|
109
|
+
*/
|
|
110
|
+
@property()
|
|
111
|
+
accessor mode: string = '';
|
|
112
|
+
|
|
113
|
+
@property({ attribute: false })
|
|
114
|
+
accessor modeOptions: string[] = [];
|
|
115
|
+
|
|
97
116
|
@property({ type: Boolean })
|
|
98
117
|
accessor showModelControls: boolean = true;
|
|
99
118
|
|
|
@@ -121,6 +140,19 @@ export class DeesHarnessComposer extends DeesElement {
|
|
|
121
140
|
box-shadow: 0 0 0 3px var(--dees-color-focus-ring);
|
|
122
141
|
}
|
|
123
142
|
|
|
143
|
+
:host([docked]) .composer {
|
|
144
|
+
border: 0;
|
|
145
|
+
border-top: 1px solid var(--dees-color-border-subtle);
|
|
146
|
+
border-radius: 0;
|
|
147
|
+
padding: var(--dees-spacing-sm) var(--dees-spacing-md) var(--dees-spacing-md);
|
|
148
|
+
box-shadow: var(--dees-shadow-up-sm);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
:host([docked]) .composer.dragOver {
|
|
152
|
+
border-top-color: var(--dees-color-accent-primary);
|
|
153
|
+
box-shadow: inset 0 3px 0 0 var(--dees-color-focus-ring);
|
|
154
|
+
}
|
|
155
|
+
|
|
124
156
|
.fileInput {
|
|
125
157
|
display: none;
|
|
126
158
|
}
|
|
@@ -214,6 +246,44 @@ export class DeesHarnessComposer extends DeesElement {
|
|
|
214
246
|
gap: var(--dees-spacing-sm);
|
|
215
247
|
}
|
|
216
248
|
|
|
249
|
+
/* segmented mode switcher (Planning / Building) */
|
|
250
|
+
.modeSwitch {
|
|
251
|
+
display: inline-flex;
|
|
252
|
+
flex: 0 0 auto;
|
|
253
|
+
padding: 2px;
|
|
254
|
+
border-radius: var(--dees-radius-md);
|
|
255
|
+
corner-shape: var(--dees-corner-shape);
|
|
256
|
+
background: var(--dees-color-fill-secondary);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.modeSwitch button {
|
|
260
|
+
height: calc(var(--dees-control-height-sm) - 4px);
|
|
261
|
+
padding: 0 10px;
|
|
262
|
+
border: 0;
|
|
263
|
+
border-radius: calc(var(--dees-radius-md) - 2px);
|
|
264
|
+
corner-shape: var(--dees-corner-shape);
|
|
265
|
+
background: transparent;
|
|
266
|
+
color: var(--dees-color-text-secondary);
|
|
267
|
+
cursor: pointer;
|
|
268
|
+
font-family: inherit;
|
|
269
|
+
font-size: var(--dees-font-control-size-sm, 12px);
|
|
270
|
+
font-weight: 500;
|
|
271
|
+
transition:
|
|
272
|
+
background var(--dees-transition-fast) var(--dees-ease-standard),
|
|
273
|
+
color var(--dees-transition-fast) var(--dees-ease-standard);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.modeSwitch button.active {
|
|
277
|
+
background: var(--dees-color-bg-primary);
|
|
278
|
+
color: var(--dees-color-text-primary);
|
|
279
|
+
box-shadow: var(--dees-shadow-xs);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.modeSwitch button:disabled {
|
|
283
|
+
cursor: default;
|
|
284
|
+
opacity: 0.55;
|
|
285
|
+
}
|
|
286
|
+
|
|
217
287
|
.modelControls {
|
|
218
288
|
display: flex;
|
|
219
289
|
gap: var(--dees-spacing-xs);
|
|
@@ -289,6 +359,26 @@ export class DeesHarnessComposer extends DeesElement {
|
|
|
289
359
|
>
|
|
290
360
|
<dees-icon icon="lucide:Paperclip" iconSize="14"></dees-icon>
|
|
291
361
|
</dees-button>
|
|
362
|
+
${this.modeOptions.length
|
|
363
|
+
? html`
|
|
364
|
+
<div class="modeSwitch" role="radiogroup" aria-label="Agent mode">
|
|
365
|
+
${this.modeOptions.map((option) => html`
|
|
366
|
+
<button
|
|
367
|
+
type="button"
|
|
368
|
+
role="radio"
|
|
369
|
+
aria-checked=${option === this.mode ? 'true' : 'false'}
|
|
370
|
+
class=${option === this.mode ? 'active' : ''}
|
|
371
|
+
?disabled=${this.disabled}
|
|
372
|
+
@click=${() => {
|
|
373
|
+
if (this.mode === option) return;
|
|
374
|
+
this.mode = option;
|
|
375
|
+
this.emit('harness-mode-change', { mode: option });
|
|
376
|
+
}}
|
|
377
|
+
>${option}</button>
|
|
378
|
+
`)}
|
|
379
|
+
</div>
|
|
380
|
+
`
|
|
381
|
+
: ''}
|
|
292
382
|
${this.showModelControls && (this.modelOptions.length || this.effortOptions.length)
|
|
293
383
|
? html`
|
|
294
384
|
<div class="modelControls">
|
|
@@ -391,6 +481,15 @@ export class DeesHarnessComposer extends DeesElement {
|
|
|
391
481
|
if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {
|
|
392
482
|
event.preventDefault();
|
|
393
483
|
this.send();
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
// Shift+Tab cycles the agent mode without leaving the prompt
|
|
487
|
+
if (event.key === 'Tab' && event.shiftKey && this.modeOptions.length) {
|
|
488
|
+
event.preventDefault();
|
|
489
|
+
const currentIndex = this.modeOptions.indexOf(this.mode);
|
|
490
|
+
const nextMode = this.modeOptions[(currentIndex + 1) % this.modeOptions.length];
|
|
491
|
+
this.mode = nextMode;
|
|
492
|
+
this.emit('harness-mode-change', { mode: nextMode });
|
|
394
493
|
}
|
|
395
494
|
};
|
|
396
495
|
|