@huanlin/dsh-plugin-aigc-canvas 0.1.2 → 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.
package/lib/client.js CHANGED
@@ -1,5 +1,5 @@
1
1
  window.__ModuleLoader__.load({
2
- id: "@dsh-external/dsh-aigc-canvas",
2
+ id: "@huanlin/dsh-plugin-aigc-canvas",
3
3
  factory: (require) => {
4
4
  var module = { exports: {} };
5
5
  var exports = module.exports;
@@ -235,10 +235,10 @@ window.__ModuleLoader__.load({
235
235
  //#endregion
236
236
  //#region \0dsh-css:D:\Projects\deepseek-harness\dsh-aigc-canvas\src\client\canvas.module.css.mjs
237
237
  const css$1 = "/* dsh-aigc-canvas client styles.\r\n *\r\n * Renders inside a better-sidebar tab panel. Follows the DSH core design\r\n * language: `--dsw-alias-*` semantic tokens, `--dsw-font-*` typography,\r\n * 36px header bar + 24x24 r6 icon buttons (mirror of SubagentView), 8px\r\n * radius cards on `--dsw-alias-bg-layer-2`, no aggressive borders —\r\n * hover/active fills carry the interaction state.\r\n */\r\n\r\n.i0op5y_canvas {\r\n position: relative;\r\n display: flex;\r\n flex-direction: column;\r\n height: 100%;\r\n font: var(--dsw-font-s-14);\r\n color: var(--dsw-alias-label-primary);\r\n background: transparent;\r\n}\r\n\r\n/* ── Header bar (mirror SubagentView: 36px h, 0 8px 0 12px) ────────────── */\r\n\r\n.i0op5y_header {\r\n flex: none;\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n height: 36px;\r\n padding: 0 8px 0 12px;\r\n}\r\n\r\n.i0op5y_title {\r\n flex: 1;\r\n min-width: 0;\r\n font: var(--dsw-font-s-14);\r\n color: var(--dsw-alias-label-secondary);\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n.i0op5y_count {\r\n flex: none;\r\n font: var(--dsw-font-xxxs-11);\r\n color: var(--dsw-alias-label-tertiary);\r\n}\r\n\r\n.i0op5y_zoom {\r\n flex: none;\r\n min-width: 36px;\r\n text-align: center;\r\n font: var(--dsw-font-xxxs-11);\r\n color: var(--dsw-alias-label-tertiary);\r\n}\r\n\r\n.i0op5y_iconButton {\r\n flex: none;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 24px;\r\n height: 24px;\r\n border: none;\r\n border-radius: 6px;\r\n background: transparent;\r\n color: var(--dsw-alias-label-secondary);\r\n cursor: pointer;\r\n font: var(--dsw-font-s-14);\r\n line-height: 1;\r\n}\r\n\r\n.i0op5y_iconButton:hover {\r\n background: var(--dsw-alias-interactive-bg-hover);\r\n color: var(--dsw-alias-label-primary);\r\n}\r\n\r\n/* Zoom slider in the header. */\r\n.i0op5y_zoomSlider {\r\n flex: none;\r\n width: 80px;\r\n height: 4px;\r\n -webkit-appearance: none;\r\n appearance: none;\r\n background: var(--dsw-alias-interactive-bg-hover);\r\n border-radius: 2px;\r\n outline: none;\r\n cursor: pointer;\r\n}\r\n\r\n.i0op5y_zoomSlider::-webkit-slider-thumb {\r\n -webkit-appearance: none;\r\n appearance: none;\r\n width: 12px;\r\n height: 12px;\r\n border-radius: 50%;\r\n background: var(--dsw-alias-label-secondary);\r\n cursor: pointer;\r\n}\r\n\r\n.i0op5y_zoomSlider::-moz-range-thumb {\r\n width: 12px;\r\n height: 12px;\r\n border: none;\r\n border-radius: 50%;\r\n background: var(--dsw-alias-label-secondary);\r\n cursor: pointer;\r\n}\r\n\r\n/* ── Infinite canvas surface ───────────────────────────────────────────── */\r\n\r\n.i0op5y_surface {\r\n flex: 1 1 auto;\r\n position: relative;\r\n overflow: hidden;\r\n touch-action: none;\r\n cursor: grab;\r\n background-color: transparent;\r\n background-image:\r\n radial-gradient(var(--dsw-alias-border-l2) 1px, transparent 1px);\r\n background-size: 24px 24px;\r\n}\r\n\r\n.i0op5y_surface:active {\r\n cursor: grabbing;\r\n}\r\n\r\n.i0op5y_world {\r\n position: absolute;\r\n left: 0;\r\n top: 0;\r\n transform-origin: 0 0;\r\n}\r\n\r\n.i0op5y_edgeLayer {\r\n position: absolute;\r\n left: 0;\r\n top: 0;\r\n width: 1px;\r\n height: 1px;\r\n overflow: visible;\r\n pointer-events: none;\r\n}\r\n\r\n.i0op5y_edgeLine {\r\n stroke: var(--dsw-alias-label-tertiary);\r\n stroke-width: 2.5;\r\n stroke-opacity: 0.55;\r\n fill: none;\r\n stroke-linecap: round;\r\n stroke-linejoin: round;\r\n}\r\n\r\n.i0op5y_edgeArrow {\r\n fill: var(--dsw-alias-label-tertiary);\r\n fill-opacity: 0.6;\r\n stroke: var(--dsw-alias-label-tertiary);\r\n stroke-width: 1;\r\n stroke-opacity: 0.6;\r\n}\r\n\r\n.i0op5y_edgePort {\r\n fill: var(--dsw-alias-bg-layer-2);\r\n stroke: var(--dsw-alias-label-tertiary);\r\n stroke-width: 2;\r\n stroke-opacity: 0.7;\r\n}\r\n\r\n.i0op5y_nodeBox {\r\n position: absolute;\r\n left: 0;\r\n top: 0;\r\n width: 240px;\r\n}\r\n\r\n.i0op5y_nodeBoxDraggable {\r\n cursor: move;\r\n touch-action: none;\r\n}\r\n\r\n.i0op5y_empty {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 2px;\r\n padding: 24px 16px;\r\n font: var(--dsw-font-xxs-12);\r\n color: var(--dsw-alias-label-tertiary);\r\n text-align: center;\r\n}\r\n\r\n.i0op5y_emptyHint {\r\n font: var(--dsw-font-xxxs-11);\r\n color: var(--dsw-alias-label-dimmed);\r\n}\r\n\r\n/* ── Node card (8px radius, bg-layer-2, no aggressive borders) ─────────── */\r\n\r\n.i0op5y_node {\r\n border-radius: 8px;\r\n background: var(--dsw-alias-bg-layer-2);\r\n overflow: hidden;\r\n}\r\n\r\n.i0op5y_nodeHeader {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 6px 10px;\r\n}\r\n\r\n.i0op5y_kindDot {\r\n flex: none;\r\n width: 6px;\r\n height: 6px;\r\n border-radius: 50%;\r\n background: var(--dsw-alias-label-tertiary);\r\n}\r\n\r\n.i0op5y_kindDot_image { background: #4caf50; }\r\n.i0op5y_kindDot_video { background: #ff9800; }\r\n.i0op5y_kindDot_audio { background: #ab47bc; }\r\n.i0op5y_kindDot_prompt { background: #6b8cff; }\r\n\r\n.i0op5y_kindLabel {\r\n font: var(--dsw-font-xxxs-11);\r\n color: var(--dsw-alias-label-tertiary);\r\n text-transform: lowercase;\r\n}\r\n\r\n.i0op5y_nodeTime {\r\n margin-left: auto;\r\n font: var(--dsw-font-xxxs-11);\r\n color: var(--dsw-alias-label-dimmed);\r\n}\r\n\r\n.i0op5y_nodeTitle {\r\n padding: 0 10px 4px;\r\n font: var(--dsw-font-s-14);\r\n color: var(--dsw-alias-label-primary);\r\n word-break: break-word;\r\n}\r\n\r\n.i0op5y_nodeDescription {\r\n padding: 0 10px 4px;\r\n font: var(--dsw-font-xxs-12);\r\n color: var(--dsw-alias-label-tertiary);\r\n font-style: italic;\r\n word-break: break-word;\r\n}\r\n\r\n.i0op5y_nodeMedia {\r\n padding: 0 10px 8px;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 4px;\r\n max-width: 100%;\r\n}\r\n\r\n.i0op5y_promptText {\r\n margin: 0;\r\n padding: 6px 8px;\r\n background: var(--dsw-alias-interactive-bg-hover);\r\n border-radius: 6px;\r\n font: var(--dsw-font-xxs-12);\r\n font-family: var(--ds-font-family-code);\r\n white-space: pre-wrap;\r\n word-break: break-word;\r\n max-height: 200px;\r\n overflow-y: auto;\r\n color: var(--dsw-alias-label-secondary);\r\n}\r\n\r\n.i0op5y_mediaImage {\r\n /* Counter-scale trick: decode at the on-screen pixel size (layout width\r\n * × zoom) so zooming in stays crisp, then visually shrink back to the\r\n * layout box. `--canvas-scale` is set on the world layer by CanvasView;\r\n * `--media-ratio` (h/w) is set on each img by CanvasNode after onLoad.\r\n *\r\n * width = 100% × scale → layout box (e.i0op5y_g. 880px at 4× zoom)\r\n * transform: scale(1/scale) → visual 220px (back to layout box size)\r\n * margin-right: 100% × (1-s) → cancel horizontal layout inflation\r\n * margin-bottom: 100% × ratio × (1-s) → cancel vertical layout inflation\r\n *\r\n * Percentages on margin resolve against the containing block's WIDTH\r\n * (the 220px card content area), so `100%` = 220px here — which is\r\n * exactly the visual width, making the math work out. */\r\n width: calc(100% * var(--canvas-scale, 1));\r\n max-width: none;\r\n height: auto;\r\n transform: scale(calc(1 / var(--canvas-scale, 1)));\r\n transform-origin: top left;\r\n margin-right: calc(100% * (1 - var(--canvas-scale, 1)));\r\n margin-bottom: calc(100% * var(--media-ratio, 0.75) * (1 - var(--canvas-scale, 1)));\r\n border-radius: 4px;\r\n display: block;\r\n}\r\n\r\n.i0op5y_mediaVideo {\r\n width: calc(100% * var(--canvas-scale, 1));\r\n max-width: none;\r\n height: auto;\r\n transform: scale(calc(1 / var(--canvas-scale, 1)));\r\n transform-origin: top left;\r\n margin-right: calc(100% * (1 - var(--canvas-scale, 1)));\r\n margin-bottom: calc(100% * var(--media-ratio, 0.75) * (1 - var(--canvas-scale, 1)));\r\n border-radius: 4px;\r\n display: block;\r\n}\r\n\r\n.i0op5y_mediaAudio {\r\n width: 100%;\r\n display: block;\r\n}\r\n\r\n.i0op5y_boundaryError {\r\n margin: 8px;\r\n padding: 8px 12px;\r\n font: var(--dsw-font-xxs-12);\r\n color: var(--dsw-alias-state-error-primary);\r\n background: var(--dsw-alias-interactive-bg-hover);\r\n border-radius: 6px;\r\n}\r\n\r\n/* ── Detail panel (elevated surface, mirror Modal/Panel aesthetic) ─────── */\r\n\r\n.i0op5y_detailPanel {\r\n position: absolute;\r\n right: 8px;\r\n top: 44px;\r\n bottom: 8px;\r\n width: 280px;\r\n display: flex;\r\n flex-direction: column;\r\n background: var(--dsw-alias-bg-layer-2);\r\n border-radius: 12px;\r\n box-shadow: var(--dsw-shadow-lv3);\r\n z-index: 10;\r\n overflow: hidden;\r\n --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);\r\n --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);\r\n}\r\n\r\n.i0op5y_detailHeader {\r\n flex: none;\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 8px 10px;\r\n}\r\n\r\n.i0op5y_detailTitle {\r\n flex: 1 1 auto;\r\n min-width: 0;\r\n font: var(--dsw-font-s-14);\r\n color: var(--dsw-alias-label-primary);\r\n word-break: break-word;\r\n}\r\n\r\n.i0op5y_detailClose {\r\n flex: none;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 24px;\r\n height: 24px;\r\n border: none;\r\n border-radius: 6px;\r\n background: transparent;\r\n color: var(--dsw-alias-label-secondary);\r\n cursor: pointer;\r\n font: var(--dsw-font-s-14);\r\n line-height: 1;\r\n}\r\n\r\n.i0op5y_detailClose:hover {\r\n background: var(--dsw-alias-interactive-bg-hover);\r\n color: var(--dsw-alias-label-primary);\r\n}\r\n\r\n.i0op5y_detailBody {\r\n flex: 1 1 auto;\r\n min-height: 0;\r\n overflow-y: auto;\r\n padding: 0 10px 10px;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 10px;\r\n}\r\n\r\n.i0op5y_detailBlock {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 4px;\r\n min-width: 0;\r\n}\r\n\r\n.i0op5y_detailLabel {\r\n font: var(--dsw-font-xxxs-11);\r\n color: var(--dsw-alias-label-tertiary);\r\n text-transform: lowercase;\r\n}\r\n\r\n.i0op5y_detailPrompt {\r\n margin: 0;\r\n padding: 6px 8px;\r\n background: var(--dsw-alias-interactive-bg-hover);\r\n border-radius: 6px;\r\n font: var(--dsw-font-xxs-12);\r\n font-family: var(--ds-font-family-code);\r\n white-space: pre-wrap;\r\n word-break: break-word;\r\n max-height: 160px;\r\n overflow-y: auto;\r\n color: var(--dsw-alias-label-secondary);\r\n}\r\n\r\n.i0op5y_detailValue {\r\n font: var(--dsw-font-xxs-12);\r\n color: var(--dsw-alias-label-secondary);\r\n word-break: break-word;\r\n}\r\n\r\n.i0op5y_metaList {\r\n margin: 0;\r\n padding: 0;\r\n display: grid;\r\n grid-template-columns: auto 1fr;\r\n gap: 2px 8px;\r\n font: var(--dsw-font-xxxs-11);\r\n color: var(--dsw-alias-label-tertiary);\r\n}\r\n\r\n.i0op5y_metaKey {\r\n font: var(--dsw-font-xxxs-strong-11);\r\n color: var(--dsw-alias-label-secondary);\r\n text-transform: lowercase;\r\n}\r\n\r\n.i0op5y_metaValue {\r\n margin: 0;\r\n color: var(--dsw-alias-label-secondary);\r\n word-break: break-all;\r\n font-family: var(--ds-font-family-code);\r\n}\r\n\r\n.i0op5y_filePath {\r\n display: block;\r\n font: var(--dsw-font-xxxs-11);\r\n font-family: var(--ds-font-family-code);\r\n color: var(--dsw-alias-label-tertiary);\r\n word-break: break-all;\r\n background: var(--dsw-alias-interactive-bg-hover);\r\n padding: 4px 6px;\r\n border-radius: 4px;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n}\r\n\r\n/* ── Minimap (bottom-right overview) ──────────────────────────────────── */\r\n\r\n.i0op5y_minimap {\r\n position: absolute;\r\n right: 8px;\r\n bottom: 8px;\r\n z-index: 5;\r\n background: var(--dsw-alias-bg-layer-2);\r\n border-radius: 8px;\r\n box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);\r\n padding: 4px;\r\n cursor: pointer;\r\n overflow: hidden;\r\n}\r\n\r\n.i0op5y_minimapSvg {\r\n display: block;\r\n pointer-events: none;\r\n}\r\n\r\n/* ── Right-click context menu ─────────────────────────────────────────── */\r\n\r\n.i0op5y_contextMenu {\r\n position: fixed;\r\n z-index: 20;\r\n min-width: 120px;\r\n background: var(--dsw-alias-bg-layer-2);\r\n border-radius: 8px;\r\n box-shadow: var(--dsw-shadow-lv3);\r\n padding: 4px;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 2px;\r\n}\r\n\r\n.i0op5y_contextMenuItem {\r\n display: block;\r\n width: 100%;\r\n padding: 6px 10px;\r\n border: none;\r\n border-radius: 6px;\r\n background: transparent;\r\n color: var(--dsw-alias-label-primary);\r\n font: var(--dsw-font-xxs-12);\r\n text-align: left;\r\n cursor: pointer;\r\n}\r\n\r\n.i0op5y_contextMenuItem:hover {\r\n background: var(--dsw-alias-state-error-bg);\r\n color: var(--dsw-alias-state-error-primary);\r\n}\r\n\r\n/* ── Drag-drop indicator + upload overlay ─────────────────────────────── */\r\n\r\n.i0op5y_dropIndicator {\r\n position: absolute;\r\n left: 0;\r\n top: 0;\r\n width: 240px;\r\n height: 110px;\r\n border: 2px dashed var(--dsw-alias-label-secondary);\r\n border-radius: 8px;\r\n background: var(--dsw-alias-interactive-bg-hover);\r\n opacity: 0.5;\r\n pointer-events: none;\r\n transform-origin: 0 0;\r\n}\r\n\r\n.i0op5y_uploadOverlay {\r\n position: absolute;\r\n inset: 0;\r\n z-index: 15;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n background: var(--dsw-alias-bg-layer-1);\r\n opacity: 0.6;\r\n font: var(--dsw-font-s-14);\r\n color: var(--dsw-alias-label-secondary);\r\n pointer-events: none;\r\n}\r\n";
238
- const tagId$1 = "@dsh-external/dsh-aigc-canvas/canvas.module.css";
238
+ const tagId$1 = "@huanlin/dsh-plugin-aigc-canvas/canvas.module.css";
239
239
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
240
240
  const tag = document.createElement("style");
241
- tag.dataset.plugin = "@dsh-external/dsh-aigc-canvas";
241
+ tag.dataset.plugin = "@huanlin/dsh-plugin-aigc-canvas";
242
242
  tag.dataset.pluginCss = tagId$1;
243
243
  tag.textContent = css$1;
244
244
  document.head.appendChild(tag);
@@ -1060,10 +1060,10 @@ window.__ModuleLoader__.load({
1060
1060
  //#endregion
1061
1061
  //#region \0dsh-css:D:\Projects\deepseek-harness\dsh-aigc-canvas\src\client\SettingsPage.module.css.mjs
1062
1062
  const css = "/* AIGC canvas settings section, in the settings-panel design language shared\r\n * with ModelsSection / GeneralSection / yet-another-subagent: 14/22 body,\r\n * 12/18 caption, 16/24 title, capsule controls (h36 r18 primary, h28 r14\r\n * secondary), 32px fields, border-l2 hairlines, and the editor as a filled\r\n * module on the panel fill.\r\n *\r\n * Every color resolves through a --dsw-alias-* token (no literal colors). */\r\n\r\n.o6nt8s_section {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 12px;\r\n max-width: 720px;\r\n color: var(--dsw-alias-label-primary);\r\n}\r\n\r\n.o6nt8s_title {\r\n margin: 0;\r\n font-size: 16px;\r\n line-height: 24px;\r\n font-weight: 500;\r\n color: var(--dsw-alias-label-primary);\r\n}\r\n\r\n.o6nt8s_intro {\r\n margin: 0;\r\n font-size: 14px;\r\n line-height: 22px;\r\n color: var(--dsw-alias-label-tertiary);\r\n}\r\n\r\n.o6nt8s_error {\r\n margin: 0;\r\n padding: 8px 12px;\r\n border: 1px solid var(--dsw-alias-state-error-primary);\r\n border-radius: 8px;\r\n background: var(--dsw-alias-interactive-bg-hover-danger);\r\n font-size: 12px;\r\n line-height: 18px;\r\n color: var(--dsw-alias-state-error-primary);\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n gap: 8px;\r\n}\r\n\r\n.o6nt8s_errorDismiss {\r\n flex: none;\r\n border: none;\r\n background: transparent;\r\n color: inherit;\r\n font-size: 16px;\r\n line-height: 1;\r\n cursor: pointer;\r\n padding: 0 4px;\r\n}\r\n\r\n.o6nt8s_rows {\r\n list-style: none;\r\n margin: 12px 0 0;\r\n padding: 0;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n}\r\n\r\n/* A configured provider: outlined on the panel fill, matching the rowCard\r\n * chrome in ModelsSection. */\r\n.o6nt8s_rowCard {\r\n border: 1px solid var(--dsw-alias-border-l2);\r\n border-radius: 12px;\r\n padding: 12px 14px;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 12px;\r\n}\r\n\r\n.o6nt8s_rowHead {\r\n display: flex;\r\n align-items: center;\r\n gap: 10px;\r\n}\r\n\r\n/* Chevron toggle: a small square with two borders, rotated to point right\r\n * (collapsed) or down (expanded). Pure CSS, no icon font. */\r\n.o6nt8s_chevronButton {\r\n flex: none;\r\n width: 24px;\r\n height: 24px;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n border: none;\r\n background: transparent;\r\n color: var(--dsw-alias-label-secondary);\r\n cursor: pointer;\r\n padding: 0;\r\n border-radius: 4px;\r\n}\r\n\r\n.o6nt8s_chevronButton:hover {\r\n background: var(--dsw-alias-interactive-bg-hover-solid);\r\n color: var(--dsw-alias-label-primary);\r\n}\r\n\r\n/* Spacer that occupies the chevron slot on cards without a toggle (e.o6nt8s_g. the\r\n * new-draft card, which is always expanded). Keeps row-head alignment. */\r\n.o6nt8s_chevronSpacer {\r\n flex: none;\r\n width: 24px;\r\n height: 24px;\r\n}\r\n\r\n.o6nt8s_chevron {\r\n width: 7px;\r\n height: 7px;\r\n border-right: 1.5px solid currentColor;\r\n border-bottom: 1.5px solid currentColor;\r\n transform: rotate(-45deg);\r\n transition: transform 0.15s ease;\r\n}\r\n\r\n.o6nt8s_chevronExpanded {\r\n transform: rotate(45deg);\r\n}\r\n\r\n.o6nt8s_rowIdentity {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n min-width: 0;\r\n flex: 1 1 auto;\r\n flex-wrap: wrap;\r\n}\r\n\r\n.o6nt8s_rowName {\r\n font-size: 14px;\r\n line-height: 22px;\r\n font-weight: 500;\r\n color: var(--dsw-alias-label-primary);\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n.o6nt8s_rowNamePlaceholder {\r\n font-size: 14px;\r\n line-height: 22px;\r\n font-weight: 500;\r\n color: var(--dsw-alias-label-tertiary);\r\n font-style: italic;\r\n}\r\n\r\n/* Builtin badge: uses DSH <Pill> with a brand-colored override to mark\r\n * seed providers. */\r\n.o6nt8s_builtinBadge {\r\n height: 18px;\r\n padding: 0 6px;\r\n border-radius: 4px;\r\n font-size: 11px;\r\n line-height: 16px;\r\n font-weight: 500;\r\n background: var(--dsw-alias-brand-primary);\r\n color: var(--dsw-alias-label-primary-foreground);\r\n letter-spacing: 0.02em;\r\n}\r\n\r\n/* Default provider badge. */\r\n.o6nt8s_defaultBadge {\r\n height: 18px;\r\n padding: 0 6px;\r\n border-radius: 4px;\r\n font-size: 11px;\r\n line-height: 16px;\r\n font-weight: 500;\r\n background: var(--dsw-alias-bg-layer-2);\r\n color: var(--dsw-alias-label-secondary);\r\n}\r\n\r\n/* Stub/real mode badge. */\r\n.o6nt8s_stubBadge {\r\n height: 18px;\r\n padding: 0 6px;\r\n border-radius: 4px;\r\n font-size: 11px;\r\n line-height: 16px;\r\n font-weight: 500;\r\n background: var(--dsw-alias-bg-layer-2);\r\n color: var(--dsw-alias-label-tertiary);\r\n}\r\n\r\n.o6nt8s_realBadge {\r\n height: 18px;\r\n padding: 0 6px;\r\n border-radius: 4px;\r\n font-size: 11px;\r\n line-height: 16px;\r\n font-weight: 500;\r\n background: var(--dsw-alias-state-success-primary);\r\n color: var(--dsw-alias-label-primary-foreground);\r\n}\r\n\r\n.o6nt8s_rowId {\r\n flex: none;\r\n padding: 1px 6px;\r\n border: 1px solid var(--dsw-alias-border-l3);\r\n border-radius: 4px;\r\n font-size: 11px;\r\n line-height: 16px;\r\n font-family: var(--dsw-font-markdown-code-block-small, monospace);\r\n color: var(--dsw-alias-label-secondary);\r\n}\r\n\r\n.o6nt8s_rowActions {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 4px;\r\n margin-left: auto;\r\n flex: none;\r\n}\r\n\r\n/* Editor surface: a filled module on the panel, matching ModelsSection's\r\n * editor chrome (bg-module-platform, r12, p14/16). */\r\n.o6nt8s_editor {\r\n border-radius: 12px;\r\n background: var(--dsw-alias-bg-module-platform);\r\n padding: 14px 16px;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 14px;\r\n}\r\n\r\n.o6nt8s_field {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 6px;\r\n}\r\n\r\n.o6nt8s_fieldLabel {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 10px;\r\n font-size: 12px;\r\n line-height: 18px;\r\n font-weight: 500;\r\n color: var(--dsw-alias-label-secondary);\r\n}\r\n\r\n/* Input: matching ModelsSection .o6nt8s_input — h32, r8, border-l2, bg-layer-1. */\r\n.o6nt8s_input {\r\n box-sizing: border-box;\r\n width: 100%;\r\n height: 32px;\r\n padding: 0 10px;\r\n border: 1px solid var(--dsw-alias-border-l2);\r\n border-radius: 8px;\r\n font: inherit;\r\n font-size: 14px;\r\n line-height: 22px;\r\n background: var(--dsw-alias-bg-layer-1);\r\n color: var(--dsw-alias-label-primary);\r\n}\r\n\r\n.o6nt8s_input:focus {\r\n outline: none;\r\n border-color: var(--dsw-alias-brand-primary);\r\n}\r\n\r\n.o6nt8s_input::placeholder {\r\n color: var(--dsw-alias-label-dimmed);\r\n}\r\n\r\n.o6nt8s_input:disabled {\r\n opacity: 0.6;\r\n cursor: default;\r\n}\r\n\r\n.o6nt8s_textarea {\r\n box-sizing: border-box;\r\n width: 100%;\r\n min-height: 64px;\r\n padding: 6px 10px;\r\n border: 1px solid var(--dsw-alias-border-l2);\r\n border-radius: 8px;\r\n font: inherit;\r\n font-size: 14px;\r\n line-height: 22px;\r\n background: var(--dsw-alias-bg-layer-1);\r\n color: var(--dsw-alias-label-primary);\r\n resize: vertical;\r\n}\r\n\r\n.o6nt8s_textarea:focus {\r\n outline: none;\r\n border-color: var(--dsw-alias-brand-primary);\r\n}\r\n\r\n.o6nt8s_textarea::placeholder {\r\n color: var(--dsw-alias-label-dimmed);\r\n}\r\n\r\n/* Auth scheme row: scheme select + optional name input side by side. */\r\n.o6nt8s_authRow {\r\n display: flex;\r\n gap: 8px;\r\n}\r\n\r\n.o6nt8s_authRow .o6nt8s_input {\r\n flex: 1 1 auto;\r\n}\r\n\r\n/* Select: same chrome as .o6nt8s_input. */\r\n.o6nt8s_select {\r\n box-sizing: border-box;\r\n flex: 0 0 auto;\r\n min-width: 130px;\r\n height: 32px;\r\n padding: 0 10px;\r\n border: 1px solid var(--dsw-alias-border-l2);\r\n border-radius: 8px;\r\n font: inherit;\r\n font-size: 14px;\r\n line-height: 22px;\r\n background: var(--dsw-alias-bg-layer-1);\r\n color: var(--dsw-alias-label-primary);\r\n}\r\n\r\n.o6nt8s_select:focus {\r\n outline: none;\r\n border-color: var(--dsw-alias-brand-primary);\r\n}\r\n\r\n/* Caption labels under fields. */\r\n.o6nt8s_desc {\r\n font-size: 12px;\r\n line-height: 18px;\r\n color: var(--dsw-alias-label-tertiary);\r\n}\r\n\r\n.o6nt8s_hint {\r\n font-size: 12px;\r\n line-height: 18px;\r\n color: var(--dsw-alias-label-secondary);\r\n}\r\n\r\n/* Buttons: capsule controls matching ModelsSection (h36 r18 primary,\r\n * h28 r14 secondary in row context). */\r\n.o6nt8s_primaryButton,\r\n.o6nt8s_secondaryButton,\r\n.o6nt8s_dangerButton,\r\n.o6nt8s_addBlockButton {\r\n box-sizing: border-box;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 4px;\r\n height: 36px;\r\n padding: 0 14px;\r\n border: none;\r\n border-radius: 18px;\r\n font: inherit;\r\n font-size: 14px;\r\n line-height: 22px;\r\n cursor: pointer;\r\n}\r\n\r\n.o6nt8s_primaryButton {\r\n background: var(--dsw-alias-button-primary-fill);\r\n color: var(--dsw-alias-label-primary-foreground);\r\n}\r\n\r\n.o6nt8s_primaryButton:hover:not(:disabled) {\r\n background: var(--dsw-alias-button-primary-hover);\r\n}\r\n\r\n.o6nt8s_secondaryButton,\r\n.o6nt8s_addBlockButton {\r\n border: 1px solid var(--dsw-alias-border-l2);\r\n background: transparent;\r\n color: var(--dsw-alias-label-primary);\r\n}\r\n\r\n.o6nt8s_secondaryButton:hover:not(:disabled),\r\n.o6nt8s_addBlockButton:hover:not(:disabled) {\r\n background: var(--dsw-alias-interactive-bg-hover-solid);\r\n}\r\n\r\n.o6nt8s_dangerButton {\r\n background: transparent;\r\n color: var(--dsw-alias-state-error-primary);\r\n}\r\n\r\n.o6nt8s_dangerButton:hover:not(:disabled) {\r\n background: var(--dsw-alias-interactive-bg-hover-danger);\r\n}\r\n\r\n/* Row-context buttons go dense (h28 r14, 12/18). */\r\n.o6nt8s_rowActions .o6nt8s_secondaryButton,\r\n.o6nt8s_rowActions .o6nt8s_dangerButton {\r\n height: 28px;\r\n padding: 0 10px;\r\n border-radius: 14px;\r\n font-size: 12px;\r\n line-height: 18px;\r\n}\r\n\r\n.o6nt8s_rowActions .o6nt8s_primaryButton {\r\n height: 28px;\r\n padding: 0 10px;\r\n border-radius: 14px;\r\n font-size: 12px;\r\n line-height: 18px;\r\n}\r\n\r\n.o6nt8s_primaryButton:disabled,\r\n.o6nt8s_secondaryButton:disabled,\r\n.o6nt8s_dangerButton:disabled,\r\n.o6nt8s_addBlockButton:disabled {\r\n opacity: 0.4;\r\n cursor: default;\r\n}\r\n\r\n.o6nt8s_primaryButton:focus-visible,\r\n.o6nt8s_secondaryButton:focus-visible,\r\n.o6nt8s_dangerButton:focus-visible,\r\n.o6nt8s_addBlockButton:focus-visible {\r\n outline: none;\r\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\r\n}\r\n\r\n/* Add-provider action: a full-width dashed-outline place card matching\r\n * ModelsSection's addBlock. */\r\n.o6nt8s_addBlockButton {\r\n width: 100%;\r\n margin-top: 12px;\r\n border-style: dashed;\r\n border-radius: 12px;\r\n height: 40px;\r\n color: var(--dsw-alias-label-secondary);\r\n}\r\n\r\n.o6nt8s_addBlockButton:hover:not(:disabled) {\r\n color: var(--dsw-alias-label-primary);\r\n border-color: var(--dsw-alias-brand-primary);\r\n}\r\n\r\n/* Empty state. */\r\n.o6nt8s_empty {\r\n margin: 0;\r\n padding: 24px 12px;\r\n text-align: center;\r\n font-size: 14px;\r\n line-height: 22px;\r\n color: var(--dsw-alias-label-tertiary);\r\n}\r\n\r\n/* Modal confirm body text. */\r\n.o6nt8s_confirmText {\r\n margin: 0;\r\n font-size: 14px;\r\n line-height: 22px;\r\n color: var(--dsw-alias-label-secondary);\r\n}\r\n\r\n.o6nt8s_loading {\r\n padding: 12px;\r\n font-size: 14px;\r\n line-height: 22px;\r\n color: var(--dsw-alias-label-tertiary);\r\n}\r\n";
1063
- const tagId = "@dsh-external/dsh-aigc-canvas/SettingsPage.module.css";
1063
+ const tagId = "@huanlin/dsh-plugin-aigc-canvas/SettingsPage.module.css";
1064
1064
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
1065
1065
  const tag = document.createElement("style");
1066
- tag.dataset.plugin = "@dsh-external/dsh-aigc-canvas";
1066
+ tag.dataset.plugin = "@huanlin/dsh-plugin-aigc-canvas";
1067
1067
  tag.dataset.pluginCss = tagId;
1068
1068
  tag.textContent = css;
1069
1069
  document.head.appendChild(tag);
@@ -1132,7 +1132,7 @@ window.__ModuleLoader__.load({
1132
1132
  * (bearer / custom header / query param) the aigc_http_request tool uses to
1133
1133
  * attach the apiKey.
1134
1134
  *
1135
- * @module @dsh-external/dsh-aigc-canvas/client/SettingsPage
1135
+ * @module @huanlin/dsh-plugin-aigc-canvas/client/SettingsPage
1136
1136
  */
1137
1137
  /** Default shape for a brand-new draft (before the user fills in id/name). */
1138
1138
  function emptyDraft() {
@@ -1587,7 +1587,7 @@ window.__ModuleLoader__.load({
1587
1587
  /**
1588
1588
  * i18n dictionaries for the AIGC canvas plugin.
1589
1589
  *
1590
- * @module @dsh-external/dsh-aigc-canvas/client/locales
1590
+ * @module @huanlin/dsh-plugin-aigc-canvas/client/locales
1591
1591
  */
1592
1592
  const NS = "dsh-aigc-canvas";
1593
1593
  const zh = {
package/lib/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["useState","createElement","css","Component","createElement","css","c1y","c2y","useSyncExternalStore","useState","useRef","useState","useCallback","css","Modal","Pill","useRef","createElement"],"sources":["../../../src/client/api.ts","../../../src/client/store.ts","../../../src/client/CanvasNode.tsx","../../../src/client/CanvasView.tsx","../../../src/client/SettingsPage.tsx","../../../src/client/locales.ts","../../../src/client/index.tsx"],"sourcesContent":["/**\r\n * Typed fetch wrapper over the /aigc-canvas JSON API.\r\n */\r\n\r\n/** One wire failure. */\r\nexport class AigcApiError extends Error {\r\n constructor(\r\n readonly code: string,\r\n message: string,\r\n ) {\r\n super(message)\r\n }\r\n}\r\n\r\n/** Element kind (matches the host enum). */\r\nexport type AigcElementKind = 'prompt' | 'image' | 'video' | 'audio'\r\n\r\n/** One canvas element (client view). */\r\nexport interface AigcElement {\r\n filePath: string\r\n uuid?: string\r\n sessionId?: string\r\n kind: AigcElementKind\r\n title: string\r\n /** Canvas position, world coordinates (infinite free canvas). */\r\n x: number\r\n /** Canvas position, world coordinates (infinite free canvas). */\r\n y: number\r\n createdAt: number\r\n producedBy: string\r\n promptText?: string\r\n mediaSize?: number\r\n meta?: Record<string, unknown>\r\n description?: string\r\n}\r\n\r\n/** One canvas edge (source filePath → target filePath). */\r\nexport interface AigcEdge {\r\n source: string\r\n target: string\r\n}\r\n\r\n/** Full canvas state for one session. */\r\nexport interface AigcCanvasState {\r\n sessionId: string\r\n elements: AigcElement[]\r\n edges: AigcEdge[]\r\n}\r\n\r\n/** One provider (wire shape, matches the host ResolvedAigcProvider). */\r\nexport interface RuntimeProvider {\r\n id: string\r\n name: string\r\n endpoint: string\r\n apiKey: string\r\n instructions: string\r\n auth: { scheme: 'bearer' | 'header' | 'query'; name: string }\r\n builtin: boolean\r\n}\r\n\r\n/** Global settings wire shape. */\r\nexport interface RuntimeGlobalSettings {\r\n requestTimeoutMs: number\r\n mediaSizeLimit: number\r\n}\r\n\r\n/** Full config response (providers + global settings). */\r\nexport interface RuntimeConfig extends RuntimeGlobalSettings {\r\n providers: RuntimeProvider[]\r\n}\r\n\r\nasync function call<T>(method: string, payload: Record<string, unknown>, signal?: AbortSignal): Promise<T> {\r\n let response: Response\r\n try {\r\n response = await fetch(`/aigc-canvas/api/${method}`, {\r\n method: 'POST',\r\n headers: { 'content-type': 'application/json' },\r\n body: JSON.stringify(payload),\r\n signal,\r\n })\r\n } catch (error) {\r\n throw new AigcApiError('network', error instanceof Error ? error.message : String(error))\r\n }\r\n const parsed: { ok?: boolean; value?: unknown; error?: { code?: string; message?: string } } | null\r\n = await response.json().catch(() => null)\r\n if (!response.ok || parsed === null || parsed.ok !== true || parsed.value === undefined) {\r\n throw new AigcApiError(\r\n parsed?.error?.code ?? 'http',\r\n parsed?.error?.message ?? `HTTP ${response.status}`,\r\n )\r\n }\r\n return parsed.value as T\r\n}\r\n\r\n/** Fetch the canvas state (elements + edges) for one session. */\r\nexport function fetchCanvas(sessionId: string, signal?: AbortSignal): Promise<AigcCanvasState> {\r\n return call<AigcCanvasState>('canvas.list', { sessionId }, signal)\r\n}\r\n\r\n/** Persist one element's new canvas position (after a client drag). */\r\nexport function moveCanvasElement(sessionId: string, uuid: string, x: number, y: number, signal?: AbortSignal): Promise<AigcElement> {\r\n return call<AigcElement>('canvas.move', { sessionId, uuid, x, y }, signal)\r\n}\r\n\r\n/** Delete one element from the canvas (also removes its edges). */\r\nexport function deleteCanvasElement(sessionId: string, uuid: string, signal?: AbortSignal): Promise<{ ok: boolean }> {\r\n return call<{ ok: boolean }>('canvas.delete', { sessionId, uuid }, signal)\r\n}\r\n\r\n/** Upload a file (drag-dropped onto the canvas) and place it as a new element. */\r\nexport function uploadCanvasFile(sessionId: string, fileName: string, mediaBase64: string, opts?: { x?: number; y?: number; description?: string }, signal?: AbortSignal): Promise<{ ok: boolean; element: AigcElement }> {\r\n return call<{ ok: boolean; element: AigcElement }>('canvas.upload', { sessionId, fileName, mediaBase64, ...opts }, signal)\r\n}\r\n\r\n/** Fetch the full runtime config (providers + global settings). */\r\nexport function fetchConfig(signal?: AbortSignal): Promise<RuntimeConfig> {\r\n return call<RuntimeConfig>('config.get', {}, signal)\r\n}\r\n\r\n/** List all providers. */\r\nexport function listProviders(signal?: AbortSignal): Promise<{ providers: RuntimeProvider[] }> {\r\n return call<{ providers: RuntimeProvider[] }>('providers.list', {}, signal)\r\n}\r\n\r\n/** Add a new provider. */\r\nexport function addProvider(provider: RuntimeProvider, signal?: AbortSignal): Promise<{ providers: RuntimeProvider[] }> {\r\n return call<{ providers: RuntimeProvider[] }>('providers.add', { provider }, signal)\r\n}\r\n\r\n/** Update an existing provider. */\r\nexport function updateProvider(provider: RuntimeProvider, signal?: AbortSignal): Promise<{ providers: RuntimeProvider[] }> {\r\n return call<{ providers: RuntimeProvider[] }>('providers.update', { provider }, signal)\r\n}\r\n\r\n/** Remove a provider by id. */\r\nexport function removeProvider(id: string, signal?: AbortSignal): Promise<{ providers: RuntimeProvider[] }> {\r\n return call<{ providers: RuntimeProvider[] }>('providers.remove', { id }, signal)\r\n}\r\n\r\n/** Build the media URL for one element's media file (by uuid; the host resolves to the file). */\r\nexport function mediaUrlOf(sessionId: string, uuid: string, download = false): string {\r\n const params = new URLSearchParams({ sessionId, uuid })\r\n if (download) params.set('download', '1')\r\n return `/aigc-canvas/file?${params.toString()}`\r\n}\r\n\r\n/** Build the WebSocket URL for the canvas push endpoint. */\r\nexport function canvasWsUrl(sessionId: string): string {\r\n const proto = window.location.protocol === 'https:' ? 'wss:' : 'ws:'\r\n return `${proto}//${window.location.host}/aigc-canvas/ws/canvas?sessionId=${encodeURIComponent(sessionId)}`\r\n}\r\n","/**\n * Canvas view store: subscribes to the host push WebSocket for one session\n * and exposes a synchronous snapshot through useSyncExternalStore. Replays\n * the latest snapshot on reconnect; falls back to a one-shot HTTP fetch\n * when the WS is unavailable so a deployment without the upgrade route\n * still renders the canvas (with manual refresh).\n *\n * The store is per-session: the better-sidebar tab instantiates one per\n * scope.sessionId, and disposes it on tab close (the WS closes with it).\n */\nimport { deleteCanvasElement, fetchCanvas, moveCanvasElement, uploadCanvasFile, canvasWsUrl, type AigcCanvasState } from './api.js'\n\n/** Empty canvas state used as the pre-load placeholder. */\nfunction emptyState(sessionId: string): AigcCanvasState {\n return { sessionId, elements: [], edges: [] }\n}\n\ninterface StoreOptions {\n sessionId: string\n}\n\n/** One store instance per tab activation. */\nexport class CanvasStore {\n /** The session id this store is bound to. */\n readonly sessionId: string\n private state: AigcCanvasState\n private listeners = new Set<() => void>()\n private ws: WebSocket | undefined\n private reconnectTimer: number | undefined\n private disposed = false\n private fetchAbort: AbortController | undefined\n\n constructor(private readonly opts: StoreOptions) {\n this.sessionId = opts.sessionId\n this.state = emptyState(opts.sessionId)\n // Kick off the initial HTTP fetch (gives a snapshot before the WS opens)\n // and the WS subscription (drives live updates).\n void this.refresh()\n this.openWs()\n }\n\n /** Snapshot reader for useSyncExternalStore. */\n getSnapshot = (): AigcCanvasState => this.state\n\n /** Subscribe listener; returns disposer. */\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener)\n return () => { this.listeners.delete(listener) }\n }\n\n /** Force a refresh (e.g. user clicked a refresh button). */\n async refresh(): Promise<void> {\n if (this.disposed) return\n this.fetchAbort?.abort()\n const ac = new AbortController()\n this.fetchAbort = ac\n try {\n const next = await fetchCanvas(this.opts.sessionId, ac.signal)\n if (!this.disposed) this.setState(next)\n } catch {\n // WS will catch up; the fetch is a best-effort priming read.\n }\n }\n\n /**\n * Persist a dragged element's new position. The authoritative snapshot\n * arrives over the WS push (the host notifies after persisting), so no\n * local state update is applied here.\n */\n async move(uuid: string, x: number, y: number): Promise<void> {\n if (this.disposed) return\n try {\n await moveCanvasElement(this.opts.sessionId, uuid, x, y)\n } catch {\n // Best-effort: the next WS snapshot carries the host's authoritative state.\n }\n }\n\n /** Delete an element (right-click → Delete). Best-effort; WS push catches up. */\n async deleteElement(uuid: string): Promise<void> {\n if (this.disposed) return\n try {\n await deleteCanvasElement(this.opts.sessionId, uuid)\n } catch {\n // Best-effort: the next WS snapshot carries the host's authoritative state.\n }\n }\n\n /** Upload a drag-dropped file and place it on the canvas. */\n async uploadFile(fileName: string, mediaBase64: string, opts?: { x?: number; y?: number }): Promise<void> {\n if (this.disposed) return\n try {\n await uploadCanvasFile(this.opts.sessionId, fileName, mediaBase64, opts)\n } catch {\n // Best-effort: the next WS snapshot carries the host's authoritative state.\n }\n }\n\n /** Tear down: close WS, abort any in-flight fetch, drop listeners. */\n dispose(): void {\n this.disposed = true\n this.fetchAbort?.abort()\n if (this.reconnectTimer !== undefined) {\n window.clearTimeout(this.reconnectTimer)\n this.reconnectTimer = undefined\n }\n if (this.ws !== undefined) {\n try { this.ws.close() } catch { /* ignore */ }\n this.ws = undefined\n }\n this.listeners.clear()\n }\n\n private setState(next: AigcCanvasState): void {\n this.state = next\n for (const fn of [...this.listeners]) fn()\n }\n\n private openWs(): void {\n if (this.disposed) return\n let ws: WebSocket\n try {\n ws = new WebSocket(canvasWsUrl(this.opts.sessionId))\n } catch {\n this.scheduleReconnect()\n return\n }\n this.ws = ws\n ws.onmessage = (event) => {\n try {\n const parsed = JSON.parse(event.data as string) as AigcCanvasState\n if (parsed && typeof parsed.sessionId === 'string') this.setState(parsed)\n } catch {\n // Ignore malformed frames — the host only sends valid JSON snapshots.\n }\n }\n ws.onclose = () => {\n if (this.disposed) return\n this.ws = undefined\n this.scheduleReconnect()\n }\n ws.onerror = () => {\n try { ws.close() } catch { /* close handler will run */ }\n }\n }\n\n private scheduleReconnect(): void {\n if (this.disposed) return\n if (this.reconnectTimer !== undefined) return\n this.reconnectTimer = window.setTimeout(() => {\n this.reconnectTimer = undefined\n this.openWs()\n }, 2000)\n }\n}\n","/**\r\n * One canvas node: renders the element's media (image / video / audio) or\r\n * its prompt text, plus a small header row with kind dot + label and the\r\n * creation time. Rendered inside the infinite-canvas world layer at its\r\n * (x, y) position; dragging is handled by the parent view (the node div\r\n * carries the drag pointer handlers). Double-click opens the detail panel.\r\n *\r\n * ZOOM / BLUR FIX\r\n * ---------------\r\n * The world layer is scaled via `transform: scale(s)`. Browsers decode\r\n * `<img>`/`<video>` at their CSS layout size (the card's 220px content\r\n * width), NOT the post-transform screen size — so zooming in upscales a\r\n * small decoded bitmap and the media looks blurry.\r\n *\r\n * To get crisp media at every zoom level, each img/video sets its CSS\r\n * width to `100% * scale` (the on-screen pixel width) and then applies\r\n * `transform: scale(1/scale)` to visually shrink back to the 220px layout\r\n * box. The browser then decodes at the larger size and the world\r\n * transform produces a 1:1 (or downscaled) screen image — sharp.\r\n *\r\n * The layout box still grows to `220*scale` wide, which would push\r\n * siblings and inflate the card. Negative `margin-right` / `margin-bottom`\r\n * (expressed as `%` of the container width = 220px) cancel the excess so\r\n * the effective layout footprint is unchanged. The bottom margin needs\r\n * the media's aspect ratio (h/w), captured from `onLoad`/`onLoadedMetadata`.\r\n */\r\nimport { createElement, useState, type CSSProperties, type ReactNode, type SyntheticEvent } from 'react'\r\nimport type { AigcElement } from './api.js'\r\nimport { mediaUrlOf } from './api.js'\r\nimport css from './canvas.module.css'\r\n\r\n/** Translation function type (from the DSH locale system). */\r\ntype Translate = (key: string) => string\r\n\r\n/** Short label for one element kind. */\r\nfunction kindLabel(kind: AigcElement['kind'], t: Translate): string {\r\n switch (kind) {\r\n case 'prompt': return t('prompt')\r\n case 'image': return t('image')\r\n case 'video': return t('video')\r\n case 'audio': return t('audio')\r\n }\r\n}\r\n\r\n/** Format the createdAt timestamp as a short HH:MM:SS. */\r\nfunction formatTime(ms: number): string {\r\n const d = new Date(ms)\r\n const pad = (n: number): string => n < 10 ? `0${n}` : String(n)\r\n return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`\r\n}\r\n\r\n/** Default aspect ratio (h/w) used before media metadata loads. 4:3 → 0.75. */\r\nconst DEFAULT_RATIO = 0.75\r\n\r\n/**\r\n * One image element. Captures its natural aspect ratio on load so the\r\n * negative bottom margin (which cancels the layout-box inflation from the\r\n * counter-scale trick) can be computed from CSS variables alone.\r\n */\r\nfunction MediaImage({ url, alt }: { url: string; alt: string }): ReactNode {\r\n const [ratio, setRatio] = useState(DEFAULT_RATIO)\r\n const onLoad = (e: SyntheticEvent<HTMLImageElement>): void => {\r\n const img = e.currentTarget\r\n if (img.naturalWidth > 0) {\r\n setRatio(img.naturalHeight / img.naturalWidth)\r\n }\r\n }\r\n return createElement('img', {\r\n className: css.mediaImage,\r\n src: url,\r\n alt,\r\n loading: 'lazy',\r\n draggable: false,\r\n onLoad,\r\n style: { ['--media-ratio' as string]: ratio } as CSSProperties,\r\n })\r\n}\r\n\r\n/**\r\n * One video element. Same counter-scale trick as MediaImage; the aspect\r\n * ratio comes from `loadedmetadata` (videoWidth / videoHeight).\r\n */\r\nfunction MediaVideo({ url }: { url: string }): ReactNode {\r\n const [ratio, setRatio] = useState(DEFAULT_RATIO)\r\n const onLoadedMetadata = (e: SyntheticEvent<HTMLVideoElement>): void => {\r\n const v = e.currentTarget\r\n if (v.videoWidth > 0) {\r\n setRatio(v.videoHeight / v.videoWidth)\r\n }\r\n }\r\n return createElement('video', {\r\n className: css.mediaVideo,\r\n src: url,\r\n controls: true,\r\n preload: 'metadata',\r\n onLoadedMetadata,\r\n style: { ['--media-ratio' as string]: ratio } as CSSProperties,\r\n })\r\n}\r\n\r\n/** Render one element's media (or prompt text) based on its kind. */\r\nfunction renderMedia(el: AigcElement): ReactNode {\r\n if (el.kind === 'prompt') {\r\n return createElement('pre', { className: css.promptText }, el.promptText ?? '')\r\n }\r\n // Media route needs the uuid (the host resolves uuid → filePath internally).\r\n // The uuid is present on every element the WS push delivers.\r\n if (el.uuid === undefined) return null\r\n const url = mediaUrlOf(el.sessionId ?? '', el.uuid)\r\n if (el.kind === 'image') {\r\n return createElement(MediaImage, { url, alt: el.title })\r\n }\r\n if (el.kind === 'video') {\r\n return createElement(MediaVideo, { url })\r\n }\r\n // audio — native control, no bitmap to sharpen\r\n return createElement('audio', {\r\n className: css.mediaAudio,\r\n src: url,\r\n controls: true,\r\n preload: 'metadata',\r\n })\r\n}\r\n\r\nexport interface CanvasNodeProps {\r\n element: AigcElement\r\n t: Translate\r\n}\r\n\r\n/** One canvas node (fixed-width card; height follows content). */\r\nexport function CanvasNode({ element, t }: CanvasNodeProps): ReactNode {\r\n const kindDotClass = `${css.kindDot} ${css[`kindDot_${element.kind}`] ?? ''}`\r\n return createElement(\r\n 'div',\r\n {\r\n className: css.node,\r\n 'data-uuid': element.uuid ?? '',\r\n 'data-filepath': element.filePath,\r\n },\r\n createElement(\r\n 'div',\r\n { className: css.nodeHeader },\r\n createElement('span', { className: kindDotClass, 'aria-hidden': true }),\r\n createElement('span', { className: css.kindLabel }, kindLabel(element.kind, t)),\r\n createElement('span', { className: css.nodeTime }, formatTime(element.createdAt)),\r\n ),\r\n createElement('div', { className: css.nodeTitle }, element.title),\r\n element.description !== undefined && element.description !== ''\r\n ? createElement('div', { className: css.nodeDescription }, element.description)\r\n : null,\r\n createElement('div', { className: css.nodeMedia }, renderMedia(element)),\r\n )\r\n}\r\n","/**\r\n * The infinite canvas view: a free, pannable + zoomable surface where\r\n * elements live at arbitrary world positions (x, y) and edges render as\r\n * smooth curves between right/left ports.\r\n *\r\n * Interactions:\r\n * - drag an element: moves it (persisted via the canvas.move API on release)\r\n * - drag the background: pans the viewport\r\n * - wheel: zooms around the cursor (clamped 0.2×–4×)\r\n * - zoom slider / +/- buttons in the header: zoom from center\r\n * - minimap (bottom-right): click/drag to pan; shows element outlines + viewport frame\r\n * - double-click an element: opens the detail panel (prompt + params + path)\r\n *\r\n * The WS push delivers authoritative snapshots; dragged positions are\r\n * applied locally as drafts during the gesture and confirmed by the push\r\n * (the host notifies after persisting the move).\r\n */\r\nimport { Component, createElement, useEffect, useRef, useState, useSyncExternalStore, type CSSProperties, type ErrorInfo, type ReactNode, type PointerEvent as ReactPointerEvent, type MouseEvent as ReactMouseEvent, type ChangeEvent as ReactChangeEvent } from 'react'\r\nimport type { AigcCanvasState, AigcEdge, AigcElement } from './api.js'\r\nimport { CanvasStore } from './store.js'\r\nimport { CanvasNode } from './CanvasNode.js'\r\nimport css from './canvas.module.css'\r\n\r\n/** Translation function type (from the DSH locale system). */\r\ntype Translate = (key: string) => string\r\n\r\n/** Error boundary so a render failure shows a strip instead of blanking. */\r\nclass CanvasBoundary extends Component<{ children: ReactNode; t: Translate }, { error: string | null }> {\r\n override state = { error: null as string | null }\r\n static getDerivedStateFromError(error: unknown): { error: string } {\r\n return { error: error instanceof Error ? error.message : String(error) }\r\n }\r\n override componentDidCatch(error: Error, info: ErrorInfo): void {\r\n console.error('[dsh-aigc-canvas] render error:', error, info.componentStack)\r\n }\r\n override render(): ReactNode {\r\n if (this.state.error !== null) {\r\n return createElement('div', { className: css.boundaryError }, `${this.props.t('loadError')}: ${this.state.error}`)\r\n }\r\n return this.props.children\r\n }\r\n}\r\n\r\n/** Viewport state: world→screen is `screen = world * scale + (x, y)`. */\r\ninterface Viewport {\r\n x: number\r\n y: number\r\n scale: number\r\n}\r\n\r\nconst MIN_SCALE = 0.2\r\nconst MAX_SCALE = 4\r\n\r\n/** Fixed node box for edge anchoring (world units). Must match CSS .nodeBox width. */\r\nconst NODE_W = 240\r\nconst NODE_H = 110\r\n\r\n/** Zoom at the cursor position, keeping the world point under the cursor fixed. */\r\nfunction zoomAt(viewport: Viewport, cx: number, cy: number, factor: number): Viewport {\r\n const scale = Math.min(MAX_SCALE, Math.max(MIN_SCALE, viewport.scale * factor))\r\n const worldX = (cx - viewport.x) / viewport.scale\r\n const worldY = (cy - viewport.y) / viewport.scale\r\n return { scale, x: cx - worldX * scale, y: cy - worldY * scale }\r\n}\r\n\r\n/** Build a uuid → element map. */\r\nfunction elementMap(elements: readonly AigcElement[]): Map<string, AigcElement> {\r\n const map = new Map<string, AigcElement>()\r\n for (const el of elements) {\r\n if (el.uuid !== undefined) map.set(el.uuid, el)\r\n }\r\n return map\r\n}\r\n\r\n/** Position resolver: returns draft position if dragging, else the element's own. */\r\ntype PosResolver = (uuid: string) => { x: number; y: number } | undefined\r\n\r\n/** Port radius (the small circle drawn at each connection point). */\r\nconst PORT_R = 5\r\n\r\n/**\r\n * One smooth-curve edge: exits the source's right-center port, curves\r\n * through two control points, enters the target's left-center port.\r\n * Drawn as an SVG cubic-bezier path + two port circles + an arrowhead.\r\n *\r\n * The control points sit on the horizontal axis at a fixed offset from\r\n * each port so the curve bows out smoothly regardless of distance —\r\n * looks like a relaxed S when the ports are vertically offset.\r\n *\r\n * Uses the position resolver so the edge follows live drag positions\r\n * (drafts) in real time, not just the persisted snapshot.\r\n */\r\nfunction renderEdge(edge: AigcEdge, resolvePos: PosResolver): ReactNode {\r\n const srcPos = resolvePos(edge.source)\r\n const tgtPos = resolvePos(edge.target)\r\n if (srcPos === undefined || tgtPos === undefined) return null\r\n // Source port: right-center of the source card.\r\n const sx = srcPos.x + NODE_W\r\n const sy = srcPos.y + NODE_H / 2\r\n // Target port: left-center of the target card.\r\n const tx = tgtPos.x\r\n const ty = tgtPos.y + NODE_H / 2\r\n // Control-point offset: half the horizontal gap, clamped so short\r\n // gaps still bow nicely and very long gaps don't over-extend.\r\n const dx = Math.abs(tx - sx)\r\n const offset = Math.max(40, Math.min(dx * 0.5, 160))\r\n // Cubic bezier: C1 to the right of source, C2 to the left of target.\r\n const c1x = sx + offset\r\n const c1y = sy\r\n const c2x = tx - offset\r\n const c2y = ty\r\n const d = `M ${sx} ${sy} C ${c1x} ${c1y}, ${c2x} ${c2y}, ${tx} ${ty}`\r\n // Arrowhead pointing right (into the target port).\r\n const arrow = 9\r\n const wing = arrow * 0.55\r\n const baseX = tx - arrow\r\n const ly = ty - wing\r\n const ry = ty + wing\r\n const arrowPath = `M ${tx} ${ty} L ${baseX} ${ly} L ${baseX} ${ry} Z`\r\n return createElement('g', { key: `${edge.source}:${edge.target}` },\r\n createElement('path', { d, className: css.edgeLine, fill: 'none' }),\r\n createElement('path', { d: arrowPath, className: css.edgeArrow }),\r\n createElement('circle', { cx: sx, cy: sy, r: PORT_R, className: css.edgePort }),\r\n createElement('circle', { cx: tx, cy: ty, r: PORT_R, className: css.edgePort }),\r\n )\r\n}\r\n\r\nexport interface CanvasViewProps {\r\n store: CanvasStore\r\n t: Translate\r\n}\r\n\r\n/**\r\n * The infinite canvas view.\r\n * @param props - store + locale translate.\r\n * @returns the canvas element.\r\n */\r\nexport function CanvasView({ store, t }: CanvasViewProps): ReactNode {\r\n const state: AigcCanvasState = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot)\r\n const [viewport, setViewport] = useState<Viewport>({ x: 0, y: 0, scale: 1 })\r\n const [drafts, setDrafts] = useState<ReadonlyMap<string, { x: number; y: number }>>(new Map())\r\n const [selected, setSelected] = useState<AigcElement | undefined>(undefined)\r\n const [contextMenu, setContextMenu] = useState<{ x: number; y: number; uuid: string } | undefined>(undefined)\r\n const [dropTarget, setDropTarget] = useState<{ x: number; y: number } | undefined>(undefined)\r\n const [uploading, setUploading] = useState(false)\r\n const surfaceRef = useRef<HTMLElement | null>(null)\r\n\r\n // Track the previous snapshot's element uuids so we can detect when new\r\n // elements appear (model just placed something) and pan the viewport to\r\n // bring the newest one into view at \"center-left\" of the visible area.\r\n const prevUuidsRef = useRef<Set<string>>(new Set())\r\n\r\n // Pan gesture (drag on empty background).\r\n const panRef = useRef<{ pointerId: number; startX: number; startY: number; orig: Viewport } | null>(null)\r\n // Element drag gesture.\r\n const dragRef = useRef<{ pointerId: number; uuid: string; startX: number; startY: number; origX: number; origY: number } | null>(null)\r\n\r\n // Wheel: zooms around the cursor (clamped 0.2×–4×). Pan is via\r\n // dragging the background. Needs a non-passive listener.\r\n useEffect(() => {\r\n const surface = surfaceRef.current\r\n if (surface === null) return\r\n const onWheel = (event: WheelEvent): void => {\r\n event.preventDefault()\r\n const rect = surface.getBoundingClientRect()\r\n const cx = event.clientX - rect.left\r\n const cy = event.clientY - rect.top\r\n const factor = event.deltaY < 0 ? 1.12 : 1 / 1.12\r\n setViewport(prev => zoomAt(prev, cx, cy, factor))\r\n }\r\n surface.addEventListener('wheel', onWheel, { passive: false })\r\n return () => surface.removeEventListener('wheel', onWheel)\r\n }, [])\r\n\r\n // Clean up stale drafts: once the persisted snapshot confirms an\r\n // element's position matches its draft, the draft is no longer needed\r\n // (posOf will return the persisted position, which is the same). This\r\n // prevents drafts from accumulating indefinitely and ensures that a\r\n // subsequent drag of the same element starts from the right position.\r\n useEffect(() => {\r\n if (drafts.size === 0) return\r\n const lookup = elementMap(state.elements)\r\n const stale: string[] = []\r\n for (const [uuid, draftPos] of drafts) {\r\n const el = lookup.get(uuid)\r\n if (el !== undefined && el.x === draftPos.x && el.y === draftPos.y) {\r\n stale.push(uuid)\r\n }\r\n }\r\n if (stale.length > 0) {\r\n setDrafts(prev => {\r\n const next = new Map(prev)\r\n for (const uuid of stale) next.delete(uuid)\r\n return next\r\n })\r\n }\r\n }, [state, drafts])\r\n\r\n // Auto-pan to newly placed elements. When the snapshot gains an element\r\n // the model just placed it; if it isn't visible in the current viewport,\r\n // pan JUST ENOUGH to bring it into view (with a margin). Unlike the old\r\n // center-at-25%/40% approach, this keeps existing elements visible when\r\n // a vertical column grows downward — only the minimal offset is applied.\r\n useEffect(() => {\r\n if (panRef.current !== null || dragRef.current !== null) return\r\n const surface = surfaceRef.current\r\n if (surface === null) return\r\n const prev = prevUuidsRef.current\r\n let newest: AigcElement | undefined\r\n for (const el of state.elements) {\r\n if (el.uuid !== undefined && !prev.has(el.uuid)) {\r\n newest = el\r\n }\r\n }\r\n const nextUuids = new Set<string>()\r\n for (const el of state.elements) {\r\n if (el.uuid !== undefined) nextUuids.add(el.uuid)\r\n }\r\n prevUuidsRef.current = nextUuids\r\n if (newest === undefined) return\r\n const rect = surface.getBoundingClientRect()\r\n const margin = 32\r\n const screenX = newest.x * viewport.scale + viewport.x\r\n const screenY = newest.y * viewport.scale + viewport.y\r\n const elemW = NODE_W * viewport.scale\r\n const elemH = NODE_H * viewport.scale\r\n let panX = 0\r\n let panY = 0\r\n // Below visible area → pan down just enough.\r\n if (screenY + elemH > rect.height - margin) {\r\n panY = (screenY + elemH) - (rect.height - margin)\r\n }\r\n // Above visible area → pan up just enough.\r\n if (screenY < margin) {\r\n panY = screenY - margin\r\n }\r\n // Right of visible area → pan right just enough.\r\n if (screenX + elemW > rect.width - margin) {\r\n panX = (screenX + elemW) - (rect.width - margin)\r\n }\r\n // Left of visible area → pan left just enough.\r\n if (screenX < margin) {\r\n panX = screenX - margin\r\n }\r\n if (panX !== 0 || panY !== 0) {\r\n setViewport(prev => ({ ...prev, x: prev.x - panX, y: prev.y - panY }))\r\n }\r\n }, [state, viewport.scale])\r\n\r\n // Track the surface dimensions for the minimap viewport frame.\r\n const [surfaceSize, setSurfaceSize] = useState({ width: 0, height: 0 })\r\n useEffect(() => {\r\n const surface = surfaceRef.current\r\n if (surface === null) return\r\n const update = (): void => {\r\n const rect = surface.getBoundingClientRect()\r\n setSurfaceSize({ width: rect.width, height: rect.height })\r\n }\r\n update()\r\n const observer = new ResizeObserver(update)\r\n observer.observe(surface)\r\n return () => observer.disconnect()\r\n }, [])\r\n\r\n /** Zoom to a target scale, keeping the center of the viewport fixed. */\r\n const zoomToCenter = (newScale: number): void => {\r\n const surface = surfaceRef.current\r\n if (surface === null) return\r\n const rect = surface.getBoundingClientRect()\r\n const cx = rect.width / 2\r\n const cy = rect.height / 2\r\n setViewport(prev => {\r\n const s = Math.min(MAX_SCALE, Math.max(MIN_SCALE, newScale))\r\n const worldX = (cx - prev.x) / prev.scale\r\n const worldY = (cy - prev.y) / prev.scale\r\n return { scale: s, x: cx - worldX * s, y: cy - worldY * s }\r\n })\r\n }\r\n\r\n const onSurfacePointerDown = (event: ReactPointerEvent<HTMLElement>): void => {\r\n if (dragRef.current !== null) return\r\n panRef.current = {\r\n pointerId: event.pointerId,\r\n startX: event.clientX,\r\n startY: event.clientY,\r\n orig: viewport,\r\n }\r\n event.currentTarget.setPointerCapture(event.pointerId)\r\n }\r\n\r\n const onSurfacePointerMove = (event: ReactPointerEvent<HTMLElement>): void => {\r\n const pan = panRef.current\r\n if (pan !== null && pan.pointerId === event.pointerId) {\r\n setViewport({\r\n ...pan.orig,\r\n x: pan.orig.x + (event.clientX - pan.startX),\r\n y: pan.orig.y + (event.clientY - pan.startY),\r\n })\r\n return\r\n }\r\n const drag = dragRef.current\r\n if (drag !== null && drag.pointerId === event.pointerId) {\r\n setDrafts(prev => {\r\n const next = new Map(prev)\r\n next.set(drag.uuid, {\r\n x: drag.origX + (event.clientX - drag.startX) / viewport.scale,\r\n y: drag.origY + (event.clientY - drag.startY) / viewport.scale,\r\n })\r\n return next\r\n })\r\n }\r\n }\r\n\r\n const onSurfacePointerUp = (event: ReactPointerEvent<HTMLElement>): void => {\r\n const pan = panRef.current\r\n if (pan !== null && pan.pointerId === event.pointerId) {\r\n panRef.current = null\r\n return\r\n }\r\n const drag = dragRef.current\r\n if (drag !== null && drag.pointerId === event.pointerId) {\r\n dragRef.current = null\r\n const pos = drafts.get(drag.uuid)\r\n if (pos !== undefined && (pos.x !== drag.origX || pos.y !== drag.origY)) {\r\n void store.move(drag.uuid, pos.x, pos.y)\r\n // Intentionally do NOT delete the draft here. The draft keeps the\r\n // element pinned at the drop position until the WS push arrives\r\n // with the persisted snapshot. Deleting now would snap the element\r\n // back to its old position, then forward again when the push lands\r\n // — visible as a two-frame jitter. A cleanup effect below removes\r\n // the draft once the snapshot confirms the new position.\r\n }\r\n }\r\n }\r\n\r\n const onNodePointerDown = (event: ReactPointerEvent<HTMLElement>, el: AigcElement): void => {\r\n if (el.uuid === undefined) return\r\n event.stopPropagation()\r\n event.currentTarget.setPointerCapture(event.pointerId)\r\n dragRef.current = {\r\n pointerId: event.pointerId,\r\n uuid: el.uuid,\r\n startX: event.clientX,\r\n startY: event.clientY,\r\n origX: el.x,\r\n origY: el.y,\r\n }\r\n }\r\n\r\n // Right-click on a node → context menu with Delete.\r\n const onNodeContextMenu = (event: ReactMouseEvent<HTMLElement>, el: AigcElement): void => {\r\n if (el.uuid === undefined) return\r\n event.preventDefault()\r\n event.stopPropagation()\r\n setContextMenu({ x: event.clientX, y: event.clientY, uuid: el.uuid })\r\n }\r\n\r\n // Click anywhere → close the context menu.\r\n const onSurfaceClick = (event: ReactMouseEvent<HTMLElement>): void => {\r\n if (contextMenu !== undefined) {\r\n event.stopPropagation()\r\n setContextMenu(undefined)\r\n }\r\n }\r\n\r\n // Delete the element from the context menu.\r\n const onDeleteElement = (uuid: string): void => {\r\n setContextMenu(undefined)\r\n if (selected?.uuid === uuid) setSelected(undefined)\r\n void store.deleteElement(uuid)\r\n }\r\n\r\n // Drag-drop files onto the canvas surface.\r\n // stopPropagation() is critical: the canvas lives inside better-sidebar's\r\n // LeafView, whose onDragOver unconditionally calls preventDefault() and\r\n // shows a 5-zone layout overlay (without checking dataTransfer.types).\r\n // Without stopPropagation, file drags trigger that overlay and the drop\r\n // gets swallowed by the parent's onDrop.\r\n const onSurfaceDragOver = (event: React.DragEvent<HTMLElement>): void => {\r\n if (event.dataTransfer.types.includes('Files')) {\r\n event.preventDefault()\r\n event.stopPropagation()\r\n event.dataTransfer.dropEffect = 'copy'\r\n const rect = surfaceRef.current?.getBoundingClientRect()\r\n if (rect !== undefined) {\r\n const sx = event.clientX - rect.left\r\n const sy = event.clientY - rect.top\r\n // Convert screen → world coords.\r\n const wx = (sx - viewport.x) / viewport.scale\r\n const wy = (sy - viewport.y) / viewport.scale\r\n setDropTarget({ x: wx, y: wy })\r\n }\r\n }\r\n }\r\n\r\n const onSurfaceDragLeave = (event: React.DragEvent<HTMLElement>): void => {\r\n // Only clear if leaving the surface itself (not a child).\r\n if (event.currentTarget === event.target) {\r\n event.stopPropagation()\r\n setDropTarget(undefined)\r\n }\r\n }\r\n\r\n const onSurfaceDrop = async (event: React.DragEvent<HTMLElement>): Promise<void> => {\r\n event.preventDefault()\r\n event.stopPropagation()\r\n setDropTarget(undefined)\r\n const files = event.dataTransfer.files\r\n if (files.length === 0) return\r\n const rect = surfaceRef.current?.getBoundingClientRect()\r\n const sx = event.clientX - (rect?.left ?? 0)\r\n const sy = event.clientY - (rect?.top ?? 0)\r\n const wx = (sx - viewport.x) / viewport.scale\r\n const wy = (sy - viewport.y) / viewport.scale\r\n setUploading(true)\r\n try {\r\n for (const file of Array.from(files)) {\r\n const buf = await file.arrayBuffer()\r\n // Convert ArrayBuffer → base64 in chunks to avoid stack overflow\r\n // (String.fromCharCode(...spread) blows the call stack for large files).\r\n const bytes = new Uint8Array(buf)\r\n let binary = ''\r\n const chunk = 0x8000\r\n for (let i = 0; i < bytes.length; i += chunk) {\r\n binary += String.fromCharCode(...bytes.subarray(i, i + chunk))\r\n }\r\n const mediaBase64 = btoa(binary)\r\n await store.uploadFile(file.name, mediaBase64, { x: wx, y: wy })\r\n }\r\n } finally {\r\n setUploading(false)\r\n }\r\n }\r\n\r\n const lookup = elementMap(state.elements)\r\n // Position resolver that checks drafts first (live drag position) then\r\n // falls back to the element's persisted position. Used by both the node\r\n // boxes and the edge renderer so connections follow dragged nodes in\r\n // real time — not only after the drag ends.\r\n const resolvePos: PosResolver = (uuid: string) => {\r\n const draft = drafts.get(uuid)\r\n if (draft !== undefined) return draft\r\n const el = lookup.get(uuid)\r\n if (el !== undefined) return { x: el.x, y: el.y }\r\n return undefined\r\n }\r\n const posOf = (el: AigcElement): { x: number; y: number } => {\r\n if (el.uuid !== undefined) {\r\n const draft = drafts.get(el.uuid)\r\n if (draft !== undefined) return draft\r\n }\r\n return { x: el.x, y: el.y }\r\n }\r\n\r\n return createElement(\r\n 'div',\r\n { className: css.canvas },\r\n createElement(\r\n 'div',\r\n { className: css.header },\r\n createElement('span', { className: css.title }, t('title')),\r\n createElement('span', { className: css.count }, `${state.elements.length} ${t('elementCount')}`),\r\n createElement('span', { className: css.count }, `${state.edges.length} ${t('edgeCount')}`),\r\n createElement('span', { className: css.zoom }, `${Math.round(viewport.scale * 100)}%`),\r\n createElement('button', {\r\n type: 'button',\r\n className: css.iconButton,\r\n onClick: () => zoomToCenter(viewport.scale * 0.8),\r\n title: t('zoomOut'),\r\n 'aria-label': t('zoomOut'),\r\n }, '−'),\r\n createElement('input', {\r\n type: 'range',\r\n className: css.zoomSlider,\r\n min: Math.round(MIN_SCALE * 100),\r\n max: Math.round(MAX_SCALE * 100),\r\n value: Math.round(viewport.scale * 100),\r\n onChange: (e: ReactChangeEvent<HTMLInputElement>) => zoomToCenter(Number(e.target.value) / 100),\r\n 'aria-label': t('zoom'),\r\n }),\r\n createElement('button', {\r\n type: 'button',\r\n className: css.iconButton,\r\n onClick: () => zoomToCenter(viewport.scale * 1.25),\r\n title: t('zoomIn'),\r\n 'aria-label': t('zoomIn'),\r\n }, '+'),\r\n createElement(\r\n 'button',\r\n {\r\n type: 'button',\r\n className: css.iconButton,\r\n onClick: () => { void store.refresh() },\r\n title: t('refresh'),\r\n 'aria-label': t('refresh'),\r\n },\r\n '↻',\r\n ),\r\n createElement(\r\n 'button',\r\n {\r\n type: 'button',\r\n className: css.iconButton,\r\n onClick: () => setViewport({ x: 0, y: 0, scale: 1 }),\r\n title: t('resetView'),\r\n 'aria-label': t('resetView'),\r\n },\r\n '⤢',\r\n ),\r\n ),\r\n createElement(\r\n 'div',\r\n {\r\n className: css.surface,\r\n ref: surfaceRef,\r\n onPointerDown: onSurfacePointerDown,\r\n onPointerMove: onSurfacePointerMove,\r\n onPointerUp: onSurfacePointerUp,\r\n onPointerCancel: onSurfacePointerUp,\r\n onDoubleClick: () => setSelected(undefined),\r\n onClick: onSurfaceClick,\r\n onContextMenu: (event: ReactMouseEvent<HTMLElement>) => {\r\n // Right-click on empty background → prevent default browser menu.\r\n event.preventDefault()\r\n },\r\n onDragOver: onSurfaceDragOver,\r\n onDragLeave: onSurfaceDragLeave,\r\n onDrop: (event: React.DragEvent<HTMLElement>) => { void onSurfaceDrop(event) },\r\n },\r\n state.elements.length === 0\r\n ? createElement('div', { className: css.empty }, createElement('span', null, t('empty')), createElement('span', { className: css.emptyHint }, t('emptyHint')))\r\n : createElement(\r\n 'div',\r\n {\r\n className: css.world,\r\n style: {\r\n transform: `translate(${viewport.x}px, ${viewport.y}px) scale(${viewport.scale})`,\r\n // Expose the current zoom to descendants so media elements\r\n // (img/video) can counter-scale: they set their CSS width to\r\n // `100% * scale` (so the browser decodes at the larger screen\r\n // resolution instead of the layout width), then transform\r\n // `scale(1/scale)` to visually shrink back to the layout box.\r\n // Without this, zooming in shows blurry media because the\r\n // browser decodes the image at the small layout size and the\r\n // world transform upscales the bitmap.\r\n ['--canvas-scale' as string]: viewport.scale,\r\n } as CSSProperties,\r\n },\r\n createElement(\r\n 'svg',\r\n {\r\n className: css.edgeLayer,\r\n 'aria-hidden': true,\r\n },\r\n ...state.edges.map(edge => renderEdge(edge, resolvePos)),\r\n ),\r\n ...state.elements.map(el => {\r\n const pos = posOf(el)\r\n return createElement(\r\n 'div',\r\n {\r\n key: el.uuid ?? el.filePath,\r\n className: `${css.nodeBox} ${el.uuid !== undefined ? css.nodeBoxDraggable : ''}`,\r\n style: { transform: `translate(${pos.x}px, ${pos.y}px)` },\r\n onPointerDown: event => onNodePointerDown(event, el),\r\n onDoubleClick: (event: ReactMouseEvent<HTMLElement>) => {\r\n event.stopPropagation()\r\n setSelected(el)\r\n },\r\n onContextMenu: event => onNodeContextMenu(event, el),\r\n },\r\n createElement(CanvasNode, { element: el, t }),\r\n )\r\n }),\r\n ),\r\n // Drop indicator: shows where the dropped file will land (world coords).\r\n dropTarget !== undefined\r\n ? createElement('div', {\r\n className: css.dropIndicator,\r\n style: {\r\n transform: `translate(${dropTarget.x * viewport.scale + viewport.x}px, ${dropTarget.y * viewport.scale + viewport.y}px) scale(${viewport.scale})`,\r\n },\r\n })\r\n : null,\r\n // Upload overlay\r\n uploading\r\n ? createElement('div', { className: css.uploadOverlay }, t('uploading'))\r\n : null,\r\n ),\r\n selected !== undefined\r\n ? createElement(DetailPanel, { element: selected, t, onClose: () => setSelected(undefined) })\r\n : null,\r\n // Right-click context menu\r\n contextMenu !== undefined\r\n ? createElement(ContextMenu, {\r\n x: contextMenu.x,\r\n y: contextMenu.y,\r\n items: [\r\n { label: t('delete'), onClick: () => onDeleteElement(contextMenu.uuid) },\r\n ],\r\n onClose: () => setContextMenu(undefined),\r\n })\r\n : null,\r\n // Minimap: bottom-right overview showing element outlines + viewport frame.\r\n state.elements.length > 0\r\n ? createElement(Minimap, {\r\n elements: state.elements,\r\n viewport,\r\n surfaceSize,\r\n setViewport,\r\n })\r\n : null,\r\n )\r\n}\r\n\r\n/** A minimal fixed-position context menu (right-click). */\r\nfunction ContextMenu(props: {\r\n x: number\r\n y: number\r\n items: Array<{ label: string; onClick: () => void }>\r\n onClose: () => void\r\n}): ReactNode {\r\n // Close on any outside click or Escape.\r\n useEffect(() => {\r\n const onDown = (): void => props.onClose()\r\n const onKey = (e: KeyboardEvent): void => { if (e.key === 'Escape') props.onClose() }\r\n window.addEventListener('pointerdown', onDown, { once: true })\r\n window.addEventListener('keydown', onKey, { once: true })\r\n return () => {\r\n window.removeEventListener('pointerdown', onDown)\r\n window.removeEventListener('keydown', onKey)\r\n }\r\n }, [props])\r\n return createElement(\r\n 'div',\r\n {\r\n className: css.contextMenu,\r\n style: { left: props.x, top: props.y },\r\n // Stop the outside-click handler from firing on the menu itself.\r\n onPointerDown: (e: ReactPointerEvent<HTMLElement>) => e.stopPropagation(),\r\n },\r\n ...props.items.map((item, i) =>\r\n createElement('button', {\r\n key: i,\r\n type: 'button',\r\n className: css.contextMenuItem,\r\n onClick: () => { item.onClick() },\r\n }, item.label),\r\n ),\r\n )\r\n}\r\n\r\n/** The double-click detail panel: prompt + generation params + path. */\r\nfunction DetailPanel({ element, t, onClose }: { element: AigcElement; t: Translate; onClose: () => void }): ReactNode {\r\n // Defensive: meta may have been persisted as a string by an older build\r\n // or sneak through the schema as a non-object. Only render entries when\r\n // we have a real plain object; otherwise show the raw value (if primitive)\r\n // or skip the section entirely.\r\n const meta = element.meta\r\n const metaEntries: Array<[string, unknown]> = Array.isArray(meta) || meta === null || typeof meta !== 'object'\r\n ? []\r\n : Object.entries(meta as Record<string, unknown>)\r\n return createElement(\r\n 'div',\r\n { className: css.detailPanel },\r\n createElement(\r\n 'div',\r\n { className: css.detailHeader },\r\n createElement('span', { className: css.detailTitle }, element.title),\r\n createElement('button', { type: 'button', className: css.detailClose, onClick: onClose, 'aria-label': t('detailClose') }, '×'),\r\n ),\r\n createElement(\r\n 'div',\r\n { className: css.detailBody },\r\n element.promptText !== undefined\r\n ? createElement(\r\n 'div',\r\n { className: css.detailBlock },\r\n createElement('span', { className: css.detailLabel }, t('detailPrompt')),\r\n createElement('pre', { className: css.detailPrompt }, element.promptText),\r\n )\r\n : null,\r\n metaEntries.length > 0\r\n ? createElement(\r\n 'div',\r\n { className: css.detailBlock },\r\n createElement('span', { className: css.detailLabel }, t('detailParams')),\r\n createElement(\r\n 'dl',\r\n { className: css.metaList },\r\n ...metaEntries.flatMap(([k, v]) => [\r\n createElement('dt', { key: `${k}-k`, className: css.metaKey }, k),\r\n createElement('dd', { key: `${k}-v`, className: css.metaValue }, formatMetaValue(v)),\r\n ]),\r\n ),\r\n )\r\n : null,\r\n createElement(\r\n 'div',\r\n { className: css.detailBlock },\r\n createElement('span', { className: css.detailLabel }, t('generatedBy')),\r\n createElement('span', { className: css.detailValue }, element.producedBy),\r\n ),\r\n createElement(\r\n 'div',\r\n { className: css.detailBlock },\r\n createElement('span', { className: css.detailLabel }, t('detailPosition')),\r\n createElement('span', { className: css.detailValue }, `(${Math.round(element.x)}, ${Math.round(element.y)})`),\r\n ),\r\n createElement(\r\n 'div',\r\n { className: css.detailBlock },\r\n createElement('span', { className: css.detailLabel }, t('detailPath')),\r\n createElement('code', { className: css.filePath }, element.filePath),\r\n ),\r\n ),\r\n )\r\n}\r\n\r\nfunction formatMetaValue(v: unknown): string {\r\n if (typeof v === 'string') return v\r\n if (typeof v === 'number' || typeof v === 'boolean') return String(v)\r\n if (v === null || v === undefined) return ''\r\n try { return JSON.stringify(v) } catch { return String(v) }\r\n}\r\n\r\n// ── Minimap ──────────────────────────────────────────────────────────────\r\n\r\nconst MINIMAP_W = 168\r\nconst MINIMAP_H = 120\r\nconst MINIMAP_PAD = 6\r\n\r\n/** Color dot per element kind in the minimap. */\r\nconst KIND_COLOR: Record<AigcElement['kind'], string> = {\r\n image: '#4caf50',\r\n video: '#ff9800',\r\n audio: '#ab47bc',\r\n prompt: '#6b8cff',\r\n}\r\n\r\n/**\r\n * Bottom-right minimap: shows all elements as small colored rectangles and\r\n * the current viewport as a frame. Click/drag to pan the viewport.\r\n */\r\nfunction Minimap(props: {\r\n elements: readonly AigcElement[]\r\n viewport: Viewport\r\n surfaceSize: { width: number; height: number }\r\n setViewport: (fn: (prev: Viewport) => Viewport) => void\r\n}): ReactNode {\r\n const { elements, viewport, surfaceSize, setViewport } = props\r\n const minimapRef = useRef<HTMLDivElement | null>(null)\r\n\r\n // Compute world bounding box: union of all elements + the current viewport.\r\n let minX = Infinity\r\n let minY = Infinity\r\n let maxX = -Infinity\r\n let maxY = -Infinity\r\n for (const el of elements) {\r\n minX = Math.min(minX, el.x)\r\n minY = Math.min(minY, el.y)\r\n maxX = Math.max(maxX, el.x + NODE_W)\r\n maxY = Math.max(maxY, el.y + NODE_H)\r\n }\r\n if (surfaceSize.width > 0 && surfaceSize.height > 0) {\r\n const vpMinX = -viewport.x / viewport.scale\r\n const vpMinY = -viewport.y / viewport.scale\r\n const vpMaxX = vpMinX + surfaceSize.width / viewport.scale\r\n const vpMaxY = vpMinY + surfaceSize.height / viewport.scale\r\n minX = Math.min(minX, vpMinX)\r\n minY = Math.min(minY, vpMinY)\r\n maxX = Math.max(maxX, vpMaxX)\r\n maxY = Math.max(maxY, vpMaxY)\r\n }\r\n // Guard against empty (shouldn't happen — caller checks, but be safe).\r\n if (!Number.isFinite(minX) || !Number.isFinite(maxX)) return null\r\n // Add a small padding around the content.\r\n minX -= 40\r\n minY -= 40\r\n maxX += 40\r\n maxY += 40\r\n const worldW = maxX - minX\r\n const worldH = maxY - minY\r\n const miniScale = Math.min(\r\n (MINIMAP_W - MINIMAP_PAD * 2) / worldW,\r\n (MINIMAP_H - MINIMAP_PAD * 2) / worldH,\r\n )\r\n const offsetX = (MINIMAP_W - worldW * miniScale) / 2\r\n const offsetY = (MINIMAP_H - worldH * miniScale) / 2\r\n const toMiniX = (wx: number): number => offsetX + (wx - minX) * miniScale\r\n const toMiniY = (wy: number): number => offsetY + (wy - minY) * miniScale\r\n\r\n // Viewport frame in minimap coords.\r\n const vpX = toMiniX(-viewport.x / viewport.scale)\r\n const vpY = toMiniY(-viewport.y / viewport.scale)\r\n const vpW = (surfaceSize.width / viewport.scale) * miniScale\r\n const vpH = (surfaceSize.height / viewport.scale) * miniScale\r\n\r\n // Click/drag on minimap → center the viewport on the clicked world point.\r\n const onPointerDown = (event: ReactPointerEvent<HTMLDivElement>): void => {\r\n event.stopPropagation()\r\n event.currentTarget.setPointerCapture(event.pointerId)\r\n const pan = (clientX: number, clientY: number): void => {\r\n const rect = minimapRef.current?.getBoundingClientRect()\r\n if (rect === undefined) return\r\n const mx = clientX - rect.left\r\n const my = clientY - rect.top\r\n // Convert minimap coords → world coords.\r\n const worldX = (mx - offsetX) / miniScale + minX\r\n const worldY = (my - offsetY) / miniScale + minY\r\n // Center viewport on this world point.\r\n setViewport(prev => ({\r\n ...prev,\r\n x: surfaceSize.width / 2 - worldX * prev.scale,\r\n y: surfaceSize.height / 2 - worldY * prev.scale,\r\n }))\r\n }\r\n pan(event.clientX, event.clientY)\r\n const onMove = (e: PointerEvent): void => pan(e.clientX, e.clientY)\r\n const onUp = (): void => {\r\n window.removeEventListener('pointermove', onMove)\r\n window.removeEventListener('pointerup', onUp)\r\n }\r\n window.addEventListener('pointermove', onMove)\r\n window.addEventListener('pointerup', onUp)\r\n }\r\n\r\n return createElement(\r\n 'div',\r\n {\r\n className: css.minimap,\r\n ref: minimapRef,\r\n onPointerDown,\r\n },\r\n createElement(\r\n 'svg',\r\n { width: MINIMAP_W, height: MINIMAP_H, className: css.minimapSvg },\r\n // Element rectangles.\r\n ...elements.map(el =>\r\n createElement('rect', {\r\n key: el.uuid ?? el.filePath,\r\n x: toMiniX(el.x),\r\n y: toMiniY(el.y),\r\n width: Math.max(2, NODE_W * miniScale),\r\n height: Math.max(2, NODE_H * miniScale),\r\n rx: 2,\r\n fill: KIND_COLOR[el.kind],\r\n fillOpacity: 0.35,\r\n stroke: KIND_COLOR[el.kind],\r\n strokeOpacity: 0.7,\r\n strokeWidth: 1,\r\n }),\r\n ),\r\n // Viewport frame: a semi-transparent fill + solid border so it's\r\n // clearly visible against the element rectangles.\r\n createElement('rect', {\r\n x: vpX,\r\n y: vpY,\r\n width: vpW,\r\n height: vpH,\r\n fill: 'var(--dsw-alias-label-primary)',\r\n fillOpacity: 0.08,\r\n stroke: 'var(--dsw-alias-label-primary)',\r\n strokeOpacity: 0.8,\r\n strokeWidth: 2,\r\n rx: 2,\r\n }),\r\n ),\r\n )\r\n}\r\n\r\n/** Wrapped export so the tab component can mount the boundary once. */\r\nexport function CanvasViewWithBoundary(props: CanvasViewProps): ReactNode {\r\n return createElement(CanvasBoundary, { t: props.t, children: createElement(CanvasView, props) })\r\n}\r\n","/**\r\n * SettingsPage — the AIGC canvas settings section: provider list CRUD.\r\n *\r\n * Visual language: matches ModelsSection / GeneralSection / yet-another-subagent —\r\n * outlined rowCard per provider (border-l2, r12, p12/14), filled editor surface\r\n * (bg-module-platform, r12, p14/16), capsule controls (h36 r18 primary,\r\n * h28 r14 secondary), 32px fields with border-l2 / bg-layer-1, 12/18 caption\r\n * labels. Every color resolves through --dsw-alias-* tokens.\r\n *\r\n * Each provider card is collapsible (chevron in the row head); the editor\r\n * surface is hidden when collapsed. Builtin providers (cordis.yml seed) carry\r\n * a `builtin`/`内置` badge next to the title. The \"+ Add provider\" button at\r\n * the bottom reveals an inline draft card with all fields editable (including\r\n * id) and Create / Cancel actions.\r\n *\r\n * Real providers carry an \"initialize\" (初始化) action: it sends a prepared\r\n * message to the current conversation so the agent probes the API with\r\n * aigc_http_request and records the usage instructions via\r\n * aigc_provider_set_instructions. The editor also exposes the auth scheme\r\n * (bearer / custom header / query param) the aigc_http_request tool uses to\r\n * attach the apiKey.\r\n *\r\n * @module @dsh-external/dsh-aigc-canvas/client/SettingsPage\r\n */\r\n\r\nimport { useCallback, useEffect, useState } from 'react'\r\nimport { Modal, Pill } from '@deepseek-ai/dsh-client-ui-primitives'\r\nimport type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\r\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\r\nimport {\r\n addProvider,\r\n fetchConfig,\r\n removeProvider,\r\n updateProvider,\r\n type RuntimeProvider,\r\n} from './api.js'\r\nimport css from './SettingsPage.module.css'\r\n\r\n/** Inject face: locale translate + conversation send (for the init action). */\r\nexport interface AigcSettingsInjected {\r\n readonly t: (key: string) => string\r\n /** Send a prompt into the current conversation scope (queued turn). */\r\n readonly send: (text: string) => Promise<void>\r\n}\r\n\r\n/** Full props: settings.section runtime share + locale seat + inject. */\r\ntype SettingsPageProps = PropsRuntime<'settings.section'> & PropsLocale<'dsh-aigc-canvas'> & AigcSettingsInjected\r\n\r\n/** Default shape for a brand-new draft (before the user fills in id/name). */\r\nfunction emptyDraft(): RuntimeProvider {\r\n return { id: '', name: '', endpoint: 'stub://aigc-backend', apiKey: '', instructions: '', auth: { scheme: 'bearer', name: '' }, builtin: false }\r\n}\r\n\r\n/**\r\n * Render the AIGC provider settings page.\r\n * @param props - settings.section runtime share + locale + inject.\r\n * @returns the page element.\r\n */\r\nexport function SettingsPage({ t, send }: SettingsPageProps) {\r\n const [providers, setProviders] = useState<readonly RuntimeProvider[]>([])\r\n const [drafts, setDrafts] = useState<readonly RuntimeProvider[]>([])\r\n const [expanded, setExpanded] = useState<ReadonlySet<string>>(new Set())\r\n const [addingNew, setAddingNew] = useState(false)\r\n const [newDraft, setNewDraft] = useState<RuntimeProvider>(emptyDraft())\r\n const [loading, setLoading] = useState(true)\r\n const [error, setError] = useState<string | undefined>(undefined)\r\n const [confirmDelete, setConfirmDelete] = useState<string | undefined>(undefined)\r\n\r\n const refresh = useCallback(async () => {\r\n setLoading(true)\r\n setError(undefined)\r\n try {\r\n const result = await fetchConfig()\r\n setProviders(result.providers)\r\n setDrafts(result.providers.map(p => ({ ...p, auth: { ...p.auth } })))\r\n } catch (err) {\r\n setError(err instanceof Error ? err.message : String(err))\r\n } finally {\r\n setLoading(false)\r\n }\r\n }, [])\r\n\r\n useEffect(() => { void refresh() }, [refresh])\r\n\r\n const add = useCallback(async () => {\r\n if (newDraft.id === '') return\r\n try {\r\n const result = await addProvider(newDraft)\r\n setProviders(result.providers)\r\n setDrafts(result.providers.map(p => ({ ...p, auth: { ...p.auth } })))\r\n setExpanded(new Set([...expanded, newDraft.id]))\r\n setAddingNew(false)\r\n setNewDraft(emptyDraft())\r\n } catch (err) {\r\n setError(err instanceof Error ? err.message : String(err))\r\n }\r\n }, [expanded, newDraft])\r\n\r\n const update = useCallback(async (draft: RuntimeProvider) => {\r\n try {\r\n const result = await updateProvider(draft)\r\n setProviders(result.providers)\r\n setDrafts(result.providers.map(p => ({ ...p, auth: { ...p.auth } })))\r\n } catch (err) {\r\n setError(err instanceof Error ? err.message : String(err))\r\n }\r\n }, [])\r\n\r\n const remove = useCallback(async (id: string) => {\r\n try {\r\n const result = await removeProvider(id)\r\n setProviders(result.providers)\r\n setDrafts(result.providers.map(p => ({ ...p, auth: { ...p.auth } })))\r\n const next = new Set(expanded)\r\n next.delete(id)\r\n setExpanded(next)\r\n } catch (err) {\r\n setError(err instanceof Error ? err.message : String(err))\r\n }\r\n }, [expanded])\r\n\r\n const init = useCallback(async (provider: RuntimeProvider) => {\r\n const label = provider.name === '' ? provider.id : provider.name\r\n const text = t('row.initPrompt').replace('{name}', label).replace('{id}', provider.id)\r\n try {\r\n await send(text)\r\n } catch (err) {\r\n setError(err instanceof Error ? err.message : String(err))\r\n }\r\n }, [send, t])\r\n\r\n const patchDraft = (id: string, patch: Partial<RuntimeProvider>): void => {\r\n setDrafts(prev => prev.map(d => (d.id === id ? { ...d, ...patch } : d)))\r\n }\r\n\r\n const toggleExpand = (id: string): void => {\r\n const next = new Set(expanded)\r\n if (next.has(id)) next.delete(id)\r\n else next.add(id)\r\n setExpanded(next)\r\n }\r\n\r\n const cancelNew = (): void => {\r\n setAddingNew(false)\r\n setNewDraft(emptyDraft())\r\n }\r\n\r\n const defaultId = providers.length > 0 ? providers[0]?.id : undefined\r\n\r\n return (\r\n <section className={css.section}>\r\n <h2 className={css.title}>{t('settingsTitle')}</h2>\r\n <p className={css.intro}>{t('settingsIntro')}</p>\r\n {error !== undefined && (\r\n <div className={css.error}>\r\n {error}\r\n <button type=\"button\" className={css.errorDismiss} onClick={() => setError(undefined)}>×</button>\r\n </div>\r\n )}\r\n {loading ? (\r\n <div className={css.loading}>{t('settingsLoading')}</div>\r\n ) : providers.length === 0 && !addingNew ? (\r\n <p className={css.empty}>{t('settingsEmpty')}</p>\r\n ) : (\r\n <ul className={css.rows}>\r\n {drafts.map(draft => (\r\n <ProviderCard\r\n key={draft.id}\r\n draft={draft}\r\n expanded={expanded.has(draft.id)}\r\n isDefault={draft.id === defaultId}\r\n t={t}\r\n onToggle={() => toggleExpand(draft.id)}\r\n onPatch={patch => patchDraft(draft.id, patch)}\r\n onSave={() => void update(draft)}\r\n onDelete={() => setConfirmDelete(draft.id)}\r\n onInit={() => void init(draft)}\r\n />\r\n ))}\r\n {addingNew && (\r\n <ProviderCard\r\n key=\"__new__\"\r\n draft={newDraft}\r\n expanded={true}\r\n isNew={true}\r\n isDefault={false}\r\n t={t}\r\n onPatch={patch => setNewDraft(prev => ({ ...prev, ...patch }))}\r\n onCreate={() => void add()}\r\n onCancel={cancelNew}\r\n />\r\n )}\r\n </ul>\r\n )}\r\n {!loading && !addingNew && (\r\n <button type=\"button\" className={css.addBlockButton} onClick={() => setAddingNew(true)}>\r\n {t('settingsAdd')}\r\n </button>\r\n )}\r\n <Modal\r\n open={confirmDelete !== undefined}\r\n onClose={() => { setConfirmDelete(undefined) }}\r\n title={t('row.deleteConfirm')}\r\n footer={(\r\n <>\r\n <button type=\"button\" className={css.secondaryButton} onClick={() => { setConfirmDelete(undefined) }}>\r\n {t('row.cancel')}\r\n </button>\r\n <button\r\n type=\"button\"\r\n className={css.dangerButton}\r\n onClick={() => {\r\n if (confirmDelete !== undefined) void remove(confirmDelete)\r\n setConfirmDelete(undefined)\r\n }}\r\n >\r\n {t('row.delete')}\r\n </button>\r\n </>\r\n )}\r\n >\r\n <p className={css.confirmText}>{t('row.deleteConfirm')}</p>\r\n </Modal>\r\n </section>\r\n )\r\n}\r\n\r\n// ─── ProviderCard ─────────────────────────────────────────────────────────────\r\n\r\ninterface ProviderCardProps {\r\n readonly draft: RuntimeProvider\r\n readonly expanded: boolean\r\n readonly isNew?: boolean\r\n readonly isDefault: boolean\r\n readonly t: (key: string) => string\r\n readonly onToggle?: () => void\r\n readonly onPatch: (patch: Partial<RuntimeProvider>) => void\r\n readonly onSave?: () => void\r\n readonly onDelete?: () => void\r\n readonly onCreate?: () => void\r\n readonly onCancel?: () => void\r\n readonly onInit?: () => void\r\n}\r\n\r\nfunction ProviderCard({ draft, expanded, isNew, isDefault, t, onToggle, onPatch, onSave, onDelete, onCreate, onCancel, onInit }: ProviderCardProps) {\r\n const isStub = draft.endpoint === '' || draft.endpoint === 'stub://aigc-backend'\r\n const patchAuth = (patch: Partial<{ scheme: 'bearer' | 'header' | 'query'; name: string }>): void => {\r\n onPatch({ auth: { ...draft.auth, ...patch } })\r\n }\r\n return (\r\n <li className={css.rowCard}>\r\n <div className={css.rowHead}>\r\n {!isNew && onToggle !== undefined && (\r\n <button type=\"button\" className={css.chevronButton} onClick={onToggle} aria-label={expanded ? t('row.collapse') : t('row.expand')}>\r\n <span className={expanded ? `${css.chevron} ${css.chevronExpanded}` : css.chevron} aria-hidden=\"true\" />\r\n </button>\r\n )}\r\n {isNew && <span className={css.chevronSpacer} aria-hidden=\"true\" />}\r\n <div className={css.rowIdentity}>\r\n {isNew ? (\r\n <span className={css.rowNamePlaceholder}>{t('settingsAdd')}</span>\r\n ) : (\r\n <span className={css.rowName}>{draft.name === '' ? draft.id : draft.name}</span>\r\n )}\r\n {draft.builtin && <Pill className={css.builtinBadge}>{t('badge.builtin')}</Pill>}\r\n {isDefault && !isNew && <Pill className={css.defaultBadge}>{t('badge.default')}</Pill>}\r\n <Pill className={isStub ? css.stubBadge : css.realBadge}>\r\n {isStub ? t('badge.stub') : t('badge.real')}\r\n </Pill>\r\n {!isNew && <code className={css.rowId}>{draft.id}</code>}\r\n </div>\r\n <div className={css.rowActions}>\r\n {isNew ? (\r\n <>\r\n <button type=\"button\" className={css.primaryButton} onClick={onCreate} disabled={draft.id === ''}>\r\n {t('row.create')}\r\n </button>\r\n <button type=\"button\" className={css.secondaryButton} onClick={onCancel}>\r\n {t('row.cancel')}\r\n </button>\r\n </>\r\n ) : (\r\n <>\r\n {!isStub && onInit !== undefined && (\r\n <button type=\"button\" className={css.secondaryButton} onClick={onInit}>\r\n {t('row.init')}\r\n </button>\r\n )}\r\n <button type=\"button\" className={css.secondaryButton} onClick={onSave}>\r\n {t('row.save')}\r\n </button>\r\n <button type=\"button\" className={css.dangerButton} onClick={onDelete}>\r\n {t('row.delete')}\r\n </button>\r\n </>\r\n )}\r\n </div>\r\n </div>\r\n {expanded && (\r\n <div className={css.editor}>\r\n {isNew && (\r\n <>\r\n <label className={css.field}>\r\n <span className={css.fieldLabel}>{t('row.id')}</span>\r\n <input\r\n className={css.input}\r\n value={draft.id}\r\n placeholder={t('row.idPlaceholder')}\r\n onChange={e => onPatch({ id: e.target.value })}\r\n />\r\n <span className={css.hint}>{t('row.idHint')}</span>\r\n </label>\r\n <label className={css.field}>\r\n <span className={css.fieldLabel}>{t('row.name')}</span>\r\n <input\r\n className={css.input}\r\n value={draft.name}\r\n placeholder={t('row.namePlaceholder')}\r\n onChange={e => onPatch({ name: e.target.value })}\r\n />\r\n </label>\r\n </>\r\n )}\r\n {!isNew && (\r\n <label className={css.field}>\r\n <span className={css.fieldLabel}>{t('row.name')}</span>\r\n <input\r\n className={css.input}\r\n value={draft.name}\r\n placeholder={t('row.namePlaceholder')}\r\n onChange={e => onPatch({ name: e.target.value })}\r\n />\r\n </label>\r\n )}\r\n <label className={css.field}>\r\n <span className={css.fieldLabel}>{t('row.endpoint')}</span>\r\n <input\r\n className={css.input}\r\n value={draft.endpoint}\r\n placeholder={t('row.endpointPlaceholder')}\r\n onChange={e => onPatch({ endpoint: e.target.value })}\r\n />\r\n <span className={css.desc}>{t('row.endpointDesc')}</span>\r\n </label>\r\n <label className={css.field}>\r\n <span className={css.fieldLabel}>{t('row.apiKey')}</span>\r\n <input\r\n className={css.input}\r\n type=\"password\"\r\n autoComplete=\"off\"\r\n value={draft.apiKey}\r\n placeholder={t('row.apiKeyPlaceholder')}\r\n onChange={e => onPatch({ apiKey: e.target.value })}\r\n />\r\n <span className={css.desc}>{t('row.apiKeyDesc')}</span>\r\n </label>\r\n <div className={css.field}>\r\n <span className={css.fieldLabel}>{t('row.auth')}</span>\r\n <div className={css.authRow}>\r\n <select\r\n className={css.select}\r\n value={draft.auth.scheme}\r\n onChange={e => patchAuth({ scheme: e.target.value as 'bearer' | 'header' | 'query' })}\r\n >\r\n <option value=\"bearer\">{t('row.authBearer')}</option>\r\n <option value=\"header\">{t('row.authHeader')}</option>\r\n <option value=\"query\">{t('row.authQuery')}</option>\r\n </select>\r\n {draft.auth.scheme !== 'bearer' && (\r\n <input\r\n className={css.input}\r\n value={draft.auth.name}\r\n placeholder={draft.auth.scheme === 'header' ? 'x-api-key' : 'api_key'}\r\n onChange={e => patchAuth({ name: e.target.value })}\r\n />\r\n )}\r\n </div>\r\n <span className={css.desc}>{t('row.authDesc')}</span>\r\n </div>\r\n <label className={css.field}>\r\n <span className={css.fieldLabel}>{t('row.instructions')}</span>\r\n <textarea\r\n className={css.textarea}\r\n value={draft.instructions}\r\n placeholder={t('row.instructionsPlaceholder')}\r\n rows={8}\r\n onChange={e => onPatch({ instructions: e.target.value })}\r\n />\r\n <span className={css.desc}>{t('row.instructionsDesc')}</span>\r\n <span className={css.hint}>{t('row.instructionsHint')}</span>\r\n </label>\r\n </div>\r\n )}\r\n </li>\r\n )\r\n}\r\n","/**\r\n * i18n dictionaries for the AIGC canvas plugin.\r\n *\r\n * @module @dsh-external/dsh-aigc-canvas/client/locales\r\n */\r\n\r\nexport const NS = 'dsh-aigc-canvas' as const\r\n\r\nexport type AigcKey =\r\n // Canvas view\r\n | 'tabTitle'\r\n | 'title'\r\n | 'empty'\r\n | 'emptyHint'\r\n | 'prompt'\r\n | 'image'\r\n | 'video'\r\n | 'audio'\r\n | 'meta'\r\n | 'generatedBy'\r\n | 'edgeCount'\r\n | 'elementCount'\r\n | 'loadError'\r\n | 'disconnected'\r\n | 'reconnecting'\r\n | 'refresh'\r\n | 'resetView'\r\n | 'zoom'\r\n | 'zoomIn'\r\n | 'zoomOut'\r\n | 'detailClose'\r\n | 'detailPrompt'\r\n | 'detailParams'\r\n | 'detailPosition'\r\n | 'detailPath'\r\n | 'delete'\r\n | 'deleteElement'\r\n | 'dropHint'\r\n | 'uploading'\r\n // Settings — page chrome\r\n | 'settingsNav'\r\n | 'settingsTitle'\r\n | 'settingsIntro'\r\n | 'settingsEmpty'\r\n | 'settingsAdd'\r\n | 'settingsLoading'\r\n | 'settingsError'\r\n // Settings — provider card\r\n | 'row.id'\r\n | 'row.name'\r\n | 'row.endpoint'\r\n | 'row.apiKey'\r\n | 'row.instructions'\r\n | 'row.idPlaceholder'\r\n | 'row.namePlaceholder'\r\n | 'row.endpointPlaceholder'\r\n | 'row.apiKeyPlaceholder'\r\n | 'row.instructionsPlaceholder'\r\n | 'row.idHint'\r\n | 'row.endpointDesc'\r\n | 'row.apiKeyDesc'\r\n | 'row.instructionsDesc'\r\n | 'row.instructionsHint'\r\n | 'row.save'\r\n | 'row.delete'\r\n | 'row.deleteConfirm'\r\n | 'row.expand'\r\n | 'row.collapse'\r\n | 'row.create'\r\n | 'row.cancel'\r\n | 'row.init'\r\n | 'row.initPrompt'\r\n | 'row.auth'\r\n | 'row.authBearer'\r\n | 'row.authHeader'\r\n | 'row.authQuery'\r\n | 'row.authDesc'\r\n | 'badge.builtin'\r\n | 'badge.stub'\r\n | 'badge.real'\r\n | 'badge.default'\r\n\r\nexport const zh: Record<AigcKey, string> = {\r\n tabTitle: 'AIGC 画布',\r\n title: 'AIGC 画布',\r\n empty: '画布是空的。模型通过 aigc_http_request 调用供应商 API 生成素材,再用 aigc_canvas_place 把文件放到画布的任意位置。',\r\n emptyHint: '可在右侧设置页配置供应商,然后让模型开始生成。',\r\n prompt: '提示词',\r\n image: '图片',\r\n video: '视频',\r\n audio: '音频',\r\n meta: '元信息',\r\n generatedBy: '生成方式',\r\n edgeCount: '条连线',\r\n elementCount: '个元素',\r\n loadError: '加载画布失败',\r\n disconnected: '已断开,正在重连…',\r\n reconnecting: '正在重连…',\r\n refresh: '刷新',\r\n resetView: '重置视图',\r\n zoom: '缩放',\r\n zoomIn: '放大',\r\n zoomOut: '缩小',\r\n detailClose: '关闭',\r\n detailPrompt: '提示词',\r\n detailParams: '生成参数',\r\n detailPosition: '位置',\r\n detailPath: '文件路径',\r\n delete: '删除',\r\n deleteElement: '删除元素',\r\n dropHint: '拖放文件到画布',\r\n uploading: '上传中…',\r\n settingsNav: 'AIGC 画布',\r\n settingsTitle: 'AIGC 供应商',\r\n settingsIntro: '配置一个或多个 AIGC 供应商。每个供应商可独立设置名称、API 地址、密钥、鉴权方式和调用说明。模型通过 aigc_get_provider_info 读取供应商列表,用 aigc_http_request 调用 API(自动携带 endpoint 和 apiKey),生成的文件用 aigc_canvas_place 放到画布上。',\r\n settingsEmpty: '暂无供应商,请在下方添加。',\r\n settingsAdd: '+ 添加供应商',\r\n settingsLoading: '加载中…',\r\n settingsError: '错误',\r\n 'row.id': 'ID',\r\n 'row.name': '名称',\r\n 'row.endpoint': 'API 地址',\r\n 'row.apiKey': 'API Key',\r\n 'row.instructions': '调用说明',\r\n 'row.idPlaceholder': 'volcano / jimeng / minimax',\r\n 'row.namePlaceholder': '显示名(如\"火山引擎\")',\r\n 'row.endpointPlaceholder': 'stub://aigc-backend',\r\n 'row.apiKeyPlaceholder': 'sk-...',\r\n 'row.instructionsPlaceholder': '调用说明由 Agent 初始化供应商时自动撰写(点击卡片上的\"初始化\"按钮)...',\r\n 'row.idHint': '小写字母、数字、连字符;必须以字母开头。作为 provider_id 传给 aigc_http_request',\r\n 'row.endpointDesc': '供应商 API 地址。填 stub://aigc-backend 使用内置 stub(合成测试媒体,不调真实 API)',\r\n 'row.apiKeyDesc': '供应商 API 密钥。stub 后端不需要。模型看不到密钥,由 aigc_http_request 自动附加',\r\n 'row.instructionsDesc': 'Agent 通过 aigc_get_provider_info 工具读取此字段,决定如何调用该供应商的 API',\r\n 'row.instructionsHint': '💡 点击卡片上的\"初始化\"按钮,Agent 会用 aigc_http_request 探测 API 并自动撰写调用说明',\r\n 'row.save': '保存',\r\n 'row.delete': '删除',\r\n 'row.deleteConfirm': '确定删除此供应商?',\r\n 'row.expand': '展开',\r\n 'row.collapse': '收起',\r\n 'row.create': '创建',\r\n 'row.cancel': '取消',\r\n 'row.init': '初始化',\r\n 'row.initPrompt': '请帮我初始化 AIGC 供应商「{name}」(id: {id}):先用 aigc_get_provider_info 查看配置,再用 aigc_http_request 探测它的 API(apiKey 会自动附加,无需手动传入),最后调用 aigc_provider_set_instructions 把调用说明保存下来,方便以后直接使用。',\r\n 'row.auth': '鉴权方式',\r\n 'row.authBearer': 'Bearer 头',\r\n 'row.authHeader': '自定义 Header',\r\n 'row.authQuery': 'URL 参数',\r\n 'row.authDesc': 'aigc_http_request 自动附加 apiKey 的方式。默认 Authorization: Bearer <key>;选择自定义 Header 或 URL 参数时需填写名称',\r\n 'badge.builtin': '内置',\r\n 'badge.stub': 'stub 模式',\r\n 'badge.real': '真实 API',\r\n 'badge.default': '默认',\r\n}\r\n\r\nexport const en: Record<AigcKey, string> = {\r\n tabTitle: 'AIGC Canvas',\r\n title: 'AIGC Canvas',\r\n empty: 'Canvas is empty. The agent calls provider APIs via aigc_http_request and places the generated files anywhere on the canvas with aigc_canvas_place.',\r\n emptyHint: 'Configure a provider in the settings tab on the right, then ask the agent to generate something.',\r\n prompt: 'Prompt',\r\n image: 'Image',\r\n video: 'Video',\r\n audio: 'Audio',\r\n meta: 'Metadata',\r\n generatedBy: 'Generated by',\r\n edgeCount: 'edges',\r\n elementCount: 'elements',\r\n loadError: 'Failed to load canvas',\r\n disconnected: 'Disconnected, reconnecting…',\r\n reconnecting: 'Reconnecting…',\r\n refresh: 'Refresh',\r\n resetView: 'Reset view',\r\n zoom: 'Zoom',\r\n zoomIn: 'Zoom in',\r\n zoomOut: 'Zoom out',\r\n detailClose: 'Close',\r\n detailPrompt: 'Prompt',\r\n detailParams: 'Generation params',\r\n detailPosition: 'Position',\r\n detailPath: 'File path',\r\n delete: 'Delete',\r\n deleteElement: 'Delete element',\r\n dropHint: 'Drop files onto canvas',\r\n uploading: 'Uploading…',\r\n settingsNav: 'AIGC Canvas',\r\n settingsTitle: 'AIGC Providers',\r\n settingsIntro: 'Configure one or more AIGC providers. Each provider has its own name, API endpoint, key, auth scheme, and usage instructions. The agent reads the provider list via aigc_get_provider_info, calls the API via aigc_http_request (endpoint + apiKey attached automatically), and places generated files onto the canvas with aigc_canvas_place.',\r\n settingsEmpty: 'No providers configured. Add one below.',\r\n settingsAdd: '+ Add provider',\r\n settingsLoading: 'Loading…',\r\n settingsError: 'Error',\r\n 'row.id': 'ID',\r\n 'row.name': 'Name',\r\n 'row.endpoint': 'Endpoint',\r\n 'row.apiKey': 'API Key',\r\n 'row.instructions': 'Instructions',\r\n 'row.idPlaceholder': 'volcano / jimeng / minimax',\r\n 'row.namePlaceholder': 'Display name (e.g. \"Volcano Engine\")',\r\n 'row.endpointPlaceholder': 'stub://aigc-backend',\r\n 'row.apiKeyPlaceholder': 'sk-...',\r\n 'row.instructionsPlaceholder': 'The agent writes these when you initialize the provider (click \"Initialize\" on the card)...',\r\n 'row.idHint': 'Lowercase letters, digits, hyphens; must start with a letter. Used as the provider_id parameter to aigc_http_request',\r\n 'row.endpointDesc': 'Provider API URL. Use stub://aigc-backend for the built-in stub (synthetic test media, no real API calls)',\r\n 'row.apiKeyDesc': 'Provider API key. Not needed for the stub backend. The agent never sees it — aigc_http_request attaches it automatically',\r\n 'row.instructionsDesc': 'The agent reads this field via the aigc_get_provider_info tool to decide how to call the provider API',\r\n 'row.instructionsHint': '💡 Click \"Initialize\" on the card: the agent probes the API with aigc_http_request and writes the instructions itself',\r\n 'row.save': 'Save',\r\n 'row.delete': 'Delete',\r\n 'row.deleteConfirm': 'Delete this provider?',\r\n 'row.expand': 'Expand',\r\n 'row.collapse': 'Collapse',\r\n 'row.create': 'Create',\r\n 'row.cancel': 'Cancel',\r\n 'row.init': 'Initialize',\r\n 'row.initPrompt': 'Please initialize the AIGC provider \"{name}\" (id: {id}): first call aigc_get_provider_info to see its config, then probe its API with aigc_http_request (the apiKey is attached automatically — do not pass it yourself), and finally call aigc_provider_set_instructions to save the usage instructions so it can be used directly later.',\r\n 'row.auth': 'Auth scheme',\r\n 'row.authBearer': 'Bearer header',\r\n 'row.authHeader': 'Custom header',\r\n 'row.authQuery': 'URL query param',\r\n 'row.authDesc': 'How aigc_http_request attaches the apiKey. Default: Authorization: Bearer <key>. For custom header or URL query param, fill in the name',\r\n 'badge.builtin': 'builtin',\r\n 'badge.stub': 'stub mode',\r\n 'badge.real': 'real API',\r\n 'badge.default': 'default',\r\n}\r\n","/**\r\n * Client half of @dsh-external/dsh-aigc-canvas: registers\r\n * (1) a better-sidebar tab (`aigc-canvas:main`) rendering the canvas view, and\r\n * (2) a settings.section slot for the provider config page.\r\n *\r\n * i18n: registers the `dsh-aigc-canvas` locale namespace (zh + en) and binds\r\n * a translate function passed to both the canvas view and the settings page\r\n * via inject — so the UI respects the DSH locale toggle (no hardcoded text).\r\n *\r\n * The settings page's \"initialize\" action sends a prepared prompt into the\r\n * current conversation via the `conversation` service (ui-conversation).\r\n */\r\nimport type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\r\n// Type-only: pulls the locale plugin's Context merge (ctx.locale).\r\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\r\n// Type-only: pulls the settings shell's SlotMap merge (settings.section).\r\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\r\n// Type-only: pulls the conversation service merge (ctx.conversation.send).\r\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\r\n// Type-only: pulls the ui-slots LocaleNamespaceMap + ctx.slots.\r\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\r\nimport type {} from 'dsh-better-sidebar/client'\r\nimport { createElement, useEffect, useRef, type ReactNode } from 'react'\r\nimport { CanvasStore } from './store.js'\r\nimport { CanvasViewWithBoundary } from './CanvasView.js'\r\nimport { SettingsPage, type AigcSettingsInjected } from './SettingsPage.js'\r\nimport { en, zh, NS, type AigcKey } from './locales.js'\r\n\r\n/** Locale namespace map declaration for the DSH locale system. */\r\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\r\n interface LocaleNamespaceMap {\r\n 'dsh-aigc-canvas': AigcKey\r\n }\r\n}\r\n\r\n/** Services required before mounting. */\r\nexport const inject = ['betterSidebar', 'slots', 'locale', 'conversation']\r\n\r\nexport function apply(ctx: ClientContext): void {\r\n // ── Locale registration ────────────────────────────────────────────────\r\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-aigc-canvas: dictionaries')\r\n const t = ctx.locale.bind(NS) as (key: string) => string\r\n\r\n // ── better-sidebar tab ──────────────────────────────────────────────────\r\n const betterSidebar = (ctx as unknown as {\r\n betterSidebar?: { registerTab(descriptor: unknown): () => void }\r\n }).betterSidebar\r\n if (betterSidebar !== undefined) {\r\n ctx.effect(() =>\r\n betterSidebar.registerTab({\r\n id: 'aigc-canvas:main',\r\n title: () => t('tabTitle'),\r\n order: 50,\r\n dedupeKey: () => 'aigc-canvas:main',\r\n component: ({ scope }: { scope: { sessionId: string } }): ReactNode => {\r\n const storeRef = useRef<CanvasStore | null>(null)\r\n if (storeRef.current === null || storeRef.current.sessionId !== scope.sessionId) {\r\n storeRef.current?.dispose()\r\n storeRef.current = new CanvasStore({ sessionId: scope.sessionId })\r\n }\r\n useEffect(() => {\r\n return () => {\r\n storeRef.current?.dispose()\r\n storeRef.current = null\r\n }\r\n }, [])\r\n return createElement(CanvasViewWithBoundary, { store: storeRef.current, t })\r\n },\r\n }),\r\n )\r\n }\r\n\r\n // ── Settings section ────────────────────────────────────────────────────\r\n const settingsInjected = (): AigcSettingsInjected => ({\r\n t,\r\n send: (text) => ctx.conversation.send(text),\r\n })\r\n ctx.slots.inject('settings.section', () =>\r\n ctx.slots.register({\r\n name: 'settings.section',\r\n id: 'aigc-canvas',\r\n order: 60,\r\n label: () => t('settingsNav'),\r\n locale: NS,\r\n inject: settingsInjected,\r\n }, SettingsPage),\r\n )\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;EAKA,IAAa,eAAb,cAAkC,MAAM;GAE3B;GADX,YACE,MACA,SACA;IACA,MAAM,OAAO;IAHJ,KAAA,OAAA;GAIX;EACF;EA2DA,eAAe,KAAQ,QAAgB,SAAkC,QAAkC;GACzG,IAAI;GACJ,IAAI;IACF,WAAW,MAAM,MAAM,oBAAoB,UAAU;KACnD,QAAQ;KACR,SAAS,EAAE,gBAAgB,mBAAmB;KAC9C,MAAM,KAAK,UAAU,OAAO;KAC5B;IACF,CAAC;GACH,SAAS,OAAO;IACd,MAAM,IAAI,aAAa,WAAW,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;GAC1F;GACA,MAAM,SACF,MAAM,SAAS,KAAK,CAAC,CAAC,YAAY,IAAI;GAC1C,IAAI,CAAC,SAAS,MAAM,WAAW,QAAQ,OAAO,OAAO,QAAQ,OAAO,UAAU,KAAA,GAC5E,MAAM,IAAI,aACR,QAAQ,OAAO,QAAQ,QACvB,QAAQ,OAAO,WAAW,QAAQ,SAAS,QAC7C;GAEF,OAAO,OAAO;EAChB;;EAGA,SAAgB,YAAY,WAAmB,QAAgD;GAC7F,OAAO,KAAsB,eAAe,EAAE,UAAU,GAAG,MAAM;EACnE;;EAGA,SAAgB,kBAAkB,WAAmB,MAAc,GAAW,GAAW,QAA4C;GACnI,OAAO,KAAkB,eAAe;IAAE;IAAW;IAAM;IAAG;GAAE,GAAG,MAAM;EAC3E;;EAGA,SAAgB,oBAAoB,WAAmB,MAAc,QAAgD;GACnH,OAAO,KAAsB,iBAAiB;IAAE;IAAW;GAAK,GAAG,MAAM;EAC3E;;EAGA,SAAgB,iBAAiB,WAAmB,UAAkB,aAAqB,MAAyD,QAAsE;GACxN,OAAO,KAA4C,iBAAiB;IAAE;IAAW;IAAU;IAAa,GAAG;GAAK,GAAG,MAAM;EAC3H;;EAGA,SAAgB,YAAY,QAA8C;GACxE,OAAO,KAAoB,cAAc,CAAC,GAAG,MAAM;EACrD;;EAQA,SAAgB,YAAY,UAA2B,QAAiE;GACtH,OAAO,KAAuC,iBAAiB,EAAE,SAAS,GAAG,MAAM;EACrF;;EAGA,SAAgB,eAAe,UAA2B,QAAiE;GACzH,OAAO,KAAuC,oBAAoB,EAAE,SAAS,GAAG,MAAM;EACxF;;EAGA,SAAgB,eAAe,IAAY,QAAiE;GAC1G,OAAO,KAAuC,oBAAoB,EAAE,GAAG,GAAG,MAAM;EAClF;;EAGA,SAAgB,WAAW,WAAmB,MAAc,WAAW,OAAe;GACpF,MAAM,SAAS,IAAI,gBAAgB;IAAE;IAAW;GAAK,CAAC;GACtD,IAAI,UAAU,OAAO,IAAI,YAAY,GAAG;GACxC,OAAO,qBAAqB,OAAO,SAAS;EAC9C;;EAGA,SAAgB,YAAY,WAA2B;GAErD,OAAO,GADO,OAAO,SAAS,aAAa,WAAW,SAAS,MAC/C,IAAI,OAAO,SAAS,KAAK,mCAAmC,mBAAmB,SAAS;EAC1G;;;;;;;;;;;;;;ECzIA,SAAS,WAAW,WAAoC;GACtD,OAAO;IAAE;IAAW,UAAU,CAAC;IAAG,OAAO,CAAC;GAAE;EAC9C;;EAOA,IAAa,cAAb,MAAyB;GAUM;;GAR7B;GACA;GACA,4BAAoB,IAAI,IAAgB;GACxC;GACA;GACA,WAAmB;GACnB;GAEA,YAAY,MAAqC;IAApB,KAAA,OAAA;IAC3B,KAAK,YAAY,KAAK;IACtB,KAAK,QAAQ,WAAW,KAAK,SAAS;IAGtC,KAAU,QAAQ;IAClB,KAAK,OAAO;GACd;;GAGA,oBAAqC,KAAK;;GAG1C,aAAa,aAAuC;IAClD,KAAK,UAAU,IAAI,QAAQ;IAC3B,aAAa;KAAE,KAAK,UAAU,OAAO,QAAQ;IAAE;GACjD;;GAGA,MAAM,UAAyB;IAC7B,IAAI,KAAK,UAAU;IACnB,KAAK,YAAY,MAAM;IACvB,MAAM,KAAK,IAAI,gBAAgB;IAC/B,KAAK,aAAa;IAClB,IAAI;KACF,MAAM,OAAO,MAAM,YAAY,KAAK,KAAK,WAAW,GAAG,MAAM;KAC7D,IAAI,CAAC,KAAK,UAAU,KAAK,SAAS,IAAI;IACxC,QAAQ,CAER;GACF;;;;;;GAOA,MAAM,KAAK,MAAc,GAAW,GAA0B;IAC5D,IAAI,KAAK,UAAU;IACnB,IAAI;KACF,MAAM,kBAAkB,KAAK,KAAK,WAAW,MAAM,GAAG,CAAC;IACzD,QAAQ,CAER;GACF;;GAGA,MAAM,cAAc,MAA6B;IAC/C,IAAI,KAAK,UAAU;IACnB,IAAI;KACF,MAAM,oBAAoB,KAAK,KAAK,WAAW,IAAI;IACrD,QAAQ,CAER;GACF;;GAGA,MAAM,WAAW,UAAkB,aAAqB,MAAkD;IACxG,IAAI,KAAK,UAAU;IACnB,IAAI;KACF,MAAM,iBAAiB,KAAK,KAAK,WAAW,UAAU,aAAa,IAAI;IACzE,QAAQ,CAER;GACF;;GAGA,UAAgB;IACd,KAAK,WAAW;IAChB,KAAK,YAAY,MAAM;IACvB,IAAI,KAAK,mBAAmB,KAAA,GAAW;KACrC,OAAO,aAAa,KAAK,cAAc;KACvC,KAAK,iBAAiB,KAAA;IACxB;IACA,IAAI,KAAK,OAAO,KAAA,GAAW;KACzB,IAAI;MAAE,KAAK,GAAG,MAAM;KAAE,QAAQ,CAAe;KAC7C,KAAK,KAAK,KAAA;IACZ;IACA,KAAK,UAAU,MAAM;GACvB;GAEA,SAAiB,MAA6B;IAC5C,KAAK,QAAQ;IACb,KAAK,MAAM,MAAM,CAAC,GAAG,KAAK,SAAS,GAAG,GAAG;GAC3C;GAEA,SAAuB;IACrB,IAAI,KAAK,UAAU;IACnB,IAAI;IACJ,IAAI;KACF,KAAK,IAAI,UAAU,YAAY,KAAK,KAAK,SAAS,CAAC;IACrD,QAAQ;KACN,KAAK,kBAAkB;KACvB;IACF;IACA,KAAK,KAAK;IACV,GAAG,aAAa,UAAU;KACxB,IAAI;MACF,MAAM,SAAS,KAAK,MAAM,MAAM,IAAc;MAC9C,IAAI,UAAU,OAAO,OAAO,cAAc,UAAU,KAAK,SAAS,MAAM;KAC1E,QAAQ,CAER;IACF;IACA,GAAG,gBAAgB;KACjB,IAAI,KAAK,UAAU;KACnB,KAAK,KAAK,KAAA;KACV,KAAK,kBAAkB;IACzB;IACA,GAAG,gBAAgB;KACjB,IAAI;MAAE,GAAG,MAAM;KAAE,QAAQ,CAA+B;IAC1D;GACF;GAEA,oBAAkC;IAChC,IAAI,KAAK,UAAU;IACnB,IAAI,KAAK,mBAAmB,KAAA,GAAW;IACvC,KAAK,iBAAiB,OAAO,iBAAiB;KAC5C,KAAK,iBAAiB,KAAA;KACtB,KAAK,OAAO;IACd,GAAG,GAAI;GACT;EACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECvHA,SAAS,UAAU,MAA2B,GAAsB;GAClE,QAAQ,MAAR;IACE,KAAK,UAAU,OAAO,EAAE,QAAQ;IAChC,KAAK,SAAS,OAAO,EAAE,OAAO;IAC9B,KAAK,SAAS,OAAO,EAAE,OAAO;IAC9B,KAAK,SAAS,OAAO,EAAE,OAAO;GAChC;EACF;;EAGA,SAAS,WAAW,IAAoB;GACtC,MAAM,IAAI,IAAI,KAAK,EAAE;GACrB,MAAM,OAAO,MAAsB,IAAI,KAAK,IAAI,MAAM,OAAO,CAAC;GAC9D,OAAO,GAAG,IAAI,EAAE,SAAS,CAAC,EAAE,GAAG,IAAI,EAAE,WAAW,CAAC,EAAE,GAAG,IAAI,EAAE,WAAW,CAAC;EAC1E;;EAGA,MAAM,gBAAgB;;;;;;EAOtB,SAAS,WAAW,EAAE,KAAK,OAAgD;GACzE,MAAM,CAAC,OAAO,aAAA,GAAYA,MAAAA,SAAAA,CAAS,aAAa;GAChD,MAAM,UAAU,MAA8C;IAC5D,MAAM,MAAM,EAAE;IACd,IAAI,IAAI,eAAe,GACrB,SAAS,IAAI,gBAAgB,IAAI,YAAY;GAEjD;GACA,QAAA,GAAOC,MAAAA,cAAAA,CAAc,OAAO;IAC1B,WAAWC,0BAAI;IACf,KAAK;IACL;IACA,SAAS;IACT,WAAW;IACX;IACA,OAAO,GAAG,kBAA4B,MAAM;GAC9C,CAAC;EACH;;;;;EAMA,SAAS,WAAW,EAAE,OAAmC;GACvD,MAAM,CAAC,OAAO,aAAA,GAAYF,MAAAA,SAAAA,CAAS,aAAa;GAChD,MAAM,oBAAoB,MAA8C;IACtE,MAAM,IAAI,EAAE;IACZ,IAAI,EAAE,aAAa,GACjB,SAAS,EAAE,cAAc,EAAE,UAAU;GAEzC;GACA,QAAA,GAAOC,MAAAA,cAAAA,CAAc,SAAS;IAC5B,WAAWC,0BAAI;IACf,KAAK;IACL,UAAU;IACV,SAAS;IACT;IACA,OAAO,GAAG,kBAA4B,MAAM;GAC9C,CAAC;EACH;;EAGA,SAAS,YAAY,IAA4B;GAC/C,IAAI,GAAG,SAAS,UACd,QAAA,GAAOD,MAAAA,cAAAA,CAAc,OAAO,EAAE,WAAWC,0BAAI,WAAW,GAAG,GAAG,cAAc,EAAE;GAIhF,IAAI,GAAG,SAAS,KAAA,GAAW,OAAO;GAClC,MAAM,MAAM,WAAW,GAAG,aAAa,IAAI,GAAG,IAAI;GAClD,IAAI,GAAG,SAAS,SACd,QAAA,GAAOD,MAAAA,cAAAA,CAAc,YAAY;IAAE;IAAK,KAAK,GAAG;GAAM,CAAC;GAEzD,IAAI,GAAG,SAAS,SACd,QAAA,GAAOA,MAAAA,cAAAA,CAAc,YAAY,EAAE,IAAI,CAAC;GAG1C,QAAA,GAAOA,MAAAA,cAAAA,CAAc,SAAS;IAC5B,WAAWC,0BAAI;IACf,KAAK;IACL,UAAU;IACV,SAAS;GACX,CAAC;EACH;;EAQA,SAAgB,WAAW,EAAE,SAAS,KAAiC;GACrE,MAAM,eAAe,GAAGA,0BAAI,QAAQ,GAAGA,0BAAI,WAAW,QAAQ,WAAW;GACzE,QAAA,GAAOD,MAAAA,cAAAA,CACL,OACA;IACE,WAAWC,0BAAI;IACf,aAAa,QAAQ,QAAQ;IAC7B,iBAAiB,QAAQ;GAC3B,IAAA,GACAD,MAAAA,cAAAA,CACE,OACA,EAAE,WAAWC,0BAAI,WAAW,IAAA,GAC5BD,MAAAA,cAAAA,CAAc,QAAQ;IAAE,WAAW;IAAc,eAAe;GAAK,CAAC,IAAA,GACtEA,MAAAA,cAAAA,CAAc,QAAQ,EAAE,WAAWC,0BAAI,UAAU,GAAG,UAAU,QAAQ,MAAM,CAAC,CAAC,IAAA,GAC9ED,MAAAA,cAAAA,CAAc,QAAQ,EAAE,WAAWC,0BAAI,SAAS,GAAG,WAAW,QAAQ,SAAS,CAAC,CAClF,IAAA,GACAD,MAAAA,cAAAA,CAAc,OAAO,EAAE,WAAWC,0BAAI,UAAU,GAAG,QAAQ,KAAK,GAChE,QAAQ,gBAAgB,KAAA,KAAa,QAAQ,gBAAgB,MAAA,GACzDD,MAAAA,cAAAA,CAAc,OAAO,EAAE,WAAWC,0BAAI,gBAAgB,GAAG,QAAQ,WAAW,IAC5E,OAAA,GACJD,MAAAA,cAAAA,CAAc,OAAO,EAAE,WAAWC,0BAAI,UAAU,GAAG,YAAY,OAAO,CAAC,CACzE;EACF;;;;;;;;;;;;;;;;;;;;;EC7HA,IAAM,iBAAN,cAA6BC,MAAAA,UAA2E;GACtG,QAAiB,EAAE,OAAO,KAAsB;GAChD,OAAO,yBAAyB,OAAmC;IACjE,OAAO,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE;GACzE;GACA,kBAA2B,OAAc,MAAuB;IAC9D,QAAQ,MAAM,mCAAmC,OAAO,KAAK,cAAc;GAC7E;GACA,SAA6B;IAC3B,IAAI,KAAK,MAAM,UAAU,MACvB,QAAA,GAAOC,MAAAA,cAAAA,CAAc,OAAO,EAAE,WAAWC,0BAAI,cAAc,GAAG,GAAG,KAAK,MAAM,EAAE,WAAW,EAAE,IAAI,KAAK,MAAM,OAAO;IAEnH,OAAO,KAAK,MAAM;GACpB;EACF;EASA,MAAM,YAAY;EAClB,MAAM,YAAY;;EAGlB,MAAM,SAAS;EACf,MAAM,SAAS;;EAGf,SAAS,OAAO,UAAoB,IAAY,IAAY,QAA0B;GACpF,MAAM,QAAQ,KAAK,IAAI,WAAW,KAAK,IAAI,WAAW,SAAS,QAAQ,MAAM,CAAC;GAC9E,MAAM,UAAU,KAAK,SAAS,KAAK,SAAS;GAC5C,MAAM,UAAU,KAAK,SAAS,KAAK,SAAS;GAC5C,OAAO;IAAE;IAAO,GAAG,KAAK,SAAS;IAAO,GAAG,KAAK,SAAS;GAAM;EACjE;;EAGA,SAAS,WAAW,UAA4D;GAC9E,MAAM,sBAAM,IAAI,IAAyB;GACzC,KAAK,MAAM,MAAM,UACf,IAAI,GAAG,SAAS,KAAA,GAAW,IAAI,IAAI,GAAG,MAAM,EAAE;GAEhD,OAAO;EACT;;EAMA,MAAM,SAAS;;;;;;;;;;;;;EAcf,SAAS,WAAW,MAAgB,YAAoC;GACtE,MAAM,SAAS,WAAW,KAAK,MAAM;GACrC,MAAM,SAAS,WAAW,KAAK,MAAM;GACrC,IAAI,WAAW,KAAA,KAAa,WAAW,KAAA,GAAW,OAAO;GAEzD,MAAM,KAAK,OAAO,IAAI;GACtB,MAAM,KAAK,OAAO,IAAI,SAAS;GAE/B,MAAM,KAAK,OAAO;GAClB,MAAM,KAAK,OAAO,IAAI,SAAS;GAG/B,MAAM,KAAK,KAAK,IAAI,KAAK,EAAE;GAC3B,MAAM,SAAS,KAAK,IAAI,IAAI,KAAK,IAAI,KAAK,IAAK,GAAG,CAAC;GAMnD,MAAM,IAAI,KAAK,GAAG,GAAG,GAAG,KAJZ,KAAK,OAIgB,GAAGC,GAAI,IAF5B,KAAK,OAE+B,GAAGC,GAAI,IAAI,GAAG,GAAG;GAEjE,MAAM,QAAQ;GACd,MAAM,OAAO,QAAQ;GACrB,MAAM,QAAQ,KAAK;GAGnB,MAAM,YAAY,KAAK,GAAG,GAAG,GAAG,KAAK,MAAM,GAFhC,KAAK,KAEiC,KAAK,MAAM,GADjD,KAAK,KACkD;GAClE,QAAA,GAAOH,MAAAA,cAAAA,CAAc,KAAK,EAAE,KAAK,GAAG,KAAK,OAAO,GAAG,KAAK,SAAS,IAAA,GAC/DA,MAAAA,cAAAA,CAAc,QAAQ;IAAE;IAAG,WAAWC,0BAAI;IAAU,MAAM;GAAO,CAAC,IAAA,GAClED,MAAAA,cAAAA,CAAc,QAAQ;IAAE,GAAG;IAAW,WAAWC,0BAAI;GAAU,CAAC,IAAA,GAChED,MAAAA,cAAAA,CAAc,UAAU;IAAE,IAAI;IAAI,IAAI;IAAI,GAAG;IAAQ,WAAWC,0BAAI;GAAS,CAAC,IAAA,GAC9ED,MAAAA,cAAAA,CAAc,UAAU;IAAE,IAAI;IAAI,IAAI;IAAI,GAAG;IAAQ,WAAWC,0BAAI;GAAS,CAAC,CAChF;EACF;;;;;;EAYA,SAAgB,WAAW,EAAE,OAAO,KAAiC;GACnE,MAAM,SAAA,GAAyBG,MAAAA,qBAAAA,CAAqB,MAAM,WAAW,MAAM,aAAa,MAAM,WAAW;GACzG,MAAM,CAAC,UAAU,gBAAA,GAAeC,MAAAA,SAAAA,CAAmB;IAAE,GAAG;IAAG,GAAG;IAAG,OAAO;GAAE,CAAC;GAC3E,MAAM,CAAC,QAAQ,cAAA,GAAaA,MAAAA,SAAAA,iBAAwD,IAAI,IAAI,CAAC;GAC7F,MAAM,CAAC,UAAU,gBAAA,GAAeA,MAAAA,SAAAA,CAAkC,KAAA,CAAS;GAC3E,MAAM,CAAC,aAAa,mBAAA,GAAkBA,MAAAA,SAAAA,CAA6D,KAAA,CAAS;GAC5G,MAAM,CAAC,YAAY,kBAAA,GAAiBA,MAAAA,SAAAA,CAA+C,KAAA,CAAS;GAC5F,MAAM,CAAC,WAAW,iBAAA,GAAgBA,MAAAA,SAAAA,CAAS,KAAK;GAChD,MAAM,cAAA,GAAaC,MAAAA,OAAAA,CAA2B,IAAI;GAKlD,MAAM,gBAAA,GAAeA,MAAAA,OAAAA,iBAAoB,IAAI,IAAI,CAAC;GAGlD,MAAM,UAAA,GAASA,MAAAA,OAAAA,CAAqF,IAAI;GAExG,MAAM,WAAA,GAAUA,MAAAA,OAAAA,CAAiH,IAAI;GAIrI,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,MAAM,UAAU,WAAW;IAC3B,IAAI,YAAY,MAAM;IACtB,MAAM,WAAW,UAA4B;KAC3C,MAAM,eAAe;KACrB,MAAM,OAAO,QAAQ,sBAAsB;KAC3C,MAAM,KAAK,MAAM,UAAU,KAAK;KAChC,MAAM,KAAK,MAAM,UAAU,KAAK;KAChC,MAAM,SAAS,MAAM,SAAS,IAAI,OAAO,IAAI;KAC7C,aAAY,SAAQ,OAAO,MAAM,IAAI,IAAI,MAAM,CAAC;IAClD;IACA,QAAQ,iBAAiB,SAAS,SAAS,EAAE,SAAS,MAAM,CAAC;IAC7D,aAAa,QAAQ,oBAAoB,SAAS,OAAO;GAC3D,GAAG,CAAC,CAAC;GAOL,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,IAAI,OAAO,SAAS,GAAG;IACvB,MAAM,SAAS,WAAW,MAAM,QAAQ;IACxC,MAAM,QAAkB,CAAC;IACzB,KAAK,MAAM,CAAC,MAAM,aAAa,QAAQ;KACrC,MAAM,KAAK,OAAO,IAAI,IAAI;KAC1B,IAAI,OAAO,KAAA,KAAa,GAAG,MAAM,SAAS,KAAK,GAAG,MAAM,SAAS,GAC/D,MAAM,KAAK,IAAI;IAEnB;IACA,IAAI,MAAM,SAAS,GACjB,WAAU,SAAQ;KAChB,MAAM,OAAO,IAAI,IAAI,IAAI;KACzB,KAAK,MAAM,QAAQ,OAAO,KAAK,OAAO,IAAI;KAC1C,OAAO;IACT,CAAC;GAEL,GAAG,CAAC,OAAO,MAAM,CAAC;GAOlB,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,IAAI,OAAO,YAAY,QAAQ,QAAQ,YAAY,MAAM;IACzD,MAAM,UAAU,WAAW;IAC3B,IAAI,YAAY,MAAM;IACtB,MAAM,OAAO,aAAa;IAC1B,IAAI;IACJ,KAAK,MAAM,MAAM,MAAM,UACrB,IAAI,GAAG,SAAS,KAAA,KAAa,CAAC,KAAK,IAAI,GAAG,IAAI,GAC5C,SAAS;IAGb,MAAM,4BAAY,IAAI,IAAY;IAClC,KAAK,MAAM,MAAM,MAAM,UACrB,IAAI,GAAG,SAAS,KAAA,GAAW,UAAU,IAAI,GAAG,IAAI;IAElD,aAAa,UAAU;IACvB,IAAI,WAAW,KAAA,GAAW;IAC1B,MAAM,OAAO,QAAQ,sBAAsB;IAC3C,MAAM,SAAS;IACf,MAAM,UAAU,OAAO,IAAI,SAAS,QAAQ,SAAS;IACrD,MAAM,UAAU,OAAO,IAAI,SAAS,QAAQ,SAAS;IACrD,MAAM,QAAQ,SAAS,SAAS;IAChC,MAAM,QAAQ,SAAS,SAAS;IAChC,IAAI,OAAO;IACX,IAAI,OAAO;IAEX,IAAI,UAAU,QAAQ,KAAK,SAAS,QAClC,OAAQ,UAAU,SAAU,KAAK,SAAS;IAG5C,IAAI,UAAU,QACZ,OAAO,UAAU;IAGnB,IAAI,UAAU,QAAQ,KAAK,QAAQ,QACjC,OAAQ,UAAU,SAAU,KAAK,QAAQ;IAG3C,IAAI,UAAU,QACZ,OAAO,UAAU;IAEnB,IAAI,SAAS,KAAK,SAAS,GACzB,aAAY,UAAS;KAAE,GAAG;KAAM,GAAG,KAAK,IAAI;KAAM,GAAG,KAAK,IAAI;IAAK,EAAE;GAEzE,GAAG,CAAC,OAAO,SAAS,KAAK,CAAC;GAG1B,MAAM,CAAC,aAAa,mBAAA,GAAkBD,MAAAA,SAAAA,CAAS;IAAE,OAAO;IAAG,QAAQ;GAAE,CAAC;GACtE,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,MAAM,UAAU,WAAW;IAC3B,IAAI,YAAY,MAAM;IACtB,MAAM,eAAqB;KACzB,MAAM,OAAO,QAAQ,sBAAsB;KAC3C,eAAe;MAAE,OAAO,KAAK;MAAO,QAAQ,KAAK;KAAO,CAAC;IAC3D;IACA,OAAO;IACP,MAAM,WAAW,IAAI,eAAe,MAAM;IAC1C,SAAS,QAAQ,OAAO;IACxB,aAAa,SAAS,WAAW;GACnC,GAAG,CAAC,CAAC;;GAGL,MAAM,gBAAgB,aAA2B;IAC/C,MAAM,UAAU,WAAW;IAC3B,IAAI,YAAY,MAAM;IACtB,MAAM,OAAO,QAAQ,sBAAsB;IAC3C,MAAM,KAAK,KAAK,QAAQ;IACxB,MAAM,KAAK,KAAK,SAAS;IACzB,aAAY,SAAQ;KAClB,MAAM,IAAI,KAAK,IAAI,WAAW,KAAK,IAAI,WAAW,QAAQ,CAAC;KAC3D,MAAM,UAAU,KAAK,KAAK,KAAK,KAAK;KACpC,MAAM,UAAU,KAAK,KAAK,KAAK,KAAK;KACpC,OAAO;MAAE,OAAO;MAAG,GAAG,KAAK,SAAS;MAAG,GAAG,KAAK,SAAS;KAAE;IAC5D,CAAC;GACH;GAEA,MAAM,wBAAwB,UAAgD;IAC5E,IAAI,QAAQ,YAAY,MAAM;IAC9B,OAAO,UAAU;KACf,WAAW,MAAM;KACjB,QAAQ,MAAM;KACd,QAAQ,MAAM;KACd,MAAM;IACR;IACA,MAAM,cAAc,kBAAkB,MAAM,SAAS;GACvD;GAEA,MAAM,wBAAwB,UAAgD;IAC5E,MAAM,MAAM,OAAO;IACnB,IAAI,QAAQ,QAAQ,IAAI,cAAc,MAAM,WAAW;KACrD,YAAY;MACV,GAAG,IAAI;MACP,GAAG,IAAI,KAAK,KAAK,MAAM,UAAU,IAAI;MACrC,GAAG,IAAI,KAAK,KAAK,MAAM,UAAU,IAAI;KACvC,CAAC;KACD;IACF;IACA,MAAM,OAAO,QAAQ;IACrB,IAAI,SAAS,QAAQ,KAAK,cAAc,MAAM,WAC5C,WAAU,SAAQ;KAChB,MAAM,OAAO,IAAI,IAAI,IAAI;KACzB,KAAK,IAAI,KAAK,MAAM;MAClB,GAAG,KAAK,SAAS,MAAM,UAAU,KAAK,UAAU,SAAS;MACzD,GAAG,KAAK,SAAS,MAAM,UAAU,KAAK,UAAU,SAAS;KAC3D,CAAC;KACD,OAAO;IACT,CAAC;GAEL;GAEA,MAAM,sBAAsB,UAAgD;IAC1E,MAAM,MAAM,OAAO;IACnB,IAAI,QAAQ,QAAQ,IAAI,cAAc,MAAM,WAAW;KACrD,OAAO,UAAU;KACjB;IACF;IACA,MAAM,OAAO,QAAQ;IACrB,IAAI,SAAS,QAAQ,KAAK,cAAc,MAAM,WAAW;KACvD,QAAQ,UAAU;KAClB,MAAM,MAAM,OAAO,IAAI,KAAK,IAAI;KAChC,IAAI,QAAQ,KAAA,MAAc,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,QAC/D,MAAW,KAAK,KAAK,MAAM,IAAI,GAAG,IAAI,CAAC;IAQ3C;GACF;GAEA,MAAM,qBAAqB,OAAuC,OAA0B;IAC1F,IAAI,GAAG,SAAS,KAAA,GAAW;IAC3B,MAAM,gBAAgB;IACtB,MAAM,cAAc,kBAAkB,MAAM,SAAS;IACrD,QAAQ,UAAU;KAChB,WAAW,MAAM;KACjB,MAAM,GAAG;KACT,QAAQ,MAAM;KACd,QAAQ,MAAM;KACd,OAAO,GAAG;KACV,OAAO,GAAG;IACZ;GACF;GAGA,MAAM,qBAAqB,OAAqC,OAA0B;IACxF,IAAI,GAAG,SAAS,KAAA,GAAW;IAC3B,MAAM,eAAe;IACrB,MAAM,gBAAgB;IACtB,eAAe;KAAE,GAAG,MAAM;KAAS,GAAG,MAAM;KAAS,MAAM,GAAG;IAAK,CAAC;GACtE;GAGA,MAAM,kBAAkB,UAA8C;IACpE,IAAI,gBAAgB,KAAA,GAAW;KAC7B,MAAM,gBAAgB;KACtB,eAAe,KAAA,CAAS;IAC1B;GACF;GAGA,MAAM,mBAAmB,SAAuB;IAC9C,eAAe,KAAA,CAAS;IACxB,IAAI,UAAU,SAAS,MAAM,YAAY,KAAA,CAAS;IAClD,MAAW,cAAc,IAAI;GAC/B;GAQA,MAAM,qBAAqB,UAA8C;IACvE,IAAI,MAAM,aAAa,MAAM,SAAS,OAAO,GAAG;KAC9C,MAAM,eAAe;KACrB,MAAM,gBAAgB;KACtB,MAAM,aAAa,aAAa;KAChC,MAAM,OAAO,WAAW,SAAS,sBAAsB;KACvD,IAAI,SAAS,KAAA,GAAW;MACtB,MAAM,KAAK,MAAM,UAAU,KAAK;MAChC,MAAM,KAAK,MAAM,UAAU,KAAK;MAEhC,MAAM,MAAM,KAAK,SAAS,KAAK,SAAS;MACxC,MAAM,MAAM,KAAK,SAAS,KAAK,SAAS;MACxC,cAAc;OAAE,GAAG;OAAI,GAAG;MAAG,CAAC;KAChC;IACF;GACF;GAEA,MAAM,sBAAsB,UAA8C;IAExE,IAAI,MAAM,kBAAkB,MAAM,QAAQ;KACxC,MAAM,gBAAgB;KACtB,cAAc,KAAA,CAAS;IACzB;GACF;GAEA,MAAM,gBAAgB,OAAO,UAAuD;IAClF,MAAM,eAAe;IACrB,MAAM,gBAAgB;IACtB,cAAc,KAAA,CAAS;IACvB,MAAM,QAAQ,MAAM,aAAa;IACjC,IAAI,MAAM,WAAW,GAAG;IACxB,MAAM,OAAO,WAAW,SAAS,sBAAsB;IACvD,MAAM,KAAK,MAAM,WAAW,MAAM,QAAQ;IAC1C,MAAM,KAAK,MAAM,WAAW,MAAM,OAAO;IACzC,MAAM,MAAM,KAAK,SAAS,KAAK,SAAS;IACxC,MAAM,MAAM,KAAK,SAAS,KAAK,SAAS;IACxC,aAAa,IAAI;IACjB,IAAI;KACF,KAAK,MAAM,QAAQ,MAAM,KAAK,KAAK,GAAG;MACpC,MAAM,MAAM,MAAM,KAAK,YAAY;MAGnC,MAAM,QAAQ,IAAI,WAAW,GAAG;MAChC,IAAI,SAAS;MACb,MAAM,QAAQ;MACd,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,OACrC,UAAU,OAAO,aAAa,GAAG,MAAM,SAAS,GAAG,IAAI,KAAK,CAAC;MAE/D,MAAM,cAAc,KAAK,MAAM;MAC/B,MAAM,MAAM,WAAW,KAAK,MAAM,aAAa;OAAE,GAAG;OAAI,GAAG;MAAG,CAAC;KACjE;IACF,UAAU;KACR,aAAa,KAAK;IACpB;GACF;GAEA,MAAM,SAAS,WAAW,MAAM,QAAQ;GAKxC,MAAM,cAA2B,SAAiB;IAChD,MAAM,QAAQ,OAAO,IAAI,IAAI;IAC7B,IAAI,UAAU,KAAA,GAAW,OAAO;IAChC,MAAM,KAAK,OAAO,IAAI,IAAI;IAC1B,IAAI,OAAO,KAAA,GAAW,OAAO;KAAE,GAAG,GAAG;KAAG,GAAG,GAAG;IAAE;GAElD;GACA,MAAM,SAAS,OAA8C;IAC3D,IAAI,GAAG,SAAS,KAAA,GAAW;KACzB,MAAM,QAAQ,OAAO,IAAI,GAAG,IAAI;KAChC,IAAI,UAAU,KAAA,GAAW,OAAO;IAClC;IACA,OAAO;KAAE,GAAG,GAAG;KAAG,GAAG,GAAG;IAAE;GAC5B;GAEA,QAAA,GAAOL,MAAAA,cAAAA,CACL,OACA,EAAE,WAAWC,0BAAI,OAAO,IAAA,GACxBD,MAAAA,cAAAA,CACE,OACA,EAAE,WAAWC,0BAAI,OAAO,IAAA,GACxBD,MAAAA,cAAAA,CAAc,QAAQ,EAAE,WAAWC,0BAAI,MAAM,GAAG,EAAE,OAAO,CAAC,IAAA,GAC1DD,MAAAA,cAAAA,CAAc,QAAQ,EAAE,WAAWC,0BAAI,MAAM,GAAG,GAAG,MAAM,SAAS,OAAO,GAAG,EAAE,cAAc,GAAG,IAAA,GAC/FD,MAAAA,cAAAA,CAAc,QAAQ,EAAE,WAAWC,0BAAI,MAAM,GAAG,GAAG,MAAM,MAAM,OAAO,GAAG,EAAE,WAAW,GAAG,IAAA,GACzFD,MAAAA,cAAAA,CAAc,QAAQ,EAAE,WAAWC,0BAAI,KAAK,GAAG,GAAG,KAAK,MAAM,SAAS,QAAQ,GAAG,EAAE,EAAE,IAAA,GACrFD,MAAAA,cAAAA,CAAc,UAAU;IACtB,MAAM;IACN,WAAWC,0BAAI;IACf,eAAe,aAAa,SAAS,QAAQ,EAAG;IAChD,OAAO,EAAE,SAAS;IAClB,cAAc,EAAE,SAAS;GAC3B,GAAG,GAAG,IAAA,GACND,MAAAA,cAAAA,CAAc,SAAS;IACrB,MAAM;IACN,WAAWC,0BAAI;IACf,KAAK,KAAK,MAAM,YAAY,GAAG;IAC/B,KAAK,KAAK,MAAM,GAAe;IAC/B,OAAO,KAAK,MAAM,SAAS,QAAQ,GAAG;IACtC,WAAW,MAA0C,aAAa,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG;IAC9F,cAAc,EAAE,MAAM;GACxB,CAAC,IAAA,GACDD,MAAAA,cAAAA,CAAc,UAAU;IACtB,MAAM;IACN,WAAWC,0BAAI;IACf,eAAe,aAAa,SAAS,QAAQ,IAAI;IACjD,OAAO,EAAE,QAAQ;IACjB,cAAc,EAAE,QAAQ;GAC1B,GAAG,GAAG,IAAA,GACND,MAAAA,cAAAA,CACE,UACA;IACE,MAAM;IACN,WAAWC,0BAAI;IACf,eAAe;KAAE,MAAW,QAAQ;IAAE;IACtC,OAAO,EAAE,SAAS;IAClB,cAAc,EAAE,SAAS;GAC3B,GACA,GACF,IAAA,GACAD,MAAAA,cAAAA,CACE,UACA;IACE,MAAM;IACN,WAAWC,0BAAI;IACf,eAAe,YAAY;KAAE,GAAG;KAAG,GAAG;KAAG,OAAO;IAAE,CAAC;IACnD,OAAO,EAAE,WAAW;IACpB,cAAc,EAAE,WAAW;GAC7B,GACA,GACF,CACF,IAAA,GACAD,MAAAA,cAAAA,CACE,OACA;IACE,WAAWC,0BAAI;IACf,KAAK;IACL,eAAe;IACf,eAAe;IACf,aAAa;IACb,iBAAiB;IACjB,qBAAqB,YAAY,KAAA,CAAS;IAC1C,SAAS;IACT,gBAAgB,UAAwC;KAEtD,MAAM,eAAe;IACvB;IACA,YAAY;IACZ,aAAa;IACb,SAAS,UAAwC;KAAE,cAAmB,KAAK;IAAE;GAC/E,GACA,MAAM,SAAS,WAAW,KAAA,GACtBD,MAAAA,cAAAA,CAAc,OAAO,EAAE,WAAWC,0BAAI,MAAM,IAAA,GAAGD,MAAAA,cAAAA,CAAc,QAAQ,MAAM,EAAE,OAAO,CAAC,IAAA,GAAGA,MAAAA,cAAAA,CAAc,QAAQ,EAAE,WAAWC,0BAAI,UAAU,GAAG,EAAE,WAAW,CAAC,CAAC,KAAA,GAC3JD,MAAAA,cAAAA,CACE,OACA;IACE,WAAWC,0BAAI;IACf,OAAO;KACL,WAAW,aAAa,SAAS,EAAE,MAAM,SAAS,EAAE,YAAY,SAAS,MAAM;MAS9E,mBAA6B,SAAS;IACzC;GACF,IAAA,GACAD,MAAAA,cAAAA,CACE,OACA;IACE,WAAWC,0BAAI;IACf,eAAe;GACjB,GACA,GAAG,MAAM,MAAM,KAAI,SAAQ,WAAW,MAAM,UAAU,CAAC,CACzD,GACA,GAAG,MAAM,SAAS,KAAI,OAAM;IAC1B,MAAM,MAAM,MAAM,EAAE;IACpB,QAAA,GAAOD,MAAAA,cAAAA,CACL,OACA;KACE,KAAK,GAAG,QAAQ,GAAG;KACnB,WAAW,GAAGC,0BAAI,QAAQ,GAAG,GAAG,SAAS,KAAA,IAAYA,0BAAI,mBAAmB;KAC5E,OAAO,EAAE,WAAW,aAAa,IAAI,EAAE,MAAM,IAAI,EAAE,KAAK;KACxD,gBAAe,UAAS,kBAAkB,OAAO,EAAE;KACnD,gBAAgB,UAAwC;MACtD,MAAM,gBAAgB;MACtB,YAAY,EAAE;KAChB;KACA,gBAAe,UAAS,kBAAkB,OAAO,EAAE;IACrD,IAAA,GACAD,MAAAA,cAAAA,CAAc,YAAY;KAAE,SAAS;KAAI;IAAE,CAAC,CAC9C;GACF,CAAC,CACH,GAEJ,eAAe,KAAA,KAAA,GACXA,MAAAA,cAAAA,CAAc,OAAO;IACnB,WAAWC,0BAAI;IACf,OAAO,EACL,WAAW,aAAa,WAAW,IAAI,SAAS,QAAQ,SAAS,EAAE,MAAM,WAAW,IAAI,SAAS,QAAQ,SAAS,EAAE,YAAY,SAAS,MAAM,GACjJ;GACF,CAAC,IACD,MAEJ,aAAA,GACID,MAAAA,cAAAA,CAAc,OAAO,EAAE,WAAWC,0BAAI,cAAc,GAAG,EAAE,WAAW,CAAC,IACrE,IACN,GACA,aAAa,KAAA,KAAA,GACTD,MAAAA,cAAAA,CAAc,aAAa;IAAE,SAAS;IAAU;IAAG,eAAe,YAAY,KAAA,CAAS;GAAE,CAAC,IAC1F,MAEJ,gBAAgB,KAAA,KAAA,GACZA,MAAAA,cAAAA,CAAc,aAAa;IACzB,GAAG,YAAY;IACf,GAAG,YAAY;IACf,OAAO,CACL;KAAE,OAAO,EAAE,QAAQ;KAAG,eAAe,gBAAgB,YAAY,IAAI;IAAE,CACzE;IACA,eAAe,eAAe,KAAA,CAAS;GACzC,CAAC,IACD,MAEJ,MAAM,SAAS,SAAS,KAAA,GACpBA,MAAAA,cAAAA,CAAc,SAAS;IACrB,UAAU,MAAM;IAChB;IACA;IACA;GACF,CAAC,IACD,IACN;EACF;;EAGA,SAAS,YAAY,OAKP;GAEZ,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,MAAM,eAAqB,MAAM,QAAQ;IACzC,MAAM,SAAS,MAA2B;KAAE,IAAI,EAAE,QAAQ,UAAU,MAAM,QAAQ;IAAE;IACpF,OAAO,iBAAiB,eAAe,QAAQ,EAAE,MAAM,KAAK,CAAC;IAC7D,OAAO,iBAAiB,WAAW,OAAO,EAAE,MAAM,KAAK,CAAC;IACxD,aAAa;KACX,OAAO,oBAAoB,eAAe,MAAM;KAChD,OAAO,oBAAoB,WAAW,KAAK;IAC7C;GACF,GAAG,CAAC,KAAK,CAAC;GACV,QAAA,GAAOA,MAAAA,cAAAA,CACL,OACA;IACE,WAAWC,0BAAI;IACf,OAAO;KAAE,MAAM,MAAM;KAAG,KAAK,MAAM;IAAE;IAErC,gBAAgB,MAAsC,EAAE,gBAAgB;GAC1E,GACA,GAAG,MAAM,MAAM,KAAK,MAAM,OAAA,GACxBD,MAAAA,cAAAA,CAAc,UAAU;IACtB,KAAK;IACL,MAAM;IACN,WAAWC,0BAAI;IACf,eAAe;KAAE,KAAK,QAAQ;IAAE;GAClC,GAAG,KAAK,KAAK,CACf,CACF;EACF;;EAGA,SAAS,YAAY,EAAE,SAAS,GAAG,WAAmF;GAKpH,MAAM,OAAO,QAAQ;GACrB,MAAM,cAAwC,MAAM,QAAQ,IAAI,KAAK,SAAS,QAAQ,OAAO,SAAS,WAClG,CAAC,IACD,OAAO,QAAQ,IAA+B;GAClD,QAAA,GAAOD,MAAAA,cAAAA,CACL,OACA,EAAE,WAAWC,0BAAI,YAAY,IAAA,GAC7BD,MAAAA,cAAAA,CACE,OACA,EAAE,WAAWC,0BAAI,aAAa,IAAA,GAC9BD,MAAAA,cAAAA,CAAc,QAAQ,EAAE,WAAWC,0BAAI,YAAY,GAAG,QAAQ,KAAK,IAAA,GACnED,MAAAA,cAAAA,CAAc,UAAU;IAAE,MAAM;IAAU,WAAWC,0BAAI;IAAa,SAAS;IAAS,cAAc,EAAE,aAAa;GAAE,GAAG,GAAG,CAC/H,IAAA,GACAD,MAAAA,cAAAA,CACE,OACA,EAAE,WAAWC,0BAAI,WAAW,GAC5B,QAAQ,eAAe,KAAA,KAAA,GACnBD,MAAAA,cAAAA,CACE,OACA,EAAE,WAAWC,0BAAI,YAAY,IAAA,GAC7BD,MAAAA,cAAAA,CAAc,QAAQ,EAAE,WAAWC,0BAAI,YAAY,GAAG,EAAE,cAAc,CAAC,IAAA,GACvED,MAAAA,cAAAA,CAAc,OAAO,EAAE,WAAWC,0BAAI,aAAa,GAAG,QAAQ,UAAU,CAC1E,IACA,MACJ,YAAY,SAAS,KAAA,GACjBD,MAAAA,cAAAA,CACE,OACA,EAAE,WAAWC,0BAAI,YAAY,IAAA,GAC7BD,MAAAA,cAAAA,CAAc,QAAQ,EAAE,WAAWC,0BAAI,YAAY,GAAG,EAAE,cAAc,CAAC,IAAA,GACvED,MAAAA,cAAAA,CACE,MACA,EAAE,WAAWC,0BAAI,SAAS,GAC1B,GAAG,YAAY,SAAS,CAAC,GAAG,OAAO,EAAA,GACjCD,MAAAA,cAAAA,CAAc,MAAM;IAAE,KAAK,GAAG,EAAE;IAAK,WAAWC,0BAAI;GAAQ,GAAG,CAAC,IAAA,GAChED,MAAAA,cAAAA,CAAc,MAAM;IAAE,KAAK,GAAG,EAAE;IAAK,WAAWC,0BAAI;GAAU,GAAG,gBAAgB,CAAC,CAAC,CACrF,CAAC,CACH,CACF,IACA,OAAA,GACJD,MAAAA,cAAAA,CACE,OACA,EAAE,WAAWC,0BAAI,YAAY,IAAA,GAC7BD,MAAAA,cAAAA,CAAc,QAAQ,EAAE,WAAWC,0BAAI,YAAY,GAAG,EAAE,aAAa,CAAC,IAAA,GACtED,MAAAA,cAAAA,CAAc,QAAQ,EAAE,WAAWC,0BAAI,YAAY,GAAG,QAAQ,UAAU,CAC1E,IAAA,GACAD,MAAAA,cAAAA,CACE,OACA,EAAE,WAAWC,0BAAI,YAAY,IAAA,GAC7BD,MAAAA,cAAAA,CAAc,QAAQ,EAAE,WAAWC,0BAAI,YAAY,GAAG,EAAE,gBAAgB,CAAC,IAAA,GACzED,MAAAA,cAAAA,CAAc,QAAQ,EAAE,WAAWC,0BAAI,YAAY,GAAG,IAAI,KAAK,MAAM,QAAQ,CAAC,EAAE,IAAI,KAAK,MAAM,QAAQ,CAAC,EAAE,EAAE,CAC9G,IAAA,GACAD,MAAAA,cAAAA,CACE,OACA,EAAE,WAAWC,0BAAI,YAAY,IAAA,GAC7BD,MAAAA,cAAAA,CAAc,QAAQ,EAAE,WAAWC,0BAAI,YAAY,GAAG,EAAE,YAAY,CAAC,IAAA,GACrED,MAAAA,cAAAA,CAAc,QAAQ,EAAE,WAAWC,0BAAI,SAAS,GAAG,QAAQ,QAAQ,CACrE,CACF,CACF;EACF;EAEA,SAAS,gBAAgB,GAAoB;GAC3C,IAAI,OAAO,MAAM,UAAU,OAAO;GAClC,IAAI,OAAO,MAAM,YAAY,OAAO,MAAM,WAAW,OAAO,OAAO,CAAC;GACpE,IAAI,MAAM,QAAQ,MAAM,KAAA,GAAW,OAAO;GAC1C,IAAI;IAAE,OAAO,KAAK,UAAU,CAAC;GAAE,QAAQ;IAAE,OAAO,OAAO,CAAC;GAAE;EAC5D;EAIA,MAAM,YAAY;EAClB,MAAM,YAAY;;EAIlB,MAAM,aAAkD;GACtD,OAAO;GACP,OAAO;GACP,OAAO;GACP,QAAQ;EACV;;;;;EAMA,SAAS,QAAQ,OAKH;GACZ,MAAM,EAAE,UAAU,UAAU,aAAa,gBAAgB;GACzD,MAAM,cAAA,GAAaK,MAAAA,OAAAA,CAA8B,IAAI;GAGrD,IAAI,OAAO;GACX,IAAI,OAAO;GACX,IAAI,OAAO;GACX,IAAI,OAAO;GACX,KAAK,MAAM,MAAM,UAAU;IACzB,OAAO,KAAK,IAAI,MAAM,GAAG,CAAC;IAC1B,OAAO,KAAK,IAAI,MAAM,GAAG,CAAC;IAC1B,OAAO,KAAK,IAAI,MAAM,GAAG,IAAI,MAAM;IACnC,OAAO,KAAK,IAAI,MAAM,GAAG,IAAI,MAAM;GACrC;GACA,IAAI,YAAY,QAAQ,KAAK,YAAY,SAAS,GAAG;IACnD,MAAM,SAAS,CAAC,SAAS,IAAI,SAAS;IACtC,MAAM,SAAS,CAAC,SAAS,IAAI,SAAS;IACtC,MAAM,SAAS,SAAS,YAAY,QAAQ,SAAS;IACrD,MAAM,SAAS,SAAS,YAAY,SAAS,SAAS;IACtD,OAAO,KAAK,IAAI,MAAM,MAAM;IAC5B,OAAO,KAAK,IAAI,MAAM,MAAM;IAC5B,OAAO,KAAK,IAAI,MAAM,MAAM;IAC5B,OAAO,KAAK,IAAI,MAAM,MAAM;GAC9B;GAEA,IAAI,CAAC,OAAO,SAAS,IAAI,KAAK,CAAC,OAAO,SAAS,IAAI,GAAG,OAAO;GAE7D,QAAQ;GACR,QAAQ;GACR,QAAQ;GACR,QAAQ;GACR,MAAM,SAAS,OAAO;GACtB,MAAM,SAAS,OAAO;GACtB,MAAM,YAAY,KAAK,IACpB,MAA+B,QAC/B,MAA+B,MAClC;GACA,MAAM,WAAW,YAAY,SAAS,aAAa;GACnD,MAAM,WAAW,YAAY,SAAS,aAAa;GACnD,MAAM,WAAW,OAAuB,WAAW,KAAK,QAAQ;GAChE,MAAM,WAAW,OAAuB,WAAW,KAAK,QAAQ;GAGhE,MAAM,MAAM,QAAQ,CAAC,SAAS,IAAI,SAAS,KAAK;GAChD,MAAM,MAAM,QAAQ,CAAC,SAAS,IAAI,SAAS,KAAK;GAChD,MAAM,MAAO,YAAY,QAAQ,SAAS,QAAS;GACnD,MAAM,MAAO,YAAY,SAAS,SAAS,QAAS;GAGpD,MAAM,iBAAiB,UAAmD;IACxE,MAAM,gBAAgB;IACtB,MAAM,cAAc,kBAAkB,MAAM,SAAS;IACrD,MAAM,OAAO,SAAiB,YAA0B;KACtD,MAAM,OAAO,WAAW,SAAS,sBAAsB;KACvD,IAAI,SAAS,KAAA,GAAW;KACxB,MAAM,KAAK,UAAU,KAAK;KAC1B,MAAM,KAAK,UAAU,KAAK;KAE1B,MAAM,UAAU,KAAK,WAAW,YAAY;KAC5C,MAAM,UAAU,KAAK,WAAW,YAAY;KAE5C,aAAY,UAAS;MACnB,GAAG;MACH,GAAG,YAAY,QAAQ,IAAI,SAAS,KAAK;MACzC,GAAG,YAAY,SAAS,IAAI,SAAS,KAAK;KAC5C,EAAE;IACJ;IACA,IAAI,MAAM,SAAS,MAAM,OAAO;IAChC,MAAM,UAAU,MAA0B,IAAI,EAAE,SAAS,EAAE,OAAO;IAClE,MAAM,aAAmB;KACvB,OAAO,oBAAoB,eAAe,MAAM;KAChD,OAAO,oBAAoB,aAAa,IAAI;IAC9C;IACA,OAAO,iBAAiB,eAAe,MAAM;IAC7C,OAAO,iBAAiB,aAAa,IAAI;GAC3C;GAEA,QAAA,GAAON,MAAAA,cAAAA,CACL,OACA;IACE,WAAWC,0BAAI;IACf,KAAK;IACL;GACF,IAAA,GACAD,MAAAA,cAAAA,CACE,OACA;IAAE,OAAO;IAAW,QAAQ;IAAW,WAAWC,0BAAI;GAAW,GAEjE,GAAG,SAAS,KAAI,QAAA,GACdD,MAAAA,cAAAA,CAAc,QAAQ;IACpB,KAAK,GAAG,QAAQ,GAAG;IACnB,GAAG,QAAQ,GAAG,CAAC;IACf,GAAG,QAAQ,GAAG,CAAC;IACf,OAAO,KAAK,IAAI,GAAG,SAAS,SAAS;IACrC,QAAQ,KAAK,IAAI,GAAG,SAAS,SAAS;IACtC,IAAI;IACJ,MAAM,WAAW,GAAG;IACpB,aAAa;IACb,QAAQ,WAAW,GAAG;IACtB,eAAe;IACf,aAAa;GACf,CAAC,CACH,IAAA,GAGAA,MAAAA,cAAAA,CAAc,QAAQ;IACpB,GAAG;IACH,GAAG;IACH,OAAO;IACP,QAAQ;IACR,MAAM;IACN,aAAa;IACb,QAAQ;IACR,eAAe;IACf,aAAa;IACb,IAAI;GACN,CAAC,CACH,CACF;EACF;;EAGA,SAAgB,uBAAuB,OAAmC;GACxE,QAAA,GAAOA,MAAAA,cAAAA,CAAc,gBAAgB;IAAE,GAAG,MAAM;IAAG,WAAA,GAAUA,MAAAA,cAAAA,CAAc,YAAY,KAAK;GAAE,CAAC;EACjG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECzzBA,SAAS,aAA8B;GACrC,OAAO;IAAE,IAAI;IAAI,MAAM;IAAI,UAAU;IAAuB,QAAQ;IAAI,cAAc;IAAI,MAAM;KAAE,QAAQ;KAAU,MAAM;IAAG;IAAG,SAAS;GAAM;EACjJ;;;;;;EAOA,SAAgB,aAAa,EAAE,GAAG,QAA2B;GAC3D,MAAM,CAAC,WAAW,iBAAA,GAAgBO,MAAAA,SAAAA,CAAqC,CAAC,CAAC;GACzE,MAAM,CAAC,QAAQ,cAAA,GAAaA,MAAAA,SAAAA,CAAqC,CAAC,CAAC;GACnE,MAAM,CAAC,UAAU,gBAAA,GAAeA,MAAAA,SAAAA,iBAA8B,IAAI,IAAI,CAAC;GACvE,MAAM,CAAC,WAAW,iBAAA,GAAgBA,MAAAA,SAAAA,CAAS,KAAK;GAChD,MAAM,CAAC,UAAU,gBAAA,GAAeA,MAAAA,SAAAA,CAA0B,WAAW,CAAC;GACtE,MAAM,CAAC,SAAS,eAAA,GAAcA,MAAAA,SAAAA,CAAS,IAAI;GAC3C,MAAM,CAAC,OAAO,aAAA,GAAYA,MAAAA,SAAAA,CAA6B,KAAA,CAAS;GAChE,MAAM,CAAC,eAAe,qBAAA,GAAoBA,MAAAA,SAAAA,CAA6B,KAAA,CAAS;GAEhF,MAAM,WAAA,GAAUC,MAAAA,YAAAA,CAAY,YAAY;IACtC,WAAW,IAAI;IACf,SAAS,KAAA,CAAS;IAClB,IAAI;KACF,MAAM,SAAS,MAAM,YAAY;KACjC,aAAa,OAAO,SAAS;KAC7B,UAAU,OAAO,UAAU,KAAI,OAAM;MAAE,GAAG;MAAG,MAAM,EAAE,GAAG,EAAE,KAAK;KAAE,EAAE,CAAC;IACtE,SAAS,KAAK;KACZ,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;IAC3D,UAAU;KACR,WAAW,KAAK;IAClB;GACF,GAAG,CAAC,CAAC;GAEL,CAAA,GAAA,MAAA,UAAA,OAAgB;IAAE,QAAa;GAAE,GAAG,CAAC,OAAO,CAAC;GAE7C,MAAM,OAAA,GAAMA,MAAAA,YAAAA,CAAY,YAAY;IAClC,IAAI,SAAS,OAAO,IAAI;IACxB,IAAI;KACF,MAAM,SAAS,MAAM,YAAY,QAAQ;KACzC,aAAa,OAAO,SAAS;KAC7B,UAAU,OAAO,UAAU,KAAI,OAAM;MAAE,GAAG;MAAG,MAAM,EAAE,GAAG,EAAE,KAAK;KAAE,EAAE,CAAC;KACpE,4BAAY,IAAI,IAAI,CAAC,GAAG,UAAU,SAAS,EAAE,CAAC,CAAC;KAC/C,aAAa,KAAK;KAClB,YAAY,WAAW,CAAC;IAC1B,SAAS,KAAK;KACZ,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;IAC3D;GACF,GAAG,CAAC,UAAU,QAAQ,CAAC;GAEvB,MAAM,UAAA,GAASA,MAAAA,YAAAA,CAAY,OAAO,UAA2B;IAC3D,IAAI;KACF,MAAM,SAAS,MAAM,eAAe,KAAK;KACzC,aAAa,OAAO,SAAS;KAC7B,UAAU,OAAO,UAAU,KAAI,OAAM;MAAE,GAAG;MAAG,MAAM,EAAE,GAAG,EAAE,KAAK;KAAE,EAAE,CAAC;IACtE,SAAS,KAAK;KACZ,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;IAC3D;GACF,GAAG,CAAC,CAAC;GAEL,MAAM,UAAA,GAASA,MAAAA,YAAAA,CAAY,OAAO,OAAe;IAC/C,IAAI;KACF,MAAM,SAAS,MAAM,eAAe,EAAE;KACtC,aAAa,OAAO,SAAS;KAC7B,UAAU,OAAO,UAAU,KAAI,OAAM;MAAE,GAAG;MAAG,MAAM,EAAE,GAAG,EAAE,KAAK;KAAE,EAAE,CAAC;KACpE,MAAM,OAAO,IAAI,IAAI,QAAQ;KAC7B,KAAK,OAAO,EAAE;KACd,YAAY,IAAI;IAClB,SAAS,KAAK;KACZ,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;IAC3D;GACF,GAAG,CAAC,QAAQ,CAAC;GAEb,MAAM,QAAA,GAAOA,MAAAA,YAAAA,CAAY,OAAO,aAA8B;IAC5D,MAAM,QAAQ,SAAS,SAAS,KAAK,SAAS,KAAK,SAAS;IAC5D,MAAM,OAAO,EAAE,gBAAgB,CAAC,CAAC,QAAQ,UAAU,KAAK,CAAC,CAAC,QAAQ,QAAQ,SAAS,EAAE;IACrF,IAAI;KACF,MAAM,KAAK,IAAI;IACjB,SAAS,KAAK;KACZ,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;IAC3D;GACF,GAAG,CAAC,MAAM,CAAC,CAAC;GAEZ,MAAM,cAAc,IAAY,UAA0C;IACxE,WAAU,SAAQ,KAAK,KAAI,MAAM,EAAE,OAAO,KAAK;KAAE,GAAG;KAAG,GAAG;IAAM,IAAI,CAAE,CAAC;GACzE;GAEA,MAAM,gBAAgB,OAAqB;IACzC,MAAM,OAAO,IAAI,IAAI,QAAQ;IAC7B,IAAI,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,EAAE;SAC3B,KAAK,IAAI,EAAE;IAChB,YAAY,IAAI;GAClB;GAEA,MAAM,kBAAwB;IAC5B,aAAa,KAAK;IAClB,YAAY,WAAW,CAAC;GAC1B;GAEA,MAAM,YAAY,UAAU,SAAS,IAAI,UAAU,EAAE,EAAE,KAAK,KAAA;GAE5D,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;IAAS,WAAWC,gCAAI;IAAxB,UAAA;KACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;MAAI,WAAWA,gCAAI;MAAQ,UAAA,EAAE,eAAe;KAAM,CAAA;KAClD,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;MAAG,WAAWA,gCAAI;MAAQ,UAAA,EAAE,eAAe;KAAK,CAAA;KAC/C,UAAU,KAAA,KACT,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAWA,gCAAI;MAApB,UAAA,CACG,OACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;OAAQ,MAAK;OAAS,WAAWA,gCAAI;OAAc,eAAe,SAAS,KAAA,CAAS;OAAG,UAAA;MAAS,CAAA,CAC7F;;KAEN,UACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAWA,gCAAI;MAAU,UAAA,EAAE,iBAAiB;KAAO,CAAA,IACtD,UAAU,WAAW,KAAK,CAAC,YAC7B,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;MAAG,WAAWA,gCAAI;MAAQ,UAAA,EAAE,eAAe;KAAK,CAAA,IAEhD,iBAAA,GAAA,kBAAA,KAAA,CAAC,MAAD;MAAI,WAAWA,gCAAI;MAAnB,UAAA,CACG,OAAO,KAAI,UACV,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD;OAES;OACP,UAAU,SAAS,IAAI,MAAM,EAAE;OAC/B,WAAW,MAAM,OAAO;OACrB;OACH,gBAAgB,aAAa,MAAM,EAAE;OACrC,UAAS,UAAS,WAAW,MAAM,IAAI,KAAK;OAC5C,cAAc,KAAK,OAAO,KAAK;OAC/B,gBAAgB,iBAAiB,MAAM,EAAE;OACzC,cAAc,KAAK,KAAK,KAAK;MAC9B,GAVM,MAAM,EAUZ,CACF,GACA,aACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD;OAEE,OAAO;OACP,UAAU;OACV,OAAO;OACP,WAAW;OACR;OACH,UAAS,UAAS,aAAY,UAAS;QAAE,GAAG;QAAM,GAAG;OAAM,EAAE;OAC7D,gBAAgB,KAAK,IAAI;OACzB,UAAU;MACX,GATK,SASL,CAED;;KAEL,CAAC,WAAW,CAAC,aACZ,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;MAAQ,MAAK;MAAS,WAAWA,gCAAI;MAAgB,eAAe,aAAa,IAAI;MAClF,UAAA,EAAE,aAAa;KACV,CAAA;KAEV,iBAAA,GAAA,kBAAA,IAAA,CAACC,sCAAAA,OAAD;MACE,MAAM,kBAAkB,KAAA;MACxB,eAAe;OAAE,iBAAiB,KAAA,CAAS;MAAE;MAC7C,OAAO,EAAE,mBAAmB;MAC5B,QACE,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;OAAQ,MAAK;OAAS,WAAWD,gCAAI;OAAiB,eAAe;QAAE,iBAAiB,KAAA,CAAS;OAAE;OAChG,UAAA,EAAE,YAAY;MACT,CAAA,GACR,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;OACE,MAAK;OACL,WAAWA,gCAAI;OACf,eAAe;QACb,IAAI,kBAAkB,KAAA,GAAW,OAAY,aAAa;QAC1D,iBAAiB,KAAA,CAAS;OAC5B;OAEC,UAAA,EAAE,YAAY;MACT,CAAA,CACR,EAAA,CAAA;MAGJ,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;OAAG,WAAWA,gCAAI;OAAc,UAAA,EAAE,mBAAmB;MAAK,CAAA;KACrD,CAAA;IACA;;EAEb;EAmBA,SAAS,aAAa,EAAE,OAAO,UAAU,OAAO,WAAW,GAAG,UAAU,SAAS,QAAQ,UAAU,UAAU,UAAU,UAA6B;GAClJ,MAAM,SAAS,MAAM,aAAa,MAAM,MAAM,aAAa;GAC3D,MAAM,aAAa,UAAkF;IACnG,QAAQ,EAAE,MAAM;KAAE,GAAG,MAAM;KAAM,GAAG;IAAM,EAAE,CAAC;GAC/C;GACA,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,MAAD;IAAI,WAAWA,gCAAI;IAAnB,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAWA,gCAAI;KAApB,UAAA;MACG,CAAC,SAAS,aAAa,KAAA,KACtB,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;OAAQ,MAAK;OAAS,WAAWA,gCAAI;OAAe,SAAS;OAAU,cAAY,WAAW,EAAE,cAAc,IAAI,EAAE,YAAY;OAC9H,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAW,WAAW,GAAGA,gCAAI,QAAQ,GAAGA,gCAAI,oBAAoBA,gCAAI;QAAS,eAAY;OAAQ,CAAA;MACjG,CAAA;MAET,SAAS,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAWA,gCAAI;OAAe,eAAY;MAAQ,CAAA;MAClE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAWA,gCAAI;OAApB,UAAA;QACG,QACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,gCAAI;SAAqB,UAAA,EAAE,aAAa;QAAQ,CAAA,IAEjE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,gCAAI;SAAU,UAAA,MAAM,SAAS,KAAK,MAAM,KAAK,MAAM;QAAW,CAAA;QAEhF,MAAM,WAAW,iBAAA,GAAA,kBAAA,IAAA,CAACE,sCAAAA,MAAD;SAAM,WAAWF,gCAAI;SAAe,UAAA,EAAE,eAAe;QAAQ,CAAA;QAC9E,aAAa,CAAC,SAAS,iBAAA,GAAA,kBAAA,IAAA,CAACE,sCAAAA,MAAD;SAAM,WAAWF,gCAAI;SAAe,UAAA,EAAE,eAAe;QAAQ,CAAA;QACrF,iBAAA,GAAA,kBAAA,IAAA,CAACE,sCAAAA,MAAD;SAAM,WAAW,SAASF,gCAAI,YAAYA,gCAAI;SAC3C,UAAA,SAAS,EAAE,YAAY,IAAI,EAAE,YAAY;QACtC,CAAA;QACL,CAAC,SAAS,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,gCAAI;SAAQ,UAAA,MAAM;QAAS,CAAA;OACpD;;MACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OAAK,WAAWA,gCAAI;OACjB,UAAA,QACC,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QAAQ,MAAK;QAAS,WAAWA,gCAAI;QAAe,SAAS;QAAU,UAAU,MAAM,OAAO;QAC3F,UAAA,EAAE,YAAY;OACT,CAAA,GACR,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QAAQ,MAAK;QAAS,WAAWA,gCAAI;QAAiB,SAAS;QAC5D,UAAA,EAAE,YAAY;OACT,CAAA,CACR,EAAA,CAAA,IAEF,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA;QACG,CAAC,UAAU,WAAW,KAAA,KACrB,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SAAQ,MAAK;SAAS,WAAWA,gCAAI;SAAiB,SAAS;SAC5D,UAAA,EAAE,UAAU;QACP,CAAA;QAEV,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SAAQ,MAAK;SAAS,WAAWA,gCAAI;SAAiB,SAAS;SAC5D,UAAA,EAAE,UAAU;QACP,CAAA;QACR,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SAAQ,MAAK;SAAS,WAAWA,gCAAI;SAAc,SAAS;SACzD,UAAA,EAAE,YAAY;QACT,CAAA;OACR,EAAA,CAAA;MAED,CAAA;KACF;IACJ,CAAA,GAAA,YACC,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAWA,gCAAI;KAApB,UAAA;MACG,SACC,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;OAAO,WAAWA,gCAAI;OAAtB,UAAA;QACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,gCAAI;SAAa,UAAA,EAAE,QAAQ;QAAQ,CAAA;QACpD,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;SACE,WAAWA,gCAAI;SACf,OAAO,MAAM;SACb,aAAa,EAAE,mBAAmB;SAClC,WAAU,MAAK,QAAQ,EAAE,IAAI,EAAE,OAAO,MAAM,CAAC;QAC9C,CAAA;QACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,gCAAI;SAAO,UAAA,EAAE,YAAY;QAAQ,CAAA;OAC7C;MACP,CAAA,GAAA,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;OAAO,WAAWA,gCAAI;OAAtB,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,gCAAI;QAAa,UAAA,EAAE,UAAU;OAAQ,CAAA,GACtD,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;QACE,WAAWA,gCAAI;QACf,OAAO,MAAM;QACb,aAAa,EAAE,qBAAqB;QACpC,WAAU,MAAK,QAAQ,EAAE,MAAM,EAAE,OAAO,MAAM,CAAC;OAChD,CAAA,CACI;MACP,CAAA,CAAA,EAAA,CAAA;MAEH,CAAC,SACA,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;OAAO,WAAWA,gCAAI;OAAtB,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,gCAAI;QAAa,UAAA,EAAE,UAAU;OAAQ,CAAA,GACtD,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;QACE,WAAWA,gCAAI;QACf,OAAO,MAAM;QACb,aAAa,EAAE,qBAAqB;QACpC,WAAU,MAAK,QAAQ,EAAE,MAAM,EAAE,OAAO,MAAM,CAAC;OAChD,CAAA,CACI;;MAET,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;OAAO,WAAWA,gCAAI;OAAtB,UAAA;QACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,gCAAI;SAAa,UAAA,EAAE,cAAc;QAAQ,CAAA;QAC1D,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;SACE,WAAWA,gCAAI;SACf,OAAO,MAAM;SACb,aAAa,EAAE,yBAAyB;SACxC,WAAU,MAAK,QAAQ,EAAE,UAAU,EAAE,OAAO,MAAM,CAAC;QACpD,CAAA;QACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,gCAAI;SAAO,UAAA,EAAE,kBAAkB;QAAQ,CAAA;OACnD;;MACP,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;OAAO,WAAWA,gCAAI;OAAtB,UAAA;QACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,gCAAI;SAAa,UAAA,EAAE,YAAY;QAAQ,CAAA;QACxD,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;SACE,WAAWA,gCAAI;SACf,MAAK;SACL,cAAa;SACb,OAAO,MAAM;SACb,aAAa,EAAE,uBAAuB;SACtC,WAAU,MAAK,QAAQ,EAAE,QAAQ,EAAE,OAAO,MAAM,CAAC;QAClD,CAAA;QACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,gCAAI;SAAO,UAAA,EAAE,gBAAgB;QAAQ,CAAA;OACjD;;MACP,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAWA,gCAAI;OAApB,UAAA;QACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,gCAAI;SAAa,UAAA,EAAE,UAAU;QAAQ,CAAA;QACtD,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;SAAK,WAAWA,gCAAI;SAApB,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;UACE,WAAWA,gCAAI;UACf,OAAO,MAAM,KAAK;UAClB,WAAU,MAAK,UAAU,EAAE,QAAQ,EAAE,OAAO,MAAuC,CAAC;UAHtF,UAAA;WAKE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;YAAQ,OAAM;YAAU,UAAA,EAAE,gBAAgB;WAAU,CAAA;WACpD,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;YAAQ,OAAM;YAAU,UAAA,EAAE,gBAAgB;WAAU,CAAA;WACpD,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;YAAQ,OAAM;YAAS,UAAA,EAAE,eAAe;WAAU,CAAA;UAC5C;SACP,CAAA,GAAA,MAAM,KAAK,WAAW,YACrB,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;UACE,WAAWA,gCAAI;UACf,OAAO,MAAM,KAAK;UAClB,aAAa,MAAM,KAAK,WAAW,WAAW,cAAc;UAC5D,WAAU,MAAK,UAAU,EAAE,MAAM,EAAE,OAAO,MAAM,CAAC;SAClD,CAAA,CAEA;;QACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,gCAAI;SAAO,UAAA,EAAE,cAAc;QAAQ,CAAA;OACjD;;MACL,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;OAAO,WAAWA,gCAAI;OAAtB,UAAA;QACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,gCAAI;SAAa,UAAA,EAAE,kBAAkB;QAAQ,CAAA;QAC9D,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD;SACE,WAAWA,gCAAI;SACf,OAAO,MAAM;SACb,aAAa,EAAE,6BAA6B;SAC5C,MAAM;SACN,WAAU,MAAK,QAAQ,EAAE,cAAc,EAAE,OAAO,MAAM,CAAC;QACxD,CAAA;QACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,gCAAI;SAAO,UAAA,EAAE,sBAAsB;QAAQ,CAAA;QAC5D,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,gCAAI;SAAO,UAAA,EAAE,sBAAsB;QAAQ,CAAA;OACvD;;KACJ;IAEL,CAAA,CAAA;;EAER;;;;;;;;ECrYA,MAAa,KAAK;EA4ElB,MAAa,KAA8B;GACzC,UAAU;GACV,OAAO;GACP,OAAO;GACP,WAAW;GACX,QAAQ;GACR,OAAO;GACP,OAAO;GACP,OAAO;GACP,MAAM;GACN,aAAa;GACb,WAAW;GACX,cAAc;GACd,WAAW;GACX,cAAc;GACd,cAAc;GACd,SAAS;GACT,WAAW;GACX,MAAM;GACN,QAAQ;GACR,SAAS;GACT,aAAa;GACb,cAAc;GACd,cAAc;GACd,gBAAgB;GAChB,YAAY;GACZ,QAAQ;GACR,eAAe;GACf,UAAU;GACV,WAAW;GACX,aAAa;GACb,eAAe;GACf,eAAe;GACf,eAAe;GACf,aAAa;GACb,iBAAiB;GACjB,eAAe;GACf,UAAU;GACV,YAAY;GACZ,gBAAgB;GAChB,cAAc;GACd,oBAAoB;GACpB,qBAAqB;GACrB,uBAAuB;GACvB,2BAA2B;GAC3B,yBAAyB;GACzB,+BAA+B;GAC/B,cAAc;GACd,oBAAoB;GACpB,kBAAkB;GAClB,wBAAwB;GACxB,wBAAwB;GACxB,YAAY;GACZ,cAAc;GACd,qBAAqB;GACrB,cAAc;GACd,gBAAgB;GAChB,cAAc;GACd,cAAc;GACd,YAAY;GACZ,kBAAkB;GAClB,YAAY;GACZ,kBAAkB;GAClB,kBAAkB;GAClB,iBAAiB;GACjB,gBAAgB;GAChB,iBAAiB;GACjB,cAAc;GACd,cAAc;GACd,iBAAiB;EACnB;EAEA,MAAa,KAA8B;GACzC,UAAU;GACV,OAAO;GACP,OAAO;GACP,WAAW;GACX,QAAQ;GACR,OAAO;GACP,OAAO;GACP,OAAO;GACP,MAAM;GACN,aAAa;GACb,WAAW;GACX,cAAc;GACd,WAAW;GACX,cAAc;GACd,cAAc;GACd,SAAS;GACT,WAAW;GACX,MAAM;GACN,QAAQ;GACR,SAAS;GACT,aAAa;GACb,cAAc;GACd,cAAc;GACd,gBAAgB;GAChB,YAAY;GACZ,QAAQ;GACR,eAAe;GACf,UAAU;GACV,WAAW;GACX,aAAa;GACb,eAAe;GACf,eAAe;GACf,eAAe;GACf,aAAa;GACb,iBAAiB;GACjB,eAAe;GACf,UAAU;GACV,YAAY;GACZ,gBAAgB;GAChB,cAAc;GACd,oBAAoB;GACpB,qBAAqB;GACrB,uBAAuB;GACvB,2BAA2B;GAC3B,yBAAyB;GACzB,+BAA+B;GAC/B,cAAc;GACd,oBAAoB;GACpB,kBAAkB;GAClB,wBAAwB;GACxB,wBAAwB;GACxB,YAAY;GACZ,cAAc;GACd,qBAAqB;GACrB,cAAc;GACd,gBAAgB;GAChB,cAAc;GACd,cAAc;GACd,YAAY;GACZ,kBAAkB;GAClB,YAAY;GACZ,kBAAkB;GAClB,kBAAkB;GAClB,iBAAiB;GACjB,gBAAgB;GAChB,iBAAiB;GACjB,cAAc;GACd,cAAc;GACd,iBAAiB;EACnB;;;;EC5LA,MAAa,SAAS;GAAC;GAAiB;GAAS;GAAU;EAAc;EAEzE,SAAgB,MAAM,KAA0B;GAE9C,IAAI,aAAa,IAAI,OAAO,SAAS,IAAI;IAAE;IAAI;GAAG,CAAC,GAAG,+BAA+B;GACrF,MAAM,IAAI,IAAI,OAAO,KAAK,EAAE;GAG5B,MAAM,gBAAiB,IAEpB;GACH,IAAI,kBAAkB,KAAA,GACpB,IAAI,aACF,cAAc,YAAY;IACxB,IAAI;IACJ,aAAa,EAAE,UAAU;IACzB,OAAO;IACP,iBAAiB;IACjB,YAAY,EAAE,YAAyD;KACrE,MAAM,YAAA,GAAWG,MAAAA,OAAAA,CAA2B,IAAI;KAChD,IAAI,SAAS,YAAY,QAAQ,SAAS,QAAQ,cAAc,MAAM,WAAW;MAC/E,SAAS,SAAS,QAAQ;MAC1B,SAAS,UAAU,IAAI,YAAY,EAAE,WAAW,MAAM,UAAU,CAAC;KACnE;KACA,CAAA,GAAA,MAAA,UAAA,OAAgB;MACd,aAAa;OACX,SAAS,SAAS,QAAQ;OAC1B,SAAS,UAAU;MACrB;KACF,GAAG,CAAC,CAAC;KACL,QAAA,GAAOC,MAAAA,cAAAA,CAAc,wBAAwB;MAAE,OAAO,SAAS;MAAS;KAAE,CAAC;IAC7E;GACF,CAAC,CACH;GAIF,MAAM,0BAAgD;IACpD;IACA,OAAO,SAAS,IAAI,aAAa,KAAK,IAAI;GAC5C;GACA,IAAI,MAAM,OAAO,0BACf,IAAI,MAAM,SAAS;IACjB,MAAM;IACN,IAAI;IACJ,OAAO;IACP,aAAa,EAAE,aAAa;IAC5B,QAAQ;IACR,QAAQ;GACV,GAAG,YAAY,CACjB;EACF"}
1
+ {"version":3,"file":"client.js","names":["useState","createElement","css","Component","createElement","css","c1y","c2y","useSyncExternalStore","useState","useRef","useState","useCallback","css","Modal","Pill","useRef","createElement"],"sources":["../../../src/client/api.ts","../../../src/client/store.ts","../../../src/client/CanvasNode.tsx","../../../src/client/CanvasView.tsx","../../../src/client/SettingsPage.tsx","../../../src/client/locales.ts","../../../src/client/index.tsx"],"sourcesContent":["/**\r\n * Typed fetch wrapper over the /aigc-canvas JSON API.\r\n */\r\n\r\n/** One wire failure. */\r\nexport class AigcApiError extends Error {\r\n constructor(\r\n readonly code: string,\r\n message: string,\r\n ) {\r\n super(message)\r\n }\r\n}\r\n\r\n/** Element kind (matches the host enum). */\r\nexport type AigcElementKind = 'prompt' | 'image' | 'video' | 'audio'\r\n\r\n/** One canvas element (client view). */\r\nexport interface AigcElement {\r\n filePath: string\r\n uuid?: string\r\n sessionId?: string\r\n kind: AigcElementKind\r\n title: string\r\n /** Canvas position, world coordinates (infinite free canvas). */\r\n x: number\r\n /** Canvas position, world coordinates (infinite free canvas). */\r\n y: number\r\n createdAt: number\r\n producedBy: string\r\n promptText?: string\r\n mediaSize?: number\r\n meta?: Record<string, unknown>\r\n description?: string\r\n}\r\n\r\n/** One canvas edge (source filePath → target filePath). */\r\nexport interface AigcEdge {\r\n source: string\r\n target: string\r\n}\r\n\r\n/** Full canvas state for one session. */\r\nexport interface AigcCanvasState {\r\n sessionId: string\r\n elements: AigcElement[]\r\n edges: AigcEdge[]\r\n}\r\n\r\n/** One provider (wire shape, matches the host ResolvedAigcProvider). */\r\nexport interface RuntimeProvider {\r\n id: string\r\n name: string\r\n endpoint: string\r\n apiKey: string\r\n instructions: string\r\n auth: { scheme: 'bearer' | 'header' | 'query'; name: string }\r\n builtin: boolean\r\n}\r\n\r\n/** Global settings wire shape. */\r\nexport interface RuntimeGlobalSettings {\r\n requestTimeoutMs: number\r\n mediaSizeLimit: number\r\n}\r\n\r\n/** Full config response (providers + global settings). */\r\nexport interface RuntimeConfig extends RuntimeGlobalSettings {\r\n providers: RuntimeProvider[]\r\n}\r\n\r\nasync function call<T>(method: string, payload: Record<string, unknown>, signal?: AbortSignal): Promise<T> {\r\n let response: Response\r\n try {\r\n response = await fetch(`/aigc-canvas/api/${method}`, {\r\n method: 'POST',\r\n headers: { 'content-type': 'application/json' },\r\n body: JSON.stringify(payload),\r\n signal,\r\n })\r\n } catch (error) {\r\n throw new AigcApiError('network', error instanceof Error ? error.message : String(error))\r\n }\r\n const parsed: { ok?: boolean; value?: unknown; error?: { code?: string; message?: string } } | null\r\n = await response.json().catch(() => null)\r\n if (!response.ok || parsed === null || parsed.ok !== true || parsed.value === undefined) {\r\n throw new AigcApiError(\r\n parsed?.error?.code ?? 'http',\r\n parsed?.error?.message ?? `HTTP ${response.status}`,\r\n )\r\n }\r\n return parsed.value as T\r\n}\r\n\r\n/** Fetch the canvas state (elements + edges) for one session. */\r\nexport function fetchCanvas(sessionId: string, signal?: AbortSignal): Promise<AigcCanvasState> {\r\n return call<AigcCanvasState>('canvas.list', { sessionId }, signal)\r\n}\r\n\r\n/** Persist one element's new canvas position (after a client drag). */\r\nexport function moveCanvasElement(sessionId: string, uuid: string, x: number, y: number, signal?: AbortSignal): Promise<AigcElement> {\r\n return call<AigcElement>('canvas.move', { sessionId, uuid, x, y }, signal)\r\n}\r\n\r\n/** Delete one element from the canvas (also removes its edges). */\r\nexport function deleteCanvasElement(sessionId: string, uuid: string, signal?: AbortSignal): Promise<{ ok: boolean }> {\r\n return call<{ ok: boolean }>('canvas.delete', { sessionId, uuid }, signal)\r\n}\r\n\r\n/** Upload a file (drag-dropped onto the canvas) and place it as a new element. */\r\nexport function uploadCanvasFile(sessionId: string, fileName: string, mediaBase64: string, opts?: { x?: number; y?: number; description?: string }, signal?: AbortSignal): Promise<{ ok: boolean; element: AigcElement }> {\r\n return call<{ ok: boolean; element: AigcElement }>('canvas.upload', { sessionId, fileName, mediaBase64, ...opts }, signal)\r\n}\r\n\r\n/** Fetch the full runtime config (providers + global settings). */\r\nexport function fetchConfig(signal?: AbortSignal): Promise<RuntimeConfig> {\r\n return call<RuntimeConfig>('config.get', {}, signal)\r\n}\r\n\r\n/** List all providers. */\r\nexport function listProviders(signal?: AbortSignal): Promise<{ providers: RuntimeProvider[] }> {\r\n return call<{ providers: RuntimeProvider[] }>('providers.list', {}, signal)\r\n}\r\n\r\n/** Add a new provider. */\r\nexport function addProvider(provider: RuntimeProvider, signal?: AbortSignal): Promise<{ providers: RuntimeProvider[] }> {\r\n return call<{ providers: RuntimeProvider[] }>('providers.add', { provider }, signal)\r\n}\r\n\r\n/** Update an existing provider. */\r\nexport function updateProvider(provider: RuntimeProvider, signal?: AbortSignal): Promise<{ providers: RuntimeProvider[] }> {\r\n return call<{ providers: RuntimeProvider[] }>('providers.update', { provider }, signal)\r\n}\r\n\r\n/** Remove a provider by id. */\r\nexport function removeProvider(id: string, signal?: AbortSignal): Promise<{ providers: RuntimeProvider[] }> {\r\n return call<{ providers: RuntimeProvider[] }>('providers.remove', { id }, signal)\r\n}\r\n\r\n/** Build the media URL for one element's media file (by uuid; the host resolves to the file). */\r\nexport function mediaUrlOf(sessionId: string, uuid: string, download = false): string {\r\n const params = new URLSearchParams({ sessionId, uuid })\r\n if (download) params.set('download', '1')\r\n return `/aigc-canvas/file?${params.toString()}`\r\n}\r\n\r\n/** Build the WebSocket URL for the canvas push endpoint. */\r\nexport function canvasWsUrl(sessionId: string): string {\r\n const proto = window.location.protocol === 'https:' ? 'wss:' : 'ws:'\r\n return `${proto}//${window.location.host}/aigc-canvas/ws/canvas?sessionId=${encodeURIComponent(sessionId)}`\r\n}\r\n","/**\n * Canvas view store: subscribes to the host push WebSocket for one session\n * and exposes a synchronous snapshot through useSyncExternalStore. Replays\n * the latest snapshot on reconnect; falls back to a one-shot HTTP fetch\n * when the WS is unavailable so a deployment without the upgrade route\n * still renders the canvas (with manual refresh).\n *\n * The store is per-session: the better-sidebar tab instantiates one per\n * scope.sessionId, and disposes it on tab close (the WS closes with it).\n */\nimport { deleteCanvasElement, fetchCanvas, moveCanvasElement, uploadCanvasFile, canvasWsUrl, type AigcCanvasState } from './api.js'\n\n/** Empty canvas state used as the pre-load placeholder. */\nfunction emptyState(sessionId: string): AigcCanvasState {\n return { sessionId, elements: [], edges: [] }\n}\n\ninterface StoreOptions {\n sessionId: string\n}\n\n/** One store instance per tab activation. */\nexport class CanvasStore {\n /** The session id this store is bound to. */\n readonly sessionId: string\n private state: AigcCanvasState\n private listeners = new Set<() => void>()\n private ws: WebSocket | undefined\n private reconnectTimer: number | undefined\n private disposed = false\n private fetchAbort: AbortController | undefined\n\n constructor(private readonly opts: StoreOptions) {\n this.sessionId = opts.sessionId\n this.state = emptyState(opts.sessionId)\n // Kick off the initial HTTP fetch (gives a snapshot before the WS opens)\n // and the WS subscription (drives live updates).\n void this.refresh()\n this.openWs()\n }\n\n /** Snapshot reader for useSyncExternalStore. */\n getSnapshot = (): AigcCanvasState => this.state\n\n /** Subscribe listener; returns disposer. */\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener)\n return () => { this.listeners.delete(listener) }\n }\n\n /** Force a refresh (e.g. user clicked a refresh button). */\n async refresh(): Promise<void> {\n if (this.disposed) return\n this.fetchAbort?.abort()\n const ac = new AbortController()\n this.fetchAbort = ac\n try {\n const next = await fetchCanvas(this.opts.sessionId, ac.signal)\n if (!this.disposed) this.setState(next)\n } catch {\n // WS will catch up; the fetch is a best-effort priming read.\n }\n }\n\n /**\n * Persist a dragged element's new position. The authoritative snapshot\n * arrives over the WS push (the host notifies after persisting), so no\n * local state update is applied here.\n */\n async move(uuid: string, x: number, y: number): Promise<void> {\n if (this.disposed) return\n try {\n await moveCanvasElement(this.opts.sessionId, uuid, x, y)\n } catch {\n // Best-effort: the next WS snapshot carries the host's authoritative state.\n }\n }\n\n /** Delete an element (right-click → Delete). Best-effort; WS push catches up. */\n async deleteElement(uuid: string): Promise<void> {\n if (this.disposed) return\n try {\n await deleteCanvasElement(this.opts.sessionId, uuid)\n } catch {\n // Best-effort: the next WS snapshot carries the host's authoritative state.\n }\n }\n\n /** Upload a drag-dropped file and place it on the canvas. */\n async uploadFile(fileName: string, mediaBase64: string, opts?: { x?: number; y?: number }): Promise<void> {\n if (this.disposed) return\n try {\n await uploadCanvasFile(this.opts.sessionId, fileName, mediaBase64, opts)\n } catch {\n // Best-effort: the next WS snapshot carries the host's authoritative state.\n }\n }\n\n /** Tear down: close WS, abort any in-flight fetch, drop listeners. */\n dispose(): void {\n this.disposed = true\n this.fetchAbort?.abort()\n if (this.reconnectTimer !== undefined) {\n window.clearTimeout(this.reconnectTimer)\n this.reconnectTimer = undefined\n }\n if (this.ws !== undefined) {\n try { this.ws.close() } catch { /* ignore */ }\n this.ws = undefined\n }\n this.listeners.clear()\n }\n\n private setState(next: AigcCanvasState): void {\n this.state = next\n for (const fn of [...this.listeners]) fn()\n }\n\n private openWs(): void {\n if (this.disposed) return\n let ws: WebSocket\n try {\n ws = new WebSocket(canvasWsUrl(this.opts.sessionId))\n } catch {\n this.scheduleReconnect()\n return\n }\n this.ws = ws\n ws.onmessage = (event) => {\n try {\n const parsed = JSON.parse(event.data as string) as AigcCanvasState\n if (parsed && typeof parsed.sessionId === 'string') this.setState(parsed)\n } catch {\n // Ignore malformed frames — the host only sends valid JSON snapshots.\n }\n }\n ws.onclose = () => {\n if (this.disposed) return\n this.ws = undefined\n this.scheduleReconnect()\n }\n ws.onerror = () => {\n try { ws.close() } catch { /* close handler will run */ }\n }\n }\n\n private scheduleReconnect(): void {\n if (this.disposed) return\n if (this.reconnectTimer !== undefined) return\n this.reconnectTimer = window.setTimeout(() => {\n this.reconnectTimer = undefined\n this.openWs()\n }, 2000)\n }\n}\n","/**\r\n * One canvas node: renders the element's media (image / video / audio) or\r\n * its prompt text, plus a small header row with kind dot + label and the\r\n * creation time. Rendered inside the infinite-canvas world layer at its\r\n * (x, y) position; dragging is handled by the parent view (the node div\r\n * carries the drag pointer handlers). Double-click opens the detail panel.\r\n *\r\n * ZOOM / BLUR FIX\r\n * ---------------\r\n * The world layer is scaled via `transform: scale(s)`. Browsers decode\r\n * `<img>`/`<video>` at their CSS layout size (the card's 220px content\r\n * width), NOT the post-transform screen size — so zooming in upscales a\r\n * small decoded bitmap and the media looks blurry.\r\n *\r\n * To get crisp media at every zoom level, each img/video sets its CSS\r\n * width to `100% * scale` (the on-screen pixel width) and then applies\r\n * `transform: scale(1/scale)` to visually shrink back to the 220px layout\r\n * box. The browser then decodes at the larger size and the world\r\n * transform produces a 1:1 (or downscaled) screen image — sharp.\r\n *\r\n * The layout box still grows to `220*scale` wide, which would push\r\n * siblings and inflate the card. Negative `margin-right` / `margin-bottom`\r\n * (expressed as `%` of the container width = 220px) cancel the excess so\r\n * the effective layout footprint is unchanged. The bottom margin needs\r\n * the media's aspect ratio (h/w), captured from `onLoad`/`onLoadedMetadata`.\r\n */\r\nimport { createElement, useState, type CSSProperties, type ReactNode, type SyntheticEvent } from 'react'\r\nimport type { AigcElement } from './api.js'\r\nimport { mediaUrlOf } from './api.js'\r\nimport css from './canvas.module.css'\r\n\r\n/** Translation function type (from the DSH locale system). */\r\ntype Translate = (key: string) => string\r\n\r\n/** Short label for one element kind. */\r\nfunction kindLabel(kind: AigcElement['kind'], t: Translate): string {\r\n switch (kind) {\r\n case 'prompt': return t('prompt')\r\n case 'image': return t('image')\r\n case 'video': return t('video')\r\n case 'audio': return t('audio')\r\n }\r\n}\r\n\r\n/** Format the createdAt timestamp as a short HH:MM:SS. */\r\nfunction formatTime(ms: number): string {\r\n const d = new Date(ms)\r\n const pad = (n: number): string => n < 10 ? `0${n}` : String(n)\r\n return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`\r\n}\r\n\r\n/** Default aspect ratio (h/w) used before media metadata loads. 4:3 → 0.75. */\r\nconst DEFAULT_RATIO = 0.75\r\n\r\n/**\r\n * One image element. Captures its natural aspect ratio on load so the\r\n * negative bottom margin (which cancels the layout-box inflation from the\r\n * counter-scale trick) can be computed from CSS variables alone.\r\n */\r\nfunction MediaImage({ url, alt }: { url: string; alt: string }): ReactNode {\r\n const [ratio, setRatio] = useState(DEFAULT_RATIO)\r\n const onLoad = (e: SyntheticEvent<HTMLImageElement>): void => {\r\n const img = e.currentTarget\r\n if (img.naturalWidth > 0) {\r\n setRatio(img.naturalHeight / img.naturalWidth)\r\n }\r\n }\r\n return createElement('img', {\r\n className: css.mediaImage,\r\n src: url,\r\n alt,\r\n loading: 'lazy',\r\n draggable: false,\r\n onLoad,\r\n style: { ['--media-ratio' as string]: ratio } as CSSProperties,\r\n })\r\n}\r\n\r\n/**\r\n * One video element. Same counter-scale trick as MediaImage; the aspect\r\n * ratio comes from `loadedmetadata` (videoWidth / videoHeight).\r\n */\r\nfunction MediaVideo({ url }: { url: string }): ReactNode {\r\n const [ratio, setRatio] = useState(DEFAULT_RATIO)\r\n const onLoadedMetadata = (e: SyntheticEvent<HTMLVideoElement>): void => {\r\n const v = e.currentTarget\r\n if (v.videoWidth > 0) {\r\n setRatio(v.videoHeight / v.videoWidth)\r\n }\r\n }\r\n return createElement('video', {\r\n className: css.mediaVideo,\r\n src: url,\r\n controls: true,\r\n preload: 'metadata',\r\n onLoadedMetadata,\r\n style: { ['--media-ratio' as string]: ratio } as CSSProperties,\r\n })\r\n}\r\n\r\n/** Render one element's media (or prompt text) based on its kind. */\r\nfunction renderMedia(el: AigcElement): ReactNode {\r\n if (el.kind === 'prompt') {\r\n return createElement('pre', { className: css.promptText }, el.promptText ?? '')\r\n }\r\n // Media route needs the uuid (the host resolves uuid → filePath internally).\r\n // The uuid is present on every element the WS push delivers.\r\n if (el.uuid === undefined) return null\r\n const url = mediaUrlOf(el.sessionId ?? '', el.uuid)\r\n if (el.kind === 'image') {\r\n return createElement(MediaImage, { url, alt: el.title })\r\n }\r\n if (el.kind === 'video') {\r\n return createElement(MediaVideo, { url })\r\n }\r\n // audio — native control, no bitmap to sharpen\r\n return createElement('audio', {\r\n className: css.mediaAudio,\r\n src: url,\r\n controls: true,\r\n preload: 'metadata',\r\n })\r\n}\r\n\r\nexport interface CanvasNodeProps {\r\n element: AigcElement\r\n t: Translate\r\n}\r\n\r\n/** One canvas node (fixed-width card; height follows content). */\r\nexport function CanvasNode({ element, t }: CanvasNodeProps): ReactNode {\r\n const kindDotClass = `${css.kindDot} ${css[`kindDot_${element.kind}`] ?? ''}`\r\n return createElement(\r\n 'div',\r\n {\r\n className: css.node,\r\n 'data-uuid': element.uuid ?? '',\r\n 'data-filepath': element.filePath,\r\n },\r\n createElement(\r\n 'div',\r\n { className: css.nodeHeader },\r\n createElement('span', { className: kindDotClass, 'aria-hidden': true }),\r\n createElement('span', { className: css.kindLabel }, kindLabel(element.kind, t)),\r\n createElement('span', { className: css.nodeTime }, formatTime(element.createdAt)),\r\n ),\r\n createElement('div', { className: css.nodeTitle }, element.title),\r\n element.description !== undefined && element.description !== ''\r\n ? createElement('div', { className: css.nodeDescription }, element.description)\r\n : null,\r\n createElement('div', { className: css.nodeMedia }, renderMedia(element)),\r\n )\r\n}\r\n","/**\r\n * The infinite canvas view: a free, pannable + zoomable surface where\r\n * elements live at arbitrary world positions (x, y) and edges render as\r\n * smooth curves between right/left ports.\r\n *\r\n * Interactions:\r\n * - drag an element: moves it (persisted via the canvas.move API on release)\r\n * - drag the background: pans the viewport\r\n * - wheel: zooms around the cursor (clamped 0.2×–4×)\r\n * - zoom slider / +/- buttons in the header: zoom from center\r\n * - minimap (bottom-right): click/drag to pan; shows element outlines + viewport frame\r\n * - double-click an element: opens the detail panel (prompt + params + path)\r\n *\r\n * The WS push delivers authoritative snapshots; dragged positions are\r\n * applied locally as drafts during the gesture and confirmed by the push\r\n * (the host notifies after persisting the move).\r\n */\r\nimport { Component, createElement, useEffect, useRef, useState, useSyncExternalStore, type CSSProperties, type ErrorInfo, type ReactNode, type PointerEvent as ReactPointerEvent, type MouseEvent as ReactMouseEvent, type ChangeEvent as ReactChangeEvent } from 'react'\r\nimport type { AigcCanvasState, AigcEdge, AigcElement } from './api.js'\r\nimport { CanvasStore } from './store.js'\r\nimport { CanvasNode } from './CanvasNode.js'\r\nimport css from './canvas.module.css'\r\n\r\n/** Translation function type (from the DSH locale system). */\r\ntype Translate = (key: string) => string\r\n\r\n/** Error boundary so a render failure shows a strip instead of blanking. */\r\nclass CanvasBoundary extends Component<{ children: ReactNode; t: Translate }, { error: string | null }> {\r\n override state = { error: null as string | null }\r\n static getDerivedStateFromError(error: unknown): { error: string } {\r\n return { error: error instanceof Error ? error.message : String(error) }\r\n }\r\n override componentDidCatch(error: Error, info: ErrorInfo): void {\r\n console.error('[dsh-aigc-canvas] render error:', error, info.componentStack)\r\n }\r\n override render(): ReactNode {\r\n if (this.state.error !== null) {\r\n return createElement('div', { className: css.boundaryError }, `${this.props.t('loadError')}: ${this.state.error}`)\r\n }\r\n return this.props.children\r\n }\r\n}\r\n\r\n/** Viewport state: world→screen is `screen = world * scale + (x, y)`. */\r\ninterface Viewport {\r\n x: number\r\n y: number\r\n scale: number\r\n}\r\n\r\nconst MIN_SCALE = 0.2\r\nconst MAX_SCALE = 4\r\n\r\n/** Fixed node box for edge anchoring (world units). Must match CSS .nodeBox width. */\r\nconst NODE_W = 240\r\nconst NODE_H = 110\r\n\r\n/** Zoom at the cursor position, keeping the world point under the cursor fixed. */\r\nfunction zoomAt(viewport: Viewport, cx: number, cy: number, factor: number): Viewport {\r\n const scale = Math.min(MAX_SCALE, Math.max(MIN_SCALE, viewport.scale * factor))\r\n const worldX = (cx - viewport.x) / viewport.scale\r\n const worldY = (cy - viewport.y) / viewport.scale\r\n return { scale, x: cx - worldX * scale, y: cy - worldY * scale }\r\n}\r\n\r\n/** Build a uuid → element map. */\r\nfunction elementMap(elements: readonly AigcElement[]): Map<string, AigcElement> {\r\n const map = new Map<string, AigcElement>()\r\n for (const el of elements) {\r\n if (el.uuid !== undefined) map.set(el.uuid, el)\r\n }\r\n return map\r\n}\r\n\r\n/** Position resolver: returns draft position if dragging, else the element's own. */\r\ntype PosResolver = (uuid: string) => { x: number; y: number } | undefined\r\n\r\n/** Port radius (the small circle drawn at each connection point). */\r\nconst PORT_R = 5\r\n\r\n/**\r\n * One smooth-curve edge: exits the source's right-center port, curves\r\n * through two control points, enters the target's left-center port.\r\n * Drawn as an SVG cubic-bezier path + two port circles + an arrowhead.\r\n *\r\n * The control points sit on the horizontal axis at a fixed offset from\r\n * each port so the curve bows out smoothly regardless of distance —\r\n * looks like a relaxed S when the ports are vertically offset.\r\n *\r\n * Uses the position resolver so the edge follows live drag positions\r\n * (drafts) in real time, not just the persisted snapshot.\r\n */\r\nfunction renderEdge(edge: AigcEdge, resolvePos: PosResolver): ReactNode {\r\n const srcPos = resolvePos(edge.source)\r\n const tgtPos = resolvePos(edge.target)\r\n if (srcPos === undefined || tgtPos === undefined) return null\r\n // Source port: right-center of the source card.\r\n const sx = srcPos.x + NODE_W\r\n const sy = srcPos.y + NODE_H / 2\r\n // Target port: left-center of the target card.\r\n const tx = tgtPos.x\r\n const ty = tgtPos.y + NODE_H / 2\r\n // Control-point offset: half the horizontal gap, clamped so short\r\n // gaps still bow nicely and very long gaps don't over-extend.\r\n const dx = Math.abs(tx - sx)\r\n const offset = Math.max(40, Math.min(dx * 0.5, 160))\r\n // Cubic bezier: C1 to the right of source, C2 to the left of target.\r\n const c1x = sx + offset\r\n const c1y = sy\r\n const c2x = tx - offset\r\n const c2y = ty\r\n const d = `M ${sx} ${sy} C ${c1x} ${c1y}, ${c2x} ${c2y}, ${tx} ${ty}`\r\n // Arrowhead pointing right (into the target port).\r\n const arrow = 9\r\n const wing = arrow * 0.55\r\n const baseX = tx - arrow\r\n const ly = ty - wing\r\n const ry = ty + wing\r\n const arrowPath = `M ${tx} ${ty} L ${baseX} ${ly} L ${baseX} ${ry} Z`\r\n return createElement('g', { key: `${edge.source}:${edge.target}` },\r\n createElement('path', { d, className: css.edgeLine, fill: 'none' }),\r\n createElement('path', { d: arrowPath, className: css.edgeArrow }),\r\n createElement('circle', { cx: sx, cy: sy, r: PORT_R, className: css.edgePort }),\r\n createElement('circle', { cx: tx, cy: ty, r: PORT_R, className: css.edgePort }),\r\n )\r\n}\r\n\r\nexport interface CanvasViewProps {\r\n store: CanvasStore\r\n t: Translate\r\n}\r\n\r\n/**\r\n * The infinite canvas view.\r\n * @param props - store + locale translate.\r\n * @returns the canvas element.\r\n */\r\nexport function CanvasView({ store, t }: CanvasViewProps): ReactNode {\r\n const state: AigcCanvasState = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot)\r\n const [viewport, setViewport] = useState<Viewport>({ x: 0, y: 0, scale: 1 })\r\n const [drafts, setDrafts] = useState<ReadonlyMap<string, { x: number; y: number }>>(new Map())\r\n const [selected, setSelected] = useState<AigcElement | undefined>(undefined)\r\n const [contextMenu, setContextMenu] = useState<{ x: number; y: number; uuid: string } | undefined>(undefined)\r\n const [dropTarget, setDropTarget] = useState<{ x: number; y: number } | undefined>(undefined)\r\n const [uploading, setUploading] = useState(false)\r\n const surfaceRef = useRef<HTMLElement | null>(null)\r\n\r\n // Track the previous snapshot's element uuids so we can detect when new\r\n // elements appear (model just placed something) and pan the viewport to\r\n // bring the newest one into view at \"center-left\" of the visible area.\r\n const prevUuidsRef = useRef<Set<string>>(new Set())\r\n\r\n // Pan gesture (drag on empty background).\r\n const panRef = useRef<{ pointerId: number; startX: number; startY: number; orig: Viewport } | null>(null)\r\n // Element drag gesture.\r\n const dragRef = useRef<{ pointerId: number; uuid: string; startX: number; startY: number; origX: number; origY: number } | null>(null)\r\n\r\n // Wheel: zooms around the cursor (clamped 0.2×–4×). Pan is via\r\n // dragging the background. Needs a non-passive listener.\r\n useEffect(() => {\r\n const surface = surfaceRef.current\r\n if (surface === null) return\r\n const onWheel = (event: WheelEvent): void => {\r\n event.preventDefault()\r\n const rect = surface.getBoundingClientRect()\r\n const cx = event.clientX - rect.left\r\n const cy = event.clientY - rect.top\r\n const factor = event.deltaY < 0 ? 1.12 : 1 / 1.12\r\n setViewport(prev => zoomAt(prev, cx, cy, factor))\r\n }\r\n surface.addEventListener('wheel', onWheel, { passive: false })\r\n return () => surface.removeEventListener('wheel', onWheel)\r\n }, [])\r\n\r\n // Clean up stale drafts: once the persisted snapshot confirms an\r\n // element's position matches its draft, the draft is no longer needed\r\n // (posOf will return the persisted position, which is the same). This\r\n // prevents drafts from accumulating indefinitely and ensures that a\r\n // subsequent drag of the same element starts from the right position.\r\n useEffect(() => {\r\n if (drafts.size === 0) return\r\n const lookup = elementMap(state.elements)\r\n const stale: string[] = []\r\n for (const [uuid, draftPos] of drafts) {\r\n const el = lookup.get(uuid)\r\n if (el !== undefined && el.x === draftPos.x && el.y === draftPos.y) {\r\n stale.push(uuid)\r\n }\r\n }\r\n if (stale.length > 0) {\r\n setDrafts(prev => {\r\n const next = new Map(prev)\r\n for (const uuid of stale) next.delete(uuid)\r\n return next\r\n })\r\n }\r\n }, [state, drafts])\r\n\r\n // Auto-pan to newly placed elements. When the snapshot gains an element\r\n // the model just placed it; if it isn't visible in the current viewport,\r\n // pan JUST ENOUGH to bring it into view (with a margin). Unlike the old\r\n // center-at-25%/40% approach, this keeps existing elements visible when\r\n // a vertical column grows downward — only the minimal offset is applied.\r\n useEffect(() => {\r\n if (panRef.current !== null || dragRef.current !== null) return\r\n const surface = surfaceRef.current\r\n if (surface === null) return\r\n const prev = prevUuidsRef.current\r\n let newest: AigcElement | undefined\r\n for (const el of state.elements) {\r\n if (el.uuid !== undefined && !prev.has(el.uuid)) {\r\n newest = el\r\n }\r\n }\r\n const nextUuids = new Set<string>()\r\n for (const el of state.elements) {\r\n if (el.uuid !== undefined) nextUuids.add(el.uuid)\r\n }\r\n prevUuidsRef.current = nextUuids\r\n if (newest === undefined) return\r\n const rect = surface.getBoundingClientRect()\r\n const margin = 32\r\n const screenX = newest.x * viewport.scale + viewport.x\r\n const screenY = newest.y * viewport.scale + viewport.y\r\n const elemW = NODE_W * viewport.scale\r\n const elemH = NODE_H * viewport.scale\r\n let panX = 0\r\n let panY = 0\r\n // Below visible area → pan down just enough.\r\n if (screenY + elemH > rect.height - margin) {\r\n panY = (screenY + elemH) - (rect.height - margin)\r\n }\r\n // Above visible area → pan up just enough.\r\n if (screenY < margin) {\r\n panY = screenY - margin\r\n }\r\n // Right of visible area → pan right just enough.\r\n if (screenX + elemW > rect.width - margin) {\r\n panX = (screenX + elemW) - (rect.width - margin)\r\n }\r\n // Left of visible area → pan left just enough.\r\n if (screenX < margin) {\r\n panX = screenX - margin\r\n }\r\n if (panX !== 0 || panY !== 0) {\r\n setViewport(prev => ({ ...prev, x: prev.x - panX, y: prev.y - panY }))\r\n }\r\n }, [state, viewport.scale])\r\n\r\n // Track the surface dimensions for the minimap viewport frame.\r\n const [surfaceSize, setSurfaceSize] = useState({ width: 0, height: 0 })\r\n useEffect(() => {\r\n const surface = surfaceRef.current\r\n if (surface === null) return\r\n const update = (): void => {\r\n const rect = surface.getBoundingClientRect()\r\n setSurfaceSize({ width: rect.width, height: rect.height })\r\n }\r\n update()\r\n const observer = new ResizeObserver(update)\r\n observer.observe(surface)\r\n return () => observer.disconnect()\r\n }, [])\r\n\r\n /** Zoom to a target scale, keeping the center of the viewport fixed. */\r\n const zoomToCenter = (newScale: number): void => {\r\n const surface = surfaceRef.current\r\n if (surface === null) return\r\n const rect = surface.getBoundingClientRect()\r\n const cx = rect.width / 2\r\n const cy = rect.height / 2\r\n setViewport(prev => {\r\n const s = Math.min(MAX_SCALE, Math.max(MIN_SCALE, newScale))\r\n const worldX = (cx - prev.x) / prev.scale\r\n const worldY = (cy - prev.y) / prev.scale\r\n return { scale: s, x: cx - worldX * s, y: cy - worldY * s }\r\n })\r\n }\r\n\r\n const onSurfacePointerDown = (event: ReactPointerEvent<HTMLElement>): void => {\r\n if (dragRef.current !== null) return\r\n panRef.current = {\r\n pointerId: event.pointerId,\r\n startX: event.clientX,\r\n startY: event.clientY,\r\n orig: viewport,\r\n }\r\n event.currentTarget.setPointerCapture(event.pointerId)\r\n }\r\n\r\n const onSurfacePointerMove = (event: ReactPointerEvent<HTMLElement>): void => {\r\n const pan = panRef.current\r\n if (pan !== null && pan.pointerId === event.pointerId) {\r\n setViewport({\r\n ...pan.orig,\r\n x: pan.orig.x + (event.clientX - pan.startX),\r\n y: pan.orig.y + (event.clientY - pan.startY),\r\n })\r\n return\r\n }\r\n const drag = dragRef.current\r\n if (drag !== null && drag.pointerId === event.pointerId) {\r\n setDrafts(prev => {\r\n const next = new Map(prev)\r\n next.set(drag.uuid, {\r\n x: drag.origX + (event.clientX - drag.startX) / viewport.scale,\r\n y: drag.origY + (event.clientY - drag.startY) / viewport.scale,\r\n })\r\n return next\r\n })\r\n }\r\n }\r\n\r\n const onSurfacePointerUp = (event: ReactPointerEvent<HTMLElement>): void => {\r\n const pan = panRef.current\r\n if (pan !== null && pan.pointerId === event.pointerId) {\r\n panRef.current = null\r\n return\r\n }\r\n const drag = dragRef.current\r\n if (drag !== null && drag.pointerId === event.pointerId) {\r\n dragRef.current = null\r\n const pos = drafts.get(drag.uuid)\r\n if (pos !== undefined && (pos.x !== drag.origX || pos.y !== drag.origY)) {\r\n void store.move(drag.uuid, pos.x, pos.y)\r\n // Intentionally do NOT delete the draft here. The draft keeps the\r\n // element pinned at the drop position until the WS push arrives\r\n // with the persisted snapshot. Deleting now would snap the element\r\n // back to its old position, then forward again when the push lands\r\n // — visible as a two-frame jitter. A cleanup effect below removes\r\n // the draft once the snapshot confirms the new position.\r\n }\r\n }\r\n }\r\n\r\n const onNodePointerDown = (event: ReactPointerEvent<HTMLElement>, el: AigcElement): void => {\r\n if (el.uuid === undefined) return\r\n event.stopPropagation()\r\n event.currentTarget.setPointerCapture(event.pointerId)\r\n dragRef.current = {\r\n pointerId: event.pointerId,\r\n uuid: el.uuid,\r\n startX: event.clientX,\r\n startY: event.clientY,\r\n origX: el.x,\r\n origY: el.y,\r\n }\r\n }\r\n\r\n // Right-click on a node → context menu with Delete.\r\n const onNodeContextMenu = (event: ReactMouseEvent<HTMLElement>, el: AigcElement): void => {\r\n if (el.uuid === undefined) return\r\n event.preventDefault()\r\n event.stopPropagation()\r\n setContextMenu({ x: event.clientX, y: event.clientY, uuid: el.uuid })\r\n }\r\n\r\n // Click anywhere → close the context menu.\r\n const onSurfaceClick = (event: ReactMouseEvent<HTMLElement>): void => {\r\n if (contextMenu !== undefined) {\r\n event.stopPropagation()\r\n setContextMenu(undefined)\r\n }\r\n }\r\n\r\n // Delete the element from the context menu.\r\n const onDeleteElement = (uuid: string): void => {\r\n setContextMenu(undefined)\r\n if (selected?.uuid === uuid) setSelected(undefined)\r\n void store.deleteElement(uuid)\r\n }\r\n\r\n // Drag-drop files onto the canvas surface.\r\n // stopPropagation() is critical: the canvas lives inside better-sidebar's\r\n // LeafView, whose onDragOver unconditionally calls preventDefault() and\r\n // shows a 5-zone layout overlay (without checking dataTransfer.types).\r\n // Without stopPropagation, file drags trigger that overlay and the drop\r\n // gets swallowed by the parent's onDrop.\r\n const onSurfaceDragOver = (event: React.DragEvent<HTMLElement>): void => {\r\n if (event.dataTransfer.types.includes('Files')) {\r\n event.preventDefault()\r\n event.stopPropagation()\r\n event.dataTransfer.dropEffect = 'copy'\r\n const rect = surfaceRef.current?.getBoundingClientRect()\r\n if (rect !== undefined) {\r\n const sx = event.clientX - rect.left\r\n const sy = event.clientY - rect.top\r\n // Convert screen → world coords.\r\n const wx = (sx - viewport.x) / viewport.scale\r\n const wy = (sy - viewport.y) / viewport.scale\r\n setDropTarget({ x: wx, y: wy })\r\n }\r\n }\r\n }\r\n\r\n const onSurfaceDragLeave = (event: React.DragEvent<HTMLElement>): void => {\r\n // Only clear if leaving the surface itself (not a child).\r\n if (event.currentTarget === event.target) {\r\n event.stopPropagation()\r\n setDropTarget(undefined)\r\n }\r\n }\r\n\r\n const onSurfaceDrop = async (event: React.DragEvent<HTMLElement>): Promise<void> => {\r\n event.preventDefault()\r\n event.stopPropagation()\r\n setDropTarget(undefined)\r\n const files = event.dataTransfer.files\r\n if (files.length === 0) return\r\n const rect = surfaceRef.current?.getBoundingClientRect()\r\n const sx = event.clientX - (rect?.left ?? 0)\r\n const sy = event.clientY - (rect?.top ?? 0)\r\n const wx = (sx - viewport.x) / viewport.scale\r\n const wy = (sy - viewport.y) / viewport.scale\r\n setUploading(true)\r\n try {\r\n for (const file of Array.from(files)) {\r\n const buf = await file.arrayBuffer()\r\n // Convert ArrayBuffer → base64 in chunks to avoid stack overflow\r\n // (String.fromCharCode(...spread) blows the call stack for large files).\r\n const bytes = new Uint8Array(buf)\r\n let binary = ''\r\n const chunk = 0x8000\r\n for (let i = 0; i < bytes.length; i += chunk) {\r\n binary += String.fromCharCode(...bytes.subarray(i, i + chunk))\r\n }\r\n const mediaBase64 = btoa(binary)\r\n await store.uploadFile(file.name, mediaBase64, { x: wx, y: wy })\r\n }\r\n } finally {\r\n setUploading(false)\r\n }\r\n }\r\n\r\n const lookup = elementMap(state.elements)\r\n // Position resolver that checks drafts first (live drag position) then\r\n // falls back to the element's persisted position. Used by both the node\r\n // boxes and the edge renderer so connections follow dragged nodes in\r\n // real time — not only after the drag ends.\r\n const resolvePos: PosResolver = (uuid: string) => {\r\n const draft = drafts.get(uuid)\r\n if (draft !== undefined) return draft\r\n const el = lookup.get(uuid)\r\n if (el !== undefined) return { x: el.x, y: el.y }\r\n return undefined\r\n }\r\n const posOf = (el: AigcElement): { x: number; y: number } => {\r\n if (el.uuid !== undefined) {\r\n const draft = drafts.get(el.uuid)\r\n if (draft !== undefined) return draft\r\n }\r\n return { x: el.x, y: el.y }\r\n }\r\n\r\n return createElement(\r\n 'div',\r\n { className: css.canvas },\r\n createElement(\r\n 'div',\r\n { className: css.header },\r\n createElement('span', { className: css.title }, t('title')),\r\n createElement('span', { className: css.count }, `${state.elements.length} ${t('elementCount')}`),\r\n createElement('span', { className: css.count }, `${state.edges.length} ${t('edgeCount')}`),\r\n createElement('span', { className: css.zoom }, `${Math.round(viewport.scale * 100)}%`),\r\n createElement('button', {\r\n type: 'button',\r\n className: css.iconButton,\r\n onClick: () => zoomToCenter(viewport.scale * 0.8),\r\n title: t('zoomOut'),\r\n 'aria-label': t('zoomOut'),\r\n }, '−'),\r\n createElement('input', {\r\n type: 'range',\r\n className: css.zoomSlider,\r\n min: Math.round(MIN_SCALE * 100),\r\n max: Math.round(MAX_SCALE * 100),\r\n value: Math.round(viewport.scale * 100),\r\n onChange: (e: ReactChangeEvent<HTMLInputElement>) => zoomToCenter(Number(e.target.value) / 100),\r\n 'aria-label': t('zoom'),\r\n }),\r\n createElement('button', {\r\n type: 'button',\r\n className: css.iconButton,\r\n onClick: () => zoomToCenter(viewport.scale * 1.25),\r\n title: t('zoomIn'),\r\n 'aria-label': t('zoomIn'),\r\n }, '+'),\r\n createElement(\r\n 'button',\r\n {\r\n type: 'button',\r\n className: css.iconButton,\r\n onClick: () => { void store.refresh() },\r\n title: t('refresh'),\r\n 'aria-label': t('refresh'),\r\n },\r\n '↻',\r\n ),\r\n createElement(\r\n 'button',\r\n {\r\n type: 'button',\r\n className: css.iconButton,\r\n onClick: () => setViewport({ x: 0, y: 0, scale: 1 }),\r\n title: t('resetView'),\r\n 'aria-label': t('resetView'),\r\n },\r\n '⤢',\r\n ),\r\n ),\r\n createElement(\r\n 'div',\r\n {\r\n className: css.surface,\r\n ref: surfaceRef,\r\n onPointerDown: onSurfacePointerDown,\r\n onPointerMove: onSurfacePointerMove,\r\n onPointerUp: onSurfacePointerUp,\r\n onPointerCancel: onSurfacePointerUp,\r\n onDoubleClick: () => setSelected(undefined),\r\n onClick: onSurfaceClick,\r\n onContextMenu: (event: ReactMouseEvent<HTMLElement>) => {\r\n // Right-click on empty background → prevent default browser menu.\r\n event.preventDefault()\r\n },\r\n onDragOver: onSurfaceDragOver,\r\n onDragLeave: onSurfaceDragLeave,\r\n onDrop: (event: React.DragEvent<HTMLElement>) => { void onSurfaceDrop(event) },\r\n },\r\n state.elements.length === 0\r\n ? createElement('div', { className: css.empty }, createElement('span', null, t('empty')), createElement('span', { className: css.emptyHint }, t('emptyHint')))\r\n : createElement(\r\n 'div',\r\n {\r\n className: css.world,\r\n style: {\r\n transform: `translate(${viewport.x}px, ${viewport.y}px) scale(${viewport.scale})`,\r\n // Expose the current zoom to descendants so media elements\r\n // (img/video) can counter-scale: they set their CSS width to\r\n // `100% * scale` (so the browser decodes at the larger screen\r\n // resolution instead of the layout width), then transform\r\n // `scale(1/scale)` to visually shrink back to the layout box.\r\n // Without this, zooming in shows blurry media because the\r\n // browser decodes the image at the small layout size and the\r\n // world transform upscales the bitmap.\r\n ['--canvas-scale' as string]: viewport.scale,\r\n } as CSSProperties,\r\n },\r\n createElement(\r\n 'svg',\r\n {\r\n className: css.edgeLayer,\r\n 'aria-hidden': true,\r\n },\r\n ...state.edges.map(edge => renderEdge(edge, resolvePos)),\r\n ),\r\n ...state.elements.map(el => {\r\n const pos = posOf(el)\r\n return createElement(\r\n 'div',\r\n {\r\n key: el.uuid ?? el.filePath,\r\n className: `${css.nodeBox} ${el.uuid !== undefined ? css.nodeBoxDraggable : ''}`,\r\n style: { transform: `translate(${pos.x}px, ${pos.y}px)` },\r\n onPointerDown: event => onNodePointerDown(event, el),\r\n onDoubleClick: (event: ReactMouseEvent<HTMLElement>) => {\r\n event.stopPropagation()\r\n setSelected(el)\r\n },\r\n onContextMenu: event => onNodeContextMenu(event, el),\r\n },\r\n createElement(CanvasNode, { element: el, t }),\r\n )\r\n }),\r\n ),\r\n // Drop indicator: shows where the dropped file will land (world coords).\r\n dropTarget !== undefined\r\n ? createElement('div', {\r\n className: css.dropIndicator,\r\n style: {\r\n transform: `translate(${dropTarget.x * viewport.scale + viewport.x}px, ${dropTarget.y * viewport.scale + viewport.y}px) scale(${viewport.scale})`,\r\n },\r\n })\r\n : null,\r\n // Upload overlay\r\n uploading\r\n ? createElement('div', { className: css.uploadOverlay }, t('uploading'))\r\n : null,\r\n ),\r\n selected !== undefined\r\n ? createElement(DetailPanel, { element: selected, t, onClose: () => setSelected(undefined) })\r\n : null,\r\n // Right-click context menu\r\n contextMenu !== undefined\r\n ? createElement(ContextMenu, {\r\n x: contextMenu.x,\r\n y: contextMenu.y,\r\n items: [\r\n { label: t('delete'), onClick: () => onDeleteElement(contextMenu.uuid) },\r\n ],\r\n onClose: () => setContextMenu(undefined),\r\n })\r\n : null,\r\n // Minimap: bottom-right overview showing element outlines + viewport frame.\r\n state.elements.length > 0\r\n ? createElement(Minimap, {\r\n elements: state.elements,\r\n viewport,\r\n surfaceSize,\r\n setViewport,\r\n })\r\n : null,\r\n )\r\n}\r\n\r\n/** A minimal fixed-position context menu (right-click). */\r\nfunction ContextMenu(props: {\r\n x: number\r\n y: number\r\n items: Array<{ label: string; onClick: () => void }>\r\n onClose: () => void\r\n}): ReactNode {\r\n // Close on any outside click or Escape.\r\n useEffect(() => {\r\n const onDown = (): void => props.onClose()\r\n const onKey = (e: KeyboardEvent): void => { if (e.key === 'Escape') props.onClose() }\r\n window.addEventListener('pointerdown', onDown, { once: true })\r\n window.addEventListener('keydown', onKey, { once: true })\r\n return () => {\r\n window.removeEventListener('pointerdown', onDown)\r\n window.removeEventListener('keydown', onKey)\r\n }\r\n }, [props])\r\n return createElement(\r\n 'div',\r\n {\r\n className: css.contextMenu,\r\n style: { left: props.x, top: props.y },\r\n // Stop the outside-click handler from firing on the menu itself.\r\n onPointerDown: (e: ReactPointerEvent<HTMLElement>) => e.stopPropagation(),\r\n },\r\n ...props.items.map((item, i) =>\r\n createElement('button', {\r\n key: i,\r\n type: 'button',\r\n className: css.contextMenuItem,\r\n onClick: () => { item.onClick() },\r\n }, item.label),\r\n ),\r\n )\r\n}\r\n\r\n/** The double-click detail panel: prompt + generation params + path. */\r\nfunction DetailPanel({ element, t, onClose }: { element: AigcElement; t: Translate; onClose: () => void }): ReactNode {\r\n // Defensive: meta may have been persisted as a string by an older build\r\n // or sneak through the schema as a non-object. Only render entries when\r\n // we have a real plain object; otherwise show the raw value (if primitive)\r\n // or skip the section entirely.\r\n const meta = element.meta\r\n const metaEntries: Array<[string, unknown]> = Array.isArray(meta) || meta === null || typeof meta !== 'object'\r\n ? []\r\n : Object.entries(meta as Record<string, unknown>)\r\n return createElement(\r\n 'div',\r\n { className: css.detailPanel },\r\n createElement(\r\n 'div',\r\n { className: css.detailHeader },\r\n createElement('span', { className: css.detailTitle }, element.title),\r\n createElement('button', { type: 'button', className: css.detailClose, onClick: onClose, 'aria-label': t('detailClose') }, '×'),\r\n ),\r\n createElement(\r\n 'div',\r\n { className: css.detailBody },\r\n element.promptText !== undefined\r\n ? createElement(\r\n 'div',\r\n { className: css.detailBlock },\r\n createElement('span', { className: css.detailLabel }, t('detailPrompt')),\r\n createElement('pre', { className: css.detailPrompt }, element.promptText),\r\n )\r\n : null,\r\n metaEntries.length > 0\r\n ? createElement(\r\n 'div',\r\n { className: css.detailBlock },\r\n createElement('span', { className: css.detailLabel }, t('detailParams')),\r\n createElement(\r\n 'dl',\r\n { className: css.metaList },\r\n ...metaEntries.flatMap(([k, v]) => [\r\n createElement('dt', { key: `${k}-k`, className: css.metaKey }, k),\r\n createElement('dd', { key: `${k}-v`, className: css.metaValue }, formatMetaValue(v)),\r\n ]),\r\n ),\r\n )\r\n : null,\r\n createElement(\r\n 'div',\r\n { className: css.detailBlock },\r\n createElement('span', { className: css.detailLabel }, t('generatedBy')),\r\n createElement('span', { className: css.detailValue }, element.producedBy),\r\n ),\r\n createElement(\r\n 'div',\r\n { className: css.detailBlock },\r\n createElement('span', { className: css.detailLabel }, t('detailPosition')),\r\n createElement('span', { className: css.detailValue }, `(${Math.round(element.x)}, ${Math.round(element.y)})`),\r\n ),\r\n createElement(\r\n 'div',\r\n { className: css.detailBlock },\r\n createElement('span', { className: css.detailLabel }, t('detailPath')),\r\n createElement('code', { className: css.filePath }, element.filePath),\r\n ),\r\n ),\r\n )\r\n}\r\n\r\nfunction formatMetaValue(v: unknown): string {\r\n if (typeof v === 'string') return v\r\n if (typeof v === 'number' || typeof v === 'boolean') return String(v)\r\n if (v === null || v === undefined) return ''\r\n try { return JSON.stringify(v) } catch { return String(v) }\r\n}\r\n\r\n// ── Minimap ──────────────────────────────────────────────────────────────\r\n\r\nconst MINIMAP_W = 168\r\nconst MINIMAP_H = 120\r\nconst MINIMAP_PAD = 6\r\n\r\n/** Color dot per element kind in the minimap. */\r\nconst KIND_COLOR: Record<AigcElement['kind'], string> = {\r\n image: '#4caf50',\r\n video: '#ff9800',\r\n audio: '#ab47bc',\r\n prompt: '#6b8cff',\r\n}\r\n\r\n/**\r\n * Bottom-right minimap: shows all elements as small colored rectangles and\r\n * the current viewport as a frame. Click/drag to pan the viewport.\r\n */\r\nfunction Minimap(props: {\r\n elements: readonly AigcElement[]\r\n viewport: Viewport\r\n surfaceSize: { width: number; height: number }\r\n setViewport: (fn: (prev: Viewport) => Viewport) => void\r\n}): ReactNode {\r\n const { elements, viewport, surfaceSize, setViewport } = props\r\n const minimapRef = useRef<HTMLDivElement | null>(null)\r\n\r\n // Compute world bounding box: union of all elements + the current viewport.\r\n let minX = Infinity\r\n let minY = Infinity\r\n let maxX = -Infinity\r\n let maxY = -Infinity\r\n for (const el of elements) {\r\n minX = Math.min(minX, el.x)\r\n minY = Math.min(minY, el.y)\r\n maxX = Math.max(maxX, el.x + NODE_W)\r\n maxY = Math.max(maxY, el.y + NODE_H)\r\n }\r\n if (surfaceSize.width > 0 && surfaceSize.height > 0) {\r\n const vpMinX = -viewport.x / viewport.scale\r\n const vpMinY = -viewport.y / viewport.scale\r\n const vpMaxX = vpMinX + surfaceSize.width / viewport.scale\r\n const vpMaxY = vpMinY + surfaceSize.height / viewport.scale\r\n minX = Math.min(minX, vpMinX)\r\n minY = Math.min(minY, vpMinY)\r\n maxX = Math.max(maxX, vpMaxX)\r\n maxY = Math.max(maxY, vpMaxY)\r\n }\r\n // Guard against empty (shouldn't happen — caller checks, but be safe).\r\n if (!Number.isFinite(minX) || !Number.isFinite(maxX)) return null\r\n // Add a small padding around the content.\r\n minX -= 40\r\n minY -= 40\r\n maxX += 40\r\n maxY += 40\r\n const worldW = maxX - minX\r\n const worldH = maxY - minY\r\n const miniScale = Math.min(\r\n (MINIMAP_W - MINIMAP_PAD * 2) / worldW,\r\n (MINIMAP_H - MINIMAP_PAD * 2) / worldH,\r\n )\r\n const offsetX = (MINIMAP_W - worldW * miniScale) / 2\r\n const offsetY = (MINIMAP_H - worldH * miniScale) / 2\r\n const toMiniX = (wx: number): number => offsetX + (wx - minX) * miniScale\r\n const toMiniY = (wy: number): number => offsetY + (wy - minY) * miniScale\r\n\r\n // Viewport frame in minimap coords.\r\n const vpX = toMiniX(-viewport.x / viewport.scale)\r\n const vpY = toMiniY(-viewport.y / viewport.scale)\r\n const vpW = (surfaceSize.width / viewport.scale) * miniScale\r\n const vpH = (surfaceSize.height / viewport.scale) * miniScale\r\n\r\n // Click/drag on minimap → center the viewport on the clicked world point.\r\n const onPointerDown = (event: ReactPointerEvent<HTMLDivElement>): void => {\r\n event.stopPropagation()\r\n event.currentTarget.setPointerCapture(event.pointerId)\r\n const pan = (clientX: number, clientY: number): void => {\r\n const rect = minimapRef.current?.getBoundingClientRect()\r\n if (rect === undefined) return\r\n const mx = clientX - rect.left\r\n const my = clientY - rect.top\r\n // Convert minimap coords → world coords.\r\n const worldX = (mx - offsetX) / miniScale + minX\r\n const worldY = (my - offsetY) / miniScale + minY\r\n // Center viewport on this world point.\r\n setViewport(prev => ({\r\n ...prev,\r\n x: surfaceSize.width / 2 - worldX * prev.scale,\r\n y: surfaceSize.height / 2 - worldY * prev.scale,\r\n }))\r\n }\r\n pan(event.clientX, event.clientY)\r\n const onMove = (e: PointerEvent): void => pan(e.clientX, e.clientY)\r\n const onUp = (): void => {\r\n window.removeEventListener('pointermove', onMove)\r\n window.removeEventListener('pointerup', onUp)\r\n }\r\n window.addEventListener('pointermove', onMove)\r\n window.addEventListener('pointerup', onUp)\r\n }\r\n\r\n return createElement(\r\n 'div',\r\n {\r\n className: css.minimap,\r\n ref: minimapRef,\r\n onPointerDown,\r\n },\r\n createElement(\r\n 'svg',\r\n { width: MINIMAP_W, height: MINIMAP_H, className: css.minimapSvg },\r\n // Element rectangles.\r\n ...elements.map(el =>\r\n createElement('rect', {\r\n key: el.uuid ?? el.filePath,\r\n x: toMiniX(el.x),\r\n y: toMiniY(el.y),\r\n width: Math.max(2, NODE_W * miniScale),\r\n height: Math.max(2, NODE_H * miniScale),\r\n rx: 2,\r\n fill: KIND_COLOR[el.kind],\r\n fillOpacity: 0.35,\r\n stroke: KIND_COLOR[el.kind],\r\n strokeOpacity: 0.7,\r\n strokeWidth: 1,\r\n }),\r\n ),\r\n // Viewport frame: a semi-transparent fill + solid border so it's\r\n // clearly visible against the element rectangles.\r\n createElement('rect', {\r\n x: vpX,\r\n y: vpY,\r\n width: vpW,\r\n height: vpH,\r\n fill: 'var(--dsw-alias-label-primary)',\r\n fillOpacity: 0.08,\r\n stroke: 'var(--dsw-alias-label-primary)',\r\n strokeOpacity: 0.8,\r\n strokeWidth: 2,\r\n rx: 2,\r\n }),\r\n ),\r\n )\r\n}\r\n\r\n/** Wrapped export so the tab component can mount the boundary once. */\r\nexport function CanvasViewWithBoundary(props: CanvasViewProps): ReactNode {\r\n return createElement(CanvasBoundary, { t: props.t, children: createElement(CanvasView, props) })\r\n}\r\n","/**\r\n * SettingsPage — the AIGC canvas settings section: provider list CRUD.\r\n *\r\n * Visual language: matches ModelsSection / GeneralSection / yet-another-subagent —\r\n * outlined rowCard per provider (border-l2, r12, p12/14), filled editor surface\r\n * (bg-module-platform, r12, p14/16), capsule controls (h36 r18 primary,\r\n * h28 r14 secondary), 32px fields with border-l2 / bg-layer-1, 12/18 caption\r\n * labels. Every color resolves through --dsw-alias-* tokens.\r\n *\r\n * Each provider card is collapsible (chevron in the row head); the editor\r\n * surface is hidden when collapsed. Builtin providers (cordis.yml seed) carry\r\n * a `builtin`/`内置` badge next to the title. The \"+ Add provider\" button at\r\n * the bottom reveals an inline draft card with all fields editable (including\r\n * id) and Create / Cancel actions.\r\n *\r\n * Real providers carry an \"initialize\" (初始化) action: it sends a prepared\r\n * message to the current conversation so the agent probes the API with\r\n * aigc_http_request and records the usage instructions via\r\n * aigc_provider_set_instructions. The editor also exposes the auth scheme\r\n * (bearer / custom header / query param) the aigc_http_request tool uses to\r\n * attach the apiKey.\r\n *\r\n * @module @huanlin/dsh-plugin-aigc-canvas/client/SettingsPage\r\n */\r\n\r\nimport { useCallback, useEffect, useState } from 'react'\r\nimport { Modal, Pill } from '@deepseek-ai/dsh-client-ui-primitives'\r\nimport type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\r\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\r\nimport {\r\n addProvider,\r\n fetchConfig,\r\n removeProvider,\r\n updateProvider,\r\n type RuntimeProvider,\r\n} from './api.js'\r\nimport css from './SettingsPage.module.css'\r\n\r\n/** Inject face: locale translate + conversation send (for the init action). */\r\nexport interface AigcSettingsInjected {\r\n readonly t: (key: string) => string\r\n /** Send a prompt into the current conversation scope (queued turn). */\r\n readonly send: (text: string) => Promise<void>\r\n}\r\n\r\n/** Full props: settings.section runtime share + locale seat + inject. */\r\ntype SettingsPageProps = PropsRuntime<'settings.section'> & PropsLocale<'dsh-aigc-canvas'> & AigcSettingsInjected\r\n\r\n/** Default shape for a brand-new draft (before the user fills in id/name). */\r\nfunction emptyDraft(): RuntimeProvider {\r\n return { id: '', name: '', endpoint: 'stub://aigc-backend', apiKey: '', instructions: '', auth: { scheme: 'bearer', name: '' }, builtin: false }\r\n}\r\n\r\n/**\r\n * Render the AIGC provider settings page.\r\n * @param props - settings.section runtime share + locale + inject.\r\n * @returns the page element.\r\n */\r\nexport function SettingsPage({ t, send }: SettingsPageProps) {\r\n const [providers, setProviders] = useState<readonly RuntimeProvider[]>([])\r\n const [drafts, setDrafts] = useState<readonly RuntimeProvider[]>([])\r\n const [expanded, setExpanded] = useState<ReadonlySet<string>>(new Set())\r\n const [addingNew, setAddingNew] = useState(false)\r\n const [newDraft, setNewDraft] = useState<RuntimeProvider>(emptyDraft())\r\n const [loading, setLoading] = useState(true)\r\n const [error, setError] = useState<string | undefined>(undefined)\r\n const [confirmDelete, setConfirmDelete] = useState<string | undefined>(undefined)\r\n\r\n const refresh = useCallback(async () => {\r\n setLoading(true)\r\n setError(undefined)\r\n try {\r\n const result = await fetchConfig()\r\n setProviders(result.providers)\r\n setDrafts(result.providers.map(p => ({ ...p, auth: { ...p.auth } })))\r\n } catch (err) {\r\n setError(err instanceof Error ? err.message : String(err))\r\n } finally {\r\n setLoading(false)\r\n }\r\n }, [])\r\n\r\n useEffect(() => { void refresh() }, [refresh])\r\n\r\n const add = useCallback(async () => {\r\n if (newDraft.id === '') return\r\n try {\r\n const result = await addProvider(newDraft)\r\n setProviders(result.providers)\r\n setDrafts(result.providers.map(p => ({ ...p, auth: { ...p.auth } })))\r\n setExpanded(new Set([...expanded, newDraft.id]))\r\n setAddingNew(false)\r\n setNewDraft(emptyDraft())\r\n } catch (err) {\r\n setError(err instanceof Error ? err.message : String(err))\r\n }\r\n }, [expanded, newDraft])\r\n\r\n const update = useCallback(async (draft: RuntimeProvider) => {\r\n try {\r\n const result = await updateProvider(draft)\r\n setProviders(result.providers)\r\n setDrafts(result.providers.map(p => ({ ...p, auth: { ...p.auth } })))\r\n } catch (err) {\r\n setError(err instanceof Error ? err.message : String(err))\r\n }\r\n }, [])\r\n\r\n const remove = useCallback(async (id: string) => {\r\n try {\r\n const result = await removeProvider(id)\r\n setProviders(result.providers)\r\n setDrafts(result.providers.map(p => ({ ...p, auth: { ...p.auth } })))\r\n const next = new Set(expanded)\r\n next.delete(id)\r\n setExpanded(next)\r\n } catch (err) {\r\n setError(err instanceof Error ? err.message : String(err))\r\n }\r\n }, [expanded])\r\n\r\n const init = useCallback(async (provider: RuntimeProvider) => {\r\n const label = provider.name === '' ? provider.id : provider.name\r\n const text = t('row.initPrompt').replace('{name}', label).replace('{id}', provider.id)\r\n try {\r\n await send(text)\r\n } catch (err) {\r\n setError(err instanceof Error ? err.message : String(err))\r\n }\r\n }, [send, t])\r\n\r\n const patchDraft = (id: string, patch: Partial<RuntimeProvider>): void => {\r\n setDrafts(prev => prev.map(d => (d.id === id ? { ...d, ...patch } : d)))\r\n }\r\n\r\n const toggleExpand = (id: string): void => {\r\n const next = new Set(expanded)\r\n if (next.has(id)) next.delete(id)\r\n else next.add(id)\r\n setExpanded(next)\r\n }\r\n\r\n const cancelNew = (): void => {\r\n setAddingNew(false)\r\n setNewDraft(emptyDraft())\r\n }\r\n\r\n const defaultId = providers.length > 0 ? providers[0]?.id : undefined\r\n\r\n return (\r\n <section className={css.section}>\r\n <h2 className={css.title}>{t('settingsTitle')}</h2>\r\n <p className={css.intro}>{t('settingsIntro')}</p>\r\n {error !== undefined && (\r\n <div className={css.error}>\r\n {error}\r\n <button type=\"button\" className={css.errorDismiss} onClick={() => setError(undefined)}>×</button>\r\n </div>\r\n )}\r\n {loading ? (\r\n <div className={css.loading}>{t('settingsLoading')}</div>\r\n ) : providers.length === 0 && !addingNew ? (\r\n <p className={css.empty}>{t('settingsEmpty')}</p>\r\n ) : (\r\n <ul className={css.rows}>\r\n {drafts.map(draft => (\r\n <ProviderCard\r\n key={draft.id}\r\n draft={draft}\r\n expanded={expanded.has(draft.id)}\r\n isDefault={draft.id === defaultId}\r\n t={t}\r\n onToggle={() => toggleExpand(draft.id)}\r\n onPatch={patch => patchDraft(draft.id, patch)}\r\n onSave={() => void update(draft)}\r\n onDelete={() => setConfirmDelete(draft.id)}\r\n onInit={() => void init(draft)}\r\n />\r\n ))}\r\n {addingNew && (\r\n <ProviderCard\r\n key=\"__new__\"\r\n draft={newDraft}\r\n expanded={true}\r\n isNew={true}\r\n isDefault={false}\r\n t={t}\r\n onPatch={patch => setNewDraft(prev => ({ ...prev, ...patch }))}\r\n onCreate={() => void add()}\r\n onCancel={cancelNew}\r\n />\r\n )}\r\n </ul>\r\n )}\r\n {!loading && !addingNew && (\r\n <button type=\"button\" className={css.addBlockButton} onClick={() => setAddingNew(true)}>\r\n {t('settingsAdd')}\r\n </button>\r\n )}\r\n <Modal\r\n open={confirmDelete !== undefined}\r\n onClose={() => { setConfirmDelete(undefined) }}\r\n title={t('row.deleteConfirm')}\r\n footer={(\r\n <>\r\n <button type=\"button\" className={css.secondaryButton} onClick={() => { setConfirmDelete(undefined) }}>\r\n {t('row.cancel')}\r\n </button>\r\n <button\r\n type=\"button\"\r\n className={css.dangerButton}\r\n onClick={() => {\r\n if (confirmDelete !== undefined) void remove(confirmDelete)\r\n setConfirmDelete(undefined)\r\n }}\r\n >\r\n {t('row.delete')}\r\n </button>\r\n </>\r\n )}\r\n >\r\n <p className={css.confirmText}>{t('row.deleteConfirm')}</p>\r\n </Modal>\r\n </section>\r\n )\r\n}\r\n\r\n// ─── ProviderCard ─────────────────────────────────────────────────────────────\r\n\r\ninterface ProviderCardProps {\r\n readonly draft: RuntimeProvider\r\n readonly expanded: boolean\r\n readonly isNew?: boolean\r\n readonly isDefault: boolean\r\n readonly t: (key: string) => string\r\n readonly onToggle?: () => void\r\n readonly onPatch: (patch: Partial<RuntimeProvider>) => void\r\n readonly onSave?: () => void\r\n readonly onDelete?: () => void\r\n readonly onCreate?: () => void\r\n readonly onCancel?: () => void\r\n readonly onInit?: () => void\r\n}\r\n\r\nfunction ProviderCard({ draft, expanded, isNew, isDefault, t, onToggle, onPatch, onSave, onDelete, onCreate, onCancel, onInit }: ProviderCardProps) {\r\n const isStub = draft.endpoint === '' || draft.endpoint === 'stub://aigc-backend'\r\n const patchAuth = (patch: Partial<{ scheme: 'bearer' | 'header' | 'query'; name: string }>): void => {\r\n onPatch({ auth: { ...draft.auth, ...patch } })\r\n }\r\n return (\r\n <li className={css.rowCard}>\r\n <div className={css.rowHead}>\r\n {!isNew && onToggle !== undefined && (\r\n <button type=\"button\" className={css.chevronButton} onClick={onToggle} aria-label={expanded ? t('row.collapse') : t('row.expand')}>\r\n <span className={expanded ? `${css.chevron} ${css.chevronExpanded}` : css.chevron} aria-hidden=\"true\" />\r\n </button>\r\n )}\r\n {isNew && <span className={css.chevronSpacer} aria-hidden=\"true\" />}\r\n <div className={css.rowIdentity}>\r\n {isNew ? (\r\n <span className={css.rowNamePlaceholder}>{t('settingsAdd')}</span>\r\n ) : (\r\n <span className={css.rowName}>{draft.name === '' ? draft.id : draft.name}</span>\r\n )}\r\n {draft.builtin && <Pill className={css.builtinBadge}>{t('badge.builtin')}</Pill>}\r\n {isDefault && !isNew && <Pill className={css.defaultBadge}>{t('badge.default')}</Pill>}\r\n <Pill className={isStub ? css.stubBadge : css.realBadge}>\r\n {isStub ? t('badge.stub') : t('badge.real')}\r\n </Pill>\r\n {!isNew && <code className={css.rowId}>{draft.id}</code>}\r\n </div>\r\n <div className={css.rowActions}>\r\n {isNew ? (\r\n <>\r\n <button type=\"button\" className={css.primaryButton} onClick={onCreate} disabled={draft.id === ''}>\r\n {t('row.create')}\r\n </button>\r\n <button type=\"button\" className={css.secondaryButton} onClick={onCancel}>\r\n {t('row.cancel')}\r\n </button>\r\n </>\r\n ) : (\r\n <>\r\n {!isStub && onInit !== undefined && (\r\n <button type=\"button\" className={css.secondaryButton} onClick={onInit}>\r\n {t('row.init')}\r\n </button>\r\n )}\r\n <button type=\"button\" className={css.secondaryButton} onClick={onSave}>\r\n {t('row.save')}\r\n </button>\r\n <button type=\"button\" className={css.dangerButton} onClick={onDelete}>\r\n {t('row.delete')}\r\n </button>\r\n </>\r\n )}\r\n </div>\r\n </div>\r\n {expanded && (\r\n <div className={css.editor}>\r\n {isNew && (\r\n <>\r\n <label className={css.field}>\r\n <span className={css.fieldLabel}>{t('row.id')}</span>\r\n <input\r\n className={css.input}\r\n value={draft.id}\r\n placeholder={t('row.idPlaceholder')}\r\n onChange={e => onPatch({ id: e.target.value })}\r\n />\r\n <span className={css.hint}>{t('row.idHint')}</span>\r\n </label>\r\n <label className={css.field}>\r\n <span className={css.fieldLabel}>{t('row.name')}</span>\r\n <input\r\n className={css.input}\r\n value={draft.name}\r\n placeholder={t('row.namePlaceholder')}\r\n onChange={e => onPatch({ name: e.target.value })}\r\n />\r\n </label>\r\n </>\r\n )}\r\n {!isNew && (\r\n <label className={css.field}>\r\n <span className={css.fieldLabel}>{t('row.name')}</span>\r\n <input\r\n className={css.input}\r\n value={draft.name}\r\n placeholder={t('row.namePlaceholder')}\r\n onChange={e => onPatch({ name: e.target.value })}\r\n />\r\n </label>\r\n )}\r\n <label className={css.field}>\r\n <span className={css.fieldLabel}>{t('row.endpoint')}</span>\r\n <input\r\n className={css.input}\r\n value={draft.endpoint}\r\n placeholder={t('row.endpointPlaceholder')}\r\n onChange={e => onPatch({ endpoint: e.target.value })}\r\n />\r\n <span className={css.desc}>{t('row.endpointDesc')}</span>\r\n </label>\r\n <label className={css.field}>\r\n <span className={css.fieldLabel}>{t('row.apiKey')}</span>\r\n <input\r\n className={css.input}\r\n type=\"password\"\r\n autoComplete=\"off\"\r\n value={draft.apiKey}\r\n placeholder={t('row.apiKeyPlaceholder')}\r\n onChange={e => onPatch({ apiKey: e.target.value })}\r\n />\r\n <span className={css.desc}>{t('row.apiKeyDesc')}</span>\r\n </label>\r\n <div className={css.field}>\r\n <span className={css.fieldLabel}>{t('row.auth')}</span>\r\n <div className={css.authRow}>\r\n <select\r\n className={css.select}\r\n value={draft.auth.scheme}\r\n onChange={e => patchAuth({ scheme: e.target.value as 'bearer' | 'header' | 'query' })}\r\n >\r\n <option value=\"bearer\">{t('row.authBearer')}</option>\r\n <option value=\"header\">{t('row.authHeader')}</option>\r\n <option value=\"query\">{t('row.authQuery')}</option>\r\n </select>\r\n {draft.auth.scheme !== 'bearer' && (\r\n <input\r\n className={css.input}\r\n value={draft.auth.name}\r\n placeholder={draft.auth.scheme === 'header' ? 'x-api-key' : 'api_key'}\r\n onChange={e => patchAuth({ name: e.target.value })}\r\n />\r\n )}\r\n </div>\r\n <span className={css.desc}>{t('row.authDesc')}</span>\r\n </div>\r\n <label className={css.field}>\r\n <span className={css.fieldLabel}>{t('row.instructions')}</span>\r\n <textarea\r\n className={css.textarea}\r\n value={draft.instructions}\r\n placeholder={t('row.instructionsPlaceholder')}\r\n rows={8}\r\n onChange={e => onPatch({ instructions: e.target.value })}\r\n />\r\n <span className={css.desc}>{t('row.instructionsDesc')}</span>\r\n <span className={css.hint}>{t('row.instructionsHint')}</span>\r\n </label>\r\n </div>\r\n )}\r\n </li>\r\n )\r\n}\r\n","/**\r\n * i18n dictionaries for the AIGC canvas plugin.\r\n *\r\n * @module @huanlin/dsh-plugin-aigc-canvas/client/locales\r\n */\r\n\r\nexport const NS = 'dsh-aigc-canvas' as const\r\n\r\nexport type AigcKey =\r\n // Canvas view\r\n | 'tabTitle'\r\n | 'title'\r\n | 'empty'\r\n | 'emptyHint'\r\n | 'prompt'\r\n | 'image'\r\n | 'video'\r\n | 'audio'\r\n | 'meta'\r\n | 'generatedBy'\r\n | 'edgeCount'\r\n | 'elementCount'\r\n | 'loadError'\r\n | 'disconnected'\r\n | 'reconnecting'\r\n | 'refresh'\r\n | 'resetView'\r\n | 'zoom'\r\n | 'zoomIn'\r\n | 'zoomOut'\r\n | 'detailClose'\r\n | 'detailPrompt'\r\n | 'detailParams'\r\n | 'detailPosition'\r\n | 'detailPath'\r\n | 'delete'\r\n | 'deleteElement'\r\n | 'dropHint'\r\n | 'uploading'\r\n // Settings — page chrome\r\n | 'settingsNav'\r\n | 'settingsTitle'\r\n | 'settingsIntro'\r\n | 'settingsEmpty'\r\n | 'settingsAdd'\r\n | 'settingsLoading'\r\n | 'settingsError'\r\n // Settings — provider card\r\n | 'row.id'\r\n | 'row.name'\r\n | 'row.endpoint'\r\n | 'row.apiKey'\r\n | 'row.instructions'\r\n | 'row.idPlaceholder'\r\n | 'row.namePlaceholder'\r\n | 'row.endpointPlaceholder'\r\n | 'row.apiKeyPlaceholder'\r\n | 'row.instructionsPlaceholder'\r\n | 'row.idHint'\r\n | 'row.endpointDesc'\r\n | 'row.apiKeyDesc'\r\n | 'row.instructionsDesc'\r\n | 'row.instructionsHint'\r\n | 'row.save'\r\n | 'row.delete'\r\n | 'row.deleteConfirm'\r\n | 'row.expand'\r\n | 'row.collapse'\r\n | 'row.create'\r\n | 'row.cancel'\r\n | 'row.init'\r\n | 'row.initPrompt'\r\n | 'row.auth'\r\n | 'row.authBearer'\r\n | 'row.authHeader'\r\n | 'row.authQuery'\r\n | 'row.authDesc'\r\n | 'badge.builtin'\r\n | 'badge.stub'\r\n | 'badge.real'\r\n | 'badge.default'\r\n\r\nexport const zh: Record<AigcKey, string> = {\r\n tabTitle: 'AIGC 画布',\r\n title: 'AIGC 画布',\r\n empty: '画布是空的。模型通过 aigc_http_request 调用供应商 API 生成素材,再用 aigc_canvas_place 把文件放到画布的任意位置。',\r\n emptyHint: '可在右侧设置页配置供应商,然后让模型开始生成。',\r\n prompt: '提示词',\r\n image: '图片',\r\n video: '视频',\r\n audio: '音频',\r\n meta: '元信息',\r\n generatedBy: '生成方式',\r\n edgeCount: '条连线',\r\n elementCount: '个元素',\r\n loadError: '加载画布失败',\r\n disconnected: '已断开,正在重连…',\r\n reconnecting: '正在重连…',\r\n refresh: '刷新',\r\n resetView: '重置视图',\r\n zoom: '缩放',\r\n zoomIn: '放大',\r\n zoomOut: '缩小',\r\n detailClose: '关闭',\r\n detailPrompt: '提示词',\r\n detailParams: '生成参数',\r\n detailPosition: '位置',\r\n detailPath: '文件路径',\r\n delete: '删除',\r\n deleteElement: '删除元素',\r\n dropHint: '拖放文件到画布',\r\n uploading: '上传中…',\r\n settingsNav: 'AIGC 画布',\r\n settingsTitle: 'AIGC 供应商',\r\n settingsIntro: '配置一个或多个 AIGC 供应商。每个供应商可独立设置名称、API 地址、密钥、鉴权方式和调用说明。模型通过 aigc_get_provider_info 读取供应商列表,用 aigc_http_request 调用 API(自动携带 endpoint 和 apiKey),生成的文件用 aigc_canvas_place 放到画布上。',\r\n settingsEmpty: '暂无供应商,请在下方添加。',\r\n settingsAdd: '+ 添加供应商',\r\n settingsLoading: '加载中…',\r\n settingsError: '错误',\r\n 'row.id': 'ID',\r\n 'row.name': '名称',\r\n 'row.endpoint': 'API 地址',\r\n 'row.apiKey': 'API Key',\r\n 'row.instructions': '调用说明',\r\n 'row.idPlaceholder': 'volcano / jimeng / minimax',\r\n 'row.namePlaceholder': '显示名(如\"火山引擎\")',\r\n 'row.endpointPlaceholder': 'stub://aigc-backend',\r\n 'row.apiKeyPlaceholder': 'sk-...',\r\n 'row.instructionsPlaceholder': '调用说明由 Agent 初始化供应商时自动撰写(点击卡片上的\"初始化\"按钮)...',\r\n 'row.idHint': '小写字母、数字、连字符;必须以字母开头。作为 provider_id 传给 aigc_http_request',\r\n 'row.endpointDesc': '供应商 API 地址。填 stub://aigc-backend 使用内置 stub(合成测试媒体,不调真实 API)',\r\n 'row.apiKeyDesc': '供应商 API 密钥。stub 后端不需要。模型看不到密钥,由 aigc_http_request 自动附加',\r\n 'row.instructionsDesc': 'Agent 通过 aigc_get_provider_info 工具读取此字段,决定如何调用该供应商的 API',\r\n 'row.instructionsHint': '💡 点击卡片上的\"初始化\"按钮,Agent 会用 aigc_http_request 探测 API 并自动撰写调用说明',\r\n 'row.save': '保存',\r\n 'row.delete': '删除',\r\n 'row.deleteConfirm': '确定删除此供应商?',\r\n 'row.expand': '展开',\r\n 'row.collapse': '收起',\r\n 'row.create': '创建',\r\n 'row.cancel': '取消',\r\n 'row.init': '初始化',\r\n 'row.initPrompt': '请帮我初始化 AIGC 供应商「{name}」(id: {id}):先用 aigc_get_provider_info 查看配置,再用 aigc_http_request 探测它的 API(apiKey 会自动附加,无需手动传入),最后调用 aigc_provider_set_instructions 把调用说明保存下来,方便以后直接使用。',\r\n 'row.auth': '鉴权方式',\r\n 'row.authBearer': 'Bearer 头',\r\n 'row.authHeader': '自定义 Header',\r\n 'row.authQuery': 'URL 参数',\r\n 'row.authDesc': 'aigc_http_request 自动附加 apiKey 的方式。默认 Authorization: Bearer <key>;选择自定义 Header 或 URL 参数时需填写名称',\r\n 'badge.builtin': '内置',\r\n 'badge.stub': 'stub 模式',\r\n 'badge.real': '真实 API',\r\n 'badge.default': '默认',\r\n}\r\n\r\nexport const en: Record<AigcKey, string> = {\r\n tabTitle: 'AIGC Canvas',\r\n title: 'AIGC Canvas',\r\n empty: 'Canvas is empty. The agent calls provider APIs via aigc_http_request and places the generated files anywhere on the canvas with aigc_canvas_place.',\r\n emptyHint: 'Configure a provider in the settings tab on the right, then ask the agent to generate something.',\r\n prompt: 'Prompt',\r\n image: 'Image',\r\n video: 'Video',\r\n audio: 'Audio',\r\n meta: 'Metadata',\r\n generatedBy: 'Generated by',\r\n edgeCount: 'edges',\r\n elementCount: 'elements',\r\n loadError: 'Failed to load canvas',\r\n disconnected: 'Disconnected, reconnecting…',\r\n reconnecting: 'Reconnecting…',\r\n refresh: 'Refresh',\r\n resetView: 'Reset view',\r\n zoom: 'Zoom',\r\n zoomIn: 'Zoom in',\r\n zoomOut: 'Zoom out',\r\n detailClose: 'Close',\r\n detailPrompt: 'Prompt',\r\n detailParams: 'Generation params',\r\n detailPosition: 'Position',\r\n detailPath: 'File path',\r\n delete: 'Delete',\r\n deleteElement: 'Delete element',\r\n dropHint: 'Drop files onto canvas',\r\n uploading: 'Uploading…',\r\n settingsNav: 'AIGC Canvas',\r\n settingsTitle: 'AIGC Providers',\r\n settingsIntro: 'Configure one or more AIGC providers. Each provider has its own name, API endpoint, key, auth scheme, and usage instructions. The agent reads the provider list via aigc_get_provider_info, calls the API via aigc_http_request (endpoint + apiKey attached automatically), and places generated files onto the canvas with aigc_canvas_place.',\r\n settingsEmpty: 'No providers configured. Add one below.',\r\n settingsAdd: '+ Add provider',\r\n settingsLoading: 'Loading…',\r\n settingsError: 'Error',\r\n 'row.id': 'ID',\r\n 'row.name': 'Name',\r\n 'row.endpoint': 'Endpoint',\r\n 'row.apiKey': 'API Key',\r\n 'row.instructions': 'Instructions',\r\n 'row.idPlaceholder': 'volcano / jimeng / minimax',\r\n 'row.namePlaceholder': 'Display name (e.g. \"Volcano Engine\")',\r\n 'row.endpointPlaceholder': 'stub://aigc-backend',\r\n 'row.apiKeyPlaceholder': 'sk-...',\r\n 'row.instructionsPlaceholder': 'The agent writes these when you initialize the provider (click \"Initialize\" on the card)...',\r\n 'row.idHint': 'Lowercase letters, digits, hyphens; must start with a letter. Used as the provider_id parameter to aigc_http_request',\r\n 'row.endpointDesc': 'Provider API URL. Use stub://aigc-backend for the built-in stub (synthetic test media, no real API calls)',\r\n 'row.apiKeyDesc': 'Provider API key. Not needed for the stub backend. The agent never sees it — aigc_http_request attaches it automatically',\r\n 'row.instructionsDesc': 'The agent reads this field via the aigc_get_provider_info tool to decide how to call the provider API',\r\n 'row.instructionsHint': '💡 Click \"Initialize\" on the card: the agent probes the API with aigc_http_request and writes the instructions itself',\r\n 'row.save': 'Save',\r\n 'row.delete': 'Delete',\r\n 'row.deleteConfirm': 'Delete this provider?',\r\n 'row.expand': 'Expand',\r\n 'row.collapse': 'Collapse',\r\n 'row.create': 'Create',\r\n 'row.cancel': 'Cancel',\r\n 'row.init': 'Initialize',\r\n 'row.initPrompt': 'Please initialize the AIGC provider \"{name}\" (id: {id}): first call aigc_get_provider_info to see its config, then probe its API with aigc_http_request (the apiKey is attached automatically — do not pass it yourself), and finally call aigc_provider_set_instructions to save the usage instructions so it can be used directly later.',\r\n 'row.auth': 'Auth scheme',\r\n 'row.authBearer': 'Bearer header',\r\n 'row.authHeader': 'Custom header',\r\n 'row.authQuery': 'URL query param',\r\n 'row.authDesc': 'How aigc_http_request attaches the apiKey. Default: Authorization: Bearer <key>. For custom header or URL query param, fill in the name',\r\n 'badge.builtin': 'builtin',\r\n 'badge.stub': 'stub mode',\r\n 'badge.real': 'real API',\r\n 'badge.default': 'default',\r\n}\r\n","/**\r\n * Client half of @huanlin/dsh-plugin-aigc-canvas: registers\r\n * (1) a better-sidebar tab (`aigc-canvas:main`) rendering the canvas view, and\r\n * (2) a settings.section slot for the provider config page.\r\n *\r\n * i18n: registers the `dsh-aigc-canvas` locale namespace (zh + en) and binds\r\n * a translate function passed to both the canvas view and the settings page\r\n * via inject — so the UI respects the DSH locale toggle (no hardcoded text).\r\n *\r\n * The settings page's \"initialize\" action sends a prepared prompt into the\r\n * current conversation via the `conversation` service (ui-conversation).\r\n */\r\nimport type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\r\n// Type-only: pulls the locale plugin's Context merge (ctx.locale).\r\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\r\n// Type-only: pulls the settings shell's SlotMap merge (settings.section).\r\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\r\n// Type-only: pulls the conversation service merge (ctx.conversation.send).\r\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\r\n// Type-only: pulls the ui-slots LocaleNamespaceMap + ctx.slots.\r\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\r\nimport type {} from 'dsh-better-sidebar/client'\r\nimport { createElement, useEffect, useRef, type ReactNode } from 'react'\r\nimport { CanvasStore } from './store.js'\r\nimport { CanvasViewWithBoundary } from './CanvasView.js'\r\nimport { SettingsPage, type AigcSettingsInjected } from './SettingsPage.js'\r\nimport { en, zh, NS, type AigcKey } from './locales.js'\r\n\r\n/** Locale namespace map declaration for the DSH locale system. */\r\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\r\n interface LocaleNamespaceMap {\r\n 'dsh-aigc-canvas': AigcKey\r\n }\r\n}\r\n\r\n/** Services required before mounting. */\r\nexport const inject = ['betterSidebar', 'slots', 'locale', 'conversation']\r\n\r\nexport function apply(ctx: ClientContext): void {\r\n // ── Locale registration ────────────────────────────────────────────────\r\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-aigc-canvas: dictionaries')\r\n const t = ctx.locale.bind(NS) as (key: string) => string\r\n\r\n // ── better-sidebar tab ──────────────────────────────────────────────────\r\n const betterSidebar = (ctx as unknown as {\r\n betterSidebar?: { registerTab(descriptor: unknown): () => void }\r\n }).betterSidebar\r\n if (betterSidebar !== undefined) {\r\n ctx.effect(() =>\r\n betterSidebar.registerTab({\r\n id: 'aigc-canvas:main',\r\n title: () => t('tabTitle'),\r\n order: 50,\r\n dedupeKey: () => 'aigc-canvas:main',\r\n component: ({ scope }: { scope: { sessionId: string } }): ReactNode => {\r\n const storeRef = useRef<CanvasStore | null>(null)\r\n if (storeRef.current === null || storeRef.current.sessionId !== scope.sessionId) {\r\n storeRef.current?.dispose()\r\n storeRef.current = new CanvasStore({ sessionId: scope.sessionId })\r\n }\r\n useEffect(() => {\r\n return () => {\r\n storeRef.current?.dispose()\r\n storeRef.current = null\r\n }\r\n }, [])\r\n return createElement(CanvasViewWithBoundary, { store: storeRef.current, t })\r\n },\r\n }),\r\n )\r\n }\r\n\r\n // ── Settings section ────────────────────────────────────────────────────\r\n const settingsInjected = (): AigcSettingsInjected => ({\r\n t,\r\n send: (text) => ctx.conversation.send(text),\r\n })\r\n ctx.slots.inject('settings.section', () =>\r\n ctx.slots.register({\r\n name: 'settings.section',\r\n id: 'aigc-canvas',\r\n order: 60,\r\n label: () => t('settingsNav'),\r\n locale: NS,\r\n inject: settingsInjected,\r\n }, SettingsPage),\r\n )\r\n}\r\n"],"mappings":"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"}
package/lib/config.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * endpoint / apiKey / instructions), editable at runtime through the DSH
5
5
  * GUI settings page; cordis.yml `config:` is the first-boot seed only.
6
6
  *
7
- * @module @dsh-external/dsh-aigc-canvas/config
7
+ * @module @huanlin/dsh-plugin-aigc-canvas/config
8
8
  */
9
9
  import z from 'schemastery';
10
10
  /** Provider id pattern: lowercase letters, digits, hyphens; must start with a letter. */
@@ -4,10 +4,10 @@
4
4
  * outside the DSH monorepo's single cordis instance, so the upstream
5
5
  * `declare module 'cordis'` augmentations do not reach this Context — and
6
6
  * the npm cordis package does not declare the DSH-vendored runtime members
7
- * (`ctx.effect`, the httpServer/sessions/loader faces). The members below
7
+ * (`ctx.effect`, the webServer/sessions/loader faces). The members below
8
8
  * mirror the actual runtime shapes this plugin touches:
9
9
  *
10
- * - httpServer: @deepseek-ai/dsh-host-webserver
10
+ * - webServer: @deepseek-ai/dsh-host-webserver
11
11
  * - sessions: @deepseek-ai/dsh-session (host side)
12
12
  * - loader: @cordisjs/plugin-loader (entry options)
13
13
  * - invariants: @deepseek-ai/dsh-invariants
@@ -30,8 +30,8 @@ export interface AigcWebUpgradeRoute {
30
30
  path: string;
31
31
  handler: (req: IncomingMessage, socket: Duplex, head: Buffer) => void | Promise<void>;
32
32
  }
33
- /** The httpServer service face this plugin uses. */
34
- export interface AigcHttpServer {
33
+ /** The webServer service face this plugin uses. */
34
+ export interface AigcWebServer {
35
35
  register(route: AigcWebRoute): () => void;
36
36
  registerUpgrade(route: AigcWebUpgradeRoute): () => void;
37
37
  }
@@ -102,7 +102,7 @@ export interface AigcToolsService {
102
102
  }
103
103
  declare module 'cordis' {
104
104
  interface Context {
105
- httpServer: AigcHttpServer;
105
+ webServer: AigcWebServer;
106
106
  sessions: AigcSessionStore;
107
107
  agents: AigcAgentRegistry;
108
108
  loader: AigcLoader;
package/lib/index.js CHANGED
@@ -15,7 +15,7 @@ import { spawn } from "node:child_process";
15
15
  * endpoint / apiKey / instructions), editable at runtime through the DSH
16
16
  * GUI settings page; cordis.yml `config:` is the first-boot seed only.
17
17
  *
18
- * @module @dsh-external/dsh-aigc-canvas/config
18
+ * @module @huanlin/dsh-plugin-aigc-canvas/config
19
19
  */
20
20
  /** Provider id pattern: lowercase letters, digits, hyphens; must start with a letter. */
21
21
  const PROVIDER_ID_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
@@ -113,7 +113,7 @@ function resolveAigcConfig(config) {
113
113
  * `~/.dsh/aigc-canvas/providers.json` so restarts keep user-added
114
114
  * providers and instructions.
115
115
  *
116
- * @module @dsh-external/dsh-aigc-canvas/provider-store
116
+ * @module @huanlin/dsh-plugin-aigc-canvas/provider-store
117
117
  */
118
118
  /** Directory for persisted AIGC canvas state (under the DSH user dir). */
119
119
  const DATA_DIR = join(homedir(), ".dsh", "aigc-canvas");
@@ -2720,7 +2720,7 @@ async function saveResponseToSession(content, ext, sessionId, cwd) {
2720
2720
  //#endregion
2721
2721
  //#region src/index.ts
2722
2722
  /**
2723
- * @dsh-external/dsh-aigc-canvas host half: the canvas registry, the provider
2723
+ * @huanlin/dsh-plugin-aigc-canvas host half: the canvas registry, the provider
2724
2724
  * store (config + per-provider usage instructions), the fenced
2725
2725
  * `/aigc-canvas/api/*` JSON API (provider CRUD + canvas.list/move) +
2726
2726
  * `/aigc-canvas/file` media route + `/aigc-canvas/ws/canvas` push WebSocket,
@@ -2741,7 +2741,7 @@ async function saveResponseToSession(content, ext, sessionId, cwd) {
2741
2741
  const name = "dsh-aigc-canvas";
2742
2742
  /** Services required before mounting. */
2743
2743
  const inject = [
2744
- "httpServer",
2744
+ "webServer",
2745
2745
  "sessions",
2746
2746
  "agents",
2747
2747
  "loader",
@@ -2957,7 +2957,7 @@ function apply(ctx, config) {
2957
2957
  }));
2958
2958
  };
2959
2959
  const api = buildApi(ctx, canvas, store, getResolved);
2960
- ctx.effect(() => ctx.httpServer.register({
2960
+ ctx.effect(() => ctx.webServer.register({
2961
2961
  kind: "prefix",
2962
2962
  path: "/aigc-canvas/api",
2963
2963
  handler: async (req, res) => {
@@ -2997,7 +2997,7 @@ function apply(ctx, config) {
2997
2997
  }
2998
2998
  }
2999
2999
  }), "dsh-aigc-canvas: /aigc-canvas/api routes");
3000
- ctx.effect(() => ctx.httpServer.register({
3000
+ ctx.effect(() => ctx.webServer.register({
3001
3001
  kind: "prefix",
3002
3002
  path: "/aigc-canvas/file",
3003
3003
  handler: async (req, res) => {
@@ -3038,7 +3038,7 @@ function apply(ctx, config) {
3038
3038
  }
3039
3039
  }), "dsh-aigc-canvas: /aigc-canvas/file media route");
3040
3040
  const wss = new WebSocketServer({ noServer: true });
3041
- ctx.effect(() => ctx.httpServer.registerUpgrade({
3041
+ ctx.effect(() => ctx.webServer.registerUpgrade({
3042
3042
  path: "/aigc-canvas/ws/canvas",
3043
3043
  handler: (req, socket, head) => {
3044
3044
  if (!fence(req)) {
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Package-owned invariant companion for `@dsh-external/dsh-aigc-canvas`.
3
- * @module @dsh-external/dsh-aigc-canvas/invariant
2
+ * Package-owned invariant companion for `@huanlin/dsh-plugin-aigc-canvas`.
3
+ * @module @huanlin/dsh-plugin-aigc-canvas/invariant
4
4
  */
5
5
  import type { Context } from './context-types.js';
6
6
  /** Cordis companion plugin name. */
package/lib/invariant.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region src/invariant.ts
2
- const PACKAGE_NAME = "@dsh-external/dsh-aigc-canvas";
2
+ const PACKAGE_NAME = "@huanlin/dsh-plugin-aigc-canvas";
3
3
  /** Cordis companion plugin name. */
4
4
  const name = "dsh-aigc-canvas-invariant";
5
5
  /** Service required before the companion can reserve package ownership. */
@@ -7,7 +7,7 @@ const inject = ["invariants"];
7
7
  /**
8
8
  * No runtime invariant: the canvas owns no service state or event protocol
9
9
  * of its own beyond the registry's own assertions (uuid existence, kind
10
- * checks) — every route is mounted under the host's httpServer fence, the
10
+ * checks) — every route is mounted under the host's webServer fence, the
11
11
  * element table is exercised by the smoke spec, and the client view is a
12
12
  * pure projection of the host state.
13
13
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@huanlin/dsh-plugin-aigc-canvas",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "DSH plugin: an infinite free canvas for the better-sidebar plus provider-agnostic generation. Exposes aigc_get_provider_info / aigc_http_request (endpoint + apiKey auto-attached) / aigc_provider_set_instructions / aigc_canvas_place / aigc_canvas_link / aigc_canvas_unlink / aigc_canvas_list_elements tools; generated files are placed at arbitrary canvas positions and can be double-clicked for prompt + params.",
5
5
  "type": "module",
6
6
  "license": "MIT",