@michengai/dsh-codex-ui 0.2.91 → 0.2.93
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 +23 -0
- package/CHANGELOG.zh-CN.md +23 -0
- package/README.md +7 -57
- package/README.zh-CN.md +7 -57
- package/dist/client.js +15 -2
- package/dist/index.mjs +140 -50
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,29 @@
|
|
|
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.93 — 2026-08-30
|
|
8
|
+
|
|
9
|
+
### Compatibility
|
|
10
|
+
|
|
11
|
+
- Resolved the active DSH Desktop profile through the public `desktopProfiles` service and delegated installs and updates to the public `desktopPnpm` package manager instead of hard-coding the `web` profile.
|
|
12
|
+
- Preserved the ordinary Web/CLI profile fallback while recognizing Desktop-provided runtime and companion-package state across restarts.
|
|
13
|
+
- Routed new-session actions through Archive Manager's optional `uiWorkspace.startSession()` service, with the standard workspace service retained as the fallback.
|
|
14
|
+
|
|
15
|
+
### Safety
|
|
16
|
+
|
|
17
|
+
- Removed the dependency on the launcher-private `desktopPnpmBootstrap` implementation detail.
|
|
18
|
+
- Failed safely when a Desktop generation exposes incomplete public services instead of falling back to an ambient CLI that could mutate another profile.
|
|
19
|
+
- Reported the running Desktop DSH runtime as installed without fabricating a version or update when the Host exposes no supported runtime path.
|
|
20
|
+
|
|
21
|
+
## 0.2.92 — 2026-08-28
|
|
22
|
+
|
|
23
|
+
Companion release: `@michengai/dsh-codex-suite-installer@0.1.9`.
|
|
24
|
+
|
|
25
|
+
### Security
|
|
26
|
+
|
|
27
|
+
- Updated the legacy Suite and its installer manifest to `@michengai/dsh-im-connect@0.1.26`.
|
|
28
|
+
- Pinned the workspace dependency graph to the compatible patched `ansi-regex@5.0.1`, resolving CVE-2021-3807 in both the Suite and test dependency paths.
|
|
29
|
+
|
|
7
30
|
## 0.2.91 — 2026-08-28
|
|
8
31
|
|
|
9
32
|
### Release process
|
package/CHANGELOG.zh-CN.md
CHANGED
|
@@ -4,6 +4,29 @@
|
|
|
4
4
|
|
|
5
5
|
本日志记录 DSH Codex UI 及其一键安装器的最近发布;更早的变更可查看 [Git 提交历史](https://github.com/MichengAI/dsh-codex-ui/commits/main)。
|
|
6
6
|
|
|
7
|
+
## 0.2.93 — 2026-08-30
|
|
8
|
+
|
|
9
|
+
### 兼容性
|
|
10
|
+
|
|
11
|
+
- 通过公开的 `desktopProfiles` service 读取 DSH Desktop 当前 Profile,并把安装与更新交给公开的 `desktopPnpm` 包管理服务,不再硬编码 `web` Profile。
|
|
12
|
+
- 保留普通 Web/CLI 的 Profile 回退,同时在 Desktop 重启前后正确识别宿主 Runtime 与配套插件状态。
|
|
13
|
+
- 新建会话优先调用 Archive Manager 可选提供的 `uiWorkspace.startSession()` service,缺失时继续使用标准工作区服务。
|
|
14
|
+
|
|
15
|
+
### 安全性
|
|
16
|
+
|
|
17
|
+
- 移除对 Launcher 私有实现细节 `desktopPnpmBootstrap` 的依赖。
|
|
18
|
+
- Desktop generation 的公开服务不完整时安全失败,不再回退到可能修改其他 Profile 的环境 CLI。
|
|
19
|
+
- 宿主没有通过受支持路径暴露 Runtime 目录时,只确认正在运行的 Desktop DSH Runtime 已安装,不伪造版本或升级状态。
|
|
20
|
+
|
|
21
|
+
## 0.2.92 — 2026-08-28
|
|
22
|
+
|
|
23
|
+
配套版本:`@michengai/dsh-codex-suite-installer@0.1.9`。
|
|
24
|
+
|
|
25
|
+
### 安全修复
|
|
26
|
+
|
|
27
|
+
- 旧版 Suite 及其安装器清单更新为 `@michengai/dsh-im-connect@0.1.26`。
|
|
28
|
+
- 工作区依赖图固定使用兼容的修复版 `ansi-regex@5.0.1`,消除 Suite 与测试依赖路径中的 CVE-2021-3807。
|
|
29
|
+
|
|
7
30
|
## 0.2.91 — 2026-08-28
|
|
8
31
|
|
|
9
32
|
### 发布流程
|
package/README.md
CHANGED
|
@@ -53,49 +53,23 @@ Conversation menu: rename, pin, unread, archive, fork, copy, and delete.
|
|
|
53
53
|
- Examples use the `web` profile; replace it with the target profile.
|
|
54
54
|
- Source installation and development require Node.js 22+ and pnpm. Installing from npm does not require running `pnpm install` in an arbitrary directory.
|
|
55
55
|
|
|
56
|
-
## Plugin combo
|
|
57
|
-
|
|
58
|
-
`@michengai/dsh-codex-suite-installer` is the lightweight one-click installer for the `@michengai/dsh-codex-suite` member set. It adds these six plugins to the same profile as **direct dependencies**:
|
|
59
|
-
|
|
60
|
-
| Plugin | npm package | Role |
|
|
61
|
-
| --- | --- | --- |
|
|
62
|
-
| Codex UI | `@michengai/dsh-codex-ui` | Codex-style sidebar, workspace tree, search, and turn navigation |
|
|
63
|
-
| Expert management | `@michengai/dsh-agency-agents` | Settings page opened from **Experts** |
|
|
64
|
-
| Skill management | `@michengai/dsh-skills-manager` | Settings page opened from **Skills** |
|
|
65
|
-
| Archive management | `@michengai/dsh-archive-manager` | Permanent deletion and archived-session management |
|
|
66
|
-
| IM Assistant | `@michengai/dsh-im-connect` | IM settings and the **Channels** tab |
|
|
67
|
-
| Scheduled tasks | `@michengai/dsh-automation` | Scheduled-task settings and the **Schedule** tab |
|
|
68
|
-
|
|
69
|
-
`dshmarket` stays optional. When it is installed, **Plugins** opens the market first.
|
|
70
|
-
|
|
71
|
-
Direct dependencies let **Settings → About** detect and update every plugin independently. The lightweight installer carries only the version manifest, and it migrates the legacy aggregate Suite without leaving duplicate patches behind.
|
|
72
|
-
|
|
73
56
|
## DSH product ecosystem
|
|
74
57
|
|
|
75
|
-
Codex UI can be installed independently or used through the desktop app
|
|
58
|
+
Codex UI can be installed independently or used through the desktop app. They share the same DSH core but serve different ways of working:
|
|
76
59
|
|
|
77
60
|
| Product | Relationship to Codex UI |
|
|
78
61
|
| --- | --- |
|
|
79
62
|
| [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) | The host runtime that provides models, sessions, tools, and the plugin system |
|
|
80
63
|
| [DSH Codex Desktop](https://github.com/MichengAI/dsh-codex-desktop) | A ready-to-install desktop product with Codex UI and the other five feature products built in |
|
|
81
|
-
| [DSH Codex Suite](https://github.com/MichengAI/dsh-codex-ui/tree/main/packages/dsh-codex-suite) | A one-click suite for existing DSH Web environments that installs Codex UI and the other five feature products |
|
|
82
64
|
| Six feature products | [Codex UI](https://github.com/MichengAI/dsh-codex-ui) · [IM Connect](https://github.com/MichengAI/dsh-im-connect) · [Automation](https://github.com/MichengAI/dsh-automation) · [Skills Manager](https://github.com/MichengAI/dsh-skills-manager) · [Archive Manager](https://github.com/MichengAI/dsh-archive-manager) · [Agency Agents](https://github.com/MichengAI/dsh-agency-agents) |
|
|
83
65
|
|
|
84
66
|
## Installation
|
|
85
67
|
|
|
86
68
|
`dsh plugin add` forwards to `pnpm add` in the profile directory. Without a version and official registry, a local mirror or minimum-release-age policy can leave you on an older build.
|
|
87
69
|
|
|
88
|
-
### Ask another agent to install
|
|
89
|
-
|
|
90
|
-
Copy one of the sentences below into DSH, Codex, or WorkBuddy and let that agent install the combo into your local `web` profile.
|
|
70
|
+
### Ask another agent to install Codex UI
|
|
91
71
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
```text
|
|
95
|
-
Use the one-click installer to add all six DSH Codex Suite members as direct dependencies of my local web profile: npx --yes @michengai/dsh-codex-suite-installer@latest --profile web. Confirm its configuration check succeeds, then remind me to restart DSH Web and hard-refresh the browser.
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
UI only:
|
|
72
|
+
Copy the sentence below into DSH, Codex, or WorkBuddy and let that agent install Codex UI into your local `web` profile.
|
|
99
73
|
|
|
100
74
|
```text
|
|
101
75
|
Install the latest DSH plugin @michengai/dsh-codex-ui into my local web profile using the official npm registry: dsh plugin --profile web add @michengai/dsh-codex-ui@latest --registry=https://registry.npmjs.org/. Then run dsh --profile web --dump-config, confirm codex-ui is mounted, and remind me to restart DSH Web and hard-refresh the browser.
|
|
@@ -103,33 +77,9 @@ Install the latest DSH plugin @michengai/dsh-codex-ui into my local web profile
|
|
|
103
77
|
|
|
104
78
|
| Product | How to use it |
|
|
105
79
|
| --- | --- |
|
|
106
|
-
| DSH | Send
|
|
107
|
-
| Codex | Send
|
|
108
|
-
| WorkBuddy | Send
|
|
109
|
-
|
|
110
|
-
The installer needs the current `dsh` on PATH. Set `DSH_BIN` when the executable lives elsewhere.
|
|
111
|
-
|
|
112
|
-
### Install the complete suite
|
|
113
|
-
|
|
114
|
-
This is the one-click combo. Run it from any PowerShell directory:
|
|
115
|
-
|
|
116
|
-
```powershell
|
|
117
|
-
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
|
118
|
-
$OutputEncoding = [System.Text.Encoding]::UTF8
|
|
119
|
-
npx --yes @michengai/dsh-codex-suite-installer@latest --profile web
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
The installer reads its exact verified member versions, adds all six members as direct profile dependencies in one `dsh plugin add`, and finishes with `dsh --profile web --dump-config`. Replace `@latest` with an installer version to pin the whole set.
|
|
123
|
-
|
|
124
|
-
Restart DSH Web and hard-refresh the browser. Existing members are aligned in place; a legacy `@michengai/dsh-codex-suite` aggregate dependency is removed only after all six direct members have been staged.
|
|
125
|
-
|
|
126
|
-
Use the same command with another profile name for a clean custom Web profile:
|
|
127
|
-
|
|
128
|
-
```powershell
|
|
129
|
-
npx --yes @michengai/dsh-codex-suite-installer@latest --profile codex
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
The installer stays in the current `DSH_HOME` and places DSH's built-in `@deepseek-ai/dsh-web-app` before the member bundles. It neither creates a separate Home nor reinstalls the official Web package.
|
|
80
|
+
| DSH | Send the sentence above to the current session. |
|
|
81
|
+
| Codex | Send the sentence above to Codex and let it install locally. |
|
|
82
|
+
| WorkBuddy | Send the sentence above to WorkBuddy. |
|
|
133
83
|
|
|
134
84
|
### Install Codex UI only
|
|
135
85
|
|
|
@@ -173,7 +123,7 @@ Open DSH Web. The left navigation is rendered by this plugin.
|
|
|
173
123
|
| Manage a conversation | Open the conversation menu to rename, pin, mark unread, archive, fork, copy, or delete. |
|
|
174
124
|
| Jump between turns | Use the turn marks on the left of the current conversation. |
|
|
175
125
|
| Inspect connectors | Open **Settings → Connectors**. Addresses, commands, and credentials are never shown. |
|
|
176
|
-
| Check companion plugins | Open **Settings → About** to install or update
|
|
126
|
+
| Check companion plugins | Open **Settings → About** to install or update individual companion plugins. |
|
|
177
127
|
|
|
178
128
|
Deleting a workspace registration does not delete its folder or conversation records. Pinned and unread state is stored only in the current browser.
|
|
179
129
|
|
package/README.zh-CN.md
CHANGED
|
@@ -53,49 +53,23 @@
|
|
|
53
53
|
- 以下示例使用 `web` profile;请替换为实际目标 profile。
|
|
54
54
|
- 从源码安装或二次开发需要 Node.js 22+ 与 pnpm;仅从 npm 安装无需在任意目录执行 `pnpm install`。
|
|
55
55
|
|
|
56
|
-
## 插件组合
|
|
57
|
-
|
|
58
|
-
`@michengai/dsh-codex-suite-installer` 是 `@michengai/dsh-codex-suite` 成员组合的轻量一键安装器,会把下面 6 个插件作为**直接依赖**装进同一个 profile:
|
|
59
|
-
|
|
60
|
-
| 插件 | npm 包 | 作用 |
|
|
61
|
-
| --- | --- | --- |
|
|
62
|
-
| Codex UI | `@michengai/dsh-codex-ui` | Codex 风格侧栏、工作区会话树、搜索和轮次导航 |
|
|
63
|
-
| 专家管理 | `@michengai/dsh-agency-agents` | 从「专家」进入对应设置页 |
|
|
64
|
-
| 技能管理 | `@michengai/dsh-skills-manager` | 从「技能」进入对应设置页 |
|
|
65
|
-
| 归档管理 | `@michengai/dsh-archive-manager` | 提供永久删除和已归档会话管理 |
|
|
66
|
-
| IM 助理 | `@michengai/dsh-im-connect` | IM 设置页和「频道」页签 |
|
|
67
|
-
| 定时任务 | `@michengai/dsh-automation` | 定时任务设置页和「定时」页签 |
|
|
68
|
-
|
|
69
|
-
`dshmarket` 仍是可选项。已安装时,「插件」入口会优先进入市场。
|
|
70
|
-
|
|
71
|
-
直接依赖让「设置 → 关于」能够分别检测和升级每个插件。轻量安装器只携带版本清单,也会自动迁移旧版聚合 Suite,避免聚合 patch 与独立 patch 冲突。
|
|
72
|
-
|
|
73
56
|
## DSH 产品生态
|
|
74
57
|
|
|
75
|
-
Codex UI
|
|
58
|
+
Codex UI 既可以独立安装,也可以随桌面端一起使用。它们共享同一个 DSH 核心,但面向不同的使用方式:
|
|
76
59
|
|
|
77
60
|
| 产品 | 与 Codex UI 的关系 |
|
|
78
61
|
| --- | --- |
|
|
79
62
|
| [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) | Codex UI 的运行宿主,提供模型、会话、工具和插件系统 |
|
|
80
63
|
| [DSH Codex Desktop](https://github.com/MichengAI/dsh-codex-desktop) | 下载安装即用的桌面产品,已内置 Codex UI 和其他 5 个功能产品 |
|
|
81
|
-
| [DSH Codex Suite](https://github.com/MichengAI/dsh-codex-ui/tree/main/packages/dsh-codex-suite) | 面向已有 DSH Web 环境的一键套件,会安装 Codex UI 和其他 5 个功能产品 |
|
|
82
64
|
| 6 个功能产品 | [Codex UI](https://github.com/MichengAI/dsh-codex-ui) · [IM Connect](https://github.com/MichengAI/dsh-im-connect) · [Automation](https://github.com/MichengAI/dsh-automation) · [Skills Manager](https://github.com/MichengAI/dsh-skills-manager) · [Archive Manager](https://github.com/MichengAI/dsh-archive-manager) · [Agency Agents](https://github.com/MichengAI/dsh-agency-agents) |
|
|
83
65
|
|
|
84
66
|
## 安装
|
|
85
67
|
|
|
86
68
|
`dsh plugin add` 会转发到 profile 目录里的 `pnpm add`。不写版本、不指定官方源时,本机镜像和最短发布间隔可能让你停在旧版。
|
|
87
69
|
|
|
88
|
-
### 交给其他 Agent
|
|
89
|
-
|
|
90
|
-
把下面其中一句复制到 DSH、Codex 或 WorkBuddy,让它代你安装到本机 `web` profile。
|
|
70
|
+
### 交给其他 Agent 一句话安装 Codex UI
|
|
91
71
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
```text
|
|
95
|
-
请用一键安装器把 DSH Codex Suite 的六个成员作为直接依赖装进本机 web profile,执行:npx --yes @michengai/dsh-codex-suite-installer@latest --profile web。确认安装器完成配置检查,并提醒我重启 DSH Web 后硬刷新浏览器。
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
只安装 Codex UI:
|
|
72
|
+
把下面这句话复制到 DSH、Codex 或 WorkBuddy,让它代你安装到本机 `web` profile。
|
|
99
73
|
|
|
100
74
|
```text
|
|
101
75
|
请把 DSH 插件 @michengai/dsh-codex-ui 最新版装进本机 web profile,使用官方 npm 源执行:dsh plugin --profile web add @michengai/dsh-codex-ui@latest --registry=https://registry.npmjs.org/。装完执行 dsh --profile web --dump-config,确认已挂载 codex-ui,并提醒我重启 DSH Web 后硬刷新浏览器。
|
|
@@ -103,33 +77,9 @@ Codex UI 既可以独立安装,也可以随桌面端或 Web 套件一起使用
|
|
|
103
77
|
|
|
104
78
|
| 产品 | 怎么用 |
|
|
105
79
|
| --- | --- |
|
|
106
|
-
| DSH |
|
|
107
|
-
| Codex |
|
|
108
|
-
| WorkBuddy |
|
|
109
|
-
|
|
110
|
-
一键安装器需要能从 PATH 找到当前 DSH;也可以用 `DSH_BIN` 指定 `dsh` 可执行文件。
|
|
111
|
-
|
|
112
|
-
### 安装完整套件
|
|
113
|
-
|
|
114
|
-
这是一键组合安装。在任意 PowerShell 目录执行:
|
|
115
|
-
|
|
116
|
-
```powershell
|
|
117
|
-
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
|
118
|
-
$OutputEncoding = [System.Text.Encoding]::UTF8
|
|
119
|
-
npx --yes @michengai/dsh-codex-suite-installer@latest --profile web
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
安装器会读取自身锁定的精确成员版本,用一次 `dsh plugin add` 将六个成员写成 profile 的直接依赖,并在最后运行 `dsh --profile web --dump-config`。需要钉死一组版本时,把 `@latest` 换成具体安装器版本。
|
|
123
|
-
|
|
124
|
-
安装后重启 DSH Web 并硬刷新浏览器。已有成员会原地对齐版本;旧版 `@michengai/dsh-codex-suite` 聚合依赖会在六个成员提升完成后自动移除。
|
|
125
|
-
|
|
126
|
-
新建自定义 Web profile 也使用同一命令,只需改 profile 名:
|
|
127
|
-
|
|
128
|
-
```powershell
|
|
129
|
-
npx --yes @michengai/dsh-codex-suite-installer@latest --profile codex
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
安装器会复用当前 `DSH_HOME`,并把 DSH 自带的 `@deepseek-ai/dsh-web-app` 放到成员 bundle 之前;不会创建独立 Home,也不会重新安装官方 Web 包。
|
|
80
|
+
| DSH | 把上面这句话发给当前会话。 |
|
|
81
|
+
| Codex | 把上面这句话发给 Codex,让它在本机执行安装。 |
|
|
82
|
+
| WorkBuddy | 把上面这句话发给 WorkBuddy。 |
|
|
133
83
|
|
|
134
84
|
### 只安装 Codex UI
|
|
135
85
|
|
|
@@ -173,7 +123,7 @@ dsh --profile web --dump-config
|
|
|
173
123
|
| 管理会话 | 打开会话菜单,进行重命名、置顶、未读、归档、派生、复制或删除。 |
|
|
174
124
|
| 跳转轮次 | 使用当前会话左侧的轮次刻度跳转到对应提问。 |
|
|
175
125
|
| 查看连接器 | 打开「设置 → 连接器」。不会展示地址、命令或凭证。 |
|
|
176
|
-
| 查看配套插件 | 打开「设置 →
|
|
126
|
+
| 查看配套插件 | 打开「设置 → 关于」,安装或更新各个配套插件。 |
|
|
177
127
|
|
|
178
128
|
删除项目注册不会删除项目目录或会话记录。置顶和未读状态只保存在当前浏览器。
|
|
179
129
|
|
package/dist/client.js
CHANGED
|
@@ -5445,6 +5445,18 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
5445
5445
|
function hasDeleteSession(value) {
|
|
5446
5446
|
return value !== null && typeof value === "object" && "deleteSession" in value && typeof value.deleteSession === "function";
|
|
5447
5447
|
}
|
|
5448
|
+
function hasStartSession(value) {
|
|
5449
|
+
return value !== null && typeof value === "object" && "startSession" in value && typeof value.startSession === "function";
|
|
5450
|
+
}
|
|
5451
|
+
/** Archive Manager replaces the official ui-workspace row with this optional service. */
|
|
5452
|
+
function startWorkspaceSession(ctx, workspaceId) {
|
|
5453
|
+
const uiWorkspace = ctx.get("uiWorkspace");
|
|
5454
|
+
if (hasStartSession(uiWorkspace)) {
|
|
5455
|
+
uiWorkspace.startSession(workspaceId);
|
|
5456
|
+
return;
|
|
5457
|
+
}
|
|
5458
|
+
ctx.workspaces.startSession(workspaceId);
|
|
5459
|
+
}
|
|
5448
5460
|
/** 替换 DSH 的官方 sidebar 插槽,不修改 DSH 源码或会话数据。 */
|
|
5449
5461
|
function apply(ctx) {
|
|
5450
5462
|
ctx.effect(() => ctx.locale.register(NS, {
|
|
@@ -5490,7 +5502,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
5490
5502
|
ctx.sessions.open(sessionId);
|
|
5491
5503
|
},
|
|
5492
5504
|
startSession: (workspaceId) => {
|
|
5493
|
-
ctx
|
|
5505
|
+
startWorkspaceSession(ctx, workspaceId);
|
|
5494
5506
|
},
|
|
5495
5507
|
toggleSidebar: () => {
|
|
5496
5508
|
ctx.layout.toggleSidebar();
|
|
@@ -5561,7 +5573,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
5561
5573
|
insertWorkspaceBefore: (workspaceId, beforeWorkspaceId) => ctx.workspaces.insertBefore(workspaceId, beforeWorkspaceId),
|
|
5562
5574
|
insertSessionBefore: (workspaceId, sessionId, beforeSessionId) => ctx.workspaces.insertSessionBefore(workspaceId, sessionId, beforeSessionId),
|
|
5563
5575
|
startSession: (workspaceId) => {
|
|
5564
|
-
ctx
|
|
5576
|
+
startWorkspaceSession(ctx, workspaceId);
|
|
5565
5577
|
}
|
|
5566
5578
|
})
|
|
5567
5579
|
}, CodexWorkspaceBrowser));
|
|
@@ -5601,6 +5613,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
5601
5613
|
//#endregion
|
|
5602
5614
|
exports.apply = apply;
|
|
5603
5615
|
exports.inject = inject;
|
|
5616
|
+
exports.startWorkspaceSession = startWorkspaceSession;
|
|
5604
5617
|
return module.exports;
|
|
5605
5618
|
}
|
|
5606
5619
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -56,13 +56,63 @@ function managedDependency(id) {
|
|
|
56
56
|
const PROFILE_PENDING_UPDATES_FILE = ".dsh-pending-updates.json";
|
|
57
57
|
const APPLY_PLUGIN_UPDATES_IPC = "apply-plugin-updates";
|
|
58
58
|
const PLUGIN_INSTALL_TIMEOUT_MS = 6e5;
|
|
59
|
-
function
|
|
60
|
-
if (
|
|
61
|
-
return
|
|
59
|
+
function optionalService(ctx, name) {
|
|
60
|
+
if (ctx === void 0) return void 0;
|
|
61
|
+
return typeof ctx.get === "function" ? ctx.get(name) : ctx[name];
|
|
62
62
|
}
|
|
63
|
-
|
|
63
|
+
function validProfileName(value) {
|
|
64
|
+
return typeof value === "string" && value !== "" && value !== "." && value !== ".." && value !== "node_modules" && !value.includes("/") && !value.includes("\\") && !/[\0-\x1f\x7f]/.test(value);
|
|
65
|
+
}
|
|
66
|
+
function profileNameFromArgv(argv) {
|
|
67
|
+
for (let index = 2; index < argv.length; index += 1) {
|
|
68
|
+
const argument = argv[index];
|
|
69
|
+
if (argument === "--profile") return argv[index + 1];
|
|
70
|
+
if (argument?.startsWith("--profile=")) return argument.slice(10);
|
|
71
|
+
}
|
|
72
|
+
return argv[2] === "web" ? "web" : void 0;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Desktop 通过可选 Host service 暴露当前 profile;普通 Web/CLI 继续使用
|
|
76
|
+
* DSH_PROFILE_DIR、命令行 profile 与默认 web profile。
|
|
77
|
+
*/
|
|
78
|
+
function resolveDependencyRuntime(ctx, options = {}) {
|
|
79
|
+
const env = options.env ?? process.env;
|
|
80
|
+
const argv = options.argv ?? process.argv;
|
|
81
|
+
const cwd = options.cwd ?? process.cwd();
|
|
82
|
+
const home = options.homeDir ?? homedir();
|
|
83
|
+
const profiles = optionalService(ctx, "desktopProfiles");
|
|
84
|
+
const desktopPnpm = optionalService(ctx, "desktopPnpm");
|
|
85
|
+
if (profiles !== void 0) {
|
|
86
|
+
const current = profiles.current;
|
|
87
|
+
if (!validProfileName(current?.name) || typeof current.dir !== "string" || !isAbsolute(current.dir)) throw new Error("DSH Desktop 当前 Profile 信息无效,请重启 Desktop 后重试。");
|
|
88
|
+
if (typeof desktopPnpm?.runPlugin !== "function") throw new Error("DSH Desktop 包管理服务尚未就绪,请重启 Desktop 后重试。");
|
|
89
|
+
const profileDir = resolve(current.dir);
|
|
90
|
+
const runtimeRoots = typeof env.DSH_RUNTIME_DIR === "string" && isAbsolute(env.DSH_RUNTIME_DIR) ? [resolve(env.DSH_RUNTIME_DIR)] : [];
|
|
91
|
+
return {
|
|
92
|
+
environmentKind: "desktop",
|
|
93
|
+
profileName: current.name,
|
|
94
|
+
profileDir,
|
|
95
|
+
runtimeRoots,
|
|
96
|
+
desktopPnpm
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
const profileDir = resolve(env.DSH_PROFILE_DIR ?? resolve(home, ".dsh", "profiles", "web"));
|
|
100
|
+
const selected = profileNameFromArgv(argv);
|
|
101
|
+
const profileName = validProfileName(selected) ? selected : validProfileName(basename(profileDir)) ? basename(profileDir) : "web";
|
|
102
|
+
const cliRuntimeRoot = argv[1] === void 0 ? void 0 : resolveDshRuntimeRoot(argv[1], cwd);
|
|
103
|
+
return {
|
|
104
|
+
environmentKind: "cli",
|
|
105
|
+
profileName,
|
|
106
|
+
profileDir,
|
|
107
|
+
runtimeRoots: [env.DSH_RUNTIME_DIR, cliRuntimeRoot].filter((root) => root !== void 0 && root !== "")
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function profileDirectory(runtime) {
|
|
111
|
+
return runtime.profileDir;
|
|
112
|
+
}
|
|
113
|
+
async function declaredPluginNames(runtime) {
|
|
64
114
|
try {
|
|
65
|
-
const manifest = JSON.parse(await readFile(resolve(profileDirectory(), "package.json"), "utf8"));
|
|
115
|
+
const manifest = JSON.parse(await readFile(resolve(profileDirectory(runtime), "package.json"), "utf8"));
|
|
66
116
|
return [.../* @__PURE__ */ new Set([...Object.keys({
|
|
67
117
|
...manifest.devDependencies,
|
|
68
118
|
...manifest.dependencies
|
|
@@ -101,17 +151,12 @@ function resolveDshRuntimeRoot(entry = process.argv[1], cwd = process.cwd()) {
|
|
|
101
151
|
const root = cliEntry.slice(0, index);
|
|
102
152
|
return root.endsWith(sep) ? root.slice(0, -1) : root;
|
|
103
153
|
}
|
|
104
|
-
function packageLookupRoots(packageName) {
|
|
105
|
-
if (!isOfficialRuntimePackage(packageName)) return [profileDirectory()];
|
|
106
|
-
|
|
107
|
-
return [...new Set([
|
|
108
|
-
runtimeDir,
|
|
109
|
-
resolveDshRuntimeRoot(),
|
|
110
|
-
profileDirectory()
|
|
111
|
-
].filter((root) => root !== void 0 && root !== ""))];
|
|
154
|
+
function packageLookupRoots(packageName, runtime) {
|
|
155
|
+
if (!isOfficialRuntimePackage(packageName)) return [profileDirectory(runtime)];
|
|
156
|
+
return [.../* @__PURE__ */ new Set([...runtime.runtimeRoots, profileDirectory(runtime)])];
|
|
112
157
|
}
|
|
113
|
-
async function installedPackageVersion(packageName) {
|
|
114
|
-
for (const root of packageLookupRoots(packageName)) try {
|
|
158
|
+
async function installedPackageVersion(packageName, runtime) {
|
|
159
|
+
for (const root of packageLookupRoots(packageName, runtime)) try {
|
|
115
160
|
const manifest = JSON.parse(await readFile(resolve(root, "node_modules", ...packageName.split("/"), "package.json"), "utf8"));
|
|
116
161
|
if (typeof manifest.version === "string" && manifest.version !== "") return manifest.version;
|
|
117
162
|
} catch (error) {
|
|
@@ -183,9 +228,9 @@ function applyReleaseExclude(source, packageName, version) {
|
|
|
183
228
|
return `${source}${source === "" || source.endsWith("\n") ? "" : eol}minimumReleaseAgeExclude:${eol}${entry}${eol}`;
|
|
184
229
|
}
|
|
185
230
|
/** 将用户本次确认的精确版本加入 Profile 的 pnpm 发布时间保护例外。 */
|
|
186
|
-
async function ensureLatestReleaseAllowed(packageName, version) {
|
|
231
|
+
async function ensureLatestReleaseAllowed(packageName, version, runtime) {
|
|
187
232
|
if (parseSemver(version) === void 0) throw new Error("npm 返回了无法识别的最新版本。");
|
|
188
|
-
const path = resolve(profileDirectory(), "pnpm-workspace.yaml");
|
|
233
|
+
const path = resolve(profileDirectory(runtime), "pnpm-workspace.yaml");
|
|
189
234
|
let source;
|
|
190
235
|
try {
|
|
191
236
|
source = await readFile(path, "utf8");
|
|
@@ -231,11 +276,16 @@ function newerVersion(installed, latest) {
|
|
|
231
276
|
for (let index = 0; index < current.core.length; index += 1) if (candidate.core[index] !== current.core[index]) return candidate.core[index] > current.core[index];
|
|
232
277
|
return comparePrerelease(candidate.prerelease, current.prerelease) > 0;
|
|
233
278
|
}
|
|
234
|
-
/**
|
|
235
|
-
async function dependencyStatuses() {
|
|
236
|
-
const declaredNames = await declaredPluginNames();
|
|
279
|
+
/** 返回当前 profile 中固定管理插件的实际安装版本与 npm latest 状态。 */
|
|
280
|
+
async function dependencyStatuses(runtime = resolveDependencyRuntime()) {
|
|
281
|
+
const declaredNames = await declaredPluginNames(runtime);
|
|
237
282
|
return Promise.all(MANAGED_DEPENDENCIES.map(async (dependency) => {
|
|
238
|
-
const version = await installedPackageVersion(dependency.packageName);
|
|
283
|
+
const version = await installedPackageVersion(dependency.packageName, runtime);
|
|
284
|
+
if (version === void 0 && runtime.environmentKind === "desktop" && isOfficialRuntimePackage(dependency.packageName)) return {
|
|
285
|
+
...dependency,
|
|
286
|
+
installed: true,
|
|
287
|
+
updateAvailable: false
|
|
288
|
+
};
|
|
239
289
|
const declared = isOfficialRuntimePackage(dependency.packageName) || isManagedPackageDeclared(dependency.packageName, declaredNames);
|
|
240
290
|
if (version === void 0 || !isManagedPackageInstalled({
|
|
241
291
|
installedVersion: version,
|
|
@@ -273,8 +323,8 @@ function isRestartableInstallError(error) {
|
|
|
273
323
|
const message = error instanceof Error ? error.message : String(error);
|
|
274
324
|
return /完全退出桌面端|正在运行的插件|pnpm 仓库不一致/.test(message);
|
|
275
325
|
}
|
|
276
|
-
async function recordPendingUpdate(packageName, version) {
|
|
277
|
-
const pendingPath = resolve(profileDirectory(), PROFILE_PENDING_UPDATES_FILE);
|
|
326
|
+
async function recordPendingUpdate(packageName, version, runtime) {
|
|
327
|
+
const pendingPath = resolve(profileDirectory(runtime), PROFILE_PENDING_UPDATES_FILE);
|
|
278
328
|
let packages = [];
|
|
279
329
|
try {
|
|
280
330
|
const parsed = JSON.parse(await readFile(pendingPath, "utf8"));
|
|
@@ -297,8 +347,8 @@ async function recordPendingUpdate(packageName, version) {
|
|
|
297
347
|
});
|
|
298
348
|
await writeFile(pendingPath, `${JSON.stringify({ packages }, void 0, 2)}\n`, "utf8");
|
|
299
349
|
}
|
|
300
|
-
async function removePendingUpdate(packageName) {
|
|
301
|
-
const pendingPath = resolve(profileDirectory(), PROFILE_PENDING_UPDATES_FILE);
|
|
350
|
+
async function removePendingUpdate(packageName, runtime) {
|
|
351
|
+
const pendingPath = resolve(profileDirectory(runtime), PROFILE_PENDING_UPDATES_FILE);
|
|
302
352
|
try {
|
|
303
353
|
const parsed = JSON.parse(await readFile(pendingPath, "utf8"));
|
|
304
354
|
if (!Array.isArray(parsed.packages)) return;
|
|
@@ -313,8 +363,8 @@ async function removePendingUpdate(packageName) {
|
|
|
313
363
|
if (error.code !== "ENOENT") throw error;
|
|
314
364
|
}
|
|
315
365
|
}
|
|
316
|
-
async function recordDeclaredVersion(packageName, version) {
|
|
317
|
-
const manifestPath = resolve(profileDirectory(), "package.json");
|
|
366
|
+
async function recordDeclaredVersion(packageName, version, runtime) {
|
|
367
|
+
const manifestPath = resolve(profileDirectory(runtime), "package.json");
|
|
318
368
|
let manifest;
|
|
319
369
|
try {
|
|
320
370
|
manifest = JSON.parse(await readFile(manifestPath, "utf8"));
|
|
@@ -344,6 +394,7 @@ function pluginExecArgv(args = process.execArgv) {
|
|
|
344
394
|
return args.filter((arg) => !/^--(?:inspect|inspect-brk|debug|debug-brk)(?:=|$)/.test(arg));
|
|
345
395
|
}
|
|
346
396
|
const activePluginChildren = /* @__PURE__ */ new Set();
|
|
397
|
+
const activeDesktopPluginHandles = /* @__PURE__ */ new Set();
|
|
347
398
|
function terminatePluginChild(child) {
|
|
348
399
|
if (child.exitCode !== null || child.killed) return;
|
|
349
400
|
if (process.platform === "win32" && child.pid !== void 0) {
|
|
@@ -367,6 +418,7 @@ function terminatePluginChild(child) {
|
|
|
367
418
|
/** 插件停用时终止仍在运行的安装进程,避免热更新后遗留 pnpm。 */
|
|
368
419
|
function disposeDependencyInstaller() {
|
|
369
420
|
for (const child of activePluginChildren) terminatePluginChild(child);
|
|
421
|
+
for (const handle of activeDesktopPluginHandles) handle.cancel();
|
|
370
422
|
}
|
|
371
423
|
function monitorPluginChild(child, timeoutMs = PLUGIN_INSTALL_TIMEOUT_MS) {
|
|
372
424
|
return new Promise((resolvePromise, reject) => {
|
|
@@ -398,14 +450,52 @@ function monitorPluginChild(child, timeoutMs = PLUGIN_INSTALL_TIMEOUT_MS) {
|
|
|
398
450
|
timeout.unref?.();
|
|
399
451
|
});
|
|
400
452
|
}
|
|
401
|
-
function
|
|
453
|
+
function monitorDesktopPlugin(handle, timeoutMs = PLUGIN_INSTALL_TIMEOUT_MS) {
|
|
454
|
+
return new Promise((resolvePromise, reject) => {
|
|
455
|
+
activeDesktopPluginHandles.add(handle);
|
|
456
|
+
let output = "";
|
|
457
|
+
let settled = false;
|
|
458
|
+
const collect = (chunk) => {
|
|
459
|
+
output = `${output}${String(chunk)}`.slice(-65536);
|
|
460
|
+
};
|
|
461
|
+
const finish = (error) => {
|
|
462
|
+
if (settled) return;
|
|
463
|
+
settled = true;
|
|
464
|
+
clearTimeout(timeout);
|
|
465
|
+
activeDesktopPluginHandles.delete(handle);
|
|
466
|
+
error === void 0 ? resolvePromise() : reject(error);
|
|
467
|
+
};
|
|
468
|
+
handle.stdout?.on("data", collect);
|
|
469
|
+
handle.stderr?.on("data", collect);
|
|
470
|
+
handle.stdout?.once("error", () => {
|
|
471
|
+
handle.cancel();
|
|
472
|
+
finish(/* @__PURE__ */ new Error("无法读取 DSH Desktop 插件安装输出。"));
|
|
473
|
+
});
|
|
474
|
+
handle.stderr?.once("error", () => {
|
|
475
|
+
handle.cancel();
|
|
476
|
+
finish(/* @__PURE__ */ new Error("无法读取 DSH Desktop 插件安装输出。"));
|
|
477
|
+
});
|
|
478
|
+
handle.done.then((outcome) => {
|
|
479
|
+
finish(outcome.exitCode === 0 && outcome.signal === null ? void 0 : pluginCommandError(output));
|
|
480
|
+
}, () => {
|
|
481
|
+
finish(pluginCommandError(output));
|
|
482
|
+
});
|
|
483
|
+
const timeout = setTimeout(() => {
|
|
484
|
+
handle.cancel();
|
|
485
|
+
finish(/* @__PURE__ */ new Error("插件安装超时,已终止安装进程。请检查网络后重试。"));
|
|
486
|
+
}, timeoutMs);
|
|
487
|
+
timeout.unref?.();
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
function runDshPlugin(args, runtime = resolveDependencyRuntime(), timeoutMs = PLUGIN_INSTALL_TIMEOUT_MS) {
|
|
491
|
+
if (runtime.desktopPnpm !== void 0) return monitorDesktopPlugin(runtime.desktopPnpm.runPlugin(args, runtime.profileDir), timeoutMs);
|
|
402
492
|
const entry = resolveDshCliEntry();
|
|
403
493
|
return monitorPluginChild(spawn(process.execPath, [
|
|
404
494
|
...pluginExecArgv(),
|
|
405
495
|
entry,
|
|
406
496
|
"plugin",
|
|
407
497
|
"--profile",
|
|
408
|
-
|
|
498
|
+
runtime.profileName,
|
|
409
499
|
...args
|
|
410
500
|
], {
|
|
411
501
|
cwd: process.cwd(),
|
|
@@ -424,11 +514,11 @@ function runDshPlugin(args, timeoutMs = PLUGIN_INSTALL_TIMEOUT_MS) {
|
|
|
424
514
|
/** 并发安装互斥:pnpm 锁文件竞争会触发 EPERM/EBUSY,同一时间只允许一个安装进程。 */
|
|
425
515
|
let installing = false;
|
|
426
516
|
/** 仅允许安装固定依赖,避免把浏览器输入转成任意命令。 */
|
|
427
|
-
async function installDependency(id, requestHotUpdate = requestDesktopHotUpdate) {
|
|
517
|
+
async function installDependency(id, requestHotUpdate = requestDesktopHotUpdate, runtime = resolveDependencyRuntime()) {
|
|
428
518
|
if (installing) throw new Error("已有依赖安装正在进行,请等待完成后再试。");
|
|
429
519
|
installing = true;
|
|
430
520
|
try {
|
|
431
|
-
return await installDependenciesLocked([id], requestHotUpdate);
|
|
521
|
+
return await installDependenciesLocked([id], requestHotUpdate, runtime);
|
|
432
522
|
} finally {
|
|
433
523
|
installing = false;
|
|
434
524
|
}
|
|
@@ -438,31 +528,31 @@ function updatableDependencyIds(statuses) {
|
|
|
438
528
|
return statuses.filter((status) => status.installed && status.updateAvailable).map((status) => status.id);
|
|
439
529
|
}
|
|
440
530
|
/** 把所有待更新版本一次写入清单,最后只请求一次桌面热更新。 */
|
|
441
|
-
async function updateAllDependencies(requestHotUpdate = requestDesktopHotUpdate) {
|
|
531
|
+
async function updateAllDependencies(requestHotUpdate = requestDesktopHotUpdate, runtime = resolveDependencyRuntime()) {
|
|
442
532
|
if (installing) throw new Error("已有依赖安装正在进行,请等待完成后再试。");
|
|
443
533
|
installing = true;
|
|
444
534
|
try {
|
|
445
|
-
const current = await dependencyStatuses();
|
|
535
|
+
const current = await dependencyStatuses(runtime);
|
|
446
536
|
const ids = updatableDependencyIds(current);
|
|
447
537
|
if (ids.length === 0) return {
|
|
448
538
|
dependencies: current,
|
|
449
539
|
updatedCount: 0
|
|
450
540
|
};
|
|
451
541
|
return {
|
|
452
|
-
dependencies: await installDependenciesLocked(ids, requestHotUpdate),
|
|
542
|
+
dependencies: await installDependenciesLocked(ids, requestHotUpdate, runtime),
|
|
453
543
|
updatedCount: ids.length
|
|
454
544
|
};
|
|
455
545
|
} finally {
|
|
456
546
|
installing = false;
|
|
457
547
|
}
|
|
458
548
|
}
|
|
459
|
-
async function installDependenciesLocked(ids, requestHotUpdate) {
|
|
549
|
+
async function installDependenciesLocked(ids, requestHotUpdate, runtime) {
|
|
460
550
|
const dependencies = [...new Set(ids)].map((id) => {
|
|
461
551
|
const dependency = managedDependency(id);
|
|
462
552
|
if (dependency === void 0) throw new Error("不支持安装该依赖。");
|
|
463
553
|
return dependency;
|
|
464
554
|
});
|
|
465
|
-
const declared = await declaredPluginNames();
|
|
555
|
+
const declared = await declaredPluginNames(runtime);
|
|
466
556
|
const requestedTargets = await Promise.all(dependencies.map(async (dependency) => {
|
|
467
557
|
const latestVersion = await npmLatestVersion(dependency.packageName);
|
|
468
558
|
if (latestVersion === void 0) throw new Error("无法获取 npm 最新版本,请检查网络或 npm registry 后重试。");
|
|
@@ -482,7 +572,7 @@ async function installDependenciesLocked(ids, requestHotUpdate) {
|
|
|
482
572
|
packageName,
|
|
483
573
|
version: requestedVersion
|
|
484
574
|
};
|
|
485
|
-
const version = await installedPackageVersion(packageName) ?? await npmLatestVersion(packageName);
|
|
575
|
+
const version = await installedPackageVersion(packageName, runtime) ?? await npmLatestVersion(packageName);
|
|
486
576
|
if (version === void 0) throw new Error("无法读取 Suite 成员版本,请检查 npm 安装后重试。");
|
|
487
577
|
return {
|
|
488
578
|
packageName,
|
|
@@ -491,27 +581,27 @@ async function installDependenciesLocked(ids, requestHotUpdate) {
|
|
|
491
581
|
}));
|
|
492
582
|
const remove = [...new Set(targets.flatMap((target) => pluginsToRemoveBeforeInstall(declared, target.packageName)))];
|
|
493
583
|
for (const target of targets) {
|
|
494
|
-
await ensureLatestReleaseAllowed(target.packageName, target.version);
|
|
495
|
-
if (!isOfficialRuntimePackage(target.packageName)) await recordDeclaredVersion(target.packageName, target.version);
|
|
496
|
-
await recordPendingUpdate(target.packageName, target.version);
|
|
584
|
+
await ensureLatestReleaseAllowed(target.packageName, target.version, runtime);
|
|
585
|
+
if (!isOfficialRuntimePackage(target.packageName)) await recordDeclaredVersion(target.packageName, target.version, runtime);
|
|
586
|
+
await recordPendingUpdate(target.packageName, target.version, runtime);
|
|
497
587
|
}
|
|
498
|
-
if (remove.length > 0) await runDshPlugin(["remove", ...remove]);
|
|
499
|
-
if (requestHotUpdate()) return dependencyStatuses();
|
|
588
|
+
if (remove.length > 0) await runDshPlugin(["remove", ...remove], runtime);
|
|
589
|
+
if (runtime.desktopPnpm === void 0 && requestHotUpdate()) return dependencyStatuses(runtime);
|
|
500
590
|
for (const target of targets) {
|
|
501
591
|
try {
|
|
502
592
|
await runDshPlugin([
|
|
503
593
|
"add",
|
|
504
594
|
`${target.packageName}@${target.version}`,
|
|
505
595
|
"--registry=https://registry.npmjs.org/"
|
|
506
|
-
]);
|
|
596
|
+
], runtime);
|
|
507
597
|
} catch (error) {
|
|
508
|
-
if (isRestartableInstallError(error)) return dependencyStatuses();
|
|
598
|
+
if (isRestartableInstallError(error)) return dependencyStatuses(runtime);
|
|
509
599
|
throw error;
|
|
510
600
|
}
|
|
511
|
-
if (await installedPackageVersion(target.packageName) !== target.version) return dependencyStatuses();
|
|
512
|
-
await removePendingUpdate(target.packageName);
|
|
601
|
+
if (await installedPackageVersion(target.packageName, runtime) !== target.version) return dependencyStatuses(runtime);
|
|
602
|
+
await removePendingUpdate(target.packageName, runtime);
|
|
513
603
|
}
|
|
514
|
-
return dependencyStatuses();
|
|
604
|
+
return dependencyStatuses(runtime);
|
|
515
605
|
}
|
|
516
606
|
//#endregion
|
|
517
607
|
//#region src/explorer-path-policy.ts
|
|
@@ -950,7 +1040,7 @@ function apply(ctx) {
|
|
|
950
1040
|
const url = new URL(request.url ?? "/", "http://localhost");
|
|
951
1041
|
try {
|
|
952
1042
|
if (request.method === "GET") {
|
|
953
|
-
const dependencies = await dependencyStatuses();
|
|
1043
|
+
const dependencies = await dependencyStatuses(resolveDependencyRuntime(ctx));
|
|
954
1044
|
response.writeHead(200, {
|
|
955
1045
|
"content-type": "application/json; charset=utf-8",
|
|
956
1046
|
"cache-control": "no-store"
|
|
@@ -972,7 +1062,7 @@ function apply(ctx) {
|
|
|
972
1062
|
const { dependencies, updatedCount } = await updateAllDependencies(() => {
|
|
973
1063
|
restartAfterResponse = typeof process.send === "function";
|
|
974
1064
|
return restartAfterResponse;
|
|
975
|
-
});
|
|
1065
|
+
}, resolveDependencyRuntime(ctx));
|
|
976
1066
|
response.writeHead(200, {
|
|
977
1067
|
"content-type": "application/json; charset=utf-8",
|
|
978
1068
|
"cache-control": "no-store"
|
|
@@ -990,7 +1080,7 @@ function apply(ctx) {
|
|
|
990
1080
|
const dependencies = await installDependency(url.searchParams.get("dependency"), () => {
|
|
991
1081
|
restartAfterResponse = typeof process.send === "function";
|
|
992
1082
|
return restartAfterResponse;
|
|
993
|
-
});
|
|
1083
|
+
}, resolveDependencyRuntime(ctx));
|
|
994
1084
|
response.writeHead(200, {
|
|
995
1085
|
"content-type": "application/json; charset=utf-8",
|
|
996
1086
|
"cache-control": "no-store"
|