dsh-ide-git 0.13.3 → 0.13.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/dsh.plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-external/dsh-ide-git",
3
- "version": "0.13.3",
3
+ "version": "0.13.4",
4
4
  "main": "./src/index.js",
5
5
  "description": "IDE 级 Git 操作面板:分支树 + 提交图谱 + 变更/暂存/提交 + 提交详情。装了 dsh-better-sidebar 时挂成它的原生 tab(右侧栏 + 底部工作台);没装时直接挂 DSH 原生右侧栏,单独安装即可用。JetBrains 风格 Git 工具窗口 for DeepSeek Harness.",
6
6
  "engines": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-ide-git",
3
- "version": "0.13.3",
3
+ "version": "0.13.4",
4
4
  "description": "DSH plugin: an IDE-grade Git tool window as a native dsh-better-sidebar tab — branch tree, commit graph, changes, commit details, JetBrains-style actions, in the right sidebar and the bottom panel. | DSH 插件:IDE 级 Git 工具窗口,以 dsh-better-sidebar 原生 Tab 挂载——分支树 / 提交图谱 / 变更与提交详情 / JetBrains 风格操作,右侧栏与底部面板双布局自适应。",
5
5
  "type": "module",
6
6
  "repository": {
package/src/client.js CHANGED
@@ -154,6 +154,8 @@ window.__ModuleLoader__.load({
154
154
  'action.details': '提交详情',
155
155
  'menu.sendToChat': '发送到对话',
156
156
  'menu.sendFilePathToChat': '发送文件路径到对话',
157
+ 'send.commitText': 'git 提交 {hash}「{subject}」(仓库 {repo})',
158
+ 'send.branchText': 'git 分支 {name}(仓库 {repo})',
157
159
  'history.empty': '这个仓库还没有提交',
158
160
  'history.loadMore': '加载更多',
159
161
  'history.filter': '文本或哈希',
@@ -354,6 +356,8 @@ window.__ModuleLoader__.load({
354
356
  'action.details': 'Commit details',
355
357
  'menu.sendToChat': 'Send to chat',
356
358
  'menu.sendFilePathToChat': 'Send file path to chat',
359
+ 'send.commitText': 'git commit {hash} "{subject}" (repo {repo})',
360
+ 'send.branchText': 'git branch {name} (repo {repo})',
357
361
  'history.empty': 'This repository has no commits yet',
358
362
  'history.loadMore': 'Load more',
359
363
  'history.filter': 'Text or hash',
@@ -562,6 +566,8 @@ window.__ModuleLoader__.load({
562
566
  'action.details': '提交詳情',
563
567
  'menu.sendToChat': '傳送到對話',
564
568
  'menu.sendFilePathToChat': '傳送檔案路徑至對話',
569
+ 'send.commitText': 'git 提交 {hash}「{subject}」(存放庫 {repo})',
570
+ 'send.branchText': 'git 分支 {name}(存放庫 {repo})',
565
571
  'history.empty': '呢個存放庫仲未有提交',
566
572
  'history.loadMore': '載入更多',
567
573
  'history.filter': '文字或雜湊',
@@ -762,6 +768,8 @@ window.__ModuleLoader__.load({
762
768
  'action.details': '提交詳情',
763
769
  'menu.sendToChat': '傳送至對話',
764
770
  'menu.sendFilePathToChat': '傳送檔案路徑至對話',
771
+ 'send.commitText': 'git 提交 {hash}「{subject}」(版本庫 {repo})',
772
+ 'send.branchText': 'git 分支 {name}(版本庫 {repo})',
765
773
  'history.empty': '這個版本庫還沒有提交',
766
774
  'history.loadMore': '載入更多',
767
775
  'history.filter': '文字或雜湊',
@@ -962,6 +970,8 @@ window.__ModuleLoader__.load({
962
970
  'action.details': '提交詳情',
963
971
  'menu.sendToChat': '傳送至對話',
964
972
  'menu.sendFilePathToChat': '傳送檔案路徑至對話',
973
+ 'send.commitText': 'git 提交 {hash}「{subject}」(存放庫 {repo})',
974
+ 'send.branchText': 'git 分支 {name}(存放庫 {repo})',
965
975
  'history.empty': '呢個存放庫仲未有提交',
966
976
  'history.loadMore': '載入更多',
967
977
  'history.filter': '文字或雜湊',
@@ -1162,6 +1172,8 @@ window.__ModuleLoader__.load({
1162
1172
  'action.details': 'コミットの詳細',
1163
1173
  'menu.sendToChat': 'チャットへ送る',
1164
1174
  'menu.sendFilePathToChat': 'ファイルパスをチャットへ送る',
1175
+ 'send.commitText': 'git コミット {hash}「{subject}」(リポジトリ {repo})',
1176
+ 'send.branchText': 'git ブランチ {name}(リポジトリ {repo})',
1165
1177
  'history.empty': 'このリポジトリにはまだコミットがありません',
1166
1178
  'history.loadMore': 'さらに読み込む',
1167
1179
  'history.filter': 'テキストまたはハッシュ',
@@ -1362,6 +1374,8 @@ window.__ModuleLoader__.load({
1362
1374
  'action.details': '커밋 상세',
1363
1375
  'menu.sendToChat': '대화로 보내기',
1364
1376
  'menu.sendFilePathToChat': '파일 경로를 대화로 보내기',
1377
+ 'send.commitText': 'git 커밋 {hash} "{subject}" (저장소 {repo})',
1378
+ 'send.branchText': 'git 브랜치 {name} (저장소 {repo})',
1365
1379
  'history.empty': '이 저장소에는 아직 커밋이 없습니다',
1366
1380
  'history.loadMore': '더 불러오기',
1367
1381
  'history.filter': '텍스트 또는 해시',
@@ -1562,6 +1576,8 @@ window.__ModuleLoader__.load({
1562
1576
  'action.details': 'Commit-Details',
1563
1577
  'menu.sendToChat': 'Im Chat senden',
1564
1578
  'menu.sendFilePathToChat': 'Dateipfad im Chat senden',
1579
+ 'send.commitText': 'git-Commit {hash} "{subject}" (Repository {repo})',
1580
+ 'send.branchText': 'git-Branch {name} (Repository {repo})',
1565
1581
  'history.empty': 'Dieses Repository hat noch keine Commits',
1566
1582
  'history.loadMore': 'Mehr laden',
1567
1583
  'history.filter': 'Text oder Hash',
@@ -1762,6 +1778,8 @@ window.__ModuleLoader__.load({
1762
1778
  'action.details': 'Détails du commit',
1763
1779
  'menu.sendToChat': 'Envoyer dans la conversation',
1764
1780
  'menu.sendFilePathToChat': 'Envoyer le chemin du fichier dans la conversation',
1781
+ 'send.commitText': 'commit git {hash} « {subject} » (dépôt {repo})',
1782
+ 'send.branchText': 'branche git {name} (dépôt {repo})',
1765
1783
  'history.empty': 'Ce dépôt n\'a pas encore de commit',
1766
1784
  'history.loadMore': 'Charger plus',
1767
1785
  'history.filter': 'Texte ou empreinte',
@@ -1962,6 +1980,8 @@ window.__ModuleLoader__.load({
1962
1980
  'action.details': 'Сведения о коммите',
1963
1981
  'menu.sendToChat': 'Отправить в чат',
1964
1982
  'menu.sendFilePathToChat': 'Отправить путь к файлу в чат',
1983
+ 'send.commitText': 'git-коммит {hash} «{subject}» (репозиторий {repo})',
1984
+ 'send.branchText': 'git-ветка {name} (репозиторий {repo})',
1965
1985
  'history.empty': 'В этом репозитории ещё нет коммитов',
1966
1986
  'history.loadMore': 'Загрузить ещё',
1967
1987
  'history.filter': 'Текст или хеш',
@@ -2162,6 +2182,8 @@ window.__ModuleLoader__.load({
2162
2182
  'action.details': 'Detalhes do commit',
2163
2183
  'menu.sendToChat': 'Enviar para a conversa',
2164
2184
  'menu.sendFilePathToChat': 'Enviar caminho do arquivo para a conversa',
2185
+ 'send.commitText': 'commit git {hash} "{subject}" (repositório {repo})',
2186
+ 'send.branchText': 'branch git {name} (repositório {repo})',
2165
2187
  'history.empty': 'Este repositório ainda não tem commits',
2166
2188
  'history.loadMore': 'Carregar mais',
2167
2189
  'history.filter': 'Texto ou hash',
@@ -2362,6 +2384,8 @@ window.__ModuleLoader__.load({
2362
2384
  'action.details': 'Dettagli del commit',
2363
2385
  'menu.sendToChat': 'Invia alla conversazione',
2364
2386
  'menu.sendFilePathToChat': 'Invia il percorso del file alla conversazione',
2387
+ 'send.commitText': 'commit git {hash} "{subject}" (repository {repo})',
2388
+ 'send.branchText': 'branch git {name} (repository {repo})',
2365
2389
  'history.empty': 'Questo repository non ha ancora commit',
2366
2390
  'history.loadMore': 'Carica altro',
2367
2391
  'history.filter': 'Testo o hash',
@@ -2562,6 +2586,8 @@ window.__ModuleLoader__.load({
2562
2586
  'action.details': 'Commit-details',
2563
2587
  'menu.sendToChat': 'Naar het gesprek verzenden',
2564
2588
  'menu.sendFilePathToChat': 'Bestandspad naar het gesprek verzenden',
2589
+ 'send.commitText': 'git-commit {hash} "{subject}" (repository {repo})',
2590
+ 'send.branchText': 'git-branch {name} (repository {repo})',
2565
2591
  'history.empty': 'Deze repository heeft nog geen commits',
2566
2592
  'history.loadMore': 'Meer laden',
2567
2593
  'history.filter': 'Tekst of hash',
@@ -2762,6 +2788,8 @@ window.__ModuleLoader__.load({
2762
2788
  'action.details': 'Szczegóły commita',
2763
2789
  'menu.sendToChat': 'Wyślij do rozmowy',
2764
2790
  'menu.sendFilePathToChat': 'Wyślij ścieżkę pliku do rozmowy',
2791
+ 'send.commitText': 'commit git {hash} „{subject}" (repozytorium {repo})',
2792
+ 'send.branchText': 'gałąź git {name} (repozytorium {repo})',
2765
2793
  'history.empty': 'To repozytorium nie ma jeszcze commitów',
2766
2794
  'history.loadMore': 'Wczytaj więcej',
2767
2795
  'history.filter': 'Tekst lub hash',
@@ -2962,6 +2990,8 @@ window.__ModuleLoader__.load({
2962
2990
  'action.details': 'Commit-detaljer',
2963
2991
  'menu.sendToChat': 'Skicka till samtalet',
2964
2992
  'menu.sendFilePathToChat': 'Skicka filsökvägen till samtalet',
2993
+ 'send.commitText': 'git-commit {hash} ”{subject}” (arkiv {repo})',
2994
+ 'send.branchText': 'git-gren {name} (arkiv {repo})',
2965
2995
  'history.empty': 'Det här arkivet har inga commits ännu',
2966
2996
  'history.loadMore': 'Ladda mer',
2967
2997
  'history.filter': 'Text eller hash',
@@ -3162,6 +3192,8 @@ window.__ModuleLoader__.load({
3162
3192
  'action.details': 'Commit ayrıntıları',
3163
3193
  'menu.sendToChat': 'Sohbete gönder',
3164
3194
  'menu.sendFilePathToChat': 'Dosya yolunu sohbete gönder',
3195
+ 'send.commitText': 'git commit {hash} "{subject}" (depo {repo})',
3196
+ 'send.branchText': 'git dalı {name} (depo {repo})',
3165
3197
  'history.empty': 'Bu depoda henüz commit yok',
3166
3198
  'history.loadMore': 'Daha fazla yükle',
3167
3199
  'history.filter': 'Metin veya hash',
@@ -3362,6 +3394,8 @@ window.__ModuleLoader__.load({
3362
3394
  'action.details': 'Detail commit',
3363
3395
  'menu.sendToChat': 'Kirim ke obrolan',
3364
3396
  'menu.sendFilePathToChat': 'Kirim jalur berkas ke obrolan',
3397
+ 'send.commitText': 'commit git {hash} "{subject}" (repositori {repo})',
3398
+ 'send.branchText': 'cabang git {name} (repositori {repo})',
3365
3399
  'history.empty': 'Repositori ini belum punya commit',
3366
3400
  'history.loadMore': 'Muat lebih banyak',
3367
3401
  'history.filter': 'Teks atau hash',
@@ -3562,6 +3596,8 @@ window.__ModuleLoader__.load({
3562
3596
  'action.details': 'Chi tiết commit',
3563
3597
  'menu.sendToChat': 'Gửi vào hội thoại',
3564
3598
  'menu.sendFilePathToChat': 'Gửi đường dẫn tệp vào hội thoại',
3599
+ 'send.commitText': 'git commit {hash} "{subject}" (kho {repo})',
3600
+ 'send.branchText': 'nhánh git {name} (kho {repo})',
3565
3601
  'history.empty': 'Kho này chưa có commit nào',
3566
3602
  'history.loadMore': 'Tải thêm',
3567
3603
  'history.filter': 'Văn bản hoặc hash',
@@ -3762,6 +3798,8 @@ window.__ModuleLoader__.load({
3762
3798
  'action.details': 'تفاصيل الالتزام',
3763
3799
  'menu.sendToChat': 'إرسال إلى المحادثة',
3764
3800
  'menu.sendFilePathToChat': 'إرسال مسار الملف إلى المحادثة',
3801
+ 'send.commitText': 'التزام git {hash} "{subject}" (المستودع {repo})',
3802
+ 'send.branchText': 'فرع git {name} (المستودع {repo})',
3765
3803
  'history.empty': 'لا توجد التزامات في هذا المستودع بعد',
3766
3804
  'history.loadMore': 'تحميل المزيد',
3767
3805
  'history.filter': 'نص أو تجزئة',
@@ -3962,6 +4000,8 @@ window.__ModuleLoader__.load({
3962
4000
  'action.details': 'कमिट विवरण',
3963
4001
  'menu.sendToChat': 'बातचीत में भेजें',
3964
4002
  'menu.sendFilePathToChat': 'फ़ाइल पथ बातचीत में भेजें',
4003
+ 'send.commitText': 'git कमिट {hash} "{subject}" (रिपॉज़िटरी {repo})',
4004
+ 'send.branchText': 'git ब्रांच {name} (रिपॉज़िटरी {repo})',
3965
4005
  'history.empty': 'इस रिपॉज़िटरी में अभी कोई कमिट नहीं है',
3966
4006
  'history.loadMore': 'और लोड करें',
3967
4007
  'history.filter': 'टेक्स्ट या हैश',
@@ -4162,6 +4202,8 @@ window.__ModuleLoader__.load({
4162
4202
  'action.details': 'รายละเอียดคอมมิต',
4163
4203
  'menu.sendToChat': 'ส่งไปยังบทสนทนา',
4164
4204
  'menu.sendFilePathToChat': 'ส่งพาธไฟล์ไปยังบทสนทนา',
4205
+ 'send.commitText': 'git คอมมิต {hash} "{subject}" (รีโพซิทอรี {repo})',
4206
+ 'send.branchText': 'git บรานช์ {name} (รีโพซิทอรี {repo})',
4165
4207
  'history.empty': 'รีโพซิทอรีนี้ยังไม่มีคอมมิต',
4166
4208
  'history.loadMore': 'โหลดเพิ่ม',
4167
4209
  'history.filter': 'ข้อความหรือแฮช',
@@ -7610,6 +7652,21 @@ window.__ModuleLoader__.load({
7610
7652
  })
7611
7653
  }, [sendToComposer])
7612
7654
 
7655
+ /* Self-describing text payloads for the commit/branch sends (v0.13.3 user
7656
+ feedback): a bare short hash or branch name is noise out of context —
7657
+ the text must say WHAT it is and WHERE from. The wording rides the
7658
+ fill() templates send.commitText / send.branchText; `repo` is the repo
7659
+ root's basename. An unknown root degrades to a neutral dash — fill()
7660
+ leaves unknown keys verbatim, so the callers must never let an
7661
+ undefined repo reach the template. The file @-chip is already
7662
+ self-describing and stays untouched. */
7663
+ const repoLabel = repoRoot === null ? '' : baseName(repoRoot)
7664
+ const sendGitSummaryToChat = useCallback((key, values) => {
7665
+ const repo = values.repo === undefined || values.repo === '' ? '—' : values.repo
7666
+ const text = fill(t(key), Object.assign({}, values, { repo: repo }))
7667
+ sendToComposer({ text: text, fallback: text })
7668
+ }, [t, sendToComposer])
7669
+
7613
7670
  const branchMenu = useCallback((event, entry) => {
7614
7671
  const current = branches === null ? '' : branches.branch
7615
7672
  const isLocal = entry.remote !== true && entry.tag !== true
@@ -7619,7 +7676,7 @@ window.__ModuleLoader__.load({
7619
7676
  isLocal ? { id: 'rebase', icon: 'compare', tone: 'violet', label: t('action.rebaseCurrentOnto'), disabled: entry.head === true || blocked, reason: blocked ? t('operation.hint') : reason, run: () => { void run('rebase', { onto: entry.name }) } } : null,
7620
7677
  isLocal ? { id: 'merge', icon: 'compare', tone: 'accent', label: t('action.mergeIntoCurrent'), disabled: entry.head === true || blocked, reason: blocked ? t('operation.hint') : reason, run: () => { void run('merge', { branch: entry.name }) } } : null,
7621
7678
  { id: 'compare', icon: 'filter', tone: 'violet', label: t('action.compare'), disabled: entry.head === true || current === '', reason: reason, run: () => { void compareWith(current, entry.name) } },
7622
- { id: 'send', icon: 'send', tone: 'accent', label: t('menu.sendToChat'), run: () => sendToComposer({ text: entry.name, fallback: entry.name }) },
7679
+ { id: 'send', icon: 'send', tone: 'accent', label: t('menu.sendToChat'), run: () => sendGitSummaryToChat('send.branchText', { name: entry.name, repo: repoLabel }) },
7623
7680
  null,
7624
7681
  { id: 'favorite', icon: 'star', tone: 'warn', label: t('action.favorite'), active: favorites.indexOf(entry.name) >= 0, run: () => toggleFavoriteBranch(entry.name) },
7625
7682
  { id: 'newBranch', icon: 'plus', tone: 'success', label: t('action.newBranchFrom'), run: () => setDialog({ kind: 'newBranch', from: entry.name }) },
@@ -7630,14 +7687,20 @@ window.__ModuleLoader__.load({
7630
7687
  { id: 'push', icon: 'push', tone: 'success', label: t('action.push'), disabled: blocked, reason: t('operation.hint'), run: () => setDialog({ kind: 'push' }) },
7631
7688
  ].filter((item) => item !== null)
7632
7689
  openMenuAt(event, items)
7633
- }, [branches, checkout, run, t, compareWith, toggleFavoriteBranch, openMenuAt, favorites, blocked, sendToComposer])
7690
+ }, [branches, checkout, run, t, compareWith, toggleFavoriteBranch, openMenuAt, favorites, blocked, sendGitSummaryToChat, repoLabel])
7634
7691
 
7635
7692
  const commitMenu = useCallback((event, commit) => {
7636
7693
  const shortHash = commit.hash.slice(0, 7)
7637
7694
  const items = [
7638
7695
  { id: 'details', icon: 'file', tone: 'primary', label: t('action.details'), run: () => { void selectCommit(commit) } },
7639
7696
  { id: 'copy', icon: 'tag', tone: 'secondary', label: t('action.copyHash'), run: () => { copyText(commit.hash) } },
7640
- { id: 'send', icon: 'send', tone: 'accent', label: t('menu.sendToChat'), run: () => sendToComposer({ text: shortHash, fallback: shortHash }) },
7697
+ { id: 'send', icon: 'send', tone: 'accent', label: t('menu.sendToChat'), run: () => {
7698
+ // A commit whose subject is empty (git tolerates empty messages)
7699
+ // degrades to the old bare-hash payload instead of faking one.
7700
+ const subject = typeof commit.subject === 'string' ? commit.subject.trim() : ''
7701
+ if (subject === '') { sendToComposer({ text: shortHash, fallback: shortHash }); return }
7702
+ sendGitSummaryToChat('send.commitText', { hash: shortHash, subject: subject, repo: repoLabel })
7703
+ } },
7641
7704
  null,
7642
7705
  { id: 'checkout', icon: 'checkout', tone: 'accent', label: t('action.checkout'), run: () => setDialog({ kind: 'checkoutCommit', hash: commit.hash }) },
7643
7706
  { id: 'branch', icon: 'plus', tone: 'success', label: t('action.newBranchHere'), run: () => setDialog({ kind: 'newBranch', from: commit.hash }) },
@@ -7650,7 +7713,7 @@ window.__ModuleLoader__.load({
7650
7713
  { id: 'resetHard', icon: 'trash', tone: 'danger', label: t('action.resetHard'), danger: true, disabled: blocked, reason: t('operation.hint'), run: () => setDialog({ kind: 'reset', hash: commit.hash, mode: 'hard' }) },
7651
7714
  ]
7652
7715
  openMenuAt(event, items)
7653
- }, [run, selectCommit, t, openMenuAt, blocked, sendToComposer])
7716
+ }, [run, selectCommit, t, openMenuAt, blocked, sendToComposer, sendGitSummaryToChat, repoLabel])
7654
7717
 
7655
7718
  const changeMenu = useCallback((event, item, group) => {
7656
7719
  const items = [
@@ -8695,30 +8758,48 @@ window.__ModuleLoader__.load({
8695
8758
  with the panel seat pinned to the visible height the scrollHeight
8696
8759
  stays clientHeight + that flow space — the wheel could still scroll
8697
8760
  the whole window by exactly that leftover (user report: the layout
8698
- fits, yet the page keeps scrolling). The overflow only exists AFTER
8699
- the new height has been applied, so measure() sets the visible-height
8700
- target and then, one frame later, CONVERGES: it reads the real
8701
- overflow and shrinks the seat by that amount. Guard rails keep it
8702
- stable: shrink only while overflow > 0 (measure() itself recomputes
8703
- the base on every pass, so the correction never compounds), clamp at
8704
- the same 240 floor, and the correction is remembered so the next
8705
- measure() starts from the already-corrected target. */
8761
+ fits, yet the page keeps scrolling). v0.13.3 report: content mounts
8762
+ or changes AFTER the first pass (the composer, the hero, a diff), and
8763
+ a single feedback convergence is not enough. measure() therefore
8764
+ recomputes the UNCORRECTED base (base.current) and hands off to the
8765
+ CONTROLLED CONVERGER below, which is re-run by every trigger: the
8766
+ initial mount, rAF/timeout follow-ups, the scrollport's own resize
8767
+ (ResizeObserver) and window resizes, and — new — the scrollport's
8768
+ content mutations (MutationObserver, debounced), because content
8769
+ growing later re-opens the overflow without resizing the scrollport
8770
+ itself. */
8706
8771
  const leftover = { current: 0 }
8772
+ const base = { current: 0 }
8773
+ /* The converger: up to FOUR rAF-spaced rounds. Each round reads
8774
+ scroll.scrollHeight - scroll.clientHeight; anything over 1px shrinks
8775
+ the seat by exactly that amount and OVERWRITES the leftover record
8776
+ (never adds — every corrected height derives from the fresh base, so
8777
+ repeated rounds cannot compound), clamped at the same 240 floor.
8778
+ Shrink-only: nothing here grows the seat back. A host without the
8779
+ conversation scrollport never reaches this code — measure() skips it
8780
+ all, silently, and never throws. */
8781
+ const converge = (scroll) => {
8782
+ let rounds = 0
8783
+ const step = () => {
8784
+ rounds += 1
8785
+ if (el.isConnected !== true) return
8786
+ const overflow = scroll.scrollHeight - scroll.clientHeight
8787
+ if (overflow <= 1) return
8788
+ leftover.current = overflow
8789
+ setSeatHeight(Math.max(240, base.current - overflow))
8790
+ if (rounds < 4) requestAnimationFrame(step)
8791
+ }
8792
+ requestAnimationFrame(step)
8793
+ }
8707
8794
  const measure = () => {
8708
8795
  let scroll = null
8709
8796
  try { scroll = el.closest('[data-conversation-scroll]') } catch (error) { void error }
8710
8797
  if (scroll === null || scroll === undefined) return
8711
8798
  const offset = Math.max(0, el.getBoundingClientRect().top - scroll.getBoundingClientRect().top)
8712
- const available = Math.round(scroll.clientHeight - offset - 8) - leftover.current
8713
- if (available >= 240) setSeatHeight(available)
8714
- requestAnimationFrame(() => {
8715
- if (el.isConnected !== true) return
8716
- const overflow = scroll.scrollHeight - scroll.clientHeight
8717
- if (overflow > 0) {
8718
- leftover.current = overflow
8719
- setSeatHeight(Math.max(240, available - overflow))
8720
- }
8721
- })
8799
+ base.current = Math.round(scroll.clientHeight - offset - 8)
8800
+ const corrected = base.current - leftover.current
8801
+ if (corrected >= 240) setSeatHeight(corrected)
8802
+ converge(scroll)
8722
8803
  }
8723
8804
  measure()
8724
8805
  const raf = requestAnimationFrame(() => { measure() })
@@ -8731,10 +8812,28 @@ window.__ModuleLoader__.load({
8731
8812
  observer.observe(scroll)
8732
8813
  }
8733
8814
  } catch (error) { void error }
8815
+ /* Content that mounts or changes later does not resize the scrollport,
8816
+ so the ResizeObserver stays silent while the overflow re-opens; the
8817
+ mutation watcher re-measures for it. Debounced ~120ms so a mount
8818
+ burst converges once instead of once per node. */
8819
+ let mutationObserver
8820
+ let mutationTimer = null
8821
+ try {
8822
+ const scroll = el.closest('[data-conversation-scroll]')
8823
+ if (scroll !== null && scroll !== undefined && typeof MutationObserver === 'function') {
8824
+ mutationObserver = new MutationObserver(() => {
8825
+ if (mutationTimer !== null) clearTimeout(mutationTimer)
8826
+ mutationTimer = setTimeout(() => { mutationTimer = null; measure() }, 120)
8827
+ })
8828
+ mutationObserver.observe(scroll, { childList: true, subtree: true })
8829
+ }
8830
+ } catch (error) { void error }
8734
8831
  window.addEventListener('resize', measure)
8735
8832
  return () => {
8736
8833
  cancelAnimationFrame(raf)
8737
8834
  clearTimeout(late)
8835
+ if (mutationTimer !== null) clearTimeout(mutationTimer)
8836
+ if (mutationObserver !== undefined) mutationObserver.disconnect()
8738
8837
  if (observer !== undefined) observer.disconnect()
8739
8838
  window.removeEventListener('resize', measure)
8740
8839
  }