@monoes/monomindcli 1.11.14 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (434) hide show
  1. package/.claude/agents/generated/channel-intelligence-director.md +87 -0
  2. package/.claude/agents/generated/chief-growth-officer.md +88 -0
  3. package/.claude/agents/generated/content-seo-strategist.md +90 -0
  4. package/.claude/agents/generated/developer-community-strategist.md +91 -0
  5. package/.claude/agents/generated/outreach-partnership-strategist.md +90 -0
  6. package/.claude/agents/generated/social-media-strategist.md +91 -0
  7. package/.claude/agents/generated/video-visual-strategist.md +90 -0
  8. package/.claude/commands/mastermind/master.md +1 -1
  9. package/.claude/helpers/auto-memory-hook.mjs +13 -4
  10. package/.claude/helpers/control-start.cjs +5 -0
  11. package/.claude/helpers/event-logger.cjs +114 -0
  12. package/.claude/helpers/handlers/adr-draft-handler.cjs +19 -5
  13. package/.claude/helpers/handlers/agent-start-handler.cjs +13 -4
  14. package/.claude/helpers/handlers/compact-handler.cjs +2 -0
  15. package/.claude/helpers/handlers/edit-handler.cjs +1 -1
  16. package/.claude/helpers/handlers/gates-handler.cjs +3 -0
  17. package/.claude/helpers/handlers/graph-status-handler.cjs +14 -8
  18. package/.claude/helpers/handlers/loops-status-handler.cjs +5 -2
  19. package/.claude/helpers/handlers/route-handler.cjs +24 -10
  20. package/.claude/helpers/handlers/session-handler.cjs +11 -4
  21. package/.claude/helpers/handlers/session-restore-handler.cjs +35 -19
  22. package/.claude/helpers/handlers/task-handler.cjs +13 -5
  23. package/.claude/helpers/hook-handler.cjs +40 -0
  24. package/.claude/helpers/intelligence.cjs +130 -53
  25. package/.claude/helpers/loop-tracker.cjs +15 -3
  26. package/.claude/helpers/memory-palace.cjs +461 -0
  27. package/.claude/helpers/memory.cjs +138 -14
  28. package/.claude/helpers/metrics-db.mjs +87 -0
  29. package/.claude/helpers/router.cjs +300 -42
  30. package/.claude/helpers/session.cjs +89 -30
  31. package/.claude/helpers/statusline.cjs +148 -4
  32. package/.claude/helpers/toggle-statusline.cjs +73 -0
  33. package/.claude/helpers/token-tracker.cjs +934 -0
  34. package/.claude/helpers/utils/micro-agents.cjs +20 -4
  35. package/.claude/helpers/utils/monograph.cjs +39 -4
  36. package/.claude/helpers/utils/telemetry.cjs +3 -3
  37. package/.claude/skills/mastermind/_protocol.md +25 -15
  38. package/.claude/skills/mastermind/architect.md +3 -3
  39. package/.claude/skills/mastermind/autodev.md +4 -2
  40. package/.claude/skills/mastermind/idea.md +10 -0
  41. package/.claude/skills/mastermind/ops.md +3 -3
  42. package/.claude/skills/mastermind/runorg.md +153 -86
  43. package/dist/src/agents/registry-builder.d.ts.map +1 -1
  44. package/dist/src/agents/registry-builder.js +2 -0
  45. package/dist/src/agents/registry-builder.js.map +1 -1
  46. package/dist/src/autopilot-state.d.ts.map +1 -1
  47. package/dist/src/autopilot-state.js +10 -5
  48. package/dist/src/autopilot-state.js.map +1 -1
  49. package/dist/src/benchmarks/benchmark-runner.d.ts.map +1 -1
  50. package/dist/src/benchmarks/benchmark-runner.js +13 -0
  51. package/dist/src/benchmarks/benchmark-runner.js.map +1 -1
  52. package/dist/src/benchmarks/metric-evaluators.d.ts.map +1 -1
  53. package/dist/src/benchmarks/metric-evaluators.js +20 -9
  54. package/dist/src/benchmarks/metric-evaluators.js.map +1 -1
  55. package/dist/src/browser/actions.d.ts.map +1 -1
  56. package/dist/src/browser/actions.js +10 -3
  57. package/dist/src/browser/actions.js.map +1 -1
  58. package/dist/src/browser/browser.d.ts.map +1 -1
  59. package/dist/src/browser/browser.js +12 -2
  60. package/dist/src/browser/browser.js.map +1 -1
  61. package/dist/src/browser/cdp.d.ts.map +1 -1
  62. package/dist/src/browser/cdp.js +21 -3
  63. package/dist/src/browser/cdp.js.map +1 -1
  64. package/dist/src/browser/har.d.ts.map +1 -1
  65. package/dist/src/browser/har.js +27 -5
  66. package/dist/src/browser/har.js.map +1 -1
  67. package/dist/src/commands/agent.d.ts.map +1 -1
  68. package/dist/src/commands/agent.js +11 -8
  69. package/dist/src/commands/agent.js.map +1 -1
  70. package/dist/src/commands/analyze.d.ts.map +1 -1
  71. package/dist/src/commands/analyze.js +36 -21
  72. package/dist/src/commands/analyze.js.map +1 -1
  73. package/dist/src/commands/autopilot.d.ts.map +1 -1
  74. package/dist/src/commands/autopilot.js +12 -4
  75. package/dist/src/commands/autopilot.js.map +1 -1
  76. package/dist/src/commands/benchmark.d.ts.map +1 -1
  77. package/dist/src/commands/benchmark.js +51 -8
  78. package/dist/src/commands/benchmark.js.map +1 -1
  79. package/dist/src/commands/browse.d.ts.map +1 -1
  80. package/dist/src/commands/browse.js +5 -2
  81. package/dist/src/commands/browse.js.map +1 -1
  82. package/dist/src/commands/claims.d.ts.map +1 -1
  83. package/dist/src/commands/claims.js +29 -11
  84. package/dist/src/commands/claims.js.map +1 -1
  85. package/dist/src/commands/cleanup.d.ts.map +1 -1
  86. package/dist/src/commands/cleanup.js +25 -5
  87. package/dist/src/commands/cleanup.js.map +1 -1
  88. package/dist/src/commands/config.d.ts.map +1 -1
  89. package/dist/src/commands/config.js +15 -7
  90. package/dist/src/commands/config.js.map +1 -1
  91. package/dist/src/commands/daemon.d.ts.map +1 -1
  92. package/dist/src/commands/daemon.js +6 -0
  93. package/dist/src/commands/daemon.js.map +1 -1
  94. package/dist/src/commands/deployment.d.ts.map +1 -1
  95. package/dist/src/commands/deployment.js +34 -19
  96. package/dist/src/commands/deployment.js.map +1 -1
  97. package/dist/src/commands/doctor.d.ts.map +1 -1
  98. package/dist/src/commands/doctor.js +133 -15
  99. package/dist/src/commands/doctor.js.map +1 -1
  100. package/dist/src/commands/guidance.d.ts.map +1 -1
  101. package/dist/src/commands/guidance.js +15 -2
  102. package/dist/src/commands/guidance.js.map +1 -1
  103. package/dist/src/commands/hive-mind.d.ts.map +1 -1
  104. package/dist/src/commands/hive-mind.js +37 -14
  105. package/dist/src/commands/hive-mind.js.map +1 -1
  106. package/dist/src/commands/hooks.d.ts.map +1 -1
  107. package/dist/src/commands/hooks.js +42 -25
  108. package/dist/src/commands/hooks.js.map +1 -1
  109. package/dist/src/commands/init.d.ts.map +1 -1
  110. package/dist/src/commands/init.js +9 -4
  111. package/dist/src/commands/init.js.map +1 -1
  112. package/dist/src/commands/issues.d.ts.map +1 -1
  113. package/dist/src/commands/issues.js +29 -26
  114. package/dist/src/commands/issues.js.map +1 -1
  115. package/dist/src/commands/mcp.d.ts.map +1 -1
  116. package/dist/src/commands/mcp.js +11 -5
  117. package/dist/src/commands/mcp.js.map +1 -1
  118. package/dist/src/commands/memory.d.ts.map +1 -1
  119. package/dist/src/commands/memory.js +10 -0
  120. package/dist/src/commands/memory.js.map +1 -1
  121. package/dist/src/commands/migrate.js +5 -5
  122. package/dist/src/commands/migrate.js.map +1 -1
  123. package/dist/src/commands/monograph.d.ts.map +1 -1
  124. package/dist/src/commands/monograph.js +18 -5
  125. package/dist/src/commands/monograph.js.map +1 -1
  126. package/dist/src/commands/monovector/backup.d.ts.map +1 -1
  127. package/dist/src/commands/monovector/backup.js +8 -2
  128. package/dist/src/commands/monovector/backup.js.map +1 -1
  129. package/dist/src/commands/monovector/benchmark.d.ts.map +1 -1
  130. package/dist/src/commands/monovector/benchmark.js +20 -7
  131. package/dist/src/commands/monovector/benchmark.js.map +1 -1
  132. package/dist/src/commands/monovector/import.d.ts.map +1 -1
  133. package/dist/src/commands/monovector/import.js +15 -0
  134. package/dist/src/commands/monovector/import.js.map +1 -1
  135. package/dist/src/commands/monovector/migrate.d.ts.map +1 -1
  136. package/dist/src/commands/monovector/migrate.js +4 -1
  137. package/dist/src/commands/monovector/migrate.js.map +1 -1
  138. package/dist/src/commands/monovector/optimize.d.ts.map +1 -1
  139. package/dist/src/commands/monovector/optimize.js +11 -0
  140. package/dist/src/commands/monovector/optimize.js.map +1 -1
  141. package/dist/src/commands/monovector/setup.d.ts.map +1 -1
  142. package/dist/src/commands/monovector/setup.js +11 -1
  143. package/dist/src/commands/monovector/setup.js.map +1 -1
  144. package/dist/src/commands/neural.js +1 -1
  145. package/dist/src/commands/neural.js.map +1 -1
  146. package/dist/src/commands/performance.d.ts.map +1 -1
  147. package/dist/src/commands/performance.js +20 -7
  148. package/dist/src/commands/performance.js.map +1 -1
  149. package/dist/src/commands/platforms.d.ts.map +1 -1
  150. package/dist/src/commands/platforms.js +90 -8
  151. package/dist/src/commands/platforms.js.map +1 -1
  152. package/dist/src/commands/plugins.d.ts.map +1 -1
  153. package/dist/src/commands/plugins.js +12 -5
  154. package/dist/src/commands/plugins.js.map +1 -1
  155. package/dist/src/commands/process.d.ts.map +1 -1
  156. package/dist/src/commands/process.js +33 -10
  157. package/dist/src/commands/process.js.map +1 -1
  158. package/dist/src/commands/progress.d.ts.map +1 -1
  159. package/dist/src/commands/progress.js +5 -3
  160. package/dist/src/commands/progress.js.map +1 -1
  161. package/dist/src/commands/providers.js +5 -5
  162. package/dist/src/commands/providers.js.map +1 -1
  163. package/dist/src/commands/replay.d.ts.map +1 -1
  164. package/dist/src/commands/replay.js +8 -2
  165. package/dist/src/commands/replay.js.map +1 -1
  166. package/dist/src/commands/route.d.ts.map +1 -1
  167. package/dist/src/commands/route.js +27 -7
  168. package/dist/src/commands/route.js.map +1 -1
  169. package/dist/src/commands/security.d.ts.map +1 -1
  170. package/dist/src/commands/security.js +4 -0
  171. package/dist/src/commands/security.js.map +1 -1
  172. package/dist/src/commands/session.d.ts.map +1 -1
  173. package/dist/src/commands/session.js +12 -1
  174. package/dist/src/commands/session.js.map +1 -1
  175. package/dist/src/commands/start.d.ts.map +1 -1
  176. package/dist/src/commands/start.js +11 -4
  177. package/dist/src/commands/start.js.map +1 -1
  178. package/dist/src/commands/status.d.ts.map +1 -1
  179. package/dist/src/commands/status.js +7 -4
  180. package/dist/src/commands/status.js.map +1 -1
  181. package/dist/src/commands/swarm.d.ts.map +1 -1
  182. package/dist/src/commands/swarm.js +27 -13
  183. package/dist/src/commands/swarm.js.map +1 -1
  184. package/dist/src/commands/task.d.ts.map +1 -1
  185. package/dist/src/commands/task.js +26 -11
  186. package/dist/src/commands/task.js.map +1 -1
  187. package/dist/src/commands/tokens.d.ts.map +1 -1
  188. package/dist/src/commands/tokens.js +7 -2
  189. package/dist/src/commands/tokens.js.map +1 -1
  190. package/dist/src/commands/transfer-store.d.ts.map +1 -1
  191. package/dist/src/commands/transfer-store.js +36 -22
  192. package/dist/src/commands/transfer-store.js.map +1 -1
  193. package/dist/src/commands/update.d.ts.map +1 -1
  194. package/dist/src/commands/update.js +15 -3
  195. package/dist/src/commands/update.js.map +1 -1
  196. package/dist/src/commands/workflow.d.ts.map +1 -1
  197. package/dist/src/commands/workflow.js +39 -6
  198. package/dist/src/commands/workflow.js.map +1 -1
  199. package/dist/src/consensus/audit-writer.d.ts.map +1 -1
  200. package/dist/src/consensus/audit-writer.js +18 -7
  201. package/dist/src/consensus/audit-writer.js.map +1 -1
  202. package/dist/src/consensus/vote-signer.d.ts.map +1 -1
  203. package/dist/src/consensus/vote-signer.js +25 -8
  204. package/dist/src/consensus/vote-signer.js.map +1 -1
  205. package/dist/src/index.d.ts.map +1 -1
  206. package/dist/src/index.js +7 -3
  207. package/dist/src/index.js.map +1 -1
  208. package/dist/src/init/executor.d.ts.map +1 -1
  209. package/dist/src/init/executor.js +14 -11
  210. package/dist/src/init/executor.js.map +1 -1
  211. package/dist/src/init/shared-instructions-generator.d.ts.map +1 -1
  212. package/dist/src/init/shared-instructions-generator.js +20 -4
  213. package/dist/src/init/shared-instructions-generator.js.map +1 -1
  214. package/dist/src/init/statusline-generator.d.ts.map +1 -1
  215. package/dist/src/init/statusline-generator.js +36 -15
  216. package/dist/src/init/statusline-generator.js.map +1 -1
  217. package/dist/src/mcp-tools/a2a-tools.d.ts.map +1 -1
  218. package/dist/src/mcp-tools/a2a-tools.js +98 -13
  219. package/dist/src/mcp-tools/a2a-tools.js.map +1 -1
  220. package/dist/src/mcp-tools/agent-tools.d.ts.map +1 -1
  221. package/dist/src/mcp-tools/agent-tools.js +16 -3
  222. package/dist/src/mcp-tools/agent-tools.js.map +1 -1
  223. package/dist/src/mcp-tools/analyze-tools.d.ts.map +1 -1
  224. package/dist/src/mcp-tools/analyze-tools.js +80 -17
  225. package/dist/src/mcp-tools/analyze-tools.js.map +1 -1
  226. package/dist/src/mcp-tools/browser-tools.d.ts.map +1 -1
  227. package/dist/src/mcp-tools/browser-tools.js +84 -22
  228. package/dist/src/mcp-tools/browser-tools.js.map +1 -1
  229. package/dist/src/mcp-tools/claims-tools.d.ts.map +1 -1
  230. package/dist/src/mcp-tools/claims-tools.js +35 -7
  231. package/dist/src/mcp-tools/claims-tools.js.map +1 -1
  232. package/dist/src/mcp-tools/config-tools.d.ts.map +1 -1
  233. package/dist/src/mcp-tools/config-tools.js +82 -17
  234. package/dist/src/mcp-tools/config-tools.js.map +1 -1
  235. package/dist/src/mcp-tools/coordination-tools.d.ts.map +1 -1
  236. package/dist/src/mcp-tools/coordination-tools.js +37 -4
  237. package/dist/src/mcp-tools/coordination-tools.js.map +1 -1
  238. package/dist/src/mcp-tools/daa-tools.d.ts.map +1 -1
  239. package/dist/src/mcp-tools/daa-tools.js +49 -7
  240. package/dist/src/mcp-tools/daa-tools.js.map +1 -1
  241. package/dist/src/mcp-tools/embeddings-tools.d.ts.map +1 -1
  242. package/dist/src/mcp-tools/embeddings-tools.js +45 -18
  243. package/dist/src/mcp-tools/embeddings-tools.js.map +1 -1
  244. package/dist/src/mcp-tools/github-tools.d.ts.map +1 -1
  245. package/dist/src/mcp-tools/github-tools.js +75 -25
  246. package/dist/src/mcp-tools/github-tools.js.map +1 -1
  247. package/dist/src/mcp-tools/guidance-tools.d.ts.map +1 -1
  248. package/dist/src/mcp-tools/guidance-tools.js +32 -10
  249. package/dist/src/mcp-tools/guidance-tools.js.map +1 -1
  250. package/dist/src/mcp-tools/hive-mind-tools.d.ts.map +1 -1
  251. package/dist/src/mcp-tools/hive-mind-tools.js +91 -20
  252. package/dist/src/mcp-tools/hive-mind-tools.js.map +1 -1
  253. package/dist/src/mcp-tools/hooks-tools.d.ts.map +1 -1
  254. package/dist/src/mcp-tools/hooks-tools.js +188 -29
  255. package/dist/src/mcp-tools/hooks-tools.js.map +1 -1
  256. package/dist/src/mcp-tools/memory-tools.d.ts.map +1 -1
  257. package/dist/src/mcp-tools/memory-tools.js +25 -7
  258. package/dist/src/mcp-tools/memory-tools.js.map +1 -1
  259. package/dist/src/mcp-tools/monograph-compat.d.ts.map +1 -1
  260. package/dist/src/mcp-tools/monograph-compat.js +11 -2
  261. package/dist/src/mcp-tools/monograph-compat.js.map +1 -1
  262. package/dist/src/mcp-tools/monograph-tools.d.ts.map +1 -1
  263. package/dist/src/mcp-tools/monograph-tools.js +476 -62
  264. package/dist/src/mcp-tools/monograph-tools.js.map +1 -1
  265. package/dist/src/mcp-tools/neural-tools.d.ts.map +1 -1
  266. package/dist/src/mcp-tools/neural-tools.js +44 -9
  267. package/dist/src/mcp-tools/neural-tools.js.map +1 -1
  268. package/dist/src/mcp-tools/performance-tools.d.ts.map +1 -1
  269. package/dist/src/mcp-tools/performance-tools.js +45 -10
  270. package/dist/src/mcp-tools/performance-tools.js.map +1 -1
  271. package/dist/src/mcp-tools/progress-tools.d.ts.map +1 -1
  272. package/dist/src/mcp-tools/progress-tools.js +7 -4
  273. package/dist/src/mcp-tools/progress-tools.js.map +1 -1
  274. package/dist/src/mcp-tools/request-tracker.d.ts.map +1 -1
  275. package/dist/src/mcp-tools/request-tracker.js +15 -1
  276. package/dist/src/mcp-tools/request-tracker.js.map +1 -1
  277. package/dist/src/mcp-tools/security-tools.d.ts.map +1 -1
  278. package/dist/src/mcp-tools/security-tools.js +61 -9
  279. package/dist/src/mcp-tools/security-tools.js.map +1 -1
  280. package/dist/src/mcp-tools/session-tools.d.ts.map +1 -1
  281. package/dist/src/mcp-tools/session-tools.js +45 -14
  282. package/dist/src/mcp-tools/session-tools.js.map +1 -1
  283. package/dist/src/mcp-tools/swarm-tools.d.ts.map +1 -1
  284. package/dist/src/mcp-tools/swarm-tools.js +15 -3
  285. package/dist/src/mcp-tools/swarm-tools.js.map +1 -1
  286. package/dist/src/mcp-tools/system-tools.d.ts.map +1 -1
  287. package/dist/src/mcp-tools/system-tools.js +14 -7
  288. package/dist/src/mcp-tools/system-tools.js.map +1 -1
  289. package/dist/src/mcp-tools/task-tools.d.ts.map +1 -1
  290. package/dist/src/mcp-tools/task-tools.js +52 -10
  291. package/dist/src/mcp-tools/task-tools.js.map +1 -1
  292. package/dist/src/mcp-tools/terminal-tools.d.ts.map +1 -1
  293. package/dist/src/mcp-tools/terminal-tools.js +40 -6
  294. package/dist/src/mcp-tools/terminal-tools.js.map +1 -1
  295. package/dist/src/mcp-tools/transfer-tools.d.ts.map +1 -1
  296. package/dist/src/mcp-tools/transfer-tools.js +37 -4
  297. package/dist/src/mcp-tools/transfer-tools.js.map +1 -1
  298. package/dist/src/mcp-tools/workflow-tools.d.ts.map +1 -1
  299. package/dist/src/mcp-tools/workflow-tools.js +29 -6
  300. package/dist/src/mcp-tools/workflow-tools.js.map +1 -1
  301. package/dist/src/memory/ewc-consolidation.d.ts.map +1 -1
  302. package/dist/src/memory/ewc-consolidation.js +26 -10
  303. package/dist/src/memory/ewc-consolidation.js.map +1 -1
  304. package/dist/src/memory/intelligence.d.ts.map +1 -1
  305. package/dist/src/memory/intelligence.js +80 -19
  306. package/dist/src/memory/intelligence.js.map +1 -1
  307. package/dist/src/memory/memory-bridge.d.ts.map +1 -1
  308. package/dist/src/memory/memory-bridge.js +21 -2
  309. package/dist/src/memory/memory-bridge.js.map +1 -1
  310. package/dist/src/memory/memory-initializer.d.ts.map +1 -1
  311. package/dist/src/memory/memory-initializer.js +67 -3
  312. package/dist/src/memory/memory-initializer.js.map +1 -1
  313. package/dist/src/memory/sona-optimizer.d.ts.map +1 -1
  314. package/dist/src/memory/sona-optimizer.js +14 -4
  315. package/dist/src/memory/sona-optimizer.js.map +1 -1
  316. package/dist/src/monovector/command-outcomes.d.ts.map +1 -1
  317. package/dist/src/monovector/command-outcomes.js +43 -7
  318. package/dist/src/monovector/command-outcomes.js.map +1 -1
  319. package/dist/src/monovector/coverage-router.d.ts.map +1 -1
  320. package/dist/src/monovector/coverage-router.js +8 -4
  321. package/dist/src/monovector/coverage-router.js.map +1 -1
  322. package/dist/src/monovector/coverage-tools.d.ts.map +1 -1
  323. package/dist/src/monovector/coverage-tools.js +6 -3
  324. package/dist/src/monovector/coverage-tools.js.map +1 -1
  325. package/dist/src/monovector/diff-classifier.d.ts.map +1 -1
  326. package/dist/src/monovector/diff-classifier.js +13 -0
  327. package/dist/src/monovector/diff-classifier.js.map +1 -1
  328. package/dist/src/monovector/route-outcomes.d.ts +2 -1
  329. package/dist/src/monovector/route-outcomes.d.ts.map +1 -1
  330. package/dist/src/monovector/route-outcomes.js +46 -4
  331. package/dist/src/monovector/route-outcomes.js.map +1 -1
  332. package/dist/src/plugins/manager.d.ts.map +1 -1
  333. package/dist/src/plugins/manager.js +8 -3
  334. package/dist/src/plugins/manager.js.map +1 -1
  335. package/dist/src/plugins/store/discovery.d.ts.map +1 -1
  336. package/dist/src/plugins/store/discovery.js +46 -2
  337. package/dist/src/plugins/store/discovery.js.map +1 -1
  338. package/dist/src/plugins/store/search.d.ts.map +1 -1
  339. package/dist/src/plugins/store/search.js +5 -4
  340. package/dist/src/plugins/store/search.js.map +1 -1
  341. package/dist/src/production/circuit-breaker.d.ts.map +1 -1
  342. package/dist/src/production/circuit-breaker.js +17 -3
  343. package/dist/src/production/circuit-breaker.js.map +1 -1
  344. package/dist/src/production/error-handler.d.ts.map +1 -1
  345. package/dist/src/production/error-handler.js +3 -0
  346. package/dist/src/production/error-handler.js.map +1 -1
  347. package/dist/src/production/monitoring.d.ts.map +1 -1
  348. package/dist/src/production/monitoring.js +20 -3
  349. package/dist/src/production/monitoring.js.map +1 -1
  350. package/dist/src/production/rate-limiter.d.ts.map +1 -1
  351. package/dist/src/production/rate-limiter.js +13 -4
  352. package/dist/src/production/rate-limiter.js.map +1 -1
  353. package/dist/src/production/retry.d.ts.map +1 -1
  354. package/dist/src/production/retry.js +17 -9
  355. package/dist/src/production/retry.js.map +1 -1
  356. package/dist/src/routing/embed-worker.js +6 -2
  357. package/dist/src/routing/embed-worker.js.map +1 -1
  358. package/dist/src/routing/embedder.d.ts.map +1 -1
  359. package/dist/src/routing/embedder.js +0 -0
  360. package/dist/src/routing/embedder.js.map +1 -1
  361. package/dist/src/routing/llm-caller.d.ts.map +1 -1
  362. package/dist/src/routing/llm-caller.js +13 -2
  363. package/dist/src/routing/llm-caller.js.map +1 -1
  364. package/dist/src/routing/route-layer-factory.d.ts.map +1 -1
  365. package/dist/src/routing/route-layer-factory.js +18 -3
  366. package/dist/src/routing/route-layer-factory.js.map +1 -1
  367. package/dist/src/services/claim-service.d.ts +1 -0
  368. package/dist/src/services/claim-service.d.ts.map +1 -1
  369. package/dist/src/services/claim-service.js +8 -0
  370. package/dist/src/services/claim-service.js.map +1 -1
  371. package/dist/src/services/config-file-manager.d.ts.map +1 -1
  372. package/dist/src/services/config-file-manager.js +14 -2
  373. package/dist/src/services/config-file-manager.js.map +1 -1
  374. package/dist/src/services/headless-worker-executor.d.ts.map +1 -1
  375. package/dist/src/services/headless-worker-executor.js +18 -2
  376. package/dist/src/services/headless-worker-executor.js.map +1 -1
  377. package/dist/src/services/worker-daemon.d.ts.map +1 -1
  378. package/dist/src/services/worker-daemon.js +348 -17
  379. package/dist/src/services/worker-daemon.js.map +1 -1
  380. package/dist/src/transfer/anonymization/index.d.ts +0 -3
  381. package/dist/src/transfer/anonymization/index.d.ts.map +1 -1
  382. package/dist/src/transfer/anonymization/index.js +16 -1
  383. package/dist/src/transfer/anonymization/index.js.map +1 -1
  384. package/dist/src/transfer/export.d.ts.map +1 -1
  385. package/dist/src/transfer/export.js +8 -0
  386. package/dist/src/transfer/export.js.map +1 -1
  387. package/dist/src/transfer/ipfs/upload.d.ts.map +1 -1
  388. package/dist/src/transfer/ipfs/upload.js +33 -3
  389. package/dist/src/transfer/ipfs/upload.js.map +1 -1
  390. package/dist/src/transfer/serialization/cfp.d.ts.map +1 -1
  391. package/dist/src/transfer/serialization/cfp.js +8 -2
  392. package/dist/src/transfer/serialization/cfp.js.map +1 -1
  393. package/dist/src/transfer/storage/gcs.d.ts.map +1 -1
  394. package/dist/src/transfer/storage/gcs.js +37 -3
  395. package/dist/src/transfer/storage/gcs.js.map +1 -1
  396. package/dist/src/transfer/store/discovery.d.ts.map +1 -1
  397. package/dist/src/transfer/store/discovery.js +45 -3
  398. package/dist/src/transfer/store/discovery.js.map +1 -1
  399. package/dist/src/transfer/store/download.d.ts.map +1 -1
  400. package/dist/src/transfer/store/download.js +5 -0
  401. package/dist/src/transfer/store/download.js.map +1 -1
  402. package/dist/src/transfer/store/publish.d.ts.map +1 -1
  403. package/dist/src/transfer/store/publish.js +13 -1
  404. package/dist/src/transfer/store/publish.js.map +1 -1
  405. package/dist/src/transfer/store/registry.d.ts +8 -0
  406. package/dist/src/transfer/store/registry.d.ts.map +1 -1
  407. package/dist/src/transfer/store/registry.js +30 -5
  408. package/dist/src/transfer/store/registry.js.map +1 -1
  409. package/dist/src/transfer/store/search.d.ts.map +1 -1
  410. package/dist/src/transfer/store/search.js +20 -5
  411. package/dist/src/transfer/store/search.js.map +1 -1
  412. package/dist/src/ui/collector.mjs +39 -5
  413. package/dist/src/ui/dashboard.html +1603 -1284
  414. package/dist/src/ui/orgs.html +722 -12
  415. package/dist/src/ui/server.mjs +717 -136
  416. package/dist/src/update/checker.d.ts.map +1 -1
  417. package/dist/src/update/checker.js +59 -7
  418. package/dist/src/update/checker.js.map +1 -1
  419. package/dist/src/update/executor.d.ts.map +1 -1
  420. package/dist/src/update/executor.js +50 -3
  421. package/dist/src/update/executor.js.map +1 -1
  422. package/dist/src/update/index.d.ts.map +1 -1
  423. package/dist/src/update/index.js +18 -1
  424. package/dist/src/update/index.js.map +1 -1
  425. package/dist/src/update/rate-limiter.d.ts +6 -0
  426. package/dist/src/update/rate-limiter.d.ts.map +1 -1
  427. package/dist/src/update/rate-limiter.js +79 -7
  428. package/dist/src/update/rate-limiter.js.map +1 -1
  429. package/dist/src/update/validator.d.ts.map +1 -1
  430. package/dist/src/update/validator.js +52 -1
  431. package/dist/src/update/validator.js.map +1 -1
  432. package/dist/tsconfig.tsbuildinfo +1 -1
  433. package/package.json +2 -3
  434. package/dist/src/ui/data/mastermind-events.jsonl +0 -59
@@ -285,6 +285,43 @@ html, body {
285
285
  .meta-cell-label { font-size: 8px; letter-spacing: 2px; color: var(--dim); margin-bottom: 4px; }
286
286
  .meta-cell-value { font-size: 11px; color: var(--text); }
287
287
 
288
+ /* ── Live status strip ─────────────────────────────────────────── */
289
+ #live-strip {
290
+ display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
291
+ background: oklch(8% 0.01 186); border: 1px solid var(--border);
292
+ border-radius: 4px; padding: 8px 12px; font-size: 10px; color: var(--dim);
293
+ letter-spacing: 0.5px;
294
+ }
295
+ #ls-state { display: flex; align-items: center; gap: 5px; }
296
+ .ls-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--dim); flex-shrink: 0; }
297
+ .ls-dot.running { background: oklch(65% 0.20 150); }
298
+ @media (prefers-reduced-motion: no-preference) { .ls-dot.running { animation: ls-pulse 2s ease-in-out infinite; } }
299
+ @keyframes ls-pulse { 0%,100%{opacity:1} 50%{opacity:0.3} }
300
+ #ls-label { font-size: 9px; letter-spacing: 2px; }
301
+ .ls-metric { font-size: 10px; color: var(--muted); }
302
+ .ls-sparkline-wrap { display: flex; align-items: flex-end; gap: 1px; height: 20px; margin-left: auto; }
303
+ .ls-bar { width: 6px; border-radius: 1px; background: oklch(62% 0.20 186 / 0.4); min-height: 2px; }
304
+ .ls-bar.active { background: oklch(62% 0.20 186 / 0.8); }
305
+ #clf-wrap {
306
+ background: oklch(8% 0.01 186); border: 1px solid var(--border);
307
+ border-radius: 4px; overflow: hidden;
308
+ }
309
+ #clf-header {
310
+ font-size: 8px; letter-spacing: 3px; color: var(--dim); padding: 6px 12px;
311
+ border-bottom: 1px solid var(--border);
312
+ }
313
+ #clf-rows { min-height: 48px; max-height: 160px; overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--teal-dim) transparent; }
314
+ .clf-row {
315
+ display: grid; grid-template-columns: 80px 70px 1fr;
316
+ gap: 8px; padding: 5px 12px;
317
+ font-size: 10px; border-bottom: 1px solid oklch(100% 0 0 / 0.03);
318
+ }
319
+ .clf-row.new { animation: clf-fadein 0.3s ease; }
320
+ @keyframes clf-fadein { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
321
+ .clf-time { color: var(--dim); font-variant-numeric: tabular-nums; }
322
+ .clf-type { color: var(--accent); }
323
+ .clf-msg { color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
324
+
288
325
  /* ── Roles list ─────────────────────────────────────────────────── */
289
326
  #roles-pane { padding: 20px; }
290
327
 
@@ -364,6 +401,116 @@ html, body {
364
401
  .hc-value.amber { color: var(--amber); }
365
402
  .hc-value.red { color: var(--red); }
366
403
 
404
+ /* ── Chat tab ───────────────────────────────────────────────────── */
405
+ #chat-pane {
406
+ display: flex; flex-direction: column; height: 100%;
407
+ overflow: hidden;
408
+ }
409
+ #chat-session-bar {
410
+ display: flex; align-items: center; gap: 8px;
411
+ padding: 10px 20px 8px;
412
+ border-bottom: 1px solid var(--border);
413
+ flex-shrink: 0; flex-wrap: wrap;
414
+ }
415
+ #chat-sess-label { font-size: 8px; letter-spacing: 2px; color: var(--dim); }
416
+ #chat-sess-select {
417
+ background: var(--bg-panel); color: var(--muted);
418
+ border: 1px solid var(--border); border-radius: 3px;
419
+ font-size: 9px; font-family: var(--mono); letter-spacing: 0.5px;
420
+ padding: 3px 6px; cursor: pointer; max-width: 260px;
421
+ }
422
+ #chat-sess-select:focus { outline: none; border-color: var(--teal-dim); }
423
+ #chat-live-dot {
424
+ width: 5px; height: 5px; border-radius: 50%;
425
+ background: var(--dim); margin-left: auto; flex-shrink: 0;
426
+ transition: background 0.4s;
427
+ }
428
+ #chat-live-dot.on { background: var(--green); animation: livepulse 2.2s ease-in-out infinite; }
429
+ #chat-live-label { font-size: 8px; color: var(--dim); }
430
+
431
+ #chat-feed-wrap {
432
+ flex: 1; overflow-y: auto; padding: 12px 20px;
433
+ display: flex; flex-direction: column; gap: 5px;
434
+ scrollbar-width: thin;
435
+ scrollbar-color: var(--teal-dim) transparent;
436
+ }
437
+ #chat-feed-wrap::-webkit-scrollbar { width: 4px; }
438
+ #chat-feed-wrap::-webkit-scrollbar-thumb { background: var(--teal-dim); border-radius: 2px; }
439
+
440
+ #chat-feed-empty {
441
+ font-size: 10px; color: var(--dim); text-align: center;
442
+ padding: 30px 0; line-height: 2;
443
+ }
444
+ #chat-agent-bar {
445
+ display: flex; align-items: center; gap: 6px;
446
+ padding: 6px 20px 7px;
447
+ border-bottom: 1px solid var(--border);
448
+ flex-shrink: 0; flex-wrap: wrap;
449
+ }
450
+ #chat-agent-label { font-size: 8px; letter-spacing: 2px; color: var(--dim); flex-shrink: 0; }
451
+ .chat-agent-pill {
452
+ font-size: 8px; padding: 2px 8px; border-radius: 10px;
453
+ border: 1px solid var(--border); color: var(--muted);
454
+ background: transparent; cursor: pointer; letter-spacing: 0.3px;
455
+ font-family: var(--mono); transition: border-color 0.15s, color 0.15s;
456
+ }
457
+ .chat-agent-pill:hover { border-color: var(--teal-dim); color: var(--text); }
458
+ .chat-agent-pill.active { border-color: var(--teal); color: var(--teal); background: oklch(62% 0.20 186 / 0.07); }
459
+
460
+ .cmsg { display: flex; flex-direction: column; max-width: 92%; }
461
+ .cmsg.csys { align-self: center; max-width: 100%; }
462
+ .cmsg.cagent { align-self: flex-start; }
463
+ .cmsg.cic { align-self: flex-start; }
464
+
465
+ @keyframes cmsg-in { from{opacity:0;transform:translateY(3px)} to{opacity:1;transform:none} }
466
+ .cmsg.new { animation: cmsg-in 0.18s ease-out; }
467
+
468
+ .cmsg.csys .cbubble {
469
+ background: oklch(10% 0.008 186);
470
+ border: 1px solid var(--border);
471
+ border-radius: 6px; padding: 4px 12px;
472
+ font-size: 9px; color: var(--dim); letter-spacing: 0.3px;
473
+ text-align: center;
474
+ }
475
+ .cmsg.cagent .cbubble {
476
+ background: oklch(11% 0.016 186);
477
+ border: 1px solid var(--teal-dim);
478
+ border-radius: 2px 8px 8px 8px;
479
+ padding: 7px 11px;
480
+ color: oklch(70% 0.010 186);
481
+ font-size: 11px; line-height: 1.6;
482
+ word-break: break-word; white-space: pre-wrap;
483
+ }
484
+ .cmsg.cic .cbubble {
485
+ background: oklch(10% 0.013 295);
486
+ border: 1px solid oklch(68% 0.18 295 / 0.22);
487
+ border-radius: 2px 8px 8px 8px;
488
+ padding: 7px 11px;
489
+ color: oklch(68% 0.010 295);
490
+ font-size: 11px; line-height: 1.6;
491
+ word-break: break-word; white-space: pre-wrap;
492
+ }
493
+ .cmsg-meta {
494
+ display: flex; align-items: center; gap: 5px;
495
+ margin-bottom: 3px; flex-wrap: wrap;
496
+ }
497
+ .cmsg.csys .cmsg-meta { display: none; }
498
+ .ctag {
499
+ font-size: 8px; padding: 1px 6px; border-radius: 10px;
500
+ border: 1px solid var(--teal-dim); color: var(--teal);
501
+ letter-spacing: 0.4px; flex-shrink: 0;
502
+ }
503
+ .ctag.sender { border-color: oklch(68% 0.18 295 / 0.35); color: oklch(68% 0.14 295); }
504
+ .ctag.receiver{ border-color: oklch(78% 0.18 80 / 0.35); color: var(--amber); }
505
+ .cic-arrow { font-size: 9px; color: var(--dim); }
506
+ .cts { font-size: 8px; color: var(--dim); margin-left: auto; }
507
+ .cevtype {
508
+ font-size: 7px; padding: 1px 4px; border-radius: 2px;
509
+ background: oklch(62% 0.20 186 / 0.07);
510
+ border: 1px solid var(--border); color: var(--dim);
511
+ letter-spacing: 0.3px;
512
+ }
513
+
367
514
  /* ── Communication edges (SVG in chart) ─────────────────────────── */
368
515
  .oc-edge { stroke: var(--teal); stroke-opacity: 0.25; stroke-width: 1; fill: none; }
369
516
  .oc-edge.command { stroke: var(--teal); stroke-opacity: 0.4; }
@@ -397,8 +544,8 @@ html, body {
397
544
 
398
545
  /* Arrow markers are inline in the SVG */
399
546
 
400
- /* ── Copy button on org items ───────────────────────────────────── */
401
- .oi-copy-btn {
547
+ /* ── Copy / Export / Import buttons on org items ────────────────── */
548
+ .oi-copy-btn, .oi-export-btn, .oi-import-btn {
402
549
  display: none;
403
550
  flex-shrink: 0;
404
551
  background: none;
@@ -414,14 +561,49 @@ html, body {
414
561
  line-height: 1.4;
415
562
  white-space: nowrap;
416
563
  }
417
- .org-item:hover .oi-copy-btn { display: inline-block; }
564
+ .org-item:hover .oi-copy-btn,
565
+ .org-item:hover .oi-export-btn,
566
+ .org-item:hover .oi-import-btn { display: inline-block; }
418
567
  .oi-copy-btn:hover {
419
568
  color: var(--teal);
420
569
  border-color: var(--teal-dim);
421
570
  background: var(--teal-glow);
422
571
  }
572
+ .oi-export-btn:hover {
573
+ color: var(--green, #4ade80);
574
+ border-color: oklch(60% 0.15 145 / 0.4);
575
+ background: oklch(60% 0.15 145 / 0.08);
576
+ }
577
+ .oi-import-btn:hover {
578
+ color: var(--amber, #facc15);
579
+ border-color: oklch(70% 0.15 85 / 0.4);
580
+ background: oklch(70% 0.15 85 / 0.08);
581
+ }
423
582
 
424
583
  /* ── Copy modal ─────────────────────────────────────────────────── */
584
+ #copy-project-list {
585
+ max-height: 180px;
586
+ overflow-y: auto;
587
+ border: 1px solid var(--border-hi);
588
+ border-radius: 4px;
589
+ margin: 4px 0 10px;
590
+ background: oklch(6% 0.008 186);
591
+ }
592
+ .copy-proj-row {
593
+ padding: 7px 10px;
594
+ font-size: 12px;
595
+ font-family: var(--mono);
596
+ color: var(--text-md);
597
+ cursor: pointer;
598
+ border-bottom: 1px solid var(--border);
599
+ white-space: nowrap;
600
+ overflow: hidden;
601
+ text-overflow: ellipsis;
602
+ }
603
+ .copy-proj-row:last-child { border-bottom: none; }
604
+ .copy-proj-row:hover { background: var(--bg-hover); color: var(--text-hi); }
605
+ .copy-proj-row.selected { background: color-mix(in srgb, var(--teal) 15%, transparent); color: var(--teal); border-left: 2px solid var(--teal); padding-left: 8px; }
606
+ .copy-proj-loading { padding: 10px; font-size: 11px; color: var(--dim); text-align: center; }
425
607
  #copy-modal-overlay {
426
608
  display: none;
427
609
  position: fixed; inset: 0;
@@ -571,6 +753,7 @@ html, body {
571
753
  <button class="tab-btn" onclick="switchTab('roles')">ROLES</button>
572
754
  <button class="tab-btn" onclick="switchTab('activity')">ACTIVITY</button>
573
755
  <button class="tab-btn" onclick="switchTab('health')">HEALTH</button>
756
+ <button class="tab-btn" onclick="switchTab('chat')">CHAT</button>
574
757
  </div>
575
758
 
576
759
  <div id="main-body">
@@ -618,6 +801,23 @@ html, body {
618
801
  </svg>
619
802
  </div>
620
803
 
804
+ <!-- Live status strip -->
805
+ <div id="live-strip">
806
+ <div id="ls-state">
807
+ <span id="ls-dot" class="ls-dot"></span>
808
+ <span id="ls-label">IDLE</span>
809
+ </div>
810
+ <div id="ls-uptime" class="ls-metric" title="Uptime">—</div>
811
+ <div id="ls-last" class="ls-metric" title="Last event">—</div>
812
+ <div id="ls-epm" class="ls-metric" title="Events / 5 min">—</div>
813
+ <div id="ls-sparkline" class="ls-sparkline-wrap"></div>
814
+ </div>
815
+ <!-- Live event feed -->
816
+ <div id="clf-wrap">
817
+ <div id="clf-header">LIVE EVENTS</div>
818
+ <div id="clf-rows"></div>
819
+ </div>
820
+
621
821
  <!-- Legend -->
622
822
  <div style="display:flex; gap:16px; flex-wrap:wrap; padding:0 2px;">
623
823
  <div style="display:flex; align-items:center; gap:5px; font-size:8px; color:var(--dim);">
@@ -662,6 +862,26 @@ html, body {
662
862
  </div>
663
863
  </div>
664
864
 
865
+ <!-- Chat tab -->
866
+ <div class="tab-pane" id="tab-chat">
867
+ <div id="chat-pane">
868
+ <div id="chat-session-bar">
869
+ <span id="chat-sess-label">SESSION</span>
870
+ <select id="chat-sess-select" onchange="selectChatSession(this.value)">
871
+ <option value="">— select a session —</option>
872
+ </select>
873
+ <div id="chat-live-dot"></div>
874
+ <span id="chat-live-label">OFFLINE</span>
875
+ </div>
876
+ <div id="chat-agent-bar" style="display:none">
877
+ <span id="chat-agent-label">AGENT</span>
878
+ </div>
879
+ <div id="chat-feed-wrap">
880
+ <div id="chat-feed-empty">Select a session above to see agent communications.</div>
881
+ </div>
882
+ </div>
883
+ </div>
884
+
665
885
  </div><!-- end main-body -->
666
886
  </div><!-- end org-detail -->
667
887
  </div><!-- end main -->
@@ -672,12 +892,14 @@ html, body {
672
892
  <div id="copy-modal">
673
893
  <div id="copy-modal-title">COPY ORG TO PROJECT</div>
674
894
  <div id="copy-modal-org">—</div>
675
- <div class="copy-modal-label">DESTINATION PROJECT PATH</div>
895
+ <div class="copy-modal-label">SELECT DESTINATION PROJECT</div>
896
+ <div id="copy-project-list"><div class="copy-proj-loading">Loading projects…</div></div>
897
+ <div class="copy-modal-label" style="margin-top:4px">OR ENTER PATH MANUALLY</div>
676
898
  <input id="copy-dest-input" type="text" placeholder="/absolute/path/to/project"
677
- onkeydown="if(event.key==='Enter')executeCopy(); if(event.key==='Escape')closeCopyModal()">
899
+ onkeydown="if(event.key==='Enter')executeCopy(); if(event.key==='Escape')closeCopyModal()"
900
+ oninput="document.querySelectorAll('.copy-proj-row').forEach(r=>r.classList.remove('selected'))">
678
901
  <div id="copy-modal-hint">
679
- The org config will be written to<br>
680
- <span style="color:var(--muted)">&lt;destination&gt;/.monomind/orgs/&lt;name&gt;.json</span>
902
+ Writes to <span style="color:var(--teal)">&lt;destination&gt;/.monomind/orgs/&lt;name&gt;.json</span>
681
903
  </div>
682
904
  <div id="copy-modal-status"></div>
683
905
  <div class="copy-modal-actions">
@@ -742,12 +964,14 @@ window.switchTab = function(tab) {
742
964
  (tab === 'chart' && b.textContent === 'ORG CHART') ||
743
965
  (tab === 'roles' && b.textContent === 'ROLES') ||
744
966
  (tab === 'activity' && b.textContent === 'ACTIVITY') ||
745
- (tab === 'health' && b.textContent === 'HEALTH'));
967
+ (tab === 'health' && b.textContent === 'HEALTH') ||
968
+ (tab === 'chat' && b.textContent === 'CHAT'));
746
969
  });
747
970
  document.querySelectorAll('.tab-pane').forEach(p => p.classList.remove('active'));
748
971
  const pane = document.getElementById('tab-' + tab);
749
972
  if (pane) pane.classList.add('active');
750
- if (orgDetailData) renderTab(tab);
973
+ if (tab === 'chat') renderChatTab();
974
+ else if (orgDetailData) renderTab(tab);
751
975
  };
752
976
 
753
977
  // ── Render all orgs in sidebar ────────────────────────────────────
@@ -795,6 +1019,8 @@ function renderSidebar() {
795
1019
  <div class="oi-name">${esc(org.name)}</div>
796
1020
  <span class="oi-badge ${org.running ? 'running' : 'idle'}">${org.running ? 'LIVE' : 'IDLE'}</span>
797
1021
  <button class="oi-copy-btn" title="Copy org to another project">COPY</button>
1022
+ <button class="oi-export-btn" title="Export org as JSON file">EXPORT</button>
1023
+ <button class="oi-import-btn" title="Import org from JSON file">IMPORT</button>
798
1024
  </div>
799
1025
  ${goalText ? `<div class="oi-goal">${esc(goalText)}</div>` : ''}
800
1026
  <div class="oi-meta">
@@ -806,6 +1032,14 @@ function renderSidebar() {
806
1032
  e.stopPropagation();
807
1033
  openCopyModal(org.name);
808
1034
  });
1035
+ item.querySelector('.oi-export-btn').addEventListener('click', e => {
1036
+ e.stopPropagation();
1037
+ exportOrg(org.name);
1038
+ });
1039
+ item.querySelector('.oi-import-btn').addEventListener('click', e => {
1040
+ e.stopPropagation();
1041
+ triggerImportOrg(org.name);
1042
+ });
809
1043
  item.addEventListener('click', () => selectOrg(org.name));
810
1044
  list.appendChild(item);
811
1045
  });
@@ -814,6 +1048,9 @@ function renderSidebar() {
814
1048
  // ── Select and load an org ────────────────────────────────────────
815
1049
  async function selectOrg(name) {
816
1050
  selectedOrg = name;
1051
+ chatCurrentId = null; // reset chat session when org changes
1052
+ orgRunStartMs = null;
1053
+ if (lsUptimeTimer) { clearInterval(lsUptimeTimer); lsUptimeTimer = null; }
817
1054
 
818
1055
  // Update sidebar active state
819
1056
  document.querySelectorAll('.org-item').forEach(el => {
@@ -879,7 +1116,7 @@ function updateHeader(listOrg, data) {
879
1116
  // ── Tab renderers ─────────────────────────────────────────────────
880
1117
  function renderTab(tab) {
881
1118
  if (!orgDetailData) return;
882
- if (tab === 'chart') renderChart();
1119
+ if (tab === 'chart') { renderChart(); initLiveStrip(); }
883
1120
  else if (tab === 'roles') renderRoles();
884
1121
  else if (tab === 'activity') renderActivity();
885
1122
  else if (tab === 'health') renderHealth();
@@ -1215,6 +1452,18 @@ function renderHealth() {
1215
1452
  <div class="hc-value ${health.tasks_pending > 5 ? 'amber' : ''}">${health.tasks_pending}</div>
1216
1453
  <div class="hc-sub">pending</div>
1217
1454
  </div>` : ''}
1455
+ ${health?.run_success_rate_7d !== null && health?.run_success_rate_7d !== undefined ? `
1456
+ <div class="health-cell">
1457
+ <div class="hc-label">SUCCESS</div>
1458
+ <div class="hc-value ${health.run_success_rate_7d >= 80 ? 'green' : health.run_success_rate_7d >= 50 ? 'amber' : 'red'}">${health.run_success_rate_7d}%</div>
1459
+ <div class="hc-sub">7d rate (${health.total_runs_7d || 0} runs)</div>
1460
+ </div>` : ''}
1461
+ ${health?.budget_used_pct !== null && health?.budget_used_pct !== undefined ? `
1462
+ <div class="health-cell">
1463
+ <div class="hc-label">BUDGET</div>
1464
+ <div class="hc-value ${health.budget_used_pct > 90 ? 'red' : health.budget_used_pct > 70 ? 'amber' : ''}">${health.budget_used_pct}%</div>
1465
+ <div class="hc-sub">tokens used</div>
1466
+ </div>` : ''}
1218
1467
  `;
1219
1468
 
1220
1469
  if (health?.errors && health.errors.length) {
@@ -1237,6 +1486,281 @@ function renderHealth() {
1237
1486
  }
1238
1487
  }
1239
1488
 
1489
+ // ── CHAT TAB ──────────────────────────────────────────────────────
1490
+ let chatSessions = []; // all sessions from /api/mastermind/sessions
1491
+ let chatCurrentId = null; // currently viewed session id
1492
+ let chatCurrentAgent = 'all'; // 'all' or an agent/role name
1493
+ let chatScrollLocked = false;
1494
+ let mmSse = null;
1495
+
1496
+ async function loadChatSessions() {
1497
+ try {
1498
+ const r = await fetch('/api/mastermind/sessions');
1499
+ if (!r.ok) return;
1500
+ chatSessions = await r.json();
1501
+ populateChatSelect();
1502
+ } catch(_) {}
1503
+ }
1504
+
1505
+ function orgSessionMatch(s) {
1506
+ if (!selectedOrg) return true;
1507
+ const orgLc = selectedOrg.toLowerCase();
1508
+ const prompt = (s.prompt || '').toLowerCase();
1509
+ if (prompt.includes('running org: ' + orgLc) || prompt.includes('org: ' + orgLc)) return true;
1510
+ // Also check events for an org field
1511
+ return (s.events || []).some(ev => (ev.org || '').toLowerCase() === orgLc);
1512
+ }
1513
+
1514
+ function populateChatSelect() {
1515
+ const sel = document.getElementById('chat-sess-select');
1516
+ if (!sel) return;
1517
+ const prev = chatCurrentId || sel.value;
1518
+
1519
+ // Filter to sessions for this org; fall back to all if none match
1520
+ const orgSessions = chatSessions.filter(orgSessionMatch);
1521
+ const list = orgSessions.length ? orgSessions : chatSessions;
1522
+ const isFiltered = orgSessions.length > 0 && orgSessions.length < chatSessions.length;
1523
+
1524
+ const placeholder = isFiltered
1525
+ ? `— ${orgSessions.length} session${orgSessions.length !== 1 ? 's' : ''} for ${selectedOrg} —`
1526
+ : '— select a session —';
1527
+ sel.innerHTML = `<option value="">${placeholder}</option>`;
1528
+
1529
+ list.forEach(s => {
1530
+ const d = new Date(s.ts);
1531
+ const ts = d.toLocaleTimeString([],{hour:'2-digit',minute:'2-digit',second:'2-digit'});
1532
+ const date = d.toLocaleDateString([],{month:'short',day:'numeric'});
1533
+ const prompt = (s.prompt || '').replace(/^running org:\s*/i, '').slice(0, 40);
1534
+ const label = `${date} ${ts} ${prompt}${prompt.length >= 40 ? '…' : ''} [${s.status || '?'}]`;
1535
+ const opt = document.createElement('option');
1536
+ opt.value = s.id;
1537
+ opt.textContent = label;
1538
+ if (s.id === prev) opt.selected = true;
1539
+ sel.appendChild(opt);
1540
+ });
1541
+
1542
+ // Auto-select most recent running session for this org
1543
+ if (!chatCurrentId) {
1544
+ const running = list.find(s => s.status === 'running');
1545
+ if (running) { sel.value = running.id; selectChatSession(running.id); }
1546
+ }
1547
+ }
1548
+
1549
+ window.selectChatSession = function(id) {
1550
+ chatCurrentId = id;
1551
+ chatCurrentAgent = 'all';
1552
+ const feed = document.getElementById('chat-feed-wrap');
1553
+ const empty = document.getElementById('chat-feed-empty');
1554
+ const bar = document.getElementById('chat-agent-bar');
1555
+ if (!id) {
1556
+ feed.querySelectorAll('.cmsg').forEach(e=>e.remove());
1557
+ if (empty) empty.style.display = 'block';
1558
+ if (bar) bar.style.display = 'none';
1559
+ return;
1560
+ }
1561
+ const sess = chatSessions.find(s => s.id === id);
1562
+ if (!sess) return;
1563
+ feed.querySelectorAll('.cmsg').forEach(e=>e.remove());
1564
+ if (empty) empty.style.display = 'none';
1565
+ populateChatAgentBar(sess.events || []);
1566
+ (sess.events || []).forEach(ev => appendChatEvent(ev, false));
1567
+ chatScrollFeed();
1568
+ };
1569
+
1570
+ function chatAgentMatchesFilter(ev) {
1571
+ if (chatCurrentAgent === 'all') return true;
1572
+ return ev.agent === chatCurrentAgent || ev.from === chatCurrentAgent || ev.to === chatCurrentAgent;
1573
+ }
1574
+
1575
+ function populateChatAgentBar(events) {
1576
+ const bar = document.getElementById('chat-agent-bar');
1577
+ if (!bar) return;
1578
+ const agentSet = new Set();
1579
+ (events || []).forEach(ev => {
1580
+ if (ev.agent) agentSet.add(ev.agent);
1581
+ if (ev.from && ev.from !== '?') agentSet.add(ev.from);
1582
+ if (ev.to && ev.to !== '?') agentSet.add(ev.to);
1583
+ });
1584
+ // Add org roles even if not yet seen in events
1585
+ if (orgDetailData && Array.isArray(orgDetailData.roles)) {
1586
+ orgDetailData.roles.forEach(r => {
1587
+ const n = typeof r === 'string' ? r : (r.role || r.name || r.id || '');
1588
+ if (n) agentSet.add(n);
1589
+ });
1590
+ }
1591
+ const agents = [...agentSet].sort();
1592
+ if (!agents.length) { bar.style.display = 'none'; return; }
1593
+ bar.style.display = 'flex';
1594
+ bar.innerHTML = '<span id="chat-agent-label">AGENT</span>';
1595
+ ['all', ...agents].forEach(name => {
1596
+ const pill = document.createElement('button');
1597
+ pill.className = 'chat-agent-pill' + (chatCurrentAgent === name ? ' active' : '');
1598
+ pill.textContent = name === 'all' ? 'ALL' : name;
1599
+ pill.dataset.agent = name;
1600
+ pill.onclick = () => selectChatAgent(name);
1601
+ bar.appendChild(pill);
1602
+ });
1603
+ }
1604
+
1605
+ window.selectChatAgent = function(name) {
1606
+ chatCurrentAgent = name;
1607
+ document.querySelectorAll('#chat-agent-bar .chat-agent-pill').forEach(p => {
1608
+ p.classList.toggle('active', p.dataset.agent === name);
1609
+ });
1610
+ const feed = document.getElementById('chat-feed-wrap');
1611
+ const empty = document.getElementById('chat-feed-empty');
1612
+ const sess = chatSessions.find(s => s.id === chatCurrentId);
1613
+ feed.querySelectorAll('.cmsg').forEach(e => e.remove());
1614
+ if (!sess) return;
1615
+ const visible = (sess.events || []).filter(ev => chatAgentMatchesFilter(ev));
1616
+ if (!visible.length) {
1617
+ if (empty) { empty.style.display = 'block'; empty.textContent = name === 'all' ? 'No events.' : `No events for "${name}"`; }
1618
+ } else {
1619
+ if (empty) empty.style.display = 'none';
1620
+ visible.forEach(ev => appendChatEvent(ev, false));
1621
+ }
1622
+ chatScrollFeed();
1623
+ };
1624
+
1625
+ function appendChatEvent(ev, animate) {
1626
+ if (!chatAgentMatchesFilter(ev)) return;
1627
+ const feed = document.getElementById('chat-feed-wrap');
1628
+ const empty = document.getElementById('chat-feed-empty');
1629
+ if (!feed) return;
1630
+ if (empty) empty.style.display = 'none';
1631
+ const ts = new Date(ev.ts || Date.now()).toLocaleTimeString([],{hour:'2-digit',minute:'2-digit',second:'2-digit'});
1632
+ const DCOLS = {build:'#60a5fa',idea:'#fbbf24',marketing:'#f472b6',review:'#34d399',research:'#a78bfa',content:'#fb923c',release:'#22d3ee',sales:'#f87171',ops:'#4ade80',finance:'#fde68a',orgs:'#c084fc'};
1633
+ const dc = d => DCOLS[d] || 'oklch(62% 0.20 186)';
1634
+ let el = null;
1635
+
1636
+ if (ev.type === 'session:start') {
1637
+ el = mkSys(`🔵 Session started${ev.prompt ? ': ' + esc(ev.prompt.slice(0,80)) : ''}`, ts);
1638
+ } else if (ev.type === 'session:complete') {
1639
+ el = mkSys(`🏁 Session complete — ${esc((ev.domains||[]).join(', ') || 'done')}`, ts);
1640
+ } else if (ev.type === 'domain:dispatch') {
1641
+ el = mkSys(`<span style="color:${dc(ev.domain)}">⚙ [${esc((ev.domain||'').toUpperCase())}]</span> ${esc(ev.cmd||'dispatched')}`, ts);
1642
+ } else if (ev.type === 'domain:complete') {
1643
+ const arts = (ev.artifacts||[]).length ? ` · ${ev.artifacts.length} artifact${ev.artifacts.length!==1?'s':''}` : '';
1644
+ el = mkSys(`<span style="color:${dc(ev.domain)}">✓ [${esc((ev.domain||'').toUpperCase())}]</span> ${esc(ev.status||'done')}${arts}`, ts);
1645
+ } else if (ev.type === 'agent:spawn') {
1646
+ const col = dc(ev.domain);
1647
+ el = mkAgent(ev.agent||'agent', `spawned: ${esc(ev.task||'task')}`, ts, col, 'spawn');
1648
+ } else if (ev.type === 'agent:message') {
1649
+ el = mkAgent(ev.agent||'agent', esc(ev.text||''), ts, dc(ev.domain), null);
1650
+ } else if (ev.type === 'intercom') {
1651
+ el = mkIntercom(ev.from, ev.to, esc(ev.msg||''), ts);
1652
+ } else if (ev.type === 'loop:start') {
1653
+ el = mkSys(`🔁 Loop: ${esc(ev.command||'')} (${ev.repeat||'?'} runs)`, ts);
1654
+ } else if (ev.type === 'loop:complete') {
1655
+ el = mkSys(`🔁 Loop done: ${esc(ev.command||'')} — ${ev.ranReps||'?'} run(s)`, ts);
1656
+ } else {
1657
+ el = mkSys(`<span style="opacity:0.4">${esc(ev.type)}${ev.domain?' ['+esc(ev.domain)+']':''}</span>`, ts);
1658
+ }
1659
+ if (!el) return;
1660
+ if (animate) el.classList.add('new');
1661
+ feed.appendChild(el);
1662
+ }
1663
+
1664
+ function mkSys(html, ts) {
1665
+ const el = document.createElement('div');
1666
+ el.className = 'cmsg csys';
1667
+ el.innerHTML = `<div class="cbubble">${html} <span style="color:var(--dim);margin-left:8px">${ts}</span></div>`;
1668
+ return el;
1669
+ }
1670
+ function mkAgent(name, text, ts, color, typeTag) {
1671
+ const el = document.createElement('div');
1672
+ el.className = 'cmsg cagent';
1673
+ const tagStyle = color ? `style="border-color:${color}44;color:${color}"` : '';
1674
+ const ttag = typeTag ? `<span class="cevtype">${esc(typeTag)}</span>` : '';
1675
+ el.innerHTML = `<div class="cmsg-meta"><span class="ctag" ${tagStyle}>${esc(name)}</span>${ttag}<span class="cts">${ts}</span></div><div class="cbubble">${text}</div>`;
1676
+ return el;
1677
+ }
1678
+ function mkIntercom(from, to, text, ts) {
1679
+ const el = document.createElement('div');
1680
+ el.className = 'cmsg cic';
1681
+ el.innerHTML = `<div class="cmsg-meta"><span class="ctag sender">${esc(from||'?')}</span><span class="cic-arrow">→</span><span class="ctag receiver">${esc(to||'?')}</span><span class="cevtype">intercom</span><span class="cts">${ts}</span></div><div class="cbubble">${text}</div>`;
1682
+ return el;
1683
+ }
1684
+
1685
+ function chatScrollFeed() {
1686
+ const feed = document.getElementById('chat-feed-wrap');
1687
+ if (feed && !chatScrollLocked) feed.scrollTop = feed.scrollHeight;
1688
+ }
1689
+
1690
+ function renderChatTab() {
1691
+ if (chatSessions.length) {
1692
+ populateChatSelect(); // re-filter immediately with current selectedOrg
1693
+ }
1694
+ loadChatSessions(); // then refresh from server
1695
+ connectMmSSE();
1696
+ const feed = document.getElementById('chat-feed-wrap');
1697
+ if (feed) {
1698
+ feed.addEventListener('scroll', () => {
1699
+ chatScrollLocked = feed.scrollHeight - feed.scrollTop - feed.clientHeight > 80;
1700
+ }, { passive: true });
1701
+ }
1702
+ }
1703
+
1704
+ function connectMmSSE() {
1705
+ if (mmSse) return; // already connected
1706
+ mmSse = new EventSource('/api/mastermind-stream');
1707
+ mmSse.onopen = () => {
1708
+ const dot = document.getElementById('chat-live-dot');
1709
+ const lbl = document.getElementById('chat-live-label');
1710
+ if (dot) dot.classList.add('on');
1711
+ if (lbl) lbl.textContent = 'LIVE';
1712
+ };
1713
+ mmSse.onmessage = e => {
1714
+ try {
1715
+ const ev = JSON.parse(e.data);
1716
+ handleMmEvent(ev);
1717
+ } catch(_) {}
1718
+ };
1719
+ mmSse.onerror = () => {
1720
+ const dot = document.getElementById('chat-live-dot');
1721
+ const lbl = document.getElementById('chat-live-label');
1722
+ if (dot) dot.classList.remove('on');
1723
+ if (lbl) lbl.textContent = 'RECONNECTING';
1724
+ mmSse = null;
1725
+ setTimeout(connectMmSSE, 4000);
1726
+ };
1727
+ }
1728
+
1729
+ function handleMmEvent(ev) {
1730
+ // Update in-memory sessions list
1731
+ if (ev.type === 'session:start') {
1732
+ const existing = chatSessions.find(s => s.id === ev.session);
1733
+ if (!existing) {
1734
+ chatSessions.unshift({ id: ev.session, ts: ev.ts||Date.now(), prompt: ev.prompt||'', status:'running', domains:[], events:[ev] });
1735
+ }
1736
+ populateChatSelect();
1737
+ // Auto-select if chat tab is active, nothing selected, and session matches this org
1738
+ if (currentTab === 'chat' && !chatCurrentId) {
1739
+ const newSess = chatSessions.find(s => s.id === ev.session);
1740
+ if (newSess && orgSessionMatch(newSess)) {
1741
+ const sel = document.getElementById('chat-sess-select');
1742
+ if (sel) { sel.value = ev.session; selectChatSession(ev.session); }
1743
+ }
1744
+ }
1745
+ return;
1746
+ }
1747
+ const sess = chatSessions.find(s => s.id === ev.session);
1748
+ if (sess) {
1749
+ (sess.events = sess.events || []).push(ev);
1750
+ if (ev.type === 'domain:dispatch' && ev.domain && !sess.domains.includes(ev.domain)) sess.domains.push(ev.domain);
1751
+ if (ev.type === 'session:complete') { sess.status = ev.status || 'complete'; sess.endTs = ev.ts; populateChatSelect(); }
1752
+ // If this is the currently-viewed session and chat tab is visible, append bubble
1753
+ if (currentTab === 'chat' && chatCurrentId === ev.session) {
1754
+ const hasNewAgent = (ev.agent && !document.querySelector(`[data-agent="${CSS.escape(ev.agent)}"]`))
1755
+ || (ev.from && !document.querySelector(`[data-agent="${CSS.escape(ev.from)}"]`))
1756
+ || (ev.to && !document.querySelector(`[data-agent="${CSS.escape(ev.to)}"]`));
1757
+ if (hasNewAgent) populateChatAgentBar(sess.events);
1758
+ appendChatEvent(ev, true);
1759
+ chatScrollFeed();
1760
+ }
1761
+ }
1762
+ }
1763
+
1240
1764
  // ── Stop org action ────────────────────────────────────────────────
1241
1765
  window.stopCurrentOrg = async function() {
1242
1766
  if (!selectedOrg) return;
@@ -1248,18 +1772,20 @@ window.stopCurrentOrg = async function() {
1248
1772
 
1249
1773
  // ── SSE org events ────────────────────────────────────────────────
1250
1774
  const orgEventLog = {};
1775
+ let orgRunStartMs = null;
1776
+ let lsUptimeTimer = null;
1251
1777
 
1252
1778
  let evtSource = null;
1253
1779
  function connectSSE() {
1254
1780
  if (evtSource) evtSource.close();
1255
- evtSource = new EventSource('/api/events');
1781
+ evtSource = new EventSource('/api/mastermind-stream');
1256
1782
  evtSource.onmessage = e => {
1257
1783
  try {
1258
1784
  const ev = JSON.parse(e.data);
1259
1785
  if (ev && typeof ev.org === 'string' && ev.type && ev.type.startsWith('org:')) {
1260
1786
  const name = ev.org;
1261
1787
  if (!orgEventLog[name]) orgEventLog[name] = [];
1262
- orgEventLog[name].push(ev);
1788
+ orgEventLog[name].push({ ...ev, _ts: Date.now() });
1263
1789
  if (orgEventLog[name].length > 50) orgEventLog[name].shift();
1264
1790
 
1265
1791
  // Refresh if this org is selected
@@ -1270,6 +1796,13 @@ function connectSSE() {
1270
1796
  if (ev.type === 'org:start' || ev.type === 'org:stop') {
1271
1797
  setTimeout(loadOrgs, 400);
1272
1798
  }
1799
+ // Update live strip for selected org on chart tab
1800
+ if (name === selectedOrg && currentTab === 'chart') {
1801
+ if (ev.type === 'org:start') orgRunStartMs = Date.now();
1802
+ if (ev.type === 'org:stop') orgRunStartMs = null;
1803
+ appendLiveFeedRow(ev, true);
1804
+ updateLiveStrip();
1805
+ }
1273
1806
  }
1274
1807
  } catch (_) {}
1275
1808
  };
@@ -1278,6 +1811,102 @@ function connectSSE() {
1278
1811
  };
1279
1812
  }
1280
1813
 
1814
+ function updateLiveStrip() {
1815
+ const events = orgEventLog[selectedOrg] || [];
1816
+ const running = orgRunStartMs !== null;
1817
+ const dot = document.getElementById('ls-dot');
1818
+ const label = document.getElementById('ls-label');
1819
+ if (!dot || !label) return;
1820
+ dot.className = 'ls-dot' + (running ? ' running' : '');
1821
+ label.textContent = running ? 'RUNNING' : 'IDLE';
1822
+
1823
+ // Uptime
1824
+ const uptimeEl = document.getElementById('ls-uptime');
1825
+ if (uptimeEl) {
1826
+ if (running && orgRunStartMs) {
1827
+ const s = Math.floor((Date.now() - orgRunStartMs) / 1000);
1828
+ const h = Math.floor(s / 3600), m = Math.floor((s % 3600) / 60), sec = s % 60;
1829
+ uptimeEl.textContent = h ? `up ${h}h ${m}m` : m ? `up ${m}m ${sec}s` : `up ${sec}s`;
1830
+ } else {
1831
+ uptimeEl.textContent = '—';
1832
+ }
1833
+ }
1834
+
1835
+ // Last event
1836
+ const lastEl = document.getElementById('ls-last');
1837
+ if (lastEl && events.length) {
1838
+ const last = events[events.length - 1];
1839
+ const ago = Math.round((Date.now() - (last._ts || Date.now())) / 1000);
1840
+ lastEl.textContent = ago < 5 ? 'just now' : ago < 60 ? ago + 's ago' : Math.floor(ago/60) + 'm ago';
1841
+ } else if (lastEl) {
1842
+ lastEl.textContent = '—';
1843
+ }
1844
+
1845
+ // Events per 5 min
1846
+ const now = Date.now();
1847
+ const epmEl = document.getElementById('ls-epm');
1848
+ if (epmEl) {
1849
+ const recent = events.filter(ev => ev._ts && now - ev._ts < 5 * 60 * 1000).length;
1850
+ epmEl.textContent = recent + ' / 5m';
1851
+ }
1852
+
1853
+ // 12-bar sparkline (25s buckets)
1854
+ renderLiveSparkline(events);
1855
+ }
1856
+
1857
+ function renderLiveSparkline(events) {
1858
+ const wrap = document.getElementById('ls-sparkline');
1859
+ if (!wrap) return;
1860
+ const now = Date.now();
1861
+ const buckets = Array.from({ length: 12 }, (_, i) => {
1862
+ const start = now - (12 - i) * 25000;
1863
+ return events.filter(ev => ev._ts && ev._ts >= start && ev._ts < start + 25000).length;
1864
+ });
1865
+ const max = Math.max(1, ...buckets);
1866
+ wrap.innerHTML = buckets.map((count, i) => {
1867
+ const h = Math.max(2, Math.round(count / max * 18));
1868
+ return `<div class="ls-bar${i === 11 ? ' active' : ''}" style="height:${h}px" title="${count} events"></div>`;
1869
+ }).join('');
1870
+ }
1871
+
1872
+ function appendLiveFeedRow(ev, isNew) {
1873
+ const rows = document.getElementById('clf-rows');
1874
+ if (!rows) return;
1875
+ const time = new Date().toLocaleTimeString('en', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' });
1876
+ const type = (ev.type || '').replace('org:', '');
1877
+ const msg = ev.message || ev.msg || ev.agent || ev.role || ev.status || '';
1878
+ const row = document.createElement('div');
1879
+ row.className = 'clf-row' + (isNew ? ' new' : '');
1880
+ row.title = msg;
1881
+ row.innerHTML = `<span class="clf-time">${time}</span><span class="clf-type">${type}</span><span class="clf-msg">${msg}</span>`;
1882
+ rows.appendChild(row);
1883
+ if (rows.children.length > 30) rows.removeChild(rows.firstChild);
1884
+ rows.scrollTop = rows.scrollHeight;
1885
+ }
1886
+
1887
+ function initLiveStrip() {
1888
+ orgRunStartMs = null;
1889
+ const rows = document.getElementById('clf-rows');
1890
+ if (rows) rows.innerHTML = '';
1891
+ const events = orgEventLog[selectedOrg] || [];
1892
+ // Seed from existing event history
1893
+ events.forEach(ev => appendLiveFeedRow(ev, false));
1894
+ // Detect running state from list data
1895
+ const listOrg = allOrgs.find(o => o.name === selectedOrg);
1896
+ if (listOrg && listOrg.running && !orgRunStartMs) {
1897
+ const acts = orgDetailData._activity || [];
1898
+ const startEv = acts.slice().reverse().find(e => e.type === 'org:start' || e.type === 'org:create');
1899
+ if (startEv && startEv.ts) orgRunStartMs = startEv.ts;
1900
+ else if (listOrg.running_since) orgRunStartMs = listOrg.running_since;
1901
+ else orgRunStartMs = Date.now(); // fallback
1902
+ } else if (listOrg && !listOrg.running) {
1903
+ orgRunStartMs = null;
1904
+ }
1905
+ updateLiveStrip();
1906
+ if (lsUptimeTimer) clearInterval(lsUptimeTimer);
1907
+ lsUptimeTimer = setInterval(updateLiveStrip, 1000);
1908
+ }
1909
+
1281
1910
  // ── Data loading ──────────────────────────────────────────────────
1282
1911
  async function loadOrgs() {
1283
1912
  try {
@@ -1307,9 +1936,30 @@ window.openCopyModal = function(name) {
1307
1936
  document.getElementById('copy-modal-status').className = '';
1308
1937
  document.getElementById('copy-confirm-btn').disabled = false;
1309
1938
  document.getElementById('copy-modal-overlay').classList.add('open');
1939
+ // Load project list
1940
+ const listEl = document.getElementById('copy-project-list');
1941
+ listEl.innerHTML = '<div class="copy-proj-loading">Loading projects…</div>';
1942
+ fetch('/api/projects').then(r => r.json()).then(data => {
1943
+ const projects = data?.projects || [];
1944
+ if (!projects.length) { listEl.innerHTML = '<div class="copy-proj-loading">No other projects found</div>'; return; }
1945
+ listEl.innerHTML = projects.map(p => {
1946
+ const label = p.name || p.slug || p.path?.split('/').pop() || p.path;
1947
+ const isCurrentDir = p.path === (window._orgDir || '');
1948
+ return `<div class="copy-proj-row${isCurrentDir ? ' selected' : ''}" title="${p.path}" onclick="selectCopyProject('${p.path.replace(/'/g,"\\'")}', this)">
1949
+ <span style="color:var(--text-hi)">${label}</span>
1950
+ <span style="color:var(--dim);font-size:10px;margin-left:6px">${p.path.replace(/\/Users\/[^/]+\//, '~/')}</span>
1951
+ </div>`;
1952
+ }).join('');
1953
+ }).catch(() => { listEl.innerHTML = '<div class="copy-proj-loading">Could not load projects</div>'; });
1310
1954
  setTimeout(() => document.getElementById('copy-dest-input').focus(), 60);
1311
1955
  };
1312
1956
 
1957
+ window.selectCopyProject = function(path, el) {
1958
+ document.querySelectorAll('.copy-proj-row').forEach(r => r.classList.remove('selected'));
1959
+ el.classList.add('selected');
1960
+ document.getElementById('copy-dest-input').value = path;
1961
+ };
1962
+
1313
1963
  window.closeCopyModal = function() {
1314
1964
  document.getElementById('copy-modal-overlay').classList.remove('open');
1315
1965
  copyTargetOrg = null;
@@ -1351,6 +2001,66 @@ window.executeCopy = async function() {
1351
2001
  }
1352
2002
  };
1353
2003
 
2004
+ // ── Export org ────────────────────────────────────────────────────
2005
+ window.exportOrg = async function(name) {
2006
+ try {
2007
+ const r = await fetch(`/api/orgs/${encodeURIComponent(name)}`);
2008
+ if (!r.ok) throw new Error(r.statusText);
2009
+ const blob = await r.blob();
2010
+ const a = document.createElement('a');
2011
+ a.href = URL.createObjectURL(blob);
2012
+ a.download = `${name}.json`;
2013
+ a.click();
2014
+ setTimeout(() => URL.revokeObjectURL(a.href), 5000);
2015
+ } catch(e) {
2016
+ alert('EXPORT FAILED: ' + e.message);
2017
+ }
2018
+ };
2019
+
2020
+ // ── Import org ────────────────────────────────────────────────────
2021
+ let importTargetOrg = null;
2022
+
2023
+ window.triggerImportOrg = function(name) {
2024
+ importTargetOrg = name;
2025
+ let inp = document.getElementById('oi-import-file-input');
2026
+ if (!inp) {
2027
+ inp = document.createElement('input');
2028
+ inp.type = 'file';
2029
+ inp.accept = '.json,application/json';
2030
+ inp.id = 'oi-import-file-input';
2031
+ inp.style.display = 'none';
2032
+ document.body.appendChild(inp);
2033
+ inp.addEventListener('change', handleImportFile);
2034
+ }
2035
+ inp.value = '';
2036
+ inp.click();
2037
+ };
2038
+
2039
+ async function handleImportFile(e) {
2040
+ const file = e.target.files[0];
2041
+ if (!file || !importTargetOrg) return;
2042
+ try {
2043
+ const text = await file.text();
2044
+ let data;
2045
+ try { data = JSON.parse(text); } catch(_) { alert('IMPORT FAILED: invalid JSON'); return; }
2046
+ const r = await fetch(`/api/orgs/${encodeURIComponent(importTargetOrg)}/import`, {
2047
+ method: 'POST',
2048
+ headers: { 'Content-Type': 'application/json' },
2049
+ body: JSON.stringify(data),
2050
+ });
2051
+ const result = await r.json();
2052
+ if (r.ok && result.ok) {
2053
+ loadOrgs();
2054
+ } else {
2055
+ alert('IMPORT FAILED: ' + (result.error || r.statusText));
2056
+ }
2057
+ } catch(e) {
2058
+ alert('IMPORT FAILED: ' + e.message);
2059
+ } finally {
2060
+ importTargetOrg = null;
2061
+ }
2062
+ }
2063
+
1354
2064
  // ── Bootstrap ─────────────────────────────────────────────────────
1355
2065
  connectSSE();
1356
2066
  loadOrgs();