@michengai/dsh-codex-ui 0.2.103 → 0.2.105
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/CHANGELOG.md +20 -0
- package/CHANGELOG.zh-CN.md +20 -0
- package/README.md +2 -0
- package/README.zh-CN.md +5 -0
- package/lib/client.js +287 -4
- package/lib/index.mjs +8 -0
- package/package.json +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,26 @@
|
|
|
4
4
|
|
|
5
5
|
This changelog records recent releases of DSH Codex UI and its one-click installer. Earlier changes remain available in the [Git history](https://github.com/MichengAI/dsh-codex-ui/commits/main).
|
|
6
6
|
|
|
7
|
+
## 0.2.105 — 2026-09-06
|
|
8
|
+
|
|
9
|
+
- Added Simplify directly below BTW on the About page, with version status, install, update, and bulk-update support.
|
|
10
|
+
|
|
11
|
+
## suite-installer-v0.1.22 — 2026-09-06
|
|
12
|
+
|
|
13
|
+
- Updated the bundled Codex UI to `0.2.105`, adding Simplify management to the About page.
|
|
14
|
+
- Updated Automation to `0.1.32`; other Suite members remain unchanged.
|
|
15
|
+
|
|
16
|
+
## 0.2.104 — 2026-09-06
|
|
17
|
+
|
|
18
|
+
- Added input history: press Up/Down in an empty composer to recall previously sent text. Each project keeps its own history.
|
|
19
|
+
- Added BTW to the About page, with version information and install/update actions.
|
|
20
|
+
- Shortened the archive plugin label to "Archived conversations".
|
|
21
|
+
|
|
22
|
+
## suite-installer-v0.1.21 — 2026-09-06
|
|
23
|
+
|
|
24
|
+
- Updated the bundled Codex UI to `0.2.104`, adding Up/Down input history and a BTW entry on the About page.
|
|
25
|
+
- Updated Skills Manager, Agency Agents, and Automation.
|
|
26
|
+
|
|
7
27
|
## 0.2.103 — 2026-09-04
|
|
8
28
|
|
|
9
29
|
Companion release: `@michengai/dsh-codex-suite-installer@0.1.20`.
|
package/CHANGELOG.zh-CN.md
CHANGED
|
@@ -4,6 +4,26 @@
|
|
|
4
4
|
|
|
5
5
|
本日志记录 DSH Codex UI 及其一键安装器的最近发布;更早的变更可查看 [Git 提交历史](https://github.com/MichengAI/dsh-codex-ui/commits/main)。
|
|
6
6
|
|
|
7
|
+
## 0.2.105 — 2026-09-06
|
|
8
|
+
|
|
9
|
+
- 关于页在 BTW 下方新增 Simplify,支持查看版本状态、安装、更新和批量更新。
|
|
10
|
+
|
|
11
|
+
## suite-installer-v0.1.22 — 2026-09-06
|
|
12
|
+
|
|
13
|
+
- 更新套件中的 Codex UI 至 `0.2.105`,在关于页新增 Simplify 管理入口。
|
|
14
|
+
- 更新 Automation 至 `0.1.32`,其他套件成员保持不变。
|
|
15
|
+
|
|
16
|
+
## 0.2.104 — 2026-09-06
|
|
17
|
+
|
|
18
|
+
- 新增输入历史:输入框为空时,按上下方向键即可找回之前发送的内容,各项目的历史独立保存。
|
|
19
|
+
- 关于页新增 BTW 旁问插件,支持查看版本、安装和更新。
|
|
20
|
+
- 将“归档会话管理”更名为“归档会话”。
|
|
21
|
+
|
|
22
|
+
## suite-installer-v0.1.21 — 2026-09-06
|
|
23
|
+
|
|
24
|
+
- 更新套件中的 Codex UI 至 `0.2.104`,新增上下键输入历史和 BTW 旁问插件入口。
|
|
25
|
+
- 同步更新 Skills Manager、Agency Agents 和 Automation。
|
|
26
|
+
|
|
7
27
|
## 0.2.103 — 2026-09-04
|
|
8
28
|
|
|
9
29
|
配套版本:`@michengai/dsh-codex-suite-installer@0.1.20`。
|
package/README.md
CHANGED
|
@@ -27,6 +27,8 @@
|
|
|
27
27
|
- List workspaces and conversations with expand/collapse, drag reorder, project pinning, unread dots, and running-state indicators.
|
|
28
28
|
- Add project and conversation menus for rename, pin, unread, archive, fork, open folder, copy, and delete.
|
|
29
29
|
- Restyle the conversation column and composer card, and add a compact turn navigator on the current session.
|
|
30
|
+
- Recall submitted text with Up/Down from an empty composer, with workspace isolation and guards for drafts, IME, and candidate menus. BTW is not required.
|
|
31
|
+
- Capture ordinary messages only from live events while the input extension is mounted. Opening or reloading conversations and loading older messages do not backfill history; input sent while the extension is unmounted is not imported.
|
|
30
32
|
- Show companion-plugin status in **Settings → About**, and install the missing pieces from npm.
|
|
31
33
|
|
|
32
34
|
## Screenshots
|
package/README.zh-CN.md
CHANGED
|
@@ -27,10 +27,15 @@
|
|
|
27
27
|
- 工作区与会话支持展开折叠、拖拽排序、项目置顶、未读圆点和运行状态。
|
|
28
28
|
- 项目和会话菜单支持重命名、置顶、未读、归档、派生、打开目录、复制和删除。
|
|
29
29
|
- 调整会话列与输入卡片视觉,并为当前会话提供紧凑轮次导航。
|
|
30
|
+
- 空输入框按上下键召回已提交文本,按工作区隔离并保护草稿、输入法和候选菜单;无需安装 BTW。
|
|
30
31
|
- 在「设置 → 关于」展示配套插件状态,并可从 npm 安装缺失项。
|
|
31
32
|
|
|
32
33
|
## 界面预览
|
|
33
34
|
|
|
35
|
+
输入历史保存在浏览器 `michengai.codex-ui.input-history.v1`,每工作区最多 200 条、最多 20 个工作区,总序列化长度最多 100 万字符。首次使用可导入旧 BTW 历史,保留旧键用于回退;关闭浏览器存储时使用内存。BTW 插件现在只负责旁问气泡。
|
|
36
|
+
|
|
37
|
+
普通消息仅从输入扩展挂载后的实时追加事件采集;打开、重载会话和加载旧消息不会回填历史,扩展未挂载期间的输入也不补录。
|
|
38
|
+
|
|
34
39
|
浅色主题:Codex 风格侧栏、工作区会话树和会话列。
|
|
35
40
|
|
|
36
41
|

|
package/lib/client.js
CHANGED
|
@@ -5952,6 +5952,14 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
5952
5952
|
id: "schedule",
|
|
5953
5953
|
packageName: "@michengai/dsh-automation"
|
|
5954
5954
|
},
|
|
5955
|
+
{
|
|
5956
|
+
id: "btw",
|
|
5957
|
+
packageName: "@michengai/dsh-btw"
|
|
5958
|
+
},
|
|
5959
|
+
{
|
|
5960
|
+
id: "simplify",
|
|
5961
|
+
packageName: "@michengai/dsh-simplify"
|
|
5962
|
+
},
|
|
5955
5963
|
{
|
|
5956
5964
|
id: "market",
|
|
5957
5965
|
packageName: "dshmarket"
|
|
@@ -6482,6 +6490,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
6482
6490
|
/** 本插件独占的界面文案命名空间。 */
|
|
6483
6491
|
const NS = "michengai.codexUi";
|
|
6484
6492
|
const zh = {
|
|
6493
|
+
"input.historyHint": "↑↓ 翻历史",
|
|
6485
6494
|
"sidebar.label": "DSH 导航",
|
|
6486
6495
|
"sidebar.expand": "展开侧边栏",
|
|
6487
6496
|
"sidebar.collapse": "收缩侧边栏",
|
|
@@ -6628,7 +6637,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
6628
6637
|
"about.feature.conversation": "保留原生消息、工具调用、输入、权限和模型选择,仅调整容器视觉",
|
|
6629
6638
|
"about.feature.navigator": "当前会话提供轮次缩略导航,可快速跳转至每一次用户提问",
|
|
6630
6639
|
"about.dependencies": "配套管理插件",
|
|
6631
|
-
"about.dependenciesDescription": "每个配套插件都可单独安装和更新,也可一键安装缺失项并更新旧版本。可分别检查 Codex UI、专家、技能、归档、IM
|
|
6640
|
+
"about.dependenciesDescription": "每个配套插件都可单独安装和更新,也可一键安装缺失项并更新旧版本。可分别检查 Codex UI、专家、技能、归档、IM、定时任务、BTW 和第三方插件市场。",
|
|
6632
6641
|
"about.loading": "正在读取依赖安装状态…",
|
|
6633
6642
|
"about.statusFailed": "暂时无法读取依赖安装状态。",
|
|
6634
6643
|
"about.refreshFailed": "依赖状态刷新失败,当前显示上次成功读取的结果。",
|
|
@@ -6662,9 +6671,11 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
6662
6671
|
"about.dependency.ui": "Codex UI",
|
|
6663
6672
|
"about.dependency.experts": "专家管理",
|
|
6664
6673
|
"about.dependency.skills": "技能管理",
|
|
6665
|
-
"about.dependency.archive": "
|
|
6674
|
+
"about.dependency.archive": "归档会话",
|
|
6666
6675
|
"about.dependency.im": "IM助理",
|
|
6667
6676
|
"about.dependency.schedule": "定时任务",
|
|
6677
|
+
"about.dependency.btw": "BTW 旁问",
|
|
6678
|
+
"about.dependency.simplify": "Simplify",
|
|
6668
6679
|
"about.dependency.market": "插件市场",
|
|
6669
6680
|
"turns.label": "当前会话轮次导航",
|
|
6670
6681
|
"turns.untitled": "未命名提问",
|
|
@@ -6681,6 +6692,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
6681
6692
|
"meta.locale": "zh-CN"
|
|
6682
6693
|
};
|
|
6683
6694
|
const en = {
|
|
6695
|
+
"input.historyHint": "↑↓ History",
|
|
6684
6696
|
"sidebar.label": "DSH navigation",
|
|
6685
6697
|
"sidebar.expand": "Expand sidebar",
|
|
6686
6698
|
"sidebar.collapse": "Collapse sidebar",
|
|
@@ -6827,7 +6839,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
6827
6839
|
"about.feature.conversation": "Keeps native messages, tool calls, composer, permissions, and model selection while refining the container visuals",
|
|
6828
6840
|
"about.feature.navigator": "Navigate directly to each user prompt with the current conversation turn navigator",
|
|
6829
6841
|
"about.dependencies": "Companion management plugins",
|
|
6830
|
-
"about.dependenciesDescription": "Install or update each companion separately, or install missing plugins and update old versions in one action. Check Codex UI, expert, skill, archive, IM, scheduled-task, and marketplace plugins on their own.",
|
|
6842
|
+
"about.dependenciesDescription": "Install or update each companion separately, or install missing plugins and update old versions in one action. Check Codex UI, expert, skill, archive, IM, scheduled-task, BTW, and marketplace plugins on their own.",
|
|
6831
6843
|
"about.loading": "Loading dependency status…",
|
|
6832
6844
|
"about.statusFailed": "Dependency status is temporarily unavailable.",
|
|
6833
6845
|
"about.refreshFailed": "Dependency status refresh failed. Showing the last successful result.",
|
|
@@ -6861,9 +6873,11 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
6861
6873
|
"about.dependency.ui": "Codex UI",
|
|
6862
6874
|
"about.dependency.experts": "Expert management",
|
|
6863
6875
|
"about.dependency.skills": "Skill management",
|
|
6864
|
-
"about.dependency.archive": "Archived
|
|
6876
|
+
"about.dependency.archive": "Archived conversations",
|
|
6865
6877
|
"about.dependency.im": "IM Assistant",
|
|
6866
6878
|
"about.dependency.schedule": "Scheduled tasks",
|
|
6879
|
+
"about.dependency.btw": "BTW",
|
|
6880
|
+
"about.dependency.simplify": "Simplify",
|
|
6867
6881
|
"about.dependency.market": "Plugin Market",
|
|
6868
6882
|
"turns.label": "Conversation turn navigation",
|
|
6869
6883
|
"turns.untitled": "Untitled prompt",
|
|
@@ -7463,6 +7477,273 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
7463
7477
|
});
|
|
7464
7478
|
}
|
|
7465
7479
|
//#endregion
|
|
7480
|
+
//#region src/client/input-history.ts
|
|
7481
|
+
const HISTORY_KEY = "michengai.codex-ui.input-history.v1";
|
|
7482
|
+
const LEGACY_HISTORY_KEY = "michengai.btw.history.v1";
|
|
7483
|
+
const MAX_STORAGE_LENGTH = 1e6;
|
|
7484
|
+
/** 只保存已发送文本;浏览器存储失败时仍保留本次内存历史。 */
|
|
7485
|
+
var InputHistory = class {
|
|
7486
|
+
storage;
|
|
7487
|
+
limit;
|
|
7488
|
+
warn;
|
|
7489
|
+
scopes = /* @__PURE__ */ new Map();
|
|
7490
|
+
constructor(storage, limit = 200, warn = console.warn) {
|
|
7491
|
+
this.storage = storage;
|
|
7492
|
+
this.limit = limit;
|
|
7493
|
+
this.warn = warn;
|
|
7494
|
+
try {
|
|
7495
|
+
const current = storage?.getItem(HISTORY_KEY);
|
|
7496
|
+
const raw = current ?? storage?.getItem(LEGACY_HISTORY_KEY);
|
|
7497
|
+
if (!raw) return;
|
|
7498
|
+
if (raw.length > MAX_STORAGE_LENGTH) throw new Error("历史数据过大");
|
|
7499
|
+
const data = JSON.parse(raw);
|
|
7500
|
+
if (typeof data !== "object" || data === null || Array.isArray(data)) throw new Error("历史格式无效");
|
|
7501
|
+
for (const [key, value] of Object.entries(data).slice(-20)) if (Array.isArray(value)) this.scopes.set(key, value.filter((item) => typeof item === "string" && item.length <= 8e3).slice(-limit));
|
|
7502
|
+
if (current === null || current === void 0) storage?.setItem(HISTORY_KEY, JSON.stringify(Object.fromEntries(this.scopes)));
|
|
7503
|
+
} catch {
|
|
7504
|
+
warn("输入历史读取失败,本次使用内存历史。");
|
|
7505
|
+
}
|
|
7506
|
+
}
|
|
7507
|
+
list(scope) {
|
|
7508
|
+
return this.scopes.get(scope) ?? [];
|
|
7509
|
+
}
|
|
7510
|
+
add(scope, text) {
|
|
7511
|
+
if (!text.trim() || text.length > 8e3) return;
|
|
7512
|
+
const previous = this.scopes.get(scope) ?? [];
|
|
7513
|
+
if (previous.at(-1) === text) return;
|
|
7514
|
+
this.scopes.delete(scope);
|
|
7515
|
+
this.scopes.set(scope, [...previous, text].slice(-this.limit));
|
|
7516
|
+
while (this.scopes.size > 20) this.scopes.delete(this.scopes.keys().next().value);
|
|
7517
|
+
let serialized = JSON.stringify(Object.fromEntries(this.scopes));
|
|
7518
|
+
while (serialized.length > MAX_STORAGE_LENGTH && this.scopes.size) {
|
|
7519
|
+
const oldest = this.scopes.keys().next().value;
|
|
7520
|
+
const entries = this.scopes.get(oldest);
|
|
7521
|
+
entries.shift();
|
|
7522
|
+
if (!entries.length) this.scopes.delete(oldest);
|
|
7523
|
+
serialized = JSON.stringify(Object.fromEntries(this.scopes));
|
|
7524
|
+
}
|
|
7525
|
+
try {
|
|
7526
|
+
this.storage?.setItem(HISTORY_KEY, serialized);
|
|
7527
|
+
} catch {
|
|
7528
|
+
this.warn("输入历史无法保存到浏览器,本次仍可使用。");
|
|
7529
|
+
}
|
|
7530
|
+
}
|
|
7531
|
+
};
|
|
7532
|
+
/** 从空输入进入,编辑历史即退出,避免覆盖用户的新草稿。 */
|
|
7533
|
+
var HistoryCursor = class {
|
|
7534
|
+
index;
|
|
7535
|
+
original = "";
|
|
7536
|
+
displayed = "";
|
|
7537
|
+
entries = [];
|
|
7538
|
+
reset() {
|
|
7539
|
+
this.index = void 0;
|
|
7540
|
+
this.entries = [];
|
|
7541
|
+
}
|
|
7542
|
+
move(direction, draft, entries) {
|
|
7543
|
+
if (this.index !== void 0 && draft !== this.displayed) this.reset();
|
|
7544
|
+
if (this.index === void 0) {
|
|
7545
|
+
if (direction !== -1 || draft !== "" || entries.length === 0) return void 0;
|
|
7546
|
+
this.original = draft;
|
|
7547
|
+
this.entries = [...entries];
|
|
7548
|
+
this.index = this.entries.length;
|
|
7549
|
+
}
|
|
7550
|
+
this.index = Math.max(0, Math.min(this.entries.length, this.index + direction));
|
|
7551
|
+
if (this.index === this.entries.length) {
|
|
7552
|
+
const restored = this.original;
|
|
7553
|
+
this.reset();
|
|
7554
|
+
return restored;
|
|
7555
|
+
}
|
|
7556
|
+
this.displayed = this.entries[this.index] ?? "";
|
|
7557
|
+
return this.displayed;
|
|
7558
|
+
}
|
|
7559
|
+
};
|
|
7560
|
+
//#endregion
|
|
7561
|
+
//#region src/client/input-history-keyboard.ts
|
|
7562
|
+
/** 只处理当前输入框的历史按键,保持 IME、菜单和富内容的原有行为。 */
|
|
7563
|
+
function bindHistoryKeys(editor, adapter) {
|
|
7564
|
+
const cursor = new HistoryCursor();
|
|
7565
|
+
let composing = false;
|
|
7566
|
+
let writingHistory = false;
|
|
7567
|
+
const begin = () => {
|
|
7568
|
+
composing = true;
|
|
7569
|
+
};
|
|
7570
|
+
const end = () => {
|
|
7571
|
+
composing = false;
|
|
7572
|
+
};
|
|
7573
|
+
const changed = () => {
|
|
7574
|
+
if (!writingHistory) cursor.reset();
|
|
7575
|
+
};
|
|
7576
|
+
const keydown = (event) => {
|
|
7577
|
+
if (event.target !== editor && !editor.contains(event.target)) return;
|
|
7578
|
+
if (event.defaultPrevented || composing || event.isComposing || event.keyCode === 229 || event.ctrlKey || event.metaKey || event.altKey || event.shiftKey || adapter.blocked()) return;
|
|
7579
|
+
if (event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
|
|
7580
|
+
const draft = adapter.draft();
|
|
7581
|
+
if (draft !== "" && !atHistoryBoundary(editor)) return;
|
|
7582
|
+
const next = cursor.move(event.key === "ArrowUp" ? -1 : 1, draft, adapter.entries());
|
|
7583
|
+
if (next === void 0) return;
|
|
7584
|
+
event.preventDefault();
|
|
7585
|
+
event.stopImmediatePropagation();
|
|
7586
|
+
writingHistory = true;
|
|
7587
|
+
try {
|
|
7588
|
+
adapter.setDraft(next);
|
|
7589
|
+
} finally {
|
|
7590
|
+
writingHistory = false;
|
|
7591
|
+
}
|
|
7592
|
+
};
|
|
7593
|
+
editor.addEventListener("compositionstart", begin);
|
|
7594
|
+
editor.addEventListener("compositionend", end);
|
|
7595
|
+
editor.addEventListener("input", changed);
|
|
7596
|
+
editor.addEventListener("keydown", keydown, true);
|
|
7597
|
+
return () => {
|
|
7598
|
+
editor.removeEventListener("compositionstart", begin);
|
|
7599
|
+
editor.removeEventListener("compositionend", end);
|
|
7600
|
+
editor.removeEventListener("input", changed);
|
|
7601
|
+
editor.removeEventListener("keydown", keydown, true);
|
|
7602
|
+
};
|
|
7603
|
+
}
|
|
7604
|
+
/** 召回文本中间或存在选区时,保留宿主编辑器的垂直光标移动。 */
|
|
7605
|
+
function atHistoryBoundary(editor) {
|
|
7606
|
+
if (editor instanceof HTMLTextAreaElement) return editor.selectionStart === editor.selectionEnd && (editor.selectionStart === 0 || editor.selectionEnd === editor.value.length);
|
|
7607
|
+
const selection = editor.ownerDocument.getSelection();
|
|
7608
|
+
if (!selection?.isCollapsed || !selection.rangeCount || !editor.contains(selection.anchorNode)) return false;
|
|
7609
|
+
const caret = selection.getRangeAt(0);
|
|
7610
|
+
const before = editor.ownerDocument.createRange();
|
|
7611
|
+
before.selectNodeContents(editor);
|
|
7612
|
+
before.setEnd(caret.startContainer, caret.startOffset);
|
|
7613
|
+
const after = editor.ownerDocument.createRange();
|
|
7614
|
+
after.selectNodeContents(editor);
|
|
7615
|
+
after.setStart(caret.endContainer, caret.endOffset);
|
|
7616
|
+
return before.toString() === "" || after.toString() === "";
|
|
7617
|
+
}
|
|
7618
|
+
/** 从本 slot 向上寻找唯一输入框,避免绑定侧栏、搜索或其他会话。 */
|
|
7619
|
+
function findComposer(anchor) {
|
|
7620
|
+
let parent = anchor.parentElement;
|
|
7621
|
+
while (parent && parent !== document.body) {
|
|
7622
|
+
const editors = parent.querySelectorAll("textarea:not([disabled]), [data-lexical-editor=\"true\"][contenteditable=\"true\"]");
|
|
7623
|
+
if (editors.length === 1) return editors[0];
|
|
7624
|
+
if (editors.length > 1) return void 0;
|
|
7625
|
+
parent = parent.parentElement;
|
|
7626
|
+
}
|
|
7627
|
+
}
|
|
7628
|
+
//#endregion
|
|
7629
|
+
//#region src/client/InputHistoryDock.tsx
|
|
7630
|
+
function InputHistoryHint({ t }) {
|
|
7631
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: `
|
|
7632
|
+
[data-composer-card] [data-input-scroll]{container:dcu-composer-input / inline-size}
|
|
7633
|
+
[data-composer-card] [data-composer-placeholder]{display:flex;align-items:baseline;justify-content:space-between;gap:12px}
|
|
7634
|
+
[data-composer-card] [data-composer-placeholder]::after{
|
|
7635
|
+
content:${JSON.stringify(t("input.historyHint"))};
|
|
7636
|
+
color:var(--dsw-alias-label-caption);font-size:12px;line-height:18px;
|
|
7637
|
+
white-space:nowrap;flex:0 0 auto;margin-right:8px;
|
|
7638
|
+
}
|
|
7639
|
+
@container dcu-composer-input (max-width:560px){
|
|
7640
|
+
[data-composer-card] [data-composer-placeholder]::after{display:none}
|
|
7641
|
+
}
|
|
7642
|
+
@media(max-width:640px){
|
|
7643
|
+
[data-composer-card] [data-composer-placeholder]::after{display:none}
|
|
7644
|
+
}
|
|
7645
|
+
` });
|
|
7646
|
+
}
|
|
7647
|
+
/** 隐形输入扩展:使用宿主状态和编辑动作,不替换编辑器或创建旁问界面。 */
|
|
7648
|
+
function InputHistoryDock({ ctx, sessionId, history, seen }) {
|
|
7649
|
+
const anchor = (0, react.useRef)(null);
|
|
7650
|
+
(0, react.useEffect)(() => {
|
|
7651
|
+
const binding = ctx.sessions.binding(sessionId);
|
|
7652
|
+
if (binding === void 0) return;
|
|
7653
|
+
const scope = ctx.sessions.list.getSnapshot().byId[sessionId]?.cwd ?? sessionId;
|
|
7654
|
+
const input = ctx.conversation.input.for(binding.ctx);
|
|
7655
|
+
const menu = ctx.inputTriggers.sessionOf(binding.ctx).menu;
|
|
7656
|
+
seen.set(binding, binding.eventSource.getSnapshot().revision);
|
|
7657
|
+
const collect = () => {
|
|
7658
|
+
const snapshot = binding.eventSource.getSnapshot();
|
|
7659
|
+
if (snapshot.change.kind !== "replace" && snapshot.revision <= (seen.get(binding) ?? -1)) return;
|
|
7660
|
+
seen.set(binding, snapshot.revision);
|
|
7661
|
+
if (snapshot.change.kind !== "append") return;
|
|
7662
|
+
for (const entry of snapshot.change.entries) {
|
|
7663
|
+
if (entry.event.type !== "user/message" || entry.event.data.source?.kind !== "user") continue;
|
|
7664
|
+
const text = entry.event.data.content.filter((block) => block.type === "text").map((block) => block.text).join("");
|
|
7665
|
+
history.add(scope, text);
|
|
7666
|
+
}
|
|
7667
|
+
};
|
|
7668
|
+
const offEvents = binding.eventSource.subscribe(collect);
|
|
7669
|
+
let previous = input.state.getSnapshot();
|
|
7670
|
+
const offInput = input.state.subscribe(() => {
|
|
7671
|
+
const next = input.state.getSnapshot();
|
|
7672
|
+
if (previous.phase === "submitting" && next.phase === "plain" && next.draft === "" && previous.imageIds.length === 0 && previous.occurrences.length === 0) history.add(scope, previous.draft);
|
|
7673
|
+
previous = next;
|
|
7674
|
+
});
|
|
7675
|
+
let editor;
|
|
7676
|
+
let offKeys = () => {};
|
|
7677
|
+
const connect = () => {
|
|
7678
|
+
const next = anchor.current === null ? void 0 : findComposer(anchor.current);
|
|
7679
|
+
if (next === editor) return;
|
|
7680
|
+
offKeys();
|
|
7681
|
+
editor = next;
|
|
7682
|
+
if (editor === void 0) return;
|
|
7683
|
+
offKeys = bindHistoryKeys(editor, {
|
|
7684
|
+
draft: () => input.state.getSnapshot().draft,
|
|
7685
|
+
entries: () => history.list(scope),
|
|
7686
|
+
setDraft: (text) => input.setDraft(text),
|
|
7687
|
+
blocked: () => {
|
|
7688
|
+
const state = input.state.getSnapshot();
|
|
7689
|
+
return state.phase === "adjudicating" || state.phase === "submitting" || state.imageIds.length > 0 || state.occurrences.length > 0 || menu.getSnapshot().open;
|
|
7690
|
+
}
|
|
7691
|
+
});
|
|
7692
|
+
};
|
|
7693
|
+
connect();
|
|
7694
|
+
const parent = anchor.current?.parentElement?.parentElement;
|
|
7695
|
+
const observer = new MutationObserver(connect);
|
|
7696
|
+
if (parent !== null && parent !== void 0) observer.observe(parent, {
|
|
7697
|
+
childList: true,
|
|
7698
|
+
subtree: true
|
|
7699
|
+
});
|
|
7700
|
+
return () => {
|
|
7701
|
+
observer.disconnect();
|
|
7702
|
+
offKeys();
|
|
7703
|
+
offInput();
|
|
7704
|
+
offEvents();
|
|
7705
|
+
};
|
|
7706
|
+
}, [
|
|
7707
|
+
ctx,
|
|
7708
|
+
sessionId,
|
|
7709
|
+
history,
|
|
7710
|
+
seen
|
|
7711
|
+
]);
|
|
7712
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7713
|
+
ref: anchor,
|
|
7714
|
+
hidden: true
|
|
7715
|
+
});
|
|
7716
|
+
}
|
|
7717
|
+
function registerInputHistory(ctx) {
|
|
7718
|
+
let storage;
|
|
7719
|
+
try {
|
|
7720
|
+
storage = window.localStorage;
|
|
7721
|
+
} catch {
|
|
7722
|
+
console.warn("[michengai-codex-ui] 浏览器存储不可用,使用内存输入历史。");
|
|
7723
|
+
}
|
|
7724
|
+
const history = new InputHistory(storage);
|
|
7725
|
+
const seen = /* @__PURE__ */ new WeakMap();
|
|
7726
|
+
function Dock(props) {
|
|
7727
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InputHistoryDock, {
|
|
7728
|
+
ctx,
|
|
7729
|
+
sessionId: props.session.sessionId,
|
|
7730
|
+
history,
|
|
7731
|
+
seen
|
|
7732
|
+
});
|
|
7733
|
+
}
|
|
7734
|
+
ctx.slots.inject("conversation.input.dock", () => ctx.slots.register({
|
|
7735
|
+
name: "conversation.input.dock",
|
|
7736
|
+
id: "codex-ui-input-history",
|
|
7737
|
+
order: -100
|
|
7738
|
+
}, Dock));
|
|
7739
|
+
ctx.slots.inject("conversation.input.dock", () => ctx.slots.register({
|
|
7740
|
+
name: "conversation.input.dock",
|
|
7741
|
+
id: "codex-ui-input-history-hint",
|
|
7742
|
+
order: -100,
|
|
7743
|
+
locale: NS
|
|
7744
|
+
}, InputHistoryHint));
|
|
7745
|
+
}
|
|
7746
|
+
//#endregion
|
|
7466
7747
|
//#region src/client/index.ts
|
|
7467
7748
|
const inject = [
|
|
7468
7749
|
"slots",
|
|
@@ -7471,6 +7752,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
7471
7752
|
"layout",
|
|
7472
7753
|
"locale",
|
|
7473
7754
|
"connection",
|
|
7755
|
+
"inputTriggers",
|
|
7474
7756
|
"conversation"
|
|
7475
7757
|
];
|
|
7476
7758
|
function hasDeleteSession(value) {
|
|
@@ -7504,6 +7786,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
7504
7786
|
en
|
|
7505
7787
|
}), "michengai-codex-ui: dictionaries");
|
|
7506
7788
|
const t = ctx.locale.bind(NS);
|
|
7789
|
+
registerInputHistory(ctx);
|
|
7507
7790
|
const connection = ctx.get("connection");
|
|
7508
7791
|
const openPath = (path) => openPathInHost(connection, path);
|
|
7509
7792
|
ctx.effect(() => observeSlimSidebar(), "michengai-codex-ui: slim sidebar");
|
package/lib/index.mjs
CHANGED
|
@@ -44,6 +44,14 @@ const MANAGED_DEPENDENCIES = [
|
|
|
44
44
|
id: "schedule",
|
|
45
45
|
packageName: "@michengai/dsh-automation"
|
|
46
46
|
},
|
|
47
|
+
{
|
|
48
|
+
id: "btw",
|
|
49
|
+
packageName: "@michengai/dsh-btw"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: "simplify",
|
|
53
|
+
packageName: "@michengai/dsh-simplify"
|
|
54
|
+
},
|
|
47
55
|
{
|
|
48
56
|
id: "market",
|
|
49
57
|
packageName: "dshmarket"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@michengai/dsh-codex-ui",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.105",
|
|
4
4
|
"description": "以 Codex 风格重构 DSH Web 侧栏的独立客户端插件",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"publishConfig": {
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"@deepseek-ai/dsh-client-ui-layout",
|
|
50
50
|
"@deepseek-ai/dsh-client-locale",
|
|
51
51
|
"@deepseek-ai/dsh-client-ui-conversation",
|
|
52
|
+
"@deepseek-ai/dsh-client-ui-input-trigger",
|
|
52
53
|
"@deepseek-ai/dsh-client-ui-workspace",
|
|
53
54
|
"@deepseek-ai/dsh-client-ui-settings-general"
|
|
54
55
|
],
|
|
@@ -65,6 +66,7 @@
|
|
|
65
66
|
"@deepseek-ai/dsh-client-locale": ">=0.1.0-rc.5 <0.2.0",
|
|
66
67
|
"@deepseek-ai/dsh-client-runtime": ">=0.1.0-rc.5 <0.2.0",
|
|
67
68
|
"@deepseek-ai/dsh-client-ui-conversation": ">=0.1.0-rc.5 <0.2.0",
|
|
69
|
+
"@deepseek-ai/dsh-client-ui-input-trigger": ">=0.1.0-rc.5 <0.2.0",
|
|
68
70
|
"@deepseek-ai/dsh-client-ui-layout": ">=0.1.0-rc.5 <0.2.0",
|
|
69
71
|
"@deepseek-ai/dsh-client-ui-primitives": ">=0.1.0-rc.5 <0.2.0",
|
|
70
72
|
"@deepseek-ai/dsh-client-ui-settings": ">=0.1.0-rc.5 <0.2.0",
|
|
@@ -96,6 +98,7 @@
|
|
|
96
98
|
"@deepseek-ai/dsh-client-test-runtime": "0.1.2-rc.1",
|
|
97
99
|
"@deepseek-ai/dsh-client-ui-chat": "0.1.2-rc.1",
|
|
98
100
|
"@deepseek-ai/dsh-client-ui-conversation": "0.1.2-rc.1",
|
|
101
|
+
"@deepseek-ai/dsh-client-ui-input-trigger": "0.1.2-rc.1",
|
|
99
102
|
"@deepseek-ai/dsh-client-ui-layout": "0.1.2-rc.1",
|
|
100
103
|
"@deepseek-ai/dsh-client-ui-primitives": "0.1.2-rc.1",
|
|
101
104
|
"@deepseek-ai/dsh-client-ui-renderer": "0.1.2-rc.1",
|