@congzhen/changewayguard 6.8.12

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 (329) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +270 -0
  3. package/dashboard-dist/api/104.index.js +1420 -0
  4. package/dashboard-dist/api/104.index.js.map +1 -0
  5. package/dashboard-dist/api/113.index.js +496 -0
  6. package/dashboard-dist/api/113.index.js.map +1 -0
  7. package/dashboard-dist/api/18.index.js +67 -0
  8. package/dashboard-dist/api/18.index.js.map +1 -0
  9. package/dashboard-dist/api/217.index.js +44 -0
  10. package/dashboard-dist/api/217.index.js.map +1 -0
  11. package/dashboard-dist/api/222.index.js +90 -0
  12. package/dashboard-dist/api/222.index.js.map +1 -0
  13. package/dashboard-dist/api/25.index.js +3562 -0
  14. package/dashboard-dist/api/25.index.js.map +1 -0
  15. package/dashboard-dist/api/280.index.js +206 -0
  16. package/dashboard-dist/api/280.index.js.map +1 -0
  17. package/dashboard-dist/api/369.index.js +115 -0
  18. package/dashboard-dist/api/369.index.js.map +1 -0
  19. package/dashboard-dist/api/377.index.js +1176 -0
  20. package/dashboard-dist/api/377.index.js.map +1 -0
  21. package/dashboard-dist/api/411.index.js +4250 -0
  22. package/dashboard-dist/api/411.index.js.map +1 -0
  23. package/dashboard-dist/api/424.index.js +135 -0
  24. package/dashboard-dist/api/424.index.js.map +1 -0
  25. package/dashboard-dist/api/573.index.js +806 -0
  26. package/dashboard-dist/api/573.index.js.map +1 -0
  27. package/dashboard-dist/api/598.index.js +328 -0
  28. package/dashboard-dist/api/598.index.js.map +1 -0
  29. package/dashboard-dist/api/62.index.js +4151 -0
  30. package/dashboard-dist/api/62.index.js.map +1 -0
  31. package/dashboard-dist/api/67.index.js +23383 -0
  32. package/dashboard-dist/api/67.index.js.map +1 -0
  33. package/dashboard-dist/api/678.index.js +2734 -0
  34. package/dashboard-dist/api/678.index.js.map +1 -0
  35. package/dashboard-dist/api/698.index.js +1896 -0
  36. package/dashboard-dist/api/698.index.js.map +1 -0
  37. package/dashboard-dist/api/720.index.js +98 -0
  38. package/dashboard-dist/api/720.index.js.map +1 -0
  39. package/dashboard-dist/api/830.index.js +95 -0
  40. package/dashboard-dist/api/830.index.js.map +1 -0
  41. package/dashboard-dist/api/831.index.js +99 -0
  42. package/dashboard-dist/api/831.index.js.map +1 -0
  43. package/dashboard-dist/api/84.index.js +64 -0
  44. package/dashboard-dist/api/84.index.js.map +1 -0
  45. package/dashboard-dist/api/900.index.js +65 -0
  46. package/dashboard-dist/api/900.index.js.map +1 -0
  47. package/dashboard-dist/api/917.index.js +88 -0
  48. package/dashboard-dist/api/917.index.js.map +1 -0
  49. package/dashboard-dist/api/948.index.js +64 -0
  50. package/dashboard-dist/api/948.index.js.map +1 -0
  51. package/dashboard-dist/api/953.index.js +67 -0
  52. package/dashboard-dist/api/953.index.js.map +1 -0
  53. package/dashboard-dist/api/975.index.js +374 -0
  54. package/dashboard-dist/api/975.index.js.map +1 -0
  55. package/dashboard-dist/api/drizzle/sqlite/0000_short_captain_stacy.sql +70 -0
  56. package/dashboard-dist/api/drizzle/sqlite/0001_closed_magus.sql +10 -0
  57. package/dashboard-dist/api/drizzle/sqlite/0002_agent_capability_observation.sql +38 -0
  58. package/dashboard-dist/api/drizzle/sqlite/0003_auth_magic_link.sql +28 -0
  59. package/dashboard-dist/api/drizzle/sqlite/0004_static_scan_fields.sql +8 -0
  60. package/dashboard-dist/api/drizzle/sqlite/0005_gateway_activity.sql +24 -0
  61. package/dashboard-dist/api/drizzle/sqlite/0006_sour_marauders.sql +41 -0
  62. package/dashboard-dist/api/drizzle/sqlite/meta/0000_snapshot.json +460 -0
  63. package/dashboard-dist/api/drizzle/sqlite/meta/0001_snapshot.json +536 -0
  64. package/dashboard-dist/api/drizzle/sqlite/meta/0006_snapshot.json +1249 -0
  65. package/dashboard-dist/api/drizzle/sqlite/meta/_journal.json +55 -0
  66. package/dashboard-dist/api/index.js +27340 -0
  67. package/dashboard-dist/api/index.js.map +1 -0
  68. package/dashboard-dist/api/package.json +16 -0
  69. package/dashboard-dist/api/sourcemap-register.cjs +1 -0
  70. package/dashboard-dist/web/assets/index-CqWIeBTD.js +158 -0
  71. package/dashboard-dist/web/assets/index-Dw7--9q4.css +1 -0
  72. package/dashboard-dist/web/changeway-logo.png +0 -0
  73. package/dashboard-dist/web/favicon.svg +29 -0
  74. package/dashboard-dist/web/index.html +14 -0
  75. package/dashboard-dist/web/logo.svg +16 -0
  76. package/dist/agent/auth.d.ts +37 -0
  77. package/dist/agent/auth.d.ts.map +1 -0
  78. package/dist/agent/auth.js +151 -0
  79. package/dist/agent/auth.js.map +1 -0
  80. package/dist/agent/behavior-detector.d.ts +150 -0
  81. package/dist/agent/behavior-detector.d.ts.map +1 -0
  82. package/dist/agent/behavior-detector.js +573 -0
  83. package/dist/agent/behavior-detector.js.map +1 -0
  84. package/dist/agent/business-reporter.d.ts +114 -0
  85. package/dist/agent/business-reporter.d.ts.map +1 -0
  86. package/dist/agent/business-reporter.js +359 -0
  87. package/dist/agent/business-reporter.js.map +1 -0
  88. package/dist/agent/config-sync.d.ts +70 -0
  89. package/dist/agent/config-sync.d.ts.map +1 -0
  90. package/dist/agent/config-sync.js +133 -0
  91. package/dist/agent/config-sync.js.map +1 -0
  92. package/dist/agent/config.d.ts +97 -0
  93. package/dist/agent/config.d.ts.map +1 -0
  94. package/dist/agent/config.js +359 -0
  95. package/dist/agent/config.js.map +1 -0
  96. package/dist/agent/content-injection-scanner.d.ts +35 -0
  97. package/dist/agent/content-injection-scanner.d.ts.map +1 -0
  98. package/dist/agent/content-injection-scanner.js +270 -0
  99. package/dist/agent/content-injection-scanner.js.map +1 -0
  100. package/dist/agent/engine-log-writer.d.ts +6 -0
  101. package/dist/agent/engine-log-writer.d.ts.map +1 -0
  102. package/dist/agent/engine-log-writer.js +18 -0
  103. package/dist/agent/engine-log-writer.js.map +1 -0
  104. package/dist/agent/env.d.ts +19 -0
  105. package/dist/agent/env.d.ts.map +1 -0
  106. package/dist/agent/env.js +43 -0
  107. package/dist/agent/env.js.map +1 -0
  108. package/dist/agent/event-reporter.d.ts +87 -0
  109. package/dist/agent/event-reporter.d.ts.map +1 -0
  110. package/dist/agent/event-reporter.js +315 -0
  111. package/dist/agent/event-reporter.js.map +1 -0
  112. package/dist/agent/file-watcher.d.ts +50 -0
  113. package/dist/agent/file-watcher.d.ts.map +1 -0
  114. package/dist/agent/file-watcher.js +135 -0
  115. package/dist/agent/file-watcher.js.map +1 -0
  116. package/dist/agent/fs-utils.d.ts +22 -0
  117. package/dist/agent/fs-utils.d.ts.map +1 -0
  118. package/dist/agent/fs-utils.js +41 -0
  119. package/dist/agent/fs-utils.js.map +1 -0
  120. package/dist/agent/gateway-manager.d.ts +59 -0
  121. package/dist/agent/gateway-manager.d.ts.map +1 -0
  122. package/dist/agent/gateway-manager.js +583 -0
  123. package/dist/agent/gateway-manager.js.map +1 -0
  124. package/dist/agent/hook-types.d.ts +276 -0
  125. package/dist/agent/hook-types.d.ts.map +1 -0
  126. package/dist/agent/hook-types.js +51 -0
  127. package/dist/agent/hook-types.js.map +1 -0
  128. package/dist/agent/index.d.ts +8 -0
  129. package/dist/agent/index.d.ts.map +1 -0
  130. package/dist/agent/index.js +8 -0
  131. package/dist/agent/index.js.map +1 -0
  132. package/dist/agent/prompt-gate.d.ts +13 -0
  133. package/dist/agent/prompt-gate.d.ts.map +1 -0
  134. package/dist/agent/prompt-gate.js +28 -0
  135. package/dist/agent/prompt-gate.js.map +1 -0
  136. package/dist/agent/prompt-input.d.ts +9 -0
  137. package/dist/agent/prompt-input.d.ts.map +1 -0
  138. package/dist/agent/prompt-input.js +158 -0
  139. package/dist/agent/prompt-input.js.map +1 -0
  140. package/dist/agent/prompt-output.d.ts +4 -0
  141. package/dist/agent/prompt-output.d.ts.map +1 -0
  142. package/dist/agent/prompt-output.js +19 -0
  143. package/dist/agent/prompt-output.js.map +1 -0
  144. package/dist/agent/runner.d.ts +23 -0
  145. package/dist/agent/runner.d.ts.map +1 -0
  146. package/dist/agent/runner.js +154 -0
  147. package/dist/agent/runner.js.map +1 -0
  148. package/dist/agent/sanitizer.d.ts +10 -0
  149. package/dist/agent/sanitizer.d.ts.map +1 -0
  150. package/dist/agent/sanitizer.js +175 -0
  151. package/dist/agent/sanitizer.js.map +1 -0
  152. package/dist/agent/scan-activity.d.ts +18 -0
  153. package/dist/agent/scan-activity.d.ts.map +1 -0
  154. package/dist/agent/scan-activity.js +32 -0
  155. package/dist/agent/scan-activity.js.map +1 -0
  156. package/dist/agent/types.d.ts +177 -0
  157. package/dist/agent/types.d.ts.map +1 -0
  158. package/dist/agent/types.js +5 -0
  159. package/dist/agent/types.js.map +1 -0
  160. package/dist/agent/workspace-scanner.d.ts +35 -0
  161. package/dist/agent/workspace-scanner.d.ts.map +1 -0
  162. package/dist/agent/workspace-scanner.js +137 -0
  163. package/dist/agent/workspace-scanner.js.map +1 -0
  164. package/dist/dashboard-launcher.d.ts +52 -0
  165. package/dist/dashboard-launcher.d.ts.map +1 -0
  166. package/dist/dashboard-launcher.js +363 -0
  167. package/dist/dashboard-launcher.js.map +1 -0
  168. package/dist/gateway/activity.d.ts +52 -0
  169. package/dist/gateway/activity.d.ts.map +1 -0
  170. package/dist/gateway/activity.js +111 -0
  171. package/dist/gateway/activity.js.map +1 -0
  172. package/dist/gateway/config.d.ts +50 -0
  173. package/dist/gateway/config.d.ts.map +1 -0
  174. package/dist/gateway/config.js +200 -0
  175. package/dist/gateway/config.js.map +1 -0
  176. package/dist/gateway/gateway/activity.d.ts +52 -0
  177. package/dist/gateway/gateway/activity.d.ts.map +1 -0
  178. package/dist/gateway/gateway/activity.js +111 -0
  179. package/dist/gateway/gateway/activity.js.map +1 -0
  180. package/dist/gateway/gateway/config.d.ts +50 -0
  181. package/dist/gateway/gateway/config.d.ts.map +1 -0
  182. package/dist/gateway/gateway/config.js +200 -0
  183. package/dist/gateway/gateway/config.js.map +1 -0
  184. package/dist/gateway/gateway/handlers/anthropic.d.ts +12 -0
  185. package/dist/gateway/gateway/handlers/anthropic.d.ts.map +1 -0
  186. package/dist/gateway/gateway/handlers/anthropic.js +254 -0
  187. package/dist/gateway/gateway/handlers/anthropic.js.map +1 -0
  188. package/dist/gateway/gateway/handlers/gemini.d.ts +12 -0
  189. package/dist/gateway/gateway/handlers/gemini.d.ts.map +1 -0
  190. package/dist/gateway/gateway/handlers/gemini.js +101 -0
  191. package/dist/gateway/gateway/handlers/gemini.js.map +1 -0
  192. package/dist/gateway/gateway/handlers/models.d.ts +4 -0
  193. package/dist/gateway/gateway/handlers/models.d.ts.map +1 -0
  194. package/dist/gateway/gateway/handlers/models.js +36 -0
  195. package/dist/gateway/gateway/handlers/models.js.map +1 -0
  196. package/dist/gateway/gateway/handlers/openai.d.ts +16 -0
  197. package/dist/gateway/gateway/handlers/openai.d.ts.map +1 -0
  198. package/dist/gateway/gateway/handlers/openai.js +254 -0
  199. package/dist/gateway/gateway/handlers/openai.js.map +1 -0
  200. package/dist/gateway/gateway/index.d.ts +27 -0
  201. package/dist/gateway/gateway/index.d.ts.map +1 -0
  202. package/dist/gateway/gateway/index.js +293 -0
  203. package/dist/gateway/gateway/index.js.map +1 -0
  204. package/dist/gateway/gateway/mapping-store.d.ts +38 -0
  205. package/dist/gateway/gateway/mapping-store.d.ts.map +1 -0
  206. package/dist/gateway/gateway/mapping-store.js +74 -0
  207. package/dist/gateway/gateway/mapping-store.js.map +1 -0
  208. package/dist/gateway/gateway/restorer.d.ts +63 -0
  209. package/dist/gateway/gateway/restorer.d.ts.map +1 -0
  210. package/dist/gateway/gateway/restorer.js +284 -0
  211. package/dist/gateway/gateway/restorer.js.map +1 -0
  212. package/dist/gateway/gateway/sanitizer.d.ts +17 -0
  213. package/dist/gateway/gateway/sanitizer.d.ts.map +1 -0
  214. package/dist/gateway/gateway/sanitizer.js +228 -0
  215. package/dist/gateway/gateway/sanitizer.js.map +1 -0
  216. package/dist/gateway/gateway/types.d.ts +53 -0
  217. package/dist/gateway/gateway/types.d.ts.map +1 -0
  218. package/dist/gateway/gateway/types.js +5 -0
  219. package/dist/gateway/gateway/types.js.map +1 -0
  220. package/dist/gateway/handlers/anthropic.d.ts +12 -0
  221. package/dist/gateway/handlers/anthropic.d.ts.map +1 -0
  222. package/dist/gateway/handlers/anthropic.js +254 -0
  223. package/dist/gateway/handlers/anthropic.js.map +1 -0
  224. package/dist/gateway/handlers/gemini.d.ts +12 -0
  225. package/dist/gateway/handlers/gemini.d.ts.map +1 -0
  226. package/dist/gateway/handlers/gemini.js +101 -0
  227. package/dist/gateway/handlers/gemini.js.map +1 -0
  228. package/dist/gateway/handlers/models.d.ts +4 -0
  229. package/dist/gateway/handlers/models.d.ts.map +1 -0
  230. package/dist/gateway/handlers/models.js +36 -0
  231. package/dist/gateway/handlers/models.js.map +1 -0
  232. package/dist/gateway/handlers/openai.d.ts +16 -0
  233. package/dist/gateway/handlers/openai.d.ts.map +1 -0
  234. package/dist/gateway/handlers/openai.js +254 -0
  235. package/dist/gateway/handlers/openai.js.map +1 -0
  236. package/dist/gateway/index.d.ts +27 -0
  237. package/dist/gateway/index.d.ts.map +1 -0
  238. package/dist/gateway/index.js +293 -0
  239. package/dist/gateway/index.js.map +1 -0
  240. package/dist/gateway/mapping-store.d.ts +38 -0
  241. package/dist/gateway/mapping-store.d.ts.map +1 -0
  242. package/dist/gateway/mapping-store.js +74 -0
  243. package/dist/gateway/mapping-store.js.map +1 -0
  244. package/dist/gateway/restorer.d.ts +63 -0
  245. package/dist/gateway/restorer.d.ts.map +1 -0
  246. package/dist/gateway/restorer.js +284 -0
  247. package/dist/gateway/restorer.js.map +1 -0
  248. package/dist/gateway/sanitizer.d.ts +17 -0
  249. package/dist/gateway/sanitizer.d.ts.map +1 -0
  250. package/dist/gateway/sanitizer.js +228 -0
  251. package/dist/gateway/sanitizer.js.map +1 -0
  252. package/dist/gateway/types.d.ts +53 -0
  253. package/dist/gateway/types.d.ts.map +1 -0
  254. package/dist/gateway/types.js +5 -0
  255. package/dist/gateway/types.js.map +1 -0
  256. package/dist/index.d.ts +19 -0
  257. package/dist/index.d.ts.map +1 -0
  258. package/dist/index.js +2084 -0
  259. package/dist/index.js.map +1 -0
  260. package/dist/memory/index.d.ts +5 -0
  261. package/dist/memory/index.d.ts.map +1 -0
  262. package/dist/memory/index.js +5 -0
  263. package/dist/memory/index.js.map +1 -0
  264. package/dist/memory/store.d.ts +82 -0
  265. package/dist/memory/store.d.ts.map +1 -0
  266. package/dist/memory/store.js +194 -0
  267. package/dist/memory/store.js.map +1 -0
  268. package/dist/platform-client/index.d.ts +63 -0
  269. package/dist/platform-client/index.d.ts.map +1 -0
  270. package/dist/platform-client/index.js +294 -0
  271. package/dist/platform-client/index.js.map +1 -0
  272. package/dist/platform-client/types.d.ts +109 -0
  273. package/dist/platform-client/types.d.ts.map +1 -0
  274. package/dist/platform-client/types.js +3 -0
  275. package/dist/platform-client/types.js.map +1 -0
  276. package/gateway/activity.d.ts +52 -0
  277. package/gateway/activity.d.ts.map +1 -0
  278. package/gateway/activity.js +111 -0
  279. package/gateway/activity.js.map +1 -0
  280. package/gateway/config.d.ts +50 -0
  281. package/gateway/config.d.ts.map +1 -0
  282. package/gateway/config.js +200 -0
  283. package/gateway/config.js.map +1 -0
  284. package/gateway/handlers/anthropic.d.ts +12 -0
  285. package/gateway/handlers/anthropic.d.ts.map +1 -0
  286. package/gateway/handlers/anthropic.js +254 -0
  287. package/gateway/handlers/anthropic.js.map +1 -0
  288. package/gateway/handlers/gemini.d.ts +12 -0
  289. package/gateway/handlers/gemini.d.ts.map +1 -0
  290. package/gateway/handlers/gemini.js +101 -0
  291. package/gateway/handlers/gemini.js.map +1 -0
  292. package/gateway/handlers/models.d.ts +4 -0
  293. package/gateway/handlers/models.d.ts.map +1 -0
  294. package/gateway/handlers/models.js +36 -0
  295. package/gateway/handlers/models.js.map +1 -0
  296. package/gateway/handlers/openai.d.ts +16 -0
  297. package/gateway/handlers/openai.d.ts.map +1 -0
  298. package/gateway/handlers/openai.js +254 -0
  299. package/gateway/handlers/openai.js.map +1 -0
  300. package/gateway/index.d.ts +27 -0
  301. package/gateway/index.d.ts.map +1 -0
  302. package/gateway/index.js +293 -0
  303. package/gateway/index.js.map +1 -0
  304. package/gateway/mapping-store.d.ts +38 -0
  305. package/gateway/mapping-store.d.ts.map +1 -0
  306. package/gateway/mapping-store.js +74 -0
  307. package/gateway/mapping-store.js.map +1 -0
  308. package/gateway/restorer.d.ts +63 -0
  309. package/gateway/restorer.d.ts.map +1 -0
  310. package/gateway/restorer.js +284 -0
  311. package/gateway/restorer.js.map +1 -0
  312. package/gateway/sanitizer.d.ts +17 -0
  313. package/gateway/sanitizer.d.ts.map +1 -0
  314. package/gateway/sanitizer.js +228 -0
  315. package/gateway/sanitizer.js.map +1 -0
  316. package/gateway/types.d.ts +53 -0
  317. package/gateway/types.d.ts.map +1 -0
  318. package/gateway/types.js +5 -0
  319. package/gateway/types.js.map +1 -0
  320. package/openclaw.plugin.json +86 -0
  321. package/package.json +74 -0
  322. package/samples/Untitled +1 -0
  323. package/samples/clean-email.txt +20 -0
  324. package/samples/test-document.md +53 -0
  325. package/samples/test-email-popup.txt +44 -0
  326. package/samples/test-email.txt +32 -0
  327. package/samples/test-webpage.html +51 -0
  328. package/scripts/enterprise-enroll.sh +89 -0
  329. package/scripts/enterprise-unenroll.sh +75 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"573.index.js","mappings":";;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;ACpQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","sources":[".././dist/routes/discovery.js",".././dist/services/discovery.js"],"sourcesContent":["import { Router } from \"express\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { scanAgents, getAgentProfile } from \"../services/discovery.js\";\nimport { db, agentQueries } from \"@og/db\";\nconst agentsDb = agentQueries(db);\nexport const discoveryRouter = Router();\nfunction fallbackAgentName(agentId) {\n return agentId ? `Agent ${agentId.slice(0, 6)}` : \"Agent\";\n}\nfunction sanitizeAgentName(name, fallback) {\n const raw = name.replace(/\\s+/g, \" \").trim();\n if (!raw)\n return fallback;\n const cleaned = raw\n .replace(/^[-*]\\s+/, \"\")\n .replace(/^[`*_~\\s]+/, \"\")\n .replace(/[`*_~\\s]+$/, \"\")\n .replace(/^\\((.*)\\)$/, \"$1\")\n .trim();\n if (!cleaned)\n return fallback;\n const lower = cleaned.toLowerCase();\n const looksLikeTemplate = /(pick something|your signature|fill this in|make it yours|workspace-relative|something weirder|ghost in the machine|how do you come across)/i.test(lower);\n return looksLikeTemplate ? fallback : cleaned;\n}\nfunction registeredToDiscovered(a) {\n const m = (a.metadata ?? {});\n const discoveredId = m.openclawId ?? a.id;\n return {\n id: discoveredId,\n name: sanitizeAgentName(a.name, fallbackAgentName(discoveredId)),\n emoji: m.emoji ?? \"🤖\",\n creature: m.creature ?? \"\",\n vibe: m.vibe ?? \"\",\n model: m.model ?? \"\",\n provider: m.provider ?? a.provider,\n workspacePath: \"\",\n ownerName: m.ownerName ?? \"\",\n avatarUrl: null,\n skills: m.skills ?? [],\n connectedSystems: m.connectedSystems ?? [],\n channels: m.channels ?? [],\n plugins: m.plugins ?? [],\n hooks: m.hooks ?? [],\n sessionCount: m.sessionCount ?? 0,\n lastActive: m.lastActive ?? a.lastSeenAt,\n };\n}\nfunction registeredToProfile(a) {\n const m = (a.metadata ?? {});\n const wf = m.workspaceFiles ?? {};\n return {\n ...registeredToDiscovered(a),\n workspaceFiles: {\n soul: wf.soul ?? \"\",\n identity: wf.identity ?? \"\",\n user: wf.user ?? \"\",\n agents: wf.agents ?? \"\",\n tools: wf.tools ?? \"\",\n heartbeat: wf.heartbeat ?? \"\",\n },\n bootstrapExists: m.bootstrapExists ?? false,\n cronJobs: m.cronJobs ?? [],\n allSkills: (m.skills ?? []).map((s) => ({ ...s, source: \"workspace\" })),\n bundledExtensions: [],\n };\n}\n// ── Routes ───────────────────────────────────────────────────────────────────\n// GET /api/discovery/agents — list all agents (DB primary, filesystem fallback)\ndiscoveryRouter.get(\"/agents\", async (_req, res, next) => {\n try {\n const tenantId = res.locals.tenantId;\n const registered = await agentsDb.findAll(tenantId);\n if (registered.length > 0) {\n res.json({ success: true, data: registered.map(registeredToDiscovered) });\n return;\n }\n // Fallback: local filesystem scan (self-hosted, same machine)\n const discovered = scanAgents();\n res.json({ success: true, data: discovered });\n }\n catch (err) {\n next(err);\n }\n});\n// GET /api/discovery/agents/:id — single agent (DB primary, filesystem fallback)\ndiscoveryRouter.get(\"/agents/:id\", async (req, res, next) => {\n try {\n const tenantId = res.locals.tenantId;\n const id = req.params.id;\n const registered = await agentsDb.findAll(tenantId);\n // Match by openclawId (from plugin) or DB id\n const match = registered.find((a) => {\n const meta = (a.metadata ?? {});\n return meta.openclawId === id || a.id === id;\n });\n if (match) {\n res.json({ success: true, data: registeredToDiscovered(match) });\n return;\n }\n // Fallback: filesystem\n const { getAgent } = await import(\"../services/discovery.js\");\n const agent = getAgent(id);\n if (!agent) {\n res.status(404).json({ success: false, error: \"Agent not found\" });\n return;\n }\n res.json({ success: true, data: agent });\n }\n catch (err) {\n next(err);\n }\n});\n// GET /api/discovery/agents/:id/avatar — serve agent avatar image (filesystem only)\ndiscoveryRouter.get(\"/agents/:id/avatar\", (req, res, next) => {\n try {\n const { getAgent } = require(\"../services/discovery.js\");\n const agent = getAgent(req.params.id);\n if (!agent || !agent.workspacePath) {\n res.status(404).json({ success: false, error: \"No avatar found\" });\n return;\n }\n const mimeTypes = {\n png: \"image/png\",\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n svg: \"image/svg+xml\",\n webp: \"image/webp\",\n };\n for (const ext of Object.keys(mimeTypes)) {\n const avatarPath = join(agent.workspacePath, `avatar.${ext}`);\n if (existsSync(avatarPath)) {\n const data = readFileSync(avatarPath);\n res.setHeader(\"Content-Type\", mimeTypes[ext]);\n res.setHeader(\"Cache-Control\", \"public, max-age=3600\");\n res.send(data);\n return;\n }\n }\n res.status(404).json({ success: false, error: \"No avatar found\" });\n }\n catch (err) {\n next(err);\n }\n});\n// GET /api/discovery/agents/:id/profile — enriched profile (DB primary, filesystem fallback)\ndiscoveryRouter.get(\"/agents/:id/profile\", async (req, res, next) => {\n try {\n const tenantId = res.locals.tenantId;\n const id = req.params.id;\n const registered = await agentsDb.findAll(tenantId);\n const match = registered.find((a) => {\n const meta = (a.metadata ?? {});\n return meta.openclawId === id || a.id === id;\n });\n if (match) {\n const profile = registeredToProfile(match);\n res.json({ success: true, data: { ...profile, registeredAgentId: match.id } });\n return;\n }\n // Fallback: filesystem\n const profile = getAgentProfile(id);\n if (!profile) {\n res.status(404).json({ success: false, error: \"Agent not found\" });\n return;\n }\n // Also try to find registeredAgentId from DB by name\n const byName = registered.find((a) => a.name === profile.name);\n res.json({ success: true, data: { ...profile, registeredAgentId: byName?.id ?? null } });\n }\n catch (err) {\n next(err);\n }\n});\n// POST /api/discovery/scan — trigger fresh scan (filesystem only, for local installs)\ndiscoveryRouter.post(\"/scan\", (_req, res, next) => {\n try {\n const agents = scanAgents();\n res.json({ success: true, data: agents });\n }\n catch (err) {\n next(err);\n }\n});\n// GET /api/discovery/agents/:id/summary — LLM-generated summary\ndiscoveryRouter.get(\"/agents/:id/summary\", async (req, res, next) => {\n try {\n const tenantId = res.locals.tenantId;\n const id = req.params.id;\n const registered = await agentsDb.findAll(tenantId);\n const match = registered.find((a) => {\n const meta = (a.metadata ?? {});\n return meta.openclawId === id || a.id === id;\n });\n const agent = match\n ? registeredToDiscovered(match)\n : (() => { const { getAgent } = require(\"../services/discovery.js\"); return getAgent(id) ?? null; })();\n if (!agent) {\n res.status(404).json({ success: false, error: \"Agent not found\" });\n return;\n }\n const prompt = `Summarize this AI agent in 2-3 concise paragraphs for a security dashboard:\n\nName: ${agent.name} ${agent.emoji}\nCreature: ${agent.creature}\nVibe: ${agent.vibe}\nModel: ${agent.provider}/${agent.model}\nSkills: ${agent.skills.map((s) => s.name).join(\", \") || \"none\"}\nConnected Systems: ${agent.connectedSystems.join(\", \") || \"none\"}\nChannels: ${agent.channels.join(\", \") || \"none\"}\nPlugins: ${agent.plugins.map((p) => `${p.name}${p.enabled ? \"\" : \" (disabled)\"}`).join(\", \") || \"none\"}\nHooks: ${agent.hooks.map((h) => `${h.name}${h.enabled ? \"\" : \" (disabled)\"}`).join(\", \") || \"none\"}\nSessions: ${agent.sessionCount}\nLast Active: ${agent.lastActive || \"unknown\"}\n\nFocus on: what this agent does, its capabilities, connected systems and potential security surface area. Keep it factual and useful for a security team.`;\n const { getEnvGatewayPort, getEnvAnthropicApiKey } = await import(\"../services/runtime-config.js\");\n const gatewayPort = getEnvGatewayPort();\n try {\n const apiKey = getEnvAnthropicApiKey();\n const response = await fetch(`http://localhost:${gatewayPort}/v1/messages`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": apiKey,\n \"anthropic-version\": \"2023-06-01\",\n },\n body: JSON.stringify({\n model: \"claude-sonnet-4-5-20250929\",\n max_tokens: 500,\n messages: [{ role: \"user\", content: prompt }],\n }),\n signal: AbortSignal.timeout(30000),\n });\n if (response.ok) {\n const data = await response.json();\n const text = data.content?.find((c) => c.type === \"text\")?.text;\n if (text) {\n res.json({ success: true, data: { summary: text } });\n return;\n }\n }\n }\n catch {\n // Gateway not available, fall through to static summary\n }\n const skillList = agent.skills.map((s) => s.name).join(\", \");\n const systemList = agent.connectedSystems.join(\", \");\n const summary = `${agent.name} is an AI agent running on ${agent.provider}/${agent.model}. ` +\n (skillList ? `It has ${agent.skills.length} skill(s): ${skillList}. ` : \"It has no registered skills. \") +\n (systemList ? `Connected systems: ${systemList}. ` : \"\") +\n `It has ${agent.sessionCount} recorded session(s)` +\n (agent.lastActive ? `, last active ${new Date(agent.lastActive).toLocaleDateString()}.` : \".\");\n res.json({ success: true, data: { summary } });\n }\n catch (err) {\n next(err);\n }\n});\n//# sourceMappingURL=discovery.js.map","import { readFileSync, readdirSync, existsSync } from \"node:fs\";\nimport { execSync } from \"node:child_process\";\nimport { join, basename, dirname } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { getEnv } from \"./runtime-config.js\";\nconst OPENCLAW_DIR = join(homedir(), \".openclaw\");\nfunction readJsonSafe(path) {\n try {\n return JSON.parse(readFileSync(path, \"utf-8\"));\n }\n catch {\n return null;\n }\n}\nfunction readFileSafe(path) {\n try {\n return readFileSync(path, \"utf-8\");\n }\n catch {\n return \"\";\n }\n}\nfunction parseOwnerName(workspacePath) {\n const content = readFileSafe(join(workspacePath, \"USER.md\"));\n if (!content)\n return \"\";\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n // Handle \"- **Name:** value\" (bullet + bold markdown)\n const bulletBold = trimmed.match(/^[-*]\\s+\\*\\*name:\\*\\*\\s*(.*)/i);\n if (bulletBold) {\n const val = bulletBold[1].trim();\n if (val)\n return val;\n continue;\n }\n // Handle \"**Name:** value\" or \"Name: value\"\n const plain = trimmed.match(/^\\*?\\*?name\\*?\\*?:\\s*(.*)/i);\n if (plain) {\n const val = plain[1].replace(/^\\*?\\*?\\s*/, \"\").trim();\n if (val)\n return val;\n }\n }\n return \"\";\n}\nconst AVATAR_EXTENSIONS = [\"png\", \"jpg\", \"jpeg\", \"svg\", \"webp\"];\nfunction discoverAvatar(workspacePath) {\n for (const ext of AVATAR_EXTENSIONS) {\n if (existsSync(join(workspacePath, `avatar.${ext}`))) {\n return ext;\n }\n }\n return null;\n}\nfunction parseIdentityMd(content) {\n const result = { name: \"\", emoji: \"\", creature: \"\", vibe: \"\" };\n const lines = content.split(\"\\n\");\n let currentKey = \"\";\n const normalize = (value) => value\n .replace(/\\s+/g, \" \")\n .trim()\n .replace(/^[`*_~\\s]+/, \"\")\n .replace(/[`*_~\\s]+$/, \"\")\n .replace(/^\\((.*)\\)$/, \"$1\")\n .trim();\n const isTemplatePlaceholder = (value) => {\n const lower = value.toLowerCase();\n return /(pick something|your signature|fill this in|make it yours|workspace-relative|something weirder|ghost in the machine|how do you come across)/i.test(lower);\n };\n const useIfValid = (key, value) => {\n const normalized = normalize(value);\n if (!normalized || isTemplatePlaceholder(normalized))\n return;\n result[key] = normalized;\n };\n for (const line of lines) {\n const trimmed = line.trim();\n if (trimmed.startsWith(\"- **Name:**\")) {\n currentKey = \"name\";\n const inline = trimmed.replace(\"- **Name:**\", \"\").trim();\n if (inline)\n useIfValid(\"name\", inline);\n }\n else if (trimmed.startsWith(\"- **Creature:**\")) {\n currentKey = \"creature\";\n const inline = trimmed.replace(\"- **Creature:**\", \"\").trim();\n if (inline)\n useIfValid(\"creature\", inline);\n }\n else if (trimmed.startsWith(\"- **Vibe:**\")) {\n currentKey = \"vibe\";\n const inline = trimmed.replace(\"- **Vibe:**\", \"\").trim();\n if (inline)\n useIfValid(\"vibe\", inline);\n }\n else if (trimmed.startsWith(\"- **Emoji:**\")) {\n currentKey = \"emoji\";\n const inline = trimmed.replace(\"- **Emoji:**\", \"\").trim();\n if (inline)\n useIfValid(\"emoji\", inline);\n }\n else if (trimmed.startsWith(\"- **\") || trimmed.startsWith(\"---\") || trimmed.startsWith(\"#\")) {\n currentKey = \"\";\n }\n else if (currentKey && trimmed) {\n const key = currentKey;\n if (!result[key])\n useIfValid(key, trimmed);\n }\n }\n return result;\n}\nfunction countSessions(agentDir) {\n const sessionsDir = join(agentDir, \"sessions\");\n if (!existsSync(sessionsDir))\n return { count: 0, lastActive: null };\n const sessionsFile = join(sessionsDir, \"sessions.json\");\n const sessionsData = readJsonSafe(sessionsFile);\n if (!sessionsData)\n return { count: 0, lastActive: null };\n let latestTs = 0;\n let count = 0;\n for (const value of Object.values(sessionsData)) {\n count++;\n if (typeof value === \"object\" && value && typeof value.updatedAt === \"number\") {\n if (value.updatedAt > latestTs)\n latestTs = value.updatedAt;\n }\n }\n return {\n count,\n lastActive: latestTs ? new Date(latestTs).toISOString() : null,\n };\n}\nfunction discoverSkills(workspacePath) {\n const skillsDir = join(workspacePath, \"skills\");\n if (!existsSync(skillsDir))\n return [];\n try {\n return readdirSync(skillsDir, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => {\n const metaPath = join(skillsDir, d.name, \"_meta.json\");\n const meta = readJsonSafe(metaPath);\n return { name: d.name, description: meta?.description };\n });\n }\n catch {\n return [];\n }\n}\nfunction discoverCredentials() {\n const credsDir = join(OPENCLAW_DIR, \"credentials\");\n if (!existsSync(credsDir))\n return [];\n try {\n return readdirSync(credsDir)\n .filter((f) => f.endsWith(\".json\"))\n .map((f) => basename(f, \".json\"));\n }\n catch {\n return [];\n }\n}\nexport function scanAgents() {\n if (!existsSync(OPENCLAW_DIR))\n return [];\n const config = readJsonSafe(join(OPENCLAW_DIR, \"openclaw.json\"));\n if (!config)\n return [];\n const agentsConfig = config.agents;\n const pluginsConfig = config.plugins;\n const hooksConfig = config.hooks;\n const gatewayConfig = config.gateway;\n const defaultModel = agentsConfig?.defaults?.model?.primary || \"unknown\";\n const workspacePath = agentsConfig?.defaults?.workspace || join(OPENCLAW_DIR, \"workspace\");\n // Parse model string like \"openai-codex/gpt-5.3-codex\"\n const [provider, model] = defaultModel.includes(\"/\")\n ? defaultModel.split(\"/\", 2)\n : [\"unknown\", defaultModel];\n // Read identity\n const identityContent = readFileSafe(join(workspacePath, \"IDENTITY.md\"));\n const identity = parseIdentityMd(identityContent);\n // Discover skills\n const skills = discoverSkills(workspacePath);\n // Connected systems (credentials)\n const connectedSystems = discoverCredentials();\n // Channels — derive from session data\n const channels = [];\n const agentsDir = join(OPENCLAW_DIR, \"agents\");\n if (existsSync(agentsDir)) {\n try {\n const agentDirs = readdirSync(agentsDir, { withFileTypes: true }).filter((d) => d.isDirectory());\n for (const agentDir of agentDirs) {\n const sessionsFile = join(agentsDir, agentDir.name, \"sessions\", \"sessions.json\");\n const sessionsData = readJsonSafe(sessionsFile);\n if (sessionsData) {\n for (const value of Object.values(sessionsData)) {\n if (typeof value === \"object\" && value && typeof value.lastChannel === \"string\") {\n if (!channels.includes(value.lastChannel)) {\n channels.push(value.lastChannel);\n }\n }\n }\n }\n }\n }\n catch { /* ignore */ }\n }\n // Plugins\n const plugins = [];\n if (pluginsConfig?.entries) {\n for (const [name, entry] of Object.entries(pluginsConfig.entries)) {\n plugins.push({ name, enabled: entry?.enabled !== false });\n }\n }\n // Hooks\n const hooks = [];\n if (hooksConfig?.internal?.entries) {\n for (const [name, entry] of Object.entries(hooksConfig.internal.entries)) {\n hooks.push({ name, enabled: entry?.enabled !== false });\n }\n }\n // Count sessions across all agent dirs\n let totalSessions = 0;\n let lastActive = null;\n if (existsSync(agentsDir)) {\n try {\n for (const dir of readdirSync(agentsDir, { withFileTypes: true })) {\n if (!dir.isDirectory())\n continue;\n const result = countSessions(join(agentsDir, dir.name));\n totalSessions += result.count;\n if (result.lastActive && (!lastActive || result.lastActive > lastActive)) {\n lastActive = result.lastActive;\n }\n }\n }\n catch { /* ignore */ }\n }\n const ownerName = parseOwnerName(workspacePath);\n const avatarExt = discoverAvatar(workspacePath);\n const agent = {\n id: \"main\",\n name: identity.name || \"Agent\",\n emoji: identity.emoji || \"🤖\",\n creature: identity.creature || \"\",\n vibe: identity.vibe || \"\",\n model,\n provider,\n workspacePath,\n ownerName,\n avatarUrl: avatarExt ? `/api/discovery/agents/main/avatar` : null,\n skills,\n connectedSystems,\n channels,\n plugins,\n hooks,\n sessionCount: totalSessions,\n lastActive,\n };\n // Check for additional agent directories\n const agents = [agent];\n if (existsSync(agentsDir)) {\n try {\n for (const dir of readdirSync(agentsDir, { withFileTypes: true })) {\n if (!dir.isDirectory() || dir.name === \"main\")\n continue;\n const agentPath = join(agentsDir, dir.name);\n const sessionInfo = countSessions(agentPath);\n agents.push({\n id: dir.name,\n name: dir.name,\n emoji: \"🤖\",\n creature: \"\",\n vibe: \"\",\n model,\n provider,\n workspacePath: agentPath,\n ownerName: \"\",\n avatarUrl: null,\n skills: [],\n connectedSystems: [],\n channels: [],\n plugins: [],\n hooks: [],\n sessionCount: sessionInfo.count,\n lastActive: sessionInfo.lastActive,\n });\n }\n }\n catch { /* ignore */ }\n }\n return agents;\n}\nexport function getAgent(id) {\n const agents = scanAgents();\n return agents.find((a) => a.id === id);\n}\n// ---- Profile enrichment ----\nfunction parseFrontmatter(content) {\n const result = {};\n if (!content.startsWith(\"---\"))\n return result;\n const end = content.indexOf(\"---\", 3);\n if (end === -1)\n return result;\n const block = content.slice(3, end);\n for (const line of block.split(\"\\n\")) {\n const match = line.match(/^(\\w[\\w\\s]*):\\s*(.+)/);\n if (match) {\n const key = match[1].trim().toLowerCase();\n let val = match[2].trim();\n // Strip surrounding quotes\n if ((val.startsWith('\"') && val.endsWith('\"')) || (val.startsWith(\"'\") && val.endsWith(\"'\"))) {\n val = val.slice(1, -1);\n }\n result[key] = val;\n }\n }\n // Try to extract nested emoji from metadata block\n const emojiMatch = block.match(/emoji:\\s*[\"']?([^\\n\"']+)[\"']?/);\n if (emojiMatch)\n result[\"emoji\"] = emojiMatch[1].trim();\n return result;\n}\nlet _openclawRoot = undefined;\nfunction resolveOpenclawRoot() {\n if (_openclawRoot !== undefined)\n return _openclawRoot;\n // Try env var first\n const skillsPath = getEnv(\"OPENCLAW_SKILLS_PATH\");\n if (skillsPath) {\n _openclawRoot = skillsPath;\n return _openclawRoot;\n }\n try {\n const bin = execSync(\"which openclaw\", { encoding: \"utf-8\", timeout: 5000 }).trim();\n if (bin) {\n // Binary is at <prefix>/bin/openclaw\n const binDir = dirname(bin);\n // Standard global install: <prefix>/bin/openclaw → <prefix>/lib/node_modules/openclaw\n // Covers nvm, volta, fnm, homebrew node, system node\n const globalPkg = join(binDir, \"..\", \"lib\", \"node_modules\", \"openclaw\");\n if (existsSync(join(globalPkg, \"skills\"))) {\n _openclawRoot = globalPkg;\n return _openclawRoot;\n }\n // Sibling layout: <pkg>/bin/openclaw → <pkg>/skills\n if (existsSync(join(binDir, \"..\", \"skills\"))) {\n _openclawRoot = join(binDir, \"..\");\n return _openclawRoot;\n }\n // node_modules/.bin symlink: node_modules/.bin/openclaw → node_modules/openclaw\n const parentDir = dirname(binDir);\n if (existsSync(join(parentDir, \"openclaw\", \"skills\"))) {\n _openclawRoot = join(parentDir, \"openclaw\");\n return _openclawRoot;\n }\n }\n }\n catch {\n // which not found or timeout\n }\n // Fallback: common locations\n const candidates = [\n join(homedir(), \".openclaw\", \"node_modules\", \"openclaw\"),\n \"/usr/local/lib/node_modules/openclaw\",\n ];\n for (const c of candidates) {\n if (existsSync(join(c, \"skills\"))) {\n _openclawRoot = c;\n return _openclawRoot;\n }\n }\n _openclawRoot = null;\n return null;\n}\nfunction discoverSystemSkills() {\n const root = resolveOpenclawRoot();\n if (!root)\n return [];\n const skillsDir = join(root, \"skills\");\n if (!existsSync(skillsDir))\n return [];\n try {\n return readdirSync(skillsDir, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => {\n const skillMd = readFileSafe(join(skillsDir, d.name, \"SKILL.md\"));\n const fm = parseFrontmatter(skillMd);\n return {\n name: fm[\"name\"] || d.name,\n description: fm[\"description\"],\n emoji: fm[\"emoji\"],\n source: \"system\",\n };\n });\n }\n catch {\n return [];\n }\n}\nfunction discoverWorkspaceSkillsEnriched(workspacePath) {\n const skillsDir = join(workspacePath, \"skills\");\n if (!existsSync(skillsDir))\n return [];\n try {\n return readdirSync(skillsDir, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => {\n // Try SKILL.md frontmatter first, fall back to _meta.json\n const skillMd = readFileSafe(join(skillsDir, d.name, \"SKILL.md\"));\n const fm = parseFrontmatter(skillMd);\n const meta = readJsonSafe(join(skillsDir, d.name, \"_meta.json\"));\n return {\n name: fm[\"name\"] || d.name,\n description: fm[\"description\"] || meta?.description,\n emoji: fm[\"emoji\"],\n source: \"workspace\",\n };\n });\n }\n catch {\n return [];\n }\n}\nfunction discoverSystemExtensions() {\n const root = resolveOpenclawRoot();\n if (!root)\n return [];\n const extDir = join(root, \"extensions\");\n if (!existsSync(extDir))\n return [];\n try {\n return readdirSync(extDir, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => {\n const pluginJson = readJsonSafe(join(extDir, d.name, \"openclaw.plugin.json\"));\n const pkgJson = readJsonSafe(join(extDir, d.name, \"package.json\"));\n return {\n name: pluginJson?.id || d.name,\n description: pkgJson?.description || \"\",\n channels: pluginJson?.channels || [],\n };\n });\n }\n catch {\n return [];\n }\n}\nexport function getAgentProfile(id) {\n const agent = getAgent(id);\n if (!agent)\n return undefined;\n const wp = agent.workspacePath;\n // Read workspace MD files\n const workspaceFiles = {\n soul: readFileSafe(join(wp, \"SOUL.md\")),\n identity: readFileSafe(join(wp, \"IDENTITY.md\")),\n user: readFileSafe(join(wp, \"USER.md\")),\n agents: readFileSafe(join(wp, \"AGENTS.md\")),\n tools: readFileSafe(join(wp, \"TOOLS.md\")),\n heartbeat: readFileSafe(join(wp, \"HEARTBEAT.md\")),\n };\n // Bootstrap existence\n const bootstrapExists = existsSync(join(wp, \"BOOTSTRAP.md\"));\n // Cron jobs\n let cronJobs = [];\n const cronPath = join(OPENCLAW_DIR, \"cron\", \"jobs.json\");\n try {\n const raw = readFileSafe(cronPath);\n if (raw) {\n const parsed = JSON.parse(raw);\n if (Array.isArray(parsed)) {\n cronJobs = parsed;\n }\n else if (typeof parsed === \"object\" && parsed !== null) {\n // Handle { jobs: [...] } shape\n cronJobs = parsed.jobs || Object.values(parsed);\n }\n }\n }\n catch {\n // ignore\n }\n // Combine system + workspace skills\n const systemSkills = discoverSystemSkills();\n const workspaceSkills = discoverWorkspaceSkillsEnriched(wp);\n const allSkills = [...systemSkills, ...workspaceSkills];\n // Bundled extensions\n const bundledExtensions = discoverSystemExtensions();\n return {\n ...agent,\n workspaceFiles,\n bootstrapExists,\n cronJobs,\n allSkills,\n bundledExtensions,\n };\n}\n//# sourceMappingURL=discovery.js.map"],"names":[],"sourceRoot":""}
@@ -0,0 +1,328 @@
1
+ export const id = 598;
2
+ export const ids = [598];
3
+ export const modules = {
4
+
5
+ /***/ 9217:
6
+ /***/ ((__webpack_module__, __webpack_exports__, __webpack_require__) => {
7
+
8
+ __webpack_require__.a(__webpack_module__, async (__webpack_handle_async_dependencies__, __webpack_async_result__) => { try {
9
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
10
+ /* harmony export */ gatewayRouter: () => (/* binding */ router)
11
+ /* harmony export */ });
12
+ /* harmony import */ var express__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(316);
13
+ /* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3024);
14
+ /* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6760);
15
+ /* harmony import */ var node_os__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8161);
16
+ /* harmony import */ var _og_db__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(6020);
17
+ var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([_og_db__WEBPACK_IMPORTED_MODULE_4__]);
18
+ _og_db__WEBPACK_IMPORTED_MODULE_4__ = (__webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__)[0];
19
+ /**
20
+ * Gateway API routes
21
+ *
22
+ * Provides status and management endpoints for the AI Security Gateway.
23
+ */
24
+
25
+
26
+
27
+
28
+
29
+ const gatewayActivityDb = (0,_og_db__WEBPACK_IMPORTED_MODULE_4__/* .gatewayActivityQueries */ .y)(_og_db__WEBPACK_IMPORTED_MODULE_4__.db);
30
+ const DEFAULT_TENANT_ID = "default";
31
+ const router = (0,express__WEBPACK_IMPORTED_MODULE_0__.Router)();
32
+ // File paths - unified to moltguard data directory
33
+ const OPENCLAW_DIR = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)((0,node_os__WEBPACK_IMPORTED_MODULE_3__.homedir)(), ".openclaw");
34
+ const MOLTGUARD_DATA_DIR = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(OPENCLAW_DIR, "extensions", "moltguard", "data");
35
+ const GATEWAY_CONFIG = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(MOLTGUARD_DATA_DIR, "gateway.json");
36
+ const GATEWAY_PID_FILE = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(MOLTGUARD_DATA_DIR, "gateway.pid");
37
+ const GATEWAY_BACKUP = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(MOLTGUARD_DATA_DIR, "gateway-backup.json");
38
+ /**
39
+ * Check if gateway process is running by checking PID file
40
+ * Note: In-process gateway (embedded in moltguard) won't have a PID file
41
+ */
42
+ function checkPidFile() {
43
+ if (!(0,node_fs__WEBPACK_IMPORTED_MODULE_1__.existsSync)(GATEWAY_PID_FILE)) {
44
+ return { hasPid: false };
45
+ }
46
+ try {
47
+ const pid = parseInt((0,node_fs__WEBPACK_IMPORTED_MODULE_1__["read"+"FileSync"])(GATEWAY_PID_FILE, "utf-8").trim(), 10);
48
+ // Signal 0 doesn't kill, just checks if process exists
49
+ process.kill(pid, 0);
50
+ return { hasPid: true, pid };
51
+ }
52
+ catch {
53
+ return { hasPid: false };
54
+ }
55
+ }
56
+ /**
57
+ * Check if gateway is actually responding by calling health endpoint
58
+ */
59
+ async function checkGatewayHealth(port) {
60
+ const controller = new AbortController();
61
+ const timeoutId = setTimeout(() => controller.abort(), 2000);
62
+ try {
63
+ const response = await fetch(`http://127.0.0.1:${port}/health`, {
64
+ signal: controller.signal,
65
+ });
66
+ clearTimeout(timeoutId);
67
+ if (response.ok) {
68
+ return { healthy: true };
69
+ }
70
+ else {
71
+ return { healthy: false, error: `Status ${response.status}` };
72
+ }
73
+ }
74
+ catch (err) {
75
+ clearTimeout(timeoutId);
76
+ return { healthy: false, error: err instanceof Error ? err.message : "Connection failed" };
77
+ }
78
+ }
79
+ /**
80
+ * Read gateway configuration
81
+ */
82
+ function readGatewayConfig() {
83
+ if (!(0,node_fs__WEBPACK_IMPORTED_MODULE_1__.existsSync)(GATEWAY_CONFIG)) {
84
+ return null;
85
+ }
86
+ try {
87
+ return JSON.parse((0,node_fs__WEBPACK_IMPORTED_MODULE_1__["read"+"FileSync"])(GATEWAY_CONFIG, "utf-8"));
88
+ }
89
+ catch {
90
+ return null;
91
+ }
92
+ }
93
+ /**
94
+ * Read gateway backup (enabled state)
95
+ */
96
+ function readGatewayBackup() {
97
+ if (!(0,node_fs__WEBPACK_IMPORTED_MODULE_1__.existsSync)(GATEWAY_BACKUP)) {
98
+ return { enabled: false, agents: [], providers: [] };
99
+ }
100
+ try {
101
+ const backup = JSON.parse((0,node_fs__WEBPACK_IMPORTED_MODULE_1__["read"+"FileSync"])(GATEWAY_BACKUP, "utf-8"));
102
+ const agents = backup.entries?.map((e) => e.agentName) || [];
103
+ const providerSet = new Set();
104
+ for (const entry of backup.entries || []) {
105
+ for (const providerName of Object.keys(entry.providers || {})) {
106
+ providerSet.add(providerName);
107
+ }
108
+ }
109
+ return {
110
+ enabled: true,
111
+ agents,
112
+ providers: Array.from(providerSet),
113
+ timestamp: backup.timestamp,
114
+ };
115
+ }
116
+ catch {
117
+ return { enabled: false, agents: [], providers: [] };
118
+ }
119
+ }
120
+ /**
121
+ * GET /api/gateway/status
122
+ * Get current gateway status
123
+ */
124
+ router.get("/status", async (_req, res) => {
125
+ try {
126
+ const { hasPid, pid } = checkPidFile();
127
+ const backup = readGatewayBackup();
128
+ const config = readGatewayConfig();
129
+ const port = config?.port || 53669;
130
+ // Check if gateway is actually running by calling health endpoint
131
+ // This works for both standalone and in-process (embedded) gateway
132
+ const { healthy } = await checkGatewayHealth(port);
133
+ const status = {
134
+ enabled: backup.enabled,
135
+ running: healthy, // Use health check instead of PID file
136
+ pid: hasPid ? pid : undefined,
137
+ port,
138
+ url: `http://127.0.0.1:${port}`,
139
+ agents: backup.agents,
140
+ providers: backup.providers,
141
+ enabledAt: backup.timestamp || null,
142
+ backends: config ? Object.keys(config.backends || {}) : [],
143
+ };
144
+ res.json({ success: true, data: status });
145
+ }
146
+ catch (error) {
147
+ res.status(500).json({
148
+ success: false,
149
+ error: error instanceof Error ? error.message : "Failed to get gateway status",
150
+ });
151
+ }
152
+ });
153
+ /**
154
+ * GET /api/gateway/config
155
+ * Get gateway configuration (without sensitive data)
156
+ */
157
+ router.get("/config", (_req, res) => {
158
+ try {
159
+ const config = readGatewayConfig();
160
+ if (!config) {
161
+ res.json({
162
+ success: true,
163
+ data: {
164
+ configured: false,
165
+ port: 53669,
166
+ backends: [],
167
+ },
168
+ });
169
+ return;
170
+ }
171
+ // Return config without API keys
172
+ const backends = config.backends || {};
173
+ const sanitizedBackends = {};
174
+ for (const [name, backend] of Object.entries(backends)) {
175
+ sanitizedBackends[name] = {
176
+ baseUrl: backend.baseUrl || "",
177
+ hasApiKey: true, // We know it exists, just don't expose it
178
+ };
179
+ }
180
+ res.json({
181
+ success: true,
182
+ data: {
183
+ configured: true,
184
+ port: config.port || 53669,
185
+ backends: sanitizedBackends,
186
+ routing: config.routing || {},
187
+ },
188
+ });
189
+ }
190
+ catch (error) {
191
+ res.status(500).json({
192
+ success: false,
193
+ error: error instanceof Error ? error.message : "Failed to get gateway config",
194
+ });
195
+ }
196
+ });
197
+ /**
198
+ * GET /api/gateway/health
199
+ * Check if gateway is responding
200
+ */
201
+ router.get("/health", async (_req, res) => {
202
+ try {
203
+ const config = readGatewayConfig();
204
+ const port = config?.port || 53669;
205
+ const { healthy, error } = await checkGatewayHealth(port);
206
+ res.json({
207
+ success: true,
208
+ data: {
209
+ healthy,
210
+ ...(error ? { error } : {}),
211
+ },
212
+ });
213
+ }
214
+ catch (error) {
215
+ res.status(500).json({
216
+ success: false,
217
+ error: error instanceof Error ? error.message : "Failed to check gateway health",
218
+ });
219
+ }
220
+ });
221
+ /**
222
+ * POST /api/gateway/activity
223
+ * Receive gateway activity events from MoltGuard
224
+ */
225
+ router.post("/activity", async (req, res) => {
226
+ try {
227
+ const event = req.body;
228
+ if (!event || !event.id || !event.type) {
229
+ res.status(400).json({
230
+ success: false,
231
+ error: "Invalid activity event: missing id or type",
232
+ });
233
+ return;
234
+ }
235
+ await gatewayActivityDb.create({
236
+ eventId: event.id,
237
+ requestId: event.requestId,
238
+ timestamp: event.timestamp,
239
+ type: event.type,
240
+ direction: event.direction,
241
+ backend: event.backend,
242
+ endpoint: event.endpoint,
243
+ model: event.model || null,
244
+ redactionCount: event.redactionCount || 0,
245
+ categories: event.categories || {},
246
+ durationMs: event.durationMs || null,
247
+ tenantId: DEFAULT_TENANT_ID,
248
+ });
249
+ res.json({ success: true });
250
+ }
251
+ catch (error) {
252
+ console.error("[gateway] Failed to save activity:", error);
253
+ res.status(500).json({
254
+ success: false,
255
+ error: error instanceof Error ? error.message : "Failed to save activity",
256
+ });
257
+ }
258
+ });
259
+ /**
260
+ * GET /api/gateway/activity
261
+ * List recent gateway activity events
262
+ */
263
+ router.get("/activity", async (req, res) => {
264
+ try {
265
+ const limit = Math.min(parseInt(req.query.limit || "100", 10), 1000);
266
+ const type = req.query.type;
267
+ const events = await gatewayActivityDb.findRecent({
268
+ tenantId: DEFAULT_TENANT_ID,
269
+ limit,
270
+ type: type === "sanitize" || type === "restore" ? type : undefined,
271
+ });
272
+ // Transform events for API response
273
+ const data = [];
274
+ for (const e of events) {
275
+ data.push({
276
+ id: e.eventId,
277
+ requestId: e.requestId,
278
+ timestamp: e.timestamp,
279
+ type: e.type,
280
+ direction: e.direction,
281
+ backend: e.backend,
282
+ endpoint: e.endpoint,
283
+ model: e.model,
284
+ redactionCount: e.redactionCount,
285
+ categories: e.categories,
286
+ durationMs: e.durationMs,
287
+ });
288
+ }
289
+ res.json({ success: true, data });
290
+ }
291
+ catch (error) {
292
+ console.error("[gateway] Failed to get activity:", error);
293
+ res.status(500).json({
294
+ success: false,
295
+ error: error instanceof Error ? error.message : "Failed to get activity",
296
+ });
297
+ }
298
+ });
299
+ /**
300
+ * GET /api/gateway/activity/stats
301
+ * Get aggregated gateway activity statistics
302
+ */
303
+ router.get("/activity/stats", async (_req, res) => {
304
+ try {
305
+ const stats = await gatewayActivityDb.stats(DEFAULT_TENANT_ID);
306
+ res.json({
307
+ success: true,
308
+ data: stats,
309
+ });
310
+ }
311
+ catch (error) {
312
+ console.error("[gateway] Failed to get activity stats:", error);
313
+ res.status(500).json({
314
+ success: false,
315
+ error: error instanceof Error ? error.message : "Failed to get activity stats",
316
+ });
317
+ }
318
+ });
319
+
320
+ //# sourceMappingURL=gateway.js.map
321
+ __webpack_async_result__();
322
+ } catch(e) { __webpack_async_result__(e); } });
323
+
324
+ /***/ })
325
+
326
+ };
327
+
328
+ //# sourceMappingURL=598.index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"598.index.js","mappings":";;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","sources":[".././dist/routes/gateway.js"],"sourcesContent":["/**\n * Gateway API routes\n *\n * Provides status and management endpoints for the AI Security Gateway.\n */\nimport { Router } from \"express\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { db, gatewayActivityQueries } from \"@og/db\";\nconst gatewayActivityDb = gatewayActivityQueries(db);\nconst DEFAULT_TENANT_ID = \"default\";\nconst router = Router();\n// File paths - unified to moltguard data directory\nconst OPENCLAW_DIR = join(homedir(), \".openclaw\");\nconst MOLTGUARD_DATA_DIR = join(OPENCLAW_DIR, \"extensions\", \"moltguard\", \"data\");\nconst GATEWAY_CONFIG = join(MOLTGUARD_DATA_DIR, \"gateway.json\");\nconst GATEWAY_PID_FILE = join(MOLTGUARD_DATA_DIR, \"gateway.pid\");\nconst GATEWAY_BACKUP = join(MOLTGUARD_DATA_DIR, \"gateway-backup.json\");\n/**\n * Check if gateway process is running by checking PID file\n * Note: In-process gateway (embedded in moltguard) won't have a PID file\n */\nfunction checkPidFile() {\n if (!existsSync(GATEWAY_PID_FILE)) {\n return { hasPid: false };\n }\n try {\n const pid = parseInt(readFileSync(GATEWAY_PID_FILE, \"utf-8\").trim(), 10);\n // Signal 0 doesn't kill, just checks if process exists\n process.kill(pid, 0);\n return { hasPid: true, pid };\n }\n catch {\n return { hasPid: false };\n }\n}\n/**\n * Check if gateway is actually responding by calling health endpoint\n */\nasync function checkGatewayHealth(port) {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 2000);\n try {\n const response = await fetch(`http://127.0.0.1:${port}/health`, {\n signal: controller.signal,\n });\n clearTimeout(timeoutId);\n if (response.ok) {\n return { healthy: true };\n }\n else {\n return { healthy: false, error: `Status ${response.status}` };\n }\n }\n catch (err) {\n clearTimeout(timeoutId);\n return { healthy: false, error: err instanceof Error ? err.message : \"Connection failed\" };\n }\n}\n/**\n * Read gateway configuration\n */\nfunction readGatewayConfig() {\n if (!existsSync(GATEWAY_CONFIG)) {\n return null;\n }\n try {\n return JSON.parse(readFileSync(GATEWAY_CONFIG, \"utf-8\"));\n }\n catch {\n return null;\n }\n}\n/**\n * Read gateway backup (enabled state)\n */\nfunction readGatewayBackup() {\n if (!existsSync(GATEWAY_BACKUP)) {\n return { enabled: false, agents: [], providers: [] };\n }\n try {\n const backup = JSON.parse(readFileSync(GATEWAY_BACKUP, \"utf-8\"));\n const agents = backup.entries?.map((e) => e.agentName) || [];\n const providerSet = new Set();\n for (const entry of backup.entries || []) {\n for (const providerName of Object.keys(entry.providers || {})) {\n providerSet.add(providerName);\n }\n }\n return {\n enabled: true,\n agents,\n providers: Array.from(providerSet),\n timestamp: backup.timestamp,\n };\n }\n catch {\n return { enabled: false, agents: [], providers: [] };\n }\n}\n/**\n * GET /api/gateway/status\n * Get current gateway status\n */\nrouter.get(\"/status\", async (_req, res) => {\n try {\n const { hasPid, pid } = checkPidFile();\n const backup = readGatewayBackup();\n const config = readGatewayConfig();\n const port = config?.port || 53669;\n // Check if gateway is actually running by calling health endpoint\n // This works for both standalone and in-process (embedded) gateway\n const { healthy } = await checkGatewayHealth(port);\n const status = {\n enabled: backup.enabled,\n running: healthy, // Use health check instead of PID file\n pid: hasPid ? pid : undefined,\n port,\n url: `http://127.0.0.1:${port}`,\n agents: backup.agents,\n providers: backup.providers,\n enabledAt: backup.timestamp || null,\n backends: config ? Object.keys(config.backends || {}) : [],\n };\n res.json({ success: true, data: status });\n }\n catch (error) {\n res.status(500).json({\n success: false,\n error: error instanceof Error ? error.message : \"Failed to get gateway status\",\n });\n }\n});\n/**\n * GET /api/gateway/config\n * Get gateway configuration (without sensitive data)\n */\nrouter.get(\"/config\", (_req, res) => {\n try {\n const config = readGatewayConfig();\n if (!config) {\n res.json({\n success: true,\n data: {\n configured: false,\n port: 53669,\n backends: [],\n },\n });\n return;\n }\n // Return config without API keys\n const backends = config.backends || {};\n const sanitizedBackends = {};\n for (const [name, backend] of Object.entries(backends)) {\n sanitizedBackends[name] = {\n baseUrl: backend.baseUrl || \"\",\n hasApiKey: true, // We know it exists, just don't expose it\n };\n }\n res.json({\n success: true,\n data: {\n configured: true,\n port: config.port || 53669,\n backends: sanitizedBackends,\n routing: config.routing || {},\n },\n });\n }\n catch (error) {\n res.status(500).json({\n success: false,\n error: error instanceof Error ? error.message : \"Failed to get gateway config\",\n });\n }\n});\n/**\n * GET /api/gateway/health\n * Check if gateway is responding\n */\nrouter.get(\"/health\", async (_req, res) => {\n try {\n const config = readGatewayConfig();\n const port = config?.port || 53669;\n const { healthy, error } = await checkGatewayHealth(port);\n res.json({\n success: true,\n data: {\n healthy,\n ...(error ? { error } : {}),\n },\n });\n }\n catch (error) {\n res.status(500).json({\n success: false,\n error: error instanceof Error ? error.message : \"Failed to check gateway health\",\n });\n }\n});\n/**\n * POST /api/gateway/activity\n * Receive gateway activity events from MoltGuard\n */\nrouter.post(\"/activity\", async (req, res) => {\n try {\n const event = req.body;\n if (!event || !event.id || !event.type) {\n res.status(400).json({\n success: false,\n error: \"Invalid activity event: missing id or type\",\n });\n return;\n }\n await gatewayActivityDb.create({\n eventId: event.id,\n requestId: event.requestId,\n timestamp: event.timestamp,\n type: event.type,\n direction: event.direction,\n backend: event.backend,\n endpoint: event.endpoint,\n model: event.model || null,\n redactionCount: event.redactionCount || 0,\n categories: event.categories || {},\n durationMs: event.durationMs || null,\n tenantId: DEFAULT_TENANT_ID,\n });\n res.json({ success: true });\n }\n catch (error) {\n console.error(\"[gateway] Failed to save activity:\", error);\n res.status(500).json({\n success: false,\n error: error instanceof Error ? error.message : \"Failed to save activity\",\n });\n }\n});\n/**\n * GET /api/gateway/activity\n * List recent gateway activity events\n */\nrouter.get(\"/activity\", async (req, res) => {\n try {\n const limit = Math.min(parseInt(req.query.limit || \"100\", 10), 1000);\n const type = req.query.type;\n const events = await gatewayActivityDb.findRecent({\n tenantId: DEFAULT_TENANT_ID,\n limit,\n type: type === \"sanitize\" || type === \"restore\" ? type : undefined,\n });\n // Transform events for API response\n const data = [];\n for (const e of events) {\n data.push({\n id: e.eventId,\n requestId: e.requestId,\n timestamp: e.timestamp,\n type: e.type,\n direction: e.direction,\n backend: e.backend,\n endpoint: e.endpoint,\n model: e.model,\n redactionCount: e.redactionCount,\n categories: e.categories,\n durationMs: e.durationMs,\n });\n }\n res.json({ success: true, data });\n }\n catch (error) {\n console.error(\"[gateway] Failed to get activity:\", error);\n res.status(500).json({\n success: false,\n error: error instanceof Error ? error.message : \"Failed to get activity\",\n });\n }\n});\n/**\n * GET /api/gateway/activity/stats\n * Get aggregated gateway activity statistics\n */\nrouter.get(\"/activity/stats\", async (_req, res) => {\n try {\n const stats = await gatewayActivityDb.stats(DEFAULT_TENANT_ID);\n res.json({\n success: true,\n data: stats,\n });\n }\n catch (error) {\n console.error(\"[gateway] Failed to get activity stats:\", error);\n res.status(500).json({\n success: false,\n error: error instanceof Error ? error.message : \"Failed to get activity stats\",\n });\n }\n});\nexport { router as gatewayRouter };\n//# sourceMappingURL=gateway.js.map"],"names":[],"sourceRoot":""}