ltcai 3.6.0 โ†’ 4.0.1

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 (238) hide show
  1. package/README.md +39 -31
  2. package/docs/CHANGELOG.md +64 -0
  3. package/docs/REALTIME_COLLABORATION.md +3 -3
  4. package/docs/V3_FRONTEND.md +9 -8
  5. package/docs/V4_BRAIN_ARCHITECTURE.md +322 -0
  6. package/docs/V4_DIGITAL_BRAIN_RECOVERY.md +552 -0
  7. package/docs/V4_IMPLEMENTATION_PLAN.md +470 -0
  8. package/docs/kg-schema.md +51 -53
  9. package/docs/spec-vs-impl.md +10 -10
  10. package/kg_schema.py +2 -520
  11. package/knowledge_graph.py +37 -4629
  12. package/knowledge_graph_api.py +11 -127
  13. package/latticeai/__init__.py +1 -1
  14. package/latticeai/api/admin.py +16 -17
  15. package/latticeai/api/agents.py +20 -7
  16. package/latticeai/api/auth.py +46 -15
  17. package/latticeai/api/chat.py +112 -76
  18. package/latticeai/api/health.py +1 -1
  19. package/latticeai/api/hooks.py +1 -1
  20. package/latticeai/api/invitations.py +100 -0
  21. package/latticeai/api/knowledge_graph.py +139 -0
  22. package/latticeai/api/local_files.py +1 -1
  23. package/latticeai/api/mcp.py +23 -11
  24. package/latticeai/api/memory.py +1 -1
  25. package/latticeai/api/models.py +1 -1
  26. package/latticeai/api/network.py +81 -0
  27. package/latticeai/api/plugins.py +3 -6
  28. package/latticeai/api/realtime.py +5 -8
  29. package/latticeai/api/search.py +26 -2
  30. package/latticeai/api/security_dashboard.py +2 -3
  31. package/latticeai/api/setup.py +2 -2
  32. package/latticeai/api/static_routes.py +11 -16
  33. package/latticeai/api/tools.py +3 -0
  34. package/latticeai/api/ui_redirects.py +26 -0
  35. package/latticeai/api/workflow_designer.py +85 -6
  36. package/latticeai/api/workspace.py +93 -57
  37. package/latticeai/app_factory.py +1781 -0
  38. package/latticeai/brain/__init__.py +18 -0
  39. package/latticeai/brain/_kg_common.py +1123 -0
  40. package/latticeai/brain/context.py +213 -0
  41. package/latticeai/brain/conversations.py +236 -0
  42. package/latticeai/brain/discovery.py +1455 -0
  43. package/latticeai/brain/documents.py +218 -0
  44. package/latticeai/brain/identity.py +175 -0
  45. package/latticeai/brain/ingest.py +644 -0
  46. package/latticeai/brain/memory.py +102 -0
  47. package/latticeai/brain/network.py +205 -0
  48. package/latticeai/brain/projection.py +561 -0
  49. package/latticeai/brain/provenance.py +401 -0
  50. package/latticeai/brain/retrieval.py +1316 -0
  51. package/latticeai/brain/schema.py +640 -0
  52. package/latticeai/brain/store.py +216 -0
  53. package/latticeai/brain/write_master.py +225 -0
  54. package/latticeai/core/agent.py +31 -7
  55. package/latticeai/core/audit.py +0 -7
  56. package/latticeai/core/config.py +1 -1
  57. package/latticeai/core/context_builder.py +1 -2
  58. package/latticeai/core/enterprise.py +1 -1
  59. package/latticeai/core/graph_curator.py +2 -2
  60. package/latticeai/core/invitations.py +131 -0
  61. package/latticeai/core/marketplace.py +1 -1
  62. package/latticeai/core/mcp_registry.py +791 -0
  63. package/latticeai/core/model_compat.py +1 -1
  64. package/latticeai/core/model_resolution.py +0 -1
  65. package/latticeai/core/multi_agent.py +238 -4
  66. package/latticeai/core/policy.py +54 -0
  67. package/latticeai/core/realtime.py +65 -44
  68. package/latticeai/core/security.py +1 -1
  69. package/latticeai/core/sessions.py +66 -10
  70. package/latticeai/core/users.py +147 -0
  71. package/latticeai/core/workflow_engine.py +114 -2
  72. package/latticeai/core/workspace_os.py +477 -29
  73. package/latticeai/models/__init__.py +7 -0
  74. package/latticeai/models/router.py +779 -0
  75. package/latticeai/server_app.py +29 -1536
  76. package/latticeai/services/agent_runtime.py +243 -4
  77. package/latticeai/services/app_context.py +75 -14
  78. package/latticeai/services/ingestion.py +47 -0
  79. package/latticeai/services/kg_portability.py +33 -3
  80. package/latticeai/services/memory_service.py +39 -11
  81. package/latticeai/services/model_runtime.py +2 -5
  82. package/latticeai/services/platform_runtime.py +100 -23
  83. package/latticeai/services/run_executor.py +328 -0
  84. package/latticeai/services/search_service.py +17 -8
  85. package/latticeai/services/tool_dispatch.py +12 -2
  86. package/latticeai/services/triggers.py +241 -0
  87. package/latticeai/services/upload_service.py +37 -12
  88. package/latticeai/services/workspace_service.py +55 -16
  89. package/llm_router.py +29 -772
  90. package/ltcai_cli.py +1 -2
  91. package/mcp_registry.py +25 -788
  92. package/p_reinforce.py +124 -14
  93. package/package.json +10 -20
  94. package/scripts/bump_version.py +99 -0
  95. package/scripts/generate_diagrams.py +0 -1
  96. package/scripts/lint_v3.mjs +105 -18
  97. package/scripts/validate_release_artifacts.py +0 -1
  98. package/scripts/wheel_smoke.py +142 -0
  99. package/server.py +11 -7
  100. package/setup_wizard.py +1142 -0
  101. package/static/sw.js +81 -52
  102. package/static/v3/asset-manifest.json +33 -25
  103. package/static/v3/css/{lattice.base.e4cdd05d.css โ†’ lattice.base.49deefb5.css} +1 -1
  104. package/static/v3/css/lattice.base.css +1 -1
  105. package/static/v3/css/{lattice.components.9b49d614.css โ†’ lattice.components.cde18231.css} +1 -1
  106. package/static/v3/css/lattice.components.css +1 -1
  107. package/static/v3/css/{lattice.shell.8fcc9d33.css โ†’ lattice.shell.29d36d85.css} +1 -1
  108. package/static/v3/css/lattice.shell.css +1 -1
  109. package/static/v3/css/{lattice.tokens.e7018963.css โ†’ lattice.tokens.304cbc40.css} +3 -0
  110. package/static/v3/css/lattice.tokens.css +3 -0
  111. package/static/v3/css/{lattice.views.22f69117.css โ†’ lattice.views.0a18b6c5.css} +2 -2
  112. package/static/v3/css/lattice.views.css +2 -2
  113. package/static/v3/index.html +3 -4
  114. package/static/v3/js/{app.c541f955.js โ†’ app.c5c80c46.js} +1 -1
  115. package/static/v3/js/core/{api.33d6320e.js โ†’ api.ba0fbf14.js} +58 -1
  116. package/static/v3/js/core/api.js +57 -0
  117. package/static/v3/js/core/i18n.880e1fec.js +575 -0
  118. package/static/v3/js/core/i18n.js +575 -0
  119. package/static/v3/js/core/routes.37522821.js +101 -0
  120. package/static/v3/js/core/routes.js +71 -63
  121. package/static/v3/js/core/{shell.8c163e0e.js โ†’ shell.e3f6bbfa.js} +68 -39
  122. package/static/v3/js/core/shell.js +66 -37
  123. package/static/v3/js/core/{store.34ebd5e6.js โ†’ store.7b2aa044.js} +11 -1
  124. package/static/v3/js/core/store.js +11 -1
  125. package/static/v3/js/views/account.eff40715.js +143 -0
  126. package/static/v3/js/views/account.js +143 -0
  127. package/static/v3/js/views/activity.0d271ef9.js +67 -0
  128. package/static/v3/js/views/activity.js +67 -0
  129. package/static/v3/js/views/{admin-users.03bac88c.js โ†’ admin-users.f7ac7b43.js} +4 -6
  130. package/static/v3/js/views/admin-users.js +4 -6
  131. package/static/v3/js/views/{agents.014d0b74.js โ†’ agents.17c5288d.js} +35 -12
  132. package/static/v3/js/views/agents.js +35 -12
  133. package/static/v3/js/views/{chat.e6dd7dd0.js โ†’ chat.e250e2cc.js} +23 -0
  134. package/static/v3/js/views/chat.js +23 -0
  135. package/static/v3/js/views/graph-canvas.17c15d65.js +509 -0
  136. package/static/v3/js/views/graph-canvas.js +509 -0
  137. package/static/v3/js/views/{hybrid-search.b22b97e0.js โ†’ hybrid-search.2fb63ed9.js} +1 -2
  138. package/static/v3/js/views/hybrid-search.js +1 -2
  139. package/static/v3/js/views/{knowledge-graph.a96040a5.js โ†’ knowledge-graph.4d09c537.js} +60 -44
  140. package/static/v3/js/views/knowledge-graph.js +60 -44
  141. package/static/v3/js/views/network.52a4f181.js +97 -0
  142. package/static/v3/js/views/network.js +97 -0
  143. package/static/v3/js/views/{planning.9ac3e313.js โ†’ planning.4876fd77.js} +26 -5
  144. package/static/v3/js/views/planning.js +26 -5
  145. package/static/v3/js/views/runs.b63b2afa.js +144 -0
  146. package/static/v3/js/views/runs.js +144 -0
  147. package/static/v3/js/views/{settings.8631fa5e.js โ†’ settings.b7140634.js} +7 -8
  148. package/static/v3/js/views/settings.js +7 -8
  149. package/static/v3/js/views/snapshots.6f5db095.js +135 -0
  150. package/static/v3/js/views/snapshots.js +135 -0
  151. package/static/v3/js/views/{workflows.26c57290.js โ†’ workflows.7752225a.js} +87 -2
  152. package/static/v3/js/views/workflows.js +87 -2
  153. package/static/v3/js/views/workspace-admin.c466029b.js +156 -0
  154. package/static/v3/js/views/workspace-admin.js +156 -0
  155. package/static/vendor/chart.umd.min.js +20 -0
  156. package/static/vendor/fonts/inter-latin-300-normal.woff2 +0 -0
  157. package/static/vendor/fonts/inter-latin-400-normal.woff2 +0 -0
  158. package/static/vendor/fonts/inter-latin-500-normal.woff2 +0 -0
  159. package/static/vendor/fonts/inter-latin-600-normal.woff2 +0 -0
  160. package/static/vendor/fonts/inter-latin-700-normal.woff2 +0 -0
  161. package/static/vendor/fonts/inter-latin-800-normal.woff2 +0 -0
  162. package/static/vendor/fonts/inter.css +44 -0
  163. package/static/vendor/icons/tabler-icons.min.css +4 -0
  164. package/static/vendor/icons/tabler-icons.woff2 +0 -0
  165. package/static/vendor/marked.min.js +69 -0
  166. package/telegram_bot.py +1 -2
  167. package/tools/commands.py +4 -2
  168. package/tools/computer.py +1 -1
  169. package/tools/documents.py +1 -3
  170. package/tools/filesystem.py +0 -4
  171. package/tools/knowledge.py +1 -3
  172. package/tools/network.py +1 -3
  173. package/codex_telegram_bot.py +0 -195
  174. package/docs/assets/v3.4.0/agent-run.png +0 -0
  175. package/docs/assets/v3.4.0/agents.png +0 -0
  176. package/docs/assets/v3.4.0/before/chat-before.png +0 -0
  177. package/docs/assets/v3.4.0/before/files-before.png +0 -0
  178. package/docs/assets/v3.4.0/chat.png +0 -0
  179. package/docs/assets/v3.4.0/connect-folder.png +0 -0
  180. package/docs/assets/v3.4.0/files.png +0 -0
  181. package/docs/assets/v3.4.0/home.png +0 -0
  182. package/docs/assets/v3.4.0/hooks-dispatch.png +0 -0
  183. package/docs/assets/v3.4.0/knowledge-graph.png +0 -0
  184. package/docs/assets/v3.4.0/local-agent.png +0 -0
  185. package/docs/assets/v3.4.0/memory.png +0 -0
  186. package/docs/assets/v3.4.0/settings.png +0 -0
  187. package/docs/assets/v3.4.0/vision-input.png +0 -0
  188. package/docs/assets/v3.4.0/workflows.png +0 -0
  189. package/docs/assets/v3.4.1/e2e_runtime_log.txt +0 -42
  190. package/docs/assets/v3.4.1/hooks-dispatch.png +0 -0
  191. package/docs/assets/v3.4.1/local-agent.png +0 -0
  192. package/docs/images/admin-dashboard.png +0 -0
  193. package/docs/images/architecture.png +0 -0
  194. package/docs/images/enterprise.png +0 -0
  195. package/docs/images/graph.png +0 -0
  196. package/docs/images/hero.gif +0 -0
  197. package/docs/images/knowledge-graph.png +0 -0
  198. package/docs/images/lattice-ai-demo.gif +0 -0
  199. package/docs/images/lattice-ai-hero.png +0 -0
  200. package/docs/images/logo.svg +0 -33
  201. package/docs/images/mobile-responsive.png +0 -0
  202. package/docs/images/model-recommendation.png +0 -0
  203. package/docs/images/onboarding.png +0 -0
  204. package/docs/images/organization.png +0 -0
  205. package/docs/images/pipeline.png +0 -0
  206. package/docs/images/screenshot-admin.png +0 -0
  207. package/docs/images/screenshot-chat.png +0 -0
  208. package/docs/images/screenshot-graph.png +0 -0
  209. package/docs/images/skills.png +0 -0
  210. package/docs/images/workspace-dark.png +0 -0
  211. package/docs/images/workspace-light.png +0 -0
  212. package/docs/images/workspace.png +0 -0
  213. package/requirements.txt +0 -16
  214. package/static/account.html +0 -115
  215. package/static/activity.html +0 -73
  216. package/static/admin.html +0 -488
  217. package/static/agents.html +0 -139
  218. package/static/chat.html +0 -844
  219. package/static/css/reference/account.css +0 -439
  220. package/static/css/reference/admin.css +0 -610
  221. package/static/css/reference/base.css +0 -1661
  222. package/static/css/reference/chat.css +0 -4623
  223. package/static/css/reference/graph.css +0 -1016
  224. package/static/css/responsive.css +0 -861
  225. package/static/graph.html +0 -124
  226. package/static/platform.css +0 -104
  227. package/static/plugins.html +0 -136
  228. package/static/scripts/account.js +0 -238
  229. package/static/scripts/admin.js +0 -1614
  230. package/static/scripts/chat.js +0 -5081
  231. package/static/scripts/graph.js +0 -1804
  232. package/static/scripts/platform.js +0 -64
  233. package/static/scripts/ux.js +0 -167
  234. package/static/scripts/workspace.js +0 -948
  235. package/static/v3/js/core/routes.2ce3815a.js +0 -93
  236. package/static/workflows.html +0 -146
  237. package/static/workspace.css +0 -1121
  238. package/static/workspace.html +0 -357
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/requirements.txt DELETED
@@ -1,16 +0,0 @@
1
- fastapi
2
- uvicorn
3
- pydantic
4
- httpx
5
- pillow
6
- openai
7
- python-docx
8
- openpyxl
9
- python-pptx
10
- python-multipart
11
- keyring
12
- authlib
13
- cryptography
14
- pdfplumber
15
- pypdfium2
16
- watchdog
@@ -1,115 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="ko">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, interactive-widget=resizes-content">
6
- <title>Lattice AI</title>
7
- <script src="/static/scripts/ux.js"></script>
8
- <link rel="manifest" href="/manifest.json">
9
- <meta name="theme-color" content="#f3ecff">
10
- <meta name="apple-mobile-web-app-capable" content="yes">
11
- <link rel="apple-touch-icon" href="/icons/apple-touch-icon.png">
12
- <link rel="icon" type="image/png" sizes="32x32" href="/icons/favicon-32.png">
13
- <link rel="preconnect" href="https://fonts.googleapis.com">
14
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
15
- <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap">
16
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/tabler-icons.min.css">
17
- <link rel="stylesheet" href="/static/css/tokens.css">
18
- <link rel="stylesheet" href="/static/css/reference/base.css">
19
- <link rel="stylesheet" href="/static/css/reference/account.css">
20
- <link rel="stylesheet" href="/static/css/reference/admin.css">
21
- <link rel="stylesheet" href="/static/css/reference/graph.css">
22
- <link rel="stylesheet" href="/static/css/reference/chat.css">
23
- <link rel="stylesheet" href="/static/css/responsive.css">
24
- </head>
25
- <body class="lattice-ref-auth">
26
- <div class="orb orb-1"></div>
27
- <div class="orb orb-2"></div>
28
- <div class="auth-titlebar" aria-hidden="true">
29
- <div class="auth-window-brand"><i class="ti ti-cube-3d-sphere"></i><span>Lattice AI</span></div>
30
- <div class="auth-window-controls"><span></span><span></span><span></span></div>
31
- </div>
32
- <div class="auth-wave auth-wave-left" aria-hidden="true"></div>
33
- <div class="auth-wave auth-wave-right" aria-hidden="true"></div>
34
- <div class="auth-network" aria-hidden="true">
35
- <span></span><span></span><span></span><span></span><span></span><span></span>
36
- </div>
37
-
38
- <div class="login-shell">
39
- <div class="brand-preview" aria-hidden="true">
40
- <div class="preview-node n1"></div>
41
- <div class="preview-node n2"></div>
42
- <div class="preview-node n3"></div>
43
- <div class="preview-node n4"></div>
44
- <div class="preview-line l1"></div>
45
- <div class="preview-line l2"></div>
46
- <div class="preview-line l3"></div>
47
- </div>
48
- <div class="card">
49
- <div class="lang-wrap">
50
- <button class="lang-btn" id="lang-btn" onclick="toggleLang()">๐ŸŒ Language</button>
51
- <div class="lang-menu" id="lang-menu">
52
- <div class="lang-opt" id="opt-ko" onclick="setLang('ko')">๐Ÿ‡ฐ๐Ÿ‡ท ํ•œ๊ตญ์–ด</div>
53
- <div class="lang-opt" id="opt-en" onclick="setLang('en')">๐Ÿ‡บ๐Ÿ‡ธ English</div>
54
- </div>
55
- </div>
56
- <!-- Login form -->
57
- <div id="login-section">
58
- <div class="hero-logo">
59
- <div class="hero-logo-mark"><i class="ti ti-cube-3d-sphere"></i></div>
60
- <h2 class="title" id="login-title">Lattice AI</h2>
61
- </div>
62
- <p class="subtitle" id="login-sub">๋‚ด PC์—์„œ ์‹œ์ž‘ํ•˜๋Š”<br>๊ฐœ์ธ AI ์›Œํฌ์ŠคํŽ˜์ด์Šค</p>
63
- <label class="auth-field">
64
- <i class="ti ti-mail"></i>
65
- <input class="input" type="email" id="login-email" placeholder="์ด๋ฉ”์ผ ์ฃผ์†Œ">
66
- </label>
67
- <label class="auth-field">
68
- <i class="ti ti-lock"></i>
69
- <input class="input" type="password" id="login-pw" placeholder="๋น„๋ฐ€๋ฒˆํ˜ธ" onkeydown="if(event.key==='Enter')doLogin()">
70
- <button type="button" class="field-eye" onclick="togglePasswordVisibility()" title="๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณด๊ธฐ"><i class="ti ti-eye"></i></button>
71
- </label>
72
- <div class="msg" id="login-msg"></div>
73
- <button class="submit" id="login-btn" onclick="doLogin()" data-ko="๋กœ๊ทธ์ธ" data-en="Log in">๋กœ๊ทธ์ธ</button>
74
- <button class="register-cta" id="go-register-link" onclick="showSection('register');return false;">ํšŒ์›๊ฐ€์ž…</button>
75
- <div id="sso-section">
76
- <div class="sso-divider" id="sso-divider-text">์กฐ์ง ๊ณ„์ •์œผ๋กœ ๋กœ๊ทธ์ธ</div>
77
- <button class="sso-btn sso-ms" onclick="doSSOLogin('microsoft')">
78
- <span class="ms-logo" aria-hidden="true"><b></b><b></b><b></b><b></b></span>
79
- <span id="sso-ms-label">Microsoft Entra ID๋กœ ๊ณ„์†ํ•˜๊ธฐ</span>
80
- </button>
81
- <button class="sso-btn sso-okta" onclick="doSSOLogin('okta')">
82
- <span class="okta-logo" aria-hidden="true"></span>
83
- <span id="sso-okta-label">Okta SSO๋กœ ๊ณ„์†ํ•˜๊ธฐ</span>
84
- </button>
85
- </div>
86
- <button class="local-start" onclick="showSection('register');return false;"><i class="ti ti-device-desktop"></i> <span id="local-start-label">๋กœ์ปฌ ๊ณ„์ •์œผ๋กœ ์‹œ์ž‘</span></button>
87
- </div>
88
-
89
- <!-- Register form -->
90
- <div id="register-section" style="display:none;">
91
- <div class="logo"><i class="ti ti-user-plus"></i></div>
92
- <h2 class="title" id="reg-title">๊ณ„์ • ๋งŒ๋“ค๊ธฐ</h2>
93
- <p class="subtitle" id="reg-sub">Lattice AI ์›Œํฌ์ŠคํŽ˜์ด์Šค์— ์ฐธ์—ฌํ•˜์„ธ์š”</p>
94
- <input class="input" type="email" id="reg-email" placeholder="์ด๋ฉ”์ผ ์ฃผ์†Œ">
95
- <input class="input" type="password" id="reg-pw" placeholder="๋น„๋ฐ€๋ฒˆํ˜ธ (4์ž ์ด์ƒ)">
96
- <input class="input" type="password" id="reg-pw2" placeholder="๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ">
97
- <input class="input" type="text" id="reg-name" placeholder="์ด๋ฆ„">
98
- <input class="input" type="text" id="reg-nick" placeholder="๋‹‰๋„ค์ž„">
99
- <div class="msg" id="reg-msg"></div>
100
- <button class="submit" id="reg-btn" onclick="doRegister()">๊ฐ€์ž…ํ•˜๊ธฐ</button>
101
- <p class="switch" id="reg-switch">
102
- <span id="have-account-text">์ด๋ฏธ ๊ณ„์ •์ด ์žˆ๋‚˜์š”?</span>
103
- <a href="#" onclick="showSection('login');return false;" id="go-login-link">๋กœ๊ทธ์ธ</a>
104
- </p>
105
- </div>
106
- </div>
107
- </div>
108
- <footer class="auth-footer">
109
- <a href="#" onclick="return false;" id="help-link">๋„์›€๋ง</a>
110
- <a href="#" onclick="return false;" id="privacy-link">๊ฐœ์ธ์ •๋ณด ์ฒ˜๋ฆฌ๋ฐฉ์นจ</a>
111
- </footer>
112
-
113
- <script src="/static/scripts/account.js"></script>
114
- </body>
115
- </html>
@@ -1,73 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, interactive-widget=resizes-content" />
6
- <title>Realtime Activity โ€” Lattice AI</title>
7
- <script src="/static/scripts/ux.js"></script>
8
- <link rel="stylesheet" href="/static/css/tokens.css" />
9
- <link rel="stylesheet" href="/static/platform.css" />
10
- <link rel="stylesheet" href="/static/css/responsive.css" />
11
- </head>
12
- <body>
13
- <main>
14
- <h1>Realtime Activity</h1>
15
- <p class="sub" id="sub">Live presence + activity feed across workspace, graph, agent, and workflow events (SSE).</p>
16
-
17
- <div class="row">
18
- <span class="badge" id="connBadge">connectingโ€ฆ</span>
19
- <span class="badge" id="presenceBadge">presence: 0</span>
20
- <div class="spacer"></div>
21
- <button class="ghost" id="clearBtn">Clear view</button>
22
- </div>
23
-
24
- <div class="section">
25
- <h3>Live feed</h3>
26
- <div id="feed"><div class="empty">Waiting for eventsโ€ฆ</div></div>
27
- </div>
28
- </main>
29
-
30
- <script type="module">
31
- import { mountHeader, api, escapeHtml, badge } from "/static/scripts/platform.js";
32
- mountHeader("/activity");
33
-
34
- const feed = document.getElementById("feed");
35
- const seen = new Set();
36
-
37
- function renderEvent(ev) {
38
- if (ev.seq && seen.has(ev.seq)) return;
39
- if (ev.seq) seen.add(ev.seq);
40
- if (feed.querySelector(".empty")) feed.innerHTML = "";
41
- const node = document.createElement("div");
42
- node.className = "timeline-item";
43
- node.innerHTML = `<div class="row">${badge(ev.area || "event")} <strong>${escapeHtml(ev.event_type || "")}</strong>
44
- <span class="t-meta">${escapeHtml(ev.workspace_id || "personal")} ยท ${escapeHtml(ev.received_at || ev.timestamp || "")}</span></div>
45
- <pre style="max-height:160px">${escapeHtml(JSON.stringify(ev.payload || {}, null, 2))}</pre>`;
46
- feed.prepend(node);
47
- while (feed.children.length > 100) feed.lastChild.remove();
48
- }
49
-
50
- async function refreshPresence() {
51
- try {
52
- const data = await api("/realtime/presence");
53
- document.getElementById("presenceBadge").textContent = `presence: ${data.presence.length}`;
54
- document.getElementById("sub").textContent =
55
- `Transport: ${data.stats.transport.toUpperCase()} ยท subscribers: ${data.stats.subscribers} ยท feed: ${data.stats.feed_size}`;
56
- } catch {}
57
- }
58
-
59
- document.getElementById("clearBtn").addEventListener("click", () => { feed.innerHTML = `<div class="empty">Cleared.</div>`; });
60
-
61
- // Seed with recent feed, then connect to the SSE stream.
62
- api("/realtime/feed?limit=30").then((d) => (d.events || []).reverse().forEach(renderEvent)).catch(() => {});
63
-
64
- const es = new EventSource("/realtime/stream");
65
- es.onopen = () => { document.getElementById("connBadge").textContent = "โ— live"; document.getElementById("connBadge").className = "badge ok"; };
66
- es.onerror = () => { document.getElementById("connBadge").textContent = "โ—‹ reconnecting"; document.getElementById("connBadge").className = "badge warn"; };
67
- es.onmessage = (e) => { try { renderEvent(JSON.parse(e.data)); } catch {} };
68
-
69
- refreshPresence();
70
- setInterval(refreshPresence, 8000);
71
- </script>
72
- </body>
73
- </html>