@shadowob/cloud 1.1.6-dev.311

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 (334) hide show
  1. package/README.md +509 -0
  2. package/dist/agent-browser-CERTMCDL.js +117 -0
  3. package/dist/agent-browser-CIRZRIY4.js +118 -0
  4. package/dist/agent-pack-LF3O5TR4.js +1236 -0
  5. package/dist/agent-pack-RQT27V7R.js +1235 -0
  6. package/dist/airtable-BG2Q75G2.js +82 -0
  7. package/dist/airtable-JCQXFM5D.js +83 -0
  8. package/dist/alipay-MZX2XCDB.js +52 -0
  9. package/dist/alipay-TZQI34RB.js +51 -0
  10. package/dist/amap-5RQB3VGC.js +45 -0
  11. package/dist/amap-KPCLZYYL.js +44 -0
  12. package/dist/atlassian-LGOEWYC7.js +54 -0
  13. package/dist/atlassian-TVS2A4IU.js +55 -0
  14. package/dist/baidu-appbuilder-6UMESXHW.js +41 -0
  15. package/dist/baidu-appbuilder-QRRL3ETM.js +42 -0
  16. package/dist/baidu-maps-HEPMVP5D.js +44 -0
  17. package/dist/baidu-maps-HXC4FBVP.js +45 -0
  18. package/dist/baidu-netdisk-G5Q6B5NH.js +45 -0
  19. package/dist/baidu-netdisk-RS2K5W2M.js +44 -0
  20. package/dist/baidu-smartprogram-EWTK5WKK.js +41 -0
  21. package/dist/baidu-smartprogram-JHD3XWF6.js +40 -0
  22. package/dist/browserbase-IUIYVYI7.js +67 -0
  23. package/dist/browserbase-JFO2PCIA.js +68 -0
  24. package/dist/canva-3YOFL7JS.js +62 -0
  25. package/dist/canva-FMYN65SM.js +61 -0
  26. package/dist/chunk-6P2K6QZR.js +529 -0
  27. package/dist/chunk-7VMRQ7MG.js +90 -0
  28. package/dist/chunk-AD3JTIU3.js +17 -0
  29. package/dist/chunk-BF6CV2Y4.js +64 -0
  30. package/dist/chunk-CTNUKOQE.js +439 -0
  31. package/dist/chunk-EEFMJYKB.js +97 -0
  32. package/dist/chunk-EJKFQ35I.js +739 -0
  33. package/dist/chunk-HUICDC56.js +62 -0
  34. package/dist/chunk-JUPAE5IA.js +527 -0
  35. package/dist/chunk-JY2HTT7Q.js +437 -0
  36. package/dist/chunk-KEPTCLUO.js +121 -0
  37. package/dist/chunk-KKK5H7YX.js +3622 -0
  38. package/dist/chunk-POSVEKIY.js +210 -0
  39. package/dist/chunk-QET4LT4J.js +5769 -0
  40. package/dist/chunk-QV4XWO3P.js +30 -0
  41. package/dist/chunk-R52J3PH2.js +120 -0
  42. package/dist/chunk-R5U7XKVJ.js +16 -0
  43. package/dist/chunk-RECNVWMT.js +212 -0
  44. package/dist/chunk-RTPBU5HF.js +92 -0
  45. package/dist/chunk-SUZ2ATT6.js +5774 -0
  46. package/dist/chunk-SVMXSIMG.js +98 -0
  47. package/dist/chunk-TV3CBM7R.js +28 -0
  48. package/dist/chunk-V2LU736V.js +3495 -0
  49. package/dist/chunk-ZUYL3W53.js +741 -0
  50. package/dist/claude-plugin-577TAQVS.js +1463 -0
  51. package/dist/claude-plugin-L3MXJJ6J.js +1464 -0
  52. package/dist/cli.js +7021 -0
  53. package/dist/cloudflare-HBBABPK6.js +114 -0
  54. package/dist/cloudflare-RDFPKMM5.js +115 -0
  55. package/dist/cnb-FLP3QX46.js +44 -0
  56. package/dist/cnb-YAVVEYFB.js +45 -0
  57. package/dist/console/index.html +12 -0
  58. package/dist/console/logo.png +0 -0
  59. package/dist/console/static/css/5079.f9e0918d.css +1 -0
  60. package/dist/console/static/css/index.7f91f806.css +1 -0
  61. package/dist/console/static/font/codicon.5b7d6fac.ttf +0 -0
  62. package/dist/console/static/js/5079.72a51ca2.js +699 -0
  63. package/dist/console/static/js/5079.72a51ca2.js.LICENSE.txt +35 -0
  64. package/dist/console/static/js/7426.f8d483ea.js +1 -0
  65. package/dist/console/static/js/async/1008.4df521b7.js +1 -0
  66. package/dist/console/static/js/async/102.1d473ec7.js +1 -0
  67. package/dist/console/static/js/async/1134.3f9fd9e7.js +1 -0
  68. package/dist/console/static/js/async/1318.4b8e48e7.js +1 -0
  69. package/dist/console/static/js/async/1360.5606da88.js +7 -0
  70. package/dist/console/static/js/async/1546.045f484f.js +1 -0
  71. package/dist/console/static/js/async/1562.187de2a8.js +1 -0
  72. package/dist/console/static/js/async/168.456d4813.js +1 -0
  73. package/dist/console/static/js/async/1750.e6dc2664.js +1 -0
  74. package/dist/console/static/js/async/1994.3fc86066.js +1 -0
  75. package/dist/console/static/js/async/2348.613ae3d9.js +1 -0
  76. package/dist/console/static/js/async/2390.1b890b9d.js +1 -0
  77. package/dist/console/static/js/async/2414.9d040212.js +1 -0
  78. package/dist/console/static/js/async/2454.4c1784ab.js +1 -0
  79. package/dist/console/static/js/async/2498.f5f92030.js +1 -0
  80. package/dist/console/static/js/async/2924.b823cd1a.js +1 -0
  81. package/dist/console/static/js/async/3062.63fddea6.js +1 -0
  82. package/dist/console/static/js/async/3078.dd712008.js +1 -0
  83. package/dist/console/static/js/async/3198.1f307065.js +1 -0
  84. package/dist/console/static/js/async/3246.3d5a899f.js +1 -0
  85. package/dist/console/static/js/async/3286.871676eb.js +1 -0
  86. package/dist/console/static/js/async/342.10bf3b90.js +1 -0
  87. package/dist/console/static/js/async/3446.9681a4d7.js +1 -0
  88. package/dist/console/static/js/async/3698.ccfaabec.js +1 -0
  89. package/dist/console/static/js/async/3790.2a1106a6.js +1 -0
  90. package/dist/console/static/js/async/4231.b29784d4.js +1 -0
  91. package/dist/console/static/js/async/4551.515bd41d.js +1 -0
  92. package/dist/console/static/js/async/4596.40f6e71b.js +1 -0
  93. package/dist/console/static/js/async/4600.4aaebe6d.js +1 -0
  94. package/dist/console/static/js/async/4718.1aae022f.js +1 -0
  95. package/dist/console/static/js/async/4846.a347c020.js +1 -0
  96. package/dist/console/static/js/async/4860.83dadf89.js +1 -0
  97. package/dist/console/static/js/async/500.fcfa37cb.js +1 -0
  98. package/dist/console/static/js/async/5096.b360203d.js +1 -0
  99. package/dist/console/static/js/async/5222.043274fe.js +1 -0
  100. package/dist/console/static/js/async/5362.f498001c.js +1 -0
  101. package/dist/console/static/js/async/54.c94f0755.js +1 -0
  102. package/dist/console/static/js/async/5478.50dd9ef0.js +2 -0
  103. package/dist/console/static/js/async/5478.50dd9ef0.js.LICENSE.txt +3 -0
  104. package/dist/console/static/js/async/5507.a6a1f793.js +1 -0
  105. package/dist/console/static/js/async/5638.bc6b102d.js +1 -0
  106. package/dist/console/static/js/async/5722.e0029049.js +1 -0
  107. package/dist/console/static/js/async/5942.74635c6b.js +1 -0
  108. package/dist/console/static/js/async/5994.1c5629c1.js +1 -0
  109. package/dist/console/static/js/async/6054.6bddf720.js +1 -0
  110. package/dist/console/static/js/async/6118.45e754e5.js +1 -0
  111. package/dist/console/static/js/async/6127.adcbcbb6.js +1 -0
  112. package/dist/console/static/js/async/614.3f434c20.js +1 -0
  113. package/dist/console/static/js/async/6234.ba3b002d.js +1 -0
  114. package/dist/console/static/js/async/6310.6546a9ba.js +1 -0
  115. package/dist/console/static/js/async/6378.9f805419.js +1 -0
  116. package/dist/console/static/js/async/6380.e4433c49.js +1 -0
  117. package/dist/console/static/js/async/6418.f23bcfda.js +1 -0
  118. package/dist/console/static/js/async/6428.77c86114.js +1 -0
  119. package/dist/console/static/js/async/6443.83318a6c.js +1 -0
  120. package/dist/console/static/js/async/6508.2b445d62.js +3 -0
  121. package/dist/console/static/js/async/6542.e82a26c8.js +1 -0
  122. package/dist/console/static/js/async/6544.62111ecb.js +1 -0
  123. package/dist/console/static/js/async/6612.a0c9fcf4.js +1 -0
  124. package/dist/console/static/js/async/6740.695aebf0.js +1 -0
  125. package/dist/console/static/js/async/6822.dbbb32bc.js +1 -0
  126. package/dist/console/static/js/async/6824.ad3540ab.js +1 -0
  127. package/dist/console/static/js/async/6930.585dab94.js +1 -0
  128. package/dist/console/static/js/async/6982.c81b95e6.js +1 -0
  129. package/dist/console/static/js/async/7046.ab2378c1.js +1 -0
  130. package/dist/console/static/js/async/7110.a603277f.js +1 -0
  131. package/dist/console/static/js/async/7142.4a21366f.js +1 -0
  132. package/dist/console/static/js/async/7348.15cc6148.js +1373 -0
  133. package/dist/console/static/js/async/7348.15cc6148.js.LICENSE.txt +14 -0
  134. package/dist/console/static/js/async/7374.b1ac5c44.js +1 -0
  135. package/dist/console/static/js/async/742.847f17ca.js +1 -0
  136. package/dist/console/static/js/async/7446.743954d8.js +1 -0
  137. package/dist/console/static/js/async/7673.59bbbaac.js +1 -0
  138. package/dist/console/static/js/async/7684.c5760c8c.js +1 -0
  139. package/dist/console/static/js/async/7714.c30d0f94.js +1 -0
  140. package/dist/console/static/js/async/8118.36d5a3bf.js +298 -0
  141. package/dist/console/static/js/async/8145.4bcf043a.js +1 -0
  142. package/dist/console/static/js/async/8246.408de938.js +1 -0
  143. package/dist/console/static/js/async/8390.bdae1f7d.js +1 -0
  144. package/dist/console/static/js/async/8422.fd94dbe1.js +1 -0
  145. package/dist/console/static/js/async/8434.94a0e2ae.js +1 -0
  146. package/dist/console/static/js/async/8518.3158de13.js +1 -0
  147. package/dist/console/static/js/async/8564.fc2eb841.js +1 -0
  148. package/dist/console/static/js/async/8678.73af4c9b.js +1 -0
  149. package/dist/console/static/js/async/8694.79747168.js +1 -0
  150. package/dist/console/static/js/async/8756.1de37b83.js +1 -0
  151. package/dist/console/static/js/async/8804.7fe6bdf9.js +3 -0
  152. package/dist/console/static/js/async/8883.e717ee94.js +1 -0
  153. package/dist/console/static/js/async/8886.fe6e876c.js +1 -0
  154. package/dist/console/static/js/async/9030.fc1ae402.js +1 -0
  155. package/dist/console/static/js/async/9094.5598d084.js +1 -0
  156. package/dist/console/static/js/async/9218.ee7b84b7.js +1 -0
  157. package/dist/console/static/js/async/94.9b80bc35.js +1 -0
  158. package/dist/console/static/js/async/9526.92aba34c.js +1 -0
  159. package/dist/console/static/js/async/9762.f83bc4f3.js +1 -0
  160. package/dist/console/static/js/async/984.e11c113a.js +1 -0
  161. package/dist/console/static/js/async/9846.246653cd.js +1 -0
  162. package/dist/console/static/js/index.4487e1ff.js +1 -0
  163. package/dist/console/static/js/lib-react.15d7ca9a.js +2 -0
  164. package/dist/console/static/js/lib-react.15d7ca9a.js.LICENSE.txt +49 -0
  165. package/dist/coze-C6PMDPBI.js +49 -0
  166. package/dist/coze-E6VGRNLV.js +48 -0
  167. package/dist/dashboard.command-J7XOZNXU.js +8 -0
  168. package/dist/dashboard.command-RV2NHDKW.js +7 -0
  169. package/dist/dingtalk-JNRNRN7E.js +77 -0
  170. package/dist/dingtalk-WZGGIAHJ.js +76 -0
  171. package/dist/douyin-miniprogram-AIJPPIZH.js +41 -0
  172. package/dist/douyin-miniprogram-HCYZ5NBW.js +42 -0
  173. package/dist/figma-2YYNSCDX.js +103 -0
  174. package/dist/figma-RYOBMENP.js +102 -0
  175. package/dist/firebase-2IJDDBXX.js +112 -0
  176. package/dist/firebase-OYSY6HPT.js +111 -0
  177. package/dist/firecrawl-2T3SBUW7.js +66 -0
  178. package/dist/firecrawl-IYYXLAZM.js +65 -0
  179. package/dist/flyai-7FJ4TRAG.js +81 -0
  180. package/dist/flyai-QS5Q6FJR.js +82 -0
  181. package/dist/gitagent-MWI75OIX.js +725 -0
  182. package/dist/gitagent-YBMWY7NZ.js +726 -0
  183. package/dist/gitee-3N7OFOM7.js +53 -0
  184. package/dist/gitee-KVNK6KLZ.js +54 -0
  185. package/dist/github-LUEC2LID.js +143 -0
  186. package/dist/github-XRO5Z3GC.js +142 -0
  187. package/dist/google-ads-A3QAJI4D.js +88 -0
  188. package/dist/google-ads-VPKWTX67.js +89 -0
  189. package/dist/google-analytics-C4UR5ZR2.js +50 -0
  190. package/dist/google-analytics-XDYZA2B7.js +49 -0
  191. package/dist/google-workspace-LL3EWVHH.js +320 -0
  192. package/dist/google-workspace-YX35SHHX.js +321 -0
  193. package/dist/huawei-xiaoyi-6BSMGJHR.js +40 -0
  194. package/dist/huawei-xiaoyi-KPWLTSHB.js +41 -0
  195. package/dist/hubspot-DIUHGEDI.js +45 -0
  196. package/dist/hubspot-FTIEMNZO.js +44 -0
  197. package/dist/huggingface-MJCOXA7E.js +116 -0
  198. package/dist/huggingface-UUXK2RHK.js +117 -0
  199. package/dist/index.d.ts +3013 -0
  200. package/dist/index.js +15649 -0
  201. package/dist/inference-ai-image-generation-CMI6R5T3.js +106 -0
  202. package/dist/inference-ai-image-generation-PXV6IG4U.js +107 -0
  203. package/dist/inference-sh-7AZOLEFI.js +94 -0
  204. package/dist/inference-sh-ABQOD3YF.js +95 -0
  205. package/dist/init.command-6E24K4H3.js +9 -0
  206. package/dist/init.command-O4HG4HKR.js +10 -0
  207. package/dist/klaviyo-6K5YEFNH.js +45 -0
  208. package/dist/klaviyo-LDPBWBSS.js +44 -0
  209. package/dist/kuaidi100-HGFM5VK2.js +42 -0
  210. package/dist/kuaidi100-UHPFCVXP.js +41 -0
  211. package/dist/lark-6LNA3LUQ.js +103 -0
  212. package/dist/lark-URVBZNS4.js +102 -0
  213. package/dist/linear-7QFSFPOD.js +57 -0
  214. package/dist/linear-T4ORUP7N.js +56 -0
  215. package/dist/lovart-PDUXRUHJ.js +99 -0
  216. package/dist/lovart-QO3SK55T.js +100 -0
  217. package/dist/meta-ads-SCNFI45S.js +42 -0
  218. package/dist/meta-ads-V6XPZWX3.js +41 -0
  219. package/dist/miclaw-5CNTW7VV.js +36 -0
  220. package/dist/miclaw-TPPPS2WN.js +35 -0
  221. package/dist/model-provider-AVSFJSZP.js +393 -0
  222. package/dist/model-provider-KFB76XV5.js +392 -0
  223. package/dist/notion-FZK76MN2.js +69 -0
  224. package/dist/notion-WFA7KGZZ.js +70 -0
  225. package/dist/oceanengine-3JZUS3PP.js +43 -0
  226. package/dist/oceanengine-5BRIJVJE.js +42 -0
  227. package/dist/opencli-PFXHGCS2.js +81 -0
  228. package/dist/opencli-VIGRJTGH.js +80 -0
  229. package/dist/paypal-33UADIPR.js +54 -0
  230. package/dist/paypal-Z5JYHIWD.js +55 -0
  231. package/dist/playwright-MG5WHK47.js +58 -0
  232. package/dist/playwright-SQAQ3DZG.js +59 -0
  233. package/dist/plugins-HZBWK3WQ.js +120 -0
  234. package/dist/plugins-I4GD5SZX.js +121 -0
  235. package/dist/posthog-MU5MAJOQ.js +79 -0
  236. package/dist/posthog-RJRRKDWB.js +80 -0
  237. package/dist/salesforce-34FVIJTG.js +82 -0
  238. package/dist/salesforce-3QZ6OFVO.js +83 -0
  239. package/dist/sentry-MCIRMACU.js +111 -0
  240. package/dist/sentry-PIWW46VA.js +110 -0
  241. package/dist/seo-suite-4SQ3I67Q.js +54 -0
  242. package/dist/seo-suite-WJXMA3S4.js +55 -0
  243. package/dist/serve.command-5FMIPQRY.js +10 -0
  244. package/dist/serve.command-DNE6GPMK.js +9 -0
  245. package/dist/shadowob-JELOWHWX.js +1068 -0
  246. package/dist/shadowob-PRSMI5MW.js +1069 -0
  247. package/dist/sherlock-2PKY2E2Y.js +66 -0
  248. package/dist/sherlock-C5ZWPPVT.js +67 -0
  249. package/dist/shopify-GL3NFVGE.js +94 -0
  250. package/dist/shopify-R4G3UXM6.js +93 -0
  251. package/dist/skill-discovery-7INAUP4D.js +77 -0
  252. package/dist/skill-discovery-YPXXV622.js +78 -0
  253. package/dist/state-7MCZBTR5.js +17 -0
  254. package/dist/state-FGOFLFBE.js +18 -0
  255. package/dist/stripe-C22RR4ZS.js +83 -0
  256. package/dist/stripe-LJNPQ3CQ.js +82 -0
  257. package/dist/supabase-IRNQ54FJ.js +98 -0
  258. package/dist/supabase-N4ONFJNQ.js +97 -0
  259. package/dist/taobao-aipaas-LRR4GMO3.js +45 -0
  260. package/dist/taobao-aipaas-RVKORSF4.js +46 -0
  261. package/dist/tapd-3JPVJ7XH.js +46 -0
  262. package/dist/tapd-TMQRSMFG.js +47 -0
  263. package/dist/tencent-ads-IGD33LO7.js +42 -0
  264. package/dist/tencent-ads-UHC6OPBV.js +43 -0
  265. package/dist/tencent-docs-C3A4J3CJ.js +47 -0
  266. package/dist/tencent-docs-O2SC4FHL.js +48 -0
  267. package/dist/tencent-maps-HMMWMNF4.js +37 -0
  268. package/dist/tencent-maps-OQOKHVW2.js +36 -0
  269. package/dist/vercel-KOXDDTHX.js +73 -0
  270. package/dist/vercel-OLNVDWMG.js +74 -0
  271. package/dist/webflow-FULU5Q2I.js +114 -0
  272. package/dist/webflow-OMJKZM54.js +115 -0
  273. package/dist/wechat-miniprogram-skyline-KYCDMQNW.js +74 -0
  274. package/dist/wechat-miniprogram-skyline-VR4FVIQL.js +75 -0
  275. package/dist/wechat-pay-BCMAJ6UW.js +50 -0
  276. package/dist/wechat-pay-YQQKXVUI.js +51 -0
  277. package/dist/wonda-NGWIORYN.js +81 -0
  278. package/dist/wonda-RBABXFNM.js +82 -0
  279. package/dist/wordpress-woocommerce-RDIUTHYT.js +57 -0
  280. package/dist/wordpress-woocommerce-RNA5HB3N.js +58 -0
  281. package/dist/wps-DAEFQHDE.js +47 -0
  282. package/dist/wps-LUWHMZQQ.js +48 -0
  283. package/dist/yuque-HCHTJWNI.js +72 -0
  284. package/dist/yuque-KRH5O74J.js +71 -0
  285. package/images/RUNNERS.md +270 -0
  286. package/images/cc-connect-runner/entrypoint.mjs +311 -0
  287. package/images/claude-runner/Dockerfile +88 -0
  288. package/images/claude-runner/RUNNER.md +222 -0
  289. package/images/claude-runner/entrypoint.mjs +2 -0
  290. package/images/codex-runner/Dockerfile +87 -0
  291. package/images/codex-runner/RUNNER.md +226 -0
  292. package/images/codex-runner/entrypoint.mjs +2 -0
  293. package/images/gemini-runner/Dockerfile +87 -0
  294. package/images/gemini-runner/RUNNER.md +218 -0
  295. package/images/gemini-runner/entrypoint.mjs +2 -0
  296. package/images/hermes-runner/Dockerfile +74 -0
  297. package/images/hermes-runner/RUNNER.md +243 -0
  298. package/images/hermes-runner/entrypoint.mjs +283 -0
  299. package/images/openclaw-runner/Dockerfile +212 -0
  300. package/images/openclaw-runner/RUNNER.md +170 -0
  301. package/images/openclaw-runner/entrypoint.mjs +1113 -0
  302. package/images/openclaw-runner/warm-runtime-deps.mjs +95 -0
  303. package/images/opencode-runner/Dockerfile +87 -0
  304. package/images/opencode-runner/RUNNER.md +202 -0
  305. package/images/opencode-runner/entrypoint.mjs +2 -0
  306. package/package.json +121 -0
  307. package/templates/agent-marketplace-buddy.template.json +131 -0
  308. package/templates/ai-werewolf.template.json +92 -0
  309. package/templates/bmad-method-buddy.template.json +123 -0
  310. package/templates/brain-fix.template.json +92 -0
  311. package/templates/claude-ads-buddy.template.json +123 -0
  312. package/templates/claude-financial-services-buddy.template.json +111 -0
  313. package/templates/claude-seo-buddy.template.json +123 -0
  314. package/templates/code-arena.template.json +92 -0
  315. package/templates/daily-brief.template.json +92 -0
  316. package/templates/e-wife.template.json +92 -0
  317. package/templates/everything-claude-code-buddy.template.json +125 -0
  318. package/templates/financial-freedom.template.json +92 -0
  319. package/templates/gitstory.template.json +92 -0
  320. package/templates/google-workspace-buddy.template.json +88 -0
  321. package/templates/gsd-buddy.template.json +119 -0
  322. package/templates/gstack-buddy.template.json +143 -0
  323. package/templates/gstack.template.json +92 -0
  324. package/templates/little-match-girl.template.json +114 -0
  325. package/templates/lovart-buddy.template.json +110 -0
  326. package/templates/marketingskills-buddy.template.json +102 -0
  327. package/templates/retire-buddy.template.json +92 -0
  328. package/templates/scientific-skills-buddy.template.json +119 -0
  329. package/templates/seomachine-buddy.template.json +113 -0
  330. package/templates/shadow-server-app-demo.template.json +105 -0
  331. package/templates/slavingia-skills-buddy.template.json +102 -0
  332. package/templates/superclaude-buddy.template.json +146 -0
  333. package/templates/superpowers-buddy.template.json +108 -0
  334. package/templates/world-pulse.template.json +92 -0
@@ -0,0 +1,283 @@
1
+ /**
2
+ * Hermes runner entrypoint.
3
+ *
4
+ * Materializes generated Hermes files and starts `hermes gateway` with the
5
+ * ShadowOB platform plugin enabled.
6
+ */
7
+
8
+ import { spawn, spawnSync } from 'node:child_process'
9
+ import {
10
+ chmodSync,
11
+ cpSync,
12
+ existsSync,
13
+ mkdirSync,
14
+ readdirSync,
15
+ readFileSync,
16
+ statSync,
17
+ writeFileSync,
18
+ } from 'node:fs'
19
+ import { createServer } from 'node:http'
20
+ import { dirname, join, resolve } from 'node:path'
21
+
22
+ const RUNTIME_NAME = 'hermes-runner'
23
+ const CONFIG_MOUNT = process.env.SHADOW_RUNNER_CONFIG_MOUNT ?? '/etc/openclaw'
24
+ const RUNTIME_FILES_PATH = join(CONFIG_MOUNT, 'runtime-files.json')
25
+ const RUNTIME_EXTENSIONS_PATH = join(CONFIG_MOUNT, 'runtime-extensions.json')
26
+ const RUNNER_HOME = process.env.HOME ?? '/home/shadow'
27
+ const HEALTH_PORT = Number.parseInt(
28
+ process.env.SHADOW_RUNNER_HEALTH_PORT ?? process.env.OPENCLAW_GATEWAY_PORT ?? '3100',
29
+ 10,
30
+ )
31
+ const LOG_DIR = process.env.SHADOW_RUNNER_LOG_DIR ?? '/var/log/shadowob'
32
+ const ALLOWED_FILE_ROOTS = [RUNNER_HOME, '/home/openclaw', '/workspace', '/etc/shadowob']
33
+
34
+ let ready = false
35
+ let child = null
36
+
37
+ const KEY_PATTERNS = [
38
+ /\bsk-ant-[A-Za-z0-9_-]{20,}\b/g,
39
+ /\bsk-proj-[A-Za-z0-9_-]{20,}\b/g,
40
+ /\bsk-[A-Za-z0-9]{20,}\b/g,
41
+ /\bgsk_[A-Za-z0-9]{20,}\b/g,
42
+ /\bBearer\s+[A-Za-z0-9._-]{20,}/g,
43
+ /\bshadow-[A-Za-z0-9._-]{20,}/g,
44
+ ]
45
+
46
+ function redact(line) {
47
+ let result = line
48
+ for (const pattern of KEY_PATTERNS) {
49
+ pattern.lastIndex = 0
50
+ result = result.replace(pattern, '[REDACTED]')
51
+ }
52
+ return result
53
+ }
54
+
55
+ function loadJson(path, fallback) {
56
+ if (!existsSync(path)) return fallback
57
+ const parsed = JSON.parse(readFileSync(path, 'utf-8'))
58
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return fallback
59
+ return parsed
60
+ }
61
+
62
+ function resolveEnvPlaceholders(value) {
63
+ return value.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g, (_, key) => process.env[key] ?? '')
64
+ }
65
+
66
+ function assertAllowedPath(path) {
67
+ const absolute = resolve(path)
68
+ if (!ALLOWED_FILE_ROOTS.some((root) => absolute === root || absolute.startsWith(`${root}/`))) {
69
+ throw new Error(`Refusing to materialize runtime file outside allowed roots: ${path}`)
70
+ }
71
+ return absolute
72
+ }
73
+
74
+ function modeForPath(path) {
75
+ if (path.endsWith('/.env') || path.endsWith('.yaml') || path.endsWith('.json')) return 0o600
76
+ return 0o644
77
+ }
78
+
79
+ function materializeRuntimeFiles() {
80
+ const files = loadJson(RUNTIME_FILES_PATH, {})
81
+ for (const [path, content] of Object.entries(files)) {
82
+ if (typeof content !== 'string') continue
83
+ const absolute = assertAllowedPath(path)
84
+ const mode = modeForPath(absolute)
85
+ mkdirSync(dirname(absolute), { recursive: true })
86
+ writeFileSync(absolute, resolveEnvPlaceholders(content), { encoding: 'utf-8', mode })
87
+ chmodSync(absolute, mode)
88
+ console.log(`[entrypoint] wrote ${absolute}`)
89
+ }
90
+ }
91
+
92
+ function materializeCredentialFiles() {
93
+ const runtimeExtensions = loadJson(RUNTIME_EXTENSIONS_PATH, {})
94
+ const files = Array.isArray(runtimeExtensions.credentialFiles)
95
+ ? runtimeExtensions.credentialFiles
96
+ : []
97
+ for (const file of files) {
98
+ if (!file || typeof file.envKey !== 'string' || typeof file.path !== 'string') continue
99
+ const value = process.env[file.envKey]
100
+ if (!value) continue
101
+ const absolute = assertAllowedPath(file.path)
102
+ const mode =
103
+ typeof file.mode === 'string' && /^[0-7]{3,4}$/.test(file.mode)
104
+ ? Number.parseInt(file.mode, 8)
105
+ : 0o600
106
+ mkdirSync(dirname(absolute), { recursive: true })
107
+ writeFileSync(absolute, value, { encoding: 'utf-8', mode })
108
+ chmodSync(absolute, mode)
109
+ console.log(`[entrypoint] materialized credential file ${absolute}`)
110
+ }
111
+ }
112
+
113
+ function entriesWithMarker(root, marker) {
114
+ if (!existsSync(root)) return []
115
+ if (existsSync(join(root, marker))) return [{ source: root, name: root.split('/').pop() }]
116
+ return readdirSync(root)
117
+ .map((name) => ({ source: join(root, name), name }))
118
+ .filter((entry) => {
119
+ try {
120
+ return statSync(entry.source).isDirectory() && existsSync(join(entry.source, marker))
121
+ } catch {
122
+ return false
123
+ }
124
+ })
125
+ }
126
+
127
+ function subagentEntries(root) {
128
+ if (!existsSync(root)) return []
129
+ return readdirSync(root)
130
+ .map((name) => ({ source: join(root, name), name }))
131
+ .filter((entry) => {
132
+ try {
133
+ const stat = statSync(entry.source)
134
+ if (stat.isFile()) return entry.name.endsWith('.md')
135
+ return stat.isDirectory()
136
+ } catch {
137
+ return false
138
+ }
139
+ })
140
+ }
141
+
142
+ function copyIfMissing(source, destination) {
143
+ if (existsSync(destination)) return false
144
+ mkdirSync(dirname(destination), { recursive: true })
145
+ cpSync(source, destination, { recursive: true })
146
+ return true
147
+ }
148
+
149
+ function isAllowedPluginAssetRoot(path) {
150
+ const absolute = resolve(path)
151
+ return [RUNNER_HOME, '/home/openclaw', '/workspace'].some(
152
+ (root) => absolute === root || absolute.startsWith(`${root}/`),
153
+ )
154
+ }
155
+
156
+ function materializePluginRuntimeAssets() {
157
+ const runtimeExtensions = loadJson(RUNTIME_EXTENSIONS_PATH, {})
158
+ const skillRoots = Array.isArray(runtimeExtensions.skillSources)
159
+ ? runtimeExtensions.skillSources
160
+ .map((source) => (typeof source?.targetPath === 'string' ? source.targetPath : undefined))
161
+ .filter((path) => path && isAllowedPluginAssetRoot(path))
162
+ .filter(Boolean)
163
+ : []
164
+ const subagentRoots = Array.isArray(runtimeExtensions.subagentSources)
165
+ ? runtimeExtensions.subagentSources
166
+ .map((source) => (typeof source?.targetPath === 'string' ? source.targetPath : undefined))
167
+ .filter((path) => path && isAllowedPluginAssetRoot(path))
168
+ .filter(Boolean)
169
+ : []
170
+ const skillDestinations = ['/workspace/.agents/skills', join(RUNNER_HOME, '.hermes/skills')]
171
+ const subagentDestinations = ['/workspace/.agents/agents', join(RUNNER_HOME, '.hermes/agents')]
172
+
173
+ for (const root of skillRoots) {
174
+ for (const entry of entriesWithMarker(root, 'SKILL.md')) {
175
+ for (const destinationRoot of skillDestinations) {
176
+ if (copyIfMissing(entry.source, join(destinationRoot, entry.name))) {
177
+ console.log(`[entrypoint] mirrored plugin skill ${entry.name} to ${destinationRoot}`)
178
+ }
179
+ }
180
+ }
181
+ }
182
+ for (const root of subagentRoots) {
183
+ for (const entry of subagentEntries(root)) {
184
+ for (const destinationRoot of subagentDestinations) {
185
+ if (copyIfMissing(entry.source, join(destinationRoot, entry.name))) {
186
+ console.log(`[entrypoint] mirrored plugin subagent ${entry.name} to ${destinationRoot}`)
187
+ }
188
+ }
189
+ }
190
+ }
191
+ }
192
+
193
+ function startHealthServer() {
194
+ const server = createServer((req, res) => {
195
+ if (req.url === '/health' || req.url === '/ready') {
196
+ res.writeHead(ready ? 200 : 503, { 'Content-Type': 'application/json' })
197
+ res.end(JSON.stringify({ status: ready ? 'ready' : 'starting', runtime: RUNTIME_NAME }))
198
+ return
199
+ }
200
+ if (req.url === '/live') {
201
+ res.writeHead(200, { 'Content-Type': 'application/json' })
202
+ res.end(JSON.stringify({ status: 'live', runtime: RUNTIME_NAME }))
203
+ return
204
+ }
205
+ res.writeHead(404)
206
+ res.end()
207
+ })
208
+ server.listen(HEALTH_PORT, '0.0.0.0', () => {
209
+ console.log(`[entrypoint] health server listening on :${HEALTH_PORT}`)
210
+ })
211
+ return server
212
+ }
213
+
214
+ function verifyBinary(command, args) {
215
+ const result = spawnSync(command, args, {
216
+ stdio: ['ignore', 'pipe', 'pipe'],
217
+ timeout: 10_000,
218
+ })
219
+ if (result.status !== 0) {
220
+ throw new Error(`${command} ${args.join(' ')} failed: ${result.stderr?.toString() ?? ''}`)
221
+ }
222
+ }
223
+
224
+ function startHermes() {
225
+ mkdirSync(LOG_DIR, { recursive: true })
226
+ const proc = spawn('hermes', ['gateway'], {
227
+ env: {
228
+ ...process.env,
229
+ HERMES_HOME: process.env.HERMES_HOME ?? join(RUNNER_HOME, '.hermes'),
230
+ },
231
+ stdio: ['ignore', 'pipe', 'pipe'],
232
+ cwd: '/workspace',
233
+ })
234
+ child = proc
235
+ proc.stdout.on('data', (chunk) => process.stdout.write(redact(chunk.toString())))
236
+ proc.stderr.on('data', (chunk) => process.stderr.write(redact(chunk.toString())))
237
+ proc.on('exit', (code, signal) => {
238
+ ready = false
239
+ console.error(`[entrypoint] hermes exited code=${code ?? 'null'} signal=${signal ?? 'null'}`)
240
+ process.exit(code ?? 1)
241
+ })
242
+ setTimeout(() => {
243
+ if (!proc.killed) ready = true
244
+ }, 3000)
245
+ }
246
+
247
+ function setupSignals(server) {
248
+ const shutdown = (signal) => {
249
+ ready = false
250
+ server.close()
251
+ if (child && !child.killed) child.kill(signal)
252
+ setTimeout(() => process.exit(0), 5000).unref()
253
+ }
254
+ process.on('SIGTERM', () => shutdown('SIGTERM'))
255
+ process.on('SIGINT', () => shutdown('SIGINT'))
256
+ }
257
+
258
+ async function main() {
259
+ console.log(`[entrypoint] ${RUNTIME_NAME} starting`)
260
+ mkdirSync('/workspace', { recursive: true })
261
+ mkdirSync('/etc/shadowob', { recursive: true })
262
+ materializeRuntimeFiles()
263
+ materializeCredentialFiles()
264
+ materializePluginRuntimeAssets()
265
+
266
+ if (process.env.SHADOW_RUNNER_VALIDATE_ONLY === '1') {
267
+ verifyBinary('hermes', ['--version'])
268
+ verifyBinary('shadowob', ['--help'])
269
+ verifyBinary('shadowob-connector', ['--help'])
270
+ ready = true
271
+ console.log('[entrypoint] validation completed')
272
+ return
273
+ }
274
+
275
+ const server = startHealthServer()
276
+ setupSignals(server)
277
+ startHermes()
278
+ }
279
+
280
+ main().catch((err) => {
281
+ console.error('[entrypoint] Fatal:', err)
282
+ process.exit(1)
283
+ })
@@ -0,0 +1,212 @@
1
+ # syntax=docker/dockerfile:1.7
2
+
3
+ # ─── OpenClaw Runner ──────────────────────────────────────────────────────
4
+ # Container image for OpenClaw gateway runtime.
5
+ #
6
+ # User: shadow:1000
7
+ # Home: /home/shadow
8
+ # State: /home/shadow/.openclaw (emptyDir mount)
9
+ # Config: /etc/openclaw (ConfigMap mount, read-only)
10
+ # Logs: /var/log/openclaw (emptyDir mount)
11
+ #
12
+ # Build from the repository root so the image can include the local
13
+ # packages/openclaw-shadowob build:
14
+ # docker build -t ghcr.io/buggyblues/openclaw-runner:latest \
15
+ # -f apps/cloud/images/openclaw-runner/Dockerfile .
16
+ # ──────────────────────────────────────────────────────────────────────────
17
+
18
+ # ── Stage 1: Builder ─────────────────────────────────────────────────────
19
+ FROM node:22-bookworm-slim AS builder
20
+
21
+ WORKDIR /build
22
+
23
+ ARG OPENCLAW_VERSION=2026.5.7
24
+ ARG SHADOWOB_OPENCLAW_PLUGIN_VERSION=latest
25
+ ARG PLAYWRIGHT_VERSION=1.59.1
26
+
27
+ # git is required by some npm packages during install. Enable pnpm here so the
28
+ # local Shadow workspace packages are built inside the image, not copied as
29
+ # host-generated dist artifacts.
30
+ RUN apt-get update && \
31
+ apt-get install -y --no-install-recommends ca-certificates git && \
32
+ rm -rf /var/lib/apt/lists/* && \
33
+ corepack enable && \
34
+ corepack prepare pnpm@10.19.0 --activate
35
+
36
+ # Install OpenClaw and the published shadowob plugin first. This provides a
37
+ # stable runtime dependency layer; local package source changes below only
38
+ # invalidate the small workspace build and overlay layers.
39
+ RUN --mount=type=cache,target=/root/.npm,sharing=locked \
40
+ npm init -y && \
41
+ npm install --prefer-offline --no-audit --fund=false \
42
+ "openclaw@${OPENCLAW_VERSION}" \
43
+ "@shadowob/openclaw-shadowob@${SHADOWOB_OPENCLAW_PLUGIN_VERSION}" \
44
+ "@shadowob/cli@latest" \
45
+ "@shadowob/connector@latest" \
46
+ "playwright-core@${PLAYWRIGHT_VERSION}"
47
+
48
+ # Cleanup dev artifacts to reduce image size. This depends only on npm deps,
49
+ # so local plugin edits do not force the dependency install/cleanup layers.
50
+ RUN find node_modules -type d \( -name ".github" -o -name "test" -o -name "tests" \
51
+ -o -name "__tests__" -o -name "examples" \) \
52
+ -exec rm -rf {} + 2>/dev/null || true && \
53
+ find node_modules -type d -name "docs" ! -path "*/openclaw/docs*" \
54
+ -exec rm -rf {} + 2>/dev/null || true && \
55
+ find node_modules \( -name "*.d.ts" -o -name "*.d.ts.map" -o -name "*.js.map" \
56
+ -o -name "CHANGELOG.md" -o -name "README.md" \) \
57
+ -delete 2>/dev/null || true
58
+
59
+ # Install the minimal workspace needed to build the local Shadow plugin. Copy
60
+ # only lockfiles and manifests first so dependency resolution stays cached while
61
+ # TypeScript source changes.
62
+ WORKDIR /workspace
63
+ COPY package.json pnpm-lock.yaml pnpm-workspace.yaml tsconfig.json .npmrc ./
64
+ COPY packages/shared/package.json packages/shared/package.json
65
+ COPY packages/sdk/package.json packages/sdk/package.json
66
+ COPY packages/cli/package.json packages/cli/package.json
67
+ COPY packages/openclaw-shadowob/package.json packages/openclaw-shadowob/package.json
68
+ RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store,sharing=locked \
69
+ pnpm config set store-dir /pnpm/store && \
70
+ pnpm install --frozen-lockfile --ignore-scripts \
71
+ --filter @shadowob/openclaw-shadowob... \
72
+ --filter @shadowob/cli...
73
+
74
+ # Build local packages in-container. This makes the image reproducible in CI and
75
+ # keeps it independent from whatever dist/ happens to exist on the host.
76
+ COPY packages/shared packages/shared
77
+ COPY packages/sdk packages/sdk
78
+ COPY packages/cli packages/cli
79
+ COPY packages/openclaw-shadowob packages/openclaw-shadowob
80
+ RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store,sharing=locked \
81
+ pnpm --filter @shadowob/shared build && \
82
+ pnpm --filter @shadowob/sdk build && \
83
+ pnpm --filter @shadowob/cli build && \
84
+ pnpm --filter @shadowob/openclaw-shadowob build
85
+
86
+ # Overlay the freshly built local Shadow packages into the runtime dependency
87
+ # tree, preventing the bundled extension from resolving older published code.
88
+ WORKDIR /build
89
+ RUN for pkg in shared sdk cli; do \
90
+ rm -rf "node_modules/@shadowob/${pkg}" && \
91
+ mkdir -p "node_modules/@shadowob/${pkg}" && \
92
+ cp -r "/workspace/packages/${pkg}/package.json" "/workspace/packages/${pkg}/dist" "node_modules/@shadowob/${pkg}/"; \
93
+ done
94
+ RUN mkdir -p extensions/shadowob && \
95
+ cp -r /workspace/packages/openclaw-shadowob/package.json \
96
+ /workspace/packages/openclaw-shadowob/openclaw.plugin.json \
97
+ /workspace/packages/openclaw-shadowob/dist \
98
+ /workspace/packages/openclaw-shadowob/skills \
99
+ extensions/shadowob/
100
+
101
+ # ── Stage 2: Runner ─────────────────────────────────────────────────────
102
+ FROM node:22-bookworm-slim AS runner
103
+
104
+ LABEL org.opencontainers.image.source="https://github.com/nicepkg/shadow"
105
+ LABEL org.opencontainers.image.description="Shadow Cloud OpenClaw Runner"
106
+
107
+ ARG PLAYWRIGHT_VERSION=1.59.1
108
+
109
+ # Install runtime dependencies (rarely changes → good cache layer). Chromium
110
+ # and Playwright browsers are intentionally baked into the image so OpenClaw
111
+ # browser/canvas tools do not try to bootstrap them after the gateway is live.
112
+ ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
113
+ RUN apt-get update && \
114
+ apt-get install -y --no-install-recommends \
115
+ ca-certificates \
116
+ chromium \
117
+ chromium-driver \
118
+ curl \
119
+ fonts-liberation \
120
+ fonts-noto-cjk \
121
+ fonts-noto-color-emoji \
122
+ git \
123
+ libasound2 \
124
+ libatk-bridge2.0-0 \
125
+ libatk1.0-0 \
126
+ libcups2 \
127
+ libdrm2 \
128
+ libgbm1 \
129
+ libgtk-3-0 \
130
+ libnss3 \
131
+ libx11-xcb1 \
132
+ libxcomposite1 \
133
+ libxdamage1 \
134
+ libxrandr2 \
135
+ python-is-python3 \
136
+ python3 \
137
+ python3-pip \
138
+ python3-venv \
139
+ tini \
140
+ xdg-utils && \
141
+ rm -rf /var/lib/apt/lists/* && \
142
+ mkdir -p /ms-playwright && \
143
+ npx -y "playwright@${PLAYWRIGHT_VERSION}" install --with-deps chromium && \
144
+ chmod -R 755 /ms-playwright
145
+
146
+ # Create non-root user shadow:1000
147
+ # node images ship with node:node at UID/GID 1000 — remove it first
148
+ RUN userdel -r node 2>/dev/null || true; \
149
+ groupdel node 2>/dev/null || true; \
150
+ groupadd -g 1000 shadow; \
151
+ useradd -u 1000 -g shadow -m -d /home/shadow -s /usr/sbin/nologin shadow
152
+
153
+ # Setup directories
154
+ WORKDIR /app
155
+ RUN mkdir -p /home/shadow/.openclaw /etc/openclaw /etc/shadowob /var/log/openclaw \
156
+ /workspace /tmp/openclaw /tmp/npm-cache && \
157
+ ln -s /home/shadow /home/openclaw && \
158
+ chown -R shadow:shadow /home/shadow /etc/shadowob /var/log/openclaw \
159
+ /workspace /tmp/openclaw /tmp/npm-cache /app
160
+
161
+ # Copy stable OpenClaw runtime deps first.
162
+ COPY --from=builder --chown=shadow:shadow /build/node_modules ./node_modules
163
+ COPY --from=builder --chown=shadow:shadow /build/package.json ./package.json
164
+
165
+ # Symlink openclaw to PATH (local install only, no global npm install)
166
+ RUN ln -s /app/node_modules/.bin/openclaw /usr/local/bin/openclaw && \
167
+ ln -s /app/node_modules/.bin/shadowob /usr/local/bin/shadowob && \
168
+ ln -s /app/node_modules/.bin/shadowob-connector /usr/local/bin/shadowob-connector
169
+
170
+ # Copy local extensions before dependency warmup so the image carries the exact
171
+ # plugin runtime dependency set used at startup. The extension layer is still
172
+ # after node_modules, so ordinary plugin edits do not invalidate the large
173
+ # pnpm install/build layers.
174
+ COPY --from=builder --chown=shadow:shadow /build/extensions ./extensions
175
+
176
+ # Stage bundled plugin runtime deps in the image so the first real Buddy reply
177
+ # does not spend minutes installing optional tool/provider packages.
178
+ COPY --chown=shadow:shadow apps/cloud/images/openclaw-runner/warm-runtime-deps.mjs ./warm-runtime-deps.mjs
179
+ ENV OPENCLAW_PLUGIN_STAGE_DIR=/opt/openclaw-runtime-deps
180
+ ENV npm_config_cache=/tmp/npm-cache
181
+ RUN --mount=type=cache,target=/tmp/npm-cache,sharing=locked \
182
+ mkdir -p /opt/openclaw-runtime-deps && \
183
+ node /app/warm-runtime-deps.mjs && \
184
+ chown -R shadow:shadow /opt/openclaw-runtime-deps
185
+
186
+ # Copy entrypoint (small, changes often → last COPY for cache)
187
+ COPY --chown=shadow:shadow apps/cloud/images/openclaw-runner/entrypoint.mjs ./entrypoint.mjs
188
+
189
+ # Health check
190
+ HEALTHCHECK --interval=15s --timeout=5s --start-period=30s --retries=3 \
191
+ CMD curl -f http://localhost:3100/health || exit 1
192
+
193
+ EXPOSE 3100
194
+
195
+ ENV NODE_ENV=production
196
+ ENV HOME=/home/shadow
197
+ ENV OPENCLAW_HEALTH_PORT=3100
198
+ ENV OPENCLAW_GATEWAY_PORT=3101
199
+ ENV OPENCLAW_NO_RESPAWN=1
200
+ ENV OPENCLAW_MODEL_PRICING_FETCH_TIMEOUT_MS=2500
201
+ ENV OPENCLAW_SKIP_STARTUP_MODEL_PREWARM=1
202
+ ENV OPENCLAW_PLUGIN_STAGE_DIR=/opt/openclaw-runtime-deps
203
+ ENV CHROME_BIN=/usr/bin/chromium
204
+ ENV CHROMIUM_PATH=/usr/bin/chromium
205
+ ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
206
+
207
+ # Run as non-root
208
+ USER shadow
209
+
210
+ # Use tini as PID 1 for proper signal handling
211
+ ENTRYPOINT ["tini", "--"]
212
+ CMD ["node", "entrypoint.mjs"]
@@ -0,0 +1,170 @@
1
+ # OpenClaw Runner Research
2
+
3
+ Research date: 2026-05-14.
4
+
5
+ ## Target role
6
+
7
+ `openclaw-runner` remains the one runner whose native process boundary is the
8
+ OpenClaw gateway. It should keep using the ShadowOB OpenClaw plugin and the
9
+ OpenClaw configuration adapter. The refactor should isolate this path rather
10
+ than letting it define the config contract for every other runner.
11
+
12
+ ## Current repository state
13
+
14
+ The current image already follows this model more closely than the ACP runners:
15
+
16
+ - Dockerfile installs OpenClaw, the ShadowOB OpenClaw plugin, ShadowOB CLI, and
17
+ ShadowOB connector CLI.
18
+ - `entrypoint.mjs` reads `/etc/openclaw/config.json`.
19
+ - Runtime extensions are read from `/etc/openclaw/runtime-extensions.json`.
20
+ - The generated OpenClaw config is written outside mutable state by default.
21
+ - File logging goes to `/var/log/openclaw/entrypoint.log`.
22
+ - Shadow slash command artifacts are surfaced through
23
+ `SHADOW_SLASH_COMMANDS_PATH`.
24
+
25
+ ## Native configuration surfaces
26
+
27
+ OpenClaw configuration is broad and should remain represented as native
28
+ OpenClaw config when this runner is selected:
29
+
30
+ | Concern | OpenClaw config area |
31
+ | --- | --- |
32
+ | Gateway process | `gateway.*` for port, bind mode, auth, TLS, push, reload, remote access. |
33
+ | Channels | `channels.*` plus plugin channels such as `channels.shadowob`. |
34
+ | Agents and workspaces | `agents.defaults`, `agents.list`, routing, workspace, sandbox, heartbeat. |
35
+ | Models | `agents.defaults.model`, `agents.defaults.models`, `models.providers`, failover and dynamic discovery. |
36
+ | Skills | `skills.*`, `agents.defaults.skills`, `agents.list[].skills`. |
37
+ | MCP | `mcp.*` and tool-related config. |
38
+ | Automation | `cron.*`, `hooks.*`, tasks, standing orders, and background task config. |
39
+ | Plugins | `plugins.*`, plugin entries, plugin resources, runtime extensions. |
40
+ | Logs | `openclaw logs`, gateway logs, and container logs under `/var/log/openclaw`. |
41
+
42
+ ## Schema and type anchors
43
+
44
+ - Static schema URL: none found in the official docs.
45
+ - Official schema source: `openclaw config schema` prints the live JSON Schema
46
+ used by validation and Control UI.
47
+ - Official drill-down source: gateway `config.schema.lookup` returns
48
+ path-scoped schema nodes.
49
+ - Cloud type anchor: `OpenClawConfig` and related types under
50
+ `apps/cloud/src/config/schema/openclaw.schema.ts`.
51
+ - Test rule: adapter unit tests should run a generated config through OpenClaw's
52
+ schema command or a checked-in fixture generated by the same command.
53
+
54
+ ## Provider and authentication notes
55
+
56
+ - OpenClaw is the only phase-1 runner that should consume OpenClaw-native
57
+ `models.providers`, failover, and dynamic discovery config.
58
+ - Provider secrets must remain env-backed or secret-file backed. ConfigMaps may
59
+ contain `${env:...}` references but not raw API keys.
60
+ - Any subscription/OAuth provider support is OpenClaw-provider specific; it must
61
+ not become the compatibility path for Claude Code, Codex, OpenCode, Gemini, or
62
+ Hermes adapters.
63
+ - Cost/audit should continue to use OpenClaw's status and usage surfaces for
64
+ OpenClaw only. Native runners collect their own usage/log surfaces.
65
+
66
+ ## Security, audit, cost, network, and tools
67
+
68
+ - Permissions: `tools.profile`, `tools.allow`, `tools.deny`, per-agent
69
+ `agents.list[].tools.*`, and `tools.exec.*`; deny must win over allow.
70
+ - Tool surface: built-in tool groups, plugin tools, MCP tools, and bundled tools
71
+ must resolve before model invocation. An explicit allowlist that resolves to
72
+ zero tools should fail closed.
73
+ - Sandbox: `agents.defaults.sandbox.*` and `agents.list[].sandbox.*` decide
74
+ where tool execution runs; gateway process itself is not sandboxed.
75
+ - Elevated mode: `tools.elevated.*` is an exec-only escape hatch and cannot
76
+ override tool policy.
77
+ - Exec approvals: host exec approval state combines OpenClaw config and
78
+ host-local `~/.openclaw/exec-approvals.json`.
79
+ - Network: sandbox Docker network defaults to no network; browser sandbox has
80
+ separate CDP and container network controls.
81
+ - Cost/audit: OpenClaw `/status` and API usage/cost docs expose token/cost
82
+ estimates for API-key auth paths; runner logs must keep those events while
83
+ redacting credentials.
84
+ - Logs: collect OpenClaw gateway logs, entrypoint logs, sandbox explain output,
85
+ and plugin load warnings.
86
+
87
+ ## Shadow integration
88
+
89
+ Keep ShadowOB integration as an OpenClaw plugin concern:
90
+
91
+ - plugin package: `@shadowob/openclaw-shadowob`
92
+ - config section: `channels.shadowob`
93
+ - runtime artifacts: slash commands, credential files, plugin resources, and
94
+ verification checks from Cloud plugin runtime extensions
95
+ - official OpenClaw slash commands are generated into
96
+ `/etc/shadowob/slash-commands.json` with `dispatch=passthrough`, registered
97
+ with Shadow for the input picker, and then forwarded to OpenClaw as the
98
+ original standalone `/...` message instead of being rewritten into a prompt
99
+ - plugin-provided slash command indexes are loaded as additional runtime
100
+ artifacts after the official OpenClaw catalog. Duplicate command names keep
101
+ the first loaded definition, so plugin commands do not replace OpenClaw's
102
+ official commands.
103
+
104
+ The OpenClaw command catalog is owned by
105
+ `apps/cloud/src/runtimes/slash-commands/openclaw.ts`. The researched official
106
+ list includes `/new`, `/compact`, `/stop`, `/session`, `/think`, `/verbose`,
107
+ `/fast`, `/reasoning`, `/elevated`, `/exec`, `/model`, `/models`, `/queue`,
108
+ `/help`, `/commands`, `/tools`, `/status`, `/tasks`, `/context`,
109
+ `/export-session`, `/whoami`, `/skill`, `/allowlist`, `/approve`, `/btw`,
110
+ `/subagents`, `/acp`, `/focus`, `/unfocus`, `/agents`, `/kill`, `/steer`,
111
+ `/config`, `/mcp`, `/plugins`, `/debug`, `/usage`, `/tts`, `/restart`,
112
+ `/activation`, `/send`, and `/bash`.
113
+
114
+ This runner can continue to support OpenClaw-native slash commands, skills,
115
+ cron jobs, hooks, and channels. No cc-connect bridge is needed.
116
+
117
+ ## Migration implications
118
+
119
+ - `buildOpenClawConfig` should move behind, or be invoked only by, the OpenClaw
120
+ runner adapter.
121
+ - OpenClaw plugin fragments should not be merged into non-OpenClaw runner
122
+ packages.
123
+ - Existing `openclaw-runner` health checks and log redaction should be kept as
124
+ the baseline for the OpenClaw image only.
125
+ - Any Cloud API field named `openclaw` should be documented as OpenClaw-specific
126
+ instead of generic runtime configuration.
127
+
128
+ ## Adapter and smoke tests
129
+
130
+ Unit tests:
131
+
132
+ - Generated config validates with OpenClaw schema.
133
+ - Tool profile, allow, deny, sandbox, elevated, and exec approval fields map
134
+ exactly from Cloud policy inputs.
135
+ - Plugin runtime extensions still materialize slash command artifacts,
136
+ credential files, MCP servers, skills, and subagents.
137
+ - Secret refs stay out of `configData` snapshots.
138
+
139
+ Container smoke:
140
+
141
+ - Start image with a minimal ShadowOB config and confirm gateway health.
142
+ - Run `openclaw config schema` and `openclaw config validate` inside the
143
+ container.
144
+ - Inspect `/var/log/openclaw` for startup logs and redaction.
145
+ - Assert workspace write behavior for `workspaceAccess` modes.
146
+
147
+ ## Open questions
148
+
149
+ - Whether Cloud should continue to accept legacy top-level OpenClaw config for a
150
+ non-OpenClaw runtime and translate a small safe subset, or reject it early.
151
+ - Whether OpenClaw runtime extensions should have a parallel runner-extension
152
+ schema for cc-connect and Hermes.
153
+
154
+ ## Sources
155
+
156
+ - OpenClaw docs index: https://docs.openclaw.ai/llms.txt
157
+ - Gateway configuration:
158
+ https://docs.openclaw.ai/gateway/configuration
159
+ - Configuration reference:
160
+ https://docs.openclaw.ai/gateway/configuration-reference
161
+ - Sandboxing: https://docs.openclaw.ai/gateway/sandboxing
162
+ - Tools: https://docs.openclaw.ai/tools
163
+ - Slash commands: https://docs.openclaw.ai/tools/slash-commands
164
+ - Exec approvals: https://docs.openclaw.ai/tools/exec-approvals
165
+ - API usage and costs:
166
+ https://docs.openclaw.ai/reference/api-usage-costs
167
+ - Cron jobs: https://docs.openclaw.ai/automation/cron-jobs
168
+ - Hooks: https://docs.openclaw.ai/automation/hooks
169
+ - Skills: https://docs.openclaw.ai/tools/skills
170
+ - Logs CLI: https://docs.openclaw.ai/cli/logs