cli-jaw 2.1.1 → 2.1.3

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 (477) hide show
  1. package/README.ja.md +8 -6
  2. package/README.ko.md +8 -6
  3. package/README.md +18 -11
  4. package/README.zh-CN.md +8 -6
  5. package/dist/bin/cli-jaw.js +19 -3
  6. package/dist/bin/cli-jaw.js.map +1 -1
  7. package/dist/bin/commands/browser.js +1 -1
  8. package/dist/bin/commands/browser.js.map +1 -1
  9. package/dist/bin/commands/chat-search.js +71 -0
  10. package/dist/bin/commands/chat-search.js.map +1 -0
  11. package/dist/bin/commands/chat.js +98 -58
  12. package/dist/bin/commands/chat.js.map +1 -1
  13. package/dist/bin/commands/dispatch.js +130 -5
  14. package/dist/bin/commands/dispatch.js.map +1 -1
  15. package/dist/bin/commands/goal.js +66 -9
  16. package/dist/bin/commands/goal.js.map +1 -1
  17. package/dist/bin/commands/history.js +61 -0
  18. package/dist/bin/commands/history.js.map +1 -0
  19. package/dist/bin/commands/lock.js +104 -0
  20. package/dist/bin/commands/lock.js.map +1 -0
  21. package/dist/bin/commands/memory.js +23 -2
  22. package/dist/bin/commands/memory.js.map +1 -1
  23. package/dist/bin/commands/orchestrate.js.map +1 -1
  24. package/dist/bin/commands/project.js +4 -1
  25. package/dist/bin/commands/project.js.map +1 -1
  26. package/dist/bin/commands/tui/fullscreen-mode.js +237 -0
  27. package/dist/bin/commands/tui/fullscreen-mode.js.map +1 -0
  28. package/dist/bin/commands/tui/input-handler.js +139 -52
  29. package/dist/bin/commands/tui/input-handler.js.map +1 -1
  30. package/dist/bin/commands/tui/overlays.js +177 -70
  31. package/dist/bin/commands/tui/overlays.js.map +1 -1
  32. package/dist/bin/commands/tui/renderer.js +70 -20
  33. package/dist/bin/commands/tui/renderer.js.map +1 -1
  34. package/dist/bin/commands/tui/simple-mode.js +1 -2
  35. package/dist/bin/commands/tui/simple-mode.js.map +1 -1
  36. package/dist/bin/commands/tui/tui-io.js +8 -0
  37. package/dist/bin/commands/tui/tui-io.js.map +1 -0
  38. package/dist/bin/commands/tui/types.js +9 -0
  39. package/dist/bin/commands/tui/types.js.map +1 -1
  40. package/dist/bin/commands/tui/ws-handler.js +115 -23
  41. package/dist/bin/commands/tui/ws-handler.js.map +1 -1
  42. package/dist/bin/commands/worker.js +159 -0
  43. package/dist/bin/commands/worker.js.map +1 -0
  44. package/dist/bin/postinstall.js +0 -76
  45. package/dist/bin/postinstall.js.map +1 -1
  46. package/dist/lib/mcp/format-converters.js +21 -2
  47. package/dist/lib/mcp/format-converters.js.map +1 -1
  48. package/dist/lib/mcp/mcp-registry.js +75 -0
  49. package/dist/lib/mcp/mcp-registry.js.map +1 -0
  50. package/dist/lib/stt.js +1 -1
  51. package/dist/lib/stt.js.map +1 -1
  52. package/dist/lib/upload.js +7 -0
  53. package/dist/lib/upload.js.map +1 -1
  54. package/dist/scripts/fresh-install-smoke.js +1 -1
  55. package/dist/scripts/fresh-install-smoke.js.map +1 -1
  56. package/dist/server.js +151 -22
  57. package/dist/server.js.map +1 -1
  58. package/dist/src/agent/agy-runtime.js +1 -0
  59. package/dist/src/agent/agy-runtime.js.map +1 -1
  60. package/dist/src/agent/agy-transcript-watcher.js +78 -0
  61. package/dist/src/agent/agy-transcript-watcher.js.map +1 -0
  62. package/dist/src/agent/agy-transcript.js +158 -0
  63. package/dist/src/agent/agy-transcript.js.map +1 -0
  64. package/dist/src/agent/args.js +51 -5
  65. package/dist/src/agent/args.js.map +1 -1
  66. package/dist/src/agent/claude-e-runtime.js +1 -1
  67. package/dist/src/agent/claude-e-runtime.js.map +1 -1
  68. package/dist/src/agent/codex-app-client.js +2 -2
  69. package/dist/src/agent/codex-app-client.js.map +1 -1
  70. package/dist/src/agent/cursor-runtime.js +1 -0
  71. package/dist/src/agent/cursor-runtime.js.map +1 -1
  72. package/dist/src/agent/error-classifier.js +6 -1
  73. package/dist/src/agent/error-classifier.js.map +1 -1
  74. package/dist/src/agent/events/claude.js +1 -0
  75. package/dist/src/agent/events/claude.js.map +1 -1
  76. package/dist/src/agent/events/codex.js +0 -44
  77. package/dist/src/agent/events/codex.js.map +1 -1
  78. package/dist/src/agent/events/helpers.js +52 -5
  79. package/dist/src/agent/events/helpers.js.map +1 -1
  80. package/dist/src/agent/events/opencode.js +6 -2
  81. package/dist/src/agent/events/opencode.js.map +1 -1
  82. package/dist/src/agent/events/summary.js +3 -2
  83. package/dist/src/agent/events/summary.js.map +1 -1
  84. package/dist/src/agent/events/tool-labels.js +8 -5
  85. package/dist/src/agent/events/tool-labels.js.map +1 -1
  86. package/dist/src/agent/kiro-auth.js +213 -0
  87. package/dist/src/agent/kiro-auth.js.map +1 -0
  88. package/dist/src/agent/kiro-models.js +79 -0
  89. package/dist/src/agent/kiro-models.js.map +1 -0
  90. package/dist/src/agent/kiro-runtime.js +314 -0
  91. package/dist/src/agent/kiro-runtime.js.map +1 -0
  92. package/dist/src/agent/lifecycle-handler.js +208 -23
  93. package/dist/src/agent/lifecycle-handler.js.map +1 -1
  94. package/dist/src/agent/memory-flush-controller.js +3 -4
  95. package/dist/src/agent/memory-flush-controller.js.map +1 -1
  96. package/dist/src/agent/resume-classifier.js +18 -1
  97. package/dist/src/agent/resume-classifier.js.map +1 -1
  98. package/dist/src/agent/session-persistence.js +2 -2
  99. package/dist/src/agent/session-persistence.js.map +1 -1
  100. package/dist/src/agent/smoke-detector.js +3 -0
  101. package/dist/src/agent/smoke-detector.js.map +1 -1
  102. package/dist/src/agent/spawn/queue.js +11 -5
  103. package/dist/src/agent/spawn/queue.js.map +1 -1
  104. package/dist/src/agent/spawn/resume.js +6 -1
  105. package/dist/src/agent/spawn/resume.js.map +1 -1
  106. package/dist/src/agent/spawn-env.js +1 -1
  107. package/dist/src/agent/spawn-env.js.map +1 -1
  108. package/dist/src/agent/spawn.js +231 -43
  109. package/dist/src/agent/spawn.js.map +1 -1
  110. package/dist/src/agent/watchdog.js +1 -1
  111. package/dist/src/agent/watchdog.js.map +1 -1
  112. package/dist/src/browser/actions.js +0 -8
  113. package/dist/src/browser/actions.js.map +1 -1
  114. package/dist/src/browser/adaptive-fetch/browser-escalation.js +5 -29
  115. package/dist/src/browser/adaptive-fetch/browser-escalation.js.map +1 -1
  116. package/dist/src/browser/adaptive-fetch/browser-runtime.js +5 -14
  117. package/dist/src/browser/adaptive-fetch/browser-runtime.js.map +1 -1
  118. package/dist/src/browser/adaptive-fetch/browser-session.js +14 -28
  119. package/dist/src/browser/adaptive-fetch/browser-session.js.map +1 -1
  120. package/dist/src/browser/adaptive-fetch/challenge-detector.js +4 -26
  121. package/dist/src/browser/adaptive-fetch/challenge-detector.js.map +1 -1
  122. package/dist/src/browser/adaptive-fetch/content-scorer.js +5 -29
  123. package/dist/src/browser/adaptive-fetch/content-scorer.js.map +1 -1
  124. package/dist/src/browser/adaptive-fetch/endpoint-resolvers.js +0 -64
  125. package/dist/src/browser/adaptive-fetch/endpoint-resolvers.js.map +1 -1
  126. package/dist/src/browser/adaptive-fetch/fetcher.js +4 -19
  127. package/dist/src/browser/adaptive-fetch/fetcher.js.map +1 -1
  128. package/dist/src/browser/adaptive-fetch/human-loop.js +0 -26
  129. package/dist/src/browser/adaptive-fetch/human-loop.js.map +1 -1
  130. package/dist/src/browser/adaptive-fetch/index.js +74 -145
  131. package/dist/src/browser/adaptive-fetch/index.js.map +1 -1
  132. package/dist/src/browser/adaptive-fetch/metadata.js +1 -41
  133. package/dist/src/browser/adaptive-fetch/metadata.js.map +1 -1
  134. package/dist/src/browser/adaptive-fetch/output.js +1 -18
  135. package/dist/src/browser/adaptive-fetch/output.js.map +1 -1
  136. package/dist/src/browser/adaptive-fetch/reader-adapters.js +43 -75
  137. package/dist/src/browser/adaptive-fetch/reader-adapters.js.map +1 -1
  138. package/dist/src/browser/adaptive-fetch/safety.js +5 -48
  139. package/dist/src/browser/adaptive-fetch/safety.js.map +1 -1
  140. package/dist/src/browser/adaptive-fetch/third-party-readers.js +0 -11
  141. package/dist/src/browser/adaptive-fetch/third-party-readers.js.map +1 -1
  142. package/dist/src/browser/adaptive-fetch/trace.js +3 -18
  143. package/dist/src/browser/adaptive-fetch/trace.js.map +1 -1
  144. package/dist/src/browser/adaptive-fetch/transforms.js +0 -23
  145. package/dist/src/browser/adaptive-fetch/transforms.js.map +1 -1
  146. package/dist/src/browser/adaptive-fetch/types.js +3 -0
  147. package/dist/src/browser/adaptive-fetch/types.js.map +1 -0
  148. package/dist/src/browser/adaptive-fetch/validators.js +0 -17
  149. package/dist/src/browser/adaptive-fetch/validators.js.map +1 -1
  150. package/dist/src/browser/adaptive-fetch/waf-profiles.js +0 -10
  151. package/dist/src/browser/adaptive-fetch/waf-profiles.js.map +1 -1
  152. package/dist/src/browser/connection.js +1 -1
  153. package/dist/src/browser/connection.js.map +1 -1
  154. package/dist/src/browser/web-ai/chatgpt-response.js +0 -1
  155. package/dist/src/browser/web-ai/chatgpt-response.js.map +1 -1
  156. package/dist/src/browser/web-ai/chatgpt.js +0 -33
  157. package/dist/src/browser/web-ai/chatgpt.js.map +1 -1
  158. package/dist/src/browser/web-ai/diagnostics.js +0 -16
  159. package/dist/src/browser/web-ai/diagnostics.js.map +1 -1
  160. package/dist/src/browser/web-ai/doctor.js.map +1 -1
  161. package/dist/src/browser/web-ai/errors.js +1 -1
  162. package/dist/src/browser/web-ai/errors.js.map +1 -1
  163. package/dist/src/browser/web-ai/grok-live.js +2 -0
  164. package/dist/src/browser/web-ai/grok-live.js.map +1 -1
  165. package/dist/src/cli/claude-models.js +2 -2
  166. package/dist/src/cli/claude-models.js.map +1 -1
  167. package/dist/src/cli/command-context.js.map +1 -1
  168. package/dist/src/cli/commands.js +16 -4
  169. package/dist/src/cli/commands.js.map +1 -1
  170. package/dist/src/cli/compact.js +2 -1
  171. package/dist/src/cli/compact.js.map +1 -1
  172. package/dist/src/cli/handlers/session-handlers.js +34 -0
  173. package/dist/src/cli/handlers/session-handlers.js.map +1 -0
  174. package/dist/src/cli/handlers-project.js.map +1 -1
  175. package/dist/src/cli/handlers-runtime.js +2 -0
  176. package/dist/src/cli/handlers-runtime.js.map +1 -1
  177. package/dist/src/cli/handlers-workflows.js +85 -17
  178. package/dist/src/cli/handlers-workflows.js.map +1 -1
  179. package/dist/src/cli/handlers.js +84 -43
  180. package/dist/src/cli/handlers.js.map +1 -1
  181. package/dist/src/cli/readiness.js +17 -1
  182. package/dist/src/cli/readiness.js.map +1 -1
  183. package/dist/src/cli/registry-live.js +17 -0
  184. package/dist/src/cli/registry-live.js.map +1 -0
  185. package/dist/src/cli/registry.js +51 -10
  186. package/dist/src/cli/registry.js.map +1 -1
  187. package/dist/src/cli/tui/composer.js +135 -5
  188. package/dist/src/cli/tui/composer.js.map +1 -1
  189. package/dist/src/cli/tui/diffview.js +41 -0
  190. package/dist/src/cli/tui/diffview.js.map +1 -0
  191. package/dist/src/cli/tui/editor.js +45 -0
  192. package/dist/src/cli/tui/editor.js.map +1 -0
  193. package/dist/src/cli/tui/file-mention.js +78 -0
  194. package/dist/src/cli/tui/file-mention.js.map +1 -0
  195. package/dist/src/cli/tui/highlight.js +82 -0
  196. package/dist/src/cli/tui/highlight.js.map +1 -0
  197. package/dist/src/cli/tui/keymap.js +21 -0
  198. package/dist/src/cli/tui/keymap.js.map +1 -1
  199. package/dist/src/cli/tui/markdown.js +124 -0
  200. package/dist/src/cli/tui/markdown.js.map +1 -0
  201. package/dist/src/cli/tui/mode.js +26 -0
  202. package/dist/src/cli/tui/mode.js.map +1 -0
  203. package/dist/src/cli/tui/overlay.js +121 -98
  204. package/dist/src/cli/tui/overlay.js.map +1 -1
  205. package/dist/src/cli/tui/render/frame.js +72 -0
  206. package/dist/src/cli/tui/render/frame.js.map +1 -0
  207. package/dist/src/cli/tui/render/layout.js +22 -0
  208. package/dist/src/cli/tui/render/layout.js.map +1 -0
  209. package/dist/src/cli/tui/render/mouse.js +25 -0
  210. package/dist/src/cli/tui/render/mouse.js.map +1 -0
  211. package/dist/src/cli/tui/render/scheduler.js +37 -0
  212. package/dist/src/cli/tui/render/scheduler.js.map +1 -0
  213. package/dist/src/cli/tui/render/viewport.js +82 -0
  214. package/dist/src/cli/tui/render/viewport.js.map +1 -0
  215. package/dist/src/cli/tui/renderers.js +37 -0
  216. package/dist/src/cli/tui/renderers.js.map +1 -1
  217. package/dist/src/cli/tui/stream.js +48 -0
  218. package/dist/src/cli/tui/stream.js.map +1 -0
  219. package/dist/src/cli/tui/text-buffer.js +143 -0
  220. package/dist/src/cli/tui/text-buffer.js.map +1 -0
  221. package/dist/src/cli/tui/theme.js +128 -0
  222. package/dist/src/cli/tui/theme.js.map +1 -0
  223. package/dist/src/cli/tui/transcript.js +4 -0
  224. package/dist/src/cli/tui/transcript.js.map +1 -1
  225. package/dist/src/command-contract/help-renderer.js +1 -1
  226. package/dist/src/command-contract/help-renderer.js.map +1 -1
  227. package/dist/src/core/chat-sessions.js +63 -0
  228. package/dist/src/core/chat-sessions.js.map +1 -0
  229. package/dist/src/core/cli-detection.js +14 -0
  230. package/dist/src/core/cli-detection.js.map +1 -1
  231. package/dist/src/core/compact.js +43 -11
  232. package/dist/src/core/compact.js.map +1 -1
  233. package/dist/src/core/config.js +14 -1
  234. package/dist/src/core/config.js.map +1 -1
  235. package/dist/src/core/db.js +52 -12
  236. package/dist/src/core/db.js.map +1 -1
  237. package/dist/src/core/employees.js +2 -2
  238. package/dist/src/core/employees.js.map +1 -1
  239. package/dist/src/core/main-session.js +3 -2
  240. package/dist/src/core/main-session.js.map +1 -1
  241. package/dist/src/discord/bot.js.map +1 -1
  242. package/dist/src/discord/discord-file.js +1 -1
  243. package/dist/src/discord/discord-file.js.map +1 -1
  244. package/dist/src/discord/send-only-client.js +1 -3
  245. package/dist/src/discord/send-only-client.js.map +1 -1
  246. package/dist/src/goal/heartbeat.js +113 -7
  247. package/dist/src/goal/heartbeat.js.map +1 -1
  248. package/dist/src/goal/store.js +44 -5
  249. package/dist/src/goal/store.js.map +1 -1
  250. package/dist/src/ide/diff.js +37 -0
  251. package/dist/src/ide/diff.js.map +1 -1
  252. package/dist/src/manager/launchd-service.js +1 -1
  253. package/dist/src/manager/launchd-service.js.map +1 -1
  254. package/dist/src/manager/lifecycle-helpers.js +14 -0
  255. package/dist/src/manager/lifecycle-helpers.js.map +1 -1
  256. package/dist/src/manager/lifecycle-store.js.map +1 -1
  257. package/dist/src/manager/lifecycle.js +94 -5
  258. package/dist/src/manager/lifecycle.js.map +1 -1
  259. package/dist/src/manager/notes/routes.js +0 -31
  260. package/dist/src/manager/notes/routes.js.map +1 -1
  261. package/dist/src/manager/notes/ws.js.map +1 -1
  262. package/dist/src/manager/preview-link-policy.js +11 -4
  263. package/dist/src/manager/preview-link-policy.js.map +1 -1
  264. package/dist/src/manager/registry.js.map +1 -1
  265. package/dist/src/manager/routes/dashboard-memory.js.map +1 -1
  266. package/dist/src/manager/scan.js +36 -1
  267. package/dist/src/manager/scan.js.map +1 -1
  268. package/dist/src/manager/server.js +42 -7
  269. package/dist/src/manager/server.js.map +1 -1
  270. package/dist/src/manager/shutdown.js +8 -3
  271. package/dist/src/manager/shutdown.js.map +1 -1
  272. package/dist/src/manager/systemd-service.js +1 -1
  273. package/dist/src/manager/systemd-service.js.map +1 -1
  274. package/dist/src/memory/indexing.js +49 -1
  275. package/dist/src/memory/indexing.js.map +1 -1
  276. package/dist/src/memory/keyword-expand.js +0 -187
  277. package/dist/src/memory/keyword-expand.js.map +1 -1
  278. package/dist/src/memory/runtime.js +3 -2
  279. package/dist/src/memory/runtime.js.map +1 -1
  280. package/dist/src/memory/shared.js.map +1 -1
  281. package/dist/src/messaging/send.js +66 -7
  282. package/dist/src/messaging/send.js.map +1 -1
  283. package/dist/src/orchestrator/collect.js +3 -2
  284. package/dist/src/orchestrator/collect.js.map +1 -1
  285. package/dist/src/orchestrator/distribute.js +9 -3
  286. package/dist/src/orchestrator/distribute.js.map +1 -1
  287. package/dist/src/orchestrator/friction.js +59 -0
  288. package/dist/src/orchestrator/friction.js.map +1 -0
  289. package/dist/src/orchestrator/gateway.js +4 -4
  290. package/dist/src/orchestrator/gateway.js.map +1 -1
  291. package/dist/src/orchestrator/pipeline.js +89 -45
  292. package/dist/src/orchestrator/pipeline.js.map +1 -1
  293. package/dist/src/orchestrator/sanitize.js +69 -0
  294. package/dist/src/orchestrator/sanitize.js.map +1 -0
  295. package/dist/src/orchestrator/seed.js +50 -0
  296. package/dist/src/orchestrator/seed.js.map +1 -0
  297. package/dist/src/orchestrator/state-machine.js +215 -76
  298. package/dist/src/orchestrator/state-machine.js.map +1 -1
  299. package/dist/src/orchestrator/worker-monitor.js +1 -1
  300. package/dist/src/orchestrator/worker-monitor.js.map +1 -1
  301. package/dist/src/orchestrator/worker-progress.js +29 -0
  302. package/dist/src/orchestrator/worker-progress.js.map +1 -0
  303. package/dist/src/orchestrator/worker-registry.js +63 -2
  304. package/dist/src/orchestrator/worker-registry.js.map +1 -1
  305. package/dist/src/prompt/builder.js +190 -115
  306. package/dist/src/prompt/builder.js.map +1 -1
  307. package/dist/src/prompt/templates/a1-system.md +124 -61
  308. package/dist/src/prompt/templates/control-system.md +2 -2
  309. package/dist/src/prompt/templates/employee.md +41 -56
  310. package/dist/src/prompt/templates/orchestration.md +23 -8
  311. package/dist/src/prompt/templates/skills.md +6 -0
  312. package/dist/src/routes/browser.js +3 -3
  313. package/dist/src/routes/browser.js.map +1 -1
  314. package/dist/src/routes/employees.js +4 -4
  315. package/dist/src/routes/employees.js.map +1 -1
  316. package/dist/src/routes/goal.js +48 -4
  317. package/dist/src/routes/goal.js.map +1 -1
  318. package/dist/src/routes/heartbeat.js +1 -1
  319. package/dist/src/routes/heartbeat.js.map +1 -1
  320. package/dist/src/routes/i18n.js +1 -1
  321. package/dist/src/routes/i18n.js.map +1 -1
  322. package/dist/src/routes/jaw-memory.js +1 -1
  323. package/dist/src/routes/jaw-memory.js.map +1 -1
  324. package/dist/src/routes/memory.js.map +1 -1
  325. package/dist/src/routes/messaging.js +8 -3
  326. package/dist/src/routes/messaging.js.map +1 -1
  327. package/dist/src/routes/orchestrate.js +267 -117
  328. package/dist/src/routes/orchestrate.js.map +1 -1
  329. package/dist/src/routes/quota-agy-reverse.js +6 -5
  330. package/dist/src/routes/quota-agy-reverse.js.map +1 -1
  331. package/dist/src/routes/quota-kiro-reverse.js +187 -0
  332. package/dist/src/routes/quota-kiro-reverse.js.map +1 -0
  333. package/dist/src/routes/quota.js +68 -6
  334. package/dist/src/routes/quota.js.map +1 -1
  335. package/dist/src/routes/settings.js +37 -8
  336. package/dist/src/routes/settings.js.map +1 -1
  337. package/dist/src/routes/skills.js.map +1 -1
  338. package/dist/src/security/path-guards.js +0 -3
  339. package/dist/src/security/path-guards.js.map +1 -1
  340. package/dist/src/security/security-audit-log.js.map +1 -1
  341. package/dist/src/shared/shell-command-display.js +51 -0
  342. package/dist/src/shared/shell-command-display.js.map +1 -0
  343. package/dist/src/telegram/bot.js.map +1 -1
  344. package/dist/src/trace/store.js +32 -0
  345. package/dist/src/trace/store.js.map +1 -1
  346. package/dist/src/types/cli-engine.js +1 -0
  347. package/dist/src/types/cli-engine.js.map +1 -1
  348. package/dist/src/workflows/employee-boundary.js +7 -7
  349. package/dist/src/workflows/employee-boundary.js.map +1 -1
  350. package/dist/src/workflows/handoff.js +16 -16
  351. package/dist/src/workflows/handoff.js.map +1 -1
  352. package/dist/src/workflows/scope-sandbox.js +58 -0
  353. package/dist/src/workflows/scope-sandbox.js.map +1 -0
  354. package/package.json +1 -1
  355. package/public/assets/providers/kiro-color.svg +15 -0
  356. package/public/assets/providers/kiro.svg +14 -0
  357. package/public/css/chat.css +27 -0
  358. package/public/css/modals.css +79 -0
  359. package/public/css/orc-state.css +10 -6
  360. package/public/css/sidebar.css +85 -0
  361. package/public/css/variables.css +6 -2
  362. package/public/dist/assets/{Agent-CIUGaUVn.js → Agent-DBKNQ6tp.js} +1 -1
  363. package/public/dist/assets/{DocPanel-C1pGgE-S.js → DocPanel-BU16GUlB.js} +1 -1
  364. package/public/dist/assets/DocPanel-gU-WkgyA.css +1 -0
  365. package/public/dist/assets/Employees-F0ssNuO-.js +1 -0
  366. package/public/dist/assets/{FolderPanel-DSkanaGN.js → FolderPanel-DT0fU8f2.js} +1 -1
  367. package/public/dist/assets/Heartbeat-fsuLzY9c.js +1 -0
  368. package/public/dist/assets/Mcp-_Yq4N3Sk.js +4 -0
  369. package/public/dist/assets/{Memory-BgN8djV4.js → Memory-CRR8kotI.js} +1 -1
  370. package/public/dist/assets/{ModelProvider-DHQ1Zvw0.js → ModelProvider-DQgISbKw.js} +1 -1
  371. package/public/dist/assets/agent-meta-C4mauPL5.js +1 -0
  372. package/public/dist/assets/app-0OQhPpTG.css +1 -0
  373. package/public/dist/assets/app-CSqIyg9A.js +55 -0
  374. package/public/dist/assets/constants-BHMkzpN_.js +1 -0
  375. package/public/dist/assets/{employees-DiNLzEXS.js → employees-CZdWHH-r.js} +7 -7
  376. package/public/dist/assets/idb-cache-0LNMskFB.js +1 -0
  377. package/public/dist/assets/idb-cache-5H89a4l8.js +1 -0
  378. package/public/dist/assets/manager-CGTQ5EIm.js +12 -0
  379. package/public/dist/assets/manager-UBunDqMH.css +1 -0
  380. package/public/dist/assets/{memory-B_nn0A4v.js → memory-B3QSmj_e.js} +9 -9
  381. package/public/dist/assets/memory-DOBqiuPc.js +1 -0
  382. package/public/dist/assets/{provider-icons-XEfJPGTe.js → provider-icons-Crv6yvlG.js} +35 -6
  383. package/public/dist/assets/render-J11oxfnl.js +28 -0
  384. package/public/dist/assets/settings-BV_2Bh0_.js +1 -0
  385. package/public/dist/assets/settings-m_cim0ov.js +151 -0
  386. package/public/dist/assets/sidebar-ZBXdBgF7.js +49 -0
  387. package/public/dist/assets/{skills-COa4iSwL.js → skills-CjaBmIPV.js} +6 -6
  388. package/public/dist/assets/skills-Xm3fl1zr.js +1 -0
  389. package/public/dist/assets/{slash-commands-C_ePvrPi.js → slash-commands-71jc07Wf.js} +1 -1
  390. package/public/dist/assets/slash-commands-BO6ssnAz.js +1 -0
  391. package/public/dist/assets/{trace-drawer-CY4z_Ie8.js → trace-drawer-Czvf2P2o.js} +1 -1
  392. package/public/dist/assets/ui-CverZJnd.js +1 -0
  393. package/public/dist/assets/ui-qKxy-4p9.js +142 -0
  394. package/public/dist/index.html +113 -86
  395. package/public/dist/manager/index.html +2 -2
  396. package/public/index.html +111 -84
  397. package/public/js/constants.ts +34 -11
  398. package/public/js/features/chat-messages.ts +13 -2
  399. package/public/js/features/chat-search.ts +5 -1
  400. package/public/js/features/chat.ts +86 -44
  401. package/public/js/features/employees.ts +7 -2
  402. package/public/js/features/idb-cache.ts +4 -0
  403. package/public/js/features/media-lightbox.ts +40 -0
  404. package/public/js/features/message-history.ts +55 -7
  405. package/public/js/features/pending-queue.ts +28 -4
  406. package/public/js/features/process-block.ts +32 -17
  407. package/public/js/features/process-log-adapter.ts +11 -2
  408. package/public/js/features/settings-cli-status-render.ts +161 -0
  409. package/public/js/features/settings-cli-status.ts +136 -187
  410. package/public/js/features/settings-core.ts +5 -1
  411. package/public/js/features/settings-mcp.ts +513 -7
  412. package/public/js/features/settings-types.ts +1 -0
  413. package/public/js/features/settings.ts +1 -1
  414. package/public/js/features/tool-ui.ts +18 -4
  415. package/public/js/features/transport-status-row.ts +3 -0
  416. package/public/js/features/ui-status.ts +5 -1
  417. package/public/js/main.ts +5 -0
  418. package/public/js/preview-parent-origin.ts +14 -0
  419. package/public/js/provider-icons.ts +6 -1
  420. package/public/js/render/file-links.ts +10 -2
  421. package/public/js/render/markdown.ts +16 -0
  422. package/public/js/ui.ts +8 -1
  423. package/public/js/virtual-scroll.ts +19 -0
  424. package/public/js/ws.ts +151 -15
  425. package/public/locales/en.json +9 -2
  426. package/public/locales/ja.json +9 -2
  427. package/public/locales/ko.json +9 -2
  428. package/public/locales/zh.json +9 -2
  429. package/public/manager/src/App.tsx +13 -70
  430. package/public/manager/src/InstancePreview.tsx +56 -11
  431. package/public/manager/src/SidebarRailRouter.tsx +32 -4
  432. package/public/manager/src/components/InstanceRow.tsx +0 -1
  433. package/public/manager/src/components/WorkbenchHeader.tsx +17 -7
  434. package/public/manager/src/doc-panel/DocPanel.tsx +14 -1
  435. package/public/manager/src/doc-panel/doc-panel.css +16 -0
  436. package/public/manager/src/folder-panel/FolderPanel.tsx +13 -2
  437. package/public/manager/src/hooks/useElectronDroppedPaths.ts +89 -0
  438. package/public/manager/src/hooks/useInstanceMessageEvents.ts +4 -15
  439. package/public/manager/src/manager-components.css +35 -1
  440. package/public/manager/src/manager-polish.css +11 -1
  441. package/public/manager/src/manager-shortcut-runner.ts +107 -0
  442. package/public/manager/src/manager-shortcuts.ts +15 -0
  443. package/public/manager/src/panels/desktop-bridge.ts +13 -0
  444. package/public/manager/src/settings/SettingsSidebar.tsx +1 -1
  445. package/public/manager/src/settings/components/sidebar-filter.ts +2 -0
  446. package/public/manager/src/settings/pages/Mcp.tsx +311 -43
  447. package/public/manager/src/settings/pages/components/McpServerCard.tsx +89 -55
  448. package/public/manager/src/settings/pages/components/agent/agent-meta.ts +32 -9
  449. package/public/manager/src/settings/pages/components/employees-helpers.ts +1 -0
  450. package/public/manager/src/settings/pages/components/heartbeat-helpers.ts +1 -0
  451. package/public/manager/src/settings/pages/mcp-helpers.ts +54 -12
  452. package/public/manager/src/settings/types.ts +1 -0
  453. package/public/manager/src/types.ts +2 -1
  454. package/scripts/fresh-install-smoke.ts +1 -1
  455. package/scripts/smoke/agy-transcript-tail-smoke.mjs +89 -0
  456. package/public/dist/assets/DocPanel-CL1scIfq.css +0 -1
  457. package/public/dist/assets/Employees-BL9MAzzx.js +0 -1
  458. package/public/dist/assets/Heartbeat-D64JCg4t.js +0 -1
  459. package/public/dist/assets/Mcp-wYwJA_61.js +0 -3
  460. package/public/dist/assets/agent-meta-BhEbjy4P.js +0 -1
  461. package/public/dist/assets/app-2Rz848bQ.js +0 -48
  462. package/public/dist/assets/app-BW-Xz2p6.css +0 -1
  463. package/public/dist/assets/constants-ahKI_aEG.js +0 -1
  464. package/public/dist/assets/idb-cache-BnZfG5FD.js +0 -1
  465. package/public/dist/assets/idb-cache-CZ3JdK8r.js +0 -1
  466. package/public/dist/assets/manager-CfyZloIP.js +0 -12
  467. package/public/dist/assets/manager-DyrwJLZr.css +0 -1
  468. package/public/dist/assets/memory-CCjNFWmO.js +0 -1
  469. package/public/dist/assets/render-CgDEBoCX.js +0 -28
  470. package/public/dist/assets/settings-CY_6tGuS.js +0 -1
  471. package/public/dist/assets/settings-DWW4GzNc.js +0 -66
  472. package/public/dist/assets/sidebar-DQKE5IA1.js +0 -23
  473. package/public/dist/assets/skills-DYTlqoke.js +0 -1
  474. package/public/dist/assets/slash-commands-D7CU5oso.js +0 -1
  475. package/public/dist/assets/ui-Car1OUvV.js +0 -1
  476. package/public/dist/assets/ui-DK_9ndj0.js +0 -140
  477. /package/public/dist/assets/{locale-DT1WRaeJ.js → locale-BHMJIzyw.js} +0 -0
@@ -1,28 +1,58 @@
1
- // ── MCP Server Settings ──
2
1
  import { api, apiJson } from '../api.js';
3
2
  import { escapeHtml } from '../render.js';
4
3
  import { t } from './i18n.js';
5
4
  import { ICONS } from '../icons.js';
6
5
 
7
- interface McpData { servers: Record<string, { command: string; args?: string[] }>; }
6
+ interface McpServer { command?: string; args?: string[]; url?: string; headers?: Record<string, string>; env?: Record<string, string>; }
7
+ interface McpData { servers: Record<string, McpServer>; }
8
8
  interface McpSyncResult { results: Record<string, boolean>; }
9
9
  interface McpInstallEntry { status: string; bin?: string; }
10
10
  interface McpInstallResult { results: Record<string, McpInstallEntry>; }
11
11
 
12
+ function getServerTag(s: McpServer): string | null {
13
+ if (s.url) return 'remote';
14
+ if (!s.command) return null;
15
+ const cmd = s.command;
16
+ if (cmd === 'npx' || cmd.endsWith('/npx')) return 'npx';
17
+ if (cmd === 'uvx' || cmd === 'uv' || cmd.endsWith('/uvx')) return 'uvx';
18
+ if (cmd === 'docker' || cmd.endsWith('/docker')) return 'docker';
19
+ return null;
20
+ }
21
+
22
+ function countBundleCandidates(servers: Record<string, McpServer>): number {
23
+ return Object.values(servers).filter(s =>
24
+ s.command === 'npx' || s.command === 'uv' || s.command === 'uvx'
25
+ ).length;
26
+ }
27
+
28
+ let cachedConfig: McpData | null = null;
29
+
12
30
  export async function loadMcpServers(): Promise<void> {
13
31
  try {
14
32
  const d = await api<McpData>('/api/mcp');
15
33
  if (!d) return;
34
+ cachedConfig = d;
16
35
  const el = document.getElementById('mcpServerList');
17
36
  if (!el) return;
18
- const names = Object.entries(d.servers || {});
19
- if (!names.length) { el.textContent = t('mcp.noServers'); return; }
20
- el.innerHTML = names.map(([n, s]) =>
21
- `<div style="padding:2px 0">• <b>${escapeHtml(n)}</b> <span style="opacity:.6">${escapeHtml(s.command)} ${(s.args || []).slice(0, 2).map(a => escapeHtml(a)).join(' ')}</span></div>`
22
- ).join('');
37
+ const entries = Object.entries(d.servers || {});
38
+ if (!entries.length) { el.textContent = t('mcp.noServers'); updateBundleLabel(0); return; }
39
+ el.innerHTML = entries.map(([n, s]) => {
40
+ const tag = getServerTag(s);
41
+ const detail = s.url || [s.command, ...(s.args || []).slice(0, 2)].filter(Boolean).map(a => escapeHtml(a!)).join(' ');
42
+ const tagHtml = tag ? ` <span style="opacity:.5;font-size:0.85em">[${escapeHtml(tag)}]</span>` : '';
43
+ return `<div style="padding:2px 0">• <b>${escapeHtml(n)}</b> <span style="opacity:.6">${detail}</span>${tagHtml}</div>`;
44
+ }).join('');
45
+ updateBundleLabel(countBundleCandidates(d.servers));
23
46
  } catch { }
24
47
  }
25
48
 
49
+ function updateBundleLabel(n: number): void {
50
+ const lbl = document.getElementById('installBundleLabel');
51
+ if (lbl) lbl.textContent = `Install bundle (${n})`;
52
+ const btn = lbl?.closest('button');
53
+ if (btn) (btn as HTMLButtonElement).disabled = n === 0;
54
+ }
55
+
26
56
  export async function syncMcpServers(): Promise<void> {
27
57
  const resultEl = document.getElementById('mcpSyncResult');
28
58
  if (!resultEl) return;
@@ -53,3 +83,479 @@ export async function installMcpGlobal(): Promise<void> {
53
83
  loadMcpServers();
54
84
  } catch (e) { resultEl.innerHTML = `${ICONS.error} ${escapeHtml((e as Error).message)}`; }
55
85
  }
86
+
87
+ // ── MCP Modal (dynamic, document.body) ──
88
+
89
+ let overlay: HTMLDivElement | null = null;
90
+ let bodyEl: HTMLDivElement | null = null;
91
+ let activeListEl: HTMLDivElement | null = null;
92
+ let addFormEl: HTMLDivElement | null = null;
93
+ let addErrorEl: HTMLDivElement | null = null;
94
+ let browseEl: HTMLDivElement | null = null;
95
+ let currentSubTab: 'local' | 'remote' = 'local';
96
+ let openState = false;
97
+ let tabBtns: HTMLButtonElement[] = [];
98
+
99
+ function ensureModal(): void {
100
+ if (overlay) return;
101
+
102
+ overlay = document.createElement('div');
103
+ overlay.id = 'mcpModal';
104
+ overlay.className = 'modal-overlay mcp-modal-overlay';
105
+ overlay.setAttribute('role', 'presentation');
106
+ overlay.setAttribute('aria-hidden', 'true');
107
+ overlay.addEventListener('click', (e) => { if (e.target === overlay) closeMcpModal(); });
108
+
109
+ const box = document.createElement('div');
110
+ box.className = 'modal-box mcp-modal-box';
111
+ box.setAttribute('role', 'dialog');
112
+ box.setAttribute('aria-modal', 'true');
113
+ box.setAttribute('aria-label', 'MCP Server Management');
114
+ box.addEventListener('click', (e) => e.stopPropagation());
115
+
116
+ const header = document.createElement('div');
117
+ header.className = 'modal-header';
118
+ const titleSpan = document.createElement('span');
119
+ titleSpan.textContent = 'MCP Server Management';
120
+ const helpBtn = document.createElement('button');
121
+ helpBtn.type = 'button';
122
+ helpBtn.className = 'help-trigger';
123
+ helpBtn.textContent = '?';
124
+ helpBtn.setAttribute('aria-label', 'MCP help');
125
+ helpBtn.addEventListener('click', () => showMcpHelp());
126
+ const closeBtn = document.createElement('button');
127
+ closeBtn.type = 'button';
128
+ closeBtn.className = 'btn-modal-close';
129
+ closeBtn.setAttribute('aria-label', 'Close');
130
+ closeBtn.textContent = 'x';
131
+ closeBtn.addEventListener('click', () => closeMcpModal());
132
+ const headerLeft = document.createElement('div');
133
+ headerLeft.style.cssText = 'display:flex;align-items:center;gap:6px';
134
+ headerLeft.append(titleSpan, helpBtn);
135
+ header.append(headerLeft, closeBtn);
136
+
137
+ bodyEl = document.createElement('div');
138
+ bodyEl.style.cssText = 'padding:16px;overflow-y:auto;flex:1';
139
+
140
+ const tabs = document.createElement('div');
141
+ tabs.style.cssText = 'display:flex;gap:4px;margin-bottom:12px';
142
+ const tabActive = createTabBtn('Active Servers', true);
143
+ const tabAdd = createTabBtn('Add New', false);
144
+ const tabBrowse = createTabBtn('Browse', false);
145
+ tabBtns = [tabActive, tabAdd, tabBrowse];
146
+ tabActive.addEventListener('click', () => switchTab('active'));
147
+ tabAdd.addEventListener('click', () => switchTab('add'));
148
+ tabBrowse.addEventListener('click', () => switchTab('browse'));
149
+ tabs.append(tabActive, tabAdd, tabBrowse);
150
+
151
+ activeListEl = document.createElement('div');
152
+
153
+ browseEl = document.createElement('div');
154
+ browseEl.style.display = 'none';
155
+ browseEl.innerHTML = '<p style="opacity:.5">Loading registry...</p>';
156
+
157
+ addFormEl = document.createElement('div');
158
+ addFormEl.style.display = 'none';
159
+ addFormEl.innerHTML = buildAddFormHTML();
160
+ addFormEl.querySelectorAll<HTMLButtonElement>('[data-mcp-subtab]').forEach(btn => {
161
+ btn.addEventListener('click', () => {
162
+ currentSubTab = btn.dataset['mcpSubtab'] as 'local' | 'remote';
163
+ switchSubTab();
164
+ });
165
+ });
166
+ addErrorEl = addFormEl.querySelector('#mcpAddError');
167
+ const addBtn = addFormEl.querySelector('[data-action="mcpAddAndSync"]');
168
+ if (addBtn) addBtn.addEventListener('click', () => void handleAddAndSync());
169
+ const cancelBtn = addFormEl.querySelector('[data-action="closeMcpModal"]');
170
+ if (cancelBtn) cancelBtn.addEventListener('click', () => closeMcpModal());
171
+
172
+ bodyEl.append(tabs, activeListEl, browseEl, addFormEl);
173
+
174
+ const footer = document.createElement('div');
175
+ footer.className = 'modal-footer';
176
+ const doneBtn = document.createElement('button');
177
+ doneBtn.type = 'button';
178
+ doneBtn.className = 'btn-save';
179
+ doneBtn.textContent = 'Close';
180
+ doneBtn.addEventListener('click', () => closeMcpModal());
181
+ footer.append(doneBtn);
182
+
183
+ box.append(header, bodyEl, footer);
184
+ overlay.append(box);
185
+ document.body.append(overlay);
186
+ }
187
+
188
+ function createTabBtn(label: string, active: boolean): HTMLButtonElement {
189
+ const btn = document.createElement('button');
190
+ btn.type = 'button';
191
+ btn.className = `btn-clear btn-tab${active ? ' is-active' : ''}`;
192
+ btn.textContent = label;
193
+ return btn;
194
+ }
195
+
196
+ function buildAddFormHTML(): string {
197
+ return `
198
+ <div style="display:flex;gap:4px;margin-bottom:8px">
199
+ <button type="button" class="btn-clear btn-tab is-active" data-mcp-subtab="local">Local</button>
200
+ <button type="button" class="btn-clear btn-tab" data-mcp-subtab="remote">Remote</button>
201
+ </div>
202
+ <div id="mcpAddLocal">
203
+ <div class="settings-row"><label>Name</label><input type="text" id="mcpAddName" placeholder="my-server"></div>
204
+ <div class="settings-row"><label>Command</label><input type="text" id="mcpAddCommand" placeholder="npx"></div>
205
+ <div class="settings-row"><label>Args (comma separated)</label><input type="text" id="mcpAddArgs" placeholder="-y, @upstash/context7-mcp"></div>
206
+ <div class="settings-row"><label>Env (KEY=value per line)</label><textarea id="mcpAddEnv" rows="2" placeholder="API_KEY=xxx"></textarea></div>
207
+ </div>
208
+ <div id="mcpAddRemote" style="display:none">
209
+ <div class="settings-row"><label>Name</label><input type="text" id="mcpAddRemoteName" placeholder="my-api"></div>
210
+ <div class="settings-row"><label>URL</label><input type="text" id="mcpAddUrl" placeholder="https://mcp.example.com/sse"></div>
211
+ <div class="settings-row"><label>Headers (KEY=value per line)</label><textarea id="mcpAddHeaders" rows="2"></textarea></div>
212
+ </div>
213
+ <div id="mcpAddError" class="text-error text-xs py-1" style="display:none"></div>
214
+ <div style="display:flex;gap:8px;margin-top:12px;justify-content:flex-end">
215
+ <button type="button" class="btn-clear" data-action="closeMcpModal">Cancel</button>
216
+ <button type="button" class="btn-clear btn-save" data-action="mcpAddAndSync">Add & Sync</button>
217
+ </div>`;
218
+ }
219
+
220
+ function switchTab(tab: 'active' | 'add' | 'browse'): void {
221
+ if (activeListEl) activeListEl.style.display = tab === 'active' ? '' : 'none';
222
+ if (addFormEl) addFormEl.style.display = tab === 'add' ? '' : 'none';
223
+ if (browseEl) browseEl.style.display = tab === 'browse' ? '' : 'none';
224
+ tabBtns.forEach((btn, i) => {
225
+ const t = ['active', 'add', 'browse'][i];
226
+ btn.classList.toggle('is-active', t === tab);
227
+ });
228
+ if (tab === 'active') renderActiveList();
229
+ if (tab === 'add') clearAddInputs();
230
+ if (tab === 'browse') void loadRegistry();
231
+ }
232
+
233
+ function switchSubTab(): void {
234
+ const local = addFormEl?.querySelector('#mcpAddLocal') as HTMLElement | null;
235
+ const remote = addFormEl?.querySelector('#mcpAddRemote') as HTMLElement | null;
236
+ if (local) local.style.display = currentSubTab === 'local' ? '' : 'none';
237
+ if (remote) remote.style.display = currentSubTab === 'remote' ? '' : 'none';
238
+ addFormEl?.querySelectorAll<HTMLButtonElement>('[data-mcp-subtab]').forEach(btn => {
239
+ btn.classList.toggle('is-active', btn.dataset['mcpSubtab'] === currentSubTab);
240
+ });
241
+ }
242
+
243
+ function renderActiveList(): void {
244
+ if (!activeListEl || !cachedConfig) return;
245
+ const entries = Object.entries(cachedConfig.servers || {});
246
+ if (!entries.length) { activeListEl.innerHTML = '<p style="opacity:.5">No active MCP servers.</p>'; return; }
247
+ activeListEl.innerHTML = entries.map(([name, srv]) => {
248
+ const tag = getServerTag(srv);
249
+ const tagHtml = tag ? `<span class="mcp-active-tag">[${escapeHtml(tag)}]</span>` : '';
250
+ const cmdLine = srv.command ? escapeHtml(srv.command) + (srv.args?.length ? ' ' + srv.args.map(a => escapeHtml(a)).join(' ') : '') : '';
251
+ const urlLine = srv.url ? escapeHtml(srv.url) : '';
252
+ const envKeys = srv.env ? Object.keys(srv.env) : [];
253
+ const headerKeys = srv.headers ? Object.keys(srv.headers) : [];
254
+
255
+ let detailHtml = '';
256
+ if (urlLine) detailHtml += `<div class="mcp-active-detail">URL: ${urlLine}</div>`;
257
+ if (cmdLine) detailHtml += `<div class="mcp-active-detail">Command: ${cmdLine}</div>`;
258
+ if (envKeys.length) detailHtml += `<div class="mcp-active-detail">Env: ${envKeys.map(k => escapeHtml(k)).join(', ')}</div>`;
259
+ if (headerKeys.length) detailHtml += `<div class="mcp-active-detail">Headers: ${headerKeys.map(k => escapeHtml(k)).join(', ')}</div>`;
260
+
261
+ return `<div class="mcp-active-row">
262
+ <div style="flex:1">
263
+ <div style="display:flex;align-items:center;gap:6px">
264
+ <span class="mcp-active-name">${escapeHtml(name)}</span>
265
+ ${tagHtml}
266
+ </div>
267
+ ${detailHtml}
268
+ </div>
269
+ <button type="button" class="btn-clear mcp-active-remove" data-mcp-remove="${escapeHtml(name)}">Remove</button>
270
+ </div>`;
271
+ }).join('');
272
+ activeListEl.querySelectorAll<HTMLButtonElement>('[data-mcp-remove]').forEach(btn => {
273
+ btn.addEventListener('click', () => {
274
+ const name = btn.dataset['mcpRemove'];
275
+ if (name) void removeMcpServer(name);
276
+ });
277
+ });
278
+ }
279
+
280
+ async function removeMcpServer(name: string): Promise<void> {
281
+ if (!cachedConfig) return;
282
+ const nextServers = { ...cachedConfig.servers };
283
+ delete nextServers[name];
284
+ try {
285
+ await apiJson('/api/mcp', 'PUT', { ...cachedConfig, servers: nextServers });
286
+ await apiJson('/api/mcp/sync', 'POST', {});
287
+ await loadMcpServers();
288
+ renderActiveList();
289
+ } catch (e) {
290
+ showAddError((e as Error).message);
291
+ }
292
+ }
293
+
294
+ function clearAddInputs(): void {
295
+ const ids = ['mcpAddName', 'mcpAddCommand', 'mcpAddArgs', 'mcpAddEnv', 'mcpAddRemoteName', 'mcpAddUrl', 'mcpAddHeaders'];
296
+ for (const id of ids) {
297
+ const el = (addFormEl ?? document).querySelector(`#${id}`) as HTMLInputElement | HTMLTextAreaElement | null;
298
+ if (el) el.value = '';
299
+ }
300
+ hideAddError();
301
+ }
302
+
303
+ function showAddError(msg: string): void {
304
+ if (!addErrorEl) return;
305
+ addErrorEl.style.display = 'block';
306
+ addErrorEl.textContent = msg;
307
+ }
308
+
309
+ function hideAddError(): void {
310
+ if (addErrorEl) addErrorEl.style.display = 'none';
311
+ }
312
+
313
+ function parseKV(text: string): Record<string, string> {
314
+ const out: Record<string, string> = {};
315
+ for (const line of text.split(/\r?\n/)) {
316
+ const trimmed = line.trim();
317
+ if (!trimmed || trimmed.startsWith('#')) continue;
318
+ const eq = trimmed.indexOf('=');
319
+ if (eq === -1) continue;
320
+ out[trimmed.slice(0, eq).trim()] = trimmed.slice(eq + 1);
321
+ }
322
+ return out;
323
+ }
324
+
325
+ function getInput(id: string): string {
326
+ const el = (addFormEl ?? document).querySelector(`#${id}`) as HTMLInputElement | HTMLTextAreaElement | null;
327
+ return el?.value?.trim() ?? '';
328
+ }
329
+
330
+ async function handleAddAndSync(): Promise<void> {
331
+ if (!cachedConfig) return;
332
+ const isRemote = currentSubTab === 'remote';
333
+ let name: string;
334
+ let server: McpServer;
335
+
336
+ if (isRemote) {
337
+ name = getInput('mcpAddRemoteName');
338
+ const url = getInput('mcpAddUrl');
339
+ const headersText = getInput('mcpAddHeaders');
340
+ if (!name) { showAddError('Name is required.'); return; }
341
+ if (!url) { showAddError('URL is required.'); return; }
342
+ server = { url };
343
+ const h = parseKV(headersText);
344
+ if (Object.keys(h).length > 0) server.headers = h;
345
+ } else {
346
+ name = getInput('mcpAddName');
347
+ const command = getInput('mcpAddCommand');
348
+ const argsText = getInput('mcpAddArgs');
349
+ const envText = getInput('mcpAddEnv');
350
+ if (!name) { showAddError('Name is required.'); return; }
351
+ if (!command) { showAddError('Command is required.'); return; }
352
+ server = { command };
353
+ const args = argsText.split(/,|\n/).map(s => s.trim()).filter(Boolean);
354
+ if (args.length > 0) server.args = args;
355
+ const env = parseKV(envText);
356
+ if (Object.keys(env).length > 0) server.env = env;
357
+ }
358
+
359
+ if (cachedConfig.servers[name]) {
360
+ showAddError(`Server "${name}" already exists.`);
361
+ return;
362
+ }
363
+
364
+ try {
365
+ const merged = { ...cachedConfig, servers: { ...cachedConfig.servers, [name]: server } };
366
+ await apiJson('/api/mcp', 'PUT', merged);
367
+ await apiJson('/api/mcp/sync', 'POST', {});
368
+ await loadMcpServers();
369
+ closeMcpModal();
370
+ } catch (e) {
371
+ showAddError((e as Error).message);
372
+ }
373
+ }
374
+
375
+ // ── MCP Help popup (in-popup) ──
376
+
377
+ function showMcpHelp(): void {
378
+ const existing = document.getElementById('mcpHelpOverlay');
379
+ if (existing) { existing.remove(); return; }
380
+
381
+ const helpOverlay = document.createElement('div');
382
+ helpOverlay.id = 'mcpHelpOverlay';
383
+ helpOverlay.className = 'mcp-help-overlay';
384
+ helpOverlay.addEventListener('click', (e) => { if (e.target === helpOverlay) helpOverlay.remove(); });
385
+
386
+ const inner = document.createElement('div');
387
+ inner.className = 'mcp-help-inner';
388
+ inner.innerHTML = `
389
+ <h4>MCP Server</h4>
390
+ <p>MCP (Model Context Protocol) adds capabilities to AI agents — like installing apps on a phone.</p>
391
+
392
+ <h4>Local Server</h4>
393
+ <p>Runs on your machine. Provide a command and args.</p>
394
+ <pre>Name: context7
395
+ Command: npx
396
+ Args: -y, @upstash/context7-mcp</pre>
397
+
398
+ <h4>Remote Server</h4>
399
+ <p>Connects to an external URL (SSE or Streamable HTTP).</p>
400
+ <pre>Name: my-api
401
+ URL: https://mcp.example.com/sse</pre>
402
+
403
+ <h4>Server Types</h4>
404
+ <p><code>[npx]</code> Node.js package (npx -y ...)<br>
405
+ <code>[uvx]</code> Python package (uvx ...)<br>
406
+ <code>[docker]</code> Docker container<br>
407
+ <code>[remote]</code> External URL</p>
408
+
409
+ <h4>After Adding</h4>
410
+ <p>The server is automatically synced to all installed CLIs (Claude, Codex, Gemini, Cursor, Copilot, OpenCode).</p>
411
+ <p><code>Install bundle</code> converts npx/uvx servers to global binaries for faster startup.</p>
412
+
413
+ <div style="text-align:right;margin-top:12px">
414
+ <button type="button" class="btn-save" id="mcpHelpClose">OK</button>
415
+ </div>
416
+ `;
417
+ helpOverlay.append(inner);
418
+ document.body.append(helpOverlay);
419
+ inner.querySelector('#mcpHelpClose')?.addEventListener('click', () => helpOverlay.remove());
420
+ }
421
+
422
+ interface RegistryEntry {
423
+ id: string; name: string; description: string; category: string;
424
+ type: string; config: Record<string, unknown>; tags: string[]; url: string;
425
+ }
426
+
427
+ interface HarnessBuiltin {
428
+ id: string; name: string; description: string; source: string; harness: string;
429
+ standalone_config?: Record<string, unknown>;
430
+ }
431
+
432
+ async function loadRegistry(): Promise<void> {
433
+ if (!browseEl) return;
434
+ browseEl.innerHTML = '<p style="opacity:.5">Loading registry...</p>';
435
+ if (!cachedConfig) await loadMcpServers();
436
+ try {
437
+ const res = await api<{ ok: boolean; entries: RegistryEntry[]; builtins?: HarnessBuiltin[] }>('/api/mcp/registry');
438
+ if (!res?.entries?.length && !res?.builtins?.length) {
439
+ browseEl.innerHTML = '<p style="opacity:.5">No MCP servers in registry.</p>';
440
+ return;
441
+ }
442
+ const installed = cachedConfig ? Object.keys(cachedConfig.servers) : [];
443
+ let html = '';
444
+ html += res.entries.map(entry => {
445
+ const isInstalled = installed.includes(entry.id);
446
+ const tagHtml = entry.tags?.slice(0, 3).map(t => `<span style="background:var(--border);padding:1px 4px;border-radius:3px;font-size:10px">${escapeHtml(t)}</span>`).join(' ') || '';
447
+ return `<div style="padding:10px 0;border-bottom:1px solid var(--border)">
448
+ <div style="display:flex;align-items:center;gap:8px">
449
+ <b>${escapeHtml(entry.name)}</b>
450
+ <span style="opacity:.5;font-size:0.85em">[${escapeHtml(entry.type)}]</span>
451
+ <span style="opacity:.4;font-size:0.85em">${escapeHtml(entry.category)}</span>
452
+ ${isInstalled
453
+ ? '<span style="color:var(--success);font-size:11px">Installed</span>'
454
+ : `<button type="button" class="btn-clear text-xs" style="color:var(--accent)" data-registry-install="${escapeHtml(entry.id)}">+ Install</button>`
455
+ }
456
+ </div>
457
+ <p style="margin:4px 0 4px 0;font-size:12px;opacity:.75">${escapeHtml(entry.description)}</p>
458
+ <div style="display:flex;gap:4px;align-items:center">
459
+ ${tagHtml}
460
+ ${entry.url ? `<a href="${escapeHtml(entry.url)}" target="_blank" rel="noopener noreferrer" style="font-size:10px;opacity:.5;margin-left:auto">source</a>` : ''}
461
+ </div>
462
+ </div>`;
463
+ }).join('');
464
+
465
+ if (res.builtins?.length) {
466
+ html += `<div style="margin-top:16px;padding-top:12px;border-top:2px solid var(--border)">
467
+ <h4 style="font-size:12px;opacity:.6;margin:0 0 8px">Harness Built-ins (omo / omx)</h4>
468
+ <p style="font-size:11px;opacity:.4;margin:0 0 8px">Not installable via registry — built into harness runtimes. Listed for reference.</p>`;
469
+ html += res.builtins.map(b => {
470
+ const hasStandalone = b.standalone_config && Object.keys(b.standalone_config).length > 0;
471
+ return `<div style="padding:6px 0;border-bottom:1px solid var(--border)">
472
+ <div style="display:flex;align-items:center;gap:6px">
473
+ <b style="font-size:12px">${escapeHtml(b.name)}</b>
474
+ <span style="opacity:.4;font-size:0.8em">${escapeHtml(b.harness)}</span>
475
+ ${hasStandalone ? `<button type="button" class="btn-clear text-xs" style="color:var(--accent)" data-builtin-install="${escapeHtml(b.id)}">+ Install standalone</button>` : ''}
476
+ </div>
477
+ <p style="margin:2px 0;font-size:11px;opacity:.65">${escapeHtml(b.description)}</p>
478
+ </div>`;
479
+ }).join('');
480
+ html += '</div>';
481
+ }
482
+
483
+ browseEl.innerHTML = html;
484
+ browseEl.querySelectorAll<HTMLButtonElement>('[data-registry-install]').forEach(btn => {
485
+ btn.addEventListener('click', () => {
486
+ const id = btn.dataset['registryInstall'];
487
+ const entry = res.entries.find(e => e.id === id);
488
+ if (entry) void installFromRegistry(entry, btn);
489
+ });
490
+ });
491
+ browseEl.querySelectorAll<HTMLButtonElement>('[data-builtin-install]').forEach(btn => {
492
+ btn.addEventListener('click', () => {
493
+ const id = btn.dataset['builtinInstall'];
494
+ const builtin = res.builtins?.find(b => b.id === id);
495
+ if (builtin?.standalone_config) {
496
+ void installFromRegistry({
497
+ id: builtin.id,
498
+ name: builtin.name,
499
+ description: builtin.description,
500
+ category: 'harness',
501
+ type: 'remote',
502
+ config: builtin.standalone_config,
503
+ tags: [],
504
+ url: builtin.source,
505
+ }, btn);
506
+ }
507
+ });
508
+ });
509
+ } catch (e) {
510
+ browseEl.innerHTML = `<p style="color:var(--color-error)">${escapeHtml((e as Error).message)}</p>`;
511
+ }
512
+ }
513
+
514
+ async function installFromRegistry(entry: RegistryEntry, btn: HTMLButtonElement): Promise<void> {
515
+ if (!cachedConfig) return;
516
+ btn.disabled = true;
517
+ btn.textContent = 'Installing...';
518
+ try {
519
+ const server = entry.config as McpServer;
520
+ const merged = { ...cachedConfig, servers: { ...cachedConfig.servers, [entry.id]: server } };
521
+ await apiJson('/api/mcp', 'PUT', merged);
522
+ await apiJson('/api/mcp/sync', 'POST', {});
523
+ await loadMcpServers();
524
+ btn.textContent = 'Installed';
525
+ btn.style.color = 'var(--success)';
526
+ } catch (e) {
527
+ btn.textContent = 'Error';
528
+ btn.disabled = false;
529
+ console.error('[mcp-registry] install failed:', (e as Error).message);
530
+ }
531
+ }
532
+
533
+ export function openMcpModal(): void {
534
+ ensureModal();
535
+ overlay?.classList.add('open');
536
+ overlay?.setAttribute('aria-hidden', 'false');
537
+ openState = true;
538
+ switchTab('active');
539
+ }
540
+
541
+ export function closeMcpModal(): void {
542
+ if (!openState) return;
543
+ overlay?.classList.remove('open');
544
+ overlay?.setAttribute('aria-hidden', 'true');
545
+ openState = false;
546
+ clearAddInputs();
547
+ document.getElementById('mcpHelpOverlay')?.remove();
548
+ }
549
+
550
+ export function initMcpModal(): void {
551
+ document.addEventListener('keydown', (e) => {
552
+ if (document.getElementById('mcpHelpOverlay')) {
553
+ if (e.key === 'Escape') { e.preventDefault(); document.getElementById('mcpHelpOverlay')?.remove(); return; }
554
+ }
555
+ if (openState && e.key === 'Escape') {
556
+ e.preventDefault();
557
+ e.stopImmediatePropagation();
558
+ closeMcpModal();
559
+ }
560
+ }, true);
561
+ }
@@ -15,6 +15,7 @@ export interface QuotaEntry {
15
15
  sessionUsageCapable?: boolean;
16
16
  displayTier?: string;
17
17
  delegatedProvider?: string;
18
+ billing?: { usedUsd?: number; limitUsd?: number; percent?: number; periodEnd?: string };
18
19
  sessionUsage?: {
19
20
  contextTokensUsed?: number | null;
20
21
  contextWindowTokens?: number | null;
@@ -3,7 +3,7 @@ export { loadSettings, updateSettings, setPerm, getModelValue, handleModelSelect
3
3
  export { setTelegram, setForwardAll, setTelegramMentionOnly, saveTelegramSettings } from './settings-telegram.js';
4
4
  export { setDiscord, setDiscordForwardAll, setDiscordAllowBots, setDiscordMentionOnly, saveDiscordSettings } from './settings-discord.js';
5
5
  export { setActiveChannel, loadFallbackOrder, saveFallbackOrder } from './settings-channel.js';
6
- export { loadMcpServers, syncMcpServers, installMcpGlobal } from './settings-mcp.js';
6
+ export { loadMcpServers, syncMcpServers, installMcpGlobal, openMcpModal, initMcpModal } from './settings-mcp.js';
7
7
  export { loadCliStatus, scheduleCliStatusRefresh, setCliStatusInterval } from './settings-cli-status.js';
8
8
  export { initCliStatusToggle, initCliStatusPreviewHooks, isCliStatusExpanded, expandCliStatus, isEmbeddedPreviewFrame } from './settings-cli-status.js';
9
9
  export { initSttSettings } from './settings-stt.js';
@@ -4,6 +4,10 @@
4
4
 
5
5
  import { escapeHtml } from '../render.js';
6
6
  import { ICONS } from '../icons.js';
7
+ import {
8
+ displayShellCommand,
9
+ displayShellCommandDetail,
10
+ } from '../../../src/shared/shell-command-display.js';
7
11
 
8
12
  export interface ToolLogEntry {
9
13
  icon: string;
@@ -33,13 +37,23 @@ function previewText(text: string, max = 100): string {
33
37
  return singleLine.length > max ? `${singleLine.slice(0, max - 1)}…` : singleLine;
34
38
  }
35
39
 
40
+ function normalizeToolEntryForDisplay(tl: ToolLogEntry): ToolLogEntry {
41
+ if (tl.toolType && tl.toolType !== 'tool') return tl;
42
+ return {
43
+ ...tl,
44
+ label: displayShellCommand(tl.label || ''),
45
+ detail: displayShellCommandDetail(tl.detail || ''),
46
+ };
47
+ }
48
+
36
49
  function renderToolItem(tl: ToolLogEntry, idx: number): string {
37
- const icon = escapeHtml(tl.icon);
38
- const label = escapeHtml(tl.label);
39
- const detail = tl.detail || '';
50
+ const displayTool = normalizeToolEntryForDisplay(tl);
51
+ const icon = escapeHtml(displayTool.icon);
52
+ const label = escapeHtml(displayTool.label);
53
+ const detail = displayTool.detail || '';
40
54
  const detailId = `tool-detail-${Date.now()}-${idx}`;
41
55
 
42
- if (hasExpandableDetail(tl)) {
56
+ if (hasExpandableDetail(displayTool)) {
43
57
  const snippet = previewText(detail);
44
58
  const snippetHtml = snippet
45
59
  ? `<span class="tool-item-snippet">${escapeHtml(snippet)}</span>`
@@ -82,10 +82,13 @@ export async function refreshTransportStatusRow(): Promise<void> {
82
82
  const health = parseChannelHealth(payload);
83
83
  if (!health) {
84
84
  container.innerHTML = '';
85
+ container.style.display = 'none';
85
86
  return;
86
87
  }
87
88
  renderTransportStatusRow(container, health);
89
+ container.style.display = '';
88
90
  } catch {
89
91
  container.innerHTML = '';
92
+ container.style.display = 'none';
90
93
  }
91
94
  }
@@ -9,13 +9,17 @@ export function setStatus(s: string): void {
9
9
  const badge = document.getElementById('statusBadge');
10
10
  const btn = document.getElementById('btnSend');
11
11
  const label = document.getElementById('typingIndicator')?.querySelector('.label') as HTMLElement | null;
12
- state.agentBusy = s === 'running';
12
+ state.agentBusy = s === 'running' || s === 'steering';
13
13
  document.getElementById('typingIndicator')?.classList.toggle('active', state.agentBusy);
14
14
  if (s === 'running') {
15
15
  if (badge) { badge.className = 'status-badge status-running'; badge.textContent = 'running'; }
16
16
  if (btn) { btn.innerHTML = ICONS.stop; btn.title = t('btn.stop'); btn.classList.add('stop-mode'); }
17
17
  if (label) label.textContent = t('status.responding');
18
18
  showSkeleton();
19
+ } else if (s === 'steering') {
20
+ if (badge) { badge.className = 'status-badge status-steering'; badge.textContent = 'steering'; }
21
+ if (btn) { btn.innerHTML = ICONS.stop; btn.title = 'Steering...'; btn.classList.add('stop-mode'); }
22
+ if (label) label.textContent = 'Steering...';
19
23
  } else {
20
24
  if (badge) { badge.className = 'status-badge status-idle'; badge.textContent = 'idle'; }
21
25
  if (btn) { btn.innerHTML = ICONS.send; btn.title = 'Send'; btn.classList.remove('stop-mode'); }