minecodex 1.0.9 → 1.0.10

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.
@@ -3,7 +3,7 @@
3
3
  CodexNotes 是一个完全本地的 Codex 个人调用层:在当前对话右上角通过一个
4
4
  Notes Toolbar Button 快速查看 Todo、Prompts 和 Files;单个分区超过 5 条时才会
5
5
  显示 `View all`,并通过 RuntimeHost 在 Codex 原生右侧工作区打开互不重复、跟随
6
- 当前 Task 的完整 Tab;内部 capability 不可用时才回退到兼容 Tab host。
6
+ 当前 Task 的完整 Tab;内部 capability 不可用时显示明确错误。
7
7
 
8
8
  目标交互与 Codex 原生 Summary 一致:窄空间使用 `Toggle notes` Popover,
9
9
  宽空间使用 `Toggle pinned notes`,并在 `shift` / `gutter` 模式中参与对话
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "minecodex",
3
- "version": "1.0.9",
3
+ "version": "1.0.10",
4
4
  "description": "Lightweight, local-first plugins for the Codex desktop app.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -132,8 +132,8 @@ Host 会再次发送当前状态。功能页面可据此暂停隐藏状态下的
132
132
  - `attach-file`:用 CDP 填充临时 file input,再把真实 `File` drop 给 Composer;只有
133
133
  观察到原生附件 chip/preview 才报告 `attach`,否则明确返回 `insert-path`。
134
134
  - `open-detail-tab`:动态发现当前 Codex React right-panel controller 与当前 Task scope,
135
- 用稳定的 `featureId-detailId` 聚焦或创建唯一原生 Tab;capability 不可用时才回退到
136
- RuntimeHost 自建的兼容 Tab host。
135
+ 传入包含 `Component`、`isAvailable`、`kind` `dropDestinations` 的标签描述对象,
136
+ 用稳定的 `featureId-detailId` 聚焦或创建唯一原生 Tab;capability 不可用时返回明确错误。
137
137
  - `resolve-file-paths`:通过 Codex preload 暴露的 Electron file bridge 解析 Finder
138
138
  drop 的真实 `File` 对象。
139
139
 
@@ -145,6 +145,8 @@ Host 会再次发送当前状态。功能页面可据此暂停隐藏状态下的
145
145
  本地 Surface 不直接导航到 loopback URL:Host 先创建 `about:blank` iframe,再校验
146
146
  manifest URL、health service/protocol/instance,抓取 HTML 并用 `Page.setDocumentContent`
147
147
  写入目标 frame。Images/Notes 只向精确的 `app://-` Origin 开放 CORS。
148
+ - CDP 重连时同步轮换后的 binding token;保留已就绪的 Surface 和编辑草稿,
149
+ 使用新 token 重试未就绪页面,避免弹窗停留在空白 iframe。
148
150
  - 入口由 Renderer 内的 MutationObserver 幂等挂载,React 重绘不会产生重复入口。
149
151
  - Summary 根据对话主区域宽度连续派生 `overlay / shift / gutter`:小于 1096px
150
152
  使用临时 Popover;1096–1535px 预留 316px 并把对话内容左移 158px;更宽时
@@ -166,7 +168,7 @@ Host 会再次发送当前状态。功能页面可据此暂停隐藏状态下的
166
168
  | --- | --- | --- |
167
169
  | loopback HTTP、manifest、Surface message schema | 项目自有稳定接口 | 可由测试直接覆盖 |
168
170
  | `window.electronBridge.getPathForFile` | 当前稳定 internal/preload | 仅用于 Finder `File` 路径解析 |
169
- | React right-panel `openTab`、Task scope、JSX runtime | private internal capability | 动态发现 bundle 并做能力检测;失败时回退自建 Tab host |
171
+ | React right-panel `openTab`、Task scope、JSX runtime | private internal capability | 动态发现 bundle 并做能力检测;失败时返回明确的不可用错误 |
170
172
  | toolbar、summary、tabs、Composer selectors | DOM inference | 统一留在本 Adapter |
171
173
  | `Runtime.addBinding`、`DOM.setFileInputFiles`、注入脚本 | high-risk CDP | 必须使用隔离 profile 验收 |
172
174
  | `togglePinnedSummary`、`composer.addFiles` 字符串 | 探索证据 | 当前实现不把它们当契约 |
@@ -5,7 +5,7 @@
5
5
  import { randomBytes } from "node:crypto";
6
6
  import { CODEX_THEME_TOKENS } from "./codex-design-contract.mjs";
7
7
 
8
- export const RUNTIME_VERSION = 100;
8
+ export const RUNTIME_VERSION = 101;
9
9
  export const HOST_BINDING_NAME = "__codexPersonalHostAction";
10
10
  export const CSP_BOOTSTRAP_VERSION = 1;
11
11
  export const CSP_BOOTSTRAP_KEY = "__mineCodexCspBootstrapVersion";
@@ -131,6 +131,7 @@ export function createInjectionSource(features, {
131
131
  }
132
132
  const currentRuntime = window.__codexPersonalRuntime;
133
133
  if (currentRuntime?.version === config.version && currentRuntime?.sessionId === config.sessionId) {
134
+ currentRuntime.updateHostBinding(config.bindingName, config.bindingToken);
134
135
  currentRuntime.ensure();
135
136
  return;
136
137
  }
@@ -2701,6 +2702,21 @@ export function createInjectionSource(features, {
2701
2702
  return true;
2702
2703
  }
2703
2704
 
2705
+ function updateHostBinding(bindingName, bindingToken) {
2706
+ if (config.bindingName === bindingName && config.bindingToken === bindingToken) return;
2707
+ // CDP 重连会轮换 token;保留已有页面和草稿,只重试未就绪的页面。
2708
+ config.bindingName = bindingName;
2709
+ config.bindingToken = bindingToken;
2710
+ for (const [requestId, pending] of pendingHostActions) {
2711
+ if (pending.kind === "surface-load") pendingHostActions.delete(requestId);
2712
+ }
2713
+ for (const record of surfaceRecords.values()) {
2714
+ if (record.ready) continue;
2715
+ record.loading = false;
2716
+ requestSurfaceLoad(record);
2717
+ }
2718
+ }
2719
+
2704
2720
  function postSurfaceActive(record, active) {
2705
2721
  if (!record || record.kind !== "page") return;
2706
2722
  record.frame.contentWindow?.postMessage({
@@ -3832,7 +3848,13 @@ export function createInjectionSource(features, {
3832
3848
  }
3833
3849
 
3834
3850
  try {
3835
- controller.openTab(scope, nativeDetailComponent(feature, detail), {
3851
+ // 原生 openTab 接收标签描述对象,并在挂载前检查可用性。
3852
+ controller.openTab(scope, {
3853
+ Component: nativeDetailComponent(feature, detail),
3854
+ kind: tabId,
3855
+ dropDestinations: ["right"],
3856
+ isAvailable: () => true,
3857
+ }, {
3836
3858
  id: tabId,
3837
3859
  kind: tabId,
3838
3860
  title: detail.label,
@@ -4421,6 +4443,7 @@ export function createInjectionSource(features, {
4421
4443
  const runtimeApi = {
4422
4444
  version: config.version,
4423
4445
  sessionId: config.sessionId,
4446
+ updateHostBinding,
4424
4447
  ensure: queueEnsure,
4425
4448
  show: showPageSurface,
4426
4449
  hide: () => {
@@ -4542,4 +4565,3 @@ export function createRuntimeReadyContract({
4542
4565
  export function createDocumentBootstrapSource(source) {
4543
4566
  return `window[${JSON.stringify(CSP_BOOTSTRAP_KEY)}] = ${CSP_BOOTSTRAP_VERSION};\n${source}`;
4544
4567
  }
4545
-