jishushell 0.4.17 → 0.4.24-beta.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.
Files changed (241) hide show
  1. package/Dockerfile.hermes-slim +193 -0
  2. package/apps/hermes-container.yaml +35 -0
  3. package/apps/ollama-binary.yaml +164 -0
  4. package/apps/ollama-cpu-container.yaml +37 -0
  5. package/apps/ollama-with-hollama-binary.yaml +159 -0
  6. package/apps/openclaw-binary.yaml +69 -0
  7. package/apps/openclaw-container.yaml +37 -0
  8. package/apps/openclaw-with-ollama-container.yaml +42 -0
  9. package/apps/openclaw-with-searxng-container.yaml +136 -0
  10. package/apps/openwebui-container.yaml +53 -0
  11. package/apps/playwright-container.yaml +120 -0
  12. package/apps/searxng-container.yaml +115 -0
  13. package/dist/auth.d.ts +1 -0
  14. package/dist/auth.js +15 -14
  15. package/dist/auth.js.map +1 -1
  16. package/dist/cli/app.d.ts +1 -0
  17. package/dist/cli/app.js +770 -52
  18. package/dist/cli/app.js.map +1 -1
  19. package/dist/cli/backup.d.ts +3 -0
  20. package/dist/cli/backup.js +434 -0
  21. package/dist/cli/backup.js.map +1 -0
  22. package/dist/cli/doctor.d.ts +1 -0
  23. package/dist/cli/doctor.js +61 -35
  24. package/dist/cli/doctor.js.map +1 -1
  25. package/dist/cli/job.d.ts +1 -0
  26. package/dist/cli/job.js +37 -99
  27. package/dist/cli/job.js.map +1 -1
  28. package/dist/cli/llm.d.ts +1 -0
  29. package/dist/cli/llm.js +20 -14
  30. package/dist/cli/llm.js.map +1 -1
  31. package/dist/cli/managed-list.d.ts +30 -0
  32. package/dist/cli/managed-list.js +129 -0
  33. package/dist/cli/managed-list.js.map +1 -0
  34. package/dist/cli/panel.d.ts +4 -3
  35. package/dist/cli/panel.js +94 -24
  36. package/dist/cli/panel.js.map +1 -1
  37. package/dist/cli/version.d.ts +1 -0
  38. package/dist/cli/version.js +12 -0
  39. package/dist/cli/version.js.map +1 -0
  40. package/dist/cli.js +47 -516
  41. package/dist/cli.js.map +1 -1
  42. package/dist/config.d.ts +68 -0
  43. package/dist/config.js +266 -12
  44. package/dist/config.js.map +1 -1
  45. package/dist/control.d.ts +10 -6
  46. package/dist/control.js +87 -6
  47. package/dist/control.js.map +1 -1
  48. package/dist/install.d.ts +16 -0
  49. package/dist/install.js +75 -26
  50. package/dist/install.js.map +1 -1
  51. package/dist/routes/agent-apps.d.ts +15 -0
  52. package/dist/routes/agent-apps.js +78 -0
  53. package/dist/routes/agent-apps.js.map +1 -0
  54. package/dist/routes/apps.js +186 -7
  55. package/dist/routes/apps.js.map +1 -1
  56. package/dist/routes/backup.js +3 -3
  57. package/dist/routes/backup.js.map +1 -1
  58. package/dist/routes/instances.d.ts +6 -0
  59. package/dist/routes/instances.js +862 -879
  60. package/dist/routes/instances.js.map +1 -1
  61. package/dist/routes/llm.js +9 -8
  62. package/dist/routes/llm.js.map +1 -1
  63. package/dist/routes/runtime.d.ts +15 -0
  64. package/dist/routes/runtime.js +69 -0
  65. package/dist/routes/runtime.js.map +1 -0
  66. package/dist/routes/setup.js +103 -8
  67. package/dist/routes/setup.js.map +1 -1
  68. package/dist/routes/system.js +25 -3
  69. package/dist/routes/system.js.map +1 -1
  70. package/dist/server.js +71 -7
  71. package/dist/server.js.map +1 -1
  72. package/dist/services/agent-apps/catalog.d.ts +30 -0
  73. package/dist/services/agent-apps/catalog.js +60 -0
  74. package/dist/services/agent-apps/catalog.js.map +1 -0
  75. package/dist/services/agent-apps/index.d.ts +36 -0
  76. package/dist/services/agent-apps/index.js +171 -0
  77. package/dist/services/agent-apps/index.js.map +1 -0
  78. package/dist/services/agent-apps/installers/adapter-probes.d.ts +49 -0
  79. package/dist/services/agent-apps/installers/adapter-probes.js +223 -0
  80. package/dist/services/agent-apps/installers/adapter-probes.js.map +1 -0
  81. package/dist/services/agent-apps/installers/adapter.d.ts +30 -0
  82. package/dist/services/agent-apps/installers/adapter.js +171 -0
  83. package/dist/services/agent-apps/installers/adapter.js.map +1 -0
  84. package/dist/services/agent-apps/installers/registry-probe.d.ts +38 -0
  85. package/dist/services/agent-apps/installers/registry-probe.js +183 -0
  86. package/dist/services/agent-apps/installers/registry-probe.js.map +1 -0
  87. package/dist/services/agent-apps/installers/shell-script.d.ts +47 -0
  88. package/dist/services/agent-apps/installers/shell-script.js +471 -0
  89. package/dist/services/agent-apps/installers/shell-script.js.map +1 -0
  90. package/dist/services/agent-apps/types.d.ts +125 -0
  91. package/dist/services/agent-apps/types.js +17 -0
  92. package/dist/services/agent-apps/types.js.map +1 -0
  93. package/dist/services/{app-compiler.d.ts → app/app-compiler.d.ts} +3 -3
  94. package/dist/services/{app-compiler.js → app/app-compiler.js} +10 -7
  95. package/dist/services/app/app-compiler.js.map +1 -0
  96. package/dist/services/app/app-manager.d.ts +142 -0
  97. package/dist/services/app/app-manager.js +2148 -0
  98. package/dist/services/app/app-manager.js.map +1 -0
  99. package/dist/services/app/custom-manager.d.ts +27 -0
  100. package/dist/services/app/custom-manager.js +285 -0
  101. package/dist/services/app/custom-manager.js.map +1 -0
  102. package/dist/services/app/hermes-agent-manager.d.ts +20 -0
  103. package/dist/services/app/hermes-agent-manager.js +289 -0
  104. package/dist/services/app/hermes-agent-manager.js.map +1 -0
  105. package/dist/services/app/id-normalizer.d.ts +27 -0
  106. package/dist/services/app/id-normalizer.js +77 -0
  107. package/dist/services/app/id-normalizer.js.map +1 -0
  108. package/dist/services/app/ollama-manager.d.ts +18 -0
  109. package/dist/services/app/ollama-manager.js +207 -0
  110. package/dist/services/app/ollama-manager.js.map +1 -0
  111. package/dist/services/app/openclaw-manager.d.ts +63 -0
  112. package/dist/services/app/openclaw-manager.js +1178 -0
  113. package/dist/services/app/openclaw-manager.js.map +1 -0
  114. package/dist/services/app/paths.d.ts +47 -0
  115. package/dist/services/app/paths.js +68 -0
  116. package/dist/services/app/paths.js.map +1 -0
  117. package/dist/services/app/registry.d.ts +17 -0
  118. package/dist/services/app/registry.js +31 -0
  119. package/dist/services/app/registry.js.map +1 -0
  120. package/dist/services/app/remote-spec.d.ts +14 -0
  121. package/dist/services/app/remote-spec.js +58 -0
  122. package/dist/services/app/remote-spec.js.map +1 -0
  123. package/dist/services/app/terminal-session-manager.d.ts +27 -0
  124. package/dist/services/app/terminal-session-manager.js +157 -0
  125. package/dist/services/app/terminal-session-manager.js.map +1 -0
  126. package/dist/services/app/types.d.ts +72 -0
  127. package/dist/services/app/types.js +16 -0
  128. package/dist/services/app/types.js.map +1 -0
  129. package/dist/services/backup-manager.js +60 -22
  130. package/dist/services/backup-manager.js.map +1 -1
  131. package/dist/services/instance-manager.d.ts +82 -39
  132. package/dist/services/instance-manager.js +575 -1142
  133. package/dist/services/instance-manager.js.map +1 -1
  134. package/dist/services/llm-proxy/circuit-breaker.js +10 -2
  135. package/dist/services/llm-proxy/circuit-breaker.js.map +1 -1
  136. package/dist/services/llm-proxy/index.d.ts +14 -1
  137. package/dist/services/llm-proxy/index.js +51 -6
  138. package/dist/services/llm-proxy/index.js.map +1 -1
  139. package/dist/services/nomad-manager.d.ts +260 -3
  140. package/dist/services/nomad-manager.js +2866 -449
  141. package/dist/services/nomad-manager.js.map +1 -1
  142. package/dist/services/panel-manager.d.ts +10 -0
  143. package/dist/services/panel-manager.js +97 -0
  144. package/dist/services/panel-manager.js.map +1 -1
  145. package/dist/services/plugin-installer.js +28 -2
  146. package/dist/services/plugin-installer.js.map +1 -1
  147. package/dist/services/process-manager.js +22 -0
  148. package/dist/services/process-manager.js.map +1 -1
  149. package/dist/services/runtime/adapters/custom.d.ts +20 -0
  150. package/dist/services/runtime/adapters/custom.js +90 -0
  151. package/dist/services/runtime/adapters/custom.js.map +1 -0
  152. package/dist/services/runtime/adapters/hermes.d.ts +174 -0
  153. package/dist/services/runtime/adapters/hermes.js +1316 -0
  154. package/dist/services/runtime/adapters/hermes.js.map +1 -0
  155. package/dist/services/runtime/adapters/openclaw-routes.d.ts +17 -0
  156. package/dist/services/runtime/adapters/openclaw-routes.js +946 -0
  157. package/dist/services/runtime/adapters/openclaw-routes.js.map +1 -0
  158. package/dist/services/runtime/adapters/openclaw.d.ts +188 -0
  159. package/dist/services/runtime/adapters/openclaw.js +2195 -0
  160. package/dist/services/runtime/adapters/openclaw.js.map +1 -0
  161. package/dist/services/runtime/errors.d.ts +28 -0
  162. package/dist/services/runtime/errors.js +31 -0
  163. package/dist/services/runtime/errors.js.map +1 -0
  164. package/dist/services/runtime/index.d.ts +34 -0
  165. package/dist/services/runtime/index.js +51 -0
  166. package/dist/services/runtime/index.js.map +1 -0
  167. package/dist/services/runtime/instance.d.ts +24 -0
  168. package/dist/services/runtime/instance.js +143 -0
  169. package/dist/services/runtime/instance.js.map +1 -0
  170. package/dist/services/runtime/migrations.d.ts +15 -0
  171. package/dist/services/runtime/migrations.js +25 -0
  172. package/dist/services/runtime/migrations.js.map +1 -0
  173. package/dist/services/runtime/registry.d.ts +13 -0
  174. package/dist/services/runtime/registry.js +32 -0
  175. package/dist/services/runtime/registry.js.map +1 -0
  176. package/dist/services/runtime/types.d.ts +545 -0
  177. package/dist/services/runtime/types.js +14 -0
  178. package/dist/services/runtime/types.js.map +1 -0
  179. package/dist/services/setup-manager.d.ts +70 -29
  180. package/dist/services/setup-manager.js +278 -597
  181. package/dist/services/setup-manager.js.map +1 -1
  182. package/dist/services/task-registry.d.ts +44 -0
  183. package/dist/services/task-registry.js +74 -0
  184. package/dist/services/task-registry.js.map +1 -0
  185. package/dist/services/telemetry/heartbeat.d.ts +6 -6
  186. package/dist/services/telemetry/heartbeat.js +29 -30
  187. package/dist/services/telemetry/heartbeat.js.map +1 -1
  188. package/dist/types.d.ts +164 -2
  189. package/dist/utils/docker-host.d.ts +15 -0
  190. package/dist/utils/docker-host.js +64 -0
  191. package/dist/utils/docker-host.js.map +1 -0
  192. package/install/jishu-install.sh +25 -2
  193. package/package.json +14 -4
  194. package/public/assets/Dashboard-rh9qpYRR.js +1 -0
  195. package/public/assets/HermesChatPanel-D6JI6lLY.js +1 -0
  196. package/public/assets/HermesConfigForm-DcbSemaj.js +4 -0
  197. package/public/assets/InitPassword-CFTKsED4.js +1 -0
  198. package/public/assets/InstanceDetail-BhNIKA6Z.js +91 -0
  199. package/public/assets/{Login-D1Bt-Lyk.js → Login-KB9qrtM0.js} +1 -1
  200. package/public/assets/NewInstance-CxkO8Hlq.js +1 -0
  201. package/public/assets/Settings-BVWJvOkU.js +1 -0
  202. package/public/assets/Setup-X-lzuaUT.js +1 -0
  203. package/public/assets/WeixinLoginPanel-gca0QTic.js +9 -0
  204. package/public/assets/index-C8B0cFJM.js +19 -0
  205. package/public/assets/index-CPhVFEsx.css +1 -0
  206. package/public/assets/input-paste-CrNVAyOy.js +1 -0
  207. package/public/assets/registry-fVUSujib.js +2 -0
  208. package/public/assets/{usePolling-CK0DfI4h.js → usePolling-Do5Erqm_.js} +1 -1
  209. package/public/assets/vendor-i18n-ucpM0OR0.js +9 -0
  210. package/public/assets/{vendor-react-B1-3Yrt-.js → vendor-react-Bk1hRGiY.js} +1 -1
  211. package/public/favicon.png +0 -0
  212. package/public/index.html +9 -4
  213. package/public/logos/hermes.png +0 -0
  214. package/public/logos/ollama.png +0 -0
  215. package/public/logos/openclaw.svg +60 -0
  216. package/scripts/build-hermes-image.sh +21 -0
  217. package/scripts/build-local.sh +54 -0
  218. package/scripts/check-adapter-isolation.ts +293 -0
  219. package/scripts/fixtures/instances/hermes-sample/instance.json +37 -0
  220. package/scripts/fixtures/instances/legacy-openclaw-sample/instance.json +7 -0
  221. package/scripts/smoke/hermes-bootstrap.sh +195 -0
  222. package/templates/hermes-entrypoint.sh +154 -0
  223. package/dist/cli/openclaw.d.ts +0 -12
  224. package/dist/cli/openclaw.js +0 -156
  225. package/dist/cli/openclaw.js.map +0 -1
  226. package/dist/services/app-compiler.js.map +0 -1
  227. package/dist/services/app-manager.d.ts +0 -17
  228. package/dist/services/app-manager.js +0 -168
  229. package/dist/services/app-manager.js.map +0 -1
  230. package/dist/services/job-manager.d.ts +0 -22
  231. package/dist/services/job-manager.js +0 -102
  232. package/dist/services/job-manager.js.map +0 -1
  233. package/public/assets/Dashboard-CQsp1Mr9.js +0 -1
  234. package/public/assets/InitPassword-BEC8SE4A.js +0 -1
  235. package/public/assets/InstanceDetail-B5wTgNEg.js +0 -17
  236. package/public/assets/NewInstance-GQzm3K9D.js +0 -1
  237. package/public/assets/Settings-ByjGlqhP.js +0 -1
  238. package/public/assets/Setup-cMF21Y-8.js +0 -1
  239. package/public/assets/index-B6qQP4mH.css +0 -1
  240. package/public/assets/index-BuTQtuNy.js +0 -16
  241. package/public/assets/vendor-i18n-CfW0RvgE.js +0 -9
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Agent apps module — unified catalog + install dispatcher for user-
3
+ * installable software around the agent ecosystem (agent runtimes, agent
4
+ * support services, agent-related CLI tools).
5
+ *
6
+ * Public surface:
7
+ * - `listAgentApps()` — card-shaped view backing `GET /api/agent-apps`
8
+ * - `getAgentApp(id)` — single entry lookup
9
+ * - `startAgentAppInstall(id)` — kicks off install/update, returns task id
10
+ */
11
+ import type { AgentAppCardView, InstallStartResult } from "./types.js";
12
+ export type { AgentAppCardView, AgentAppStatus, InstallStartResult } from "./types.js";
13
+ export declare function listAgentApps(): Promise<AgentAppCardView[]>;
14
+ export declare function getAgentApp(id: string): Promise<AgentAppCardView | null>;
15
+ export declare function startAgentAppInstall(id: string, options?: Record<string, any>): Promise<InstallStartResult>;
16
+ /**
17
+ * Backs `POST /api/agent-apps/check-updates`. Runs the update probe for
18
+ * every app across all installer kinds in parallel. Slow networks can take
19
+ * tens of seconds — the endpoint holds the connection until all probes
20
+ * complete or time out individually.
21
+ *
22
+ * - adapter kind: registry HTTPS digest comparison (cached)
23
+ * - shell-script kind: GitHub Releases API tag vs installed version (direct,
24
+ * no cache yet; light-weight call so acceptable)
25
+ */
26
+ export declare function checkAllAgentAppUpdates(): Promise<{
27
+ checkedAt: number;
28
+ results: Record<string, boolean | null>;
29
+ }>;
30
+ /**
31
+ * Newest "last checked" timestamp across all installer kinds. The UI
32
+ * ("上次检查更新:2 分钟前") reads this — it doesn't care which installer
33
+ * owned the probe, only when *any* probe last finished.
34
+ */
35
+ export declare function getAgentAppUpdatesLastCheckedAt(): number | null;
36
+ export declare function startAgentAppUninstall(id: string): Promise<InstallStartResult>;
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Agent apps module — unified catalog + install dispatcher for user-
3
+ * installable software around the agent ecosystem (agent runtimes, agent
4
+ * support services, agent-related CLI tools).
5
+ *
6
+ * Public surface:
7
+ * - `listAgentApps()` — card-shaped view backing `GET /api/agent-apps`
8
+ * - `getAgentApp(id)` — single entry lookup
9
+ * - `startAgentAppInstall(id)` — kicks off install/update, returns task id
10
+ */
11
+ import { AGENT_APP_CATALOG, getCatalogEntry } from "./catalog.js";
12
+ import { countInstancesUsingAgentType, findRunningAdapterTask, forceRefreshAllAdapterUpdates, getUpdateCacheLastCheckedAt, probeAdapterImageSizeMB, probeAdapterStatus, probeAdapterUpdateAvailable, startAdapterInstall, startAdapterUninstall, } from "./installers/adapter.js";
13
+ import { findRunningShellScriptTask, getShellScriptUpdateCacheLastCheckedAt, probeShellScriptSizeMB, probeShellScriptStatus, readShellScriptUpdateAvailable, refreshShellScriptUpdateCache, startShellScriptInstall, startShellScriptUninstall, } from "./installers/shell-script.js";
14
+ async function buildCardView(entry) {
15
+ const status = { installed: false };
16
+ let diskSpaceMB = null;
17
+ if (entry.source.kind === "adapter") {
18
+ // Probe status + size + update-availability in parallel. Each docker
19
+ // shell call has its own short timeout so a slow daemon degrades to
20
+ // "unknown" fields rather than hanging the whole catalog response.
21
+ const [probe, sizeMB, updateAvailable] = await Promise.all([
22
+ probeAdapterStatus(entry.source.agentType),
23
+ probeAdapterImageSizeMB(entry.source.agentType),
24
+ probeAdapterUpdateAvailable(entry.source.agentType),
25
+ ]);
26
+ if (probe) {
27
+ status.installed = probe.installed;
28
+ status.imageReady = probe.imageReady;
29
+ status.version = probe.version;
30
+ status.digest = probe.digest;
31
+ }
32
+ const running = findRunningAdapterTask(entry.source.agentType);
33
+ status.currentTaskId = running?.id;
34
+ status.currentTaskKind = running?.kind;
35
+ status.updateAvailable = status.installed ? updateAvailable : null;
36
+ diskSpaceMB = sizeMB;
37
+ }
38
+ else if (entry.source.kind === "shell-script") {
39
+ // Hot-path probes only. Update availability is a cached read (written
40
+ // by `checkAllAgentAppUpdates`) — this branch never makes an outbound
41
+ // HTTP call to GitHub so the 5 s catalog poll can't trip rate limits
42
+ // or stall on slow WAN.
43
+ const [probe, sizeMB] = await Promise.all([
44
+ probeShellScriptStatus(entry.source),
45
+ probeShellScriptSizeMB(entry.source),
46
+ ]);
47
+ if (probe) {
48
+ status.installed = probe.installed;
49
+ status.imageReady = probe.installed; // shell tools are binary-or-not; treat installed == imageReady
50
+ status.version = probe.version;
51
+ }
52
+ const running = findRunningShellScriptTask(entry.id);
53
+ status.currentTaskId = running?.id;
54
+ status.currentTaskKind = running?.kind;
55
+ status.updateAvailable = status.installed ? readShellScriptUpdateAvailable(entry.id) : null;
56
+ diskSpaceMB = sizeMB;
57
+ }
58
+ return {
59
+ id: entry.id,
60
+ name: entry.name,
61
+ category: entry.category,
62
+ description: entry.description,
63
+ icon: entry.icon,
64
+ diskSpaceMB,
65
+ source: entry.source,
66
+ status,
67
+ actions: entry.actions,
68
+ required: entry.required,
69
+ };
70
+ }
71
+ export async function listAgentApps() {
72
+ return Promise.all(AGENT_APP_CATALOG.map(buildCardView));
73
+ }
74
+ export async function getAgentApp(id) {
75
+ const entry = getCatalogEntry(id);
76
+ if (!entry)
77
+ return null;
78
+ return buildCardView(entry);
79
+ }
80
+ export async function startAgentAppInstall(id, options = {}) {
81
+ const entry = getCatalogEntry(id);
82
+ if (!entry) {
83
+ return { ok: false, error: `Unknown agent app "${id}"` };
84
+ }
85
+ if (!entry.actions.install && !entry.actions.update) {
86
+ return { ok: false, error: `Agent app "${id}" does not support install/update` };
87
+ }
88
+ if (entry.source.kind === "adapter") {
89
+ return startAdapterInstall(entry.source.agentType, options);
90
+ }
91
+ if (entry.source.kind === "shell-script") {
92
+ return startShellScriptInstall(entry.id, entry.source);
93
+ }
94
+ return {
95
+ ok: false,
96
+ error: `Installer for source kind "${entry.source.kind}" is not implemented yet`,
97
+ };
98
+ }
99
+ /**
100
+ * Backs `POST /api/agent-apps/check-updates`. Runs the update probe for
101
+ * every app across all installer kinds in parallel. Slow networks can take
102
+ * tens of seconds — the endpoint holds the connection until all probes
103
+ * complete or time out individually.
104
+ *
105
+ * - adapter kind: registry HTTPS digest comparison (cached)
106
+ * - shell-script kind: GitHub Releases API tag vs installed version (direct,
107
+ * no cache yet; light-weight call so acceptable)
108
+ */
109
+ export async function checkAllAgentAppUpdates() {
110
+ const adapterAgents = [];
111
+ const shellScriptEntries = [];
112
+ for (const entry of AGENT_APP_CATALOG) {
113
+ if (entry.source.kind === "adapter")
114
+ adapterAgents.push(entry.source.agentType);
115
+ else if (entry.source.kind === "shell-script") {
116
+ shellScriptEntries.push({ id: entry.id, source: entry.source });
117
+ }
118
+ }
119
+ const [adapterResults, shellScriptResults] = await Promise.all([
120
+ forceRefreshAllAdapterUpdates(adapterAgents),
121
+ Promise.all(shellScriptEntries.map(async ({ id, source }) => {
122
+ const value = await refreshShellScriptUpdateCache(id, source);
123
+ return [id, value];
124
+ })),
125
+ ]);
126
+ const results = { ...adapterResults };
127
+ for (const [id, value] of shellScriptResults)
128
+ results[id] = value;
129
+ return { checkedAt: Date.now(), results };
130
+ }
131
+ /**
132
+ * Newest "last checked" timestamp across all installer kinds. The UI
133
+ * ("上次检查更新:2 分钟前") reads this — it doesn't care which installer
134
+ * owned the probe, only when *any* probe last finished.
135
+ */
136
+ export function getAgentAppUpdatesLastCheckedAt() {
137
+ const adapterAt = getUpdateCacheLastCheckedAt();
138
+ const shellScriptAt = getShellScriptUpdateCacheLastCheckedAt();
139
+ if (adapterAt == null)
140
+ return shellScriptAt;
141
+ if (shellScriptAt == null)
142
+ return adapterAt;
143
+ return Math.max(adapterAt, shellScriptAt);
144
+ }
145
+ export async function startAgentAppUninstall(id) {
146
+ const entry = getCatalogEntry(id);
147
+ if (!entry) {
148
+ return { ok: false, error: `Unknown agent app "${id}"` };
149
+ }
150
+ if (!entry.actions.uninstall) {
151
+ return { ok: false, error: `${entry.name} 不支持卸载` };
152
+ }
153
+ if (entry.source.kind === "adapter") {
154
+ const depCount = countInstancesUsingAgentType(entry.source.agentType);
155
+ if (depCount > 0) {
156
+ return {
157
+ ok: false,
158
+ error: `还有 ${depCount} 个实例使用 ${entry.name},请先删除这些实例再卸载`,
159
+ };
160
+ }
161
+ return startAdapterUninstall(entry.source.agentType);
162
+ }
163
+ if (entry.source.kind === "shell-script") {
164
+ return startShellScriptUninstall(entry.id, entry.source);
165
+ }
166
+ return {
167
+ ok: false,
168
+ error: `Uninstaller for source kind "${entry.source.kind}" is not implemented yet`,
169
+ };
170
+ }
171
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/agent-apps/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Probe functions used by `buildCardView` to populate an adapter-backed
3
+ * `AgentAppCardView` — install status, disk size, and update availability.
4
+ *
5
+ * The update probe is the expensive one (needs to reach the upstream
6
+ * registry) so it runs behind a stale-while-revalidate cache: callers see
7
+ * whatever is cached immediately, and a background refresh kicks off when
8
+ * the cache is stale. `forceRefreshAllAdapterUpdates` is the explicit
9
+ * "check updates now" path used by the UI button; it awaits in-flight
10
+ * refreshes instead of skipping them so the button's result reflects the
11
+ * newest state, not the value that was cached at click time.
12
+ */
13
+ /**
14
+ * Resolve the docker image an adapter's instances currently run on. Prefers
15
+ * the installed record in panel.json.runtime_catalog; falls back to the
16
+ * adapter's declared default so update checks still work even when the app
17
+ * has been uninstalled (or was never installed through the new flow).
18
+ */
19
+ export declare function resolveAdapterImage(agentType: string): string | null;
20
+ export declare function probeAdapterStatus(agentType: string): Promise<{
21
+ installed: boolean;
22
+ imageReady: boolean;
23
+ version?: string;
24
+ digest?: string;
25
+ } | null>;
26
+ /**
27
+ * Read the disk size (MB, decimal) of the adapter's current docker image.
28
+ * Uses `docker image ls --format {{.Size}}` (same cumulative-layer total
29
+ * admins see in `docker images`) instead of `docker image inspect .Size`
30
+ * which reports dedup'd unique bytes and doesn't match operator
31
+ * expectation.
32
+ */
33
+ export declare function probeAdapterImageSizeMB(agentType: string): Promise<number | null>;
34
+ /**
35
+ * Lazy background probe: returns whatever is currently cached, and kicks
36
+ * off a refresh in the background if the cache is stale. First cold call
37
+ * returns `null`; the next catalog poll after the refresh lands will flip
38
+ * to the real value.
39
+ */
40
+ export declare function probeAdapterUpdateAvailable(agentType: string): Promise<boolean | null>;
41
+ /** Timestamp (ms since epoch) when the freshest cached probe completed. */
42
+ export declare function getUpdateCacheLastCheckedAt(): number | null;
43
+ /**
44
+ * Explicit "check updates now" path — backs `POST /api/agent-apps/check-
45
+ * updates`. Bypasses the TTL entirely: if a refresh is already running it
46
+ * awaits it instead of skipping (so the response carries the newest value,
47
+ * not a stale cached null). Runs all targets in parallel.
48
+ */
49
+ export declare function forceRefreshAllAdapterUpdates(agentTypes: string[]): Promise<Record<string, boolean | null>>;
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Probe functions used by `buildCardView` to populate an adapter-backed
3
+ * `AgentAppCardView` — install status, disk size, and update availability.
4
+ *
5
+ * The update probe is the expensive one (needs to reach the upstream
6
+ * registry) so it runs behind a stale-while-revalidate cache: callers see
7
+ * whatever is cached immediately, and a background refresh kicks off when
8
+ * the cache is stale. `forceRefreshAllAdapterUpdates` is the explicit
9
+ * "check updates now" path used by the UI button; it awaits in-flight
10
+ * refreshes instead of skipping them so the button's result reflects the
11
+ * newest state, not the value that was cached at click time.
12
+ */
13
+ import { execFile } from "child_process";
14
+ import { promisify } from "util";
15
+ import { HERMES_DEFAULT_IMAGE, getOpenclawDockerImage, getRuntimeCatalogEntry, } from "../../../config.js";
16
+ import { getAdapter, hasAdapter } from "../../runtime/index.js";
17
+ import { fetchRemoteDigest, parseImageRef } from "./registry-probe.js";
18
+ const execFileAsync = promisify(execFile);
19
+ // ── Image resolution ────────────────────────────────────────────────────
20
+ /**
21
+ * Resolve the docker image an adapter's instances currently run on. Prefers
22
+ * the installed record in panel.json.runtime_catalog; falls back to the
23
+ * adapter's declared default so update checks still work even when the app
24
+ * has been uninstalled (or was never installed through the new flow).
25
+ */
26
+ export function resolveAdapterImage(agentType) {
27
+ if (agentType === "openclaw")
28
+ return getOpenclawDockerImage();
29
+ const entry = getRuntimeCatalogEntry(agentType);
30
+ const fromCatalog = entry?.defaultImage;
31
+ if (typeof fromCatalog === "string" && fromCatalog.trim())
32
+ return fromCatalog;
33
+ // Fallback: hardcoded defaults per adapter. Adapters that want to
34
+ // participate in update checks without a runtime_catalog entry (yet)
35
+ // advertise their default here.
36
+ if (agentType === "hermes")
37
+ return HERMES_DEFAULT_IMAGE;
38
+ return null;
39
+ }
40
+ // ── Status probe ────────────────────────────────────────────────────────
41
+ export async function probeAdapterStatus(agentType) {
42
+ if (!hasAdapter(agentType))
43
+ return null;
44
+ const adapter = getAdapter(agentType);
45
+ if (!adapter.getInstallStatus)
46
+ return null;
47
+ try {
48
+ return (await Promise.race([
49
+ Promise.resolve(adapter.getInstallStatus()),
50
+ new Promise((_, reject) => setTimeout(() => reject(new Error("install-status probe timed out")), 2500)),
51
+ ]));
52
+ }
53
+ catch {
54
+ return null;
55
+ }
56
+ }
57
+ // ── Image size probe ────────────────────────────────────────────────────
58
+ /**
59
+ * Read the disk size (MB, decimal) of the adapter's current docker image.
60
+ * Uses `docker image ls --format {{.Size}}` (same cumulative-layer total
61
+ * admins see in `docker images`) instead of `docker image inspect .Size`
62
+ * which reports dedup'd unique bytes and doesn't match operator
63
+ * expectation.
64
+ */
65
+ export async function probeAdapterImageSizeMB(agentType) {
66
+ const image = resolveAdapterImage(agentType);
67
+ if (!image)
68
+ return null;
69
+ try {
70
+ const { stdout } = await execFileAsync("docker", ["image", "ls", "--format", "{{.Size}}", image], { timeout: 2500, encoding: "utf-8" });
71
+ const firstLine = stdout.split("\n")[0]?.trim();
72
+ if (!firstLine)
73
+ return null;
74
+ return parseDockerSizeToMB(firstLine);
75
+ }
76
+ catch {
77
+ return null;
78
+ }
79
+ }
80
+ /**
81
+ * Parse docker's human-readable size strings ("2.26GB", "593MB", "12.5kB")
82
+ * into megabytes. Docker uses decimal (SI) units for these displays.
83
+ */
84
+ function parseDockerSizeToMB(raw) {
85
+ const m = raw.trim().match(/^(\d+(?:\.\d+)?)\s*(B|kB|MB|GB|TB)$/i);
86
+ if (!m)
87
+ return null;
88
+ const value = parseFloat(m[1]);
89
+ if (!Number.isFinite(value))
90
+ return null;
91
+ const unit = m[2].toLowerCase();
92
+ const mb = unit === "b" ? value / 1_000_000 :
93
+ unit === "kb" ? value / 1_000 :
94
+ unit === "mb" ? value :
95
+ unit === "gb" ? value * 1_000 :
96
+ unit === "tb" ? value * 1_000_000 : NaN;
97
+ return Number.isFinite(mb) ? Math.round(mb) : null;
98
+ }
99
+ const updateCache = new Map();
100
+ const UPDATE_CACHE_TTL_OK_MS = 10 * 60 * 1000;
101
+ const UPDATE_CACHE_TTL_NULL_MS = 60 * 1000;
102
+ /**
103
+ * Read the local RepoDigest sha for the given image — this is what docker
104
+ * recorded when it pulled the tag (the manifest-list's digest for
105
+ * multi-arch images), so it lines up with what the registry HEAD returns.
106
+ */
107
+ async function readLocalDigest(image) {
108
+ try {
109
+ const { stdout } = await execFileAsync("docker", ["image", "inspect", "--format", "{{range .RepoDigests}}{{.}}{{println}}{{end}}", image], { timeout: 5_000, encoding: "utf-8" });
110
+ const line = stdout.split("\n").find((l) => l.includes("@sha256:"));
111
+ const m = line?.match(/@sha256:([a-f0-9]{64})/);
112
+ return m ? m[1] : null;
113
+ }
114
+ catch {
115
+ return null;
116
+ }
117
+ }
118
+ async function readRemoteDigest(image) {
119
+ const ref = parseImageRef(image);
120
+ if (!ref)
121
+ return null;
122
+ return fetchRemoteDigest(ref);
123
+ }
124
+ /**
125
+ * Refresh the update-cache entry for one agentType. Safe to call while a
126
+ * refresh is already in flight — the second caller awaits the same
127
+ * promise instead of starting a duplicate probe.
128
+ */
129
+ function refreshUpdateCache(agentType, image) {
130
+ const cached = updateCache.get(agentType);
131
+ if (cached?.inflight)
132
+ return cached.inflight;
133
+ const t0 = Date.now();
134
+ console.log(`[agent-apps] ${agentType}: probing digest for ${image}`);
135
+ const inflight = (async () => {
136
+ try {
137
+ const [local, remote] = await Promise.all([
138
+ readLocalDigest(image),
139
+ readRemoteDigest(image),
140
+ ]);
141
+ const value = !local || !remote ? null : local !== remote;
142
+ console.log(`[agent-apps] ${agentType}: local=${local?.slice(0, 12) ?? "null"} ` +
143
+ `remote=${remote?.slice(0, 12) ?? "null"} result=${value} (+${Date.now() - t0}ms)`);
144
+ updateCache.set(agentType, { value, at: Date.now() });
145
+ }
146
+ catch (e) {
147
+ console.log(`[agent-apps] ${agentType}: probe error ${e?.message || e} (+${Date.now() - t0}ms)`);
148
+ updateCache.set(agentType, { value: null, at: Date.now() });
149
+ }
150
+ })();
151
+ updateCache.set(agentType, {
152
+ value: cached?.value ?? null,
153
+ at: cached?.at ?? 0,
154
+ inflight,
155
+ });
156
+ // When the async IIFE above writes the final value, the new entry will
157
+ // not carry `inflight`, so subsequent calls will see the fresh state.
158
+ inflight.finally(() => {
159
+ const final = updateCache.get(agentType);
160
+ if (final?.inflight === inflight) {
161
+ updateCache.set(agentType, { value: final.value, at: final.at });
162
+ }
163
+ });
164
+ return inflight;
165
+ }
166
+ /**
167
+ * Lazy background probe: returns whatever is currently cached, and kicks
168
+ * off a refresh in the background if the cache is stale. First cold call
169
+ * returns `null`; the next catalog poll after the refresh lands will flip
170
+ * to the real value.
171
+ */
172
+ export async function probeAdapterUpdateAvailable(agentType) {
173
+ const image = resolveAdapterImage(agentType);
174
+ if (!image)
175
+ return null;
176
+ const cached = updateCache.get(agentType);
177
+ const now = Date.now();
178
+ const ttl = cached?.value == null ? UPDATE_CACHE_TTL_NULL_MS : UPDATE_CACHE_TTL_OK_MS;
179
+ const stale = !cached || now - cached.at > ttl;
180
+ if (stale && !cached?.inflight) {
181
+ refreshUpdateCache(agentType, image).catch(() => {
182
+ // swallowed — refreshUpdateCache writes a null entry on its own
183
+ });
184
+ }
185
+ return cached?.value ?? null;
186
+ }
187
+ /** Timestamp (ms since epoch) when the freshest cached probe completed. */
188
+ export function getUpdateCacheLastCheckedAt() {
189
+ let latest = 0;
190
+ for (const entry of updateCache.values()) {
191
+ if (entry.at > latest)
192
+ latest = entry.at;
193
+ }
194
+ return latest > 0 ? latest : null;
195
+ }
196
+ /**
197
+ * Explicit "check updates now" path — backs `POST /api/agent-apps/check-
198
+ * updates`. Bypasses the TTL entirely: if a refresh is already running it
199
+ * awaits it instead of skipping (so the response carries the newest value,
200
+ * not a stale cached null). Runs all targets in parallel.
201
+ */
202
+ export async function forceRefreshAllAdapterUpdates(agentTypes) {
203
+ const targets = [];
204
+ for (const agentType of agentTypes) {
205
+ const image = resolveAdapterImage(agentType);
206
+ if (image)
207
+ targets.push({ agentType, image });
208
+ }
209
+ await Promise.all(targets.map(({ agentType, image }) => {
210
+ const cached = updateCache.get(agentType);
211
+ // Already refreshing → wait for it. Otherwise start a fresh probe
212
+ // even if the TTL hasn't expired (user explicitly asked for a check).
213
+ if (cached?.inflight)
214
+ return cached.inflight;
215
+ return refreshUpdateCache(agentType, image);
216
+ }));
217
+ const out = {};
218
+ for (const { agentType } of targets) {
219
+ out[agentType] = updateCache.get(agentType)?.value ?? null;
220
+ }
221
+ return out;
222
+ }
223
+ //# sourceMappingURL=adapter-probes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-probes.js","sourceRoot":"","sources":["../../../../src/services/agent-apps/installers/adapter-probes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Installer strategy for adapter-backed agent apps (hermes, openclaw).
3
+ *
4
+ * Delegates install to `adapter.startBuildRuntimeImage` (preferred when
5
+ * present — openclaw builds its image locally) or
6
+ * `adapter.startInstallRuntime` (hermes pulls from GHCR). Uninstall runs
7
+ * locally here (docker image rm + clear runtime_catalog + drop shim).
8
+ *
9
+ * Probe + cache logic lives in `adapter-probes.ts`; this file re-exports
10
+ * the probes so callers import one entry point.
11
+ */
12
+ import type { InstallStartResult } from "../types.js";
13
+ export { forceRefreshAllAdapterUpdates, getUpdateCacheLastCheckedAt, probeAdapterImageSizeMB, probeAdapterStatus, probeAdapterUpdateAvailable, resolveAdapterImage, } from "./adapter-probes.js";
14
+ export declare function startAdapterInstall(agentType: string, options?: Record<string, any>): Promise<InstallStartResult>;
15
+ export declare function startAdapterUninstall(agentType: string): InstallStartResult;
16
+ /**
17
+ * Current running task for this agentType. Returns both the id and the
18
+ * kind so the UI can render "安装中" vs "卸载中" from one field instead
19
+ * of having to guess from task name shape.
20
+ *
21
+ * Install tasks match by prefix (`openclaw`, `openclaw-docker-pull`,
22
+ * `hermes`). Uninstall tasks use the disjoint `uninstall-${agentType}`
23
+ * name so no prefix collision is possible.
24
+ */
25
+ export declare function findRunningAdapterTask(agentType: string): {
26
+ id: string;
27
+ kind: "install" | "uninstall";
28
+ } | undefined;
29
+ /** Count live instances bound to this agentType — used to block uninstall. */
30
+ export declare function countInstancesUsingAgentType(agentType: string): number;