jishushell 0.6.5 → 0.6.18

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 (998) hide show
  1. package/apps/anythingllm-container.yaml +15 -170
  2. package/apps/browserless-chromium-container.yaml +15 -10
  3. package/apps/filebrowser-container.yaml +14 -9
  4. package/apps/hermes-container.yaml +23 -2
  5. package/apps/jishu-kb-container.yaml +29 -161
  6. package/apps/ollama-binary.yaml +32 -28
  7. package/apps/ollama-cpu-container.yaml +5 -0
  8. package/apps/ollama-with-hollama-binary.yaml +33 -28
  9. package/apps/openclaw-binary.yaml +34 -10
  10. package/apps/openclaw-container.yaml +31 -7
  11. package/apps/openclaw-with-ollama-container.yaml +8 -2
  12. package/apps/openclaw-with-searxng-container.yaml +18 -6
  13. package/apps/searxng-container.yaml +11 -6
  14. package/apps/weknora-container.yaml +21 -21
  15. package/dependencies/jishushell-panel-0.6.18.tgz +0 -0
  16. package/dist/cli/app.js +244 -213
  17. package/dist/cli/app.js.map +1 -1
  18. package/dist/cli/backup.js +15 -12
  19. package/dist/cli/backup.js.map +1 -1
  20. package/dist/cli/core.d.ts +4 -3
  21. package/dist/cli/core.js +392 -227
  22. package/dist/cli/core.js.map +1 -1
  23. package/dist/cli/doctor.d.ts +1 -1
  24. package/dist/cli/doctor.js +17 -10
  25. package/dist/cli/doctor.js.map +1 -1
  26. package/dist/cli/job.js +62 -14
  27. package/dist/cli/job.js.map +1 -1
  28. package/dist/cli/llm.js +80 -11
  29. package/dist/cli/llm.js.map +1 -1
  30. package/dist/cli/managed-list.d.ts +1 -3
  31. package/dist/cli/managed-list.js +18 -16
  32. package/dist/cli/managed-list.js.map +1 -1
  33. package/dist/cli/migrate.d.ts +2 -0
  34. package/dist/cli/migrate.js +160 -0
  35. package/dist/cli/migrate.js.map +1 -0
  36. package/dist/cli.js +1 -0
  37. package/dist/cli.js.map +1 -1
  38. package/dist/config.d.ts +23 -19
  39. package/dist/config.js +60 -49
  40. package/dist/config.js.map +1 -1
  41. package/dist/control.d.ts +6 -6
  42. package/dist/control.js +31 -23
  43. package/dist/control.js.map +1 -1
  44. package/dist/core.d.ts +5 -5
  45. package/dist/core.js +5 -5
  46. package/dist/core.js.map +1 -1
  47. package/dist/install.d.ts +2 -2
  48. package/dist/install.js +18 -18
  49. package/dist/install.js.map +1 -1
  50. package/dist/routes/apps.d.ts +1 -1
  51. package/dist/routes/apps.js +101 -193
  52. package/dist/routes/apps.js.map +1 -1
  53. package/dist/routes/auth.js +1 -1
  54. package/dist/routes/auth.js.map +1 -1
  55. package/dist/routes/backup.js +1 -1
  56. package/dist/routes/backup.js.map +1 -1
  57. package/dist/routes/external-mounts.d.ts +1 -1
  58. package/dist/routes/external-mounts.js +1 -1
  59. package/dist/routes/external-mounts.js.map +1 -1
  60. package/dist/routes/file-mounts.d.ts +4 -3
  61. package/dist/routes/file-mounts.js +51 -30
  62. package/dist/routes/file-mounts.js.map +1 -1
  63. package/dist/routes/files-organize.d.ts +2 -2
  64. package/dist/routes/files-organize.js +5 -5
  65. package/dist/routes/files-organize.js.map +1 -1
  66. package/dist/routes/files.d.ts +1 -1
  67. package/dist/routes/files.js +1 -1
  68. package/dist/routes/files.js.map +1 -1
  69. package/dist/routes/instances.d.ts +10 -4
  70. package/dist/routes/instances.js +323 -541
  71. package/dist/routes/instances.js.map +1 -1
  72. package/dist/routes/integration-apps.d.ts +14 -0
  73. package/dist/routes/integration-apps.js +81 -0
  74. package/dist/routes/integration-apps.js.map +1 -0
  75. package/dist/routes/integrations.d.ts +9 -0
  76. package/dist/routes/integrations.js +12 -0
  77. package/dist/routes/integrations.js.map +1 -0
  78. package/dist/routes/llm-proxy.js +26 -3
  79. package/dist/routes/llm-proxy.js.map +1 -1
  80. package/dist/routes/setup.js +53 -38
  81. package/dist/routes/setup.js.map +1 -1
  82. package/dist/routes/system.js +108 -68
  83. package/dist/routes/system.js.map +1 -1
  84. package/dist/routes/webdav.d.ts +1 -1
  85. package/dist/routes/webdav.js +2 -2
  86. package/dist/routes/webdav.js.map +1 -1
  87. package/dist/server.js +315 -213
  88. package/dist/server.js.map +1 -1
  89. package/dist/services/app-common/app-compiler.js +186 -0
  90. package/dist/services/app-common/app-compiler.js.map +1 -0
  91. package/dist/services/app-common/app-shared.d.ts +15 -0
  92. package/dist/services/app-common/app-shared.js +64 -0
  93. package/dist/services/app-common/app-shared.js.map +1 -0
  94. package/dist/services/app-common/capability-service.d.ts +45 -0
  95. package/dist/services/app-common/capability-service.js +331 -0
  96. package/dist/services/app-common/capability-service.js.map +1 -0
  97. package/dist/services/app-common/catalog-service.d.ts +59 -0
  98. package/dist/services/app-common/catalog-service.js +308 -0
  99. package/dist/services/app-common/catalog-service.js.map +1 -0
  100. package/dist/services/app-common/create-pipeline.d.ts +26 -0
  101. package/dist/services/app-common/create-pipeline.js +298 -0
  102. package/dist/services/app-common/create-pipeline.js.map +1 -0
  103. package/dist/services/app-common/delete-service.d.ts +5 -0
  104. package/dist/services/app-common/delete-service.js +104 -0
  105. package/dist/services/app-common/delete-service.js.map +1 -0
  106. package/dist/services/app-common/execution-owner.d.ts +23 -0
  107. package/dist/services/app-common/execution-owner.js +124 -0
  108. package/dist/services/app-common/execution-owner.js.map +1 -0
  109. package/dist/services/app-common/execution-service.d.ts +23 -0
  110. package/dist/services/app-common/execution-service.js +105 -0
  111. package/dist/services/app-common/execution-service.js.map +1 -0
  112. package/dist/services/app-common/id-normalizer.d.ts +31 -0
  113. package/dist/services/app-common/id-normalizer.js +83 -0
  114. package/dist/services/app-common/id-normalizer.js.map +1 -0
  115. package/dist/services/app-common/install-store.d.ts +34 -0
  116. package/dist/services/app-common/install-store.js +261 -0
  117. package/dist/services/app-common/install-store.js.map +1 -0
  118. package/dist/services/app-common/instance-store.d.ts +78 -0
  119. package/dist/services/app-common/instance-store.js +495 -0
  120. package/dist/services/app-common/instance-store.js.map +1 -0
  121. package/dist/services/app-common/integration-refs.d.ts +17 -0
  122. package/dist/services/app-common/integration-refs.js +47 -0
  123. package/dist/services/app-common/integration-refs.js.map +1 -0
  124. package/dist/services/app-common/lifecycle-pipeline.d.ts +62 -0
  125. package/dist/services/app-common/lifecycle-pipeline.js +317 -0
  126. package/dist/services/app-common/lifecycle-pipeline.js.map +1 -0
  127. package/dist/services/app-common/lifecycle-scripts.d.ts +38 -0
  128. package/dist/services/app-common/lifecycle-scripts.js +935 -0
  129. package/dist/services/app-common/lifecycle-scripts.js.map +1 -0
  130. package/dist/services/app-common/lifecycle-service.d.ts +68 -0
  131. package/dist/services/app-common/lifecycle-service.js +467 -0
  132. package/dist/services/app-common/lifecycle-service.js.map +1 -0
  133. package/dist/services/app-common/paths.d.ts +29 -0
  134. package/dist/services/app-common/paths.js +34 -0
  135. package/dist/services/app-common/paths.js.map +1 -0
  136. package/dist/services/app-common/platform-transform.d.ts +32 -0
  137. package/dist/services/app-common/platform-transform.js +65 -0
  138. package/dist/services/app-common/platform-transform.js.map +1 -0
  139. package/dist/services/app-common/provide-resolver.d.ts +29 -0
  140. package/dist/services/app-common/provide-resolver.js +129 -0
  141. package/dist/services/app-common/provide-resolver.js.map +1 -0
  142. package/dist/services/app-common/remote-spec.d.ts +14 -0
  143. package/dist/services/app-common/remote-spec.js +58 -0
  144. package/dist/services/app-common/remote-spec.js.map +1 -0
  145. package/dist/services/app-common/runtime-builder.d.ts +1 -0
  146. package/dist/services/app-common/runtime-builder.js +2 -0
  147. package/dist/services/app-common/runtime-builder.js.map +1 -0
  148. package/dist/services/app-common/runtime-facts.d.ts +19 -0
  149. package/dist/services/app-common/runtime-facts.js +126 -0
  150. package/dist/services/app-common/runtime-facts.js.map +1 -0
  151. package/dist/services/app-common/service.d.ts +9 -0
  152. package/dist/services/app-common/service.js +10 -0
  153. package/dist/services/app-common/service.js.map +1 -0
  154. package/dist/services/app-common/spec-materializer.d.ts +9 -0
  155. package/dist/services/app-common/spec-materializer.js +361 -0
  156. package/dist/services/app-common/spec-materializer.js.map +1 -0
  157. package/dist/services/app-common/status-refresh.d.ts +33 -0
  158. package/dist/services/app-common/status-refresh.js +759 -0
  159. package/dist/services/app-common/status-refresh.js.map +1 -0
  160. package/dist/services/app-common/task-service.d.ts +29 -0
  161. package/dist/services/app-common/task-service.js +93 -0
  162. package/dist/services/app-common/task-service.js.map +1 -0
  163. package/dist/services/app-common/terminal-session-manager.js +157 -0
  164. package/dist/services/app-common/terminal-session-manager.js.map +1 -0
  165. package/dist/services/app-modules/browserless/routes.d.ts +9 -0
  166. package/dist/services/app-modules/browserless/routes.js +517 -0
  167. package/dist/services/app-modules/browserless/routes.js.map +1 -0
  168. package/dist/services/app-modules/routes.d.ts +2 -0
  169. package/dist/services/app-modules/routes.js +5 -0
  170. package/dist/services/app-modules/routes.js.map +1 -0
  171. package/dist/services/backup/backup-admin.d.ts +95 -0
  172. package/dist/services/backup/backup-admin.js +246 -0
  173. package/dist/services/backup/backup-admin.js.map +1 -0
  174. package/dist/services/backup/backup-manager.d.ts +264 -0
  175. package/dist/services/backup/backup-manager.js +2318 -0
  176. package/dist/services/backup/backup-manager.js.map +1 -0
  177. package/dist/services/backup/backup-verify.js +240 -0
  178. package/dist/services/backup/backup-verify.js.map +1 -0
  179. package/dist/services/capabilities/browser-policy.d.ts +14 -0
  180. package/dist/services/capabilities/browser-policy.js +141 -0
  181. package/dist/services/capabilities/browser-policy.js.map +1 -0
  182. package/dist/services/capabilities/contract.d.ts +50 -0
  183. package/dist/services/capabilities/contract.js +129 -0
  184. package/dist/services/capabilities/contract.js.map +1 -0
  185. package/dist/services/capabilities/endpoint-validator.d.ts +42 -0
  186. package/dist/services/capabilities/endpoint-validator.js +114 -0
  187. package/dist/services/capabilities/endpoint-validator.js.map +1 -0
  188. package/dist/services/capabilities/health.d.ts +16 -0
  189. package/dist/services/capabilities/health.js +121 -0
  190. package/dist/services/capabilities/health.js.map +1 -0
  191. package/dist/services/capabilities/registry.d.ts +56 -0
  192. package/dist/services/capabilities/registry.js +222 -0
  193. package/dist/services/capabilities/registry.js.map +1 -0
  194. package/dist/services/capabilities/sync.d.ts +7 -0
  195. package/dist/services/capabilities/sync.js +223 -0
  196. package/dist/services/capabilities/sync.js.map +1 -0
  197. package/dist/services/capability-proxy/html-rewriters/browserless.d.ts +1 -0
  198. package/dist/services/capability-proxy/html-rewriters/browserless.js +83 -0
  199. package/dist/services/capability-proxy/html-rewriters/browserless.js.map +1 -0
  200. package/dist/services/capability-proxy/html-rewriters/index.d.ts +12 -0
  201. package/dist/services/capability-proxy/html-rewriters/index.js +25 -0
  202. package/dist/services/capability-proxy/html-rewriters/index.js.map +1 -0
  203. package/dist/services/capability-proxy/html-rewriters/jishukb.d.ts +1 -0
  204. package/dist/services/capability-proxy/html-rewriters/jishukb.js +161 -0
  205. package/dist/services/capability-proxy/html-rewriters/jishukb.js.map +1 -0
  206. package/dist/services/connections/admin.d.ts +80 -0
  207. package/dist/services/connections/admin.js +327 -0
  208. package/dist/services/connections/admin.js.map +1 -0
  209. package/dist/services/connections/apply.d.ts +110 -0
  210. package/dist/services/connections/apply.js +444 -0
  211. package/dist/services/connections/apply.js.map +1 -0
  212. package/dist/services/connections/resolver.d.ts +82 -0
  213. package/dist/services/connections/resolver.js +289 -0
  214. package/dist/services/connections/resolver.js.map +1 -0
  215. package/dist/services/connections/suggestions.d.ts +27 -0
  216. package/dist/services/connections/suggestions.js +124 -0
  217. package/dist/services/connections/suggestions.js.map +1 -0
  218. package/dist/services/connections/transactor.d.ts +39 -0
  219. package/dist/services/connections/transactor.js +307 -0
  220. package/dist/services/connections/transactor.js.map +1 -0
  221. package/dist/services/files/external-mounts.js +187 -0
  222. package/dist/services/files/external-mounts.js.map +1 -0
  223. package/dist/services/files/files-manager.d.ts +265 -0
  224. package/dist/services/files/files-manager.js +1189 -0
  225. package/dist/services/files/files-manager.js.map +1 -0
  226. package/dist/services/files/files-mounts.d.ts +42 -0
  227. package/dist/services/files/files-mounts.js +207 -0
  228. package/dist/services/files/files-mounts.js.map +1 -0
  229. package/dist/services/files/organize/applier.js +218 -0
  230. package/dist/services/files/organize/applier.js.map +1 -0
  231. package/dist/services/files/organize/rules.js +286 -0
  232. package/dist/services/files/organize/rules.js.map +1 -0
  233. package/dist/services/files/organize/scanner.js +366 -0
  234. package/dist/services/files/organize/scanner.js.map +1 -0
  235. package/dist/services/files/organize/store.js +82 -0
  236. package/dist/services/files/organize/store.js.map +1 -0
  237. package/dist/services/files/webdav/server.d.ts +47 -0
  238. package/dist/services/files/webdav/server.js +329 -0
  239. package/dist/services/files/webdav/server.js.map +1 -0
  240. package/dist/services/files/webdav/xml-builder.js.map +1 -0
  241. package/dist/services/instances/admin.d.ts +23 -0
  242. package/dist/services/instances/admin.js +218 -0
  243. package/dist/services/instances/admin.js.map +1 -0
  244. package/dist/services/instances/clone.d.ts +26 -0
  245. package/dist/services/instances/clone.js +78 -0
  246. package/dist/services/instances/clone.js.map +1 -0
  247. package/dist/services/instances/config-admin.d.ts +17 -0
  248. package/dist/services/instances/config-admin.js +181 -0
  249. package/dist/services/instances/config-admin.js.map +1 -0
  250. package/dist/services/instances/manager.d.ts +231 -0
  251. package/dist/services/instances/manager.js +1348 -0
  252. package/dist/services/instances/manager.js.map +1 -0
  253. package/dist/services/instances/passwords.js +173 -0
  254. package/dist/services/instances/passwords.js.map +1 -0
  255. package/dist/services/instances/types.d.ts +21 -0
  256. package/dist/services/instances/types.js +2 -0
  257. package/dist/services/instances/types.js.map +1 -0
  258. package/dist/services/integrations/anythingllm/integration.d.ts +25 -0
  259. package/dist/services/integrations/anythingllm/integration.js +251 -0
  260. package/dist/services/integrations/anythingllm/integration.js.map +1 -0
  261. package/dist/services/integrations/catalog.d.ts +3 -0
  262. package/dist/services/integrations/catalog.js +73 -0
  263. package/dist/services/integrations/catalog.js.map +1 -0
  264. package/dist/services/integrations/custom/integration.d.ts +28 -0
  265. package/dist/services/integrations/custom/integration.js +179 -0
  266. package/dist/services/integrations/custom/integration.js.map +1 -0
  267. package/dist/services/integrations/hermes/integration.d.ts +194 -0
  268. package/dist/services/integrations/hermes/integration.js +1669 -0
  269. package/dist/services/integrations/hermes/integration.js.map +1 -0
  270. package/dist/services/integrations/index.d.ts +40 -0
  271. package/dist/services/integrations/index.js +59 -0
  272. package/dist/services/integrations/index.js.map +1 -0
  273. package/dist/services/integrations/installable/catalog.d.ts +33 -0
  274. package/dist/services/integrations/installable/catalog.js +88 -0
  275. package/dist/services/integrations/installable/catalog.js.map +1 -0
  276. package/dist/services/integrations/installable/index.d.ts +35 -0
  277. package/dist/services/integrations/installable/index.js +170 -0
  278. package/dist/services/integrations/installable/index.js.map +1 -0
  279. package/dist/services/integrations/installable/installers/integration-probes.d.ts +50 -0
  280. package/dist/services/integrations/installable/installers/integration-probes.js +231 -0
  281. package/dist/services/integrations/installable/installers/integration-probes.js.map +1 -0
  282. package/dist/services/integrations/installable/installers/integration.d.ts +30 -0
  283. package/dist/services/integrations/installable/installers/integration.js +177 -0
  284. package/dist/services/integrations/installable/installers/integration.js.map +1 -0
  285. package/dist/services/integrations/installable/installers/registry-probe.js.map +1 -0
  286. package/dist/services/integrations/installable/installers/shell-script.d.ts +46 -0
  287. package/dist/services/integrations/installable/installers/shell-script.js +487 -0
  288. package/dist/services/integrations/installable/installers/shell-script.js.map +1 -0
  289. package/dist/services/integrations/installable/types.d.ts +130 -0
  290. package/dist/services/integrations/installable/types.js +19 -0
  291. package/dist/services/integrations/installable/types.js.map +1 -0
  292. package/dist/services/integrations/jishukb/integration.d.ts +22 -0
  293. package/dist/services/integrations/jishukb/integration.js +189 -0
  294. package/dist/services/integrations/jishukb/integration.js.map +1 -0
  295. package/dist/services/integrations/openclaw/anythingllm-shim.d.ts +46 -0
  296. package/dist/services/integrations/openclaw/anythingllm-shim.js +281 -0
  297. package/dist/services/integrations/openclaw/anythingllm-shim.js.map +1 -0
  298. package/dist/services/integrations/openclaw/drive-shim.js +490 -0
  299. package/dist/services/integrations/openclaw/drive-shim.js.map +1 -0
  300. package/dist/services/integrations/openclaw/integration.d.ts +424 -0
  301. package/dist/services/integrations/openclaw/integration.js +4402 -0
  302. package/dist/services/integrations/openclaw/integration.js.map +1 -0
  303. package/dist/services/integrations/openclaw/jishukb-shim.d.ts +48 -0
  304. package/dist/services/integrations/openclaw/jishukb-shim.js +750 -0
  305. package/dist/services/integrations/openclaw/jishukb-shim.js.map +1 -0
  306. package/dist/services/integrations/openclaw/mcporter-lite.js +276 -0
  307. package/dist/services/integrations/openclaw/mcporter-lite.js.map +1 -0
  308. package/dist/services/integrations/openclaw/mcporter.d.ts +46 -0
  309. package/dist/services/integrations/openclaw/mcporter.js +112 -0
  310. package/dist/services/integrations/openclaw/mcporter.js.map +1 -0
  311. package/dist/services/integrations/openclaw/routes.d.ts +21 -0
  312. package/dist/services/integrations/openclaw/routes.js +1191 -0
  313. package/dist/services/integrations/openclaw/routes.js.map +1 -0
  314. package/dist/services/integrations/registry.d.ts +17 -0
  315. package/dist/services/integrations/registry.js +36 -0
  316. package/dist/services/integrations/registry.js.map +1 -0
  317. package/dist/services/integrations/routes.d.ts +2 -0
  318. package/dist/services/integrations/routes.js +9 -0
  319. package/dist/services/integrations/routes.js.map +1 -0
  320. package/dist/services/integrations/types.d.ts +469 -0
  321. package/dist/services/integrations/types.js +2 -0
  322. package/dist/services/integrations/types.js.map +1 -0
  323. package/dist/services/legacy-migrator/classifier.d.ts +44 -0
  324. package/dist/services/legacy-migrator/classifier.js +309 -0
  325. package/dist/services/legacy-migrator/classifier.js.map +1 -0
  326. package/dist/services/legacy-migrator/executor.d.ts +42 -0
  327. package/dist/services/legacy-migrator/executor.js +637 -0
  328. package/dist/services/legacy-migrator/executor.js.map +1 -0
  329. package/dist/services/legacy-migrator/index.d.ts +31 -0
  330. package/dist/services/legacy-migrator/index.js +34 -0
  331. package/dist/services/legacy-migrator/index.js.map +1 -0
  332. package/dist/services/legacy-migrator/planner.d.ts +8 -0
  333. package/dist/services/legacy-migrator/planner.js +154 -0
  334. package/dist/services/legacy-migrator/planner.js.map +1 -0
  335. package/dist/services/legacy-migrator/provider-settings.d.ts +6 -0
  336. package/dist/services/legacy-migrator/provider-settings.js +72 -0
  337. package/dist/services/legacy-migrator/provider-settings.js.map +1 -0
  338. package/dist/services/legacy-migrator/report.d.ts +9 -0
  339. package/dist/services/legacy-migrator/report.js +99 -0
  340. package/dist/services/legacy-migrator/report.js.map +1 -0
  341. package/dist/services/legacy-migrator/scanner.d.ts +13 -0
  342. package/dist/services/legacy-migrator/scanner.js +157 -0
  343. package/dist/services/legacy-migrator/scanner.js.map +1 -0
  344. package/dist/services/legacy-migrator/types.d.ts +97 -0
  345. package/dist/services/legacy-migrator/types.js +23 -0
  346. package/dist/services/legacy-migrator/types.js.map +1 -0
  347. package/dist/services/llm-proxy/instance-proxy.d.ts +17 -1
  348. package/dist/services/llm-proxy/instance-proxy.js +171 -44
  349. package/dist/services/llm-proxy/instance-proxy.js.map +1 -1
  350. package/dist/services/llm-proxy/probe.js +5 -14
  351. package/dist/services/llm-proxy/probe.js.map +1 -1
  352. package/dist/services/llm-proxy/providers.js +23 -31
  353. package/dist/services/llm-proxy/providers.js.map +1 -1
  354. package/dist/services/llm-proxy/ssrf.d.ts +11 -4
  355. package/dist/services/llm-proxy/ssrf.js +45 -7
  356. package/dist/services/llm-proxy/ssrf.js.map +1 -1
  357. package/dist/services/llm-proxy/validate-key.js +16 -37
  358. package/dist/services/llm-proxy/validate-key.js.map +1 -1
  359. package/dist/services/repair/runtime-repair.d.ts +22 -0
  360. package/dist/services/repair/runtime-repair.js +307 -0
  361. package/dist/services/repair/runtime-repair.js.map +1 -0
  362. package/dist/services/runtime/driver-registry.d.ts +21 -0
  363. package/dist/services/runtime/driver-registry.js +22 -0
  364. package/dist/services/runtime/driver-registry.js.map +1 -0
  365. package/dist/services/runtime/drivers/nomad.d.ts +260 -0
  366. package/dist/services/runtime/drivers/nomad.js +3092 -0
  367. package/dist/services/runtime/drivers/nomad.js.map +1 -0
  368. package/dist/services/runtime/errors.d.ts +3 -3
  369. package/dist/services/runtime/errors.js +3 -3
  370. package/dist/services/runtime/instance.d.ts +14 -16
  371. package/dist/services/runtime/instance.js +93 -123
  372. package/dist/services/runtime/instance.js.map +1 -1
  373. package/dist/services/runtime/job-id.d.ts +1 -1
  374. package/dist/services/runtime/job-id.js +1 -1
  375. package/dist/services/runtime/mcp-shims/firewall.d.ts +2 -2
  376. package/dist/services/runtime/mcp-shims/firewall.js +2 -2
  377. package/dist/services/runtime/mcp-shims/searxng-shim.d.ts +3 -5
  378. package/dist/services/runtime/mcp-shims/searxng-shim.js +3 -5
  379. package/dist/services/runtime/mcp-shims/searxng-shim.js.map +1 -1
  380. package/dist/services/runtime/mcp-shims/write-mcp-entry.d.ts +20 -20
  381. package/dist/services/runtime/mcp-shims/write-mcp-entry.js +16 -16
  382. package/dist/services/runtime/mcp-shims/write-mcp-entry.js.map +1 -1
  383. package/dist/services/runtime/ownership-marker.d.ts +83 -0
  384. package/dist/services/runtime/ownership-marker.js +109 -0
  385. package/dist/services/runtime/ownership-marker.js.map +1 -0
  386. package/dist/services/runtime/types.d.ts +22 -501
  387. package/dist/services/runtime/types.js +0 -12
  388. package/dist/services/runtime/types.js.map +1 -1
  389. package/dist/services/runtime/workload-compiler.d.ts +17 -0
  390. package/dist/services/runtime/workload-compiler.js +525 -0
  391. package/dist/services/runtime/workload-compiler.js.map +1 -0
  392. package/dist/services/runtime/workload-types.d.ts +11 -0
  393. package/dist/services/runtime/workload-types.js +2 -0
  394. package/dist/services/runtime/workload-types.js.map +1 -0
  395. package/dist/services/setup/core-manager.d.ts +50 -0
  396. package/dist/services/setup/core-manager.js +456 -0
  397. package/dist/services/setup/core-manager.js.map +1 -0
  398. package/dist/services/setup/plugin-installer.js +136 -0
  399. package/dist/services/setup/plugin-installer.js.map +1 -0
  400. package/dist/services/setup/setup-manager.d.ts +158 -0
  401. package/dist/services/setup/setup-manager.js +2768 -0
  402. package/dist/services/setup/setup-manager.js.map +1 -0
  403. package/dist/services/system/cli-command.d.ts +5 -0
  404. package/dist/services/system/cli-command.js +18 -0
  405. package/dist/services/system/cli-command.js.map +1 -0
  406. package/dist/services/system/macos-launchd.js +312 -0
  407. package/dist/services/system/macos-launchd.js.map +1 -0
  408. package/dist/services/system/repair-orchestrator.d.ts +71 -0
  409. package/dist/services/system/repair-orchestrator.js +412 -0
  410. package/dist/services/system/repair-orchestrator.js.map +1 -0
  411. package/dist/services/system/system-monitor.js +96 -0
  412. package/dist/services/system/system-monitor.js.map +1 -0
  413. package/dist/services/system/system-ollama-provider.d.ts +14 -0
  414. package/dist/services/system/system-ollama-provider.js +129 -0
  415. package/dist/services/system/system-ollama-provider.js.map +1 -0
  416. package/dist/services/system/system-reconciler.d.ts +59 -0
  417. package/dist/services/system/system-reconciler.js +710 -0
  418. package/dist/services/system/system-reconciler.js.map +1 -0
  419. package/dist/services/system/update-manager.d.ts +43 -0
  420. package/dist/services/system/update-manager.js +315 -0
  421. package/dist/services/system/update-manager.js.map +1 -0
  422. package/dist/services/system/upgrade-finalize.d.ts +80 -0
  423. package/dist/services/system/upgrade-finalize.js +507 -0
  424. package/dist/services/system/upgrade-finalize.js.map +1 -0
  425. package/dist/services/tasks/registry.d.ts +44 -0
  426. package/dist/services/tasks/registry.js +90 -0
  427. package/dist/services/tasks/registry.js.map +1 -0
  428. package/dist/services/telemetry/activation.d.ts +6 -2
  429. package/dist/services/telemetry/activation.js +6 -2
  430. package/dist/services/telemetry/activation.js.map +1 -1
  431. package/dist/services/telemetry/heartbeat.d.ts +6 -2
  432. package/dist/services/telemetry/heartbeat.js +6 -2
  433. package/dist/services/telemetry/heartbeat.js.map +1 -1
  434. package/dist/services/workspaces/builder.d.ts +29 -0
  435. package/dist/services/workspaces/builder.js +186 -0
  436. package/dist/services/workspaces/builder.js.map +1 -0
  437. package/dist/types.d.ts +331 -45
  438. package/dist/utils/instance-lock.d.ts +2 -2
  439. package/dist/utils/instance-lock.js +2 -2
  440. package/install/jishu-install.sh +107 -26
  441. package/install/jishu-uninstall.sh +8 -0
  442. package/install/post-install.sh +162 -185
  443. package/install/post-uninstall.sh +6 -0
  444. package/node_modules/@fastify/static/.github/workflows/ci.yml +1 -1
  445. package/node_modules/@fastify/static/.github/workflows/lock-threads.yml +19 -0
  446. package/node_modules/@fastify/static/LICENSE +1 -3
  447. package/node_modules/@fastify/static/example/server-benchmark.js +39 -0
  448. package/node_modules/@fastify/static/index.js +169 -23
  449. package/node_modules/@fastify/static/lib/dirList.js +20 -6
  450. package/node_modules/@fastify/static/package.json +10 -8
  451. package/node_modules/@fastify/static/test/dir-list.test.js +82 -0
  452. package/node_modules/@fastify/static/test/static.test.js +326 -4
  453. package/node_modules/@fastify/static/types/index.d.ts +0 -4
  454. package/node_modules/@fastify/static/types/index.test-d.ts +1 -1
  455. package/node_modules/content-disposition/README.md +21 -22
  456. package/node_modules/content-disposition/index.js +122 -44
  457. package/node_modules/content-disposition/package.json +16 -20
  458. package/node_modules/glob/README.md +39 -130
  459. package/node_modules/glob/dist/commonjs/glob.d.ts +8 -0
  460. package/node_modules/glob/dist/commonjs/glob.d.ts.map +1 -1
  461. package/node_modules/glob/dist/commonjs/glob.js +2 -1
  462. package/node_modules/glob/dist/commonjs/glob.js.map +1 -1
  463. package/node_modules/glob/dist/commonjs/index.min.js +4 -0
  464. package/node_modules/glob/dist/commonjs/index.min.js.map +7 -0
  465. package/node_modules/glob/dist/commonjs/pattern.d.ts +3 -0
  466. package/node_modules/glob/dist/commonjs/pattern.d.ts.map +1 -1
  467. package/node_modules/glob/dist/commonjs/pattern.js +4 -0
  468. package/node_modules/glob/dist/commonjs/pattern.js.map +1 -1
  469. package/node_modules/glob/dist/esm/glob.d.ts +8 -0
  470. package/node_modules/glob/dist/esm/glob.d.ts.map +1 -1
  471. package/node_modules/glob/dist/esm/glob.js +2 -1
  472. package/node_modules/glob/dist/esm/glob.js.map +1 -1
  473. package/node_modules/glob/dist/esm/index.min.js +4 -0
  474. package/node_modules/glob/dist/esm/index.min.js.map +7 -0
  475. package/node_modules/glob/dist/esm/pattern.d.ts +3 -0
  476. package/node_modules/glob/dist/esm/pattern.d.ts.map +1 -1
  477. package/node_modules/glob/dist/esm/pattern.js +4 -0
  478. package/node_modules/glob/dist/esm/pattern.js.map +1 -1
  479. package/node_modules/glob/package.json +38 -37
  480. package/node_modules/jishushell-panel/README.md +4 -4
  481. package/node_modules/jishushell-panel/output/dist/server.js +17 -6
  482. package/node_modules/jishushell-panel/output/dist/server.js.map +1 -1
  483. package/node_modules/jishushell-panel/output/public/assets/ApiKeyField-NKcbHjNz.js +1 -0
  484. package/node_modules/jishushell-panel/output/public/assets/Dashboard-Da1fL38t.js +1 -0
  485. package/node_modules/jishushell-panel/output/public/assets/HermesChatPanel-DZvmYsoh.js +1 -0
  486. package/node_modules/jishushell-panel/output/public/assets/HermesConfigForm-BLUWlKwm.js +4 -0
  487. package/node_modules/jishushell-panel/output/public/assets/InitPassword-BAKsshzk.js +1 -0
  488. package/node_modules/jishushell-panel/output/public/assets/InstanceDetail-Dgyc_TX5.js +14 -0
  489. package/node_modules/jishushell-panel/output/public/assets/Login-DHeOmwI8.js +1 -0
  490. package/node_modules/jishushell-panel/output/public/assets/NewInstance-CIy0cYtp.js +1 -0
  491. package/node_modules/jishushell-panel/output/public/assets/ProviderRecommendations-H0ByEYF0.js +1 -0
  492. package/node_modules/jishushell-panel/output/public/assets/Settings-DAT-UMfP.js +1 -0
  493. package/node_modules/jishushell-panel/output/public/assets/Setup-g3uckFYR.js +1 -0
  494. package/node_modules/jishushell-panel/output/public/assets/WeixinLoginPanel-D-T6BxkQ.js +1 -0
  495. package/node_modules/jishushell-panel/output/public/assets/api-C70Gt678.js +4 -0
  496. package/node_modules/jishushell-panel/output/public/assets/index-DnnqTf7s.css +1 -0
  497. package/node_modules/jishushell-panel/output/public/assets/index-ERt6_ngA.js +23 -0
  498. package/node_modules/jishushell-panel/output/public/assets/registry-DF93EzIb.js +2 -0
  499. package/node_modules/jishushell-panel/output/public/assets/rolldown-runtime-QTnfLwEv.js +1 -0
  500. package/node_modules/jishushell-panel/output/public/assets/setup-task-q21GnI0E.js +1 -0
  501. package/node_modules/jishushell-panel/output/public/assets/usePolling-DeoThIQn.js +1 -0
  502. package/node_modules/jishushell-panel/output/public/assets/vendor-i18n-CS8DFbkQ.js +1 -0
  503. package/node_modules/jishushell-panel/output/public/assets/vendor-react-Cc84NArf.js +8 -0
  504. package/node_modules/jishushell-panel/output/public/index.html +6 -4
  505. package/node_modules/jishushell-panel/package.json +2 -2
  506. package/node_modules/semver/classes/range.js +11 -2
  507. package/node_modules/semver/package.json +2 -2
  508. package/package.json +12 -64
  509. package/scripts/check-app-path-boundaries.mjs +121 -0
  510. package/scripts/check-app-spec.mjs +127 -25
  511. package/scripts/check-colima-launchd.mjs +10 -8
  512. package/scripts/check-integration-isolation.ts +541 -0
  513. package/scripts/check-new-file-tests.mjs +11 -3
  514. package/scripts/check-open-core-boundaries.mjs +60 -10
  515. package/scripts/check-test-layering.sh +1 -1
  516. package/scripts/fixtures/instances/hermes-sample/instance.json +3 -2
  517. package/scripts/fixtures/instances/legacy-openclaw-sample/instance.json +1 -1
  518. package/scripts/local-web-upgrade-test.README +4 -3
  519. package/scripts/local-web-upgrade-test.example.env +2 -2
  520. package/scripts/local-web-upgrade-test.sh +14 -1
  521. package/scripts/pack-gui-and-send-pi.sh +41 -0
  522. package/scripts/perf/instances.js +1 -1
  523. package/scripts/prune-open-core-dist.mjs +89 -2
  524. package/scripts/smoke/hermes-bootstrap.sh +5 -5
  525. package/templates/hermes-entrypoint.sh +19 -29
  526. package/apps/openwebui-container.yaml +0 -97
  527. package/apps/playwright-container.yaml +0 -126
  528. package/dependencies/jishushell-panel-0.6.5.tgz +0 -0
  529. package/dist/crypto-shim.d.ts +0 -1
  530. package/dist/crypto-shim.js +0 -2
  531. package/dist/crypto-shim.js.map +0 -1
  532. package/dist/routes/agent-apps.d.ts +0 -14
  533. package/dist/routes/agent-apps.js +0 -77
  534. package/dist/routes/agent-apps.js.map +0 -1
  535. package/dist/routes/internal.d.ts +0 -2
  536. package/dist/routes/internal.js +0 -55
  537. package/dist/routes/internal.js.map +0 -1
  538. package/dist/routes/openclaw-routes.d.ts +0 -22
  539. package/dist/routes/openclaw-routes.js +0 -1020
  540. package/dist/routes/openclaw-routes.js.map +0 -1
  541. package/dist/routes/runtime.d.ts +0 -15
  542. package/dist/routes/runtime.js +0 -76
  543. package/dist/routes/runtime.js.map +0 -1
  544. package/dist/services/agent-apps/catalog.d.ts +0 -33
  545. package/dist/services/agent-apps/catalog.js +0 -88
  546. package/dist/services/agent-apps/catalog.js.map +0 -1
  547. package/dist/services/agent-apps/index.d.ts +0 -36
  548. package/dist/services/agent-apps/index.js +0 -171
  549. package/dist/services/agent-apps/index.js.map +0 -1
  550. package/dist/services/agent-apps/installers/adapter-probes.d.ts +0 -49
  551. package/dist/services/agent-apps/installers/adapter-probes.js +0 -230
  552. package/dist/services/agent-apps/installers/adapter-probes.js.map +0 -1
  553. package/dist/services/agent-apps/installers/adapter.d.ts +0 -30
  554. package/dist/services/agent-apps/installers/adapter.js +0 -171
  555. package/dist/services/agent-apps/installers/adapter.js.map +0 -1
  556. package/dist/services/agent-apps/installers/registry-probe.js.map +0 -1
  557. package/dist/services/agent-apps/installers/shell-script.d.ts +0 -47
  558. package/dist/services/agent-apps/installers/shell-script.js +0 -488
  559. package/dist/services/agent-apps/installers/shell-script.js.map +0 -1
  560. package/dist/services/agent-apps/types.d.ts +0 -128
  561. package/dist/services/agent-apps/types.js +0 -17
  562. package/dist/services/agent-apps/types.js.map +0 -1
  563. package/dist/services/app/app-compiler.js +0 -185
  564. package/dist/services/app/app-compiler.js.map +0 -1
  565. package/dist/services/app/app-manager.d.ts +0 -184
  566. package/dist/services/app/app-manager.js +0 -2933
  567. package/dist/services/app/app-manager.js.map +0 -1
  568. package/dist/services/app/custom-manager.d.ts +0 -27
  569. package/dist/services/app/custom-manager.js +0 -382
  570. package/dist/services/app/custom-manager.js.map +0 -1
  571. package/dist/services/app/hermes-agent-manager.d.ts +0 -20
  572. package/dist/services/app/hermes-agent-manager.js +0 -299
  573. package/dist/services/app/hermes-agent-manager.js.map +0 -1
  574. package/dist/services/app/id-normalizer.d.ts +0 -27
  575. package/dist/services/app/id-normalizer.js +0 -77
  576. package/dist/services/app/id-normalizer.js.map +0 -1
  577. package/dist/services/app/ollama-manager.d.ts +0 -18
  578. package/dist/services/app/ollama-manager.js +0 -224
  579. package/dist/services/app/ollama-manager.js.map +0 -1
  580. package/dist/services/app/openclaw-manager.d.ts +0 -63
  581. package/dist/services/app/openclaw-manager.js +0 -1215
  582. package/dist/services/app/openclaw-manager.js.map +0 -1
  583. package/dist/services/app/paths.d.ts +0 -27
  584. package/dist/services/app/paths.js +0 -40
  585. package/dist/services/app/paths.js.map +0 -1
  586. package/dist/services/app/platform-transform.d.ts +0 -32
  587. package/dist/services/app/platform-transform.js +0 -65
  588. package/dist/services/app/platform-transform.js.map +0 -1
  589. package/dist/services/app/provide-resolver.d.ts +0 -29
  590. package/dist/services/app/provide-resolver.js +0 -135
  591. package/dist/services/app/provide-resolver.js.map +0 -1
  592. package/dist/services/app/registry.d.ts +0 -17
  593. package/dist/services/app/registry.js +0 -31
  594. package/dist/services/app/registry.js.map +0 -1
  595. package/dist/services/app/remote-spec.d.ts +0 -14
  596. package/dist/services/app/remote-spec.js +0 -58
  597. package/dist/services/app/remote-spec.js.map +0 -1
  598. package/dist/services/app/terminal-session-manager.js +0 -157
  599. package/dist/services/app/terminal-session-manager.js.map +0 -1
  600. package/dist/services/app/types.d.ts +0 -74
  601. package/dist/services/app/types.js +0 -16
  602. package/dist/services/app/types.js.map +0 -1
  603. package/dist/services/app-config-admin.d.ts +0 -17
  604. package/dist/services/app-config-admin.js +0 -177
  605. package/dist/services/app-config-admin.js.map +0 -1
  606. package/dist/services/app-create-from-installed.d.ts +0 -23
  607. package/dist/services/app-create-from-installed.js +0 -75
  608. package/dist/services/app-create-from-installed.js.map +0 -1
  609. package/dist/services/app-passwords.js +0 -173
  610. package/dist/services/app-passwords.js.map +0 -1
  611. package/dist/services/backup-admin.d.ts +0 -101
  612. package/dist/services/backup-admin.js +0 -259
  613. package/dist/services/backup-admin.js.map +0 -1
  614. package/dist/services/backup-manager.d.ts +0 -264
  615. package/dist/services/backup-manager.js +0 -2263
  616. package/dist/services/backup-manager.js.map +0 -1
  617. package/dist/services/backup-verify.js +0 -240
  618. package/dist/services/backup-verify.js.map +0 -1
  619. package/dist/services/capability-endpoint-validator.d.ts +0 -41
  620. package/dist/services/capability-endpoint-validator.js +0 -114
  621. package/dist/services/capability-endpoint-validator.js.map +0 -1
  622. package/dist/services/capability-health.d.ts +0 -16
  623. package/dist/services/capability-health.js +0 -121
  624. package/dist/services/capability-health.js.map +0 -1
  625. package/dist/services/capability-registry.d.ts +0 -29
  626. package/dist/services/capability-registry.js +0 -176
  627. package/dist/services/capability-registry.js.map +0 -1
  628. package/dist/services/capability-sync.d.ts +0 -4
  629. package/dist/services/capability-sync.js +0 -220
  630. package/dist/services/capability-sync.js.map +0 -1
  631. package/dist/services/connection-admin.d.ts +0 -74
  632. package/dist/services/connection-admin.js +0 -287
  633. package/dist/services/connection-admin.js.map +0 -1
  634. package/dist/services/connection-apply.d.ts +0 -91
  635. package/dist/services/connection-apply.js +0 -471
  636. package/dist/services/connection-apply.js.map +0 -1
  637. package/dist/services/connection-resolver.d.ts +0 -65
  638. package/dist/services/connection-resolver.js +0 -281
  639. package/dist/services/connection-resolver.js.map +0 -1
  640. package/dist/services/connection-transactor.d.ts +0 -39
  641. package/dist/services/connection-transactor.js +0 -354
  642. package/dist/services/connection-transactor.js.map +0 -1
  643. package/dist/services/core-manager.d.ts +0 -50
  644. package/dist/services/core-manager.js +0 -411
  645. package/dist/services/core-manager.js.map +0 -1
  646. package/dist/services/external-mounts.js +0 -187
  647. package/dist/services/external-mounts.js.map +0 -1
  648. package/dist/services/files-manager.d.ts +0 -252
  649. package/dist/services/files-manager.js +0 -1156
  650. package/dist/services/files-manager.js.map +0 -1
  651. package/dist/services/files-mounts.d.ts +0 -42
  652. package/dist/services/files-mounts.js +0 -207
  653. package/dist/services/files-mounts.js.map +0 -1
  654. package/dist/services/instance-admin.d.ts +0 -26
  655. package/dist/services/instance-admin.js +0 -218
  656. package/dist/services/instance-admin.js.map +0 -1
  657. package/dist/services/instance-manager.d.ts +0 -192
  658. package/dist/services/instance-manager.js +0 -1289
  659. package/dist/services/instance-manager.js.map +0 -1
  660. package/dist/services/macos-launchd.js +0 -312
  661. package/dist/services/macos-launchd.js.map +0 -1
  662. package/dist/services/nomad-manager.d.ts +0 -307
  663. package/dist/services/nomad-manager.js +0 -3958
  664. package/dist/services/nomad-manager.js.map +0 -1
  665. package/dist/services/organize/applier.js +0 -218
  666. package/dist/services/organize/applier.js.map +0 -1
  667. package/dist/services/organize/rules.js +0 -286
  668. package/dist/services/organize/rules.js.map +0 -1
  669. package/dist/services/organize/scanner.js +0 -366
  670. package/dist/services/organize/scanner.js.map +0 -1
  671. package/dist/services/organize/store.js +0 -82
  672. package/dist/services/organize/store.js.map +0 -1
  673. package/dist/services/plugin-installer.js +0 -128
  674. package/dist/services/plugin-installer.js.map +0 -1
  675. package/dist/services/process-manager.d.ts +0 -25
  676. package/dist/services/process-manager.js +0 -568
  677. package/dist/services/process-manager.js.map +0 -1
  678. package/dist/services/runtime/adapters/custom.d.ts +0 -20
  679. package/dist/services/runtime/adapters/custom.js +0 -188
  680. package/dist/services/runtime/adapters/custom.js.map +0 -1
  681. package/dist/services/runtime/adapters/hermes.d.ts +0 -204
  682. package/dist/services/runtime/adapters/hermes.js +0 -1684
  683. package/dist/services/runtime/adapters/hermes.js.map +0 -1
  684. package/dist/services/runtime/adapters/openclaw-mcporter.d.ts +0 -45
  685. package/dist/services/runtime/adapters/openclaw-mcporter.js +0 -108
  686. package/dist/services/runtime/adapters/openclaw-mcporter.js.map +0 -1
  687. package/dist/services/runtime/adapters/openclaw.d.ts +0 -426
  688. package/dist/services/runtime/adapters/openclaw.js +0 -3975
  689. package/dist/services/runtime/adapters/openclaw.js.map +0 -1
  690. package/dist/services/runtime/index.d.ts +0 -34
  691. package/dist/services/runtime/index.js +0 -51
  692. package/dist/services/runtime/index.js.map +0 -1
  693. package/dist/services/runtime/mcp-shims/anythingllm-shim.d.ts +0 -46
  694. package/dist/services/runtime/mcp-shims/anythingllm-shim.js +0 -281
  695. package/dist/services/runtime/mcp-shims/anythingllm-shim.js.map +0 -1
  696. package/dist/services/runtime/mcp-shims/drive-shim.js +0 -490
  697. package/dist/services/runtime/mcp-shims/drive-shim.js.map +0 -1
  698. package/dist/services/runtime/mcp-shims/jishukb-shim.d.ts +0 -48
  699. package/dist/services/runtime/mcp-shims/jishukb-shim.js +0 -723
  700. package/dist/services/runtime/mcp-shims/jishukb-shim.js.map +0 -1
  701. package/dist/services/runtime/mcp-shims/mcporter-lite.js +0 -276
  702. package/dist/services/runtime/mcp-shims/mcporter-lite.js.map +0 -1
  703. package/dist/services/runtime/migrations.d.ts +0 -23
  704. package/dist/services/runtime/migrations.js +0 -125
  705. package/dist/services/runtime/migrations.js.map +0 -1
  706. package/dist/services/runtime/registry.d.ts +0 -13
  707. package/dist/services/runtime/registry.js +0 -32
  708. package/dist/services/runtime/registry.js.map +0 -1
  709. package/dist/services/runtime-identity.d.ts +0 -13
  710. package/dist/services/runtime-identity.js +0 -166
  711. package/dist/services/runtime-identity.js.map +0 -1
  712. package/dist/services/runtime-repair.d.ts +0 -52
  713. package/dist/services/runtime-repair.js +0 -352
  714. package/dist/services/runtime-repair.js.map +0 -1
  715. package/dist/services/setup-manager.d.ts +0 -158
  716. package/dist/services/setup-manager.js +0 -2740
  717. package/dist/services/setup-manager.js.map +0 -1
  718. package/dist/services/suggestions.d.ts +0 -27
  719. package/dist/services/suggestions.js +0 -133
  720. package/dist/services/suggestions.js.map +0 -1
  721. package/dist/services/system-monitor.js +0 -79
  722. package/dist/services/system-monitor.js.map +0 -1
  723. package/dist/services/system-ollama-provider.d.ts +0 -14
  724. package/dist/services/system-ollama-provider.js +0 -125
  725. package/dist/services/system-ollama-provider.js.map +0 -1
  726. package/dist/services/system-reconciler.d.ts +0 -72
  727. package/dist/services/system-reconciler.js +0 -600
  728. package/dist/services/system-reconciler.js.map +0 -1
  729. package/dist/services/task-registry.d.ts +0 -44
  730. package/dist/services/task-registry.js +0 -76
  731. package/dist/services/task-registry.js.map +0 -1
  732. package/dist/services/types-shim.d.ts +0 -16
  733. package/dist/services/types-shim.js +0 -2
  734. package/dist/services/types-shim.js.map +0 -1
  735. package/dist/services/update-manager.d.ts +0 -47
  736. package/dist/services/update-manager.js +0 -351
  737. package/dist/services/update-manager.js.map +0 -1
  738. package/dist/services/webdav/server.d.ts +0 -24
  739. package/dist/services/webdav/server.js +0 -420
  740. package/dist/services/webdav/server.js.map +0 -1
  741. package/dist/services/webdav/xml-builder.js.map +0 -1
  742. package/dist/services/workspace-builder.d.ts +0 -29
  743. package/dist/services/workspace-builder.js +0 -188
  744. package/dist/services/workspace-builder.js.map +0 -1
  745. package/node_modules/@fastify/static/.github/stale.yml +0 -21
  746. package/node_modules/@isaacs/cliui/LICENSE.md +0 -63
  747. package/node_modules/@isaacs/cliui/README.md +0 -151
  748. package/node_modules/@isaacs/cliui/dist/commonjs/ansi-regex/index.d.ts +0 -4
  749. package/node_modules/@isaacs/cliui/dist/commonjs/ansi-regex/index.d.ts.map +0 -1
  750. package/node_modules/@isaacs/cliui/dist/commonjs/ansi-regex/index.js +0 -16
  751. package/node_modules/@isaacs/cliui/dist/commonjs/ansi-regex/index.js.map +0 -1
  752. package/node_modules/@isaacs/cliui/dist/commonjs/ansi-styles/index.d.ts +0 -34
  753. package/node_modules/@isaacs/cliui/dist/commonjs/ansi-styles/index.d.ts.map +0 -1
  754. package/node_modules/@isaacs/cliui/dist/commonjs/ansi-styles/index.js +0 -170
  755. package/node_modules/@isaacs/cliui/dist/commonjs/ansi-styles/index.js.map +0 -1
  756. package/node_modules/@isaacs/cliui/dist/commonjs/eastasianwidth/index.d.ts +0 -6
  757. package/node_modules/@isaacs/cliui/dist/commonjs/eastasianwidth/index.d.ts.map +0 -1
  758. package/node_modules/@isaacs/cliui/dist/commonjs/eastasianwidth/index.js +0 -307
  759. package/node_modules/@isaacs/cliui/dist/commonjs/eastasianwidth/index.js.map +0 -1
  760. package/node_modules/@isaacs/cliui/dist/commonjs/emoji-regex/index.d.ts +0 -2
  761. package/node_modules/@isaacs/cliui/dist/commonjs/emoji-regex/index.d.ts.map +0 -1
  762. package/node_modules/@isaacs/cliui/dist/commonjs/emoji-regex/index.js +0 -7
  763. package/node_modules/@isaacs/cliui/dist/commonjs/emoji-regex/index.js.map +0 -1
  764. package/node_modules/@isaacs/cliui/dist/commonjs/index.d.ts +0 -41
  765. package/node_modules/@isaacs/cliui/dist/commonjs/index.d.ts.map +0 -1
  766. package/node_modules/@isaacs/cliui/dist/commonjs/index.js +0 -322
  767. package/node_modules/@isaacs/cliui/dist/commonjs/index.js.map +0 -1
  768. package/node_modules/@isaacs/cliui/dist/commonjs/index.min.js +0 -12
  769. package/node_modules/@isaacs/cliui/dist/commonjs/index.min.js.map +0 -7
  770. package/node_modules/@isaacs/cliui/dist/commonjs/package.json +0 -3
  771. package/node_modules/@isaacs/cliui/dist/commonjs/string-width/index.d.ts +0 -5
  772. package/node_modules/@isaacs/cliui/dist/commonjs/string-width/index.d.ts.map +0 -1
  773. package/node_modules/@isaacs/cliui/dist/commonjs/string-width/index.js +0 -49
  774. package/node_modules/@isaacs/cliui/dist/commonjs/string-width/index.js.map +0 -1
  775. package/node_modules/@isaacs/cliui/dist/commonjs/strip-ansi/index.d.ts +0 -2
  776. package/node_modules/@isaacs/cliui/dist/commonjs/strip-ansi/index.d.ts.map +0 -1
  777. package/node_modules/@isaacs/cliui/dist/commonjs/strip-ansi/index.js +0 -8
  778. package/node_modules/@isaacs/cliui/dist/commonjs/strip-ansi/index.js.map +0 -1
  779. package/node_modules/@isaacs/cliui/dist/commonjs/wrap-ansi/index.d.ts +0 -7
  780. package/node_modules/@isaacs/cliui/dist/commonjs/wrap-ansi/index.d.ts.map +0 -1
  781. package/node_modules/@isaacs/cliui/dist/commonjs/wrap-ansi/index.js +0 -176
  782. package/node_modules/@isaacs/cliui/dist/commonjs/wrap-ansi/index.js.map +0 -1
  783. package/node_modules/@isaacs/cliui/dist/esm/ansi-regex/index.d.ts +0 -4
  784. package/node_modules/@isaacs/cliui/dist/esm/ansi-regex/index.d.ts.map +0 -1
  785. package/node_modules/@isaacs/cliui/dist/esm/ansi-regex/index.js +0 -12
  786. package/node_modules/@isaacs/cliui/dist/esm/ansi-regex/index.js.map +0 -1
  787. package/node_modules/@isaacs/cliui/dist/esm/ansi-styles/index.d.ts +0 -34
  788. package/node_modules/@isaacs/cliui/dist/esm/ansi-styles/index.d.ts.map +0 -1
  789. package/node_modules/@isaacs/cliui/dist/esm/ansi-styles/index.js +0 -167
  790. package/node_modules/@isaacs/cliui/dist/esm/ansi-styles/index.js.map +0 -1
  791. package/node_modules/@isaacs/cliui/dist/esm/eastasianwidth/index.d.ts +0 -6
  792. package/node_modules/@isaacs/cliui/dist/esm/eastasianwidth/index.d.ts.map +0 -1
  793. package/node_modules/@isaacs/cliui/dist/esm/eastasianwidth/index.js +0 -299
  794. package/node_modules/@isaacs/cliui/dist/esm/eastasianwidth/index.js.map +0 -1
  795. package/node_modules/@isaacs/cliui/dist/esm/emoji-regex/index.d.ts +0 -2
  796. package/node_modules/@isaacs/cliui/dist/esm/emoji-regex/index.d.ts.map +0 -1
  797. package/node_modules/@isaacs/cliui/dist/esm/emoji-regex/index.js +0 -3
  798. package/node_modules/@isaacs/cliui/dist/esm/emoji-regex/index.js.map +0 -1
  799. package/node_modules/@isaacs/cliui/dist/esm/index.d.ts +0 -41
  800. package/node_modules/@isaacs/cliui/dist/esm/index.d.ts.map +0 -1
  801. package/node_modules/@isaacs/cliui/dist/esm/index.js +0 -317
  802. package/node_modules/@isaacs/cliui/dist/esm/index.js.map +0 -1
  803. package/node_modules/@isaacs/cliui/dist/esm/index.min.js +0 -12
  804. package/node_modules/@isaacs/cliui/dist/esm/index.min.js.map +0 -7
  805. package/node_modules/@isaacs/cliui/dist/esm/package.json +0 -3
  806. package/node_modules/@isaacs/cliui/dist/esm/string-width/index.d.ts +0 -5
  807. package/node_modules/@isaacs/cliui/dist/esm/string-width/index.d.ts.map +0 -1
  808. package/node_modules/@isaacs/cliui/dist/esm/string-width/index.js +0 -46
  809. package/node_modules/@isaacs/cliui/dist/esm/string-width/index.js.map +0 -1
  810. package/node_modules/@isaacs/cliui/dist/esm/strip-ansi/index.d.ts +0 -2
  811. package/node_modules/@isaacs/cliui/dist/esm/strip-ansi/index.d.ts.map +0 -1
  812. package/node_modules/@isaacs/cliui/dist/esm/strip-ansi/index.js +0 -4
  813. package/node_modules/@isaacs/cliui/dist/esm/strip-ansi/index.js.map +0 -1
  814. package/node_modules/@isaacs/cliui/dist/esm/wrap-ansi/index.d.ts +0 -7
  815. package/node_modules/@isaacs/cliui/dist/esm/wrap-ansi/index.d.ts.map +0 -1
  816. package/node_modules/@isaacs/cliui/dist/esm/wrap-ansi/index.js +0 -172
  817. package/node_modules/@isaacs/cliui/dist/esm/wrap-ansi/index.js.map +0 -1
  818. package/node_modules/@isaacs/cliui/package.json +0 -163
  819. package/node_modules/content-disposition/HISTORY.md +0 -60
  820. package/node_modules/cross-spawn/LICENSE +0 -21
  821. package/node_modules/cross-spawn/README.md +0 -89
  822. package/node_modules/cross-spawn/index.js +0 -39
  823. package/node_modules/cross-spawn/lib/enoent.js +0 -59
  824. package/node_modules/cross-spawn/lib/parse.js +0 -91
  825. package/node_modules/cross-spawn/lib/util/escape.js +0 -47
  826. package/node_modules/cross-spawn/lib/util/readShebang.js +0 -23
  827. package/node_modules/cross-spawn/lib/util/resolveCommand.js +0 -52
  828. package/node_modules/cross-spawn/package.json +0 -73
  829. package/node_modules/foreground-child/LICENSE +0 -15
  830. package/node_modules/foreground-child/README.md +0 -128
  831. package/node_modules/foreground-child/dist/commonjs/all-signals.d.ts +0 -2
  832. package/node_modules/foreground-child/dist/commonjs/all-signals.d.ts.map +0 -1
  833. package/node_modules/foreground-child/dist/commonjs/all-signals.js +0 -58
  834. package/node_modules/foreground-child/dist/commonjs/all-signals.js.map +0 -1
  835. package/node_modules/foreground-child/dist/commonjs/index.d.ts +0 -58
  836. package/node_modules/foreground-child/dist/commonjs/index.d.ts.map +0 -1
  837. package/node_modules/foreground-child/dist/commonjs/index.js +0 -123
  838. package/node_modules/foreground-child/dist/commonjs/index.js.map +0 -1
  839. package/node_modules/foreground-child/dist/commonjs/package.json +0 -3
  840. package/node_modules/foreground-child/dist/commonjs/proxy-signals.d.ts +0 -6
  841. package/node_modules/foreground-child/dist/commonjs/proxy-signals.d.ts.map +0 -1
  842. package/node_modules/foreground-child/dist/commonjs/proxy-signals.js +0 -38
  843. package/node_modules/foreground-child/dist/commonjs/proxy-signals.js.map +0 -1
  844. package/node_modules/foreground-child/dist/commonjs/watchdog.d.ts +0 -10
  845. package/node_modules/foreground-child/dist/commonjs/watchdog.d.ts.map +0 -1
  846. package/node_modules/foreground-child/dist/commonjs/watchdog.js +0 -50
  847. package/node_modules/foreground-child/dist/commonjs/watchdog.js.map +0 -1
  848. package/node_modules/foreground-child/dist/esm/all-signals.d.ts +0 -2
  849. package/node_modules/foreground-child/dist/esm/all-signals.d.ts.map +0 -1
  850. package/node_modules/foreground-child/dist/esm/all-signals.js +0 -52
  851. package/node_modules/foreground-child/dist/esm/all-signals.js.map +0 -1
  852. package/node_modules/foreground-child/dist/esm/index.d.ts +0 -58
  853. package/node_modules/foreground-child/dist/esm/index.d.ts.map +0 -1
  854. package/node_modules/foreground-child/dist/esm/index.js +0 -115
  855. package/node_modules/foreground-child/dist/esm/index.js.map +0 -1
  856. package/node_modules/foreground-child/dist/esm/package.json +0 -3
  857. package/node_modules/foreground-child/dist/esm/proxy-signals.d.ts +0 -6
  858. package/node_modules/foreground-child/dist/esm/proxy-signals.d.ts.map +0 -1
  859. package/node_modules/foreground-child/dist/esm/proxy-signals.js +0 -34
  860. package/node_modules/foreground-child/dist/esm/proxy-signals.js.map +0 -1
  861. package/node_modules/foreground-child/dist/esm/watchdog.d.ts +0 -10
  862. package/node_modules/foreground-child/dist/esm/watchdog.d.ts.map +0 -1
  863. package/node_modules/foreground-child/dist/esm/watchdog.js +0 -46
  864. package/node_modules/foreground-child/dist/esm/watchdog.js.map +0 -1
  865. package/node_modules/foreground-child/package.json +0 -106
  866. package/node_modules/glob/dist/esm/bin.d.mts +0 -3
  867. package/node_modules/glob/dist/esm/bin.d.mts.map +0 -1
  868. package/node_modules/glob/dist/esm/bin.mjs +0 -346
  869. package/node_modules/glob/dist/esm/bin.mjs.map +0 -1
  870. package/node_modules/isexe/.npmignore +0 -2
  871. package/node_modules/isexe/LICENSE +0 -15
  872. package/node_modules/isexe/README.md +0 -51
  873. package/node_modules/isexe/index.js +0 -57
  874. package/node_modules/isexe/mode.js +0 -41
  875. package/node_modules/isexe/package.json +0 -31
  876. package/node_modules/isexe/test/basic.js +0 -221
  877. package/node_modules/isexe/windows.js +0 -42
  878. package/node_modules/jackspeak/LICENSE.md +0 -55
  879. package/node_modules/jackspeak/README.md +0 -394
  880. package/node_modules/jackspeak/dist/commonjs/index.d.ts +0 -323
  881. package/node_modules/jackspeak/dist/commonjs/index.d.ts.map +0 -1
  882. package/node_modules/jackspeak/dist/commonjs/index.js +0 -944
  883. package/node_modules/jackspeak/dist/commonjs/index.js.map +0 -1
  884. package/node_modules/jackspeak/dist/commonjs/index.min.js +0 -33
  885. package/node_modules/jackspeak/dist/commonjs/index.min.js.map +0 -7
  886. package/node_modules/jackspeak/dist/commonjs/package.json +0 -3
  887. package/node_modules/jackspeak/dist/esm/index.d.ts +0 -323
  888. package/node_modules/jackspeak/dist/esm/index.d.ts.map +0 -1
  889. package/node_modules/jackspeak/dist/esm/index.js +0 -936
  890. package/node_modules/jackspeak/dist/esm/index.js.map +0 -1
  891. package/node_modules/jackspeak/dist/esm/index.min.js +0 -33
  892. package/node_modules/jackspeak/dist/esm/index.min.js.map +0 -7
  893. package/node_modules/jackspeak/dist/esm/package.json +0 -3
  894. package/node_modules/jackspeak/package.json +0 -115
  895. package/node_modules/jishushell-panel/output/public/assets/ApiKeyField-D1i7zWXR.js +0 -1
  896. package/node_modules/jishushell-panel/output/public/assets/Dashboard-sWIvL43F.js +0 -1
  897. package/node_modules/jishushell-panel/output/public/assets/HermesChatPanel-DQ8RyvQY.js +0 -1
  898. package/node_modules/jishushell-panel/output/public/assets/HermesConfigForm-tIbPP1sB.js +0 -4
  899. package/node_modules/jishushell-panel/output/public/assets/InitPassword-C3Slq3Dd.js +0 -1
  900. package/node_modules/jishushell-panel/output/public/assets/InstanceDetail-7JqY9tq4.js +0 -92
  901. package/node_modules/jishushell-panel/output/public/assets/Login-BXLDJlQN.js +0 -1
  902. package/node_modules/jishushell-panel/output/public/assets/NewInstance-dLc5Xrpx.js +0 -1
  903. package/node_modules/jishushell-panel/output/public/assets/ProviderRecommendations-DIAXxesl.js +0 -1
  904. package/node_modules/jishushell-panel/output/public/assets/Settings-Bd5utbBh.js +0 -1
  905. package/node_modules/jishushell-panel/output/public/assets/Setup-Yn9_20FL.js +0 -1
  906. package/node_modules/jishushell-panel/output/public/assets/WeixinLoginPanel-C21doQTJ.js +0 -9
  907. package/node_modules/jishushell-panel/output/public/assets/index-CCkaIEjn.js +0 -20
  908. package/node_modules/jishushell-panel/output/public/assets/index-D7qxy-Vh.css +0 -1
  909. package/node_modules/jishushell-panel/output/public/assets/registry-B2ZQZXWL.js +0 -2
  910. package/node_modules/jishushell-panel/output/public/assets/usePolling-BFZm4do_.js +0 -1
  911. package/node_modules/jishushell-panel/output/public/assets/vendor-i18n-DqPtOicc.js +0 -9
  912. package/node_modules/jishushell-panel/output/public/assets/vendor-react-DW5juQin.js +0 -59
  913. package/node_modules/package-json-from-dist/LICENSE.md +0 -63
  914. package/node_modules/package-json-from-dist/README.md +0 -110
  915. package/node_modules/package-json-from-dist/dist/commonjs/index.d.ts +0 -89
  916. package/node_modules/package-json-from-dist/dist/commonjs/index.d.ts.map +0 -1
  917. package/node_modules/package-json-from-dist/dist/commonjs/index.js +0 -134
  918. package/node_modules/package-json-from-dist/dist/commonjs/index.js.map +0 -1
  919. package/node_modules/package-json-from-dist/dist/commonjs/package.json +0 -3
  920. package/node_modules/package-json-from-dist/dist/esm/index.d.ts +0 -89
  921. package/node_modules/package-json-from-dist/dist/esm/index.d.ts.map +0 -1
  922. package/node_modules/package-json-from-dist/dist/esm/index.js +0 -129
  923. package/node_modules/package-json-from-dist/dist/esm/index.js.map +0 -1
  924. package/node_modules/package-json-from-dist/dist/esm/package.json +0 -3
  925. package/node_modules/package-json-from-dist/package.json +0 -68
  926. package/node_modules/path-key/index.d.ts +0 -40
  927. package/node_modules/path-key/index.js +0 -16
  928. package/node_modules/path-key/license +0 -9
  929. package/node_modules/path-key/package.json +0 -39
  930. package/node_modules/path-key/readme.md +0 -61
  931. package/node_modules/safe-buffer/LICENSE +0 -21
  932. package/node_modules/safe-buffer/README.md +0 -584
  933. package/node_modules/safe-buffer/index.d.ts +0 -187
  934. package/node_modules/safe-buffer/index.js +0 -65
  935. package/node_modules/safe-buffer/package.json +0 -51
  936. package/node_modules/shebang-command/index.js +0 -19
  937. package/node_modules/shebang-command/license +0 -9
  938. package/node_modules/shebang-command/package.json +0 -34
  939. package/node_modules/shebang-command/readme.md +0 -34
  940. package/node_modules/shebang-regex/index.d.ts +0 -22
  941. package/node_modules/shebang-regex/index.js +0 -2
  942. package/node_modules/shebang-regex/license +0 -9
  943. package/node_modules/shebang-regex/package.json +0 -35
  944. package/node_modules/shebang-regex/readme.md +0 -33
  945. package/node_modules/signal-exit/LICENSE.txt +0 -16
  946. package/node_modules/signal-exit/README.md +0 -74
  947. package/node_modules/signal-exit/dist/cjs/browser.d.ts +0 -12
  948. package/node_modules/signal-exit/dist/cjs/browser.d.ts.map +0 -1
  949. package/node_modules/signal-exit/dist/cjs/browser.js +0 -10
  950. package/node_modules/signal-exit/dist/cjs/browser.js.map +0 -1
  951. package/node_modules/signal-exit/dist/cjs/index.d.ts +0 -48
  952. package/node_modules/signal-exit/dist/cjs/index.d.ts.map +0 -1
  953. package/node_modules/signal-exit/dist/cjs/index.js +0 -279
  954. package/node_modules/signal-exit/dist/cjs/index.js.map +0 -1
  955. package/node_modules/signal-exit/dist/cjs/package.json +0 -3
  956. package/node_modules/signal-exit/dist/cjs/signals.d.ts +0 -29
  957. package/node_modules/signal-exit/dist/cjs/signals.d.ts.map +0 -1
  958. package/node_modules/signal-exit/dist/cjs/signals.js +0 -42
  959. package/node_modules/signal-exit/dist/cjs/signals.js.map +0 -1
  960. package/node_modules/signal-exit/dist/mjs/browser.d.ts +0 -12
  961. package/node_modules/signal-exit/dist/mjs/browser.d.ts.map +0 -1
  962. package/node_modules/signal-exit/dist/mjs/browser.js +0 -4
  963. package/node_modules/signal-exit/dist/mjs/browser.js.map +0 -1
  964. package/node_modules/signal-exit/dist/mjs/index.d.ts +0 -48
  965. package/node_modules/signal-exit/dist/mjs/index.d.ts.map +0 -1
  966. package/node_modules/signal-exit/dist/mjs/index.js +0 -275
  967. package/node_modules/signal-exit/dist/mjs/index.js.map +0 -1
  968. package/node_modules/signal-exit/dist/mjs/package.json +0 -3
  969. package/node_modules/signal-exit/dist/mjs/signals.d.ts +0 -29
  970. package/node_modules/signal-exit/dist/mjs/signals.d.ts.map +0 -1
  971. package/node_modules/signal-exit/dist/mjs/signals.js +0 -39
  972. package/node_modules/signal-exit/dist/mjs/signals.js.map +0 -1
  973. package/node_modules/signal-exit/package.json +0 -106
  974. package/node_modules/which/CHANGELOG.md +0 -166
  975. package/node_modules/which/LICENSE +0 -15
  976. package/node_modules/which/README.md +0 -54
  977. package/node_modules/which/bin/node-which +0 -52
  978. package/node_modules/which/package.json +0 -43
  979. package/node_modules/which/which.js +0 -125
  980. package/scripts/check-adapter-isolation.ts +0 -293
  981. /package/dist/services/{app → app-common}/app-compiler.d.ts +0 -0
  982. /package/dist/services/{app → app-common}/terminal-session-manager.d.ts +0 -0
  983. /package/dist/services/{backup-verify.d.ts → backup/backup-verify.d.ts} +0 -0
  984. /package/dist/services/{external-mounts.d.ts → files/external-mounts.d.ts} +0 -0
  985. /package/dist/services/{organize → files/organize}/applier.d.ts +0 -0
  986. /package/dist/services/{organize → files/organize}/rules.d.ts +0 -0
  987. /package/dist/services/{organize → files/organize}/scanner.d.ts +0 -0
  988. /package/dist/services/{organize → files/organize}/store.d.ts +0 -0
  989. /package/dist/services/{webdav → files/webdav}/xml-builder.d.ts +0 -0
  990. /package/dist/services/{webdav → files/webdav}/xml-builder.js +0 -0
  991. /package/dist/services/{app-passwords.d.ts → instances/passwords.d.ts} +0 -0
  992. /package/dist/services/{agent-apps → integrations/installable}/installers/registry-probe.d.ts +0 -0
  993. /package/dist/services/{agent-apps → integrations/installable}/installers/registry-probe.js +0 -0
  994. /package/dist/services/{runtime/mcp-shims → integrations/openclaw}/drive-shim.d.ts +0 -0
  995. /package/dist/services/{runtime/mcp-shims → integrations/openclaw}/mcporter-lite.d.ts +0 -0
  996. /package/dist/services/{plugin-installer.d.ts → setup/plugin-installer.d.ts} +0 -0
  997. /package/dist/services/{macos-launchd.d.ts → system/macos-launchd.d.ts} +0 -0
  998. /package/dist/services/{system-monitor.d.ts → system/system-monitor.d.ts} +0 -0
@@ -0,0 +1,1669 @@
1
+ /**
2
+ * HermesIntegration — first non-OpenClaw runtime integration.
3
+ *
4
+ * Legacy AppIntegration implementation retained during migration toward the
5
+ * model described in docs/core-app-architecture.md.
6
+ *
7
+ * Current scope:
8
+ * - Only create / buildRuntime / getRuntimeVersion are wired up.
9
+ * - Baseline image mode only. Overlay upgrade CLI is deferred.
10
+ * - Assumes the Hermes integration runtime record has been populated in
11
+ * core.json.runtime_catalog.hermes: defaultImage (+ optional
12
+ * defaultImageDigest), resources, homeDirName.
13
+ */
14
+ import { execFileSync } from "child_process";
15
+ import { createRequire } from "node:module";
16
+ import { fileURLToPath } from "node:url";
17
+ import { chmodSync, chownSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, statSync, writeFileSync } from "fs";
18
+ import { randomBytes } from "crypto";
19
+ import { dirname, join } from "path";
20
+ import { getCoreConfig, getIntegrationRuntimeEntry, setIntegrationRuntimeEntry, HERMES_DEFAULT_IMAGE, } from "../../../config.js";
21
+ import { ensureDirContainer, writeConfigFile, writeSecretFile, } from "../../../utils/fs.js";
22
+ import { safeWriteJson } from "../../../utils/safe-json.js";
23
+ import { ensureInstanceProxyToken } from "../../llm-proxy/instance-proxy.js";
24
+ import { getDefaultLlmProvider, normalizeProviderApi } from "../../llm-proxy/providers.js";
25
+ import { getCoreProxyBaseUrl } from "../../llm-proxy/proxy-runtime.js";
26
+ import { getInstance, getInstanceRuntime, resolveServiceUser, updateInstanceMeta, updateEnvFile, } from "../../instances/manager.js";
27
+ import { getInstanceDir as instanceDir, instanceMetaPath } from "../../../config.js";
28
+ import { createTask, emitTask, spawnWithTask, resolveDockerInvocation, captureImageDigest, } from "../../setup/setup-manager.js";
29
+ import { InstanceCreationRejected } from "../../runtime/errors.js";
30
+ import YAML from "yaml";
31
+ import { registerIntegration } from "../registry.js";
32
+ import { writeOwnershipMarker } from "../../runtime/ownership-marker.js";
33
+ import { SEARXNG_MCP_SHIM_SOURCE } from "../../runtime/mcp-shims/searxng-shim.js";
34
+ import { resolveEnvTemplate, writeMcpEntry } from "../../runtime/mcp-shims/write-mcp-entry.js";
35
+ import * as capabilityRegistry from "../../capabilities/registry.js";
36
+ const SEARXNG_SHIM_REL_PATH = "__mcp_shims__/searxng/index.mjs";
37
+ const UPSTREAM_SECRET_ENV_NAME = "UPSTREAM_API_KEY";
38
+ const HERMES_CONTAINER_PORT = 8642;
39
+ const HERMES_CONTAINER_HOME = "/opt/data";
40
+ const HERMES_CONTAINER_SHIM = "/usr/local/bin/jishushell-hermes-entry.sh";
41
+ const HERMES_HOST_SHIM_NAME = "jishushell-hermes-entry.sh";
42
+ // Host peripheral device nodes worth passing into a privileged Hermes
43
+ // container so the agent reaches cameras / GPU / audio like a native install.
44
+ // Directory roots are fully expanded; the prefixes match numbered top-level
45
+ // nodes (e.g. /dev/video0, /dev/media1, /dev/mali0).
46
+ const PERIPHERAL_DEV_ROOTS = ["/dev/dri", "/dev/snd"];
47
+ const PERIPHERAL_DEV_PREFIXES = ["/dev/video", "/dev/media", "/dev/v4l-subdev", "/dev/mali", "/dev/dma_heap"];
48
+ // Raw-disk / kernel-memory / device-mapper nodes that must NEVER be passed
49
+ // into a container, even if a hand-edited `runtime.devices` entry — or a
50
+ // symlink sitting under a peripheral prefix (e.g. /dev/videoX -> /dev/sda) —
51
+ // resolves to one. Peripheral passthrough must not silently become raw host
52
+ // disk or physical-memory access. Prefix match (anchored at /dev/) so
53
+ // partitions like /dev/sda1 and /dev/nvme0n1p2 are covered too.
54
+ const FORBIDDEN_DEVICE_RE = /^\/dev\/(mem|kmem|kmsg|port|sd[a-z]|hd[a-z]|vd[a-z]|nvme\d|mmcblk\d|sr\d|md\d|loop\d|dm-\d|mapper\/|disk\/|block\/)/;
55
+ /**
56
+ * Enumerate the host's media/accelerator device nodes (plus any explicit
57
+ * extras from `runtime.devices`) so a privileged container can open them.
58
+ * Returns docker `devices` entries (real, symlink-resolved paths, deduped)
59
+ * and the set of owning group gids — the (non-root) container user is added
60
+ * to those gids via `group_add` so the 0660 root:video / root:render /
61
+ * root:audio nodes are actually accessible inside the container. Missing
62
+ * nodes are skipped, so this is a no-op on hosts without such hardware.
63
+ */
64
+ function collectPrivilegedDevices(extraPaths = []) {
65
+ const candidates = new Set(extraPaths);
66
+ for (const root of PERIPHERAL_DEV_ROOTS) {
67
+ try {
68
+ for (const name of readdirSync(root))
69
+ candidates.add(`${root}/${name}`);
70
+ }
71
+ catch { /* root absent on this host */ }
72
+ }
73
+ try {
74
+ for (const name of readdirSync("/dev")) {
75
+ const full = `/dev/${name}`;
76
+ if (PERIPHERAL_DEV_PREFIXES.some((p) => full.startsWith(p)))
77
+ candidates.add(full);
78
+ }
79
+ }
80
+ catch { /* /dev unreadable (non-Linux) */ }
81
+ const devices = [];
82
+ const gids = new Set();
83
+ const seen = new Set();
84
+ for (const path of candidates) {
85
+ let real;
86
+ try {
87
+ real = realpathSync(path);
88
+ }
89
+ catch {
90
+ continue;
91
+ }
92
+ if (seen.has(real))
93
+ continue;
94
+ seen.add(real);
95
+ // Defense-in-depth: only ever expose real /dev nodes, and never raw
96
+ // disk / memory / device-mapper targets — applies to auto-discovered
97
+ // nodes (catches a malicious symlink under a peripheral prefix) and to
98
+ // explicit runtime.devices entries alike.
99
+ if (!real.startsWith("/dev/") || FORBIDDEN_DEVICE_RE.test(real)) {
100
+ console.warn(`[hermes] refusing device passthrough "${path}" -> "${real}" (outside /dev or on denylist)`);
101
+ continue;
102
+ }
103
+ let st;
104
+ try {
105
+ st = statSync(real);
106
+ }
107
+ catch {
108
+ continue;
109
+ }
110
+ if (!st.isCharacterDevice() && !st.isBlockDevice())
111
+ continue;
112
+ devices.push({ host_path: real, container_path: real, cgroup_permissions: "rw" });
113
+ if (typeof st.gid === "number" && st.gid > 0)
114
+ gids.add(st.gid);
115
+ }
116
+ return { devices, groupAdd: [...gids].map(String) };
117
+ }
118
+ const HERMES_CONTAINER_WORKDIR = "/opt/hermes";
119
+ export const HERMES_PREFERRED_HOST_PORT = HERMES_CONTAINER_PORT;
120
+ const HERMES_VERSION_LABEL = "org.opencontainers.image.version";
121
+ const HERMES_MUTABLE_TAG_RE = /:(latest|slim)$/;
122
+ const HERMES_CATALOG_DEFAULTS = {
123
+ configFormat: "yaml+env",
124
+ homeDirName: "agent-home",
125
+ resources: { CPU: 1000, MemoryMB: 1024 },
126
+ allowDockerSock: false,
127
+ };
128
+ function readOfficialHermesRepoDigest(image) {
129
+ const repo = imageRepository(HERMES_DEFAULT_IMAGE);
130
+ if (!repo)
131
+ return null;
132
+ try {
133
+ const invocation = resolveDockerInvocation();
134
+ const raw = execFileSync(invocation.cmd, [
135
+ ...invocation.argsPrefix,
136
+ "image",
137
+ "inspect",
138
+ "--format",
139
+ "{{range .RepoDigests}}{{.}}{{println}}{{end}}",
140
+ image,
141
+ ], { timeout: 5_000, encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] });
142
+ const prefix = `${repo}@sha256:`;
143
+ return raw
144
+ .split("\n")
145
+ .map((line) => line.trim())
146
+ .find((line) => line.startsWith(prefix) && /^[a-f0-9]{64}$/i.test(line.slice(prefix.length))) ?? null;
147
+ }
148
+ catch {
149
+ return null;
150
+ }
151
+ }
152
+ function assertOfficialHermesImage(image) {
153
+ const digest = readOfficialHermesRepoDigest(image);
154
+ if (digest)
155
+ return digest;
156
+ const repo = imageRepository(HERMES_DEFAULT_IMAGE) ?? HERMES_DEFAULT_IMAGE;
157
+ throw new Error(`Hermes image ${image} is not a JishuShell-provided runtime image. ` +
158
+ `It must be pulled from ${repo} and retain an official RepoDigest.`);
159
+ }
160
+ function imageRepository(image) {
161
+ const digestIdx = image.indexOf("@");
162
+ const withoutDigest = digestIdx >= 0 ? image.slice(0, digestIdx) : image;
163
+ const colonIdx = withoutDigest.lastIndexOf(":");
164
+ const slashIdx = withoutDigest.lastIndexOf("/");
165
+ if (colonIdx > slashIdx)
166
+ return withoutDigest.slice(0, colonIdx);
167
+ return withoutDigest || null;
168
+ }
169
+ function imageTag(image) {
170
+ const colonIdx = image.lastIndexOf(":");
171
+ const slashIdx = image.lastIndexOf("/");
172
+ if (colonIdx <= slashIdx)
173
+ return null;
174
+ const tag = image.slice(colonIdx + 1);
175
+ return tag && tag !== "<none>" && tag !== "none" ? tag : null;
176
+ }
177
+ function imageTagVersion(image) {
178
+ const tag = imageTag(image);
179
+ return tag && /^\d+\.\d+\.\d+/.test(tag) ? tag : undefined;
180
+ }
181
+ function versionScore(image) {
182
+ const tag = imageTag(image) ?? "";
183
+ const semver = tag.match(/^v?(\d+)\.(\d+)\.(\d+)/);
184
+ if (semver) {
185
+ return [
186
+ 3,
187
+ Number.parseInt(semver[1], 10),
188
+ Number.parseInt(semver[2], 10),
189
+ Number.parseInt(semver[3], 10),
190
+ tag,
191
+ ];
192
+ }
193
+ if (tag === "latest")
194
+ return [2, 0, 0, 0, tag];
195
+ if (tag === "slim")
196
+ return [1, 0, 0, 0, tag];
197
+ return [0, 0, 0, 0, tag];
198
+ }
199
+ function compareLocalHermesImages(left, right) {
200
+ const a = versionScore(left);
201
+ const b = versionScore(right);
202
+ for (let i = 0; i < 4; i++) {
203
+ const diff = b[i] - a[i];
204
+ if (diff !== 0)
205
+ return diff;
206
+ }
207
+ return b[4].localeCompare(a[4]);
208
+ }
209
+ function findLocalHermesImage() {
210
+ const repo = imageRepository(HERMES_DEFAULT_IMAGE);
211
+ if (!repo)
212
+ return null;
213
+ try {
214
+ const invocation = resolveDockerInvocation();
215
+ const out = execFileSync(invocation.cmd, [...invocation.argsPrefix, "image", "ls", "--format", "{{.Repository}}:{{.Tag}}"], { timeout: 5_000, encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] });
216
+ const candidates = out
217
+ .split("\n")
218
+ .map((line) => line.trim())
219
+ .filter((line) => line.startsWith(`${repo}:`) && !!imageTag(line));
220
+ for (const candidate of candidates.sort(compareLocalHermesImages)) {
221
+ const digest = readOfficialHermesRepoDigest(candidate);
222
+ if (digest)
223
+ return { image: candidate, digest };
224
+ }
225
+ return null;
226
+ }
227
+ catch {
228
+ return null;
229
+ }
230
+ }
231
+ function persistHermesCatalogForImage(image, existing, officialDigest) {
232
+ const next = {
233
+ ...HERMES_CATALOG_DEFAULTS,
234
+ ...(existing ?? {}),
235
+ defaultImage: image,
236
+ };
237
+ const digest = officialDigest ?? readOfficialHermesRepoDigest(image);
238
+ if (digest)
239
+ next.defaultImageDigest = digest;
240
+ else
241
+ delete next.defaultImageDigest;
242
+ setIntegrationRuntimeEntry("hermes", next);
243
+ }
244
+ /**
245
+ * Read `org.opencontainers.image.version` LABEL from a local image.
246
+ * Returns the version string if it matches `N.N.N...`, null otherwise.
247
+ */
248
+ function readHermesImageVersion(image) {
249
+ try {
250
+ const out = execFileSync("docker", ["inspect", "--format", `{{ index .Config.Labels "${HERMES_VERSION_LABEL}" }}`, image], { timeout: 5_000, encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }).trim();
251
+ return /^\d+\.\d+\.\d+/.test(out) ? out : null;
252
+ }
253
+ catch {
254
+ return null;
255
+ }
256
+ }
257
+ /**
258
+ * If `stored` has a mutable tag (`:latest` / `:slim`), read the bundled
259
+ * version from the image's LABEL and create a local `:${version}` tag
260
+ * alias, then drop the mutable source tag. Mirrors the OpenClaw pin in
261
+ * config.ts:migrateOpenclawImageTagIfNeeded, but uses the LABEL instead
262
+ * of spawning the container (Hermes images bake the version into the
263
+ * manifest, OpenClaw's used to lie — see that function's docstring).
264
+ *
265
+ * Returns the pinned tag on success, null when nothing was changed.
266
+ */
267
+ function pinHermesImageToLabeledVersion(stored) {
268
+ if (!HERMES_MUTABLE_TAG_RE.test(stored))
269
+ return null;
270
+ const version = readHermesImageVersion(stored);
271
+ if (!version)
272
+ return null;
273
+ const colonIdx = stored.lastIndexOf(":");
274
+ const slashIdx = stored.lastIndexOf("/");
275
+ if (colonIdx <= slashIdx)
276
+ return null;
277
+ const pinnedTag = `${stored.slice(0, colonIdx)}:${version}`;
278
+ if (pinnedTag === stored)
279
+ return null;
280
+ try {
281
+ execFileSync("docker", ["tag", stored, pinnedTag], { timeout: 10_000, stdio: "ignore" });
282
+ }
283
+ catch {
284
+ return null;
285
+ }
286
+ try {
287
+ execFileSync("docker", ["rmi", stored], { timeout: 10_000, stdio: "ignore" });
288
+ }
289
+ catch { /* best-effort cleanup */ }
290
+ return pinnedTag;
291
+ }
292
+ /**
293
+ * One-shot startup migration for Hermes installs whose
294
+ * catalog still stores `:latest` / `:slim`. Silent no-op when the catalog
295
+ * already holds a pinned tag, when docker is unreachable, or when the
296
+ * local image lacks the expected LABEL. Called from server.ts onReady.
297
+ */
298
+ export function migrateHermesImageTagIfNeeded() {
299
+ const entry = getIntegrationRuntimeEntry("hermes");
300
+ if (!entry || typeof entry.defaultImage !== "string")
301
+ return;
302
+ const stored = entry.defaultImage;
303
+ const pinned = pinHermesImageToLabeledVersion(stored);
304
+ if (!pinned)
305
+ return;
306
+ setIntegrationRuntimeEntry("hermes", { ...entry, defaultImage: pinned });
307
+ console.log(`[hermes] migrated runtime_catalog.hermes.defaultImage: ${stored} → ${pinned}`);
308
+ }
309
+ // ── Nomad primitives (mirrored from the Nomad driver so HermesIntegration's
310
+ // buildNomadTask is self-contained) ─────────────────────────────────
311
+ const DOCKER_IMAGE_RE = /^[a-zA-Z0-9][a-zA-Z0-9\-_.:/@]*$/;
312
+ const MAX_DOCKER_IMAGE_NAME_LEN = 256;
313
+ // Matches the shape Feishu issues from `archetype=PersonalAgent` device-flow
314
+ // (cli_ prefix + alphanumerics). Kept narrow on purpose — wider wildcards
315
+ // would accept untrusted strings propagated from the OAuth response body.
316
+ const FEISHU_APP_ID_RE = /^cli_[a-zA-Z0-9]{8,64}$/;
317
+ // iLink Bot IDs are numeric-ish bot handles issued by Tencent. Keep the
318
+ // same 128-char ceiling + charset OpenClaw's integration uses so invalid
319
+ // payloads from a tampered OAuth response don't become filesystem paths.
320
+ const SAFE_WEIXIN_ACCOUNT_ID_RE = /^[a-zA-Z0-9@._-]{1,128}$/;
321
+ const DEFAULT_CAPABILITIES = {
322
+ ui: {
323
+ http: true,
324
+ websocket: false,
325
+ // "inline" = JishuShell-side chat UI that POSTs to
326
+ // /api/instances/:id/agent/chat (which forwards to Hermes's own
327
+ // /v1/chat/completions endpoint with the per-instance API_SERVER_KEY).
328
+ // NOT the same as "openclaw" which iframes a full OpenClaw control UI.
329
+ chatPanel: "inline",
330
+ },
331
+ pairing: {
332
+ list: true,
333
+ approve: true,
334
+ // Capability is `false` until the integration, routes, and CLI actually
335
+ // ship revoke / clear-pending surfaces. Declaring them true here
336
+ // with no backing implementation would mislead the UI and any
337
+ // external caller into attempting unreachable operations.
338
+ revoke: false,
339
+ clearPending: false,
340
+ },
341
+ configEditor: "yaml+env",
342
+ configSchema: false,
343
+ customProvider: true,
344
+ pluginInstall: false,
345
+ skills: true,
346
+ mcp: true,
347
+ memory: true,
348
+ backupRestore: false,
349
+ usageStats: false,
350
+ restartlessReload: false,
351
+ messagingPlatforms: [
352
+ "feishu",
353
+ "weixin",
354
+ "telegram",
355
+ "discord",
356
+ "slack",
357
+ "whatsapp",
358
+ "signal",
359
+ "email",
360
+ ],
361
+ };
362
+ const HERMES_AGENT_HOME_SUBDIRS = [
363
+ "cron",
364
+ "sessions",
365
+ "logs",
366
+ "hooks",
367
+ "memories",
368
+ "skills",
369
+ "skins",
370
+ "plans",
371
+ "workspace",
372
+ "home",
373
+ ];
374
+ const HERMES_AGENT_HOME_NESTED_DIRS = [
375
+ ["weixin"],
376
+ ["weixin", "accounts"],
377
+ ["hermes-overlay"],
378
+ ];
379
+ const HERMES_SECRET_ENV_RE = /(KEY|TOKEN|SECRET|PASSWORD)$/i;
380
+ function defaultHermesModelId() {
381
+ const dp = getDefaultLlmProvider();
382
+ const selected = typeof dp?.selectedModelId === "string" ? dp.selectedModelId.trim() : "";
383
+ if (selected)
384
+ return selected;
385
+ const first = Array.isArray(dp?.models) ? dp.models.find((model) => typeof model?.id === "string" && model.id.trim()) : null;
386
+ return first?.id || "default";
387
+ }
388
+ function defaultHermesConfigYaml() {
389
+ // Main agent routes through our `jsproxy` custom provider — honest: we
390
+ // really are an OpenAI-compatible proxy that may sit in front of any
391
+ // upstream (MiniMax/OpenAI/Anthropic/…). Aliasing to any built-in
392
+ // provider name (e.g. `minimax`) would leak upstream-specific request
393
+ // fields to unrelated backends and create surprising breakage.
394
+ //
395
+ // Hermes expects `custom_providers` as a YAML list (each entry an
396
+ // object with a `name` field). See Hermes config schema at
397
+ // https://hermes-agent.nousresearch.com/docs/user-guide/configuration/
398
+ const doc = {
399
+ model: {
400
+ provider: "jsproxy",
401
+ default: defaultHermesModelId(),
402
+ },
403
+ terminal: {
404
+ backend: "local",
405
+ },
406
+ custom_providers: [
407
+ {
408
+ name: "jsproxy",
409
+ base_url: getCoreProxyBaseUrl(),
410
+ api_key: "${JSPROXY_API_KEY}",
411
+ },
412
+ ],
413
+ };
414
+ return YAML.stringify(doc).trimEnd() + "\n";
415
+ }
416
+ function defaultHermesEnvText() {
417
+ // Hermes refuses to bind 0.0.0.0 without an API_SERVER_KEY (safety gate).
418
+ // Generate a random 32-byte hex key per instance so unauthenticated access
419
+ // is impossible even though the host port is published.
420
+ const apiServerKey = randomBytes(32).toString("hex");
421
+ return [
422
+ "API_SERVER_ENABLED=true",
423
+ "API_SERVER_HOST=0.0.0.0",
424
+ `API_SERVER_PORT=${HERMES_CONTAINER_PORT}`,
425
+ `API_SERVER_KEY=${apiServerKey}`,
426
+ // Main agent provider lookup uses JSPROXY_API_KEY (referenced from
427
+ // config.yaml custom_providers). Seeded by ensureInstanceProxyToken.
428
+ "JSPROXY_API_KEY=",
429
+ // OPENAI_BASE_URL + OPENAI_API_KEY are the standard env vars Hermes's
430
+ // `auxiliary_client._try_custom_endpoint` reads to auto-discover a
431
+ // generic OpenAI-compatible endpoint. Pointing them at our jsproxy
432
+ // stops the auxiliary resolution chain from falling through to the
433
+ // Nous Portal (which needs cookie auth and emits a 401 warning at
434
+ // every agent startup). The aux token is a mirror of JSPROXY_API_KEY
435
+ // populated by syncHermesProxyEnv after ensureInstanceProxyToken runs.
436
+ `OPENAI_BASE_URL=${getCoreProxyBaseUrl()}`,
437
+ "OPENAI_API_KEY=",
438
+ // Allow all users for the smoke path; production deployments should
439
+ // configure per-platform allowlists via TELEGRAM_ALLOWED_USERS etc.
440
+ "GATEWAY_ALLOW_ALL_USERS=true",
441
+ "",
442
+ ].join("\n");
443
+ }
444
+ /**
445
+ * After `ensureInstanceProxyToken(instanceId)` writes JSPROXY_API_KEY into
446
+ * the Hermes .env, mirror the same token into OPENAI_API_KEY and make
447
+ * sure OPENAI_BASE_URL points at our jsproxy. This gives the
448
+ * auxiliary_client / vision client / trajectory compressor a valid
449
+ * OpenAI-compatible endpoint to auto-discover, so startup no longer
450
+ * emits the `custom/main requested but no endpoint credentials found`
451
+ * warning + Nous 401. Safe to call repeatedly (idempotent).
452
+ */
453
+ function syncHermesProxyEnv(instanceId) {
454
+ const paths = resolveHermesPaths(instanceId);
455
+ if (!paths.secretEnv || !existsSync(paths.secretEnv))
456
+ return;
457
+ const env = parseEnvFileFromText(readFileSync(paths.secretEnv, "utf-8"));
458
+ const token = env.JSPROXY_API_KEY?.trim();
459
+ if (!token)
460
+ return;
461
+ const updates = {};
462
+ if (env.OPENAI_API_KEY !== token)
463
+ updates.OPENAI_API_KEY = token;
464
+ const expectedBase = getCoreProxyBaseUrl();
465
+ if (env.OPENAI_BASE_URL !== expectedBase)
466
+ updates.OPENAI_BASE_URL = expectedBase;
467
+ if (Object.keys(updates).length === 0)
468
+ return;
469
+ updateEnvFile(paths.secretEnv, updates);
470
+ }
471
+ function syncHermesProviderSecret(instanceId) {
472
+ const paths = resolveHermesPaths(instanceId);
473
+ if (!paths.secretEnv)
474
+ return;
475
+ const providerEnvPath = join(dirname(paths.secretEnv), "provider.env");
476
+ const existing = existsSync(providerEnvPath)
477
+ ? parseEnvFileFromText(readFileSync(providerEnvPath, "utf-8"))
478
+ : {};
479
+ if (existing[UPSTREAM_SECRET_ENV_NAME]?.trim())
480
+ return;
481
+ const dp = getDefaultLlmProvider();
482
+ if (!dp?.id || !dp.apiKey)
483
+ return;
484
+ const meta = getInstance(instanceId);
485
+ if (meta) {
486
+ const providerId = String(meta["x-jishushell"]?.proxy?.upstream?.providerId || "").trim();
487
+ if (providerId && providerId !== dp.id)
488
+ return;
489
+ }
490
+ updateEnvFile(providerEnvPath, { [UPSTREAM_SECRET_ENV_NAME]: dp.apiKey });
491
+ }
492
+ function ensureHermesConfigFiles(paths) {
493
+ if (!paths.primaryConfig || !existsSync(paths.primaryConfig)) {
494
+ writeConfigFile(paths.primaryConfig, defaultHermesConfigYaml());
495
+ }
496
+ if (!paths.secretEnv || !existsSync(paths.secretEnv)) {
497
+ writeSecretFile(paths.secretEnv, defaultHermesEnvText());
498
+ }
499
+ writeHermesEntrypointShim(paths);
500
+ }
501
+ function secretEnvFields(envText) {
502
+ const env = parseEnvFileFromText(envText);
503
+ return Object.keys(env)
504
+ .filter((key) => HERMES_SECRET_ENV_RE.test(key))
505
+ .map((key) => `env.${key}`);
506
+ }
507
+ function parseEnvFileFromText(envText) {
508
+ const env = {};
509
+ for (let line of envText.split("\n")) {
510
+ line = line.trim();
511
+ if (!line || line.startsWith("#"))
512
+ continue;
513
+ if (line.startsWith("export "))
514
+ line = line.slice(7).trimStart();
515
+ if (!line.includes("="))
516
+ continue;
517
+ const eqIdx = line.indexOf("=");
518
+ const key = line.slice(0, eqIdx).trim();
519
+ let value = line.slice(eqIdx + 1).trim();
520
+ if (!key)
521
+ continue;
522
+ if (value.length >= 2 && value[0] === value[value.length - 1] && (value[0] === "'" || value[0] === '"')) {
523
+ value = value.slice(1, -1);
524
+ }
525
+ env[key] = value;
526
+ }
527
+ return env;
528
+ }
529
+ function injectHermesUpstreamKeyStatus(instanceId, config) {
530
+ const merged = structuredClone(config);
531
+ const upstream = merged["x-jishushell"]?.proxy?.upstream;
532
+ if (!upstream || typeof upstream !== "object")
533
+ return merged;
534
+ const paths = resolveHermesPaths(instanceId);
535
+ if (!paths.secretEnv)
536
+ return merged;
537
+ const providerEnvPath = join(dirname(paths.secretEnv), "provider.env");
538
+ if (!existsSync(providerEnvPath))
539
+ return merged;
540
+ const providerEnv = parseEnvFileFromText(readFileSync(providerEnvPath, "utf-8"));
541
+ upstream.hasApiKey = !!String(providerEnv[UPSTREAM_SECRET_ENV_NAME] || "").trim();
542
+ return merged;
543
+ }
544
+ function normalizeEnvText(raw) {
545
+ const trimmed = raw.replace(/\r\n/g, "\n").replace(/\r/g, "\n").trimEnd();
546
+ return trimmed ? `${trimmed}\n` : "";
547
+ }
548
+ function bundledHermesEntrypointPath() {
549
+ return join(dirname(fileURLToPath(import.meta.url)), "../../../../templates/hermes-entrypoint.sh");
550
+ }
551
+ function hermesHostShimPath(paths) {
552
+ return join(paths.integrationHome, "bin", HERMES_HOST_SHIM_NAME);
553
+ }
554
+ function writeHermesEntrypointShim(paths) {
555
+ const target = hermesHostShimPath(paths);
556
+ mkdirSync(dirname(target), { recursive: true });
557
+ const source = readFileSync(bundledHermesEntrypointPath(), "utf-8");
558
+ if (!existsSync(target) || readFileSync(target, "utf-8") !== source) {
559
+ writeFileSync(target, source, { mode: 0o755 });
560
+ }
561
+ chmodSync(target, 0o755);
562
+ return target;
563
+ }
564
+ function ensureHermesRuntimeVolumes(volumes, paths) {
565
+ const next = Array.isArray(volumes) ? [...volumes] : [];
566
+ if (!next.some((volume) => volume.containerPath === HERMES_CONTAINER_HOME)) {
567
+ next.unshift({ hostPath: paths.integrationHome, containerPath: HERMES_CONTAINER_HOME, mode: "rw" });
568
+ }
569
+ const shimPath = writeHermesEntrypointShim(paths);
570
+ if (!next.some((volume) => volume.containerPath === HERMES_CONTAINER_SHIM)) {
571
+ next.push({ hostPath: shimPath, containerPath: HERMES_CONTAINER_SHIM, mode: "ro" });
572
+ }
573
+ return next;
574
+ }
575
+ function resolveHermesRuntimeUser() {
576
+ const serviceUser = resolveServiceUser();
577
+ const uid = serviceUser?.uid ?? process.getuid?.() ?? 1000;
578
+ const gid = serviceUser?.gid ?? process.getgid?.() ?? 1000;
579
+ return `${uid}:${gid}`;
580
+ }
581
+ function sanitizeHermesRuntimeEnv(env) {
582
+ const next = { ...(env ?? {}) };
583
+ delete next.HERMES_UID;
584
+ delete next.HERMES_GID;
585
+ return next;
586
+ }
587
+ /**
588
+ * Resolve the hermes instance filesystem layout. Agent-home lives inside the
589
+ * per-instance directory and is bind-mounted to /opt/data inside the container.
590
+ */
591
+ export function resolveHermesPaths(instanceId) {
592
+ const catalog = getIntegrationRuntimeEntry("hermes");
593
+ const homeDirName = catalog?.homeDirName || "agent-home";
594
+ const resolvedInstanceDir = instanceDir(instanceId);
595
+ const integrationHome = join(resolvedInstanceDir, homeDirName);
596
+ return {
597
+ instanceDir: resolvedInstanceDir,
598
+ integrationHome,
599
+ primaryConfig: join(integrationHome, "config.yaml"),
600
+ secretEnv: join(integrationHome, ".env"),
601
+ };
602
+ }
603
+ function withHermesDefaultUpstream(meta) {
604
+ const dp = getDefaultLlmProvider();
605
+ if (!dp?.id)
606
+ return meta;
607
+ const modelList = Array.isArray(dp.models)
608
+ ? dp.models
609
+ .map((m) => ({
610
+ id: String(m?.id ?? ""),
611
+ name: String(m?.name ?? m?.id ?? ""),
612
+ contextWindow: Number(m?.contextWindow) || 128000,
613
+ }))
614
+ .filter((m) => m.id)
615
+ : [];
616
+ const selectedModelId = String(dp.selectedModelId || modelList[0]?.id || "");
617
+ if (selectedModelId && modelList.every((m) => m.id !== selectedModelId)) {
618
+ modelList.unshift({ id: selectedModelId, name: selectedModelId, contextWindow: 128000 });
619
+ }
620
+ return {
621
+ ...meta,
622
+ "x-jishushell": {
623
+ proxy: {
624
+ upstream: {
625
+ providerId: String(dp.id),
626
+ baseUrl: String(dp.baseUrl || ""),
627
+ api: normalizeProviderApi(dp.api),
628
+ authHeader: dp.authHeader === true,
629
+ headers: {},
630
+ models: modelList,
631
+ selectedModelId,
632
+ apiKey: "",
633
+ hasApiKey: !!dp.apiKey,
634
+ clearApiKey: false,
635
+ },
636
+ },
637
+ },
638
+ };
639
+ }
640
+ async function finalizeHermesCreatedInstance(instanceId) {
641
+ const metaPath = instanceMetaPath(instanceId);
642
+ if (existsSync(metaPath)) {
643
+ const nextMeta = withHermesDefaultUpstream(getInstance(instanceId) ?? {});
644
+ if (nextMeta["x-jishushell"]) {
645
+ updateInstanceMeta(instanceId, { "x-jishushell": nextMeta["x-jishushell"] });
646
+ }
647
+ }
648
+ try {
649
+ ensureInstanceProxyToken(instanceId);
650
+ syncHermesProxyEnv(instanceId);
651
+ syncHermesProviderSecret(instanceId);
652
+ }
653
+ catch (e) {
654
+ console.warn(`[hermes] failed to seed proxy token for ${instanceId}: ${e.message}`);
655
+ }
656
+ const svcUser = resolveServiceUser();
657
+ if (svcUser) {
658
+ try {
659
+ execFileSync("chown", ["-R", `${svcUser.uid}:${svcUser.gid}`, instanceDir(instanceId)], { timeout: 10_000 });
660
+ }
661
+ catch (e) {
662
+ console.warn(`[hermes] chown for ${instanceId} failed:`, e.message);
663
+ }
664
+ }
665
+ }
666
+ /**
667
+ * §17 — find the capability-registry entry that produced a given
668
+ * resolved env URL (e.g. `SEARCH_API_BASE_URL = http://x:8080/search`).
669
+ * Match by host:port (and path when declared). Returns the entry so
670
+ * applyConnectionEnv can read its `toolSchema`. Returns null when no
671
+ * match — caller falls back to the legacy PR 7 path.
672
+ */
673
+ function findSearchProviderForUrl(rawUrl) {
674
+ let parsed;
675
+ try {
676
+ parsed = new URL(rawUrl);
677
+ }
678
+ catch {
679
+ return null;
680
+ }
681
+ const targetHost = parsed.hostname.toLowerCase();
682
+ const targetPort = Number(parsed.port) || (parsed.protocol === "https:" ? 443 : 80);
683
+ const targetPath = parsed.pathname.replace(/\/+$/u, "");
684
+ const snapshot = capabilityRegistry.snapshot().providersByCapability ?? {};
685
+ for (const entries of Object.values(snapshot)) {
686
+ for (const entry of entries) {
687
+ if (entry.kind !== "search" || entry.interface !== "searxng-json")
688
+ continue;
689
+ const entryHost = (entry.host ?? "").toLowerCase();
690
+ const entryPort = entry.hostPort;
691
+ const entryPath = (entry.path ?? "").replace(/\/+$/u, "");
692
+ if (entryPort !== targetPort)
693
+ continue;
694
+ if (entryHost && entryHost !== targetHost) {
695
+ // Tolerate localhost <-> 127.0.0.1 / advertised-host mismatches by
696
+ // accepting any host when the port + path match — env URLs go
697
+ // through the Nomad driver's host rewriting which can disagree with
698
+ // registry's stored host.
699
+ }
700
+ if (entryPath && targetPath && entryPath !== targetPath)
701
+ continue;
702
+ return entry;
703
+ }
704
+ }
705
+ return null;
706
+ }
707
+ class HermesIntegration {
708
+ kind = "hermes";
709
+ displayName = "Hermes Agent";
710
+ defaultCapabilities = DEFAULT_CAPABILITIES;
711
+ preferredHostPort = HERMES_PREFERRED_HOST_PORT;
712
+ manifest = {
713
+ kind: "hermes",
714
+ displayName: "Hermes Agent",
715
+ description: "NousResearch Hermes — Telegram / Discord / Slack / Signal 等 IM 接入",
716
+ defaultCapabilities: DEFAULT_CAPABILITIES,
717
+ requiresNomadDocker: true,
718
+ diskSpaceMB: 5120,
719
+ catalogGroup: "agents",
720
+ catalogIcon: "hermes",
721
+ defaultTab: "chat",
722
+ supportsClone: false,
723
+ connectionRole: "agent",
724
+ defaultConnectionApplyMode: "proxy-upstream",
725
+ requiredForSetupReady: false,
726
+ };
727
+ hooks = {
728
+ onCreatePrepare: async (ctx) => this.prepareInitialLayout(ctx),
729
+ onCreate: async ({ instanceId }) => {
730
+ await finalizeHermesCreatedInstance(instanceId);
731
+ },
732
+ /**
733
+ * Hermes pre-start: verify the docker image retains the official
734
+ * ghcr.io/x-aijishu/hermes-runtime RepoDigest before Nomad receives it.
735
+ * No config patches (the shim bootstraps `.env` / `config.yaml` on first
736
+ * run) and no Nomad Variables template (Hermes reads keys from the
737
+ * bind-mounted `.env`, not from secrets).
738
+ */
739
+ onBeforeStart: async (args) => {
740
+ const catalog = getIntegrationRuntimeEntry("hermes");
741
+ const image = catalog?.defaultImageDigest
742
+ || catalog?.defaultImage;
743
+ if (!image) {
744
+ throw new Error("Hermes runtime is not installed. Run POST /api/setup/install/hermes first.");
745
+ }
746
+ if (!DOCKER_IMAGE_RE.test(image) || image.length > MAX_DOCKER_IMAGE_NAME_LEN) {
747
+ throw new Error(`Invalid Hermes docker image: "${image}"`);
748
+ }
749
+ assertOfficialHermesImage(image);
750
+ // Idempotent migration: pre-alias Hermes instances created before the
751
+ // OPENAI_* env switch still carry only JSPROXY_API_KEY. Every start
752
+ // mirrors that token into OPENAI_API_KEY and pins OPENAI_BASE_URL at
753
+ // the jsproxy so auxiliary_client auto-discovery stops hitting Nous.
754
+ // Safe to re-run on every restart.
755
+ try {
756
+ syncHermesProxyEnv(args.instanceId);
757
+ }
758
+ catch { /* best-effort */ }
759
+ try {
760
+ syncHermesProviderSecret(args.instanceId);
761
+ }
762
+ catch { /* best-effort */ }
763
+ },
764
+ };
765
+ async prepareInitialLayout(ctx) {
766
+ // Prereq validation: Hermes only runs under nomad+docker with a persisted
767
+ // integration runtime record. These checks fire before any FS state is
768
+ // created so a misconfigured host never produces a half-laid-out instance
769
+ // dir.
770
+ // Routes layer detects `InstanceCreationRejected` and returns 409 with
771
+ // `code` / `requestedKind` / `currentServiceManager` / `currentNomadDriver`.
772
+ const coreConfig = getCoreConfig();
773
+ const svcMgr = coreConfig.service_manager || "nomad";
774
+ const driver = coreConfig.nomad_driver || "docker";
775
+ if (svcMgr !== "nomad") {
776
+ throw new InstanceCreationRejected({
777
+ code: "RUNTIME_REQUIRES_NOMAD_DOCKER",
778
+ requestedKind: "hermes",
779
+ currentServiceManager: svcMgr,
780
+ currentNomadDriver: driver,
781
+ hint: `Hermes requires service_manager="nomad" (current: "${svcMgr}"). ` +
782
+ `Switch in core.json or via settings before creating a Hermes instance.`,
783
+ });
784
+ }
785
+ if (driver !== "docker") {
786
+ throw new InstanceCreationRejected({
787
+ code: "RUNTIME_REQUIRES_NOMAD_DOCKER",
788
+ requestedKind: "hermes",
789
+ currentServiceManager: svcMgr,
790
+ currentNomadDriver: driver,
791
+ hint: `Hermes requires nomad_driver="docker" (current: "${driver}").`,
792
+ });
793
+ }
794
+ const catalog = coreConfig.runtime_catalog?.hermes;
795
+ if (!catalog || !catalog.defaultImage) {
796
+ throw new InstanceCreationRejected({
797
+ code: "RUNTIME_PREREQ_MISSING",
798
+ requestedKind: "hermes",
799
+ currentServiceManager: svcMgr,
800
+ currentNomadDriver: driver,
801
+ hint: `Hermes runtime is not installed. Run POST /api/setup/install/hermes first.`,
802
+ });
803
+ }
804
+ const paths = resolveHermesPaths(ctx.instanceId);
805
+ mkdirSync(paths.integrationHome, { recursive: true });
806
+ // Step 5 (bootstrap ownership marker): write the marker immediately
807
+ // after the home directory exists. Hermes's `integrationHome` is
808
+ // always under the per-instance dir (see resolveHermesPaths) so the
809
+ // framework's `deleteInstance` rm already covers cleanup; the marker
810
+ // is written for cross-integration consistency and as defense-in-depth
811
+ // for any future layout that hosts agent-home outside the instance
812
+ // dir. The marker is consulted only at install pre-check / install
813
+ // rollback / uninstall — never by status / start / proxy paths.
814
+ writeOwnershipMarker(paths.integrationHome, {
815
+ instanceId: ctx.instanceId,
816
+ integrationKind: "hermes",
817
+ });
818
+ for (const sub of HERMES_AGENT_HOME_SUBDIRS) {
819
+ mkdirSync(join(paths.integrationHome, sub), { recursive: true });
820
+ }
821
+ for (const segments of HERMES_AGENT_HOME_NESTED_DIRS) {
822
+ mkdirSync(join(paths.integrationHome, ...segments), { recursive: true });
823
+ }
824
+ ensureHermesConfigFiles(paths);
825
+ return paths;
826
+ }
827
+ async buildRuntime(instanceId) {
828
+ const catalog = getIntegrationRuntimeEntry("hermes");
829
+ if (!catalog) {
830
+ throw new Error("Hermes runtime is not installed. Run POST /api/setup/install/hermes first.");
831
+ }
832
+ // Prefer digest over tag for image pinning. When installHermes captured a
833
+ // digest it is stored alongside the tag; integration favors digest.
834
+ const image = catalog.defaultImageDigest
835
+ || catalog.defaultImage;
836
+ if (!image) {
837
+ throw new Error("Hermes integration runtime record missing defaultImage");
838
+ }
839
+ // Only run JishuShell-provided Hermes runtime images. A local tag alone
840
+ // is not enough because anyone can retag an arbitrary image; RepoDigest
841
+ // records that Docker pulled this image from our official repository.
842
+ assertOfficialHermesImage(image);
843
+ const paths = resolveHermesPaths(instanceId);
844
+ ensureHermesConfigFiles(paths);
845
+ // Migrate pre-alias instances (created before the switch to
846
+ // provider:minimax) in-place: mirror JSPROXY_API_KEY into MINIMAX_API_KEY
847
+ // and pin MINIMAX_BASE_URL at the jsproxy. Idempotent — no-op on
848
+ // instances already aligned with the new template.
849
+ try {
850
+ syncHermesProxyEnv(instanceId);
851
+ }
852
+ catch { /* best-effort */ }
853
+ try {
854
+ syncHermesProviderSecret(instanceId);
855
+ }
856
+ catch { /* best-effort */ }
857
+ // Baseline mode is detected by ABSENCE of JISHUSHELL_HERMES_SOURCE_REF.
858
+ // We deliberately do NOT inject this env here. Only the (future) upgrade CLI
859
+ // populates it after a per-instance overlay build.
860
+ const env = {
861
+ API_SERVER_ENABLED: "true",
862
+ API_SERVER_HOST: "0.0.0.0",
863
+ API_SERVER_PORT: String(HERMES_CONTAINER_PORT),
864
+ };
865
+ const resources = catalog.resources && typeof catalog.resources === "object"
866
+ ? {
867
+ CPU: Number(catalog.resources.CPU) || 1000,
868
+ MemoryMB: Number(catalog.resources.MemoryMB) || 1024,
869
+ MemoryMaxMB: catalog.resources.MemoryMaxMB != null
870
+ ? Number(catalog.resources.MemoryMaxMB)
871
+ : undefined,
872
+ }
873
+ : { CPU: 1000, MemoryMB: 1024 };
874
+ return {
875
+ image,
876
+ // Invoke the shim via /bin/bash explicitly instead of execve'ing the
877
+ // script file directly. Debian-based containers always ship /bin/bash,
878
+ // and this bypasses EACCES on execve when bind-mounted script files
879
+ // occasionally lose their exec bit through the container runtime.
880
+ command: "/bin/bash",
881
+ args: [HERMES_CONTAINER_SHIM, "gateway", "run"],
882
+ cwd: HERMES_CONTAINER_WORKDIR,
883
+ user: resolveHermesRuntimeUser(),
884
+ env,
885
+ envFiles: paths.secretEnv ? [paths.secretEnv] : undefined,
886
+ resources,
887
+ volumes: ensureHermesRuntimeVolumes(undefined, paths),
888
+ ports: [
889
+ {
890
+ name: "gateway",
891
+ containerPort: HERMES_CONTAINER_PORT,
892
+ hostPort: 0, // allocated by instance-manager
893
+ visibility: "external",
894
+ },
895
+ ],
896
+ health: {
897
+ type: "http",
898
+ path: "/health",
899
+ port: HERMES_CONTAINER_PORT,
900
+ },
901
+ };
902
+ }
903
+ async getPersistedRuntimeSpec(instanceId) {
904
+ const { getInstanceRuntime } = await import("../../instances/manager.js");
905
+ const persisted = getInstanceRuntime(instanceId);
906
+ if (!persisted || typeof persisted !== "object") {
907
+ throw new Error(`Hermes instance ${instanceId} has no persisted runtime spec`);
908
+ }
909
+ const paths = resolveHermesPaths(instanceId);
910
+ ensureHermesConfigFiles(paths);
911
+ const envFiles = Array.isArray(persisted.envFiles)
912
+ ? [...(persisted.envFiles ?? [])]
913
+ : [];
914
+ if (paths.secretEnv && !envFiles.includes(paths.secretEnv)) {
915
+ envFiles.unshift(paths.secretEnv);
916
+ }
917
+ return {
918
+ ...persisted,
919
+ command: "/bin/bash",
920
+ args: Array.isArray(persisted.args) && persisted.args.length > 0
921
+ ? persisted.args
922
+ : [HERMES_CONTAINER_SHIM, "gateway", "run"],
923
+ cwd: persisted.cwd || HERMES_CONTAINER_WORKDIR,
924
+ user: resolveHermesRuntimeUser(),
925
+ env: sanitizeHermesRuntimeEnv(persisted.env),
926
+ envFiles,
927
+ volumes: ensureHermesRuntimeVolumes(persisted.volumes, paths),
928
+ };
929
+ }
930
+ async buildRuntimeContribution(instanceId) {
931
+ // Opt-in privilege relaxation (per-instance runtime.privileged). Default
932
+ // keeps the hardened container (base cap_drop=ALL / no-new-privileges
933
+ // applied by the workload compiler; Hermes already runs a writable
934
+ // rootfs). When privileged is enabled, the driverConfig deep-merges over
935
+ // that base to drop those hardening flags and passes through host
936
+ // peripheral devices + group_add of their owning gids so the agent reaches
937
+ // cameras / GPU / audio like a native install. Toggle via
938
+ // `jishushell job privileged`.
939
+ const rawRuntime = getInstanceRuntime(instanceId);
940
+ const privileged = rawRuntime.privileged === true;
941
+ const peripherals = privileged
942
+ ? collectPrivilegedDevices(Array.isArray(rawRuntime.devices) ? rawRuntime.devices.map(String) : [])
943
+ : { devices: [], groupAdd: [] };
944
+ if (privileged) {
945
+ console.warn(`[hermes] instance ${instanceId} running with privileged=true — hardening relaxed (default caps, no-new-privileges off); ${peripherals.devices.length} host device(s) passed through, group_add=[${peripherals.groupAdd.join(",")}]`);
946
+ }
947
+ const driverConfig = {
948
+ init: true,
949
+ shm_size: 1073741824,
950
+ mounts: [{ type: "tmpfs", target: "/tmp", tmpfs_options: { size: 536870912 } }],
951
+ ...(privileged
952
+ ? {
953
+ cap_drop: [],
954
+ security_opt: [],
955
+ readonly_rootfs: false,
956
+ ...(peripherals.devices.length > 0 ? { devices: peripherals.devices } : {}),
957
+ ...(peripherals.groupAdd.length > 0 ? { group_add: peripherals.groupAdd } : {}),
958
+ }
959
+ : {}),
960
+ };
961
+ const paths = resolveHermesPaths(instanceId);
962
+ ensureHermesConfigFiles(paths);
963
+ const templates = [];
964
+ if (paths.secretEnv && existsSync(paths.secretEnv)) {
965
+ templates.push({
966
+ DestPath: "secrets/hermes.env",
967
+ Envvars: true,
968
+ EmbeddedTmpl: readFileSync(paths.secretEnv, "utf-8"),
969
+ ChangeMode: "restart",
970
+ });
971
+ }
972
+ return {
973
+ tasks: {
974
+ gateway: {
975
+ driverConfig,
976
+ ...(templates.length > 0 ? { templates } : {}),
977
+ },
978
+ },
979
+ };
980
+ }
981
+ /**
982
+ * Hermes has no `openclaw.json` — it stores upstream metadata directly
983
+ * on instance.json under `x-jishushell`. Return a synthetic stub
984
+ * containing just that block so the LLM proxy's
985
+ * `deriveUpstreamConfig()` finds what it needs.
986
+ */
987
+ getNativeConfig(instanceId) {
988
+ const config = this.getStoredNativeConfig(instanceId);
989
+ if (!config)
990
+ return null;
991
+ return injectHermesUpstreamKeyStatus(instanceId, config);
992
+ }
993
+ getStoredNativeConfig(instanceId) {
994
+ // Lazy import to avoid pulling the full instance-manager into top-level
995
+ // static graph (integrations reach back for framework primitives on demand).
996
+ try {
997
+ const req = createRequire(import.meta.url);
998
+ const im = req("../../instances/manager.js");
999
+ const meta = im.getInstance(instanceId);
1000
+ if (!meta)
1001
+ return null;
1002
+ return { "x-jishushell": meta["x-jishushell"] || {} };
1003
+ }
1004
+ catch {
1005
+ return null;
1006
+ }
1007
+ }
1008
+ /**
1009
+ * Persist the `x-jishushell` meta block to instance.json. Hermes's user-
1010
+ * facing config lives in yaml+env (editable via `writeConfig`), so this
1011
+ * hook is scoped to the meta block only — any other keys in the payload
1012
+ * are ignored intentionally.
1013
+ *
1014
+ * Called by `llm-proxy.saveInstanceConfig` when the editor saves a
1015
+ * per-instance provider override. By implementing the same
1016
+ * `saveNativeConfig(instanceId, {x-jishushell})` contract OpenClaw uses,
1017
+ * Hermes piggy-backs on the shared API key encryption + rollback flow.
1018
+ */
1019
+ saveNativeConfig(instanceId, config) {
1020
+ const xJishushell = config?.["x-jishushell"];
1021
+ if (!xJishushell || typeof xJishushell !== "object")
1022
+ return false;
1023
+ try {
1024
+ const req = createRequire(import.meta.url);
1025
+ const im = req("../../instances/manager.js");
1026
+ if (!im.getInstance(instanceId))
1027
+ return false;
1028
+ im.updateInstanceMeta(instanceId, { "x-jishushell": xJishushell });
1029
+ return true;
1030
+ }
1031
+ catch (e) {
1032
+ console.warn(`[hermes] saveNativeConfig failed for ${instanceId}: ${e.message}`);
1033
+ return false;
1034
+ }
1035
+ }
1036
+ /**
1037
+ * Connection-apply hook: translate resolved bindings into Hermes-native
1038
+ * config.yaml updates.
1039
+ *
1040
+ * Hermes' web tool only supports Firecrawl/Tavily/Exa/Parallel as direct
1041
+ * search backends — it does NOT recognize SearXNG natively. We expose
1042
+ * SearXNG (and any other MCP-shaped capability) to the agent via the
1043
+ * jishushell MCP firewall (see `mcp-shims/firewall.ts`).
1044
+ *
1045
+ * The firewall replaces the upstream package's `tools/list` description
1046
+ * with the canonical wording declared in app yaml's
1047
+ * `provides[].tool_schema` — preventing prompt-injection like the
1048
+ * "news / recent events" + `time_range` slots of upstream `mcp-searxng`,
1049
+ * which was rewriting Chinese queries into English and hallucinating
1050
+ * dates on MiniMax-class models.
1051
+ *
1052
+ * For each `SEARCH_API_BASE_URL` (or future MCP-shaped slot):
1053
+ * 1. Find the producing capability entry in the registry.
1054
+ * 2. If it carries `toolSchema`, drop firewall + config.json into
1055
+ * agent-home and write `mcp_servers.<cap_id>` pointing at it.
1056
+ * 3. If it doesn't (legacy yaml without §17 fields), fall back to
1057
+ * the PR 7 in-tree searxng-shim — kept for one release cycle as
1058
+ * backstop while community apps migrate.
1059
+ *
1060
+ * Other env (OPENAI_API_BASE_URL etc.) is a no-op here; the framework
1061
+ * still injects them through the Nomad driver's runtime env phase
1062
+ * and Hermes picks them up natively.
1063
+ */
1064
+ async applyConnectionEnv(instanceId, env) {
1065
+ const searchUrl = env.SEARCH_API_BASE_URL;
1066
+ if (typeof searchUrl !== "string")
1067
+ return;
1068
+ if (searchUrl === "") {
1069
+ // Empty value = unbind. Strip any connection-managed searxng /
1070
+ // search-* entries from mcp_servers so the next start doesn't keep
1071
+ // routing through a dead provider. We're conservative: only entries
1072
+ // we know we may have written (`searxng` for the legacy shim path,
1073
+ // and any `*_search` shaped key for the §17 firewall path's stable
1074
+ // alias) get removed.
1075
+ try {
1076
+ const paths = resolveHermesPaths(instanceId);
1077
+ if (!paths.primaryConfig || !existsSync(paths.primaryConfig))
1078
+ return;
1079
+ const yamlText = readFileSync(paths.primaryConfig, "utf-8");
1080
+ const parsed = YAML.parse(yamlText) ?? {};
1081
+ if (parsed?.mcp_servers && typeof parsed.mcp_servers === "object") {
1082
+ for (const key of Object.keys(parsed.mcp_servers)) {
1083
+ if (key === "searxng" || /(^|_)search$/.test(key)) {
1084
+ delete parsed.mcp_servers[key];
1085
+ }
1086
+ }
1087
+ }
1088
+ writeConfigFile(paths.primaryConfig, YAML.stringify(parsed).trimEnd() + "\n");
1089
+ }
1090
+ catch (e) {
1091
+ console.warn(`[hermes] applyConnectionEnv unbind failed for ${instanceId}: ${e.message}`);
1092
+ }
1093
+ return;
1094
+ }
1095
+ try {
1096
+ const paths = resolveHermesPaths(instanceId);
1097
+ ensureHermesConfigFiles(paths);
1098
+ const yamlText = readFileSync(paths.primaryConfig, "utf-8");
1099
+ const parsed = YAML.parse(yamlText) ?? {};
1100
+ parsed.mcp_servers = parsed.mcp_servers ?? {};
1101
+ // Try the §17 firewall path first — look up the producer capability
1102
+ // entry to find a tool_schema declared by the provider's yaml.
1103
+ const provider = findSearchProviderForUrl(searchUrl);
1104
+ const svcUser = resolveServiceUser();
1105
+ const serviceUser = svcUser ? { uid: svcUser.uid, gid: svcUser.gid } : undefined;
1106
+ if (provider?.toolSchema) {
1107
+ const upstreamEnv = resolveEnvTemplate(provider.toolSchema.upstream.env_template, env);
1108
+ const entry = writeMcpEntry({
1109
+ integrationHomeDir: paths.integrationHome,
1110
+ containerIntegrationHomeDir: HERMES_CONTAINER_HOME,
1111
+ capabilityId: provider.capability,
1112
+ toolSchema: provider.toolSchema,
1113
+ upstreamEnv,
1114
+ serviceUser,
1115
+ });
1116
+ // mcp_servers map key — use a stable short alias (the bare tool
1117
+ // name) so users editing config.yaml see something readable.
1118
+ const mapKey = provider.toolSchema.name.replace(/_web_search$|_search$/u, "")
1119
+ || provider.capability;
1120
+ parsed.mcp_servers[mapKey] = { ...entry, enabled: true };
1121
+ }
1122
+ else {
1123
+ // Fallback: legacy PR 7 per-capability shim. Strip trailing
1124
+ // /search to get the SearXNG origin for the shim's SEARXNG_URL env.
1125
+ // The URL is re-rendered from the registry on each instance start
1126
+ // (lifecycle connection refresh), so host IP changes are picked
1127
+ // up automatically when the user restarts the consuming agent.
1128
+ let baseUrl = searchUrl;
1129
+ try {
1130
+ const u = new URL(searchUrl);
1131
+ if (u.pathname === "/search" || u.pathname === "/search/") {
1132
+ u.pathname = "";
1133
+ baseUrl = u.toString().replace(/\/$/, "");
1134
+ }
1135
+ }
1136
+ catch {
1137
+ return;
1138
+ }
1139
+ const shimAbsPath = join(paths.integrationHome, SEARXNG_SHIM_REL_PATH);
1140
+ mkdirSync(dirname(shimAbsPath), { recursive: true });
1141
+ writeFileSync(shimAbsPath, SEARXNG_MCP_SHIM_SOURCE, { mode: 0o755 });
1142
+ try {
1143
+ if (serviceUser) {
1144
+ chownSync(dirname(shimAbsPath), serviceUser.uid, serviceUser.gid);
1145
+ chownSync(shimAbsPath, serviceUser.uid, serviceUser.gid);
1146
+ }
1147
+ }
1148
+ catch {
1149
+ /* best-effort */
1150
+ }
1151
+ parsed.mcp_servers.searxng = {
1152
+ command: "node",
1153
+ args: [`${HERMES_CONTAINER_HOME}/${SEARXNG_SHIM_REL_PATH}`],
1154
+ env: { SEARXNG_URL: baseUrl },
1155
+ enabled: true,
1156
+ };
1157
+ }
1158
+ writeConfigFile(paths.primaryConfig, YAML.stringify(parsed).trimEnd() + "\n");
1159
+ }
1160
+ catch (e) {
1161
+ console.warn(`[hermes] applyConnectionEnv failed for ${instanceId}: ${e.message}`);
1162
+ }
1163
+ }
1164
+ listConnectionSideEffectFiles(args) {
1165
+ const paths = resolveHermesPaths(args.instanceId);
1166
+ const integrationHome = paths.integrationHome;
1167
+ const files = new Set([
1168
+ paths.primaryConfig,
1169
+ paths.secretEnv,
1170
+ join(dirname(paths.secretEnv), "provider.env"),
1171
+ join(integrationHome, SEARXNG_SHIM_REL_PATH),
1172
+ ]);
1173
+ for (const binding of args.bindings) {
1174
+ for (const entry of binding.entries) {
1175
+ const shimDir = join(integrationHome, "__mcp_shims__", entry.capability);
1176
+ files.add(join(shimDir, "firewall.mjs"));
1177
+ files.add(join(shimDir, "config.json"));
1178
+ }
1179
+ }
1180
+ return Array.from(files);
1181
+ }
1182
+ async getRuntimeVersion(instanceId) {
1183
+ const catalog = getIntegrationRuntimeEntry("hermes");
1184
+ const digest = catalog?.defaultImageDigest;
1185
+ // Read per-instance SOURCE_REF from instance.json without introducing
1186
+ // a runtime→instance-manager cycle: late require to break the chain.
1187
+ // If the env isn't set, we are in baseline mode.
1188
+ let ref;
1189
+ try {
1190
+ const { getInstance } = await import("../../instances/manager.js");
1191
+ const meta = getInstance(instanceId);
1192
+ const envRef = meta?.runtime?.env?.JISHUSHELL_HERMES_SOURCE_REF;
1193
+ if (typeof envRef === "string" && envRef.trim())
1194
+ ref = envRef.trim();
1195
+ }
1196
+ catch {
1197
+ // best-effort: if instance lookup fails, report baseline
1198
+ }
1199
+ return {
1200
+ integrationKind: "hermes",
1201
+ ref,
1202
+ digest,
1203
+ mode: ref ? "overlay" : "baseline",
1204
+ };
1205
+ }
1206
+ async getConfigMeta(instanceId) {
1207
+ const doc = await this.readConfig(instanceId);
1208
+ return {
1209
+ integrationKind: "hermes",
1210
+ format: "yaml+env",
1211
+ schemaId: "hermes/v1",
1212
+ capabilities: this.defaultCapabilities,
1213
+ secretFields: doc.format === "yaml+env" ? secretEnvFields(doc.env) : [],
1214
+ runtimeVersion: await this.getRuntimeVersion(instanceId),
1215
+ };
1216
+ }
1217
+ async readConfig(instanceId) {
1218
+ const paths = resolveHermesPaths(instanceId);
1219
+ ensureHermesConfigFiles(paths);
1220
+ // Surface the instance.json `x-jishushell` meta block alongside yaml/env
1221
+ // so the Config form can round-trip per-instance upstream provider
1222
+ // overrides through the same ConfigDocument shape OpenClaw uses.
1223
+ const xJishushell = this.getStoredNativeConfig(instanceId)?.["x-jishushell"];
1224
+ const doc = {
1225
+ format: "yaml+env",
1226
+ yaml: readFileSync(paths.primaryConfig, "utf-8"),
1227
+ env: readFileSync(paths.secretEnv, "utf-8"),
1228
+ };
1229
+ if (xJishushell && typeof xJishushell === "object") {
1230
+ doc["x-jishushell"] = xJishushell;
1231
+ }
1232
+ return doc;
1233
+ }
1234
+ async writeConfig(instanceId, doc) {
1235
+ if (doc.format !== "yaml+env") {
1236
+ throw new Error(`Hermes config requires format="yaml+env", got "${doc.format}"`);
1237
+ }
1238
+ YAML.parse(doc.yaml);
1239
+ const envText = normalizeEnvText(doc.env);
1240
+ parseEnvFileFromText(envText);
1241
+ const paths = resolveHermesPaths(instanceId);
1242
+ ensureHermesConfigFiles(paths);
1243
+ // Atomicity: the x-jishushell save path (via llm-proxy.saveInstanceConfig)
1244
+ // can reject for reasons we only learn after some I/O — missing upstream
1245
+ // API key, provider.env write failure, etc. Snapshot the current YAML/ENV
1246
+ // contents BEFORE overwriting them so we can restore on failure and
1247
+ // callers never see a half-applied save (new YAML on disk + rejected
1248
+ // x-jishushell would leave the instance in a dirty state).
1249
+ const priorYaml = readFileSync(paths.primaryConfig, "utf-8");
1250
+ const priorEnv = readFileSync(paths.secretEnv, "utf-8");
1251
+ writeConfigFile(paths.primaryConfig, doc.yaml.trimEnd() + "\n");
1252
+ writeSecretFile(paths.secretEnv, envText);
1253
+ // If the caller included per-instance upstream metadata, route it
1254
+ // through the shared llm-proxy save flow — that path owns API key
1255
+ // encryption, provider.env persistence, rollback on secret failures,
1256
+ // and upstream cache invalidation. We deliberately reuse it instead
1257
+ // of duplicating the logic here so Hermes and OpenClaw agree bit-
1258
+ // for-bit on how per-instance provider config is stored.
1259
+ const xJishushell = doc["x-jishushell"];
1260
+ if (xJishushell && typeof xJishushell === "object") {
1261
+ try {
1262
+ const { saveInstanceConfig } = await import("../../llm-proxy/instance-proxy.js");
1263
+ await saveInstanceConfig(instanceId, { "x-jishushell": xJishushell });
1264
+ }
1265
+ catch (e) {
1266
+ try {
1267
+ writeConfigFile(paths.primaryConfig, priorYaml);
1268
+ writeSecretFile(paths.secretEnv, priorEnv);
1269
+ }
1270
+ catch (rollbackErr) {
1271
+ console.error(`[hermes] CRITICAL: YAML/ENV rollback failed for ${instanceId}:`, rollbackErr?.message || rollbackErr);
1272
+ }
1273
+ throw e;
1274
+ }
1275
+ }
1276
+ return this.readConfig(instanceId);
1277
+ }
1278
+ /**
1279
+ * Persist Feishu/Lark OAuth credentials returned by the device-flow
1280
+ * endpoints. The HTTP route belongs to the OpenClaw integration surface, but
1281
+ * persistence dispatches through the consumer integration here because Hermes
1282
+ * owns its private config/env layout.
1283
+ *
1284
+ * Hermes reads platform config from two places on every gateway start:
1285
+ * - `config.yaml` → `platforms.feishu.enabled` + `platforms.feishu.extra.*`
1286
+ * - `.env` → `FEISHU_APP_ID`, `FEISHU_APP_SECRET`
1287
+ *
1288
+ * We write into BOTH. The YAML holds structural config (enabled flag,
1289
+ * connection mode, domain) and references the secret env vars via
1290
+ * `${...}` interpolation. That way the YAML can be backed up / shared
1291
+ * without leaking credentials, and the real secrets live next to the
1292
+ * .env the user already edits.
1293
+ */
1294
+ saveFeishuCredentials(instanceId, creds) {
1295
+ if (!FEISHU_APP_ID_RE.test(creds.appId)) {
1296
+ throw new Error(`Invalid Feishu appId format: expected cli_<alnum> (got "${creds.appId}")`);
1297
+ }
1298
+ if (!creds.appSecret || typeof creds.appSecret !== "string" || creds.appSecret.length < 4) {
1299
+ throw new Error("Invalid Feishu appSecret: must be a non-empty string");
1300
+ }
1301
+ const domainName = creds.domain === "lark" ? "lark" : "feishu";
1302
+ const paths = resolveHermesPaths(instanceId);
1303
+ ensureHermesConfigFiles(paths);
1304
+ // Merge into existing YAML rather than overwrite — the user may have
1305
+ // customised model/terminal/custom_providers/etc. via the Config tab.
1306
+ const currentYaml = readFileSync(paths.primaryConfig, "utf-8");
1307
+ const parsed = YAML.parse(currentYaml) || {};
1308
+ parsed.platforms = parsed.platforms || {};
1309
+ const prior = parsed.platforms.feishu || {};
1310
+ const priorExtra = prior.extra || {};
1311
+ parsed.platforms.feishu = {
1312
+ ...prior,
1313
+ enabled: true,
1314
+ extra: {
1315
+ ...priorExtra,
1316
+ // Env interpolation: hermes expands ${FOO} at load time against
1317
+ // the process env, which Docker populates from agent-home/.env.
1318
+ app_id: "${FEISHU_APP_ID}",
1319
+ app_secret: "${FEISHU_APP_SECRET}",
1320
+ domain_name: domainName,
1321
+ connection_mode: priorExtra.connection_mode || "websocket",
1322
+ },
1323
+ };
1324
+ writeConfigFile(paths.primaryConfig, YAML.stringify(parsed).trimEnd() + "\n");
1325
+ // Env merge preserves unrelated keys (API_SERVER_KEY, JSPROXY_API_KEY, …).
1326
+ updateEnvFile(paths.secretEnv, {
1327
+ FEISHU_APP_ID: creds.appId,
1328
+ FEISHU_APP_SECRET: creds.appSecret,
1329
+ });
1330
+ console.log(`[hermes] Feishu credentials saved for ${instanceId}, domain=${domainName}`);
1331
+ }
1332
+ /**
1333
+ * Persist WeChat (personal-account) credentials returned by iLink Bot API's QR
1334
+ * login flow. Called from the shared `/api/instances/:id/weixin/login`
1335
+ * handler via `instance-manager.saveWeixinCredentials` → integration dispatch.
1336
+ *
1337
+ * Upstream Hermes's `WeixinAdapter.__init__` scans
1338
+ * `$HERMES_HOME/weixin/accounts/*.json` at startup and auto-connects every
1339
+ * account file it finds, so the handshake we persist here is everything
1340
+ * the runtime needs to come online after an instance restart. The JSON
1341
+ * shape is pinned to upstream's `save_weixin_account` helper:
1342
+ * `{token, base_url, user_id, saved_at}` with mode 0600.
1343
+ *
1344
+ * We also flip `platforms.weixin.enabled: true` in the instance's
1345
+ * config.yaml so the gateway actually tries to connect the integration on
1346
+ * next start (without it, hermes ignores the weixin folder entirely).
1347
+ */
1348
+ saveWeixinCredentials(instanceId, creds) {
1349
+ if (!creds.accountId || !SAFE_WEIXIN_ACCOUNT_ID_RE.test(creds.accountId)) {
1350
+ throw new Error(`Invalid WeChat accountId: must be 1-128 chars of [a-zA-Z0-9@._-], got "${creds.accountId}"`);
1351
+ }
1352
+ if (!creds.token || typeof creds.token !== "string" || creds.token.length < 4) {
1353
+ throw new Error("Invalid WeChat bot token: must be a non-empty string");
1354
+ }
1355
+ const home = resolveHermesPaths(instanceId).integrationHome;
1356
+ const accountsDir = join(home, "weixin", "accounts");
1357
+ ensureDirContainer(accountsDir);
1358
+ // Match upstream `save_weixin_account` exactly — WeixinAdapter reloads
1359
+ // this file at connect time so we can't improvise the field names.
1360
+ const payload = {
1361
+ token: creds.token,
1362
+ base_url: creds.baseUrl,
1363
+ user_id: creds.userId || "",
1364
+ saved_at: new Date().toISOString().replace(/\.\d+Z$/, "Z"),
1365
+ };
1366
+ const accountPath = join(accountsDir, `${creds.accountId}.json`);
1367
+ safeWriteJson(accountPath, payload);
1368
+ try {
1369
+ chmodSync(accountPath, 0o600);
1370
+ }
1371
+ catch { /* best effort */ }
1372
+ // Hermes runs as the `hermes` user inside the container; on the host
1373
+ // the bind-mount is owned by the core service user. `ensureDirContainer`
1374
+ // already handles ownership for the dir — file-level chown is a noop
1375
+ // in the container path and not available as a shared helper here, so
1376
+ // we rely on the directory permissions inheriting to the new file.
1377
+ // Enable platforms.weixin in config.yaml (merge, preserve other keys).
1378
+ // Upstream WeixinAdapter resolves startup credentials in this order at
1379
+ // init time (weixin.py:1066-1067):
1380
+ // token = config.token || extra.token || env WEIXIN_TOKEN
1381
+ // account_id = extra.account_id || env WEIXIN_ACCOUNT_ID
1382
+ // The per-account JSON we wrote above is state storage (refresh
1383
+ // cursor, context token cache), not the startup seed — without the
1384
+ // YAML + env entries below the integration crashes with
1385
+ // "WEIXIN_TOKEN is required".
1386
+ const paths = resolveHermesPaths(instanceId);
1387
+ ensureHermesConfigFiles(paths);
1388
+ const currentYaml = readFileSync(paths.primaryConfig, "utf-8");
1389
+ const parsed = YAML.parse(currentYaml) || {};
1390
+ parsed.platforms = parsed.platforms || {};
1391
+ const prior = parsed.platforms.weixin || {};
1392
+ const priorExtra = prior.extra || {};
1393
+ parsed.platforms.weixin = {
1394
+ ...prior,
1395
+ enabled: true,
1396
+ extra: {
1397
+ ...priorExtra,
1398
+ // Same env-interpolation convention used by the feishu save path:
1399
+ // YAML references ${VAR}, the real value lives in agent-home/.env.
1400
+ account_id: "${WEIXIN_ACCOUNT_ID}",
1401
+ token: "${WEIXIN_TOKEN}",
1402
+ },
1403
+ };
1404
+ writeConfigFile(paths.primaryConfig, YAML.stringify(parsed).trimEnd() + "\n");
1405
+ updateEnvFile(paths.secretEnv, {
1406
+ WEIXIN_ACCOUNT_ID: creds.accountId,
1407
+ WEIXIN_TOKEN: creds.token,
1408
+ });
1409
+ console.log(`[hermes] WeChat credentials saved for ${instanceId}, account=${creds.accountId}`);
1410
+ }
1411
+ /**
1412
+ * List connected WeChat accounts for an instance. Backs the panel UI's
1413
+ * "Connected Accounts" section in WeixinLoginPanel. Tolerates a missing
1414
+ * directory (returns empty) and skips sidecar files the runtime writes
1415
+ * alongside account records (sync buffers + context-token caches).
1416
+ */
1417
+ getWeixinAccounts(instanceId) {
1418
+ const home = resolveHermesPaths(instanceId).integrationHome;
1419
+ if (!home)
1420
+ return [];
1421
+ const accountsDir = join(home, "weixin", "accounts");
1422
+ if (!existsSync(accountsDir))
1423
+ return [];
1424
+ const results = [];
1425
+ for (const f of readdirSync(accountsDir)) {
1426
+ if (!f.endsWith(".json"))
1427
+ continue;
1428
+ // Skip sidecar files written by the runtime (sync cursor + context
1429
+ // token cache). They share the accounts dir but aren't accounts.
1430
+ if (f.endsWith(".sync.json") || f.endsWith(".context-tokens.json"))
1431
+ continue;
1432
+ try {
1433
+ const data = JSON.parse(readFileSync(join(accountsDir, f), "utf-8"));
1434
+ results.push({
1435
+ accountId: f.replace(/\.json$/, ""),
1436
+ userId: typeof data.user_id === "string" ? data.user_id : undefined,
1437
+ savedAt: typeof data.saved_at === "string" ? data.saved_at : undefined,
1438
+ });
1439
+ }
1440
+ catch {
1441
+ /* malformed account file — skip */
1442
+ }
1443
+ }
1444
+ return results;
1445
+ }
1446
+ /**
1447
+ * Rewrite only the host-side published gateway port.
1448
+ *
1449
+ * Hermes keeps listening on a fixed `HERMES_CONTAINER_PORT` inside the
1450
+ * container regardless of how Core publishes it; reallocation only
1451
+ * touches `hostPort`. Missing canonical `runtime.ports[]` is a migration
1452
+ * error for ordinary lifecycle paths.
1453
+ */
1454
+ reallocateRuntimePort(runtime, newPort) {
1455
+ if (Array.isArray(runtime.ports) && runtime.ports.length > 0) {
1456
+ runtime.ports = runtime.ports.map((port, idx) => idx === 0 ? { ...port, hostPort: newPort } : port);
1457
+ return;
1458
+ }
1459
+ throw new Error("[hermes-integration] reallocateRuntimePort: instance is missing canonical "
1460
+ + "runtime.ports[]; run migration or repair before reallocating.");
1461
+ }
1462
+ // Each integration owns its own Nomad job prefix, derived from the agent
1463
+ // type (`hermes-<id>`, `openclaw-<id>`, …). Any new runtime should
1464
+ // declare its own prefix here so job IDs are self-describing and
1465
+ // multiple runtime kinds never collide in the Nomad Raft namespace.
1466
+ nomadJobPrefix = "hermes-";
1467
+ // Startup-only Core configuration normalization. This pins the global
1468
+ // Hermes image reference in core.json; it never reads or writes an instance.
1469
+ normalizeCoreConfigOnStartup() {
1470
+ migrateHermesImageTagIfNeeded();
1471
+ }
1472
+ // Inline chat forwarder dispatch — framework reads this from
1473
+ // `routes/instances.ts:/api/instances/:id/agent/chat`. Declaring the
1474
+ // descriptor (rather than hardcoding API_SERVER_KEY in the route) lets
1475
+ // other OpenAI-compat agents plug in without touching framework code.
1476
+ inlineChatDescriptor = {
1477
+ apiKeyEnvVar: "API_SERVER_KEY",
1478
+ endpointPath: "/v1/chat/completions",
1479
+ };
1480
+ async buildPairingListCommand(_instanceId) {
1481
+ return ["hermes", "pairing", "list"];
1482
+ }
1483
+ async buildPairingApproveCommand(_instanceId, input) {
1484
+ return ["hermes", "pairing", "approve", input.channel, input.code];
1485
+ }
1486
+ // ── Legacy runtime install (aligned with OpenClaw pull flow) ──────────
1487
+ //
1488
+ // Pull-only flow — no local Dockerfile build fallback. Hermes ships as
1489
+ // a ~2.4 GB pre-built image on GHCR; building from upstream source on
1490
+ // a Raspberry Pi would take 20+ minutes and almost always fails on
1491
+ // resource-constrained hardware. If the pull fails we return a clear
1492
+ // error so the user can fix network / registry access rather than
1493
+ // silently burning an hour on a futile source build.
1494
+ //
1495
+ // Steps:
1496
+ // 1. docker image inspect — reuse existing local image if present
1497
+ // 2. docker pull ghcr.io/x-aijishu/hermes-runtime:latest
1498
+ // 3. capture RepoDigest for digest pinning (best-effort)
1499
+ // 4. Copy templates/hermes-entrypoint.sh to ~/.jishushell/runtimes/hermes/
1500
+ // 5. Write integration runtime record into core.json.runtime_catalog
1501
+ async installRuntime(_opts) {
1502
+ const task = createTask("hermes");
1503
+ try {
1504
+ await this.prepareHermesWithTask(task);
1505
+ if (task.status === "error") {
1506
+ return {
1507
+ ok: false,
1508
+ message: "Hermes installation failed",
1509
+ taskId: task.id,
1510
+ };
1511
+ }
1512
+ return {
1513
+ ok: true,
1514
+ message: "Hermes runtime installed",
1515
+ taskId: task.id,
1516
+ };
1517
+ }
1518
+ catch (e) {
1519
+ emitTask(task, { type: "error", message: `Hermes 安装失败: ${e.message}` });
1520
+ task.status = "error";
1521
+ return {
1522
+ ok: false,
1523
+ message: "Hermes installation failed",
1524
+ error: e.message,
1525
+ taskId: task.id,
1526
+ };
1527
+ }
1528
+ }
1529
+ /**
1530
+ * Non-blocking variant — returns a task id immediately and runs the
1531
+ * install in the background. Matches OpenClaw's startBuildRuntimeImage.
1532
+ */
1533
+ startInstallRuntime(_opts) {
1534
+ const task = createTask("hermes");
1535
+ this.prepareHermesWithTask(task).catch((e) => {
1536
+ // Mirror errors to stderr so post-mortem via journalctl works.
1537
+ // Task events live in memory and vanish after TASK_MAX_AGE / core
1538
+ // restart — leaving us blind if the UI stops polling before the
1539
+ // failure arrives.
1540
+ console.error(`[hermes] install failed (task=${task.id}):`, e?.stack || e?.message || e);
1541
+ emitTask(task, { type: "error", message: `Hermes 安装失败: ${e?.message || e}` });
1542
+ task.status = "error";
1543
+ });
1544
+ return { ok: true, message: "Hermes install started", taskId: task.id };
1545
+ }
1546
+ /**
1547
+ * Shared helper that pulls (or builds) the Hermes runtime image and
1548
+ * finalises the integration runtime record. Mirrors OpenClaw's
1549
+ * `pullOrBuildOpenclawImageWithTask` so both runtimes expose the same
1550
+ * install UX (local → pull → fallback build → digest pin).
1551
+ */
1552
+ async prepareHermesWithTask(task) {
1553
+ emitTask(task, { type: "progress", message: "准备 Hermes runtime...", progress: 0 });
1554
+ const invocation = resolveDockerInvocation();
1555
+ // Always pull. When the image is already local and up-to-date with
1556
+ // upstream, docker pull returns in a few seconds after a registry
1557
+ // digest check — the trade is worthwhile because it keeps "reinstall"
1558
+ // from turning into a three-second no-op. Failures are clearly
1559
+ // reported instead of silently retrying with a local fallback: Hermes
1560
+ // cannot be built locally (Python toolchain + wheels OOMs on Pi).
1561
+ emitTask(task, {
1562
+ type: "progress",
1563
+ message: `拉取 Hermes 镜像: ${HERMES_DEFAULT_IMAGE} (已缓存时约 10s)...`,
1564
+ progress: 10,
1565
+ });
1566
+ const pull = await spawnWithTask(task, invocation.cmd, [...invocation.argsPrefix, "pull", HERMES_DEFAULT_IMAGE], { timeout: 1800000 });
1567
+ if (!pull.ok) {
1568
+ console.error(`[hermes] docker pull failed for ${HERMES_DEFAULT_IMAGE} — output follows:\n${pull.output}`);
1569
+ emitTask(task, {
1570
+ type: "error",
1571
+ message: `Hermes 镜像拉取失败。请检查网络/registry 认证,或手动执行: docker pull ${HERMES_DEFAULT_IMAGE}`,
1572
+ });
1573
+ task.status = "error";
1574
+ return;
1575
+ }
1576
+ // 3. capture digest (best-effort)
1577
+ emitTask(task, { type: "progress", message: "捕获镜像 digest...", progress: 75 });
1578
+ const digest = captureImageDigest(HERMES_DEFAULT_IMAGE);
1579
+ if (digest) {
1580
+ emitTask(task, { type: "log", message: `Digest: ${digest}` });
1581
+ }
1582
+ else {
1583
+ emitTask(task, {
1584
+ type: "log",
1585
+ message: "No RepoDigest available (local build); will use :latest tag",
1586
+ });
1587
+ }
1588
+ // 4. pin the mutable tag to the image's LABEL version (e.g.
1589
+ // ghcr.io/…:latest → ghcr.io/…:0.10.0). Parity with OpenClaw's
1590
+ // migrateOpenclawImageTagIfNeeded: keeps core.json referencing an
1591
+ // immutable tag so nothing — Nomad image_pull, doctor, UI — ever
1592
+ // sees a mutable alias after install. No-op when the image was
1593
+ // locally built or lacks the LABEL.
1594
+ emitTask(task, { type: "progress", message: "锁定镜像版本标签...", progress: 85 });
1595
+ const pinnedTag = pinHermesImageToLabeledVersion(HERMES_DEFAULT_IMAGE);
1596
+ const storedImage = pinnedTag ?? HERMES_DEFAULT_IMAGE;
1597
+ if (pinnedTag) {
1598
+ emitTask(task, { type: "log", message: `Pinned tag: ${pinnedTag}` });
1599
+ }
1600
+ // 5. persist integration runtime record
1601
+ // The shim is baked into the image (see Dockerfile.hermes-slim's
1602
+ // COPY / LABEL). No host-side shim install needed anymore — we
1603
+ // verify the official RepoDigest at buildRuntime()/onBeforeStart time.
1604
+ emitTask(task, { type: "progress", message: "写入 integration runtime record...", progress: 95 });
1605
+ setIntegrationRuntimeEntry("hermes", {
1606
+ ...HERMES_CATALOG_DEFAULTS,
1607
+ defaultImage: storedImage,
1608
+ ...(digest ? { defaultImageDigest: digest } : {}),
1609
+ });
1610
+ emitTask(task, {
1611
+ type: "done",
1612
+ message: digest
1613
+ ? `Hermes 安装完成, 镜像已 pin 到 digest (tag=${storedImage})`
1614
+ : `Hermes 安装完成 (tag=${storedImage})`,
1615
+ progress: 100,
1616
+ });
1617
+ task.status = "done";
1618
+ }
1619
+ /**
1620
+ * Hermes readiness: the image must retain an official RepoDigest from
1621
+ * ghcr.io/x-aijishu/hermes-runtime. This accepts images pulled directly
1622
+ * from our registry (and docker save/load copies that preserve RepoDigests)
1623
+ * while rejecting arbitrary local retags that only look like Hermes runtime.
1624
+ */
1625
+ getInstallStatus() {
1626
+ const entry = getIntegrationRuntimeEntry("hermes");
1627
+ const storedImage = typeof entry?.defaultImage === "string" ? entry.defaultImage.trim() : "";
1628
+ if (storedImage) {
1629
+ const digest = readOfficialHermesRepoDigest(storedImage);
1630
+ if (digest) {
1631
+ return {
1632
+ installed: true,
1633
+ imageReady: true,
1634
+ version: imageTagVersion(storedImage),
1635
+ digest: entry?.defaultImageDigest ?? digest,
1636
+ };
1637
+ }
1638
+ const localImage = findLocalHermesImage();
1639
+ if (localImage) {
1640
+ persistHermesCatalogForImage(localImage.image, entry, localImage.digest);
1641
+ return {
1642
+ installed: true,
1643
+ imageReady: true,
1644
+ version: imageTagVersion(localImage.image),
1645
+ digest: localImage.digest,
1646
+ };
1647
+ }
1648
+ return {
1649
+ installed: true,
1650
+ imageReady: false,
1651
+ version: imageTagVersion(storedImage),
1652
+ digest: entry?.defaultImageDigest,
1653
+ };
1654
+ }
1655
+ const localImage = findLocalHermesImage();
1656
+ if (!localImage)
1657
+ return { installed: false, imageReady: false };
1658
+ persistHermesCatalogForImage(localImage.image, entry, localImage.digest);
1659
+ return {
1660
+ installed: true,
1661
+ imageReady: true,
1662
+ version: imageTagVersion(localImage.image),
1663
+ digest: localImage.digest,
1664
+ };
1665
+ }
1666
+ }
1667
+ export const hermesIntegration = new HermesIntegration();
1668
+ registerIntegration(hermesIntegration);
1669
+ //# sourceMappingURL=integration.js.map