minecodex 0.1.11 → 0.1.13

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/README.md CHANGED
@@ -1,31 +1,32 @@
1
+ <p align="center">
2
+ <img src="./assets/readme/hero.svg" width="100%" alt="MineCodex:给 Codex Desktop 增加轻量、本地优先的插件,包含模型滑条、笔记与图片库">
3
+ </p>
4
+
1
5
  # MineCodex
2
6
 
3
- MineCodex 给 Codex Desktop 增加三个轻量、本地优先的插件:
7
+ MineCodex 给 Codex Desktop 增加一组轻量、本地优先的扩展功能。所有数据均保存在本地,不经过任何第三方服务器,也不会改变 Codex 的原有使用习惯。
8
+
9
+ ## 插件列表
4
10
 
5
- - **Model Slider**:更清楚、更顺滑的模型选择窗口。
6
- - **Notes**:跨会话管理 Todo、Prompts Files。
7
- - **Images**:集中浏览生成图片、Prompt 和来源任务。
11
+ | 插件 | 说明 |
12
+ | --- | --- |
13
+ | **Model Slider** | 更清晰、更顺滑的模型切换面板:具备品牌标识、常用收藏与流畅交互 |
14
+ | **Notes** | 跨会话管理待办事项、常用提示词与文件,可随时从 Codex 工具栏快速复用 |
15
+ | **Images** | 集中浏览生成的图片、Prompt 和来源任务,轻松保存原图或快速返回原会话 |
16
+ | **Hide Upsell Banner** | 隐藏输入框上方的用量提示横幅,仅优化界面展示,不影响正常的用量统计 |
8
17
 
9
18
  ## 安装
10
19
 
11
- MineCodex v1 仅支持 macOS,需要 Node.js 22.5 或更高版本。安装时会从
12
- `/Applications/ChatGPT.app` 或 `~/Applications/ChatGPT.app` 查找 Codex Desktop;
13
- 如果两处都找不到,安装会停止并给出提示。
20
+ MineCodex 目前仅支持 macOS 系统,需要 Node.js 22.5 或更高版本。安装程序会自动扫描 `/Applications/ChatGPT.app` 或 `~/Applications/ChatGPT.app` 寻找 Codex Desktop;如果两处均未找到,安装将暂停并给出说明。
14
21
 
15
22
  ```bash
16
23
  npm install -g minecodex
17
24
  mcx install
18
25
  ```
19
26
 
20
- `mcx install` 不会关闭或启动 Codex,也不会改变当前窗口。安装完成后,终端会提示
21
- MineCodex 将在下次重启 Codex 时启用,并询问是否现在重启;默认答案是 **No**。
22
- 安装过程只有在用户明确确认,或之后主动运行 `mcx restart` 时,才会关闭并重新打开
23
- Codex。安装后,macOS 的“登录项与扩展”中会显示名为 **MineCodex** 的后台项目。
24
- 这个后台项目负责插件与本地控制台:用户退出 Codex 后,它会保持停止;用户后来从
25
- Dock 主动打开 Codex 时,这次新启动会被视为明确的启动意图,并切换为可注入的托管
26
- 实例。由于普通 Dock 启动本身没有 CDP,首次切换时 Codex 可能会短暂重开一次。
27
+ 运行 `mcx install` 不会强制关闭或启动 Codex,也不会影响当前打开的窗口。安装完成后,终端会说明更改将在下一次重启 Codex 时生效,并询问是否立即重启;默认选项为 **No**。只有在您明确确认,或后续手动运行 `mcx restart` 时,才会重新打开 Codex。安装完成后,macOS 的“登录项与扩展”中会添加名为 **MineCodex** 的后台项目。
27
28
 
28
- 安装后三个插件默认开启。打开本地控制台:
29
+ 打开本地控制台:
29
30
 
30
31
  ```bash
31
32
  mcx open
@@ -33,19 +34,22 @@ mcx open
33
34
 
34
35
  常用命令:
35
36
 
36
- ```text
37
- mcx install
38
- mcx uninstall [--purge]
39
- mcx update
40
- mcx open
41
- mcx status [--json]
42
- mcx restart
43
- ```
37
+ | 命令 | 作用 |
38
+ | --- | --- |
39
+ | `mcx install` | 安装或修复 MineCodex |
40
+ | `mcx uninstall [--purge]` | 移除扩展;默认保留个人数据,带 `--purge` 参数才会清理 |
41
+ | `mcx update` | 更新到最新的稳定版本 |
42
+ | `mcx open` | 打开 MineCodex 控制台 |
43
+ | `mcx status [--json]` | 查看安装与插件运行状态 |
44
+ | `mcx restart` | 重启 Codex 并应用插件开启/关闭状态 |
45
+
46
+ 关闭某项功能仅停用对应的扩展服务,不会删除任何个人数据;修改设置后运行 `mcx restart` 即可应用更改。
47
+
48
+ 运行 `mcx uninstall` 会移除名为 MineCodex 的后台项目,并默认保留配置设置、Notes 笔记和 Images 图片索引;只有显式加上 `--purge` 参数,才会清理 MineCodex 产生的本地配置。MineCodex 绝不会删除 `~/.codex/generated_images` 中的原始图片或 Notes 引用的本地文件。
49
+
50
+ ## 工作原理
44
51
 
45
- 关闭插件只会停用对应功能,不会删除数据;保存开关后运行 `mcx restart` 应用变更。
46
- `mcx uninstall` 会移除名为 MineCodex 的后台项目,并默认保留 MineCodex 设置、
47
- Notes 数据和 Images 索引;只有显式传入 `--purge` 才会删除 MineCodex 自有数据。
48
- MineCodex 永远不会删除 `~/.codex/generated_images` 中的原图或 Notes 引用的源文件。
52
+ MineCodex 统一管理 Codex 内的菜单入口、主题风格与界面适配。每个插件(Model Slider、Notes、Images)独立管理各自的数据与操作页面;Hide Upsell Banner 专注于界面展示的优化,不影响实际的用量计算。所有功能按需开启,关闭后即停止运行。
49
53
 
50
54
  ## 开发
51
55
 
@@ -57,9 +61,6 @@ npm run pack:check
57
61
  npm run pack:audit
58
62
  ```
59
63
 
60
- MineCodex 是唯一发布仓库。三个插件继续拥有各自的数据和页面;RuntimeHost 只负责
61
- Codex 中的入口、主题与交互适配。
64
+ ## 许可
62
65
 
63
- MineCodex 是非官方独立项目,与 OpenAI 无关联。项目自有代码以 MIT License 授权;
64
- 第三方图标、品牌和兼容资产遵循各自的权利说明,见
65
- [`features/model-slider/THIRD_PARTY_NOTICES.md`](features/model-slider/THIRD_PARTY_NOTICES.md)。
66
+ MineCodex 是非官方独立扩展项目,与 OpenAI 无关联。项目自有代码以 MIT License 授权;第三方图标、品牌和兼容资产遵循各自的权利说明,见 [`features/model-slider/THIRD_PARTY_NOTICES.md`](features/model-slider/THIRD_PARTY_NOTICES.md)。
@@ -8,6 +8,20 @@ licensed under the MIT License. Product names and marks remain the property of t
8
8
 
9
9
  The upstream license text is preserved in `vendor/cc-switch-LICENSE`.
10
10
 
11
+ ## Zhipu official favicon
12
+
13
+ `assets/providers/zhipu.svg` wraps the official Z.ai (Zhipu) favicon
14
+ downloaded from <https://www.zhipuai.cn/favicon.png> in an SVG container.
15
+ The favicon and Z.ai marks remain the property of Zhipu AI; the wrapper is
16
+ distributed under MineCodex's MIT License.
17
+
18
+ ## Simple Icons (Xiaomi)
19
+
20
+ `assets/providers/xiaomimimo.svg` uses the Xiaomi mark from
21
+ [`simple-icons/simple-icons`](https://github.com/simple-icons/simple-icons)
22
+ (`icons/xiaomi.svg`), licensed under CC0 1.0. The Xiaomi brand mark remains
23
+ the property of Xiaomi Corporation.
24
+
11
25
  ## Lucide
12
26
 
13
27
  Lucide icons distributed by MineCodex include the Model Slider UI icons, Notes action and
@@ -1 +1 @@
1
- <svg fill="currentColor" height="1em" style="flex:none;line-height:1" viewBox="0 0 152 132" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Logo</title><g transform="translate(10 58)"><path d="M64.9008 0.00138769C64.6875 -0.00400695 64.4753 0.0339904 64.2771 0.113075C64.0789 0.192159 63.8988 0.310682 63.7478 0.461454C63.5968 0.612226 63.478 0.792105 63.3985 0.990178C63.3191 1.18825 63.2808 1.40039 63.2858 1.61373C63.2858 2.04553 63.4574 2.45964 63.7627 2.76497C64.068 3.0703 64.4821 3.24183 64.9139 3.24183C65.3457 3.24183 65.7599 3.0703 66.0652 2.76497C66.3705 2.45964 66.542 2.04553 66.542 1.61373C66.5473 1.39811 66.5082 1.18371 66.4271 0.983812C66.3461 0.783917 66.2249 0.602783 66.0711 0.451629C65.9172 0.300476 65.734 0.182523 65.5327 0.105076C65.3314 0.027629 65.1163 -0.00766247 64.9008 0.00138769Z"></path><path d="M66.1689 4.55469H63.6296V15.7255H66.1689V4.55469Z"></path><path d="M38.8643 4.06641C35.3586 4.06641 33.0872 6.76065 33.0872 10.0326C33.0872 13.3045 35.3717 16.0014 38.8643 16.0014C42.3568 16.0014 44.6414 13.3072 44.6414 10.0326C44.6414 6.75802 42.3673 4.06641 38.8643 4.06641ZM38.8643 13.6932C37.0261 13.6932 35.5844 12.3408 35.5844 10.0326C35.5844 7.72437 37.0261 6.37463 38.8643 6.37463C40.7025 6.37463 42.1415 7.727 42.1415 10.0326C42.1415 12.3382 40.7025 13.6932 38.8643 13.6932Z"></path><path d="M17.7909 0.000890693C17.5765 -0.00632181 17.3629 0.0303305 17.1631 0.108601C16.9634 0.186872 16.7817 0.305111 16.6293 0.456073C16.4768 0.607034 16.3568 0.787536 16.2766 0.986515C16.1964 1.18549 16.1577 1.39876 16.1628 1.61323C16.1628 2.04503 16.3343 2.45914 16.6397 2.76447C16.945 3.0698 17.3591 3.24133 17.7909 3.24133C18.2227 3.24133 18.6368 3.0698 18.9421 2.76447C19.2475 2.45914 19.419 2.04503 19.419 1.61323C19.4241 1.39876 19.3854 1.18549 19.3052 0.986515C19.225 0.787536 19.105 0.607034 18.9525 0.456073C18.8001 0.305111 18.6184 0.186872 18.4187 0.108601C18.2189 0.0303305 18.0053 -0.00632181 17.7909 0.000890693Z"></path><path d="M11.7564 15.7252L0.359741 1.61328H3.51615L15.1124 15.7252H11.7564Z"></path><path d="M3.35861 15.7252L14.7527 1.61328H11.5963L0 15.7252H3.35861Z"></path><path d="M19.0618 4.55469H16.5225V15.7255H19.0618V4.55469Z"></path><path d="M26.5905 3.78906C24.5055 3.78906 23.0454 4.31426 21.7009 5.36464L22.6988 7.20282C23.6328 6.41651 24.8055 5.96948 26.0259 5.93448C27.7354 5.93448 28.7543 6.82993 28.7543 8.38975H26.8347C23.0139 8.38975 20.9184 10.2699 21.1442 12.8539C21.4068 15.921 24.6158 16.005 24.9808 16.005C26.5563 16.005 28.0321 15.4799 28.7543 14.5214V15.7188H31.2936V8.37662C31.2936 7.12404 30.7001 3.78906 26.5905 3.78906ZM28.7543 11.1418C28.7231 11.8658 28.4128 12.5496 27.8885 13.05C27.3642 13.5503 26.6666 13.8282 25.9419 13.8255C24.7392 13.8255 23.9304 13.2504 23.8411 12.3366C23.7518 11.4227 24.5921 10.2831 27.5174 10.2831H28.7569L28.7543 11.1418Z"></path><path d="M57.7238 4.11087C57.0499 4.09158 56.3837 4.25893 55.7989 4.59444C55.2141 4.92994 54.7334 5.42054 54.4099 6.01207C53.7954 4.64394 52.7923 4.11087 51.6868 4.11087C51.1688 4.13165 50.6626 4.2713 50.2072 4.51901C49.7519 4.76672 49.3596 5.11585 49.0608 5.5394V4.55203H46.5215V15.7255H49.0608V9.11859C49.0608 8.25464 49.0608 6.40071 50.8044 6.40071C52.5481 6.40071 52.5481 8.25465 52.5481 8.72732V15.7255H55.0139V8.72732C55.0139 8.25465 55.0139 6.40071 56.7575 6.40071C58.5011 6.40071 58.5038 8.25464 58.5038 9.11859V15.7255H61.0404V8.4017C61.0536 5.3976 59.6093 4.11087 57.7238 4.11087Z"></path><path d="M73.7449 15.9987C73.4083 15.998 73.0857 15.8638 72.8479 15.6256C72.6101 15.3873 72.4766 15.0644 72.4766 14.7278V7.165C72.4914 6.83757 72.632 6.52848 72.869 6.30203C73.1059 6.07559 73.4211 5.94922 73.7488 5.94922C74.0766 5.94922 74.3918 6.07559 74.6287 6.30203C74.8657 6.52848 75.0062 6.83757 75.0211 7.165V14.7278C75.0208 14.895 74.9875 15.0606 74.9232 15.215C74.8588 15.3693 74.7647 15.5095 74.6462 15.6276C74.5277 15.7456 74.3871 15.8391 74.2325 15.9028C74.0778 15.9665 73.9122 15.9991 73.7449 15.9987Z"></path><path d="M87.3607 15.9993C87.0234 15.9993 86.6998 15.8655 86.4611 15.6272C86.2223 15.389 86.0878 15.0657 86.0871 14.7284V4.67881L81.4654 9.45281C81.2304 9.69657 80.9081 9.83697 80.5695 9.84312C80.231 9.84928 79.9038 9.72069 79.6601 9.48563C79.4163 9.25058 79.2759 8.92832 79.2697 8.58976C79.2667 8.42211 79.2967 8.25551 79.358 8.09947C79.4194 7.94342 79.5108 7.80098 79.6272 7.68028L86.4469 0.661082C86.6229 0.478921 86.8494 0.35354 87.0973 0.301033C87.3451 0.248526 87.603 0.271291 87.8378 0.366403C88.0727 0.461516 88.2737 0.624637 88.4151 0.834827C88.5566 1.04502 88.632 1.29268 88.6317 1.54603V14.7284C88.6317 15.0655 88.4978 15.3887 88.2594 15.6271C88.021 15.8654 87.6978 15.9993 87.3607 15.9993Z"></path><path d="M80.5514 9.82621C80.3824 9.82749 80.2149 9.79518 80.0584 9.73117C79.902 9.66716 79.7599 9.57272 79.6402 9.45332L72.8337 2.4315C72.599 2.18948 72.4701 1.86414 72.4752 1.52705C72.4804 1.18996 72.6193 0.868726 72.8613 0.634023C73.1033 0.399319 73.4287 0.270369 73.7658 0.27554C74.1028 0.280711 74.4241 0.419579 74.6588 0.661595L81.4653 7.66767C81.6389 7.84735 81.7558 8.07413 81.8015 8.31977C81.8472 8.56541 81.8196 8.81906 81.7222 9.04914C81.6248 9.27922 81.4618 9.47557 81.2537 9.61374C81.0455 9.75191 80.8013 9.8258 80.5514 9.82621Z"></path><path d="M98.3029 15.9992C97.9659 15.9992 97.6426 15.8653 97.4042 15.627C97.1659 15.3886 97.032 15.0654 97.032 14.7283V7.1655C97.032 6.82842 97.1659 6.50514 97.4042 6.26679C97.6426 6.02844 97.9659 5.89453 98.3029 5.89453C98.64 5.89453 98.9633 6.02844 99.2017 6.26679C99.44 6.50514 99.5739 6.82842 99.5739 7.1655V14.7283C99.5739 15.0654 99.44 15.3886 99.2017 15.627C98.9633 15.8653 98.64 15.9992 98.3029 15.9992Z"></path><path d="M111.916 16.0004C111.579 16.0004 111.256 15.8664 111.017 15.6281C110.779 15.3897 110.645 15.0665 110.645 14.7294V4.67982L106.023 9.45382C105.788 9.69584 105.467 9.83457 105.129 9.83949C104.792 9.84442 104.466 9.71513 104.224 9.48008C103.982 9.24503 103.844 8.92346 103.839 8.58613C103.834 8.24879 103.963 7.92331 104.198 7.6813L111.005 0.662093C111.181 0.483575 111.407 0.361405 111.653 0.311007C111.899 0.260609 112.155 0.284243 112.387 0.378925C112.62 0.473608 112.819 0.635093 112.96 0.842994C113.101 1.05089 113.177 1.29589 113.179 1.54704V14.7294C113.178 15.0649 113.045 15.3866 112.809 15.6246C112.572 15.8625 112.251 15.9976 111.916 16.0004Z"></path><path d="M105.109 9.82618C104.94 9.82746 104.773 9.79516 104.616 9.73115C104.46 9.66713 104.318 9.57269 104.198 9.45329L97.3917 2.43147C97.2687 2.31326 97.1708 2.1715 97.1037 2.01463C97.0367 1.85777 97.0019 1.68901 97.0015 1.51842C97.001 1.34783 97.0349 1.1789 97.1012 1.02169C97.1674 0.864476 97.2646 0.722207 97.387 0.603357C97.5093 0.484507 97.6544 0.391509 97.8135 0.329905C97.9725 0.268302 98.1424 0.239353 98.3129 0.244785C98.4834 0.250217 98.6511 0.289918 98.8059 0.361522C98.9607 0.433126 99.0996 0.535168 99.2141 0.661566L106.023 7.66764C106.197 7.84732 106.314 8.0741 106.359 8.31974C106.405 8.56538 106.378 8.81903 106.28 9.04911C106.183 9.27919 106.02 9.47554 105.812 9.61371C105.603 9.75189 105.359 9.82577 105.109 9.82618Z"></path><path d="M92.8305 15.9997C92.4935 15.9997 92.1702 15.8658 91.9318 15.6274C91.6935 15.3891 91.5596 15.0658 91.5596 14.7287V1.54636C91.5596 1.20928 91.6935 0.886001 91.9318 0.647648C92.1702 0.409296 92.4935 0.275391 92.8305 0.275391C93.1676 0.275391 93.4909 0.409296 93.7292 0.647648C93.9676 0.886001 94.1015 1.20928 94.1015 1.54636V14.7287C94.1015 14.8956 94.0686 15.0609 94.0048 15.2151C93.9409 15.3693 93.8473 15.5094 93.7292 15.6274C93.6112 15.7454 93.4711 15.839 93.3169 15.9029C93.1627 15.9668 92.9974 15.9997 92.8305 15.9997Z"></path><path d="M123.42 15.9814C122.03 15.9865 120.663 15.6287 119.454 14.9433C118.244 14.2579 117.235 13.2687 116.525 12.0735C115.815 10.8783 115.43 9.5185 115.407 8.12863C115.384 6.73875 115.724 5.36692 116.393 4.1488C116.561 3.86356 116.833 3.65487 117.152 3.56707C117.471 3.47927 117.811 3.51928 118.101 3.67859C118.391 3.8379 118.608 4.10397 118.704 4.42026C118.801 4.73656 118.771 5.07816 118.62 5.3725C118.053 6.40664 117.836 7.59693 118.003 8.76468C118.169 9.93243 118.71 11.0147 119.544 11.8489C120.378 12.6831 121.46 13.2244 122.628 13.3914C123.795 13.5584 124.986 13.3421 126.02 12.7751C126.315 12.6125 126.663 12.5738 126.987 12.6676C127.311 12.7614 127.584 12.98 127.747 13.2753C127.909 13.5706 127.948 13.9184 127.854 14.2422C127.76 14.566 127.542 14.8393 127.246 15.0019C126.074 15.6455 124.758 15.9824 123.42 15.9814Z"></path><path d="M129.287 12.5052C129.071 12.5044 128.86 12.4484 128.672 12.3424C128.378 12.1795 128.159 11.9066 128.066 11.5833C127.972 11.26 128.009 10.9126 128.171 10.6171C128.738 9.58297 128.955 8.39268 128.788 7.22493C128.622 6.05718 128.081 4.97496 127.247 4.14073C126.413 3.30649 125.331 2.76525 124.163 2.59825C122.996 2.43125 121.805 2.64749 120.771 3.21452C120.624 3.30059 120.462 3.3564 120.293 3.37863C120.125 3.40087 119.954 3.38908 119.79 3.34397C119.626 3.29886 119.473 3.22134 119.339 3.116C119.206 3.01066 119.095 2.87964 119.013 2.73069C118.931 2.58174 118.88 2.41788 118.863 2.24882C118.845 2.07975 118.862 1.90891 118.912 1.7464C118.962 1.58389 119.044 1.43301 119.153 1.3027C119.262 1.17238 119.396 1.06527 119.547 0.987704C121.064 0.155491 122.809 -0.162266 124.522 0.0821474C126.234 0.326561 127.822 1.11995 129.045 2.34319C130.268 3.56642 131.061 5.15347 131.306 6.86604C131.55 8.5786 131.232 10.3242 130.4 11.8408C130.291 12.0411 130.13 12.2084 129.934 12.3253C129.739 12.4422 129.515 12.5043 129.287 12.5052Z"></path></g></svg>
1
+ <svg role="img" viewBox="0 0 24 24" fill="#FF6900" xmlns="http://www.w3.org/2000/svg"><title>Xiaomi</title><path d="M12 0C8.016 0 4.756.255 2.493 2.516.23 4.776 0 8.033 0 12.012c0 3.98.23 7.235 2.494 9.497C4.757 23.77 8.017 24 12 24c3.983 0 7.243-.23 9.506-2.491C23.77 19.247 24 15.99 24 12.012c0-3.984-.233-7.243-2.502-9.504C19.234.252 15.978 0 12 0zM4.906 7.405h5.624c1.47 0 3.007.068 3.764.827.746.746.827 2.233.83 3.676v4.54a.15.15 0 0 1-.152.147h-1.947a.15.15 0 0 1-.152-.148V11.83c-.002-.806-.048-1.634-.464-2.051-.358-.36-1.026-.441-1.72-.458H7.158a.15.15 0 0 0-.151.147v6.98a.15.15 0 0 1-.152.148H4.906a.15.15 0 0 1-.15-.148V7.554a.15.15 0 0 1 .15-.149zm12.131 0h1.949a.15.15 0 0 1 .15.15v8.892a.15.15 0 0 1-.15.148h-1.949a.15.15 0 0 1-.151-.148V7.554a.15.15 0 0 1 .151-.149zM8.92 10.948h2.046c.083 0 .15.066.15.147v5.352a.15.15 0 0 1-.15.148H8.92a.15.15 0 0 1-.152-.148v-5.352a.15.15 0 0 1 .152-.147Z" fill="#FF6900"/></svg>
@@ -1 +1 @@
1
- <svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Zhipu</title><path d="M11.991 23.503a.24.24 0 00-.244.248.24.24 0 00.244.249.24.24 0 00.245-.249.24.24 0 00-.22-.247l-.025-.001zM9.671 5.365a1.697 1.697 0 011.099 2.132l-.071.172-.016.04-.018.054c-.07.16-.104.32-.104.498-.035.71.47 1.279 1.186 1.314h.366c1.309.053 2.338 1.173 2.286 2.523-.052 1.332-1.152 2.38-2.478 2.327h-.174c-.715.018-1.274.64-1.239 1.368 0 .124.018.23.053.337.209.373.54.658.96.8.75.23 1.517-.125 1.9-.782l.018-.035c.402-.64 1.17-.96 1.92-.711.854.284 1.378 1.226 1.099 2.167a1.661 1.661 0 01-2.077 1.102 1.711 1.711 0 01-.907-.711l-.017-.035c-.2-.323-.463-.58-.851-.711l-.056-.018a1.646 1.646 0 00-1.954.746 1.66 1.66 0 01-1.065.764 1.677 1.677 0 01-1.989-1.279c-.209-.906.332-1.83 1.257-2.043a1.51 1.51 0 01.296-.035h.018c.68-.071 1.151-.622 1.116-1.333a1.307 1.307 0 00-.227-.693 2.515 2.515 0 01-.366-1.403 2.39 2.39 0 01.366-1.208c.14-.195.21-.444.227-.693.018-.71-.506-1.261-1.186-1.332l-.07-.018a1.43 1.43 0 01-.299-.07l-.05-.019a1.7 1.7 0 01-1.047-2.114 1.68 1.68 0 012.094-1.101zm-5.575 10.11c.26-.264.639-.367.994-.27.355.096.633.379.728.74.095.362-.007.748-.267 1.013-.402.41-1.053.41-1.455 0a1.062 1.062 0 010-1.482zm14.845-.294c.359-.09.738.024.992.297.254.274.344.665.237 1.025-.107.36-.396.634-.756.718-.551.128-1.1-.22-1.23-.781a1.05 1.05 0 01.757-1.26zm-.064-4.39c.314.32.49.753.49 1.206 0 .452-.176.886-.49 1.206-.315.32-.74.5-1.185.5-.444 0-.87-.18-1.184-.5a1.727 1.727 0 010-2.412 1.654 1.654 0 012.369 0zm-11.243.163c.364.484.447 1.128.218 1.691a1.665 1.665 0 01-2.188.923c-.855-.36-1.26-1.358-.907-2.228a1.68 1.68 0 011.33-1.038c.593-.08 1.183.169 1.547.652zm11.545-4.221c.368 0 .708.2.892.524.184.324.184.724 0 1.048a1.026 1.026 0 01-.892.524c-.568 0-1.03-.47-1.03-1.048 0-.579.462-1.048 1.03-1.048zm-14.358 0c.368 0 .707.2.891.524.184.324.184.724 0 1.048a1.026 1.026 0 01-.891.524c-.569 0-1.03-.47-1.03-1.048 0-.579.461-1.048 1.03-1.048zm10.031-1.475c.925 0 1.675.764 1.675 1.706s-.75 1.705-1.675 1.705-1.674-.763-1.674-1.705c0-.942.75-1.706 1.674-1.706zm-2.626-.684c.362-.082.653-.356.761-.718a1.062 1.062 0 00-.238-1.028 1.017 1.017 0 00-.996-.294c-.547.14-.881.7-.752 1.257.13.558.675.907 1.225.783zm0 16.876c.359-.087.644-.36.75-.72a1.062 1.062 0 00-.237-1.019 1.018 1.018 0 00-.985-.301 1.037 1.037 0 00-.762.717c-.108.361-.017.754.239 1.028.245.263.606.377.953.305l.043-.01zM17.19 3.5a.631.631 0 00.628-.64c0-.355-.279-.64-.628-.64a.631.631 0 00-.628.64c0 .355.28.64.628.64zm-10.38 0a.631.631 0 00.628-.64c0-.355-.28-.64-.628-.64a.631.631 0 00-.628.64c0 .355.279.64.628.64zm-5.182 7.852a.631.631 0 00-.628.64c0 .354.28.639.628.639a.63.63 0 00.627-.606l.001-.034a.62.62 0 00-.628-.64zm5.182 9.13a.631.631 0 00-.628.64c0 .355.279.64.628.64a.631.631 0 00.628-.64c0-.355-.28-.64-.628-.64zm10.38.018a.631.631 0 00-.628.64c0 .355.28.64.628.64a.631.631 0 00.628-.64c0-.355-.279-.64-.628-.64zm5.182-9.148a.631.631 0 00-.628.64c0 .354.279.639.628.639a.631.631 0 00.628-.64c0-.355-.28-.64-.628-.64zm-.384-4.992a.24.24 0 00.244-.249.24.24 0 00-.244-.249.24.24 0 00-.244.249c0 .142.122.249.244.249zM11.991.497a.24.24 0 00.245-.248A.24.24 0 0011.99 0a.24.24 0 00-.244.249c0 .133.108.236.223.247l.021.001zM2.011 6.36a.24.24 0 00.245-.249.24.24 0 00-.244-.249.24.24 0 00-.244.249.24.24 0 00.244.249zm0 11.263a.24.24 0 00-.243.248.24.24 0 00.244.249.24.24 0 00.244-.249.252.252 0 00-.244-.248zm19.995-.018a.24.24 0 00-.245.248.24.24 0 00.245.25.24.24 0 00.244-.25.252.252 0 00-.244-.248z" fill="#3859FF" fill-rule="nonzero"></path></svg>
1
+ <svg height="1em" style="flex:none;line-height:1" viewBox="0 0 96 96" width="1em" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>Zhipu</title><image href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAOgSURBVHgB7Z3LcRpBEIYb2QcfCWGVARkIIhAZQAaQAUsE4AggAysDUAZkAI6Avfq0noaljGERjxn6MdNf1V/S6qLZ/ufRM10MDbhO06nr9ObUrp6bYFxi5bRx+nD6rH5/CAzyyGnrVJoe1swpgzvpgQU+pNZVTG9iBMDe4Fg1Agu+XBP6ghoZu3pwQgb7eUpD42MQrq+7TPJbZcAU9immQcMPpz9Oywb86/0GLYXT6wtYz+dit8FFA97B4OINDcjA4KKNa0AJBheFGcDMCxismAHMmAHMmAHMmAHMfAdPms3mTpwURbHTMZTt2mw24IPXyV6/3y+5abfbZ+1ar9clBbPZzPdkVLcBeZ6ftWk0GpUUoMlZlqVrAAbgtD0YECparZZv8EvVi3Cn0/nvGef8xWIBFIzHY1itVhAClSOgbuqZTCYlBXUjz0P6DHC9nK0d2+02xLyv14C6hQ+fqbKe4XAYMvi6DMCeX9f78O8UBEg5z+R9HM294XEpJ7j1ACj+Ny76vpuuOkqtokw5e73es95DXmBvFdW8P51On/kesoJ6qyh3u09+F1mBvUV49kNF4JRTvwGUKWfdZi95A+bzeUlB3WYveQMGg0FJQaBTzrgMwIDgMQAFT0w59RqgqMASnwHKCixxGaCtwBKVAe6MKbaUU5cBVCknwW5XnwGKCyz6DVBeYNFvgOYCi3oDIk85ZRsQSYFFrwGRFFh0GhBRgUWfAd1ut6RCyLwvx4AICyy6DIiwwKLHgEgLLDoMiLjAosOAiAss8g1IcLcrx4AECixyDUikwCLXgEQKLDINSKjAIs+AxAos8gxIrMAiywBLORkNSLTAIseARAssMgxIuMDCb0DiBZa75H1f0CkuIDCZTIACvK+h7mOjVB+drbun6BGCOspZYMHRQJXyIri5DBCzcMHnLLBQbvYOiDKAu8BCNfKOEWUAZ4GFauSdIsYAzt0u5cg7RYQB3AUW6nn/mBAGeF1Zxn1FGN6Ugmmvdh52j7PAgqOBmxAjwOu+IKre53Mx6zPu9wmJfX8AM3Z3NDNmADNmADNmADNmADNogP+BtvEwZgAvKzTgEwwufqMBSzC4+IU7YdzPr6ufBi2vhzXgJxjUzJ02hwfs/fg126WJRGuo+RbbvsCGxqoeXCAX1MhYlcMVcgGNTDb4B/qwn6e0vJh0bauY3kUG+5Va04tKDHwOX6T4DbhO5tR2eq9+b4FxiaLSEvYnDB9w5ajnLzy3z1aOtKIfAAAAAElFTkSuQmCC" x="0" y="0" width="96" height="96" preserveAspectRatio="xMidYMid meet"/></svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "minecodex",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "Lightweight, local-first plugins for the Codex desktop app.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -439,6 +439,20 @@ export function createInjectionSource(features, {
439
439
  }) ?? null;
440
440
  }
441
441
 
442
+ function nativeSidePanelButton() {
443
+ return Array.from(document.querySelectorAll("button")).find((button) => {
444
+ if (button.getAttribute("aria-label") !== "Toggle side panel") return false;
445
+ return isVisibleToolbarControl(button);
446
+ }) ?? null;
447
+ }
448
+
449
+ function nativeTemporaryChatButton() {
450
+ return Array.from(document.querySelectorAll("button")).find((button) => {
451
+ if (!/temporary chat/i.test(button.getAttribute("aria-label") ?? "")) return false;
452
+ return isVisibleToolbarControl(button);
453
+ }) ?? null;
454
+ }
455
+
442
456
  function toolbarControlRoot(button) {
443
457
  return button?.parentElement?.parentElement ?? button?.parentElement ?? button ?? null;
444
458
  }
@@ -463,12 +477,28 @@ export function createInjectionSource(features, {
463
477
  if (!group) {
464
478
  group = document.createElement("div");
465
479
  group.setAttribute("data-codex-personal-summary-toolbar-group", "fallback");
466
- group.className = "ms-auto flex shrink-0 items-center gap-1.5";
480
+ // The host toolbar strip is pointer-events:none; without this the
481
+ // fallback entries would be visible but unclickable.
482
+ group.className = "ms-auto flex shrink-0 items-center gap-1.5 pointer-events-auto";
483
+ // Same structure as the native tool group (e.g. the temporary-chat
484
+ // group in Chat mode): an in-flow ms-auto strip inside the flexible
485
+ // header area. It sits at the right edge while the side panel is
486
+ // closed and, when the side panel widens its host container, moves
487
+ // together with the native layout exactly like Chat mode does.
467
488
  toolbarHost.append(group);
468
489
  }
469
490
  return group;
470
491
  }
471
492
 
493
+ function toolbarEntryFitsHeader(entryRoot) {
494
+ const header = entryRoot.closest("header");
495
+ if (!header) return true;
496
+ const headerRect = header.getBoundingClientRect();
497
+ const entryRect = entryRoot.getBoundingClientRect();
498
+ if (entryRect.width <= 0 || entryRect.height <= 0) return false;
499
+ return entryRect.right <= headerRect.right + 1 && entryRect.left >= headerRect.left - 1;
500
+ }
501
+
472
502
  function isNativeSummaryButton(element) {
473
503
  if (!(element instanceof Element)) return false;
474
504
  const button = element.closest("button");
@@ -613,10 +643,42 @@ export function createInjectionSource(features, {
613
643
  }
614
644
  }
615
645
 
646
+ function nativeCssModuleClass(tokenName, root = document) {
647
+ const pattern = new RegExp(`^_${tokenName}_[A-Za-z0-9_-]+$`);
648
+ const live = Array.from(root.querySelectorAll(`[class*="_${tokenName}_"]`))
649
+ .flatMap((element) => Array.from(element.classList))
650
+ .find((name) => pattern.test(name));
651
+ if (live) return live;
652
+ const selectorPattern = new RegExp(`\\.(_${tokenName}_[A-Za-z0-9_-]+)`);
653
+ const find = (rules) => {
654
+ for (const rule of rules ?? []) {
655
+ const match = String(rule.selectorText ?? "").match(selectorPattern);
656
+ if (match?.[1]) return match[1];
657
+ try {
658
+ const nested = find(rule.cssRules);
659
+ if (nested) return nested;
660
+ } catch {
661
+ // Ignore inaccessible nested rules and continue with Codex's readable sheets.
662
+ }
663
+ }
664
+ return null;
665
+ };
666
+ for (const sheet of document.styleSheets) {
667
+ try {
668
+ const match = find(sheet.cssRules);
669
+ if (match) return match;
670
+ } catch {
671
+ // Ignore cross-origin stylesheets.
672
+ }
673
+ }
674
+ return null;
675
+ }
676
+
616
677
  function createNativeFastIcon(active) {
617
678
  const definition = modelSelectorNativeFastIcons?.[active ? "active" : "inactive"];
618
679
  const icon = createModelSelectorIcon(definition, { brand: true });
619
- if (icon) icon.classList.add("_FastModeIcon_1ryrb_423");
680
+ const iconClass = nativeCssModuleClass("FastModeIcon");
681
+ if (icon && iconClass) icon.classList.add(iconClass);
620
682
  return icon;
621
683
  }
622
684
 
@@ -687,10 +749,52 @@ export function createInjectionSource(features, {
687
749
  for (let depth = 0; fiber && depth < 40; depth += 1, fiber = fiber.return) {
688
750
  const props = fiber.memoizedProps;
689
751
  if (Array.isArray(props?.models) && typeof props.onSelectReasoningEffort === "function") return props;
752
+ if (
753
+ props?.models
754
+ && typeof props.models === "object"
755
+ && !Array.isArray(props.models)
756
+ && typeof props.onModelChange === "function"
757
+ && props.selectedModel
758
+ ) {
759
+ return chatComposerModelController(props);
760
+ }
690
761
  }
691
762
  return null;
692
763
  }
693
764
 
765
+ function chatComposerModelController(props) {
766
+ const selected = props.selectedModel ?? {};
767
+ if (!Array.isArray(props.models?.versionOptions) || !selected.versionId) return null;
768
+ const version = props.models.versionOptions.find(
769
+ (candidate) => String(candidate.id ?? "") === String(selected.versionId ?? ""),
770
+ );
771
+ if (!version) return null;
772
+ const options = Array.isArray(version?.options) ? version.options : [];
773
+ const effortFor = (option) => String(option?.title ?? option?.lane ?? "").toLowerCase();
774
+ const efforts = options.map(effortFor).filter(Boolean);
775
+ const selectedOption = options.find(
776
+ (option) => String(option.thinkingEffort ?? "") === String(selected.thinkingEffort ?? ""),
777
+ );
778
+ const selectedEffort = selectedOption ? effortFor(selectedOption) : (efforts[0] ?? "instant");
779
+ const models = [{
780
+ model: String(selected.slug ?? ""),
781
+ displayName: String(version?.label ?? selected.slug ?? ""),
782
+ defaultReasoningEffort: selectedEffort,
783
+ supportedReasoningEfforts: efforts.map((effort) => ({ reasoningEffort: effort })),
784
+ }];
785
+ return {
786
+ models,
787
+ onSelectReasoningEffort(effort) {
788
+ const target = options.find((option) => effortFor(option) === String(effort).toLowerCase());
789
+ if (!target) return;
790
+ const next = { ...selected, slug: String(target.slug ?? selected.slug ?? "") };
791
+ if (target.thinkingEffort) next.thinkingEffort = target.thinkingEffort;
792
+ else delete next.thinkingEffort;
793
+ props.onModelChange(next);
794
+ },
795
+ };
796
+ }
797
+
694
798
  function nativeCatalogModelFor(identity) {
695
799
  const models = nativeComposerModelController()?.models ?? [];
696
800
  const exact = models.find((model) => String(model.model ?? "").toLowerCase() === identity.raw.toLowerCase());
@@ -1106,11 +1210,11 @@ export function createInjectionSource(features, {
1106
1210
  const observedIdentity = modelIdentity(observedRaw);
1107
1211
  const nativeDescriptor = nativeModelDescriptorForItem(item, observedRaw);
1108
1212
  const catalogModel = catalogModelFor(observedIdentity, selector);
1109
- const raw = nativeDescriptor?.slug ?? catalogModel?.slug ?? observedRaw;
1213
+ const raw = catalogModel?.slug ?? nativeDescriptor?.slug ?? observedRaw;
1110
1214
  item.dataset.codexModelSliderRaw = raw;
1111
1215
  item.dataset.codexModelSliderItem = "";
1112
1216
  item.dataset.codexModelSliderOrder = String(index);
1113
- item.dataset.codexModelSliderIdentitySource = nativeDescriptor ? "native" : catalogModel ? "catalog" : "visible";
1217
+ item.dataset.codexModelSliderIdentitySource = catalogModel ? "catalog" : nativeDescriptor ? "native" : "visible";
1114
1218
  if (item.querySelector("[data-codex-model-slider-row]")) return;
1115
1219
 
1116
1220
  const identity = modelIdentity(raw);
@@ -1397,12 +1501,17 @@ export function createInjectionSource(features, {
1397
1501
  if (!track) return;
1398
1502
  track.querySelectorAll('[class*="_FastParticleClip_"]').forEach((element) => element.remove());
1399
1503
  if (!enabled || matchMedia("(prefers-reduced-motion: reduce)").matches) return;
1504
+ const clipClass = nativeCssModuleClass("FastParticleClip");
1505
+ const particlesClass = nativeCssModuleClass("FastTrackParticles");
1506
+ const pathClass = nativeCssModuleClass("FastTrackParticlePath");
1507
+ const particleClass = nativeCssModuleClass("TrackParticle");
1508
+ if (!clipClass || !particlesClass || !pathClass || !particleClass) return;
1400
1509
  const clip = document.createElement("span");
1401
- clip.className = "_FastParticleClip_3jngk_242";
1510
+ clip.className = clipClass;
1402
1511
  clip.setAttribute("aria-hidden", "true");
1403
1512
  clip.style.opacity = "1";
1404
1513
  const particles = document.createElement("span");
1405
- particles.className = "_FastTrackParticles_1pz9e_1";
1514
+ particles.className = particlesClass;
1406
1515
  particles.setAttribute("aria-hidden", "true");
1407
1516
  particles.setAttribute("data-animation-active", "true");
1408
1517
  const travelDuration = 1.9;
@@ -1415,12 +1524,12 @@ export function createInjectionSource(features, {
1415
1524
  const speed = 1 + (nativeParticleSeed(index, 21) - 0.5) * 0.4;
1416
1525
  const duration = travelDuration / speed;
1417
1526
  const path = document.createElement("span");
1418
- path.className = "_FastTrackParticlePath_1pz9e_7";
1527
+ path.className = pathClass;
1419
1528
  path.style.animationDelay = `${index * stagger - duration * remainingTravel}s`;
1420
1529
  path.style.animationDuration = `${duration}s`;
1421
1530
  path.style.top = `${12 + nativeParticleSeed(index, 23) * 76}%`;
1422
1531
  const particle = document.createElement("span");
1423
- particle.className = "_TrackParticle_1pz9e_22";
1532
+ particle.className = particleClass;
1424
1533
  particle.style.opacity = String(0.4 + nativeParticleSeed(index, 11) * 0.6);
1425
1534
  particle.style.transform = `translate(-50%, -50%) scale(${0.5 + nativeParticleSeed(index, 12) * 0.45})`;
1426
1535
  path.append(particle);
@@ -1509,26 +1618,37 @@ export function createInjectionSource(features, {
1509
1618
  function createGenericModelSlider(parentMenu, selector, identity, model, selectedEffort) {
1510
1619
  const efforts = model.supportedReasoningLevels.map((level) => level.effort);
1511
1620
  const selectedIndex = Math.max(0, efforts.indexOf(selectedEffort));
1621
+ const classes = Object.fromEntries([
1622
+ "Menu",
1623
+ "ViewToggle",
1624
+ "ViewToggleContent",
1625
+ "ViewToggleIcon",
1626
+ "ViewControls",
1627
+ "FastModeToggle",
1628
+ "FastModeToggleContent",
1629
+ "SimpleView",
1630
+ ].map((tokenName) => [tokenName, nativeCssModuleClass(tokenName, parentMenu)]));
1631
+ if (Object.values(classes).some((name) => !name)) return null;
1512
1632
  const shell = document.createElement("div");
1513
1633
  shell.setAttribute("data-codex-model-slider-generic", `${identity.raw}:${selectedEffort}`);
1514
- shell.className = "_Menu_1ryrb_2";
1634
+ shell.className = classes.Menu;
1515
1635
  shell.setAttribute("data-view", "simple");
1516
1636
  shell.setAttribute("data-reduced-motion", String(matchMedia("(prefers-reduced-motion: reduce)").matches));
1517
1637
  shell.setAttribute("data-transitions-ready", "false");
1518
1638
  const nativeRow = nativeModelPickerRow(parentMenu);
1519
1639
  const modelButton = document.createElement("div");
1520
- modelButton.className = "_ViewToggle_1ryrb_13";
1640
+ modelButton.className = classes.ViewToggle;
1521
1641
  modelButton.setAttribute("role", "button");
1522
1642
  modelButton.setAttribute("tabindex", "0");
1523
1643
  modelButton.setAttribute("data-codex-model-slider-model-button", "");
1524
1644
  modelButton.setAttribute("aria-label", `Model ${modelDisplayLabel(identity, selector)}`);
1525
1645
  const buttonContent = document.createElement("span");
1526
- buttonContent.className = "_ViewToggleContent_1ryrb_334";
1646
+ buttonContent.className = classes.ViewToggleContent;
1527
1647
  const buttonLabel = document.createElement("span");
1528
1648
  buttonLabel.textContent = modelDisplayLabel(identity, selector);
1529
1649
  const nativeChevron = nativeRow?.querySelector("svg")?.cloneNode(true);
1530
1650
  if (nativeChevron) {
1531
- nativeChevron.className.baseVal = "_ViewToggleIcon_1ryrb_85";
1651
+ nativeChevron.className.baseVal = classes.ViewToggleIcon;
1532
1652
  nativeChevron.setAttribute("aria-hidden", "true");
1533
1653
  buttonContent.append(buttonLabel, nativeChevron);
1534
1654
  } else {
@@ -1544,7 +1664,7 @@ export function createInjectionSource(features, {
1544
1664
  });
1545
1665
 
1546
1666
  const viewControls = document.createElement("div");
1547
- viewControls.className = "_ViewControls_1ryrb_12";
1667
+ viewControls.className = classes.ViewControls;
1548
1668
  viewControls.setAttribute("data-expanded", "false");
1549
1669
  viewControls.setAttribute("data-ultra-warning-visible", "false");
1550
1670
  const controller = nativeComposerModelController();
@@ -1560,7 +1680,7 @@ export function createInjectionSource(features, {
1560
1680
  if (supportsFast) {
1561
1681
  const fastButton = document.createElement("button");
1562
1682
  fastButton.type = "button";
1563
- fastButton.className = "_FastModeToggle_1ryrb_14";
1683
+ fastButton.className = classes.FastModeToggle;
1564
1684
  fastButton.setAttribute("data-codex-model-slider-fast", "");
1565
1685
  fastButton.setAttribute("aria-pressed", String(fastEnabled));
1566
1686
  fastButton.setAttribute("data-fast-mode-enabled", String(fastEnabled));
@@ -1571,7 +1691,7 @@ export function createInjectionSource(features, {
1571
1691
  : (locale === "zh-CN" ? "开启 Fast 模式" : "Enable Fast mode"));
1572
1692
  const fastIcon = createNativeFastIcon(fastEnabled);
1573
1693
  const fastContent = document.createElement("span");
1574
- fastContent.className = "_FastModeToggleContent_1ryrb_399";
1694
+ fastContent.className = classes.FastModeToggleContent;
1575
1695
  fastContent.setAttribute("data-codex-model-slider-fast-content", "");
1576
1696
  if (fastIcon) fastContent.append(fastIcon);
1577
1697
  fastButton.append(fastContent);
@@ -1677,7 +1797,7 @@ export function createInjectionSource(features, {
1677
1797
  selectNativeEffort(parentMenu, efforts[pendingIndex]);
1678
1798
  });
1679
1799
  const simpleView = document.createElement("div");
1680
- simpleView.className = "_SimpleView_1ryrb_50";
1800
+ simpleView.className = classes.SimpleView;
1681
1801
  simpleView.append(nativeSlider ?? rail);
1682
1802
  shell.append(viewControls, simpleView);
1683
1803
  return shell;
@@ -1715,12 +1835,13 @@ export function createInjectionSource(features, {
1715
1835
  existing?.remove();
1716
1836
  const nativeContainer = parentMenu.firstElementChild;
1717
1837
  if (!nativeContainer) return false;
1838
+ const shell = createGenericModelSlider(parentMenu, selector, identity, model, selectedEffort);
1839
+ if (!shell) return false;
1718
1840
  if (!modelSelectorGenericContainers.has(nativeContainer)) {
1719
1841
  modelSelectorGenericContainers.set(nativeContainer, nativeContainer.style.display);
1720
1842
  }
1721
1843
  parentMenu.setAttribute("data-codex-model-slider-generic-menu", "");
1722
1844
  nativeContainer.style.display = "none";
1723
- const shell = createGenericModelSlider(parentMenu, selector, identity, model, selectedEffort);
1724
1845
  shell.setAttribute("data-codex-model-slider-generic", key);
1725
1846
  parentMenu.append(shell);
1726
1847
  return true;
@@ -2056,7 +2177,10 @@ export function createInjectionSource(features, {
2056
2177
  }
2057
2178
 
2058
2179
  function currentComposer() {
2059
- return document.querySelector('[data-codex-composer="true"][contenteditable="true"]');
2180
+ const marked = document.querySelector('[data-codex-composer="true"][contenteditable="true"]');
2181
+ if (marked) return marked;
2182
+ return Array.from(document.querySelectorAll('[contenteditable="true"][role="textbox"]'))
2183
+ .find((element) => isVisibleToolbarControl(element)) ?? null;
2060
2184
  }
2061
2185
 
2062
2186
  function rememberComposerSelection() {
@@ -2379,9 +2503,16 @@ export function createInjectionSource(features, {
2379
2503
  const entryRect = entry.getBoundingClientRect();
2380
2504
  const scrollRect = mainContentViewport()?.querySelector(".thread-scroll-container")
2381
2505
  ?.getBoundingClientRect();
2506
+ // The native conversation header is a fixed overlay that starts above the
2507
+ // thread scroll container (scroll top is often 0 while the header still
2508
+ // occupies the top toolbar strip). Anchor below the header so the pinned
2509
+ // surface never covers the toolbar entry used to close it again.
2510
+ const header = entry.closest("header");
2511
+ const headerBottom = header?.getBoundingClientRect().bottom ?? 0;
2512
+ const contentTop = Math.max(scrollRect?.top ?? 0, headerBottom);
2382
2513
  const top = displayMode === "overlay"
2383
2514
  ? entryRect.bottom + layout.popoverOffset
2384
- : (scrollRect?.top ?? 46) + layout.verticalInset;
2515
+ : (contentTop || 46) + layout.verticalInset;
2385
2516
  const right = displayMode === "overlay"
2386
2517
  ? Math.max(layout.popoverOffset, innerWidth - entryRect.right)
2387
2518
  : Math.max(layout.panelInset, innerWidth - target.right + layout.panelInset);
@@ -3169,15 +3300,23 @@ export function createInjectionSource(features, {
3169
3300
 
3170
3301
  function ensureToolbarEntries() {
3171
3302
  if (!toolbarFeatures.length) return;
3172
- const bottomPanelButton = nativeBottomPanelButton();
3173
- if (!bottomPanelButton) return;
3303
+ const temporaryChatButton = nativeTemporaryChatButton();
3174
3304
  const summaryButton = nativeSummaryButton();
3175
- const summaryRoot = toolbarControlRoot(summaryButton);
3176
- const summaryGroup = nativeSummaryToolbarGroup(summaryButton);
3177
- const fallbackGroup = summaryGroup ? null : ensureFallbackSummaryToolbarGroup(bottomPanelButton);
3178
- const targetGroup = summaryGroup ?? fallbackGroup;
3305
+ const bottomPanelButton = nativeBottomPanelButton();
3306
+ const sidePanelButton = nativeSidePanelButton();
3307
+ const anchorButton = temporaryChatButton ?? summaryButton ?? bottomPanelButton ?? sidePanelButton;
3308
+ if (!anchorButton) return;
3309
+ const anchorRoot = toolbarControlRoot(anchorButton);
3310
+ // The side-panel toggle sits in a narrow fixed container that travels
3311
+ // with the native panel. Entries anchored to it must live in the
3312
+ // fallback toolbar group, otherwise the Notes entry would be dragged
3313
+ // into the side panel and hidden. The Notes entry is only grouped with
3314
+ // the native summary button when that button is the anchor.
3315
+ const useFallbackAnchor = anchorButton === sidePanelButton;
3316
+ const summaryGroup = useFallbackAnchor ? null : nativeSummaryToolbarGroup(anchorButton);
3317
+ let targetGroup = summaryGroup ?? ensureFallbackSummaryToolbarGroup(anchorButton);
3179
3318
  if (!targetGroup) return;
3180
- let cursor = summaryRoot;
3319
+ let cursor = useFallbackAnchor ? null : anchorRoot;
3181
3320
  for (const feature of toolbarFeatures) {
3182
3321
  const entries = Array.from(document.querySelectorAll(`[${entryMarker}="${feature.id}"]`));
3183
3322
  for (const duplicate of entries.slice(1)) {
@@ -3185,7 +3324,7 @@ export function createInjectionSource(features, {
3185
3324
  }
3186
3325
  const entry = entries[0]?.isConnected
3187
3326
  ? entries[0]
3188
- : createToolbarEntry(feature, summaryButton ?? bottomPanelButton);
3327
+ : createToolbarEntry(feature, anchorButton);
3189
3328
  const entryRoot = entry?.closest("[data-codex-personal-toolbar-entry]") ?? entry;
3190
3329
  if (!entryRoot) continue;
3191
3330
  if (cursor) {
@@ -3193,10 +3332,24 @@ export function createInjectionSource(features, {
3193
3332
  } else if (targetGroup.lastElementChild !== entryRoot) {
3194
3333
  targetGroup.append(entryRoot);
3195
3334
  }
3335
+ // Narrow native anchor containers (e.g. the Work-mode side-panel
3336
+ // button) can push the entry outside the header so it becomes
3337
+ // unreachable. Move it into the fallback toolbar group instead.
3338
+ if (summaryGroup && !toolbarEntryFitsHeader(entryRoot)) {
3339
+ const fallback = ensureFallbackSummaryToolbarGroup(anchorButton);
3340
+ if (fallback && fallback !== summaryGroup) {
3341
+ fallback.append(entryRoot);
3342
+ targetGroup = fallback;
3343
+ cursor = null;
3344
+ }
3345
+ }
3196
3346
  cursor = entryRoot;
3197
3347
  }
3198
3348
  if (summaryGroup) {
3199
- document.querySelectorAll("[data-codex-personal-summary-toolbar-group]").forEach((group) => group.remove());
3349
+ document.querySelectorAll("[data-codex-personal-summary-toolbar-group]").forEach((group) => {
3350
+ const used = [...group.querySelectorAll(`[${entryMarker}]`)].some((entry) => entry.isConnected);
3351
+ if (!used) group.remove();
3352
+ });
3200
3353
  }
3201
3354
  }
3202
3355