myaiforone 1.0.0

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 (315) hide show
  1. package/README.md +113 -0
  2. package/agents/_template/CLAUDE.md +18 -0
  3. package/agents/_template/agent.json +7 -0
  4. package/agents/platform/agentcreator/CLAUDE.md +300 -0
  5. package/agents/platform/appcreator/CLAUDE.md +158 -0
  6. package/agents/platform/gym/CLAUDE.md +486 -0
  7. package/agents/platform/gym/agent.json +40 -0
  8. package/agents/platform/gym/programs/agent-building/program.json +160 -0
  9. package/agents/platform/gym/programs/automations-mastery/program.json +129 -0
  10. package/agents/platform/gym/programs/getting-started/program.json +124 -0
  11. package/agents/platform/gym/programs/mcp-integrations/program.json +116 -0
  12. package/agents/platform/gym/programs/multi-model-strategy/program.json +115 -0
  13. package/agents/platform/gym/programs/prompt-engineering/program.json +136 -0
  14. package/agents/platform/gym/souls/alex.md +12 -0
  15. package/agents/platform/gym/souls/jordan.md +12 -0
  16. package/agents/platform/gym/souls/morgan.md +12 -0
  17. package/agents/platform/gym/souls/riley.md +12 -0
  18. package/agents/platform/gym/souls/sam.md +12 -0
  19. package/agents/platform/hub/CLAUDE.md +372 -0
  20. package/agents/platform/promptcreator/CLAUDE.md +130 -0
  21. package/agents/platform/skillcreator/CLAUDE.md +163 -0
  22. package/bin/cli.js +566 -0
  23. package/config.example.json +310 -0
  24. package/dist/agent-registry.d.ts +32 -0
  25. package/dist/agent-registry.d.ts.map +1 -0
  26. package/dist/agent-registry.js +144 -0
  27. package/dist/agent-registry.js.map +1 -0
  28. package/dist/channels/discord.d.ts +17 -0
  29. package/dist/channels/discord.d.ts.map +1 -0
  30. package/dist/channels/discord.js +114 -0
  31. package/dist/channels/discord.js.map +1 -0
  32. package/dist/channels/imessage.d.ts +23 -0
  33. package/dist/channels/imessage.d.ts.map +1 -0
  34. package/dist/channels/imessage.js +214 -0
  35. package/dist/channels/imessage.js.map +1 -0
  36. package/dist/channels/slack.d.ts +19 -0
  37. package/dist/channels/slack.d.ts.map +1 -0
  38. package/dist/channels/slack.js +167 -0
  39. package/dist/channels/slack.js.map +1 -0
  40. package/dist/channels/telegram.d.ts +19 -0
  41. package/dist/channels/telegram.d.ts.map +1 -0
  42. package/dist/channels/telegram.js +274 -0
  43. package/dist/channels/telegram.js.map +1 -0
  44. package/dist/channels/types.d.ts +44 -0
  45. package/dist/channels/types.d.ts.map +1 -0
  46. package/dist/channels/types.js +18 -0
  47. package/dist/channels/types.js.map +1 -0
  48. package/dist/channels/whatsapp.d.ts +23 -0
  49. package/dist/channels/whatsapp.d.ts.map +1 -0
  50. package/dist/channels/whatsapp.js +189 -0
  51. package/dist/channels/whatsapp.js.map +1 -0
  52. package/dist/config.d.ts +134 -0
  53. package/dist/config.d.ts.map +1 -0
  54. package/dist/config.js +127 -0
  55. package/dist/config.js.map +1 -0
  56. package/dist/cron.d.ts +8 -0
  57. package/dist/cron.d.ts.map +1 -0
  58. package/dist/cron.js +35 -0
  59. package/dist/cron.js.map +1 -0
  60. package/dist/decrypt-keys.d.ts +7 -0
  61. package/dist/decrypt-keys.d.ts.map +1 -0
  62. package/dist/decrypt-keys.js +53 -0
  63. package/dist/decrypt-keys.js.map +1 -0
  64. package/dist/encrypt-keys.d.ts +8 -0
  65. package/dist/encrypt-keys.d.ts.map +1 -0
  66. package/dist/encrypt-keys.js +62 -0
  67. package/dist/encrypt-keys.js.map +1 -0
  68. package/dist/executor.d.ts +31 -0
  69. package/dist/executor.d.ts.map +1 -0
  70. package/dist/executor.js +2009 -0
  71. package/dist/executor.js.map +1 -0
  72. package/dist/gemini-executor.d.ts +27 -0
  73. package/dist/gemini-executor.d.ts.map +1 -0
  74. package/dist/gemini-executor.js +160 -0
  75. package/dist/gemini-executor.js.map +1 -0
  76. package/dist/goals.d.ts +24 -0
  77. package/dist/goals.d.ts.map +1 -0
  78. package/dist/goals.js +189 -0
  79. package/dist/goals.js.map +1 -0
  80. package/dist/gym/activity-digest.d.ts +30 -0
  81. package/dist/gym/activity-digest.d.ts.map +1 -0
  82. package/dist/gym/activity-digest.js +506 -0
  83. package/dist/gym/activity-digest.js.map +1 -0
  84. package/dist/gym/dimension-scorer.d.ts +76 -0
  85. package/dist/gym/dimension-scorer.d.ts.map +1 -0
  86. package/dist/gym/dimension-scorer.js +236 -0
  87. package/dist/gym/dimension-scorer.js.map +1 -0
  88. package/dist/gym/gym-router.d.ts +7 -0
  89. package/dist/gym/gym-router.d.ts.map +1 -0
  90. package/dist/gym/gym-router.js +718 -0
  91. package/dist/gym/gym-router.js.map +1 -0
  92. package/dist/gym/index.d.ts +11 -0
  93. package/dist/gym/index.d.ts.map +1 -0
  94. package/dist/gym/index.js +11 -0
  95. package/dist/gym/index.js.map +1 -0
  96. package/dist/heartbeat.d.ts +21 -0
  97. package/dist/heartbeat.d.ts.map +1 -0
  98. package/dist/heartbeat.js +163 -0
  99. package/dist/heartbeat.js.map +1 -0
  100. package/dist/index.d.ts +2 -0
  101. package/dist/index.d.ts.map +1 -0
  102. package/dist/index.js +254 -0
  103. package/dist/index.js.map +1 -0
  104. package/dist/keystore.d.ts +22 -0
  105. package/dist/keystore.d.ts.map +1 -0
  106. package/dist/keystore.js +178 -0
  107. package/dist/keystore.js.map +1 -0
  108. package/dist/logger.d.ts +9 -0
  109. package/dist/logger.d.ts.map +1 -0
  110. package/dist/logger.js +45 -0
  111. package/dist/logger.js.map +1 -0
  112. package/dist/memory/daily.d.ts +22 -0
  113. package/dist/memory/daily.d.ts.map +1 -0
  114. package/dist/memory/daily.js +82 -0
  115. package/dist/memory/daily.js.map +1 -0
  116. package/dist/memory/embeddings.d.ts +15 -0
  117. package/dist/memory/embeddings.d.ts.map +1 -0
  118. package/dist/memory/embeddings.js +154 -0
  119. package/dist/memory/embeddings.js.map +1 -0
  120. package/dist/memory/index.d.ts +32 -0
  121. package/dist/memory/index.d.ts.map +1 -0
  122. package/dist/memory/index.js +159 -0
  123. package/dist/memory/index.js.map +1 -0
  124. package/dist/memory/search.d.ts +21 -0
  125. package/dist/memory/search.d.ts.map +1 -0
  126. package/dist/memory/search.js +77 -0
  127. package/dist/memory/search.js.map +1 -0
  128. package/dist/memory/store.d.ts +23 -0
  129. package/dist/memory/store.d.ts.map +1 -0
  130. package/dist/memory/store.js +144 -0
  131. package/dist/memory/store.js.map +1 -0
  132. package/dist/ollama-executor.d.ts +17 -0
  133. package/dist/ollama-executor.d.ts.map +1 -0
  134. package/dist/ollama-executor.js +112 -0
  135. package/dist/ollama-executor.js.map +1 -0
  136. package/dist/openai-executor.d.ts +38 -0
  137. package/dist/openai-executor.d.ts.map +1 -0
  138. package/dist/openai-executor.js +197 -0
  139. package/dist/openai-executor.js.map +1 -0
  140. package/dist/router.d.ts +11 -0
  141. package/dist/router.d.ts.map +1 -0
  142. package/dist/router.js +185 -0
  143. package/dist/router.js.map +1 -0
  144. package/dist/test-message.d.ts +2 -0
  145. package/dist/test-message.d.ts.map +1 -0
  146. package/dist/test-message.js +60 -0
  147. package/dist/test-message.js.map +1 -0
  148. package/dist/utils/imsg-db-reader.d.ts +24 -0
  149. package/dist/utils/imsg-db-reader.d.ts.map +1 -0
  150. package/dist/utils/imsg-db-reader.js +92 -0
  151. package/dist/utils/imsg-db-reader.js.map +1 -0
  152. package/dist/utils/imsg-rpc.d.ts +25 -0
  153. package/dist/utils/imsg-rpc.d.ts.map +1 -0
  154. package/dist/utils/imsg-rpc.js +149 -0
  155. package/dist/utils/imsg-rpc.js.map +1 -0
  156. package/dist/utils/message-formatter.d.ts +3 -0
  157. package/dist/utils/message-formatter.d.ts.map +1 -0
  158. package/dist/utils/message-formatter.js +69 -0
  159. package/dist/utils/message-formatter.js.map +1 -0
  160. package/dist/web-ui.d.ts +12 -0
  161. package/dist/web-ui.d.ts.map +1 -0
  162. package/dist/web-ui.js +5784 -0
  163. package/dist/web-ui.js.map +1 -0
  164. package/dist/whatsapp-chats.d.ts +2 -0
  165. package/dist/whatsapp-chats.d.ts.map +1 -0
  166. package/dist/whatsapp-chats.js +76 -0
  167. package/dist/whatsapp-chats.js.map +1 -0
  168. package/dist/whatsapp-login.d.ts +2 -0
  169. package/dist/whatsapp-login.d.ts.map +1 -0
  170. package/dist/whatsapp-login.js +90 -0
  171. package/dist/whatsapp-login.js.map +1 -0
  172. package/dist/wiki-sync.d.ts +21 -0
  173. package/dist/wiki-sync.d.ts.map +1 -0
  174. package/dist/wiki-sync.js +147 -0
  175. package/dist/wiki-sync.js.map +1 -0
  176. package/docs/AddNewAgentGuide.md +100 -0
  177. package/docs/AddNewMcpGuide.md +72 -0
  178. package/docs/Architecture.md +795 -0
  179. package/docs/CLAUDE-AI-SETUP.md +166 -0
  180. package/docs/Setup.md +297 -0
  181. package/docs/ai-gym-architecture.md +1040 -0
  182. package/docs/ai-gym-build-plan.md +343 -0
  183. package/docs/ai-gym-onboarding.md +122 -0
  184. package/docs/appcreator_plan.md +348 -0
  185. package/docs/platform-mcp-audit.md +320 -0
  186. package/docs/server-deployment-plan.md +503 -0
  187. package/docs/superpowers/plans/2026-03-25-marketplace.md +1281 -0
  188. package/docs/superpowers/specs/2026-03-25-marketplace-design.md +287 -0
  189. package/docs/user-guide.md +2016 -0
  190. package/mcp-catalog.json +628 -0
  191. package/package.json +63 -0
  192. package/public/MyAIforOne-logomark-512.svg +16 -0
  193. package/public/MyAIforOne-logomark-transparent.svg +15 -0
  194. package/public/activity.html +314 -0
  195. package/public/admin.html +1674 -0
  196. package/public/agent-dashboard.html +670 -0
  197. package/public/api-docs.html +1106 -0
  198. package/public/automations.html +722 -0
  199. package/public/canvas.css +223 -0
  200. package/public/canvas.js +588 -0
  201. package/public/changelog.html +231 -0
  202. package/public/gym.html +2766 -0
  203. package/public/home.html +1930 -0
  204. package/public/index.html +2809 -0
  205. package/public/lab.html +1643 -0
  206. package/public/library.html +1442 -0
  207. package/public/marketplace.html +1101 -0
  208. package/public/mcp-docs.html +441 -0
  209. package/public/mini.html +390 -0
  210. package/public/monitor.html +584 -0
  211. package/public/org.html +4304 -0
  212. package/public/projects.html +734 -0
  213. package/public/settings.html +645 -0
  214. package/public/tasks.html +932 -0
  215. package/public/trainers/alex.svg +12 -0
  216. package/public/trainers/jordan.svg +12 -0
  217. package/public/trainers/morgan.svg +12 -0
  218. package/public/trainers/riley.svg +12 -0
  219. package/public/trainers/sam.svg +12 -0
  220. package/public/user-guide.html +218 -0
  221. package/registry/agents.json +3 -0
  222. package/registry/apps.json +20 -0
  223. package/registry/installed-drafts.json +3 -0
  224. package/registry/mcps.json +1084 -0
  225. package/registry/prompts/personal/mcp-test-prompt.md +6 -0
  226. package/registry/prompts/personal/memory-recall.md +6 -0
  227. package/registry/prompts/platform/brainstorm.md +15 -0
  228. package/registry/prompts/platform/code-review.md +16 -0
  229. package/registry/prompts/platform/explain.md +16 -0
  230. package/registry/prompts.json +58 -0
  231. package/registry/skills/external/brainstorming.md +5 -0
  232. package/registry/skills/external/code-review.md +40 -0
  233. package/registry/skills/external/frontend-patterns.md +642 -0
  234. package/registry/skills/external/frontend-slides.md +184 -0
  235. package/registry/skills/external/systematic-debugging.md +5 -0
  236. package/registry/skills/external/tdd.md +328 -0
  237. package/registry/skills/external/verification-before-completion.md +5 -0
  238. package/registry/skills/external/writing-plans.md +5 -0
  239. package/registry/skills/platform/ai41_app_build.md +930 -0
  240. package/registry/skills/platform/ai41_app_deploy.md +168 -0
  241. package/registry/skills/platform/ai41_app_orchestrator.md +239 -0
  242. package/registry/skills/platform/ai41_app_patterns.md +359 -0
  243. package/registry/skills/platform/ai41_app_register.md +85 -0
  244. package/registry/skills/platform/ai41_app_scaffold.md +421 -0
  245. package/registry/skills/platform/ai41_app_verify.md +107 -0
  246. package/registry/skills/platform/opProjectCreate.md +239 -0
  247. package/registry/skills/platform/op_devbrowser.md +136 -0
  248. package/registry/skills/platform/sop_brandguidelines.md +103 -0
  249. package/registry/skills/platform/sop_docx.md +117 -0
  250. package/registry/skills/platform/sop_frontenddesign.md +44 -0
  251. package/registry/skills/platform/sop_frontenddesign_v2.md +659 -0
  252. package/registry/skills/platform/sop_mcpbuilder.md +133 -0
  253. package/registry/skills/platform/sop_pdf.md +172 -0
  254. package/registry/skills/platform/sop_pptx.md +133 -0
  255. package/registry/skills/platform/sop_skillcreator.md +104 -0
  256. package/registry/skills/platform/sop_themefactory.md +128 -0
  257. package/registry/skills/platform/sop_webapptesting.md +75 -0
  258. package/registry/skills/platform/sop_webartifactsbuilder.md +97 -0
  259. package/registry/skills/platform/sop_xlsx.md +134 -0
  260. package/registry/skills.json +1055 -0
  261. package/scripts/discover-chats.sh +11 -0
  262. package/scripts/install-service-windows.ps1 +87 -0
  263. package/scripts/install-service.sh +52 -0
  264. package/scripts/seed-registry.ts +195 -0
  265. package/scripts/test-send.sh +5 -0
  266. package/scripts/tray-indicator.ps1 +35 -0
  267. package/scripts/uninstall-service-windows.ps1 +23 -0
  268. package/scripts/uninstall-service.sh +15 -0
  269. package/scripts/xbar-myagent.5s.sh +32 -0
  270. package/server/mcp-server/dist/index.d.ts +11 -0
  271. package/server/mcp-server/dist/index.js +1332 -0
  272. package/server/mcp-server/dist/lib/api-client.d.ts +165 -0
  273. package/server/mcp-server/dist/lib/api-client.js +241 -0
  274. package/server/mcp-server/index.ts +1545 -0
  275. package/server/mcp-server/lib/api-client.ts +366 -0
  276. package/server/mcp-server/tsconfig.json +14 -0
  277. package/src/agent-registry.ts +180 -0
  278. package/src/channels/discord.ts +129 -0
  279. package/src/channels/imessage.ts +261 -0
  280. package/src/channels/slack.ts +208 -0
  281. package/src/channels/telegram.ts +307 -0
  282. package/src/channels/types.ts +62 -0
  283. package/src/channels/whatsapp.ts +227 -0
  284. package/src/config.ts +281 -0
  285. package/src/cron.ts +43 -0
  286. package/src/decrypt-keys.ts +60 -0
  287. package/src/encrypt-keys.ts +70 -0
  288. package/src/executor.ts +2190 -0
  289. package/src/gemini-executor.ts +212 -0
  290. package/src/goals.ts +240 -0
  291. package/src/gym/activity-digest.ts +546 -0
  292. package/src/gym/dimension-scorer.ts +297 -0
  293. package/src/gym/gym-router.ts +801 -0
  294. package/src/gym/index.ts +19 -0
  295. package/src/heartbeat.ts +220 -0
  296. package/src/index.ts +275 -0
  297. package/src/keystore.ts +190 -0
  298. package/src/logger.ts +51 -0
  299. package/src/memory/daily.ts +101 -0
  300. package/src/memory/embeddings.ts +185 -0
  301. package/src/memory/index.ts +218 -0
  302. package/src/memory/search.ts +124 -0
  303. package/src/memory/store.ts +189 -0
  304. package/src/ollama-executor.ts +126 -0
  305. package/src/openai-executor.ts +259 -0
  306. package/src/router.ts +230 -0
  307. package/src/test-message.ts +72 -0
  308. package/src/utils/imsg-db-reader.ts +109 -0
  309. package/src/utils/imsg-rpc.ts +178 -0
  310. package/src/utils/message-formatter.ts +90 -0
  311. package/src/web-ui.ts +5778 -0
  312. package/src/whatsapp-chats.ts +91 -0
  313. package/src/whatsapp-login.ts +110 -0
  314. package/src/wiki-sync.ts +199 -0
  315. package/tsconfig.json +19 -0
@@ -0,0 +1,1106 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>MyAIforOne — API & MCP Docs</title>
7
+ <link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&family=Syne:wght@600;700;800&display=swap" rel="stylesheet">
8
+ <style>
9
+ *,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
10
+ :root{
11
+ --bg:#060a13;--surface:rgba(12,18,33,0.95);--card:rgba(16,22,40,0.85);
12
+ --input:rgba(0,0,0,0.35);--border:rgba(56,189,248,0.08);--border-glow:rgba(56,189,248,0.18);
13
+ --text:#e2e8f0;--text-dim:#94a3b8;--text-muted:rgba(148,163,184,0.5);
14
+ --accent:#22d3ee;--accent-bg:rgba(6,182,212,0.12);
15
+ --mcp:#34d399;--mcp-bg:rgba(52,211,153,0.12);
16
+ --green:#4ade80;--green-bg:rgba(74,222,128,0.1);--blue:#60a5fa;--blue-bg:rgba(96,165,250,0.1);
17
+ --amber:#fbbf24;--amber-bg:rgba(251,191,36,0.1);--red:#f87171;--red-bg:rgba(248,113,113,0.1);
18
+ --purple:#a78bfa;--purple-bg:rgba(167,139,250,0.1);
19
+ --font:'DM Sans',system-ui,sans-serif;--mono:'IBM Plex Mono',monospace;--display:'Syne',sans-serif;
20
+ }
21
+ [data-theme="light"]{
22
+ --bg:#f4f6f9;--surface:rgba(255,255,255,0.95);--card:rgba(255,255,255,0.9);
23
+ --input:rgba(0,0,0,0.04);--border:rgba(0,0,0,0.08);--border-glow:rgba(14,116,144,0.18);
24
+ --text:#0f172a;--text-dim:#475569;--text-muted:rgba(100,116,139,0.5);
25
+ --accent:#0891b2;--accent-bg:rgba(14,116,144,0.08);
26
+ --mcp:#059669;--mcp-bg:rgba(5,150,105,0.08);
27
+ --green:#16a34a;--green-bg:rgba(22,163,74,0.08);--blue:#2563eb;--blue-bg:rgba(37,99,235,0.08);
28
+ --amber:#d97706;--amber-bg:rgba(217,119,6,0.08);--red:#dc2626;--red-bg:rgba(220,38,38,0.08);
29
+ --purple:#7c3aed;--purple-bg:rgba(124,58,237,0.08);
30
+ }
31
+ html,body{width:100%;height:100%;overflow:hidden;background:var(--bg);font-family:var(--font);color:var(--text)}
32
+
33
+ /* Layout */
34
+ .layout{display:flex;height:100vh}
35
+ .sidebar{width:280px;flex-shrink:0;background:var(--surface);border-right:1px solid var(--border);display:flex;flex-direction:column;overflow:hidden}
36
+ .main{flex:1;overflow-y:auto;padding:24px 32px}
37
+
38
+ /* Top-level tab bar */
39
+ .top-tabs{display:flex;border-bottom:1px solid var(--border);flex-shrink:0}
40
+ .top-tab{flex:1;padding:10px 16px;text-align:center;font-family:var(--display);font-size:12px;font-weight:700;cursor:pointer;border:none;background:transparent;color:var(--text-muted);transition:all .2s;border-bottom:2px solid transparent;letter-spacing:.04em}
41
+ .top-tab:hover{color:var(--text-dim)}
42
+ .top-tab.active-api{color:var(--accent);border-bottom-color:var(--accent);background:var(--accent-bg)}
43
+ .top-tab.active-mcp{color:var(--mcp);border-bottom-color:var(--mcp);background:var(--mcp-bg)}
44
+
45
+ /* Sidebar */
46
+ .sidebar-header{padding:16px 16px 12px;border-bottom:1px solid var(--border)}
47
+ .sidebar-title{font-family:var(--display);font-size:15px;font-weight:800;margin-bottom:8px}
48
+ .sidebar-title.api-title{color:var(--accent)}
49
+ .sidebar-title.mcp-title{color:var(--mcp)}
50
+ .sidebar-search{width:100%;padding:6px 10px;border-radius:7px;border:1px solid var(--border);background:var(--input);color:var(--text);font-family:var(--font);font-size:12px;outline:none}
51
+ .sidebar-search:focus{border-color:var(--border-glow)}
52
+ .sidebar-search::placeholder{color:var(--text-muted)}
53
+ .sidebar-body{flex:1;overflow-y:auto;padding:8px 0}
54
+ .sidebar-body::-webkit-scrollbar{width:3px}
55
+ .sidebar-body::-webkit-scrollbar-thumb{background:rgba(56,189,248,0.2);border-radius:2px}
56
+
57
+ .cat-group{margin-bottom:4px}
58
+ .cat-header{display:flex;align-items:center;gap:6px;padding:6px 16px;cursor:pointer;font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--text-dim);transition:color .2s}
59
+ .cat-header:hover{color:var(--accent)}
60
+ .cat-header .count{margin-left:auto;font-size:9px;color:var(--text-muted);font-weight:500}
61
+ .cat-header .arrow{font-size:8px;transition:transform .2s}
62
+ .cat-header.open .arrow{transform:rotate(90deg)}
63
+ .cat-items{display:none;padding:0 8px 4px}
64
+ .cat-header.open + .cat-items{display:block}
65
+
66
+ /* MCP sidebar overrides */
67
+ .mcp-mode .cat-header:hover{color:var(--mcp)}
68
+ .mcp-mode .sidebar-body::-webkit-scrollbar-thumb{background:rgba(52,211,153,0.3)}
69
+
70
+ /* API endpoint items */
71
+ .ep-item{display:flex;align-items:center;gap:6px;padding:5px 8px;border-radius:6px;cursor:pointer;transition:background .15s;font-size:11px}
72
+ .ep-item:hover{background:var(--accent-bg)}
73
+ .ep-item.active{background:var(--accent-bg);border-left:2px solid var(--accent)}
74
+ .method-badge{font-family:var(--mono);font-size:9px;font-weight:700;padding:2px 5px;border-radius:3px;text-transform:uppercase;flex-shrink:0;min-width:38px;text-align:center}
75
+ .method-GET{background:var(--green-bg);color:var(--green)}
76
+ .method-POST{background:var(--blue-bg);color:var(--blue)}
77
+ .method-PUT{background:var(--amber-bg);color:var(--amber)}
78
+ .method-DELETE{background:var(--red-bg);color:var(--red)}
79
+ .method-PATCH{background:var(--purple-bg);color:var(--purple)}
80
+ .ep-path{font-family:var(--mono);font-size:10px;color:var(--text-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
81
+
82
+ /* MCP tool items */
83
+ .tool-item{padding:5px 8px;border-radius:6px;cursor:pointer;font-size:11px;font-family:var(--mono);color:var(--text-dim);transition:background .15s;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
84
+ .tool-item:hover{background:var(--mcp-bg);color:var(--text)}
85
+ .tool-item.active{background:var(--mcp-bg);color:var(--mcp);border-left:2px solid var(--mcp)}
86
+
87
+ /* Sidebar nav links */
88
+ .sidebar-nav{padding:8px 16px;border-top:1px solid var(--border);display:flex;gap:8px;flex-shrink:0}
89
+ .sidebar-nav a{font-size:11px;color:var(--text-muted);text-decoration:none;padding:4px 8px;border-radius:5px;border:1px solid var(--border);transition:all .2s}
90
+ .sidebar-nav a:hover{border-color:var(--border-glow);color:var(--text-dim)}
91
+ .sidebar-nav a.active-api{border-color:var(--accent);color:var(--accent);background:var(--accent-bg)}
92
+ .sidebar-nav a.active-mcp{border-color:var(--mcp);color:var(--mcp);background:var(--mcp-bg)}
93
+
94
+ /* Main panel */
95
+ .overview{max-width:800px}
96
+ .overview h1{font-family:var(--display);font-size:28px;font-weight:800;margin-bottom:4px}
97
+ .overview .subtitle{color:var(--text-dim);font-size:14px;margin-bottom:24px}
98
+ .stat-row{display:flex;gap:12px;margin-bottom:24px;flex-wrap:wrap}
99
+ .stat-card{padding:14px 18px;border-radius:10px;border:1px solid var(--border);background:var(--card);min-width:120px}
100
+ .stat-val{font-family:var(--display);font-size:22px;font-weight:800;color:var(--accent)}
101
+ .stat-label{font-size:11px;color:var(--text-muted);margin-top:2px}
102
+ .mcp-mode .stat-val{color:var(--mcp)}
103
+ .cat-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:10px;margin-top:16px}
104
+ .cat-card{padding:12px 16px;border-radius:10px;border:1px solid var(--border);background:var(--card);cursor:pointer;transition:all .2s}
105
+ .cat-card:hover{border-color:var(--border-glow);transform:translateY(-1px)}
106
+ .cat-card-name{font-family:var(--display);font-size:13px;font-weight:700;color:var(--accent);margin-bottom:2px}
107
+ .cat-card-count{font-size:11px;color:var(--text-muted)}
108
+ .mcp-mode .cat-card-name{color:var(--mcp)}
109
+
110
+ /* Endpoint detail */
111
+ .ep-detail{max-width:900px}
112
+ .ep-detail-header{display:flex;align-items:center;gap:10px;margin-bottom:4px;flex-wrap:wrap}
113
+ .ep-detail-header .method-badge{font-size:12px;padding:4px 10px}
114
+ .ep-detail-path{font-family:var(--mono);font-size:16px;font-weight:600}
115
+ .ep-detail-summary{color:var(--text-dim);font-size:13px;margin-bottom:20px}
116
+
117
+ .section{background:var(--card);border:1px solid var(--border);border-radius:10px;margin-bottom:16px;overflow:hidden}
118
+ .section-title{padding:12px 16px;font-size:11px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--text-dim);border-bottom:1px solid var(--border)}
119
+ .section-body{padding:16px}
120
+
121
+ /* Param inputs (API) */
122
+ .param-row{display:flex;gap:8px;align-items:center;margin-bottom:8px;flex-wrap:wrap}
123
+ .param-label{font-family:var(--mono);font-size:11px;font-weight:600;color:var(--accent);min-width:120px}
124
+ .param-input{flex:1;min-width:150px;padding:6px 10px;border-radius:6px;border:1px solid var(--border);background:var(--input);color:var(--text);font-family:var(--mono);font-size:11px;outline:none}
125
+ .param-input:focus{border-color:var(--border-glow)}
126
+ .param-input::placeholder{color:var(--text-muted)}
127
+ .param-type{font-size:10px;color:var(--text-muted);font-family:var(--mono)}
128
+ .param-req{font-size:9px;color:var(--red);font-weight:700}
129
+
130
+ /* MCP param table */
131
+ .mcp-param-row{display:flex;align-items:baseline;gap:8px;padding:6px 0;border-bottom:1px solid var(--border);font-size:12px}
132
+ .mcp-param-row:last-child{border-bottom:none}
133
+ .mcp-param-name{font-family:var(--mono);font-weight:600;color:var(--mcp);min-width:120px}
134
+ .mcp-param-type{font-family:var(--mono);font-size:10px;color:var(--text-muted);min-width:60px}
135
+ .mcp-param-req{font-size:9px;font-weight:700;color:var(--amber);min-width:55px}
136
+ .mcp-param-desc{color:var(--text-dim);flex:1}
137
+
138
+ /* MCP tool detail */
139
+ .tool-detail{max-width:800px}
140
+ .tool-name{font-family:var(--mono);font-size:18px;font-weight:700;color:var(--mcp);margin-bottom:4px}
141
+ .tool-desc{color:var(--text-dim);font-size:13px;margin-bottom:16px}
142
+ .tool-cat-badge{font-size:9px;font-weight:700;padding:2px 8px;border-radius:4px;background:var(--mcp-bg);color:var(--mcp);margin-bottom:12px;display:inline-block}
143
+
144
+ /* Body editor */
145
+ .body-editor{width:100%;min-height:120px;padding:12px;border-radius:8px;border:1px solid var(--border);background:#0d1117;color:var(--green);font-family:var(--mono);font-size:11px;line-height:1.6;resize:vertical;outline:none}
146
+ .body-editor:focus{border-color:var(--border-glow)}
147
+
148
+ /* Buttons */
149
+ .btn{padding:8px 18px;border-radius:8px;font-family:var(--font);font-size:12px;font-weight:600;cursor:pointer;border:none;transition:all .2s}
150
+ .btn-send{background:var(--accent);color:#000}.btn-send:hover{filter:brightness(1.1)}
151
+ .btn-send:disabled{opacity:.4;cursor:not-allowed}
152
+ .btn-outline{background:transparent;border:1px solid var(--border);color:var(--text-dim)}.btn-outline:hover{border-color:var(--border-glow);color:var(--text)}
153
+ .btn-row{display:flex;gap:8px;margin-top:12px;align-items:center}
154
+
155
+ /* Response */
156
+ .resp-status{display:inline-flex;align-items:center;gap:6px;font-family:var(--mono);font-size:12px;font-weight:700;padding:4px 10px;border-radius:6px;margin-bottom:8px}
157
+ .resp-2xx{background:var(--green-bg);color:var(--green)}
158
+ .resp-4xx{background:var(--amber-bg);color:var(--amber)}
159
+ .resp-5xx{background:var(--red-bg);color:var(--red)}
160
+ .resp-body{background:#0d1117;border-radius:8px;padding:12px;font-family:var(--mono);font-size:11px;line-height:1.6;color:#e6edf3;max-height:400px;overflow:auto;white-space:pre-wrap;word-break:break-word;border:1px solid rgba(255,255,255,0.05)}
161
+
162
+ /* cURL / example boxes */
163
+ .curl-box,.example-box{background:#0d1117;border-radius:8px;padding:12px;font-family:var(--mono);font-size:11px;line-height:1.6;color:#e6edf3;position:relative;white-space:pre-wrap;word-break:break-all;border:1px solid rgba(255,255,255,0.05)}
164
+ .copy-btn{position:absolute;top:8px;right:8px;padding:3px 8px;border-radius:5px;border:1px solid rgba(255,255,255,0.1);background:rgba(255,255,255,0.05);color:var(--text-dim);font-size:10px;cursor:pointer;transition:all .2s}
165
+ .copy-btn:hover{background:rgba(255,255,255,0.1);color:var(--text)}
166
+
167
+ /* History */
168
+ .history-row{display:flex;align-items:center;gap:8px;padding:8px 0;border-bottom:1px solid var(--border);cursor:pointer;transition:background .15s;font-size:11px}
169
+ .history-row:hover{background:var(--accent-bg)}
170
+ .history-row:last-child{border-bottom:none}
171
+ .history-time{font-family:var(--mono);font-size:10px;color:var(--text-muted);min-width:70px}
172
+ .history-status{font-family:var(--mono);font-size:10px;font-weight:700;min-width:30px}
173
+
174
+ /* Connect box (MCP) */
175
+ .connect-box{padding:14px;border-radius:10px;border:1px solid var(--border);background:var(--card);margin-top:16px}
176
+ .connect-title{font-size:11px;font-weight:700;color:var(--text-dim);margin-bottom:6px}
177
+
178
+ /* Theme toggle */
179
+ .theme-btn{position:fixed;top:12px;right:12px;z-index:10;width:32px;height:32px;border-radius:8px;border:1px solid var(--border);background:var(--surface);color:var(--text-dim);cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:14px}
180
+
181
+ /* Tab content visibility */
182
+ .tab-content{display:none}
183
+ .tab-content.active{display:flex;flex-direction:column;flex:1;overflow:hidden}
184
+ </style>
185
+ </head>
186
+ <body>
187
+ <button class="theme-btn" onclick="toggleTheme()" title="Toggle theme">&#9728;</button>
188
+
189
+ <div class="layout">
190
+ <div class="sidebar" id="sidebar">
191
+ <!-- Top-level tabs -->
192
+ <div class="top-tabs">
193
+ <button class="top-tab active-api" id="tabApi" onclick="switchTab('api')">REST API</button>
194
+ <button class="top-tab" id="tabMcp" onclick="switchTab('mcp')">MCP Tools</button>
195
+ </div>
196
+
197
+ <!-- API sidebar content -->
198
+ <div class="tab-content active" id="apiSidebarContent">
199
+ <div class="sidebar-header">
200
+ <div class="sidebar-title api-title">MyAIforOne API</div>
201
+ <input class="sidebar-search" id="apiSearch" placeholder="Search endpoints..." oninput="filterEndpoints()">
202
+ </div>
203
+ <div class="sidebar-body" id="apiSidebarBody"></div>
204
+ <div class="sidebar-nav" id="apiNav">
205
+ <a href="#" class="active-api" id="navOverview" onclick="showOverview();return false">Overview</a>
206
+ <a href="#" id="navHistory" onclick="showHistory();return false">History</a>
207
+ <a href="/" target="_blank">Home</a>
208
+ </div>
209
+ </div>
210
+
211
+ <!-- MCP sidebar content -->
212
+ <div class="tab-content" id="mcpSidebarContent">
213
+ <div class="sidebar-header">
214
+ <div class="sidebar-title mcp-title">MCP Tools</div>
215
+ <input class="sidebar-search" id="mcpSearch" placeholder="Search tools..." oninput="filterTools()">
216
+ </div>
217
+ <div class="sidebar-body mcp-mode" id="mcpSidebarBody"></div>
218
+ <div class="sidebar-nav" id="mcpNav">
219
+ <a href="#" class="active-mcp" id="navMcpOverview" onclick="showMcpOverview();return false">Overview</a>
220
+ <a href="/" target="_blank">Home</a>
221
+ </div>
222
+ </div>
223
+ </div>
224
+
225
+ <!-- Main panels -->
226
+ <div class="main" id="apiMain"></div>
227
+ <div class="main" id="mcpMain" style="display:none"></div>
228
+ </div>
229
+
230
+ <script>
231
+ // ═══ ENDPOINT CATALOG (REST API) ════════════════════════════════════
232
+ const CATALOG = [
233
+ // -- Dashboard & Health --
234
+ { cat: "Dashboard", method: "GET", path: "/api/dashboard", summary: "Get full dashboard: agents, channels, accounts, uptime" },
235
+ { cat: "Dashboard", method: "GET", path: "/health", summary: "Health check" },
236
+ { cat: "Dashboard", method: "GET", path: "/api/agent-registry", summary: "Get agent registry with search keywords" },
237
+
238
+ // -- Agents --
239
+ { cat: "Agents", method: "GET", path: "/api/agents", summary: "List all agents (optional ?org= filter)", params: [{ name: "org", in: "query", type: "string", desc: "Filter by organization" }] },
240
+ { cat: "Agents", method: "GET", path: "/api/agents/:id", summary: "Get agent details + CLAUDE.md content", params: [{ name: "id", in: "path", type: "string", required: true }] },
241
+ { cat: "Agents", method: "GET", path: "/api/agents/:id/instructions", summary: "Get agent CLAUDE.md system prompt", params: [{ name: "id", in: "path", type: "string", required: true }] },
242
+ { cat: "Agents", method: "POST", path: "/api/agents", summary: "Create a new agent", body: { name: { type: "string", required: true }, mentionAlias: { type: "string", required: true }, description: { type: "string" }, workspace: { type: "string" }, organization: { type: "string" }, function: { type: "string" }, title: { type: "string" }, skills: { type: "string[]" }, mcps: { type: "string[]" }, tools: { type: "string[]" }, prompts: { type: "string[]" }, subAgents: { type: "string[]|'*'" }, claudeAccount: { type: "string" }, persistent: { type: "boolean", default: true }, streaming: { type: "boolean", default: true }, advancedMemory: { type: "boolean" }, timeout: { type: "number", desc: "Timeout in ms (default 14400000)" }, heartbeatInstructions: { type: "string" }, agentClass: { type: "string", desc: "standard | platform | builder" }, wiki: { type: "boolean", desc: "Enable Wiki Learning (captures facts from conversations into learned.md)" }, wikiSync: { type: "object", desc: "{ enabled: boolean, schedule: string (cron) } — auto-merge learned facts on schedule" } } },
243
+ { cat: "Agents", method: "PUT", path: "/api/agents/:id", summary: "Update agent config", params: [{ name: "id", in: "path", type: "string", required: true }], body: { name: { type: "string" }, alias: { type: "string" }, description: { type: "string" }, workspace: { type: "string" }, org: { type: "array", desc: "[{ organization, function, title, reportsTo? }]" }, persistent: { type: "boolean" }, streaming: { type: "boolean" }, advancedMemory: { type: "boolean" }, autonomousCapable: { type: "boolean" }, timeout: { type: "number" }, tools: { type: "string[]" }, skills: { type: "string[]" }, mcps: { type: "string[]" }, prompts: { type: "string[]" }, subAgents: { type: "string[]|'*'" }, claudeAccount: { type: "string" }, instructions: { type: "string", desc: "Update CLAUDE.md content" }, heartbeatInstructions: { type: "string" }, agentClass: { type: "string", desc: "standard | platform | builder" }, executor: { type: "string", desc: "'claude' (default) or 'ollama:<model>'" }, wiki: { type: "boolean", desc: "Enable Wiki Learning" }, wikiSync: { type: "object", desc: "{ enabled: boolean, schedule: string (cron) } — auto-merge learned facts on schedule" } } },
244
+ { cat: "Agents", method: "DELETE", path: "/api/agents/:id", summary: "Delete agent and optionally remove home dir", params: [{ name: "id", in: "path", type: "string", required: true }] },
245
+ { cat: "Agents", method: "POST", path: "/api/agents/:agentId/recover", summary: "Recover from session corruption (recreates session)", params: [{ name: "agentId", in: "path", type: "string", required: true }] },
246
+ { cat: "Agents", method: "GET", path: "/api/whoami/:agentId", summary: "Get Claude auth status for the account this agent uses", params: [{ name: "agentId", in: "path", type: "string", required: true }] },
247
+ { cat: "Agents", method: "POST", path: "/api/agents/:id/heartbeat", summary: "Trigger a heartbeat check (async, returns immediately)", params: [{ name: "id", in: "path", type: "string", required: true }], body: { triggeredBy: { type: "string", desc: "Label for trigger source (default: manual)" } } },
248
+ { cat: "Agents", method: "GET", path: "/api/agents/:id/heartbeat-history", summary: "Get recent heartbeat run history", params: [{ name: "id", in: "path", type: "string", required: true }, { name: "limit", in: "query", type: "number", desc: "Max entries (default 20)" }] },
249
+
250
+ // -- Wiki Sync --
251
+ { cat: "Agents", method: "POST", path: "/api/agents/:id/wiki-sync", summary: "Trigger wiki sync for an agent (merges learned.md into context.md)", params: [{ name: "id", in: "path", type: "string", required: true }] },
252
+ { cat: "Agents", method: "GET", path: "/api/agents/:id/wiki-sync-history", summary: "Get wiki sync execution history", params: [{ name: "id", in: "path", type: "string", required: true }, { name: "limit", in: "query", type: "number", desc: "Max entries (default 20)" }] },
253
+
254
+ // -- Chat --
255
+ { cat: "Chat", method: "POST", path: "/api/chat/:agentId", summary: "Send message to agent (non-streaming)", params: [{ name: "agentId", in: "path", type: "string", required: true }], body: { text: { type: "string", required: true }, accountOverride: { type: "string" } } },
256
+ { cat: "Chat", method: "POST", path: "/api/chat/:agentId/stream", summary: "Start streaming chat — returns jobId", params: [{ name: "agentId", in: "path", type: "string", required: true }], body: { text: { type: "string", required: true }, accountOverride: { type: "string" } } },
257
+ { cat: "Chat", method: "GET", path: "/api/chat/jobs/:jobId/stream", summary: "Stream SSE events for a job (reconnectable via ?after=N)", params: [{ name: "jobId", in: "path", type: "string", required: true }, { name: "after", in: "query", type: "number", desc: "Resume from event index" }] },
258
+ { cat: "Chat", method: "GET", path: "/api/chat/jobs/:jobId/raw", summary: "Stream raw Claude output lines for a job", params: [{ name: "jobId", in: "path", type: "string", required: true }] },
259
+ { cat: "Chat", method: "POST", path: "/api/chat/jobs/:jobId/stop", summary: "Stop a running chat job", params: [{ name: "jobId", in: "path", type: "string", required: true }] },
260
+ { cat: "Chat", method: "POST", path: "/api/delegate", summary: "Delegate message to agent (inter-agent)", body: { agentId: { type: "string", required: true }, text: { type: "string", required: true }, channel: { type: "string" }, chatId: { type: "string" } } },
261
+
262
+ // -- Sessions --
263
+ { cat: "Sessions", method: "GET", path: "/api/agents/:agentId/sessions", summary: "List active sessions for an agent", params: [{ name: "agentId", in: "path", type: "string", required: true }] },
264
+ { cat: "Sessions", method: "POST", path: "/api/agents/:agentId/sessions/reset", summary: "Reset session (optionally per sender)", params: [{ name: "agentId", in: "path", type: "string", required: true }], body: { senderId: { type: "string", desc: "Specific sender to reset" } } },
265
+ { cat: "Sessions", method: "DELETE", path: "/api/agents/:agentId/sessions/:senderId", summary: "Delete a specific sender session", params: [{ name: "agentId", in: "path", type: "string", required: true }, { name: "senderId", in: "path", type: "string", required: true }] },
266
+
267
+ // -- Model --
268
+ { cat: "Model", method: "GET", path: "/api/agents/:agentId/model", summary: "Get current model override", params: [{ name: "agentId", in: "path", type: "string", required: true }] },
269
+ { cat: "Model", method: "PUT", path: "/api/agents/:agentId/model", summary: "Set model override (opus, sonnet, haiku, or full ID)", params: [{ name: "agentId", in: "path", type: "string", required: true }], body: { model: { type: "string", required: true, desc: "opus | sonnet | haiku | full model ID" } } },
270
+ { cat: "Model", method: "DELETE", path: "/api/agents/:agentId/model", summary: "Clear model override (use agent default)", params: [{ name: "agentId", in: "path", type: "string", required: true }] },
271
+
272
+ // -- Cost --
273
+ { cat: "Cost", method: "GET", path: "/api/agents/:agentId/cost", summary: "Cost summary: today, week, all-time, by-day breakdown", params: [{ name: "agentId", in: "path", type: "string", required: true }] },
274
+ { cat: "Cost", method: "GET", path: "/api/cost/all", summary: "Cost summary across ALL agents" },
275
+
276
+ // -- Skills --
277
+ { cat: "Skills", method: "GET", path: "/api/agents/:agentId/skills", summary: "List all skills available to an agent (shared + org + agent)", params: [{ name: "agentId", in: "path", type: "string", required: true }] },
278
+ { cat: "Skills", method: "GET", path: "/api/skills/org/:orgName", summary: "List all skills in an org", params: [{ name: "orgName", in: "path", type: "string", required: true }] },
279
+ { cat: "Skills", method: "POST", path: "/api/skills/create", summary: "Create a skill file at the correct location based on scope and register it in skills.json", body: { id: { type: "string", required: true }, name: { type: "string", required: true }, description: { type: "string", required: true }, content: { type: "string", required: true }, scope: { type: "string", required: true, desc: "global | personal | org | agent" }, orgName: { type: "string", desc: "Required if scope is org" }, agentId: { type: "string", desc: "Required if scope is agent" } } },
280
+
281
+ // -- Files --
282
+ { cat: "Files", method: "POST", path: "/api/upload/:agentId", summary: "Upload file(s) to agent FileStorage", params: [{ name: "agentId", in: "path", type: "string", required: true }] },
283
+ { cat: "Files", method: "GET", path: "/api/agents/:agentId/files", summary: "List files in agent FileStorage", params: [{ name: "agentId", in: "path", type: "string", required: true }] },
284
+ { cat: "Files", method: "GET", path: "/api/agents/:agentId/download", summary: "Download a file from agent workspace", params: [{ name: "agentId", in: "path", type: "string", required: true }, { name: "path", in: "query", type: "string", required: true, desc: "File path to download" }] },
285
+
286
+ // -- Tasks --
287
+ { cat: "Tasks", method: "GET", path: "/api/agents/:id/tasks", summary: "List tasks for agent", params: [{ name: "id", in: "path", type: "string", required: true }] },
288
+ { cat: "Tasks", method: "GET", path: "/api/agents/:id/tasks/stats", summary: "Task stats (counts by status)", params: [{ name: "id", in: "path", type: "string", required: true }] },
289
+ { cat: "Tasks", method: "POST", path: "/api/agents/:id/tasks", summary: "Create task for agent", params: [{ name: "id", in: "path", type: "string", required: true }], body: { title: { type: "string", required: true }, description: { type: "string" }, priority: { type: "string", enum: ["low","medium","high","critical"] }, project: { type: "string" } } },
290
+ { cat: "Tasks", method: "PUT", path: "/api/agents/:id/tasks/:taskId", summary: "Update task", params: [{ name: "id", in: "path", type: "string", required: true }, { name: "taskId", in: "path", type: "string", required: true }], body: { status: { type: "string" }, title: { type: "string" } } },
291
+ { cat: "Tasks", method: "DELETE", path: "/api/agents/:id/tasks/:taskId", summary: "Delete task", params: [{ name: "id", in: "path", type: "string", required: true }, { name: "taskId", in: "path", type: "string", required: true }] },
292
+ { cat: "Tasks", method: "POST", path: "/api/agents/:id/projects", summary: "Create a project", params: [{ name: "id", in: "path", type: "string", required: true }], body: { name: { type: "string", required: true } } },
293
+ { cat: "Tasks", method: "GET", path: "/api/tasks/all", summary: "Get all tasks across all agents" },
294
+
295
+ // -- Projects --
296
+ { cat: "Projects", method: "GET", path: "/api/projects", summary: "List all projects" },
297
+ { cat: "Projects", method: "GET", path: "/api/projects/:id", summary: "Get project detail with task rollup", params: [{ name: "id", in: "path", type: "string", required: true }] },
298
+ { cat: "Projects", method: "POST", path: "/api/projects", summary: "Create a new project", body: { name: { type: "string", required: true }, description: { type: "string" }, owner: { type: "string" }, teamMembers: { type: "string[]" }, plan: { type: "string" }, notes: { type: "string" } } },
299
+ { cat: "Projects", method: "PUT", path: "/api/projects/:id", summary: "Update a project", params: [{ name: "id", in: "path", type: "string", required: true }], body: { name: { type: "string" }, description: { type: "string" }, status: { type: "string" }, owner: { type: "string" }, teamMembers: { type: "string[]" }, plan: { type: "string" }, notes: { type: "string" }, linkedTasks: { type: "string[]" }, linkedAgents: { type: "string[]" }, linkedOrgs: { type: "string[]" }, linkedApps: { type: "string[]" }, linkedArtifacts: { type: "string[]" } } },
300
+ { cat: "Projects", method: "DELETE", path: "/api/projects/:id", summary: "Delete a project", params: [{ name: "id", in: "path", type: "string", required: true }] },
301
+ { cat: "Projects", method: "POST", path: "/api/projects/:id/link", summary: "Link entity to project", params: [{ name: "id", in: "path", type: "string", required: true }], body: { type: { type: "string", required: true, desc: "task | agent | org | app | artifact" }, value: { type: "any", required: true } } },
302
+ { cat: "Projects", method: "POST", path: "/api/projects/:id/unlink", summary: "Unlink entity from project", params: [{ name: "id", in: "path", type: "string", required: true }], body: { type: { type: "string", required: true, desc: "task | agent | org | app | artifact" }, value: { type: "any", required: true } } },
303
+ { cat: "Projects", method: "GET", path: "/api/projects/:id/status", summary: "Get project status report", params: [{ name: "id", in: "path", type: "string", required: true }] },
304
+ { cat: "Projects", method: "POST", path: "/api/projects/:id/execute", summary: "Start autonomous execution — creates a scheduled goal on the owner agent", params: [{ name: "id", in: "path", type: "string", required: true }], body: { schedule: { type: "string", desc: "Cron expression (default \"*/15 * * * *\")" }, reportTo: { type: "string", desc: "channel:chatId" }, budget: { type: "object", desc: "{ maxDailyUsd: number }" } } },
305
+ { cat: "Projects", method: "POST", path: "/api/projects/:id/pause", summary: "Pause autonomous project execution — disables the execution goal", params: [{ name: "id", in: "path", type: "string", required: true }] },
306
+
307
+ // -- Automations --
308
+ { cat: "Automations", method: "GET", path: "/api/automations", summary: "List all goals and crons across agents" },
309
+ { cat: "Automations", method: "POST", path: "/api/agents/:id/goals", summary: "Create goal for agent", params: [{ name: "id", in: "path", type: "string", required: true }], body: { description: { type: "string", required: true }, heartbeat: { type: "string", required: true, desc: "Cron expression" }, successCriteria: { type: "string" }, instructions: { type: "string" } } },
310
+ { cat: "Automations", method: "POST", path: "/api/agents/:id/goals/:goalId/toggle", summary: "Enable/disable a goal", params: [{ name: "id", in: "path", type: "string", required: true }, { name: "goalId", in: "path", type: "string", required: true }] },
311
+ { cat: "Automations", method: "POST", path: "/api/agents/:id/goals/:goalId/trigger", summary: "Manually trigger a goal run", params: [{ name: "id", in: "path", type: "string", required: true }, { name: "goalId", in: "path", type: "string", required: true }] },
312
+ { cat: "Automations", method: "GET", path: "/api/agents/:id/goals/:goalId/history", summary: "Goal run history", params: [{ name: "id", in: "path", type: "string", required: true }, { name: "goalId", in: "path", type: "string", required: true }] },
313
+ { cat: "Automations", method: "DELETE", path: "/api/agents/:id/goals/:goalId", summary: "Delete a goal", params: [{ name: "id", in: "path", type: "string", required: true }, { name: "goalId", in: "path", type: "string", required: true }] },
314
+ { cat: "Automations", method: "POST", path: "/api/agents/:id/cron", summary: "Create cron job", params: [{ name: "id", in: "path", type: "string", required: true }], body: { schedule: { type: "string", required: true, desc: "Cron expression" }, message: { type: "string", required: true } } },
315
+ { cat: "Automations", method: "POST", path: "/api/agents/:id/cron/:index/toggle", summary: "Enable/disable a cron", params: [{ name: "id", in: "path", type: "string", required: true }, { name: "index", in: "path", type: "number", required: true }] },
316
+ { cat: "Automations", method: "POST", path: "/api/agents/:id/cron/:index/trigger", summary: "Manually trigger a cron run", params: [{ name: "id", in: "path", type: "string", required: true }, { name: "index", in: "path", type: "number", required: true }] },
317
+ { cat: "Automations", method: "GET", path: "/api/agents/:id/cron/:index/history", summary: "Cron run history", params: [{ name: "id", in: "path", type: "string", required: true }, { name: "index", in: "path", type: "number", required: true }] },
318
+ { cat: "Automations", method: "DELETE", path: "/api/agents/:id/cron/:index", summary: "Delete a cron", params: [{ name: "id", in: "path", type: "string", required: true }, { name: "index", in: "path", type: "number", required: true }] },
319
+
320
+ // -- MCPs --
321
+ { cat: "MCPs", method: "GET", path: "/api/mcps", summary: "List registered MCP servers" },
322
+ { cat: "MCPs", method: "GET", path: "/api/mcp-catalog", summary: "Get pre-hosted MCP catalog" },
323
+ { cat: "MCPs", method: "GET", path: "/api/agents/:id/mcp-keys", summary: "List MCP API keys for agent", params: [{ name: "id", in: "path", type: "string", required: true }] },
324
+ { cat: "MCPs", method: "POST", path: "/api/agents/:id/mcp-keys", summary: "Save MCP API key", params: [{ name: "id", in: "path", type: "string", required: true }], body: { mcpName: { type: "string", required: true }, envVar: { type: "string", required: true, desc: "Environment variable name (e.g. GMAIL_ACCESS_TOKEN)" }, value: { type: "string", required: true, desc: "Secret value" } } },
325
+ { cat: "MCPs", method: "DELETE", path: "/api/agents/:id/mcp-keys/:mcpName", summary: "Delete MCP API key", params: [{ name: "id", in: "path", type: "string", required: true }, { name: "mcpName", in: "path", type: "string", required: true }] },
326
+ { cat: "MCPs", method: "POST", path: "/api/agents/:id/mcp-connections", summary: "Create MCP connection instance (instanceName auto-generated from baseMcp+label)", params: [{ name: "id", in: "path", type: "string", required: true }], body: { baseMcp: { type: "string", required: true, desc: "Base MCP server name from registry" }, label: { type: "string", required: true, desc: "Human-readable label" }, envVar: { type: "string", required: true, desc: "Environment variable name" }, value: { type: "string", required: true, desc: "Secret value" }, description: { type: "string" } } },
327
+ { cat: "MCPs", method: "GET", path: "/api/agents/:id/mcp-connections", summary: "List MCP connections for agent", params: [{ name: "id", in: "path", type: "string", required: true }] },
328
+ { cat: "MCPs", method: "DELETE", path: "/api/agents/:id/mcp-connections/:instanceName", summary: "Delete MCP connection", params: [{ name: "id", in: "path", type: "string", required: true }, { name: "instanceName", in: "path", type: "string", required: true }] },
329
+
330
+ // -- Channels --
331
+ { cat: "Channels", method: "GET", path: "/api/channels", summary: "List all channels with config and agent routes" },
332
+ { cat: "Channels", method: "PUT", path: "/api/channels/:channelName", summary: "Update channel config (sticky routing, etc.)", params: [{ name: "channelName", in: "path", type: "string", required: true }], body: { stickyRouting: { type: "string", enum: ["none","sticky","prefix"] }, stickyPrefix: { type: "string" }, stickyTimeoutMs: { type: "number" } } },
333
+ { cat: "Channels", method: "POST", path: "/api/channels/:channelName/agents", summary: "Add agent route to channel", params: [{ name: "channelName", in: "path", type: "string", required: true }], body: { agentId: { type: "string", required: true }, chatId: { type: "string", required: true }, requireMention: { type: "boolean", default: true } } },
334
+ { cat: "Channels", method: "DELETE", path: "/api/channels/:channelName/agents/:agentId", summary: "Remove agent route from channel", params: [{ name: "channelName", in: "path", type: "string", required: true }, { name: "agentId", in: "path", type: "string", required: true }] },
335
+ { cat: "Channels", method: "POST", path: "/api/channels/:channelName/monitored", summary: "Add monitored chat to channel", params: [{ name: "channelName", in: "path", type: "string", required: true }], body: { chatId: { type: "string", required: true } } },
336
+ { cat: "Channels", method: "DELETE", path: "/api/channels/:channelName/monitored", summary: "Remove monitored chat", params: [{ name: "channelName", in: "path", type: "string", required: true }], body: { chatId: { type: "string", required: true } } },
337
+ { cat: "Channels", method: "GET", path: "/api/sticky-routing", summary: "Get sticky routing config for all channels" },
338
+
339
+ // -- Marketplace / Registry --
340
+ { cat: "Registry", method: "GET", path: "/api/marketplace/:type", summary: "List registry items by type", params: [{ name: "type", in: "path", type: "string", required: true, desc: "agents | skills | mcps | prompts | apps" }] },
341
+ { cat: "Registry", method: "POST", path: "/api/marketplace/install", summary: "Install registry item", body: { id: { type: "string", required: true }, type: { type: "string", required: true } } },
342
+ { cat: "Registry", method: "POST", path: "/api/marketplace/assign", summary: "Assign skill/MCP to agent", body: { agentId: { type: "string", required: true }, itemId: { type: "string", required: true }, type: { type: "string", required: true } } },
343
+ { cat: "Registry", method: "GET", path: "/api/marketplace/scan-skills", summary: "Scan directory for unregistered skills", params: [{ name: "dir", in: "query", type: "string", desc: "Directory to scan (default: ~/.claude/commands)" }] },
344
+ { cat: "Registry", method: "POST", path: "/api/marketplace/import-skills", summary: "Import scanned skills into registry", body: { files: { type: "array", required: true } } },
345
+ { cat: "Registry", method: "POST", path: "/api/marketplace/create-prompt", summary: "Create a new prompt template", body: { id: { type: "string", required: true }, name: { type: "string", required: true }, content: { type: "string", required: true } } },
346
+ { cat: "Registry", method: "GET", path: "/api/marketplace/prompt-trigger", summary: "Get prompt trigger setting" },
347
+ { cat: "Registry", method: "POST", path: "/api/marketplace/prompt-trigger", summary: "Update prompt trigger setting", body: { trigger: { type: "string", required: true } } },
348
+ { cat: "Registry", method: "POST", path: "/api/marketplace/add-mcp", summary: "Add MCP to registry", body: { id: { type: "string", required: true }, name: { type: "string", required: true }, type: { type: "string", required: true }, url: { type: "string" } } },
349
+ { cat: "Registry", method: "POST", path: "/api/marketplace/platform-default", summary: "Set a marketplace item as a platform default", body: { id: { type: "string", required: true }, type: { type: "string", required: true } } },
350
+ { cat: "Registry", method: "POST", path: "/api/import-from-folder", summary: "Import skills from a local folder into the marketplace registry", body: { folderPath: { type: "string", required: true, desc: "Absolute path to folder containing skill files" } } },
351
+
352
+ // -- Lab --
353
+ { cat: "Lab", method: "GET", path: "/api/platform-agents", summary: "List platform-managed creator agents for the Lab page", response: "{ agents: [{ id, name, description, streaming }] }" },
354
+ { cat: "Lab", method: "GET", path: "/api/browse-dirs", summary: "List subdirectories of a given path (for Lab directory picker)", params: [{ name: "path", in: "query", type: "string", desc: "Directory path (defaults to home dir, supports ~ prefix)" }], response: "{ path, dirs[] } or { error }" },
355
+
356
+ // -- Apps --
357
+ { cat: "Apps", method: "GET", path: "/api/apps", summary: "List all registered apps" },
358
+ { cat: "Apps", method: "POST", path: "/api/apps", summary: "Register a new app", body: { name: { type: "string", required: true }, url: { type: "string" }, provider: { type: "string" }, category: { type: "string" }, githubRepo: { type: "string" } } },
359
+ { cat: "Apps", method: "PUT", path: "/api/apps/:id", summary: "Update app", params: [{ name: "id", in: "path", type: "string", required: true }] },
360
+ { cat: "Apps", method: "DELETE", path: "/api/apps/:id", summary: "Delete app", params: [{ name: "id", in: "path", type: "string", required: true }] },
361
+ { cat: "Apps", method: "POST", path: "/api/apps/:id/check-health", summary: "Check app health/status", params: [{ name: "id", in: "path", type: "string", required: true }] },
362
+
363
+ // -- SaaS Publishing --
364
+ { cat: "SaaS", method: "GET", path: "/api/saas/config", summary: "Get SaaS connection config (baseUrl, connected flag, hasKey flag)" },
365
+ { cat: "SaaS", method: "PUT", path: "/api/saas/config", summary: "Save SaaS connection settings", body: { baseUrl: { type: "string", required: true, desc: "Base URL of the SaaS instance (e.g. https://app.myai41.com)" }, apiKey: { type: "string", required: true, desc: "SaaS API key (mak_...)" } } },
366
+ { cat: "SaaS", method: "POST", path: "/api/saas/test", summary: "Test connection to SaaS instance (uses body values or falls back to saved config)", body: { baseUrl: { type: "string", desc: "Override saved base URL" }, apiKey: { type: "string", desc: "Override saved API key" } } },
367
+ { cat: "SaaS", method: "POST", path: "/api/saas/publish", summary: "Publish a skill, prompt, or app to the connected SaaS platform", body: { type: { type: "string", required: true, enum: ["skill", "prompt", "app"], desc: "Type of item to publish" }, id: { type: "string", required: true, desc: "Local registry ID of the item" }, destination: { type: "string", required: true, enum: ["library", "marketplace"], desc: "library = company-private, marketplace = public" } } },
368
+
369
+ // -- Activity & Logs --
370
+ { cat: "Activity", method: "GET", path: "/api/activity", summary: "Get activity feed (latest conversations across agents)", params: [{ name: "limit", in: "query", type: "number", desc: "Max entries (default 100)" }] },
371
+ { cat: "Activity", method: "GET", path: "/api/agents/:agentId/logs", summary: "Paginated conversation logs with search", params: [{ name: "agentId", in: "path", type: "string", required: true }, { name: "limit", in: "query", type: "number", desc: "Max entries (default 50)" }, { name: "offset", in: "query", type: "number" }, { name: "search", in: "query", type: "string", desc: "Keyword filter" }] },
372
+
373
+ // -- Memory --
374
+ { cat: "Memory", method: "GET", path: "/api/agents/:agentId/memory", summary: "List memory entries (context.md + daily files + index)", params: [{ name: "agentId", in: "path", type: "string", required: true }, { name: "limit", in: "query", type: "number", desc: "Max daily files (default 20)" }] },
375
+ { cat: "Memory", method: "POST", path: "/api/agents/:agentId/memory/search", summary: "Keyword search across memory", params: [{ name: "agentId", in: "path", type: "string", required: true }], body: { query: { type: "string", required: true } } },
376
+ { cat: "Memory", method: "DELETE", path: "/api/agents/:agentId/memory/context", summary: "Clear agent context.md", params: [{ name: "agentId", in: "path", type: "string", required: true }] },
377
+
378
+ // -- Pairing --
379
+ { cat: "Pairing", method: "GET", path: "/api/pairing", summary: "List paired senders and pairing status" },
380
+ { cat: "Pairing", method: "POST", path: "/api/pairing", summary: "Manually pair a sender", body: { senderKey: { type: "string", required: true, desc: "Format: channel:senderId" } } },
381
+ { cat: "Pairing", method: "DELETE", path: "/api/pairing/:senderKey", summary: "Unpair a sender", params: [{ name: "senderKey", in: "path", type: "string", required: true }] },
382
+
383
+ // -- Config / Accounts --
384
+ { cat: "Config", method: "GET", path: "/api/config/accounts", summary: "List Claude accounts (name -> config dir)" },
385
+ { cat: "Config", method: "POST", path: "/api/config/accounts", summary: "Add/update Claude account", body: { name: { type: "string", required: true }, path: { type: "string", required: true, desc: "Config directory path (e.g. ~/.claude)" } } },
386
+ { cat: "Config", method: "DELETE", path: "/api/config/accounts/:name", summary: "Remove Claude account", params: [{ name: "name", in: "path", type: "string", required: true }] },
387
+ { cat: "Config", method: "POST", path: "/api/config/accounts/login", summary: "Start login flow — spawns claude auth, returns OAuth URL", body: { name: { type: "string", required: true }, path: { type: "string", required: true } } },
388
+ { cat: "Config", method: "POST", path: "/api/config/accounts/login/code", summary: "Submit auth code to waiting login process", body: { sessionId: { type: "string", required: true }, code: { type: "string", required: true } } },
389
+ { cat: "Config", method: "GET", path: "/api/config/accounts/:name/status", summary: "Check if account is authenticated", params: [{ name: "name", in: "path", type: "string", required: true }] },
390
+ { cat: "Config", method: "GET", path: "/api/config/service", summary: "Get service settings (personalAgentsDir, personalRegistryDir, port, logLevel, defaultClaudeAccount, multiModelEnabled, platformDefaultExecutor, ollamaBaseUrl, providerKeys, gymEnabled, aibriefingEnabled, gymOnlyMode)" },
391
+ { cat: "Config", method: "PUT", path: "/api/config/service", summary: "Update service settings (all fields optional, only provided fields are changed)", body: { personalAgentsDir: { type: "string" }, personalRegistryDir: { type: "string" }, webUIPort: { type: "number" }, logLevel: { type: "string" }, defaultClaudeAccount: { type: "string" }, multiModelEnabled: { type: "boolean" }, platformDefaultExecutor: { type: "string" }, ollamaBaseUrl: { type: "string" }, providerKeys: { type: "object", desc: "{ openai, xai, google, groq, together, mistral }" }, gymEnabled: { type: "boolean" }, aibriefingEnabled: { type: "boolean" }, gymOnlyMode: { type: "boolean" } } },
392
+
393
+ // -- Changelog --
394
+ { cat: "Dashboard", method: "GET", path: "/api/changelog", summary: "Get recent changelog parsed from git history (grouped by date)" },
395
+
396
+ // -- xbar --
397
+ { cat: "Config", method: "GET", path: "/api/ollama-proxy", summary: "Proxy requests to local Ollama API for multi-model support. Returns model list or generation results." },
398
+ { cat: "Config", method: "POST", path: "/api/install-xbar", summary: "Install xbar status bar plugin (macOS only)" },
399
+
400
+ // -- Webhook --
401
+ { cat: "Chat", method: "POST", path: "/webhook/:agentId", summary: "Send a message via webhook (external trigger)", params: [{ name: "agentId", in: "path", type: "string", required: true }], body: { text: { type: "string", required: true }, channel: { type: "string", desc: "Override reply channel" }, chatId: { type: "string", desc: "Override reply chat ID" } } },
402
+
403
+ // -- AI Gym --
404
+ { cat: "AI Gym", method: "GET", path: "/api/gym/learner-profile", summary: "Get the learner's profile (dimensions, streak, trainer, programs)" },
405
+ { cat: "AI Gym", method: "PUT", path: "/api/gym/learner-profile", summary: "Update learner profile fields (merges with existing)" },
406
+ { cat: "AI Gym", method: "GET", path: "/api/gym/plan", summary: "Get the learner's training plan (two-bucket structure)" },
407
+ { cat: "AI Gym", method: "PUT", path: "/api/gym/plan", summary: "Update the training plan" },
408
+ { cat: "AI Gym", method: "GET", path: "/api/gym/progress", summary: "Get program completion progress" },
409
+ { cat: "AI Gym", method: "PUT", path: "/api/gym/progress", summary: "Update program progress" },
410
+ { cat: "AI Gym", method: "GET", path: "/api/gym/cards", summary: "List all gym cards (recommendations, tips)" },
411
+ { cat: "AI Gym", method: "POST", path: "/api/gym/cards", summary: "Create a new gym card", body: { title: { type: "string", required: true }, description: { type: "string", required: true }, type: { type: "string", required: true }, cta: { type: "string" }, ctaAction: { type: "string" } } },
412
+ { cat: "AI Gym", method: "DELETE", path: "/api/gym/cards/:id", summary: "Dismiss/delete a gym card", params: [{ name: "id", in: "path", type: "string", required: true }] },
413
+ { cat: "AI Gym", method: "POST", path: "/api/gym/dimensions/snapshot", summary: "Save a weekly dimension score snapshot", body: { date: { type: "string", desc: "ISO date (defaults to today)" }, dimensions: { type: "object", required: true, desc: "{ application, communication, knowledge, orchestration, craft }" } } },
414
+ { cat: "AI Gym", method: "GET", path: "/api/gym/dimensions/history", summary: "Get all dimension score snapshots" },
415
+ { cat: "AI Gym", method: "GET", path: "/api/gym/programs", summary: "List all training programs" },
416
+ { cat: "AI Gym", method: "GET", path: "/api/gym/programs/:slug", summary: "Get a program with full modules and steps", params: [{ name: "slug", in: "path", type: "string", required: true }] },
417
+ { cat: "AI Gym", method: "POST", path: "/api/gym/programs", summary: "Create a new program", body: { title: { type: "string", required: true }, slug: { type: "string", desc: "URL-safe identifier (auto-generated if omitted)" }, description: { type: "string", required: true }, difficulty: { type: "string", required: true }, tier: { type: "string", required: true }, modules: { type: "array", required: true } } },
418
+ { cat: "AI Gym", method: "PATCH", path: "/api/gym/programs/:slug", summary: "Update a program's metadata", params: [{ name: "slug", in: "path", type: "string", required: true }] },
419
+ { cat: "AI Gym", method: "DELETE", path: "/api/gym/programs/:slug", summary: "Delete a program", params: [{ name: "slug", in: "path", type: "string", required: true }] },
420
+ { cat: "AI Gym", method: "POST", path: "/api/gym/programs/import-markdown", summary: "Import a program from markdown (H1=program, H2=module, H3=step)", body: { markdown: { type: "string", required: true } } },
421
+ { cat: "AI Gym", method: "GET", path: "/api/agents/:id/activity-summary", summary: "Aggregated agent activity: message count, active days, topics, tool use counts, last active", params: [{ name: "id", in: "path", type: "string", required: true }] },
422
+ { cat: "AI Gym", method: "GET", path: "/api/agents/:id/logs", summary: "Paginated conversation logs (newest first)", params: [{ name: "id", in: "path", type: "string", required: true }, { name: "limit", in: "query", type: "number", desc: "Max entries (default 50)" }, { name: "offset", in: "query", type: "number", desc: "Starting offset (default 0)" }] },
423
+ { cat: "AI Gym", method: "GET", path: "/api/agents/logs/search", summary: "Full-text search across agent logs", params: [{ name: "q", in: "query", type: "string", required: true, desc: "Search keyword" }, { name: "agentIds", in: "query", type: "string", desc: "Comma-separated agent IDs to filter" }] },
424
+ { cat: "AI Gym", method: "POST", path: "/api/gym/digest/run", summary: "Manually trigger the activity digest (analyzes all agent activity, scores dimensions, generates cards)" },
425
+ { cat: "AI Gym", method: "GET", path: "/api/gym/feed", summary: "Aggregated feed: tips/nudges from gym cards, platform updates from changelog, AI briefing" },
426
+ { cat: "AI Gym", method: "GET", path: "/api/gym/config", summary: "Get public gym config flags (gymEnabled, gymOnlyMode, aibriefingEnabled)" },
427
+ { cat: "AI Gym", method: "GET", path: "/api/gym/guides", summary: "List all coach-created guides (programs with source=coach)" },
428
+ { cat: "AI Gym", method: "POST", path: "/api/gym/guides", summary: "Create a coach-generated guide from a training session", body: { title: { type: "string", required: true }, description: { type: "string" }, difficulty: { type: "string" }, dimensions: { type: "array" }, estimatedTime: { type: "string" }, modules: { type: "array" }, content: { type: "string" } } },
429
+ { cat: "AI Gym", method: "GET", path: "/api/gym/insights", summary: "Get pre-computed AI insights (generated weekly by the gym goal). Used by 'You tell me' mode." },
430
+ { cat: "AI Gym", method: "POST", path: "/api/gym/insights", summary: "Save AI-generated insights from weekly analysis", body: { insights: { type: "array", required: true, desc: "Array of { title, description, dimension?, agentId? }" }, topRecommendation: { type: "string", desc: "Single best recommendation" }, summary: { type: "string", desc: "Brief summary of observations" } } },
431
+
432
+ // -- Session Tabs --
433
+ { cat: "Sessions", method: "GET", path: "/api/agents/:agentId/session-tabs", summary: "List all named session tabs (includes closed, with last message preview)", params: [{ name: "agentId", in: "path", type: "string", required: true }] },
434
+ { cat: "Sessions", method: "POST", path: "/api/agents/:agentId/session-tabs", summary: "Create a named session tab (optionally routes to a different agent)", params: [{ name: "agentId", in: "path", type: "string", required: true }], body: { tabId: { type: "string", required: true, desc: "Unique slug (e.g. 'project-alpha')" }, label: { type: "string", required: true }, targetAgentId: { type: "string", desc: "Route tab messages to this agent instead" } } },
435
+ { cat: "Sessions", method: "PUT", path: "/api/agents/:agentId/session-tabs/:tabId", summary: "Rename a session tab", params: [{ name: "agentId", in: "path", type: "string", required: true }, { name: "tabId", in: "path", type: "string", required: true }], body: { label: { type: "string", required: true } } },
436
+ { cat: "Sessions", method: "DELETE", path: "/api/agents/:agentId/session-tabs/:tabId", summary: "Delete a session tab and its Claude session", params: [{ name: "agentId", in: "path", type: "string", required: true }, { name: "tabId", in: "path", type: "string", required: true }] },
437
+ { cat: "Sessions", method: "GET", path: "/api/agents/:agentId/session-tabs/:tabId/history", summary: "Get full conversation history for a session tab", params: [{ name: "agentId", in: "path", type: "string", required: true }, { name: "tabId", in: "path", type: "string", required: true }] },
438
+
439
+ // -- Profile --
440
+ { cat: "Profile", method: "GET", path: "/api/profile", summary: "Get the user's profile (name, role, industry, AI experience, interests)" },
441
+ { cat: "Profile", method: "PUT", path: "/api/profile", summary: "Update the user's profile", body: { name: { type: "string" }, role: { type: "string" }, industry: { type: "string" }, aiExperience: { type: "string", desc: "beginner | intermediate | advanced" }, interests: { type: "string[]" } } },
442
+
443
+ // -- Memory (continued) --
444
+ { cat: "Memory", method: "POST", path: "/api/agents/:agentId/memory/write", summary: "Write content to agent memory (context.md or daily journal)", params: [{ name: "agentId", in: "path", type: "string", required: true }], body: { content: { type: "string", required: true }, target: { type: "string", desc: "context | daily | overwrite (default: overwrite)" } } },
445
+
446
+ // -- Skills (continued) --
447
+ { cat: "Skills", method: "GET", path: "/api/skills/content", summary: "Read full content of a skill markdown file", params: [{ name: "path", in: "query", type: "string", required: true, desc: "Absolute path to skill .md file" }] },
448
+
449
+ // -- Files (continued) --
450
+ { cat: "Files", method: "POST", path: "/api/upload/:agentId/json", summary: "Upload a file via JSON (base64-encoded content)", params: [{ name: "agentId", in: "path", type: "string", required: true }], body: { fileName: { type: "string", required: true }, base64Content: { type: "string", required: true }, mode: { type: "string", desc: "temp | permanent (default: temp)" } } },
451
+
452
+ // -- Automations (continued) --
453
+ { cat: "Automations", method: "PUT", path: "/api/agents/:id/goals/:goalId", summary: "Update a goal's config", params: [{ name: "id", in: "path", type: "string", required: true }, { name: "goalId", in: "path", type: "string", required: true }], body: { description: { type: "string" }, successMetric: { type: "string" }, enabled: { type: "boolean" }, budget: { type: "number", desc: "Max daily USD" }, heartbeat: { type: "any" }, reportTargets: { type: "any" } } },
454
+ { cat: "Automations", method: "PUT", path: "/api/agents/:id/cron/:index", summary: "Update a cron job's schedule, message, or channel", params: [{ name: "id", in: "path", type: "string", required: true }, { name: "index", in: "path", type: "number", required: true }], body: { schedule: { type: "string" }, message: { type: "string" }, channel: { type: "string" }, chatId: { type: "string" }, enabled: { type: "boolean" } } },
455
+
456
+ // -- Config (continued) --
457
+ { cat: "Config", method: "POST", path: "/api/config/provider-test", summary: "Test an API key for a cloud provider", body: { provider: { type: "string", required: true, desc: "openai | grok | gemini | groq | together | mistral" } } },
458
+ { cat: "Config", method: "POST", path: "/api/restart", summary: "Restart the MyAgent gateway service" },
459
+
460
+ // -- Utility --
461
+ { cat: "Utility", method: "POST", path: "/api/open-folder", summary: "Open a folder in Finder (macOS), Explorer (Windows), or xdg-open (Linux)", body: { path: { type: "string", required: true, desc: "Absolute or ~ path to open" } } },
462
+
463
+ // -- Discovery --
464
+ { cat: "Discovery", method: "GET", path: "/api/capabilities", summary: "Structured summary of all platform capabilities by category" },
465
+ { cat: "Discovery", method: "GET", path: "/api/user-guide", summary: "Full platform user guide — every page, button, API, and MCP tool" },
466
+
467
+ // -- Drive --
468
+ { cat: "Drive", method: "GET", path: "/api/drive/browse", summary: "Browse files and folders in the PersonalAgents data drive", params: [{ name: "path", in: "query", type: "string", desc: "Path to browse (default: drive root)" }] },
469
+ { cat: "Drive", method: "GET", path: "/api/drive/read", summary: "Read a file from the PersonalAgents data drive (max 1MB)", params: [{ name: "path", in: "query", type: "string", required: true }] },
470
+ { cat: "Drive", method: "GET", path: "/api/drive/search", summary: "Full-text search across the PersonalAgents data drive", params: [{ name: "q", in: "query", type: "string", required: true }, { name: "path", in: "query", type: "string", desc: "Scope to subdirectory" }, { name: "limit", in: "query", type: "number", desc: "Max results (default 50)" }, { name: "types", in: "query", type: "string", desc: "Comma-separated extensions" }] },
471
+ ];
472
+
473
+ // ═══ MCP TOOL CATALOG ═══════════════════════════════════════════════
474
+ const TOOLS = [
475
+ // Dashboard
476
+ {cat:"Dashboard",name:"health_check",desc:"Check if the MyAgent gateway is running",params:[]},
477
+ {cat:"Dashboard",name:"get_dashboard",desc:"Get full dashboard: all agents, channels, accounts, uptime",params:[]},
478
+
479
+ // Agents
480
+ {cat:"Agents",name:"list_agents",desc:"List all agents, optionally filtered by organization",params:[{n:"org",t:"string",r:false,d:"Filter by organization name"}]},
481
+ {cat:"Agents",name:"get_agent",desc:"Get detailed info about a specific agent",params:[{n:"agentId",t:"string",r:true}]},
482
+ {cat:"Agents",name:"get_agent_instructions",desc:"Get an agent's CLAUDE.md system prompt",params:[{n:"agentId",t:"string",r:true}]},
483
+ {cat:"Agents",name:"create_agent",desc:"Create a new agent with full configuration",params:[{n:"agentId",t:"string",r:true,d:"Unique ID (lowercase, hyphens)"},{n:"name",t:"string",r:true},{n:"alias",t:"string",r:true,d:"e.g. @myagent"},{n:"description",t:"string",r:false},{n:"workspace",t:"string",r:false},{n:"organization",t:"string",r:false},{n:"function",t:"string",r:false},{n:"title",t:"string",r:false},{n:"persistent",t:"boolean",r:false},{n:"streaming",t:"boolean",r:false},{n:"advancedMemory",t:"boolean",r:false},{n:"autonomousCapable",t:"boolean",r:false},{n:"tools",t:"string[]",r:false},{n:"skills",t:"string[]",r:false},{n:"mcps",t:"string[]",r:false},{n:"prompts",t:"string[]",r:false},{n:"subAgents",t:"string[]|'*'",r:false,d:"Sub-agents for group agent"},{n:"claudeAccount",t:"string",r:false},{n:"timeout",t:"number",r:false,d:"Timeout in ms (default 14400000)"},{n:"heartbeatInstructions",t:"string",r:false,d:"Custom heartbeat instructions (saved to heartbeat.md)"},{n:"agentClass",t:"enum",r:false,d:"standard | platform | builder"},{n:"executor",t:"string",r:false,d:"Executor override: 'claude' (default) or 'ollama:<model>' (e.g. 'ollama:gemma2')"},{n:"wiki",t:"boolean",r:false,d:"Enable Wiki Learning"},{n:"wikiSync",t:"object",r:false,d:"{ enabled, schedule } — auto-merge learned facts"}]},
484
+ {cat:"Agents",name:"update_agent",desc:"Update an existing agent's configuration",params:[{n:"agentId",t:"string",r:true},{n:"name",t:"string",r:false},{n:"alias",t:"string",r:false},{n:"description",t:"string",r:false},{n:"workspace",t:"string",r:false},{n:"organization",t:"string",r:false,d:"Organization name"},{n:"function",t:"string",r:false,d:"Org function/department"},{n:"title",t:"string",r:false,d:"Org title/role"},{n:"reportsTo",t:"string",r:false,d:"Alias of reporting agent"},{n:"persistent",t:"boolean",r:false},{n:"streaming",t:"boolean",r:false},{n:"advancedMemory",t:"boolean",r:false},{n:"autonomousCapable",t:"boolean",r:false},{n:"tools",t:"string[]",r:false},{n:"skills",t:"string[]",r:false},{n:"mcps",t:"string[]",r:false},{n:"prompts",t:"string[]",r:false},{n:"subAgents",t:"string[]|'*'",r:false,d:"Sub-agents for group agent"},{n:"claudeAccount",t:"string",r:false},{n:"instructions",t:"string",r:false,d:"Update CLAUDE.md content"},{n:"timeout",t:"number",r:false},{n:"heartbeatInstructions",t:"string",r:false,d:"Custom heartbeat instructions (saved to heartbeat.md)"},{n:"agentClass",t:"enum",r:false,d:"standard | platform | builder"},{n:"executor",t:"string",r:false,d:"Executor override: 'claude' (default) or 'ollama:<model>'"},{n:"wiki",t:"boolean",r:false,d:"Enable Wiki Learning"},{n:"wikiSync",t:"object",r:false,d:"{ enabled, schedule } — auto-merge learned facts"}]},
485
+ {cat:"Agents",name:"delete_agent",desc:"Delete an agent",params:[{n:"agentId",t:"string",r:true}]},
486
+ {cat:"Agents",name:"recover_agent",desc:"Recover agent from session corruption",params:[{n:"agentId",t:"string",r:true}]},
487
+
488
+ // Chat
489
+ {cat:"Chat",name:"send_message",desc:"Send a message to an agent and get the response",params:[{n:"agentId",t:"string",r:true},{n:"text",t:"string",r:true},{n:"accountOverride",t:"string",r:false,d:"Use a different Claude account"}]},
490
+ {cat:"Chat",name:"delegate_message",desc:"Send a message between agents (inter-agent delegation)",params:[{n:"agentId",t:"string",r:true,d:"Target agent ID"},{n:"text",t:"string",r:true}]},
491
+
492
+ // Sessions
493
+ {cat:"Sessions",name:"list_sessions",desc:"List active conversation sessions for an agent",params:[{n:"agentId",t:"string",r:true}]},
494
+ {cat:"Sessions",name:"reset_session",desc:"Reset an agent's conversation session",params:[{n:"agentId",t:"string",r:true},{n:"senderId",t:"string",r:false,d:"Specific sender to reset"}]},
495
+ {cat:"Sessions",name:"delete_session",desc:"Delete a specific sender's session",params:[{n:"agentId",t:"string",r:true},{n:"senderId",t:"string",r:true}]},
496
+
497
+ // Model
498
+ {cat:"Model",name:"get_model",desc:"Get the current model override for an agent",params:[{n:"agentId",t:"string",r:true}]},
499
+ {cat:"Model",name:"set_model",desc:"Set a model override (opus, sonnet, haiku, or full ID)",params:[{n:"agentId",t:"string",r:true},{n:"model",t:"string",r:true,d:"opus | sonnet | haiku | full model ID"}]},
500
+ {cat:"Model",name:"clear_model",desc:"Clear model override, use agent default",params:[{n:"agentId",t:"string",r:true}]},
501
+
502
+ // Cost
503
+ {cat:"Cost",name:"get_agent_cost",desc:"Cost breakdown: today, week, all-time, by-day",params:[{n:"agentId",t:"string",r:true}]},
504
+ {cat:"Cost",name:"get_all_costs",desc:"Cost summary across ALL agents",params:[]},
505
+
506
+ // Skills
507
+ {cat:"Skills",name:"get_agent_skills",desc:"List all skills available to an agent (shared + org + agent)",params:[{n:"agentId",t:"string",r:true}]},
508
+ {cat:"Skills",name:"get_org_skills",desc:"List all skills in an organization",params:[{n:"orgName",t:"string",r:true}]},
509
+ {cat:"Skills",name:"create_skill",desc:"Create a skill file and register it in skills.json",params:[{n:"id",t:"string",r:true},{n:"name",t:"string",r:true},{n:"description",t:"string",r:true},{n:"content",t:"string",r:true},{n:"scope",t:"enum",r:true,d:"global | personal | org | agent"},{n:"orgName",t:"string",r:false,d:"Required if scope is org"},{n:"agentId",t:"string",r:false,d:"Required if scope is agent"}]},
510
+
511
+ // Tasks
512
+ {cat:"Tasks",name:"list_tasks",desc:"List tasks assigned to an agent",params:[{n:"agentId",t:"string",r:true}]},
513
+ {cat:"Tasks",name:"get_task_stats",desc:"Task statistics (counts by status)",params:[{n:"agentId",t:"string",r:true}]},
514
+ {cat:"Tasks",name:"create_task",desc:"Create a task for an agent",params:[{n:"agentId",t:"string",r:true},{n:"title",t:"string",r:true},{n:"description",t:"string",r:false},{n:"priority",t:"enum",r:false,d:"low | medium | high | critical"},{n:"project",t:"string",r:false}]},
515
+ {cat:"Tasks",name:"update_task",desc:"Update a task status or details",params:[{n:"agentId",t:"string",r:true},{n:"taskId",t:"string",r:true},{n:"status",t:"string",r:false},{n:"title",t:"string",r:false}]},
516
+ {cat:"Tasks",name:"delete_task",desc:"Delete a task",params:[{n:"agentId",t:"string",r:true},{n:"taskId",t:"string",r:true}]},
517
+ {cat:"Tasks",name:"get_all_tasks",desc:"Get all tasks across all agents",params:[]},
518
+ {cat:"Tasks",name:"create_project",desc:"Create a project for organizing tasks",params:[{n:"agentId",t:"string",r:true},{n:"name",t:"string",r:true}]},
519
+
520
+ // Automations
521
+ {cat:"Automations",name:"list_automations",desc:"List all goals and crons across all agents",params:[]},
522
+ {cat:"Automations",name:"create_goal",desc:"Create an autonomous goal for an agent",params:[{n:"agentId",t:"string",r:true},{n:"id",t:"string",r:true},{n:"description",t:"string",r:true},{n:"heartbeat",t:"string",r:true,d:"Cron expression"},{n:"successCriteria",t:"string",r:false},{n:"instructions",t:"string",r:false}]},
523
+ {cat:"Automations",name:"toggle_goal",desc:"Enable or disable a goal",params:[{n:"agentId",t:"string",r:true},{n:"goalId",t:"string",r:true}]},
524
+ {cat:"Automations",name:"trigger_goal",desc:"Manually trigger a goal run",params:[{n:"agentId",t:"string",r:true},{n:"goalId",t:"string",r:true}]},
525
+ {cat:"Automations",name:"get_goal_history",desc:"Get run history for a goal",params:[{n:"agentId",t:"string",r:true},{n:"goalId",t:"string",r:true}]},
526
+ {cat:"Automations",name:"delete_goal",desc:"Delete a goal",params:[{n:"agentId",t:"string",r:true},{n:"goalId",t:"string",r:true}]},
527
+ {cat:"Automations",name:"create_cron",desc:"Create a scheduled cron job",params:[{n:"agentId",t:"string",r:true},{n:"schedule",t:"string",r:true,d:"Cron expression"},{n:"message",t:"string",r:true},{n:"channel",t:"string",r:true},{n:"chatId",t:"string",r:true},{n:"enabled",t:"boolean",r:false}]},
528
+ {cat:"Automations",name:"toggle_cron",desc:"Enable or disable a cron job",params:[{n:"agentId",t:"string",r:true},{n:"index",t:"number",r:true}]},
529
+ {cat:"Automations",name:"trigger_cron",desc:"Manually trigger a cron run",params:[{n:"agentId",t:"string",r:true},{n:"index",t:"number",r:true}]},
530
+ {cat:"Automations",name:"get_cron_history",desc:"Get run history for a cron",params:[{n:"agentId",t:"string",r:true},{n:"index",t:"number",r:true}]},
531
+ {cat:"Automations",name:"delete_cron",desc:"Delete a cron job",params:[{n:"agentId",t:"string",r:true},{n:"index",t:"number",r:true}]},
532
+
533
+ // MCPs
534
+ {cat:"MCPs",name:"list_mcps",desc:"List registered MCP servers",params:[]},
535
+ {cat:"MCPs",name:"get_mcp_catalog",desc:"Get the pre-hosted MCP catalog",params:[]},
536
+ {cat:"MCPs",name:"list_mcp_keys",desc:"List MCP API keys for an agent",params:[{n:"agentId",t:"string",r:true}]},
537
+ {cat:"MCPs",name:"save_mcp_key",desc:"Save an MCP API key",params:[{n:"agentId",t:"string",r:true},{n:"mcpName",t:"string",r:true},{n:"envVar",t:"string",r:true,d:"Environment variable name (e.g. GMAIL_ACCESS_TOKEN)"},{n:"value",t:"string",r:true,d:"Secret value"}]},
538
+ {cat:"MCPs",name:"delete_mcp_key",desc:"Delete an MCP API key",params:[{n:"agentId",t:"string",r:true},{n:"mcpName",t:"string",r:true}]},
539
+ {cat:"MCPs",name:"list_mcp_connections",desc:"List MCP connections for an agent",params:[{n:"agentId",t:"string",r:true}]},
540
+ {cat:"MCPs",name:"create_mcp_connection",desc:"Create an MCP connection instance (instanceName auto-generated)",params:[{n:"agentId",t:"string",r:true},{n:"baseMcp",t:"string",r:true,d:"Base MCP server name from registry"},{n:"label",t:"string",r:true,d:"Human-readable label"},{n:"envVar",t:"string",r:true,d:"Environment variable name"},{n:"value",t:"string",r:true,d:"Secret value"},{n:"description",t:"string",r:false}]},
541
+ {cat:"MCPs",name:"delete_mcp_connection",desc:"Delete an MCP connection",params:[{n:"agentId",t:"string",r:true},{n:"instanceName",t:"string",r:true}]},
542
+
543
+ // Channels
544
+ {cat:"Channels",name:"list_channels",desc:"List all messaging channels with config and routes",params:[]},
545
+ {cat:"Channels",name:"update_channel",desc:"Update channel settings (sticky routing, enabled)",params:[{n:"channelName",t:"string",r:true},{n:"enabled",t:"boolean",r:false},{n:"stickyRouting",t:"enum",r:false,d:"none | sticky | prefix"},{n:"stickyPrefix",t:"string",r:false},{n:"stickyTimeoutMs",t:"number",r:false}]},
546
+ {cat:"Channels",name:"add_agent_route",desc:"Add an agent route to a channel",params:[{n:"channelName",t:"string",r:true},{n:"agentId",t:"string",r:true},{n:"chatId",t:"string",r:true},{n:"requireMention",t:"boolean",r:false},{n:"allowFrom",t:"string[]",r:false}]},
547
+ {cat:"Channels",name:"remove_agent_route",desc:"Remove an agent's route from a channel",params:[{n:"channelName",t:"string",r:true},{n:"agentId",t:"string",r:true}]},
548
+ {cat:"Channels",name:"add_monitored_chat",desc:"Add a monitored chat ID",params:[{n:"channelName",t:"string",r:true},{n:"chatId",t:"string",r:true}]},
549
+ {cat:"Channels",name:"remove_monitored_chat",desc:"Remove a monitored chat",params:[{n:"channelName",t:"string",r:true},{n:"chatId",t:"string",r:true}]},
550
+ {cat:"Channels",name:"get_sticky_routing",desc:"Get sticky routing config for all channels",params:[]},
551
+
552
+ // Activity & Logs
553
+ {cat:"Activity",name:"get_activity",desc:"Get recent activity feed across all agents",params:[{n:"limit",t:"number",r:false}]},
554
+ {cat:"Activity",name:"get_agent_logs",desc:"Paginated conversation logs with search",params:[{n:"agentId",t:"string",r:true},{n:"limit",t:"number",r:false},{n:"offset",t:"number",r:false},{n:"search",t:"string",r:false,d:"Keyword filter"}]},
555
+
556
+ // Memory
557
+ {cat:"Memory",name:"get_agent_memory",desc:"List memory entries (context.md + daily files)",params:[{n:"agentId",t:"string",r:true},{n:"limit",t:"number",r:false}]},
558
+ {cat:"Memory",name:"search_memory",desc:"Search an agent's memory by keyword",params:[{n:"agentId",t:"string",r:true},{n:"query",t:"string",r:true}]},
559
+ {cat:"Memory",name:"clear_memory_context",desc:"Clear an agent's context.md",params:[{n:"agentId",t:"string",r:true}]},
560
+
561
+ // Pairing
562
+ {cat:"Pairing",name:"list_paired_senders",desc:"List paired/authorized senders",params:[]},
563
+ {cat:"Pairing",name:"pair_sender",desc:"Manually authorize a sender",params:[{n:"senderKey",t:"string",r:true,d:"Format: channel:senderId"}]},
564
+ {cat:"Pairing",name:"unpair_sender",desc:"Remove an authorized sender",params:[{n:"senderKey",t:"string",r:true}]},
565
+
566
+ // Config
567
+ {cat:"Config",name:"list_accounts",desc:"List Claude accounts (name -> config dir)",params:[]},
568
+ {cat:"Config",name:"add_account",desc:"Add a Claude account",params:[{n:"name",t:"string",r:true},{n:"path",t:"string",r:true,d:"Config dir (e.g. ~/.claude)"}]},
569
+ {cat:"Config",name:"delete_account",desc:"Remove a Claude account",params:[{n:"name",t:"string",r:true}]},
570
+ {cat:"Config",name:"check_account_status",desc:"Check if account is authenticated",params:[{n:"name",t:"string",r:true}]},
571
+ {cat:"Config",name:"start_account_login",desc:"Start OAuth login — returns URL",params:[{n:"name",t:"string",r:true},{n:"path",t:"string",r:true}]},
572
+ {cat:"Config",name:"get_service_config",desc:"Get service settings",params:[]},
573
+ {cat:"Config",name:"update_service_config",desc:"Update service settings (restart required)",params:[{n:"personalAgentsDir",t:"string",r:false},{n:"personalRegistryDir",t:"string",r:false},{n:"webUIPort",t:"number",r:false},{n:"logLevel",t:"string",r:false},{n:"logFile",t:"string",r:false},{n:"pairingCode",t:"string",r:false},{n:"webhookSecret",t:"string",r:false}]},
574
+
575
+ // Apps
576
+ {cat:"Apps",name:"list_apps",desc:"List all registered apps",params:[]},
577
+ {cat:"Apps",name:"create_app",desc:"Register a new app",params:[{n:"name",t:"string",r:true},{n:"url",t:"string",r:false},{n:"provider",t:"string",r:false},{n:"category",t:"string",r:false},{n:"githubRepo",t:"string",r:false}]},
578
+ {cat:"Apps",name:"update_app",desc:"Update an existing app",params:[{n:"id",t:"string",r:true},{n:"name",t:"string",r:false},{n:"url",t:"string",r:false}]},
579
+ {cat:"Apps",name:"delete_app",desc:"Delete an app",params:[{n:"id",t:"string",r:true}]},
580
+ {cat:"Apps",name:"check_app_health",desc:"Check app health/status",params:[{n:"id",t:"string",r:true}]},
581
+
582
+ // Files
583
+ {cat:"Files",name:"list_agent_files",desc:"List files in an agent's FileStorage",params:[{n:"agentId",t:"string",r:true}]},
584
+ {cat:"Files",name:"download_agent_file",desc:"Download a file from an agent's file storage",params:[{n:"agentId",t:"string",r:true},{n:"path",t:"string",r:true,d:"File path within agent storage"}]},
585
+
586
+ // Registry
587
+ {cat:"Registry",name:"browse_registry",desc:"Browse marketplace by type",params:[{n:"type",t:"enum",r:true,d:"skills | agents | mcps | prompts | apps"}]},
588
+ {cat:"Registry",name:"install_registry_item",desc:"Install a skill/MCP/agent from registry",params:[{n:"id",t:"string",r:true},{n:"type",t:"string",r:true}]},
589
+ {cat:"Registry",name:"assign_to_agent",desc:"Assign a skill or MCP to an agent",params:[{n:"agentId",t:"string",r:true},{n:"itemId",t:"string",r:true},{n:"type",t:"string",r:true,d:"skill or mcp"}]},
590
+ {cat:"Registry",name:"scan_skills",desc:"Scan directory for unregistered skills",params:[{n:"dir",t:"string",r:false}]},
591
+ {cat:"Registry",name:"create_prompt",desc:"Create a prompt template",params:[{n:"id",t:"string",r:true},{n:"name",t:"string",r:true},{n:"content",t:"string",r:true}]},
592
+ {cat:"Registry",name:"add_mcp_to_registry",desc:"Add MCP server to registry",params:[{n:"id",t:"string",r:true},{n:"name",t:"string",r:true},{n:"type",t:"string",r:true},{n:"url",t:"string",r:false}]},
593
+
594
+ // Registry (continued)
595
+ {cat:"Registry",name:"set_platform_default",desc:"Set a marketplace item as the platform default",params:[{n:"type",t:"string",r:true,d:"Item type (skill, mcp, prompt)"},{n:"id",t:"string",r:true,d:"Item ID"}]},
596
+ {cat:"Registry",name:"import_skills",desc:"Import scanned skills into an agent",params:[{n:"agentId",t:"string",r:true},{n:"skills",t:"string[]",r:true,d:"Skill names to import"}]},
597
+ {cat:"Registry",name:"get_prompt_trigger",desc:"Get the current prompt trigger character",params:[]},
598
+ {cat:"Registry",name:"set_prompt_trigger",desc:"Set the prompt trigger character",params:[{n:"trigger",t:"string",r:true,d:"Trigger character (e.g. / or !)"}]},
599
+
600
+ // Config (continued)
601
+ {cat:"Config",name:"submit_login_code",desc:"Submit authentication code for account login",params:[{n:"accountName",t:"string",r:true},{n:"code",t:"string",r:true,d:"Auth code from OAuth flow"}]},
602
+
603
+ // Chat (continued)
604
+ {cat:"Chat",name:"get_chat_job_raw",desc:"Get raw output lines from a streaming chat job",params:[{n:"jobId",t:"string",r:true,d:"Job ID from startStream"},{n:"after",t:"number",r:false,d:"Line index to start from"}]},
605
+
606
+ // Dashboard (continued)
607
+ {cat:"Dashboard",name:"get_agent_registry",desc:"Get the agent registry with delegation keywords",params:[]},
608
+
609
+ // Lab
610
+ {cat:"Lab",name:"get_platform_agents",desc:"List platform-managed creator agents (used by Lab)",params:[]},
611
+ {cat:"Lab",name:"browse_dirs",desc:"Browse subdirectories of a given path (for Lab directory picker)",params:[{n:"path",t:"string",r:false,d:"Directory path (defaults to home dir, supports ~ prefix)"}]},
612
+
613
+ // Heartbeat
614
+ {cat:"Agents",name:"trigger_heartbeat",desc:"Trigger a heartbeat check for an agent (runs async, returns immediately)",params:[{n:"agentId",t:"string",r:true},{n:"triggeredBy",t:"string",r:false,d:"Label for trigger source (default: manual)"}]},
615
+ {cat:"Agents",name:"get_heartbeat_history",desc:"Get recent heartbeat run history for an agent",params:[{n:"agentId",t:"string",r:true},{n:"limit",t:"number",r:false,d:"Max entries (default 20)"}]},
616
+
617
+ // Wiki Sync
618
+ {cat:"Agents",name:"trigger_wiki_sync",desc:"Trigger wiki sync for an agent (merges learned.md into context.md)",params:[{n:"agentId",t:"string",r:true}]},
619
+ {cat:"Agents",name:"get_wiki_sync_history",desc:"Get wiki sync execution history for an agent",params:[{n:"agentId",t:"string",r:true},{n:"limit",t:"number",r:false,d:"Max entries (default 20)"}]},
620
+
621
+ // Whoami
622
+ {cat:"Agents",name:"whoami",desc:"Get Claude auth status for the account an agent uses",params:[{n:"agentId",t:"string",r:true}]},
623
+
624
+ // Changelog
625
+ {cat:"Dashboard",name:"get_changelog",desc:"Get recent changelog parsed from git history (grouped by date)",params:[]},
626
+
627
+ // xbar
628
+ {cat:"Config",name:"install_xbar",desc:"Install xbar status bar plugin (macOS only)",params:[]},
629
+
630
+ // Chat Streaming
631
+ {cat:"Chat",name:"start_stream",desc:"Start a streaming chat — returns jobId to poll with get_chat_job_raw",params:[{n:"agentId",t:"string",r:true},{n:"text",t:"string",r:true},{n:"accountOverride",t:"string",r:false,d:"Use a different Claude account"}]},
632
+ {cat:"Chat",name:"stop_chat_job",desc:"Stop a running chat job",params:[{n:"jobId",t:"string",r:true,d:"Job ID from start_stream"}]},
633
+
634
+ // Webhook
635
+ {cat:"Chat",name:"send_webhook",desc:"Send a message to an agent via webhook (external trigger)",params:[{n:"agentId",t:"string",r:true},{n:"text",t:"string",r:true},{n:"secret",t:"string",r:false,d:"Webhook secret (x-webhook-secret header)"},{n:"channel",t:"string",r:false,d:"Override reply channel"},{n:"chatId",t:"string",r:false,d:"Override reply chat ID"}]},
636
+
637
+ // Session Tabs
638
+ {cat:"Sessions",name:"create_session_tab",desc:"Create a named session tab on an agent's chat page, optionally routing to a different agent",params:[{n:"agentId",t:"string",r:true,d:"Agent whose chat page hosts the tab"},{n:"tabId",t:"string",r:true,d:"Unique tab slug"},{n:"label",t:"string",r:true},{n:"targetAgentId",t:"string",r:false,d:"Route messages to this agent instead"}]},
639
+ {cat:"Sessions",name:"list_session_tabs",desc:"List all named session tabs (includes closed sessions with last message preview)",params:[{n:"agentId",t:"string",r:true}]},
640
+ {cat:"Sessions",name:"get_session_tab_history",desc:"Get full conversation history for a specific session tab",params:[{n:"agentId",t:"string",r:true},{n:"tabId",t:"string",r:true}]},
641
+ {cat:"Sessions",name:"rename_session_tab",desc:"Rename a session tab",params:[{n:"agentId",t:"string",r:true},{n:"tabId",t:"string",r:true},{n:"label",t:"string",r:true}]},
642
+ {cat:"Sessions",name:"delete_session_tab",desc:"Permanently delete a session tab and its Claude session state",params:[{n:"agentId",t:"string",r:true},{n:"tabId",t:"string",r:true}]},
643
+
644
+ // Profile
645
+ {cat:"Profile",name:"get_profile",desc:"Get the user's profile (name, role, industry, AI experience, interests)",params:[]},
646
+ {cat:"Profile",name:"update_profile",desc:"Update the user's profile",params:[{n:"name",t:"string",r:false},{n:"role",t:"string",r:false},{n:"industry",t:"string",r:false},{n:"aiExperience",t:"enum",r:false,d:"beginner | intermediate | advanced"},{n:"interests",t:"string[]",r:false}]},
647
+
648
+ // Memory (continued)
649
+ {cat:"Memory",name:"write_memory",desc:"Write content to an agent's memory (context.md or daily journal)",params:[{n:"agentId",t:"string",r:true},{n:"content",t:"string",r:true},{n:"target",t:"enum",r:false,d:"context | daily | overwrite (default: overwrite)"}]},
650
+
651
+ // Skills (continued)
652
+ {cat:"Skills",name:"get_skill_content",desc:"Read the full content of a skill markdown file",params:[{n:"path",t:"string",r:true,d:"Absolute path to the skill .md file"}]},
653
+
654
+ // Files (continued)
655
+ {cat:"Files",name:"upload_file",desc:"Upload a file to an agent's FileStorage (base64-encoded)",params:[{n:"agentId",t:"string",r:true},{n:"fileName",t:"string",r:true},{n:"base64Content",t:"string",r:true},{n:"mode",t:"enum",r:false,d:"temp | permanent (default: temp)"}]},
656
+
657
+ // Automations (continued)
658
+ {cat:"Automations",name:"update_goal",desc:"Update an existing goal's configuration",params:[{n:"agentId",t:"string",r:true},{n:"goalId",t:"string",r:true},{n:"description",t:"string",r:false},{n:"successMetric",t:"string",r:false},{n:"enabled",t:"boolean",r:false},{n:"budget",t:"number",r:false,d:"Max daily USD"},{n:"heartbeat",t:"any",r:false},{n:"reportTargets",t:"any",r:false}]},
659
+ {cat:"Automations",name:"update_cron",desc:"Update an existing cron job's schedule, message, or channel",params:[{n:"agentId",t:"string",r:true},{n:"index",t:"number",r:true},{n:"schedule",t:"string",r:false},{n:"message",t:"string",r:false},{n:"channel",t:"string",r:false},{n:"chatId",t:"string",r:false},{n:"enabled",t:"boolean",r:false}]},
660
+
661
+ // Config (continued)
662
+ {cat:"Config",name:"test_provider",desc:"Test an API key for a cloud provider (OpenAI, Grok, Gemini, Groq, Together, Mistral)",params:[{n:"provider",t:"string",r:true,d:"openai | grok | gemini | groq | together | mistral"}]},
663
+ {cat:"Config",name:"restart_service",desc:"Restart the MyAgent gateway service",params:[]},
664
+
665
+ // Discovery
666
+ {cat:"Discovery",name:"list_capabilities",desc:"Get a structured summary of all platform capabilities grouped by category",params:[]},
667
+ {cat:"Discovery",name:"get_user_guide",desc:"Get the full platform user guide — every page, button, API, and MCP tool documented",params:[]},
668
+
669
+ // Drive
670
+ {cat:"Drive",name:"browse_drive",desc:"Browse files and folders in the PersonalAgents data drive",params:[{n:"path",t:"string",r:false,d:"Path to browse (default: drive root)"}]},
671
+ {cat:"Drive",name:"read_drive_file",desc:"Read a file from the PersonalAgents data drive (max 1MB)",params:[{n:"path",t:"string",r:true,d:"Absolute path to the file"}]},
672
+ {cat:"Drive",name:"search_drive",desc:"Full-text search across the PersonalAgents data drive",params:[{n:"q",t:"string",r:true},{n:"path",t:"string",r:false,d:"Scope to subdirectory"},{n:"limit",t:"number",r:false,d:"Max results (default 50)"},{n:"types",t:"string",r:false,d:"Comma-separated extensions"}]},
673
+
674
+ // AI Gym — Learner Profile
675
+ {cat:"AI Gym",name:"get_learner_profile",desc:"Get the learner's AI Gym profile including dimensions, streak, trainer selection, and programs",params:[]},
676
+ {cat:"AI Gym",name:"update_learner_profile",desc:"Update fields in the learner profile",params:[{n:"data",t:"object",r:true,d:"Fields to merge into the learner profile"}]},
677
+
678
+ // AI Gym — Plan
679
+ {cat:"AI Gym",name:"get_plan",desc:"Get the learner's training plan (on-the-job + platform-driven buckets)",params:[]},
680
+ {cat:"AI Gym",name:"update_plan",desc:"Write an updated training plan",params:[{n:"data",t:"object",r:true,d:"Full plan to write"}]},
681
+
682
+ // AI Gym — Progress
683
+ {cat:"AI Gym",name:"get_gym_progress",desc:"Get program completion progress for all programs",params:[]},
684
+ {cat:"AI Gym",name:"update_gym_progress",desc:"Update program progress",params:[{n:"data",t:"object",r:true,d:"Progress keyed by program slug"}]},
685
+
686
+ // AI Gym — Cards
687
+ {cat:"AI Gym",name:"list_gym_cards",desc:"List all active gym cards (recommendations, tips, nudges)",params:[]},
688
+ {cat:"AI Gym",name:"create_gym_card",desc:"Create a gym card with a recommendation or tip",params:[{n:"title",t:"string",r:true},{n:"description",t:"string",r:true},{n:"type",t:"string",r:true},{n:"cta",t:"string",r:false,d:"Call-to-action text"},{n:"ctaAction",t:"string",r:false}]},
689
+ {cat:"AI Gym",name:"dismiss_gym_card",desc:"Remove a gym card",params:[{n:"id",t:"string",r:true}]},
690
+
691
+ // AI Gym — Dimensions
692
+ {cat:"AI Gym",name:"snapshot_dimensions",desc:"Save a weekly dimension score snapshot",params:[{n:"date",t:"string",r:false,d:"Snapshot date (defaults to today)"},{n:"dimensions",t:"object",r:true,d:"Object with score per dimension"}]},
693
+ {cat:"AI Gym",name:"get_dimension_history",desc:"Get all weekly dimension score snapshots",params:[]},
694
+
695
+ // AI Gym — Programs
696
+ {cat:"AI Gym",name:"list_gym_programs",desc:"List all available training programs",params:[]},
697
+ {cat:"AI Gym",name:"get_gym_program",desc:"Get a program with full modules and steps",params:[{n:"slug",t:"string",r:true}]},
698
+ {cat:"AI Gym",name:"import_program",desc:"Import a program from markdown (H1=program, H2=module, H3=step)",params:[{n:"markdown",t:"string",r:true}]},
699
+ {cat:"AI Gym",name:"update_gym_program",desc:"Update a program's metadata",params:[{n:"slug",t:"string",r:true},{n:"body",t:"object",r:true}]},
700
+ {cat:"AI Gym",name:"delete_gym_program",desc:"Delete a training program",params:[{n:"slug",t:"string",r:true}]},
701
+
702
+ // AI Gym — Agent Activity
703
+ {cat:"AI Gym",name:"get_agent_activity_summary",desc:"Get aggregated activity stats for an agent",params:[{n:"agentId",t:"string",r:true}]},
704
+ {cat:"AI Gym",name:"search_agent_logs",desc:"Full-text search across agent conversation logs",params:[{n:"q",t:"string",r:true},{n:"agentIds",t:"string",r:false,d:"Comma-separated agent IDs"}]},
705
+
706
+ // AI Gym — Digest
707
+ {cat:"AI Gym",name:"run_gym_digest",desc:"Manually trigger the activity digest (analyzes all activity, scores dimensions, generates cards)",params:[]},
708
+ ];
709
+
710
+ // ═══ STATE ═══════════════════════════════════════════════════════════
711
+ let activeTab = 'api'; // 'api' | 'mcp'
712
+ let currentView = 'overview'; // overview | endpoint | history
713
+ let selectedEp = null;
714
+ let selectedTool = null;
715
+ let apiHistory = JSON.parse(localStorage.getItem('api-docs-history') || '[]');
716
+
717
+ // ═══ INIT ════════════════════════════════════════════════════════════
718
+ function init() {
719
+ applyTheme(localStorage.getItem('api-docs-theme') || 'dark');
720
+ // Check URL hash
721
+ const hash = window.location.hash.replace('#','');
722
+ if (hash === 'mcp') {
723
+ switchTab('mcp');
724
+ } else {
725
+ switchTab('api');
726
+ }
727
+ }
728
+
729
+ // ═══ THEME ═══════════════════════════════════════════════════════════
730
+ function applyTheme(t) { document.documentElement.setAttribute('data-theme', t); localStorage.setItem('api-docs-theme', t); }
731
+ function toggleTheme() { applyTheme(document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark'); }
732
+
733
+ // ═══ TAB SWITCHING ═══════════════════════════════════════════════════
734
+ function switchTab(tab) {
735
+ activeTab = tab;
736
+ window.location.hash = tab;
737
+
738
+ // Tab buttons
739
+ const tabApi = document.getElementById('tabApi');
740
+ const tabMcp = document.getElementById('tabMcp');
741
+ tabApi.className = 'top-tab' + (tab === 'api' ? ' active-api' : '');
742
+ tabMcp.className = 'top-tab' + (tab === 'mcp' ? ' active-mcp' : '');
743
+
744
+ // Sidebar content
745
+ document.getElementById('apiSidebarContent').classList.toggle('active', tab === 'api');
746
+ document.getElementById('mcpSidebarContent').classList.toggle('active', tab === 'mcp');
747
+
748
+ // Main panels
749
+ document.getElementById('apiMain').style.display = tab === 'api' ? '' : 'none';
750
+ document.getElementById('mcpMain').style.display = tab === 'mcp' ? '' : 'none';
751
+
752
+ if (tab === 'api') {
753
+ renderApiSidebar();
754
+ showOverview();
755
+ } else {
756
+ renderMcpSidebar();
757
+ showMcpOverview();
758
+ }
759
+ }
760
+
761
+ // ═══ UTILS ═══════════════════════════════════════════════════════════
762
+ function esc(s) { return String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;'); }
763
+ function copyText(t) { navigator.clipboard.writeText(t).catch(() => {}); }
764
+
765
+ function setApiNav(id) {
766
+ document.querySelectorAll('#apiNav a').forEach(a => { a.className = a.className.replace(/active-api/g,'').trim(); });
767
+ if (id) document.getElementById(id)?.classList.add('active-api');
768
+ }
769
+ function setMcpNav(id) {
770
+ document.querySelectorAll('#mcpNav a').forEach(a => { a.className = a.className.replace(/active-mcp/g,'').trim(); });
771
+ if (id) document.getElementById(id)?.classList.add('active-mcp');
772
+ }
773
+
774
+ // ═══════════════════════════════════════════════════════════════════
775
+ // REST API TAB
776
+ // ═══════════════════════════════════════════════════════════════════
777
+
778
+ function getApiCategories() {
779
+ const cats = {};
780
+ CATALOG.forEach(ep => { if (!cats[ep.cat]) cats[ep.cat] = []; cats[ep.cat].push(ep); });
781
+ return cats;
782
+ }
783
+
784
+ function renderApiSidebar(filter) {
785
+ const cats = getApiCategories();
786
+ const q = (filter || '').toLowerCase();
787
+ let html = '';
788
+ for (const [cat, eps] of Object.entries(cats)) {
789
+ const filtered = q ? eps.filter(e => e.path.toLowerCase().includes(q) || e.summary.toLowerCase().includes(q) || e.method.toLowerCase().includes(q)) : eps;
790
+ if (filtered.length === 0) continue;
791
+ const isOpen = q || (selectedEp && selectedEp.cat === cat);
792
+ html += `<div class="cat-group">
793
+ <div class="cat-header${isOpen ? ' open' : ''}" onclick="this.classList.toggle('open')">
794
+ <span class="arrow">&#9656;</span> ${esc(cat)} <span class="count">${filtered.length}</span>
795
+ </div>
796
+ <div class="cat-items">
797
+ ${filtered.map(ep => {
798
+ const idx = CATALOG.indexOf(ep);
799
+ const active = selectedEp === ep ? ' active' : '';
800
+ return `<div class="ep-item${active}" onclick="selectEndpoint(${idx})">
801
+ <span class="method-badge method-${ep.method}">${ep.method}</span>
802
+ <span class="ep-path">${esc(ep.path)}</span>
803
+ </div>`;
804
+ }).join('')}
805
+ </div>
806
+ </div>`;
807
+ }
808
+ document.getElementById('apiSidebarBody').innerHTML = html;
809
+ }
810
+
811
+ function filterEndpoints() { renderApiSidebar(document.getElementById('apiSearch').value); }
812
+
813
+ // ── API Overview ──
814
+ function showOverview() {
815
+ currentView = 'overview';
816
+ selectedEp = null;
817
+ setApiNav('navOverview');
818
+ renderApiSidebar();
819
+ const cats = getApiCategories();
820
+ const catNames = Object.keys(cats);
821
+ document.getElementById('apiMain').innerHTML = `
822
+ <div class="overview">
823
+ <h1>MyAIforOne API</h1>
824
+ <div class="subtitle">Multi-channel agent gateway — ${CATALOG.length} endpoints across ${catNames.length} domains</div>
825
+ <div class="stat-row">
826
+ <div class="stat-card"><div class="stat-val">${CATALOG.length}</div><div class="stat-label">Endpoints</div></div>
827
+ <div class="stat-card"><div class="stat-val">${catNames.length}</div><div class="stat-label">Categories</div></div>
828
+ <div class="stat-card"><div class="stat-val">${CATALOG.filter(e=>e.method==='GET').length}</div><div class="stat-label">GET</div></div>
829
+ <div class="stat-card"><div class="stat-val">${CATALOG.filter(e=>e.method==='POST').length}</div><div class="stat-label">POST</div></div>
830
+ <div class="stat-card"><div class="stat-val">${CATALOG.filter(e=>e.method==='PUT').length}</div><div class="stat-label">PUT</div></div>
831
+ <div class="stat-card"><div class="stat-val">${CATALOG.filter(e=>e.method==='DELETE').length}</div><div class="stat-label">DELETE</div></div>
832
+ </div>
833
+ <div style="font-size:12px;color:var(--text-dim);margin-bottom:10px;font-weight:600">CATEGORIES</div>
834
+ <div class="cat-grid">
835
+ ${catNames.map(c => `<div class="cat-card" onclick="jumpToApiCat('${c}')">
836
+ <div class="cat-card-name">${esc(c)}</div>
837
+ <div class="cat-card-count">${cats[c].length} endpoint${cats[c].length>1?'s':''}</div>
838
+ </div>`).join('')}
839
+ </div>
840
+ <div style="margin-top:24px;padding:16px;border-radius:10px;border:1px solid var(--border);background:var(--card)">
841
+ <div style="font-size:12px;font-weight:700;color:var(--accent);margin-bottom:8px">Authentication</div>
842
+ <div style="font-size:12px;color:var(--text-dim);line-height:1.8">
843
+ This API runs on <code style="font-family:var(--mono);background:var(--input);padding:1px 5px;border-radius:3px">localhost</code> and has <strong>no authentication</strong> by default.
844
+ All endpoints are accessible without tokens. When deploying remotely, add auth middleware.
845
+ </div>
846
+ </div>
847
+ </div>`;
848
+ }
849
+
850
+ function jumpToApiCat(cat) {
851
+ const eps = CATALOG.filter(e => e.cat === cat);
852
+ if (eps.length) selectEndpoint(CATALOG.indexOf(eps[0]));
853
+ }
854
+
855
+ // ── Endpoint Detail ──
856
+ function selectEndpoint(idx) {
857
+ selectedEp = CATALOG[idx];
858
+ currentView = 'endpoint';
859
+ setApiNav(null);
860
+ renderApiSidebar(document.getElementById('apiSearch').value);
861
+ renderEndpoint(selectedEp);
862
+ }
863
+
864
+ function renderEndpoint(ep) {
865
+ const pathParams = (ep.params || []).filter(p => p.in === 'path');
866
+ const queryParams = (ep.params || []).filter(p => p.in === 'query');
867
+ const hasBody = ep.body && Object.keys(ep.body).length > 0;
868
+
869
+ let html = `<div class="ep-detail">
870
+ <div class="ep-detail-header">
871
+ <span class="method-badge method-${ep.method}">${ep.method}</span>
872
+ <span class="ep-detail-path">${esc(ep.path)}</span>
873
+ </div>
874
+ <div class="ep-detail-summary">${esc(ep.summary)}</div>`;
875
+
876
+ if (pathParams.length) {
877
+ html += `<div class="section"><div class="section-title">Path Parameters</div><div class="section-body">
878
+ ${pathParams.map(p => `<div class="param-row">
879
+ <span class="param-label">${esc(p.name)} ${p.required ? '<span class="param-req">required</span>' : ''}</span>
880
+ <input class="param-input" id="param-${p.name}" placeholder="${esc(p.desc || p.type || 'value')}" data-param="${p.name}">
881
+ <span class="param-type">${esc(p.type || 'string')}</span>
882
+ </div>`).join('')}
883
+ </div></div>`;
884
+ }
885
+
886
+ if (queryParams.length) {
887
+ html += `<div class="section"><div class="section-title">Query Parameters</div><div class="section-body">
888
+ ${queryParams.map(p => `<div class="param-row">
889
+ <span class="param-label">${esc(p.name)}</span>
890
+ <input class="param-input" id="query-${p.name}" placeholder="${esc(p.desc || p.type || 'optional')}" data-query="${p.name}">
891
+ <span class="param-type">${esc(p.type || 'string')}</span>
892
+ </div>`).join('')}
893
+ </div></div>`;
894
+ }
895
+
896
+ if (hasBody) {
897
+ const example = {};
898
+ for (const [k, v] of Object.entries(ep.body)) {
899
+ if (v.example !== undefined) example[k] = v.example;
900
+ else if (v.type === 'boolean') example[k] = v.default ?? true;
901
+ else if (v.type === 'number') example[k] = v.default ?? 0;
902
+ else if (v.enum) example[k] = v.enum[0];
903
+ else example[k] = v.default ?? '';
904
+ }
905
+ html += `<div class="section"><div class="section-title">Request Body</div><div class="section-body">
906
+ <div style="margin-bottom:8px;font-size:10px;color:var(--text-muted)">
907
+ ${Object.entries(ep.body).map(([k, v]) => `<span style="margin-right:12px"><code style="font-family:var(--mono);color:var(--accent)">${k}</code> <span style="color:var(--text-muted)">${v.type}${v.required ? ' &middot; required' : ''}${v.desc ? ' &middot; ' + esc(v.desc) : ''}</span></span>`).join('')}
908
+ </div>
909
+ <textarea class="body-editor" id="bodyEditor">${JSON.stringify(example, null, 2)}</textarea>
910
+ <button class="btn btn-outline" style="margin-top:6px;font-size:10px" onclick="document.getElementById('bodyEditor').value=JSON.stringify(${JSON.stringify(example).replace(/"/g,'&quot;')},null,2)">Reset Example</button>
911
+ </div></div>`;
912
+ }
913
+
914
+ html += `<div class="btn-row">
915
+ <button class="btn btn-send" id="sendBtn" onclick="executeRequest()">Send Request</button>
916
+ <button class="btn btn-outline" onclick="showCurl()">Show cURL</button>
917
+ </div>`;
918
+ html += `<div id="curlBox" style="display:none;margin-top:12px"></div>`;
919
+ html += `<div id="responseBox" style="margin-top:16px"></div>`;
920
+ html += `</div>`;
921
+ document.getElementById('apiMain').innerHTML = html;
922
+ }
923
+
924
+ function buildUrl(ep) {
925
+ let url = ep.path;
926
+ (ep.params || []).filter(p => p.in === 'path').forEach(p => {
927
+ const el = document.getElementById(`param-${p.name}`);
928
+ const val = el ? el.value.trim() : '';
929
+ url = url.replace(`:${p.name}`, encodeURIComponent(val || `{${p.name}}`));
930
+ });
931
+ const qp = [];
932
+ (ep.params || []).filter(p => p.in === 'query').forEach(p => {
933
+ const el = document.getElementById(`query-${p.name}`);
934
+ const val = el ? el.value.trim() : '';
935
+ if (val) qp.push(`${encodeURIComponent(p.name)}=${encodeURIComponent(val)}`);
936
+ });
937
+ if (qp.length) url += '?' + qp.join('&');
938
+ return url;
939
+ }
940
+
941
+ async function executeRequest() {
942
+ if (!selectedEp) return;
943
+ const btn = document.getElementById('sendBtn');
944
+ btn.disabled = true; btn.textContent = 'Sending...';
945
+
946
+ const url = buildUrl(selectedEp);
947
+ const hasBody = selectedEp.body && Object.keys(selectedEp.body).length > 0;
948
+ const opts = { method: selectedEp.method, headers: {} };
949
+ if (hasBody && (selectedEp.method === 'POST' || selectedEp.method === 'PUT' || selectedEp.method === 'PATCH')) {
950
+ opts.headers['Content-Type'] = 'application/json';
951
+ try { opts.body = document.getElementById('bodyEditor').value; } catch {}
952
+ }
953
+
954
+ const start = performance.now();
955
+ try {
956
+ const res = await fetch(url, opts);
957
+ const duration = Math.round(performance.now() - start);
958
+ let body;
959
+ const ct = res.headers.get('content-type') || '';
960
+ if (ct.includes('json')) body = JSON.stringify(await res.json(), null, 2);
961
+ else if (ct.includes('text/event-stream')) body = '(SSE stream — use browser EventSource or curl)';
962
+ else body = await res.text();
963
+
964
+ const cls = res.status < 300 ? 'resp-2xx' : res.status < 500 ? 'resp-4xx' : 'resp-5xx';
965
+ document.getElementById('responseBox').innerHTML = `
966
+ <div class="section"><div class="section-title">Response</div><div class="section-body">
967
+ <div class="resp-status ${cls}">${res.status} ${res.statusText} &nbsp;&middot;&nbsp; ${duration}ms</div>
968
+ <div class="resp-body">${esc(body)}</div>
969
+ </div></div>`;
970
+
971
+ apiHistory.unshift({ method: selectedEp.method, path: url, status: res.status, duration, time: new Date().toISOString(), catIdx: CATALOG.indexOf(selectedEp) });
972
+ if (apiHistory.length > 50) apiHistory.length = 50;
973
+ localStorage.setItem('api-docs-history', JSON.stringify(apiHistory));
974
+ } catch (e) {
975
+ document.getElementById('responseBox').innerHTML = `
976
+ <div class="section"><div class="section-title">Error</div><div class="section-body">
977
+ <div class="resp-status resp-5xx">Network Error</div>
978
+ <div class="resp-body">${esc(e.message)}</div>
979
+ </div></div>`;
980
+ } finally {
981
+ btn.disabled = false; btn.textContent = 'Send Request';
982
+ }
983
+ }
984
+
985
+ function showCurl() {
986
+ if (!selectedEp) return;
987
+ const url = window.location.origin + buildUrl(selectedEp);
988
+ const hasBody = selectedEp.body && Object.keys(selectedEp.body).length > 0;
989
+ let cmd = `curl -X ${selectedEp.method} '${url}'`;
990
+ if (hasBody && (selectedEp.method === 'POST' || selectedEp.method === 'PUT' || selectedEp.method === 'PATCH')) {
991
+ const body = document.getElementById('bodyEditor')?.value || '{}';
992
+ cmd += ` \\\n -H 'Content-Type: application/json' \\\n -d '${body.replace(/'/g, "\\'")}'`;
993
+ }
994
+ document.getElementById('curlBox').innerHTML = `<div class="curl-box"><button class="copy-btn" onclick="copyText(this.parentElement.querySelector('code').textContent)">Copy</button><code>${esc(cmd)}</code></div>`;
995
+ document.getElementById('curlBox').style.display = 'block';
996
+ }
997
+
998
+ // ── History ──
999
+ function showHistory() {
1000
+ currentView = 'history';
1001
+ selectedEp = null;
1002
+ setApiNav('navHistory');
1003
+ renderApiSidebar();
1004
+ if (!apiHistory.length) {
1005
+ document.getElementById('apiMain').innerHTML = `<div class="overview"><h1>Request History</h1><div class="subtitle">No requests yet. Send one from any endpoint.</div></div>`;
1006
+ return;
1007
+ }
1008
+ document.getElementById('apiMain').innerHTML = `<div class="overview"><h1>Request History</h1>
1009
+ <div class="subtitle">${apiHistory.length} requests &nbsp;&middot;&nbsp; <a href="#" onclick="apiHistory=[];localStorage.removeItem('api-docs-history');showHistory();return false" style="color:var(--red);font-size:12px">Clear all</a></div>
1010
+ <div class="section"><div class="section-body">
1011
+ ${apiHistory.map((h, i) => {
1012
+ const cls = h.status < 300 ? 'color:var(--green)' : h.status < 500 ? 'color:var(--amber)' : 'color:var(--red)';
1013
+ return `<div class="history-row" onclick="selectEndpoint(${h.catIdx})">
1014
+ <span class="method-badge method-${h.method}" style="font-size:8px;padding:1px 4px">${h.method}</span>
1015
+ <span style="flex:1;font-family:var(--mono);font-size:10px;color:var(--text-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${esc(h.path)}</span>
1016
+ <span class="history-status" style="${cls}">${h.status}</span>
1017
+ <span style="font-size:10px;color:var(--text-muted)">${h.duration}ms</span>
1018
+ <span class="history-time">${new Date(h.time).toLocaleTimeString()}</span>
1019
+ </div>`;
1020
+ }).join('')}
1021
+ </div></div>
1022
+ </div>`;
1023
+ }
1024
+
1025
+
1026
+ // ═══════════════════════════════════════════════════════════════════
1027
+ // MCP TOOLS TAB
1028
+ // ═══════════════════════════════════════════════════════════════════
1029
+
1030
+ function getMcpCategories() {
1031
+ const c = {};
1032
+ TOOLS.forEach(t => { if (!c[t.cat]) c[t.cat] = []; c[t.cat].push(t); });
1033
+ return c;
1034
+ }
1035
+
1036
+ function renderMcpSidebar(q) {
1037
+ const cats = getMcpCategories();
1038
+ const s = (q || '').toLowerCase();
1039
+ let h = '';
1040
+ for (const [cat, tools] of Object.entries(cats)) {
1041
+ const f = s ? tools.filter(t => t.name.includes(s) || t.desc.toLowerCase().includes(s)) : tools;
1042
+ if (!f.length) continue;
1043
+ const open = s || (selectedTool && selectedTool.cat === cat);
1044
+ h += `<div class="cat-group"><div class="cat-header${open ? ' open' : ''}" onclick="this.classList.toggle('open')"><span class="arrow">&#9656;</span>${esc(cat)}<span class="count">${f.length}</span></div><div class="cat-items">${f.map(t => `<div class="tool-item${selectedTool === t ? ' active' : ''}" onclick="selectMcpTool('${t.name}')">${t.name}</div>`).join('')}</div></div>`;
1045
+ }
1046
+ document.getElementById('mcpSidebarBody').innerHTML = h;
1047
+ }
1048
+
1049
+ function filterTools() { renderMcpSidebar(document.getElementById('mcpSearch').value); }
1050
+
1051
+ // ── MCP Overview ──
1052
+ function showMcpOverview() {
1053
+ selectedTool = null;
1054
+ setMcpNav('navMcpOverview');
1055
+ renderMcpSidebar();
1056
+ const cats = getMcpCategories();
1057
+ const cn = Object.keys(cats);
1058
+ document.getElementById('mcpMain').innerHTML = `<div class="overview mcp-mode"><h1>MCP Tools</h1><div class="sub" style="color:var(--text-dim);font-size:13px;margin-bottom:20px">MyAIforOne Agent Gateway — ${TOOLS.length} tools across ${cn.length} categories</div>
1059
+ <div class="stat-row"><div class="stat-card"><div class="stat-val">${TOOLS.length}</div><div class="stat-label">Tools</div></div><div class="stat-card"><div class="stat-val">${cn.length}</div><div class="stat-label">Categories</div></div><div class="stat-card"><div class="stat-val">stdio</div><div class="stat-label">Transport</div></div></div>
1060
+ <div style="font-size:11px;font-weight:700;color:var(--text-dim);margin-bottom:8px">CATEGORIES</div>
1061
+ <div class="cat-grid">${cn.map(c => `<div class="cat-card" onclick="jumpMcpCat('${c}')"><div class="cat-card-name">${c}</div><div class="cat-card-count">${cats[c].length} tools</div></div>`).join('')}</div>
1062
+ <div class="connect-box"><div class="connect-title">Connect to this MCP</div><div class="example-box"><button class="copy-btn" onclick="copyText(this.nextElementSibling.textContent)">Copy</button><code>// Claude Code: add to .mcp.json
1063
+ {
1064
+ "mcpServers": {
1065
+ "myaiforone": {
1066
+ "command": "node",
1067
+ "args": ["server/mcp-server/dist/index.js"],
1068
+ "cwd": "/path/to/channelToAgentToClaude"
1069
+ }
1070
+ }
1071
+ }</code></div></div></div>`;
1072
+ }
1073
+
1074
+ function jumpMcpCat(c) { const t = TOOLS.find(t => t.cat === c); if (t) selectMcpTool(t.name); }
1075
+
1076
+ // ── MCP Tool Detail ──
1077
+ function selectMcpTool(name) {
1078
+ selectedTool = TOOLS.find(t => t.name === name);
1079
+ if (!selectedTool) return;
1080
+ setMcpNav(null);
1081
+ renderMcpSidebar(document.getElementById('mcpSearch').value);
1082
+ const t = selectedTool;
1083
+ const hasParams = t.params.length > 0;
1084
+ const example = {};
1085
+ t.params.forEach(p => { if (p.r) example[p.n] = p.t === 'number' ? 0 : p.t === 'boolean' ? true : `<${p.n}>`; });
1086
+
1087
+ let h = `<div class="tool-detail mcp-mode"><div class="tool-cat-badge">${esc(t.cat)}</div><div class="tool-name">${t.name}</div><div class="tool-desc">${esc(t.desc)}</div>`;
1088
+ if (hasParams) {
1089
+ h += `<div class="section"><div class="section-title">Parameters</div><div class="section-body">${t.params.map(p => `<div class="mcp-param-row"><span class="mcp-param-name">${p.n}</span><span class="mcp-param-type">${esc(p.t)}</span><span class="mcp-param-req">${p.r ? 'required' : ''}</span><span class="mcp-param-desc">${esc(p.d || '')}</span></div>`).join('')}</div></div>`;
1090
+ }
1091
+ h += `<div class="section"><div class="section-title">Example Call</div><div class="section-body"><div class="example-box"><button class="copy-btn" onclick="copyText(this.nextElementSibling.textContent)">Copy</button><code>${esc(JSON.stringify({ tool: t.name, arguments: hasParams ? example : undefined }, null, 2))}</code></div></div></div>`;
1092
+ h += `</div>`;
1093
+ document.getElementById('mcpMain').innerHTML = h;
1094
+ }
1095
+
1096
+ // ═══ HASH CHANGE ═════════════════════════════════════════════════════
1097
+ window.addEventListener('hashchange', () => {
1098
+ const hash = window.location.hash.replace('#','');
1099
+ if (hash === 'mcp' && activeTab !== 'mcp') switchTab('mcp');
1100
+ else if (hash === 'api' && activeTab !== 'api') switchTab('api');
1101
+ });
1102
+
1103
+ init();
1104
+ </script>
1105
+ </body>
1106
+ </html>