@0xmaxma/claude-gateway 2.0.6 → 2.0.7

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 (364) hide show
  1. package/README.md +14 -1
  2. package/dist/agent/builtin-commands.js +5 -5
  3. package/dist/agent/builtin-commands.js.map +1 -1
  4. package/dist/agent/command-help.d.ts +9 -0
  5. package/dist/agent/command-help.d.ts.map +1 -0
  6. package/dist/agent/command-help.js +50 -0
  7. package/dist/agent/command-help.js.map +1 -0
  8. package/dist/agent/dreaming/index.d.ts +6 -3
  9. package/dist/agent/dreaming/index.d.ts.map +1 -1
  10. package/dist/agent/dreaming/index.js +21 -1
  11. package/dist/agent/dreaming/index.js.map +1 -1
  12. package/dist/agent/knowledge/reflection.d.ts +7 -4
  13. package/dist/agent/knowledge/reflection.d.ts.map +1 -1
  14. package/dist/agent/knowledge/reflection.js +19 -1
  15. package/dist/agent/knowledge/reflection.js.map +1 -1
  16. package/dist/agent/runner.d.ts +37 -3
  17. package/dist/agent/runner.d.ts.map +1 -1
  18. package/dist/agent/runner.js +164 -47
  19. package/dist/agent/runner.js.map +1 -1
  20. package/dist/agent/session-confirmations.d.ts +12 -0
  21. package/dist/agent/session-confirmations.d.ts.map +1 -0
  22. package/dist/agent/session-confirmations.js +43 -0
  23. package/dist/agent/session-confirmations.js.map +1 -0
  24. package/dist/agent/session-status.d.ts +7 -0
  25. package/dist/agent/session-status.d.ts.map +1 -0
  26. package/dist/agent/session-status.js +16 -0
  27. package/dist/agent/session-status.js.map +1 -0
  28. package/dist/agent/skill-learning/index.d.ts +5 -1
  29. package/dist/agent/skill-learning/index.d.ts.map +1 -1
  30. package/dist/agent/skill-learning/index.js +23 -1
  31. package/dist/agent/skill-learning/index.js.map +1 -1
  32. package/dist/agent/skill-learning/notifier.d.ts +2 -1
  33. package/dist/agent/skill-learning/notifier.d.ts.map +1 -1
  34. package/dist/agent/skill-learning/notifier.js +1 -0
  35. package/dist/agent/skill-learning/notifier.js.map +1 -1
  36. package/dist/api/apps-router.d.ts.map +1 -1
  37. package/dist/api/apps-router.js +1 -3
  38. package/dist/api/apps-router.js.map +1 -1
  39. package/dist/api/cron-router.d.ts +1 -1
  40. package/dist/api/cron-router.d.ts.map +1 -1
  41. package/dist/api/cron-router.js +4 -4
  42. package/dist/api/cron-router.js.map +1 -1
  43. package/dist/api/dashboard-processes.d.ts +86 -0
  44. package/dist/api/dashboard-processes.d.ts.map +1 -0
  45. package/dist/api/dashboard-processes.js +155 -0
  46. package/dist/api/dashboard-processes.js.map +1 -0
  47. package/dist/api/dashboard-sessions.d.ts +15 -0
  48. package/dist/api/dashboard-sessions.d.ts.map +1 -0
  49. package/dist/api/dashboard-sessions.js +66 -0
  50. package/dist/api/dashboard-sessions.js.map +1 -0
  51. package/dist/api/gateway-router.d.ts +3 -4
  52. package/dist/api/gateway-router.d.ts.map +1 -1
  53. package/dist/api/gateway-router.js +77 -56
  54. package/dist/api/gateway-router.js.map +1 -1
  55. package/dist/api/oauth-connectors-router.d.ts +1 -1
  56. package/dist/api/oauth-connectors-router.d.ts.map +1 -1
  57. package/dist/api/oauth-connectors-router.js +11 -21
  58. package/dist/api/oauth-connectors-router.js.map +1 -1
  59. package/dist/api/router.d.ts +1 -1
  60. package/dist/api/router.d.ts.map +1 -1
  61. package/dist/api/router.js +3 -9
  62. package/dist/api/router.js.map +1 -1
  63. package/dist/api/share-router.d.ts +1 -1
  64. package/dist/api/share-router.d.ts.map +1 -1
  65. package/dist/api/share-router.js +1 -1
  66. package/dist/api/share-router.js.map +1 -1
  67. package/dist/api/slack-webhook-router.js +1 -1
  68. package/dist/api/slack-webhook-router.js.map +1 -1
  69. package/dist/api/voice-router.d.ts +1 -0
  70. package/dist/api/voice-router.d.ts.map +1 -1
  71. package/dist/api/voice-router.js +7 -0
  72. package/dist/api/voice-router.js.map +1 -1
  73. package/dist/apps/agent-container-migration.d.ts +2 -0
  74. package/dist/apps/agent-container-migration.d.ts.map +1 -1
  75. package/dist/apps/agent-container-migration.js +59 -2
  76. package/dist/apps/agent-container-migration.js.map +1 -1
  77. package/dist/apps/agent-manager.d.ts +4 -2
  78. package/dist/apps/agent-manager.d.ts.map +1 -1
  79. package/dist/apps/agent-manager.js +39 -3
  80. package/dist/apps/agent-manager.js.map +1 -1
  81. package/dist/apps/installer.d.ts +4 -3
  82. package/dist/apps/installer.d.ts.map +1 -1
  83. package/dist/apps/installer.js +8 -4
  84. package/dist/apps/installer.js.map +1 -1
  85. package/dist/build-provenance.json +8 -0
  86. package/dist/cli/args.js +1 -1
  87. package/dist/cli/args.js.map +1 -1
  88. package/dist/cli/commands/app.d.ts.map +1 -1
  89. package/dist/cli/commands/app.js +39 -3
  90. package/dist/cli/commands/app.js.map +1 -1
  91. package/dist/cli/commands/doctor.d.ts.map +1 -1
  92. package/dist/cli/commands/doctor.js +6 -2
  93. package/dist/cli/commands/doctor.js.map +1 -1
  94. package/dist/cli/commands/safemode.d.ts +2 -0
  95. package/dist/cli/commands/safemode.d.ts.map +1 -0
  96. package/dist/cli/commands/safemode.js +279 -0
  97. package/dist/cli/commands/safemode.js.map +1 -0
  98. package/dist/cli/dependencies.d.ts +2 -0
  99. package/dist/cli/dependencies.d.ts.map +1 -1
  100. package/dist/cli/dependencies.js +81 -0
  101. package/dist/cli/dependencies.js.map +1 -1
  102. package/dist/cli/index.d.ts.map +1 -1
  103. package/dist/cli/index.js +11 -1
  104. package/dist/cli/index.js.map +1 -1
  105. package/dist/cli/manager.d.ts.map +1 -1
  106. package/dist/cli/manager.js +4 -1
  107. package/dist/cli/manager.js.map +1 -1
  108. package/dist/config/agent-lifecycle.d.ts +26 -0
  109. package/dist/config/agent-lifecycle.d.ts.map +1 -0
  110. package/dist/config/agent-lifecycle.js +63 -0
  111. package/dist/config/agent-lifecycle.js.map +1 -0
  112. package/dist/config/loader.d.ts.map +1 -1
  113. package/dist/config/loader.js +11 -0
  114. package/dist/config/loader.js.map +1 -1
  115. package/dist/config/reload-policy.d.ts +9 -0
  116. package/dist/config/reload-policy.d.ts.map +1 -0
  117. package/dist/config/reload-policy.js +62 -0
  118. package/dist/config/reload-policy.js.map +1 -0
  119. package/dist/config/watcher.d.ts +3 -2
  120. package/dist/config/watcher.d.ts.map +1 -1
  121. package/dist/config/watcher.js +34 -51
  122. package/dist/config/watcher.js.map +1 -1
  123. package/dist/cron/tool-schemas.d.ts +296 -0
  124. package/dist/cron/tool-schemas.d.ts.map +1 -0
  125. package/dist/cron/tool-schemas.js +122 -0
  126. package/dist/cron/tool-schemas.js.map +1 -0
  127. package/dist/index.js +141 -158
  128. package/dist/index.js.map +1 -1
  129. package/dist/orchestration/agent-tool-schemas.js +4 -4
  130. package/dist/orchestration/agent-tool-schemas.js.map +1 -1
  131. package/dist/orchestration/background-work.d.ts +9 -0
  132. package/dist/orchestration/background-work.d.ts.map +1 -0
  133. package/dist/orchestration/background-work.js +49 -0
  134. package/dist/orchestration/background-work.js.map +1 -0
  135. package/dist/orchestration/bridge.d.ts +6 -15
  136. package/dist/orchestration/bridge.d.ts.map +1 -1
  137. package/dist/orchestration/bridge.js +67 -32
  138. package/dist/orchestration/bridge.js.map +1 -1
  139. package/dist/orchestration/capabilities.d.ts.map +1 -1
  140. package/dist/orchestration/capabilities.js +18 -10
  141. package/dist/orchestration/capabilities.js.map +1 -1
  142. package/dist/orchestration/capacity.d.ts +3 -2
  143. package/dist/orchestration/capacity.d.ts.map +1 -1
  144. package/dist/orchestration/capacity.js +7 -0
  145. package/dist/orchestration/capacity.js.map +1 -1
  146. package/dist/orchestration/channel-controls.d.ts.map +1 -1
  147. package/dist/orchestration/channel-controls.js +3 -2
  148. package/dist/orchestration/channel-controls.js.map +1 -1
  149. package/dist/orchestration/cli-skills.d.ts +5 -0
  150. package/dist/orchestration/cli-skills.d.ts.map +1 -1
  151. package/dist/orchestration/container-tool-schemas.d.ts +37 -0
  152. package/dist/orchestration/container-tool-schemas.d.ts.map +1 -0
  153. package/dist/orchestration/container-tool-schemas.js +27 -0
  154. package/dist/orchestration/container-tool-schemas.js.map +1 -0
  155. package/dist/orchestration/container.d.ts.map +1 -1
  156. package/dist/orchestration/container.js +7 -0
  157. package/dist/orchestration/container.js.map +1 -1
  158. package/dist/orchestration/dashboard-reader-worker.js +7 -7
  159. package/dist/orchestration/dashboard-reader-worker.js.map +1 -1
  160. package/dist/orchestration/decision-context.js +1 -1
  161. package/dist/orchestration/decision-context.js.map +1 -1
  162. package/dist/orchestration/gateway-tasks/controller.d.ts +29 -0
  163. package/dist/orchestration/gateway-tasks/controller.d.ts.map +1 -0
  164. package/dist/orchestration/gateway-tasks/controller.js +139 -0
  165. package/dist/orchestration/gateway-tasks/controller.js.map +1 -0
  166. package/dist/orchestration/gateway-tasks/safemode.d.ts +19 -0
  167. package/dist/orchestration/gateway-tasks/safemode.d.ts.map +1 -0
  168. package/dist/orchestration/gateway-tasks/safemode.js +128 -0
  169. package/dist/orchestration/gateway-tasks/safemode.js.map +1 -0
  170. package/dist/orchestration/process-turn.d.ts +11 -2
  171. package/dist/orchestration/process-turn.d.ts.map +1 -1
  172. package/dist/orchestration/process-turn.js +47 -7
  173. package/dist/orchestration/process-turn.js.map +1 -1
  174. package/dist/orchestration/recovery.d.ts.map +1 -1
  175. package/dist/orchestration/recovery.js +4 -2
  176. package/dist/orchestration/recovery.js.map +1 -1
  177. package/dist/orchestration/runtime.d.ts +10 -0
  178. package/dist/orchestration/runtime.d.ts.map +1 -1
  179. package/dist/orchestration/runtime.js +31 -4
  180. package/dist/orchestration/runtime.js.map +1 -1
  181. package/dist/orchestration/skills.d.ts +2 -0
  182. package/dist/orchestration/skills.d.ts.map +1 -1
  183. package/dist/orchestration/skills.js +4 -3
  184. package/dist/orchestration/skills.js.map +1 -1
  185. package/dist/orchestration/task-controls.d.ts +12 -0
  186. package/dist/orchestration/task-controls.d.ts.map +1 -1
  187. package/dist/orchestration/task-controls.js +3 -1
  188. package/dist/orchestration/task-controls.js.map +1 -1
  189. package/dist/orchestration/tasks/driver.d.ts.map +1 -1
  190. package/dist/orchestration/tasks/driver.js +99 -12
  191. package/dist/orchestration/tasks/driver.js.map +1 -1
  192. package/dist/orchestration/tasks/pool.d.ts +2 -0
  193. package/dist/orchestration/tasks/pool.d.ts.map +1 -1
  194. package/dist/orchestration/tasks/pool.js +4 -0
  195. package/dist/orchestration/tasks/pool.js.map +1 -1
  196. package/dist/orchestration/tasks/scheduler.d.ts.map +1 -1
  197. package/dist/orchestration/tasks/scheduler.js +4 -0
  198. package/dist/orchestration/tasks/scheduler.js.map +1 -1
  199. package/dist/orchestration/tasks/service.d.ts +4 -0
  200. package/dist/orchestration/tasks/service.d.ts.map +1 -1
  201. package/dist/orchestration/tasks/service.js +38 -8
  202. package/dist/orchestration/tasks/service.js.map +1 -1
  203. package/dist/orchestration/token-ledger.d.ts +1 -0
  204. package/dist/orchestration/token-ledger.d.ts.map +1 -1
  205. package/dist/orchestration/token-ledger.js +6 -2
  206. package/dist/orchestration/token-ledger.js.map +1 -1
  207. package/dist/orchestration/token-usage.d.ts +3 -0
  208. package/dist/orchestration/token-usage.d.ts.map +1 -1
  209. package/dist/orchestration/token-usage.js +12 -3
  210. package/dist/orchestration/token-usage.js.map +1 -1
  211. package/dist/orchestration/types.d.ts +19 -1
  212. package/dist/orchestration/types.d.ts.map +1 -1
  213. package/dist/orchestration/types.js.map +1 -1
  214. package/dist/orchestration/worker-crons.d.ts +5 -0
  215. package/dist/orchestration/worker-crons.d.ts.map +1 -0
  216. package/dist/orchestration/worker-crons.js +84 -0
  217. package/dist/orchestration/worker-crons.js.map +1 -0
  218. package/dist/orchestration/worker-harness.d.ts +15 -0
  219. package/dist/orchestration/worker-harness.d.ts.map +1 -0
  220. package/dist/orchestration/worker-harness.js +72 -0
  221. package/dist/orchestration/worker-harness.js.map +1 -0
  222. package/dist/safemode/config.d.ts +7 -0
  223. package/dist/safemode/config.d.ts.map +1 -0
  224. package/dist/safemode/config.js +67 -0
  225. package/dist/safemode/config.js.map +1 -0
  226. package/dist/safemode/context.d.ts +7 -0
  227. package/dist/safemode/context.d.ts.map +1 -0
  228. package/dist/safemode/context.js +397 -0
  229. package/dist/safemode/context.js.map +1 -0
  230. package/dist/safemode/external-owners.d.ts +19 -0
  231. package/dist/safemode/external-owners.d.ts.map +1 -0
  232. package/dist/safemode/external-owners.js +229 -0
  233. package/dist/safemode/external-owners.js.map +1 -0
  234. package/dist/safemode/native.d.ts +38 -0
  235. package/dist/safemode/native.d.ts.map +1 -0
  236. package/dist/safemode/native.js +220 -0
  237. package/dist/safemode/native.js.map +1 -0
  238. package/dist/safemode/params.d.ts +10 -0
  239. package/dist/safemode/params.d.ts.map +1 -0
  240. package/dist/safemode/params.js +86 -0
  241. package/dist/safemode/params.js.map +1 -0
  242. package/dist/safemode/provenance.d.ts +45 -0
  243. package/dist/safemode/provenance.d.ts.map +1 -0
  244. package/dist/safemode/provenance.js +153 -0
  245. package/dist/safemode/provenance.js.map +1 -0
  246. package/dist/safemode/runner.d.ts +17 -0
  247. package/dist/safemode/runner.d.ts.map +1 -0
  248. package/dist/safemode/runner.js +398 -0
  249. package/dist/safemode/runner.js.map +1 -0
  250. package/dist/safemode/store.d.ts +56 -0
  251. package/dist/safemode/store.d.ts.map +1 -0
  252. package/dist/safemode/store.js +451 -0
  253. package/dist/safemode/store.js.map +1 -0
  254. package/dist/session/codex-auth.d.ts +37 -0
  255. package/dist/session/codex-auth.d.ts.map +1 -0
  256. package/dist/session/codex-auth.js +266 -0
  257. package/dist/session/codex-auth.js.map +1 -0
  258. package/dist/session/codex-container-runtime.d.ts +15 -0
  259. package/dist/session/codex-container-runtime.d.ts.map +1 -0
  260. package/dist/session/codex-container-runtime.js +85 -0
  261. package/dist/session/codex-container-runtime.js.map +1 -0
  262. package/dist/session/codex-context-defaults.json +5 -0
  263. package/dist/session/codex-context.d.ts +13 -0
  264. package/dist/session/codex-context.d.ts.map +1 -0
  265. package/dist/session/codex-context.js +27 -0
  266. package/dist/session/codex-context.js.map +1 -0
  267. package/dist/session/codex-extension-discovery.d.ts +21 -0
  268. package/dist/session/codex-extension-discovery.d.ts.map +1 -0
  269. package/dist/session/codex-extension-discovery.js +132 -0
  270. package/dist/session/codex-extension-discovery.js.map +1 -0
  271. package/dist/session/codex-native-mcp-client.d.ts +37 -0
  272. package/dist/session/codex-native-mcp-client.d.ts.map +1 -0
  273. package/dist/session/codex-native-mcp-client.js +164 -0
  274. package/dist/session/codex-native-mcp-client.js.map +1 -0
  275. package/dist/session/codex-policy.d.ts +6 -0
  276. package/dist/session/codex-policy.d.ts.map +1 -0
  277. package/dist/session/codex-policy.js +17 -0
  278. package/dist/session/codex-policy.js.map +1 -0
  279. package/dist/session/codex-process.d.ts +114 -0
  280. package/dist/session/codex-process.d.ts.map +1 -0
  281. package/dist/session/codex-process.js +759 -0
  282. package/dist/session/codex-process.js.map +1 -0
  283. package/dist/session/codex-runtime.d.ts +20 -0
  284. package/dist/session/codex-runtime.d.ts.map +1 -0
  285. package/dist/session/codex-runtime.js +182 -0
  286. package/dist/session/codex-runtime.js.map +1 -0
  287. package/dist/session/codex-tool-capture.d.ts +35 -0
  288. package/dist/session/codex-tool-capture.d.ts.map +1 -0
  289. package/dist/session/codex-tool-capture.js +178 -0
  290. package/dist/session/codex-tool-capture.js.map +1 -0
  291. package/dist/session/container-connectors.d.ts +10 -0
  292. package/dist/session/container-connectors.d.ts.map +1 -0
  293. package/dist/session/container-connectors.js +41 -0
  294. package/dist/session/container-connectors.js.map +1 -0
  295. package/dist/session/container-extensions.d.ts +4 -0
  296. package/dist/session/container-extensions.d.ts.map +1 -0
  297. package/dist/session/container-extensions.js +45 -0
  298. package/dist/session/container-extensions.js.map +1 -0
  299. package/dist/session/managed-connectors.d.ts +16 -0
  300. package/dist/session/managed-connectors.d.ts.map +1 -0
  301. package/dist/session/managed-connectors.js +25 -0
  302. package/dist/session/managed-connectors.js.map +1 -0
  303. package/dist/session/process-diagnostics.d.ts +14 -0
  304. package/dist/session/process-diagnostics.d.ts.map +1 -0
  305. package/dist/session/process-diagnostics.js +39 -0
  306. package/dist/session/process-diagnostics.js.map +1 -0
  307. package/dist/session/process.d.ts +4 -0
  308. package/dist/session/process.d.ts.map +1 -1
  309. package/dist/session/process.js +21 -16
  310. package/dist/session/process.js.map +1 -1
  311. package/dist/session/request-tool-capture.d.ts +1 -1
  312. package/dist/session/request-tool-capture.d.ts.map +1 -1
  313. package/dist/session/runtime-profile.d.ts +8 -0
  314. package/dist/session/runtime-profile.d.ts.map +1 -1
  315. package/dist/session/runtime-profile.js +3 -2
  316. package/dist/session/runtime-profile.js.map +1 -1
  317. package/dist/session/worker-environment.d.ts +5 -0
  318. package/dist/session/worker-environment.d.ts.map +1 -0
  319. package/dist/session/worker-environment.js +27 -0
  320. package/dist/session/worker-environment.js.map +1 -0
  321. package/dist/session/worker-extensions.d.ts +20 -0
  322. package/dist/session/worker-extensions.d.ts.map +1 -0
  323. package/dist/session/worker-extensions.js +322 -0
  324. package/dist/session/worker-extensions.js.map +1 -0
  325. package/dist/skills/loader.d.ts +2 -0
  326. package/dist/skills/loader.d.ts.map +1 -1
  327. package/dist/skills/loader.js.map +1 -1
  328. package/dist/types.d.ts +30 -0
  329. package/dist/types.d.ts.map +1 -1
  330. package/dist/ui/codex-context.d.ts +4 -0
  331. package/dist/ui/codex-context.d.ts.map +1 -0
  332. package/dist/ui/codex-context.js +15 -0
  333. package/dist/ui/codex-context.js.map +1 -0
  334. package/dist/ui/dashboard-client.d.ts.map +1 -1
  335. package/dist/ui/dashboard-client.js +14 -11
  336. package/dist/ui/dashboard-client.js.map +1 -1
  337. package/dist/ui/dashboard-presentation.d.ts +1 -1
  338. package/dist/ui/dashboard-presentation.d.ts.map +1 -1
  339. package/dist/ui/dashboard-presentation.js +2 -2
  340. package/dist/ui/dashboard-presentation.js.map +1 -1
  341. package/dist/ui/token-report.d.ts +3 -0
  342. package/dist/ui/token-report.d.ts.map +1 -1
  343. package/dist/ui/token-report.js +22 -10
  344. package/dist/ui/token-report.js.map +1 -1
  345. package/dist/ui/web-ui.d.ts.map +1 -1
  346. package/dist/ui/web-ui.js +53 -132
  347. package/dist/ui/web-ui.js.map +1 -1
  348. package/mcp/capability-catalog.ts +2 -0
  349. package/mcp/extension-catalog.ts +18 -0
  350. package/mcp/lazy-connector.ts +4 -2
  351. package/mcp/lazy-tools.test.ts +29 -0
  352. package/mcp/modules.ts +1 -0
  353. package/mcp/server.ts +2 -2
  354. package/mcp/tools/cron/module.ts +8 -114
  355. package/mcp/tools/discord/commands.ts +4 -1
  356. package/mcp/tools/safemode/module.test.ts +29 -0
  357. package/mcp/tools/telegram/receiver-server.ts +2 -22
  358. package/mcp/tools/telegram/task-detail.ts +2 -1
  359. package/package.json +3 -2
  360. package/scripts/orchestration/audit-codex-context.cjs +83 -0
  361. package/scripts/orchestration/benchmark-worker-harnesses.cjs +112 -0
  362. package/scripts/orchestration/smoke-codex-extensions.ts +29 -0
  363. package/scripts/orchestration/smoke-codex-worker.cjs +166 -0
  364. package/scripts/orchestration/smoke-safemode-codex.cjs +66 -0
package/dist/ui/web-ui.js CHANGED
@@ -373,7 +373,7 @@ ${dashboard_theme_1.dashboardFontLink}<script>try{document.documentElement.datas
373
373
  <body><div class="layout"><aside class="sidebar" id="dashboard-sidebar"><div class="brand row" id="sidebar-brand" role="button" tabindex="0" aria-label="Collapse sidebar" aria-expanded="true" aria-controls="dashboard-sidebar"><div class="brandmark" aria-hidden="true">✳</div><div>Claude Gateway<small>OPERATIONS CONSOLE</small></div></div><div class="navlabel">WORKSPACE</div><nav class="tabs" aria-label="Main navigation"><button class="tab active" id="tab-overview" data-view="view-overview"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M3 3h7v7H3zM14 3h7v4h-7zM14 11h7v10h-7zM3 14h7v7H3z"/></svg>Overview</button><button class="tab " id="tab-sessions" data-view="view-sessions"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M21 11a8 8 0 0 1-8 8H6l-4 3 1-7a8 8 0 1 1 18-4Z"/></svg>Conversations</button><button class="tab " id="tab-tasks" data-view="view-tasks"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M9 5h12M9 12h12M9 19h12M3 5l1 1 2-3M3 12l1 1 2-3M3 19l1 1 2-3"/></svg>Tasks</button><button class="tab " id="tab-usage" data-view="view-usage"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M4 20V10m8 10V4m8 16v-7"/></svg>Usage & tokens</button><button class="tab " id="tab-kb" data-view="view-kb"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M4 3h7v18H4zM14 3h7v18h-7zM7 7h1m9 0h1"/></svg>Knowledge base</button><button class="tab " id="tab-dreams" data-view="view-dreams"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M20 15A9 9 0 0 1 9 4 9 9 0 1 0 20 15Z"/></svg>Nightly dreaming</button><button class="tab " id="tab-system" data-view="view-system"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M3 4h18v6H3zM3 14h18v6H3zM6 7h1M6 17h1"/></svg>System</button></nav><div class="sidebarfoot"><div class="instance">Claude Gateway<br><span id="gateway-version"></span></div></div></aside><div class="main"><header class="topbar"><div class="row"><button id="dash-menu" class="mobilemenu" aria-label="Collapse sidebar" aria-expanded="true" aria-controls="dashboard-sidebar" title="Collapse sidebar"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M9 4v16"/></svg></button><h1 id="dash-current-view">Overview</h1></div><div id="top-right"><span id="refresh-indicator">Connecting…</span>${(0, dashboard_controls_1.themeButtonHtml)('dash-theme')}<button id="logout-btn">Logout</button></div></header><main class="shell-content"><div class="meta">Uptime: <span id="uptime">—</span> · Started: <span id="started-at">—</span> · Updated: <span id="last-updated">—</span></div>
374
374
  <div id="view-overview" class="view"><div class="heading" style="margin-top:24px"><div class="eyebrow">ONE WORKSPACE. EVERY CONVERSATION.</div><h1>Good work, <span class="gradient-title">in motion.</span></h1><p>Your agents, ongoing work, and what needs your attention.</p></div><div class="dash-grid" id="overview-stats"></div>${(0, dashboard_charts_1.dashboardChartsHtml)(timezone)}<section class="dash-panel" id="overview-attention-panel" hidden><h2>Needs your attention</h2><p class="live-note">Inspect the task here, then reply to your agent in the original chat.</p><div class="dash-mini-list" id="overview-attention"></div></section><section class="dash-panel"><h2>Agents</h2><div class="agents-bar" id="agents-bar"></div></section><section class="dash-panel"><h2>Active & recent work</h2><div id="overview-tasks"></div></section></div>
375
375
  <div class="dash-filter turn-filters"><input id="dash-search" type="search" aria-label="Filter displayed sessions" placeholder="Filter this page by session, chat or model…">${(0, dashboard_range_1.rangeButtons)("dash-scope", "24h", timezone)}<select id="dash-agent-filter" aria-label="Filter agent"><option value="">All agents</option></select></div><div class="dash-pager"><span data-dash-page></span><div class="row"><button data-dash-prev disabled>← Previous</button><button data-dash-next disabled>Next →</button></div></div>
376
- <div id="view-tasks" class="view" style="display:none"><h2>Tasks & workers</h2><p id="tasks-scope" class="live-note"></p><div id="task-results"></div></div><div id="view-usage" class="view" style="display:none"><h2>Usage & tokens</h2><p class="live-note">Session totals include every recorded attempt, including retries. Missing measurements are shown as —. Open a report for input, cache write, cache read, output and per-turn details.</p><div id="usage-results"></div></div>
376
+ <div id="view-tasks" class="view" style="display:none"><h2>Tasks</h2><p id="tasks-scope" class="live-note"></p><div id="task-results"></div></div><div id="view-usage" class="view" style="display:none"><h2>Usage & tokens</h2><p class="live-note">Session totals include every recorded attempt, including retries. Missing measurements are shown as —. Open a report for input, cache write, cache read, output and per-turn details.</p><div id="usage-results"></div></div>
377
377
  <div id="view-system" class="view" style="display:none">
378
378
  <h2>Processes</h2>
379
379
  <div class="proc-tree" id="proc-tree">Loading...</div>
@@ -829,11 +829,11 @@ ${dashboard_theme_1.dashboardFontLink}<script>try{document.documentElement.datas
829
829
 
830
830
  // Format a context-window token count compactly: 1234 -> "1.2k", 45000 -> "45k".
831
831
  // Full value is kept in the tooltip. 0/unknown renders as a dash.
832
- function toolInventory(loaded, used, contextTools) {
832
+ function toolInventory(loaded, used, contextTools, harness) {
833
833
  function list(label, names) {
834
834
  return '<div title="'+(Array.isArray(names)?escHtml(names.join(', ')||'None'):'Not recorded')+'">'+label+': '+(Array.isArray(names)?compactNumber(names.length):'—')+'</div>';
835
835
  }
836
- return list('Loaded', contextTools)+list('Used', used);
836
+ return list('Loaded', contextTools)+list('Used', Array.isArray(used)?used.map(name=>harness==='codex'&&name==='Bash'?'Shell':name):used);
837
837
  }
838
838
 
839
839
  function fmtRecordedTokens(n) {
@@ -899,145 +899,66 @@ ${dashboard_theme_1.dashboardFontLink}<script>try{document.documentElement.datas
899
899
  try {
900
900
  const res = await fetch(apiUrl('/processes'));
901
901
  if (res.status === 401) { onUnauthorized(); return; }
902
- if (!res.ok) return;
902
+ if (!res.ok) throw new Error('Process inspection unavailable (HTTP '+res.status+')');
903
903
  const data = await res.json();
904
- renderProcessTree(data.processes || [], data.numCpus || 1);
904
+ renderProcessTree(data.processes || [], data.numCpus || 1, data.containers || [], data.warnings || []);
905
905
  } catch(e) {
906
906
  document.getElementById('proc-tree').textContent = 'Error: ' + e.message;
907
907
  }
908
908
  }
909
909
 
910
- function renderProcessTree(procs, numCpus) {
911
- if (!procs.length) {
912
- document.getElementById('proc-tree').textContent = '— no gateway processes found ';
913
- return;
914
- }
915
-
916
- const pidMap = {};
917
- procs.forEach(function(p) { pidMap[p.pid] = p; });
918
-
919
- // Aggregate resource usage across the whole gateway process tree.
920
- // ps %cpu is per-core (100% = 1 core), so divide by numCpus to get
921
- // a normalized 0–100% load figure across all available cores.
922
- // RSS is summed and may slightly over-count shared pages.
923
- let rawCpuSum = 0, totalRssKb = 0;
924
- procs.forEach(function(p) {
925
- rawCpuSum += Number(p.cpu) || 0;
926
- totalRssKb += Number(p.rssKb) || 0;
927
- });
928
- const totalCpu = rawCpuSum / (numCpus || 1);
929
- const totalMemMb = totalRssKb / 1024;
930
- const memStr = totalMemMb >= 1024
931
- ? (totalMemMb / 1024).toFixed(2) + ' GB'
932
- : totalMemMb.toFixed(0) + ' MB';
933
-
934
- function cat(p) {
935
- const a = p.args;
936
- if (a.includes('node') && (a.includes('dist/index') || a.includes('dist/entry'))) return 'orchestrator';
937
- if (a.includes('claude-pty-shell')) return 'pty';
938
- if (a.includes('bun') && a.includes('mcp/server')) return 'mcp';
939
- if (a.includes('bun') && a.includes('telegram') && a.includes('receiver')) return 'telegram';
940
- if (a.includes('bun') && a.includes('discord') && a.includes('receiver')) return 'discord';
941
- if (a.includes('--mcp-config') && (a.includes('--session-id') || a.includes('--print'))) {
942
- if (a.includes('--session-id')) {
943
- const parent = pidMap[p.ppid];
944
- return (parent && cat(parent) === 'pty') ? 'claude-pty' : 'claude-headless';
945
- }
946
- return 'claude-headless';
910
+ function renderProcessTree(procs, numCpus, containers, warnings) {
911
+ const unique = Array.from(new Map(procs.map(p=>[p.pid,p])).values());
912
+ const memory = kb => kb >= 1048576 ? (kb/1048576).toFixed(2)+' GB' : (kb/1024).toFixed(0)+' MB';
913
+ const resources = rows => 'CPU '+(rows.reduce((s,p)=>s+(Number(p.cpu)||0),0)/numCpus).toFixed(1)+'% · MEM '+memory(rows.reduce((s,p)=>s+(Number(p.rssKb)||0),0));
914
+ const lines = ['<span class="proc-summary">∑ '+unique.length+' procs · '+resources(unique)+'</span>',
915
+ '<span class="ts">CPU: lifetime average, normalized across cores · MEM: summed RSS</span>',''];
916
+ const label = p => [p.group==='container' ? p.role : '',p.agentId,p.harness === 'codex' ? 'Codex' : p.harness === 'claude' ? 'Claude Code' : '',p.name,p.mode,p.model].filter(Boolean).map(escHtml).join(' · ');
917
+ function processRows(rows) {
918
+ const ids = new Set(rows.map(p=>p.pid));
919
+ const children = new Map();
920
+ rows.forEach(p=>{if(!children.has(p.ppid))children.set(p.ppid,[]);children.get(p.ppid).push(p);});
921
+ const printed = new Set();
922
+ function print(p,depth) {
923
+ if(printed.has(p.pid))return;
924
+ printed.add(p.pid);
925
+ const prefix = ' '.repeat(Math.min(depth,6)+1);
926
+ const root = p.pid === p.rootPid;
927
+ lines.push(prefix+(depth?'└─ ':'')+'PID '+p.pid+(p.group==='container'?' · Container PID '+(p.containerPid||'—'):'')+' '+escHtml(p.command)+' · '+resources([p]));
928
+ if(root && label(p))lines.push(prefix+' '+label(p));
929
+ if(root && p.sessionId)lines.push(prefix+' Session '+escHtml(p.sessionId));
930
+ if(root && p.taskId)lines.push(prefix+' Task '+escHtml(p.taskId)+(p.title?' · '+escHtml(p.title):''));
931
+ (children.get(p.pid)||[]).forEach(child=>print(child,depth+1));
947
932
  }
948
- return 'other';
949
- }
950
-
951
- // Show full command lines (no truncation) — text wraps inside the box.
952
- function full(args) {
953
- return escHtml(args);
933
+ rows.filter(p=>!ids.has(p.ppid)).forEach(p=>print(p,0));
934
+ rows.forEach(p=>print(p,0));
935
+ if(!rows.length)lines.push(' <span class="ts">— none —</span>');
954
936
  }
955
-
956
- function sessionId(args) {
957
- const m = args.match(/--session-id\\s+(\\S+)/);
958
- return m ? escHtml(m[1]) : '?';
959
- }
960
-
961
- function agentName(args) {
962
- const m = args.match(/agents\\/([^/]+)\\/workspace/);
963
- return m ? m[1] : '?';
964
- }
965
-
966
- const lines = [];
967
- // First line: total resource usage across the whole gateway tree.
968
- lines.push(
969
- '<span class="proc-summary">' +
970
- '\\u2211 ' + procs.length + ' procs' +
971
- ' \\u00b7 CPU ' + totalCpu.toFixed(1) + '%' +
972
- ' \\u00b7 MEM ' + memStr +
973
- '</span>'
974
- );
975
- lines.push('');
976
- const orchestrator = procs.find(function(p) { return cat(p) === 'orchestrator'; });
977
- const ptys = procs.filter(function(p) { return cat(p) === 'pty'; });
978
- const headless = procs.filter(function(p) { return cat(p) === 'claude-headless'; });
979
- const telegramReceivers = procs.filter(function(p) { return cat(p) === 'telegram'; });
980
- const discordReceivers = procs.filter(function(p) { return cat(p) === 'discord'; });
981
- const mcpServers = procs.filter(function(p) { return cat(p) === 'mcp'; });
982
-
983
- const gatewayPids = new Set(procs.map(function(p) { return p.pid; }));
984
- const orphans = procs.filter(function(p) {
985
- const c = cat(p);
986
- return (c === 'claude-pty' || c === 'claude-headless' || c === 'pty' || c === 'mcp')
987
- && !gatewayPids.has(p.ppid)
988
- && p.pid !== (orchestrator && orchestrator.pid);
937
+ [['gateway','Gateway'],['agent','Agents'],['worker','Workers']].forEach(pair=>{
938
+ const rows=unique.filter(p=>p.group===pair[0]);
939
+ lines.push('<span class="proc-label">'+pair[1]+'</span>');processRows(rows);lines.push('');
989
940
  });
990
-
991
- if (orchestrator) {
992
- lines.push('<span class="proc-orchestrator">Orchestrator</span>');
993
- lines.push(' PID ' + orchestrator.pid + ' <span class="proc-orchestrator">' + full(orchestrator.args) + '</span>');
994
- lines.push('');
995
- }
996
-
997
- const sessionCount = ptys.length + headless.length;
998
- lines.push('<span class="proc-label">Sessions (' + sessionCount + ')</span>');
999
-
1000
- ptys.forEach(function(pty) {
1001
- const agent = agentName(pty.args);
1002
- lines.push(' PID ' + pty.pid + ' <span class="proc-pty">wrap-shell</span> [' + agent + ']');
1003
- const claudeChild = procs.find(function(p) { return p.ppid === pty.pid && cat(p) === 'claude-pty'; });
1004
- if (claudeChild) {
1005
- lines.push(' \\u2514\\u2500 PID ' + claudeChild.pid + ' <span class="proc-claude">claude ' + sessionId(claudeChild.args) + '</span>');
1006
- const mcp = mcpServers.find(function(p) { return p.ppid === claudeChild.pid; });
1007
- if (mcp) {
1008
- lines.push(' \\u2514\\u2500 PID ' + mcp.pid + ' <span class="proc-mcp">mcp</span>');
1009
- }
1010
- }
941
+ lines.push('<span class="proc-label">App containers</span>');
942
+ containers.forEach(c=>{
943
+ const rows=unique.filter(p=>p.group==='container'&&p.container===c.name);
944
+ lines.push(' '+escHtml(c.name)+' · '+escHtml(c.state)+' · '+(c.error?'CPU — · MEM —':resources(rows)));
945
+ lines.push(' Agents: '+c.agentIds.map(escHtml).join(', '));
946
+ if(c.id)lines.push(' Container '+escHtml(c.id));
947
+ if(c.error)lines.push(' <span class="ts">'+escHtml(c.error)+'</span>');
948
+ processRows(rows);
1011
949
  });
1012
-
1013
- headless.forEach(function(cl) {
1014
- const agent = agentName(cl.args);
1015
- lines.push(' PID ' + cl.pid + ' <span class="proc-claude">claude --print</span>' + (agent !== '?' ? ' [' + agent + ']' : ''));
1016
- const mcp = mcpServers.find(function(p) { return p.ppid === cl.pid; });
1017
- if (mcp) {
1018
- lines.push(' \\u2514\\u2500 PID ' + mcp.pid + ' <span class="proc-mcp">mcp</span>');
1019
- }
1020
- });
1021
-
1022
- if (sessionCount === 0) lines.push(' <span class="ts">\\u2014 none \\u2014</span>');
1023
- lines.push('');
1024
-
1025
- lines.push('<span class="proc-label">Receivers</span>');
1026
- if (telegramReceivers.length) lines.push(' Telegram \\u00d7' + telegramReceivers.length);
1027
- if (discordReceivers.length) lines.push(' Discord \\u00d7' + discordReceivers.length);
1028
- if (!telegramReceivers.length && !discordReceivers.length) lines.push(' <span class="ts">\\u2014 none \\u2014</span>');
1029
- lines.push('');
1030
-
1031
- lines.push('<span class="proc-label">Orphans</span>');
1032
- if (orphans.length) {
1033
- orphans.forEach(function(p) {
1034
- lines.push(' \\u26a0 PID ' + p.pid + ' <span class="proc-orphan">' + full(p.args) + '</span>');
1035
- });
1036
- } else {
1037
- lines.push(' <span class="ts">none \\u2705</span>');
1038
- }
1039
-
1040
- document.getElementById('proc-tree').innerHTML = lines.join('\\n');
950
+ if(!containers.length)lines.push(' <span class="ts">— none —</span>');
951
+ lines.push('','<span class="proc-label">Safemode</span>');
952
+ processRows(unique.filter(p=>p.group==='safemode'));
953
+ lines.push('','<span class="proc-label">Receivers</span>');
954
+ const receivers=unique.filter(p=>p.group==='receiver');
955
+ ['telegram','discord'].forEach(name=>{const count=receivers.filter(p=>p.receiver===name).length;if(count)lines.push(' '+name[0].toUpperCase()+name.slice(1)+' ×'+count);});
956
+ if(!receivers.length)lines.push(' <span class="ts">— none —</span>');
957
+ lines.push('','<span class="proc-label">Orphans</span>');
958
+ const orphans=unique.filter(p=>p.group==='orphan');
959
+ if(orphans.length)processRows(orphans);else lines.push(' <span class="ts">none</span>');
960
+ warnings.forEach(w=>lines.push('<span class="ts">'+escHtml(w)+'</span>'));
961
+ document.getElementById('proc-tree').innerHTML=lines.join('\\n');
1041
962
  }
1042
963
 
1043
964
  // Logout — revoke the session cookie server-side, then land on the login page.
@@ -1 +1 @@
1
- {"version":3,"file":"web-ui.js","sourceRoot":"","sources":["../../src/ui/web-ui.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"web-ui.js","sourceRoot":"","sources":["../../src/ui/web-ui.ts"],"names":[],"mappings":"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"}
@@ -27,12 +27,14 @@ const input = JSON.parse(Buffer.concat(chunks).toString());
27
27
  const profileKeys = [
28
28
  'GATEWAY_ORCHESTRATION_ROLE',
29
29
  'GATEWAY_ORCHESTRATION_MEDIA',
30
+ 'GATEWAY_ORCHESTRATION_CRON',
30
31
  'GATEWAY_ORCHESTRATION_TICKET_FILE',
31
32
  ];
32
33
  const original = profileKeys.map((key) => process.env[key]);
33
34
  Object.assign(process.env, {
34
35
  GATEWAY_ORCHESTRATION_ROLE: 'worker',
35
36
  GATEWAY_ORCHESTRATION_MEDIA: 'true',
37
+ GATEWAY_ORCHESTRATION_CRON: 'true',
36
38
  GATEWAY_ORCHESTRATION_TICKET_FILE: '/capability-discovery-no-execution',
37
39
  });
38
40
  const worker = new Set(
@@ -0,0 +1,18 @@
1
+ // This entry is bundled for Node and evaluated only inside the selected app.
2
+ // Reuse the host file reader so scope/enablement/resource rules cannot drift.
3
+ import { readFileSync } from 'fs';
4
+ import { readClaudeExtensions, mergeCodexExtensions, addUnambiguousSkillAliases } from '../dist/session/worker-extensions.js';
5
+
6
+ const result = readClaudeExtensions(process.argv[1] || '/workspace', { ...process.env, HOME: process.argv[2] || process.env.HOME });
7
+ const native = (globalThis as any).__gatewayNativeExtensions;
8
+ if (native) mergeCodexExtensions(result, native);
9
+ for (const name of Object.keys(result.servers)) if (name.startsWith('codex_')) delete result.servers[name];
10
+ let size = 0;
11
+ for (const skill of result.skills) {
12
+ skill.content = readFileSync(skill.filePath, 'utf8');
13
+ size += Buffer.byteLength(skill.content);
14
+ if (size > 8 * 1024 * 1024) throw new Error('CONTAINER_EXTENSION_CATALOG_TOO_LARGE');
15
+ skill.fileScope = 'container';
16
+ }
17
+ addUnambiguousSkillAliases(result.skills);
18
+ process.stdout.write(JSON.stringify(result));
@@ -10,15 +10,17 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
10
10
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
11
11
  import { CallToolRequestSchema, ListToolsRequestSchema, ToolListChangedNotificationSchema } from '@modelcontextprotocol/sdk/types.js';
12
12
  import { createLazyToolCatalog, LAZY_TOOL_DEFINITIONS } from './lazy-tools';
13
+ import { CodexNativeClient } from '../dist/session/codex-native-mcp-client.js';
13
14
 
14
15
  const config = JSON.parse(readFileSync(process.argv[2], 'utf8'));
15
- const client = new Client({name:'gateway-lazy-connector',version:'1'});
16
+ const client: any = config.nativeCodex ? new CodexNativeClient(config.nativeCodex) : new Client({name:'gateway-lazy-connector',version:'1'});
16
17
  const shutdown = new AbortController();
17
18
  let connection: Promise<void> | undefined;
18
19
  let catalog: ReturnType<typeof createLazyToolCatalog> | undefined;
19
20
  let loading: Promise<ReturnType<typeof createLazyToolCatalog>> | undefined;
20
21
  function connect(): Promise<void> {
21
22
  if (!connection) connection = (async()=>{
23
+ if (config.nativeCodex) { await client.connect(); return; }
22
24
  const transport = config.command ? new StdioClientTransport({command:config.command,args:config.args,env:{...process.env,...config.env},cwd:config.cwd,stderr:'inherit'})
23
25
  : config.type === 'sse' ? new SSEClientTransport(new URL(config.url),{requestInit:{headers:config.headers}})
24
26
  : new StreamableHTTPClientTransport(new URL(config.url),{requestInit:{headers:config.headers}});
@@ -35,7 +37,7 @@ async function discover() {
35
37
  do {
36
38
  if(++pages>500)throw Error('Connector catalog pagination exceeded page limit');
37
39
  const page=await client.listTools(cursor?{cursor}:{},{timeout:10000,signal:shutdown.signal});
38
- const pageTools=page.tools.map(t=>({...t,description:t.description??''}));
40
+ const pageTools=page.tools.filter(t => (!Array.isArray(config.enabled_tools) || config.enabled_tools.includes(t.name)) && !config.disabled_tools?.includes(t.name)).map(t=>({...t,description:t.description??''}));
39
41
  bytes+=Buffer.byteLength(JSON.stringify(pageTools));
40
42
  if(tools.length+pageTools.length>10000||bytes>8*1024*1024)throw Error('Connector catalog too large');
41
43
  tools.push(...pageTools);
@@ -150,3 +150,32 @@ test('real lazy inventory preserves every execution schema and successful browse
150
150
  local.stop(true); rmSync(dir, { recursive: true, force: true });
151
151
  }
152
152
  }, 15000);
153
+
154
+ test('cron tools survive module registration and lazy discovery, while privileged modules remain unavailable', async () => {
155
+ const dir = mkdtempSync(join(tmpdir(), 'cron-lazy-'));
156
+ const calls: string[] = [];
157
+ const bridge = Bun.serve({hostname:'127.0.0.1',port:0,async fetch(req) {
158
+ const body=await req.json(); calls.push(body.tool);
159
+ return Response.json(body.tool === 'cron_list' ? {jobs:[]} : {active:true});
160
+ }});
161
+ const ticket=join(dir,'ticket.json');writeFileSync(ticket,JSON.stringify({url:`http://127.0.0.1:${bridge.port}`,token:'fixture'}));
162
+ const client=new Client({name:'cron-test',version:'1'});
163
+ try{
164
+ await client.connect(new StdioClientTransport({command:'bun',args:[join(import.meta.dir,'server.ts')],stderr:'ignore',env:{PATH:process.env.PATH??'',HOME:dir,GATEWAY_AGENT_ID:'fixture',GATEWAY_WORKSPACE_DIR:dir,GATEWAY_ORCHESTRATION_ROLE:'worker',GATEWAY_ORCHESTRATION_MEDIA:'true',GATEWAY_ORCHESTRATION_CRON:'true',GATEWAY_ORCHESTRATION_TICKET_FILE:ticket,GATEWAY_LAZY_TOOLS:'true'}}));
165
+ const search=await client.callTool({name:'tool_search',arguments:{query:'cron'}});
166
+ expect(JSON.parse((search.content as any)[0].text).total).toBe(6);
167
+ const result=await client.callTool({name:'tool_call',arguments:{name:'cron_list',arguments:{}}});
168
+ expect(result.isError).not.toBe(true);expect(calls).toEqual(['task_validate','cron_list']);
169
+ for(const name of ['agent_create','install_app','skill_install','api_request','telegram_send_message']){
170
+ const denied=await client.callTool({name:'tool_call',arguments:{name,arguments:{}}});expect(denied.isError).toBe(true);
171
+ }
172
+ }finally{await client.close();bridge.stop(true);rmSync(dir,{recursive:true,force:true});}
173
+ },15000);
174
+
175
+ test('all registered worker modules follow the scoped execution policy',async()=>{
176
+ const {gatewayModules}=await import('./modules');
177
+ expect(gatewayModules('agent').map(m=>m.id)).toEqual(['memory','safemode']);
178
+ expect(gatewayModules('worker',true).map(m=>m.id)).toEqual(['memory','cron','image','video','share-file','browser']);
179
+ const standalone=gatewayModules().map(m=>m.id);
180
+ for(const id of ['cron','image','video','share-file','browser','skills','apps','agent','api','telegram','discord','line','slack','whatsapp','whatsapp_cloud','wechat'])expect(standalone).toContain(id);
181
+ });
package/mcp/modules.ts CHANGED
@@ -25,6 +25,7 @@ export function gatewayModules(
25
25
  return role
26
26
  ? [
27
27
  new MemoryModule(),
28
+ ...(role === 'worker' ? [new CronModule()] : []),
28
29
  ...(role === 'worker' && media
29
30
  ? [
30
31
  new ImageModule(),
package/mcp/server.ts CHANGED
@@ -46,8 +46,8 @@ for (const mod of modules) {
46
46
  if (!visible) continue;
47
47
 
48
48
  for (const tool of mod.getTools()) {
49
- if (ORCHESTRATION_ROLE && !['memory_search', 'memory_get'].includes(tool.name) && !(ORCHESTRATION_ROLE === 'worker' &&
50
- ((mod.id === 'image' || mod.id === 'video' || mod.id === 'share-file' || mod.id === 'browser') || (mod.id === 'memory' && process.env.GATEWAY_ORCHESTRATION_WRITE_MEMORY === 'true')))) continue;
49
+ if (ORCHESTRATION_ROLE && !(ORCHESTRATION_ROLE === 'agent' && mod.id === 'safemode') && !['memory_search', 'memory_get'].includes(tool.name) && !(ORCHESTRATION_ROLE === 'worker' &&
50
+ ((mod.id === 'cron' || mod.id === 'image' || mod.id === 'video' || mod.id === 'share-file' || mod.id === 'browser') || (mod.id === 'memory' && process.env.GATEWAY_ORCHESTRATION_WRITE_MEMORY === 'true')))) continue;
51
51
  toolMap.set(tool.name, mod);
52
52
  visibleTools.push(tool);
53
53
  }
@@ -1,3 +1,5 @@
1
+ import { CRON_TOOLS } from '../../../dist/cron/tool-schemas.js';
2
+ import { callTaskBridge } from '../tasks/module';
1
3
  /**
2
4
  * Cron tool module — implements ToolModule interface.
3
5
  * Provides cron job management tools via the gateway REST API.
@@ -21,7 +23,7 @@ export class CronModule implements ToolModule {
21
23
  private client: CronClient | null = null;
22
24
 
23
25
  isEnabled(): boolean {
24
- return Boolean(process.env.GATEWAY_API_URL && process.env.GATEWAY_AGENT_ID);
26
+ return Boolean((process.env.GATEWAY_ORCHESTRATION_ROLE === 'worker' && process.env.GATEWAY_ORCHESTRATION_CRON === 'true' && process.env.GATEWAY_ORCHESTRATION_TICKET_FILE) || (process.env.GATEWAY_API_URL && process.env.GATEWAY_AGENT_ID));
25
27
  }
26
28
 
27
29
  private getClient(): CronClient {
@@ -35,121 +37,13 @@ export class CronModule implements ToolModule {
35
37
  }
36
38
 
37
39
  getTools(): McpToolDefinition[] {
38
- return [
39
- {
40
- name: 'cron_list',
41
- description: 'List scheduled cron jobs for this agent',
42
- inputSchema: {
43
- type: 'object',
44
- properties: {},
45
- additionalProperties: false,
46
- },
47
- },
48
- {
49
- name: 'cron_create',
50
- description: 'Create a new cron job',
51
- inputSchema: {
52
- type: 'object',
53
- properties: {
54
- name: { type: 'string', description: 'Job name' },
55
- schedule: { type: 'string', description: '5-field cron expression' },
56
- type: { type: 'string', enum: ['command', 'agent'], description: 'Job type' },
57
- command: { type: 'string', description: 'Shell command (type=command)' },
58
- prompt: { type: 'string', description: 'Agent prompt (type=agent)' },
59
- telegram: { type: 'string', description: 'Telegram chat_id for delivery — full response on success (type=agent), or a short failure notice on error (any type)' },
60
- discord: { type: 'string', description: 'Discord channel_id for delivery — full response on success (type=agent), or a short failure notice on error (any type)' },
61
- timeout_ms: { type: 'number', description: 'Timeout in milliseconds' },
62
- scheduleKind: {
63
- type: 'string',
64
- enum: ['cron', 'at'],
65
- description: 'Schedule type: "cron" for recurring (default), "at" for one-shot at a specific ISO datetime',
66
- },
67
- scheduleAt: {
68
- type: 'string',
69
- description: 'ISO 8601 datetime for one-shot execution (required when scheduleKind=at)',
70
- },
71
- deleteAfterRun: {
72
- type: 'boolean',
73
- description: 'Delete the job after it runs once. Defaults to true for scheduleKind=at, false for cron',
74
- },
75
- },
76
- required: ['name', 'type'],
77
- additionalProperties: false,
78
- },
79
- },
80
- {
81
- name: 'cron_delete',
82
- description: 'Delete a cron job by ID',
83
- inputSchema: {
84
- type: 'object',
85
- properties: {
86
- job_id: { type: 'string', description: 'Job ID to delete' },
87
- },
88
- required: ['job_id'],
89
- additionalProperties: false,
90
- },
91
- },
92
- {
93
- name: 'cron_update',
94
- description: 'Update an existing cron job. Provide job_id plus only the fields to change.',
95
- inputSchema: {
96
- type: 'object',
97
- properties: {
98
- job_id: { type: 'string', description: 'ID of the job to update' },
99
- name: { type: 'string', description: 'Job name' },
100
- schedule: { type: 'string', description: '5-field cron expression' },
101
- type: { type: 'string', enum: ['command', 'agent'], description: 'Job type' },
102
- command: { type: 'string', description: 'Shell command (type=command)' },
103
- prompt: { type: 'string', description: 'Agent prompt (type=agent)' },
104
- telegram: { type: 'string', description: 'Telegram chat_id for delivery — full response on success (type=agent), or a short failure notice on error (any type)' },
105
- discord: { type: 'string', description: 'Discord channel_id for delivery — full response on success (type=agent), or a short failure notice on error (any type)' },
106
- timeout_ms: { type: 'number', description: 'Timeout in milliseconds' },
107
- scheduleKind: {
108
- type: 'string',
109
- enum: ['cron', 'at'],
110
- description: 'Schedule type: "cron" for recurring, "at" for one-shot at a specific ISO datetime',
111
- },
112
- scheduleAt: {
113
- type: 'string',
114
- description: 'ISO 8601 datetime for one-shot execution (required when scheduleKind=at)',
115
- },
116
- deleteAfterRun: {
117
- type: 'boolean',
118
- description: 'Delete the job after it runs once',
119
- },
120
- },
121
- required: ['job_id'],
122
- additionalProperties: false,
123
- },
124
- },
125
- {
126
- name: 'cron_run',
127
- description: 'Run a cron job immediately',
128
- inputSchema: {
129
- type: 'object',
130
- properties: {
131
- job_id: { type: 'string', description: 'Job ID to run' },
132
- },
133
- required: ['job_id'],
134
- additionalProperties: false,
135
- },
136
- },
137
- {
138
- name: 'cron_get_runs',
139
- description: 'Get run history for a cron job',
140
- inputSchema: {
141
- type: 'object',
142
- properties: {
143
- job_id: { type: 'string', description: 'Job ID' },
144
- },
145
- required: ['job_id'],
146
- additionalProperties: false,
147
- },
148
- },
149
- ];
40
+ return CRON_TOOLS;
150
41
  }
151
42
 
152
- async handleTool(name: string, args: Record<string, unknown>): Promise<McpToolResult> {
43
+ async handleTool(name: string, args: Record<string, unknown>, signal?: AbortSignal): Promise<McpToolResult> {
44
+ if (process.env.GATEWAY_ORCHESTRATION_ROLE === 'worker') {
45
+ return callTaskBridge(name, args, crypto.randomUUID(), signal ?? new AbortController().signal);
46
+ }
153
47
  const client = this.getClient();
154
48
 
155
49
  try {
@@ -13,6 +13,10 @@ export const SLASH_COMMANDS: SlashCommandDef[] = [
13
13
  },
14
14
  { name: 'clear', description: 'Reset model context without deleting chat history' },
15
15
  { name: 'compact', description: 'Compact Claude Code context without changing chat history' },
16
+ { name: 'help', description: 'Show all supported commands' },
17
+ { name: 'restart', description: 'Restart the session process after confirmation' },
18
+ { name: 'sessions', description: 'List sessions' },
19
+ { name: 'models', description: 'List and select a model' },
16
20
  { name: 'session', description: 'Show current session info' },
17
21
  {
18
22
  name: 'new',
@@ -32,7 +36,6 @@ export function commandDefinitions(orchestration:boolean,interactive:boolean):Sl
32
36
  {name:'voice',description:'Turn automatic voice replies on or off',options:[{name:'mode',description:'on or off (omit to show buttons)',required:false,type:'STRING' as const}]},
33
37
  {name:'voices',description:'Choose the agent voice'},
34
38
  {name:'tasks',description:'View pending tasks in this conversation'},
35
- {name:'help',description:'Show available orchestration controls'},
36
39
  ] : []),
37
40
  {name:'stop',description:orchestration?'Stop a response or choose a task to stop':'Stop the agent response'},
38
41
  ...(interactive && !orchestration ? [{name:'cli',description:'Open the live terminal viewer'}] : []),
@@ -0,0 +1,29 @@
1
+ import { expect, test } from 'bun:test';
2
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
3
+ import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
4
+ import { mkdtempSync, writeFileSync, rmSync } from 'node:fs';
5
+ import { tmpdir } from 'node:os';
6
+ import { join } from 'node:path';
7
+ test('real MCP never loads legacy safemode schemas for agents or workers', async () => {
8
+ const directory = mkdtempSync(join(tmpdir(), 'safemode-mcp-'));
9
+ const calls: Array<{ tool: string; args: unknown }> = [];
10
+ let allow = false;
11
+ const bridge = Bun.serve({ hostname: '127.0.0.1', port: 0, async fetch(req) {
12
+ calls.push(await req.json()); return allow ? Response.json({ allowed: true }) : new Response('ACCESS_DENIED', { status: 403 });
13
+ } });
14
+ const ticket = join(directory, 'ticket.json');
15
+ writeFileSync(ticket, JSON.stringify({ url: `http://127.0.0.1:${bridge.port}`, token: 'synthetic-test' }));
16
+ const clients: Client[] = [];
17
+ try {
18
+ for (const [role, permittedTools] of [['agent',true],['agent',false],['worker',true]] as const) {
19
+ const client = new Client({ name: 'safemode-test', version: '1' }); clients.push(client);
20
+ await client.connect(new StdioClientTransport({ command: 'bun', args: [join(import.meta.dir, '../../server.ts')], stderr: 'ignore', env: {
21
+ PATH: process.env.PATH ?? '', HOME: directory, GATEWAY_ORCHESTRATION_ROLE: role, GATEWAY_SAFEMODE_ALLOWED: permittedTools ? 'true' : '', GATEWAY_ORCHESTRATION_TICKET_FILE: ticket,
22
+ } }));
23
+ const listed = (await client.listTools()).tools.filter(tool => tool.name.startsWith('safemode_'));
24
+ expect(listed).toEqual([]);
25
+ expect((await client.callTool({name:'safemode_list',arguments:{}})).isError).toBe(true);
26
+ }
27
+ expect(calls).toHaveLength(0);
28
+ } finally { for (const client of clients) await client.close(); bridge.stop(true); rmSync(directory, { recursive: true, force: true }); }
29
+ }, 15000);
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env bun
2
+ import { commandHelp } from '../../../dist/agent/command-help.js';
2
3
  import { parseSessionInfo } from './session-browser';
3
4
  /**
4
5
  * Telegram channel for Claude Gateway.
@@ -1162,28 +1163,7 @@ bot.command('start', async ctx => {
1162
1163
 
1163
1164
  bot.command('help', async ctx => {
1164
1165
  if (ctx.chat?.type !== 'private') return
1165
- await ctx.reply(
1166
- `Messages you send here route to a paired Claude Code session. ` +
1167
- `Text and photos are forwarded; replies and reactions come back.\n\n` +
1168
- `*Session management*\n` +
1169
- `/session — show current session info\n` +
1170
- `/sessions — list and switch between sessions\n` +
1171
- `/new <name> — create a new session\n` +
1172
- `/rename <name> — rename current session\n` +
1173
- `/clear — reset context; keep chat history\n` +
1174
- `/compact — compact Claude Code context; keep chat history\n` +
1175
- (ORCHESTRATION_ENABLED ? `/stop — stop the reply and choose a task to cancel\n` : `/stop — interrupt the running turn\n`) +
1176
- `/restart — graceful restart session\n\n` +
1177
- `*Agent*\n` +
1178
- `/model — show current AI model\n` +
1179
- `/models — switch AI model\n` +
1180
- (ORCHESTRATION_ENABLED ? `/tasks — view pending tasks in this chat\n/voice — turn automatic voice replies on/off (default off)\n/voices — choose the agent voice\n` : '') +
1181
- (INTERACTIVE_CLI_ENABLED ? `/cli — open the live terminal viewer\n\n` : '\n') +
1182
- `*Account*\n` +
1183
- `/start — pairing instructions\n` +
1184
- `/status — check your pairing state`,
1185
- { parse_mode: 'Markdown' }
1186
- )
1166
+ await ctx.reply(commandHelp('telegram', ORCHESTRATION_ENABLED, INTERACTIVE_CLI_ENABLED))
1187
1167
  })
1188
1168
 
1189
1169
  bot.command('status', async ctx => {
@@ -4,6 +4,7 @@ import type { ProcessSample } from '../../../src/orchestration/process-activity'
4
4
  import type { ToolOutcome } from '../../../src/orchestration/execution-observation';
5
5
 
6
6
  export interface TaskDetail {
7
+ harness?: 'claude' | 'codex';
7
8
  title: string; state: string; startedAt?: number; finishedAt?: number;
8
9
  timing?: Partial<Record<'working' | 'tool' | 'input' | 'queued' | 'other' | 'finished', number>>;
9
10
  timingMeasuredFrom?: number;
@@ -28,7 +29,7 @@ export function formatTaskDetail(task: TaskDetail, label: string): string {
28
29
  const lastTool = activity?.lastTool;
29
30
  const diagnostics = [counters, lastTool ? `Last tool: ${lastTool.name} · ${lastTool.status === 'error' ? 'Reported error' : 'Result received'}${lastTool.exitCode === undefined ? '' : ` · Exit code: ${lastTool.exitCode}`}\nReported at: ${new Date(lastTool.observedAt).toISOString().replace('T',' ').replace(/\.\d{3}Z$/, ' UTC')}` : '', activity?.observationStatus ?? activity?.status, activity?.quiet ? 'No recent tool/model progress; task retained for inspection or cancellation.' : ''].filter(Boolean);
30
31
  return [
31
- `${task.title}\n${label} · Elapsed: ${formatTaskElapsed(task.startedAt,task.finishedAt)}`,
32
+ `${task.title}\n${label} · Elapsed: ${formatTaskElapsed(task.startedAt,task.finishedAt)}${task.harness ? `\nHarness: ${task.harness === 'codex' ? 'Codex' : 'Claude Code'}` : ''}`,
32
33
  formatTiming(task.timing) ? 'Time breakdown\n' + formatTiming(task.timing) + (task.timingMeasuredFrom && task.startedAt && task.timingMeasuredFrom > task.startedAt + 1000 ? '\nMeasured since ' + new Date(task.timingMeasuredFrom).toISOString() : '') : '',
33
34
  progressLines.length ? `Progress\n${progressLines.join('\n')}` : '',
34
35
  diagnostics.length ? `Diagnostics\n${diagnostics.join('\n')}` : '',