minecodex 2.0.29 → 2.0.30
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 +1 -2
- package/features/quick-chat/codex-feature.json +23 -5
- package/features/quick-chat/src/adapters/codex/history.mjs +8 -0
- package/features/quick-chat/src/adapters/codex/pin.mjs +3 -8
- package/features/quick-chat/src/adapters/codex/renderer.mjs +17 -13
- package/features/quick-chat/src/adapters/codex/shortcut.mjs +43 -8
- package/features/quick-chat/src/frontend/entry.mjs +6 -4
- package/features/quick-chat/src/frontend/exit.mjs +14 -0
- package/features/quick-chat/src/injection-source.mjs +5 -2
- package/package.json +3 -7
- package/packages/cli/src/config.mjs +3 -2
- package/packages/cli/src/control-server.mjs +1 -1
- package/features/quick-chat-repair/assets/history.svg +0 -17
- package/features/quick-chat-repair/codex-feature.json +0 -10
- package/features/quick-chat-repair/src/frontend/entry.mjs +0 -12
- package/features/quick-chat-repair/src/injection-source.mjs +0 -5
- package/features/quick-chat-repair/vendor/lucide-LICENSE +0 -15
- /package/features/{quick-chat-repair → quick-chat}/src/adapters/codex/presence.mjs +0 -0
package/README.md
CHANGED
|
@@ -18,8 +18,7 @@ MineCodex 给 Codex Desktop 增加一组轻量、本地优先的扩展功能。
|
|
|
18
18
|
| **文件级联浏览** · Cascading File Browser | 点击文件顶部路径,分列浏览文件夹并快速切换文件。 |
|
|
19
19
|
| **图片集合** · Image Collection | 集中浏览生成的图片,查看提示词并复用创作思路。 |
|
|
20
20
|
| **站点收藏** · Saved Sites | 发现项目正在运行的网页,收藏常用网址,随时打开。 |
|
|
21
|
-
|
|
|
22
|
-
| **快捷聊天增强** · Quick Chat | 补回 Codex 模式的 ⌘⌥N,恢复最小化输入框;发送后展开聊天,可固定内容窗口并查看原生聊天历史。 |
|
|
21
|
+
| **快捷聊天增强** · Enhance Quick Chat | 补回 ⌘⌥N;关闭后开新聊天,最小化后恢复当前聊天,发送后展开。支持固定窗口、原生历史与退出遮罩修复。 |
|
|
23
22
|
| **侧栏聚焦** · Sidebar Focus | 一键收起侧栏中的其他分组,再次点击恢复原来的展开状态。 |
|
|
24
23
|
| **隐藏额度推广** · Hide Usage Promotions | 隐藏输入框上方的套餐升级推广,让对话更清爽。 |
|
|
25
24
|
|
|
@@ -2,9 +2,27 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"id": "quick-chat",
|
|
4
4
|
"version": "0.1.0",
|
|
5
|
-
"label": {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
5
|
+
"label": {
|
|
6
|
+
"en": "Enhance Quick Chat",
|
|
7
|
+
"zh-CN": "快捷聊天增强"
|
|
8
|
+
},
|
|
9
|
+
"description": {
|
|
10
|
+
"en": "Start fresh after closing, restore minimized chats, expand after sending, pin conversations, and repair native exit layers.",
|
|
11
|
+
"zh-CN": "关闭后开启全新聊天,恢复最小化输入框、发送后展开、固定聊天,并修复退出后的透明遮罩残留。"
|
|
12
|
+
},
|
|
13
|
+
"entry": {
|
|
14
|
+
"kind": "page-script",
|
|
15
|
+
"script": "src/frontend/entry.mjs",
|
|
16
|
+
"sourceFactory": "src/injection-source.mjs",
|
|
17
|
+
"resources": {
|
|
18
|
+
"history": "assets/history.svg",
|
|
19
|
+
"pin": "assets/pin.svg"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"icon": {
|
|
23
|
+
"resource": "assets/history.svg"
|
|
24
|
+
},
|
|
25
|
+
"placement": {
|
|
26
|
+
"order": 75
|
|
27
|
+
}
|
|
10
28
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// 统一解释原生历史列表;原始 React 节点不越过 Adapter 边界。
|
|
2
|
+
export function quickChatHistoryVisible(node) {
|
|
3
|
+
if (Array.isArray(node)) return node.some(quickChatHistoryVisible);
|
|
4
|
+
const props = node?.props;
|
|
5
|
+
if (!props || props.hidden || props.inert || props['aria-hidden']) return false;
|
|
6
|
+
if (Array.isArray(props.conversations) && typeof props.onConversationSelect === 'function' && typeof props.onNewChat === 'function') return true;
|
|
7
|
+
return quickChatHistoryVisible(props.children);
|
|
8
|
+
}
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
+
import {quickChatHistoryVisible} from "./history.mjs";
|
|
1
2
|
export function createQuickChatPinAdapter(codex) {
|
|
2
3
|
const layerSelector = '.fixed.inset-0.zoom-adjusted-viewport.pointer-events-auto';
|
|
3
|
-
|
|
4
|
-
if (Array.isArray(node)) return node.some(historyVisible);
|
|
5
|
-
const props = node?.props;
|
|
6
|
-
if (!props || props.hidden || props.inert || props['aria-hidden']) return false;
|
|
7
|
-
if (Array.isArray(props.conversations) && typeof props.onConversationSelect === 'function' && typeof props.onNewChat === 'function') return true;
|
|
8
|
-
return historyVisible(props.children);
|
|
9
|
-
}
|
|
4
|
+
|
|
10
5
|
function surfaces() {
|
|
11
6
|
const inCodex = [...document.querySelectorAll('button[aria-haspopup="menu"]')].some(button => button.checkVisibility({visibilityProperty:true})
|
|
12
7
|
&& codex.props(button, p => typeof p.onModeSelect === 'function' && typeof p.mode === 'string', 80)?.mode === 'codex');
|
|
@@ -24,7 +19,7 @@ export function createQuickChatPinAdapter(codex) {
|
|
|
24
19
|
if (!composer || composer.isWorkConversation || composer.annotationSubmitTarget || composer.isWidgetOverlay || !session?.hasConversation || !floating) return [];
|
|
25
20
|
const anchor = surface.querySelector('header button[data-quick-chat-drag-handle]');
|
|
26
21
|
const expanded = floating.presentation === 'expanded' || floating.forceExpanded;
|
|
27
|
-
const history =
|
|
22
|
+
const history = quickChatHistoryVisible(floating.renderTranscript?.());
|
|
28
23
|
return [{surface, layer, sessionId:session.conversationId, anchor, minimized:Boolean(floating.isMinimized), expanded:Boolean(expanded), history,
|
|
29
24
|
expand:() => floating.onPresentationChange('expanded'),
|
|
30
25
|
showPin:Boolean(anchor && expanded && !floating.isMinimized && !history)}];
|
|
@@ -1,14 +1,10 @@
|
|
|
1
|
+
import {quickChatHistoryVisible} from "./history.mjs";
|
|
1
2
|
export function createQuickChatAdapter(codex) {
|
|
2
|
-
const receipts = new WeakMap();
|
|
3
|
+
const receipts = new WeakMap(), subscriptions = new WeakMap(), emitters = new WeakMap();
|
|
4
|
+
let nextSubscription = 1;
|
|
3
5
|
let nextReceipt = 1;
|
|
4
6
|
const surfaceSelector = '[data-floating-chat-surface]';
|
|
5
|
-
|
|
6
|
-
if (Array.isArray(node)) return node.some(historyList);
|
|
7
|
-
const props = node?.props;
|
|
8
|
-
if (!props || props.hidden || props.inert || props['aria-hidden']) return false;
|
|
9
|
-
if (Array.isArray(props.conversations) && typeof props.onConversationSelect === 'function' && typeof props.onNewChat === 'function') return true;
|
|
10
|
-
return historyList(props.children);
|
|
11
|
-
}
|
|
7
|
+
|
|
12
8
|
function read(surface) {
|
|
13
9
|
if (!surface?.isConnected || surface.closest('[hidden], [inert], [aria-hidden="true"]')) return null;
|
|
14
10
|
const editable = surface.querySelector('[data-chatgpt-composer] [contenteditable="true"]');
|
|
@@ -31,7 +27,10 @@ export function createQuickChatAdapter(codex) {
|
|
|
31
27
|
if (fiber.memoizedProps?.session?.conversationId !== session.conversationId) continue;
|
|
32
28
|
for (let hook = fiber.memoizedState, count = 0; hook && count < 140; hook = hook.next, count++) {
|
|
33
29
|
const value = hook.memoizedState;
|
|
34
|
-
|
|
30
|
+
// 26.1007 的按会话订阅状态为 [value, store, atom],value 不再重复存 conversationId。
|
|
31
|
+
const record=Array.isArray(value) ? value[0] : value;
|
|
32
|
+
if (record && typeof record === "object" && "owner" in record && typeof record.presentation === "string"
|
|
33
|
+
&& (record.conversationId == null || record.conversationId === session.conversationId)) receipt = record;
|
|
35
34
|
}
|
|
36
35
|
if (receipt) break;
|
|
37
36
|
}
|
|
@@ -43,16 +42,21 @@ export function createQuickChatAdapter(codex) {
|
|
|
43
42
|
codex.props(button, props => props.variant === "composer" && typeof props.onProjectChange === "function"));
|
|
44
43
|
const projectRail = project?.closest('[data-composer-rail-item]') ?? null;
|
|
45
44
|
const expanded = Boolean(floating.presentation === "expanded" || floating.forceExpanded);
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
const emitter = controller?.eventEmitter;
|
|
46
|
+
const subscribable = typeof emitter?.addListener === "function" && typeof emitter?.removeListener === "function";
|
|
47
|
+
if (subscribable && !subscriptions.has(emitter)) subscriptions.set(emitter, nextSubscription++);
|
|
48
|
+
const snapshot = {surface, editable, minimize, projectRail, background:!session.hasConversation && floating.forceExpanded ? background : null, sessionId:session.conversationId, hasConversation:session.hasConversation,
|
|
49
|
+
canSubmit:Boolean(state && !state.submitDisabled && !state.submitLoading), receiptId:receipt ? receipts.get(receipt) : 0, receiptPresentation:receipt?.presentation ?? null, subscriptionId:subscribable ? subscriptions.get(emitter) : 0,
|
|
50
|
+
expanded, showHistory:Boolean(minimize && !expanded), historyVisible:quickChatHistoryVisible(floating.renderTranscript?.()),
|
|
49
51
|
expand:() => floating.onPresentationChange("expanded"),
|
|
50
52
|
// 历史动作通过 forceExpanded 临时展开;不要覆盖最小化后的恢复形态。
|
|
51
53
|
history:() => history.onSelect()};
|
|
54
|
+
if (subscribable) emitters.set(snapshot, emitter);
|
|
55
|
+
return snapshot;
|
|
52
56
|
}
|
|
53
57
|
function surfaces() { return [...document.querySelectorAll(surfaceSelector)].map(read).filter(Boolean); }
|
|
54
58
|
function subscribe(snapshot, listener) {
|
|
55
|
-
const emitter = snapshot
|
|
59
|
+
const emitter = emitters.get(snapshot);
|
|
56
60
|
if (!emitter?.addListener || !emitter?.removeListener) return () => {};
|
|
57
61
|
// 不改变原生 emit 的 handled 结果,也不接管发送。
|
|
58
62
|
const submit = () => { listener(); return false; };
|
|
@@ -8,8 +8,24 @@ export function quickChatOpenExport(source) {
|
|
|
8
8
|
return name;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
// 新建和恢复共用原生打开状态;退出动画残留的 DOM 不代表会话仍打开。
|
|
12
|
+
export function quickChatLifecycleExports(source) {
|
|
13
|
+
const open = quickChatOpenExport(source);
|
|
14
|
+
const exports = source.slice(source.lastIndexOf('export{'));
|
|
15
|
+
const escaped = value => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
16
|
+
const local = exports.match(new RegExp(`(?:\\{|,)([\\w$]+) as ${escaped(open)}(?:,|\\})`))?.[1];
|
|
17
|
+
const start = source.indexOf(`function ${local}(`);
|
|
18
|
+
const body = source.slice(start, source.indexOf('function ', start + 9));
|
|
19
|
+
const create = body.match(/if\([\w$]+==null\)\{([\w$]+)\([\w$]+,[\w$]+\);return\}/)?.[1];
|
|
20
|
+
const state = body.match(/[\w$]+\.get\(([\w$]+)\)\|\|/)?.[1];
|
|
21
|
+
const exportOf = name => name && exports.match(new RegExp(`(?:\\{|,)${escaped(name)} as ([\\w$]+)(?:,|\\})`))?.[1];
|
|
22
|
+
const createExport = exportOf(create), openState = exportOf(state);
|
|
23
|
+
if (!createExport || !openState) throw new Error('quick-chat-lifecycle-contract-unavailable');
|
|
24
|
+
return {open, create:createExport, openState};
|
|
25
|
+
}
|
|
26
|
+
|
|
11
27
|
export function installQuickChatShortcut(signal, codex, discover = null) {
|
|
12
|
-
let bindings = null, disposed = false;
|
|
28
|
+
let bindings = null, disposed = false, pendingFocus = null;
|
|
13
29
|
function activateExisting() {
|
|
14
30
|
// 原生恢复按钮同时恢复 presentation、取消最小化并聚焦输入框。
|
|
15
31
|
for (const button of document.querySelectorAll('button')) {
|
|
@@ -33,6 +49,20 @@ export function installQuickChatShortcut(signal, codex, discover = null) {
|
|
|
33
49
|
}
|
|
34
50
|
return false;
|
|
35
51
|
}
|
|
52
|
+
function sessionId(surface) { return codex.props(surface,p=>p.session?.conversationId)?.session?.conversationId; }
|
|
53
|
+
function focusNew() {
|
|
54
|
+
if (!pendingFocus || disposed || signal.aborted) return;
|
|
55
|
+
if (!bindings.isOpen(pendingFocus.scope)) { pendingFocus=null; return; }
|
|
56
|
+
for (const surface of document.querySelectorAll('[data-floating-chat-surface]')) {
|
|
57
|
+
const id=sessionId(surface);
|
|
58
|
+
if (!id || pendingFocus.previous.has(id) || surface.closest('[hidden], [inert], [aria-hidden="true"]')) continue;
|
|
59
|
+
const editable=surface.querySelector('[data-chatgpt-composer] [contenteditable="true"]');
|
|
60
|
+
if (!editable?.checkVisibility({visibilityProperty:true})) continue;
|
|
61
|
+
pendingFocus=null;
|
|
62
|
+
editable.focus({preventScroll:true});
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
36
66
|
function context() {
|
|
37
67
|
for (const button of document.querySelectorAll('button[aria-haspopup="menu"]')) {
|
|
38
68
|
if (!button.checkVisibility({visibilityProperty:true})) continue;
|
|
@@ -56,9 +86,10 @@ export function installQuickChatShortcut(signal, codex, discover = null) {
|
|
|
56
86
|
const commands = Object.values(module).find(v => Array.isArray(v) && v.some(c => c?.id === 'temporaryChat') && v.some(c => c?.id === 'newTask'));
|
|
57
87
|
if (!commands) throw new Error('quick-chat-command-catalog-unavailable');
|
|
58
88
|
if (commands.some(c => c.id === 'quickChat')) return {native:true};
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
89
|
+
const roles = quickChatLifecycleExports(source);
|
|
90
|
+
const open = module[roles.open], create = module[roles.create], openState = module[roles.openState];
|
|
91
|
+
if (typeof open !== 'function' || typeof create !== 'function' || !openState) throw new Error('quick-chat-open-action-unavailable');
|
|
92
|
+
return {native:false, open, create, isOpen:scope => scope.get(openState)};
|
|
62
93
|
}
|
|
63
94
|
const ready = (discover ?? load)().then(value => {
|
|
64
95
|
if (disposed || signal.aborted) return;
|
|
@@ -68,8 +99,12 @@ export function installQuickChatShortcut(signal, codex, discover = null) {
|
|
|
68
99
|
function keydown(event) {
|
|
69
100
|
if (disposed || signal.aborted || bindings?.native || event.defaultPrevented || event.repeat || event.isComposing
|
|
70
101
|
|| !event.metaKey || !event.altKey || event.ctrlKey || event.shiftKey || event.code !== 'KeyN') return;
|
|
71
|
-
|
|
72
|
-
|
|
102
|
+
const scope = bindings && context();
|
|
103
|
+
if (scope && bindings.isOpen(scope) === false) {
|
|
104
|
+
pendingFocus={scope,previous:new Set([...document.querySelectorAll('[data-floating-chat-surface]')].map(sessionId))};
|
|
105
|
+
bindings.create(scope);
|
|
106
|
+
focusNew();
|
|
107
|
+
} else if (!activateExisting()) {
|
|
73
108
|
if (!scope) return;
|
|
74
109
|
bindings.open(scope);
|
|
75
110
|
}
|
|
@@ -77,7 +112,7 @@ export function installQuickChatShortcut(signal, codex, discover = null) {
|
|
|
77
112
|
event.stopPropagation();
|
|
78
113
|
}
|
|
79
114
|
document.addEventListener('keydown', keydown, {signal});
|
|
80
|
-
function dispose() { disposed = true; document.removeEventListener('keydown', keydown); bindings = null; }
|
|
115
|
+
function dispose() { disposed = true; document.removeEventListener('keydown', keydown); bindings = null; pendingFocus=null; }
|
|
81
116
|
signal.addEventListener('abort', dispose, {once:true});
|
|
82
|
-
return {ready, dispose};
|
|
117
|
+
return {ready, dispose, sync:focusNew};
|
|
83
118
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const exitRepair = installQuickChatExitRepair(signal, createQuickChatExitAdapter(config.codex));
|
|
1
2
|
const native = createQuickChatAdapter(config.codex);
|
|
2
3
|
const shortcut = installQuickChatShortcut(signal, config.codex);
|
|
3
4
|
const pin = installQuickChatPin(signal, config);
|
|
@@ -24,15 +25,16 @@ function releaseProjectRail(instance) { instance.projectRail?.removeAttribute('d
|
|
|
24
25
|
function remove(instance) { releaseBackground(instance); releaseProjectRail(instance); instance.minimize?.removeAttribute('data-mcx-quick-chat-minimize'); instance.unsubscribe(); instance.button?.remove(); instance.tracker.clear(); instance.historyTracker.clear(); }
|
|
25
26
|
function sync() {
|
|
26
27
|
if (disposed) return;
|
|
28
|
+
shortcut.sync();
|
|
27
29
|
pin.sync();
|
|
28
30
|
const snapshots = native.surfaces(), active = new Set();
|
|
29
31
|
for (const snapshot of snapshots) {
|
|
30
32
|
active.add(snapshot.surface);
|
|
31
33
|
let instance = instances.get(snapshot.surface);
|
|
32
34
|
const selected = instance?.historyTracker.selected(snapshot);
|
|
33
|
-
if (!instance || instance.sessionId !== snapshot.sessionId || instance.
|
|
35
|
+
if (!instance || instance.sessionId !== snapshot.sessionId || instance.subscriptionId !== snapshot.subscriptionId) {
|
|
34
36
|
if (instance) remove(instance);
|
|
35
|
-
instance = {sessionId:snapshot.sessionId,
|
|
37
|
+
instance = {sessionId:snapshot.sessionId, subscriptionId:snapshot.subscriptionId, tracker:createSubmissionTracker(), historyTracker:createHistoryTracker(), button:null};
|
|
36
38
|
const begin = () => { const current = native.read(snapshot.surface); if (current) instance.tracker.begin(current); };
|
|
37
39
|
instance.unsubscribe = native.subscribe(snapshot, begin);
|
|
38
40
|
instances.set(snapshot.surface, instance);
|
|
@@ -98,7 +100,7 @@ config.registerSelfCheck?.(() => {
|
|
|
98
100
|
const available = (!anchors.length || history) && (!pinned.applicable || pinned.available);
|
|
99
101
|
return {state:applicable ? available ? 'available' : 'unavailable' : 'not-applicable',
|
|
100
102
|
reason:applicable ? available ? null : 'quick-chat-controls-unavailable' : 'no-classic-quick-chat-floating-controls',
|
|
101
|
-
checks:[...(anchors.length ? [{name:'quick-chat-history',available:history}] : []), ...(pinned.applicable ? [{name:'quick-chat-pin',available:pinned.available}] : [])],
|
|
103
|
+
checks:[{name:"native-exit-observer",available:exitRepair.status()}, ...(anchors.length ? [{name:'quick-chat-history',available:history}] : []), ...(pinned.applicable ? [{name:'quick-chat-pin',available:pinned.available}] : [])],
|
|
102
104
|
scopes:snapshots.map(item=>({name:'quick-chat',element:item.surface}))};
|
|
103
105
|
});
|
|
104
|
-
return () => { disposed = true; shortcut.dispose(); pin.dispose(); observer.disconnect(); for (const instance of instances.values()) remove(instance); instances.clear(); style.remove(); };
|
|
106
|
+
return () => { disposed = true; exitRepair.dispose(); shortcut.dispose(); pin.dispose(); observer.disconnect(); for (const instance of instances.values()) remove(instance); instances.clear(); style.remove(); };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function installQuickChatExitRepair(signal, native) {
|
|
2
|
+
let scheduled = false, disposed = false;
|
|
3
|
+
function schedule() {
|
|
4
|
+
if (scheduled || disposed) return;
|
|
5
|
+
scheduled = true;
|
|
6
|
+
queueMicrotask(() => { scheduled = false; if (!disposed) native.reconcile(); });
|
|
7
|
+
}
|
|
8
|
+
const observer = new MutationObserver(schedule);
|
|
9
|
+
observer.observe(document.documentElement, {subtree:true, childList:true, attributes:true, attributeFilter:['style']});
|
|
10
|
+
schedule();
|
|
11
|
+
function dispose() { disposed = true; observer.disconnect(); }
|
|
12
|
+
signal.addEventListener('abort',dispose,{once:true});
|
|
13
|
+
return {dispose,status:()=>!disposed};
|
|
14
|
+
}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
import {quickChatHistoryVisible} from "./adapters/codex/history.mjs";
|
|
2
|
+
import {createQuickChatExitAdapter} from "./adapters/codex/presence.mjs";
|
|
3
|
+
import {installQuickChatExitRepair} from "./frontend/exit.mjs";
|
|
1
4
|
import { readFile } from "node:fs/promises";
|
|
2
5
|
import { createQuickChatAdapter } from "./adapters/codex/renderer.mjs";
|
|
3
|
-
import { quickChatOpenExport, installQuickChatShortcut } from "./adapters/codex/shortcut.mjs";
|
|
6
|
+
import { quickChatOpenExport, quickChatLifecycleExports, installQuickChatShortcut } from "./adapters/codex/shortcut.mjs";
|
|
4
7
|
import { createSubmissionTracker } from "./domain/submission.mjs";
|
|
5
8
|
import { createQuickChatPinAdapter } from "./adapters/codex/pin.mjs";
|
|
6
9
|
import { installQuickChatPin } from "./frontend/pin.mjs";
|
|
7
10
|
import { createHistoryTracker } from "./domain/history.mjs";
|
|
8
11
|
export async function createPageScriptSource() {
|
|
9
12
|
const source = await readFile(new URL("./frontend/entry.mjs", import.meta.url), "utf8");
|
|
10
|
-
return `const createQuickChatPinAdapter=${createQuickChatPinAdapter.toString()};\nconst installQuickChatPin=${installQuickChatPin.toString()};\nconst quickChatOpenExport=${quickChatOpenExport.toString()};\nconst installQuickChatShortcut=${installQuickChatShortcut.toString()};\nconst createQuickChatAdapter=${createQuickChatAdapter.toString()};\nconst createSubmissionTracker=${createSubmissionTracker.toString()};\nconst createHistoryTracker=${createHistoryTracker.toString()};\n${source}`;
|
|
13
|
+
return `const quickChatHistoryVisible=${quickChatHistoryVisible.toString()};\nconst createQuickChatExitAdapter=${createQuickChatExitAdapter.toString()};\nconst installQuickChatExitRepair=${installQuickChatExitRepair.toString()};\nconst createQuickChatPinAdapter=${createQuickChatPinAdapter.toString()};\nconst installQuickChatPin=${installQuickChatPin.toString()};\nconst quickChatOpenExport=${quickChatOpenExport.toString()};\nconst quickChatLifecycleExports=${quickChatLifecycleExports.toString()};\nconst installQuickChatShortcut=${installQuickChatShortcut.toString()};\nconst createQuickChatAdapter=${createQuickChatAdapter.toString()};\nconst createSubmissionTracker=${createSubmissionTracker.toString()};\nconst createHistoryTracker=${createHistoryTracker.toString()};\n${source}`;
|
|
11
14
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "minecodex",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.30",
|
|
4
4
|
"description": "Lightweight, local-first plugins for the Codex desktop app.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -76,18 +76,14 @@
|
|
|
76
76
|
"apps/dashboard/transport.js",
|
|
77
77
|
"packages/plugin/src",
|
|
78
78
|
"packages/plugin/assets",
|
|
79
|
-
"packages/plugin/plugin.json"
|
|
80
|
-
"features/quick-chat-repair/src",
|
|
81
|
-
"features/quick-chat-repair/assets",
|
|
82
|
-
"features/quick-chat-repair/vendor/lucide-LICENSE",
|
|
83
|
-
"features/quick-chat-repair/codex-feature.json"
|
|
79
|
+
"packages/plugin/plugin.json"
|
|
84
80
|
],
|
|
85
81
|
"engines": {
|
|
86
82
|
"node": ">=22.5.0"
|
|
87
83
|
},
|
|
88
84
|
"scripts": {
|
|
89
85
|
"start": "node packages/cli/bin/mcx.mjs serve",
|
|
90
|
-
"test": "node --test packages/cli/test/*.test.mjs packages/runtime-host/test/*.test.mjs features/model-slider/test/*.test.mjs features/notes/test/*.test.mjs features/images/test/*.test.mjs features/hide-upsell-banner/test/*.test.mjs features/session-status/test/*.test.mjs features/usage-meter/test/*.test.mjs apps/dashboard/test/*.test.mjs features/unread-inbox/test/*.test.mjs features/quick-chat/test/*.test.mjs features/sidebar-focus/test/*.test.mjs features/sites/test/*.test.mjs packages/ui/test/*.test.mjs packages/codex-adapter/test/*.test.mjs features/markdown-reading/test/*.test.mjs features/file-navigation/test/*.test.mjs packages/plugin/test/*.test.mjs
|
|
86
|
+
"test": "node --test packages/cli/test/*.test.mjs packages/runtime-host/test/*.test.mjs features/model-slider/test/*.test.mjs features/notes/test/*.test.mjs features/images/test/*.test.mjs features/hide-upsell-banner/test/*.test.mjs features/session-status/test/*.test.mjs features/usage-meter/test/*.test.mjs apps/dashboard/test/*.test.mjs features/unread-inbox/test/*.test.mjs features/quick-chat/test/*.test.mjs features/sidebar-focus/test/*.test.mjs features/sites/test/*.test.mjs packages/ui/test/*.test.mjs packages/codex-adapter/test/*.test.mjs features/markdown-reading/test/*.test.mjs features/file-navigation/test/*.test.mjs packages/plugin/test/*.test.mjs",
|
|
91
87
|
"test:cli": "node --test packages/cli/test/*.test.mjs",
|
|
92
88
|
"test:runtime": "node --test packages/runtime-host/test/*.test.mjs",
|
|
93
89
|
"check": "node scripts/check-syntax.mjs",
|
|
@@ -2,7 +2,7 @@ import { randomBytes } from "node:crypto";
|
|
|
2
2
|
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
|
|
5
|
-
export const FEATURE_IDS = Object.freeze(["model-slider", "notes", "images", "hide-upsell-banner", "session-status", "usage-meter", "sidebar-focus", "sites", "markdown-reading", "file-navigation", "quick-chat"
|
|
5
|
+
export const FEATURE_IDS = Object.freeze(["model-slider", "notes", "images", "hide-upsell-banner", "session-status", "usage-meter", "sidebar-focus", "sites", "markdown-reading", "file-navigation", "quick-chat"]);
|
|
6
6
|
export const DEFAULT_CONFIG = Object.freeze({
|
|
7
7
|
schemaVersion: 1,
|
|
8
8
|
features: Object.freeze({
|
|
@@ -17,7 +17,6 @@ export const DEFAULT_CONFIG = Object.freeze({
|
|
|
17
17
|
"markdown-reading": true,
|
|
18
18
|
"file-navigation": true,
|
|
19
19
|
"quick-chat": true,
|
|
20
|
-
"quick-chat-repair": true,
|
|
21
20
|
}),
|
|
22
21
|
});
|
|
23
22
|
|
|
@@ -43,6 +42,8 @@ export function normalizeConfig(value = {}) {
|
|
|
43
42
|
};
|
|
44
43
|
// 暂停的 Task 通知不继承旧配置,也不再提供开启入口。
|
|
45
44
|
delete features["unread-inbox"];
|
|
45
|
+
// 退出修复归入 Quick Chat,统一沿用 quick-chat 开关。
|
|
46
|
+
delete features["quick-chat-repair"];
|
|
46
47
|
return {
|
|
47
48
|
...value,
|
|
48
49
|
schemaVersion: 1,
|
|
@@ -14,7 +14,7 @@ import { createDataTransfer, MAX_TRANSFER_BYTES } from "./data-transfer/service.
|
|
|
14
14
|
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../..");
|
|
15
15
|
const packageMetadata = JSON.parse(await readFile(path.join(packageRoot, "package.json"), "utf8"));
|
|
16
16
|
const MAX_BODY_BYTES = 64 * 1024;
|
|
17
|
-
const DASHBOARD_FEATURE_ORDER = ["model-slider", "notes", "usage-meter", "session-status", "markdown-reading", "file-navigation", "images", "sites", "quick-chat", "
|
|
17
|
+
const DASHBOARD_FEATURE_ORDER = ["model-slider", "notes", "usage-meter", "session-status", "markdown-reading", "file-navigation", "images", "sites", "quick-chat", "sidebar-focus", "hide-upsell-banner"];
|
|
18
18
|
const CONTENT_TYPES = new Map([
|
|
19
19
|
[".css", "text/css; charset=utf-8"],
|
|
20
20
|
[".html", "text/html; charset=utf-8"],
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
<!-- @license lucide-static v0.468.0 - ISC -->
|
|
2
|
-
<svg
|
|
3
|
-
class="lucide lucide-history"
|
|
4
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
5
|
-
width="24"
|
|
6
|
-
height="24"
|
|
7
|
-
viewBox="0 0 24 24"
|
|
8
|
-
fill="none"
|
|
9
|
-
stroke="currentColor"
|
|
10
|
-
stroke-width="2"
|
|
11
|
-
stroke-linecap="round"
|
|
12
|
-
stroke-linejoin="round"
|
|
13
|
-
>
|
|
14
|
-
<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" />
|
|
15
|
-
<path d="M3 3v5h5" />
|
|
16
|
-
<path d="M12 7v5l4 2" />
|
|
17
|
-
</svg>
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"schemaVersion": 1,
|
|
3
|
-
"id": "quick-chat-repair",
|
|
4
|
-
"version": "0.1.0",
|
|
5
|
-
"label": {"en":"Quick Chat Exit Repair", "zh-CN":"Quick Chat 退出修复"},
|
|
6
|
-
"description": {"en":"Fix the native transparent layer that blocks clicks after closing Quick Chat.", "zh-CN":"修复关闭 Quick Chat 后透明层残留、主页面无法点击的问题。"},
|
|
7
|
-
"entry": {"kind":"page-script", "script":"src/frontend/entry.mjs", "sourceFactory":"src/injection-source.mjs"},
|
|
8
|
-
"icon": {"resource":"assets/history.svg"},
|
|
9
|
-
"placement": {"order":76}
|
|
10
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
const native = createQuickChatExitAdapter(config.codex);
|
|
2
|
-
let scheduled = false, disposed = false;
|
|
3
|
-
function schedule() {
|
|
4
|
-
if (scheduled || disposed) return;
|
|
5
|
-
scheduled = true;
|
|
6
|
-
queueMicrotask(() => { scheduled = false; if (!disposed) native.reconcile(); });
|
|
7
|
-
}
|
|
8
|
-
const observer = new MutationObserver(schedule);
|
|
9
|
-
observer.observe(document.documentElement, {subtree:true, childList:true, attributes:true, attributeFilter:['style']});
|
|
10
|
-
schedule();
|
|
11
|
-
config.registerSelfCheck?.(() => ({state:'available', checks:[{name:'native-exit-observer', available:!disposed}], scopes:[]}));
|
|
12
|
-
return () => { disposed = true; observer.disconnect(); };
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import {readFile} from 'node:fs/promises';
|
|
2
|
-
import {createQuickChatExitAdapter} from './adapters/codex/presence.mjs';
|
|
3
|
-
export async function createPageScriptSource() {
|
|
4
|
-
return `const createQuickChatExitAdapter=${createQuickChatExitAdapter.toString()};\n${await readFile(new URL('./frontend/entry.mjs', import.meta.url), 'utf8')}`;
|
|
5
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
ISC License
|
|
2
|
-
|
|
3
|
-
Copyright (c) for portions of Lucide are held by Cole Bemis 2013-2022 as part of Feather (MIT). All other copyright (c) for Lucide are held by Lucide Contributors 2022.
|
|
4
|
-
|
|
5
|
-
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
-
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
-
copyright notice and this permission notice appear in all copies.
|
|
8
|
-
|
|
9
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
-
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
-
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
-
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
-
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
-
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
-
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
File without changes
|