@michengai/dsh-codex-ui 0.2.86 → 0.2.88
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 +35 -0
- package/CHANGELOG.zh-CN.md +35 -0
- package/dist/client.js +311 -49
- package/dist/index.mjs +278 -1
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,41 @@
|
|
|
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.88 — 2026-08-26
|
|
8
|
+
|
|
9
|
+
Companion release: `@michengai/dsh-codex-suite-installer@0.1.5`.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Replaced the lightweight **Settings → Connectors** tool list with the complete `dsh-mcp-connector` marketplace and connection manager whenever that optional external plugin is installed.
|
|
14
|
+
- Kept the existing **Connectors** home/sidebar action as the single entry point and suppressed the external plugin's separate launcher in both expanded and compact Codex sidebar layouts.
|
|
15
|
+
- Preserved the original current-session MCP tool directory as an automatic fallback when `dsh-mcp-connector` is absent or its Web UI is unavailable.
|
|
16
|
+
|
|
17
|
+
### Compatibility
|
|
18
|
+
|
|
19
|
+
- Added a same-origin, source-validated Prompt bridge that creates or reuses a workspace session and places the selected marketplace Prompt into its draft.
|
|
20
|
+
- Synchronized the embedded marketplace with the DSH-selected light or dark theme without modifying the externally maintained plugin or making it a required dependency.
|
|
21
|
+
- Updated the lightweight installer to pin Codex UI `0.2.88`; the legacy aggregate Suite remains private and unpublished.
|
|
22
|
+
|
|
23
|
+
Published packages: [`@michengai/dsh-codex-ui@0.2.88`](https://www.npmjs.com/package/@michengai/dsh-codex-ui/v/0.2.88) and [`@michengai/dsh-codex-suite-installer@0.1.5`](https://www.npmjs.com/package/@michengai/dsh-codex-suite-installer/v/0.1.5).
|
|
24
|
+
|
|
25
|
+
## 0.2.87 — 2026-08-26
|
|
26
|
+
|
|
27
|
+
Companion release: `@michengai/dsh-codex-suite-installer@0.1.4`.
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- Restored Chinese labels for the built-in permission presets in Settings and Chat with an exact-match compatibility adapter that leaves custom presets, prose, icons, and Host menu layout untouched.
|
|
32
|
+
- Made **Open in File Explorer** bypass in-app file previews, close its menu immediately, and open Windows Explorer in the foreground and maximized.
|
|
33
|
+
- Restyled conversation and workspace rename fields to match the native settings form, including helper copy, accessible labels, and a visible focus state.
|
|
34
|
+
- Kept the Codex UI **About** section at the bottom of Settings even when third-party plugins add later sections.
|
|
35
|
+
|
|
36
|
+
### Compatibility
|
|
37
|
+
|
|
38
|
+
- Updated the lightweight installer to pin Codex UI `0.2.87`, IM Connect `0.1.24`, and Automation `0.1.15`; the legacy aggregate Suite remains private and unpublished.
|
|
39
|
+
|
|
40
|
+
Published packages: [`@michengai/dsh-codex-ui@0.2.87`](https://www.npmjs.com/package/@michengai/dsh-codex-ui/v/0.2.87) and [`@michengai/dsh-codex-suite-installer@0.1.4`](https://www.npmjs.com/package/@michengai/dsh-codex-suite-installer/v/0.1.4).
|
|
41
|
+
|
|
7
42
|
## 0.2.86 — 2026-08-25
|
|
8
43
|
|
|
9
44
|
Companion release: `@michengai/dsh-codex-suite-installer@0.1.3`.
|
package/CHANGELOG.zh-CN.md
CHANGED
|
@@ -4,6 +4,41 @@
|
|
|
4
4
|
|
|
5
5
|
本日志记录 DSH Codex UI 及其一键安装器的最近发布;更早的变更可查看 [Git 提交历史](https://github.com/MichengAI/dsh-codex-ui/commits/main)。
|
|
6
6
|
|
|
7
|
+
## 0.2.88 — 2026-08-26
|
|
8
|
+
|
|
9
|
+
配套版本:`@michengai/dsh-codex-suite-installer@0.1.5`。
|
|
10
|
+
|
|
11
|
+
### 调整
|
|
12
|
+
|
|
13
|
+
- 安装外部可选插件 `dsh-mcp-connector` 时,用其完整的市场与连接管理界面替换轻量的“设置 → 连接器”工具列表。
|
|
14
|
+
- 首页/侧边栏继续以“连接器”作为唯一入口,展开与收缩状态下均不再显示外部插件单独注入的启动入口。
|
|
15
|
+
- 未安装 `dsh-mcp-connector` 或其 Web UI 不可用时,自动回退到原有的当前会话 MCP 工具目录。
|
|
16
|
+
|
|
17
|
+
### 兼容性
|
|
18
|
+
|
|
19
|
+
- 增加同源且校验消息来源的 Prompt 桥接,可创建或复用工作区会话,并把市场中的 Prompt 写入新会话草稿。
|
|
20
|
+
- 让内嵌市场跟随 DSH 当前选择的明暗主题;不修改外部插件,也不将其变为强制依赖。
|
|
21
|
+
- 轻量安装器同步固定 Codex UI `0.2.88`;旧聚合 Suite 继续保持私有且不发布。
|
|
22
|
+
|
|
23
|
+
发布包:[`@michengai/dsh-codex-ui@0.2.88`](https://www.npmjs.com/package/@michengai/dsh-codex-ui/v/0.2.88) 与 [`@michengai/dsh-codex-suite-installer@0.1.5`](https://www.npmjs.com/package/@michengai/dsh-codex-suite-installer/v/0.1.5)。
|
|
24
|
+
|
|
25
|
+
## 0.2.87 — 2026-08-26
|
|
26
|
+
|
|
27
|
+
配套版本:`@michengai/dsh-codex-suite-installer@0.1.4`。
|
|
28
|
+
|
|
29
|
+
### 修复
|
|
30
|
+
|
|
31
|
+
- 恢复设置与 Chat 中三个内置权限预设的中文显示;兼容逻辑只精确替换权限控件文案,不改动自定义预设、正文、图标或宿主菜单布局。
|
|
32
|
+
- “在资源管理器中打开”不再被应用内文件预览拦截;点击后立即收起菜单,并在前台最大化打开 Windows 资源管理器。
|
|
33
|
+
- 将会话和工作区重命名输入框调整为原生设置表单样式,补充辅助说明、无障碍名称和清晰的焦点状态。
|
|
34
|
+
- 即使第三方插件继续注册设置分区,也保证 Codex UI 自带的“关于”入口始终位于最底部。
|
|
35
|
+
|
|
36
|
+
### 兼容性
|
|
37
|
+
|
|
38
|
+
- 轻量安装器同步固定 Codex UI `0.2.87`、IM Connect `0.1.24` 和 Automation `0.1.15`;旧聚合 Suite 继续保持私有且不发布。
|
|
39
|
+
|
|
40
|
+
发布包:[`@michengai/dsh-codex-ui@0.2.87`](https://www.npmjs.com/package/@michengai/dsh-codex-ui/v/0.2.87) 与 [`@michengai/dsh-codex-suite-installer@0.1.4`](https://www.npmjs.com/package/@michengai/dsh-codex-suite-installer/v/0.1.4)。
|
|
41
|
+
|
|
7
42
|
## 0.2.86 — 2026-08-25
|
|
8
43
|
|
|
9
44
|
配套版本:`@michengai/dsh-codex-suite-installer@0.1.3`。
|
package/dist/client.js
CHANGED
|
@@ -1334,8 +1334,9 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1334
1334
|
.dcu-wb-rename-actions{display:flex;justify-content:flex-end;gap:8px}
|
|
1335
1335
|
.dcu-wb-delete-button{color:var(--dsw-alias-state-error-primary)!important}
|
|
1336
1336
|
.dcu-wb-delete-copy{margin:0;color:var(--dcu-sidebar-secondary);font-size:13px;line-height:20px}
|
|
1337
|
-
.dcu-wb-rename-input{width:100%;height:
|
|
1338
|
-
.dcu-wb-rename-input:
|
|
1337
|
+
.dcu-wb-rename-input{box-sizing:border-box;width:100%;height:36px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:7px 10px;outline:0;background:var(--dsw-alias-background-secondary);color:var(--dsw-alias-label-primary);font:14px/20px var(--dsw-font-family,inherit);caret-color:var(--dsw-alias-state-business-primary);transition:border-color 120ms ease,box-shadow 120ms ease}
|
|
1338
|
+
.dcu-wb-rename-input:hover{border-color:color-mix(in srgb,var(--dsw-alias-label-primary) 32%,var(--dsw-alias-border-l2))}
|
|
1339
|
+
.dcu-wb-rename-input:focus{border-color:var(--dsw-alias-state-business-primary);box-shadow:0 0 0 1px color-mix(in srgb,var(--dsw-alias-state-business-primary) 28%,transparent)}
|
|
1339
1340
|
`;
|
|
1340
1341
|
const runningStyles = `.dcu-wb-running{flex:none;width:12px;height:12px;border:2px solid color-mix(in srgb,var(--dcu-sidebar-secondary) 25%,transparent);border-top-color:var(--dcu-sidebar-secondary);border-radius:50%;animation:dcu-wb-spin .8s linear infinite}@keyframes dcu-wb-spin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion:reduce){.dcu-wb-running{animation:none}}`;
|
|
1341
1342
|
const typographyStyles = `.dcu-wb{font:14px/20px var(--dcu-font,var(--dsw-font-family))}.dcu-wb-section-label{color:var(--dcu-sidebar-tertiary);font-size:13px;font-weight:400;letter-spacing:.02em}.dcu-wb-project-title{font-size:14px;line-height:20px;font-weight:400;color:var(--dcu-sidebar-primary)}.dcu-wb-session-title{font-size:14px;line-height:20px;font-weight:400;color:var(--dcu-sidebar-secondary)}.dcu-wb-session.dcu-wb-selected .dcu-wb-session-title,.dcu-wb-session:hover .dcu-wb-session-title{color:var(--dcu-sidebar-primary)}.dcu-wb-empty{color:var(--dcu-sidebar-tertiary);font-size:13px;line-height:18px}.dcu-wb-nochat{padding:0 8px 4px 28px;color:var(--dcu-sidebar-tertiary);font-size:14px;line-height:20px}`;
|
|
@@ -1605,6 +1606,11 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1605
1606
|
await (0, _deepseek_ai_dsh_client_ui_primitives.writeClipboard)(value);
|
|
1606
1607
|
});
|
|
1607
1608
|
};
|
|
1609
|
+
const openPathImmediately = (path) => {
|
|
1610
|
+
setMenu(void 0);
|
|
1611
|
+
setHeaderMenu(void 0);
|
|
1612
|
+
run("open-path", () => openPath(path));
|
|
1613
|
+
};
|
|
1608
1614
|
const toggleGroup = (key, defaultOpen = true) => {
|
|
1609
1615
|
setExpanded((current) => ({
|
|
1610
1616
|
...current,
|
|
@@ -1816,7 +1822,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1816
1822
|
setPinnedWorkspaceIds((ids) => togglePinnedWorkspace(ids, workspace.workspaceId));
|
|
1817
1823
|
setMenu(void 0);
|
|
1818
1824
|
}
|
|
1819
|
-
if (id === "openPath")
|
|
1825
|
+
if (id === "openPath") openPathImmediately(workspace.path);
|
|
1820
1826
|
if (id === "delete") {
|
|
1821
1827
|
setDeleteTarget({
|
|
1822
1828
|
id: workspace.workspaceId,
|
|
@@ -2040,7 +2046,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2040
2046
|
setMenu(void 0);
|
|
2041
2047
|
}
|
|
2042
2048
|
if (action === "fork") run("fork", () => forkSession(id));
|
|
2043
|
-
if (action === "openPath" && path !== void 0)
|
|
2049
|
+
if (action === "openPath" && path !== void 0) openPathImmediately(path);
|
|
2044
2050
|
if (action === "copyPath") copy(path);
|
|
2045
2051
|
if (action === "copyTitle") copy(session.displayTitle);
|
|
2046
2052
|
if (action === "copyId") copy(id);
|
|
@@ -2380,7 +2386,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2380
2386
|
setMenu(void 0);
|
|
2381
2387
|
}
|
|
2382
2388
|
if (action === "fork") run("fork", () => forkSession(id));
|
|
2383
|
-
if (action === "openPath" && session.cwd !== void 0)
|
|
2389
|
+
if (action === "openPath" && session.cwd !== void 0) openPathImmediately(session.cwd);
|
|
2384
2390
|
if (action === "copyPath") copy(session.cwd);
|
|
2385
2391
|
if (action === "copyTitle") copy(title);
|
|
2386
2392
|
if (action === "copyId") copy(id);
|
|
@@ -2417,7 +2423,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2417
2423
|
setError(void 0);
|
|
2418
2424
|
}
|
|
2419
2425
|
if (action === "fork") run("fork", () => forkSession(id));
|
|
2420
|
-
if (action === "openPath" && path !== void 0)
|
|
2426
|
+
if (action === "openPath" && path !== void 0) openPathImmediately(path);
|
|
2421
2427
|
if (action === "copyPath") copy(path);
|
|
2422
2428
|
if (action === "copyTitle") copy(session.displayTitle);
|
|
2423
2429
|
if (action === "copyId") copy(id);
|
|
@@ -2446,6 +2452,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2446
2452
|
},
|
|
2447
2453
|
closeLabel: t("sessions.close"),
|
|
2448
2454
|
title: renameTarget?.kind === "workspace" ? t("workspace.rename") : t("sessions.rename"),
|
|
2455
|
+
description: t("sessions.renameDescription"),
|
|
2449
2456
|
footer: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2450
2457
|
className: "dcu-wb-rename-actions",
|
|
2451
2458
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
@@ -2463,6 +2470,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2463
2470
|
}),
|
|
2464
2471
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
2465
2472
|
className: "dcu-wb-rename-input",
|
|
2473
|
+
"aria-label": renameTarget?.kind === "workspace" ? t("workspace.rename") : t("sessions.rename"),
|
|
2466
2474
|
value: renameDraft,
|
|
2467
2475
|
autoFocus: true,
|
|
2468
2476
|
onFocus: (event) => {
|
|
@@ -2675,6 +2683,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2675
2683
|
},
|
|
2676
2684
|
closeLabel: t("sessions.close"),
|
|
2677
2685
|
title: t("sessions.rename"),
|
|
2686
|
+
description: t("sessions.renameDescription"),
|
|
2678
2687
|
footer: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2679
2688
|
className: "dcu-wb-rename-actions",
|
|
2680
2689
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
@@ -2692,6 +2701,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2692
2701
|
}),
|
|
2693
2702
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
2694
2703
|
className: "dcu-wb-rename-input",
|
|
2704
|
+
"aria-label": t("sessions.rename"),
|
|
2695
2705
|
value: renameDraft,
|
|
2696
2706
|
autoFocus: true,
|
|
2697
2707
|
onFocus: (event) => {
|
|
@@ -3233,6 +3243,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3233
3243
|
.dcu-menu-icon{display:grid;place-items:center start;width:20px;height:20px}.dcu-menu-icon svg,.dcu-footer-link svg{display:block;width:16px;height:16px;color:var(--dcu-sidebar-icon)}.dcu-menu button:disabled{color:var(--dcu-sidebar-secondary);cursor:default;opacity:1}.dcu-menu button:disabled svg{color:var(--dcu-sidebar-secondary)}
|
|
3234
3244
|
.dcu-extension-items{display:grid;gap:1px;margin:1px 0 4px 28px}.dcu-extension-items button{min-height:32px;color:var(--dcu-sidebar-secondary);font-size:13px;font-weight:400}
|
|
3235
3245
|
.dcu-workspaces{display:flex;min-height:0;flex:1;flex-direction:column;margin-top:2px;padding-top:8px;border-top:1px solid var(--dcu-sidebar-border)}.dcu-workspaces.dcu-workspaces-tabs{padding-top:0;border-top:0}.dcu-im-tabs{display:flex;gap:16px;margin:0 8px 12px;padding:0;border-bottom:1px solid var(--dcu-sidebar-border)}.dcu-im-tab{appearance:none;border:0;background:transparent;color:var(--dcu-sidebar-secondary);padding:8px 0 7px;font:14px/22px var(--dcu-font);font-weight:500;cursor:pointer}.dcu-im-tab[data-on=true]{color:var(--dcu-sidebar-primary);font-weight:600;box-shadow:inset 0 -2px 0 currentColor}.dcu-native-workspaces{display:flex;min-height:0;flex:1}.dcu-native-workspaces>*{min-width:0;flex:1}.dcu-native-workspaces .ima-tabs,.dcu-native-workspaces [role=tablist]{display:none!important}.dcu-foot{display:grid;width:var(--dcu-sidebar-wide-width);gap:4px;padding:8px 6px 12px;border-top:1px solid var(--dcu-sidebar-border);transition:opacity 120ms ease-out,transform 160ms cubic-bezier(.16,1,.3,1)}.dcu-root.dcu-collapsing>.dcu-foot{opacity:0;transform:translateX(-4px);pointer-events:none}.dcu-footer-actions:empty,.dcu-settings-seat:empty{display:none}.dcu-settings-seat>button{width:100%;min-height:36px;padding-left:4px!important;color:var(--dcu-sidebar-navigation);font:14px/20px var(--dcu-font);font-weight:400}.dcu-compact{width:100%;align-items:flex-start;overflow:hidden;padding:10px 0 8px}.dcu-compact-nav{display:flex;flex:1;min-height:0;flex-direction:column;align-items:center;gap:2px;overflow:auto;padding:6px 0}.dcu-compact .dcu-icon{width:36px;height:36px;flex:none}.dcu-compact .dcu-foot{width:36px;margin-top:auto;margin-left:10px;padding:8px 0;border-top:0}.dcu-compact .dcu-settings-seat{width:36px;overflow:hidden}.dcu-compact .dcu-settings-seat>button{display:grid;place-items:center;width:36px;min-height:36px;padding:0!important;font-size:0!important;line-height:0}.dcu-compact .dcu-settings-seat>button svg{width:16px;height:16px}.dcu-compact .dcu-footer-link{display:flex;justify-content:center;width:36px;padding:0;font-size:0}.dcu-compact .dcu-footer-link svg{width:16px;height:16px}
|
|
3246
|
+
.dcu-native-workspaces{flex-direction:column}.dcu-native-workspaces>[data-mcp-connector-top-mount=true]{flex:none}.dcu-root .mcpConnectorLauncher,.dcu-root [data-mcp-connector-top-mount=true]{display:none!important}
|
|
3236
3247
|
.dcu-dependency-notice{margin:0 10px 8px;border:1px solid var(--dcu-sidebar-border);border-radius:8px;padding:8px;color:var(--dcu-sidebar-secondary);font-size:12px;line-height:18px}
|
|
3237
3248
|
[role="dialog"][aria-labelledby]{width:min(1000px,calc(100vw - 48px));max-width:calc(100vw - 48px);height:min(800px,calc(100vh - 48px))}
|
|
3238
3249
|
.dcu-search-scrim{position:fixed;z-index:10020;inset:0;display:flex;justify-content:center;align-items:flex-start;padding:72px 20px;background:color-mix(in srgb,#000 48%,transparent);animation:dcu-search-scrim-in 140ms ease-out}.dcu-search-dialog{width:min(560px,100%);max-height:min(640px,calc(100vh - 120px));overflow:auto;border:1px solid var(--dcu-sidebar-border);border-radius:16px;padding:10px;background:var(--dsw-specific-menu);box-shadow:var(--dsw-shadow-lv4);animation:dcu-search-dialog-in 180ms cubic-bezier(.16,1,.3,1)}@keyframes dcu-search-scrim-in{from{opacity:0}to{opacity:1}}@keyframes dcu-search-dialog-in{from{opacity:0;transform:translateY(-6px) scale(.985)}to{opacity:1;transform:none}}.dcu-search-input{margin-bottom:8px}.dcu-search-section{padding:6px 0}.dcu-search-title{padding:0 8px 4px;color:var(--dcu-sidebar-tertiary);font-size:12px;font-weight:600}.dcu-search-row{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:12px;width:100%;min-height:34px;border:0;border-radius:8px;padding:6px 8px;background:transparent;color:var(--dcu-sidebar-primary);font:inherit;text-align:left;cursor:pointer}.dcu-search-row:hover,.dcu-search-row[data-active=true]{background:var(--dcu-sidebar-hover)}.dcu-search-main{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dcu-search-detail{max-width:160px;overflow:hidden;color:var(--dcu-sidebar-tertiary);font-size:12px;text-overflow:ellipsis;white-space:nowrap}.dcu-search-empty{padding:18px 8px;color:var(--dcu-sidebar-tertiary);font-size:13px}@media (prefers-reduced-motion:reduce){.dcu-expanded-shell,.dcu-root.dcu-compact .dcu-compact-shell,.dcu-foot,.dcu-search-scrim,.dcu-search-dialog{animation:none;transition:none}}
|
|
@@ -4180,16 +4191,82 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4180
4191
|
}
|
|
4181
4192
|
//#endregion
|
|
4182
4193
|
//#region src/client/ConnectorsSection.tsx
|
|
4194
|
+
const MCP_CONNECTOR_UI = "/mcp-connector/ui/";
|
|
4195
|
+
const PROMPT_REQUEST_TYPE = "mcp-connector:start-session";
|
|
4196
|
+
const PROMPT_RESULT_TYPE = "mcp-connector:start-session-result";
|
|
4183
4197
|
const stylesheet$1 = `
|
|
4184
|
-
.dcu-connectors{color:var(--dsw-alias-label-primary)}.dcu-connectors h2{margin:0;font-size:18px}.dcu-connectors p{margin:6px 0 18px;color:var(--dsw-alias-label-secondary);font-size:12px}.dcu-connector-list{overflow:hidden;border:1px solid var(--dsw-alias-border-l2);border-radius:9px}.dcu-connector{padding:12px;border-bottom:1px solid var(--dsw-alias-border-l2)}.dcu-connector:last-child{border-bottom:0}.dcu-connector-head{display:flex;align-items:center;gap:8px;font-weight:650}.dcu-connector-meta{margin:3px 0 8px;color:var(--dsw-alias-label-tertiary);font-size:11px}.dcu-connector-tool{padding:5px 0 0 24px;color:var(--dsw-alias-label-secondary);font-size:12px}.dcu-connector-tool span{display:block;margin-top:1px;color:var(--dsw-alias-label-tertiary);font-size:11px}.dcu-connector-empty{padding:20px 8px;color:var(--dsw-alias-label-secondary);text-align:center}
|
|
4198
|
+
.dcu-connectors{color:var(--dsw-alias-label-primary)}.dcu-connectors h2{margin:0;font-size:18px}.dcu-connectors p{margin:6px 0 18px;color:var(--dsw-alias-label-secondary);font-size:12px}.dcu-connector-frame{display:block;width:100%;height:clamp(420px,calc(100vh - 160px),700px);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-base);color-scheme:light dark}.dcu-connector-list{overflow:hidden;border:1px solid var(--dsw-alias-border-l2);border-radius:9px}.dcu-connector{padding:12px;border-bottom:1px solid var(--dsw-alias-border-l2)}.dcu-connector:last-child{border-bottom:0}.dcu-connector-head{display:flex;align-items:center;gap:8px;font-weight:650}.dcu-connector-meta{margin:3px 0 8px;color:var(--dsw-alias-label-tertiary);font-size:11px}.dcu-connector-tool{padding:5px 0 0 24px;color:var(--dsw-alias-label-secondary);font-size:12px}.dcu-connector-tool span{display:block;margin-top:1px;color:var(--dsw-alias-label-tertiary);font-size:11px}.dcu-connector-empty{padding:20px 8px;color:var(--dsw-alias-label-secondary);text-align:center}
|
|
4185
4199
|
`;
|
|
4200
|
+
const frameLightTheme = `:root{color-scheme:light;--bg:#f8f9fb;--card:#fff;--line:#e5e7eb;--text:#111827;--text-2:#4b5563;--muted:#9ca3af;--accent:#4f46e5;--accent-hover:#4338ca;--accent-light:#eef2ff;--ok:#059669;--ok-bg:#ecfdf5;--warn:#d97706;--warn-bg:#fffbeb;--bad:#dc2626;--bad-bg:#fef2f2;--shadow:0 1px 3px rgba(0,0,0,.08),0 1px 2px rgba(0,0,0,.06);--shadow-lg:0 10px 25px rgba(0,0,0,.1)}`;
|
|
4201
|
+
const frameDarkTheme = `:root{color-scheme:dark;--bg:#111318;--card:#1b1e25;--line:#30343d;--text:#f3f4f6;--text-2:#c4c8d0;--muted:#8e96a3;--accent:#818cf8;--accent-hover:#6366f1;--accent-light:#252750;--ok:#34d399;--ok-bg:#0d3027;--warn:#fbbf24;--warn-bg:#35280b;--bad:#f87171;--bad-bg:#3b171b;--shadow:0 1px 3px rgba(0,0,0,.35);--shadow-lg:0 16px 35px rgba(0,0,0,.45)}`;
|
|
4186
4202
|
function isConnector(value) {
|
|
4187
4203
|
if (value === null || typeof value !== "object") return false;
|
|
4188
4204
|
const item = value;
|
|
4189
4205
|
return typeof item.name === "string" && Array.isArray(item.tools) && item.tools.every((tool) => tool !== null && typeof tool === "object" && typeof tool.name === "string" && typeof tool.description === "string");
|
|
4190
4206
|
}
|
|
4191
|
-
|
|
4192
|
-
|
|
4207
|
+
function isPromptRequest(value) {
|
|
4208
|
+
if (value === null || typeof value !== "object") return false;
|
|
4209
|
+
const item = value;
|
|
4210
|
+
return item.type === PROMPT_REQUEST_TYPE && typeof item.requestId === "string" && item.requestId !== "" && typeof item.prompt === "string" && item.prompt.trim() !== "";
|
|
4211
|
+
}
|
|
4212
|
+
function syncFrameTheme(frame) {
|
|
4213
|
+
const doc = frame?.contentDocument;
|
|
4214
|
+
if (doc === null || doc === void 0) return;
|
|
4215
|
+
let style = doc.head.querySelector("style[data-michengai-host-theme]");
|
|
4216
|
+
if (style === null) {
|
|
4217
|
+
style = doc.createElement("style");
|
|
4218
|
+
style.dataset.michengaiHostTheme = "true";
|
|
4219
|
+
doc.head.append(style);
|
|
4220
|
+
}
|
|
4221
|
+
style.textContent = document.body.hasAttribute("data-ds-dark-theme") ? frameDarkTheme : frameLightTheme;
|
|
4222
|
+
}
|
|
4223
|
+
function ConnectorMarket({ startPromptSession }) {
|
|
4224
|
+
const frameRef = (0, react.useRef)(null);
|
|
4225
|
+
(0, react.useEffect)(() => {
|
|
4226
|
+
const onMessage = (event) => {
|
|
4227
|
+
const frameWindow = frameRef.current?.contentWindow;
|
|
4228
|
+
if (event.origin !== window.location.origin || frameWindow === null || frameWindow === void 0 || event.source !== frameWindow) return;
|
|
4229
|
+
if (!isPromptRequest(event.data)) return;
|
|
4230
|
+
const { requestId, prompt } = event.data;
|
|
4231
|
+
const reply = (ok, message) => {
|
|
4232
|
+
frameWindow.postMessage({
|
|
4233
|
+
type: PROMPT_RESULT_TYPE,
|
|
4234
|
+
requestId,
|
|
4235
|
+
ok,
|
|
4236
|
+
message
|
|
4237
|
+
}, window.location.origin);
|
|
4238
|
+
};
|
|
4239
|
+
startPromptSession(prompt).then(() => {
|
|
4240
|
+
reply(true, "已带入新会话");
|
|
4241
|
+
}, (error) => {
|
|
4242
|
+
reply(false, error instanceof Error ? error.message : String(error));
|
|
4243
|
+
});
|
|
4244
|
+
};
|
|
4245
|
+
const syncTheme = () => {
|
|
4246
|
+
syncFrameTheme(frameRef.current);
|
|
4247
|
+
};
|
|
4248
|
+
const observer = new MutationObserver(syncTheme);
|
|
4249
|
+
observer.observe(document.body, {
|
|
4250
|
+
attributes: true,
|
|
4251
|
+
attributeFilter: ["data-ds-dark-theme"]
|
|
4252
|
+
});
|
|
4253
|
+
window.addEventListener("message", onMessage);
|
|
4254
|
+
return () => {
|
|
4255
|
+
observer.disconnect();
|
|
4256
|
+
window.removeEventListener("message", onMessage);
|
|
4257
|
+
};
|
|
4258
|
+
}, [startPromptSession]);
|
|
4259
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("iframe", {
|
|
4260
|
+
ref: frameRef,
|
|
4261
|
+
className: "dcu-connector-frame",
|
|
4262
|
+
src: MCP_CONNECTOR_UI,
|
|
4263
|
+
title: "MCP连接器",
|
|
4264
|
+
onLoad: () => {
|
|
4265
|
+
syncFrameTheme(frameRef.current);
|
|
4266
|
+
}
|
|
4267
|
+
});
|
|
4268
|
+
}
|
|
4269
|
+
function NativeConnectorList({ sessionStore, t }) {
|
|
4193
4270
|
const sessionId = (0, react.useSyncExternalStore)(sessionStore.subscribe, () => sessionStore.getSnapshot().current);
|
|
4194
4271
|
const [connectors, setConnectors] = (0, react.useState)([]);
|
|
4195
4272
|
const [state, setState] = (0, react.useState)("loading");
|
|
@@ -4215,46 +4292,74 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4215
4292
|
controller.abort();
|
|
4216
4293
|
};
|
|
4217
4294
|
}, [sessionId]);
|
|
4295
|
+
if (sessionId === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4296
|
+
className: "dcu-connector-empty",
|
|
4297
|
+
children: t("connectors.openSession")
|
|
4298
|
+
});
|
|
4299
|
+
if (state === "loading") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4300
|
+
className: "dcu-connector-empty",
|
|
4301
|
+
children: t("connectors.loading")
|
|
4302
|
+
});
|
|
4303
|
+
if (state === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4304
|
+
className: "dcu-connector-empty",
|
|
4305
|
+
children: t("connectors.failed")
|
|
4306
|
+
});
|
|
4307
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4308
|
+
className: "dcu-connector-list",
|
|
4309
|
+
children: [connectors.map((connector) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
|
|
4310
|
+
className: "dcu-connector",
|
|
4311
|
+
children: [
|
|
4312
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4313
|
+
className: "dcu-connector-head",
|
|
4314
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconLinkOutline16, { size: 16 }), connector.name]
|
|
4315
|
+
}),
|
|
4316
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4317
|
+
className: "dcu-connector-meta",
|
|
4318
|
+
children: t("connectors.toolCount", { count: connector.tools.length })
|
|
4319
|
+
}),
|
|
4320
|
+
connector.tools.map((tool) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4321
|
+
className: "dcu-connector-tool",
|
|
4322
|
+
children: [tool.name, tool.description !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tool.description })]
|
|
4323
|
+
}, tool.name))
|
|
4324
|
+
]
|
|
4325
|
+
}, connector.name)), connectors.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4326
|
+
className: "dcu-connector-empty",
|
|
4327
|
+
children: t("connectors.empty")
|
|
4328
|
+
})]
|
|
4329
|
+
});
|
|
4330
|
+
}
|
|
4331
|
+
/** 安装 dsh-mcp-connector 时显示完整市场,否则回退到当前会话的 MCP 工具目录。 */
|
|
4332
|
+
function ConnectorsSection({ sessionStore, startPromptSession, t }) {
|
|
4333
|
+
const [marketAvailable, setMarketAvailable] = (0, react.useState)();
|
|
4334
|
+
(0, react.useEffect)(() => {
|
|
4335
|
+
const controller = new AbortController();
|
|
4336
|
+
fetch(MCP_CONNECTOR_UI, {
|
|
4337
|
+
method: "HEAD",
|
|
4338
|
+
cache: "no-store",
|
|
4339
|
+
signal: controller.signal
|
|
4340
|
+
}).then((response) => {
|
|
4341
|
+
if (!controller.signal.aborted) setMarketAvailable(response.ok);
|
|
4342
|
+
}).catch(() => {
|
|
4343
|
+
if (!controller.signal.aborted) setMarketAvailable(false);
|
|
4344
|
+
});
|
|
4345
|
+
return () => {
|
|
4346
|
+
controller.abort();
|
|
4347
|
+
};
|
|
4348
|
+
}, []);
|
|
4218
4349
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
4219
4350
|
className: "dcu-connectors",
|
|
4220
4351
|
"aria-label": t("connectors.title"),
|
|
4221
|
-
children: [
|
|
4222
|
-
|
|
4352
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: stylesheet$1 }), marketAvailable === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4353
|
+
className: "dcu-connector-empty",
|
|
4354
|
+
children: t("connectors.loading")
|
|
4355
|
+
}) : marketAvailable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConnectorMarket, { startPromptSession }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
4223
4356
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", { children: t("connectors.title") }),
|
|
4224
4357
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("connectors.description") }),
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
}) : state === "loading" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4229
|
-
className: "dcu-connector-empty",
|
|
4230
|
-
children: t("connectors.loading")
|
|
4231
|
-
}) : state === "failed" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4232
|
-
className: "dcu-connector-empty",
|
|
4233
|
-
children: t("connectors.failed")
|
|
4234
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4235
|
-
className: "dcu-connector-list",
|
|
4236
|
-
children: [connectors.map((connector) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
|
|
4237
|
-
className: "dcu-connector",
|
|
4238
|
-
children: [
|
|
4239
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4240
|
-
className: "dcu-connector-head",
|
|
4241
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconLinkOutline16, { size: 16 }), connector.name]
|
|
4242
|
-
}),
|
|
4243
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4244
|
-
className: "dcu-connector-meta",
|
|
4245
|
-
children: t("connectors.toolCount", { count: connector.tools.length })
|
|
4246
|
-
}),
|
|
4247
|
-
connector.tools.map((tool) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4248
|
-
className: "dcu-connector-tool",
|
|
4249
|
-
children: [tool.name, tool.description !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tool.description })]
|
|
4250
|
-
}, tool.name))
|
|
4251
|
-
]
|
|
4252
|
-
}, connector.name)), connectors.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4253
|
-
className: "dcu-connector-empty",
|
|
4254
|
-
children: t("connectors.empty")
|
|
4255
|
-
})]
|
|
4358
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(NativeConnectorList, {
|
|
4359
|
+
sessionStore,
|
|
4360
|
+
t
|
|
4256
4361
|
})
|
|
4257
|
-
]
|
|
4362
|
+
] })]
|
|
4258
4363
|
});
|
|
4259
4364
|
}
|
|
4260
4365
|
//#endregion
|
|
@@ -4327,6 +4432,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4327
4432
|
"sessions.markRead": "标记为已读",
|
|
4328
4433
|
"sessions.unread": "未读",
|
|
4329
4434
|
"sessions.rename": "重命名会话",
|
|
4435
|
+
"sessions.renameDescription": "保持简短且易于识别",
|
|
4330
4436
|
"sessions.archive": "归档会话",
|
|
4331
4437
|
"sessions.delete": "删除会话",
|
|
4332
4438
|
"sessions.deleteDescription": "将永久删除会话“{name}”及其全部记录,此操作不可恢复。",
|
|
@@ -4449,6 +4555,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4449
4555
|
"sessions.markRead": "Mark as read",
|
|
4450
4556
|
"sessions.unread": "Unread",
|
|
4451
4557
|
"sessions.rename": "Rename conversation",
|
|
4558
|
+
"sessions.renameDescription": "Keep it short and easy to recognize.",
|
|
4452
4559
|
"sessions.archive": "Archive conversation",
|
|
4453
4560
|
"sessions.delete": "Delete conversation",
|
|
4454
4561
|
"sessions.deleteDescription": "This permanently deletes “{name}” and all of its records. This cannot be undone.",
|
|
@@ -4505,6 +4612,30 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4505
4612
|
"turns.untitled": "Untitled prompt",
|
|
4506
4613
|
"turns.jump": "Jump to turn {index}: {summary}"
|
|
4507
4614
|
};
|
|
4615
|
+
//#endregion
|
|
4616
|
+
//#region src/client/host-open-path.ts
|
|
4617
|
+
const OPEN_IN_EXPLORER_ENDPOINT = "/api/michengai/codex-ui/open-in-explorer";
|
|
4618
|
+
/** “在资源管理器中打开”属于明确的系统动作,不应被侧边栏文件预览器接管。 */
|
|
4619
|
+
async function openPathInHost(connection, path, fetcher = fetch) {
|
|
4620
|
+
let foregroundResponse;
|
|
4621
|
+
try {
|
|
4622
|
+
foregroundResponse = await fetcher(OPEN_IN_EXPLORER_ENDPOINT, {
|
|
4623
|
+
method: "POST",
|
|
4624
|
+
headers: { "content-type": "application/json" },
|
|
4625
|
+
body: JSON.stringify({ path })
|
|
4626
|
+
});
|
|
4627
|
+
} catch {}
|
|
4628
|
+
if (foregroundResponse?.ok) return;
|
|
4629
|
+
if (foregroundResponse !== void 0 && foregroundResponse.status !== 404 && foregroundResponse.status !== 501) {
|
|
4630
|
+
const payload = await foregroundResponse.json().catch(() => ({}));
|
|
4631
|
+
throw new Error(typeof payload.error === "string" ? payload.error : "无法在前台打开资源管理器。");
|
|
4632
|
+
}
|
|
4633
|
+
const response = await connection.api.host.openPath({ path });
|
|
4634
|
+
if (!response.result.ok) throw new Error(`path open failed: ${response.result.error.message}`);
|
|
4635
|
+
}
|
|
4636
|
+
//#endregion
|
|
4637
|
+
//#region src/client/settings-nav-icons.ts
|
|
4638
|
+
const ABOUT_SETTINGS_NAV_ORDER = "2147483647";
|
|
4508
4639
|
const SETTINGS_NAV_ICON_HTML = {
|
|
4509
4640
|
experts: "<path fill=\"currentColor\" d=\"M11.0307 5.46369C11.0305 3.78995 9.6734 2.43357 7.99961 2.43357C6.32601 2.43379 4.96972 3.79009 4.96949 5.46369C4.96949 7.13748 6.32587 8.49455 7.99961 8.49477C9.67354 8.49477 11.0307 7.13762 11.0307 5.46369ZM12.3163 5.46369C12.3163 7.84777 10.3837 9.78042 7.99961 9.78042C5.61572 9.7802 3.68288 7.84763 3.68288 5.46369C3.6831 3.07993 5.61586 1.14718 7.99961 1.14695C10.3836 1.14695 12.3161 3.0798 12.3163 5.46369Z\"/><path fill=\"currentColor\" d=\"M8.00002 10.3316C11.7343 10.3316 14.1864 11.8997 15.0387 14.4445L14.4292 14.6483L13.8197 14.8531C13.1955 12.9893 11.3673 11.6182 8.00002 11.6182C4.63277 11.6182 2.80455 12.9893 2.18031 14.8531L1.5708 14.6483L0.961304 14.4445C1.81368 11.8997 4.26579 10.3316 8.00002 10.3316Z\"/>",
|
|
4510
4641
|
skills: "<path fill=\"currentColor\" d=\"M12.5113 15.4067C12.4395 15.6249 12.1308 15.6249 12.059 15.4067L11.643 14.1416C11.454 13.567 11.0033 13.1164 10.4288 12.9274L9.16369 12.5113C8.94544 12.4395 8.94544 12.1308 9.16369 12.059L10.4288 11.643C11.0033 11.454 11.454 11.0033 11.643 10.4288L12.059 9.16369C12.1308 8.94544 12.4395 8.94544 12.5113 9.16369L12.9274 10.4288C13.1164 11.0033 13.567 11.454 14.1416 11.643L15.4067 12.059C15.6249 12.1308 15.6249 12.4395 15.4067 12.5113L14.1416 12.9274C13.567 13.1164 13.1164 13.567 12.9274 14.1416L12.5113 15.4067Z\"/><path fill=\"currentColor\" d=\"M9.02246 0.546878C9.9822 0.546878 10.7564 0.545403 11.374 0.612307C12.0042 0.680586 12.5515 0.826244 13.0273 1.17188C13.3052 1.37376 13.5501 1.61868 13.752 1.89649C14.0975 2.37225 14.2432 2.91984 14.3115 3.54981C14.3784 4.16727 14.377 4.94206 14.377 5.90137V8.51367C13.9611 8.29533 13.5071 8.13985 13.0273 8.06055V5.90137C13.0273 4.9121 13.0259 4.22322 12.9688 3.69532C12.9129 3.18044 12.8098 2.89782 12.6592 2.69043C12.5406 2.52724 12.3966 2.38326 12.2334 2.26465C12.026 2.11404 11.7437 2.0109 11.2285 1.95508C10.7005 1.89789 10.0122 1.89649 9.02246 1.89649H6.55371C5.56395 1.89649 4.87569 1.89787 4.34766 1.95508C3.83242 2.01092 3.55022 2.11398 3.34278 2.26465C3.17953 2.38329 3.03564 2.52719 2.91699 2.69043C2.76642 2.89782 2.66325 3.18042 2.60742 3.69532C2.55027 4.22322 2.54883 4.9121 2.54883 5.90137V10.0986C2.54883 11.0878 2.55031 11.7768 2.60742 12.3047C2.66326 12.8196 2.76642 13.1032 2.91699 13.3105C3.03558 13.4736 3.17966 13.6178 3.34278 13.7363C3.5502 13.8869 3.83265 13.9901 4.34766 14.0459C4.87568 14.1031 5.56398 14.1035 6.55371 14.1035H8.08399C8.27443 14.6025 8.55077 15.0585 8.89551 15.4541H6.55371C5.59402 15.4541 4.81976 15.4546 4.20215 15.3877C3.57204 15.3194 3.02468 15.1738 2.54883 14.8281C2.27111 14.6263 2.02606 14.3813 1.82422 14.1035C1.47883 13.6278 1.33293 13.08 1.26465 12.4502C1.19783 11.8327 1.19922 11.0579 1.19922 10.0986V5.90137C1.19922 4.94206 1.1978 4.16727 1.26465 3.54981C1.33295 2.91984 1.47867 2.37225 1.82422 1.89649C2.02613 1.61864 2.27098 1.37379 2.54883 1.17188C3.02472 0.826181 3.57197 0.6806 4.20215 0.612307C4.81976 0.545393 5.594 0.546877 6.55371 0.546878H9.02246ZM9.19629 9.14649H4.5459V7.84571H9.19629V9.14649ZM11.0303 6.10645H4.5459V4.80567H11.0303V6.10645Z\"/>",
|
|
@@ -4534,9 +4665,20 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4534
4665
|
function applySettingsNavIcon(button) {
|
|
4535
4666
|
const id = settingsNavIconId(button.textContent ?? "");
|
|
4536
4667
|
if (id === void 0) return false;
|
|
4668
|
+
let changed = false;
|
|
4669
|
+
if (id === "about") {
|
|
4670
|
+
if (!button.hasAttribute("data-dcu-settings-about-last")) {
|
|
4671
|
+
button.setAttribute("data-dcu-settings-about-last", "");
|
|
4672
|
+
changed = true;
|
|
4673
|
+
}
|
|
4674
|
+
if (button.style.getPropertyValue("order") !== "2147483647" || button.style.getPropertyPriority("order") !== "important") {
|
|
4675
|
+
button.style.setProperty("order", ABOUT_SETTINGS_NAV_ORDER, "important");
|
|
4676
|
+
changed = true;
|
|
4677
|
+
}
|
|
4678
|
+
}
|
|
4537
4679
|
const svg = button.querySelector("svg");
|
|
4538
|
-
if (svg === null) return
|
|
4539
|
-
if (svg.getAttribute("data-dcu-nav-icon") === id) return
|
|
4680
|
+
if (svg === null) return changed;
|
|
4681
|
+
if (svg.getAttribute("data-dcu-nav-icon") === id) return changed;
|
|
4540
4682
|
svg.setAttribute("data-dcu-nav-icon", id);
|
|
4541
4683
|
svg.setAttribute("viewBox", id === "archive" ? "0 0 20 20" : id === "about" ? "0 0 14 14" : "0 0 16 16");
|
|
4542
4684
|
svg.setAttribute("fill", "none");
|
|
@@ -4581,6 +4723,105 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4581
4723
|
};
|
|
4582
4724
|
}
|
|
4583
4725
|
//#endregion
|
|
4726
|
+
//#region src/client/permission-labels.ts
|
|
4727
|
+
const PERMISSION_LABELS = [
|
|
4728
|
+
{
|
|
4729
|
+
aliases: [
|
|
4730
|
+
"Read Only",
|
|
4731
|
+
"preset.readOnly",
|
|
4732
|
+
"只读"
|
|
4733
|
+
],
|
|
4734
|
+
en: "Read Only",
|
|
4735
|
+
zh: "只读"
|
|
4736
|
+
},
|
|
4737
|
+
{
|
|
4738
|
+
aliases: [
|
|
4739
|
+
"Workspace Write",
|
|
4740
|
+
"preset.workspaceWrite",
|
|
4741
|
+
"工作区写入"
|
|
4742
|
+
],
|
|
4743
|
+
en: "Workspace Write",
|
|
4744
|
+
zh: "工作区写入"
|
|
4745
|
+
},
|
|
4746
|
+
{
|
|
4747
|
+
aliases: [
|
|
4748
|
+
"Full access",
|
|
4749
|
+
"preset.fullAccess",
|
|
4750
|
+
"完全访问"
|
|
4751
|
+
],
|
|
4752
|
+
en: "Full access",
|
|
4753
|
+
zh: "完全访问"
|
|
4754
|
+
}
|
|
4755
|
+
];
|
|
4756
|
+
const INTERACTIVE_SELECTOR = "button, [role=\"menuitem\"], [role=\"menuitemradio\"], [role=\"option\"]";
|
|
4757
|
+
function targetLabel(value, activeLocale) {
|
|
4758
|
+
const definition = PERMISSION_LABELS.find((item) => item.aliases.includes(value));
|
|
4759
|
+
if (definition === void 0) return void 0;
|
|
4760
|
+
return activeLocale.toLowerCase().startsWith("zh") ? definition.zh : definition.en;
|
|
4761
|
+
}
|
|
4762
|
+
function applyPermissionLabel(element, activeLocale) {
|
|
4763
|
+
const document = element.ownerDocument;
|
|
4764
|
+
const showText = document.defaultView?.NodeFilter.SHOW_TEXT ?? 4;
|
|
4765
|
+
const walker = document.createTreeWalker(element, showText);
|
|
4766
|
+
let changed = false;
|
|
4767
|
+
let node = walker.nextNode();
|
|
4768
|
+
while (node !== null) {
|
|
4769
|
+
const value = node.nodeValue ?? "";
|
|
4770
|
+
const trimmed = value.trim();
|
|
4771
|
+
const next = targetLabel(trimmed, activeLocale);
|
|
4772
|
+
if (next !== void 0 && next !== trimmed) {
|
|
4773
|
+
node.nodeValue = value.replace(trimmed, next);
|
|
4774
|
+
changed = true;
|
|
4775
|
+
}
|
|
4776
|
+
node = walker.nextNode();
|
|
4777
|
+
}
|
|
4778
|
+
return changed;
|
|
4779
|
+
}
|
|
4780
|
+
/** 只修正权限选择控件里的内置预设名称,不改动正文或自定义权限名称。 */
|
|
4781
|
+
function localizePermissionLabels(root, activeLocale) {
|
|
4782
|
+
let changed = 0;
|
|
4783
|
+
const rootElement = root.nodeType === 1 ? root : void 0;
|
|
4784
|
+
const elements = rootElement?.matches(INTERACTIVE_SELECTOR) === true ? [rootElement, ...rootElement.querySelectorAll(INTERACTIVE_SELECTOR)] : [...root.querySelectorAll(INTERACTIVE_SELECTOR)];
|
|
4785
|
+
for (const element of elements) if (applyPermissionLabel(element, activeLocale)) changed += 1;
|
|
4786
|
+
return changed;
|
|
4787
|
+
}
|
|
4788
|
+
/** 兼容宿主设置页和 Chat 中由官方组件直接输出的英文权限名称。 */
|
|
4789
|
+
function observePermissionLabels(locale) {
|
|
4790
|
+
if (typeof document === "undefined" || document.body === null) return () => {};
|
|
4791
|
+
let applying = false;
|
|
4792
|
+
let frame;
|
|
4793
|
+
const apply = () => {
|
|
4794
|
+
if (applying) return;
|
|
4795
|
+
applying = true;
|
|
4796
|
+
const active = locale.getSnapshot?.().active ?? document.documentElement.lang ?? window.navigator.language ?? "zh";
|
|
4797
|
+
try {
|
|
4798
|
+
localizePermissionLabels(document, active);
|
|
4799
|
+
} finally {
|
|
4800
|
+
applying = false;
|
|
4801
|
+
}
|
|
4802
|
+
};
|
|
4803
|
+
const schedule = () => {
|
|
4804
|
+
if (frame !== void 0) return;
|
|
4805
|
+
frame = window.requestAnimationFrame(() => {
|
|
4806
|
+
frame = void 0;
|
|
4807
|
+
apply();
|
|
4808
|
+
});
|
|
4809
|
+
};
|
|
4810
|
+
apply();
|
|
4811
|
+
const observer = new MutationObserver(schedule);
|
|
4812
|
+
observer.observe(document.body, {
|
|
4813
|
+
childList: true,
|
|
4814
|
+
characterData: true,
|
|
4815
|
+
subtree: true
|
|
4816
|
+
});
|
|
4817
|
+
const unsubscribe = locale.subscribe?.(schedule) ?? (() => {});
|
|
4818
|
+
return () => {
|
|
4819
|
+
observer.disconnect();
|
|
4820
|
+
unsubscribe();
|
|
4821
|
+
if (frame !== void 0) window.cancelAnimationFrame(frame);
|
|
4822
|
+
};
|
|
4823
|
+
}
|
|
4824
|
+
//#endregion
|
|
4584
4825
|
//#region src/client/conversation-dom.ts
|
|
4585
4826
|
/**
|
|
4586
4827
|
* DSH 尚未公开会话滚动容器和消息锚点服务;把兼容读取集中在这里,方便
|
|
@@ -4828,7 +5069,9 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4828
5069
|
"sessions",
|
|
4829
5070
|
"workspaces",
|
|
4830
5071
|
"layout",
|
|
4831
|
-
"locale"
|
|
5072
|
+
"locale",
|
|
5073
|
+
"connection",
|
|
5074
|
+
"conversation"
|
|
4832
5075
|
];
|
|
4833
5076
|
function hasDeleteSession(value) {
|
|
4834
5077
|
return value !== null && typeof value === "object" && "deleteSession" in value && typeof value.deleteSession === "function";
|
|
@@ -4840,8 +5083,11 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4840
5083
|
en
|
|
4841
5084
|
}), "michengai-codex-ui: dictionaries");
|
|
4842
5085
|
const t = ctx.locale.bind(NS);
|
|
5086
|
+
const connection = ctx.get("connection");
|
|
5087
|
+
const openPath = (path) => openPathInHost(connection, path);
|
|
4843
5088
|
ctx.effect(() => observeSlimSidebar(), "michengai-codex-ui: slim sidebar");
|
|
4844
5089
|
ctx.effect(() => observeSettingsNavIcons(), "michengai-codex-ui: settings nav icons");
|
|
5090
|
+
ctx.effect(() => observePermissionLabels(ctx.locale), "michengai-codex-ui: permission labels");
|
|
4845
5091
|
ctx.effect(() => observeConversationHeader(), "michengai-codex-ui: conversation header");
|
|
4846
5092
|
const companionSlots = createCompanionTabSource(ctx.slots);
|
|
4847
5093
|
ctx.slots.inject("sidebar", () => ctx.slots.register({
|
|
@@ -4884,7 +5130,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4884
5130
|
deleteSession,
|
|
4885
5131
|
forkSession,
|
|
4886
5132
|
renameSession,
|
|
4887
|
-
openPath
|
|
5133
|
+
openPath,
|
|
4888
5134
|
companionSlots
|
|
4889
5135
|
})
|
|
4890
5136
|
}, CodexSidebar));
|
|
@@ -4913,6 +5159,21 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4913
5159
|
const result = await registry.deleteSession(sessionId);
|
|
4914
5160
|
if (!result.ok) throw new Error(result.error?.message ?? t("sessions.deleteUnavailable"));
|
|
4915
5161
|
};
|
|
5162
|
+
const startConnectorPromptSession = async (promptText) => {
|
|
5163
|
+
const prompt = promptText.trim();
|
|
5164
|
+
if (prompt === "") throw new Error("Prompt 不能为空");
|
|
5165
|
+
const workspaces = ctx.workspaces.list.getSnapshot();
|
|
5166
|
+
const currentSessionId = ctx.sessions.list.getSnapshot().current;
|
|
5167
|
+
const targetWorkspaceId = (currentSessionId === void 0 ? void 0 : workspaces.items.find((workspace) => workspace.sessionIds.includes(currentSessionId))?.workspaceId) ?? workspaces.recentWorkspaceId;
|
|
5168
|
+
if (targetWorkspaceId === void 0) throw new Error("请先选择一个工作空间,再使用示例 Prompt");
|
|
5169
|
+
const sessionId = await ctx.workspaces.connectWorkspace(targetWorkspaceId);
|
|
5170
|
+
const conversation = ctx.get("conversation");
|
|
5171
|
+
if (conversation === void 0) throw new Error("DSH 对话服务尚未就绪,请稍后重试");
|
|
5172
|
+
const binding = ctx.sessions.binding(sessionId);
|
|
5173
|
+
if (binding === void 0) throw new Error("新会话尚未就绪,请稍后重试");
|
|
5174
|
+
conversation.input.for(binding.ctx).setDraft(prompt);
|
|
5175
|
+
ctx.sessions.open(sessionId);
|
|
5176
|
+
};
|
|
4916
5177
|
ctx.slots.inject("sidebar.workspaces", () => ctx.slots.register({
|
|
4917
5178
|
name: "sidebar.workspaces",
|
|
4918
5179
|
priority: -1,
|
|
@@ -4922,7 +5183,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4922
5183
|
deleteSession,
|
|
4923
5184
|
deleteWorkspace: (workspaceId) => ctx.workspaces.delete(workspaceId),
|
|
4924
5185
|
forkSession,
|
|
4925
|
-
openPath
|
|
5186
|
+
openPath,
|
|
4926
5187
|
openSession: (sessionId) => {
|
|
4927
5188
|
ctx.sessions.open(sessionId);
|
|
4928
5189
|
},
|
|
@@ -4956,13 +5217,14 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4956
5217
|
icon: "connector",
|
|
4957
5218
|
inject: () => ({
|
|
4958
5219
|
sessionStore: ctx.sessions.list,
|
|
5220
|
+
startPromptSession: startConnectorPromptSession,
|
|
4959
5221
|
t
|
|
4960
5222
|
})
|
|
4961
5223
|
}, ConnectorsSection));
|
|
4962
5224
|
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
4963
5225
|
name: "settings.section",
|
|
4964
5226
|
id: "about",
|
|
4965
|
-
order:
|
|
5227
|
+
order: Number.MAX_SAFE_INTEGER,
|
|
4966
5228
|
label: () => t("about.nav"),
|
|
4967
5229
|
locale: NS
|
|
4968
5230
|
}, AboutSection));
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { mkdir, readFile, rename, rm, unlink, writeFile } from "node:fs/promises";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
|
-
import { basename, dirname, join, resolve, sep } from "node:path";
|
|
4
|
+
import { basename, dirname, isAbsolute, join, resolve, sep } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { randomUUID } from "node:crypto";
|
|
7
7
|
//#region src/dependencies.ts
|
|
@@ -529,6 +529,224 @@ function hostServices(ctx) {
|
|
|
529
529
|
};
|
|
530
530
|
}
|
|
531
531
|
//#endregion
|
|
532
|
+
//#region src/native-explorer.ts
|
|
533
|
+
const WINDOWS_EXPLORER_TIMEOUT_MS = 8e3;
|
|
534
|
+
const WINDOWS_FOREGROUND_EXPLORER_SCRIPT = String.raw`
|
|
535
|
+
$ErrorActionPreference = 'Stop'
|
|
536
|
+
|
|
537
|
+
Add-Type -TypeDefinition @'
|
|
538
|
+
using System;
|
|
539
|
+
using System.Runtime.InteropServices;
|
|
540
|
+
public static class DcuWindowFocus {
|
|
541
|
+
[DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
|
|
542
|
+
[DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint pid);
|
|
543
|
+
[DllImport("kernel32.dll")] public static extern uint GetCurrentThreadId();
|
|
544
|
+
[DllImport("user32.dll")] public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool attach);
|
|
545
|
+
[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int command);
|
|
546
|
+
[DllImport("user32.dll")] public static extern bool BringWindowToTop(IntPtr hWnd);
|
|
547
|
+
[DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr hWnd);
|
|
548
|
+
}
|
|
549
|
+
'@
|
|
550
|
+
|
|
551
|
+
$shell = New-Object -ComObject Shell.Application
|
|
552
|
+
|
|
553
|
+
function Find-ExplorerWindow([string]$path) {
|
|
554
|
+
foreach ($item in @($shell.Windows())) {
|
|
555
|
+
try {
|
|
556
|
+
$candidate = [IO.Path]::GetFullPath([string]$item.Document.Folder.Self.Path).TrimEnd('\')
|
|
557
|
+
if ($candidate -ieq $path) { return $item }
|
|
558
|
+
} catch {}
|
|
559
|
+
}
|
|
560
|
+
return $null
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
function Open-ExplorerInForeground([string]$target) {
|
|
564
|
+
$target = [IO.Path]::GetFullPath($target).TrimEnd('\')
|
|
565
|
+
$window = Find-ExplorerWindow $target
|
|
566
|
+
if ($null -eq $window) {
|
|
567
|
+
$shell.Explore($target)
|
|
568
|
+
for ($attempt = 0; $attempt -lt 120 -and $null -eq $window; $attempt += 1) {
|
|
569
|
+
Start-Sleep -Milliseconds 25
|
|
570
|
+
$window = Find-ExplorerWindow $target
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
if ($null -eq $window) { throw 'Explorer window was not found.' }
|
|
574
|
+
|
|
575
|
+
$handle = [IntPtr]([long]$window.HWND)
|
|
576
|
+
$foreground = [DcuWindowFocus]::GetForegroundWindow()
|
|
577
|
+
$foregroundProcessId = 0
|
|
578
|
+
$foregroundThread = [DcuWindowFocus]::GetWindowThreadProcessId($foreground, [ref]$foregroundProcessId)
|
|
579
|
+
$currentThread = [DcuWindowFocus]::GetCurrentThreadId()
|
|
580
|
+
$attached = $foregroundThread -ne 0 -and [DcuWindowFocus]::AttachThreadInput($currentThread, $foregroundThread, $true)
|
|
581
|
+
try {
|
|
582
|
+
[void][DcuWindowFocus]::ShowWindowAsync($handle, 3)
|
|
583
|
+
[void][DcuWindowFocus]::BringWindowToTop($handle)
|
|
584
|
+
if (-not [DcuWindowFocus]::SetForegroundWindow($handle)) { throw 'Explorer could not be activated.' }
|
|
585
|
+
} finally {
|
|
586
|
+
if ($attached) { [void][DcuWindowFocus]::AttachThreadInput($currentThread, $foregroundThread, $false) }
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
[Console]::Out.WriteLine('READY')
|
|
591
|
+
[Console]::Out.Flush()
|
|
592
|
+
while (($line = [Console]::In.ReadLine()) -ne $null) {
|
|
593
|
+
if ([string]::IsNullOrWhiteSpace($line)) { continue }
|
|
594
|
+
$parts = $line.Split([char]9, 2)
|
|
595
|
+
$requestId = $parts[0]
|
|
596
|
+
try {
|
|
597
|
+
if ($parts.Count -ne 2) { throw 'Invalid request.' }
|
|
598
|
+
$target = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($parts[1]))
|
|
599
|
+
Open-ExplorerInForeground $target
|
|
600
|
+
[Console]::Out.WriteLine(('OK' + [char]9 + $requestId))
|
|
601
|
+
} catch {
|
|
602
|
+
$message = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes([string]$_.Exception.Message))
|
|
603
|
+
[Console]::Out.WriteLine(('ERR' + [char]9 + $requestId + [char]9 + $message))
|
|
604
|
+
}
|
|
605
|
+
[Console]::Out.Flush()
|
|
606
|
+
}
|
|
607
|
+
`;
|
|
608
|
+
/**
|
|
609
|
+
* 常驻的 Windows Explorer 前台激活助手。
|
|
610
|
+
* PowerShell 与窗口 API 只在 Host 启动时初始化一次,点击时仅发送一行路径请求。
|
|
611
|
+
*/
|
|
612
|
+
var ForegroundExplorer = class {
|
|
613
|
+
run;
|
|
614
|
+
platform;
|
|
615
|
+
child;
|
|
616
|
+
startupChild;
|
|
617
|
+
starting;
|
|
618
|
+
stdout = "";
|
|
619
|
+
sequence = 0;
|
|
620
|
+
pending = /* @__PURE__ */ new Map();
|
|
621
|
+
disposed = false;
|
|
622
|
+
constructor(run = spawn, platform = process.platform) {
|
|
623
|
+
this.run = run;
|
|
624
|
+
this.platform = platform;
|
|
625
|
+
}
|
|
626
|
+
/** 在用户点击前完成 PowerShell 与窗口 API 初始化。 */
|
|
627
|
+
warmup() {
|
|
628
|
+
if (this.platform !== "win32") return Promise.resolve();
|
|
629
|
+
return this.ensureStarted().then(() => void 0);
|
|
630
|
+
}
|
|
631
|
+
async open(path) {
|
|
632
|
+
if (this.platform !== "win32") throw new Error("foreground Explorer is only available on Windows");
|
|
633
|
+
if (!isAbsolute(path)) throw new Error("Explorer path must be absolute");
|
|
634
|
+
if (this.disposed) throw new Error("Explorer helper has been disposed");
|
|
635
|
+
const child = await this.ensureStarted();
|
|
636
|
+
const requestId = String(++this.sequence);
|
|
637
|
+
const encodedPath = Buffer.from(path, "utf8").toString("base64");
|
|
638
|
+
return await new Promise((resolve, reject) => {
|
|
639
|
+
const timeout = setTimeout(() => {
|
|
640
|
+
this.pending.delete(requestId);
|
|
641
|
+
reject(/* @__PURE__ */ new Error("Explorer activation timed out"));
|
|
642
|
+
}, WINDOWS_EXPLORER_TIMEOUT_MS);
|
|
643
|
+
timeout.unref?.();
|
|
644
|
+
this.pending.set(requestId, {
|
|
645
|
+
resolve,
|
|
646
|
+
reject,
|
|
647
|
+
timeout
|
|
648
|
+
});
|
|
649
|
+
child.stdin.write(`${requestId}\t${encodedPath}\n`, (error) => {
|
|
650
|
+
if (error === null || error === void 0) return;
|
|
651
|
+
const request = this.pending.get(requestId);
|
|
652
|
+
if (request === void 0) return;
|
|
653
|
+
clearTimeout(request.timeout);
|
|
654
|
+
this.pending.delete(requestId);
|
|
655
|
+
request.reject(error);
|
|
656
|
+
});
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
dispose() {
|
|
660
|
+
this.disposed = true;
|
|
661
|
+
this.failAll(/* @__PURE__ */ new Error("Explorer helper has been disposed"));
|
|
662
|
+
this.startupChild?.kill();
|
|
663
|
+
this.child?.kill();
|
|
664
|
+
this.startupChild = void 0;
|
|
665
|
+
this.child = void 0;
|
|
666
|
+
this.starting = void 0;
|
|
667
|
+
}
|
|
668
|
+
ensureStarted() {
|
|
669
|
+
if (this.disposed) return Promise.reject(/* @__PURE__ */ new Error("Explorer helper has been disposed"));
|
|
670
|
+
if (this.child !== void 0) return Promise.resolve(this.child);
|
|
671
|
+
if (this.starting !== void 0) return this.starting;
|
|
672
|
+
const encoded = Buffer.from(WINDOWS_FOREGROUND_EXPLORER_SCRIPT, "utf16le").toString("base64");
|
|
673
|
+
this.starting = new Promise((resolve, reject) => {
|
|
674
|
+
const child = this.run("powershell.exe", [
|
|
675
|
+
"-NoLogo",
|
|
676
|
+
"-NoProfile",
|
|
677
|
+
"-NonInteractive",
|
|
678
|
+
"-EncodedCommand",
|
|
679
|
+
encoded
|
|
680
|
+
], { windowsHide: true });
|
|
681
|
+
this.startupChild = child;
|
|
682
|
+
let settled = false;
|
|
683
|
+
const finishStart = (error) => {
|
|
684
|
+
if (settled) return;
|
|
685
|
+
settled = true;
|
|
686
|
+
clearTimeout(startupTimeout);
|
|
687
|
+
if (error !== void 0) {
|
|
688
|
+
this.starting = void 0;
|
|
689
|
+
if (this.startupChild === child) this.startupChild = void 0;
|
|
690
|
+
child.kill();
|
|
691
|
+
reject(error);
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
if (this.disposed) {
|
|
695
|
+
this.starting = void 0;
|
|
696
|
+
if (this.startupChild === child) this.startupChild = void 0;
|
|
697
|
+
child.kill();
|
|
698
|
+
reject(/* @__PURE__ */ new Error("Explorer helper has been disposed"));
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
if (this.startupChild === child) this.startupChild = void 0;
|
|
702
|
+
this.child = child;
|
|
703
|
+
this.starting = void 0;
|
|
704
|
+
resolve(child);
|
|
705
|
+
};
|
|
706
|
+
const startupTimeout = setTimeout(() => finishStart(/* @__PURE__ */ new Error("Explorer helper startup timed out")), WINDOWS_EXPLORER_TIMEOUT_MS);
|
|
707
|
+
startupTimeout.unref?.();
|
|
708
|
+
child.stdout.on("data", (chunk) => {
|
|
709
|
+
this.stdout += String(chunk);
|
|
710
|
+
let newline = this.stdout.indexOf("\n");
|
|
711
|
+
while (newline >= 0) {
|
|
712
|
+
const line = this.stdout.slice(0, newline).trimEnd();
|
|
713
|
+
this.stdout = this.stdout.slice(newline + 1);
|
|
714
|
+
if (line === "READY") finishStart();
|
|
715
|
+
else this.handleResponse(line);
|
|
716
|
+
newline = this.stdout.indexOf("\n");
|
|
717
|
+
}
|
|
718
|
+
});
|
|
719
|
+
child.once("error", (error) => finishStart(error));
|
|
720
|
+
child.once("exit", () => {
|
|
721
|
+
if (!settled) finishStart(/* @__PURE__ */ new Error("Explorer helper exited during startup"));
|
|
722
|
+
if (this.child === child) this.child = void 0;
|
|
723
|
+
this.failAll(/* @__PURE__ */ new Error("Explorer helper exited"));
|
|
724
|
+
});
|
|
725
|
+
});
|
|
726
|
+
return this.starting;
|
|
727
|
+
}
|
|
728
|
+
handleResponse(line) {
|
|
729
|
+
const [status, requestId, encodedMessage] = line.split(" ");
|
|
730
|
+
const request = requestId === void 0 ? void 0 : this.pending.get(requestId);
|
|
731
|
+
if (request === void 0) return;
|
|
732
|
+
clearTimeout(request.timeout);
|
|
733
|
+
this.pending.delete(requestId);
|
|
734
|
+
if (status === "OK") {
|
|
735
|
+
request.resolve();
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
const message = encodedMessage === void 0 ? "Explorer activation failed" : Buffer.from(encodedMessage, "base64").toString("utf8");
|
|
739
|
+
request.reject(new Error(message));
|
|
740
|
+
}
|
|
741
|
+
failAll(error) {
|
|
742
|
+
for (const request of this.pending.values()) {
|
|
743
|
+
clearTimeout(request.timeout);
|
|
744
|
+
request.reject(error);
|
|
745
|
+
}
|
|
746
|
+
this.pending.clear();
|
|
747
|
+
}
|
|
748
|
+
};
|
|
749
|
+
//#endregion
|
|
532
750
|
//#region src/workspace-preferences.ts
|
|
533
751
|
const WORKSPACE_PREFERENCES_FILE = ".dsh-codex-ui-preferences.json";
|
|
534
752
|
/** Desktop 和普通 DSH Web 共用 Profile;服务换端口或重启后目录仍保持稳定。 */
|
|
@@ -596,6 +814,7 @@ function writeWorkspacePreferences(pinnedWorkspaceIds, path = workspacePreferenc
|
|
|
596
814
|
//#region src/index.ts
|
|
597
815
|
const connectorsEndpoint = "/api/michengai/codex-ui/connectors";
|
|
598
816
|
const dependenciesEndpoint = "/api/michengai/codex-ui/dependencies";
|
|
817
|
+
const explorerEndpoint = "/api/michengai/codex-ui/open-in-explorer";
|
|
599
818
|
const preferencesEndpoint = "/api/michengai/codex-ui/preferences";
|
|
600
819
|
const maxPreferencesBodyBytes = 32768;
|
|
601
820
|
function headerValue(headers, name) {
|
|
@@ -656,6 +875,8 @@ const inject = [
|
|
|
656
875
|
function apply(ctx) {
|
|
657
876
|
const host = hostServices(ctx);
|
|
658
877
|
ctx.effect(() => {
|
|
878
|
+
const foregroundExplorer = new ForegroundExplorer();
|
|
879
|
+
foregroundExplorer.warmup().catch((error) => ctx.logger.warn("foreground explorer warmup failed: %s", error));
|
|
659
880
|
const disposeConnectors = host.webServer.register({
|
|
660
881
|
kind: "exact",
|
|
661
882
|
path: connectorsEndpoint,
|
|
@@ -844,10 +1065,66 @@ function apply(ctx) {
|
|
|
844
1065
|
}
|
|
845
1066
|
}
|
|
846
1067
|
});
|
|
1068
|
+
const disposeExplorer = host.webServer.register({
|
|
1069
|
+
kind: "exact",
|
|
1070
|
+
path: explorerEndpoint,
|
|
1071
|
+
handler: async (request, response) => {
|
|
1072
|
+
if (request.method !== "POST") {
|
|
1073
|
+
response.writeHead(405, { allow: "POST" });
|
|
1074
|
+
response.end();
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
1077
|
+
if (crossSiteRequest(request)) {
|
|
1078
|
+
response.writeHead(403, {
|
|
1079
|
+
"content-type": "application/json; charset=utf-8",
|
|
1080
|
+
"cache-control": "no-store"
|
|
1081
|
+
});
|
|
1082
|
+
response.end(JSON.stringify({ error: "已拒绝跨站请求。" }));
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
1085
|
+
if (process.platform !== "win32") {
|
|
1086
|
+
response.writeHead(501, {
|
|
1087
|
+
"content-type": "application/json; charset=utf-8",
|
|
1088
|
+
"cache-control": "no-store"
|
|
1089
|
+
});
|
|
1090
|
+
response.end(JSON.stringify({ error: "当前平台使用系统默认打开方式。" }));
|
|
1091
|
+
return;
|
|
1092
|
+
}
|
|
1093
|
+
try {
|
|
1094
|
+
const body = JSON.parse(await readRequestBody(request));
|
|
1095
|
+
if (typeof body.path !== "string" || body.path.trim() === "") {
|
|
1096
|
+
response.writeHead(400, {
|
|
1097
|
+
"content-type": "application/json; charset=utf-8",
|
|
1098
|
+
"cache-control": "no-store"
|
|
1099
|
+
});
|
|
1100
|
+
response.end(JSON.stringify({ error: "目录路径无效。" }));
|
|
1101
|
+
return;
|
|
1102
|
+
}
|
|
1103
|
+
await foregroundExplorer.open(body.path);
|
|
1104
|
+
response.writeHead(200, {
|
|
1105
|
+
"content-type": "application/json; charset=utf-8",
|
|
1106
|
+
"cache-control": "no-store"
|
|
1107
|
+
});
|
|
1108
|
+
response.end(JSON.stringify({
|
|
1109
|
+
opened: true,
|
|
1110
|
+
foreground: true
|
|
1111
|
+
}));
|
|
1112
|
+
} catch (error) {
|
|
1113
|
+
ctx.logger.warn("foreground explorer open failed: %s", error);
|
|
1114
|
+
response.writeHead(error instanceof SyntaxError ? 400 : 503, {
|
|
1115
|
+
"content-type": "application/json; charset=utf-8",
|
|
1116
|
+
"cache-control": "no-store"
|
|
1117
|
+
});
|
|
1118
|
+
response.end(JSON.stringify({ error: error instanceof SyntaxError ? "目录路径格式无效。" : "无法在前台打开资源管理器。" }));
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
});
|
|
847
1122
|
return () => {
|
|
848
1123
|
disposeDependencyInstaller();
|
|
1124
|
+
foregroundExplorer.dispose();
|
|
849
1125
|
disposeConnectors();
|
|
850
1126
|
disposeDependencies();
|
|
1127
|
+
disposeExplorer();
|
|
851
1128
|
disposePreferences();
|
|
852
1129
|
};
|
|
853
1130
|
}, "michengai-codex-ui: catalogs");
|
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.88",
|
|
4
4
|
"description": "以 Codex 风格重构 DSH Web 侧栏的独立客户端插件",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"publishConfig": {
|
|
@@ -53,6 +53,11 @@
|
|
|
53
53
|
"platform": "web"
|
|
54
54
|
}
|
|
55
55
|
},
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "tsc --noEmit && tsdown",
|
|
58
|
+
"typecheck": "tsc --noEmit",
|
|
59
|
+
"test": "pnpm run typecheck && vitest run tests/client-runtime.integration.spec.ts && tsdown && node tests/run-assertions.mjs"
|
|
60
|
+
},
|
|
56
61
|
"peerDependencies": {
|
|
57
62
|
"@deepseek-ai/cordis": ">=4.0.1 <5.0.0",
|
|
58
63
|
"@deepseek-ai/dsh-client-locale": ">=0.1.0-rc.0 <0.2.0",
|
|
@@ -98,10 +103,5 @@
|
|
|
98
103
|
"tsx": "^4.22.4",
|
|
99
104
|
"typescript": "^6.0.3",
|
|
100
105
|
"vitest": "^4.1.8"
|
|
101
|
-
},
|
|
102
|
-
"scripts": {
|
|
103
|
-
"build": "tsc --noEmit && tsdown",
|
|
104
|
-
"typecheck": "tsc --noEmit",
|
|
105
|
-
"test": "pnpm run typecheck && vitest run tests/client-runtime.integration.spec.ts && tsdown && node tests/run-assertions.mjs"
|
|
106
106
|
}
|
|
107
|
-
}
|
|
107
|
+
}
|