cli-jaw 2.2.15 → 2.2.17

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 (425) hide show
  1. package/README.md +23 -2
  2. package/dist/bin/cli-jaw.js +39 -0
  3. package/dist/bin/cli-jaw.js.map +1 -1
  4. package/dist/bin/commands/_shared/dashboard-client.js +42 -0
  5. package/dist/bin/commands/_shared/dashboard-client.js.map +1 -0
  6. package/dist/bin/commands/_shared/search-format.js +40 -0
  7. package/dist/bin/commands/_shared/search-format.js.map +1 -0
  8. package/dist/bin/commands/chat-search.js +5 -3
  9. package/dist/bin/commands/chat-search.js.map +1 -1
  10. package/dist/bin/commands/dashboard-chat.js +14 -31
  11. package/dist/bin/commands/dashboard-chat.js.map +1 -1
  12. package/dist/bin/commands/dashboard-memory.js +12 -49
  13. package/dist/bin/commands/dashboard-memory.js.map +1 -1
  14. package/dist/bin/commands/doctor.js +56 -11
  15. package/dist/bin/commands/doctor.js.map +1 -1
  16. package/dist/bin/commands/init.js +31 -1
  17. package/dist/bin/commands/init.js.map +1 -1
  18. package/dist/bin/commands/memory.js +5 -1
  19. package/dist/bin/commands/memory.js.map +1 -1
  20. package/dist/bin/commands/provider.js +23 -0
  21. package/dist/bin/commands/provider.js.map +1 -1
  22. package/dist/bin/commands/slack.js +57 -3
  23. package/dist/bin/commands/slack.js.map +1 -1
  24. package/dist/bin/commands/tui/input-handler.js +1 -1
  25. package/dist/bin/commands/tui/input-handler.js.map +1 -1
  26. package/dist/bin/commands/tui/slash-command-runner.js +4 -5
  27. package/dist/bin/commands/tui/slash-command-runner.js.map +1 -1
  28. package/dist/bin/postinstall.js +16 -18
  29. package/dist/bin/postinstall.js.map +1 -1
  30. package/dist/lib/media-kind.js +28 -0
  31. package/dist/lib/media-kind.js.map +1 -0
  32. package/dist/lib/upload.js +27 -10
  33. package/dist/lib/upload.js.map +1 -1
  34. package/dist/server.js +35 -51
  35. package/dist/server.js.map +1 -1
  36. package/dist/src/agent/args.js +34 -0
  37. package/dist/src/agent/args.js.map +1 -1
  38. package/dist/src/agent/codex-app-client.js +1016 -135
  39. package/dist/src/agent/codex-app-client.js.map +1 -1
  40. package/dist/src/agent/codex-app-events.js +72 -1
  41. package/dist/src/agent/codex-app-events.js.map +1 -1
  42. package/dist/src/agent/codex-host-pool.js +617 -0
  43. package/dist/src/agent/codex-host-pool.js.map +1 -0
  44. package/dist/src/agent/jwc-runtime.js +12 -4
  45. package/dist/src/agent/jwc-runtime.js.map +1 -1
  46. package/dist/src/agent/kiro-auth.js +10 -4
  47. package/dist/src/agent/kiro-auth.js.map +1 -1
  48. package/dist/src/agent/kiro-runtime.js +45 -8
  49. package/dist/src/agent/kiro-runtime.js.map +1 -1
  50. package/dist/src/agent/lifecycle-handler.js +75 -52
  51. package/dist/src/agent/lifecycle-handler.js.map +1 -1
  52. package/dist/src/agent/memory-flush-controller.js +241 -33
  53. package/dist/src/agent/memory-flush-controller.js.map +1 -1
  54. package/dist/src/agent/prompt-context.js +4 -0
  55. package/dist/src/agent/prompt-context.js.map +1 -1
  56. package/dist/src/agent/runtime-pool.js +64 -34
  57. package/dist/src/agent/runtime-pool.js.map +1 -1
  58. package/dist/src/agent/session-persistence.js +71 -15
  59. package/dist/src/agent/session-persistence.js.map +1 -1
  60. package/dist/src/agent/spawn/queue.js +319 -162
  61. package/dist/src/agent/spawn/queue.js.map +1 -1
  62. package/dist/src/agent/spawn.js +581 -268
  63. package/dist/src/agent/spawn.js.map +1 -1
  64. package/dist/src/bgtask/types.js +1 -1
  65. package/dist/src/bgtask/types.js.map +1 -1
  66. package/dist/src/browser/adaptive-fetch/safety.js +25 -0
  67. package/dist/src/browser/adaptive-fetch/safety.js.map +1 -1
  68. package/dist/src/browser/connection.js +2 -8
  69. package/dist/src/browser/connection.js.map +1 -1
  70. package/dist/src/cli/capability-probe-worker.js +172 -0
  71. package/dist/src/cli/capability-probe-worker.js.map +1 -0
  72. package/dist/src/cli/capability-probe.js +83 -0
  73. package/dist/src/cli/capability-probe.js.map +1 -0
  74. package/dist/src/cli/claude-models.js +2 -2
  75. package/dist/src/cli/claude-models.js.map +1 -1
  76. package/dist/src/cli/cli-status-worker.js +296 -0
  77. package/dist/src/cli/cli-status-worker.js.map +1 -0
  78. package/dist/src/cli/cli-status.js +81 -0
  79. package/dist/src/cli/cli-status.js.map +1 -0
  80. package/dist/src/cli/command-context.js +17 -5
  81. package/dist/src/cli/command-context.js.map +1 -1
  82. package/dist/src/cli/compact.js +56 -19
  83. package/dist/src/cli/compact.js.map +1 -1
  84. package/dist/src/cli/handlers-runtime.js +6 -4
  85. package/dist/src/cli/handlers-runtime.js.map +1 -1
  86. package/dist/src/cli/handlers.js +7 -2
  87. package/dist/src/cli/handlers.js.map +1 -1
  88. package/dist/src/cli/opencodex-models.js +5 -32
  89. package/dist/src/cli/opencodex-models.js.map +1 -1
  90. package/dist/src/cli/opencodex-runtime.js +82 -0
  91. package/dist/src/cli/opencodex-runtime.js.map +1 -0
  92. package/dist/src/cli/readiness.js +35 -18
  93. package/dist/src/cli/readiness.js.map +1 -1
  94. package/dist/src/cli/registry-live.js +8 -2
  95. package/dist/src/cli/registry-live.js.map +1 -1
  96. package/dist/src/cli/registry.js +1 -1
  97. package/dist/src/cli/registry.js.map +1 -1
  98. package/dist/src/core/browser-open-default.js +6 -4
  99. package/dist/src/core/browser-open-default.js.map +1 -1
  100. package/dist/src/core/browser-open.js +11 -15
  101. package/dist/src/core/browser-open.js.map +1 -1
  102. package/dist/src/core/bus.js +7 -1
  103. package/dist/src/core/bus.js.map +1 -1
  104. package/dist/src/core/chat-sessions.js +121 -12
  105. package/dist/src/core/chat-sessions.js.map +1 -1
  106. package/dist/src/core/cli-detect.js +148 -4
  107. package/dist/src/core/cli-detect.js.map +1 -1
  108. package/dist/src/core/codex-config.js +21 -0
  109. package/dist/src/core/codex-config.js.map +1 -1
  110. package/dist/src/core/compact.js +73 -21
  111. package/dist/src/core/compact.js.map +1 -1
  112. package/dist/src/core/config.js +449 -20
  113. package/dist/src/core/config.js.map +1 -1
  114. package/dist/src/core/db.js +225 -0
  115. package/dist/src/core/db.js.map +1 -1
  116. package/dist/src/core/event-bus.js +49 -4
  117. package/dist/src/core/event-bus.js.map +1 -1
  118. package/dist/src/core/event-scope.js +100 -0
  119. package/dist/src/core/event-scope.js.map +1 -0
  120. package/dist/src/core/install-integrity.js +176 -0
  121. package/dist/src/core/install-integrity.js.map +1 -0
  122. package/dist/src/core/main-session.js +64 -21
  123. package/dist/src/core/main-session.js.map +1 -1
  124. package/dist/src/core/message-summary.js +12 -2
  125. package/dist/src/core/message-summary.js.map +1 -1
  126. package/dist/src/core/platform-kind.js +139 -0
  127. package/dist/src/core/platform-kind.js.map +1 -0
  128. package/dist/src/core/rate-limit.js +156 -0
  129. package/dist/src/core/rate-limit.js.map +1 -0
  130. package/dist/src/core/runtime-settings.js +165 -17
  131. package/dist/src/core/runtime-settings.js.map +1 -1
  132. package/dist/src/core/session-context.js +7 -0
  133. package/dist/src/core/session-context.js.map +1 -0
  134. package/dist/src/core/session-ops.js +53 -9
  135. package/dist/src/core/session-ops.js.map +1 -1
  136. package/dist/src/core/settings-merge.js +105 -3
  137. package/dist/src/core/settings-merge.js.map +1 -1
  138. package/dist/src/core/settings-watch.js +29 -5
  139. package/dist/src/core/settings-watch.js.map +1 -1
  140. package/dist/src/core/widget-watcher.js +15 -2
  141. package/dist/src/core/widget-watcher.js.map +1 -1
  142. package/dist/src/discord/bot.js +5 -2
  143. package/dist/src/discord/bot.js.map +1 -1
  144. package/dist/src/discord/commands.js +4 -4
  145. package/dist/src/discord/commands.js.map +1 -1
  146. package/dist/src/goal/heartbeat.js +1 -1
  147. package/dist/src/goal/heartbeat.js.map +1 -1
  148. package/dist/src/goal/runtime.js +1 -1
  149. package/dist/src/goal/runtime.js.map +1 -1
  150. package/dist/src/goal-run/controller.js +2 -2
  151. package/dist/src/goal-run/controller.js.map +1 -1
  152. package/dist/src/manager/internal-fetch.js +15 -0
  153. package/dist/src/manager/internal-fetch.js.map +1 -0
  154. package/dist/src/manager/logs.js +2 -1
  155. package/dist/src/manager/logs.js.map +1 -1
  156. package/dist/src/manager/memory/chat-federation.js +104 -11
  157. package/dist/src/manager/memory/chat-federation.js.map +1 -1
  158. package/dist/src/manager/memory/federation.js +100 -0
  159. package/dist/src/manager/memory/federation.js.map +1 -1
  160. package/dist/src/manager/metadata.js +4 -1
  161. package/dist/src/manager/metadata.js.map +1 -1
  162. package/dist/src/manager/notes/assets.js +1 -1
  163. package/dist/src/manager/notes/assets.js.map +1 -1
  164. package/dist/src/manager/notes/frontmatter.js +5 -49
  165. package/dist/src/manager/notes/frontmatter.js.map +1 -1
  166. package/dist/src/manager/notes/link-resolver.js +2 -2
  167. package/dist/src/manager/notes/link-resolver.js.map +1 -1
  168. package/dist/src/manager/notes/remote-assets.js +1 -1
  169. package/dist/src/manager/notes/remote-assets.js.map +1 -1
  170. package/dist/src/manager/notes/routes.js +2 -2
  171. package/dist/src/manager/notes/routes.js.map +1 -1
  172. package/dist/src/manager/notes/store.js +2 -2
  173. package/dist/src/manager/notes/store.js.map +1 -1
  174. package/dist/src/manager/notes/trash.js +1 -1
  175. package/dist/src/manager/notes/trash.js.map +1 -1
  176. package/dist/src/manager/notes/vault-index.js +2 -2
  177. package/dist/src/manager/notes/vault-index.js.map +1 -1
  178. package/dist/src/manager/notes/wiki-links.js +1 -1
  179. package/dist/src/manager/notes/wiki-links.js.map +1 -1
  180. package/dist/src/manager/notes/wiki-routes.js +84 -0
  181. package/dist/src/manager/notes/wiki-routes.js.map +1 -0
  182. package/dist/src/manager/proxy.js +1 -0
  183. package/dist/src/manager/proxy.js.map +1 -1
  184. package/dist/src/manager/routes/dashboard-memory.js +24 -1
  185. package/dist/src/manager/routes/dashboard-memory.js.map +1 -1
  186. package/dist/src/manager/routes/runtime-monitor.js +1 -1
  187. package/dist/src/manager/routes/runtime-monitor.js.map +1 -1
  188. package/dist/src/manager/scan.js +5 -3
  189. package/dist/src/manager/scan.js.map +1 -1
  190. package/dist/src/manager/server.js +20 -6
  191. package/dist/src/manager/server.js.map +1 -1
  192. package/dist/src/manager/telegram-hub/hub-bot.js +4 -3
  193. package/dist/src/manager/telegram-hub/hub-bot.js.map +1 -1
  194. package/dist/src/manager/worker-events.js +2 -1
  195. package/dist/src/manager/worker-events.js.map +1 -1
  196. package/dist/src/memory/heartbeat.js +6 -5
  197. package/dist/src/memory/heartbeat.js.map +1 -1
  198. package/dist/src/memory/indexing.js +162 -45
  199. package/dist/src/memory/indexing.js.map +1 -1
  200. package/dist/src/messaging/channel-validate.js +14 -1
  201. package/dist/src/messaging/channel-validate.js.map +1 -1
  202. package/dist/src/messaging/redact.js +2 -1
  203. package/dist/src/messaging/redact.js.map +1 -1
  204. package/dist/src/messaging/session-key.js +21 -2
  205. package/dist/src/messaging/session-key.js.map +1 -1
  206. package/dist/src/notes/constants.js.map +1 -0
  207. package/dist/src/notes/frontmatter.js +59 -0
  208. package/dist/src/notes/frontmatter.js.map +1 -0
  209. package/dist/src/notes/path-guards.js.map +1 -0
  210. package/dist/src/notes/search.js.map +1 -0
  211. package/dist/src/orchestrator/attestation.js +1 -1
  212. package/dist/src/orchestrator/attestation.js.map +1 -1
  213. package/dist/src/orchestrator/gateway.js +135 -31
  214. package/dist/src/orchestrator/gateway.js.map +1 -1
  215. package/dist/src/orchestrator/pipeline.js +53 -21
  216. package/dist/src/orchestrator/pipeline.js.map +1 -1
  217. package/dist/src/orchestrator/scope.js +36 -2
  218. package/dist/src/orchestrator/scope.js.map +1 -1
  219. package/dist/src/orchestrator/session-lanes.js +87 -0
  220. package/dist/src/orchestrator/session-lanes.js.map +1 -0
  221. package/dist/src/orchestrator/session-work.js +25 -0
  222. package/dist/src/orchestrator/session-work.js.map +1 -0
  223. package/dist/src/orchestrator/state-machine.js +1 -5
  224. package/dist/src/orchestrator/state-machine.js.map +1 -1
  225. package/dist/src/orchestrator/worker-registry.js +20 -10
  226. package/dist/src/orchestrator/worker-registry.js.map +1 -1
  227. package/dist/src/prompt/builder.js +40 -2
  228. package/dist/src/prompt/builder.js.map +1 -1
  229. package/dist/src/prompt/templates/a1-system.md +8 -1
  230. package/dist/src/routes/agent-control.js +44 -8
  231. package/dist/src/routes/agent-control.js.map +1 -1
  232. package/dist/src/routes/chat-sessions.js +34 -6
  233. package/dist/src/routes/chat-sessions.js.map +1 -1
  234. package/dist/src/routes/command.js +63 -8
  235. package/dist/src/routes/command.js.map +1 -1
  236. package/dist/src/routes/events.js +11 -2
  237. package/dist/src/routes/events.js.map +1 -1
  238. package/dist/src/routes/link-preview.js +1 -27
  239. package/dist/src/routes/link-preview.js.map +1 -1
  240. package/dist/src/routes/messages.js +6 -5
  241. package/dist/src/routes/messages.js.map +1 -1
  242. package/dist/src/routes/messaging.js +45 -1
  243. package/dist/src/routes/messaging.js.map +1 -1
  244. package/dist/src/routes/orchestrate.js +53 -33
  245. package/dist/src/routes/orchestrate.js.map +1 -1
  246. package/dist/src/routes/search.js +84 -0
  247. package/dist/src/routes/search.js.map +1 -0
  248. package/dist/src/routes/session-request.js +29 -0
  249. package/dist/src/routes/session-request.js.map +1 -0
  250. package/dist/src/routes/settings.js +110 -3
  251. package/dist/src/routes/settings.js.map +1 -1
  252. package/dist/src/routes/static.js +30 -8
  253. package/dist/src/routes/static.js.map +1 -1
  254. package/dist/src/routes/system.js +1 -1
  255. package/dist/src/routes/system.js.map +1 -1
  256. package/dist/src/routes/wiki.js +122 -0
  257. package/dist/src/routes/wiki.js.map +1 -0
  258. package/dist/src/search/contract.js +2 -0
  259. package/dist/src/search/contract.js.map +1 -0
  260. package/dist/src/search/coordinator.js +153 -0
  261. package/dist/src/search/coordinator.js.map +1 -0
  262. package/dist/src/search/provider.js +40 -0
  263. package/dist/src/search/provider.js.map +1 -0
  264. package/dist/src/search/providers/chat.js +115 -0
  265. package/dist/src/search/providers/chat.js.map +1 -0
  266. package/dist/src/search/providers/memory.js +53 -0
  267. package/dist/src/search/providers/memory.js.map +1 -0
  268. package/dist/src/search/providers/wiki.js +80 -0
  269. package/dist/src/search/providers/wiki.js.map +1 -0
  270. package/dist/src/slack/api.js +10 -1
  271. package/dist/src/slack/api.js.map +1 -1
  272. package/dist/src/slack/attachment-recovery.js +42 -0
  273. package/dist/src/slack/attachment-recovery.js.map +1 -0
  274. package/dist/src/slack/bot.js +120 -41
  275. package/dist/src/slack/bot.js.map +1 -1
  276. package/dist/src/slack/commands.js +24 -8
  277. package/dist/src/slack/commands.js.map +1 -1
  278. package/dist/src/slack/events.js +12 -1
  279. package/dist/src/slack/events.js.map +1 -1
  280. package/dist/src/slack/history.js +108 -0
  281. package/dist/src/slack/history.js.map +1 -0
  282. package/dist/src/slack/inbound-file.js +242 -0
  283. package/dist/src/slack/inbound-file.js.map +1 -0
  284. package/dist/src/slack/inbound-url.js +39 -0
  285. package/dist/src/slack/inbound-url.js.map +1 -0
  286. package/dist/src/slack/ingress.js +140 -0
  287. package/dist/src/slack/ingress.js.map +1 -0
  288. package/dist/src/slack/manifest.js +3 -0
  289. package/dist/src/slack/manifest.js.map +1 -1
  290. package/dist/src/slack/socket.js +1 -1
  291. package/dist/src/slack/socket.js.map +1 -1
  292. package/dist/src/slack/thread-tracker.js +86 -0
  293. package/dist/src/slack/thread-tracker.js.map +1 -0
  294. package/dist/src/telegram/bot.js +21 -11
  295. package/dist/src/telegram/bot.js.map +1 -1
  296. package/dist/src/wiki/config.js +193 -0
  297. package/dist/src/wiki/config.js.map +1 -0
  298. package/dist/src/wiki/entities.js +61 -0
  299. package/dist/src/wiki/entities.js.map +1 -0
  300. package/dist/src/wiki/ontology.js +72 -0
  301. package/dist/src/wiki/ontology.js.map +1 -0
  302. package/dist/src/wiki/prompt.js +172 -0
  303. package/dist/src/wiki/prompt.js.map +1 -0
  304. package/dist/src/wiki/safe-traversal.js +198 -0
  305. package/dist/src/wiki/safe-traversal.js.map +1 -0
  306. package/dist/src/wiki/scaffold.js +77 -0
  307. package/dist/src/wiki/scaffold.js.map +1 -0
  308. package/package.json +6 -5
  309. package/public/css/session-hub.css +266 -0
  310. package/public/dist/assets/AdvancedExport-DYGcCAUq.js +1 -0
  311. package/public/dist/assets/Agent-CNNQ7KkJ.js +1 -0
  312. package/public/dist/assets/{DesignPanel-BGMPhZSx.js → DesignPanel-DcL369nB.js} +1 -1
  313. package/public/dist/assets/{DocPanel-Dz-J_l5M.js → DocPanel-K8A2pm_1.js} +1 -1
  314. package/public/dist/assets/{FolderPanel-DbPhzzvi.js → FolderPanel-CV52EzwG.js} +1 -1
  315. package/public/dist/assets/{MilkdownWysiwygEditor-Em7iC6y9.js → MilkdownWysiwygEditor-BKOCDI4Z.js} +1 -1
  316. package/public/dist/assets/api-B25zNNFJ.js +1 -0
  317. package/public/dist/assets/{app-DX4e6isX.css → app-DjgGeXhJ.css} +1 -1
  318. package/public/dist/assets/app-Dsgp4xpU.js +55 -0
  319. package/public/dist/assets/bgtask-badge-C6h5C-o4.js +1 -0
  320. package/public/dist/assets/{bgtask-badge-qMkKOZx0.js → bgtask-badge-CpavV0Jc.js} +4 -4
  321. package/public/dist/assets/{employees-BnobWM_2.js → employees-BJyEgim7.js} +4 -4
  322. package/public/dist/assets/idb-cache-B5PX63p7.js +1 -0
  323. package/public/dist/assets/{idb-cache-BzzftUET.js → idb-cache-lOntwU3S.js} +1 -1
  324. package/public/dist/assets/{iframe-renderer-C5vRbbl9.js → iframe-renderer-B8k3AvTv.js} +12 -12
  325. package/public/dist/assets/iframe-renderer-BO_GgCTR.js +1 -0
  326. package/public/dist/assets/manager-LkGs6qEJ.css +1 -0
  327. package/public/dist/assets/manager-kXYQyMhR.js +13 -0
  328. package/public/dist/assets/{memory-DF4kPwwC.js → memory-D2RbBVO-.js} +11 -11
  329. package/public/dist/assets/memory-amsvg4Ey.js +1 -0
  330. package/public/dist/assets/message-history-BGHZxvgV.js +1 -0
  331. package/public/dist/assets/message-history-Bw2E_b8L.js +1 -0
  332. package/public/dist/assets/pi-settings-5HVg1sXJ.js +1 -0
  333. package/public/dist/assets/render-BkGcpH7z.js +157 -0
  334. package/public/dist/assets/settings-B1FPORO2.js +56 -0
  335. package/public/dist/assets/settings-CMN-zN4Q.js +1 -0
  336. package/public/dist/assets/settings-core-B_OjGYVN.js +1 -0
  337. package/public/dist/assets/settings-core-CxRwqx86.js +144 -0
  338. package/public/dist/assets/sidebar-DW78DANx.js +49 -0
  339. package/public/dist/assets/skills-Dz-9Yrxr.js +1 -0
  340. package/public/dist/assets/{skills-IGquen_j.js → skills-lWi0ZFiV.js} +6 -6
  341. package/public/dist/assets/{slash-commands-ZRDOL99E.js → slash-commands-DYOI6nKj.js} +1 -1
  342. package/public/dist/assets/slash-commands-xJFCdTTM.js +1 -0
  343. package/public/dist/assets/{trace-drawer-D8To8fYt.js → trace-drawer-DBX9xzmt.js} +1 -1
  344. package/public/dist/assets/{ui-Hx_mNoDf.js → ui-Bx7eqnXt.js} +1 -1
  345. package/public/dist/assets/ui-JOcrYeG-.js +1 -0
  346. package/public/dist/assets/{wiki-link-suggestions-DZQc78gj.js → wiki-link-suggestions-Dp6kBQVu.js} +1 -1
  347. package/public/dist/index.html +4 -4
  348. package/public/dist/manager/index.html +2 -2
  349. package/public/index.html +3 -2
  350. package/public/js/event-channel.ts +25 -0
  351. package/public/js/features/channel-onboarding-flow.ts +16 -1
  352. package/public/js/features/channel-onboarding.ts +20 -2
  353. package/public/js/features/chat-messages.ts +3 -1
  354. package/public/js/features/chat-search.ts +2 -1
  355. package/public/js/features/chat.ts +56 -18
  356. package/public/js/features/elicitation.ts +15 -0
  357. package/public/js/features/idb-cache.ts +34 -0
  358. package/public/js/features/message-history.ts +2 -1
  359. package/public/js/features/session-hub.ts +334 -0
  360. package/public/js/features/settings-cli-status-render.ts +1 -1
  361. package/public/js/features/settings-cli-status.ts +25 -11
  362. package/public/js/features/settings-core.ts +72 -3
  363. package/public/js/features/settings-types.ts +32 -0
  364. package/public/js/features/ui-status.ts +2 -1
  365. package/public/js/main.ts +20 -0
  366. package/public/js/render/compose-block.ts +7 -0
  367. package/public/js/ws.ts +22 -2
  368. package/public/locales/en.json +46 -4
  369. package/public/locales/ja.json +46 -4
  370. package/public/locales/ko.json +46 -4
  371. package/public/locales/zh.json +46 -4
  372. package/public/manager/src/App.tsx +1 -1
  373. package/public/manager/src/InstancePreview.tsx +5 -1
  374. package/public/manager/src/api.ts +2 -1
  375. package/public/manager/src/components/InstanceGroups.tsx +10 -0
  376. package/public/manager/src/components/InstanceListContent.tsx +24 -1
  377. package/public/manager/src/components/InstanceRow.tsx +33 -3
  378. package/public/manager/src/components/InstanceSessionList.tsx +132 -0
  379. package/public/manager/src/hooks/useActiveSessionDisclosure.ts +45 -0
  380. package/public/manager/src/lib/resilient-fetch.ts +93 -0
  381. package/public/manager/src/lib/session-store.ts +216 -0
  382. package/public/manager/src/manager-components.css +97 -0
  383. package/public/manager/src/settings/pages/AdvancedExport.tsx +12 -2
  384. package/public/manager/src/settings/pages/Agent.tsx +113 -1
  385. package/public/manager/src/settings/pages/components/agent/agent-meta.ts +1 -1
  386. package/scripts/bundle-sidecar.sh +50 -2
  387. package/scripts/burst-scenario.mjs +72 -0
  388. package/scripts/check-redaction-sinks.mjs +1 -0
  389. package/scripts/check-strict-baseline.mjs +1 -1
  390. package/scripts/ensure-native-modules.cjs +50 -3
  391. package/scripts/install-risk-gate.mjs +8 -0
  392. package/scripts/install-wsl.sh +27 -2
  393. package/scripts/install.ps1 +121 -0
  394. package/scripts/install.sh +28 -2
  395. package/scripts/postinstall-guard.cjs +44 -2
  396. package/scripts/release-gates.mjs +12 -0
  397. package/dist/src/manager/notes/constants.js.map +0 -1
  398. package/dist/src/manager/notes/path-guards.js.map +0 -1
  399. package/dist/src/manager/notes/search.js.map +0 -1
  400. package/public/dist/assets/AdvancedExport-DsDpqXoH.js +0 -1
  401. package/public/dist/assets/Agent-BjbZVZ9p.js +0 -1
  402. package/public/dist/assets/api-C9dOxby7.js +0 -1
  403. package/public/dist/assets/app-BzD_ZLvt.js +0 -55
  404. package/public/dist/assets/bgtask-badge-Dqbp-Y4e.js +0 -1
  405. package/public/dist/assets/idb-cache-ZH6lOebk.js +0 -1
  406. package/public/dist/assets/iframe-renderer-Df4KIVyx.js +0 -1
  407. package/public/dist/assets/manager-C4eNDNFt.css +0 -1
  408. package/public/dist/assets/manager-DaN201mN.js +0 -13
  409. package/public/dist/assets/memory-D-bULTHl.js +0 -1
  410. package/public/dist/assets/message-history-C4WOisGx.js +0 -1
  411. package/public/dist/assets/message-history-ZBoza6ew.js +0 -1
  412. package/public/dist/assets/pi-settings-CBUGDAuT.js +0 -1
  413. package/public/dist/assets/render-DYX6GRQ0.js +0 -122
  414. package/public/dist/assets/settings-DbJpGoaX.js +0 -55
  415. package/public/dist/assets/settings-SreihUje.js +0 -1
  416. package/public/dist/assets/settings-core-B1Y5Nb4Z.js +0 -1
  417. package/public/dist/assets/settings-core-DobZWIZ7.js +0 -140
  418. package/public/dist/assets/sidebar-Cp22g0Gv.js +0 -49
  419. package/public/dist/assets/skills-DwPIP08e.js +0 -1
  420. package/public/dist/assets/slash-commands-BBVfwcnW.js +0 -1
  421. package/public/dist/assets/ui-CAicpUZc.js +0 -1
  422. /package/dist/src/{manager/notes → notes}/constants.js +0 -0
  423. /package/dist/src/{manager/notes → notes}/path-guards.js +0 -0
  424. /package/dist/src/{manager/notes → notes}/search.js +0 -0
  425. /package/public/dist/assets/{pi-settings-Dh5lgb87.js → pi-settings-DEuKgvIj.js} +0 -0
@@ -1,4 +1,6 @@
1
1
  import { escapeHtml } from './html.js';
2
+ import { t } from '../features/i18n.js';
3
+ import { canSendFromCurrentView, showReadOnlySwitchAffordance } from '../features/session-hub.js';
2
4
 
3
5
  type ComposeKind = 'email' | 'message' | 'document' | 'other';
4
6
 
@@ -288,6 +290,11 @@ function submitFollowup(block: HTMLElement, spec: ComposeBlockSpec): void {
288
290
  setFollowupNotice(block, '채팅 입력창을 찾을 수 없습니다.');
289
291
  return;
290
292
  }
293
+ if (!canSendFromCurrentView()) {
294
+ showReadOnlySwitchAffordance();
295
+ setFollowupNotice(block, t('sessionReadonly.composeRejected'));
296
+ return;
297
+ }
291
298
  const { subject, body } = currentText(block);
292
299
  input.value = composeFollowupPrompt(spec, subject, body, instruction);
293
300
  input.dispatchEvent(createInputEvent(input, 'input'));
package/public/js/ws.ts CHANGED
@@ -12,6 +12,7 @@ import type { HeartbeatRuntimeState, OrcStateName, ResolvedSelectionState } from
12
12
  import { notifyUnreadResponse } from './features/attention-badge.js';
13
13
  import { shouldApplyOrcStateEvent } from './features/orchestrate-scope.js';
14
14
  import { providerLabel } from './provider-icons.js';
15
+ import { handleSessionListBroadcast } from './features/session-hub.js';
15
16
 
16
17
  const ROADMAP_PHASES = ['I', 'P', 'A', 'B', 'C'] as const;
17
18
 
@@ -113,6 +114,7 @@ interface WsMessage {
113
114
  steerWaitMs?: number;
114
115
  textLen?: number;
115
116
  sseReplay?: boolean;
117
+ deleted?: { id?: string; seq?: number };
116
118
  }
117
119
 
118
120
  // Agent phase state (populated by agent_status events from orchestrator)
@@ -331,6 +333,17 @@ function requestBrowserRestoreSync(reason: string): void {
331
333
  // same path for forward-compat and resolves to a signature-skip no-op today.
332
334
  function handleSettingsChange(msg: { cli?: string; projectDirs?: string[] | null; changedKeys?: string[] }): void {
333
335
  const changedKeys = Array.isArray(msg.changedKeys) ? msg.changedKeys : [];
336
+ // Turning multi-session on or off changes what the SERVER puts on every event and
337
+ // what this tab is subscribed to, and the two are decided at different times: the
338
+ // session view is built once at boot and the channel carries the scope it produced.
339
+ // Leaving a live page running across that change gives one of two bad outcomes — a
340
+ // tab still filtered to `local:<id>` after the server stopped stamping scopes goes
341
+ // silent, and an unscoped connection after the gate comes on starts receiving every
342
+ // session's output. Neither is repairable from here, so the page reloads (072 §1.3a).
343
+ if (changedKeys.includes('multiSession')) {
344
+ window.location.reload();
345
+ return;
346
+ }
334
347
  if (changedKeys.includes('workingDir') || changedKeys.includes('projectDirs')) {
335
348
  // 82 A-phase audit: never reassign snapshotReady here — only
336
349
  // channel-up/replay-gap own that promise (orc_state gate awaits it).
@@ -1063,8 +1076,13 @@ function handleServerEvent(msg: WsMessage): void {
1063
1076
  getVirtualScroll().clear();
1064
1077
  const el = document.getElementById('chatMessages');
1065
1078
  if (el) el.innerHTML = '';
1066
- // Intentional clear — also wipe IndexedDB cache
1067
- import('./features/idb-cache.js').then(m => m.clearCache()).catch(() => {});
1079
+ // Intentional clear — also wipe this tab's cached history. The cache is keyed by
1080
+ // location and working directory, NOT by execution scope, so it clears its own
1081
+ // current scope rather than the one the event carries: passing the server's scope
1082
+ // here would name a key the cache has never written and delete nothing.
1083
+ // The tab only reaches this branch for a clear it owns, because the SSE filter
1084
+ // already dropped other sessions' clears upstream.
1085
+ import('./features/idb-cache.js').then(m => m.clearScopedCache()).catch(() => {});
1068
1086
  } else if (msg.type === 'session_reset') {
1069
1087
  addSystemMsg(`${ICONS.refresh} Session reset — history preserved`, 'tool-activity');
1070
1088
  } else if (msg.type === 'agent_added' || msg.type === 'agent_updated' || msg.type === 'agent_deleted') {
@@ -1123,6 +1141,8 @@ function handleServerEvent(msg: WsMessage): void {
1123
1141
  addSystemMsg(`⚠️ Goal continuation failed: ${escapeHtml(msg.error || '')}`, 'tool-activity');
1124
1142
  } else if (msg.type === 'settings_change') {
1125
1143
  handleSettingsChange(msg as { cli?: string; projectDirs?: string[] | null; changedKeys?: string[] });
1144
+ } else if (msg.type === 'session_list') {
1145
+ handleSessionListBroadcast(msg);
1126
1146
  } else if (msg.type === 'session_switched' || msg.type === 'session_created') {
1127
1147
  // Reload messages for the new active session
1128
1148
  window.location.reload();
@@ -152,6 +152,8 @@
152
152
  "ws.disconnected": "Disconnected — reconnecting...",
153
153
  "tg.settingsUnsupported": "Settings changes are not supported on Telegram.",
154
154
  "dc.settingsUnsupported": "Settings changes are not supported on Discord.",
155
+ "sl.settingsUnsupported": "Settings changes are not supported on Slack.",
156
+ "cmd.runtimeSelectionInstanceWide": "The CLI and model are shared by every session on this instance. Change them from the instance web settings.",
155
157
  "tg.promptUnsupported": "(Not supported on Telegram)",
156
158
  "tg.queued": "Added to queue (#{count})",
157
159
  "tg.imageCaption": "[📷 Image] {caption}",
@@ -202,12 +204,39 @@
202
204
  "cli.noReadyCli": "No authenticated CLI available — install and authenticate at least one CLI above to get started.",
203
205
  "chat.cmd.fail": "Command execution failed: {msg}",
204
206
  "chat.file.sent": "[User sent a file: {path}]\nPlease read and analyze this file.",
207
+ "chat.file.sentImage": "[User sent an image: {path}]\nPlease analyze this image.",
208
+ "chat.file.sentVideo": "[User sent a video: {path}]\nPlease check this video file.",
205
209
  "chat.file.sentWithMsg": "\n\nUser message: {text}",
206
210
  "chat.file.uploadFail": "File upload failed: {msg}",
207
211
  "chat.requestFail": "Request failed ({status})",
208
212
  "chat.continue": "Continuing the current task.",
209
213
  "chat.noPendingContinue": "No pending work to continue.",
210
214
  "chat.voice.label": "🎤 [Voice message]",
215
+ "sessionHub.title": "Sessions",
216
+ "sessionHub.description": "Review local and channel conversations by session.",
217
+ "sessionHub.defaultSession": "Default session",
218
+ "sessionHub.sessionLabel": "Session {seq}",
219
+ "sessionHub.source.local": "Local",
220
+ "sessionHub.source.slack": "Slack",
221
+ "sessionHub.source.telegram": "Telegram",
222
+ "sessionHub.source.discord": "Discord",
223
+ "sessionHub.messages": "Messages",
224
+ "sessionHub.lastActivity": "Last activity",
225
+ "sessionHub.noActivity": "No activity",
226
+ "sessionHub.empty.title": "No channel sessions yet",
227
+ "sessionHub.empty.description": "Connect a channel and each conversation will appear here as a session.",
228
+ "sessionHub.empty.action": "Connect a channel in settings",
229
+ "sessionHub.listAria": "Session list",
230
+ "sessionHub.delete": "Delete",
231
+ "sessionHub.deleteConfirm": "Delete this session? Its conversation history will also be deleted.",
232
+ "sessionHub.deleteRemoteDisabled": "Sessions connected to a channel cannot be deleted.",
233
+ "sessionHub.deleteFailed": "The session could not be deleted. Check whether it has active work.",
234
+ "sessionReadonly.message": "Read-only. Switch to this session before sending.",
235
+ "sessionReadonly.remote": "Sessions connected to a channel are read-only on the web.",
236
+ "sessionReadonly.switch": "Switch to /{seq}",
237
+ "sessionReadonly.openSessions": "Open session list",
238
+ "sessionReadonly.composeRejected": "This session is read-only. Use the switch action above.",
239
+ "sessionReadonly.elicitationRejected": "Responses cannot be sent from a read-only session. Switch sessions and try again.",
211
240
  "skill.loadFail": "Failed to load skills",
212
241
  "skill.count": "{active} active / {total} total",
213
242
  "skill.countFiltered": "{shown} shown / {active} active / {total} total",
@@ -825,9 +854,9 @@
825
854
  "bgtask.title": "Background",
826
855
  "tg.elicitationExpired": "Selection expired. Please reply with text.",
827
856
  "settings.slack.guide.step1Title": "Create the Slack app",
828
- "settings.slack.guide.step1Desc": "Create an App → From an app manifest → pick workspace → paste",
857
+ "settings.slack.guide.step1Desc": "Create an App → From an app manifest → pick workspace → paste. For an existing app, add files:read.",
829
858
  "settings.slack.guide.copyManifest": "Copy manifest",
830
- "settings.slack.guide.copyManifestDone": "Copied — paste it into Slack",
859
+ "settings.slack.guide.copyManifestDone": "Copied — paste the files:read manifest into Slack",
831
860
  "settings.slack.guide.copyManifestFail": "Copy failed — use jaw slack manifest",
832
861
  "settings.slack.guide.openApps": "Open apps page",
833
862
  "settings.slack.guide.step2Title": "Paste the bot token",
@@ -838,10 +867,21 @@
838
867
  "settings.slack.advanced": "Advanced settings",
839
868
  "settings.slack.attachPort": "Attach instance port",
840
869
  "settings.channel.notAttachInstanceHint": "Another instance owns this Slack connection (check the attach instance port)",
841
- "settings.slack.guide.step2Desc": "App settings → OAuth & Permissions → Install to Workspace → copy Bot User OAuth Token",
870
+ "settings.slack.guide.step2Desc": "App settings → OAuth & Permissions → confirm files:read → Reinstall to Workspace → copy Bot User OAuth Token",
842
871
  "settings.slack.guide.step3Location": "App settings → Basic Information → App-Level Tokens → Generate Token (connections:write)",
843
872
  "slack.progress.start": "Gathering context...",
844
873
  "slack.progress.working": "Working",
874
+ "slack.files.partialFailure": "⚠️ Some attachments were skipped:",
875
+ "slack.files.allFailure": "⚠️ No attachment could be processed, so the request was not run:",
876
+ "slack.files.limit": "Files are limited to 50 MiB each and 10 files or 100 MiB per message.",
877
+ "slack.files.error.external_file_unsupported": "External Slack files are not supported",
878
+ "slack.files.error.private_network": "The download location is not safe",
879
+ "slack.files.error.redirect_limit": "The redirect limit was exceeded",
880
+ "slack.files.error.size_exceeded": "The file size limit was exceeded",
881
+ "slack.files.error.message_budget_exceeded": "The message attachment limit was exceeded",
882
+ "slack.files.error.missing_scope": "Add files:read and reinstall the app",
883
+ "slack.files.error.ingress_cancelled": "Processing was cancelled",
884
+ "slack.files.error.download_failed": "The file could not be downloaded",
845
885
  "onboarding.open": "Setup wizard",
846
886
  "onboarding.optional": "optional",
847
887
  "onboarding.validate": "Validate",
@@ -854,6 +894,8 @@
854
894
  "onboarding.guide.telegram": "Open @BotFather in Telegram, send /newbot, pick a name and username, and copy the bot token it returns. Paste it below and press Validate.",
855
895
  "onboarding.guide.discord": "At discord.com/developers/applications choose New Application, then Bot, then Reset Token. Enable MESSAGE CONTENT INTENT under Privileged Gateway Intents. Get the server ID by enabling Developer Mode in Discord, then right-click the server and copy its ID.",
856
896
  "onboarding.guide.slack": "At api.slack.com/apps use Create an App, From an app manifest. Then get the bot token (xoxb-) from OAuth & Permissions, Install to Workspace, and the app-level token (xapp-, connections:write) from Basic Information, App-Level Tokens.",
897
+ "onboarding.slackExistingApp": "For an existing app, add files:read under OAuth & Permissions, then choose Reinstall to Workspace.",
898
+ "onboarding.warning.missingCapabilities": "Optional capability {capabilities} is missing, so inbound attachments are disabled. Add it and reinstall the app. Text messages still work.",
857
899
  "onboarding.token.botToken": "Bot token",
858
900
  "onboarding.token.appToken": "App-level token",
859
901
  "onboarding.token.guildId": "Server ID",
@@ -886,4 +928,4 @@
886
928
  "onboarding.hint.slack.botToken": "Bot User OAuth Token from OAuth & Permissions (starts with xoxb-).",
887
929
  "onboarding.hint.slack.appToken": "Basic Information, App-Level Tokens (xapp-, connections:write).",
888
930
  "onboarding.progressLabel": "Step {step} of {total}"
889
- }
931
+ }
@@ -150,6 +150,8 @@
150
150
  "ws.disconnected": "接続が切れました — 再接続中...",
151
151
  "tg.settingsUnsupported": "Telegram では設定変更に対応していません。",
152
152
  "dc.settingsUnsupported": "Discord では設定変更に対応していません。",
153
+ "sl.settingsUnsupported": "Slack では設定変更に対応していません。",
154
+ "cmd.runtimeSelectionInstanceWide": "CLI とモデルの選択はこのインスタンスの全セッションで共有されます。インスタンスのウェブ設定から変更してください。",
153
155
  "tg.promptUnsupported": "(Telegram では未対応)",
154
156
  "tg.queued": "キューに追加しました(#{count})",
155
157
  "tg.imageCaption": "[📷 画像] {caption}",
@@ -200,12 +202,39 @@
200
202
  "cli.noReadyCli": "認証済み CLI がありません。開始するには、上の一覧から少なくとも 1 つの CLI をインストールして認証してください。",
201
203
  "chat.cmd.fail": "コマンド実行に失敗しました: {msg}",
202
204
  "chat.file.sent": "[ユーザーがファイルを送信しました: {path}]\nこのファイルを読み取って分析してください。",
205
+ "chat.file.sentImage": "[ユーザーが画像を送信しました: {path}]\nこの画像を分析してください。",
206
+ "chat.file.sentVideo": "[ユーザーが動画を送信しました: {path}]\nこの動画ファイルを確認してください。",
203
207
  "chat.file.sentWithMsg": "\n\nユーザーメッセージ: {text}",
204
208
  "chat.file.uploadFail": "ファイルのアップロードに失敗しました: {msg}",
205
209
  "chat.requestFail": "リクエストに失敗しました({status})",
206
210
  "chat.continue": "現在の作業を続行しています。",
207
211
  "chat.noPendingContinue": "続行できる保留中の作業はありません。",
208
212
  "chat.voice.label": "🎤 [音声メッセージ]",
213
+ "sessionHub.title": "セッション",
214
+ "sessionHub.description": "ローカルとチャンネルの会話をセッション別に確認します。",
215
+ "sessionHub.defaultSession": "基本セッション",
216
+ "sessionHub.sessionLabel": "セッション {seq}",
217
+ "sessionHub.source.local": "ローカル",
218
+ "sessionHub.source.slack": "Slack",
219
+ "sessionHub.source.telegram": "Telegram",
220
+ "sessionHub.source.discord": "Discord",
221
+ "sessionHub.messages": "メッセージ",
222
+ "sessionHub.lastActivity": "最終アクティビティ",
223
+ "sessionHub.noActivity": "アクティビティなし",
224
+ "sessionHub.empty.title": "チャンネルセッションはまだありません",
225
+ "sessionHub.empty.description": "チャンネルを接続すると、会話ごとのセッションがここに表示されます。",
226
+ "sessionHub.empty.action": "設定でチャンネルを接続",
227
+ "sessionHub.listAria": "セッション一覧",
228
+ "sessionHub.delete": "削除",
229
+ "sessionHub.deleteConfirm": "このセッションを削除しますか?会話履歴も一緒に削除されます。",
230
+ "sessionHub.deleteRemoteDisabled": "チャンネルに接続されたセッションは削除できません。",
231
+ "sessionHub.deleteFailed": "セッションを削除できませんでした。実行中の作業がないか確認してください。",
232
+ "sessionReadonly.message": "読み取り専用です。送信する前にこのセッションへ切り替えてください。",
233
+ "sessionReadonly.remote": "チャンネルに接続されたセッションはWebでは読み取り専用です。",
234
+ "sessionReadonly.switch": "/{seq} に切り替え",
235
+ "sessionReadonly.openSessions": "セッション一覧を開く",
236
+ "sessionReadonly.composeRejected": "このセッションは読み取り専用です。上の切り替え操作を使用してください。",
237
+ "sessionReadonly.elicitationRejected": "読み取り専用セッションからは応答を送信できません。切り替えてから再試行してください。",
209
238
  "skill.loadFail": "スキルを読み込めませんでした",
210
239
  "skill.count": "有効 {active} 件 / 全 {total} 件",
211
240
  "skill.countFiltered": "表示 {shown} 件 / 有効 {active} 件 / 全 {total} 件",
@@ -814,9 +843,9 @@
814
843
  "bgtask.title": "バックグラウンド",
815
844
  "tg.elicitationExpired": "選択セッションの有効期限が切れました。テキストで返信してください。",
816
845
  "settings.slack.guide.step1Title": "Slack アプリを作成",
817
- "settings.slack.guide.step1Desc": "Create an App → From an app manifest → ワークスペース選択 → 貼り付け",
846
+ "settings.slack.guide.step1Desc": "Create an App → From an app manifest → ワークスペース選択 → 貼り付け。既存アプリには files:read を追加します。",
818
847
  "settings.slack.guide.copyManifest": "マニフェストをコピー",
819
- "settings.slack.guide.copyManifestDone": "コピーしました — Slack に貼り付けてください",
848
+ "settings.slack.guide.copyManifestDone": "コピーしました — files:read を含むマニフェストを Slack に貼り付けてください",
820
849
  "settings.slack.guide.copyManifestFail": "コピー失敗 — jaw slack manifest を使用",
821
850
  "settings.slack.guide.openApps": "アプリページを開く",
822
851
  "settings.slack.guide.step2Title": "ボットトークンを貼り付け",
@@ -827,10 +856,21 @@
827
856
  "settings.slack.advanced": "詳細設定",
828
857
  "settings.slack.attachPort": "接続インスタンスのポート",
829
858
  "settings.channel.notAttachInstanceHint": "別のインスタンスがこの Slack 接続を所有しています(接続インスタンスのポートを確認)",
830
- "settings.slack.guide.step2Desc": "アプリ設定 → OAuth & Permissions → Install to Workspace → Bot User OAuth Token をコピー",
859
+ "settings.slack.guide.step2Desc": "アプリ設定 → OAuth & Permissions → files:read を確認 → Reinstall to Workspace → Bot User OAuth Token をコピー",
831
860
  "settings.slack.guide.step3Location": "アプリ設定 → Basic Information → App-Level Tokens → Generate Token (connections:write)",
832
861
  "slack.progress.start": "情報を収集中...",
833
862
  "slack.progress.working": "作業中",
863
+ "slack.files.partialFailure": "⚠️ 一部の添付ファイルを除外しました:",
864
+ "slack.files.allFailure": "⚠️ 添付ファイルを処理できなかったため、リクエストを実行しませんでした:",
865
+ "slack.files.limit": "ファイルは1件50 MiB、メッセージあたり10件・100 MiBまでです。",
866
+ "slack.files.error.external_file_unsupported": "Slack 外部ファイルには対応していません",
867
+ "slack.files.error.private_network": "安全でないダウンロード先です",
868
+ "slack.files.error.redirect_limit": "リダイレクト上限を超えました",
869
+ "slack.files.error.size_exceeded": "ファイルサイズ上限を超えました",
870
+ "slack.files.error.message_budget_exceeded": "メッセージの添付容量上限を超えました",
871
+ "slack.files.error.missing_scope": "files:read を追加してアプリを再インストールしてください",
872
+ "slack.files.error.ingress_cancelled": "処理がキャンセルされました",
873
+ "slack.files.error.download_failed": "ファイルをダウンロードできませんでした",
834
874
  "onboarding.open": "セットアップウィザード",
835
875
  "onboarding.optional": "任意",
836
876
  "onboarding.validate": "検証",
@@ -843,6 +883,8 @@
843
883
  "onboarding.guide.telegram": "Open @BotFather in Telegram, send /newbot, pick a name and username, and copy the bot token it returns. Paste it below and press Validate.",
844
884
  "onboarding.guide.discord": "At discord.com/developers/applications choose New Application, then Bot, then Reset Token. Enable MESSAGE CONTENT INTENT under Privileged Gateway Intents. Get the server ID by enabling Developer Mode in Discord, then right-click the server and copy its ID.",
845
885
  "onboarding.guide.slack": "At api.slack.com/apps use Create an App, From an app manifest. Then get the bot token (xoxb-) from OAuth & Permissions, Install to Workspace, and the app-level token (xapp-, connections:write) from Basic Information, App-Level Tokens.",
886
+ "onboarding.slackExistingApp": "既存アプリでは OAuth & Permissions に files:read を追加し、Reinstall to Workspace を実行してください。",
887
+ "onboarding.warning.missingCapabilities": "任意機能の権限 {capabilities} がないため、添付ファイル受信は無効です。権限を追加してアプリを再インストールしてください。テキストは引き続き利用できます。",
846
888
  "onboarding.token.botToken": "ボットトークン",
847
889
  "onboarding.token.appToken": "アプリレベルトークン",
848
890
  "onboarding.token.guildId": "サーバー ID",
@@ -886,4 +928,4 @@
886
928
  "settings.channel.testSendFail": "送信失敗: {error}",
887
929
  "settings.channel.testSendOk": "送信成功",
888
930
  "onboarding.progressLabel": "{total} ステップ中 {step} ステップ目"
889
- }
931
+ }
@@ -152,6 +152,8 @@
152
152
  "ws.disconnected": "연결 끊김 — 재연결 중...",
153
153
  "tg.settingsUnsupported": "Telegram에서 설정 변경은 지원하지 않습니다.",
154
154
  "dc.settingsUnsupported": "Discord에서 설정 변경은 지원하지 않습니다.",
155
+ "sl.settingsUnsupported": "Slack에서 설정 변경은 지원하지 않습니다.",
156
+ "cmd.runtimeSelectionInstanceWide": "CLI와 모델 선택은 이 인스턴스의 모든 세션이 함께 씁니다. 인스턴스 웹 설정에서 바꿔주세요.",
155
157
  "tg.promptUnsupported": "(Telegram에서 미지원)",
156
158
  "tg.queued": "대기열에 추가됨 ({count}번째)",
157
159
  "tg.imageCaption": "[📷 이미지] {caption}",
@@ -202,12 +204,39 @@
202
204
  "cli.noReadyCli": "인증된 CLI가 없습니다 — 위에서 하나 이상의 CLI를 설치하고 인증해 주세요.",
203
205
  "chat.cmd.fail": "커맨드 실행 실패: {msg}",
204
206
  "chat.file.sent": "[사용자가 파일을 보냈습니다: {path}]\n이 파일을 Read 도구로 읽고 분석해주세요.",
207
+ "chat.file.sentImage": "[사용자가 이미지를 보냈습니다: {path}]\n이 이미지를 분석해주세요.",
208
+ "chat.file.sentVideo": "[사용자가 동영상을 보냈습니다: {path}]\n이 동영상 파일을 확인해주세요.",
205
209
  "chat.file.sentWithMsg": "\n\n사용자 메시지: {text}",
206
210
  "chat.file.uploadFail": "파일 업로드 실패: {msg}",
207
211
  "chat.requestFail": "요청 실패 ({status})",
208
212
  "chat.continue": "현재 작업을 이어서 진행합니다.",
209
213
  "chat.noPendingContinue": "이어갈 작업이 없습니다.",
210
214
  "chat.voice.label": "🎤 [음성 메시지]",
215
+ "sessionHub.title": "세션",
216
+ "sessionHub.description": "채널과 로컬 대화를 세션별로 확인합니다.",
217
+ "sessionHub.defaultSession": "기본 세션",
218
+ "sessionHub.sessionLabel": "세션 {seq}",
219
+ "sessionHub.source.local": "로컬",
220
+ "sessionHub.source.slack": "Slack",
221
+ "sessionHub.source.telegram": "Telegram",
222
+ "sessionHub.source.discord": "Discord",
223
+ "sessionHub.messages": "메시지",
224
+ "sessionHub.lastActivity": "마지막 활동",
225
+ "sessionHub.noActivity": "활동 없음",
226
+ "sessionHub.empty.title": "아직 채널 세션이 없습니다",
227
+ "sessionHub.empty.description": "채널을 연결하면 대화별 세션이 여기 생깁니다.",
228
+ "sessionHub.empty.action": "설정에서 채널 연결하기",
229
+ "sessionHub.listAria": "세션 목록",
230
+ "sessionHub.delete": "삭제",
231
+ "sessionHub.deleteConfirm": "이 세션을 삭제할까요? 대화 기록도 함께 삭제됩니다.",
232
+ "sessionHub.deleteRemoteDisabled": "채널에 연결된 세션은 삭제할 수 없습니다.",
233
+ "sessionHub.deleteFailed": "세션을 삭제하지 못했습니다. 실행 중인지 확인해 주세요.",
234
+ "sessionReadonly.message": "읽기 전용입니다. 이 세션에서 보내려면 먼저 전환하세요.",
235
+ "sessionReadonly.remote": "채널에 연결된 세션은 웹에서 읽기 전용입니다.",
236
+ "sessionReadonly.switch": "세션 /{seq}(으)로 전환",
237
+ "sessionReadonly.openSessions": "세션 목록 열기",
238
+ "sessionReadonly.composeRejected": "읽기 전용 세션입니다. 위 전환 버튼을 사용해 주세요.",
239
+ "sessionReadonly.elicitationRejected": "읽기 전용 세션에서는 응답을 보낼 수 없습니다. 세션을 전환한 뒤 다시 시도하세요.",
211
240
  "skill.loadFail": "스킬 로드 실패",
212
241
  "skill.count": "활성 {active}개 / 전체 {total}개",
213
242
  "skill.countFiltered": "검색 {shown}개 / 활성 {active}개 / 전체 {total}개",
@@ -825,9 +854,9 @@
825
854
  "bgtask.title": "백그라운드",
826
855
  "tg.elicitationExpired": "선택 세션이 만료되었습니다. 텍스트로 답해주세요.",
827
856
  "settings.slack.guide.step1Title": "Slack 앱 만들기",
828
- "settings.slack.guide.step1Desc": "Create an App → From an app manifest → 워크스페이스 선택 → 붙여넣기",
857
+ "settings.slack.guide.step1Desc": "Create an App → From an app manifest → 워크스페이스 선택 → 붙여넣기. 기존 앱은 files:read를 추가하세요.",
829
858
  "settings.slack.guide.copyManifest": "매니페스트 복사",
830
- "settings.slack.guide.copyManifestDone": "복사됨 — Slack에 붙여넣으세요",
859
+ "settings.slack.guide.copyManifestDone": "복사됨 — files:read 포함 매니페스트를 Slack에 붙여넣으세요",
831
860
  "settings.slack.guide.copyManifestFail": "복사 실패 — jaw slack manifest 사용",
832
861
  "settings.slack.guide.openApps": "앱 페이지 열기",
833
862
  "settings.slack.guide.step2Title": "봇 토큰 붙여넣기",
@@ -838,10 +867,21 @@
838
867
  "settings.slack.advanced": "고급 설정",
839
868
  "settings.slack.attachPort": "연결 인스턴스 포트",
840
869
  "settings.channel.notAttachInstanceHint": "다른 인스턴스가 이 Slack 연결을 소유하고 있습니다 (연결 인스턴스 포트 확인)",
841
- "settings.slack.guide.step2Desc": "앱 설정 → OAuth & Permissions → Install to Workspace → Bot User OAuth Token 복사",
870
+ "settings.slack.guide.step2Desc": "앱 설정 → OAuth & Permissions → files:read 확인 → Reinstall to Workspace → Bot User OAuth Token 복사",
842
871
  "settings.slack.guide.step3Location": "앱 설정 → Basic Information → App-Level Tokens → Generate Token (connections:write)",
843
872
  "slack.progress.start": "정보 수집 중...",
844
873
  "slack.progress.working": "작업 중",
874
+ "slack.files.partialFailure": "⚠️ 일부 첨부파일을 제외했습니다:",
875
+ "slack.files.allFailure": "⚠️ 첨부파일을 처리하지 못해 요청을 실행하지 않았습니다:",
876
+ "slack.files.limit": "파일은 한 개당 50 MiB, 메시지당 10개·100 MiB까지 처리됩니다.",
877
+ "slack.files.error.external_file_unsupported": "Slack 외부 파일은 지원하지 않습니다",
878
+ "slack.files.error.private_network": "안전하지 않은 다운로드 위치입니다",
879
+ "slack.files.error.redirect_limit": "리다이렉트 한도를 초과했습니다",
880
+ "slack.files.error.size_exceeded": "파일 크기 한도를 초과했습니다",
881
+ "slack.files.error.message_budget_exceeded": "메시지 첨부 용량 한도를 초과했습니다",
882
+ "slack.files.error.missing_scope": "files:read 권한을 추가하고 앱을 재설치하세요",
883
+ "slack.files.error.ingress_cancelled": "처리가 취소되었습니다",
884
+ "slack.files.error.download_failed": "파일을 다운로드하지 못했습니다",
845
885
  "onboarding.open": "설정 마법사",
846
886
  "onboarding.optional": "선택",
847
887
  "onboarding.validate": "검증",
@@ -854,6 +894,8 @@
854
894
  "onboarding.guide.telegram": "텔레그램에서 @BotFather 를 열고 /newbot 을 보낸 뒤, 이름과 username을 정하면 봇 토큰이 나옵니다. 그 토큰을 아래에 붙여넣고 검증을 누르세요.",
855
895
  "onboarding.guide.discord": "discord.com/developers/applications 에서 New Application → Bot → Reset Token 으로 토큰을 만들고, Privileged Gateway Intents 의 MESSAGE CONTENT INTENT 를 켜세요. 서버 ID는 Discord 설정에서 개발자 모드를 켠 뒤 서버 우클릭 → ID 복사로 얻습니다.",
856
896
  "onboarding.guide.slack": "api.slack.com/apps 에서 Create an App → From an app manifest 로 앱을 만든 뒤, OAuth & Permissions → Install to Workspace 에서 봇 토큰(xoxb-), Basic Information → App-Level Tokens 에서 앱 토큰(xapp-, connections:write)을 발급받으세요.",
897
+ "onboarding.slackExistingApp": "기존 앱은 OAuth & Permissions에서 files:read를 추가한 뒤 Reinstall to Workspace를 실행하세요.",
898
+ "onboarding.warning.missingCapabilities": "선택 기능 권한({capabilities})이 없어 첨부파일 수신은 꺼져 있습니다. 권한을 추가하고 앱을 재설치하세요. 텍스트 메시지는 계속 사용할 수 있습니다.",
857
899
  "onboarding.token.botToken": "봇 토큰",
858
900
  "onboarding.token.appToken": "앱 레벨 토큰",
859
901
  "onboarding.token.guildId": "서버 ID",
@@ -886,4 +928,4 @@
886
928
  "onboarding.hint.slack.botToken": "OAuth & Permissions의 Bot User OAuth Token (xoxb-로 시작).",
887
929
  "onboarding.hint.slack.appToken": "Basic Information → App-Level Tokens (xapp-, connections:write).",
888
930
  "onboarding.progressLabel": "{total}단계 중 {step}단계"
889
- }
931
+ }
@@ -150,6 +150,8 @@
150
150
  "ws.disconnected": "连接已断开 — 正在重连...",
151
151
  "tg.settingsUnsupported": "Telegram 不支持修改设置。",
152
152
  "dc.settingsUnsupported": "Discord 不支持修改设置。",
153
+ "sl.settingsUnsupported": "Slack 不支持修改设置。",
154
+ "cmd.runtimeSelectionInstanceWide": "CLI 与模型选择由本实例的所有会话共用。请在实例网页设置中修改。",
153
155
  "tg.promptUnsupported": "(Telegram 不支持)",
154
156
  "tg.queued": "已加入队列(第 {count} 个)",
155
157
  "tg.imageCaption": "[📷 图片] {caption}",
@@ -200,12 +202,39 @@
200
202
  "cli.noReadyCli": "没有已认证的 CLI。请先在上方安装并认证至少一个 CLI。",
201
203
  "chat.cmd.fail": "命令执行失败:{msg}",
202
204
  "chat.file.sent": "[用户发送了文件:{path}]\n请读取并分析这个文件。",
205
+ "chat.file.sentImage": "[用户发送了图片:{path}]\n请分析这张图片。",
206
+ "chat.file.sentVideo": "[用户发送了视频:{path}]\n请查看这个视频文件。",
203
207
  "chat.file.sentWithMsg": "\n\n用户消息:{text}",
204
208
  "chat.file.uploadFail": "文件上传失败:{msg}",
205
209
  "chat.requestFail": "请求失败({status})",
206
210
  "chat.continue": "正在继续当前任务。",
207
211
  "chat.noPendingContinue": "没有可继续的待处理工作。",
208
212
  "chat.voice.label": "🎤 [语音消息]",
213
+ "sessionHub.title": "会话",
214
+ "sessionHub.description": "按会话查看本地和频道对话。",
215
+ "sessionHub.defaultSession": "默认会话",
216
+ "sessionHub.sessionLabel": "会话 {seq}",
217
+ "sessionHub.source.local": "本地",
218
+ "sessionHub.source.slack": "Slack",
219
+ "sessionHub.source.telegram": "Telegram",
220
+ "sessionHub.source.discord": "Discord",
221
+ "sessionHub.messages": "消息",
222
+ "sessionHub.lastActivity": "最后活动",
223
+ "sessionHub.noActivity": "暂无活动",
224
+ "sessionHub.empty.title": "尚无频道会话",
225
+ "sessionHub.empty.description": "连接频道后,每个对话会作为会话显示在这里。",
226
+ "sessionHub.empty.action": "在设置中连接频道",
227
+ "sessionHub.listAria": "会话列表",
228
+ "sessionHub.delete": "删除",
229
+ "sessionHub.deleteConfirm": "要删除此会话吗?对话记录也会一并删除。",
230
+ "sessionHub.deleteRemoteDisabled": "无法删除已连接到频道的会话。",
231
+ "sessionHub.deleteFailed": "无法删除会话。请确认该会话是否仍有正在进行的任务。",
232
+ "sessionReadonly.message": "当前为只读。发送前请先切换到此会话。",
233
+ "sessionReadonly.remote": "连接到频道的会话在网页端为只读。",
234
+ "sessionReadonly.switch": "切换到 /{seq}",
235
+ "sessionReadonly.openSessions": "打开会话列表",
236
+ "sessionReadonly.composeRejected": "此会话为只读。请使用上方的切换操作。",
237
+ "sessionReadonly.elicitationRejected": "无法从只读会话发送回复。请切换会话后重试。",
209
238
  "skill.loadFail": "无法加载技能",
210
239
  "skill.count": "{active} 个启用 / 共 {total} 个",
211
240
  "skill.countFiltered": "显示 {shown} 个 / 启用 {active} 个 / 共 {total} 个",
@@ -814,9 +843,9 @@
814
843
  "bgtask.title": "后台任务",
815
844
  "tg.elicitationExpired": "选择会话已过期,请用文字回复。",
816
845
  "settings.slack.guide.step1Title": "创建 Slack 应用",
817
- "settings.slack.guide.step1Desc": "Create an App → From an app manifest → 选择工作区 → 粘贴",
846
+ "settings.slack.guide.step1Desc": "Create an App → From an app manifest → 选择工作区 → 粘贴。现有应用需添加 files:read。",
818
847
  "settings.slack.guide.copyManifest": "复制清单",
819
- "settings.slack.guide.copyManifestDone": "已复制 — 请粘贴到 Slack",
848
+ "settings.slack.guide.copyManifestDone": "已复制 — 请将含 files:read 的 manifest 粘贴到 Slack",
820
849
  "settings.slack.guide.copyManifestFail": "复制失败 — 请使用 jaw slack manifest",
821
850
  "settings.slack.guide.openApps": "打开应用页面",
822
851
  "settings.slack.guide.step2Title": "粘贴机器人令牌",
@@ -827,10 +856,21 @@
827
856
  "settings.slack.advanced": "高级设置",
828
857
  "settings.slack.attachPort": "连接实例端口",
829
858
  "settings.channel.notAttachInstanceHint": "另一个实例拥有此 Slack 连接(请检查连接实例端口)",
830
- "settings.slack.guide.step2Desc": "应用设置 → OAuth & Permissions → Install to Workspace → 复制 Bot User OAuth Token",
859
+ "settings.slack.guide.step2Desc": "应用设置 → OAuth & Permissions → 确认 files:read → Reinstall to Workspace → 复制 Bot User OAuth Token",
831
860
  "settings.slack.guide.step3Location": "应用设置 → Basic Information → App-Level Tokens → Generate Token (connections:write)",
832
861
  "slack.progress.start": "正在收集信息...",
833
862
  "slack.progress.working": "处理中",
863
+ "slack.files.partialFailure": "⚠️ 已跳过部分附件:",
864
+ "slack.files.allFailure": "⚠️ 无法处理附件,因此未运行请求:",
865
+ "slack.files.limit": "每个文件上限为 50 MiB,每条消息最多 10 个文件或 100 MiB。",
866
+ "slack.files.error.external_file_unsupported": "不支持 Slack 外部文件",
867
+ "slack.files.error.private_network": "下载位置不安全",
868
+ "slack.files.error.redirect_limit": "超过重定向次数限制",
869
+ "slack.files.error.size_exceeded": "超过文件大小限制",
870
+ "slack.files.error.message_budget_exceeded": "超过消息附件容量限制",
871
+ "slack.files.error.missing_scope": "请添加 files:read 并重新安装应用",
872
+ "slack.files.error.ingress_cancelled": "处理已取消",
873
+ "slack.files.error.download_failed": "无法下载文件",
834
874
  "onboarding.open": "设置向导",
835
875
  "onboarding.optional": "可选",
836
876
  "onboarding.validate": "验证",
@@ -843,6 +883,8 @@
843
883
  "onboarding.guide.telegram": "Open @BotFather in Telegram, send /newbot, pick a name and username, and copy the bot token it returns. Paste it below and press Validate.",
844
884
  "onboarding.guide.discord": "At discord.com/developers/applications choose New Application, then Bot, then Reset Token. Enable MESSAGE CONTENT INTENT under Privileged Gateway Intents. Get the server ID by enabling Developer Mode in Discord, then right-click the server and copy its ID.",
845
885
  "onboarding.guide.slack": "At api.slack.com/apps use Create an App, From an app manifest. Then get the bot token (xoxb-) from OAuth & Permissions, Install to Workspace, and the app-level token (xapp-, connections:write) from Basic Information, App-Level Tokens.",
886
+ "onboarding.slackExistingApp": "对于现有应用,请在 OAuth & Permissions 中添加 files:read,然后选择 Reinstall to Workspace。",
887
+ "onboarding.warning.missingCapabilities": "缺少可选权限 {capabilities},因此无法接收附件。请添加权限并重新安装应用。文本消息仍可使用。",
846
888
  "onboarding.token.botToken": "机器人令牌",
847
889
  "onboarding.token.appToken": "应用级令牌",
848
890
  "onboarding.token.guildId": "服务器 ID",
@@ -886,4 +928,4 @@
886
928
  "settings.channel.testSendFail": "发送失败:{error}",
887
929
  "settings.channel.testSendOk": "发送成功",
888
930
  "onboarding.progressLabel": "第 {step} 步,共 {total} 步"
889
- }
931
+ }
@@ -260,7 +260,6 @@ export function App() { if (readTrayRemindersMode(window.location.search) && REM
260
260
  setSettingsDirty(false); activityUnread.markPortSeen(instance.port); view.setSelectedPort(instance.port); view.setDrawerOpen(false);
261
261
  void saveUi({ selectedPort: instance.port });
262
262
  }
263
-
264
263
  function handleTabChange(tab: DashboardDetailTab): void {
265
264
  if (tab !== 'settings' && !canLeaveDirtySettings()) return;
266
265
  if (tab !== 'settings') setSettingsDirty(false);
@@ -476,6 +475,7 @@ export function App() { if (readTrayRemindersMode(window.location.search) && REM
476
475
  busyPorts={messageActivity.busyPorts} showLatestActivityTitles={view.showLatestActivityTitles}
477
476
  showInlineLabelEditor={view.showInlineLabelEditor} showSidebarRuntimeLine={view.showSidebarRuntimeLine}
478
477
  showSelectedRowActions={view.showSelectedRowActions} profiles={profiles} getLabel={instanceLabel}
478
+ onRouteToSettings={(port) => { /* 260806 D3: Active-row re-click → Settings */ view.setActiveDetailTab('settings'); void saveUi({ selectedPort: port, selectedTab: 'settings' }); }}
479
479
  formatUptime={formatUptime} onSelect={handleSelectInstance} onPreview={handlePreview}
480
480
  onMarkActivitySeen={activityUnread.markPortSeen} onInstanceLabelSave={labelEditor.saveInstanceLabel}
481
481
  onLifecycle={(action, instance) => void handleLifecycle(action, instance)} />
@@ -41,6 +41,7 @@ type PreviewSendMessage = {
41
41
  type?: unknown;
42
42
  requestId?: unknown;
43
43
  prompt?: unknown;
44
+ sessionId?: unknown;
44
45
  };
45
46
 
46
47
  type PreviewDroppedFilesMessage = {
@@ -345,7 +346,10 @@ export function InstancePreview(props: InstancePreviewProps) {
345
346
  });
346
347
  return;
347
348
  }
348
- void sendInstanceMessage(props.instance!.port, prompt)
349
+ // Forward the session the preview is showing, or the instance writes into
350
+ // whichever session happens to be globally active instead.
351
+ const sessionId = typeof data.sessionId === 'string' ? data.sessionId : undefined;
352
+ void sendInstanceMessage(props.instance!.port, prompt, sessionId)
349
353
  .then(result => {
350
354
  postPreviewSendResult(event.source, event.origin, requestId, {
351
355
  ok: result.ok,
@@ -120,11 +120,12 @@ export async function pickInstanceProjectFolder(port: number): Promise<{ project
120
120
  export async function sendInstanceMessage(
121
121
  port: number,
122
122
  prompt: string,
123
+ sessionId?: string,
123
124
  ): Promise<{ ok: boolean; status: number; data: DashboardInstanceMessageResult }> {
124
125
  const response = await fetch(`/api/dashboard/instances/${port}/message`, {
125
126
  method: 'POST',
126
127
  headers: { 'content-type': 'application/json' },
127
- body: JSON.stringify({ prompt }),
128
+ body: JSON.stringify(sessionId ? { prompt, sessionId } : { prompt }),
128
129
  });
129
130
  const data = await response.json().catch(() => ({})) as DashboardInstanceMessageResult;
130
131
  return { ok: response.ok, status: response.status, data };
@@ -1,3 +1,4 @@
1
+ import type { ReactNode } from 'react';
1
2
  import { InstanceRow } from './InstanceRow';
2
3
  import type {
3
4
  DashboardInstance,
@@ -20,6 +21,11 @@ type InstanceGroupsProps = {
20
21
  showInlineLabelEditor?: boolean;
21
22
  showSidebarRuntimeLine?: boolean;
22
23
  showSelectedRowActions?: boolean;
24
+ /** Session disclosure for the Active row (devlog 260806 D2). */
25
+ activeSessionCount?: number;
26
+ activeSessionsOpen?: boolean;
27
+ onToggleActiveSessions?: (port: number) => void;
28
+ renderActiveSessionList?: (port: number) => ReactNode;
23
29
  getLabel: (instance: DashboardInstance) => string;
24
30
  formatUptime: (seconds: number | null) => string;
25
31
  onSelect: (instance: DashboardInstance) => void;
@@ -91,6 +97,9 @@ function renderInstanceRow(
91
97
  {...(props.showInlineLabelEditor !== undefined ? { showInlineLabelEditor: props.showInlineLabelEditor } : {})}
92
98
  {...(props.showSidebarRuntimeLine !== undefined ? { showRuntimeLine: props.showSidebarRuntimeLine } : {})}
93
99
  {...(props.showSelectedRowActions !== undefined ? { showSelectedActions: props.showSelectedRowActions } : {})}
100
+ {...(priority === 'active' && props.activeSessionCount !== undefined ? { sessionCount: props.activeSessionCount } : {})}
101
+ {...(priority === 'active' && props.activeSessionsOpen !== undefined ? { sessionsOpen: props.activeSessionsOpen } : {})}
102
+ {...(priority === 'active' && props.onToggleActiveSessions ? { onToggleSessions: props.onToggleActiveSessions } : {})}
94
103
  priority={priority}
95
104
  label={props.getLabel(instance)}
96
105
  uptime={props.formatUptime(instance.uptime)}
@@ -120,6 +129,7 @@ function renderRows(
120
129
  instance.profileId ? profileMap.get(instance.profileId) : undefined,
121
130
  group.id === 'active' ? 'active' : 'normal',
122
131
  ))}
132
+ {group.id === 'active' && group.instances[0] ? props.renderActiveSessionList?.(group.instances[0].port) : null}
123
133
  </section>
124
134
  ));
125
135
  }