jishushell 0.4.17 → 0.4.24
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/Dockerfile.hermes-slim +193 -0
- package/apps/hermes-container.yaml +35 -0
- package/apps/ollama-binary.yaml +200 -0
- package/apps/ollama-cpu-container.yaml +37 -0
- package/apps/ollama-with-hollama-binary.yaml +195 -0
- package/apps/openclaw-binary.yaml +69 -0
- package/apps/openclaw-container.yaml +37 -0
- package/apps/openclaw-with-ollama-container.yaml +42 -0
- package/apps/openclaw-with-searxng-container.yaml +136 -0
- package/apps/openwebui-container.yaml +53 -0
- package/apps/playwright-container.yaml +120 -0
- package/apps/searxng-container.yaml +115 -0
- package/dist/auth.d.ts +1 -0
- package/dist/auth.js +15 -14
- package/dist/auth.js.map +1 -1
- package/dist/cli/app.d.ts +1 -0
- package/dist/cli/app.js +710 -52
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/backup.d.ts +3 -0
- package/dist/cli/backup.js +434 -0
- package/dist/cli/backup.js.map +1 -0
- package/dist/cli/doctor.d.ts +1 -0
- package/dist/cli/doctor.js +61 -35
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/job.d.ts +1 -0
- package/dist/cli/job.js +37 -99
- package/dist/cli/job.js.map +1 -1
- package/dist/cli/llm.d.ts +1 -0
- package/dist/cli/llm.js +20 -14
- package/dist/cli/llm.js.map +1 -1
- package/dist/cli/managed-list.d.ts +30 -0
- package/dist/cli/managed-list.js +129 -0
- package/dist/cli/managed-list.js.map +1 -0
- package/dist/cli/panel.d.ts +4 -3
- package/dist/cli/panel.js +94 -24
- package/dist/cli/panel.js.map +1 -1
- package/dist/cli/version.d.ts +1 -0
- package/dist/cli/version.js +12 -0
- package/dist/cli/version.js.map +1 -0
- package/dist/cli.js +47 -516
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +68 -0
- package/dist/config.js +266 -12
- package/dist/config.js.map +1 -1
- package/dist/control.d.ts +10 -6
- package/dist/control.js +87 -6
- package/dist/control.js.map +1 -1
- package/dist/install.d.ts +16 -0
- package/dist/install.js +75 -26
- package/dist/install.js.map +1 -1
- package/dist/routes/agent-apps.d.ts +15 -0
- package/dist/routes/agent-apps.js +78 -0
- package/dist/routes/agent-apps.js.map +1 -0
- package/dist/routes/apps.js +186 -7
- package/dist/routes/apps.js.map +1 -1
- package/dist/routes/backup.js +3 -3
- package/dist/routes/backup.js.map +1 -1
- package/dist/routes/instances.d.ts +6 -0
- package/dist/routes/instances.js +862 -879
- package/dist/routes/instances.js.map +1 -1
- package/dist/routes/llm.js +9 -8
- package/dist/routes/llm.js.map +1 -1
- package/dist/routes/runtime.d.ts +15 -0
- package/dist/routes/runtime.js +69 -0
- package/dist/routes/runtime.js.map +1 -0
- package/dist/routes/setup.js +103 -8
- package/dist/routes/setup.js.map +1 -1
- package/dist/routes/system.js +25 -3
- package/dist/routes/system.js.map +1 -1
- package/dist/server.js +71 -7
- package/dist/server.js.map +1 -1
- package/dist/services/agent-apps/catalog.d.ts +30 -0
- package/dist/services/agent-apps/catalog.js +60 -0
- package/dist/services/agent-apps/catalog.js.map +1 -0
- package/dist/services/agent-apps/index.d.ts +36 -0
- package/dist/services/agent-apps/index.js +171 -0
- package/dist/services/agent-apps/index.js.map +1 -0
- package/dist/services/agent-apps/installers/adapter-probes.d.ts +49 -0
- package/dist/services/agent-apps/installers/adapter-probes.js +223 -0
- package/dist/services/agent-apps/installers/adapter-probes.js.map +1 -0
- package/dist/services/agent-apps/installers/adapter.d.ts +30 -0
- package/dist/services/agent-apps/installers/adapter.js +171 -0
- package/dist/services/agent-apps/installers/adapter.js.map +1 -0
- package/dist/services/agent-apps/installers/registry-probe.d.ts +38 -0
- package/dist/services/agent-apps/installers/registry-probe.js +183 -0
- package/dist/services/agent-apps/installers/registry-probe.js.map +1 -0
- package/dist/services/agent-apps/installers/shell-script.d.ts +47 -0
- package/dist/services/agent-apps/installers/shell-script.js +471 -0
- package/dist/services/agent-apps/installers/shell-script.js.map +1 -0
- package/dist/services/agent-apps/types.d.ts +125 -0
- package/dist/services/agent-apps/types.js +17 -0
- package/dist/services/agent-apps/types.js.map +1 -0
- package/dist/services/{app-compiler.d.ts → app/app-compiler.d.ts} +3 -3
- package/dist/services/{app-compiler.js → app/app-compiler.js} +10 -7
- package/dist/services/app/app-compiler.js.map +1 -0
- package/dist/services/app/app-manager.d.ts +142 -0
- package/dist/services/app/app-manager.js +1988 -0
- package/dist/services/app/app-manager.js.map +1 -0
- package/dist/services/app/custom-manager.d.ts +27 -0
- package/dist/services/app/custom-manager.js +285 -0
- package/dist/services/app/custom-manager.js.map +1 -0
- package/dist/services/app/hermes-agent-manager.d.ts +20 -0
- package/dist/services/app/hermes-agent-manager.js +289 -0
- package/dist/services/app/hermes-agent-manager.js.map +1 -0
- package/dist/services/app/id-normalizer.d.ts +27 -0
- package/dist/services/app/id-normalizer.js +77 -0
- package/dist/services/app/id-normalizer.js.map +1 -0
- package/dist/services/app/ollama-manager.d.ts +18 -0
- package/dist/services/app/ollama-manager.js +207 -0
- package/dist/services/app/ollama-manager.js.map +1 -0
- package/dist/services/app/openclaw-manager.d.ts +63 -0
- package/dist/services/app/openclaw-manager.js +1178 -0
- package/dist/services/app/openclaw-manager.js.map +1 -0
- package/dist/services/app/paths.d.ts +47 -0
- package/dist/services/app/paths.js +68 -0
- package/dist/services/app/paths.js.map +1 -0
- package/dist/services/app/registry.d.ts +17 -0
- package/dist/services/app/registry.js +31 -0
- package/dist/services/app/registry.js.map +1 -0
- package/dist/services/app/remote-spec.d.ts +14 -0
- package/dist/services/app/remote-spec.js +58 -0
- package/dist/services/app/remote-spec.js.map +1 -0
- package/dist/services/app/terminal-session-manager.d.ts +27 -0
- package/dist/services/app/terminal-session-manager.js +157 -0
- package/dist/services/app/terminal-session-manager.js.map +1 -0
- package/dist/services/app/types.d.ts +72 -0
- package/dist/services/app/types.js +16 -0
- package/dist/services/app/types.js.map +1 -0
- package/dist/services/backup-manager.js +60 -22
- package/dist/services/backup-manager.js.map +1 -1
- package/dist/services/instance-manager.d.ts +82 -39
- package/dist/services/instance-manager.js +575 -1142
- package/dist/services/instance-manager.js.map +1 -1
- package/dist/services/llm-proxy/circuit-breaker.js +10 -2
- package/dist/services/llm-proxy/circuit-breaker.js.map +1 -1
- package/dist/services/llm-proxy/index.d.ts +14 -1
- package/dist/services/llm-proxy/index.js +51 -6
- package/dist/services/llm-proxy/index.js.map +1 -1
- package/dist/services/nomad-manager.d.ts +260 -3
- package/dist/services/nomad-manager.js +2866 -449
- package/dist/services/nomad-manager.js.map +1 -1
- package/dist/services/panel-manager.d.ts +10 -0
- package/dist/services/panel-manager.js +97 -0
- package/dist/services/panel-manager.js.map +1 -1
- package/dist/services/plugin-installer.js +28 -2
- package/dist/services/plugin-installer.js.map +1 -1
- package/dist/services/process-manager.js +22 -0
- package/dist/services/process-manager.js.map +1 -1
- package/dist/services/runtime/adapters/custom.d.ts +20 -0
- package/dist/services/runtime/adapters/custom.js +90 -0
- package/dist/services/runtime/adapters/custom.js.map +1 -0
- package/dist/services/runtime/adapters/hermes.d.ts +174 -0
- package/dist/services/runtime/adapters/hermes.js +1316 -0
- package/dist/services/runtime/adapters/hermes.js.map +1 -0
- package/dist/services/runtime/adapters/openclaw-routes.d.ts +17 -0
- package/dist/services/runtime/adapters/openclaw-routes.js +946 -0
- package/dist/services/runtime/adapters/openclaw-routes.js.map +1 -0
- package/dist/services/runtime/adapters/openclaw.d.ts +188 -0
- package/dist/services/runtime/adapters/openclaw.js +2195 -0
- package/dist/services/runtime/adapters/openclaw.js.map +1 -0
- package/dist/services/runtime/errors.d.ts +28 -0
- package/dist/services/runtime/errors.js +31 -0
- package/dist/services/runtime/errors.js.map +1 -0
- package/dist/services/runtime/index.d.ts +34 -0
- package/dist/services/runtime/index.js +51 -0
- package/dist/services/runtime/index.js.map +1 -0
- package/dist/services/runtime/instance.d.ts +24 -0
- package/dist/services/runtime/instance.js +143 -0
- package/dist/services/runtime/instance.js.map +1 -0
- package/dist/services/runtime/migrations.d.ts +15 -0
- package/dist/services/runtime/migrations.js +25 -0
- package/dist/services/runtime/migrations.js.map +1 -0
- package/dist/services/runtime/registry.d.ts +13 -0
- package/dist/services/runtime/registry.js +32 -0
- package/dist/services/runtime/registry.js.map +1 -0
- package/dist/services/runtime/types.d.ts +545 -0
- package/dist/services/runtime/types.js +14 -0
- package/dist/services/runtime/types.js.map +1 -0
- package/dist/services/setup-manager.d.ts +70 -29
- package/dist/services/setup-manager.js +278 -597
- package/dist/services/setup-manager.js.map +1 -1
- package/dist/services/task-registry.d.ts +44 -0
- package/dist/services/task-registry.js +74 -0
- package/dist/services/task-registry.js.map +1 -0
- package/dist/services/telemetry/heartbeat.d.ts +6 -6
- package/dist/services/telemetry/heartbeat.js +29 -30
- package/dist/services/telemetry/heartbeat.js.map +1 -1
- package/dist/types.d.ts +162 -2
- package/dist/utils/docker-host.d.ts +15 -0
- package/dist/utils/docker-host.js +64 -0
- package/dist/utils/docker-host.js.map +1 -0
- package/install/jishu-install.sh +25 -1
- package/package.json +14 -4
- package/public/assets/Dashboard-B-JoOjBQ.js +1 -0
- package/public/assets/HermesChatPanel-mFSureyc.js +1 -0
- package/public/assets/HermesConfigForm-DvR05LK1.js +4 -0
- package/public/assets/InitPassword-CVA8wQA6.js +1 -0
- package/public/assets/InstanceDetail-DcZW2QGO.js +91 -0
- package/public/assets/{Login-D1Bt-Lyk.js → Login-BWsZH2mu.js} +1 -1
- package/public/assets/NewInstance-BCIrAd86.js +1 -0
- package/public/assets/Settings-xkDcduFz.js +1 -0
- package/public/assets/Setup-Cfuwj4gV.js +1 -0
- package/public/assets/WeixinLoginPanel-CnjR8xMu.js +9 -0
- package/public/assets/index-CPhVFEsx.css +1 -0
- package/public/assets/index-DQsM6Joa.js +19 -0
- package/public/assets/input-paste-CrNVAyOy.js +1 -0
- package/public/assets/registry-B4UFJdpA.js +2 -0
- package/public/assets/{usePolling-CK0DfI4h.js → usePolling-Do5Erqm_.js} +1 -1
- package/public/assets/vendor-i18n-ucpM0OR0.js +9 -0
- package/public/assets/{vendor-react-B1-3Yrt-.js → vendor-react-Bk1hRGiY.js} +1 -1
- package/public/favicon.png +0 -0
- package/public/index.html +9 -4
- package/public/logos/hermes.png +0 -0
- package/public/logos/ollama.png +0 -0
- package/public/logos/openclaw.svg +60 -0
- package/scripts/build-hermes-image.sh +21 -0
- package/scripts/build-local.sh +54 -0
- package/scripts/check-adapter-isolation.ts +293 -0
- package/scripts/fixtures/instances/hermes-sample/instance.json +37 -0
- package/scripts/fixtures/instances/legacy-openclaw-sample/instance.json +7 -0
- package/scripts/smoke/hermes-bootstrap.sh +195 -0
- package/templates/hermes-entrypoint.sh +154 -0
- package/dist/cli/openclaw.d.ts +0 -12
- package/dist/cli/openclaw.js +0 -156
- package/dist/cli/openclaw.js.map +0 -1
- package/dist/services/app-compiler.js.map +0 -1
- package/dist/services/app-manager.d.ts +0 -17
- package/dist/services/app-manager.js +0 -168
- package/dist/services/app-manager.js.map +0 -1
- package/dist/services/job-manager.d.ts +0 -22
- package/dist/services/job-manager.js +0 -102
- package/dist/services/job-manager.js.map +0 -1
- package/public/assets/Dashboard-CQsp1Mr9.js +0 -1
- package/public/assets/InitPassword-BEC8SE4A.js +0 -1
- package/public/assets/InstanceDetail-B5wTgNEg.js +0 -17
- package/public/assets/NewInstance-GQzm3K9D.js +0 -1
- package/public/assets/Settings-ByjGlqhP.js +0 -1
- package/public/assets/Setup-cMF21Y-8.js +0 -1
- package/public/assets/index-B6qQP4mH.css +0 -1
- package/public/assets/index-BuTQtuNy.js +0 -16
- package/public/assets/vendor-i18n-CfW0RvgE.js +0 -9
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Installer strategy for shell-script-driven agent apps (Ollama and any other
|
|
3
|
+
* system tool shipped as a `curl | bash` installer).
|
|
4
|
+
*
|
|
5
|
+
* Responsibilities:
|
|
6
|
+
* - probe installed version + binary size via `probeCommand`
|
|
7
|
+
* - probe update availability via GitHub Releases (when `githubRepo` set)
|
|
8
|
+
* - install: fetch script → optional sha256 verify → `sudo -n bash`
|
|
9
|
+
* - uninstall: stop+disable systemd unit + rm binary + rm extraCleanup
|
|
10
|
+
*
|
|
11
|
+
* Heavy ops stream progress through the shared task-registry so the UI
|
|
12
|
+
* picks them up via `/api/setup/tasks/:id`, identical to adapter installs.
|
|
13
|
+
*/
|
|
14
|
+
import { execFile } from "child_process";
|
|
15
|
+
import { createHash } from "crypto";
|
|
16
|
+
import { mkdtempSync, rmSync, writeFileSync } from "fs";
|
|
17
|
+
import { tmpdir } from "os";
|
|
18
|
+
import { join } from "path";
|
|
19
|
+
import { promisify } from "util";
|
|
20
|
+
import { createTask, emitTask, getRunningTasks, } from "../../task-registry.js";
|
|
21
|
+
const execFileAsync = promisify(execFile);
|
|
22
|
+
const VERSION_DEFAULT_RE = /\b(\d+\.\d+\.\d+)\b/;
|
|
23
|
+
export async function probeShellScriptStatus(source) {
|
|
24
|
+
const { cmd, args } = source.probeCommand;
|
|
25
|
+
try {
|
|
26
|
+
const { stdout } = await execFileAsync(cmd, args, {
|
|
27
|
+
timeout: 5_000,
|
|
28
|
+
encoding: "utf-8",
|
|
29
|
+
});
|
|
30
|
+
const re = source.versionRegex ? new RegExp(source.versionRegex) : VERSION_DEFAULT_RE;
|
|
31
|
+
const m = stdout.match(re);
|
|
32
|
+
return { installed: true, version: m?.[1] };
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
// ENOENT = binary not found → cleanly "not installed". Any other
|
|
36
|
+
// failure (exec error, timeout) we report as unknown rather than
|
|
37
|
+
// definitively "not installed" so a transient shell hang does not
|
|
38
|
+
// flip the UI from 已安装 to 未安装 mid-session.
|
|
39
|
+
if (e?.code === "ENOENT")
|
|
40
|
+
return { installed: false };
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export async function probeShellScriptSizeMB(source) {
|
|
45
|
+
if (!source.binaryPath)
|
|
46
|
+
return null;
|
|
47
|
+
try {
|
|
48
|
+
const { stdout } = await execFileAsync("du", ["-sb", source.binaryPath], {
|
|
49
|
+
timeout: 3_000,
|
|
50
|
+
encoding: "utf-8",
|
|
51
|
+
});
|
|
52
|
+
const bytes = parseInt(stdout.trim().split(/\s+/)[0] || "", 10);
|
|
53
|
+
if (!Number.isFinite(bytes) || bytes <= 0)
|
|
54
|
+
return null;
|
|
55
|
+
return Math.round(bytes / 1_000_000);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Update-availability cache for shell-script apps. Separate from the adapter
|
|
63
|
+
* SWR cache in `adapter-probes.ts` so the two install kinds stay decoupled.
|
|
64
|
+
*
|
|
65
|
+
* Shape:
|
|
66
|
+
* - `value`: last known answer (true/false) or null on probe failure.
|
|
67
|
+
* - `at`: ms since epoch of the last refresh.
|
|
68
|
+
*
|
|
69
|
+
* The cache is only written by `refreshShellScriptUpdateCache` (called from
|
|
70
|
+
* `checkAllAgentAppUpdates`). `buildCardView` reads the cache *without* any
|
|
71
|
+
* network I/O — the hot path can't stall on a slow GitHub call.
|
|
72
|
+
*/
|
|
73
|
+
const shellScriptUpdateCache = new Map();
|
|
74
|
+
/**
|
|
75
|
+
* Read-only cache lookup used by `buildCardView`. Returns null (UI stays
|
|
76
|
+
* neutral) until the user clicks "检查更新" at least once, which kicks off
|
|
77
|
+
* the network probe via `refreshShellScriptUpdateCache`.
|
|
78
|
+
*
|
|
79
|
+
* Intentionally NOT falling back to an on-demand probe here — the catalog
|
|
80
|
+
* endpoint is polled every 5 s and the GitHub Releases API is slow + rate-
|
|
81
|
+
* limited. See docs/agent-apps-design.md "update checks only on explicit
|
|
82
|
+
* click".
|
|
83
|
+
*/
|
|
84
|
+
export function readShellScriptUpdateAvailable(appId) {
|
|
85
|
+
return shellScriptUpdateCache.get(appId)?.value ?? null;
|
|
86
|
+
}
|
|
87
|
+
export function getShellScriptUpdateCacheLastCheckedAt() {
|
|
88
|
+
let latest = 0;
|
|
89
|
+
for (const entry of shellScriptUpdateCache.values()) {
|
|
90
|
+
if (entry.at > latest)
|
|
91
|
+
latest = entry.at;
|
|
92
|
+
}
|
|
93
|
+
return latest > 0 ? latest : null;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Compare installed version vs GitHub Releases latest tag. Writes the
|
|
97
|
+
* result to the cache and returns it. Called by `checkAllAgentAppUpdates`;
|
|
98
|
+
* not called from the catalog hot path.
|
|
99
|
+
*/
|
|
100
|
+
export async function refreshShellScriptUpdateCache(appId, source) {
|
|
101
|
+
const value = await probeShellScriptUpdateNow(source);
|
|
102
|
+
shellScriptUpdateCache.set(appId, { value, at: Date.now() });
|
|
103
|
+
return value;
|
|
104
|
+
}
|
|
105
|
+
async function probeShellScriptUpdateNow(source) {
|
|
106
|
+
if (!source.githubRepo)
|
|
107
|
+
return null;
|
|
108
|
+
const probe = await probeShellScriptStatus(source);
|
|
109
|
+
if (!probe?.installed || !probe.version)
|
|
110
|
+
return null;
|
|
111
|
+
const apiUrl = `https://api.github.com/repos/${source.githubRepo}/releases/latest`;
|
|
112
|
+
try {
|
|
113
|
+
const controller = new AbortController();
|
|
114
|
+
const timer = setTimeout(() => controller.abort(), 15_000);
|
|
115
|
+
let body;
|
|
116
|
+
try {
|
|
117
|
+
const resp = await fetch(apiUrl, {
|
|
118
|
+
headers: {
|
|
119
|
+
Accept: "application/vnd.github+json",
|
|
120
|
+
"User-Agent": "jishushell-agent-apps",
|
|
121
|
+
},
|
|
122
|
+
signal: controller.signal,
|
|
123
|
+
});
|
|
124
|
+
if (!resp.ok)
|
|
125
|
+
return null;
|
|
126
|
+
body = (await resp.json());
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
clearTimeout(timer);
|
|
130
|
+
}
|
|
131
|
+
const latest = (body.tag_name || "").replace(/^v/, "").trim();
|
|
132
|
+
if (!latest)
|
|
133
|
+
return null;
|
|
134
|
+
return latest !== probe.version;
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
export function findRunningShellScriptTask(appId) {
|
|
141
|
+
const install = getRunningTasks(appId)[0];
|
|
142
|
+
if (install)
|
|
143
|
+
return { id: install.id, kind: "install" };
|
|
144
|
+
const uninstall = getRunningTasks(`uninstall-${appId}`)[0];
|
|
145
|
+
if (uninstall)
|
|
146
|
+
return { id: uninstall.id, kind: "uninstall" };
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
export async function startShellScriptInstall(appId, source) {
|
|
150
|
+
// Block install when uninstall is running — destructive of each other.
|
|
151
|
+
if (getRunningTasks(`uninstall-${appId}`).length > 0) {
|
|
152
|
+
return {
|
|
153
|
+
ok: false,
|
|
154
|
+
error: `${appId} 正在卸载,请等待卸载完成后再安装`,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
const existing = getRunningTasks(appId);
|
|
158
|
+
if (existing.length > 0) {
|
|
159
|
+
return {
|
|
160
|
+
ok: true,
|
|
161
|
+
taskId: existing[0].id,
|
|
162
|
+
reused: true,
|
|
163
|
+
message: `${appId} 安装已在进行中`,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
// Preflight: if the daemon cannot gain privileges (e.g. systemd's
|
|
167
|
+
// NoNewPrivileges hardening is on), hand back a manual command for the
|
|
168
|
+
// user to run in a terminal instead of starting a task that is doomed.
|
|
169
|
+
const priv = await probePrivilegeEscalation();
|
|
170
|
+
if (!priv.ok) {
|
|
171
|
+
return {
|
|
172
|
+
ok: false,
|
|
173
|
+
error: `面板无法自动提权安装 (${priv.reason})`,
|
|
174
|
+
manualReason: describeManualPrivilegeReason(priv.reason),
|
|
175
|
+
manualCommand: buildManualInstallCommand(source, priv.reason),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
const task = createTask(appId);
|
|
179
|
+
runShellScriptInstall(task, source).catch((e) => {
|
|
180
|
+
emitTask(task, { type: "error", message: `安装失败: ${e?.message || e}` });
|
|
181
|
+
task.status = "error";
|
|
182
|
+
});
|
|
183
|
+
return { ok: true, taskId: task.id };
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Probe whether the daemon can actually execute something as root. Checks
|
|
187
|
+
* three failure modes:
|
|
188
|
+
* 1. sudo not in PATH
|
|
189
|
+
* 2. systemd NoNewPrivileges=true (sudo refuses, distinct error text)
|
|
190
|
+
* 3. sudoers blocks this user (password required / not allowed)
|
|
191
|
+
*/
|
|
192
|
+
async function probePrivilegeEscalation() {
|
|
193
|
+
try {
|
|
194
|
+
await execFileAsync("sudo", ["-n", "true"], { timeout: 3_000 });
|
|
195
|
+
return { ok: true };
|
|
196
|
+
}
|
|
197
|
+
catch (e) {
|
|
198
|
+
const stderr = String(e?.stderr || "").toLowerCase();
|
|
199
|
+
if (e?.code === "ENOENT")
|
|
200
|
+
return { ok: false, reason: "sudo 不在 PATH" };
|
|
201
|
+
if (stderr.includes("no new privileges")) {
|
|
202
|
+
return { ok: false, reason: "systemd NoNewPrivileges=true" };
|
|
203
|
+
}
|
|
204
|
+
if (stderr.includes("password is required") || stderr.includes("a password is required")) {
|
|
205
|
+
return { ok: false, reason: "sudoers 需要密码" };
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
ok: false,
|
|
209
|
+
reason: e?.message ? String(e.message).slice(0, 120) : "sudo 不可用",
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function buildManualInstallCommand(source, reason) {
|
|
214
|
+
if (reason === "sudo 不在 PATH") {
|
|
215
|
+
return `curl -fsSL ${source.scriptUrl} | sh`;
|
|
216
|
+
}
|
|
217
|
+
return `curl -fsSL ${source.scriptUrl} | sudo sh`;
|
|
218
|
+
}
|
|
219
|
+
function describeManualPrivilegeReason(reason) {
|
|
220
|
+
if (reason === "sudo 不在 PATH") {
|
|
221
|
+
return "当前环境没有 sudo,请切换到 root 终端后手动执行下面的命令";
|
|
222
|
+
}
|
|
223
|
+
if (reason === "systemd NoNewPrivileges=true") {
|
|
224
|
+
return "面板服务被 systemd 安全策略限制,不能在后台自动 sudo;请在你自己的终端执行下面的命令";
|
|
225
|
+
}
|
|
226
|
+
if (reason === "sudoers 需要密码") {
|
|
227
|
+
return "当前系统的 sudo 需要密码,后台任务不能代输;请在终端执行下面的命令,终端会提示你输入密码";
|
|
228
|
+
}
|
|
229
|
+
return `后台无法自动提权:${reason}`;
|
|
230
|
+
}
|
|
231
|
+
async function runShellScriptInstall(task, source) {
|
|
232
|
+
emitTask(task, { type: "progress", message: "检查 sudo 权限...", progress: 5 });
|
|
233
|
+
// Panel runs as a non-root user. The install script needs sudo. We use
|
|
234
|
+
// `sudo -n` (non-interactive); if it prompts for a password we bail with
|
|
235
|
+
// a clear message instead of hanging.
|
|
236
|
+
try {
|
|
237
|
+
await execFileAsync("sudo", ["-n", "true"], { timeout: 3_000 });
|
|
238
|
+
}
|
|
239
|
+
catch (e) {
|
|
240
|
+
const detail = [
|
|
241
|
+
e?.code ? `code=${e.code}` : "",
|
|
242
|
+
e?.signal ? `signal=${e.signal}` : "",
|
|
243
|
+
e?.stderr ? `stderr=${String(e.stderr).trim().slice(0, 200)}` : "",
|
|
244
|
+
e?.message ? `msg=${String(e.message).slice(0, 200)}` : "",
|
|
245
|
+
].filter(Boolean).join(" | ");
|
|
246
|
+
console.error(`[agent-apps] sudo -n true failed: ${detail}`);
|
|
247
|
+
emitTask(task, {
|
|
248
|
+
type: "error",
|
|
249
|
+
message: `需要免密 sudo。[${detail || "no details"}] 请在终端执行 sudo visudo 允许当前用户免密,或手动运行安装命令。`,
|
|
250
|
+
});
|
|
251
|
+
task.status = "error";
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
emitTask(task, {
|
|
255
|
+
type: "progress",
|
|
256
|
+
message: `下载安装脚本: ${source.scriptUrl}`,
|
|
257
|
+
progress: 15,
|
|
258
|
+
});
|
|
259
|
+
const controller = new AbortController();
|
|
260
|
+
const dlTimer = setTimeout(() => controller.abort(), 60_000);
|
|
261
|
+
let scriptText;
|
|
262
|
+
try {
|
|
263
|
+
const resp = await fetch(source.scriptUrl, { signal: controller.signal });
|
|
264
|
+
if (!resp.ok) {
|
|
265
|
+
emitTask(task, {
|
|
266
|
+
type: "error",
|
|
267
|
+
message: `下载失败: HTTP ${resp.status}`,
|
|
268
|
+
});
|
|
269
|
+
task.status = "error";
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
scriptText = await resp.text();
|
|
273
|
+
}
|
|
274
|
+
catch (e) {
|
|
275
|
+
emitTask(task, { type: "error", message: `下载失败: ${e?.message || e}` });
|
|
276
|
+
task.status = "error";
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
finally {
|
|
280
|
+
clearTimeout(dlTimer);
|
|
281
|
+
}
|
|
282
|
+
if (source.scriptSha256) {
|
|
283
|
+
const actual = createHash("sha256").update(scriptText).digest("hex");
|
|
284
|
+
if (actual !== source.scriptSha256) {
|
|
285
|
+
emitTask(task, {
|
|
286
|
+
type: "error",
|
|
287
|
+
message: `sha256 校验失败: 期望 ${source.scriptSha256}, 实际 ${actual}`,
|
|
288
|
+
});
|
|
289
|
+
task.status = "error";
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
emitTask(task, { type: "log", message: `sha256 校验通过` });
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
emitTask(task, {
|
|
296
|
+
type: "log",
|
|
297
|
+
message: "(未配置 sha256 校验;生产环境建议 pin 到固定版本)",
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
// Write to a temp dir with restrictive mode so the script file cannot be
|
|
301
|
+
// substituted between check and exec.
|
|
302
|
+
const scriptDir = mkdtempSync(join(tmpdir(), "agent-app-install-"));
|
|
303
|
+
const scriptPath = join(scriptDir, "install.sh");
|
|
304
|
+
writeFileSync(scriptPath, scriptText, { mode: 0o700 });
|
|
305
|
+
emitTask(task, {
|
|
306
|
+
type: "progress",
|
|
307
|
+
message: "执行安装脚本(sudo bash)...",
|
|
308
|
+
progress: 40,
|
|
309
|
+
});
|
|
310
|
+
const ok = await runWithStream(task, "sudo", ["-n", "bash", scriptPath], 30 * 60_000);
|
|
311
|
+
try {
|
|
312
|
+
rmSync(scriptDir, { recursive: true, force: true });
|
|
313
|
+
}
|
|
314
|
+
catch { /* best effort */ }
|
|
315
|
+
if (!ok) {
|
|
316
|
+
emitTask(task, { type: "error", message: "安装脚本返回非零退出码" });
|
|
317
|
+
task.status = "error";
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
emitTask(task, { type: "progress", message: "验证安装...", progress: 95 });
|
|
321
|
+
const status = await probeShellScriptStatus(source);
|
|
322
|
+
if (!status?.installed) {
|
|
323
|
+
emitTask(task, {
|
|
324
|
+
type: "error",
|
|
325
|
+
message: "安装脚本执行后仍检测不到可执行命令,请查看日志排查",
|
|
326
|
+
});
|
|
327
|
+
task.status = "error";
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
emitTask(task, {
|
|
331
|
+
type: "done",
|
|
332
|
+
message: status.version ? `安装完成: v${status.version}` : "安装完成",
|
|
333
|
+
progress: 100,
|
|
334
|
+
});
|
|
335
|
+
task.status = "done";
|
|
336
|
+
}
|
|
337
|
+
export async function startShellScriptUninstall(appId, source) {
|
|
338
|
+
// Block uninstall while install is in flight.
|
|
339
|
+
if (getRunningTasks(appId).length > 0) {
|
|
340
|
+
return {
|
|
341
|
+
ok: false,
|
|
342
|
+
error: `${appId} 正在安装/更新,请等待完成后再卸载`,
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
if (getRunningTasks(`uninstall-${appId}`).length > 0) {
|
|
346
|
+
return {
|
|
347
|
+
ok: false,
|
|
348
|
+
error: `${appId} 卸载已在进行中`,
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
const priv = await probePrivilegeEscalation();
|
|
352
|
+
if (!priv.ok) {
|
|
353
|
+
const manual = buildManualUninstallCommand(source);
|
|
354
|
+
return {
|
|
355
|
+
ok: false,
|
|
356
|
+
error: `面板无法以 root 执行 (${priv.reason})`,
|
|
357
|
+
manualReason: priv.reason,
|
|
358
|
+
manualCommand: manual,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
const task = createTask(`uninstall-${appId}`);
|
|
362
|
+
runShellScriptUninstall(task, source).catch((e) => {
|
|
363
|
+
emitTask(task, { type: "error", message: `卸载失败: ${e?.message || e}` });
|
|
364
|
+
task.status = "error";
|
|
365
|
+
});
|
|
366
|
+
return { ok: true, taskId: task.id };
|
|
367
|
+
}
|
|
368
|
+
function buildManualUninstallCommand(source) {
|
|
369
|
+
const parts = [];
|
|
370
|
+
if (source.systemdUnit) {
|
|
371
|
+
parts.push(`sudo systemctl stop ${source.systemdUnit}`);
|
|
372
|
+
parts.push(`sudo systemctl disable ${source.systemdUnit}`);
|
|
373
|
+
}
|
|
374
|
+
const rmTargets = [];
|
|
375
|
+
if (source.binaryPath)
|
|
376
|
+
rmTargets.push(source.binaryPath);
|
|
377
|
+
if (source.extraCleanup)
|
|
378
|
+
rmTargets.push(...source.extraCleanup);
|
|
379
|
+
if (rmTargets.length > 0) {
|
|
380
|
+
parts.push(`sudo rm -rf ${rmTargets.join(" ")}`);
|
|
381
|
+
}
|
|
382
|
+
return parts.join(" && ");
|
|
383
|
+
}
|
|
384
|
+
async function runShellScriptUninstall(task, source) {
|
|
385
|
+
try {
|
|
386
|
+
await execFileAsync("sudo", ["-n", "true"], { timeout: 3_000 });
|
|
387
|
+
}
|
|
388
|
+
catch {
|
|
389
|
+
emitTask(task, {
|
|
390
|
+
type: "error",
|
|
391
|
+
message: "需要免密 sudo。请手动运行卸载命令。",
|
|
392
|
+
});
|
|
393
|
+
task.status = "error";
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
// systemd stop/disable failures are treated as warnings, not hard errors:
|
|
397
|
+
// the unit may not exist (e.g. the user installed via a different path),
|
|
398
|
+
// which is not a reason to leave the app in a limbo "half-uninstalled"
|
|
399
|
+
// state. The binary rm below is what actually defines success.
|
|
400
|
+
if (source.systemdUnit) {
|
|
401
|
+
emitTask(task, {
|
|
402
|
+
type: "progress",
|
|
403
|
+
message: `停止 systemd 服务: ${source.systemdUnit}`,
|
|
404
|
+
progress: 20,
|
|
405
|
+
});
|
|
406
|
+
const stopped = await runWithStream(task, "sudo", ["-n", "systemctl", "stop", source.systemdUnit], 15_000);
|
|
407
|
+
if (!stopped) {
|
|
408
|
+
emitTask(task, { type: "log", message: "systemctl stop 失败(可能服务未启用),继续卸载" });
|
|
409
|
+
}
|
|
410
|
+
const disabled = await runWithStream(task, "sudo", ["-n", "systemctl", "disable", source.systemdUnit], 15_000);
|
|
411
|
+
if (!disabled) {
|
|
412
|
+
emitTask(task, { type: "log", message: "systemctl disable 失败(可能服务未启用),继续卸载" });
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
const removalTargets = [];
|
|
416
|
+
if (source.binaryPath)
|
|
417
|
+
removalTargets.push(source.binaryPath);
|
|
418
|
+
if (source.extraCleanup)
|
|
419
|
+
removalTargets.push(...source.extraCleanup);
|
|
420
|
+
// Binary removal is the load-bearing step. If rm fails, post-probe will
|
|
421
|
+
// still see the binary and the app is effectively still installed —
|
|
422
|
+
// that has to be surfaced as an error rather than a silent success.
|
|
423
|
+
if (removalTargets.length > 0) {
|
|
424
|
+
emitTask(task, {
|
|
425
|
+
type: "progress",
|
|
426
|
+
message: `删除文件: ${removalTargets.join(", ")}`,
|
|
427
|
+
progress: 60,
|
|
428
|
+
});
|
|
429
|
+
const removed = await runWithStream(task, "sudo", ["-n", "rm", "-rf", "--", ...removalTargets], 30_000);
|
|
430
|
+
if (!removed) {
|
|
431
|
+
emitTask(task, {
|
|
432
|
+
type: "error",
|
|
433
|
+
message: `rm 失败(${removalTargets.join(", ")}),卸载未完成。请查看日志或手动清理。`,
|
|
434
|
+
});
|
|
435
|
+
task.status = "error";
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
// Post-verify: the probe command should now fail with ENOENT. If it
|
|
440
|
+
// still works, the rm command "succeeded" but something else put the
|
|
441
|
+
// binary back (alternate PATH, alias, etc.) — treat as error so the UI
|
|
442
|
+
// flags it instead of optimistically showing "已安装 → 未安装".
|
|
443
|
+
const post = await probeShellScriptStatus(source);
|
|
444
|
+
if (post?.installed) {
|
|
445
|
+
emitTask(task, {
|
|
446
|
+
type: "error",
|
|
447
|
+
message: "rm 返回 0 但 probeCommand 仍可用,可能存在其它路径的安装残留,请手动排查。",
|
|
448
|
+
});
|
|
449
|
+
task.status = "error";
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
emitTask(task, { type: "done", message: "卸载完成", progress: 100 });
|
|
453
|
+
task.status = "done";
|
|
454
|
+
}
|
|
455
|
+
function runWithStream(task, cmd, args, timeoutMs) {
|
|
456
|
+
return new Promise((resolve) => {
|
|
457
|
+
const child = execFile(cmd, args, { timeout: timeoutMs, encoding: "utf-8", maxBuffer: 16 * 1024 * 1024 }, (err, stdout, stderr) => {
|
|
458
|
+
const output = `${stdout || ""}${stderr || ""}`;
|
|
459
|
+
for (const raw of output.split(/\r?\n/)) {
|
|
460
|
+
const line = raw.trim();
|
|
461
|
+
if (line)
|
|
462
|
+
emitTask(task, { type: "log", message: line });
|
|
463
|
+
}
|
|
464
|
+
resolve(!err);
|
|
465
|
+
});
|
|
466
|
+
child.on("error", (e) => {
|
|
467
|
+
emitTask(task, { type: "log", message: `[exec-error] ${e.message}` });
|
|
468
|
+
});
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
//# sourceMappingURL=shell-script.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-script.js","sourceRoot":"","sources":["../../../../src/services/agent-apps/installers/shell-script.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AAC5B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EACL,UAAU,EACV,QAAQ,EACR,eAAe,GAEhB,MAAM,wBAAwB,CAAC;AAGhC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAI1C,MAAM,kBAAkB,GAAG,qBAAqB,CAAC;AAEjD,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,MAAyB;IAEzB,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC,YAAY,CAAC;IAC1C,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,IAAI,EAAE;YAChD,OAAO,EAAE,KAAK;YACd,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC;QACH,MAAM,EAAE,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC;QACtF,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC3B,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9C,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QAChB,iEAAiE;QACjE,iEAAiE;QACjE,kEAAkE;QAClE,2CAA2C;QAC3C,IAAI,CAAC,EAAE,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;QACtD,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,MAAyB;IAEzB,IAAI,CAAC,MAAM,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,EAAE;YACvE,OAAO,EAAE,KAAK;YACd,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC;QACH,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QAChE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACvD,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,sBAAsB,GAAG,IAAI,GAAG,EAAiD,CAAC;AAExF;;;;;;;;;GASG;AACH,MAAM,UAAU,8BAA8B,CAAC,KAAa;IAC1D,OAAO,sBAAsB,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,sCAAsC;IACpD,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,KAAK,IAAI,sBAAsB,CAAC,MAAM,EAAE,EAAE,CAAC;QACpD,IAAI,KAAK,CAAC,EAAE,GAAG,MAAM;YAAE,MAAM,GAAG,KAAK,CAAC,EAAE,CAAC;IAC3C,CAAC;IACD,OAAO,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACpC,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,6BAA6B,CACjD,KAAa,EACb,MAAyB;IAEzB,MAAM,KAAK,GAAG,MAAM,yBAAyB,CAAC,MAAM,CAAC,CAAC;IACtD,sBAAsB,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC7D,OAAO,KAAK,CAAC;AACf,CAAC;AAED,KAAK,UAAU,yBAAyB,CACtC,MAAyB;IAEzB,IAAI,CAAC,MAAM,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IACpC,MAAM,KAAK,GAAG,MAAM,sBAAsB,CAAC,MAAM,CAAC,CAAC;IACnD,IAAI,CAAC,KAAK,EAAE,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAErD,MAAM,MAAM,GAAG,gCAAgC,MAAM,CAAC,UAAU,kBAAkB,CAAC;IACnF,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,MAAM,CAAC,CAAC;QAC3D,IAAI,IAA2B,CAAC;QAChC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,MAAM,EAAE;gBAC/B,OAAO,EAAE;oBACP,MAAM,EAAE,6BAA6B;oBACrC,YAAY,EAAE,uBAAuB;iBACtC;gBACD,MAAM,EAAE,UAAU,CAAC,MAAM;aAC1B,CAAC,CAAC;YACH,IAAI,CAAC,IAAI,CAAC,EAAE;gBAAE,OAAO,IAAI,CAAC;YAC1B,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAA0B,CAAC;QACtD,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;QACD,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC9D,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QACzB,OAAO,MAAM,KAAK,KAAK,CAAC,OAAO,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,KAAa;IAEb,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,IAAI,OAAO;QAAE,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IACxD,MAAM,SAAS,GAAG,eAAe,CAAC,aAAa,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,IAAI,SAAS;QAAE,OAAO,EAAE,EAAE,EAAE,SAAS,CAAC,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IAC9D,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,KAAa,EACb,MAAyB;IAEzB,uEAAuE;IACvE,IAAI,eAAe,CAAC,aAAa,KAAK,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrD,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,GAAG,KAAK,mBAAmB;SACnC,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACxC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,OAAO;YACL,EAAE,EAAE,IAAI;YACR,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;YACtB,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,GAAG,KAAK,UAAU;SAC5B,CAAC;IACJ,CAAC;IAED,kEAAkE;IAClE,uEAAuE;IACvE,uEAAuE;IACvE,MAAM,IAAI,GAAG,MAAM,wBAAwB,EAAE,CAAC;IAC9C,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QACb,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,eAAe,IAAI,CAAC,MAAM,GAAG;YACpC,YAAY,EAAE,6BAA6B,CAAC,IAAI,CAAC,MAAM,CAAC;YACxD,aAAa,EAAE,yBAAyB,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;SAC9D,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC/B,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;QAC9C,QAAQ,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,OAAO,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QACvE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;IACxB,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;AACvC,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,wBAAwB;IACrC,IAAI,CAAC;QACH,MAAM,aAAa,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAChE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QAChB,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QACrD,IAAI,CAAC,EAAE,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;QACvE,IAAI,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;YACzC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,8BAA8B,EAAE,CAAC;QAC/D,CAAC;QACD,IAAI,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EAAE,CAAC;YACzF,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;QAC/C,CAAC;QACD,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU;SAClE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,yBAAyB,CAAC,MAAyB,EAAE,MAAc;IAC1E,IAAI,MAAM,KAAK,cAAc,EAAE,CAAC;QAC9B,OAAO,cAAc,MAAM,CAAC,SAAS,OAAO,CAAC;IAC/C,CAAC;IACD,OAAO,cAAc,MAAM,CAAC,SAAS,YAAY,CAAC;AACpD,CAAC;AAED,SAAS,6BAA6B,CAAC,MAAc;IACnD,IAAI,MAAM,KAAK,cAAc,EAAE,CAAC;QAC9B,OAAO,oCAAoC,CAAC;IAC9C,CAAC;IACD,IAAI,MAAM,KAAK,8BAA8B,EAAE,CAAC;QAC9C,OAAO,mDAAmD,CAAC;IAC7D,CAAC;IACD,IAAI,MAAM,KAAK,cAAc,EAAE,CAAC;QAC9B,OAAO,iDAAiD,CAAC;IAC3D,CAAC;IACD,OAAO,YAAY,MAAM,EAAE,CAAC;AAC9B,CAAC;AAED,KAAK,UAAU,qBAAqB,CAClC,IAAU,EACV,MAAyB;IAEzB,QAAQ,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;IAC5E,uEAAuE;IACvE,yEAAyE;IACzE,sCAAsC;IACtC,IAAI,CAAC;QACH,MAAM,aAAa,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IAClE,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QAChB,MAAM,MAAM,GAAG;YACb,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE;YAC/B,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE;YACrC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,UAAU,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;YAClE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;SAC3D,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9B,OAAO,CAAC,KAAK,CAAC,qCAAqC,MAAM,EAAE,CAAC,CAAC;QAC7D,QAAQ,CAAC,IAAI,EAAE;YACb,IAAI,EAAE,OAAO;YACb,OAAO,EACL,cAAc,MAAM,IAAI,YAAY,0CAA0C;SACjF,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;QACtB,OAAO;IACT,CAAC;IAED,QAAQ,CAAC,IAAI,EAAE;QACb,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,WAAW,MAAM,CAAC,SAAS,EAAE;QACtC,QAAQ,EAAE,EAAE;KACb,CAAC,CAAC;IACH,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,MAAM,CAAC,CAAC;IAC7D,IAAI,UAAkB,CAAC;IACvB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;QAC1E,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,QAAQ,CAAC,IAAI,EAAE;gBACb,IAAI,EAAE,OAAO;gBACb,OAAO,EAAE,cAAc,IAAI,CAAC,MAAM,EAAE;aACrC,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;YACtB,OAAO;QACT,CAAC;QACD,UAAU,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;IACjC,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QAChB,QAAQ,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,OAAO,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QACvE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;QACtB,OAAO;IACT,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;IAED,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACxB,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACrE,IAAI,MAAM,KAAK,MAAM,CAAC,YAAY,EAAE,CAAC;YACnC,QAAQ,CAAC,IAAI,EAAE;gBACb,IAAI,EAAE,OAAO;gBACb,OAAO,EAAE,mBAAmB,MAAM,CAAC,YAAY,QAAQ,MAAM,EAAE;aAChE,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;YACtB,OAAO;QACT,CAAC;QACD,QAAQ,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,CAAC;IAC1D,CAAC;SAAM,CAAC;QACN,QAAQ,CAAC,IAAI,EAAE;YACb,IAAI,EAAE,KAAK;YACX,OAAO,EAAE,kCAAkC;SAC5C,CAAC,CAAC;IACL,CAAC;IAED,yEAAyE;IACzE,sCAAsC;IACtC,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,oBAAoB,CAAC,CAAC,CAAC;IACpE,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;IACjD,aAAa,CAAC,UAAU,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAEvD,QAAQ,CAAC,IAAI,EAAE;QACb,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,sBAAsB;QAC/B,QAAQ,EAAE,EAAE;KACb,CAAC,CAAC;IAEH,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,EAAE,GAAG,MAAM,CAAC,CAAC;IACtF,IAAI,CAAC;QAAC,MAAM,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;IAExF,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,QAAQ,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,CAAC;QAC1D,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;QACtB,OAAO;IACT,CAAC;IAED,QAAQ,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC,MAAM,CAAC,CAAC;IACpD,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC;QACvB,QAAQ,CAAC,IAAI,EAAE;YACb,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,2BAA2B;SACrC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;QACtB,OAAO;IACT,CAAC;IAED,QAAQ,CAAC,IAAI,EAAE;QACb,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM;QAC7D,QAAQ,EAAE,GAAG;KACd,CAAC,CAAC;IACH,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;AACvB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,KAAa,EACb,MAAyB;IAEzB,8CAA8C;IAC9C,IAAI,eAAe,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtC,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,GAAG,KAAK,oBAAoB;SACpC,CAAC;IACJ,CAAC;IACD,IAAI,eAAe,CAAC,aAAa,KAAK,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrD,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,GAAG,KAAK,UAAU;SAC1B,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,wBAAwB,EAAE,CAAC;IAC9C,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,2BAA2B,CAAC,MAAM,CAAC,CAAC;QACnD,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,kBAAkB,IAAI,CAAC,MAAM,GAAG;YACvC,YAAY,EAAE,IAAI,CAAC,MAAM;YACzB,aAAa,EAAE,MAAM;SACtB,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,UAAU,CAAC,aAAa,KAAK,EAAE,CAAC,CAAC;IAC9C,uBAAuB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;QAChD,QAAQ,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,OAAO,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QACvE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;IACxB,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;AACvC,CAAC;AAED,SAAS,2BAA2B,CAAC,MAAyB;IAC5D,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CAAC,uBAAuB,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;QACxD,KAAK,CAAC,IAAI,CAAC,0BAA0B,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7D,CAAC;IACD,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,IAAI,MAAM,CAAC,UAAU;QAAE,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACzD,IAAI,MAAM,CAAC,YAAY;QAAE,SAAS,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;IAChE,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,KAAK,CAAC,IAAI,CAAC,eAAe,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC;AAED,KAAK,UAAU,uBAAuB,CACpC,IAAU,EACV,MAAyB;IAEzB,IAAI,CAAC;QACH,MAAM,aAAa,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IAClE,CAAC;IAAC,MAAM,CAAC;QACP,QAAQ,CAAC,IAAI,EAAE;YACb,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,sBAAsB;SAChC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;QACtB,OAAO;IACT,CAAC;IAED,0EAA0E;IAC1E,yEAAyE;IACzE,uEAAuE;IACvE,+DAA+D;IAC/D,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QACvB,QAAQ,CAAC,IAAI,EAAE;YACb,IAAI,EAAE,UAAU;YAChB,OAAO,EAAE,kBAAkB,MAAM,CAAC,WAAW,EAAE;YAC/C,QAAQ,EAAE,EAAE;SACb,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,aAAa,CACjC,IAAI,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,EAAE,MAAM,CACtE,CAAC;QACF,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,QAAQ,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,iCAAiC,EAAE,CAAC,CAAC;QAC9E,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,aAAa,CAClC,IAAI,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,CAAC,WAAW,CAAC,EAAE,MAAM,CACzE,CAAC;QACF,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,QAAQ,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,oCAAoC,EAAE,CAAC,CAAC;QACjF,CAAC;IACH,CAAC;IAED,MAAM,cAAc,GAAa,EAAE,CAAC;IACpC,IAAI,MAAM,CAAC,UAAU;QAAE,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC9D,IAAI,MAAM,CAAC,YAAY;QAAE,cAAc,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;IAErE,wEAAwE;IACxE,oEAAoE;IACpE,oEAAoE;IACpE,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,QAAQ,CAAC,IAAI,EAAE;YACb,IAAI,EAAE,UAAU;YAChB,OAAO,EAAE,SAAS,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YAC7C,QAAQ,EAAE,EAAE;SACb,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,aAAa,CACjC,IAAI,EACJ,MAAM,EACN,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,cAAc,CAAC,EAC5C,MAAM,CACP,CAAC;QACF,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,QAAQ,CAAC,IAAI,EAAE;gBACb,IAAI,EAAE,OAAO;gBACb,OAAO,EAAE,SAAS,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,qBAAqB;aACjE,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;YACtB,OAAO;QACT,CAAC;IACH,CAAC;IAED,oEAAoE;IACpE,qEAAqE;IACrE,uEAAuE;IACvE,0DAA0D;IAC1D,MAAM,IAAI,GAAG,MAAM,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAClD,IAAI,IAAI,EAAE,SAAS,EAAE,CAAC;QACpB,QAAQ,CAAC,IAAI,EAAE;YACb,IAAI,EAAE,OAAO;YACb,OAAO,EACL,iDAAiD;SACpD,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;QACtB,OAAO;IACT,CAAC;IAED,QAAQ,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;IACjE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;AACvB,CAAC;AAED,SAAS,aAAa,CACpB,IAAU,EACV,GAAW,EACX,IAAc,EACd,SAAiB;IAEjB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,KAAK,GAAG,QAAQ,CACpB,GAAG,EACH,IAAI,EACJ,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,EACtE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;YACtB,MAAM,MAAM,GAAG,GAAG,MAAM,IAAI,EAAE,GAAG,MAAM,IAAI,EAAE,EAAE,CAAC;YAChD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;gBACxC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;gBACxB,IAAI,IAAI;oBAAE,QAAQ,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3D,CAAC;YACD,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC;QAChB,CAAC,CACF,CAAC;QACF,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;YACtB,QAAQ,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACxE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for the agent-apps module.
|
|
3
|
+
*
|
|
4
|
+
* "Agent apps" are installable Tier-1 agent runtimes (hermes, openclaw).
|
|
5
|
+
* They are surfaced to the user through the "运行时安装" page and share one
|
|
6
|
+
* install/update/uninstall pipeline driven by the RuntimeAdapter contract.
|
|
7
|
+
*
|
|
8
|
+
* Non-agent AppSpec bundles (ollama, searxng, openwebui, ...) live under
|
|
9
|
+
* `/apps/*.yaml` and install via `POST /api/apps/install` into the generic
|
|
10
|
+
* `custom` AppTypeManager — they are NOT part of this catalog.
|
|
11
|
+
*
|
|
12
|
+
* The `AgentAppCategory` and `AgentAppSource` kinds also cover historical
|
|
13
|
+
* CLI-tool / system-service installers (`shell-script`, `npm-global`) that
|
|
14
|
+
* may gain new entries in future phases.
|
|
15
|
+
*/
|
|
16
|
+
export type AgentAppCategory = "agent-runtime" | "system-service" | "cli-tool";
|
|
17
|
+
/**
|
|
18
|
+
* How an app is installed on disk. Each kind maps to an installer strategy in
|
|
19
|
+
* `installers/`. Today only `adapter` (hermes + openclaw) has catalog entries;
|
|
20
|
+
* `shell-script` / `npm-global` remain in the type union for future use.
|
|
21
|
+
*/
|
|
22
|
+
export type AgentAppSource = {
|
|
23
|
+
kind: "adapter";
|
|
24
|
+
/** Matches an entry in `runtime/index.ts` adapter registry. */
|
|
25
|
+
agentType: string;
|
|
26
|
+
} | {
|
|
27
|
+
kind: "shell-script";
|
|
28
|
+
/**
|
|
29
|
+
* URL of the install script. Fetched over HTTPS; sha256 is verified
|
|
30
|
+
* when `scriptSha256` is set. Leaving sha256 out is supported but
|
|
31
|
+
* surfaces a warning in the install log.
|
|
32
|
+
*/
|
|
33
|
+
scriptUrl: string;
|
|
34
|
+
scriptSha256?: string;
|
|
35
|
+
/** Command used to detect install status + read version. */
|
|
36
|
+
probeCommand: {
|
|
37
|
+
cmd: string;
|
|
38
|
+
args: string[];
|
|
39
|
+
};
|
|
40
|
+
/** Regex with a `(version)` capture group applied to `probeCommand`
|
|
41
|
+
* stdout. Default: `/\b(\d+\.\d+\.\d+)\b/`. */
|
|
42
|
+
versionRegex?: string;
|
|
43
|
+
/**
|
|
44
|
+
* GitHub slug (`owner/name`) used to look up the latest release via
|
|
45
|
+
* the REST API during update checks. Leave unset to disable update
|
|
46
|
+
* detection for this app.
|
|
47
|
+
*/
|
|
48
|
+
githubRepo?: string;
|
|
49
|
+
/** systemd unit name (without `.service`) stopped + disabled on
|
|
50
|
+
* uninstall. Leave unset if the app is not a daemon. */
|
|
51
|
+
systemdUnit?: string;
|
|
52
|
+
/** Absolute path of the primary binary removed on uninstall. Also
|
|
53
|
+
* used for the disk-size probe (`du -sb`). */
|
|
54
|
+
binaryPath?: string;
|
|
55
|
+
/** Additional absolute paths removed on uninstall (state dirs,
|
|
56
|
+
* systemd unit file, etc.). */
|
|
57
|
+
extraCleanup?: string[];
|
|
58
|
+
} | {
|
|
59
|
+
kind: "npm-global";
|
|
60
|
+
packageName: string;
|
|
61
|
+
};
|
|
62
|
+
export interface AgentAppStatus {
|
|
63
|
+
installed: boolean;
|
|
64
|
+
imageReady?: boolean;
|
|
65
|
+
version?: string;
|
|
66
|
+
digest?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Whether the registry has a newer image than the one stored locally.
|
|
69
|
+
* `true` = upstream digest differs from local
|
|
70
|
+
* `false` = local is up-to-date
|
|
71
|
+
* `null` = probe failed / docker too old / offline (UI stays neutral)
|
|
72
|
+
*/
|
|
73
|
+
updateAvailable?: boolean | null;
|
|
74
|
+
/** Task id currently installing/updating this app, if any. */
|
|
75
|
+
currentTaskId?: string;
|
|
76
|
+
/**
|
|
77
|
+
* Shape of `currentTaskId`: install/update tasks vs. uninstall tasks use
|
|
78
|
+
* disjoint task names so they cannot collide. The frontend relies on this
|
|
79
|
+
* kind to render the right verb ("安装中" vs "卸载中") and to avoid
|
|
80
|
+
* toasting "install complete" when an uninstall finishes.
|
|
81
|
+
*/
|
|
82
|
+
currentTaskKind?: "install" | "uninstall";
|
|
83
|
+
}
|
|
84
|
+
export interface AgentAppCardView {
|
|
85
|
+
id: string;
|
|
86
|
+
name: string;
|
|
87
|
+
category: AgentAppCategory;
|
|
88
|
+
description: string;
|
|
89
|
+
/** Optional lucide-style icon key the frontend can map to an SVG. */
|
|
90
|
+
icon?: string;
|
|
91
|
+
/** Approximate install size surfaced in the UI (may be `null` when unknown). */
|
|
92
|
+
diskSpaceMB?: number | null;
|
|
93
|
+
source: AgentAppSource;
|
|
94
|
+
status: AgentAppStatus;
|
|
95
|
+
/** Whether each lifecycle action is supported by this app's installer. */
|
|
96
|
+
actions: {
|
|
97
|
+
install: boolean;
|
|
98
|
+
update: boolean;
|
|
99
|
+
uninstall: boolean;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* True when this app is required for basic panel function (currently
|
|
103
|
+
* openclaw). The UI uses this to hide the uninstall button.
|
|
104
|
+
*/
|
|
105
|
+
required: boolean;
|
|
106
|
+
}
|
|
107
|
+
export interface InstallStartResult {
|
|
108
|
+
ok: boolean;
|
|
109
|
+
taskId?: string;
|
|
110
|
+
reused?: boolean;
|
|
111
|
+
error?: string;
|
|
112
|
+
message?: string;
|
|
113
|
+
/**
|
|
114
|
+
* Populated when the install/uninstall requires privilege escalation that
|
|
115
|
+
* the panel daemon cannot perform itself (e.g. the service runs with
|
|
116
|
+
* `NoNewPrivileges=true`, which blocks sudo's setuid path).
|
|
117
|
+
*
|
|
118
|
+
* The UI should show this to the user as a one-line shell command to run
|
|
119
|
+
* in their own terminal. After the user executes it, the regular status
|
|
120
|
+
* probe cycle picks up the new install state automatically.
|
|
121
|
+
*/
|
|
122
|
+
manualCommand?: string;
|
|
123
|
+
/** Human-readable reason the daemon can't self-execute (UI subtitle). */
|
|
124
|
+
manualReason?: string;
|
|
125
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for the agent-apps module.
|
|
3
|
+
*
|
|
4
|
+
* "Agent apps" are installable Tier-1 agent runtimes (hermes, openclaw).
|
|
5
|
+
* They are surfaced to the user through the "运行时安装" page and share one
|
|
6
|
+
* install/update/uninstall pipeline driven by the RuntimeAdapter contract.
|
|
7
|
+
*
|
|
8
|
+
* Non-agent AppSpec bundles (ollama, searxng, openwebui, ...) live under
|
|
9
|
+
* `/apps/*.yaml` and install via `POST /api/apps/install` into the generic
|
|
10
|
+
* `custom` AppTypeManager — they are NOT part of this catalog.
|
|
11
|
+
*
|
|
12
|
+
* The `AgentAppCategory` and `AgentAppSource` kinds also cover historical
|
|
13
|
+
* CLI-tool / system-service installers (`shell-script`, `npm-global`) that
|
|
14
|
+
* may gain new entries in future phases.
|
|
15
|
+
*/
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/services/agent-apps/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import type { AppSpec, AppTask, AppTaskPort, AppTaskHealth } from "
|
|
1
|
+
import type { AppSpec, AppTask, AppTaskPort, AppTaskHealth } from "../../types.js";
|
|
2
2
|
export declare function parseCpuToMHz(cpu?: string): number;
|
|
3
3
|
export declare function parseMemoryToMB(memory?: string): number;
|
|
4
4
|
/** Compile AppTask ports → Nomad network port mappings */
|
|
5
5
|
export declare function compilePorts(ports?: AppTaskPort[]): Record<string, any>[];
|
|
6
6
|
/** Compile AppTask health → Nomad service check */
|
|
7
|
-
export declare function compileHealthCheck(health?: AppTaskHealth, taskName?: string): Record<string, any> | null;
|
|
7
|
+
export declare function compileHealthCheck(health?: AppTaskHealth, taskName?: string, ports?: AppTaskPort[]): Record<string, any> | null;
|
|
8
8
|
/** Map AppTask role → Nomad lifecycle hook */
|
|
9
|
-
export declare function compileLifecycle(role
|
|
9
|
+
export declare function compileLifecycle(role?: string): Record<string, any> | null;
|
|
10
10
|
export declare function compileTaskRuntime(task: AppTask, instanceId: string): Record<string, any>;
|
|
11
11
|
/**
|
|
12
12
|
* Compile a full AppSpec into a Nomad-compatible task group structure.
|