minecodex 1.2.0 → 1.2.1

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.
@@ -20,6 +20,8 @@
20
20
 
21
21
  状态行和输入框共用内容宽度,单行高度为 24px,顶部留 2px 内边距;每个状态按钮高 22px,内边距为上下 3px、左右 7px。宽度不足时自然换行,不覆盖输入框或悬浮控件。统计图标采用 Lucide Gauge,用量图标采用 Phosphor Database 单路径版本,两者以 14px 绘制;上下文使用与 Codex 原生相同参数的 12px 百分环。弹层由按钮锚定,键盘可聚焦,Escape 和点击外部关闭。遵守系统减少动态效果设置,不添加持续动画。
22
22
 
23
+ 状态行以当前输入框所在的会话为准,不依赖侧栏中可能因项目折叠而卸载的 Thread 行。新聊天没有会话 ID 时隐藏旧数据;首条消息建立会话并产生记录后,以 160ms 淡入和 4px 上移出现,减少动态效果设置下立即显示。
24
+
23
25
  ## 数据呈现
24
26
 
25
27
  界面文案跟随 Codex 的 `html[lang]`:中文语言使用简体中文,其他语言使用英文;运行中切换语言时同步更新状态行和已打开的明细浮窗。MineCodex Web 使用同样的中英文规则提供本功能开关。
@@ -32,6 +32,9 @@ style.id = STYLE_ID;
32
32
  style.textContent = `
33
33
  [${MARKER}] { box-sizing:border-box; display:flex; flex-wrap:wrap; justify-content:center; align-items:center; gap:0 12px; margin:-2px auto -6px; padding-top:2px; max-width:100%; min-height:24px; min-width:0; font-family:var(--font-sans-default,inherit); font-size:var(--text-xs,12px); line-height:16px; font-variant-numeric:tabular-nums; color:var(--color-text-tertiary); }
34
34
  [${MARKER}][hidden] { display:none; }
35
+ [${MARKER}]:not([hidden]) { animation:mcx-session-status-enter 160ms ease-out both; }
36
+ @keyframes mcx-session-status-enter { from { opacity:0; transform:translateY(4px); } to { opacity:1; transform:translateY(0); } }
37
+ @media (prefers-reduced-motion: reduce) { [${MARKER}]:not([hidden]) { animation:none; } }
35
38
  [${MARKER}] button { box-sizing:border-box; display:inline-flex; align-items:center; gap:5px; height:22px; color:inherit; font:inherit; border:0; border-radius:var(--radius-xl,12px); background:transparent; padding:3px 7px; cursor:pointer; white-space:nowrap; }
36
39
  [${MARKER}] svg, [data-minecodex-session-status-panel] h3 svg { width:14px; height:14px; flex:none; stroke-width:1.75; }
37
40
  [${MARKER}] [data-kind="context"] svg, [data-minecodex-session-status-panel] h3 .context-ring { width:12px; height:12px; stroke-width:2; }
@@ -261,6 +264,13 @@ function findComposer() {
261
264
  return document.querySelector('[data-codex-composer="true"][contenteditable="true"]')
262
265
  ?? document.querySelector('[contenteditable="true"][role="textbox"]');
263
266
  }
267
+ function syncVisibility(composer) {
268
+ const portal = composer?.closest('[data-codex-composer-root]')?.querySelector('[data-above-composer-portal]');
269
+ const activeThreadId = portal?.getAttribute('data-above-composer-conversation-id');
270
+ const hasData = snapshot && (snapshot.turns > 0 || snapshot.totalTokens != null);
271
+ root.hidden = !hasData || (portal && snapshot.threadId !== activeThreadId);
272
+ if (root.hidden) closePanel();
273
+ }
264
274
  function ensurePosition() {
265
275
  const composer = findComposer();
266
276
  if (!composer) { root.remove(); closePanel(); return; }
@@ -271,10 +281,11 @@ function ensurePosition() {
271
281
  card.after(root);
272
282
  closePanel();
273
283
  }
284
+ syncVisibility(composer);
274
285
  }
275
286
  function render() {
276
- root.hidden = !snapshot || (snapshot.turns === 0 && snapshot.totalTokens == null);
277
- if (root.hidden) { closePanel(); return; }
287
+ syncVisibility(findComposer());
288
+ if (root.hidden) return;
278
289
  buttons[0].querySelector(".status-label").textContent = `${number(snapshot.turns)} ${copy.turns} ${number(snapshot.steps)} ${copy.steps} · ${snapshot.observedTps == null ? "—" : number(snapshot.observedTps)} tok/s`;
279
290
  buttons[1].querySelector(".status-label").textContent = `${compact(snapshot.totalTokens)} · ${copy.cache} ${snapshot.cacheHitPercent == null ? "—" : `${snapshot.cacheHitPercent}%`}`;
280
291
  buttons[2].querySelector(".status-label").textContent = snapshot.contextPercent == null ? "—" : `${snapshot.contextPercent}%`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "minecodex",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "Lightweight, local-first plugins for the Codex desktop app.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -44,6 +44,19 @@ export {
44
44
  responsiveSummaryDisplayMode,
45
45
  responsiveSummaryVisibleSurface,
46
46
  } from "./codex-injection.mjs";
47
+
48
+ export const SESSION_STATUS_THREAD_ID_EXPRESSION = `(() => {
49
+ const composer = document.querySelector('[data-codex-composer="true"][contenteditable="true"]')
50
+ ?? document.querySelector('[contenteditable="true"][role="textbox"]');
51
+ const card = composer?.closest('[data-codex-composer-root]');
52
+ const portal = card?.querySelector('[data-above-composer-portal]');
53
+ if (portal) return portal.getAttribute('data-above-composer-conversation-id');
54
+ if (card?.getAttribute('data-composer-placement') === 'home') return null;
55
+ const selected = document.querySelector('[data-app-action-sidebar-thread-selected="true"]');
56
+ return selected?.getAttribute('data-app-action-sidebar-thread-id')
57
+ ?? location.pathname + location.search + location.hash;
58
+ })()`;
59
+
47
60
  export class CodexRuntime {
48
61
  constructor({
49
62
  features,
@@ -685,11 +698,7 @@ export class CodexRuntime {
685
698
  if (!this.injectedTargets.has(targetId)) continue;
686
699
  try {
687
700
  const response = await client.send("Runtime.evaluate", {
688
- expression: `(() => {
689
- const selected = document.querySelector('[data-app-action-sidebar-thread-selected="true"]');
690
- return selected?.getAttribute('data-app-action-sidebar-thread-id')
691
- ?? location.pathname + location.search;
692
- })()`,
701
+ expression: SESSION_STATUS_THREAD_ID_EXPRESSION,
693
702
  returnByValue: true,
694
703
  });
695
704
  const threadId = threadIdFromLocation(response.result?.value);