dsh-plugin-lookatstudy 0.12.2 → 0.12.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.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["createElement","useSyncExternalStore","MODES","createElement","useState","useRef","createElement","useState","useState","createElement","createElement","createElement"],"sources":["../src/client/styles.ts","../src/client/icons.tsx","../src/client/data.ts","../src/markdown.ts","../src/vendor/mermaid-elk-rewrite.ts","../src/client/enhance.ts","../src/vendor/cmap-elk-layout.ts","../src/client/locale.ts","../src/client/diagrams.ts","../src/client/views.tsx","../src/client/starter.tsx","../src/client/settings.tsx","../src/client/dock.tsx","../src/client/toolviews.tsx","../src/client/index.ts"],"sourcesContent":["/**\n * Style injection for the study tab: one `<style>` element of `.lks-*`\n * classes authored against the dsh `--dsw-*` design tokens, so the tab\n * follows the app's theme (light/dark) instead of carrying its own palette.\n * CSS Modules are unavailable to patch-layer bundles, so the stylesheet is\n * injected once at client-plugin apply; the `data-` attribute keeps the\n * injection idempotent.\n * @module dsh-plugin-lookatstudy/client/styles\n */\n\n/** Marker attribute proving the stylesheet is already in the document. */\nconst STYLE_ID = 'data-dsh-plugin-lookatstudy'\n\n/**\n * The study tab's stylesheet. Class names are `lks-*` namespaced; colors,\n * fonts, and radii come from `--dsw-*` tokens wherever the concept exists.\n */\nexport const STUDY_CSS = `\n/* State inks: small colored text must clear WCAG AA (4.5:1), but the host's\n raw state tokens (success/warn primaries) sit at 2.3–2.6:1 on light\n backgrounds, and success/error *label* aliases are not published by this\n host at all (the tv-chip used to reference them and silently inherit).\n Mixing the state color toward label-primary keeps the hue while pulling\n luminance to the readable pole — and works in BOTH themes, because\n label-primary is always the current theme's high-contrast ink. */\n.lks-root{--lks-warn-ink:color-mix(in srgb,var(--dsw-alias-state-warn-label) 45%,var(--dsw-alias-label-primary));--lks-ok-ink:color-mix(in srgb,var(--dsw-alias-state-success-primary) 40%,var(--dsw-alias-label-primary));--lks-err-ink:color-mix(in srgb,var(--dsw-alias-state-error-primary) 55%,var(--dsw-alias-label-primary));font-family:var(--dsw-font-family)}\n.lks-root :where(button){font-family:var(--dsw-font-family);cursor:pointer;border:none;background:none;padding:0}\n.lks-root :where(a){color:var(--dsw-alias-state-business-primary)}\n\n/* ── the study tab: composer-width center, self-scrolling flanks ──\n data-conversation-composer-overlay (set on the root element) opts the\n view into the host's overlay mode: viewArea becomes a fixed-height\n non-growing host and the composer floats over the tab's bottom band, so\n the tab itself never feeds the page scroll. The bottom padding clears the\n floating composer via the host-published live --dsh-composer-height. The\n tutor column shares the conversation column's width axis\n (--dsh-composer-card-max-width inherits from ConversationRoot's root) but\n is capped at 42% of the tab so the BLACKBOARD — the reading surface —\n keeps the lion's share at every wide width; the composer card follows the\n tutor column's real measured width (views.tsx), so the two stay visually\n tied. Flanking columns absorb the remaining width and scroll independently. */\n.lks-study{height:100%;min-height:0;width:100%;box-sizing:border-box;overflow:hidden;display:flex;flex-direction:column;padding:10px 14px calc(var(--dsh-composer-height, 152px) + 12px);color:var(--dsw-alias-label-primary);container:lksstudy/inline-size}\n/* Direction carrier (a container query cannot style the container itself). */\n.lks-body{flex:1;min-height:0;min-width:0;display:flex;gap:16px}\n.lks-col{display:flex;flex-direction:column;min-width:0}\n.lks-colhead{flex:none;font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary);letter-spacing:.06em;text-transform:uppercase;margin-bottom:10px}\n.lks-col-rail{flex:0 1 260px;min-width:180px;overflow-y:auto;padding:2px 6px}\n.lks-col-tutor{flex:0 1 auto;width:min(100%,var(--dsh-composer-card-max-width,780px),42cqi);min-width:360px;overflow:hidden}\n.lks-col-bb{flex:1 1 0;min-width:320px;overflow-y:auto;padding:2px 6px}\n/* While the study view is mounted in wide mode, the host composer card is\n shifted under the tutor column (the transcript's width axis) instead of the\n scroll body's center — views.tsx measures the offset, sets the variables\n and toggles the class, and removes all three whenever the shift collapses\n (narrow pane, hidden view) so the host's natural centering and width come\n back. max-width tracks the tutor column's live width: the tutor shrinks\n proportionally below ~1857px containers, and the card shrinks with it. */\n[data-composer-card].lks-composer-follow{align-self:flex-start;margin-left:var(--lks-composer-shift,0px);max-width:var(--lks-composer-follow-width,var(--dsh-composer-card-max-width,780px))}\n/* narrow (<1220px): one composer-width pane at a time, chosen by a centered\n segmented pill group (joined buttons in one capsule — button language, not\n tab language, against the host's view tabs right above). */\n.lks-switch{display:none;flex-direction:row;gap:2px;align-self:center;margin-bottom:10px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:999px;padding:3px}\n.lks-switch-btn{border-radius:999px;padding:5px 18px;font-size:14px;color:var(--dsw-alias-label-tertiary);background:transparent;transition:background .12s ease,color .12s ease}\n.lks-switch-btn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}\n.lks-switch-btn.on{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 86%,#000);color:#fff;font-weight:600}\n@container lksstudy (max-width: 1220px){\n .lks-body{flex-direction:column}\n .lks-switch{display:flex}\n .lks-colhead{display:none}\n .lks-col{flex:1 1 auto;min-height:0;width:auto;overflow-y:auto}\n .lks-col-tutor{width:min(100%,var(--dsh-composer-card-max-width,780px));overflow:hidden;display:flex;flex-direction:column}\n .lks-study[data-pane='rail'] .lks-col-tutor,.lks-study[data-pane='rail'] .lks-col-bb,\n .lks-study[data-pane='tutor'] .lks-col-rail,.lks-study[data-pane='tutor'] .lks-col-bb,\n .lks-study[data-pane='bb'] .lks-col-rail,.lks-study[data-pane='bb'] .lks-col-tutor{display:none}\n}\n\n/* ── left column: course rail ── */\n.lks-rail-head{display:flex;align-items:center;gap:6px;margin-bottom:4px}\n.lks-rail-head .lks-rail-select{flex:1;min-width:0;margin-bottom:0}\n.lks-rail-head .lks-btn{padding:3px 8px;font-size:13px}\n.lks-rail-title{font-size:16px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.lks-rail-sub{font-size:13px;color:var(--dsw-alias-label-secondary);margin:4px 0 6px}\n.lks-masterybar{height:5px;border-radius:3px;background:var(--dsw-alias-bg-layer-3);overflow:hidden;margin-bottom:8px}\n.lks-masterybar i{display:block;height:100%;width:100%;background:var(--dsw-alias-state-success-primary);transform-origin:0 50%;transition:transform .3s ease}\n.lks-masterybar.gold i{background:var(--dsw-alias-state-warn-primary)}\n.lks-search{width:100%;box-sizing:border-box;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;color:var(--dsw-alias-label-primary);font-family:inherit;font-size:13.5px;padding:5px 9px;margin-bottom:4px}\n.lks-search:focus{outline:none;border-color:var(--dsw-alias-state-business-primary);box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}\n.lks-sec-num{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;border-radius:50%;background:var(--dsw-alias-state-warn-tertiary);color:var(--lks-warn-ink);font-size:11px;font-weight:700;margin-right:4px}\n.lks-tag.due{background:var(--dsw-alias-state-warn-tertiary);color:var(--lks-warn-ink)}\n.lks-import{margin-top:8px}\n.lks-import .lks-inputrow{margin-top:0}\n.lks-inputrow{display:flex;gap:8px;align-items:flex-end;flex:none;margin-top:8px}\n.lks-input{flex:1;min-width:0;resize:none;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;color:var(--dsw-alias-label-primary);font-family:inherit;font-size:14px;line-height:1.6;padding:8px 10px}\n.lks-input:focus{outline:none;border-color:var(--dsw-alias-state-business-primary)}\n.lks-input:disabled{opacity:.55}\n.lks-import-hint{font-size:12.5px;color:var(--dsw-alias-label-secondary);margin-top:6px;line-height:1.7}\n.lks-duebox{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;padding:10px 12px;margin:8px 0 14px;font-size:13.5px}\n.lks-duebox .lks-due-item{color:var(--dsw-alias-label-secondary);margin-top:4px;display:flex;justify-content:space-between;gap:10px}\n.lks-duebox .lks-over{color:var(--lks-warn-ink);flex:none}\n\n.lks-sec{font-size:12px;color:var(--dsw-alias-label-secondary);text-transform:uppercase;letter-spacing:.05em;margin:14px 0 4px}\n/* Collapsible section head: a real button (keyboard can toggle it), sticky so\n the current chapter stays identified while 4000px of nodes scroll under it. */\n.lks-sechead{display:flex;align-items:center;gap:6px;width:100%;box-sizing:border-box;font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary);text-align:left;padding:6px 4px;margin:14px 0 4px;border-radius:6px;position:sticky;top:0;z-index:1;background:var(--dsw-alias-bg-base)}\n.lks-sechead:hover{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover)}\n.lks-sechead:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary);outline:none}\n.lks-sechead-t{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.lks-sechead-c{flex:none;font-size:10px}\n.lks-sechead-n{flex:none;font-size:11px;text-transform:none;letter-spacing:0}\n.lks-node{display:flex;align-items:center;gap:8px;width:100%;text-align:left;padding:6px 9px;border-radius:8px;margin:1px 0;cursor:pointer}\n.lks-node:hover{background:var(--dsw-alias-interactive-bg-hover)}\n.lks-node:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary);outline:none}\n.lks-node.focus{background:var(--dsw-alias-bg-layer-3);outline:1px solid var(--dsw-alias-border-l2)}\n.lks-node .lks-g{width:18px;text-align:center;flex:none}\n.lks-node .lks-t{flex:1;font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n/* aria-disabled (not the disabled attribute): the row stays focusable so the\n status tooltip can explain WHY it is locked — Firefox drops titles on truly\n disabled form controls. */\n.lks-node[aria-disabled='true']{opacity:.45;cursor:not-allowed}\n.lks-node[aria-disabled='true']:hover{background:none}\n.lks-tag{font-size:11px;border-radius:4px;padding:0 4px;flex:none}\n.lks-tag.weak{background:var(--dsw-alias-state-warn-tertiary);color:var(--lks-warn-ink)}\n.lks-tag.fric{background:var(--dsw-alias-state-error-tertiary);color:var(--lks-err-ink)}\n.lks-bar{width:44px;height:4px;border-radius:2px;background:var(--dsw-alias-bg-layer-3);overflow:hidden;flex:none}\n.lks-bar i{display:block;height:100%;width:100%;background:var(--dsw-alias-state-success-primary);transform-origin:0 50%}\n.lks-pct{font-size:12px;color:var(--dsw-alias-label-secondary);flex:none;width:32px;text-align:right}\n\n.lks-empty{color:var(--dsw-alias-label-secondary);text-align:center;padding:48px 8px;font-size:14px;line-height:2}\n.lks-actbar{display:flex;flex-direction:row;justify-content:flex-end;flex:none;padding-bottom:8px}\n\n/* ── middle column: the tutor ── */\n.lks-transcript{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:10px;padding:4px 2px}\n.lks-msg{max-width:94%;font-size:16px;line-height:1.7;border-radius:12px;padding:8px 12px;word-break:break-word}\n.lks-msg.user{align-self:flex-end;white-space:pre-wrap;background:var(--dsw-alias-state-business-tertiary);color:var(--dsw-alias-label-primary-bluish)}\n.lks-msg.assistant{align-self:flex-start;background:var(--dsw-alias-bg-layer-2)}\n.lks-msg.streaming{opacity:.7}\n.lks-msg.thinking{align-self:flex-start;display:inline-flex;align-items:center;gap:8px;font-size:13px;color:var(--dsw-alias-label-secondary);background:none;border-radius:0;padding:2px}\n.lks-msg.error{align-self:stretch;color:var(--dsw-alias-state-error-primary);font-size:13px;background:none;border-radius:0;padding:1px 2px}\n/* quiz-taking surface: the tutor's A–D options become clickable answers on the last settled reply */\n.lks-turn{display:flex;flex-direction:column;align-items:flex-start;max-width:94%}\n.lks-quiz{display:flex;flex-direction:column;gap:6px;width:100%;margin:2px 0 4px}\n.lks-opt{display:flex;align-items:baseline;gap:10px;text-align:left;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:10px;padding:8px 14px;font-size:14px;line-height:1.5;color:var(--dsw-alias-label-secondary);cursor:pointer;font-family:inherit;transition:border-color .12s ease,color .12s ease,background .12s ease}\n.lks-opt:hover{border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-state-business-tertiary)}\n.lks-opt:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary);outline:none}\n.lks-optletter{font-weight:700;color:var(--dsw-alias-label-primary-bluish);flex:none}\n\n/* soul pills (native tool-row trigger language: 28px transparent, tinted active) */\n.lks-pills{display:inline-flex;align-items:center;height:28px}\n.lks-pill{display:inline-flex;align-items:center;gap:6px;height:28px;padding:0 10px;border:none;border-radius:24px;background:transparent;color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:20px;font-weight:500;transition:background .12s ease,color .12s ease}\n.lks-pill:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}\n.lks-pill:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary);outline:none}\n.lks-pill.on{background:var(--dsw-alias-state-business-tertiary);color:var(--dsw-alias-label-primary-bluish)}\n.lks-pill.on:hover{background:var(--dsw-alias-state-business-tertiary);color:var(--dsw-alias-label-primary-bluish)}\n\n/* SVG glyph alignment (status icons, tag badges, dock segments, icon buttons) */\n.lks-g svg{display:block;margin:0 auto}\n.lks-tag{display:inline-flex;align-items:center;gap:2px;line-height:1}\n.lks-dockseg{display:inline-flex;align-items:center;gap:3px}\n.lks-dock-due svg,.lks-dock-streak svg{flex:none}\n.lks-dock-due.lks-muted svg,.lks-dock-streak.lks-muted svg{opacity:.75}\n.lks-btn svg,.lks-viewtab svg,.lks-sechead svg{flex:none}\n.lks-viewtab svg,.lks-btn svg{align-self:center}\n\n/* ic_ds_* glyph carriers + busy spinner (native .8s linear spin) */\n@keyframes lks-spin{to{transform:rotate(360deg)}}\n.lks-spin{animation:lks-spin .8s linear infinite}\n\n/* dormant state: pills/starters stay visible but inert (aria-disabled, same\n contract as locked lesson rows — focusable so the hint explains why) */\n.lks-pill[aria-disabled='true'],.lks-starter[aria-disabled='true']{opacity:.45;cursor:not-allowed}\n.lks-pill[aria-disabled='true']:hover,.lks-starter[aria-disabled='true']:hover{background:transparent;border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary)}\n.lks-dormant{font-size:13px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);border:1px dashed var(--dsw-alias-border-l2);border-radius:10px;padding:10px 12px;margin:8px 0;line-height:1.7}\n\n/* starter chips */\n.lks-dock{display:flex;align-items:center;flex-wrap:wrap;gap:6px;padding:0 2px 6px;flex:none}\n.lks-starter{border:1px solid var(--dsw-alias-border-l2);border-radius:999px;padding:4px 12px;font-size:13px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);transition:border-color .12s ease,color .12s ease}\n.lks-starter:hover{border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-label-primary)}\n\n/* proposal banner + shared buttons */\n/* A mastery proposal is a positive, informational moment — business tint, not\n the warn tint it previously wore (a reviewer flagged the semantic mismatch). */\n.lks-banner{display:flex;align-items:center;gap:10px;background:var(--dsw-alias-state-business-tertiary);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;padding:10px 14px;margin:8px 0;font-size:14px;flex:none}\n.lks-banner .lks-why{flex:1;color:var(--dsw-alias-label-secondary)}\n.lks-btn{display:inline-flex;align-items:center;gap:6px;border-radius:8px;padding:6px 14px;font-size:13.5px;font-weight:600;flex:none}\n.lks-btn:focus-visible,.lks-starter:focus-visible,.lks-switch-btn:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary);outline:none}\n.lks-btn.primary{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 86%,#000);color:#fff}\n.lks-btn.primary:hover{filter:brightness(1.1)}\n.lks-btn.primary:disabled{opacity:.5;cursor:default;filter:none}\n.lks-btn.ghost{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary);border:1px solid var(--dsw-alias-border-l2)}\n.lks-btn.ghost:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l3)}\n\n/* ── right column: blackboard ── */\n.lks-lessonhead h2{font-size:18px;margin:0 0 4px;font-weight:700}\n.lks-lessonhead .lks-meta{color:var(--dsw-alias-label-secondary);font-size:13px;margin-bottom:4px}\n.lks-chips{display:flex;flex-wrap:wrap;gap:6px;margin:8px 0}\n.lks-chip{border-radius:999px;padding:2px 10px;font-size:12.5px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary)}\n.lks-chip.weak{background:var(--dsw-alias-state-warn-tertiary);color:var(--lks-warn-ink)}\n\n/* blackboard view tabs (same joined-capsule button language as the narrow\n mode switcher — buttons, not tabs, against the host's view tabs above) */\n.lks-viewtabs{display:flex;gap:2px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:999px;padding:3px;width:max-content;margin:10px 0}\n.lks-viewtab{border-radius:999px;padding:4px 16px;font-size:13.5px;color:var(--dsw-alias-label-secondary);background:transparent;transition:background .12s ease,color .12s ease}\n.lks-viewtab:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}\n.lks-viewtab.on{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 86%,#000);color:#fff;font-weight:600}\n.lks-viewtab:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary);outline:none}\n\n/* rendered markdown (host-sanitized lesson bodies and assistant replies) */\n.lks-prose{font-size:16px;line-height:1.75}\n.lks-prose h1,.lks-prose h2,.lks-prose h3,.lks-prose h4{margin:14px 0 6px;line-height:1.4}\n.lks-prose p{margin:6px 0}\n.lks-prose pre{background:var(--dsw-alias-markdown-code-block);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;padding:10px;overflow-x:auto;margin:8px 0;font-size:13.5px;font-family:var(--dsw-font-markdown-code-block-small)}\n.lks-prose code{font-family:var(--dsw-font-markdown-code);background:var(--dsw-alias-bg-layer-3);border-radius:4px;padding:1px 5px;font-size:.92em}\n.lks-prose pre code{background:none;padding:0}\n.lks-prose table{border-collapse:collapse;margin:8px 0;display:block;max-width:100%;overflow-x:auto}\n.lks-prose th,.lks-prose td{border:1px solid var(--dsw-alias-border-l2);padding:5px 11px;font-size:14px}\n.lks-prose th{background:var(--dsw-alias-bg-layer-2)}\n.lks-prose blockquote{border-left:3px solid var(--dsw-alias-state-business-primary);padding:2px 12px;color:var(--dsw-alias-label-secondary);margin:8px 0}\n.lks-prose ul,.lks-prose ol{padding-left:22px;margin:6px 0}\n.lks-prose img{max-width:100%}\n/* width guards for CDN-rendered artifacts (both teach and diagram panes are\n .lks-prose): mermaid/elk SVGs carry fixed width attributes; KaTeX\n display math can exceed the column; both must degrade to fit/scroll\n internally instead of stretching the blackboard. */\n.lks-prose svg{max-width:100%;height:auto}\n.lks-prose .katex-display{overflow-x:auto;overflow-y:hidden;padding:2px 0}\n\n/* Cornell notes zones */\n.lks-bb-notes{margin-top:14px;padding-top:10px;border-top:1px solid var(--dsw-alias-border-l1)}\n.lks-zone{margin-bottom:14px}\n.lks-zone-h{font-size:14px;color:var(--dsw-alias-label-secondary);margin:0 0 8px;font-weight:600}\n.lks-note{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;padding:10px 14px;margin-bottom:8px}\n.lks-note .lks-note-src{float:right;font-size:11.5px;color:var(--dsw-alias-label-secondary)}\n.lks-note .lks-note-title{font-weight:600;font-size:13px}\n.lks-note .lks-note-text{margin-top:4px;font-size:13px;color:var(--dsw-alias-label-secondary);line-height:1.65}\n.lks-note .lks-note-text p{margin:4px 0}\n.lks-note .lks-note-text table{border-collapse:collapse;margin:6px 0;display:block;max-width:100%;overflow-x:auto}\n.lks-note .lks-note-text th,.lks-note .lks-note-text td{border:1px solid var(--dsw-alias-border-l2);padding:4px 8px;font-size:12.5px}\n.lks-note .lks-note-text code{font-family:var(--dsw-font-markdown-code);background:var(--dsw-alias-bg-layer-3);border-radius:4px;padding:1px 4px;font-size:.95em}\n.lks-note .lks-note-q{margin-top:6px;color:var(--dsw-alias-label-tertiary);font-size:12px;border-left:2px solid var(--dsw-alias-state-warn-primary);padding-left:8px}\n\n/* inline error text (write-action failures) */\n.lks-propcard-err{color:var(--dsw-alias-state-error-primary);font-size:12px;margin-top:6px;flex:none}\n\n/* settings section (settings.section entry inside the host settings shell) */\n.lks-settings{display:flex;flex-direction:column;gap:18px;font-family:var(--dsw-font-family);color:var(--dsw-alias-label-primary)}\n.lks-set-row h3{margin:0 0 4px;font-size:15px;font-weight:600}\n.lks-set-hint{margin:0 0 10px;font-size:13px;color:var(--dsw-alias-label-secondary)}\n.lks-set-state{margin-left:10px;font-size:13px;color:var(--dsw-alias-label-secondary)}\n.lks-set-stats{margin:0;padding-left:18px;font-size:14px;line-height:1.9}\n.lks-set-path{font-family:var(--dsw-font-markdown-code);font-size:12.5px;background:var(--dsw-alias-bg-layer-3);border-radius:6px;padding:3px 8px;word-break:break-all}\n\n/* composer dock status pill (conversation.composer.dock entry) */\n.lks-dockpill{display:inline-flex;gap:10px;align-items:center;font-size:12px;color:var(--dsw-alias-label-secondary)}\n.lks-dockseg{white-space:nowrap}\n.lks-dock-due{color:var(--lks-warn-ink)}\n.lks-dock-streak{color:var(--dsw-alias-state-business-primary)}\n.lks-dockseg.lks-muted{color:var(--dsw-alias-label-secondary)}\n\n/* concept map legend (amber = weak) */\n.lks-cmap-legend{display:inline-flex;align-items:center;gap:5px;font-size:12px;color:var(--dsw-alias-label-secondary);margin-top:4px}\n.lks-cmap-legend i{width:10px;height:10px;border-radius:3px;background:var(--dsw-alias-state-warn-tertiary,#fef5e7);border:1px solid var(--dsw-alias-state-warn-primary,#dd8629)}\n\n/* keyed tool.call.toolview cards (conversation tab tool rows) */\n.lks-tv{display:flex;flex-direction:column;gap:4px;padding:6px 10px;border-radius:10px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);font-size:13px}\n.lks-tv.err{border-color:var(--dsw-alias-state-error-primary)}\n.lks-tv-head{font-weight:600;color:var(--dsw-alias-label-secondary);font-size:12px}\n.lks-tv-chip{align-self:flex-start;border-radius:999px;padding:2px 10px;font-size:12.5px;font-weight:600}\n.lks-tv-chip.ok{background:var(--dsw-alias-state-success-tertiary);color:var(--lks-ok-ink)}\n.lks-tv-chip.bad{background:var(--dsw-alias-state-error-tertiary);color:var(--lks-err-ink)}\n.lks-tv-line{color:var(--dsw-alias-label-secondary);line-height:1.6;white-space:pre-wrap}\n/* exam star card + the failure moment */\n.lks-tv-stars{display:inline-flex;align-items:center;gap:5px;font-size:13px;font-weight:600;color:var(--lks-warn-ink)}\n.lks-tv-stars .dim{opacity:.22}\n.lks-tv-stars-label{font-weight:400;color:var(--dsw-alias-label-secondary)}\n.lks-tv-failnote{margin-top:4px;font-size:12.5px;color:var(--dsw-alias-label-secondary);line-height:1.6}\n`\n\n/**\n * Inject the study stylesheet into `document.head` (idempotent).\n * @returns the stylesheet element (existing one when already injected).\n */\nexport function ensureStudyStyles(): HTMLStyleElement {\n const existing = document.head.querySelector(`style[${STYLE_ID}]`)\n if (existing !== null) return existing\n const style = document.createElement('style')\n style.setAttribute(STYLE_ID, '')\n style.textContent = STUDY_CSS\n document.head.appendChild(style)\n return style\n}\n","/**\n * ic_ds_* glyphs vendored from @deepseek-ai/dsh-client-ui-primitives\n * (src/icons/index.tsx, same figma source as the host's icon set) so the\n * plugin's client bundle stays self-contained per the dsh client-bundle\n * contract — only react and dsh-client-runtime/client are runtime-external;\n * importing the host package root would drag its CSS modules into the\n * inlined bundle. Re-sync these three paths if the host icon set redesigns\n * them; scripts/verify.mjs pins the path data.\n *\n * 2026-09-01 critique round: seven more ic_ds glyphs vendored (play/plus/\n * trash/refresh/globe/goal/warning) plus plugin-original learning-domain\n * companions (lock/star/book/crown/bolt/power/pin/flame) drawn in the same\n * language — those are NOT ic_ds, see their section comment below.\n * @module dsh-plugin-lookatstudy/client/icons\n */\n\nimport { createElement } from 'react'\n\n/** Shared props for every vendored glyph (mirrors the host's IconProps). */\ninterface IconProps {\n /** Square edge in px; defaults to the glyph's own drawn size. */\n size?: number\n /** Extra class for layout placement; color rides currentColor. */\n className?: string\n}\n\n/** ic_ds_think_outline_16 */\nexport function IconThinkOutline16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', {\n d: 'M8.00192 6.64454C8.75026 6.64454 9.35732 7.25169 9.35739 8.00001C9.35739 8.74838 8.7503 9.35548 8.00192 9.35548C7.25367 9.35533 6.64743 8.74829 6.64743 8.00001C6.6475 7.25178 7.25371 6.64468 8.00192 6.64454Z',\n fill: 'currentColor',\n }),\n createElement('path', {\n 'fill-rule': 'evenodd',\n 'clip-rule': 'evenodd',\n d: 'M9.97165 1.29981C11.5853 0.718916 13.271 0.642197 14.3144 1.68555C15.3577 2.72902 15.2811 4.41466 14.7002 6.02833C14.4707 6.66561 14.1504 7.32937 13.75 8.00001C14.1504 8.67062 14.4707 9.33444 14.7002 9.97169C15.2811 11.5854 15.3578 13.271 14.3144 14.3145C13.271 15.3579 11.5854 15.2811 9.97165 14.7002C9.3344 14.4708 8.67059 14.1505 7.99997 13.75C7.32933 14.1505 6.66558 14.4708 6.02829 14.7002C4.41461 15.2811 2.72899 15.3578 1.68552 14.3145C0.642155 13.271 0.71887 11.5854 1.29977 9.97169C1.52915 9.33454 1.84865 8.67049 2.24899 8.00001C1.84866 7.32953 1.52915 6.66544 1.29977 6.02833C0.718852 4.41459 0.64207 2.729 1.68552 1.68555C2.72897 0.642112 4.41456 0.718887 6.02829 1.29981C6.66541 1.52918 7.32949 1.8487 7.99997 2.24903C8.67045 1.84869 9.33451 1.52919 9.97165 1.29981ZM12.9404 9.2129C12.4391 9.893 11.8616 10.5681 11.2148 11.2149C10.568 11.8616 9.89296 12.4391 9.21286 12.9404C9.62532 13.1579 10.0271 13.338 10.4121 13.4766C11.9146 14.0174 12.9172 13.8738 13.3955 13.3955C13.8737 12.9173 14.0174 11.9146 13.4765 10.4121C13.3379 10.0271 13.1578 9.62535 12.9404 9.2129ZM3.05856 9.2129C2.84121 9.62523 2.66197 10.0272 2.52341 10.4121C1.98252 11.9146 2.12627 12.9172 2.60446 13.3955C3.08278 13.8737 4.08544 14.0174 5.58786 13.4766C5.97264 13.338 6.37389 13.1577 6.7861 12.9404C6.10624 12.4393 5.43168 11.8614 4.78513 11.2149C4.13823 10.5679 3.55992 9.89313 3.05856 9.2129ZM7.99899 3.792C7.23179 4.31419 6.45306 4.95512 5.70407 5.70411C4.95509 6.45309 4.31415 7.23184 3.79196 7.99903C4.3143 8.76666 4.95471 9.54653 5.70407 10.2959C6.45309 11.0449 7.23271 11.6848 7.99997 12.207C8.76725 11.6848 9.54683 11.0449 10.2959 10.2959C11.0449 9.54686 11.6848 8.76729 12.207 8.00001C11.6848 7.23275 11.0449 6.45312 10.2959 5.70411C9.5465 4.95475 8.76662 4.31434 7.99899 3.792ZM5.58786 2.52344C4.08533 1.98255 3.08272 2.12625 2.60446 2.6045C2.12621 3.08275 1.98252 4.08536 2.52341 5.5879C2.66189 5.97253 2.8414 6.37409 3.05856 6.78614C3.55983 6.10611 4.1384 5.43189 4.78513 4.78516C5.43186 4.13843 6.10606 3.55987 6.7861 3.0586C6.37405 2.84144 5.97249 2.66192 5.58786 2.52344ZM13.3955 2.6045C12.9172 2.12631 11.9146 1.98257 10.4121 2.52344C10.0272 2.66201 9.62519 2.84125 9.21286 3.0586C9.8931 3.55996 10.5679 4.13827 11.2148 4.78516C11.8614 5.43172 12.4392 6.10627 12.9404 6.78614C13.1577 6.37393 13.338 5.97267 13.4765 5.5879C14.0174 4.08549 13.8736 3.08281 13.3955 2.6045Z',\n fill: 'currentColor',\n }))\n}\n\n/** ic_ds_loading_outline_16 */\nexport function IconLoadingOutline16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', {\n d: 'M2.871 13.1286C0.0387669 10.2962 0.0387669 5.70383 2.871 2.87141C5.70341 0.0390029 10.2957 0.0391154 13.1282 2.87141L12.1387 3.86094C9.85292 1.57538 6.1469 1.57596 3.86123 3.86163C1.57573 6.14732 1.57573 9.85269 3.86123 12.1384C6.1469 14.424 9.85292 14.4246 12.1387 12.1391L13.1282 13.1286C10.2957 15.9609 5.70341 15.961 2.871 13.1286Z',\n fill: 'currentColor',\n }))\n}\n\n/** ic_ds_download_outline_16 */\nexport function IconDownloadOutline16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', {\n d: 'M15.3695 11.411L15.1234 12.8866C14.8869 14.3042 13.6603 15.3436 12.223 15.3436H3.77673C2.33958 15.3434 1.1128 14.3042 0.876343 12.8866L0.630249 11.411L2.05408 11.1747L2.29919 12.6493C2.41973 13.3713 3.04475 13.9001 3.77673 13.9003H12.223C12.9551 13.9002 13.58 13.3713 13.7006 12.6493L13.9457 11.1747L15.3695 11.411ZM8.72205 8.994C8.77717 8.93934 8.83792 8.88106 8.90271 8.81627L12.4828 5.23424L13.5043 6.25572L9.92224 9.8358C9.6395 10.1185 9.38763 10.3732 9.15857 10.5575C8.91892 10.7503 8.63953 10.9224 8.2865 10.9784C8.09711 11.0083 7.90363 11.0083 7.71423 10.9784C7.36106 10.9224 7.0809 10.7503 6.84119 10.5575C6.61215 10.3732 6.36022 10.1185 6.07751 9.8358L2.49646 6.25572L3.51697 5.23424L7.09705 8.81627C7.16219 8.88142 7.22331 8.94006 7.27869 8.99498V1.3065H8.72205V8.994Z',\n fill: 'currentColor',\n }))\n}\n\n/** Vendored 2026-09-01 for the critique icon round (same figma source as the three above). */\n/** IconPlayOutline16 */\nexport function IconPlayOutline16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M14.1446 8C14.1446 4.6062 11.3938 1.85539 8 1.85539C4.6062 1.85539 1.85539 4.6062 1.85539 8C1.85539 11.3938 4.6062 14.1446 8 14.1446C11.3938 14.1446 14.1446 11.3938 14.1446 8ZM15.511 8C15.511 12.148 12.148 15.511 8 15.511C3.85202 15.511 0.489014 12.148 0.489014 8C0.489014 3.85202 3.85202 0.489014 8 0.489014C12.148 0.489014 15.511 3.85202 15.511 8Z', fill: 'currentColor' }),\n createElement('path', { d: 'M10.5617 8.42578C10.852 8.21614 10.852 7.78386 10.5617 7.57422L7.25708 5.18751C6.90974 4.93666 6.42436 5.18484 6.42436 5.61329V10.3867C6.42436 10.8152 6.90974 11.0633 7.25708 10.8125L10.5617 8.42578Z', fill: 'currentColor' }))\n}\n\n/** IconPlusOutline16 */\nexport function IconPlusOutline16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M8.64453 1.5V7.34961H14.5V8.65039H8.64453V14.5H7.34473V8.65039H1.5V7.34961H7.34473V1.5H8.64453Z', fill: 'currentColor' }))\n}\n\n/** IconTrashOutline16 */\nexport function IconTrashOutline16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M14.4782 4.84067L14.2138 10.1152C14.1102 12.1872 14.067 13.0115 13.3866 13.9607C13.1044 14.3546 12.7498 14.6912 12.3424 14.9535C11.8239 15.2872 11.2415 15.4316 10.5585 15.4998C9.88727 15.5668 9.04946 15.5656 7.99998 15.5656C6.95051 15.5656 6.1127 15.5668 5.44142 15.4998C4.75851 15.4316 4.17602 15.2872 3.65753 14.9535C3.25012 14.6912 2.89559 14.3546 2.61332 13.9607C1.93296 13.0115 1.88979 12.1872 1.78619 10.1152L1.52179 4.84067L2.89006 4.77277L3.15343 10.0463C3.26221 12.2218 3.32452 12.6015 3.72646 13.1624C3.90825 13.4161 4.13686 13.6334 4.39927 13.8023C4.66204 13.9714 5.00263 14.0792 5.57825 14.1367C6.16562 14.1953 6.92298 14.1963 7.99998 14.1963C9.07699 14.1963 9.83434 14.1953 10.4217 14.1367C10.9973 14.0792 11.3379 13.9714 11.6007 13.8023C11.8631 13.6334 12.0917 13.4161 12.2735 13.1624C12.6755 12.6015 12.7378 12.2218 12.8465 10.0463L13.1099 4.77277L14.4782 4.84067ZM5.43011 6.22849H6.7994V11.3909H5.43011V6.22849ZM9.20056 6.22849H10.5699V11.3909H9.20056V6.22849ZM8.53597 0.434431C9.17976 0.434431 9.6522 0.426926 10.0966 0.571258C10.2357 0.616451 10.3717 0.672554 10.502 0.738948C10.9182 0.951107 11.2464 1.29099 11.7015 1.74612L12.4978 2.54136H15.3742V3.91169H0.625732V2.54136H3.50218L4.29845 1.74612C4.75358 1.29099 5.08174 0.951107 5.49801 0.738948C5.62831 0.672554 5.76425 0.616451 5.90334 0.571258C6.34776 0.426926 6.82021 0.434431 7.46399 0.434431H8.53597ZM7.46399 1.80476C6.73208 1.80476 6.51641 1.81187 6.32617 1.87369C6.25545 1.89667 6.18668 1.92533 6.12041 1.95907C5.96398 2.03878 5.82348 2.16253 5.44142 2.54136H10.5585C10.1765 2.16253 10.036 2.03878 9.87955 1.95907C9.81329 1.92533 9.74452 1.89667 9.6738 1.87369C9.48356 1.81187 9.26789 1.80476 8.53597 1.80476H7.46399Z', fill: 'currentColor' }))\n}\n\n/** IconRefreshOutline16 */\nexport function IconRefreshOutline16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M7.92136 0.349152C10.3744 0.349234 12.5564 1.5052 13.9557 3.29894L15.1281 2.12759C15.3303 1.92546 15.6767 2.06943 15.6767 2.35538V5.53923C15.6766 5.71626 15.5329 5.85976 15.3559 5.86002H12.171C11.8854 5.8597 11.7426 5.51465 11.9443 5.31249L12.9641 4.29056C11.8237 2.74305 9.98908 1.74106 7.92136 1.74097C4.46436 1.74097 1.66233 4.543 1.66233 8C1.66233 11.457 4.46436 14.259 7.92136 14.259C11.3782 14.2589 14.1804 11.4569 14.1804 8H15.5722C15.5722 12.2251 12.1465 15.6507 7.92136 15.6508C3.69614 15.6508 0.270508 12.2252 0.270508 8C0.270508 3.77478 3.69614 0.349152 7.92136 0.349152Z', fill: 'currentColor' }))\n}\n\n/** IconGlobeOutline14 */\nexport function IconGlobeOutline14({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M7.00018 0.353516C10.6708 0.353535 13.6468 3.32958 13.6469 7.00018C13.6468 10.6708 10.6708 13.6468 7.00018 13.6469C3.32957 13.6468 0.353535 10.6708 0.353516 7.00018C0.353535 3.32957 3.32957 0.353531 7.00018 0.353516ZM5.44643 7.59661C5.49463 8.97506 5.70762 10.191 6.02136 11.0793C6.20141 11.5891 6.40328 11.9585 6.59898 12.1889C6.79501 12.4196 6.93213 12.454 7.00018 12.454C7.06822 12.454 7.20533 12.4197 7.40138 12.1889C7.59708 11.9585 7.79895 11.589 7.979 11.0793C8.29274 10.191 8.50574 8.97506 8.55394 7.59661H5.44643ZM1.57861 7.59661C1.80785 9.70467 3.2386 11.4509 5.1715 12.1388C5.07135 11.9317 4.97972 11.7098 4.89746 11.477C4.53084 10.4391 4.30224 9.0828 4.25357 7.59661H1.57861ZM9.74679 7.59661C9.69813 9.0828 9.46952 10.4391 9.1029 11.477C9.0206 11.7099 8.92818 11.9316 8.82797 12.1388C10.7613 11.4511 12.1925 9.70496 12.4218 7.59661H9.74679ZM5.1706 1.8616C3.23814 2.54963 1.80876 4.29604 1.5795 6.40376H4.25357C4.30224 4.91756 4.53083 3.56129 4.89746 2.5234C4.97968 2.29066 5.07051 2.0686 5.1706 1.8616ZM7.00018 1.54637C6.93213 1.54638 6.79503 1.5807 6.59898 1.81145C6.40332 2.04177 6.20139 2.41058 6.02136 2.92012C5.70754 3.80851 5.49461 5.02499 5.44643 6.40376H8.55394C8.50575 5.025 8.29282 3.80851 7.979 2.92012C7.79898 2.41059 7.59705 2.04177 7.40138 1.81145C7.20531 1.58067 7.06823 1.54637 7.00018 1.54637ZM8.82887 1.8616C8.92902 2.0687 9.02064 2.29053 9.1029 2.5234C9.46953 3.56129 9.69812 4.91756 9.74679 6.40376H12.4209C12.1916 4.29575 10.7618 2.54943 8.82887 1.8616Z', fill: 'currentColor' }))\n}\n\n/** IconGoalOutline16 */\nexport function IconGoalOutline16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M8 0C8.31451 0 8.62464 0.019379 8.92969 0.0546875C8.48228 0.403371 8.0952 0.825758 7.78809 1.30469C4.18586 1.41664 1.2998 4.37061 1.2998 8C1.2998 11.7003 4.29969 14.7002 8 14.7002C11.6297 14.7002 14.5829 11.8136 14.6943 8.21094C15.1734 7.90377 15.5956 7.51688 15.9443 7.06934C15.9797 7.37473 16 7.68512 16 8C16 12.4183 12.4183 16 8 16C3.58172 16 0 12.4183 0 8C0 3.58172 3.58172 0 8 0ZM7.0166 3.6084C7.00658 3.73765 7 3.86817 7 4C7 4.31845 7.03098 4.62973 7.08789 4.93164C5.76489 5.32438 4.7998 6.54958 4.7998 8C4.7998 9.76731 6.23269 11.2002 8 11.2002C9.45065 11.2002 10.6749 10.2345 11.0674 8.91113C11.3696 8.96818 11.6812 9 12 9C12.1315 9 12.2617 8.99239 12.3906 8.98242C11.9423 10.995 10.1477 12.5 8 12.5C5.51472 12.5 3.5 10.4853 3.5 8C3.5 5.85255 5.00435 4.05702 7.0166 3.6084Z', fill: 'currentColor' }),\n createElement('path', { d: 'M7.5 8.62109L9.12109 7', fill: 'currentColor' }),\n createElement('path', { d: 'M9.08245 3.35798L11.8651 0.575334C11.895 0.545384 11.9463 0.56391 11.9502 0.606086L12.2362 3.69859C12.2384 3.72259 12.2574 3.74159 12.2814 3.74378L15.3697 4.02583C15.4119 4.02968 15.4305 4.08101 15.4005 4.11098L12.618 6.89351C12.6086 6.90289 12.5959 6.90816 12.5826 6.90816L9.11781 6.90815C9.09019 6.90816 9.06781 6.88577 9.06781 6.85816L9.06781 3.39333C9.06781 3.38007 9.07308 3.36735 9.08245 3.35798Z', fill: 'currentColor' }))\n}\n\n/** IconWarningOutline16 */\nexport function IconWarningOutline16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M6.3002 3.32843L7.69986 3.32843L7.69986 7.79657H6.3002L6.3002 3.32843Z', fill: 'currentColor' }),\n createElement('path', { d: 'M6.3002 9.01935H7.69986V10.6711H6.3002V9.01935Z', fill: 'currentColor' }),\n createElement('path', { d: 'M12.6328 6.99976C12.6328 3.88874 10.111 1.36694 7 1.36694C3.88899 1.36695 1.3672 3.88875 1.36719 6.99976C1.36719 10.1108 3.88899 12.6326 7 12.6326C10.111 12.6326 12.6328 10.1108 12.6328 6.99976ZM13.8582 6.99976C13.8582 10.7873 10.7876 13.8579 7 13.8579C3.21244 13.8579 0.141846 10.7873 0.141846 6.99976C0.141857 3.2122 3.21245 0.141612 7 0.141602C10.7876 0.141602 13.8581 3.21219 13.8582 6.99976Z', fill: 'currentColor' }))\n}\n\n\n/**\n * Plugin-original companions for learning-domain glyphs the host set does not\n * carry (lock/star/book/crown/bolt/power/pin/flame) — authored here in the\n * same 16px currentColor filled language as the ic_ds set, but they are NOT\n * ic_ds glyphs and must be re-drawn (not re-synced) if the style drifts.\n */\n/** IconLockFill16 */\nexport function IconLockFill16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { 'fill-rule': 'evenodd', 'clip-rule': 'evenodd', d: 'M5 6.5V5a3 3 0 0 1 6 0v1.5h.6c.77 0 1.4.63 1.4 1.4v5.7c0 .77-.63 1.4-1.4 1.4H4.4A1.4 1.4 0 0 1 3 13.6V7.9c0-.77.63-1.4 1.4-1.4H5Zm1.444 0h3.112V5a1.556 1.556 0 0 0-3.112 0v1.5Z', fill: 'currentColor' }))\n}\n\n/** IconStarFill16 */\nexport function IconStarFill16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M8 1.6l1.86 3.77 4.16.6-3.01 2.94.71 4.14L8 11.42l-3.72 1.96.71-4.15-3.01-2.93 4.16-.6L8 1.6Z', fill: 'currentColor' }))\n}\n\n/** IconBookFill16 */\nexport function IconBookFill16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { 'fill-rule': 'evenodd', 'clip-rule': 'evenodd', d: 'M8 3.1C6.6 2.15 4.65 1.75 2.5 1.75c-.5 0-1 .03-1.5.1v10.7c.5-.07 1-.1 1.5-.1 2.15 0 4.1.4 5.5 1.35 1.4-.95 3.35-1.35 5.5-1.35.5 0 1 .03 1.5.1V1.85c-.5-.07-1-.1-1.5-.1-2.15 0-4.1.4-5.5 1.35ZM7.2 4.9v7.3C5.9 11.55 4.3 11.3 2.6 11.3V3.45c1.7 0 3.3.25 4.6 1.45Zm1.6 0c1.3-1.2 2.9-1.45 4.6-1.45v7.85c-1.7 0-3.3.25-4.6.9V4.9Z', fill: 'currentColor' }))\n}\n\n/** IconCrownFill16 */\nexport function IconCrownFill16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M1.7 11.2 1 4.9l3.6 2.2L8 2.6l3.4 4.5L15 4.9l-.7 6.3H1.7Zm.5 1.4h11.6v1.5H2.1v-1.5Z', fill: 'currentColor' }))\n}\n\n/** IconBoltFill16 */\nexport function IconBoltFill16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M9.6 1 3.4 9.3h3.4L6.3 15l6.3-8.5H9.2L9.6 1Z', fill: 'currentColor' }))\n}\n\n/** IconPowerFill16 */\nexport function IconPowerFill16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M7.2 1h1.6v5.6H7.2V1Z', fill: 'currentColor' }),\n createElement('path', { 'fill-rule': 'evenodd', 'clip-rule': 'evenodd', d: 'M4.55 3.15A6 6 0 1 0 11.45 3.15L12.5 4.2a7.5 7.5 0 1 1-9 0l1.05-1.05Z', fill: 'currentColor' }))\n}\n\n/** IconPinFill16 */\nexport function IconPinFill16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { 'fill-rule': 'evenodd', 'clip-rule': 'evenodd', d: 'M8 1.4a4.8 4.8 0 0 1 4.8 4.8c0 3.4-4.8 8.4-4.8 8.4S3.2 9.6 3.2 6.2A4.8 4.8 0 0 1 8 1.4Zm0 2.7a2.1 2.1 0 1 0 0 4.2 2.1 2.1 0 0 0 0-4.2Z', fill: 'currentColor' }))\n}\n\n/** IconFlameFill16 */\nexport function IconFlameFill16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M8.9 1.2c.4 2.5-.9 3.9-2.1 5.2C5.6 7.7 4.4 9 4.4 10.9a3.9 3.9 0 0 0 7.8 0c0-1.6-.7-2.9-1.5-4-.3.8-.8 1.4-1.6 1.7.5-2.4-.2-5.4-1.2-7.4Z', fill: 'currentColor' }))\n}\n\n","/**\n * Shared client-side study store: one module-level poller over the host\n * plugin's `/lookatstudy/api/state` endpoint, plus the three write actions\n * (focus, mode, reverse message). Every seat component binds through\n * {@link useStudy}; subscribers share the single 3 s poll cycle and the last\n * snapshot, so mounting more controls costs no extra requests.\n * @module dsh-plugin-lookatstudy/client/data\n */\n\nimport { useSyncExternalStore } from 'react'\n\n/** Wire shape of `GET /lookatstudy/api/state` (structural mirror of the host's WorkbenchState). */\nexport interface StudyState {\n readonly active: boolean\n readonly mode: 'direct' | 'guide' | 'practice'\n readonly courses: ReadonlyArray<{\n readonly courseId: string\n readonly title: string\n readonly mastered: number\n readonly total: number\n readonly avgMasteryPct: number | null\n readonly sections: ReadonlyArray<{\n readonly title: string\n readonly index: number\n readonly lessons: ReadonlyArray<{\n readonly id: string\n readonly title: string\n readonly kind: 'study' | 'practice' | 'exam'\n readonly status: string\n readonly masteryPct: number | null\n readonly weakConcepts: number\n readonly frictionCount: number\n readonly due: boolean\n readonly focus: boolean\n }>\n }>\n }>\n readonly focusLessonId: string | null\n readonly lesson: {\n readonly lessonId: string\n readonly courseTitle: string\n readonly sectionTitle: string\n readonly title: string\n readonly status: string\n readonly masteryPct: number | null\n readonly strategy: string\n readonly concepts: ReadonlyArray<{ title: string; masteryPct: number; weak: boolean }>\n readonly starters: ReadonlyArray<{ label: string; message: string }>\n readonly notes: ReadonlyArray<{ id: string; zone: string; title: string; text: string; source: string; quote: string | null }>\n readonly html: string\n readonly markdown: string\n } | null\n readonly dueCount: number\n readonly due: ReadonlyArray<{ lessonId: string; lessonTitle: string; courseTitle: string; overdueDays: number }>\n readonly pendingProposals: ReadonlyArray<{ id: string; lessonTitle: string; rationale: string }>\n readonly memory: { global: string | null; lesson: string | null; pattern: string | null }\n readonly lessonSessions: Readonly<Record<string, string>>\n /** XP + streak block (mirrors study_courses; feeds the dock pill and the settings page). */\n readonly progress: {\n readonly totalXp: number\n readonly level: number\n readonly levelPct: number\n readonly todayXp: number\n readonly dailyGoal: number\n readonly streak: number\n readonly longestStreak: number\n readonly freezeCount: number\n }\n /** Absolute state-file path (read-only display). */\n readonly statePath: string\n /** Plugin version from the running build's package.json (settings About row). */\n readonly version: string\n}\n\n/** Poll cadence for the shared store; one cycle serves every mounted seat. */\nconst POLL_MS = 3_000\n\ntype Listener = () => void\n\nasync function fetchJson(url: string, init?: RequestInit): Promise<unknown> {\n const res = await fetch(url, init)\n const body: unknown = await res.json().catch(() => null)\n if (!res.ok) {\n const error = body !== null && typeof body === 'object' && 'error' in body && typeof body.error === 'string'\n ? body.error\n : `HTTP ${res.status}`\n throw new Error(error)\n }\n return body\n}\n\nclass StudyStore {\n private snapshot: StudyState | null = null\n private readonly listeners = new Set<Listener>()\n private timer: ReturnType<typeof setInterval> | undefined\n private inflight = false\n\n subscribe = (listener: Listener): (() => void) => {\n this.listeners.add(listener)\n if (this.listeners.size === 1) {\n void this.tick()\n this.timer = setInterval(() => { void this.tick() }, POLL_MS)\n }\n return () => {\n this.listeners.delete(listener)\n if (this.listeners.size === 0 && this.timer !== undefined) {\n clearInterval(this.timer)\n this.timer = undefined\n }\n }\n }\n\n getSnapshot = (): StudyState | null => this.snapshot\n\n private emit(): void {\n for (const listener of this.listeners) listener()\n }\n\n private async tick(): Promise<void> {\n if (this.inflight) return\n this.inflight = true\n try {\n const next = await fetchJson('/lookatstudy/api/state') as StudyState\n this.snapshot = next\n this.emit()\n } catch {\n // Host route absent (headless composition) or transient failure: keep\n // the last snapshot; seats render their loading/empty states.\n } finally {\n this.inflight = false\n }\n }\n\n /** One immediate re-read (after a write action). */\n refresh(): void {\n void this.tick()\n }\n\n /** Switch the tutor's soul mode directly (host persists and applies it on the next request). */\n async setMode(mode: StudyState['mode']): Promise<void> {\n await fetchJson('/lookatstudy/api/mode', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ mode }),\n })\n this.refresh()\n }\n\n /**\n * Flip learning mode. The host syncs its tool registry before responding,\n * so awaiting this guarantees the `study_*` tools exist for the next prompt.\n */\n async activate(active: boolean): Promise<void> {\n await fetchJson('/lookatstudy/api/active', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ active }),\n })\n this.refresh()\n }\n\n /** Full-text lesson search (rail fallback when local title matching misses). */\n async searchLessons(query: string): Promise<Array<{ lessonId: string; lessonTitle: string; snippet: string }>> {\n const body = await fetchJson(`/lookatstudy/api/search?q=${encodeURIComponent(query)}`) as { matches?: Array<{ lessonId: string; lessonTitle: string; snippet: string }> }\n return body.matches ?? []\n }\n\n /** Point the tutor's focus at one lesson. */\n async setFocus(lessonId: string): Promise<void> {\n await fetchJson('/lookatstudy/api/focus', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ lessonId }),\n })\n this.refresh()\n }\n\n /** Record the dsh session backing one lesson (the simplified thread system). */\n async bindLessonSession(lessonId: string, sessionId: string): Promise<void> {\n await fetchJson('/lookatstudy/api/lesson-session', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ lessonId, sessionId }),\n })\n this.refresh()\n }\n\n /** Delete one course (and its proposals) from the host state. */\n async deleteCourse(courseId: string): Promise<void> {\n await fetchJson('/lookatstudy/api/course/delete', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ courseId }),\n })\n this.refresh()\n }\n}\n\n/** The one shared store instance backing every study seat component. */\nexport const studyStore = new StudyStore()\n\n/** React binding: live snapshot plus the write actions. */\nexport function useStudy(): {\n data: StudyState | null\n activate: (active: boolean) => Promise<void>\n setMode: (mode: StudyState['mode']) => Promise<void>\n setFocus: (lessonId: string) => Promise<void>\n searchLessons: (query: string) => Promise<Array<{ lessonId: string; lessonTitle: string; snippet: string }>>\n deleteCourse: (courseId: string) => Promise<void>\n bindLessonSession: (lessonId: string, sessionId: string) => Promise<void>\n} {\n const data = useSyncExternalStore(studyStore.subscribe, studyStore.getSnapshot, studyStore.getSnapshot)\n return {\n data,\n activate: studyStore.activate.bind(studyStore),\n setMode: studyStore.setMode.bind(studyStore),\n setFocus: studyStore.setFocus.bind(studyStore),\n searchLessons: studyStore.searchLessons.bind(studyStore),\n deleteCourse: studyStore.deleteCourse.bind(studyStore),\n bindLessonSession: studyStore.bindLessonSession.bind(studyStore),\n }\n}\n","/**\n * Server-side markdown → HTML for the study workbench's 讲解 view. Escapes\n * every HTML character first, then renders a pragmatic GFM subset (headings,\n * fenced code, inline code, bold/italic, links, lists, blockquotes, tables,\n * hr, paragraphs). Lesson bodies are imported teaching material, so raw HTML\n * never passes through.\n * @module dsh-plugin-lookatstudy/markdown\n */\n\n/** Escape all HTML-significant characters. */\nfunction escapeHtml(text: string): string {\n return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;')\n}\n\n/** Render inline markup (code, bold, italic, links, images) over escaped text.\n * Image src allowlist: https?:// or data:image/ — folder imports inline local\n * images as data URLs (capped), GitHub imports reference jsDelivr; anything\n * else stays literal text (no broken relative images, no exotic schemes). */\nfunction inline(escaped: string): string {\n return escaped\n .replace(/`([^`]+)`/g, '<code>$1</code>')\n .replace(/\\*\\*([^*]+)\\*\\*/g, '<strong>$1</strong>')\n .replace(/\\*([^*]+)\\*/g, '<em>$1</em>')\n .replace(/!\\[([^\\]]*)\\]\\((https?:\\/\\/[^)\\s]+|data:image\\/[^)\\s]+)\\)/g, (_m, alt: string, src: string) => `<img src=\"${src}\" alt=\"${alt}\" loading=\"lazy\">`)\n .replace(/\\[([^\\]]+)\\]\\((https?:\\/\\/[^)\\s]+)\\)/g, '<a href=\"$2\" target=\"_blank\" rel=\"noreferrer\">$1</a>')\n}\n\n/** Interleave one body with its translation, paragraph by paragraph (upstream\n * translation-layout \"microsoft\" semantics: original paragraph then its\n * translation as a quote, tight pairing for bilingual reading; length\n * mismatches append the remainder in order). Pure. */\nexport function renderBilingual(bodyMd: string, translationMd: string): string {\n const par = (md: string): string[] => md.split(/\\n\\s*\\n/).map(p => p.trim()).filter(p => p !== '')\n const a = par(bodyMd)\n const b = par(translationMd)\n const out: string[] = []\n for (let i = 0; i < Math.max(a.length, b.length); i++) {\n if (a[i] !== undefined) out.push(a[i]!)\n if (b[i] !== undefined) out.push(`> ${b[i]!.split('\\n').join('\\n> ')}`)\n }\n return out.join('\\n\\n')\n}\n\n/** True when the line opens a GFM table row (pipes with a delimiter row next). */\nfunction isTableRow(line: string): boolean {\n return line.trim().startsWith('|') && line.trim().endsWith('|') && line.includes('|', 1)\n}\n\nfunction isDelimiterRow(line: string): boolean {\n const trimmed = line.trim()\n if (!trimmed.startsWith('|') || !trimmed.endsWith('|')) return false\n const cells = trimmed.replace(/^\\|/, '').replace(/\\|$/, '').split('|').map(c => c.trim())\n return cells.length > 0 && cells.every(c => /^:?-+:?$/.test(c))\n}\n\n/** Split a table row into trimmed cells (leading/trailing pipes removed). */\nfunction rowCells(line: string): string[] {\n return line.trim().replace(/^\\|/, '').replace(/\\|$/, '').split('|').map(c => c.trim())\n}\n\n/**\n * Render markdown text to sanitized HTML.\n * @param md - markdown source (lesson body).\n * @returns HTML string safe to inject into the page.\n */\nexport function renderMarkdown(md: string): string {\n const lines = escapeHtml(md).split(/\\r?\\n/)\n const out: string[] = []\n let i = 0\n\n const flushParagraph = (buffer: string[]): void => {\n if (buffer.length > 0) out.push(`<p>${inline(buffer.join(' '))}</p>`)\n }\n\n let paragraph: string[] = []\n while (i < lines.length) {\n const line = lines[i]!\n\n // Fenced code block\n const fence = /^```(\\w*)\\s*$/.exec(line.trim())\n if (fence) {\n flushParagraph(paragraph)\n paragraph = []\n const lang = fence[1] ?? ''\n const code: string[] = []\n i++\n while (i < lines.length && lines[i]!.trim() !== '```') {\n code.push(lines[i]!)\n i++\n }\n i++ // closing fence\n out.push(`<pre><code${lang === '' ? '' : ` class=\"lang-${lang}\"`}>${code.join('\\n')}</code></pre>`)\n continue\n }\n\n // Heading\n const heading = /^(#{1,6})\\s+(.*)$/.exec(line)\n if (heading) {\n flushParagraph(paragraph)\n paragraph = []\n const level = heading[1]!.length\n out.push(`<h${level}>${inline(heading[2]!)}</h${level}>`)\n i++\n continue\n }\n\n // Horizontal rule\n if (/^\\s*(-{3,}|\\*{3,}|_{3,})\\s*$/.test(line)) {\n flushParagraph(paragraph)\n paragraph = []\n out.push('<hr>')\n i++\n continue\n }\n\n // Blockquote\n if (/^\\s*&gt;\\s?/.test(line)) {\n flushParagraph(paragraph)\n paragraph = []\n const quote: string[] = []\n while (i < lines.length && /^\\s*&gt;\\s?/.test(lines[i]!)) {\n quote.push(lines[i]!.replace(/^\\s*&gt;\\s?/, ''))\n i++\n }\n out.push(`<blockquote><p>${inline(quote.join(' '))}</p></blockquote>`)\n continue\n }\n\n // Unordered list\n if (/^\\s*[-*+]\\s+/.test(line)) {\n flushParagraph(paragraph)\n paragraph = []\n const items: string[] = []\n while (i < lines.length && /^\\s*[-*+]\\s+/.test(lines[i]!)) {\n items.push(`<li>${inline(lines[i]!.replace(/^\\s*[-*+]\\s+/, ''))}</li>`)\n i++\n }\n out.push(`<ul>${items.join('')}</ul>`)\n continue\n }\n\n // Ordered list\n if (/^\\s*\\d+\\.\\s+/.test(line)) {\n flushParagraph(paragraph)\n paragraph = []\n const items: string[] = []\n while (i < lines.length && /^\\s*\\d+\\.\\s+/.test(lines[i]!)) {\n items.push(`<li>${inline(lines[i]!.replace(/^\\s*\\d+\\.\\s+/, ''))}</li>`)\n i++\n }\n out.push(`<ol>${items.join('')}</ol>`)\n continue\n }\n\n // GFM table\n if (isTableRow(line) && i + 1 < lines.length && isDelimiterRow(lines[i + 1]!)) {\n flushParagraph(paragraph)\n paragraph = []\n const headers = rowCells(line)\n i += 2\n const rows: string[] = []\n while (i < lines.length && isTableRow(lines[i]!)) {\n const cells = rowCells(lines[i]!)\n rows.push(`<tr>${cells.map(c => `<td>${inline(c)}</td>`).join('')}</tr>`)\n i++\n }\n out.push(`<table><thead><tr>${headers.map(h => `<th>${inline(h)}</th>`).join('')}</tr></thead><tbody>${rows.join('')}</tbody></table>`)\n continue\n }\n\n // Blank line ends the paragraph\n if (line.trim() === '') {\n flushParagraph(paragraph)\n paragraph = []\n i++\n continue\n }\n\n paragraph.push(line.trim())\n i++\n }\n flushParagraph(paragraph)\n return out.join('\\n')\n}\n","// Vendored from LookatStudy src/renderer/lib/mermaid-elk-rewrite.ts (MIT License, https://github.com/Kaiji-Z/LookatStudy).\n// Unmodified except this provenance header (elkjs dynamic import target adapted to CDN).\n/**\n * mermaid-elk-rewrite —— flowchart → flowchart-elk 前缀改写(v0.21 纯函数)。\n *\n * 只在渲染层改写:LLM 出题提示词(draw_diagram)与语法修复回路\n * (diagram-repair-service)都继续产出/接收**原版 flowchart 语法**,零改动;\n * renderMermaid 喂给 mermaid 前把 flowchart/graph 声明行改成 flowchart-elk ——\n * 同一套语法换 ELK 布局引擎(正交路由,复杂流程图边交叉显著少于 dagre)。\n *\n * mermaid 机制:flowchart-elk 前缀 → detector 置 config.layout=\"elk\" → 查\n * registerLayoutLoaders 注册的 \"elk\" 算法;未注册则静默退 dagre 并 console.warn\n * (ui-test 靠该 warn 断言 ELK 真实生效)。\n *\n * 范围:只改首个内容行的 flowchart 家族声明;sequenceDiagram/stateDiagram-v2/\n * classDiagram 等其余图类型原样返回(ELK 布局只对 flowchart 家族注册)。\n */\n\n/** 首个内容行(跳过空行与 %% 注释/`%%{init}%%` 指令行)的 flowchart 声明改为\n * flowchart-elk;已是 flowchart-elk 则幂等返回;其他图类型不动。 */\nexport function rewriteFlowchartToElk(code: string): string {\n const lines = code.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i] ?? \"\";\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(\"%%\")) continue;\n if (/^flowchart-elk\\b/i.test(trimmed)) return code;\n if (/^(flowchart|graph)\\b/i.test(trimmed)) {\n lines[i] = line.replace(/^(\\s*)(flowchart|graph)\\b/i, \"$1flowchart-elk\");\n return lines.join(\"\\n\");\n }\n // 首个内容行不是 flowchart 家族 → 其他图类型,不改写\n return code;\n }\n return code;\n}\n","/**\n * Post-render blackboard enhancement (SPEC Phase 2): math (KaTeX), code\n * highlighting (shiki), and mermaid diagrams — every dependency loaded from a\n * CDN at runtime (zero-dependency mandate: nothing enters the bundle), every\n * failure degrading silently to the existing plain rendering. Upstream parity:\n * math-normalize runs host-side before renderMarkdown; the CDN + lazy-singleton\n * pattern follows upstream lazy-shiki/lazy-mermaid, pointed at esm.sh/cdnjs.\n *\n * Test seams: every loader is injectable via `setEnhanceDeps` so node:test\n * proves the enhance/degrade paths offline (the structural-test discipline:\n * prove a gate fails first, then trust its green).\n */\n\n/** Map a lang-xxx class to shiki's grammar id (upstream's curated set, aliases included). */\nconst LANG_ALIAS: Record<string, string> = {\n ts: 'typescript', tsx: 'tsx', js: 'javascript', jsx: 'jsx', mjs: 'javascript', cjs: 'javascript',\n py: 'python', rb: 'ruby', rs: 'rust', 'c++': 'cpp', cs: 'csharp', kt: 'kotlin', sh: 'bash', shell: 'bash', zsh: 'bash',\n yml: 'yaml', md: 'markdown', tex: 'latex', docker: 'dockerfile',\n}\n\nimport { rewriteFlowchartToElk } from '../vendor/mermaid-elk-rewrite.ts'\n\ntype KatexLike = { renderToString(tex: string, opts: Record<string, unknown>): string }\ntype ShikiLike = { codeToHtml(code: string, opts: Record<string, unknown>): Promise<string> }\ntype MermaidLike = { registerLayoutLoaders(l: unknown): void; initialize(cfg: Record<string, unknown>): void; render(id: string, code: string): Promise<{ svg: string }> }\n\nexport interface EnhanceDeps {\n loadKatex?: () => Promise<KatexLike>\n loadShiki?: () => Promise<ShikiLike>\n loadMermaid?: () => Promise<MermaidLike>\n}\nlet deps: EnhanceDeps = {}\nexport function setEnhanceDeps(d: EnhanceDeps | null): void { deps = d ?? {} }\n\n/* ---------------- CDN loaders (production defaults) ---------------- */\n\nconst CDN = {\n katexJs: 'https://cdn.jsdelivr.net/npm/katex@0.16.22/dist/katex.min.js',\n katexCss: 'https://cdn.jsdelivr.net/npm/katex@0.16.22/dist/katex.min.css',\n shiki: 'https://esm.sh/shiki@1.29.2',\n mermaid: 'https://esm.sh/mermaid@11.4.1',\n mermaidElk: 'https://esm.sh/@mermaid-js/layout-elk@0.1.7',\n}\n\nfunction loadScript(src: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const el = document.createElement('script')\n el.src = src\n el.onload = () => { resolve() }\n el.onerror = () => { reject(new Error(`script load failed: ${src}`)) }\n document.head.append(el)\n })\n}\n\nlet katexPromise: Promise<KatexLike> | null = null\nfunction defaultLoadKatex(): Promise<KatexLike> {\n katexPromise ??= (async () => {\n if (!document.querySelector(`link[data-lks-katex]`)) {\n const link = document.createElement('link')\n link.rel = 'stylesheet'\n link.href = CDN.katexCss\n link.setAttribute('data-lks-katex', '1')\n document.head.append(link)\n }\n if ((window as { katex?: KatexLike }).katex === undefined) await loadScript(CDN.katexJs)\n const katex = (window as { katex?: KatexLike }).katex\n if (katex === undefined) throw new Error('katex missing after load')\n return katex\n })()\n return katexPromise\n}\n\nlet shikiPromise: Promise<ShikiLike> | null = null\nfunction defaultLoadShiki(): Promise<ShikiLike> {\n shikiPromise ??= import(/* @vite-ignore */ CDN.shiki).then((mod: Record<string, unknown>) => {\n const create = mod.createHighlighter as ((opts: Record<string, unknown>) => Promise<ShikiLike>) | undefined\n if (create === undefined) throw new Error('shiki createHighlighter missing')\n return create({ themes: ['github-dark', 'github-light'], langs: ['typescript', 'javascript', 'python', 'bash', 'json', 'yaml', 'css', 'html', 'markdown', 'cpp', 'go', 'rust', 'java', 'sql'] })\n }) as Promise<ShikiLike>\n return shikiPromise\n}\n\nlet mermaidPromise: Promise<MermaidLike> | null = null\nfunction defaultLoadMermaid(): Promise<MermaidLike> {\n mermaidPromise ??= (async () => {\n const mod = await import(/* @vite-ignore */ CDN.mermaid) as Record<string, unknown>\n const mermaid = mod.default as MermaidLike\n try {\n const elk = await import(/* @vite-ignore */ CDN.mermaidElk) as Record<string, unknown>\n mermaid.registerLayoutLoaders(elk.default)\n } catch { /* ELK unavailable → mermaid falls back to dagre silently */ }\n mermaid.initialize({ startOnLoad: false, theme: 'base', securityLevel: 'loose' })\n return mermaid\n })()\n return mermaidPromise\n}\n\n/* ---------------- enhancers ---------------- */\n\n/** Split one text node's data around the FIRST math span; returns null when none. */\nfunction findMathSpan(text: string): { before: string; tex: string; after: string; display: boolean } | null {\n const display = /\\$\\$([^$]+)\\$\\$/.exec(text)\n const inline = /\\$([^$\\n]+)\\$/.exec(text)\n if (display === null && inline === null) return null\n const m = display !== null && (inline === null || display.index <= inline.index) ? { ...display, display: true } : inline === null ? null : { ...inline, display: false }\n if (m === null) return null\n return { before: text.slice(0, m.index), tex: m[1]!, after: text.slice(m.index + m[0].length), display: m.display }\n}\n\n/** KaTeX every $..$ / $$..$$ in the container; degrades to plain text on any failure. */\nexport async function enhanceMath(container: HTMLElement): Promise<number> {\n let katex: KatexLike\n try { katex = await (deps.loadKatex ?? defaultLoadKatex)() } catch { return 0 }\n let replaced = 0\n const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT)\n const targets: Text[] = []\n let node: Node | null\n while ((node = walker.nextNode()) !== null) {\n if (findMathSpan((node as Text).data) !== null && (node as Text).parentElement?.tagName !== 'CODE') targets.push(node as Text)\n }\n for (const t of targets) {\n const span = findMathSpan(t.data)\n if (span === null) continue\n try {\n const html = katex.renderToString(span.tex, { displayMode: span.display, throwOnError: false })\n const holder = document.createElement('span')\n holder.innerHTML = html\n if (span.before !== '') t.before(document.createTextNode(span.before))\n t.before(holder)\n t.data = span.after\n replaced++\n } catch { /* leave the text as-is */ }\n }\n return replaced\n}\n\n/** shiki-highlight every fenced code block; unknown langs and failures keep the plain <pre>. */\nexport async function enhanceCode(container: HTMLElement): Promise<number> {\n let shiki: ShikiLike\n try { shiki = await (deps.loadShiki ?? defaultLoadShiki)() } catch { return 0 }\n let replaced = 0\n const blocks = [...container.querySelectorAll<HTMLElement>('pre > code')]\n for (const code of blocks) {\n if (code.dataset.lksEnhanced === '1') continue\n const langClass = [...code.classList].find(c => c.startsWith('lang-'))\n if (langClass === undefined) continue\n const lang = LANG_ALIAS[langClass.slice(5)] ?? langClass.slice(5)\n try {\n const html = await shiki.codeToHtml(code.textContent ?? '', {\n lang,\n themes: { light: 'github-light', dark: 'github-dark' },\n defaultColor: false,\n cssVariables: { '--shiki-dark': 'var(--shiki-dark, #e6edf3)' },\n })\n code.dataset.lksEnhanced = '1'\n const pre = code.parentElement!\n const wrap = document.createElement('div')\n wrap.className = 'lks-shiki'\n wrap.innerHTML = html\n pre.replaceWith(wrap)\n replaced++\n } catch { code.dataset.lksEnhanced = '1' /* don't retry a failing lang */ }\n }\n return replaced\n}\n\n/** Render mermaid fence blocks to SVG (ELK layout via the registered loader);\n * the flowchart prefix rewrite is upstream's mermaid-elk-rewrite, vendored. */\nexport async function enhanceDiagrams(container: HTMLElement): Promise<number> {\n let mermaid: MermaidLike\n try { mermaid = await (deps.loadMermaid ?? defaultLoadMermaid)() } catch { return 0 }\n let replaced = 0\n const blocks = [...container.querySelectorAll<HTMLElement>('pre > code.lang-mermaid')]\n for (const code of blocks) {\n if (code.dataset.lksEnhanced === '1') continue\n code.dataset.lksEnhanced = '1'\n try {\n const { svg } = await mermaid.render(`lks-mermaid-${replaced}`, rewriteFlowchartToElk(code.textContent ?? ''))\n const wrap = document.createElement('div')\n wrap.className = 'lks-mermaid'\n wrap.innerHTML = svg\n code.parentElement!.replaceWith(wrap)\n replaced++\n } catch { /* keep the code block as-is */ }\n }\n return replaced\n}\n\n/** The full pass over one freshly-rendered container. Never throws. */\nexport async function enhanceRendered(container: HTMLElement): Promise<void> {\n try { await enhanceDiagrams(container) } catch { /* degrade */ }\n try { await enhanceCode(container) } catch { /* degrade */ }\n try { await enhanceMath(container) } catch { /* degrade */ }\n}\n\n","// Vendored from LookatStudy src/renderer/lib/cmap-elk-layout.ts (MIT License, https://github.com/Kaiji-Z/LookatStudy).\n// Unmodified except this provenance header (elkjs dynamic import target adapted to CDN).\n/**\n * cmap-elk-layout —— 概念图 v2 布局(ELK layered,复合分组 + 正交路由)。\n *\n * v0.12 径向布局的视觉评审结论:空白与拥挤并存/边交叉/无层级,且交叉消解要靠\n * 自研启发式。v0.21 换 elkjs(draw.io 新版同款 Eclipse Layout Kernel):\n * - 分组 = ELK 复合图(compound children):组容器盒 + 标题栏留白\n * - 连线 = elk.edgeRouting ORTHOGONAL:直角折线绕开盒子,结构性消灭\"线穿节点\"\n * - 分组来源:LLM show_concept_map 的可选 groups 字段;缺省/无效时客户端按\n * 邻接聚类兜底(clusterByAdjacency,确定性多源 BFS),不回头折腾 prompt\n *\n * 结构分层(全部可单测):\n * resolveGroups / clusterByAdjacency / cmNodeBox / buildElkGraph —— 纯函数\n * flattenElkResult —— 把 ELK 输出递归拍平成绝对坐标(复合嵌套只有一层)\n * layoutConceptMap —— 异步管线,elkjs 走动态 import(lazy chunk,同 mermaid)\n *\n * CJK 估宽/两行包裹沿用 v0.12 已验证的实现(estTextWidth/wrapLabel 原样迁移)。\n * 全链确定性:输入序驱动 + ELK 无随机源,verify-artifact-cmap-v2 断言两次运行\n * 逐坐标全等。\n */\n\n// ============================================================\n// 数据类型(与 artifact-harness ConceptMapData 对齐,groups 为 v2 增列)\n// ============================================================\n\nexport interface CmNode {\n id: string;\n label: string;\n}\nexport interface CmEdge {\n from: string;\n to: string;\n label?: string;\n}\nexport interface CmGroup {\n id: string;\n label: string;\n nodeIds: string[];\n}\n\n// ============================================================\n// 文本度量(v0.12 迁移,CJK 感知)\n// ============================================================\n\n/** 字符宽度估算:CJK 全宽,ASCII 约 0.58em,其余(BBOP…)同 ASCII。 */\nexport function estTextWidth(text: string, fontSize = 13): number {\n let w = 0;\n for (const ch of text) w += /[\\u2e80-\\u9fff\\uf900-\\ufaff\\uff00-\\uffef\\u3000-\\u303f]/.test(ch) ? fontSize : fontSize * 0.58;\n return w;\n}\n\nconst LINE_MAX_PX = 118;\n\n/** 标签包裹:≤2 行;优先自然断点(空格///-),CJK 连续按宽度一半硬拆;仍超宽截断。 */\nexport function wrapLabel(label: string): string[] {\n if (estTextWidth(label) <= LINE_MAX_PX) return [label];\n const breaks: number[] = [];\n for (let i = 0; i < label.length; i++) {\n if (/[\\s/\\-—·]/.test(label[i] ?? \"\")) breaks.push(i);\n }\n const mid = label.length / 2;\n let split = -1;\n let best = Infinity;\n for (const b of breaks) {\n const d = Math.abs(b + 1 - mid);\n if (d < best) {\n best = d;\n split = b;\n }\n }\n let l1: string;\n let l2: string;\n if (split >= 0) {\n l1 = label.slice(0, split + 1).trim();\n l2 = label.slice(split + 1).trim();\n } else {\n let acc = 0;\n let idx = 0;\n for (const ch of label) {\n acc += estTextWidth(ch);\n idx++;\n if (acc >= estTextWidth(label) / 2) break;\n }\n l1 = label.slice(0, idx);\n l2 = label.slice(idx);\n }\n if (estTextWidth(l1) <= LINE_MAX_PX && estTextWidth(l2) <= LINE_MAX_PX) return [l1, l2];\n const fit = (s: string) => {\n let out = \"\";\n for (const ch of s) {\n if (estTextWidth(out + ch + \"…\") > LINE_MAX_PX) break;\n out += ch;\n }\n return out + \"…\";\n };\n return [estTextWidth(l1) > LINE_MAX_PX ? fit(l1) : l1, estTextWidth(l2) > LINE_MAX_PX ? fit(l2) : l2];\n}\n\n/** 节点盒:hub(度数最大或 ≥4)字号/内边距更大;宽高由包裹后行宽决定。 */\nexport function cmNodeBox(label: string, hub: boolean): { width: number; height: number; lines: string[] } {\n const lines = wrapLabel(label);\n const fs = hub ? 14 : 13;\n const textW = Math.max(...lines.map((l) => estTextWidth(l, fs)));\n const padX = hub ? 30 : 24;\n const lh = 17;\n const padY = hub ? 18 : 14;\n return {\n width: Math.min(hub ? 200 : 180, Math.max(hub ? 92 : 76, textW + padX)),\n height: padY + lines.length * lh,\n lines,\n };\n}\n\n// ============================================================\n// 分组解析:LLM groups 优先,邻接聚类兜底\n// ============================================================\n\nexport interface ResolvedGroups {\n groups: CmGroup[];\n /** true = 来自客户端聚类(LLM 未给/无效) */\n fallback: boolean;\n}\n\n/**\n * 净化 LLM groups:丢弃指向不存在节点的 nodeIds、去重(先到先得)、\n * 剩余成员 < 2 的组丢弃;唯一覆盖全部节点的单组视为无效(一个巨容器没有信息量)。\n * 净化后为空 → clusterByAdjacency 兜底。\n */\nexport function resolveGroups(nodes: CmNode[], edges: CmEdge[], input?: CmGroup[] | null): ResolvedGroups {\n const ids = new Set(nodes.map((n) => n.id));\n if (Array.isArray(input) && input.length > 0) {\n const assigned = new Set<string>();\n const groups: CmGroup[] = [];\n for (const g of input) {\n if (!g || typeof g.id !== \"string\" || !g.id) continue;\n const nodeIds = Array.isArray(g.nodeIds)\n ? [...new Set(g.nodeIds.filter((x) => typeof x === \"string\" && ids.has(x) && !assigned.has(x)))]\n : [];\n if (nodeIds.length < 2) continue;\n nodeIds.forEach((x) => assigned.add(x));\n groups.push({ id: g.id, label: typeof g.label === \"string\" && g.label ? g.label : \"分组\", nodeIds });\n }\n if (groups.length > 0 && !(groups.length === 1 && assigned.size === nodes.length && nodes.length > 2)) {\n return { groups, fallback: false };\n }\n }\n return { groups: clusterByAdjacency(nodes, edges), fallback: true };\n}\n\n/**\n * 邻接聚类兜底(确定性):度数 top-k 节点做种子(k = clamp(ceil(n/4),1,3)),\n * 多源 BFS 就近归属(平手先出现的种子赢);孤立节点不归组(根层漂浮,不造假组)。\n * 组名 = 种子标签(≤5 字加\"相关\")。\n */\nexport function clusterByAdjacency(nodes: CmNode[], edges: CmEdge[]): CmGroup[] {\n if (nodes.length < 4) return []; // 太小不分组\n const index = new Map(nodes.map((n, i) => [n.id, i] as const));\n const adj = new Map<string, string[]>();\n for (const n of nodes) adj.set(n.id, []);\n const seenPair = new Set<string>();\n for (const e of edges) {\n if (!index.has(e.from) || !index.has(e.to) || e.from === e.to) continue;\n const key = [e.from, e.to].sort().join(\"→\");\n if (seenPair.has(key)) continue;\n seenPair.add(key);\n adj.get(e.from)!.push(e.to);\n adj.get(e.to)!.push(e.from);\n }\n const ranked = [...nodes].sort((a, b) => {\n const da = adj.get(a.id)!.length;\n const db = adj.get(b.id)!.length;\n return da !== db ? db - da : (index.get(a.id) ?? 0) - (index.get(b.id) ?? 0);\n });\n const k = Math.min(3, Math.max(1, Math.ceil(nodes.length / 4)));\n const seeds = ranked.slice(0, k).filter((s) => (adj.get(s.id)?.length ?? 0) > 0);\n if (seeds.length === 0) return [];\n const owner = new Map<string, number>(); // nodeId → seed 下标\n seeds.forEach((s, si) => owner.set(s.id, si));\n const queue = seeds.map((s) => s.id);\n while (queue.length) {\n const cur = queue.shift()!;\n const si = owner.get(cur)!;\n for (const nb of adj.get(cur) ?? []) {\n if (owner.has(nb)) continue;\n owner.set(nb, si);\n queue.push(nb);\n }\n }\n const groups: CmGroup[] = [];\n seeds.forEach((s, si) => {\n const nodeIds = nodes.filter((n) => owner.get(n.id) === si).map((n) => n.id);\n if (nodeIds.length < 2) return;\n groups.push({\n id: `grp-${s.id}`,\n label: s.label.length <= 5 ? `${s.label}相关` : s.label,\n nodeIds,\n });\n });\n return groups;\n}\n\n// ============================================================\n// ELK 图构建(纯函数,不触 elkjs —— 结构可脱离引擎直测)\n// ============================================================\n\n/** ELK JSON 的最小结构(只声明我们用到的字段;elkjs 原样吃任意附加字段)。 */\nexport interface ElkGraphJSON {\n id: string;\n layoutOptions?: Record<string, string>;\n width?: number;\n height?: number;\n x?: number;\n y?: number;\n children?: ElkGraphJSON[];\n edges?: {\n id: string;\n sources: string[];\n targets: string[];\n /** elkjs 在 hierarchyHandling=INCLUDE_CHILDREN 下把全部边挂到根,坐标属于 container 指向的容器 */\n container?: string;\n sections?: {\n startPoint: { x: number; y: number };\n endPoint: { x: number; y: number };\n bendPoints?: { x: number; y: number }[];\n }[];\n }[];\n}\n\n/** 组容器标题栏高度:ELK 组盒顶部 padding 要为标题留白。 */\nexport const GROUP_TITLE_PX = 34;\n\nexport function buildElkGraph(nodes: CmNode[], edges: CmEdge[], groups: CmGroup[]): ElkGraphJSON {\n const ids = new Set(nodes.map((n) => n.id));\n const degree = new Map<string, number>();\n for (const n of nodes) degree.set(n.id, 0);\n const seenPair = new Set<string>();\n const drawEdges: CmEdge[] = [];\n for (const e of edges) {\n if (!ids.has(e.from) || !ids.has(e.to) || e.from === e.to) continue;\n const key = [e.from, e.to].sort().join(\"→\");\n if (seenPair.has(key)) continue;\n seenPair.add(key);\n drawEdges.push(e);\n degree.set(e.from, degree.get(e.from)! + 1);\n degree.set(e.to, degree.get(e.to)! + 1);\n }\n let hubId = nodes[0]?.id ?? \"\";\n for (const n of nodes) if ((degree.get(n.id) ?? 0) > (degree.get(hubId) ?? 0)) hubId = n.id;\n\n const inGroup = new Map<string, string>(); // nodeId → groupId\n for (const g of groups) for (const nid of g.nodeIds) if (ids.has(nid) && !inGroup.has(nid)) inGroup.set(nid, g.id);\n\n const nodeChild = (n: CmNode): ElkGraphJSON => {\n const box = cmNodeBox(n.label, n.id === hubId || (degree.get(n.id) ?? 0) >= 4);\n return { id: n.id, width: Math.ceil(box.width), height: Math.ceil(box.height) };\n };\n\n const children: ElkGraphJSON[] = [];\n for (const g of groups) {\n const members = g.nodeIds.filter((nid) => inGroup.get(nid) === g.id && ids.has(nid));\n if (members.length === 0) continue;\n children.push({\n id: `g:${g.id}`,\n layoutOptions: { \"elk.padding\": `[top=${GROUP_TITLE_PX},left=14,bottom=12,right=14]` },\n children: members.map((nid) => nodeChild(nodes.find((n) => n.id === nid)!)),\n });\n }\n for (const n of nodes) {\n if (!inGroup.has(n.id)) children.push(nodeChild(n));\n }\n\n return {\n id: \"root\",\n layoutOptions: {\n \"elk.algorithm\": \"layered\",\n \"elk.direction\": \"DOWN\",\n \"elk.edgeRouting\": \"ORTHOGONAL\",\n // 复合图关键开关:layered 默认不处理嵌套(跨组边不路由、无 sections),\n // INCLUDE_CHILDREN 让整个复合图一次分层,跨组边才有正交折线\n \"elk.hierarchyHandling\": \"INCLUDE_CHILDREN\",\n \"elk.spacing.nodeNode\": \"34\",\n \"elk.spacing.edgeNode\": \"26\",\n \"elk.spacing.componentComponent\": \"48\",\n \"elk.layered.spacing.nodeNodeBetweenLayers\": \"56\",\n },\n children,\n edges: drawEdges.map((e, i) => ({ id: `e${i}`, sources: [e.from], targets: [e.to] })),\n };\n}\n\n// ============================================================\n// ELK 输出拍平(复合嵌套一层:root → 组盒 → 节点盒)\n// ============================================================\n\nexport interface CmapNodeGeo {\n id: string;\n x: number; // 左上角(绝对)\n y: number;\n w: number;\n h: number;\n lines: string[];\n hub: boolean;\n groupId: string | null;\n /** 颜色档 = 所属组序号(0-4 循环);无组 = -1(中性) */\n colorIdx: number;\n}\nexport interface CmapGroupGeo {\n id: string;\n label: string;\n x: number;\n y: number;\n w: number;\n h: number;\n colorIdx: number;\n}\nexport interface CmapEdgeGeo {\n from: string;\n to: string;\n label?: string;\n pts: { x: number; y: number }[];\n /** 边标签锚点(折线弧长中点);无标签为 null */\n labelPt: { x: number; y: number } | null;\n}\nexport interface CmapLayout {\n width: number;\n height: number;\n nodes: CmapNodeGeo[];\n groups: CmapGroupGeo[];\n edges: CmapEdgeGeo[];\n hubId: string;\n /** true = 分组来自客户端兜底(调试/未来 UI 提示用) */\n groupsFallback: boolean;\n}\n\n/** 折线弧长中点(标签锚点)。 */\nfunction polylineMidpoint(pts: { x: number; y: number }[]): { x: number; y: number } {\n if (pts.length === 0) return { x: 0, y: 0 };\n if (pts.length === 1) return pts[0];\n const segLens = [];\n let total = 0;\n for (let i = 1; i < pts.length; i++) {\n const l = Math.hypot(pts[i].x - pts[i - 1].x, pts[i].y - pts[i - 1].y);\n segLens.push(l);\n total += l;\n }\n let remain = total / 2;\n for (let i = 0; i < segLens.length; i++) {\n if (remain <= segLens[i] || i === segLens.length - 1) {\n const t = segLens[i] === 0 ? 0 : remain / segLens[i];\n return {\n x: pts[i].x + (pts[i + 1].x - pts[i].x) * t,\n y: pts[i].y + (pts[i + 1].y - pts[i].y) * t,\n };\n }\n remain -= segLens[i];\n }\n return pts[pts.length - 1];\n}\n\nexport function flattenElkResult(\n elkOut: ElkGraphJSON,\n nodes: CmNode[],\n edges: CmEdge[],\n groups: CmGroup[],\n groupsFallback: boolean,\n hubId: string,\n): CmapLayout {\n const nodesById = new Map(nodes.map((n) => [n.id, n] as const));\n const groupColor = new Map<string, number>();\n groups.forEach((g, i) => groupColor.set(g.id, i % 5));\n const groupById = new Map(groups.map((g) => [g.id, g] as const));\n const memberGroup = new Map<string, string>();\n for (const g of groups) for (const nid of g.nodeIds) if (!memberGroup.has(nid)) memberGroup.set(nid, g.id);\n\n const outNodes: CmapNodeGeo[] = [];\n const outGroups: CmapGroupGeo[] = [];\n const outEdges: CmapEdgeGeo[] = [];\n\n // elkjs 把边统一挂到根数组,坐标属于 e.container 指向的容器(INCLUDE_CHILDREN 下)——\n // 必须先收集\"容器 id → 绝对偏移\"表,再按 container 加偏移;按树位置加偏移会让组内边整体错位。\n const containerOff = new Map<string, { x: number; y: number }>([[\"root\", { x: 0, y: 0 }]]);\n const rawEdges: { e: NonNullable<ElkGraphJSON[\"edges\"]>[number]; fallback: { x: number; y: number } }[] = [];\n\n const walk = (elk: ElkGraphJSON, offX: number, offY: number, containerId: string | null) => {\n for (const child of elk.children ?? []) {\n const cx = offX + (child.x ?? 0);\n const cy = offY + (child.y ?? 0);\n if (child.children?.length) {\n const gid = child.id.startsWith(\"g:\") ? child.id.slice(2) : child.id;\n const meta = groupById.get(gid);\n outGroups.push({\n id: gid,\n label: meta?.label ?? \"分组\",\n x: cx,\n y: cy,\n w: child.width ?? 0,\n h: child.height ?? 0,\n colorIdx: groupColor.get(gid) ?? 0,\n });\n containerOff.set(child.id, { x: cx, y: cy });\n walk(child, cx, cy, gid);\n } else {\n const n = nodesById.get(child.id);\n if (!n) continue;\n const box = cmNodeBox(n.label, n.id === hubId);\n const gid = memberGroup.get(n.id) ?? null;\n outNodes.push({\n id: n.id,\n x: cx,\n y: cy,\n w: child.width ?? Math.ceil(box.width),\n h: child.height ?? Math.ceil(box.height),\n lines: box.lines,\n hub: n.id === hubId,\n groupId: containerId,\n colorIdx: gid != null ? groupColor.get(gid) ?? 0 : -1,\n });\n }\n }\n for (const e of elk.edges ?? []) {\n // 记录现场偏移兜底:理论上边也可挂在 LCA 自己的 edges 里(无 container 字段)\n rawEdges.push({ e, fallback: { x: offX, y: offY } });\n }\n };\n walk(elkOut, 0, 0, null);\n\n for (const { e, fallback } of rawEdges) {\n const sec = e.sections?.[0];\n if (!sec) continue;\n const off = (e.container != null ? containerOff.get(e.container) : undefined) ?? fallback;\n const pts = [sec.startPoint, ...(sec.bendPoints ?? []), sec.endPoint].map((p) => ({\n x: p.x + off.x,\n y: p.y + off.y,\n }));\n const idx = Number(e.id.slice(1));\n const src = edges[idx];\n if (!src) continue;\n outEdges.push({ from: src.from, to: src.to, label: src.label, pts, labelPt: src.label ? polylineMidpoint(pts) : null });\n }\n\n return {\n width: Math.ceil(elkOut.width ?? 0),\n height: Math.ceil(elkOut.height ?? 0),\n nodes: outNodes,\n groups: outGroups,\n edges: outEdges,\n hubId,\n groupsFallback,\n };\n}\n\n// ============================================================\n// 异步管线:elkjs 动态 import(独立 lazy chunk)\n// ============================================================\n\ntype ElkInstance = { layout: (graph: ElkGraphJSON) => Promise<ElkGraphJSON> };\nlet elkPromise: Promise<ElkInstance> | null = null;\n\n/** elkjs 单例:elk.bundled.js 主线程版(无 Worker,打包器友好,React Flow 生态同款)。 */\nfunction loadElk(): Promise<ElkInstance> {\n elkPromise ??= import(/* @vite-ignore */ \"https://esm.sh/elkjs@0.12/lib/elk.bundled.js\").then((mod: { default: unknown }) => {\n // interop 双环境:CJS(Node/tsx)default 在 mod.default;打包后 ESM 可能整包即构造器\n const m = mod as unknown as Record<string, unknown>;\n const Ctor = (m.default ?? m) as new () => ElkInstance;\n return new Ctor();\n });\n return elkPromise;\n}\n\n/** 概念图 → 分组解析 → ELK 布局 → 绝对坐标几何。输入相同则输出逐字段全等。 */\nexport async function layoutConceptMap(\n nodes: CmNode[],\n edges: CmEdge[],\n groups?: CmGroup[] | null,\n): Promise<CmapLayout> {\n const resolved = resolveGroups(nodes, edges, groups);\n const graph = buildElkGraph(nodes, edges, resolved.groups);\n const hubId = computeHubId(nodes, edges);\n const elk = await loadElk();\n const out = await elk.layout(graph);\n return flattenElkResult(out, nodes, edges, resolved.groups, resolved.fallback, hubId);\n}\n\nfunction computeHubId(nodes: CmNode[], edges: CmEdge[]): string {\n const ids = new Set(nodes.map((n) => n.id));\n const degree = new Map<string, number>();\n for (const n of nodes) degree.set(n.id, 0);\n const seen = new Set<string>();\n for (const e of edges) {\n if (!ids.has(e.from) || !ids.has(e.to) || e.from === e.to) continue;\n const key = [e.from, e.to].sort().join(\"→\");\n if (seen.has(key)) continue;\n seen.add(key);\n degree.set(e.from, degree.get(e.from)! + 1);\n degree.set(e.to, degree.get(e.to)! + 1);\n }\n let hubId = nodes[0]?.id ?? \"\";\n for (const n of nodes) if ((degree.get(n.id) ?? 0) > (degree.get(hubId) ?? 0)) hubId = n.id;\n return hubId;\n}\n","/**\n * The study tab's locale surface: one `lookatstudy` namespace registered with\n * the framework locale service (zh + en, key sets identical — the service\n * enforces balance at register time and this module's tests re-assert it).\n * `makeT` is the pure lookup (own chain: locale → zh → key, `{name}` template\n * interpolation — the same semantics as the service's translate) so unit\n * tests and non-slot code can translate without a live context;\n * `bindStudyT` prefers the service's stable `bind()` when present.\n * @module dsh-plugin-lookatstudy/client/locale\n */\n\n/** Flat key → template string, `{name}` placeholders (LocaleDict shape). */\nexport type StudyDict = Record<string, string>\n\n/** Simplified Chinese dictionary (also the fallback locale). */\nexport const ZH: StudyDict = {\n 'tab.label': '学习',\n 'col.rail': '课程',\n 'col.tutor': '导师',\n 'col.bb': '黑板',\n 'pane.rail': '课程',\n 'pane.tutor': '导师',\n 'pane.bb': '黑板',\n 'viewtab.teach': '讲解',\n 'viewtab.cmap': '概念图',\n 'viewtab.cmap.title': '本课概念之间的关系图',\n 'loading': '加载中…',\n 'start.title': '一键准备学习:建立学习工作区、开启会话并让导师就位',\n 'start.go': '开始学习',\n 'start.enter': '进入学习',\n 'start.busy': '正在准备学习区…',\n 'soul.direct': '直讲',\n 'soul.direct.hint': '精讲:先讲清楚,再确认懂没懂',\n 'soul.guide': '引导',\n 'soul.guide.hint': '引导:让你自己往前推一步,导师递台阶',\n 'soul.practice': '实战',\n 'soul.practice.hint': '实战:在真实世界的乱问题里学',\n 'zone.understand': '🧠 理解区 — 知识结构',\n 'zone.record': '📝 记录区 — 我的话',\n 'zone.practice': '✍️ 练习区 — 答题日志',\n 'rail.empty.title': '暂无课程',\n 'rail.empty.hint': '粘贴 markdown → 说「导入为课程」',\n 'rail.empty.hint2': '本地文件夹 → 说「导入 D:/path/to/folder」',\n 'rail.empty.placeholder': 'GitHub 仓库链接,如 microsoft/AI-For-Beginners',\n 'rail.empty.button': '导入',\n 'rail.empty.demo': '导入示例课程',\n 'rail.mastered': '毕业 {mastered}/{total} 课',\n 'rail.avg': '平均掌握度 {pct}%',\n 'rail.avg.none': '尚无掌握度数据',\n 'rail.search': '搜索课时…(多关键词空格分隔)',\n 'rail.locate.title': '在课程树中定位当前焦点课时(自动展开所在章节)',\n 'rail.locate': '回到当前课时',\n 'rail.due': '待复习 {count}',\n 'rail.due.over': '超{days}天',\n 'rail.due.start': '开始复习',\n 'rail.due.tag': '这课时的复习今天到期(SM-2)',\n 'rail.delete': '删除本课程',\n 'rail.delete.confirm': '确认删除?',\n 'rail.delete.title.confirm': '再点一次确认删除(含全部进度与笔记)。反悔前可先在设置页备份状态文件',\n 'rail.section.collapse': '折叠本章节',\n 'rail.section.expand': '展开本章节({count} 课时)',\n 'rail.section.count': '{count} 课',\n 'rail.lesson.opening': '正在打开课时会话…',\n 'rail.lesson.openHint': '(点击将打开本课专属会话)',\n 'rail.import.toggle': '导入课程',\n 'rail.import.close': '收起导入',\n 'tag.weak': '{count} 个薄弱知识点,测验会优先考察',\n 'tag.friction': '{count} 次卡点记录(你说\"不懂\"时导师记下的)',\n 'tag.mastery': '课时掌握度 {pct}%(取最薄弱知识点)',\n 'tag.mastery.short': '课时掌握度 = 最薄弱知识点的掌握度',\n 'status.exam': '章节测验:本节全部课时掌握度 ≥50% 后开放',\n 'status.mastered': '已毕业:掌握度 ≥90%(或你接受了掌握提案)',\n 'status.in_progress': '学习中:已开课,掌握度从 50% 起步',\n 'status.available': '可开始:已解锁,尚未学习',\n 'status.locked': '未解锁:先完成前面的课时',\n 'chip.unattributed': '未归因',\n 'chip.correct': '✓ 答对 · {concept}',\n 'chip.wrong': '✗ 答错 · {concept}',\n 'row.thinking': '导师思考中…',\n 'row.thinking.title': '导师正在推理,回复马上就来',\n 'quiz.title': '点击选项作答,也可以直接打字回答',\n 'quiz.answer': '选 {letter}:{text}',\n 'tutor.dormant': '学习模式已关闭 — 点右上「▶ 开始学习」开启导师,按钮恢复可用。',\n 'tutor.empty': '对话会出现在这里',\n 'tutor.empty.hint': '在下方输入框和导师说话',\n 'proposal.text': '导师提议你已掌握「{lesson}」:{rationale}',\n 'proposal.accept': '接受',\n 'proposal.decline': '再练练',\n 'bb.empty': '黑板还空着',\n 'bb.empty.hint': '在左侧课程树选择一课',\n 'bb.mastery': '掌握度 {pct}%',\n 'cmap.legend': '琥珀色 = 薄弱知识点(掌握度 <70%)',\n 'cmap.node.pct': '掌握度 {pct}%',\n 'bb.strategy': '本课学法',\n 'bb.fallback.cmap.empty': '概念图需要先由导师定义本课概念',\n 'bb.fallback.cmap': '概念图渲染不可用(布局引擎加载失败) — 已回退讲解视图',\n 'bb.notes': '笔记',\n 'bb.notes.empty': '这一课还没有笔记',\n 'tv.exam.stars': '本次 {n}★(历史最佳 {best}★)',\n 'tv.exam.fail': '这轮没拿到星——错题就是下一课的地图,从每题的解析看起。',\n 'active.off.title': '注册 study 工具并载入导师人格,之后普通对话和现在一样',\n 'active.on.title': '注销 study 工具与导师人格;学习进度保留,可随时重新开启',\n 'active.off': '▶ 开始学习',\n 'active.on': '⏻ 退出学习模式',\n 'prompt.kickoff': '开始学习:查看我的学习状态并打开当前焦点课时。如果我还没有课程,推荐我导入示例课程(AI-For-Beginners)并说明怎么开始。回复最后请提醒我点上方「学习」页签进入学习界面。',\n 'settings.nav': '学习',\n 'settings.mode': '教学风格',\n 'settings.mode.hint': '导师的讲解风格;也可在学习页随时切换',\n 'settings.studyMode': '学习模式',\n 'settings.studyMode.hint': '开启后注册 study_* 工具并载入导师人格;进度与笔记始终保留',\n 'settings.on': '状态:已开启',\n 'settings.off': '状态:已关闭',\n 'settings.turnOn': '开启',\n 'settings.turnOff': '关闭',\n 'settings.stats': '学习统计',\n 'settings.stats.courses': '课程 {count} 个',\n 'settings.stats.xp': 'XP {xp} · Lv{level}({pct}%)',\n 'settings.stats.today': '今日 {xp}/{goal}',\n 'settings.stats.streak': '连续 {days} 天(最长 {best},剩冻结 {freeze})',\n 'settings.about': '关于',\n 'settings.about.hint': '当前运行的构建版本,点击查看该版更新内容。',\n 'settings.stateFile': '状态文件',\n 'settings.stateFile.hint': '学习进度存放于本机 JSON,换机可迁移',\n 'dock.title': '学习状态:待复习 {due} · 连续 {streak} 天 · Lv{level} — 点上方「学习」页签进入',\n 'dock.due': '{count}',\n 'dock.streak': '{days}天',\n 'dock.lv': 'Lv{level}',\n 'prompt.import': '导入课程:用 study_import_github 抓取 {url}',\n 'prompt.lesson': '学习「{title}」:用 study_lesson 打开这一课开始学习。',\n 'prompt.exam': '开始「{section}」的章节测验:按本节课时出题,答完逐题判分',\n 'prompt.review': '开始今天的复习,从最到期的课时开始',\n 'prompt.proposal.accept': '接受提案 {id} —— 确认标记这课为已掌握',\n 'prompt.proposal.decline': '拒绝提案 {id} —— 我想再练练',\n}\n\n/** English dictionary — key set must equal {@link ZH}'s (test-asserted). */\nexport const EN: StudyDict = {\n 'tab.label': 'Study',\n 'col.rail': 'Courses',\n 'col.tutor': 'Tutor',\n 'col.bb': 'Blackboard',\n 'pane.rail': 'Courses',\n 'pane.tutor': 'Tutor',\n 'pane.bb': 'Board',\n 'viewtab.teach': 'Teach',\n 'viewtab.cmap': 'Concepts',\n 'viewtab.cmap.title': 'The lesson\\'s concepts relate',\n 'loading': 'Loading…',\n 'start.title': 'One click to study: workspace + session + tutor, all set up',\n 'start.go': 'Start learning',\n 'start.enter': 'Enter study',\n 'start.busy': 'Preparing the study area…',\n 'soul.direct': 'Direct',\n 'soul.direct.hint': 'Explain first, then check understanding',\n 'soul.guide': 'Guide',\n 'soul.guide.hint': 'You push one step forward; the tutor hands you the stairs',\n 'soul.practice': 'Practice',\n 'soul.practice.hint': 'Learn inside real, messy problems',\n 'zone.understand': '🧠 Understand — knowledge structure',\n 'zone.record': '📝 Record — in my own words',\n 'zone.practice': '✍️ Practice — answer log',\n 'rail.empty.title': 'No courses yet',\n 'rail.empty.hint': 'Paste markdown → say \"import as a course\"',\n 'rail.empty.hint2': 'Local folder → say \"import D:/path/to/folder\"',\n 'rail.empty.placeholder': 'GitHub repo link, e.g. microsoft/AI-For-Beginners',\n 'rail.empty.button': 'Import',\n 'rail.empty.demo': 'Import the demo course',\n 'rail.mastered': '{mastered}/{total} lessons graduated',\n 'rail.avg': 'avg mastery {pct}%',\n 'rail.avg.none': 'no mastery data yet',\n 'rail.search': 'Search lessons… (space-separated keywords)',\n 'rail.locate.title': 'Locate the current focus lesson in the tree (auto-expands its section)',\n 'rail.locate': 'Back to current lesson',\n 'rail.due': '{count} due',\n 'rail.due.over': '{days}d overdue',\n 'rail.due.start': 'Start reviewing',\n 'rail.due.tag': 'this lesson\\'s review is due today (SM-2)',\n 'rail.delete': 'Delete this course',\n 'rail.delete.confirm': 'Delete?',\n 'rail.delete.title.confirm': 'Click again to confirm (all progress and notes included). Back up via the state file in Settings first',\n 'rail.section.collapse': 'Collapse this section',\n 'rail.section.expand': 'Expand this section ({count} lessons)',\n 'rail.section.count': '{count} lessons',\n 'rail.lesson.opening': 'Opening the lesson session…',\n 'rail.lesson.openHint': ' (opens this lesson\\'s own session)',\n 'rail.import.toggle': 'Import a course',\n 'rail.import.close': 'Collapse import',\n 'tag.weak': '{count} weak concepts — quizzes target them first',\n 'tag.friction': '{count} friction marks (logged when you said you were stuck)',\n 'tag.mastery': 'lesson mastery {pct}% (the weakest concept)',\n 'tag.mastery.short': 'lesson mastery = the weakest concept\\'s mastery',\n 'status.exam': 'Section exam: opens when every lesson in the section reaches ≥50% mastery',\n 'status.mastered': 'Graduated: mastery ≥90% (or you accepted a mastery proposal)',\n 'status.in_progress': 'Learning: opened, mastery starts at 50%',\n 'status.available': 'Ready: unlocked, not started',\n 'status.locked': 'Locked: finish the preceding lessons first',\n 'chip.unattributed': 'unattributed',\n 'chip.correct': '✓ correct · {concept}',\n 'chip.wrong': '✗ wrong · {concept}',\n 'row.thinking': 'tutor is thinking…',\n 'row.thinking.title': 'The tutor is reasoning; the reply is coming',\n 'quiz.title': 'Click an option to answer, or just type',\n 'quiz.answer': 'Choose {letter}: {text}',\n 'tutor.dormant': 'Study mode is off — click \"▶ Start learning\" above to wake the tutor and re-enable these controls.',\n 'tutor.empty': 'The conversation will appear here',\n 'tutor.empty.hint': 'Talk to the tutor in the input below',\n 'proposal.text': 'The tutor proposes you have mastered \"{lesson}\": {rationale}',\n 'proposal.accept': 'Accept',\n 'proposal.decline': 'Keep practicing',\n 'bb.empty': 'The blackboard is empty',\n 'bb.empty.hint': 'Pick a lesson in the course tree on the left',\n 'bb.mastery': 'mastery {pct}%',\n 'cmap.legend': 'Amber = weak concept (mastery < 70%)',\n 'cmap.node.pct': 'mastery {pct}%',\n 'bb.strategy': 'Approach',\n 'bb.fallback.cmap.empty': 'The concept map needs the tutor to define this lesson\\'s concepts first',\n 'bb.fallback.cmap': 'Concept map unavailable (layout engine failed to load) — fell back to the teach view',\n 'bb.notes': 'Notes',\n 'bb.notes.empty': 'No notes for this lesson yet',\n 'tv.exam.stars': 'This attempt {n}★ (best {best}★)',\n 'tv.exam.fail': 'No stars this round — the wrong answers are the map for the next one; start with their explanations.',\n 'active.off.title': 'Register the study tools and load the tutor persona; plain chats stay as they are',\n 'active.on.title': 'Retire the study tools and tutor persona; progress is kept and you can re-enable anytime',\n 'active.off': '▶ Start learning',\n 'active.on': '⏻ Exit study mode',\n 'prompt.kickoff': 'Start learning: check my study state and open the current focus lesson. If I have no course yet, suggest importing the demo course (AI-For-Beginners) and explain how to begin. Remind me at the end to open the \"Study\" tab above to enter the study UI.',\n 'settings.nav': 'Study',\n 'settings.mode': 'Teaching style',\n 'settings.mode.hint': 'The tutor\\'s explanation style; switchable anytime in the study tab too',\n 'settings.studyMode': 'Study mode',\n 'settings.studyMode.hint': 'On registers the study_* tools and the tutor persona; progress and notes are always kept',\n 'settings.on': 'Status: on',\n 'settings.off': 'Status: off',\n 'settings.turnOn': 'Turn on',\n 'settings.turnOff': 'Turn off',\n 'settings.stats': 'Study stats',\n 'settings.stats.courses': '{count} courses',\n 'settings.stats.xp': 'XP {xp} · Lv{level} ({pct}%)',\n 'settings.stats.today': 'Today {xp}/{goal}',\n 'settings.stats.streak': 'Streak {days}d (best {best}, {freeze} freeze left)',\n 'settings.about': 'About',\n 'settings.about.hint': 'The version of the running build — click to see its release notes.',\n 'settings.stateFile': 'State file',\n 'settings.stateFile.hint': 'Your progress lives in a local JSON file — copy it to migrate machines',\n 'dock.title': 'Study status: {due} due · {streak}d streak · Lv{level} — open the Study tab above to continue',\n 'dock.due': '{count}',\n 'dock.streak': '{days}d',\n 'dock.lv': 'Lv{level}',\n 'prompt.import': 'Import a course: fetch {url} with study_import_github',\n 'prompt.lesson': 'Study \"{title}\": open this lesson with study_lesson and start teaching.',\n 'prompt.exam': 'Start the section exam for \"{section}\": quiz me on this section\\'s lessons and grade each answer',\n 'prompt.review': 'Start today\\'s review, from the most overdue lesson first',\n 'prompt.proposal.accept': 'Accept proposal {id} — confirm marking this lesson as mastered',\n 'prompt.proposal.decline': 'Reject proposal {id} — I want to practice more',\n}\n\n/** Both dictionaries under their locale ids (the service's register shape). */\nexport const STUDY_DICTS = { zh: ZH, en: EN }\n\n/** The namespace id this plugin registers with the framework locale service. */\nexport const STUDY_NS = 'lookatstudy'\n\n/** Translate function for the study namespace. */\nexport type StudyT = (key: string, params?: Record<string, unknown>) => string\n\n/**\n * Pure translator with the service's semantics: own-locale dict → zh\n * fallback → the key itself, `{name}` interpolation left untouched when the\n * param is missing.\n * @param locale - active locale id ('zh'/'en'; unknown ids fall back to zh).\n * @returns a stable-shaped translate function.\n */\nexport function makeT(locale: string): StudyT {\n const dict = locale === 'en' ? EN : ZH\n return (key, params) => {\n const template = dict[key] ?? ZH[key] ?? key\n if (params === undefined) return template\n return template.replace(/\\{(\\w+)\\}/g, (match, name: string) =>\n name in params ? String(params[name]) : match)\n }\n}\n\n/** Minimal shape of the framework locale service this plugin consumes. */\nexport interface LocaleServiceFace {\n register(ns: string, dicts: Record<string, StudyDict>): () => void\n bind(ns: string): StudyT\n subscribe(fn: () => void): () => void\n}\n\n/**\n * Register the namespace with the framework locale service.\n * @param locale - the client locale service when present.\n * @returns the registration disposer (a no-op when the service is absent or\n * a hostile re-registration was refused).\n */\nexport function registerStudyLocale(locale?: LocaleServiceFace): () => void {\n if (locale === undefined) return () => {}\n try {\n return locale.register(STUDY_NS, STUDY_DICTS)\n } catch {\n // A namespace/locale already claimed by someone else must not break the\n // tab — fall back to the pure translator everywhere.\n return () => {}\n }\n}\n\n/**\n * The live translator: the service's stable `bind` when present (reads the\n * active locale at call time, so a locale-change re-render picks new\n * strings), the pure zh translator otherwise.\n * @param locale - the client locale service when present.\n */\nexport function studyTranslator(locale?: LocaleServiceFace): StudyT {\n return locale === undefined ? makeT('zh') : locale.bind(STUDY_NS)\n}\n\n/** The module's active translator — zh until the view factory installs the live bind. */\nlet activeT: StudyT = makeT('zh')\n\n/**\n * Install the client-wide translator (called once at client apply, before\n * any component renders).\n */\nexport function setStudyTranslator(t: StudyT): void {\n activeT = t\n}\n\n/**\n * Translate through the active translator — the import every client module\n * uses for user-visible copy. Pure helpers take an optional explicit `t`\n * defaulting to the current active translator, evaluated per call.\n */\nexport function tr(key: string, params?: Record<string, unknown>): string {\n return activeT(key, params)\n}\n","/**\n * Blackboard diagram views (SPEC Phase 2): the lesson concept map (ELK layered\n * layout via the vendored cmap-elk-layout + CDN elkjs, draw.io-flavored SVG\n * skin rendered plugin-side). Degrades honestly: any CDN/ELK failure leaves a\n * one-line notice instead of a broken pane.\n *\n * The lesson mind map view was RETIRED with upstream v0.26.0 (2026-09-01\n * port): body text that has headings already shows its structure, text without\n * headings yields a first-line-truncated node graph nobody can read — both\n * lose — and this concept map already covers the semantic-structure need at\n * higher quality. Its three CDN imports went with it.\n */\n\nimport { layoutConceptMap, type CmNode, type CmEdge } from '../vendor/cmap-elk-layout.ts'\nimport { tr } from './locale.ts'\n\n\n/** Lesson concept map: the lesson node + its concepts (weak ones accented),\n * laid out by the vendored ELK pipeline, skinned draw.io-style (plugin-original,\n * upstream's skin is coupled to its token pipeline). Mastery shades the nodes. */\nexport async function renderLessonConceptMap(\n container: HTMLElement,\n lessonTitle: string,\n concepts: ReadonlyArray<{ title: string; masteryPct: number }>,\n): Promise<void> {\n const nodes: CmNode[] = [{ id: 'lesson', label: lessonTitle }, ...concepts.map(c => ({ id: `c-${c.title}`, label: c.title }))]\n const edges: CmEdge[] = concepts.map(c => ({ from: 'lesson', to: `c-${c.title}` }))\n const layout = await layoutConceptMap(nodes, edges)\n const masteryBy = new Map(concepts.map(c => [`c-${c.title}`, c.masteryPct]))\n const ns = 'http://www.w3.org/2000/svg'\n const svg = document.createElementNS(ns, 'svg')\n svg.setAttribute('width', String(Math.max(320, layout.width)))\n svg.setAttribute('height', String(Math.max(200, layout.height)))\n svg.setAttribute('viewBox', `0 0 ${layout.width} ${layout.height}`)\n svg.setAttribute('style', 'max-width:100%;background:var(--dsw-alias-bg-layer-1, #fff);border:1px solid var(--dsw-alias-border-l2, #d0d7de);border-radius:8px')\n for (const e of layout.edges) {\n const path = document.createElementNS(ns, 'path')\n path.setAttribute('d', e.pts.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x},${p.y}`).join(' '))\n path.setAttribute('fill', 'none')\n path.setAttribute('stroke', 'var(--dsw-alias-border-l2, #8b949e)')\n path.setAttribute('stroke-width', '1.5')\n svg.append(path)\n }\n for (const n of layout.nodes) {\n const g = document.createElementNS(ns, 'g')\n g.setAttribute('transform', `translate(${n.x},${n.y})`)\n const rect = document.createElementNS(ns, 'rect')\n const isLesson = n.id === 'lesson'\n const mastery = masteryBy.get(n.id)\n rect.setAttribute('width', String(n.w))\n rect.setAttribute('height', String(n.h))\n rect.setAttribute('rx', '6')\n rect.setAttribute('fill', mastery !== undefined && mastery < 70 ? 'var(--dsw-alias-state-warn-tertiary, #fef5e7)' : 'var(--dsw-alias-bg-layer-2, #f6f8fa)')\n rect.setAttribute('stroke', isLesson ? 'var(--dsw-alias-state-business-primary, #0969da)' : 'var(--dsw-alias-border-l2, #8b949e)')\n rect.setAttribute('stroke-width', isLesson ? '2' : '1')\n g.append(rect)\n n.lines.forEach((line, li) => {\n const label = document.createElementNS(ns, 'text')\n label.setAttribute('x', String(n.w / 2))\n label.setAttribute('y', String(n.h / 2 - (n.lines.length - 1) * 7 + li * 14 + 4))\n label.setAttribute('text-anchor', 'middle')\n label.setAttribute('font-size', isLesson ? '13' : '12')\n label.setAttribute('font-weight', isLesson ? '600' : '400')\n label.setAttribute('fill', 'var(--dsw-alias-label-primary, #1f2328)')\n label.textContent = line\n g.append(label)\n })\n const title = document.createElementNS(ns, 'title')\n const label = n.lines.join(' ')\n title.textContent = isLesson || mastery === undefined ? label : `${label} · ${tr('cmap.node.pct', { pct: mastery })}`\n g.append(title)\n svg.append(g)\n }\n container.append(svg)\n const legend = document.createElement('span')\n legend.className = 'lks-cmap-legend'\n const swatch = document.createElement('i')\n legend.append(swatch, document.createTextNode(tr('cmap.legend')))\n container.append(legend)\n}\n","/**\n * The study tab: one `conversation.view` entry rendering the whole plugin —\n * a simplified LookatStudy inside dsh, three columns in the tab. Left: the\n * course map (selector, tree, due box, one-click demo import). Middle: the\n * tutor conversation — a read-only transcript folded from the session\n * snapshot (user text, assistant text rendered through the plugin's own\n * markdown pipeline; tool calls stay in the host conversation's toolview\n * cards — a mirrored second record diverged) plus the soul pills, starters,\n * pending proposal banner, and a reverse-channel input. Right: the blackboard —\n * focus-lesson 讲解 and the Cornell 笔记 zones. Nothing outside this tab\n * touches dsh chrome.\n * @module dsh-plugin-lookatstudy/client/views\n */\n\nimport { createElement, useEffect, useRef, useState } from 'react'\nimport type { KeyboardEvent as ReactKeyboardEvent, ReactNode } from 'react'\nimport {\n IconBoltFill16, IconBookFill16, IconCrownFill16, IconFlameFill16, IconGlobeOutline14,\n IconGoalOutline16, IconLockFill16, IconPinFill16, IconPlayOutline16, IconPlusOutline16,\n IconPowerFill16, IconRefreshOutline16, IconStarFill16, IconTrashOutline16,\n IconDownloadOutline16, IconLoadingOutline16, IconWarningOutline16,\n} from './icons.tsx'\nimport type { ConvViewProps } from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\nimport type {\n AssistantBlock, ConversationNode, ConversationSnapshot, PartialAssistant,\n} from '@deepseek-ai/dsh-client-runtime/client'\nimport { useStudy } from './data.ts'\nimport { renderMarkdown } from '../markdown.ts'\nimport { enhanceRendered, setEnhanceDeps } from './enhance.ts'\nimport { renderLessonConceptMap } from './diagrams.ts'\nimport { tr, type StudyT } from './locale.ts'\n\n/** The three souls, in pill order (labels from LookatStudy's mode switcher). */\nconst MODES: ReadonlyArray<{ id: 'direct' | 'guide' | 'practice'; labelKey: string; hintKey: string }> = [\n { id: 'direct', labelKey: 'soul.direct', hintKey: 'soul.direct.hint' },\n { id: 'guide', labelKey: 'soul.guide', hintKey: 'soul.guide.hint' },\n { id: 'practice', labelKey: 'soul.practice', hintKey: 'soul.practice.hint' },\n]\n\n/** Zone keys for the Cornell notebook (understand / record / practice). */\nconst ZONES: ReadonlyArray<readonly [string, string]> = [\n ['understand', 'zone.understand'],\n ['record', 'zone.record'],\n ['practice', 'zone.practice'],\n]\n\n/** Status icon for one lesson row (LookatStudy's map icon semantics, SVG glyphs). */\nfunction statusIcon(kind: string, status: string): ReactNode {\n if (kind === 'exam') return createElement(IconGoalOutline16, { size: 14 })\n if (status === 'mastered') return createElement(IconCrownFill16, { size: 14 })\n if (status === 'in_progress') return createElement(IconBookFill16, { size: 14 })\n if (status === 'available') return createElement(IconStarFill16, { size: 14 })\n return createElement(IconLockFill16, { size: 14 })\n}\n\n/** LookatStudy's exam gate: an exam node opens only when every sibling study lesson reached mastery ≥50%. */\nfunction examOpen(lessons: ReadonlyArray<{ kind: string; masteryPct: number | null }>): boolean {\n return lessons.every(l => l.kind !== 'study' || (l.masteryPct ?? 0) >= 50)\n}\n\n/** Multi-keyword AND title filter (LookatStudy course-tree-filter). */\nfunction titleMatches(title: string, query: string): boolean {\n const keys = query.trim().toLowerCase().split(/\\s+/).filter(Boolean)\n return keys.every(k => title.toLowerCase().includes(k))\n}\n\n/**\n * Default expansion for one rail section: collapsed when every study lesson is\n * done (mastered) or not yet reachable (locked) — long courses otherwise scroll\n * 5× their viewport. The active frontier and the focus lesson's section stay\n * open; exam nodes never force a section open (they are gated separately).\n * Pure.\n * @param section - one course section projection with lesson kinds/statuses.\n */\nexport function sectionDefaultOpen(section: { lessons: ReadonlyArray<{ kind: string; status: string; focus: boolean }> }): boolean {\n return section.lessons.some(l => l.focus || (l.kind !== 'exam' && l.status !== 'mastered' && l.status !== 'locked'))\n}\n\n/** The rail's import row: a GitHub URL input plus the paste/folder hints. */\nfunction ImportRow({ send }: { send: StudySend }): ReactNode {\n const [url, setUrl] = useState('')\n return createElement('div', { className: 'lks-import' },\n createElement('div', { className: 'lks-inputrow' },\n createElement('input', {\n className: 'lks-input',\n type: 'url',\n placeholder: tr('rail.empty.placeholder'),\n value: url,\n onChange: (e: { target: { value: string } }) => { setUrl(e.target.value) },\n onKeyDown: (e: ReactKeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter' && url.trim() !== '') send(tr('prompt.import', { url: url.trim() }))\n },\n }),\n createElement('button', {\n className: 'lks-btn primary',\n disabled: url.trim() === '',\n onClick: () => { send(tr('prompt.import', { url: url.trim() })) },\n }, tr('rail.empty.button')),\n ),\n createElement('div', { className: 'lks-import-hint' },\n tr('rail.empty.hint'), createElement('br'),\n tr('rail.empty.hint2')),\n )\n}\n\n/** One rendered transcript row (pure fold of the conversation snapshot). */\nexport interface ChatRow {\n readonly key: string\n readonly role: 'user' | 'assistant' | 'error' | 'streaming' | 'thinking'\n readonly text: string\n}\n\n/**\n * Tooltip text for one course-tree status glyph. Pure (the translator is an\n * optional parameter defaulting to the active one, evaluated per call).\n * @param kind - lesson kind ('study' | 'practice' | 'exam').\n * @param status - lesson status ('locked' | 'available' | 'in_progress' | 'mastered').\n * @param t - translator (defaults to the module's active translator).\n */\nexport function statusTitle(kind: string, status: string, t: StudyT = tr): string {\n if (kind === 'exam') return t('status.exam')\n switch (status) {\n case 'mastered': return t('status.mastered')\n case 'in_progress': return t('status.in_progress')\n case 'available': return t('status.available')\n default: return t('status.locked')\n }\n}\n\n/**\n * Extract the last quiz option block (2–4 consecutive `A. …` `B. …` lines,\n * letters strictly consecutive from A) from an assistant reply — the raw text\n * of the tutor's question becomes the clickable answer surface. Pure.\n * @param text - one assistant reply's markdown.\n * @returns the options of the last valid block, or [] when none.\n */\nexport function quizOptions(text: string): ReadonlyArray<{ letter: string; text: string }> {\n const runs: Array<Array<{ letter: string; text: string }>> = []\n let run: Array<{ letter: string; text: string }> = []\n const flush = (): void => {\n if (run.length >= 2) runs.push(run)\n run = []\n }\n for (const line of text.split('\\n')) {\n const match = /^([A-D])[.、:)]\\s+(.+)$/.exec(line.trim())\n if (match === null) {\n flush()\n continue\n }\n const nextLetter = run.length === 0 ? 'A' : String.fromCharCode(run[run.length - 1]!.letter.charCodeAt(0) + 1)\n if (match[1] === nextLetter) run.push({ letter: match[1], text: match[2]! })\n else {\n flush()\n if (match[1] === 'A') run.push({ letter: match[1], text: match[2]! })\n }\n }\n flush()\n return runs.at(-1) ?? []\n}\n\nfunction textOf(blocks: readonly { type: string; text?: string }[]): string {\n return blocks.filter(b => b.type === 'text').map(b => b.text ?? '').join('\\n\\n').trim()\n}\n\nfunction assistantText(blocks: readonly AssistantBlock[]): string {\n return blocks.filter(b => b.kind === 'text').map(b => b.text).join('\\n\\n').trim()\n}\n\n/**\n * Fold conversation nodes (plus the streaming partial) into render rows.\n * Tool results are skipped: the host conversation renders the rich\n * `tool.call.toolview` cards, and the tutor column stays a pure persona\n * surface (a transcript mirror there grew a second, diverging record).\n * @param nodes - finalized conversation nodes from the snapshot.\n * @param partial - the in-flight assistant partial, or null.\n * @param t - translator (defaults to the active one, per call).\n * @returns ordered rows; never mutates its inputs.\n */\nexport function transcriptRows(nodes: readonly ConversationNode[], partial: PartialAssistant | null, t: StudyT = tr): readonly ChatRow[] {\n const rows: ChatRow[] = []\n for (const node of nodes) {\n switch (node.kind) {\n case 'user':\n case 'steering': {\n const text = textOf(node.content)\n if (text !== '') rows.push({ key: `u${node.seq}`, role: 'user', text })\n break\n }\n case 'assistant': {\n const text = assistantText(node.blocks)\n if (text !== '') rows.push({ key: `a${node.seq}`, role: 'assistant', text })\n break\n }\n case 'turn-error':\n rows.push({ key: `e${node.seq}`, role: 'error', text: node.message })\n break\n default:\n break\n }\n }\n if (partial !== null) {\n const text = assistantText(partial.blocks)\n if (text !== '') rows.push({ key: 'streaming', role: 'streaming', text })\n // No text yet means the tutor is reasoning (or lining up tool calls) —\n // without this row the column sits dead silent through the whole phase.\n else rows.push({ key: 'thinking', role: 'thinking', text: t('row.thinking') })\n }\n return rows\n}\n\n/** Small inline error surface for failed write actions (shared with the settings page). */\nexport function ActionError({ error }: { error: string | null }): ReactNode {\n if (error === null) return null\n return createElement('div', { className: 'lks-propcard-err' }, error)\n}\n\n/**\n * Land one message in the dsh composer and submit it — the same path as the\n * Send button, so button text is visible in the native input for a beat and\n * then goes through the full submission pipeline (no reverse channel).\n */\nexport type StudySend = (text: string) => void\n\n/** Narrow-mode pane selector: which of the three columns is the main display. */\ntype StudyPane = 'rail' | 'tutor' | 'bb'\n\n/** sessionStorage key keeping the narrow-mode pane across view remounts (tab switches) and reloads. */\nconst PANE_KEY = 'dsh-plugin-lookatstudy:pane'\n\n/** Narrow the stored value back to a pane id; anything else (or nothing stored) falls back to 导师. Pure, unit-testable. */\nexport function pickPane(stored: string | null): StudyPane {\n return stored === 'rail' || stored === 'tutor' || stored === 'bb' ? stored : 'tutor'\n}\n\n/** Read the persisted pane; the try swallows only the SecurityError privacy modes throw on storage access — the fallback is the default pane. */\nfunction storedPane(): StudyPane {\n try {\n return pickPane(sessionStorage.getItem(PANE_KEY))\n } catch {\n return 'tutor'\n }\n}\n\n/**\n * The framework's branded `SessionId`, minted locally (structural twin of the\n * brand — session ids are plain strings on the wire; the brand exists to keep\n * opaque ids out of string APIs). Replaces the former `as never` casts.\n */\ntype SessionId = string & { readonly __sessionBrand: 'SessionId' }\nconst sessionId = (id: string): SessionId => id as SessionId\n\n/** The whole study tab. Wide = three columns (课程 | 导师 | 黑板); narrow (<1220px) = one composer-width pane with a three-way switcher. */\nexport function studyView(ctx: ClientContext): (props: ConvViewProps) => ReactNode {\n return function StudyView(props: ConvViewProps): ReactNode {\n return createElement(StudyTab, { ...props, ctx, key: 'tab' })\n }\n}\n\n/** Tab body: the factory-bound ctx carries workspaces/sessions for the per-lesson session jumps. */\nfunction StudyTab({ useSession, inputActions, ctx }: ConvViewProps & { ctx: ClientContext }): ReactNode {\n const { data, activate, setMode, setFocus, searchLessons, deleteCourse, bindLessonSession } = useStudy()\n const snapshot = useSession((s: ConversationSnapshot) => s)\n const [pane, setPane] = useState<StudyPane>(storedPane)\n const rootRef = useRef<HTMLDivElement | null>(null)\n // The wide layout puts the tutor column left of the scroll body's center\n // (fixed rail + flexible blackboard), so the floating composer would sit\n // mid-screen under nothing. While this view is mounted and measurable, shift\n // the host composer card ([data-composer-card], a stable host anchor) under\n // the tutor column; any collapsed shift (narrow single-pane mode, hidden\n // view, no room) removes the class and restores the host's natural\n // centering. ResizeObserver on the study root catches mount/show/hide/resize.\n useEffect(() => {\n const root = rootRef.current\n const card = document.querySelector<HTMLElement>('[data-composer-card]')\n const seat = card?.parentElement ?? null\n if (root === null || card === null || seat === null) return\n const clear = (): void => {\n card.classList.remove('lks-composer-follow')\n card.style.removeProperty('--lks-composer-shift')\n card.style.removeProperty('--lks-composer-follow-width')\n }\n const apply = (): void => {\n const tutor = root.querySelector<HTMLElement>('.lks-col-tutor')\n const rail = root.querySelector<HTMLElement>('.lks-col-rail')\n if (tutor === null || rail === null || getComputedStyle(rail).display === 'none') return clear()\n const seatRect = seat.getBoundingClientRect()\n const tutorRect = tutor.getBoundingClientRect()\n if (seatRect.width === 0 || tutorRect.width === 0) return clear()\n const pad = parseFloat(getComputedStyle(seat).paddingLeft) || 0\n const cardW = card.getBoundingClientRect().width\n const max = seatRect.width - 2 * pad - cardW\n const shift = Math.round(Math.max(0, Math.min(tutorRect.left - (seatRect.left + pad), max)))\n if (shift < 2) return clear()\n card.style.setProperty('--lks-composer-shift', `${shift}px`)\n // The tutor column shrinks proportionally below ~1857px containers\n // (42cqi cap) — the docked composer card tracks that live width so the\n // card never overhangs the transcript column it sits under.\n card.style.setProperty('--lks-composer-follow-width', `${Math.round(tutorRect.width)}px`)\n card.classList.add('lks-composer-follow')\n }\n apply()\n const ro = new ResizeObserver(apply)\n ro.observe(root)\n ro.observe(seat)\n window.addEventListener('resize', apply)\n return () => {\n ro.disconnect()\n window.removeEventListener('resize', apply)\n clear()\n }\n }, [])\n const send: StudySend = (text) => {\n void (async () => {\n // Dormant installs activate first: the host registers the study tools\n // before the activation POST resolves, so the prompt meets a model that\n // can already call them.\n if (data?.active !== true) await activate(true)\n inputActions.setDraft(text)\n inputActions.submit()\n })()\n }\n // The bound translator reads the active locale at call time; a locale\n // switch must re-render to pick the new strings (the framework `t` seat\n // does this for slot entries — the deep component tree rides this bump).\n const [, bumpLocale] = useState(0)\n useEffect(() => {\n const localeSvc = (ctx as { locale?: { subscribe(fn: () => void): () => void } }).locale\n if (localeSvc === undefined) return\n return localeSvc.subscribe(() => { bumpLocale(v => v + 1) })\n }, [ctx])\n const panes: ReadonlyArray<{ id: StudyPane; labelKey: string }> = [\n { id: 'rail', labelKey: 'pane.rail' },\n { id: 'tutor', labelKey: 'pane.tutor' },\n { id: 'bb', labelKey: 'pane.bb' },\n ]\n return createElement('div', {\n ref: rootRef,\n className: 'lks-root lks-study',\n 'data-conversation-composer-overlay': '',\n 'data-pane': pane,\n },\n // Always-visible activation bar: the tab is the fallback entry when another\n // plugin's composer takeover hides the starter pill.\n createElement('div', { className: 'lks-actbar' },\n data === null ? null : createElement('button', {\n className: `lks-btn ${data.active ? 'ghost' : 'primary'}`,\n title: data.active ? tr('active.on.title') : tr('active.off.title'),\n onClick: () => { void activate(!data.active) },\n }, data.active ? createElement(IconPowerFill16, { size: 13 }) : createElement(IconPlayOutline16, { size: 13 }), data.active ? tr('active.on') : tr('active.off')),\n ),\n // .lks-body carries the row/column direction so the container query can\n // flip it — a container query cannot style the container element itself.\n createElement('div', { className: 'lks-body' },\n createElement('div', { className: 'lks-switch' },\n ...panes.map(p => createElement('button', {\n key: p.id,\n className: `lks-switch-btn${pane === p.id ? ' on' : ''}`,\n 'aria-pressed': String(pane === p.id),\n onClick: () => {\n setPane(p.id)\n try {\n sessionStorage.setItem(PANE_KEY, p.id)\n } catch {\n // Privacy modes forbid storage writes; the in-memory choice still holds this page.\n }\n },\n }, tr(p.labelKey))),\n ),\n createElement(CourseRail, { data, activate, setFocus, searchLessons, deleteCourse, bindLessonSession, send, ctx, currentSessionId: snapshot.sessionId }),\n createElement(TutorColumn, { data, setMode, send, snapshot }),\n createElement(BlackboardColumn, { data }),\n ),\n )\n}\n\ntype StudyData = ReturnType<typeof useStudy>['data']\n\n/** Left column: course management (pick/delete/search/import), lesson tree, due box. */\nfunction CourseRail({ data, activate, setFocus, searchLessons, deleteCourse, bindLessonSession, send, ctx, currentSessionId }: {\n data: StudyData\n activate: (active: boolean) => Promise<void>\n setFocus: (id: string) => Promise<void>\n searchLessons: (query: string) => Promise<Array<{ lessonId: string; lessonTitle: string; snippet: string }>>\n deleteCourse: (courseId: string) => Promise<void>\n bindLessonSession: (lessonId: string, sessionId: string) => Promise<void>\n send: StudySend\n ctx: ClientContext\n currentSessionId: string\n}): ReactNode {\n const [jumping, setJumping] = useState<string | null>(null)\n /** Open (or mint) the lesson's own session — the simplified thread system. */\n const openLessonThread = (lesson: { id: string; title: string }): void => {\n if (jumping !== null) return\n const mapped = data?.lessonSessions[lesson.id]\n if (mapped === currentSessionId) {\n void setFocus(lesson.id).catch(reportError)\n return\n }\n if (mapped !== undefined && ctx.sessions.binding(sessionId(mapped)) !== undefined) {\n void setFocus(lesson.id).catch(reportError)\n ctx.sessions.open(sessionId(mapped))\n return\n }\n setJumping(lesson.id)\n void setFocus(lesson.id).then(() => (async () => {\n // Minting a lesson session prompts directly (not through `send`), so\n // activation happens here too — same dormant-install guarantee.\n if (data?.active !== true) await activate(true)\n const area = await fetch('/lookatstudy/api/study-workspace')\n if (!area.ok) throw new Error(`study area unavailable (HTTP ${area.status})`)\n const { path } = await area.json() as { path: string }\n const workspace = await ctx.workspaces.create({ path })\n // connectWorkspace mints a fresh blank session once the workspace's\n // previous blank is used — each lesson thereby gets its own thread.\n const sessionId = await ctx.workspaces.connectWorkspace(workspace.workspaceId)\n const actx = ctx.sessions.scope(sessionId)\n const face = actx === undefined ? undefined : ctx.sessions.sessionOf(actx)\n if (face === undefined) throw new Error('lesson session is not addressable yet')\n const result = await face.prompt([{ type: 'text', text: tr('prompt.lesson', { title: lesson.title }) }], 'queue')\n if (!result.ok) throw new Error(`lesson prompt rejected: ${result.error.code}: ${result.error.message}`)\n await bindLessonSession(lesson.id, sessionId)\n ctx.sessions.open(sessionId)\n })()).then(\n () => { setJumping(null) },\n (err: unknown) => { reportError(err); setJumping(null) },\n )\n }\n const [selectedCourse, setSelectedCourse] = useState('')\n const [query, setQuery] = useState('')\n const [confirmDelete, setConfirmDelete] = useState(false)\n // An armed delete disarms on outside click or Escape — a stray second\n // click anywhere else must not be able to confirm destruction.\n useEffect(() => {\n if (!confirmDelete) return\n const disarm = (): void => { setConfirmDelete(false) }\n const onKey = (e: KeyboardEvent): void => { if (e.key === 'Escape') disarm() }\n window.addEventListener('click', disarm)\n window.addEventListener('keydown', onKey)\n return () => {\n window.removeEventListener('click', disarm)\n window.removeEventListener('keydown', onKey)\n }\n }, [confirmDelete])\n const [showImport, setShowImport] = useState(false)\n /** Per-section open overrides (courseId/sectionTitle → open?), on top of the frontier default. */\n const [secOpen, setSecOpen] = useState<Record<string, boolean>>({})\n const [error, setError] = useState<string | null>(null)\n const reportError = (err: unknown): void => { setError(err instanceof Error ? err.message : String(err)) }\n const body: ReactNode = data === null\n ? createElement('div', { className: 'lks-empty' }, tr('loading'))\n : data.courses.length === 0\n ? createElement('div', { className: 'lks-empty' },\n tr('rail.empty.title'), createElement('br'),\n createElement('button', {\n className: 'lks-btn primary',\n style: { margin: '10px 0' },\n onClick: () => { send(tr('prompt.import', { url: 'https://github.com/microsoft/AI-For-Beginners' })) },\n }, createElement(IconDownloadOutline16, null), tr('rail.empty.demo')),\n createElement(ImportRow, { send }),\n )\n : (() => {\n const courseId = data.courses.some(c => c.courseId === selectedCourse)\n ? selectedCourse\n : data.courses[0]!.courseId\n const course = data.courses.find(c => c.courseId === courseId)!\n return createElement('div', null,\n createElement('div', { className: 'lks-rail-head' },\n data.courses.length > 1\n ? createElement('select', {\n className: 'lks-rail-select',\n value: courseId,\n onChange: (e: { target: { value: string } }) => { setSelectedCourse(e.target.value); setConfirmDelete(false) },\n }, ...data.courses.map(c => createElement('option', { key: c.courseId, value: c.courseId }, c.title)))\n : createElement('div', { className: 'lks-rail-title', title: course.title }, course.title),\n createElement('button', {\n className: `lks-btn ${confirmDelete ? 'primary' : 'ghost'}`,\n title: confirmDelete ? tr('rail.delete.title.confirm') : tr('rail.delete'),\n onClick: (e: { stopPropagation: () => void }) => {\n e.stopPropagation()\n if (!confirmDelete) { setConfirmDelete(true); return }\n setConfirmDelete(false)\n deleteCourse(courseId).then(() => { setSelectedCourse('') }, reportError)\n },\n }, confirmDelete ? tr('rail.delete.confirm') : createElement(IconTrashOutline16, { size: 14 })),\n ),\n createElement('div', { className: 'lks-rail-sub' }, tr('rail.mastered', { mastered: course.mastered, total: course.total })),\n createElement('div', {\n className: `lks-masterybar${course.avgMasteryPct === 100 ? ' gold' : ''}`,\n title: course.avgMasteryPct === null ? tr('rail.avg.none') : tr('rail.avg', { pct: course.avgMasteryPct }),\n }, createElement('i', { style: { transform: `scaleX(${(course.avgMasteryPct ?? 0) / 100})` } })),\n createElement('input', {\n className: 'lks-search',\n type: 'search',\n placeholder: tr('rail.search'),\n value: query,\n onChange: (e: { target: { value: string } }) => { setQuery(e.target.value) },\n onKeyDown: (e: ReactKeyboardEvent<HTMLInputElement>) => {\n if (e.key !== 'Enter' || query.trim() === '') return\n for (const section of course.sections) {\n const hit = section.lessons.find(l => l.kind !== 'exam' && l.status !== 'locked' && titleMatches(l.title, query))\n if (hit !== undefined) {\n void setFocus(hit.id).catch(reportError)\n return\n }\n }\n // No title hit → full-text over lesson bodies (host-side search)\n void searchLessons(query).then(hits => {\n const hit = hits.find(h => h.lessonId.startsWith(`${courseId}:`)) ?? hits[0]\n if (hit !== undefined) { setQuery(''); void setFocus(hit.lessonId).catch(reportError) }\n }).catch(reportError)\n },\n }),\n course.sections.some(s => s.lessons.some(l => l.focus))\n ? createElement('button', {\n className: 'lks-btn ghost',\n style: { margin: '0 0 6px', padding: '3px 8px', fontSize: '13px' },\n title: tr('rail.locate.title'),\n onClick: () => {\n const focusSection = course.sections.find(s => s.lessons.some(l => l.focus))\n if (focusSection === undefined) return\n setSecOpen(m => ({ ...m, [`${courseId}/${focusSection.title}`]: true }))\n // One frame past the React commit, so the freshly-expanded node exists to scroll to.\n window.setTimeout(() => {\n document.querySelector('.lks-col-rail .lks-node.focus')?.scrollIntoView({ block: 'center', behavior: 'smooth' })\n }, 60)\n },\n }, createElement(IconPinFill16, { size: 13 }), tr('rail.locate'))\n : null,\n data.dueCount > 0\n ? createElement('div', { className: 'lks-duebox' },\n createElement(IconRefreshOutline16, { size: 13 }), tr('rail.due', { count: data.dueCount }),\n ...data.due.map(d => createElement('div', { key: d.lessonId, className: 'lks-due-item' },\n createElement('span', null, d.lessonTitle),\n d.overdueDays > 0 ? createElement('span', { className: 'lks-over' }, tr('rail.due.over', { days: d.overdueDays })) : null)),\n createElement('button', {\n className: 'lks-btn ghost',\n style: { marginTop: '6px' },\n onClick: () => { send(tr('prompt.review')) },\n }, tr('rail.due.start')),\n )\n : null,\n ...course.sections.flatMap(section => {\n const examAllowed = examOpen(section.lessons)\n const lessons = section.lessons.filter(l => query.trim() === '' || titleMatches(l.title, query) || l.focus)\n if (lessons.length === 0) return []\n const secKey = `${courseId}/${section.title}`\n // Active search overrides collapse (results must be visible);\n // otherwise the user's toggle wins over the frontier default.\n const open = query.trim() !== '' || (secOpen[secKey] ?? sectionDefaultOpen(section))\n return [\n createElement('button', {\n key: section.title,\n type: 'button',\n className: 'lks-sechead',\n 'aria-expanded': String(open),\n title: open ? tr('rail.section.collapse') : tr('rail.section.expand', { count: section.lessons.length }),\n onClick: () => { setSecOpen(m => ({ ...m, [secKey]: !open })) },\n },\n createElement('span', { className: 'lks-sec-num' }, String(section.index + 1)),\n createElement('span', { className: 'lks-sechead-t' }, section.title),\n open ? null : createElement('span', { className: 'lks-sechead-n' }, tr('rail.section.count', { count: section.lessons.length })),\n createElement('span', { className: 'lks-sechead-c' }, open ? '▾' : '▸')),\n ...(open ? lessons.map(lesson => {\n const locked = lesson.status === 'locked' || (lesson.kind === 'exam' && !examAllowed)\n // aria-disabled (not the disabled attribute): the row stays\n // focusable so its title can explain WHY it is locked.\n return createElement('button', {\n key: lesson.id,\n type: 'button',\n className: `lks-node${lesson.focus ? ' focus' : ''}`,\n 'aria-disabled': locked || undefined,\n title: jumping === lesson.id\n ? tr('rail.lesson.opening')\n : `${lesson.title} — ${statusTitle(lesson.kind, locked ? 'locked' : lesson.status)}${locked || lesson.kind === 'exam' ? '' : tr('rail.lesson.openHint')}`,\n onClick: () => {\n if (locked) return\n if (lesson.kind === 'exam') {\n void setFocus(lesson.id).catch(reportError)\n send(tr('prompt.exam', { section: section.title }))\n return\n }\n openLessonThread(lesson)\n },\n },\n createElement('span', { className: 'lks-g' }, jumping === lesson.id ? createElement(IconLoadingOutline16, { size: 14, className: 'lks-spin' }) : statusIcon(lesson.kind, locked ? 'locked' : lesson.status)),\n createElement('span', { className: 'lks-t' }, lesson.title),\n lesson.due ? createElement('span', { className: 'lks-tag due', title: tr('rail.due.tag') }, createElement(IconRefreshOutline16, { size: 11 })) : null,\n lesson.weakConcepts > 0 ? createElement('span', { className: 'lks-tag weak', title: tr('tag.weak', { count: lesson.weakConcepts }) }, createElement(IconBoltFill16, { size: 10 }), String(lesson.weakConcepts)) : null,\n lesson.frictionCount > 0 ? createElement('span', { className: 'lks-tag fric', title: tr('tag.friction', { count: lesson.frictionCount }) }, createElement(IconWarningOutline16, { size: 10 }), String(lesson.frictionCount)) : null,\n lesson.masteryPct !== null\n ? createElement('span', { className: 'lks-bar', title: tr('tag.mastery', { pct: lesson.masteryPct }) }, createElement('i', { style: { transform: `scaleX(${lesson.masteryPct / 100})` } }))\n : null,\n lesson.masteryPct !== null ? createElement('span', { className: 'lks-pct', title: tr('tag.mastery.short') }, `${lesson.masteryPct}%`) : null,\n )\n }) : []),\n ]\n }),\n createElement('button', {\n className: 'lks-btn ghost',\n style: { marginTop: '10px' },\n onClick: () => { setShowImport(!showImport) },\n }, showImport ? tr('rail.import.close') : createElement(IconPlusOutline16, { size: 13 }), tr('rail.import.toggle')),\n showImport ? createElement(ImportRow, { send }) : null,\n )\n })()\n return createElement('div', { className: 'lks-col lks-col-rail' },\n createElement('div', { className: 'lks-colhead' }, tr('col.rail')),\n body,\n createElement(ActionError, { error }),\n )\n}\n\n/** One transcript row's element; `interactive` adds the quiz-answer buttons to an assistant row. */\nfunction chatRowElement(row: ChatRow, interactive?: { send: StudySend }): ReactNode {\n if (row.role === 'user') {\n return createElement('div', { key: row.key, className: 'lks-msg user' }, row.text)\n }\n if (row.role === 'error') {\n return createElement('div', { key: row.key, className: 'lks-msg error' }, `⚠ ${row.text}`)\n }\n if (row.role === 'thinking') {\n return createElement('div', { key: row.key, className: 'lks-msg thinking', title: tr('row.thinking.title') },\n createElement(IconLoadingOutline16, { size: 14, className: 'lks-spin' }),\n row.text)\n }\n const cls = row.role === 'streaming' ? 'lks-msg assistant lks-prose streaming' : 'lks-msg assistant lks-prose'\n const body = createElement('div', {\n key: row.key,\n className: cls,\n dangerouslySetInnerHTML: { __html: renderMarkdown(row.text) },\n })\n const options = interactive === undefined || row.role === 'streaming' ? [] : quizOptions(row.text)\n if (options.length < 2) return body\n return createElement('div', { key: row.key, className: 'lks-turn' },\n body,\n createElement('div', { className: 'lks-quiz', title: tr('quiz.title') },\n ...options.map(opt => createElement('button', {\n key: opt.letter,\n className: 'lks-opt',\n onClick: () => { interactive.send(tr('quiz.answer', { letter: opt.letter, text: opt.text })) },\n },\n createElement('span', { className: 'lks-optletter' }, opt.letter),\n createElement('span', null, opt.text))),\n ))\n}\n\n/** Middle column: the tutor — transcript, proposal banner, pills, starters. Typing happens in the native composer below the tab. */\nfunction TutorColumn({ data, setMode, send, snapshot }: {\n data: StudyData\n setMode: (mode: 'direct' | 'guide' | 'practice') => Promise<void>\n send: StudySend\n snapshot: ConversationSnapshot\n}): ReactNode {\n const [error, setError] = useState<string | null>(null)\n const rows = transcriptRows(snapshot.nodes, snapshot.partial)\n // Quiz buttons only on the last settled assistant reply: older questions are\n // already answered, and the streaming partial may cut an option mid-line.\n const lastAssistant = rows.reduce((acc, row, i) => row.role === 'assistant' ? i : acc, -1)\n const scrollRef = useRef<HTMLDivElement | null>(null)\n useEffect(() => {\n const el = scrollRef.current\n if (el !== null) el.scrollTop = el.scrollHeight\n }, [rows.length])\n // Transcript enhancement rides the same scroll container: assistant math/code\n // diagrams get their CDN pass after every row change (idempotent per element).\n useEffect(() => {\n const el = scrollRef.current\n if (el !== null && rows.length > 0) void enhanceRendered(el).catch(() => { /* degrade */ })\n }, [rows.length])\n const proposal = data?.pendingProposals[0] ?? null\n const lesson = data?.lesson ?? null\n const dormant = data?.active !== true\n /** Mode switches are the only fallible write left here (host route); surface failures inline. */\n const fire = (action: Promise<void>): void => {\n action.then(() => { setError(null) }, (err: unknown) => { setError(err instanceof Error ? err.message : String(err)) })\n }\n return createElement('div', { className: 'lks-col lks-col-tutor' },\n createElement('div', { className: 'lks-colhead' }, tr('col.tutor')),\n dormant\n ? createElement('div', { className: 'lks-dormant' }, tr('tutor.dormant'))\n : null,\n createElement('div', { className: 'lks-transcript', ref: scrollRef },\n rows.length === 0 && !dormant\n ? createElement('div', { className: 'lks-empty' }, tr('tutor.empty'), createElement('br'), tr('tutor.empty.hint'))\n : rows.map((row, i) => chatRowElement(row, !dormant && i === lastAssistant ? { send } : undefined)),\n ),\n proposal !== null\n ? createElement('div', { className: 'lks-banner' },\n createElement('span', null, '🎓'),\n createElement('span', { className: 'lks-why' }, tr('proposal.text', { lesson: proposal.lessonTitle, rationale: proposal.rationale })),\n createElement('button', {\n className: 'lks-btn primary',\n onClick: () => { send(tr('prompt.proposal.accept', { id: proposal.id })) },\n }, tr('proposal.accept')),\n createElement('button', {\n className: 'lks-btn ghost',\n onClick: () => { send(tr('prompt.proposal.decline', { id: proposal.id })) },\n }, tr('proposal.decline')),\n )\n : null,\n createElement('div', { className: 'lks-pills', style: { height: 'auto', padding: '4px 0' } },\n ...MODES.map(mode => createElement('button', {\n key: mode.id,\n className: `lks-pill${data?.mode === mode.id ? ' on' : ''}`,\n 'aria-pressed': String(data?.mode === mode.id),\n 'aria-disabled': dormant || undefined,\n title: dormant ? tr('tutor.dormant') : tr(mode.hintKey),\n onClick: () => { if (!dormant) fire(setMode(mode.id)) },\n }, tr(mode.labelKey))),\n ),\n lesson !== null && lesson.starters.length > 0\n ? createElement('div', { className: 'lks-dock', style: { padding: '0 0 6px' } },\n ...lesson.starters.map(s => createElement('button', {\n key: s.label,\n className: 'lks-starter',\n 'aria-disabled': dormant || undefined,\n title: dormant ? tr('tutor.dormant') : s.message,\n onClick: () => { if (!dormant) send(s.message) },\n }, s.label)),\n )\n : null,\n createElement(ActionError, { error }),\n )\n}\n\n/** Right column: the blackboard — focus-lesson 讲解/脑图/概念图 plus the Cornell 笔记. */\nfunction BlackboardColumn({ data }: { data: StudyData }): ReactNode {\n const lesson = data?.lesson ?? null\n const [pane, setPane] = useState<'teach' | 'cmap'>('teach')\n const proseRef = useRef<HTMLDivElement | null>(null)\n const diagRef = useRef<HTMLDivElement | null>(null)\n // Post-render enhancement: math/shiki/mermaid via CDN, every failure degrades silently.\n useEffect(() => {\n if (pane !== 'teach' || proseRef.current === null || lesson === null) return\n const el = proseRef.current\n void enhanceRendered(el).catch(() => { /* degrade */ })\n }, [pane, lesson?.html])\n // Diagram panes (also CDN + vendored layout, honest one-line failure notice).\n useEffect(() => {\n if (pane !== 'cmap' || diagRef.current === null || lesson === null) return\n const el = diagRef.current\n el.textContent = ''\n const run = lesson.concepts.length === 0\n ? Promise.reject(new Error('no concepts'))\n : renderLessonConceptMap(el, lesson.title, lesson.concepts.map(c => ({ title: c.title, masteryPct: c.masteryPct })))\n run.catch((err) => {\n console.error('lks diagram pane failed:', pane, err)\n el.textContent = lesson.concepts.length === 0\n ? tr('bb.fallback.cmap.empty')\n : tr('bb.fallback.cmap')\n })\n }, [pane, lesson?.lessonId, lesson?.concepts.length])\n\n const body: ReactNode = lesson === null\n ? createElement('div', { className: 'lks-empty' }, tr('bb.empty'), createElement('br'), tr('bb.empty.hint'))\n : createElement('div', null,\n createElement('div', { className: 'lks-lessonhead' },\n createElement('h2', null, lesson.title),\n createElement('div', { className: 'lks-meta' },\n `${lesson.courseTitle} · ${statusTitle('study', lesson.status)}`\n + (lesson.masteryPct === null ? '' : ` · ${tr('bb.mastery', { pct: lesson.masteryPct })}`)),\n createElement('div', { className: 'lks-meta' }, `${tr('bb.strategy')}:${lesson.strategy}`),\n lesson.concepts.length > 0\n ? createElement('div', { className: 'lks-chips' },\n ...lesson.concepts.map(c => createElement('span', {\n key: c.title,\n className: `lks-chip${c.weak ? ' weak' : ''}`,\n }, `${c.title} ${c.masteryPct}%${c.weak ? ' ⚡' : ''}`)))\n : null,\n ),\n createElement('div', { className: 'lks-viewtabs' },\n createElement('button', { className: `lks-viewtab${pane === 'teach' ? ' on' : ''}`, 'aria-pressed': String(pane === 'teach'), onClick: () => { setPane('teach') } }, tr('viewtab.teach')),\n createElement('button', { className: `lks-viewtab${pane === 'cmap' ? ' on' : ''}`, 'aria-pressed': String(pane === 'cmap'), title: tr('viewtab.cmap.title'), onClick: () => { setPane('cmap') } }, createElement(IconGlobeOutline14, { size: 13 }), tr('viewtab.cmap')),\n ),\n pane === 'teach'\n ? createElement('div', { className: 'lks-prose', ref: proseRef, dangerouslySetInnerHTML: { __html: lesson.html } })\n : createElement('div', { className: 'lks-prose', ref: diagRef }),\n createElement('div', { className: 'lks-bb-notes' },\n createElement('div', { className: 'lks-sec' }, tr('bb.notes')),\n lesson.notes.length === 0\n ? createElement('div', { className: 'lks-empty', style: { padding: '16px 0' } }, tr('bb.notes.empty'))\n : ZONES.filter(([zone]) => lesson.notes.some(n => n.zone === zone)).map(([zone, labelKey]) =>\n createElement('div', { key: zone, className: 'lks-zone' },\n createElement('div', { className: 'lks-zone-h' }, tr(labelKey)),\n ...lesson.notes.filter(n => n.zone === zone).map(n => createElement('div', { key: n.id, className: 'lks-note' },\n createElement('span', { className: 'lks-note-src' }, n.source),\n createElement('div', { className: 'lks-note-title' }, n.title),\n createElement('div', { className: 'lks-note-text', dangerouslySetInnerHTML: { __html: renderMarkdown(n.text) } }),\n n.quote !== null ? createElement('div', { className: 'lks-note-q' }, `“${n.quote}”`) : null,\n )),\n )),\n ),\n )\n return createElement('div', { className: 'lks-col lks-col-bb' },\n createElement('div', { className: 'lks-colhead' }, tr('col.bb')),\n body,\n )\n}\n","/**\n * The one-click study starter: a pill button in the blank-session (hero)\n * composer tool row. One click adopts the plugin's dedicated study workspace\n * (created by the host beside the state file), opens a session in it, sends\n * the kickoff prompt through the session API, and makes that session current\n * — the learner lands in the chat with the tutor already responding, one\n * click away from the 学习 tab (view switching is ui-conversation-private,\n * not reachable from an additive plugin).\n * @module dsh-plugin-lookatstudy/client/starter\n */\n\nimport { createElement, useState } from 'react'\nimport type { ReactNode } from 'react'\nimport { IconLoadingOutline16, IconThinkOutline16 } from './icons.tsx'\nimport { useStudy } from './data.ts'\nimport { tr } from './locale.ts'\nimport type { InputZone } from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\n\n/**\n * Build the hero starter button bound to the framework services.\n * @param ctx - client root context (workspaces + sessions injected).\n * @returns the component for `conversation.input.left`.\n */\nexport function studyStartButton(ctx: ClientContext): (props: InputZone) => ReactNode {\n return function StudyStartButton({ session }: InputZone): ReactNode {\n if (session.blank !== true) return null\n return createElement(Inner, { key: 'inner', ctx })\n }\n}\n\n/** Button body in its own component so hook order stays constant. */\nfunction Inner({ ctx }: { ctx: ClientContext }): ReactNode {\n const { data, activate } = useStudy()\n const [busy, setBusy] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const start = (): void => {\n if (busy) return\n setBusy(true)\n setError(null)\n void (async () => {\n try {\n // Dormant installs activate first: the host registers the study tools\n // before this POST resolves, so the kickoff prompt below meets a model\n // that can already call them.\n if (data?.active !== true) await activate(true)\n const area = await fetch('/lookatstudy/api/study-workspace')\n if (!area.ok) throw new Error(`study area unavailable (HTTP ${area.status})`)\n const { path } = await area.json() as { path: string }\n const workspace = await ctx.workspaces.create({ path })\n const sessionId = await ctx.workspaces.connectWorkspace(workspace.workspaceId)\n const actx = ctx.sessions.scope(sessionId)\n const face = actx === undefined ? undefined : ctx.sessions.sessionOf(actx)\n if (face === undefined) throw new Error('study session is not addressable yet')\n const result = await face.prompt([{ type: 'text', text: tr('prompt.kickoff') }], 'queue')\n if (!result.ok) throw new Error(`kickoff prompt rejected: ${result.error.code}: ${result.error.message}`)\n ctx.sessions.open(sessionId)\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err))\n setBusy(false)\n }\n })()\n }\n return createElement('span', { className: 'lks-root', style: { display: 'inline-flex', alignItems: 'center', gap: '8px' } },\n createElement('button', {\n className: 'lks-pill on',\n title: tr('start.title'),\n disabled: busy,\n onClick: start,\n },\n busy\n ? createElement(IconLoadingOutline16, { className: 'lks-spin' })\n : createElement(IconThinkOutline16, null),\n busy ? tr('start.busy') : data?.active === true ? tr('start.enter') : tr('start.go')),\n error !== null ? createElement('span', { className: 'lks-propcard-err', style: { marginTop: 0 } }, error) : null,\n )\n}\n","/**\n * The plugin's settings page: one `settings.section` entry riding the host's\n * settings shell. Teaching style and study mode write through the same host\n * routes the study tab uses (POST /api/mode, /api/active — the latter syncs\n * the tool registry before responding); stats and the state-file path are\n * read-only projections of the shared poll store. Pure display + the store's\n * existing write actions; no new routes, no new requests beyond the poll.\n * @module dsh-plugin-lookatstudy/client/settings\n */\n\nimport { createElement, useState } from 'react'\nimport type { ReactNode } from 'react'\nimport { useStudy } from './data.ts'\nimport { tr } from './locale.ts'\nimport { ActionError } from './views.tsx'\n\n/** The three souls in pill order (same shape as the study tab's pills). */\nconst MODES: ReadonlyArray<{ id: 'direct' | 'guide' | 'practice'; labelKey: string; hintKey: string }> = [\n { id: 'direct', labelKey: 'soul.direct', hintKey: 'soul.direct.hint' },\n { id: 'guide', labelKey: 'soul.guide', hintKey: 'soul.guide.hint' },\n { id: 'practice', labelKey: 'soul.practice', hintKey: 'soul.practice.hint' },\n]\n\n/**\n * The settings section component. Props from the settings shell (`close`) are\n * unused — every control stays on the page.\n */\nexport function StudySettingsSection(): ReactNode {\n const { data, setMode, activate } = useStudy()\n const [error, setError] = useState<string | null>(null)\n const fire = (action: Promise<void>): void => {\n action.then(() => { setError(null) }, (err: unknown) => { setError(err instanceof Error ? err.message : String(err)) })\n }\n const progress = data?.progress\n return createElement('div', { className: 'lks-root lks-settings' },\n createElement('section', { className: 'lks-set-row' },\n createElement('h3', null, tr('settings.mode')),\n createElement('p', { className: 'lks-set-hint' }, tr('settings.mode.hint')),\n createElement('div', { className: 'lks-pills' },\n ...MODES.map(mode => createElement('button', {\n key: mode.id,\n className: `lks-pill${data?.mode === mode.id ? ' on' : ''}`,\n title: tr(mode.hintKey),\n onClick: () => { fire(setMode(mode.id)) },\n }, tr(mode.labelKey))),\n ),\n ),\n createElement('section', { className: 'lks-set-row' },\n createElement('h3', null, tr('settings.studyMode')),\n createElement('p', { className: 'lks-set-hint' }, tr('settings.studyMode.hint')),\n createElement('div', null,\n createElement('button', {\n className: `lks-btn ${data?.active === true ? 'ghost' : 'primary'}`,\n onClick: () => { if (data !== null) fire(activate(!data.active)) },\n }, data?.active === true ? tr('settings.turnOff') : tr('settings.turnOn')),\n createElement('span', { className: 'lks-set-state' }, data?.active === true ? tr('settings.on') : tr('settings.off')),\n ),\n ),\n progress === undefined ? null : createElement('section', { className: 'lks-set-row' },\n createElement('h3', null, tr('settings.stats')),\n createElement('ul', { className: 'lks-set-stats' },\n createElement('li', null, tr('settings.stats.courses', { count: data?.courses.length ?? 0 })),\n createElement('li', null, tr('settings.stats.xp', { xp: progress.totalXp, level: progress.level, pct: progress.levelPct })),\n createElement('li', null, tr('settings.stats.today', { xp: progress.todayXp, goal: progress.dailyGoal })),\n createElement('li', null, tr('settings.stats.streak', { days: progress.streak, best: progress.longestStreak, freeze: progress.freezeCount })),\n ),\n ),\n createElement('section', { className: 'lks-set-row' },\n createElement('h3', null, tr('settings.about')),\n createElement('p', { className: 'lks-set-hint' }, tr('settings.about.hint')),\n data?.version ? createElement('a',\n { href: `https://github.com/Kaiji-Z/dsh-plugin-lookatstudy/releases/tag/v${data.version}`, target: '_blank', rel: 'noreferrer' },\n `v${data.version}`) : null,\n ),\n createElement('section', { className: 'lks-set-row' },\n createElement('h3', null, tr('settings.stateFile')),\n createElement('p', { className: 'lks-set-hint' }, tr('settings.stateFile.hint')),\n data === null ? null : createElement('code', { className: 'lks-set-path' }, data.statePath),\n ),\n createElement(ActionError, { error }),\n )\n}\n","/**\n * The composer dock status pill: one `conversation.composer.dock` entry (the\n * ambient readout band under the composer, next to the token stats) showing\n * due reviews / streak / level while the study surface is ACTIVE — dormant\n * installs render nothing at all, the same visibility the tool registry has.\n * Data rides the shared 3 s poll store (no extra requests). Display-only:\n * conversation-view tab switching is ui-conversation-private (the starter\n * button's limitation), so the tooltip points at the Study tab instead.\n * @module dsh-plugin-lookatstudy/client/dock\n */\n\nimport { createElement } from 'react'\nimport { IconBoltFill16, IconFlameFill16 } from './icons.tsx'\nimport type { ReactNode } from 'react'\nimport { useStudy } from './data.ts'\nimport { tr } from './locale.ts'\n\n/** Pure projection of the pill's segments (testable without React). `muted` marks zero-value segments — an empty state must not wear a warning color. */\nexport function dockSegments(progress: { dueCount: number; streak: number; level: number }): ReadonlyArray<{ key: string; text: string; muted: boolean }> {\n return [\n { key: 'due', text: tr('dock.due', { count: progress.dueCount }), muted: progress.dueCount === 0 },\n { key: 'streak', text: tr('dock.streak', { days: progress.streak }), muted: progress.streak === 0 },\n { key: 'lv', text: tr('dock.lv', { level: progress.level }), muted: false },\n ]\n}\n\n/** The dock entry component; renders nothing while data is loading or dormant. */\nexport function StudyDockPill(): ReactNode {\n const { data } = useStudy()\n if (data === null || data.active !== true) return null\n const segments = dockSegments({ dueCount: data.dueCount, streak: data.progress.streak, level: data.progress.level })\n return createElement('span', {\n className: 'lks-root lks-dockpill',\n title: tr('dock.title', { due: data.dueCount, streak: data.progress.streak, level: data.progress.level }),\n },\n ...segments.map(s => createElement('span', { key: s.key, className: `lks-dockseg lks-dock-${s.key}${s.muted ? ' lks-muted' : ''}` },\n s.key === 'due' ? createElement(IconBoltFill16, { size: 11 }) : s.key === 'streak' ? createElement(IconFlameFill16, { size: 11 }) : null, s.text)),\n )\n}\n","/**\n * Keyed `tool.call.toolview` entries: learning-aware cards for the\n * conversation tab's tool rows (our own study tab renders its own chips, but\n * learning also happens in the plain 对话 view). One generic card body over\n * the result's `meta` (the tool's presentationMeta lines — replay-safe by\n * construction) with a per-tool header; `study_record_answer` additionally\n * parses its args for a live ✓/✗ tone while the call is still running.\n * @module dsh-plugin-lookatstudy/client/toolviews\n */\n\nimport { createElement } from 'react'\nimport type { ReactNode } from 'react'\nimport { tr } from './locale.ts'\n\n/** Structural slice of ToolCallBlock the views consume. */\nexport interface ToolBlockFace {\n kind?: string\n name?: string\n argsRaw?: string\n content?: ReadonlyArray<{ type: string; text?: string }>\n isError?: boolean\n meta?: unknown\n}\n\n/** Props slice the slot passes (ToolCallOwnerProps). */\nexport interface ToolViewPropsFace {\n toolName: string\n block: ToolBlockFace\n}\n\n/** Header glyph per tool (missing tools simply use the generic row). */\nconst TOOL_GLYPHS: Record<string, string> = {\n study_record_answer: '✍️',\n study_lesson: '📘',\n study_due_reviews: '🔁',\n study_exam_result: '🎯',\n}\n\n/** The ✓/✗ tone from record_answer's args; null for other shapes. Pure. */\nexport function answerTone(argsRaw: string | undefined): { correct: boolean; concept: string } | null {\n if (argsRaw === undefined) return null\n try {\n const args = JSON.parse(argsRaw) as { concept?: unknown; correct?: unknown }\n return {\n correct: args.correct === true,\n concept: typeof args.concept === 'string' && args.concept !== '' ? args.concept : tr('chip.unattributed'),\n }\n } catch {\n return null\n }\n}\n\n/** Card lines: the result's meta (string[]) when present, else its text content. Pure. */\nexport function metaLines(block: ToolBlockFace): string[] {\n if (Array.isArray(block.meta)) {\n const lines = (block.meta as unknown[]).filter((x): x is string => typeof x === 'string')\n if (lines.length > 0) return lines\n }\n return (block.content ?? [])\n .filter(b => b.type === 'text' && typeof b.text === 'string')\n .map(b => (b.text as string).split('\\n'))\n .flat()\n .filter(l => l.trim() !== '')\n}\n\n/** Shared card body: header + lines; error results keep their text visible. */\nfunction studyToolCard(toolName: string, block: ToolBlockFace, extra?: ReactNode): ReactNode {\n const lines = metaLines(block)\n const glyph = TOOL_GLYPHS[toolName] ?? '🔧'\n return createElement('div', { className: `lks-tv${block.isError === true ? ' err' : ''}` },\n extra ?? null,\n createElement('span', { className: 'lks-tv-head' }, `${glyph} ${toolName}`),\n lines.length === 0\n ? null\n : createElement('div', { className: 'lks-tv-lines' },\n ...lines.map((line, i) => createElement('div', { key: String(i), className: 'lks-tv-line' }, line)),\n ),\n )\n}\n\n/** study_record_answer: live ✓/✗ tone from args + the graded line from meta. */\nexport function StudyAnswerView({ toolName, block }: ToolViewPropsFace): ReactNode {\n const tone = answerTone(block.argsRaw)\n const chip = tone === null ? null : createElement('span', { className: `lks-tv-chip ${tone.correct ? 'ok' : 'bad'}` },\n tr(tone.correct ? 'chip.correct' : 'chip.wrong', { concept: tone.concept }))\n return studyToolCard(toolName, block, chip)\n}\n\n/** Generic meta-line card for the read-type study tools. */\nexport function StudyLessonView({ toolName, block }: ToolViewPropsFace): ReactNode {\n return studyToolCard(toolName, block)\n}\n\n/** study_due_reviews list card. */\nexport function StudyDueView({ toolName, block }: ToolViewPropsFace): ReactNode {\n return studyToolCard(toolName, block)\n}\n\n/** Stars from the exam card's presentationMeta line (`N★`); null when absent. Pure. */\nexport function examStars(block: ToolBlockFace): { stars: number; best: number } | null {\n const lines = metaLines(block)\n for (const line of lines) {\n const m = /^([0-3])★\\s*\\(?(?:best\\s*([0-3])★)?/.exec(line.trim()) ?? /^(?:本次\\s*)?([0-3])★/.exec(line.trim())\n if (m !== null) return { stars: Number(m[1]), best: Number(m[2] ?? m[1]) }\n }\n return null\n}\n\n/** study_exam_result star card — and the failure moment finally gets its line. */\nexport function StudyExamView({ toolName, block }: ToolViewPropsFace): ReactNode {\n const r = examStars(block)\n const stars = r === null\n ? null\n : createElement('span', { className: 'lks-tv-stars' },\n [0, 1, 2].map(i => createElement('span', { key: i, className: i < r.stars ? 'full' : 'dim' }, '★')),\n createElement('span', { className: 'lks-tv-stars-label' }, tr('tv.exam.stars', { n: r.stars, best: r.best })))\n const fail = r !== null && r.stars === 0 ? createElement('div', { className: 'lks-tv-failnote' }, tr('tv.exam.fail')) : null\n return studyToolCard(toolName, block, createElement('span', null, stars, fail))\n}\n","/**\n * Browser half of dsh-plugin-lookatstudy (`dsh.client`): ONE conversation\n * view tab — 「学习」— carrying the whole plugin. Inside the tab it is a\n * simplified LookatStudy in three columns (课程 | 老师 | 黑板); nothing\n * outside the tab modifies dsh chrome. Live study state comes from the shared\n * poll store over the host plugin's `/lookatstudy/api/*` routes; the tutor\n * column additionally reads the session snapshot through the framework\n * standard kit and sends messages via the same reverse channel as the\n * standalone workbench page.\n * @module dsh-plugin-lookatstudy/client\n */\n\nimport type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\nimport type { ReactNode } from 'react'\nimport { ensureStudyStyles } from './styles.ts'\nimport { studyView } from './views.tsx'\nimport { studyStartButton } from './starter.tsx'\nimport { StudySettingsSection } from './settings.tsx'\nimport { StudyDockPill } from './dock.tsx'\nimport { StudyAnswerView, StudyDueView, StudyExamView, StudyLessonView, type ToolViewPropsFace } from './toolviews.tsx'\nimport { registerStudyLocale, setStudyTranslator, studyTranslator, tr, type LocaleServiceFace } from './locale.ts'\n\n/** The toolview components' expected props (structural slice of ToolCallViewProps). */\ntype ToolViewProps = ToolViewPropsFace\n\nexport { studyView, transcriptRows } from './views.tsx'\nexport type { ChatRow } from './views.tsx'\n\nexport const inject = ['slots', 'workspaces', 'sessions', 'locale']\n\n/**\n * Register the study surfaces: styles inject once; the single\n * `conversation.view` tab carries the whole plugin; the hero starter button\n * (`conversation.input.left`, blank sessions only) automates the onboarding —\n * study workspace + session + kickoff prompt in one click. The `lookatstudy`\n * locale namespace rides the framework locale service (zh/en) and the\n * client-wide translator is installed before any component renders; both\n * slot entries declare the namespace so the framework synthesizes their `t`\n * seat and follows locale switches for the labels.\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n ensureStudyStyles()\n const localeSvc = (ctx as { locale?: LocaleServiceFace }).locale\n ctx.effect(() => registerStudyLocale(localeSvc), 'lookatstudy.locale()')\n setStudyTranslator(studyTranslator(localeSvc))\n ctx.slots.inject('conversation.view', () => ctx.slots.register(\n { name: 'conversation.view', id: 'lookatstudy-study', order: 15, label: () => tr('tab.label'), locale: 'lookatstudy' },\n studyView(ctx),\n ))\n ctx.slots.inject('conversation.input.left', () => ctx.slots.register(\n { name: 'conversation.input.left', id: 'lookatstudy-start', order: 10, locale: 'lookatstudy' },\n studyStartButton(ctx),\n ))\n // One settings page in the host settings shell: teaching style + study mode\n // through the same host routes the tab uses, plus read-only stats and the\n // state-file path.\n ctx.slots.inject('settings.section', () => ctx.slots.register(\n { name: 'settings.section', id: 'lookatstudy', order: 30, label: () => tr('settings.nav'), locale: 'lookatstudy' },\n StudySettingsSection,\n ))\n // The ambient study-status pill under the composer (due/streak/level); the\n // component itself renders nothing while dormant or loading.\n ctx.slots.inject('conversation.composer.dock', () => ctx.slots.register(\n { name: 'conversation.composer.dock', id: 'lookatstudy-status', order: 10, locale: 'lookatstudy' },\n StudyDockPill,\n ))\n // Learning-aware cards for the conversation tab's tool rows (keyed by wire\n // tool name; unregistered study tools keep the generic row).\n const toolviews: ReadonlyArray<[string, (props: ToolViewProps) => ReactNode]> = [\n ['study_record_answer', StudyAnswerView],\n ['study_lesson', StudyLessonView],\n ['study_due_reviews', StudyDueView],\n ['study_exam_result', StudyExamView],\n ]\n for (const [tool, component] of toolviews) {\n ctx.slots.inject('tool.call.toolview', () => ctx.slots.register(\n { name: 'tool.call.toolview', key: tool, locale: 'lookatstudy' },\n component,\n ))\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":["createElement","useSyncExternalStore","MODES","createElement","useState","useRef","createElement","useState","useState","createElement","createElement","createElement"],"sources":["../src/client/styles.ts","../src/client/icons.tsx","../src/client/data.ts","../src/markdown.ts","../src/vendor/mermaid-elk-rewrite.ts","../src/client/enhance.ts","../src/vendor/cmap-elk-layout.ts","../src/client/locale.ts","../src/client/diagrams.ts","../src/client/views.tsx","../src/client/starter.tsx","../src/client/settings.tsx","../src/client/dock.tsx","../src/client/toolviews.tsx","../src/client/index.ts"],"sourcesContent":["/**\n * Style injection for the study tab: one `<style>` element of `.lks-*`\n * classes authored against the dsh `--dsw-*` design tokens, so the tab\n * follows the app's theme (light/dark) instead of carrying its own palette.\n * CSS Modules are unavailable to patch-layer bundles, so the stylesheet is\n * injected once at client-plugin apply; the `data-` attribute keeps the\n * injection idempotent.\n * @module dsh-plugin-lookatstudy/client/styles\n */\n\n/** Marker attribute proving the stylesheet is already in the document. */\nconst STYLE_ID = 'data-dsh-plugin-lookatstudy'\n\n/**\n * The study tab's stylesheet. Class names are `lks-*` namespaced; colors,\n * fonts, and radii come from `--dsw-*` tokens wherever the concept exists.\n */\nexport const STUDY_CSS = `\n/* State inks: small colored text must clear WCAG AA (4.5:1), but the host's\n raw state tokens (success/warn primaries) sit at 2.3–2.6:1 on light\n backgrounds, and success/error *label* aliases are not published by this\n host at all (the tv-chip used to reference them and silently inherit).\n Mixing the state color toward label-primary keeps the hue while pulling\n luminance to the readable pole — and works in BOTH themes, because\n label-primary is always the current theme's high-contrast ink. */\n.lks-root{--lks-warn-ink:color-mix(in srgb,var(--dsw-alias-state-warn-label) 45%,var(--dsw-alias-label-primary));--lks-ok-ink:color-mix(in srgb,var(--dsw-alias-state-success-primary) 40%,var(--dsw-alias-label-primary));--lks-err-ink:color-mix(in srgb,var(--dsw-alias-state-error-primary) 55%,var(--dsw-alias-label-primary));font-family:var(--dsw-font-family)}\n.lks-root :where(button){font-family:var(--dsw-font-family);cursor:pointer;border:none;background:none;padding:0}\n.lks-root :where(a){color:var(--dsw-alias-state-business-primary)}\n\n/* ── the study tab: composer-width center, self-scrolling flanks ──\n data-conversation-composer-overlay (set on the root element) opts the\n view into the host's overlay mode: viewArea becomes a fixed-height\n non-growing host and the composer floats over the tab's bottom band, so\n the tab itself never feeds the page scroll. The bottom padding clears the\n floating composer via the host-published live --dsh-composer-height. The\n tutor column shares the conversation column's width axis\n (--dsh-composer-card-max-width inherits from ConversationRoot's root) but\n is capped at 42% of the tab so the BLACKBOARD — the reading surface —\n keeps the lion's share at every wide width; the composer card follows the\n tutor column's real measured width (views.tsx), so the two stay visually\n tied. Flanking columns absorb the remaining width and scroll independently. */\n.lks-study{height:100%;min-height:0;width:100%;box-sizing:border-box;overflow:hidden;display:flex;flex-direction:column;padding:10px 14px calc(var(--dsh-composer-height, 152px) + 12px);color:var(--dsw-alias-label-primary);container:lksstudy/inline-size}\n/* Direction carrier (a container query cannot style the container itself). */\n.lks-body{flex:1;min-height:0;min-width:0;display:flex;gap:16px}\n.lks-col{display:flex;flex-direction:column;min-width:0}\n.lks-colhead{flex:none;font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary);letter-spacing:.06em;text-transform:uppercase;margin-bottom:10px}\n.lks-col-rail{flex:0 1 260px;min-width:180px;overflow-y:auto;padding:2px 6px}\n.lks-col-tutor{flex:0 1 auto;width:min(100%,var(--dsh-composer-card-max-width,780px),42cqi);min-width:360px;overflow:hidden}\n.lks-col-bb{flex:1 1 0;min-width:320px;overflow-y:auto;padding:2px 6px}\n/* While the study view is mounted in wide mode, the host composer card is\n shifted under the tutor column (the transcript's width axis) instead of the\n scroll body's center — views.tsx measures the offset, sets the variables\n and toggles the class, and removes all three whenever the shift collapses\n (narrow pane, hidden view) so the host's natural centering and width come\n back. max-width tracks the tutor column's live width: the tutor shrinks\n proportionally below ~1857px containers, and the card shrinks with it. */\n[data-composer-card].lks-composer-follow{align-self:flex-start;margin-left:var(--lks-composer-shift,0px);max-width:var(--lks-composer-follow-width,var(--dsh-composer-card-max-width,780px))}\n/* narrow (<1220px): one composer-width pane at a time, chosen by a centered\n segmented pill group (joined buttons in one capsule — button language, not\n tab language, against the host's view tabs right above). */\n.lks-switch{display:none;flex-direction:row;gap:2px;align-self:center;margin-bottom:10px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:999px;padding:3px}\n.lks-switch-btn{border-radius:999px;padding:5px 18px;font-size:14px;color:var(--dsw-alias-label-tertiary);background:transparent;transition:background .12s ease,color .12s ease}\n.lks-switch-btn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}\n.lks-switch-btn.on{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 86%,#000);color:#fff;font-weight:600}\n@container lksstudy (max-width: 1220px){\n .lks-body{flex-direction:column}\n .lks-switch{display:flex}\n .lks-colhead{display:none}\n .lks-col{flex:1 1 auto;min-height:0;width:auto;overflow-y:auto}\n .lks-col-tutor{width:min(100%,var(--dsh-composer-card-max-width,780px));overflow:hidden;display:flex;flex-direction:column}\n .lks-study[data-pane='rail'] .lks-col-tutor,.lks-study[data-pane='rail'] .lks-col-bb,\n .lks-study[data-pane='tutor'] .lks-col-rail,.lks-study[data-pane='tutor'] .lks-col-bb,\n .lks-study[data-pane='bb'] .lks-col-rail,.lks-study[data-pane='bb'] .lks-col-tutor{display:none}\n}\n\n/* ── left column: course rail ── */\n.lks-rail-head{display:flex;align-items:center;gap:6px;margin-bottom:4px}\n.lks-rail-head .lks-rail-select{flex:1;min-width:0;margin-bottom:0}\n.lks-rail-head .lks-btn{padding:3px 8px;font-size:13px}\n.lks-rail-title{font-size:16px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.lks-rail-sub{font-size:13px;color:var(--dsw-alias-label-secondary);margin:4px 0 6px}\n.lks-masterybar{height:5px;border-radius:3px;background:var(--dsw-alias-bg-layer-3);overflow:hidden;margin-bottom:8px}\n.lks-masterybar i{display:block;height:100%;width:100%;background:var(--dsw-alias-state-success-primary);transform-origin:0 50%;transition:transform .3s ease}\n.lks-masterybar.gold i{background:var(--dsw-alias-state-warn-primary)}\n.lks-search{width:100%;box-sizing:border-box;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;color:var(--dsw-alias-label-primary);font-family:inherit;font-size:13.5px;padding:5px 9px;margin-bottom:4px}\n.lks-search:focus{outline:none;border-color:var(--dsw-alias-state-business-primary);box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}\n.lks-sec-num{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;border-radius:50%;background:var(--dsw-alias-state-warn-tertiary);color:var(--lks-warn-ink);font-size:11px;font-weight:700;margin-right:4px}\n.lks-tag.due{background:var(--dsw-alias-state-warn-tertiary);color:var(--lks-warn-ink)}\n.lks-import{margin-top:8px}\n.lks-import .lks-inputrow{margin-top:0}\n.lks-inputrow{display:flex;gap:8px;align-items:flex-end;flex:none;margin-top:8px}\n.lks-input{flex:1;min-width:0;resize:none;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;color:var(--dsw-alias-label-primary);font-family:inherit;font-size:14px;line-height:1.6;padding:8px 10px}\n.lks-input:focus{outline:none;border-color:var(--dsw-alias-state-business-primary)}\n.lks-input:disabled{opacity:.55}\n.lks-import-hint{font-size:12.5px;color:var(--dsw-alias-label-secondary);margin-top:6px;line-height:1.7}\n.lks-duebox{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;padding:10px 12px;margin:8px 0 14px;font-size:13.5px}\n.lks-duebox .lks-due-item{color:var(--dsw-alias-label-secondary);margin-top:4px;display:flex;justify-content:space-between;gap:10px}\n.lks-duebox .lks-over{color:var(--lks-warn-ink);flex:none}\n\n.lks-sec{font-size:12px;color:var(--dsw-alias-label-secondary);text-transform:uppercase;letter-spacing:.05em;margin:14px 0 4px}\n/* Collapsible section head: a real button (keyboard can toggle it), sticky so\n the current chapter stays identified while 4000px of nodes scroll under it. */\n.lks-sechead{display:flex;align-items:center;gap:6px;width:100%;box-sizing:border-box;font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary);text-align:left;padding:6px 4px;margin:14px 0 4px;border-radius:6px;position:sticky;top:0;z-index:1;background:var(--dsw-alias-bg-base)}\n.lks-sechead:hover{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover)}\n.lks-sechead:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary);outline:none}\n.lks-sechead-t{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.lks-sechead-c{flex:none;font-size:10px}\n.lks-sechead-n{flex:none;font-size:11px;text-transform:none;letter-spacing:0}\n.lks-node{display:flex;align-items:center;gap:8px;width:100%;text-align:left;padding:6px 9px;border-radius:8px;margin:1px 0;cursor:pointer}\n.lks-node:hover{background:var(--dsw-alias-interactive-bg-hover)}\n.lks-node:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary);outline:none}\n.lks-node.focus{background:var(--dsw-alias-bg-layer-3);outline:1px solid var(--dsw-alias-border-l2)}\n.lks-node .lks-g{width:18px;text-align:center;flex:none}\n.lks-node .lks-t{flex:1;font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n/* aria-disabled (not the disabled attribute): the row stays focusable so the\n status tooltip can explain WHY it is locked — Firefox drops titles on truly\n disabled form controls. */\n.lks-node[aria-disabled='true']{opacity:.45;cursor:not-allowed}\n.lks-node[aria-disabled='true']:hover{background:none}\n.lks-tag{font-size:11px;border-radius:4px;padding:0 4px;flex:none}\n.lks-tag.weak{background:var(--dsw-alias-state-warn-tertiary);color:var(--lks-warn-ink)}\n.lks-tag.fric{background:var(--dsw-alias-state-error-tertiary);color:var(--lks-err-ink)}\n.lks-bar{width:44px;height:4px;border-radius:2px;background:var(--dsw-alias-bg-layer-3);overflow:hidden;flex:none}\n.lks-bar i{display:block;height:100%;width:100%;background:var(--dsw-alias-state-success-primary);transform-origin:0 50%}\n.lks-pct{font-size:12px;color:var(--dsw-alias-label-secondary);flex:none;width:32px;text-align:right}\n\n.lks-empty{color:var(--dsw-alias-label-secondary);text-align:center;padding:48px 8px;font-size:14px;line-height:2}\n.lks-actbar{display:flex;flex-direction:row;justify-content:flex-end;flex:none;padding-bottom:8px}\n\n/* ── middle column: the tutor ── */\n.lks-transcript{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:10px;padding:4px 2px}\n.lks-msg{max-width:94%;font-size:16px;line-height:1.7;border-radius:12px;padding:8px 12px;word-break:break-word}\n.lks-msg.user{align-self:flex-end;white-space:pre-wrap;background:var(--dsw-alias-state-business-tertiary);color:var(--dsw-alias-label-primary-bluish)}\n.lks-msg.assistant{align-self:flex-start;background:var(--dsw-alias-bg-layer-2)}\n.lks-msg.streaming{opacity:.7}\n.lks-msg.thinking{align-self:flex-start;display:inline-flex;align-items:center;gap:8px;font-size:13px;color:var(--dsw-alias-label-secondary);background:none;border-radius:0;padding:2px}\n.lks-msg.error{align-self:stretch;color:var(--dsw-alias-state-error-primary);font-size:13px;background:none;border-radius:0;padding:1px 2px}\n/* quiz-taking surface: the tutor's A–D options become clickable answers on the last settled reply */\n.lks-turn{display:flex;flex-direction:column;align-items:flex-start;max-width:94%}\n.lks-quiz{display:flex;flex-direction:column;gap:6px;width:100%;margin:2px 0 4px}\n.lks-opt{display:flex;align-items:baseline;gap:10px;text-align:left;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:10px;padding:8px 14px;font-size:14px;line-height:1.5;color:var(--dsw-alias-label-secondary);cursor:pointer;font-family:inherit;transition:border-color .12s ease,color .12s ease,background .12s ease}\n.lks-opt:hover{border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-state-business-tertiary)}\n.lks-opt:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary);outline:none}\n.lks-optletter{font-weight:700;color:var(--dsw-alias-label-primary-bluish);flex:none}\n\n/* soul pills (native tool-row trigger language: 28px transparent, tinted active) */\n.lks-pills{display:inline-flex;align-items:center;height:28px}\n.lks-pill{display:inline-flex;align-items:center;gap:6px;height:28px;padding:0 10px;border:none;border-radius:24px;background:transparent;color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:20px;font-weight:500;transition:background .12s ease,color .12s ease}\n.lks-pill:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}\n.lks-pill:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary);outline:none}\n.lks-pill.on{background:var(--dsw-alias-state-business-tertiary);color:var(--dsw-alias-label-primary-bluish)}\n.lks-pill.on:hover{background:var(--dsw-alias-state-business-tertiary);color:var(--dsw-alias-label-primary-bluish)}\n\n/* SVG glyph alignment (status icons, tag badges, dock segments, icon buttons) */\n.lks-g svg{display:block;margin:0 auto}\n.lks-tag{display:inline-flex;align-items:center;gap:2px;line-height:1}\n.lks-dockseg{display:inline-flex;align-items:center;gap:3px}\n.lks-dock-due svg,.lks-dock-streak svg{flex:none}\n.lks-dock-due.lks-muted svg,.lks-dock-streak.lks-muted svg{opacity:.75}\n.lks-btn svg,.lks-viewtab svg,.lks-sechead svg{flex:none}\n.lks-viewtab svg,.lks-btn svg{align-self:center}\n\n/* ic_ds_* glyph carriers + busy spinner (native .8s linear spin) */\n@keyframes lks-spin{to{transform:rotate(360deg)}}\n.lks-spin{animation:lks-spin .8s linear infinite}\n\n/* dormant state: pills/starters stay visible but inert (aria-disabled, same\n contract as locked lesson rows — focusable so the hint explains why) */\n.lks-pill[aria-disabled='true'],.lks-starter[aria-disabled='true']{opacity:.45;cursor:not-allowed}\n.lks-pill[aria-disabled='true']:hover,.lks-starter[aria-disabled='true']:hover{background:transparent;border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary)}\n.lks-dormant{font-size:13px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);border:1px dashed var(--dsw-alias-border-l2);border-radius:10px;padding:10px 12px;margin:8px 0;line-height:1.7}\n\n/* starter chips */\n.lks-dock{display:flex;align-items:center;flex-wrap:wrap;gap:6px;padding:0 2px 6px;flex:none}\n.lks-starter{border:1px solid var(--dsw-alias-border-l2);border-radius:999px;padding:4px 12px;font-size:13px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);transition:border-color .12s ease,color .12s ease}\n.lks-starter:hover{border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-label-primary)}\n\n/* proposal banner + shared buttons */\n/* A mastery proposal is a positive, informational moment — business tint, not\n the warn tint it previously wore (a reviewer flagged the semantic mismatch). */\n.lks-banner{display:flex;align-items:center;gap:10px;background:var(--dsw-alias-state-business-tertiary);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;padding:10px 14px;margin:8px 0;font-size:14px;flex:none}\n.lks-banner .lks-why{flex:1;color:var(--dsw-alias-label-secondary)}\n.lks-btn{display:inline-flex;align-items:center;gap:6px;border-radius:8px;padding:6px 14px;font-size:13.5px;font-weight:600;flex:none}\n.lks-btn:focus-visible,.lks-starter:focus-visible,.lks-switch-btn:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary);outline:none}\n.lks-btn.primary{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 86%,#000);color:#fff}\n.lks-btn.primary:hover{filter:brightness(1.1)}\n.lks-btn.primary:disabled{opacity:.5;cursor:default;filter:none}\n.lks-btn.ghost{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary);border:1px solid var(--dsw-alias-border-l2)}\n.lks-btn.ghost:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l3)}\n\n/* ── right column: blackboard ── */\n.lks-lessonhead h2{font-size:18px;margin:0 0 4px;font-weight:700}\n.lks-lessonhead .lks-meta{color:var(--dsw-alias-label-secondary);font-size:13px;margin-bottom:4px}\n.lks-chips{display:flex;flex-wrap:wrap;gap:6px;margin:8px 0}\n.lks-chip{border-radius:999px;padding:2px 10px;font-size:12.5px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary)}\n.lks-chip.weak{background:var(--dsw-alias-state-warn-tertiary);color:var(--lks-warn-ink)}\n\n/* blackboard view tabs (same joined-capsule button language as the narrow\n mode switcher — buttons, not tabs, against the host's view tabs above) */\n.lks-viewtabs{display:flex;gap:2px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:999px;padding:3px;width:max-content;margin:10px 0}\n.lks-viewtab{border-radius:999px;padding:4px 16px;font-size:13.5px;color:var(--dsw-alias-label-secondary);background:transparent;transition:background .12s ease,color .12s ease}\n.lks-viewtab:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}\n.lks-viewtab.on{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 86%,#000);color:#fff;font-weight:600}\n.lks-viewtab:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary);outline:none}\n\n/* rendered markdown (host-sanitized lesson bodies and assistant replies) */\n.lks-prose{font-size:16px;line-height:1.75}\n.lks-prose h1,.lks-prose h2,.lks-prose h3,.lks-prose h4{margin:14px 0 6px;line-height:1.4}\n.lks-prose p{margin:6px 0}\n.lks-prose pre{background:var(--dsw-alias-markdown-code-block);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;padding:10px;overflow-x:auto;margin:8px 0;font-size:13.5px;font-family:var(--dsw-font-markdown-code-block-small)}\n.lks-prose code{font-family:var(--dsw-font-markdown-code);background:var(--dsw-alias-bg-layer-3);border-radius:4px;padding:1px 5px;font-size:.92em}\n.lks-prose pre code{background:none;padding:0}\n.lks-prose table{border-collapse:collapse;margin:8px 0;display:block;max-width:100%;overflow-x:auto}\n.lks-prose th,.lks-prose td{border:1px solid var(--dsw-alias-border-l2);padding:5px 11px;font-size:14px}\n.lks-prose th{background:var(--dsw-alias-bg-layer-2)}\n.lks-prose blockquote{border-left:3px solid var(--dsw-alias-state-business-primary);padding:2px 12px;color:var(--dsw-alias-label-secondary);margin:8px 0}\n.lks-prose ul,.lks-prose ol{padding-left:22px;margin:6px 0}\n.lks-prose img{max-width:100%}\n/* width guards for CDN-rendered artifacts (both teach and diagram panes are\n .lks-prose): mermaid/elk SVGs carry fixed width attributes; KaTeX\n display math can exceed the column; both must degrade to fit/scroll\n internally instead of stretching the blackboard. */\n.lks-prose svg{max-width:100%;height:auto}\n.lks-prose .katex-display{overflow-x:auto;overflow-y:hidden;padding:2px 0}\n\n/* Cornell notes zones */\n.lks-bb-notes{margin-top:14px;padding-top:10px;border-top:1px solid var(--dsw-alias-border-l1)}\n.lks-zone{margin-bottom:14px}\n.lks-zone-h{font-size:14px;color:var(--dsw-alias-label-secondary);margin:0 0 8px;font-weight:600}\n.lks-note{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;padding:10px 14px;margin-bottom:8px}\n.lks-note .lks-note-src{float:right;font-size:11.5px;color:var(--dsw-alias-label-secondary)}\n.lks-note .lks-note-title{font-weight:600;font-size:13px}\n.lks-note .lks-note-text{margin-top:4px;font-size:13px;color:var(--dsw-alias-label-secondary);line-height:1.65}\n.lks-note .lks-note-text p{margin:4px 0}\n.lks-note .lks-note-text table{border-collapse:collapse;margin:6px 0;display:block;max-width:100%;overflow-x:auto}\n.lks-note .lks-note-text th,.lks-note .lks-note-text td{border:1px solid var(--dsw-alias-border-l2);padding:4px 8px;font-size:12.5px}\n.lks-note .lks-note-text code{font-family:var(--dsw-font-markdown-code);background:var(--dsw-alias-bg-layer-3);border-radius:4px;padding:1px 4px;font-size:.95em}\n.lks-note .lks-note-q{margin-top:6px;color:var(--dsw-alias-label-tertiary);font-size:12px;border-left:2px solid var(--dsw-alias-state-warn-primary);padding-left:8px}\n\n/* inline error text (write-action failures) */\n.lks-propcard-err{color:var(--dsw-alias-state-error-primary);font-size:12px;margin-top:6px;flex:none}\n\n/* settings section (settings.section entry inside the host settings shell) */\n.lks-settings{display:flex;flex-direction:column;gap:18px;font-family:var(--dsw-font-family);color:var(--dsw-alias-label-primary)}\n.lks-set-row h3{margin:0 0 4px;font-size:15px;font-weight:600}\n.lks-set-hint{margin:0 0 10px;font-size:13px;color:var(--dsw-alias-label-secondary)}\n.lks-set-state{margin-left:10px;font-size:13px;color:var(--dsw-alias-label-secondary)}\n.lks-set-stats{margin:0;padding-left:18px;font-size:14px;line-height:1.9}\n.lks-set-path{font-family:var(--dsw-font-markdown-code);font-size:12.5px;background:var(--dsw-alias-bg-layer-3);border-radius:6px;padding:3px 8px;word-break:break-all}\n\n/* composer dock status pill (conversation.composer.dock entry) */\n.lks-dockpill{display:inline-flex;gap:10px;align-items:center;font-size:12px;color:var(--dsw-alias-label-secondary)}\n.lks-dockseg{white-space:nowrap}\n.lks-dock-due{color:var(--lks-warn-ink)}\n.lks-dock-streak{color:var(--dsw-alias-state-business-primary)}\n.lks-dockseg.lks-muted{color:var(--dsw-alias-label-secondary)}\n\n/* concept map legend (amber = weak) */\n.lks-cmap-legend{display:inline-flex;align-items:center;gap:5px;font-size:12px;color:var(--dsw-alias-label-secondary);margin-top:4px}\n.lks-cmap-legend i{width:10px;height:10px;border-radius:3px;background:var(--dsw-alias-state-warn-tertiary,#fef5e7);border:1px solid var(--dsw-alias-state-warn-primary,#dd8629)}\n\n/* keyed tool.call.toolview cards (conversation tab tool rows) */\n.lks-tv{display:flex;flex-direction:column;gap:4px;padding:6px 10px;border-radius:10px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);font-size:13px}\n.lks-tv.err{border-color:var(--dsw-alias-state-error-primary)}\n.lks-tv-head{font-weight:600;color:var(--dsw-alias-label-secondary);font-size:12px}\n.lks-tv-chip{align-self:flex-start;border-radius:999px;padding:2px 10px;font-size:12.5px;font-weight:600}\n.lks-tv-chip.ok{background:var(--dsw-alias-state-success-tertiary);color:var(--lks-ok-ink)}\n.lks-tv-chip.bad{background:var(--dsw-alias-state-error-tertiary);color:var(--lks-err-ink)}\n.lks-tv-line{color:var(--dsw-alias-label-secondary);line-height:1.6;white-space:pre-wrap}\n/* exam star card + the failure moment */\n.lks-tv-stars{display:inline-flex;align-items:center;gap:5px;font-size:13px;font-weight:600;color:var(--lks-warn-ink)}\n.lks-tv-stars .dim{opacity:.22}\n.lks-tv-stars-label{font-weight:400;color:var(--dsw-alias-label-secondary)}\n.lks-tv-failnote{margin-top:4px;font-size:12.5px;color:var(--dsw-alias-label-secondary);line-height:1.6}\n`\n\n/**\n * Inject the study stylesheet into `document.head` (idempotent).\n * @returns the stylesheet element (existing one when already injected).\n */\nexport function ensureStudyStyles(): HTMLStyleElement {\n const existing = document.head.querySelector(`style[${STYLE_ID}]`)\n if (existing !== null) return existing\n const style = document.createElement('style')\n style.setAttribute(STYLE_ID, '')\n style.textContent = STUDY_CSS\n document.head.appendChild(style)\n return style\n}\n","/**\n * ic_ds_* glyphs vendored from @deepseek-ai/dsh-client-ui-primitives\n * (src/icons/index.tsx, same figma source as the host's icon set) so the\n * plugin's client bundle stays self-contained per the dsh client-bundle\n * contract — only react is runtime-external; importing the host package\n * root would drag its CSS modules into the inlined bundle. Re-sync these\n * three paths if the host icon set redesigns them; scripts/verify.mjs\n * pins the path data.\n *\n * 2026-09-01 critique round: seven more ic_ds glyphs vendored (play/plus/\n * trash/refresh/globe/goal/warning) plus plugin-original learning-domain\n * companions (lock/star/book/crown/bolt/power/pin/flame) drawn in the same\n * language — those are NOT ic_ds, see their section comment below.\n * @module dsh-plugin-lookatstudy/client/icons\n */\n\nimport { createElement } from 'react'\n\n/** Shared props for every vendored glyph (mirrors the host's IconProps). */\ninterface IconProps {\n /** Square edge in px; defaults to the glyph's own drawn size. */\n size?: number\n /** Extra class for layout placement; color rides currentColor. */\n className?: string\n}\n\n/** ic_ds_think_outline_16 */\nexport function IconThinkOutline16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', {\n d: 'M8.00192 6.64454C8.75026 6.64454 9.35732 7.25169 9.35739 8.00001C9.35739 8.74838 8.7503 9.35548 8.00192 9.35548C7.25367 9.35533 6.64743 8.74829 6.64743 8.00001C6.6475 7.25178 7.25371 6.64468 8.00192 6.64454Z',\n fill: 'currentColor',\n }),\n createElement('path', {\n 'fill-rule': 'evenodd',\n 'clip-rule': 'evenodd',\n d: 'M9.97165 1.29981C11.5853 0.718916 13.271 0.642197 14.3144 1.68555C15.3577 2.72902 15.2811 4.41466 14.7002 6.02833C14.4707 6.66561 14.1504 7.32937 13.75 8.00001C14.1504 8.67062 14.4707 9.33444 14.7002 9.97169C15.2811 11.5854 15.3578 13.271 14.3144 14.3145C13.271 15.3579 11.5854 15.2811 9.97165 14.7002C9.3344 14.4708 8.67059 14.1505 7.99997 13.75C7.32933 14.1505 6.66558 14.4708 6.02829 14.7002C4.41461 15.2811 2.72899 15.3578 1.68552 14.3145C0.642155 13.271 0.71887 11.5854 1.29977 9.97169C1.52915 9.33454 1.84865 8.67049 2.24899 8.00001C1.84866 7.32953 1.52915 6.66544 1.29977 6.02833C0.718852 4.41459 0.64207 2.729 1.68552 1.68555C2.72897 0.642112 4.41456 0.718887 6.02829 1.29981C6.66541 1.52918 7.32949 1.8487 7.99997 2.24903C8.67045 1.84869 9.33451 1.52919 9.97165 1.29981ZM12.9404 9.2129C12.4391 9.893 11.8616 10.5681 11.2148 11.2149C10.568 11.8616 9.89296 12.4391 9.21286 12.9404C9.62532 13.1579 10.0271 13.338 10.4121 13.4766C11.9146 14.0174 12.9172 13.8738 13.3955 13.3955C13.8737 12.9173 14.0174 11.9146 13.4765 10.4121C13.3379 10.0271 13.1578 9.62535 12.9404 9.2129ZM3.05856 9.2129C2.84121 9.62523 2.66197 10.0272 2.52341 10.4121C1.98252 11.9146 2.12627 12.9172 2.60446 13.3955C3.08278 13.8737 4.08544 14.0174 5.58786 13.4766C5.97264 13.338 6.37389 13.1577 6.7861 12.9404C6.10624 12.4393 5.43168 11.8614 4.78513 11.2149C4.13823 10.5679 3.55992 9.89313 3.05856 9.2129ZM7.99899 3.792C7.23179 4.31419 6.45306 4.95512 5.70407 5.70411C4.95509 6.45309 4.31415 7.23184 3.79196 7.99903C4.3143 8.76666 4.95471 9.54653 5.70407 10.2959C6.45309 11.0449 7.23271 11.6848 7.99997 12.207C8.76725 11.6848 9.54683 11.0449 10.2959 10.2959C11.0449 9.54686 11.6848 8.76729 12.207 8.00001C11.6848 7.23275 11.0449 6.45312 10.2959 5.70411C9.5465 4.95475 8.76662 4.31434 7.99899 3.792ZM5.58786 2.52344C4.08533 1.98255 3.08272 2.12625 2.60446 2.6045C2.12621 3.08275 1.98252 4.08536 2.52341 5.5879C2.66189 5.97253 2.8414 6.37409 3.05856 6.78614C3.55983 6.10611 4.1384 5.43189 4.78513 4.78516C5.43186 4.13843 6.10606 3.55987 6.7861 3.0586C6.37405 2.84144 5.97249 2.66192 5.58786 2.52344ZM13.3955 2.6045C12.9172 2.12631 11.9146 1.98257 10.4121 2.52344C10.0272 2.66201 9.62519 2.84125 9.21286 3.0586C9.8931 3.55996 10.5679 4.13827 11.2148 4.78516C11.8614 5.43172 12.4392 6.10627 12.9404 6.78614C13.1577 6.37393 13.338 5.97267 13.4765 5.5879C14.0174 4.08549 13.8736 3.08281 13.3955 2.6045Z',\n fill: 'currentColor',\n }))\n}\n\n/** ic_ds_loading_outline_16 */\nexport function IconLoadingOutline16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', {\n d: 'M2.871 13.1286C0.0387669 10.2962 0.0387669 5.70383 2.871 2.87141C5.70341 0.0390029 10.2957 0.0391154 13.1282 2.87141L12.1387 3.86094C9.85292 1.57538 6.1469 1.57596 3.86123 3.86163C1.57573 6.14732 1.57573 9.85269 3.86123 12.1384C6.1469 14.424 9.85292 14.4246 12.1387 12.1391L13.1282 13.1286C10.2957 15.9609 5.70341 15.961 2.871 13.1286Z',\n fill: 'currentColor',\n }))\n}\n\n/** ic_ds_download_outline_16 */\nexport function IconDownloadOutline16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', {\n d: 'M15.3695 11.411L15.1234 12.8866C14.8869 14.3042 13.6603 15.3436 12.223 15.3436H3.77673C2.33958 15.3434 1.1128 14.3042 0.876343 12.8866L0.630249 11.411L2.05408 11.1747L2.29919 12.6493C2.41973 13.3713 3.04475 13.9001 3.77673 13.9003H12.223C12.9551 13.9002 13.58 13.3713 13.7006 12.6493L13.9457 11.1747L15.3695 11.411ZM8.72205 8.994C8.77717 8.93934 8.83792 8.88106 8.90271 8.81627L12.4828 5.23424L13.5043 6.25572L9.92224 9.8358C9.6395 10.1185 9.38763 10.3732 9.15857 10.5575C8.91892 10.7503 8.63953 10.9224 8.2865 10.9784C8.09711 11.0083 7.90363 11.0083 7.71423 10.9784C7.36106 10.9224 7.0809 10.7503 6.84119 10.5575C6.61215 10.3732 6.36022 10.1185 6.07751 9.8358L2.49646 6.25572L3.51697 5.23424L7.09705 8.81627C7.16219 8.88142 7.22331 8.94006 7.27869 8.99498V1.3065H8.72205V8.994Z',\n fill: 'currentColor',\n }))\n}\n\n/** Vendored 2026-09-01 for the critique icon round (same figma source as the three above). */\n/** IconPlayOutline16 */\nexport function IconPlayOutline16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M14.1446 8C14.1446 4.6062 11.3938 1.85539 8 1.85539C4.6062 1.85539 1.85539 4.6062 1.85539 8C1.85539 11.3938 4.6062 14.1446 8 14.1446C11.3938 14.1446 14.1446 11.3938 14.1446 8ZM15.511 8C15.511 12.148 12.148 15.511 8 15.511C3.85202 15.511 0.489014 12.148 0.489014 8C0.489014 3.85202 3.85202 0.489014 8 0.489014C12.148 0.489014 15.511 3.85202 15.511 8Z', fill: 'currentColor' }),\n createElement('path', { d: 'M10.5617 8.42578C10.852 8.21614 10.852 7.78386 10.5617 7.57422L7.25708 5.18751C6.90974 4.93666 6.42436 5.18484 6.42436 5.61329V10.3867C6.42436 10.8152 6.90974 11.0633 7.25708 10.8125L10.5617 8.42578Z', fill: 'currentColor' }))\n}\n\n/** IconPlusOutline16 */\nexport function IconPlusOutline16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M8.64453 1.5V7.34961H14.5V8.65039H8.64453V14.5H7.34473V8.65039H1.5V7.34961H7.34473V1.5H8.64453Z', fill: 'currentColor' }))\n}\n\n/** IconTrashOutline16 */\nexport function IconTrashOutline16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M14.4782 4.84067L14.2138 10.1152C14.1102 12.1872 14.067 13.0115 13.3866 13.9607C13.1044 14.3546 12.7498 14.6912 12.3424 14.9535C11.8239 15.2872 11.2415 15.4316 10.5585 15.4998C9.88727 15.5668 9.04946 15.5656 7.99998 15.5656C6.95051 15.5656 6.1127 15.5668 5.44142 15.4998C4.75851 15.4316 4.17602 15.2872 3.65753 14.9535C3.25012 14.6912 2.89559 14.3546 2.61332 13.9607C1.93296 13.0115 1.88979 12.1872 1.78619 10.1152L1.52179 4.84067L2.89006 4.77277L3.15343 10.0463C3.26221 12.2218 3.32452 12.6015 3.72646 13.1624C3.90825 13.4161 4.13686 13.6334 4.39927 13.8023C4.66204 13.9714 5.00263 14.0792 5.57825 14.1367C6.16562 14.1953 6.92298 14.1963 7.99998 14.1963C9.07699 14.1963 9.83434 14.1953 10.4217 14.1367C10.9973 14.0792 11.3379 13.9714 11.6007 13.8023C11.8631 13.6334 12.0917 13.4161 12.2735 13.1624C12.6755 12.6015 12.7378 12.2218 12.8465 10.0463L13.1099 4.77277L14.4782 4.84067ZM5.43011 6.22849H6.7994V11.3909H5.43011V6.22849ZM9.20056 6.22849H10.5699V11.3909H9.20056V6.22849ZM8.53597 0.434431C9.17976 0.434431 9.6522 0.426926 10.0966 0.571258C10.2357 0.616451 10.3717 0.672554 10.502 0.738948C10.9182 0.951107 11.2464 1.29099 11.7015 1.74612L12.4978 2.54136H15.3742V3.91169H0.625732V2.54136H3.50218L4.29845 1.74612C4.75358 1.29099 5.08174 0.951107 5.49801 0.738948C5.62831 0.672554 5.76425 0.616451 5.90334 0.571258C6.34776 0.426926 6.82021 0.434431 7.46399 0.434431H8.53597ZM7.46399 1.80476C6.73208 1.80476 6.51641 1.81187 6.32617 1.87369C6.25545 1.89667 6.18668 1.92533 6.12041 1.95907C5.96398 2.03878 5.82348 2.16253 5.44142 2.54136H10.5585C10.1765 2.16253 10.036 2.03878 9.87955 1.95907C9.81329 1.92533 9.74452 1.89667 9.6738 1.87369C9.48356 1.81187 9.26789 1.80476 8.53597 1.80476H7.46399Z', fill: 'currentColor' }))\n}\n\n/** IconRefreshOutline16 */\nexport function IconRefreshOutline16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M7.92136 0.349152C10.3744 0.349234 12.5564 1.5052 13.9557 3.29894L15.1281 2.12759C15.3303 1.92546 15.6767 2.06943 15.6767 2.35538V5.53923C15.6766 5.71626 15.5329 5.85976 15.3559 5.86002H12.171C11.8854 5.8597 11.7426 5.51465 11.9443 5.31249L12.9641 4.29056C11.8237 2.74305 9.98908 1.74106 7.92136 1.74097C4.46436 1.74097 1.66233 4.543 1.66233 8C1.66233 11.457 4.46436 14.259 7.92136 14.259C11.3782 14.2589 14.1804 11.4569 14.1804 8H15.5722C15.5722 12.2251 12.1465 15.6507 7.92136 15.6508C3.69614 15.6508 0.270508 12.2252 0.270508 8C0.270508 3.77478 3.69614 0.349152 7.92136 0.349152Z', fill: 'currentColor' }))\n}\n\n/** IconGlobeOutline14 */\nexport function IconGlobeOutline14({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M7.00018 0.353516C10.6708 0.353535 13.6468 3.32958 13.6469 7.00018C13.6468 10.6708 10.6708 13.6468 7.00018 13.6469C3.32957 13.6468 0.353535 10.6708 0.353516 7.00018C0.353535 3.32957 3.32957 0.353531 7.00018 0.353516ZM5.44643 7.59661C5.49463 8.97506 5.70762 10.191 6.02136 11.0793C6.20141 11.5891 6.40328 11.9585 6.59898 12.1889C6.79501 12.4196 6.93213 12.454 7.00018 12.454C7.06822 12.454 7.20533 12.4197 7.40138 12.1889C7.59708 11.9585 7.79895 11.589 7.979 11.0793C8.29274 10.191 8.50574 8.97506 8.55394 7.59661H5.44643ZM1.57861 7.59661C1.80785 9.70467 3.2386 11.4509 5.1715 12.1388C5.07135 11.9317 4.97972 11.7098 4.89746 11.477C4.53084 10.4391 4.30224 9.0828 4.25357 7.59661H1.57861ZM9.74679 7.59661C9.69813 9.0828 9.46952 10.4391 9.1029 11.477C9.0206 11.7099 8.92818 11.9316 8.82797 12.1388C10.7613 11.4511 12.1925 9.70496 12.4218 7.59661H9.74679ZM5.1706 1.8616C3.23814 2.54963 1.80876 4.29604 1.5795 6.40376H4.25357C4.30224 4.91756 4.53083 3.56129 4.89746 2.5234C4.97968 2.29066 5.07051 2.0686 5.1706 1.8616ZM7.00018 1.54637C6.93213 1.54638 6.79503 1.5807 6.59898 1.81145C6.40332 2.04177 6.20139 2.41058 6.02136 2.92012C5.70754 3.80851 5.49461 5.02499 5.44643 6.40376H8.55394C8.50575 5.025 8.29282 3.80851 7.979 2.92012C7.79898 2.41059 7.59705 2.04177 7.40138 1.81145C7.20531 1.58067 7.06823 1.54637 7.00018 1.54637ZM8.82887 1.8616C8.92902 2.0687 9.02064 2.29053 9.1029 2.5234C9.46953 3.56129 9.69812 4.91756 9.74679 6.40376H12.4209C12.1916 4.29575 10.7618 2.54943 8.82887 1.8616Z', fill: 'currentColor' }))\n}\n\n/** IconGoalOutline16 */\nexport function IconGoalOutline16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M8 0C8.31451 0 8.62464 0.019379 8.92969 0.0546875C8.48228 0.403371 8.0952 0.825758 7.78809 1.30469C4.18586 1.41664 1.2998 4.37061 1.2998 8C1.2998 11.7003 4.29969 14.7002 8 14.7002C11.6297 14.7002 14.5829 11.8136 14.6943 8.21094C15.1734 7.90377 15.5956 7.51688 15.9443 7.06934C15.9797 7.37473 16 7.68512 16 8C16 12.4183 12.4183 16 8 16C3.58172 16 0 12.4183 0 8C0 3.58172 3.58172 0 8 0ZM7.0166 3.6084C7.00658 3.73765 7 3.86817 7 4C7 4.31845 7.03098 4.62973 7.08789 4.93164C5.76489 5.32438 4.7998 6.54958 4.7998 8C4.7998 9.76731 6.23269 11.2002 8 11.2002C9.45065 11.2002 10.6749 10.2345 11.0674 8.91113C11.3696 8.96818 11.6812 9 12 9C12.1315 9 12.2617 8.99239 12.3906 8.98242C11.9423 10.995 10.1477 12.5 8 12.5C5.51472 12.5 3.5 10.4853 3.5 8C3.5 5.85255 5.00435 4.05702 7.0166 3.6084Z', fill: 'currentColor' }),\n createElement('path', { d: 'M7.5 8.62109L9.12109 7', fill: 'currentColor' }),\n createElement('path', { d: 'M9.08245 3.35798L11.8651 0.575334C11.895 0.545384 11.9463 0.56391 11.9502 0.606086L12.2362 3.69859C12.2384 3.72259 12.2574 3.74159 12.2814 3.74378L15.3697 4.02583C15.4119 4.02968 15.4305 4.08101 15.4005 4.11098L12.618 6.89351C12.6086 6.90289 12.5959 6.90816 12.5826 6.90816L9.11781 6.90815C9.09019 6.90816 9.06781 6.88577 9.06781 6.85816L9.06781 3.39333C9.06781 3.38007 9.07308 3.36735 9.08245 3.35798Z', fill: 'currentColor' }))\n}\n\n/** IconWarningOutline16 */\nexport function IconWarningOutline16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M6.3002 3.32843L7.69986 3.32843L7.69986 7.79657H6.3002L6.3002 3.32843Z', fill: 'currentColor' }),\n createElement('path', { d: 'M6.3002 9.01935H7.69986V10.6711H6.3002V9.01935Z', fill: 'currentColor' }),\n createElement('path', { d: 'M12.6328 6.99976C12.6328 3.88874 10.111 1.36694 7 1.36694C3.88899 1.36695 1.3672 3.88875 1.36719 6.99976C1.36719 10.1108 3.88899 12.6326 7 12.6326C10.111 12.6326 12.6328 10.1108 12.6328 6.99976ZM13.8582 6.99976C13.8582 10.7873 10.7876 13.8579 7 13.8579C3.21244 13.8579 0.141846 10.7873 0.141846 6.99976C0.141857 3.2122 3.21245 0.141612 7 0.141602C10.7876 0.141602 13.8581 3.21219 13.8582 6.99976Z', fill: 'currentColor' }))\n}\n\n\n/**\n * Plugin-original companions for learning-domain glyphs the host set does not\n * carry (lock/star/book/crown/bolt/power/pin/flame) — authored here in the\n * same 16px currentColor filled language as the ic_ds set, but they are NOT\n * ic_ds glyphs and must be re-drawn (not re-synced) if the style drifts.\n */\n/** IconLockFill16 */\nexport function IconLockFill16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { 'fill-rule': 'evenodd', 'clip-rule': 'evenodd', d: 'M5 6.5V5a3 3 0 0 1 6 0v1.5h.6c.77 0 1.4.63 1.4 1.4v5.7c0 .77-.63 1.4-1.4 1.4H4.4A1.4 1.4 0 0 1 3 13.6V7.9c0-.77.63-1.4 1.4-1.4H5Zm1.444 0h3.112V5a1.556 1.556 0 0 0-3.112 0v1.5Z', fill: 'currentColor' }))\n}\n\n/** IconStarFill16 */\nexport function IconStarFill16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M8 1.6l1.86 3.77 4.16.6-3.01 2.94.71 4.14L8 11.42l-3.72 1.96.71-4.15-3.01-2.93 4.16-.6L8 1.6Z', fill: 'currentColor' }))\n}\n\n/** IconBookFill16 */\nexport function IconBookFill16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { 'fill-rule': 'evenodd', 'clip-rule': 'evenodd', d: 'M8 3.1C6.6 2.15 4.65 1.75 2.5 1.75c-.5 0-1 .03-1.5.1v10.7c.5-.07 1-.1 1.5-.1 2.15 0 4.1.4 5.5 1.35 1.4-.95 3.35-1.35 5.5-1.35.5 0 1 .03 1.5.1V1.85c-.5-.07-1-.1-1.5-.1-2.15 0-4.1.4-5.5 1.35ZM7.2 4.9v7.3C5.9 11.55 4.3 11.3 2.6 11.3V3.45c1.7 0 3.3.25 4.6 1.45Zm1.6 0c1.3-1.2 2.9-1.45 4.6-1.45v7.85c-1.7 0-3.3.25-4.6.9V4.9Z', fill: 'currentColor' }))\n}\n\n/** IconCrownFill16 */\nexport function IconCrownFill16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M1.7 11.2 1 4.9l3.6 2.2L8 2.6l3.4 4.5L15 4.9l-.7 6.3H1.7Zm.5 1.4h11.6v1.5H2.1v-1.5Z', fill: 'currentColor' }))\n}\n\n/** IconBoltFill16 */\nexport function IconBoltFill16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M9.6 1 3.4 9.3h3.4L6.3 15l6.3-8.5H9.2L9.6 1Z', fill: 'currentColor' }))\n}\n\n/** IconPowerFill16 */\nexport function IconPowerFill16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M7.2 1h1.6v5.6H7.2V1Z', fill: 'currentColor' }),\n createElement('path', { 'fill-rule': 'evenodd', 'clip-rule': 'evenodd', d: 'M4.55 3.15A6 6 0 1 0 11.45 3.15L12.5 4.2a7.5 7.5 0 1 1-9 0l1.05-1.05Z', fill: 'currentColor' }))\n}\n\n/** IconPinFill16 */\nexport function IconPinFill16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { 'fill-rule': 'evenodd', 'clip-rule': 'evenodd', d: 'M8 1.4a4.8 4.8 0 0 1 4.8 4.8c0 3.4-4.8 8.4-4.8 8.4S3.2 9.6 3.2 6.2A4.8 4.8 0 0 1 8 1.4Zm0 2.7a2.1 2.1 0 1 0 0 4.2 2.1 2.1 0 0 0 0-4.2Z', fill: 'currentColor' }))\n}\n\n/** IconFlameFill16 */\nexport function IconFlameFill16({ size = 16, className }: IconProps) {\n return createElement('svg', {\n width: size, height: size, className, viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', { d: 'M8.9 1.2c.4 2.5-.9 3.9-2.1 5.2C5.6 7.7 4.4 9 4.4 10.9a3.9 3.9 0 0 0 7.8 0c0-1.6-.7-2.9-1.5-4-.3.8-.8 1.4-1.6 1.7.5-2.4-.2-5.4-1.2-7.4Z', fill: 'currentColor' }))\n}\n\n","/**\n * Shared client-side study store: one module-level poller over the host\n * plugin's `/lookatstudy/api/state` endpoint, plus the three write actions\n * (focus, mode, reverse message). Every seat component binds through\n * {@link useStudy}; subscribers share the single 3 s poll cycle and the last\n * snapshot, so mounting more controls costs no extra requests.\n * @module dsh-plugin-lookatstudy/client/data\n */\n\nimport { useSyncExternalStore } from 'react'\n\n/** Wire shape of `GET /lookatstudy/api/state` (structural mirror of the host's WorkbenchState). */\nexport interface StudyState {\n readonly active: boolean\n readonly mode: 'direct' | 'guide' | 'practice'\n readonly courses: ReadonlyArray<{\n readonly courseId: string\n readonly title: string\n readonly mastered: number\n readonly total: number\n readonly avgMasteryPct: number | null\n readonly sections: ReadonlyArray<{\n readonly title: string\n readonly index: number\n readonly lessons: ReadonlyArray<{\n readonly id: string\n readonly title: string\n readonly kind: 'study' | 'practice' | 'exam'\n readonly status: string\n readonly masteryPct: number | null\n readonly weakConcepts: number\n readonly frictionCount: number\n readonly due: boolean\n readonly focus: boolean\n }>\n }>\n }>\n readonly focusLessonId: string | null\n readonly lesson: {\n readonly lessonId: string\n readonly courseTitle: string\n readonly sectionTitle: string\n readonly title: string\n readonly status: string\n readonly masteryPct: number | null\n readonly strategy: string\n readonly concepts: ReadonlyArray<{ title: string; masteryPct: number; weak: boolean }>\n readonly starters: ReadonlyArray<{ label: string; message: string }>\n readonly notes: ReadonlyArray<{ id: string; zone: string; title: string; text: string; source: string; quote: string | null }>\n readonly html: string\n readonly markdown: string\n } | null\n readonly dueCount: number\n readonly due: ReadonlyArray<{ lessonId: string; lessonTitle: string; courseTitle: string; overdueDays: number }>\n readonly pendingProposals: ReadonlyArray<{ id: string; lessonTitle: string; rationale: string }>\n readonly memory: { global: string | null; lesson: string | null; pattern: string | null }\n readonly lessonSessions: Readonly<Record<string, string>>\n /** XP + streak block (mirrors study_courses; feeds the dock pill and the settings page). */\n readonly progress: {\n readonly totalXp: number\n readonly level: number\n readonly levelPct: number\n readonly todayXp: number\n readonly dailyGoal: number\n readonly streak: number\n readonly longestStreak: number\n readonly freezeCount: number\n }\n /** Absolute state-file path (read-only display). */\n readonly statePath: string\n /** Plugin version from the running build's package.json (settings About row). */\n readonly version: string\n}\n\n/** Poll cadence for the shared store; one cycle serves every mounted seat. */\nconst POLL_MS = 3_000\n\ntype Listener = () => void\n\nasync function fetchJson(url: string, init?: RequestInit): Promise<unknown> {\n const res = await fetch(url, init)\n const body: unknown = await res.json().catch(() => null)\n if (!res.ok) {\n const error = body !== null && typeof body === 'object' && 'error' in body && typeof body.error === 'string'\n ? body.error\n : `HTTP ${res.status}`\n throw new Error(error)\n }\n return body\n}\n\nclass StudyStore {\n private snapshot: StudyState | null = null\n private readonly listeners = new Set<Listener>()\n private timer: ReturnType<typeof setInterval> | undefined\n private inflight = false\n\n subscribe = (listener: Listener): (() => void) => {\n this.listeners.add(listener)\n if (this.listeners.size === 1) {\n void this.tick()\n this.timer = setInterval(() => { void this.tick() }, POLL_MS)\n }\n return () => {\n this.listeners.delete(listener)\n if (this.listeners.size === 0 && this.timer !== undefined) {\n clearInterval(this.timer)\n this.timer = undefined\n }\n }\n }\n\n getSnapshot = (): StudyState | null => this.snapshot\n\n private emit(): void {\n for (const listener of this.listeners) listener()\n }\n\n private async tick(): Promise<void> {\n if (this.inflight) return\n this.inflight = true\n try {\n const next = await fetchJson('/lookatstudy/api/state') as StudyState\n this.snapshot = next\n this.emit()\n } catch {\n // Host route absent (headless composition) or transient failure: keep\n // the last snapshot; seats render their loading/empty states.\n } finally {\n this.inflight = false\n }\n }\n\n /** One immediate re-read (after a write action). */\n refresh(): void {\n void this.tick()\n }\n\n /** Switch the tutor's soul mode directly (host persists and applies it on the next request). */\n async setMode(mode: StudyState['mode']): Promise<void> {\n await fetchJson('/lookatstudy/api/mode', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ mode }),\n })\n this.refresh()\n }\n\n /**\n * Flip learning mode. The host syncs its tool registry before responding,\n * so awaiting this guarantees the `study_*` tools exist for the next prompt.\n */\n async activate(active: boolean): Promise<void> {\n await fetchJson('/lookatstudy/api/active', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ active }),\n })\n this.refresh()\n }\n\n /** Full-text lesson search (rail fallback when local title matching misses). */\n async searchLessons(query: string): Promise<Array<{ lessonId: string; lessonTitle: string; snippet: string }>> {\n const body = await fetchJson(`/lookatstudy/api/search?q=${encodeURIComponent(query)}`) as { matches?: Array<{ lessonId: string; lessonTitle: string; snippet: string }> }\n return body.matches ?? []\n }\n\n /** Point the tutor's focus at one lesson. */\n async setFocus(lessonId: string): Promise<void> {\n await fetchJson('/lookatstudy/api/focus', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ lessonId }),\n })\n this.refresh()\n }\n\n /** Record the dsh session backing one lesson (the simplified thread system). */\n async bindLessonSession(lessonId: string, sessionId: string): Promise<void> {\n await fetchJson('/lookatstudy/api/lesson-session', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ lessonId, sessionId }),\n })\n this.refresh()\n }\n\n /** Delete one course (and its proposals) from the host state. */\n async deleteCourse(courseId: string): Promise<void> {\n await fetchJson('/lookatstudy/api/course/delete', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ courseId }),\n })\n this.refresh()\n }\n}\n\n/** The one shared store instance backing every study seat component. */\nexport const studyStore = new StudyStore()\n\n/** React binding: live snapshot plus the write actions. */\nexport function useStudy(): {\n data: StudyState | null\n activate: (active: boolean) => Promise<void>\n setMode: (mode: StudyState['mode']) => Promise<void>\n setFocus: (lessonId: string) => Promise<void>\n searchLessons: (query: string) => Promise<Array<{ lessonId: string; lessonTitle: string; snippet: string }>>\n deleteCourse: (courseId: string) => Promise<void>\n bindLessonSession: (lessonId: string, sessionId: string) => Promise<void>\n} {\n const data = useSyncExternalStore(studyStore.subscribe, studyStore.getSnapshot, studyStore.getSnapshot)\n return {\n data,\n activate: studyStore.activate.bind(studyStore),\n setMode: studyStore.setMode.bind(studyStore),\n setFocus: studyStore.setFocus.bind(studyStore),\n searchLessons: studyStore.searchLessons.bind(studyStore),\n deleteCourse: studyStore.deleteCourse.bind(studyStore),\n bindLessonSession: studyStore.bindLessonSession.bind(studyStore),\n }\n}\n","/**\n * Server-side markdown → HTML for the study workbench's 讲解 view. Escapes\n * every HTML character first, then renders a pragmatic GFM subset (headings,\n * fenced code, inline code, bold/italic, links, lists, blockquotes, tables,\n * hr, paragraphs). Lesson bodies are imported teaching material, so raw HTML\n * never passes through.\n * @module dsh-plugin-lookatstudy/markdown\n */\n\n/** Escape all HTML-significant characters. */\nfunction escapeHtml(text: string): string {\n return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;')\n}\n\n/** Render inline markup (code, bold, italic, links, images) over escaped text.\n * Image src allowlist: https?:// or data:image/ — folder imports inline local\n * images as data URLs (capped), GitHub imports reference jsDelivr; anything\n * else stays literal text (no broken relative images, no exotic schemes). */\nfunction inline(escaped: string): string {\n return escaped\n .replace(/`([^`]+)`/g, '<code>$1</code>')\n .replace(/\\*\\*([^*]+)\\*\\*/g, '<strong>$1</strong>')\n .replace(/\\*([^*]+)\\*/g, '<em>$1</em>')\n .replace(/!\\[([^\\]]*)\\]\\((https?:\\/\\/[^)\\s]+|data:image\\/[^)\\s]+)\\)/g, (_m, alt: string, src: string) => `<img src=\"${src}\" alt=\"${alt}\" loading=\"lazy\">`)\n .replace(/\\[([^\\]]+)\\]\\((https?:\\/\\/[^)\\s]+)\\)/g, '<a href=\"$2\" target=\"_blank\" rel=\"noreferrer\">$1</a>')\n}\n\n/** Interleave one body with its translation, paragraph by paragraph (upstream\n * translation-layout \"microsoft\" semantics: original paragraph then its\n * translation as a quote, tight pairing for bilingual reading; length\n * mismatches append the remainder in order). Pure. */\nexport function renderBilingual(bodyMd: string, translationMd: string): string {\n const par = (md: string): string[] => md.split(/\\n\\s*\\n/).map(p => p.trim()).filter(p => p !== '')\n const a = par(bodyMd)\n const b = par(translationMd)\n const out: string[] = []\n for (let i = 0; i < Math.max(a.length, b.length); i++) {\n if (a[i] !== undefined) out.push(a[i]!)\n if (b[i] !== undefined) out.push(`> ${b[i]!.split('\\n').join('\\n> ')}`)\n }\n return out.join('\\n\\n')\n}\n\n/** True when the line opens a GFM table row (pipes with a delimiter row next). */\nfunction isTableRow(line: string): boolean {\n return line.trim().startsWith('|') && line.trim().endsWith('|') && line.includes('|', 1)\n}\n\nfunction isDelimiterRow(line: string): boolean {\n const trimmed = line.trim()\n if (!trimmed.startsWith('|') || !trimmed.endsWith('|')) return false\n const cells = trimmed.replace(/^\\|/, '').replace(/\\|$/, '').split('|').map(c => c.trim())\n return cells.length > 0 && cells.every(c => /^:?-+:?$/.test(c))\n}\n\n/** Split a table row into trimmed cells (leading/trailing pipes removed). */\nfunction rowCells(line: string): string[] {\n return line.trim().replace(/^\\|/, '').replace(/\\|$/, '').split('|').map(c => c.trim())\n}\n\n/**\n * Render markdown text to sanitized HTML.\n * @param md - markdown source (lesson body).\n * @returns HTML string safe to inject into the page.\n */\nexport function renderMarkdown(md: string): string {\n const lines = escapeHtml(md).split(/\\r?\\n/)\n const out: string[] = []\n let i = 0\n\n const flushParagraph = (buffer: string[]): void => {\n if (buffer.length > 0) out.push(`<p>${inline(buffer.join(' '))}</p>`)\n }\n\n let paragraph: string[] = []\n while (i < lines.length) {\n const line = lines[i]!\n\n // Fenced code block\n const fence = /^```(\\w*)\\s*$/.exec(line.trim())\n if (fence) {\n flushParagraph(paragraph)\n paragraph = []\n const lang = fence[1] ?? ''\n const code: string[] = []\n i++\n while (i < lines.length && lines[i]!.trim() !== '```') {\n code.push(lines[i]!)\n i++\n }\n i++ // closing fence\n out.push(`<pre><code${lang === '' ? '' : ` class=\"lang-${lang}\"`}>${code.join('\\n')}</code></pre>`)\n continue\n }\n\n // Heading\n const heading = /^(#{1,6})\\s+(.*)$/.exec(line)\n if (heading) {\n flushParagraph(paragraph)\n paragraph = []\n const level = heading[1]!.length\n out.push(`<h${level}>${inline(heading[2]!)}</h${level}>`)\n i++\n continue\n }\n\n // Horizontal rule\n if (/^\\s*(-{3,}|\\*{3,}|_{3,})\\s*$/.test(line)) {\n flushParagraph(paragraph)\n paragraph = []\n out.push('<hr>')\n i++\n continue\n }\n\n // Blockquote\n if (/^\\s*&gt;\\s?/.test(line)) {\n flushParagraph(paragraph)\n paragraph = []\n const quote: string[] = []\n while (i < lines.length && /^\\s*&gt;\\s?/.test(lines[i]!)) {\n quote.push(lines[i]!.replace(/^\\s*&gt;\\s?/, ''))\n i++\n }\n out.push(`<blockquote><p>${inline(quote.join(' '))}</p></blockquote>`)\n continue\n }\n\n // Unordered list\n if (/^\\s*[-*+]\\s+/.test(line)) {\n flushParagraph(paragraph)\n paragraph = []\n const items: string[] = []\n while (i < lines.length && /^\\s*[-*+]\\s+/.test(lines[i]!)) {\n items.push(`<li>${inline(lines[i]!.replace(/^\\s*[-*+]\\s+/, ''))}</li>`)\n i++\n }\n out.push(`<ul>${items.join('')}</ul>`)\n continue\n }\n\n // Ordered list\n if (/^\\s*\\d+\\.\\s+/.test(line)) {\n flushParagraph(paragraph)\n paragraph = []\n const items: string[] = []\n while (i < lines.length && /^\\s*\\d+\\.\\s+/.test(lines[i]!)) {\n items.push(`<li>${inline(lines[i]!.replace(/^\\s*\\d+\\.\\s+/, ''))}</li>`)\n i++\n }\n out.push(`<ol>${items.join('')}</ol>`)\n continue\n }\n\n // GFM table\n if (isTableRow(line) && i + 1 < lines.length && isDelimiterRow(lines[i + 1]!)) {\n flushParagraph(paragraph)\n paragraph = []\n const headers = rowCells(line)\n i += 2\n const rows: string[] = []\n while (i < lines.length && isTableRow(lines[i]!)) {\n const cells = rowCells(lines[i]!)\n rows.push(`<tr>${cells.map(c => `<td>${inline(c)}</td>`).join('')}</tr>`)\n i++\n }\n out.push(`<table><thead><tr>${headers.map(h => `<th>${inline(h)}</th>`).join('')}</tr></thead><tbody>${rows.join('')}</tbody></table>`)\n continue\n }\n\n // Blank line ends the paragraph\n if (line.trim() === '') {\n flushParagraph(paragraph)\n paragraph = []\n i++\n continue\n }\n\n paragraph.push(line.trim())\n i++\n }\n flushParagraph(paragraph)\n return out.join('\\n')\n}\n","// Vendored from LookatStudy src/renderer/lib/mermaid-elk-rewrite.ts (MIT License, https://github.com/Kaiji-Z/LookatStudy).\n// Unmodified except this provenance header (elkjs dynamic import target adapted to CDN).\n/**\n * mermaid-elk-rewrite —— flowchart → flowchart-elk 前缀改写(v0.21 纯函数)。\n *\n * 只在渲染层改写:LLM 出题提示词(draw_diagram)与语法修复回路\n * (diagram-repair-service)都继续产出/接收**原版 flowchart 语法**,零改动;\n * renderMermaid 喂给 mermaid 前把 flowchart/graph 声明行改成 flowchart-elk ——\n * 同一套语法换 ELK 布局引擎(正交路由,复杂流程图边交叉显著少于 dagre)。\n *\n * mermaid 机制:flowchart-elk 前缀 → detector 置 config.layout=\"elk\" → 查\n * registerLayoutLoaders 注册的 \"elk\" 算法;未注册则静默退 dagre 并 console.warn\n * (ui-test 靠该 warn 断言 ELK 真实生效)。\n *\n * 范围:只改首个内容行的 flowchart 家族声明;sequenceDiagram/stateDiagram-v2/\n * classDiagram 等其余图类型原样返回(ELK 布局只对 flowchart 家族注册)。\n */\n\n/** 首个内容行(跳过空行与 %% 注释/`%%{init}%%` 指令行)的 flowchart 声明改为\n * flowchart-elk;已是 flowchart-elk 则幂等返回;其他图类型不动。 */\nexport function rewriteFlowchartToElk(code: string): string {\n const lines = code.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i] ?? \"\";\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(\"%%\")) continue;\n if (/^flowchart-elk\\b/i.test(trimmed)) return code;\n if (/^(flowchart|graph)\\b/i.test(trimmed)) {\n lines[i] = line.replace(/^(\\s*)(flowchart|graph)\\b/i, \"$1flowchart-elk\");\n return lines.join(\"\\n\");\n }\n // 首个内容行不是 flowchart 家族 → 其他图类型,不改写\n return code;\n }\n return code;\n}\n","/**\n * Post-render blackboard enhancement (SPEC Phase 2): math (KaTeX), code\n * highlighting (shiki), and mermaid diagrams — every dependency loaded from a\n * CDN at runtime (zero-dependency mandate: nothing enters the bundle), every\n * failure degrading silently to the existing plain rendering. Upstream parity:\n * math-normalize runs host-side before renderMarkdown; the CDN + lazy-singleton\n * pattern follows upstream lazy-shiki/lazy-mermaid, pointed at esm.sh/cdnjs.\n *\n * Test seams: every loader is injectable via `setEnhanceDeps` so node:test\n * proves the enhance/degrade paths offline (the structural-test discipline:\n * prove a gate fails first, then trust its green).\n */\n\n/** Map a lang-xxx class to shiki's grammar id (upstream's curated set, aliases included). */\nconst LANG_ALIAS: Record<string, string> = {\n ts: 'typescript', tsx: 'tsx', js: 'javascript', jsx: 'jsx', mjs: 'javascript', cjs: 'javascript',\n py: 'python', rb: 'ruby', rs: 'rust', 'c++': 'cpp', cs: 'csharp', kt: 'kotlin', sh: 'bash', shell: 'bash', zsh: 'bash',\n yml: 'yaml', md: 'markdown', tex: 'latex', docker: 'dockerfile',\n}\n\nimport { rewriteFlowchartToElk } from '../vendor/mermaid-elk-rewrite.ts'\n\ntype KatexLike = { renderToString(tex: string, opts: Record<string, unknown>): string }\ntype ShikiLike = { codeToHtml(code: string, opts: Record<string, unknown>): Promise<string> }\ntype MermaidLike = { registerLayoutLoaders(l: unknown): void; initialize(cfg: Record<string, unknown>): void; render(id: string, code: string): Promise<{ svg: string }> }\n\nexport interface EnhanceDeps {\n loadKatex?: () => Promise<KatexLike>\n loadShiki?: () => Promise<ShikiLike>\n loadMermaid?: () => Promise<MermaidLike>\n}\nlet deps: EnhanceDeps = {}\nexport function setEnhanceDeps(d: EnhanceDeps | null): void { deps = d ?? {} }\n\n/* ---------------- CDN loaders (production defaults) ---------------- */\n\nconst CDN = {\n katexJs: 'https://cdn.jsdelivr.net/npm/katex@0.16.22/dist/katex.min.js',\n katexCss: 'https://cdn.jsdelivr.net/npm/katex@0.16.22/dist/katex.min.css',\n shiki: 'https://esm.sh/shiki@1.29.2',\n mermaid: 'https://esm.sh/mermaid@11.4.1',\n mermaidElk: 'https://esm.sh/@mermaid-js/layout-elk@0.1.7',\n}\n\nfunction loadScript(src: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const el = document.createElement('script')\n el.src = src\n el.onload = () => { resolve() }\n el.onerror = () => { reject(new Error(`script load failed: ${src}`)) }\n document.head.append(el)\n })\n}\n\nlet katexPromise: Promise<KatexLike> | null = null\nfunction defaultLoadKatex(): Promise<KatexLike> {\n katexPromise ??= (async () => {\n if (!document.querySelector(`link[data-lks-katex]`)) {\n const link = document.createElement('link')\n link.rel = 'stylesheet'\n link.href = CDN.katexCss\n link.setAttribute('data-lks-katex', '1')\n document.head.append(link)\n }\n if ((window as { katex?: KatexLike }).katex === undefined) await loadScript(CDN.katexJs)\n const katex = (window as { katex?: KatexLike }).katex\n if (katex === undefined) throw new Error('katex missing after load')\n return katex\n })()\n return katexPromise\n}\n\nlet shikiPromise: Promise<ShikiLike> | null = null\nfunction defaultLoadShiki(): Promise<ShikiLike> {\n shikiPromise ??= import(/* @vite-ignore */ CDN.shiki).then((mod: Record<string, unknown>) => {\n const create = mod.createHighlighter as ((opts: Record<string, unknown>) => Promise<ShikiLike>) | undefined\n if (create === undefined) throw new Error('shiki createHighlighter missing')\n return create({ themes: ['github-dark', 'github-light'], langs: ['typescript', 'javascript', 'python', 'bash', 'json', 'yaml', 'css', 'html', 'markdown', 'cpp', 'go', 'rust', 'java', 'sql'] })\n }) as Promise<ShikiLike>\n return shikiPromise\n}\n\nlet mermaidPromise: Promise<MermaidLike> | null = null\nfunction defaultLoadMermaid(): Promise<MermaidLike> {\n mermaidPromise ??= (async () => {\n const mod = await import(/* @vite-ignore */ CDN.mermaid) as Record<string, unknown>\n const mermaid = mod.default as MermaidLike\n try {\n const elk = await import(/* @vite-ignore */ CDN.mermaidElk) as Record<string, unknown>\n mermaid.registerLayoutLoaders(elk.default)\n } catch { /* ELK unavailable → mermaid falls back to dagre silently */ }\n mermaid.initialize({ startOnLoad: false, theme: 'base', securityLevel: 'loose' })\n return mermaid\n })()\n return mermaidPromise\n}\n\n/* ---------------- enhancers ---------------- */\n\n/** Split one text node's data around the FIRST math span; returns null when none. */\nfunction findMathSpan(text: string): { before: string; tex: string; after: string; display: boolean } | null {\n const display = /\\$\\$([^$]+)\\$\\$/.exec(text)\n const inline = /\\$([^$\\n]+)\\$/.exec(text)\n if (display === null && inline === null) return null\n const m = display !== null && (inline === null || display.index <= inline.index) ? { ...display, display: true } : inline === null ? null : { ...inline, display: false }\n if (m === null) return null\n return { before: text.slice(0, m.index), tex: m[1]!, after: text.slice(m.index + m[0].length), display: m.display }\n}\n\n/** KaTeX every $..$ / $$..$$ in the container; degrades to plain text on any failure. */\nexport async function enhanceMath(container: HTMLElement): Promise<number> {\n let katex: KatexLike\n try { katex = await (deps.loadKatex ?? defaultLoadKatex)() } catch { return 0 }\n let replaced = 0\n const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT)\n const targets: Text[] = []\n let node: Node | null\n while ((node = walker.nextNode()) !== null) {\n if (findMathSpan((node as Text).data) !== null && (node as Text).parentElement?.tagName !== 'CODE') targets.push(node as Text)\n }\n for (const t of targets) {\n const span = findMathSpan(t.data)\n if (span === null) continue\n try {\n const html = katex.renderToString(span.tex, { displayMode: span.display, throwOnError: false })\n const holder = document.createElement('span')\n holder.innerHTML = html\n if (span.before !== '') t.before(document.createTextNode(span.before))\n t.before(holder)\n t.data = span.after\n replaced++\n } catch { /* leave the text as-is */ }\n }\n return replaced\n}\n\n/** shiki-highlight every fenced code block; unknown langs and failures keep the plain <pre>. */\nexport async function enhanceCode(container: HTMLElement): Promise<number> {\n let shiki: ShikiLike\n try { shiki = await (deps.loadShiki ?? defaultLoadShiki)() } catch { return 0 }\n let replaced = 0\n const blocks = [...container.querySelectorAll<HTMLElement>('pre > code')]\n for (const code of blocks) {\n if (code.dataset.lksEnhanced === '1') continue\n const langClass = [...code.classList].find(c => c.startsWith('lang-'))\n if (langClass === undefined) continue\n const lang = LANG_ALIAS[langClass.slice(5)] ?? langClass.slice(5)\n try {\n const html = await shiki.codeToHtml(code.textContent ?? '', {\n lang,\n themes: { light: 'github-light', dark: 'github-dark' },\n defaultColor: false,\n cssVariables: { '--shiki-dark': 'var(--shiki-dark, #e6edf3)' },\n })\n code.dataset.lksEnhanced = '1'\n const pre = code.parentElement!\n const wrap = document.createElement('div')\n wrap.className = 'lks-shiki'\n wrap.innerHTML = html\n pre.replaceWith(wrap)\n replaced++\n } catch { code.dataset.lksEnhanced = '1' /* don't retry a failing lang */ }\n }\n return replaced\n}\n\n/** Render mermaid fence blocks to SVG (ELK layout via the registered loader);\n * the flowchart prefix rewrite is upstream's mermaid-elk-rewrite, vendored. */\nexport async function enhanceDiagrams(container: HTMLElement): Promise<number> {\n let mermaid: MermaidLike\n try { mermaid = await (deps.loadMermaid ?? defaultLoadMermaid)() } catch { return 0 }\n let replaced = 0\n const blocks = [...container.querySelectorAll<HTMLElement>('pre > code.lang-mermaid')]\n for (const code of blocks) {\n if (code.dataset.lksEnhanced === '1') continue\n code.dataset.lksEnhanced = '1'\n try {\n const { svg } = await mermaid.render(`lks-mermaid-${replaced}`, rewriteFlowchartToElk(code.textContent ?? ''))\n const wrap = document.createElement('div')\n wrap.className = 'lks-mermaid'\n wrap.innerHTML = svg\n code.parentElement!.replaceWith(wrap)\n replaced++\n } catch { /* keep the code block as-is */ }\n }\n return replaced\n}\n\n/** The full pass over one freshly-rendered container. Never throws. */\nexport async function enhanceRendered(container: HTMLElement): Promise<void> {\n try { await enhanceDiagrams(container) } catch { /* degrade */ }\n try { await enhanceCode(container) } catch { /* degrade */ }\n try { await enhanceMath(container) } catch { /* degrade */ }\n}\n\n","// Vendored from LookatStudy src/renderer/lib/cmap-elk-layout.ts (MIT License, https://github.com/Kaiji-Z/LookatStudy).\n// Unmodified except this provenance header (elkjs dynamic import target adapted to CDN).\n/**\n * cmap-elk-layout —— 概念图 v2 布局(ELK layered,复合分组 + 正交路由)。\n *\n * v0.12 径向布局的视觉评审结论:空白与拥挤并存/边交叉/无层级,且交叉消解要靠\n * 自研启发式。v0.21 换 elkjs(draw.io 新版同款 Eclipse Layout Kernel):\n * - 分组 = ELK 复合图(compound children):组容器盒 + 标题栏留白\n * - 连线 = elk.edgeRouting ORTHOGONAL:直角折线绕开盒子,结构性消灭\"线穿节点\"\n * - 分组来源:LLM show_concept_map 的可选 groups 字段;缺省/无效时客户端按\n * 邻接聚类兜底(clusterByAdjacency,确定性多源 BFS),不回头折腾 prompt\n *\n * 结构分层(全部可单测):\n * resolveGroups / clusterByAdjacency / cmNodeBox / buildElkGraph —— 纯函数\n * flattenElkResult —— 把 ELK 输出递归拍平成绝对坐标(复合嵌套只有一层)\n * layoutConceptMap —— 异步管线,elkjs 走动态 import(lazy chunk,同 mermaid)\n *\n * CJK 估宽/两行包裹沿用 v0.12 已验证的实现(estTextWidth/wrapLabel 原样迁移)。\n * 全链确定性:输入序驱动 + ELK 无随机源,verify-artifact-cmap-v2 断言两次运行\n * 逐坐标全等。\n */\n\n// ============================================================\n// 数据类型(与 artifact-harness ConceptMapData 对齐,groups 为 v2 增列)\n// ============================================================\n\nexport interface CmNode {\n id: string;\n label: string;\n}\nexport interface CmEdge {\n from: string;\n to: string;\n label?: string;\n}\nexport interface CmGroup {\n id: string;\n label: string;\n nodeIds: string[];\n}\n\n// ============================================================\n// 文本度量(v0.12 迁移,CJK 感知)\n// ============================================================\n\n/** 字符宽度估算:CJK 全宽,ASCII 约 0.58em,其余(BBOP…)同 ASCII。 */\nexport function estTextWidth(text: string, fontSize = 13): number {\n let w = 0;\n for (const ch of text) w += /[\\u2e80-\\u9fff\\uf900-\\ufaff\\uff00-\\uffef\\u3000-\\u303f]/.test(ch) ? fontSize : fontSize * 0.58;\n return w;\n}\n\nconst LINE_MAX_PX = 118;\n\n/** 标签包裹:≤2 行;优先自然断点(空格///-),CJK 连续按宽度一半硬拆;仍超宽截断。 */\nexport function wrapLabel(label: string): string[] {\n if (estTextWidth(label) <= LINE_MAX_PX) return [label];\n const breaks: number[] = [];\n for (let i = 0; i < label.length; i++) {\n if (/[\\s/\\-—·]/.test(label[i] ?? \"\")) breaks.push(i);\n }\n const mid = label.length / 2;\n let split = -1;\n let best = Infinity;\n for (const b of breaks) {\n const d = Math.abs(b + 1 - mid);\n if (d < best) {\n best = d;\n split = b;\n }\n }\n let l1: string;\n let l2: string;\n if (split >= 0) {\n l1 = label.slice(0, split + 1).trim();\n l2 = label.slice(split + 1).trim();\n } else {\n let acc = 0;\n let idx = 0;\n for (const ch of label) {\n acc += estTextWidth(ch);\n idx++;\n if (acc >= estTextWidth(label) / 2) break;\n }\n l1 = label.slice(0, idx);\n l2 = label.slice(idx);\n }\n if (estTextWidth(l1) <= LINE_MAX_PX && estTextWidth(l2) <= LINE_MAX_PX) return [l1, l2];\n const fit = (s: string) => {\n let out = \"\";\n for (const ch of s) {\n if (estTextWidth(out + ch + \"…\") > LINE_MAX_PX) break;\n out += ch;\n }\n return out + \"…\";\n };\n return [estTextWidth(l1) > LINE_MAX_PX ? fit(l1) : l1, estTextWidth(l2) > LINE_MAX_PX ? fit(l2) : l2];\n}\n\n/** 节点盒:hub(度数最大或 ≥4)字号/内边距更大;宽高由包裹后行宽决定。 */\nexport function cmNodeBox(label: string, hub: boolean): { width: number; height: number; lines: string[] } {\n const lines = wrapLabel(label);\n const fs = hub ? 14 : 13;\n const textW = Math.max(...lines.map((l) => estTextWidth(l, fs)));\n const padX = hub ? 30 : 24;\n const lh = 17;\n const padY = hub ? 18 : 14;\n return {\n width: Math.min(hub ? 200 : 180, Math.max(hub ? 92 : 76, textW + padX)),\n height: padY + lines.length * lh,\n lines,\n };\n}\n\n// ============================================================\n// 分组解析:LLM groups 优先,邻接聚类兜底\n// ============================================================\n\nexport interface ResolvedGroups {\n groups: CmGroup[];\n /** true = 来自客户端聚类(LLM 未给/无效) */\n fallback: boolean;\n}\n\n/**\n * 净化 LLM groups:丢弃指向不存在节点的 nodeIds、去重(先到先得)、\n * 剩余成员 < 2 的组丢弃;唯一覆盖全部节点的单组视为无效(一个巨容器没有信息量)。\n * 净化后为空 → clusterByAdjacency 兜底。\n */\nexport function resolveGroups(nodes: CmNode[], edges: CmEdge[], input?: CmGroup[] | null): ResolvedGroups {\n const ids = new Set(nodes.map((n) => n.id));\n if (Array.isArray(input) && input.length > 0) {\n const assigned = new Set<string>();\n const groups: CmGroup[] = [];\n for (const g of input) {\n if (!g || typeof g.id !== \"string\" || !g.id) continue;\n const nodeIds = Array.isArray(g.nodeIds)\n ? [...new Set(g.nodeIds.filter((x) => typeof x === \"string\" && ids.has(x) && !assigned.has(x)))]\n : [];\n if (nodeIds.length < 2) continue;\n nodeIds.forEach((x) => assigned.add(x));\n groups.push({ id: g.id, label: typeof g.label === \"string\" && g.label ? g.label : \"分组\", nodeIds });\n }\n if (groups.length > 0 && !(groups.length === 1 && assigned.size === nodes.length && nodes.length > 2)) {\n return { groups, fallback: false };\n }\n }\n return { groups: clusterByAdjacency(nodes, edges), fallback: true };\n}\n\n/**\n * 邻接聚类兜底(确定性):度数 top-k 节点做种子(k = clamp(ceil(n/4),1,3)),\n * 多源 BFS 就近归属(平手先出现的种子赢);孤立节点不归组(根层漂浮,不造假组)。\n * 组名 = 种子标签(≤5 字加\"相关\")。\n */\nexport function clusterByAdjacency(nodes: CmNode[], edges: CmEdge[]): CmGroup[] {\n if (nodes.length < 4) return []; // 太小不分组\n const index = new Map(nodes.map((n, i) => [n.id, i] as const));\n const adj = new Map<string, string[]>();\n for (const n of nodes) adj.set(n.id, []);\n const seenPair = new Set<string>();\n for (const e of edges) {\n if (!index.has(e.from) || !index.has(e.to) || e.from === e.to) continue;\n const key = [e.from, e.to].sort().join(\"→\");\n if (seenPair.has(key)) continue;\n seenPair.add(key);\n adj.get(e.from)!.push(e.to);\n adj.get(e.to)!.push(e.from);\n }\n const ranked = [...nodes].sort((a, b) => {\n const da = adj.get(a.id)!.length;\n const db = adj.get(b.id)!.length;\n return da !== db ? db - da : (index.get(a.id) ?? 0) - (index.get(b.id) ?? 0);\n });\n const k = Math.min(3, Math.max(1, Math.ceil(nodes.length / 4)));\n const seeds = ranked.slice(0, k).filter((s) => (adj.get(s.id)?.length ?? 0) > 0);\n if (seeds.length === 0) return [];\n const owner = new Map<string, number>(); // nodeId → seed 下标\n seeds.forEach((s, si) => owner.set(s.id, si));\n const queue = seeds.map((s) => s.id);\n while (queue.length) {\n const cur = queue.shift()!;\n const si = owner.get(cur)!;\n for (const nb of adj.get(cur) ?? []) {\n if (owner.has(nb)) continue;\n owner.set(nb, si);\n queue.push(nb);\n }\n }\n const groups: CmGroup[] = [];\n seeds.forEach((s, si) => {\n const nodeIds = nodes.filter((n) => owner.get(n.id) === si).map((n) => n.id);\n if (nodeIds.length < 2) return;\n groups.push({\n id: `grp-${s.id}`,\n label: s.label.length <= 5 ? `${s.label}相关` : s.label,\n nodeIds,\n });\n });\n return groups;\n}\n\n// ============================================================\n// ELK 图构建(纯函数,不触 elkjs —— 结构可脱离引擎直测)\n// ============================================================\n\n/** ELK JSON 的最小结构(只声明我们用到的字段;elkjs 原样吃任意附加字段)。 */\nexport interface ElkGraphJSON {\n id: string;\n layoutOptions?: Record<string, string>;\n width?: number;\n height?: number;\n x?: number;\n y?: number;\n children?: ElkGraphJSON[];\n edges?: {\n id: string;\n sources: string[];\n targets: string[];\n /** elkjs 在 hierarchyHandling=INCLUDE_CHILDREN 下把全部边挂到根,坐标属于 container 指向的容器 */\n container?: string;\n sections?: {\n startPoint: { x: number; y: number };\n endPoint: { x: number; y: number };\n bendPoints?: { x: number; y: number }[];\n }[];\n }[];\n}\n\n/** 组容器标题栏高度:ELK 组盒顶部 padding 要为标题留白。 */\nexport const GROUP_TITLE_PX = 34;\n\nexport function buildElkGraph(nodes: CmNode[], edges: CmEdge[], groups: CmGroup[]): ElkGraphJSON {\n const ids = new Set(nodes.map((n) => n.id));\n const degree = new Map<string, number>();\n for (const n of nodes) degree.set(n.id, 0);\n const seenPair = new Set<string>();\n const drawEdges: CmEdge[] = [];\n for (const e of edges) {\n if (!ids.has(e.from) || !ids.has(e.to) || e.from === e.to) continue;\n const key = [e.from, e.to].sort().join(\"→\");\n if (seenPair.has(key)) continue;\n seenPair.add(key);\n drawEdges.push(e);\n degree.set(e.from, degree.get(e.from)! + 1);\n degree.set(e.to, degree.get(e.to)! + 1);\n }\n let hubId = nodes[0]?.id ?? \"\";\n for (const n of nodes) if ((degree.get(n.id) ?? 0) > (degree.get(hubId) ?? 0)) hubId = n.id;\n\n const inGroup = new Map<string, string>(); // nodeId → groupId\n for (const g of groups) for (const nid of g.nodeIds) if (ids.has(nid) && !inGroup.has(nid)) inGroup.set(nid, g.id);\n\n const nodeChild = (n: CmNode): ElkGraphJSON => {\n const box = cmNodeBox(n.label, n.id === hubId || (degree.get(n.id) ?? 0) >= 4);\n return { id: n.id, width: Math.ceil(box.width), height: Math.ceil(box.height) };\n };\n\n const children: ElkGraphJSON[] = [];\n for (const g of groups) {\n const members = g.nodeIds.filter((nid) => inGroup.get(nid) === g.id && ids.has(nid));\n if (members.length === 0) continue;\n children.push({\n id: `g:${g.id}`,\n layoutOptions: { \"elk.padding\": `[top=${GROUP_TITLE_PX},left=14,bottom=12,right=14]` },\n children: members.map((nid) => nodeChild(nodes.find((n) => n.id === nid)!)),\n });\n }\n for (const n of nodes) {\n if (!inGroup.has(n.id)) children.push(nodeChild(n));\n }\n\n return {\n id: \"root\",\n layoutOptions: {\n \"elk.algorithm\": \"layered\",\n \"elk.direction\": \"DOWN\",\n \"elk.edgeRouting\": \"ORTHOGONAL\",\n // 复合图关键开关:layered 默认不处理嵌套(跨组边不路由、无 sections),\n // INCLUDE_CHILDREN 让整个复合图一次分层,跨组边才有正交折线\n \"elk.hierarchyHandling\": \"INCLUDE_CHILDREN\",\n \"elk.spacing.nodeNode\": \"34\",\n \"elk.spacing.edgeNode\": \"26\",\n \"elk.spacing.componentComponent\": \"48\",\n \"elk.layered.spacing.nodeNodeBetweenLayers\": \"56\",\n },\n children,\n edges: drawEdges.map((e, i) => ({ id: `e${i}`, sources: [e.from], targets: [e.to] })),\n };\n}\n\n// ============================================================\n// ELK 输出拍平(复合嵌套一层:root → 组盒 → 节点盒)\n// ============================================================\n\nexport interface CmapNodeGeo {\n id: string;\n x: number; // 左上角(绝对)\n y: number;\n w: number;\n h: number;\n lines: string[];\n hub: boolean;\n groupId: string | null;\n /** 颜色档 = 所属组序号(0-4 循环);无组 = -1(中性) */\n colorIdx: number;\n}\nexport interface CmapGroupGeo {\n id: string;\n label: string;\n x: number;\n y: number;\n w: number;\n h: number;\n colorIdx: number;\n}\nexport interface CmapEdgeGeo {\n from: string;\n to: string;\n label?: string;\n pts: { x: number; y: number }[];\n /** 边标签锚点(折线弧长中点);无标签为 null */\n labelPt: { x: number; y: number } | null;\n}\nexport interface CmapLayout {\n width: number;\n height: number;\n nodes: CmapNodeGeo[];\n groups: CmapGroupGeo[];\n edges: CmapEdgeGeo[];\n hubId: string;\n /** true = 分组来自客户端兜底(调试/未来 UI 提示用) */\n groupsFallback: boolean;\n}\n\n/** 折线弧长中点(标签锚点)。 */\nfunction polylineMidpoint(pts: { x: number; y: number }[]): { x: number; y: number } {\n if (pts.length === 0) return { x: 0, y: 0 };\n if (pts.length === 1) return pts[0];\n const segLens = [];\n let total = 0;\n for (let i = 1; i < pts.length; i++) {\n const l = Math.hypot(pts[i].x - pts[i - 1].x, pts[i].y - pts[i - 1].y);\n segLens.push(l);\n total += l;\n }\n let remain = total / 2;\n for (let i = 0; i < segLens.length; i++) {\n if (remain <= segLens[i] || i === segLens.length - 1) {\n const t = segLens[i] === 0 ? 0 : remain / segLens[i];\n return {\n x: pts[i].x + (pts[i + 1].x - pts[i].x) * t,\n y: pts[i].y + (pts[i + 1].y - pts[i].y) * t,\n };\n }\n remain -= segLens[i];\n }\n return pts[pts.length - 1];\n}\n\nexport function flattenElkResult(\n elkOut: ElkGraphJSON,\n nodes: CmNode[],\n edges: CmEdge[],\n groups: CmGroup[],\n groupsFallback: boolean,\n hubId: string,\n): CmapLayout {\n const nodesById = new Map(nodes.map((n) => [n.id, n] as const));\n const groupColor = new Map<string, number>();\n groups.forEach((g, i) => groupColor.set(g.id, i % 5));\n const groupById = new Map(groups.map((g) => [g.id, g] as const));\n const memberGroup = new Map<string, string>();\n for (const g of groups) for (const nid of g.nodeIds) if (!memberGroup.has(nid)) memberGroup.set(nid, g.id);\n\n const outNodes: CmapNodeGeo[] = [];\n const outGroups: CmapGroupGeo[] = [];\n const outEdges: CmapEdgeGeo[] = [];\n\n // elkjs 把边统一挂到根数组,坐标属于 e.container 指向的容器(INCLUDE_CHILDREN 下)——\n // 必须先收集\"容器 id → 绝对偏移\"表,再按 container 加偏移;按树位置加偏移会让组内边整体错位。\n const containerOff = new Map<string, { x: number; y: number }>([[\"root\", { x: 0, y: 0 }]]);\n const rawEdges: { e: NonNullable<ElkGraphJSON[\"edges\"]>[number]; fallback: { x: number; y: number } }[] = [];\n\n const walk = (elk: ElkGraphJSON, offX: number, offY: number, containerId: string | null) => {\n for (const child of elk.children ?? []) {\n const cx = offX + (child.x ?? 0);\n const cy = offY + (child.y ?? 0);\n if (child.children?.length) {\n const gid = child.id.startsWith(\"g:\") ? child.id.slice(2) : child.id;\n const meta = groupById.get(gid);\n outGroups.push({\n id: gid,\n label: meta?.label ?? \"分组\",\n x: cx,\n y: cy,\n w: child.width ?? 0,\n h: child.height ?? 0,\n colorIdx: groupColor.get(gid) ?? 0,\n });\n containerOff.set(child.id, { x: cx, y: cy });\n walk(child, cx, cy, gid);\n } else {\n const n = nodesById.get(child.id);\n if (!n) continue;\n const box = cmNodeBox(n.label, n.id === hubId);\n const gid = memberGroup.get(n.id) ?? null;\n outNodes.push({\n id: n.id,\n x: cx,\n y: cy,\n w: child.width ?? Math.ceil(box.width),\n h: child.height ?? Math.ceil(box.height),\n lines: box.lines,\n hub: n.id === hubId,\n groupId: containerId,\n colorIdx: gid != null ? groupColor.get(gid) ?? 0 : -1,\n });\n }\n }\n for (const e of elk.edges ?? []) {\n // 记录现场偏移兜底:理论上边也可挂在 LCA 自己的 edges 里(无 container 字段)\n rawEdges.push({ e, fallback: { x: offX, y: offY } });\n }\n };\n walk(elkOut, 0, 0, null);\n\n for (const { e, fallback } of rawEdges) {\n const sec = e.sections?.[0];\n if (!sec) continue;\n const off = (e.container != null ? containerOff.get(e.container) : undefined) ?? fallback;\n const pts = [sec.startPoint, ...(sec.bendPoints ?? []), sec.endPoint].map((p) => ({\n x: p.x + off.x,\n y: p.y + off.y,\n }));\n const idx = Number(e.id.slice(1));\n const src = edges[idx];\n if (!src) continue;\n outEdges.push({ from: src.from, to: src.to, label: src.label, pts, labelPt: src.label ? polylineMidpoint(pts) : null });\n }\n\n return {\n width: Math.ceil(elkOut.width ?? 0),\n height: Math.ceil(elkOut.height ?? 0),\n nodes: outNodes,\n groups: outGroups,\n edges: outEdges,\n hubId,\n groupsFallback,\n };\n}\n\n// ============================================================\n// 异步管线:elkjs 动态 import(独立 lazy chunk)\n// ============================================================\n\ntype ElkInstance = { layout: (graph: ElkGraphJSON) => Promise<ElkGraphJSON> };\nlet elkPromise: Promise<ElkInstance> | null = null;\n\n/** elkjs 单例:elk.bundled.js 主线程版(无 Worker,打包器友好,React Flow 生态同款)。 */\nfunction loadElk(): Promise<ElkInstance> {\n elkPromise ??= import(/* @vite-ignore */ \"https://esm.sh/elkjs@0.12/lib/elk.bundled.js\").then((mod: { default: unknown }) => {\n // interop 双环境:CJS(Node/tsx)default 在 mod.default;打包后 ESM 可能整包即构造器\n const m = mod as unknown as Record<string, unknown>;\n const Ctor = (m.default ?? m) as new () => ElkInstance;\n return new Ctor();\n });\n return elkPromise;\n}\n\n/** 概念图 → 分组解析 → ELK 布局 → 绝对坐标几何。输入相同则输出逐字段全等。 */\nexport async function layoutConceptMap(\n nodes: CmNode[],\n edges: CmEdge[],\n groups?: CmGroup[] | null,\n): Promise<CmapLayout> {\n const resolved = resolveGroups(nodes, edges, groups);\n const graph = buildElkGraph(nodes, edges, resolved.groups);\n const hubId = computeHubId(nodes, edges);\n const elk = await loadElk();\n const out = await elk.layout(graph);\n return flattenElkResult(out, nodes, edges, resolved.groups, resolved.fallback, hubId);\n}\n\nfunction computeHubId(nodes: CmNode[], edges: CmEdge[]): string {\n const ids = new Set(nodes.map((n) => n.id));\n const degree = new Map<string, number>();\n for (const n of nodes) degree.set(n.id, 0);\n const seen = new Set<string>();\n for (const e of edges) {\n if (!ids.has(e.from) || !ids.has(e.to) || e.from === e.to) continue;\n const key = [e.from, e.to].sort().join(\"→\");\n if (seen.has(key)) continue;\n seen.add(key);\n degree.set(e.from, degree.get(e.from)! + 1);\n degree.set(e.to, degree.get(e.to)! + 1);\n }\n let hubId = nodes[0]?.id ?? \"\";\n for (const n of nodes) if ((degree.get(n.id) ?? 0) > (degree.get(hubId) ?? 0)) hubId = n.id;\n return hubId;\n}\n","/**\n * The study tab's locale surface: one `lookatstudy` namespace registered with\n * the framework locale service (zh + en, key sets identical — the service\n * enforces balance at register time and this module's tests re-assert it).\n * `makeT` is the pure lookup (own chain: locale → zh → key, `{name}` template\n * interpolation — the same semantics as the service's translate) so unit\n * tests and non-slot code can translate without a live context;\n * `bindStudyT` prefers the service's stable `bind()` when present.\n * @module dsh-plugin-lookatstudy/client/locale\n */\n\n/** Flat key → template string, `{name}` placeholders (LocaleDict shape). */\nexport type StudyDict = Record<string, string>\n\n/** Simplified Chinese dictionary (also the fallback locale). */\nexport const ZH: StudyDict = {\n 'tab.label': '学习',\n 'col.rail': '课程',\n 'col.tutor': '导师',\n 'col.bb': '黑板',\n 'pane.rail': '课程',\n 'pane.tutor': '导师',\n 'pane.bb': '黑板',\n 'viewtab.teach': '讲解',\n 'viewtab.cmap': '概念图',\n 'viewtab.cmap.title': '本课概念之间的关系图',\n 'loading': '加载中…',\n 'start.title': '一键准备学习:建立学习工作区、开启会话并让导师就位',\n 'start.go': '开始学习',\n 'start.enter': '进入学习',\n 'start.busy': '正在准备学习区…',\n 'soul.direct': '直讲',\n 'soul.direct.hint': '精讲:先讲清楚,再确认懂没懂',\n 'soul.guide': '引导',\n 'soul.guide.hint': '引导:让你自己往前推一步,导师递台阶',\n 'soul.practice': '实战',\n 'soul.practice.hint': '实战:在真实世界的乱问题里学',\n 'zone.understand': '🧠 理解区 — 知识结构',\n 'zone.record': '📝 记录区 — 我的话',\n 'zone.practice': '✍️ 练习区 — 答题日志',\n 'rail.empty.title': '暂无课程',\n 'rail.empty.hint': '粘贴 markdown → 说「导入为课程」',\n 'rail.empty.hint2': '本地文件夹 → 说「导入 D:/path/to/folder」',\n 'rail.empty.placeholder': 'GitHub 仓库链接,如 microsoft/AI-For-Beginners',\n 'rail.empty.button': '导入',\n 'rail.empty.demo': '导入示例课程',\n 'rail.mastered': '毕业 {mastered}/{total} 课',\n 'rail.avg': '平均掌握度 {pct}%',\n 'rail.avg.none': '尚无掌握度数据',\n 'rail.search': '搜索课时…(多关键词空格分隔)',\n 'rail.locate.title': '在课程树中定位当前焦点课时(自动展开所在章节)',\n 'rail.locate': '回到当前课时',\n 'rail.due': '待复习 {count}',\n 'rail.due.over': '超{days}天',\n 'rail.due.start': '开始复习',\n 'rail.due.tag': '这课时的复习今天到期(SM-2)',\n 'rail.delete': '删除本课程',\n 'rail.delete.confirm': '确认删除?',\n 'rail.delete.title.confirm': '再点一次确认删除(含全部进度与笔记)。反悔前可先在设置页备份状态文件',\n 'rail.section.collapse': '折叠本章节',\n 'rail.section.expand': '展开本章节({count} 课时)',\n 'rail.section.count': '{count} 课',\n 'rail.lesson.opening': '正在打开课时会话…',\n 'rail.lesson.openHint': '(点击将打开本课专属会话)',\n 'rail.import.toggle': '导入课程',\n 'rail.import.close': '收起导入',\n 'tag.weak': '{count} 个薄弱知识点,测验会优先考察',\n 'tag.friction': '{count} 次卡点记录(你说\"不懂\"时导师记下的)',\n 'tag.mastery': '课时掌握度 {pct}%(取最薄弱知识点)',\n 'tag.mastery.short': '课时掌握度 = 最薄弱知识点的掌握度',\n 'status.exam': '章节测验:本节全部课时掌握度 ≥50% 后开放',\n 'status.mastered': '已毕业:掌握度 ≥90%(或你接受了掌握提案)',\n 'status.in_progress': '学习中:已开课,掌握度从 50% 起步',\n 'status.available': '可开始:已解锁,尚未学习',\n 'status.locked': '未解锁:先完成前面的课时',\n 'chip.unattributed': '未归因',\n 'chip.correct': '✓ 答对 · {concept}',\n 'chip.wrong': '✗ 答错 · {concept}',\n 'row.thinking': '导师思考中…',\n 'row.thinking.title': '导师正在推理,回复马上就来',\n 'quiz.title': '点击选项作答,也可以直接打字回答',\n 'quiz.answer': '选 {letter}:{text}',\n 'tutor.dormant': '学习模式已关闭 — 点右上「▶ 开始学习」开启导师,按钮恢复可用。',\n 'tutor.empty': '对话会出现在这里',\n 'tutor.empty.hint': '在下方输入框和导师说话',\n 'proposal.text': '导师提议你已掌握「{lesson}」:{rationale}',\n 'proposal.accept': '接受',\n 'proposal.decline': '再练练',\n 'bb.empty': '黑板还空着',\n 'bb.empty.hint': '在左侧课程树选择一课',\n 'bb.mastery': '掌握度 {pct}%',\n 'cmap.legend': '琥珀色 = 薄弱知识点(掌握度 <70%)',\n 'cmap.node.pct': '掌握度 {pct}%',\n 'bb.strategy': '本课学法',\n 'bb.fallback.cmap.empty': '概念图需要先由导师定义本课概念',\n 'bb.fallback.cmap': '概念图渲染不可用(布局引擎加载失败) — 已回退讲解视图',\n 'bb.notes': '笔记',\n 'bb.notes.empty': '这一课还没有笔记',\n 'tv.exam.stars': '本次 {n}★(历史最佳 {best}★)',\n 'tv.exam.fail': '这轮没拿到星——错题就是下一课的地图,从每题的解析看起。',\n 'active.off.title': '注册 study 工具并载入导师人格,之后普通对话和现在一样',\n 'active.on.title': '注销 study 工具与导师人格;学习进度保留,可随时重新开启',\n 'active.off': '▶ 开始学习',\n 'active.on': '⏻ 退出学习模式',\n 'prompt.kickoff': '开始学习:查看我的学习状态并打开当前焦点课时。如果我还没有课程,推荐我导入示例课程(AI-For-Beginners)并说明怎么开始。回复最后请提醒我点上方「学习」页签进入学习界面。',\n 'settings.nav': '学习',\n 'settings.mode': '教学风格',\n 'settings.mode.hint': '导师的讲解风格;也可在学习页随时切换',\n 'settings.studyMode': '学习模式',\n 'settings.studyMode.hint': '开启后注册 study_* 工具并载入导师人格;进度与笔记始终保留',\n 'settings.on': '状态:已开启',\n 'settings.off': '状态:已关闭',\n 'settings.turnOn': '开启',\n 'settings.turnOff': '关闭',\n 'settings.stats': '学习统计',\n 'settings.stats.courses': '课程 {count} 个',\n 'settings.stats.xp': 'XP {xp} · Lv{level}({pct}%)',\n 'settings.stats.today': '今日 {xp}/{goal}',\n 'settings.stats.streak': '连续 {days} 天(最长 {best},剩冻结 {freeze})',\n 'settings.about': '关于',\n 'settings.about.hint': '当前运行的构建版本,点击查看该版更新内容。',\n 'settings.stateFile': '状态文件',\n 'settings.stateFile.hint': '学习进度存放于本机 JSON,换机可迁移',\n 'dock.title': '学习状态:待复习 {due} · 连续 {streak} 天 · Lv{level} — 点上方「学习」页签进入',\n 'dock.due': '{count}',\n 'dock.streak': '{days}天',\n 'dock.lv': 'Lv{level}',\n 'prompt.import': '导入课程:用 study_import_github 抓取 {url}',\n 'prompt.lesson': '学习「{title}」:用 study_lesson 打开这一课开始学习。',\n 'prompt.exam': '开始「{section}」的章节测验:按本节课时出题,答完逐题判分',\n 'prompt.review': '开始今天的复习,从最到期的课时开始',\n 'prompt.proposal.accept': '接受提案 {id} —— 确认标记这课为已掌握',\n 'prompt.proposal.decline': '拒绝提案 {id} —— 我想再练练',\n}\n\n/** English dictionary — key set must equal {@link ZH}'s (test-asserted). */\nexport const EN: StudyDict = {\n 'tab.label': 'Study',\n 'col.rail': 'Courses',\n 'col.tutor': 'Tutor',\n 'col.bb': 'Blackboard',\n 'pane.rail': 'Courses',\n 'pane.tutor': 'Tutor',\n 'pane.bb': 'Board',\n 'viewtab.teach': 'Teach',\n 'viewtab.cmap': 'Concepts',\n 'viewtab.cmap.title': 'The lesson\\'s concepts relate',\n 'loading': 'Loading…',\n 'start.title': 'One click to study: workspace + session + tutor, all set up',\n 'start.go': 'Start learning',\n 'start.enter': 'Enter study',\n 'start.busy': 'Preparing the study area…',\n 'soul.direct': 'Direct',\n 'soul.direct.hint': 'Explain first, then check understanding',\n 'soul.guide': 'Guide',\n 'soul.guide.hint': 'You push one step forward; the tutor hands you the stairs',\n 'soul.practice': 'Practice',\n 'soul.practice.hint': 'Learn inside real, messy problems',\n 'zone.understand': '🧠 Understand — knowledge structure',\n 'zone.record': '📝 Record — in my own words',\n 'zone.practice': '✍️ Practice — answer log',\n 'rail.empty.title': 'No courses yet',\n 'rail.empty.hint': 'Paste markdown → say \"import as a course\"',\n 'rail.empty.hint2': 'Local folder → say \"import D:/path/to/folder\"',\n 'rail.empty.placeholder': 'GitHub repo link, e.g. microsoft/AI-For-Beginners',\n 'rail.empty.button': 'Import',\n 'rail.empty.demo': 'Import the demo course',\n 'rail.mastered': '{mastered}/{total} lessons graduated',\n 'rail.avg': 'avg mastery {pct}%',\n 'rail.avg.none': 'no mastery data yet',\n 'rail.search': 'Search lessons… (space-separated keywords)',\n 'rail.locate.title': 'Locate the current focus lesson in the tree (auto-expands its section)',\n 'rail.locate': 'Back to current lesson',\n 'rail.due': '{count} due',\n 'rail.due.over': '{days}d overdue',\n 'rail.due.start': 'Start reviewing',\n 'rail.due.tag': 'this lesson\\'s review is due today (SM-2)',\n 'rail.delete': 'Delete this course',\n 'rail.delete.confirm': 'Delete?',\n 'rail.delete.title.confirm': 'Click again to confirm (all progress and notes included). Back up via the state file in Settings first',\n 'rail.section.collapse': 'Collapse this section',\n 'rail.section.expand': 'Expand this section ({count} lessons)',\n 'rail.section.count': '{count} lessons',\n 'rail.lesson.opening': 'Opening the lesson session…',\n 'rail.lesson.openHint': ' (opens this lesson\\'s own session)',\n 'rail.import.toggle': 'Import a course',\n 'rail.import.close': 'Collapse import',\n 'tag.weak': '{count} weak concepts — quizzes target them first',\n 'tag.friction': '{count} friction marks (logged when you said you were stuck)',\n 'tag.mastery': 'lesson mastery {pct}% (the weakest concept)',\n 'tag.mastery.short': 'lesson mastery = the weakest concept\\'s mastery',\n 'status.exam': 'Section exam: opens when every lesson in the section reaches ≥50% mastery',\n 'status.mastered': 'Graduated: mastery ≥90% (or you accepted a mastery proposal)',\n 'status.in_progress': 'Learning: opened, mastery starts at 50%',\n 'status.available': 'Ready: unlocked, not started',\n 'status.locked': 'Locked: finish the preceding lessons first',\n 'chip.unattributed': 'unattributed',\n 'chip.correct': '✓ correct · {concept}',\n 'chip.wrong': '✗ wrong · {concept}',\n 'row.thinking': 'tutor is thinking…',\n 'row.thinking.title': 'The tutor is reasoning; the reply is coming',\n 'quiz.title': 'Click an option to answer, or just type',\n 'quiz.answer': 'Choose {letter}: {text}',\n 'tutor.dormant': 'Study mode is off — click \"▶ Start learning\" above to wake the tutor and re-enable these controls.',\n 'tutor.empty': 'The conversation will appear here',\n 'tutor.empty.hint': 'Talk to the tutor in the input below',\n 'proposal.text': 'The tutor proposes you have mastered \"{lesson}\": {rationale}',\n 'proposal.accept': 'Accept',\n 'proposal.decline': 'Keep practicing',\n 'bb.empty': 'The blackboard is empty',\n 'bb.empty.hint': 'Pick a lesson in the course tree on the left',\n 'bb.mastery': 'mastery {pct}%',\n 'cmap.legend': 'Amber = weak concept (mastery < 70%)',\n 'cmap.node.pct': 'mastery {pct}%',\n 'bb.strategy': 'Approach',\n 'bb.fallback.cmap.empty': 'The concept map needs the tutor to define this lesson\\'s concepts first',\n 'bb.fallback.cmap': 'Concept map unavailable (layout engine failed to load) — fell back to the teach view',\n 'bb.notes': 'Notes',\n 'bb.notes.empty': 'No notes for this lesson yet',\n 'tv.exam.stars': 'This attempt {n}★ (best {best}★)',\n 'tv.exam.fail': 'No stars this round — the wrong answers are the map for the next one; start with their explanations.',\n 'active.off.title': 'Register the study tools and load the tutor persona; plain chats stay as they are',\n 'active.on.title': 'Retire the study tools and tutor persona; progress is kept and you can re-enable anytime',\n 'active.off': '▶ Start learning',\n 'active.on': '⏻ Exit study mode',\n 'prompt.kickoff': 'Start learning: check my study state and open the current focus lesson. If I have no course yet, suggest importing the demo course (AI-For-Beginners) and explain how to begin. Remind me at the end to open the \"Study\" tab above to enter the study UI.',\n 'settings.nav': 'Study',\n 'settings.mode': 'Teaching style',\n 'settings.mode.hint': 'The tutor\\'s explanation style; switchable anytime in the study tab too',\n 'settings.studyMode': 'Study mode',\n 'settings.studyMode.hint': 'On registers the study_* tools and the tutor persona; progress and notes are always kept',\n 'settings.on': 'Status: on',\n 'settings.off': 'Status: off',\n 'settings.turnOn': 'Turn on',\n 'settings.turnOff': 'Turn off',\n 'settings.stats': 'Study stats',\n 'settings.stats.courses': '{count} courses',\n 'settings.stats.xp': 'XP {xp} · Lv{level} ({pct}%)',\n 'settings.stats.today': 'Today {xp}/{goal}',\n 'settings.stats.streak': 'Streak {days}d (best {best}, {freeze} freeze left)',\n 'settings.about': 'About',\n 'settings.about.hint': 'The version of the running build — click to see its release notes.',\n 'settings.stateFile': 'State file',\n 'settings.stateFile.hint': 'Your progress lives in a local JSON file — copy it to migrate machines',\n 'dock.title': 'Study status: {due} due · {streak}d streak · Lv{level} — open the Study tab above to continue',\n 'dock.due': '{count}',\n 'dock.streak': '{days}d',\n 'dock.lv': 'Lv{level}',\n 'prompt.import': 'Import a course: fetch {url} with study_import_github',\n 'prompt.lesson': 'Study \"{title}\": open this lesson with study_lesson and start teaching.',\n 'prompt.exam': 'Start the section exam for \"{section}\": quiz me on this section\\'s lessons and grade each answer',\n 'prompt.review': 'Start today\\'s review, from the most overdue lesson first',\n 'prompt.proposal.accept': 'Accept proposal {id} — confirm marking this lesson as mastered',\n 'prompt.proposal.decline': 'Reject proposal {id} — I want to practice more',\n}\n\n/** Both dictionaries under their locale ids (the service's register shape). */\nexport const STUDY_DICTS = { zh: ZH, en: EN }\n\n/** The namespace id this plugin registers with the framework locale service. */\nexport const STUDY_NS = 'lookatstudy'\n\n/** Translate function for the study namespace. */\nexport type StudyT = (key: string, params?: Record<string, unknown>) => string\n\n/**\n * Pure translator with the service's semantics: own-locale dict → zh\n * fallback → the key itself, `{name}` interpolation left untouched when the\n * param is missing.\n * @param locale - active locale id ('zh'/'en'; unknown ids fall back to zh).\n * @returns a stable-shaped translate function.\n */\nexport function makeT(locale: string): StudyT {\n const dict = locale === 'en' ? EN : ZH\n return (key, params) => {\n const template = dict[key] ?? ZH[key] ?? key\n if (params === undefined) return template\n return template.replace(/\\{(\\w+)\\}/g, (match, name: string) =>\n name in params ? String(params[name]) : match)\n }\n}\n\n/** Minimal shape of the framework locale service this plugin consumes. */\nexport interface LocaleServiceFace {\n register(ns: string, dicts: Record<string, StudyDict>): () => void\n bind(ns: string): StudyT\n subscribe(fn: () => void): () => void\n}\n\n/**\n * Register the namespace with the framework locale service.\n * @param locale - the client locale service when present.\n * @returns the registration disposer (a no-op when the service is absent or\n * a hostile re-registration was refused).\n */\nexport function registerStudyLocale(locale?: LocaleServiceFace): () => void {\n if (locale === undefined) return () => {}\n try {\n return locale.register(STUDY_NS, STUDY_DICTS)\n } catch {\n // A namespace/locale already claimed by someone else must not break the\n // tab — fall back to the pure translator everywhere.\n return () => {}\n }\n}\n\n/**\n * The live translator: the service's stable `bind` when present (reads the\n * active locale at call time, so a locale-change re-render picks new\n * strings), the pure zh translator otherwise.\n * @param locale - the client locale service when present.\n */\nexport function studyTranslator(locale?: LocaleServiceFace): StudyT {\n return locale === undefined ? makeT('zh') : locale.bind(STUDY_NS)\n}\n\n/** The module's active translator — zh until the view factory installs the live bind. */\nlet activeT: StudyT = makeT('zh')\n\n/**\n * Install the client-wide translator (called once at client apply, before\n * any component renders).\n */\nexport function setStudyTranslator(t: StudyT): void {\n activeT = t\n}\n\n/**\n * Translate through the active translator — the import every client module\n * uses for user-visible copy. Pure helpers take an optional explicit `t`\n * defaulting to the current active translator, evaluated per call.\n */\nexport function tr(key: string, params?: Record<string, unknown>): string {\n return activeT(key, params)\n}\n","/**\n * Blackboard diagram views (SPEC Phase 2): the lesson concept map (ELK layered\n * layout via the vendored cmap-elk-layout + CDN elkjs, draw.io-flavored SVG\n * skin rendered plugin-side). Degrades honestly: any CDN/ELK failure leaves a\n * one-line notice instead of a broken pane.\n *\n * The lesson mind map view was RETIRED with upstream v0.26.0 (2026-09-01\n * port): body text that has headings already shows its structure, text without\n * headings yields a first-line-truncated node graph nobody can read — both\n * lose — and this concept map already covers the semantic-structure need at\n * higher quality. Its three CDN imports went with it.\n */\n\nimport { layoutConceptMap, type CmNode, type CmEdge } from '../vendor/cmap-elk-layout.ts'\nimport { tr } from './locale.ts'\n\n\n/** Lesson concept map: the lesson node + its concepts (weak ones accented),\n * laid out by the vendored ELK pipeline, skinned draw.io-style (plugin-original,\n * upstream's skin is coupled to its token pipeline). Mastery shades the nodes. */\nexport async function renderLessonConceptMap(\n container: HTMLElement,\n lessonTitle: string,\n concepts: ReadonlyArray<{ title: string; masteryPct: number }>,\n): Promise<void> {\n const nodes: CmNode[] = [{ id: 'lesson', label: lessonTitle }, ...concepts.map(c => ({ id: `c-${c.title}`, label: c.title }))]\n const edges: CmEdge[] = concepts.map(c => ({ from: 'lesson', to: `c-${c.title}` }))\n const layout = await layoutConceptMap(nodes, edges)\n const masteryBy = new Map(concepts.map(c => [`c-${c.title}`, c.masteryPct]))\n const ns = 'http://www.w3.org/2000/svg'\n const svg = document.createElementNS(ns, 'svg')\n svg.setAttribute('width', String(Math.max(320, layout.width)))\n svg.setAttribute('height', String(Math.max(200, layout.height)))\n svg.setAttribute('viewBox', `0 0 ${layout.width} ${layout.height}`)\n svg.setAttribute('style', 'max-width:100%;background:var(--dsw-alias-bg-layer-1, #fff);border:1px solid var(--dsw-alias-border-l2, #d0d7de);border-radius:8px')\n for (const e of layout.edges) {\n const path = document.createElementNS(ns, 'path')\n path.setAttribute('d', e.pts.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x},${p.y}`).join(' '))\n path.setAttribute('fill', 'none')\n path.setAttribute('stroke', 'var(--dsw-alias-border-l2, #8b949e)')\n path.setAttribute('stroke-width', '1.5')\n svg.append(path)\n }\n for (const n of layout.nodes) {\n const g = document.createElementNS(ns, 'g')\n g.setAttribute('transform', `translate(${n.x},${n.y})`)\n const rect = document.createElementNS(ns, 'rect')\n const isLesson = n.id === 'lesson'\n const mastery = masteryBy.get(n.id)\n rect.setAttribute('width', String(n.w))\n rect.setAttribute('height', String(n.h))\n rect.setAttribute('rx', '6')\n rect.setAttribute('fill', mastery !== undefined && mastery < 70 ? 'var(--dsw-alias-state-warn-tertiary, #fef5e7)' : 'var(--dsw-alias-bg-layer-2, #f6f8fa)')\n rect.setAttribute('stroke', isLesson ? 'var(--dsw-alias-state-business-primary, #0969da)' : 'var(--dsw-alias-border-l2, #8b949e)')\n rect.setAttribute('stroke-width', isLesson ? '2' : '1')\n g.append(rect)\n n.lines.forEach((line, li) => {\n const label = document.createElementNS(ns, 'text')\n label.setAttribute('x', String(n.w / 2))\n label.setAttribute('y', String(n.h / 2 - (n.lines.length - 1) * 7 + li * 14 + 4))\n label.setAttribute('text-anchor', 'middle')\n label.setAttribute('font-size', isLesson ? '13' : '12')\n label.setAttribute('font-weight', isLesson ? '600' : '400')\n label.setAttribute('fill', 'var(--dsw-alias-label-primary, #1f2328)')\n label.textContent = line\n g.append(label)\n })\n const title = document.createElementNS(ns, 'title')\n const label = n.lines.join(' ')\n title.textContent = isLesson || mastery === undefined ? label : `${label} · ${tr('cmap.node.pct', { pct: mastery })}`\n g.append(title)\n svg.append(g)\n }\n container.append(svg)\n const legend = document.createElement('span')\n legend.className = 'lks-cmap-legend'\n const swatch = document.createElement('i')\n legend.append(swatch, document.createTextNode(tr('cmap.legend')))\n container.append(legend)\n}\n","/**\n * The study tab: one `conversation.view` entry rendering the whole plugin —\n * a simplified LookatStudy inside dsh, three columns in the tab. Left: the\n * course map (selector, tree, due box, one-click demo import). Middle: the\n * tutor conversation — a read-only transcript folded from the session\n * snapshot (user text, assistant text rendered through the plugin's own\n * markdown pipeline; tool calls stay in the host conversation's toolview\n * cards — a mirrored second record diverged) plus the soul pills, starters,\n * pending proposal banner, and a reverse-channel input. Right: the blackboard —\n * focus-lesson 讲解 and the Cornell 笔记 zones. Nothing outside this tab\n * touches dsh chrome.\n * @module dsh-plugin-lookatstudy/client/views\n */\n\nimport { createElement, useEffect, useRef, useState } from 'react'\nimport type { KeyboardEvent as ReactKeyboardEvent, ReactNode } from 'react'\nimport {\n IconBoltFill16, IconBookFill16, IconCrownFill16, IconFlameFill16, IconGlobeOutline14,\n IconGoalOutline16, IconLockFill16, IconPinFill16, IconPlayOutline16, IconPlusOutline16,\n IconPowerFill16, IconRefreshOutline16, IconStarFill16, IconTrashOutline16,\n IconDownloadOutline16, IconLoadingOutline16, IconWarningOutline16,\n} from './icons.tsx'\nimport type { ClientContext, SessionMachineSnapshot, StudyViewProps, TranscriptNode, TranscriptPartial, TranscriptSlice } from './faces.ts'\nimport { useStudy } from './data.ts'\nimport { renderMarkdown } from '../markdown.ts'\nimport { enhanceRendered, setEnhanceDeps } from './enhance.ts'\nimport { renderLessonConceptMap } from './diagrams.ts'\nimport { tr, type StudyT } from './locale.ts'\n\n/** The three souls, in pill order (labels from LookatStudy's mode switcher). */\nconst MODES: ReadonlyArray<{ id: 'direct' | 'guide' | 'practice'; labelKey: string; hintKey: string }> = [\n { id: 'direct', labelKey: 'soul.direct', hintKey: 'soul.direct.hint' },\n { id: 'guide', labelKey: 'soul.guide', hintKey: 'soul.guide.hint' },\n { id: 'practice', labelKey: 'soul.practice', hintKey: 'soul.practice.hint' },\n]\n\n/** Zone keys for the Cornell notebook (understand / record / practice). */\nconst ZONES: ReadonlyArray<readonly [string, string]> = [\n ['understand', 'zone.understand'],\n ['record', 'zone.record'],\n ['practice', 'zone.practice'],\n]\n\n/** Status icon for one lesson row (LookatStudy's map icon semantics, SVG glyphs). */\nfunction statusIcon(kind: string, status: string): ReactNode {\n if (kind === 'exam') return createElement(IconGoalOutline16, { size: 14 })\n if (status === 'mastered') return createElement(IconCrownFill16, { size: 14 })\n if (status === 'in_progress') return createElement(IconBookFill16, { size: 14 })\n if (status === 'available') return createElement(IconStarFill16, { size: 14 })\n return createElement(IconLockFill16, { size: 14 })\n}\n\n/** LookatStudy's exam gate: an exam node opens only when every sibling study lesson reached mastery ≥50%. */\nfunction examOpen(lessons: ReadonlyArray<{ kind: string; masteryPct: number | null }>): boolean {\n return lessons.every(l => l.kind !== 'study' || (l.masteryPct ?? 0) >= 50)\n}\n\n/** Multi-keyword AND title filter (LookatStudy course-tree-filter). */\nfunction titleMatches(title: string, query: string): boolean {\n const keys = query.trim().toLowerCase().split(/\\s+/).filter(Boolean)\n return keys.every(k => title.toLowerCase().includes(k))\n}\n\n/**\n * Default expansion for one rail section: collapsed when every study lesson is\n * done (mastered) or not yet reachable (locked) — long courses otherwise scroll\n * 5× their viewport. The active frontier and the focus lesson's section stay\n * open; exam nodes never force a section open (they are gated separately).\n * Pure.\n * @param section - one course section projection with lesson kinds/statuses.\n */\nexport function sectionDefaultOpen(section: { lessons: ReadonlyArray<{ kind: string; status: string; focus: boolean }> }): boolean {\n return section.lessons.some(l => l.focus || (l.kind !== 'exam' && l.status !== 'mastered' && l.status !== 'locked'))\n}\n\n/** The rail's import row: a GitHub URL input plus the paste/folder hints. */\nfunction ImportRow({ send }: { send: StudySend }): ReactNode {\n const [url, setUrl] = useState('')\n return createElement('div', { className: 'lks-import' },\n createElement('div', { className: 'lks-inputrow' },\n createElement('input', {\n className: 'lks-input',\n type: 'url',\n placeholder: tr('rail.empty.placeholder'),\n value: url,\n onChange: (e: { target: { value: string } }) => { setUrl(e.target.value) },\n onKeyDown: (e: ReactKeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter' && url.trim() !== '') send(tr('prompt.import', { url: url.trim() }))\n },\n }),\n createElement('button', {\n className: 'lks-btn primary',\n disabled: url.trim() === '',\n onClick: () => { send(tr('prompt.import', { url: url.trim() })) },\n }, tr('rail.empty.button')),\n ),\n createElement('div', { className: 'lks-import-hint' },\n tr('rail.empty.hint'), createElement('br'),\n tr('rail.empty.hint2')),\n )\n}\n\n/** One rendered transcript row (pure fold of the conversation snapshot). */\nexport interface ChatRow {\n readonly key: string\n readonly role: 'user' | 'assistant' | 'error' | 'streaming' | 'thinking'\n readonly text: string\n}\n\n/**\n * Tooltip text for one course-tree status glyph. Pure (the translator is an\n * optional parameter defaulting to the active one, evaluated per call).\n * @param kind - lesson kind ('study' | 'practice' | 'exam').\n * @param status - lesson status ('locked' | 'available' | 'in_progress' | 'mastered').\n * @param t - translator (defaults to the module's active translator).\n */\nexport function statusTitle(kind: string, status: string, t: StudyT = tr): string {\n if (kind === 'exam') return t('status.exam')\n switch (status) {\n case 'mastered': return t('status.mastered')\n case 'in_progress': return t('status.in_progress')\n case 'available': return t('status.available')\n default: return t('status.locked')\n }\n}\n\n/**\n * Extract the last quiz option block (2–4 consecutive `A. …` `B. …` lines,\n * letters strictly consecutive from A) from an assistant reply — the raw text\n * of the tutor's question becomes the clickable answer surface. Pure.\n * @param text - one assistant reply's markdown.\n * @returns the options of the last valid block, or [] when none.\n */\nexport function quizOptions(text: string): ReadonlyArray<{ letter: string; text: string }> {\n const runs: Array<Array<{ letter: string; text: string }>> = []\n let run: Array<{ letter: string; text: string }> = []\n const flush = (): void => {\n if (run.length >= 2) runs.push(run)\n run = []\n }\n for (const line of text.split('\\n')) {\n const match = /^([A-D])[.、:)]\\s+(.+)$/.exec(line.trim())\n if (match === null) {\n flush()\n continue\n }\n const nextLetter = run.length === 0 ? 'A' : String.fromCharCode(run[run.length - 1]!.letter.charCodeAt(0) + 1)\n if (match[1] === nextLetter) run.push({ letter: match[1], text: match[2]! })\n else {\n flush()\n if (match[1] === 'A') run.push({ letter: match[1], text: match[2]! })\n }\n }\n flush()\n return runs.at(-1) ?? []\n}\n\nfunction textOf(blocks: readonly { type: string; text?: string }[] | undefined): string {\n return (blocks ?? []).filter(b => b.type === 'text').map(b => b.text ?? '').join('\\n\\n').trim()\n}\n\nfunction assistantText(blocks: readonly { kind: string; text?: string }[] | undefined): string {\n return (blocks ?? []).filter(b => b.kind === 'text').map(b => b.text ?? '').join('\\n\\n').trim()\n}\n\n/**\n * Fold conversation nodes (plus the streaming partial) into render rows.\n * Tool results are skipped: the host conversation renders the rich\n * `tool.call.toolview` cards, and the tutor column stays a pure persona\n * surface (a transcript mirror there grew a second, diverging record).\n * Both inputs tolerate undefined: newer hosts (DSH v0.1.2-alpha.4) mount\n * the conversation view before session data exists, and the fold must\n * degrade to an empty transcript instead of blanking the whole tab.\n * @param nodes - finalized conversation nodes from the snapshot.\n * @param partial - the in-flight assistant partial, or null.\n * @param t - translator (defaults to the active one, per call).\n * @returns ordered rows; never mutates its inputs.\n */\nexport function transcriptRows(nodes: readonly TranscriptNode[] | undefined, partial: TranscriptPartial | null | undefined, t: StudyT = tr): readonly ChatRow[] {\n const rows: ChatRow[] = []\n for (const node of nodes ?? []) {\n switch (node.kind) {\n case 'user':\n case 'steering': {\n const text = textOf(node.content)\n if (text !== '') rows.push({ key: `u${node.seq}`, role: 'user', text })\n break\n }\n case 'assistant': {\n const text = assistantText(node.blocks)\n if (text !== '') rows.push({ key: `a${node.seq}`, role: 'assistant', text })\n break\n }\n case 'turn-error':\n rows.push({ key: `e${node.seq}`, role: 'error', text: node.message ?? '' })\n break\n default:\n break\n }\n }\n if (partial != null) {\n const text = assistantText(partial.blocks)\n if (text !== '') rows.push({ key: 'streaming', role: 'streaming', text })\n // No text yet means the tutor is reasoning (or lining up tool calls) —\n // without this row the column sits dead silent through the whole phase.\n else rows.push({ key: 'thinking', role: 'thinking', text: t('row.thinking') })\n }\n return rows\n}\n\n/** Small inline error surface for failed write actions (shared with the settings page). */\nexport function ActionError({ error }: { error: string | null }): ReactNode {\n if (error === null) return null\n return createElement('div', { className: 'lks-propcard-err' }, error)\n}\n\n/**\n * Land one message in the dsh composer and submit it — the same path as the\n * Send button, so button text is visible in the native input for a beat and\n * then goes through the full submission pipeline (no reverse channel).\n */\nexport type StudySend = (text: string) => void\n\n/**\n * Resolve the transcript across host generations. 0.1.3+ hosts expose the\n * node array as the Chat target's `legacy` slice; pre-0.1.3 hosts hand the\n * whole conversation snapshot (nodes + partial) through `useSession`, whose\n * 0.1.3+ successor returns the session MACHINE (no node array). The array\n * check tells those two `useSession` shapes apart. Pure.\n */\nexport function pickTranscript(\n chatLegacy: TranscriptSlice | undefined,\n sessionSnapshot: (TranscriptSlice & SessionMachineSnapshot) | undefined,\n): TranscriptSlice | undefined {\n if (chatLegacy !== undefined) return chatLegacy\n return sessionSnapshot !== undefined && Array.isArray(sessionSnapshot.nodes) ? sessionSnapshot : undefined\n}\n\n/** Narrow-mode pane selector: which of the three columns is the main display. */\ntype StudyPane = 'rail' | 'tutor' | 'bb'\n\n/** sessionStorage key keeping the narrow-mode pane across view remounts (tab switches) and reloads. */\nconst PANE_KEY = 'dsh-plugin-lookatstudy:pane'\n\n/** Narrow the stored value back to a pane id; anything else (or nothing stored) falls back to 导师. Pure, unit-testable. */\nexport function pickPane(stored: string | null): StudyPane {\n return stored === 'rail' || stored === 'tutor' || stored === 'bb' ? stored : 'tutor'\n}\n\n/** Read the persisted pane; the try swallows only the SecurityError privacy modes throw on storage access — the fallback is the default pane. */\nfunction storedPane(): StudyPane {\n try {\n return pickPane(sessionStorage.getItem(PANE_KEY))\n } catch {\n return 'tutor'\n }\n}\n\n/**\n * The framework's branded `SessionId`, minted locally (structural twin of the\n * brand — session ids are plain strings on the wire; the brand exists to keep\n * opaque ids out of string APIs). Replaces the former `as never` casts.\n */\ntype SessionId = string & { readonly __sessionBrand: 'SessionId' }\nconst sessionId = (id: string): SessionId => id as SessionId\n\n/** The whole study tab. Wide = three columns (课程 | 导师 | 黑板); narrow (<1220px) = one composer-width pane with a three-way switcher. */\nexport function studyView(ctx: ClientContext): (props: StudyViewProps) => ReactNode {\n return function StudyView(props: StudyViewProps): ReactNode {\n return createElement(StudyTab, { ...props, ctx, key: 'tab' })\n }\n}\n\n/** Tab body: the factory-bound ctx carries workspaces/sessions for the per-lesson session jumps. */\nfunction StudyTab({ inputActions, ctx, ...standard }: StudyViewProps & { ctx: ClientContext }): ReactNode {\n const { data, activate, setMode, setFocus, searchLessons, deleteCourse, bindLessonSession } = useStudy()\n // The transcript moved twice across host generations (see pickTranscript).\n // Both hooks are version-stable, so the optional calls keep hook order\n // constant on any given host.\n const chatLegacy = standard.useChat?.((s) => s.legacy)\n const sessionSnapshot = standard.useSession?.((s) => s)\n const snapshot: TranscriptSlice | undefined = pickTranscript(chatLegacy, sessionSnapshot)\n // Newer hosts (DSH v0.1.2-alpha.4) mount the tab before session data\n // exists, so every read off this value guards for undefined.\n const currentSessionId = standard.sessionId ?? snapshot?.sessionId ?? ''\n const [pane, setPane] = useState<StudyPane>(storedPane)\n const rootRef = useRef<HTMLDivElement | null>(null)\n // The wide layout puts the tutor column left of the scroll body's center\n // (fixed rail + flexible blackboard), so the floating composer would sit\n // mid-screen under nothing. While this view is mounted and measurable, shift\n // the host composer card ([data-composer-card], a stable host anchor) under\n // the tutor column; any collapsed shift (narrow single-pane mode, hidden\n // view, no room) removes the class and restores the host's natural\n // centering. ResizeObserver on the study root catches mount/show/hide/resize.\n useEffect(() => {\n const root = rootRef.current\n const card = document.querySelector<HTMLElement>('[data-composer-card]')\n const seat = card?.parentElement ?? null\n if (root === null || card === null || seat === null) return\n const clear = (): void => {\n card.classList.remove('lks-composer-follow')\n card.style.removeProperty('--lks-composer-shift')\n card.style.removeProperty('--lks-composer-follow-width')\n }\n const apply = (): void => {\n const tutor = root.querySelector<HTMLElement>('.lks-col-tutor')\n const rail = root.querySelector<HTMLElement>('.lks-col-rail')\n if (tutor === null || rail === null || getComputedStyle(rail).display === 'none') return clear()\n const seatRect = seat.getBoundingClientRect()\n const tutorRect = tutor.getBoundingClientRect()\n if (seatRect.width === 0 || tutorRect.width === 0) return clear()\n const pad = parseFloat(getComputedStyle(seat).paddingLeft) || 0\n const cardW = card.getBoundingClientRect().width\n const max = seatRect.width - 2 * pad - cardW\n const shift = Math.round(Math.max(0, Math.min(tutorRect.left - (seatRect.left + pad), max)))\n if (shift < 2) return clear()\n card.style.setProperty('--lks-composer-shift', `${shift}px`)\n // The tutor column shrinks proportionally below ~1857px containers\n // (42cqi cap) — the docked composer card tracks that live width so the\n // card never overhangs the transcript column it sits under.\n card.style.setProperty('--lks-composer-follow-width', `${Math.round(tutorRect.width)}px`)\n card.classList.add('lks-composer-follow')\n }\n apply()\n const ro = new ResizeObserver(apply)\n ro.observe(root)\n ro.observe(seat)\n window.addEventListener('resize', apply)\n return () => {\n ro.disconnect()\n window.removeEventListener('resize', apply)\n clear()\n }\n }, [])\n const send: StudySend = (text) => {\n void (async () => {\n // Dormant installs activate first: the host registers the study tools\n // before the activation POST resolves, so the prompt meets a model that\n // can already call them.\n if (data?.active !== true) await activate(true)\n inputActions.setDraft(text)\n inputActions.submit()\n })()\n }\n // The bound translator reads the active locale at call time; a locale\n // switch must re-render to pick the new strings (the framework `t` seat\n // does this for slot entries — the deep component tree rides this bump).\n const [, bumpLocale] = useState(0)\n useEffect(() => {\n const localeSvc = ctx.locale\n if (localeSvc === undefined) return\n return localeSvc.subscribe(() => { bumpLocale(v => v + 1) })\n }, [ctx])\n const panes: ReadonlyArray<{ id: StudyPane; labelKey: string }> = [\n { id: 'rail', labelKey: 'pane.rail' },\n { id: 'tutor', labelKey: 'pane.tutor' },\n { id: 'bb', labelKey: 'pane.bb' },\n ]\n return createElement('div', {\n ref: rootRef,\n className: 'lks-root lks-study',\n 'data-conversation-composer-overlay': '',\n 'data-pane': pane,\n },\n // Always-visible activation bar: the tab is the fallback entry when another\n // plugin's composer takeover hides the starter pill.\n createElement('div', { className: 'lks-actbar' },\n data === null ? null : createElement('button', {\n className: `lks-btn ${data.active ? 'ghost' : 'primary'}`,\n title: data.active ? tr('active.on.title') : tr('active.off.title'),\n onClick: () => { void activate(!data.active) },\n }, data.active ? createElement(IconPowerFill16, { size: 13 }) : createElement(IconPlayOutline16, { size: 13 }), data.active ? tr('active.on') : tr('active.off')),\n ),\n // .lks-body carries the row/column direction so the container query can\n // flip it — a container query cannot style the container element itself.\n createElement('div', { className: 'lks-body' },\n createElement('div', { className: 'lks-switch' },\n ...panes.map(p => createElement('button', {\n key: p.id,\n className: `lks-switch-btn${pane === p.id ? ' on' : ''}`,\n 'aria-pressed': String(pane === p.id),\n onClick: () => {\n setPane(p.id)\n try {\n sessionStorage.setItem(PANE_KEY, p.id)\n } catch {\n // Privacy modes forbid storage writes; the in-memory choice still holds this page.\n }\n },\n }, tr(p.labelKey))),\n ),\n createElement(CourseRail, { data, activate, setFocus, searchLessons, deleteCourse, bindLessonSession, send, ctx, currentSessionId }),\n createElement(TutorColumn, { data, setMode, send, snapshot }),\n createElement(BlackboardColumn, { data }),\n ),\n )\n}\n\ntype StudyData = ReturnType<typeof useStudy>['data']\n\n/** Left column: course management (pick/delete/search/import), lesson tree, due box. */\nfunction CourseRail({ data, activate, setFocus, searchLessons, deleteCourse, bindLessonSession, send, ctx, currentSessionId }: {\n data: StudyData\n activate: (active: boolean) => Promise<void>\n setFocus: (id: string) => Promise<void>\n searchLessons: (query: string) => Promise<Array<{ lessonId: string; lessonTitle: string; snippet: string }>>\n deleteCourse: (courseId: string) => Promise<void>\n bindLessonSession: (lessonId: string, sessionId: string) => Promise<void>\n send: StudySend\n ctx: ClientContext\n currentSessionId: string\n}): ReactNode {\n const [jumping, setJumping] = useState<string | null>(null)\n /** Open (or mint) the lesson's own session — the simplified thread system. */\n const openLessonThread = (lesson: { id: string; title: string }): void => {\n if (jumping !== null) return\n const mapped = data?.lessonSessions[lesson.id]\n if (mapped === currentSessionId) {\n void setFocus(lesson.id).catch(reportError)\n return\n }\n if (mapped !== undefined && ctx.sessions.binding(sessionId(mapped)) !== undefined) {\n void setFocus(lesson.id).catch(reportError)\n ctx.sessions.open(sessionId(mapped))\n return\n }\n setJumping(lesson.id)\n void setFocus(lesson.id).then(() => (async () => {\n // Minting a lesson session prompts directly (not through `send`), so\n // activation happens here too — same dormant-install guarantee.\n if (data?.active !== true) await activate(true)\n const area = await fetch('/lookatstudy/api/study-workspace')\n if (!area.ok) throw new Error(`study area unavailable (HTTP ${area.status})`)\n const { path } = await area.json() as { path: string }\n const workspace = await ctx.workspaces.create({ path })\n // 0.1.3 moved the session mint from workspaces.connectWorkspace to\n // sessions.create (same dual-host detect as the starter). Each lesson\n // gets its own thread: a fresh blank session per lesson node.\n const sessionId = ctx.workspaces.connectWorkspace !== undefined\n ? await ctx.workspaces.connectWorkspace(workspace.workspaceId)\n : await ctx.sessions.create({ workspaceId: workspace.workspaceId })\n const actx = ctx.sessions.scope(sessionId)\n const face = actx === undefined ? undefined : ctx.sessions.sessionOf(actx)\n if (face === undefined) throw new Error('lesson session is not addressable yet')\n const result = await face.prompt([{ type: 'text', text: tr('prompt.lesson', { title: lesson.title }) }], 'queue')\n if (!result.ok) throw new Error(`lesson prompt rejected: ${result.error.code}: ${result.error.message}`)\n await bindLessonSession(lesson.id, sessionId)\n ctx.sessions.open(sessionId)\n })()).then(\n () => { setJumping(null) },\n (err: unknown) => { reportError(err); setJumping(null) },\n )\n }\n const [selectedCourse, setSelectedCourse] = useState('')\n const [query, setQuery] = useState('')\n const [confirmDelete, setConfirmDelete] = useState(false)\n // An armed delete disarms on outside click or Escape — a stray second\n // click anywhere else must not be able to confirm destruction.\n useEffect(() => {\n if (!confirmDelete) return\n const disarm = (): void => { setConfirmDelete(false) }\n const onKey = (e: KeyboardEvent): void => { if (e.key === 'Escape') disarm() }\n window.addEventListener('click', disarm)\n window.addEventListener('keydown', onKey)\n return () => {\n window.removeEventListener('click', disarm)\n window.removeEventListener('keydown', onKey)\n }\n }, [confirmDelete])\n const [showImport, setShowImport] = useState(false)\n /** Per-section open overrides (courseId/sectionTitle → open?), on top of the frontier default. */\n const [secOpen, setSecOpen] = useState<Record<string, boolean>>({})\n const [error, setError] = useState<string | null>(null)\n const reportError = (err: unknown): void => { setError(err instanceof Error ? err.message : String(err)) }\n const body: ReactNode = data === null\n ? createElement('div', { className: 'lks-empty' }, tr('loading'))\n : data.courses.length === 0\n ? createElement('div', { className: 'lks-empty' },\n tr('rail.empty.title'), createElement('br'),\n createElement('button', {\n className: 'lks-btn primary',\n style: { margin: '10px 0' },\n onClick: () => { send(tr('prompt.import', { url: 'https://github.com/microsoft/AI-For-Beginners' })) },\n }, createElement(IconDownloadOutline16, null), tr('rail.empty.demo')),\n createElement(ImportRow, { send }),\n )\n : (() => {\n const courseId = data.courses.some(c => c.courseId === selectedCourse)\n ? selectedCourse\n : data.courses[0]!.courseId\n const course = data.courses.find(c => c.courseId === courseId)!\n return createElement('div', null,\n createElement('div', { className: 'lks-rail-head' },\n data.courses.length > 1\n ? createElement('select', {\n className: 'lks-rail-select',\n value: courseId,\n onChange: (e: { target: { value: string } }) => { setSelectedCourse(e.target.value); setConfirmDelete(false) },\n }, ...data.courses.map(c => createElement('option', { key: c.courseId, value: c.courseId }, c.title)))\n : createElement('div', { className: 'lks-rail-title', title: course.title }, course.title),\n createElement('button', {\n className: `lks-btn ${confirmDelete ? 'primary' : 'ghost'}`,\n title: confirmDelete ? tr('rail.delete.title.confirm') : tr('rail.delete'),\n onClick: (e: { stopPropagation: () => void }) => {\n e.stopPropagation()\n if (!confirmDelete) { setConfirmDelete(true); return }\n setConfirmDelete(false)\n deleteCourse(courseId).then(() => { setSelectedCourse('') }, reportError)\n },\n }, confirmDelete ? tr('rail.delete.confirm') : createElement(IconTrashOutline16, { size: 14 })),\n ),\n createElement('div', { className: 'lks-rail-sub' }, tr('rail.mastered', { mastered: course.mastered, total: course.total })),\n createElement('div', {\n className: `lks-masterybar${course.avgMasteryPct === 100 ? ' gold' : ''}`,\n title: course.avgMasteryPct === null ? tr('rail.avg.none') : tr('rail.avg', { pct: course.avgMasteryPct }),\n }, createElement('i', { style: { transform: `scaleX(${(course.avgMasteryPct ?? 0) / 100})` } })),\n createElement('input', {\n className: 'lks-search',\n type: 'search',\n placeholder: tr('rail.search'),\n value: query,\n onChange: (e: { target: { value: string } }) => { setQuery(e.target.value) },\n onKeyDown: (e: ReactKeyboardEvent<HTMLInputElement>) => {\n if (e.key !== 'Enter' || query.trim() === '') return\n for (const section of course.sections) {\n const hit = section.lessons.find(l => l.kind !== 'exam' && l.status !== 'locked' && titleMatches(l.title, query))\n if (hit !== undefined) {\n void setFocus(hit.id).catch(reportError)\n return\n }\n }\n // No title hit → full-text over lesson bodies (host-side search)\n void searchLessons(query).then(hits => {\n const hit = hits.find(h => h.lessonId.startsWith(`${courseId}:`)) ?? hits[0]\n if (hit !== undefined) { setQuery(''); void setFocus(hit.lessonId).catch(reportError) }\n }).catch(reportError)\n },\n }),\n course.sections.some(s => s.lessons.some(l => l.focus))\n ? createElement('button', {\n className: 'lks-btn ghost',\n style: { margin: '0 0 6px', padding: '3px 8px', fontSize: '13px' },\n title: tr('rail.locate.title'),\n onClick: () => {\n const focusSection = course.sections.find(s => s.lessons.some(l => l.focus))\n if (focusSection === undefined) return\n setSecOpen(m => ({ ...m, [`${courseId}/${focusSection.title}`]: true }))\n // One frame past the React commit, so the freshly-expanded node exists to scroll to.\n window.setTimeout(() => {\n document.querySelector('.lks-col-rail .lks-node.focus')?.scrollIntoView({ block: 'center', behavior: 'smooth' })\n }, 60)\n },\n }, createElement(IconPinFill16, { size: 13 }), tr('rail.locate'))\n : null,\n data.dueCount > 0\n ? createElement('div', { className: 'lks-duebox' },\n createElement(IconRefreshOutline16, { size: 13 }), tr('rail.due', { count: data.dueCount }),\n ...data.due.map(d => createElement('div', { key: d.lessonId, className: 'lks-due-item' },\n createElement('span', null, d.lessonTitle),\n d.overdueDays > 0 ? createElement('span', { className: 'lks-over' }, tr('rail.due.over', { days: d.overdueDays })) : null)),\n createElement('button', {\n className: 'lks-btn ghost',\n style: { marginTop: '6px' },\n onClick: () => { send(tr('prompt.review')) },\n }, tr('rail.due.start')),\n )\n : null,\n ...course.sections.flatMap(section => {\n const examAllowed = examOpen(section.lessons)\n const lessons = section.lessons.filter(l => query.trim() === '' || titleMatches(l.title, query) || l.focus)\n if (lessons.length === 0) return []\n const secKey = `${courseId}/${section.title}`\n // Active search overrides collapse (results must be visible);\n // otherwise the user's toggle wins over the frontier default.\n const open = query.trim() !== '' || (secOpen[secKey] ?? sectionDefaultOpen(section))\n return [\n createElement('button', {\n key: section.title,\n type: 'button',\n className: 'lks-sechead',\n 'aria-expanded': String(open),\n title: open ? tr('rail.section.collapse') : tr('rail.section.expand', { count: section.lessons.length }),\n onClick: () => { setSecOpen(m => ({ ...m, [secKey]: !open })) },\n },\n createElement('span', { className: 'lks-sec-num' }, String(section.index + 1)),\n createElement('span', { className: 'lks-sechead-t' }, section.title),\n open ? null : createElement('span', { className: 'lks-sechead-n' }, tr('rail.section.count', { count: section.lessons.length })),\n createElement('span', { className: 'lks-sechead-c' }, open ? '▾' : '▸')),\n ...(open ? lessons.map(lesson => {\n const locked = lesson.status === 'locked' || (lesson.kind === 'exam' && !examAllowed)\n // aria-disabled (not the disabled attribute): the row stays\n // focusable so its title can explain WHY it is locked.\n return createElement('button', {\n key: lesson.id,\n type: 'button',\n className: `lks-node${lesson.focus ? ' focus' : ''}`,\n 'aria-disabled': locked || undefined,\n title: jumping === lesson.id\n ? tr('rail.lesson.opening')\n : `${lesson.title} — ${statusTitle(lesson.kind, locked ? 'locked' : lesson.status)}${locked || lesson.kind === 'exam' ? '' : tr('rail.lesson.openHint')}`,\n onClick: () => {\n if (locked) return\n if (lesson.kind === 'exam') {\n void setFocus(lesson.id).catch(reportError)\n send(tr('prompt.exam', { section: section.title }))\n return\n }\n openLessonThread(lesson)\n },\n },\n createElement('span', { className: 'lks-g' }, jumping === lesson.id ? createElement(IconLoadingOutline16, { size: 14, className: 'lks-spin' }) : statusIcon(lesson.kind, locked ? 'locked' : lesson.status)),\n createElement('span', { className: 'lks-t' }, lesson.title),\n lesson.due ? createElement('span', { className: 'lks-tag due', title: tr('rail.due.tag') }, createElement(IconRefreshOutline16, { size: 11 })) : null,\n lesson.weakConcepts > 0 ? createElement('span', { className: 'lks-tag weak', title: tr('tag.weak', { count: lesson.weakConcepts }) }, createElement(IconBoltFill16, { size: 10 }), String(lesson.weakConcepts)) : null,\n lesson.frictionCount > 0 ? createElement('span', { className: 'lks-tag fric', title: tr('tag.friction', { count: lesson.frictionCount }) }, createElement(IconWarningOutline16, { size: 10 }), String(lesson.frictionCount)) : null,\n lesson.masteryPct !== null\n ? createElement('span', { className: 'lks-bar', title: tr('tag.mastery', { pct: lesson.masteryPct }) }, createElement('i', { style: { transform: `scaleX(${lesson.masteryPct / 100})` } }))\n : null,\n lesson.masteryPct !== null ? createElement('span', { className: 'lks-pct', title: tr('tag.mastery.short') }, `${lesson.masteryPct}%`) : null,\n )\n }) : []),\n ]\n }),\n createElement('button', {\n className: 'lks-btn ghost',\n style: { marginTop: '10px' },\n onClick: () => { setShowImport(!showImport) },\n }, showImport ? tr('rail.import.close') : createElement(IconPlusOutline16, { size: 13 }), tr('rail.import.toggle')),\n showImport ? createElement(ImportRow, { send }) : null,\n )\n })()\n return createElement('div', { className: 'lks-col lks-col-rail' },\n createElement('div', { className: 'lks-colhead' }, tr('col.rail')),\n body,\n createElement(ActionError, { error }),\n )\n}\n\n/** One transcript row's element; `interactive` adds the quiz-answer buttons to an assistant row. */\nfunction chatRowElement(row: ChatRow, interactive?: { send: StudySend }): ReactNode {\n if (row.role === 'user') {\n return createElement('div', { key: row.key, className: 'lks-msg user' }, row.text)\n }\n if (row.role === 'error') {\n return createElement('div', { key: row.key, className: 'lks-msg error' }, `⚠ ${row.text}`)\n }\n if (row.role === 'thinking') {\n return createElement('div', { key: row.key, className: 'lks-msg thinking', title: tr('row.thinking.title') },\n createElement(IconLoadingOutline16, { size: 14, className: 'lks-spin' }),\n row.text)\n }\n const cls = row.role === 'streaming' ? 'lks-msg assistant lks-prose streaming' : 'lks-msg assistant lks-prose'\n const body = createElement('div', {\n key: row.key,\n className: cls,\n dangerouslySetInnerHTML: { __html: renderMarkdown(row.text) },\n })\n const options = interactive === undefined || row.role === 'streaming' ? [] : quizOptions(row.text)\n if (options.length < 2) return body\n return createElement('div', { key: row.key, className: 'lks-turn' },\n body,\n createElement('div', { className: 'lks-quiz', title: tr('quiz.title') },\n ...options.map(opt => createElement('button', {\n key: opt.letter,\n className: 'lks-opt',\n onClick: () => { interactive.send(tr('quiz.answer', { letter: opt.letter, text: opt.text })) },\n },\n createElement('span', { className: 'lks-optletter' }, opt.letter),\n createElement('span', null, opt.text))),\n ))\n}\n\n/** Middle column: the tutor — transcript, proposal banner, pills, starters. Typing happens in the native composer below the tab. */\nfunction TutorColumn({ data, setMode, send, snapshot }: {\n data: StudyData\n setMode: (mode: 'direct' | 'guide' | 'practice') => Promise<void>\n send: StudySend\n snapshot: TranscriptSlice | undefined\n}): ReactNode {\n const [error, setError] = useState<string | null>(null)\n const rows = transcriptRows(snapshot?.nodes, snapshot?.partial ?? null)\n // Quiz buttons only on the last settled assistant reply: older questions are\n // already answered, and the streaming partial may cut an option mid-line.\n const lastAssistant = rows.reduce((acc, row, i) => row.role === 'assistant' ? i : acc, -1)\n const scrollRef = useRef<HTMLDivElement | null>(null)\n useEffect(() => {\n const el = scrollRef.current\n if (el !== null) el.scrollTop = el.scrollHeight\n }, [rows.length])\n // Transcript enhancement rides the same scroll container: assistant math/code\n // diagrams get their CDN pass after every row change (idempotent per element).\n useEffect(() => {\n const el = scrollRef.current\n if (el !== null && rows.length > 0) void enhanceRendered(el).catch(() => { /* degrade */ })\n }, [rows.length])\n const proposal = data?.pendingProposals[0] ?? null\n const lesson = data?.lesson ?? null\n const dormant = data?.active !== true\n /** Mode switches are the only fallible write left here (host route); surface failures inline. */\n const fire = (action: Promise<void>): void => {\n action.then(() => { setError(null) }, (err: unknown) => { setError(err instanceof Error ? err.message : String(err)) })\n }\n return createElement('div', { className: 'lks-col lks-col-tutor' },\n createElement('div', { className: 'lks-colhead' }, tr('col.tutor')),\n dormant\n ? createElement('div', { className: 'lks-dormant' }, tr('tutor.dormant'))\n : null,\n createElement('div', { className: 'lks-transcript', ref: scrollRef },\n rows.length === 0 && !dormant\n ? createElement('div', { className: 'lks-empty' }, tr('tutor.empty'), createElement('br'), tr('tutor.empty.hint'))\n : rows.map((row, i) => chatRowElement(row, !dormant && i === lastAssistant ? { send } : undefined)),\n ),\n proposal !== null\n ? createElement('div', { className: 'lks-banner' },\n createElement('span', null, '🎓'),\n createElement('span', { className: 'lks-why' }, tr('proposal.text', { lesson: proposal.lessonTitle, rationale: proposal.rationale })),\n createElement('button', {\n className: 'lks-btn primary',\n onClick: () => { send(tr('prompt.proposal.accept', { id: proposal.id })) },\n }, tr('proposal.accept')),\n createElement('button', {\n className: 'lks-btn ghost',\n onClick: () => { send(tr('prompt.proposal.decline', { id: proposal.id })) },\n }, tr('proposal.decline')),\n )\n : null,\n createElement('div', { className: 'lks-pills', style: { height: 'auto', padding: '4px 0' } },\n ...MODES.map(mode => createElement('button', {\n key: mode.id,\n className: `lks-pill${data?.mode === mode.id ? ' on' : ''}`,\n 'aria-pressed': String(data?.mode === mode.id),\n 'aria-disabled': dormant || undefined,\n title: dormant ? tr('tutor.dormant') : tr(mode.hintKey),\n onClick: () => { if (!dormant) fire(setMode(mode.id)) },\n }, tr(mode.labelKey))),\n ),\n lesson !== null && lesson.starters.length > 0\n ? createElement('div', { className: 'lks-dock', style: { padding: '0 0 6px' } },\n ...lesson.starters.map(s => createElement('button', {\n key: s.label,\n className: 'lks-starter',\n 'aria-disabled': dormant || undefined,\n title: dormant ? tr('tutor.dormant') : s.message,\n onClick: () => { if (!dormant) send(s.message) },\n }, s.label)),\n )\n : null,\n createElement(ActionError, { error }),\n )\n}\n\n/** Right column: the blackboard — focus-lesson 讲解/脑图/概念图 plus the Cornell 笔记. */\nfunction BlackboardColumn({ data }: { data: StudyData }): ReactNode {\n const lesson = data?.lesson ?? null\n const [pane, setPane] = useState<'teach' | 'cmap'>('teach')\n const proseRef = useRef<HTMLDivElement | null>(null)\n const diagRef = useRef<HTMLDivElement | null>(null)\n // Post-render enhancement: math/shiki/mermaid via CDN, every failure degrades silently.\n useEffect(() => {\n if (pane !== 'teach' || proseRef.current === null || lesson === null) return\n const el = proseRef.current\n void enhanceRendered(el).catch(() => { /* degrade */ })\n }, [pane, lesson?.html])\n // Diagram panes (also CDN + vendored layout, honest one-line failure notice).\n useEffect(() => {\n if (pane !== 'cmap' || diagRef.current === null || lesson === null) return\n const el = diagRef.current\n el.textContent = ''\n const run = lesson.concepts.length === 0\n ? Promise.reject(new Error('no concepts'))\n : renderLessonConceptMap(el, lesson.title, lesson.concepts.map(c => ({ title: c.title, masteryPct: c.masteryPct })))\n run.catch((err) => {\n console.error('lks diagram pane failed:', pane, err)\n el.textContent = lesson.concepts.length === 0\n ? tr('bb.fallback.cmap.empty')\n : tr('bb.fallback.cmap')\n })\n }, [pane, lesson?.lessonId, lesson?.concepts.length])\n\n const body: ReactNode = lesson === null\n ? createElement('div', { className: 'lks-empty' }, tr('bb.empty'), createElement('br'), tr('bb.empty.hint'))\n : createElement('div', null,\n createElement('div', { className: 'lks-lessonhead' },\n createElement('h2', null, lesson.title),\n createElement('div', { className: 'lks-meta' },\n `${lesson.courseTitle} · ${statusTitle('study', lesson.status)}`\n + (lesson.masteryPct === null ? '' : ` · ${tr('bb.mastery', { pct: lesson.masteryPct })}`)),\n createElement('div', { className: 'lks-meta' }, `${tr('bb.strategy')}:${lesson.strategy}`),\n lesson.concepts.length > 0\n ? createElement('div', { className: 'lks-chips' },\n ...lesson.concepts.map(c => createElement('span', {\n key: c.title,\n className: `lks-chip${c.weak ? ' weak' : ''}`,\n }, `${c.title} ${c.masteryPct}%${c.weak ? ' ⚡' : ''}`)))\n : null,\n ),\n createElement('div', { className: 'lks-viewtabs' },\n createElement('button', { className: `lks-viewtab${pane === 'teach' ? ' on' : ''}`, 'aria-pressed': String(pane === 'teach'), onClick: () => { setPane('teach') } }, tr('viewtab.teach')),\n createElement('button', { className: `lks-viewtab${pane === 'cmap' ? ' on' : ''}`, 'aria-pressed': String(pane === 'cmap'), title: tr('viewtab.cmap.title'), onClick: () => { setPane('cmap') } }, createElement(IconGlobeOutline14, { size: 13 }), tr('viewtab.cmap')),\n ),\n pane === 'teach'\n ? createElement('div', { className: 'lks-prose', ref: proseRef, dangerouslySetInnerHTML: { __html: lesson.html } })\n : createElement('div', { className: 'lks-prose', ref: diagRef }),\n createElement('div', { className: 'lks-bb-notes' },\n createElement('div', { className: 'lks-sec' }, tr('bb.notes')),\n lesson.notes.length === 0\n ? createElement('div', { className: 'lks-empty', style: { padding: '16px 0' } }, tr('bb.notes.empty'))\n : ZONES.filter(([zone]) => lesson.notes.some(n => n.zone === zone)).map(([zone, labelKey]) =>\n createElement('div', { key: zone, className: 'lks-zone' },\n createElement('div', { className: 'lks-zone-h' }, tr(labelKey)),\n ...lesson.notes.filter(n => n.zone === zone).map(n => createElement('div', { key: n.id, className: 'lks-note' },\n createElement('span', { className: 'lks-note-src' }, n.source),\n createElement('div', { className: 'lks-note-title' }, n.title),\n createElement('div', { className: 'lks-note-text', dangerouslySetInnerHTML: { __html: renderMarkdown(n.text) } }),\n n.quote !== null ? createElement('div', { className: 'lks-note-q' }, `“${n.quote}”`) : null,\n )),\n )),\n ),\n )\n return createElement('div', { className: 'lks-col lks-col-bb' },\n createElement('div', { className: 'lks-colhead' }, tr('col.bb')),\n body,\n )\n}\n","/**\n * The one-click study starter: a pill button in the blank-session (hero)\n * composer tool row. One click adopts the plugin's dedicated study workspace\n * (created by the host beside the state file), opens a session in it, sends\n * the kickoff prompt through the session API, and makes that session current\n * — the learner lands in the chat with the tutor already responding, one\n * click away from the 学习 tab (view switching is ui-conversation-private,\n * not reachable from an additive plugin).\n * @module dsh-plugin-lookatstudy/client/starter\n */\n\nimport { createElement, useState } from 'react'\nimport type { ReactNode } from 'react'\nimport { IconLoadingOutline16, IconThinkOutline16 } from './icons.tsx'\nimport { useStudy } from './data.ts'\nimport { tr } from './locale.ts'\nimport type { ClientContext, StudyInputProps } from './faces.ts'\n\n/**\n * Build the hero starter button bound to the framework services.\n * @param ctx - client root context (workspaces + sessions injected).\n * @returns the component for `conversation.input.left`.\n */\nexport function studyStartButton(ctx: ClientContext): (props: StudyInputProps) => ReactNode {\n return function StudyStartButton(props: StudyInputProps): ReactNode {\n // The blank flag moved across host generations: pre-0.1.3 hosts pass the\n // InputZone owner prop; 0.1.3+ removed the owner and expose the flag on\n // the session machine standard hook. Either source may be absent (and\n // 0.1.2-alpha.4 calls input slots before session data exists at all) —\n // no blank session means no starter, not a crash.\n const machine = props.useSession?.((s) => s)\n if ((props.session?.blank ?? machine?.blank) !== true) return null\n return createElement(Inner, { key: 'inner', ctx })\n }\n}\n\n/** Button body in its own component so hook order stays constant. */\nfunction Inner({ ctx }: { ctx: ClientContext }): ReactNode {\n const { data, activate } = useStudy()\n const [busy, setBusy] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const start = (): void => {\n if (busy) return\n setBusy(true)\n setError(null)\n void (async () => {\n try {\n // Dormant installs activate first: the host registers the study tools\n // before this POST resolves, so the kickoff prompt below meets a model\n // that can already call them.\n if (data?.active !== true) await activate(true)\n const area = await fetch('/lookatstudy/api/study-workspace')\n if (!area.ok) throw new Error(`study area unavailable (HTTP ${area.status})`)\n const { path } = await area.json() as { path: string }\n const workspace = await ctx.workspaces.create({ path })\n // 0.1.3 moved the session mint from workspaces.connectWorkspace to\n // sessions.create; feature-detect so either host generation works.\n const sessionId = ctx.workspaces.connectWorkspace !== undefined\n ? await ctx.workspaces.connectWorkspace(workspace.workspaceId)\n : await ctx.sessions.create({ workspaceId: workspace.workspaceId })\n const actx = ctx.sessions.scope(sessionId)\n const face = actx === undefined ? undefined : ctx.sessions.sessionOf(actx)\n if (face === undefined) throw new Error('study session is not addressable yet')\n const result = await face.prompt([{ type: 'text', text: tr('prompt.kickoff') }], 'queue')\n if (!result.ok) throw new Error(`kickoff prompt rejected: ${result.error.code}: ${result.error.message}`)\n ctx.sessions.open(sessionId)\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err))\n setBusy(false)\n }\n })()\n }\n return createElement('span', { className: 'lks-root', style: { display: 'inline-flex', alignItems: 'center', gap: '8px' } },\n createElement('button', {\n className: 'lks-pill on',\n title: tr('start.title'),\n disabled: busy,\n onClick: start,\n },\n busy\n ? createElement(IconLoadingOutline16, { className: 'lks-spin' })\n : createElement(IconThinkOutline16, null),\n busy ? tr('start.busy') : data?.active === true ? tr('start.enter') : tr('start.go')),\n error !== null ? createElement('span', { className: 'lks-propcard-err', style: { marginTop: 0 } }, error) : null,\n )\n}\n","/**\n * The plugin's settings page: one `settings.section` entry riding the host's\n * settings shell. Teaching style and study mode write through the same host\n * routes the study tab uses (POST /api/mode, /api/active — the latter syncs\n * the tool registry before responding); stats and the state-file path are\n * read-only projections of the shared poll store. Pure display + the store's\n * existing write actions; no new routes, no new requests beyond the poll.\n * @module dsh-plugin-lookatstudy/client/settings\n */\n\nimport { createElement, useState } from 'react'\nimport type { ReactNode } from 'react'\nimport { useStudy } from './data.ts'\nimport { tr } from './locale.ts'\nimport { ActionError } from './views.tsx'\n\n/** The three souls in pill order (same shape as the study tab's pills). */\nconst MODES: ReadonlyArray<{ id: 'direct' | 'guide' | 'practice'; labelKey: string; hintKey: string }> = [\n { id: 'direct', labelKey: 'soul.direct', hintKey: 'soul.direct.hint' },\n { id: 'guide', labelKey: 'soul.guide', hintKey: 'soul.guide.hint' },\n { id: 'practice', labelKey: 'soul.practice', hintKey: 'soul.practice.hint' },\n]\n\n/**\n * The settings section component. Props from the settings shell (`close`) are\n * unused — every control stays on the page.\n */\nexport function StudySettingsSection(): ReactNode {\n const { data, setMode, activate } = useStudy()\n const [error, setError] = useState<string | null>(null)\n const fire = (action: Promise<void>): void => {\n action.then(() => { setError(null) }, (err: unknown) => { setError(err instanceof Error ? err.message : String(err)) })\n }\n const progress = data?.progress\n return createElement('div', { className: 'lks-root lks-settings' },\n createElement('section', { className: 'lks-set-row' },\n createElement('h3', null, tr('settings.mode')),\n createElement('p', { className: 'lks-set-hint' }, tr('settings.mode.hint')),\n createElement('div', { className: 'lks-pills' },\n ...MODES.map(mode => createElement('button', {\n key: mode.id,\n className: `lks-pill${data?.mode === mode.id ? ' on' : ''}`,\n title: tr(mode.hintKey),\n onClick: () => { fire(setMode(mode.id)) },\n }, tr(mode.labelKey))),\n ),\n ),\n createElement('section', { className: 'lks-set-row' },\n createElement('h3', null, tr('settings.studyMode')),\n createElement('p', { className: 'lks-set-hint' }, tr('settings.studyMode.hint')),\n createElement('div', null,\n createElement('button', {\n className: `lks-btn ${data?.active === true ? 'ghost' : 'primary'}`,\n onClick: () => { if (data !== null) fire(activate(!data.active)) },\n }, data?.active === true ? tr('settings.turnOff') : tr('settings.turnOn')),\n createElement('span', { className: 'lks-set-state' }, data?.active === true ? tr('settings.on') : tr('settings.off')),\n ),\n ),\n progress === undefined ? null : createElement('section', { className: 'lks-set-row' },\n createElement('h3', null, tr('settings.stats')),\n createElement('ul', { className: 'lks-set-stats' },\n createElement('li', null, tr('settings.stats.courses', { count: data?.courses.length ?? 0 })),\n createElement('li', null, tr('settings.stats.xp', { xp: progress.totalXp, level: progress.level, pct: progress.levelPct })),\n createElement('li', null, tr('settings.stats.today', { xp: progress.todayXp, goal: progress.dailyGoal })),\n createElement('li', null, tr('settings.stats.streak', { days: progress.streak, best: progress.longestStreak, freeze: progress.freezeCount })),\n ),\n ),\n createElement('section', { className: 'lks-set-row' },\n createElement('h3', null, tr('settings.about')),\n createElement('p', { className: 'lks-set-hint' }, tr('settings.about.hint')),\n data?.version ? createElement('a',\n { href: `https://github.com/Kaiji-Z/dsh-plugin-lookatstudy/releases/tag/v${data.version}`, target: '_blank', rel: 'noreferrer' },\n `v${data.version}`) : null,\n ),\n createElement('section', { className: 'lks-set-row' },\n createElement('h3', null, tr('settings.stateFile')),\n createElement('p', { className: 'lks-set-hint' }, tr('settings.stateFile.hint')),\n data === null ? null : createElement('code', { className: 'lks-set-path' }, data.statePath),\n ),\n createElement(ActionError, { error }),\n )\n}\n","/**\n * The composer dock status pill: one `conversation.composer.dock` entry (the\n * ambient readout band under the composer, next to the token stats) showing\n * due reviews / streak / level while the study surface is ACTIVE — dormant\n * installs render nothing at all, the same visibility the tool registry has.\n * Data rides the shared 3 s poll store (no extra requests). Display-only:\n * conversation-view tab switching is ui-conversation-private (the starter\n * button's limitation), so the tooltip points at the Study tab instead.\n * @module dsh-plugin-lookatstudy/client/dock\n */\n\nimport { createElement } from 'react'\nimport { IconBoltFill16, IconFlameFill16 } from './icons.tsx'\nimport type { ReactNode } from 'react'\nimport { useStudy } from './data.ts'\nimport { tr } from './locale.ts'\n\n/** Pure projection of the pill's segments (testable without React). `muted` marks zero-value segments — an empty state must not wear a warning color. */\nexport function dockSegments(progress: { dueCount: number; streak: number; level: number }): ReadonlyArray<{ key: string; text: string; muted: boolean }> {\n return [\n { key: 'due', text: tr('dock.due', { count: progress.dueCount }), muted: progress.dueCount === 0 },\n { key: 'streak', text: tr('dock.streak', { days: progress.streak }), muted: progress.streak === 0 },\n { key: 'lv', text: tr('dock.lv', { level: progress.level }), muted: false },\n ]\n}\n\n/** The dock entry component; renders nothing while data is loading or dormant. */\nexport function StudyDockPill(): ReactNode {\n const { data } = useStudy()\n if (data === null || data.active !== true) return null\n const segments = dockSegments({ dueCount: data.dueCount, streak: data.progress.streak, level: data.progress.level })\n return createElement('span', {\n className: 'lks-root lks-dockpill',\n title: tr('dock.title', { due: data.dueCount, streak: data.progress.streak, level: data.progress.level }),\n },\n ...segments.map(s => createElement('span', { key: s.key, className: `lks-dockseg lks-dock-${s.key}${s.muted ? ' lks-muted' : ''}` },\n s.key === 'due' ? createElement(IconBoltFill16, { size: 11 }) : s.key === 'streak' ? createElement(IconFlameFill16, { size: 11 }) : null, s.text)),\n )\n}\n","/**\n * Keyed `tool.call.toolview` entries: learning-aware cards for the\n * conversation tab's tool rows (our own study tab renders its own chips, but\n * learning also happens in the plain 对话 view). One generic card body over\n * the result's `meta` (the tool's presentationMeta lines — replay-safe by\n * construction) with a per-tool header; `study_record_answer` additionally\n * parses its args for a live ✓/✗ tone while the call is still running.\n * @module dsh-plugin-lookatstudy/client/toolviews\n */\n\nimport { createElement } from 'react'\nimport type { ReactNode } from 'react'\nimport { tr } from './locale.ts'\n\n/** Structural slice of ToolCallBlock the views consume. */\nexport interface ToolBlockFace {\n kind?: string\n name?: string\n argsRaw?: string\n content?: ReadonlyArray<{ type: string; text?: string }>\n isError?: boolean\n meta?: unknown\n}\n\n/** Props slice the slot passes (ToolCallOwnerProps). */\nexport interface ToolViewPropsFace {\n toolName: string\n block: ToolBlockFace\n}\n\n/** Header glyph per tool (missing tools simply use the generic row). */\nconst TOOL_GLYPHS: Record<string, string> = {\n study_record_answer: '✍️',\n study_lesson: '📘',\n study_due_reviews: '🔁',\n study_exam_result: '🎯',\n}\n\n/** The ✓/✗ tone from record_answer's args; null for other shapes. Pure. */\nexport function answerTone(argsRaw: string | undefined): { correct: boolean; concept: string } | null {\n if (argsRaw === undefined) return null\n try {\n const args = JSON.parse(argsRaw) as { concept?: unknown; correct?: unknown }\n return {\n correct: args.correct === true,\n concept: typeof args.concept === 'string' && args.concept !== '' ? args.concept : tr('chip.unattributed'),\n }\n } catch {\n return null\n }\n}\n\n/** Card lines: the result's meta (string[]) when present, else its text content. Pure. */\nexport function metaLines(block: ToolBlockFace): string[] {\n if (Array.isArray(block.meta)) {\n const lines = (block.meta as unknown[]).filter((x): x is string => typeof x === 'string')\n if (lines.length > 0) return lines\n }\n return (block.content ?? [])\n .filter(b => b.type === 'text' && typeof b.text === 'string')\n .map(b => (b.text as string).split('\\n'))\n .flat()\n .filter(l => l.trim() !== '')\n}\n\n/** Shared card body: header + lines; error results keep their text visible. */\nfunction studyToolCard(toolName: string, block: ToolBlockFace, extra?: ReactNode): ReactNode {\n const lines = metaLines(block)\n const glyph = TOOL_GLYPHS[toolName] ?? '🔧'\n return createElement('div', { className: `lks-tv${block.isError === true ? ' err' : ''}` },\n extra ?? null,\n createElement('span', { className: 'lks-tv-head' }, `${glyph} ${toolName}`),\n lines.length === 0\n ? null\n : createElement('div', { className: 'lks-tv-lines' },\n ...lines.map((line, i) => createElement('div', { key: String(i), className: 'lks-tv-line' }, line)),\n ),\n )\n}\n\n/** study_record_answer: live ✓/✗ tone from args + the graded line from meta. */\nexport function StudyAnswerView({ toolName, block }: ToolViewPropsFace): ReactNode {\n const tone = answerTone(block.argsRaw)\n const chip = tone === null ? null : createElement('span', { className: `lks-tv-chip ${tone.correct ? 'ok' : 'bad'}` },\n tr(tone.correct ? 'chip.correct' : 'chip.wrong', { concept: tone.concept }))\n return studyToolCard(toolName, block, chip)\n}\n\n/** Generic meta-line card for the read-type study tools. */\nexport function StudyLessonView({ toolName, block }: ToolViewPropsFace): ReactNode {\n return studyToolCard(toolName, block)\n}\n\n/** study_due_reviews list card. */\nexport function StudyDueView({ toolName, block }: ToolViewPropsFace): ReactNode {\n return studyToolCard(toolName, block)\n}\n\n/** Stars from the exam card's presentationMeta line (`N★`); null when absent. Pure. */\nexport function examStars(block: ToolBlockFace): { stars: number; best: number } | null {\n const lines = metaLines(block)\n for (const line of lines) {\n const m = /^([0-3])★\\s*\\(?(?:best\\s*([0-3])★)?/.exec(line.trim()) ?? /^(?:本次\\s*)?([0-3])★/.exec(line.trim())\n if (m !== null) return { stars: Number(m[1]), best: Number(m[2] ?? m[1]) }\n }\n return null\n}\n\n/** study_exam_result star card — and the failure moment finally gets its line. */\nexport function StudyExamView({ toolName, block }: ToolViewPropsFace): ReactNode {\n const r = examStars(block)\n const stars = r === null\n ? null\n : createElement('span', { className: 'lks-tv-stars' },\n [0, 1, 2].map(i => createElement('span', { key: i, className: i < r.stars ? 'full' : 'dim' }, '★')),\n createElement('span', { className: 'lks-tv-stars-label' }, tr('tv.exam.stars', { n: r.stars, best: r.best })))\n const fail = r !== null && r.stars === 0 ? createElement('div', { className: 'lks-tv-failnote' }, tr('tv.exam.fail')) : null\n return studyToolCard(toolName, block, createElement('span', null, stars, fail))\n}\n","/**\n * Browser half of dsh-plugin-lookatstudy (`dsh.client`): ONE conversation\n * view tab — 「学习」— carrying the whole plugin. Inside the tab it is a\n * simplified LookatStudy in three columns (课程 | 老师 | 黑板); nothing\n * outside the tab modifies dsh chrome. Live study state comes from the shared\n * poll store over the host plugin's `/lookatstudy/api/*` routes; the tutor\n * column additionally reads the session snapshot through the framework\n * standard kit and sends messages via the same reverse channel as the\n * standalone workbench page.\n * @module dsh-plugin-lookatstudy/client\n */\n\nimport type { ReactNode } from 'react'\nimport type { ClientContext } from './faces.ts'\nimport { ensureStudyStyles } from './styles.ts'\nimport { studyView } from './views.tsx'\nimport { studyStartButton } from './starter.tsx'\nimport { StudySettingsSection } from './settings.tsx'\nimport { StudyDockPill } from './dock.tsx'\nimport { StudyAnswerView, StudyDueView, StudyExamView, StudyLessonView, type ToolViewPropsFace } from './toolviews.tsx'\nimport { registerStudyLocale, setStudyTranslator, studyTranslator, tr, type LocaleServiceFace } from './locale.ts'\n\n/** The toolview components' expected props (structural slice of ToolCallViewProps). */\ntype ToolViewProps = ToolViewPropsFace\n\nexport { studyView, transcriptRows } from './views.tsx'\nexport type { ChatRow } from './views.tsx'\n\nexport const inject = ['slots', 'workspaces', 'sessions', 'locale']\n\n/**\n * Register the study surfaces: styles inject once; the single\n * `conversation.view` tab carries the whole plugin; the hero starter button\n * (`conversation.input.left`, blank sessions only) automates the onboarding —\n * study workspace + session + kickoff prompt in one click. The `lookatstudy`\n * locale namespace rides the framework locale service (zh/en) and the\n * client-wide translator is installed before any component renders; both\n * slot entries declare the namespace so the framework synthesizes their `t`\n * seat and follows locale switches for the labels.\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n ensureStudyStyles()\n const localeSvc = (ctx as { locale?: LocaleServiceFace }).locale\n ctx.effect(() => registerStudyLocale(localeSvc), 'lookatstudy.locale()')\n setStudyTranslator(studyTranslator(localeSvc))\n ctx.slots.inject('conversation.view', () => ctx.slots.register(\n { name: 'conversation.view', id: 'lookatstudy-study', order: 15, label: () => tr('tab.label'), locale: 'lookatstudy' },\n studyView(ctx),\n ))\n ctx.slots.inject('conversation.input.left', () => ctx.slots.register(\n { name: 'conversation.input.left', id: 'lookatstudy-start', order: 10, locale: 'lookatstudy' },\n studyStartButton(ctx),\n ))\n // One settings page in the host settings shell: teaching style + study mode\n // through the same host routes the tab uses, plus read-only stats and the\n // state-file path.\n ctx.slots.inject('settings.section', () => ctx.slots.register(\n { name: 'settings.section', id: 'lookatstudy', order: 30, label: () => tr('settings.nav'), locale: 'lookatstudy' },\n StudySettingsSection,\n ))\n // The ambient study-status pill under the composer (due/streak/level); the\n // component itself renders nothing while dormant or loading.\n ctx.slots.inject('conversation.composer.dock', () => ctx.slots.register(\n { name: 'conversation.composer.dock', id: 'lookatstudy-status', order: 10, locale: 'lookatstudy' },\n StudyDockPill,\n ))\n // Learning-aware cards for the conversation tab's tool rows (keyed by wire\n // tool name; unregistered study tools keep the generic row).\n const toolviews: ReadonlyArray<[string, (props: ToolViewProps) => ReactNode]> = [\n ['study_record_answer', StudyAnswerView],\n ['study_lesson', StudyLessonView],\n ['study_due_reviews', StudyDueView],\n ['study_exam_result', StudyExamView],\n ]\n for (const [tool, component] of toolviews) {\n ctx.slots.inject('tool.call.toolview', () => ctx.slots.register(\n { name: 'tool.call.toolview', key: tool, locale: 'lookatstudy' },\n component,\n ))\n }\n}\n"],"mappings":"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"}