dsh-superagent-console 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/cordis.patch.yml +4 -0
- package/lib/client.js +51 -11
- package/lib/index.d.ts +2 -0
- package/lib/index.js +31 -5
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -33,9 +33,11 @@ vendor 补丁(seams):`sync-client.mjs` 在每次 vendor 复制后,对 `c
|
|
|
33
33
|
| L0 | 服务端 fetch `{target}/orchestrator/api/state`(带 `x-orchestrator-request: 1`) | 引擎可达 |
|
|
34
34
|
| L1 | `~/.dsh/profiles/<profile>/package.json` 依赖含 `dsh-superagent` + checkout 有 `lib/` 产物 | 服务已部署 |
|
|
35
35
|
| L2 | `scripts/dsh-superagent status`(exit 0 健康 / 1 停止 / 2 组件错误 / 3 等待 setup) | 健康细分 |
|
|
36
|
-
| L3 | dsh ≥0.2.1、node ^22.19\|\|≥24、pnpm、git、tmux、python3 | 前置依赖 |
|
|
36
|
+
| L3 | dsh ≥0.2.1、node ^22.19\|\|≥24、pnpm、git、tmux、python3(缺项附补齐提示命令) | 前置依赖 |
|
|
37
37
|
|
|
38
|
-
状态 → 动作一一映射:`running` → 官方面板;`installed-stopped` → 启动按钮;`installed-unhealthy` → 重启按钮;`not-installed` → 在线安装;`prereq-missing` →
|
|
38
|
+
状态 → 动作一一映射:`running` → 官方面板;`installed-stopped` → 启动按钮;`installed-unhealthy` → 重启按钮;`not-installed` → 在线安装;`prereq-missing` → 列出缺项与补齐命令(不提供安装按钮)。
|
|
39
|
+
|
|
40
|
+
探测 PATH 由 `spawnPath` 组装:运行中 node 的 bin 目录 + 配置的 `extraPath` + **桌面 App 自带的 dsh CLI 目录**(从运行中二进制相对推导 `<App>.app/Contents/Resources/runtime/cli/bin`,存在才追加)。因此桌面用户无需自行安装 dsh;`extraPath` 中显式安装的用户版本优先于内置 CLI。
|
|
39
41
|
|
|
40
42
|
## 在线安装流水线(8 段)
|
|
41
43
|
|
package/cordis.patch.yml
ADDED
package/lib/client.js
CHANGED
|
@@ -7852,7 +7852,12 @@ window.__ModuleLoader__.load({
|
|
|
7852
7852
|
children: props.label
|
|
7853
7853
|
});
|
|
7854
7854
|
}
|
|
7855
|
-
function PrereqList({ prereqs, title }) {
|
|
7855
|
+
function PrereqList({ prereqs, title, st }) {
|
|
7856
|
+
const copy = (text) => {
|
|
7857
|
+
const clip = navigator.clipboard;
|
|
7858
|
+
if (!clip) return;
|
|
7859
|
+
clip.writeText(text).catch(() => void 0);
|
|
7860
|
+
};
|
|
7856
7861
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7857
7862
|
style: { marginTop: 16 },
|
|
7858
7863
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -7865,13 +7870,45 @@ window.__ModuleLoader__.load({
|
|
|
7865
7870
|
},
|
|
7866
7871
|
children: prereqs.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
7867
7872
|
style: { color: item.ok ? "inherit" : "var(--dsh-danger, #d64545)" },
|
|
7868
|
-
children: [
|
|
7869
|
-
|
|
7870
|
-
|
|
7871
|
-
|
|
7872
|
-
|
|
7873
|
-
|
|
7874
|
-
|
|
7873
|
+
children: [
|
|
7874
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
7875
|
+
style: monoStyle,
|
|
7876
|
+
children: item.name
|
|
7877
|
+
}),
|
|
7878
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
7879
|
+
style: { opacity: .75 },
|
|
7880
|
+
children: [" — ", item.detail]
|
|
7881
|
+
}),
|
|
7882
|
+
!item.ok && item.hint && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
7883
|
+
style: {
|
|
7884
|
+
display: "inline-flex",
|
|
7885
|
+
alignItems: "center",
|
|
7886
|
+
gap: 6,
|
|
7887
|
+
marginLeft: 8
|
|
7888
|
+
},
|
|
7889
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
7890
|
+
style: {
|
|
7891
|
+
...monoStyle,
|
|
7892
|
+
opacity: .85
|
|
7893
|
+
},
|
|
7894
|
+
children: item.hint
|
|
7895
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
7896
|
+
type: "button",
|
|
7897
|
+
onClick: () => {
|
|
7898
|
+
copy(item.hint ?? "");
|
|
7899
|
+
},
|
|
7900
|
+
style: {
|
|
7901
|
+
...buttonStyle,
|
|
7902
|
+
padding: "1px 8px",
|
|
7903
|
+
fontSize: 11,
|
|
7904
|
+
borderRadius: 6,
|
|
7905
|
+
color: "inherit",
|
|
7906
|
+
borderColor: "var(--dsh-border, rgba(128,128,128,.4))"
|
|
7907
|
+
},
|
|
7908
|
+
children: st("copyCommand")
|
|
7909
|
+
})]
|
|
7910
|
+
})
|
|
7911
|
+
]
|
|
7875
7912
|
}, item.name))
|
|
7876
7913
|
})]
|
|
7877
7914
|
});
|
|
@@ -8084,7 +8121,8 @@ window.__ModuleLoader__.load({
|
|
|
8084
8121
|
}),
|
|
8085
8122
|
(status.state === "not-installed" || status.state === "prereq-missing" || installing) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PrereqList, {
|
|
8086
8123
|
prereqs: status.prereqs,
|
|
8087
|
-
title: st("prereqsTitle")
|
|
8124
|
+
title: st("prereqsTitle"),
|
|
8125
|
+
st
|
|
8088
8126
|
}),
|
|
8089
8127
|
(installing || status.setup.current || STAGES.some((id) => status.setup.stages[id]?.status !== "pending")) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StageList, {
|
|
8090
8128
|
setup: status.setup,
|
|
@@ -8166,7 +8204,7 @@ window.__ModuleLoader__.load({
|
|
|
8166
8204
|
descStopped: "引擎服务处于停止状态,可以一键拉起(tmux 会话由生命周期脚本托管)。",
|
|
8167
8205
|
descUnhealthy: "引擎进程存在但管理 API 不可达或组件报错,可尝试重启。",
|
|
8168
8206
|
descNotInstalled: "引擎运行在独立的 DSH profile 中。点击安装后,控制台会在线拉取官方源码、自动构建并部署到独立 profile(npm 上无此包,源码构建是官方唯一安装路径)。",
|
|
8169
|
-
descPrereq: "
|
|
8207
|
+
descPrereq: "在线安装需要以下工具,红项按提示命令补齐后点「重试」(凭据类操作仍需本人完成)。",
|
|
8170
8208
|
install: "在线安装引擎",
|
|
8171
8209
|
installResume: "继续安装",
|
|
8172
8210
|
installing: "正在安装…",
|
|
@@ -8176,6 +8214,7 @@ window.__ModuleLoader__.load({
|
|
|
8176
8214
|
starting: "正在启动…",
|
|
8177
8215
|
restarting: "正在重启…",
|
|
8178
8216
|
prereqsTitle: "前置依赖",
|
|
8217
|
+
copyCommand: "复制",
|
|
8179
8218
|
stageTitle: "安装进度",
|
|
8180
8219
|
setupWait: "引擎已启动,正在等待首次配置(Source 设置需在引擎面板完成)。",
|
|
8181
8220
|
manuallyStopped: "引擎带有手动停止标记,已按需忽略。",
|
|
@@ -8196,7 +8235,7 @@ window.__ModuleLoader__.load({
|
|
|
8196
8235
|
descStopped: "The engine service is stopped. Start it with one click (the tmux session is managed by the lifecycle script).",
|
|
8197
8236
|
descUnhealthy: "The engine process exists but the management API is unreachable or a component reports an error. Try a restart.",
|
|
8198
8237
|
descNotInstalled: "The engine runs in its own dedicated DSH profile. Installing fetches the official source online, builds it, and deploys it into that profile (the package is not published to npm; source build + link is the only official path).",
|
|
8199
|
-
descPrereq: "The online installer needs the tools below
|
|
8238
|
+
descPrereq: "The online installer needs the tools below — fix failing entries with the suggested command, then Retry (credential steps stay yours).",
|
|
8200
8239
|
install: "Install engine online",
|
|
8201
8240
|
installResume: "Resume install",
|
|
8202
8241
|
installing: "Installing…",
|
|
@@ -8206,6 +8245,7 @@ window.__ModuleLoader__.load({
|
|
|
8206
8245
|
starting: "Starting…",
|
|
8207
8246
|
restarting: "Restarting…",
|
|
8208
8247
|
prereqsTitle: "Prerequisites",
|
|
8248
|
+
copyCommand: "Copy",
|
|
8209
8249
|
stageTitle: "Install progress",
|
|
8210
8250
|
setupWait: "Engine is up and waiting for first-time setup (Source configuration happens in the engine panel).",
|
|
8211
8251
|
manuallyStopped: "The engine carries a manual-stop marker; honored on demand.",
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -37,13 +37,31 @@ const Config = z.object({
|
|
|
37
37
|
* Every spawn goes through `execFile` with an argv array (never a shell
|
|
38
38
|
* string), an explicit timeout, and an augmented PATH: the desktop app
|
|
39
39
|
* process may run with a minimal GUI PATH, so the node installation bin
|
|
40
|
-
* directory
|
|
40
|
+
* directory, the configured `extraPath` entries, and the app's bundled
|
|
41
|
+
* dsh CLI directory are prepended (in that order; user entries win).
|
|
41
42
|
*/
|
|
42
43
|
const MAX_BUFFER = 16777216;
|
|
43
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* Directory of the dsh CLI shipped inside the desktop app bundle: the
|
|
46
|
+
* Electron binary lives at `<App>.app/Contents/MacOS/<bin>`, so the bundled
|
|
47
|
+
* CLI resolves to `../Resources/runtime/cli/bin`. Null outside an app
|
|
48
|
+
* bundle (plain node runs, tests) or when the bundle carries no CLI.
|
|
49
|
+
* Uncached on purpose: spawns are rare and the probe is one existsSync.
|
|
50
|
+
*/
|
|
51
|
+
function bundledCliDir(execPath = process.execPath) {
|
|
52
|
+
const candidate = path.join(path.dirname(execPath), "..", "Resources", "runtime", "cli", "bin");
|
|
53
|
+
return existsSync(path.join(candidate, "dsh")) ? candidate : null;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* PATH prepended for every spawned tool: the running node's bin dir, the
|
|
57
|
+
* configured extras, the app's bundled CLI dir (fallback only, so an
|
|
58
|
+
* explicit user install keeps winning), then the inherited PATH.
|
|
59
|
+
*/
|
|
44
60
|
function spawnPath(extraPath) {
|
|
45
61
|
const parts = [path.dirname(process.execPath)];
|
|
46
62
|
if (extraPath) parts.push(...extraPath.split(":").filter(Boolean));
|
|
63
|
+
const bundled = bundledCliDir();
|
|
64
|
+
if (bundled) parts.push(bundled);
|
|
47
65
|
const inherited = process.env.PATH ?? "";
|
|
48
66
|
return [...parts, inherited].filter(Boolean).join(":");
|
|
49
67
|
}
|
|
@@ -220,7 +238,13 @@ async function engineHealth(engineDir, profileName, target, env = {}) {
|
|
|
220
238
|
};
|
|
221
239
|
}
|
|
222
240
|
}
|
|
223
|
-
/**
|
|
241
|
+
/** Locale-neutral remediation commands surfaced next to a failed check (darwin only). */
|
|
242
|
+
function missingHint(name) {
|
|
243
|
+
if (process.platform !== "darwin") return void 0;
|
|
244
|
+
if (name === "tmux") return "brew install tmux";
|
|
245
|
+
if (name === "pnpm") return "npm install -g pnpm";
|
|
246
|
+
}
|
|
247
|
+
/** L3: toolchain probe; never throws, missing tools surface as ok:false entries (with a hint where one applies). */
|
|
224
248
|
async function prereqCheck(env = {}) {
|
|
225
249
|
const checks = [nodeOk()];
|
|
226
250
|
for (const tool of TOOL_CHECKS) {
|
|
@@ -233,7 +257,8 @@ async function prereqCheck(env = {}) {
|
|
|
233
257
|
checks.push({
|
|
234
258
|
name: tool.name,
|
|
235
259
|
ok: false,
|
|
236
|
-
detail: result.code === -1 ? "not found on PATH" : tail(output, 200)
|
|
260
|
+
detail: result.code === -1 ? "not found on PATH" : tail(output, 200),
|
|
261
|
+
hint: missingHint(tool.name)
|
|
237
262
|
});
|
|
238
263
|
continue;
|
|
239
264
|
}
|
|
@@ -242,7 +267,8 @@ async function prereqCheck(env = {}) {
|
|
|
242
267
|
checks.push({
|
|
243
268
|
name: tool.name,
|
|
244
269
|
ok,
|
|
245
|
-
detail: ok ? version : `${version} (needs >= ${tool.min})
|
|
270
|
+
detail: ok ? version : `${version} (needs >= ${tool.min})`,
|
|
271
|
+
hint: ok ? void 0 : missingHint(tool.name)
|
|
246
272
|
});
|
|
247
273
|
}
|
|
248
274
|
return checks;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-superagent-console",
|
|
3
3
|
"description": "Desktop console for the Superagent engine: the official panel embedded over a same-origin proxy. Detects the engine's state, installs it online (source build into a dedicated profile) when missing, and starts/restarts it on demand; the engine stays resident across desktop restarts.",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.2",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Shuai-S",
|
|
7
7
|
"type": "module",
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
18
|
"lib",
|
|
19
|
-
"locale/*.json"
|
|
19
|
+
"locale/*.json",
|
|
20
|
+
"cordis.patch.yml"
|
|
20
21
|
],
|
|
21
22
|
"engines": {
|
|
22
23
|
"node": "^22.19.0 || >=24.0.0"
|