@runcore-sh/runcore 0.1.8 → 0.1.10

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 (225) hide show
  1. package/dist/access/manifest.d.ts +59 -0
  2. package/dist/access/manifest.d.ts.map +1 -0
  3. package/dist/access/manifest.js +251 -0
  4. package/dist/access/manifest.js.map +1 -0
  5. package/dist/activity/log.d.ts +1 -1
  6. package/dist/activity/log.d.ts.map +1 -1
  7. package/dist/agents/autonomous.d.ts.map +1 -1
  8. package/dist/agents/autonomous.js +38 -0
  9. package/dist/agents/autonomous.js.map +1 -1
  10. package/dist/agents/governance.d.ts +70 -0
  11. package/dist/agents/governance.d.ts.map +1 -0
  12. package/dist/agents/governance.js +220 -0
  13. package/dist/agents/governance.js.map +1 -0
  14. package/dist/agents/governed-spawn.d.ts +83 -0
  15. package/dist/agents/governed-spawn.d.ts.map +1 -0
  16. package/dist/agents/governed-spawn.js +186 -0
  17. package/dist/agents/governed-spawn.js.map +1 -0
  18. package/dist/agents/heartbeat.d.ts +91 -0
  19. package/dist/agents/heartbeat.d.ts.map +1 -0
  20. package/dist/agents/heartbeat.js +323 -0
  21. package/dist/agents/heartbeat.js.map +1 -0
  22. package/dist/agents/index.d.ts +4 -1
  23. package/dist/agents/index.d.ts.map +1 -1
  24. package/dist/agents/index.js +6 -1
  25. package/dist/agents/index.js.map +1 -1
  26. package/dist/agents/spawn-policy.d.ts +45 -0
  27. package/dist/agents/spawn-policy.d.ts.map +1 -0
  28. package/dist/agents/spawn-policy.js +202 -0
  29. package/dist/agents/spawn-policy.js.map +1 -0
  30. package/dist/alert.d.ts +16 -0
  31. package/dist/alert.d.ts.map +1 -0
  32. package/dist/alert.js +70 -0
  33. package/dist/alert.js.map +1 -0
  34. package/dist/cli.js +261 -32
  35. package/dist/cli.js.map +1 -1
  36. package/dist/credentials/store.d.ts +1 -1
  37. package/dist/credentials/store.d.ts.map +1 -1
  38. package/dist/credentials/store.js +14 -3
  39. package/dist/credentials/store.js.map +1 -1
  40. package/dist/crystallizer.d.ts +56 -0
  41. package/dist/crystallizer.d.ts.map +1 -0
  42. package/dist/crystallizer.js +159 -0
  43. package/dist/crystallizer.js.map +1 -0
  44. package/dist/distiller.d.ts +48 -0
  45. package/dist/distiller.d.ts.map +1 -0
  46. package/dist/distiller.js +140 -0
  47. package/dist/distiller.js.map +1 -0
  48. package/dist/files/deep-index.d.ts +59 -0
  49. package/dist/files/deep-index.d.ts.map +1 -0
  50. package/dist/files/deep-index.js +337 -0
  51. package/dist/files/deep-index.js.map +1 -0
  52. package/dist/files/import.d.ts +44 -0
  53. package/dist/files/import.d.ts.map +1 -0
  54. package/dist/files/import.js +213 -0
  55. package/dist/files/import.js.map +1 -0
  56. package/dist/files/index-local.d.ts +37 -0
  57. package/dist/files/index-local.d.ts.map +1 -0
  58. package/dist/files/index-local.js +198 -0
  59. package/dist/files/index-local.js.map +1 -0
  60. package/dist/google/auth.d.ts +2 -0
  61. package/dist/google/auth.d.ts.map +1 -1
  62. package/dist/google/auth.js +2 -0
  63. package/dist/google/auth.js.map +1 -1
  64. package/dist/integrations/gate.d.ts +40 -0
  65. package/dist/integrations/gate.d.ts.map +1 -0
  66. package/dist/integrations/gate.js +100 -0
  67. package/dist/integrations/gate.js.map +1 -0
  68. package/dist/lib/audit.d.ts +43 -0
  69. package/dist/lib/audit.d.ts.map +1 -0
  70. package/dist/lib/audit.js +120 -0
  71. package/dist/lib/audit.js.map +1 -0
  72. package/dist/lib/brain-io.d.ts.map +1 -1
  73. package/dist/lib/brain-io.js +52 -0
  74. package/dist/lib/brain-io.js.map +1 -1
  75. package/dist/lib/dpapi.d.ts +14 -0
  76. package/dist/lib/dpapi.d.ts.map +1 -0
  77. package/dist/lib/dpapi.js +104 -0
  78. package/dist/lib/dpapi.js.map +1 -0
  79. package/dist/lib/glob-match.d.ts +22 -0
  80. package/dist/lib/glob-match.d.ts.map +1 -0
  81. package/dist/lib/glob-match.js +64 -0
  82. package/dist/lib/glob-match.js.map +1 -0
  83. package/dist/lib/locked.d.ts +40 -0
  84. package/dist/lib/locked.d.ts.map +1 -0
  85. package/dist/lib/locked.js +130 -0
  86. package/dist/lib/locked.js.map +1 -0
  87. package/dist/llm/complete.d.ts.map +1 -1
  88. package/dist/llm/complete.js +5 -2
  89. package/dist/llm/complete.js.map +1 -1
  90. package/dist/llm/fetch-guard.d.ts +16 -0
  91. package/dist/llm/fetch-guard.d.ts.map +1 -0
  92. package/dist/llm/fetch-guard.js +61 -0
  93. package/dist/llm/fetch-guard.js.map +1 -0
  94. package/dist/llm/guard.d.ts +40 -0
  95. package/dist/llm/guard.d.ts.map +1 -0
  96. package/dist/llm/guard.js +88 -0
  97. package/dist/llm/guard.js.map +1 -0
  98. package/dist/llm/membrane.d.ts +46 -0
  99. package/dist/llm/membrane.d.ts.map +1 -0
  100. package/dist/llm/membrane.js +123 -0
  101. package/dist/llm/membrane.js.map +1 -0
  102. package/dist/llm/providers/index.d.ts +5 -1
  103. package/dist/llm/providers/index.d.ts.map +1 -1
  104. package/dist/llm/providers/index.js +8 -1
  105. package/dist/llm/providers/index.js.map +1 -1
  106. package/dist/llm/redact.d.ts +39 -0
  107. package/dist/llm/redact.d.ts.map +1 -0
  108. package/dist/llm/redact.js +155 -0
  109. package/dist/llm/redact.js.map +1 -0
  110. package/dist/llm/sensitive-registry.d.ts +33 -0
  111. package/dist/llm/sensitive-registry.d.ts.map +1 -0
  112. package/dist/llm/sensitive-registry.js +106 -0
  113. package/dist/llm/sensitive-registry.js.map +1 -0
  114. package/dist/mcp-server.d.ts +11 -0
  115. package/dist/mcp-server.d.ts.map +1 -0
  116. package/dist/mcp-server.js +520 -0
  117. package/dist/mcp-server.js.map +1 -0
  118. package/dist/mdns.d.ts +17 -0
  119. package/dist/mdns.d.ts.map +1 -0
  120. package/dist/mdns.js +110 -0
  121. package/dist/mdns.js.map +1 -0
  122. package/dist/nerve/push.d.ts +26 -0
  123. package/dist/nerve/push.d.ts.map +1 -0
  124. package/dist/nerve/push.js +170 -0
  125. package/dist/nerve/push.js.map +1 -0
  126. package/dist/nerve/state.d.ts +35 -0
  127. package/dist/nerve/state.d.ts.map +1 -0
  128. package/dist/nerve/state.js +257 -0
  129. package/dist/nerve/state.js.map +1 -0
  130. package/dist/posture/engine.d.ts +41 -0
  131. package/dist/posture/engine.d.ts.map +1 -0
  132. package/dist/posture/engine.js +217 -0
  133. package/dist/posture/engine.js.map +1 -0
  134. package/dist/posture/index.d.ts +11 -0
  135. package/dist/posture/index.d.ts.map +1 -0
  136. package/dist/posture/index.js +10 -0
  137. package/dist/posture/index.js.map +1 -0
  138. package/dist/posture/middleware.d.ts +30 -0
  139. package/dist/posture/middleware.d.ts.map +1 -0
  140. package/dist/posture/middleware.js +92 -0
  141. package/dist/posture/middleware.js.map +1 -0
  142. package/dist/posture/types.d.ts +61 -0
  143. package/dist/posture/types.d.ts.map +1 -0
  144. package/dist/posture/types.js +48 -0
  145. package/dist/posture/types.js.map +1 -0
  146. package/dist/resend/inbox.d.ts +23 -0
  147. package/dist/resend/inbox.d.ts.map +1 -0
  148. package/dist/resend/inbox.js +198 -0
  149. package/dist/resend/inbox.js.map +1 -0
  150. package/dist/resend/webhooks.d.ts +30 -0
  151. package/dist/resend/webhooks.d.ts.map +1 -0
  152. package/dist/resend/webhooks.js +244 -0
  153. package/dist/resend/webhooks.js.map +1 -0
  154. package/dist/server.d.ts +5 -1
  155. package/dist/server.d.ts.map +1 -1
  156. package/dist/server.js +773 -58
  157. package/dist/server.js.map +1 -1
  158. package/dist/settings.d.ts +14 -1
  159. package/dist/settings.d.ts.map +1 -1
  160. package/dist/settings.js +32 -1
  161. package/dist/settings.js.map +1 -1
  162. package/dist/tier/bond.d.ts +51 -0
  163. package/dist/tier/bond.d.ts.map +1 -0
  164. package/dist/tier/bond.js +154 -0
  165. package/dist/tier/bond.js.map +1 -0
  166. package/dist/tier/freeze.d.ts +21 -0
  167. package/dist/tier/freeze.d.ts.map +1 -0
  168. package/dist/tier/freeze.js +73 -0
  169. package/dist/tier/freeze.js.map +1 -0
  170. package/dist/tier/gate.d.ts +11 -0
  171. package/dist/tier/gate.d.ts.map +1 -0
  172. package/dist/tier/gate.js +25 -0
  173. package/dist/tier/gate.js.map +1 -0
  174. package/dist/tier/heartbeat.d.ts +22 -0
  175. package/dist/tier/heartbeat.d.ts.map +1 -0
  176. package/dist/tier/heartbeat.js +128 -0
  177. package/dist/tier/heartbeat.js.map +1 -0
  178. package/dist/tier/token.d.ts +22 -0
  179. package/dist/tier/token.d.ts.map +1 -0
  180. package/dist/tier/token.js +100 -0
  181. package/dist/tier/token.js.map +1 -0
  182. package/dist/tier/types.d.ts +44 -0
  183. package/dist/tier/types.d.ts.map +1 -0
  184. package/dist/tier/types.js +61 -0
  185. package/dist/tier/types.js.map +1 -0
  186. package/dist/updater.d.ts +32 -0
  187. package/dist/updater.d.ts.map +1 -0
  188. package/dist/updater.js +145 -0
  189. package/dist/updater.js.map +1 -0
  190. package/dist/vault/policy.d.ts +42 -0
  191. package/dist/vault/policy.d.ts.map +1 -0
  192. package/dist/vault/policy.js +159 -0
  193. package/dist/vault/policy.js.map +1 -0
  194. package/dist/vault/store.d.ts +6 -0
  195. package/dist/vault/store.d.ts.map +1 -1
  196. package/dist/vault/store.js +15 -5
  197. package/dist/vault/store.js.map +1 -1
  198. package/dist/vault/transfer.d.ts +33 -0
  199. package/dist/vault/transfer.d.ts.map +1 -0
  200. package/dist/vault/transfer.js +187 -0
  201. package/dist/vault/transfer.js.map +1 -0
  202. package/dist/voucher.d.ts +39 -0
  203. package/dist/voucher.d.ts.map +1 -0
  204. package/dist/voucher.js +105 -0
  205. package/dist/voucher.js.map +1 -0
  206. package/dist/webhooks/handlers.d.ts +10 -0
  207. package/dist/webhooks/handlers.d.ts.map +1 -1
  208. package/dist/webhooks/handlers.js +53 -0
  209. package/dist/webhooks/handlers.js.map +1 -1
  210. package/dist/webhooks/index.d.ts +2 -2
  211. package/dist/webhooks/index.d.ts.map +1 -1
  212. package/dist/webhooks/index.js +2 -2
  213. package/dist/webhooks/index.js.map +1 -1
  214. package/dist/webhooks/verify.d.ts +8 -0
  215. package/dist/webhooks/verify.d.ts.map +1 -1
  216. package/dist/webhooks/verify.js +56 -0
  217. package/dist/webhooks/verify.js.map +1 -1
  218. package/package.json +8 -2
  219. package/public/board.html +8 -3
  220. package/public/browser.html +8 -3
  221. package/public/library.html +8 -3
  222. package/public/observatory.html +8 -3
  223. package/public/ops.html +8 -3
  224. package/public/registry.html +627 -0
  225. package/public/roadmap.html +975 -0
@@ -0,0 +1,627 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>{{INSTANCE_NAME}} — Registry</title>
7
+ <style>
8
+ :root {
9
+ --bg: #0e0e10;
10
+ --surface: #18181b;
11
+ --surface2: #222226;
12
+ --border: #2e2e33;
13
+ --text: #e4e4e7;
14
+ --text-dim: #8b8b94;
15
+ --accent: #6d5dfc;
16
+ --green: #22c55e;
17
+ --red: #ef4444;
18
+ --yellow: #eab308;
19
+ --orange: #f97316;
20
+ --blue: #3b82f6;
21
+ --purple: #a78bfa;
22
+ --mono: 'SF Mono', 'Cascadia Code', 'Fira Code', monospace;
23
+ }
24
+
25
+ * { margin: 0; padding: 0; box-sizing: border-box; }
26
+
27
+ body {
28
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
29
+ background: var(--bg);
30
+ color: var(--text);
31
+ height: 100vh;
32
+ display: flex;
33
+ flex-direction: column;
34
+ overflow: hidden;
35
+ }
36
+
37
+ /* --- Header --- */
38
+ header {
39
+ display: flex;
40
+ align-items: center;
41
+ justify-content: space-between;
42
+ padding: 16px 24px;
43
+ border-bottom: 1px solid var(--border);
44
+ background: var(--surface);
45
+ flex-shrink: 0;
46
+ }
47
+
48
+ header h1 {
49
+ font-size: 18px;
50
+ font-weight: 600;
51
+ letter-spacing: -0.3px;
52
+ }
53
+
54
+ header h1 a {
55
+ color: var(--text);
56
+ text-decoration: none;
57
+ }
58
+
59
+ header h1 a:hover { opacity: 0.8; }
60
+ header h1 span { color: var(--text-dim); font-weight: 400; }
61
+
62
+ .header-nav {
63
+ display: flex;
64
+ align-items: center;
65
+ gap: 8px;
66
+ margin-left: 16px;
67
+ }
68
+
69
+ .header-nav a {
70
+ color: var(--text-dim);
71
+ text-decoration: none;
72
+ font-size: 13px;
73
+ padding: 4px 10px;
74
+ border-radius: 6px;
75
+ border: 1px solid var(--border);
76
+ transition: all 0.15s;
77
+ }
78
+
79
+ .header-nav a:hover { color: var(--text); border-color: var(--accent); background: rgba(109,93,252,0.1); }
80
+ .header-nav a.active { color: var(--text); border-color: var(--border); background: var(--surface2); }
81
+
82
+ .header-nav .nav-divider {
83
+ width: 1px;
84
+ height: 18px;
85
+ background: var(--border);
86
+ margin: 0 4px;
87
+ align-self: center;
88
+ }
89
+
90
+ .header-actions {
91
+ display: flex;
92
+ align-items: center;
93
+ gap: 12px;
94
+ }
95
+
96
+ .settings-link {
97
+ color: var(--text-dim);
98
+ text-decoration: none;
99
+ font-size: 18px;
100
+ transition: color 0.15s;
101
+ }
102
+
103
+ .settings-link:hover { color: var(--text); }
104
+
105
+ /* --- Main layout --- */
106
+ .main {
107
+ flex: 1;
108
+ overflow-y: auto;
109
+ padding: 24px;
110
+ }
111
+
112
+ .panels {
113
+ display: flex;
114
+ gap: 24px;
115
+ max-width: 1200px;
116
+ margin: 0 auto;
117
+ }
118
+
119
+ .panel {
120
+ flex: 1;
121
+ min-width: 0;
122
+ background: var(--surface);
123
+ border: 1px solid var(--border);
124
+ border-radius: 10px;
125
+ overflow: hidden;
126
+ }
127
+
128
+ .panel-header {
129
+ padding: 16px 20px;
130
+ border-bottom: 1px solid var(--border);
131
+ font-size: 14px;
132
+ font-weight: 600;
133
+ text-transform: uppercase;
134
+ letter-spacing: 0.5px;
135
+ color: var(--text-dim);
136
+ }
137
+
138
+ .panel-body {
139
+ padding: 12px 0;
140
+ }
141
+
142
+ /* --- Service rows --- */
143
+ .service-row {
144
+ padding: 12px 20px;
145
+ border-bottom: 1px solid var(--border);
146
+ }
147
+
148
+ .service-row:last-child { border-bottom: none; }
149
+
150
+ .service-top {
151
+ display: flex;
152
+ align-items: center;
153
+ gap: 10px;
154
+ }
155
+
156
+ .status-dot {
157
+ width: 8px;
158
+ height: 8px;
159
+ border-radius: 50%;
160
+ flex-shrink: 0;
161
+ }
162
+
163
+ .status-dot.green { background: var(--green); }
164
+ .status-dot.gray { background: var(--text-dim); opacity: 0.4; }
165
+
166
+ .service-name {
167
+ font-size: 14px;
168
+ font-weight: 500;
169
+ flex: 1;
170
+ }
171
+
172
+ .service-provider {
173
+ font-size: 12px;
174
+ color: var(--text-dim);
175
+ font-family: var(--mono);
176
+ }
177
+
178
+ .service-status {
179
+ font-size: 12px;
180
+ color: var(--text-dim);
181
+ margin-top: 4px;
182
+ padding-left: 18px;
183
+ }
184
+
185
+ .service-status.connected { color: var(--green); }
186
+
187
+ /* --- Setup steps --- */
188
+ .setup-toggle {
189
+ font-size: 12px;
190
+ color: var(--accent);
191
+ cursor: pointer;
192
+ margin-top: 6px;
193
+ padding-left: 18px;
194
+ user-select: none;
195
+ }
196
+
197
+ .setup-toggle:hover { text-decoration: underline; }
198
+
199
+ .setup-steps {
200
+ display: none;
201
+ margin-top: 8px;
202
+ padding-left: 18px;
203
+ }
204
+
205
+ .setup-steps.open { display: block; }
206
+
207
+ .setup-step {
208
+ display: flex;
209
+ align-items: center;
210
+ gap: 8px;
211
+ padding: 4px 0;
212
+ font-size: 13px;
213
+ color: var(--text-dim);
214
+ }
215
+
216
+ .step-check {
217
+ width: 14px;
218
+ height: 14px;
219
+ border: 1.5px solid var(--border);
220
+ border-radius: 3px;
221
+ display: flex;
222
+ align-items: center;
223
+ justify-content: center;
224
+ flex-shrink: 0;
225
+ font-size: 10px;
226
+ }
227
+
228
+ .step-check.done {
229
+ border-color: var(--green);
230
+ color: var(--green);
231
+ }
232
+
233
+ .connect-btn {
234
+ display: inline-block;
235
+ margin-top: 8px;
236
+ padding: 5px 14px;
237
+ font-size: 12px;
238
+ font-weight: 500;
239
+ color: var(--text);
240
+ background: var(--accent);
241
+ border: none;
242
+ border-radius: 6px;
243
+ cursor: pointer;
244
+ transition: opacity 0.15s;
245
+ }
246
+
247
+ .connect-btn:hover { opacity: 0.85; }
248
+ .connect-btn:disabled { opacity: 0.4; cursor: not-allowed; }
249
+
250
+ /* --- Capability rows --- */
251
+ .cap-group {
252
+ padding: 12px 20px 8px;
253
+ }
254
+
255
+ .cap-group-title {
256
+ font-size: 11px;
257
+ font-weight: 600;
258
+ text-transform: uppercase;
259
+ letter-spacing: 0.5px;
260
+ color: var(--text-dim);
261
+ margin-bottom: 8px;
262
+ }
263
+
264
+ .cap-row {
265
+ display: flex;
266
+ align-items: center;
267
+ gap: 10px;
268
+ padding: 6px 0;
269
+ }
270
+
271
+ .cap-id {
272
+ font-size: 13px;
273
+ font-family: var(--mono);
274
+ flex: 1;
275
+ min-width: 0;
276
+ overflow: hidden;
277
+ text-overflow: ellipsis;
278
+ white-space: nowrap;
279
+ }
280
+
281
+ .cap-tag {
282
+ font-size: 11px;
283
+ font-family: var(--mono);
284
+ color: var(--text-dim);
285
+ background: var(--surface2);
286
+ padding: 2px 6px;
287
+ border-radius: 4px;
288
+ white-space: nowrap;
289
+ }
290
+
291
+ /* --- Toggle switch --- */
292
+ .toggle {
293
+ position: relative;
294
+ width: 32px;
295
+ height: 18px;
296
+ flex-shrink: 0;
297
+ }
298
+
299
+ .toggle input {
300
+ opacity: 0;
301
+ width: 0;
302
+ height: 0;
303
+ }
304
+
305
+ .toggle-slider {
306
+ position: absolute;
307
+ inset: 0;
308
+ background: var(--border);
309
+ border-radius: 9px;
310
+ cursor: pointer;
311
+ transition: background 0.2s;
312
+ }
313
+
314
+ .toggle-slider::before {
315
+ content: '';
316
+ position: absolute;
317
+ width: 14px;
318
+ height: 14px;
319
+ left: 2px;
320
+ top: 2px;
321
+ background: var(--text);
322
+ border-radius: 50%;
323
+ transition: transform 0.2s;
324
+ }
325
+
326
+ .toggle input:checked + .toggle-slider {
327
+ background: var(--green);
328
+ }
329
+
330
+ .toggle input:checked + .toggle-slider::before {
331
+ transform: translateX(14px);
332
+ }
333
+
334
+ /* --- Loading / error --- */
335
+ .loading {
336
+ text-align: center;
337
+ padding: 40px 20px;
338
+ color: var(--text-dim);
339
+ font-size: 14px;
340
+ }
341
+
342
+ .error-msg {
343
+ text-align: center;
344
+ padding: 20px;
345
+ color: var(--red);
346
+ font-size: 13px;
347
+ }
348
+
349
+ /* --- Responsive --- */
350
+ @media (max-width: 768px) {
351
+ header { padding: 12px 16px; }
352
+ .header-nav { display: none; }
353
+ .panels { flex-direction: column; }
354
+ .main { padding: 16px; }
355
+ }
356
+ </style>
357
+ </head>
358
+ <body>
359
+
360
+ <header>
361
+ <div style="display:flex;align-items:center;">
362
+ <h1><a href="/">{{INSTANCE_NAME}}</a> <span>· Registry</span></h1>
363
+ <nav class="header-nav">
364
+ <a href="/">Chat</a>
365
+ <a href="/library">Library</a>
366
+ <a href="/personal">Personal</a>
367
+ <a href="/life">Life</a>
368
+ <a href="/registry" class="active">Registry</a>
369
+ <span class="nav-divider"></span>
370
+ <a href="/observatory">Observatory</a>
371
+ <a href="/ops">Operations</a>
372
+ <a href="/board">Board</a>
373
+ <a href="/roadmap">Roadmap</a>
374
+ </nav>
375
+ </div>
376
+ <div class="header-actions">
377
+ <a href="/?settings=open" class="settings-link" title="Settings">&#9881;</a>
378
+ </div>
379
+ </header>
380
+
381
+ <div class="main">
382
+ <div class="panels">
383
+ <!-- Services panel -->
384
+ <div class="panel">
385
+ <div class="panel-header">Services</div>
386
+ <div class="panel-body" id="services-panel">
387
+ <div class="loading">Loading services…</div>
388
+ </div>
389
+ </div>
390
+
391
+ <!-- Capabilities panel -->
392
+ <div class="panel">
393
+ <div class="panel-header">Capabilities</div>
394
+ <div class="panel-body" id="caps-panel">
395
+ <div class="loading">Loading capabilities…</div>
396
+ </div>
397
+ </div>
398
+ </div>
399
+ </div>
400
+
401
+ <script>
402
+ (function() {
403
+ let currentData = null;
404
+
405
+ async function fetchData() {
406
+ try {
407
+ const res = await fetch("/api/capabilities");
408
+ if (!res.ok) throw new Error("HTTP " + res.status);
409
+ return await res.json();
410
+ } catch (err) {
411
+ return null;
412
+ }
413
+ }
414
+
415
+ // Category labels and order
416
+ const CATEGORY_ORDER = ["platform", "channel", "sidecar"];
417
+ const CATEGORY_LABELS = { platform: "Platforms", channel: "Channels", sidecar: "Sidecars" };
418
+
419
+ // --- Render services panel (data-driven from IntegrationRegistry) ---
420
+ function renderServices(data) {
421
+ const panel = document.getElementById("services-panel");
422
+ if (!data) {
423
+ panel.innerHTML = '<div class="error-msg">Failed to load services</div>';
424
+ return;
425
+ }
426
+
427
+ const integrations = data.integrations || [];
428
+ const vaultKeyNames = (data.vaultKeys || []).map(k => typeof k === "string" ? k : k.name);
429
+
430
+ if (integrations.length === 0) {
431
+ panel.innerHTML = '<div class="loading">No integrations registered</div>';
432
+ return;
433
+ }
434
+
435
+ // Group by category
436
+ const groups = {};
437
+ for (const cat of CATEGORY_ORDER) groups[cat] = [];
438
+ for (const int of integrations) {
439
+ const cat = int.category || "platform";
440
+ if (!groups[cat]) groups[cat] = [];
441
+ groups[cat].push(int);
442
+ }
443
+
444
+ let html = "";
445
+ for (const cat of CATEGORY_ORDER) {
446
+ const items = groups[cat];
447
+ if (!items || items.length === 0) continue;
448
+
449
+ html += '<div class="cap-group"><div class="cap-group-title">' + CATEGORY_LABELS[cat] + '</div></div>';
450
+
451
+ for (const int of items) {
452
+ const isAvailable = int.configured && int.authenticated;
453
+ const dotClass = isAvailable ? "green" : "gray";
454
+ const statusText = isAvailable ? "Connected" : (int.configured ? "Configured" : "Not configured");
455
+ const statusClass = isAvailable ? "connected" : "";
456
+
457
+ html += '<div class="service-row">';
458
+ html += '<div class="service-top">';
459
+ html += '<div class="status-dot ' + dotClass + '"></div>';
460
+ html += '<div class="service-name">' + int.displayName + '</div>';
461
+ html += '<div class="service-provider">' + int.id + '</div>';
462
+ html += '</div>';
463
+ html += '<div class="service-status ' + statusClass + '">' + statusText + '</div>';
464
+
465
+ // Setup steps for non-sidecar integrations that aren't fully connected
466
+ if (!isAvailable && cat !== "sidecar" && int.requiredKeys && int.requiredKeys.length > 0) {
467
+ html += '<div class="setup-toggle" data-svc="' + int.id + '">&#9660; Setup Steps</div>';
468
+ html += '<div class="setup-steps" id="setup-' + int.id + '">';
469
+
470
+ // Key requirements
471
+ for (const key of int.requiredKeys) {
472
+ const done = vaultKeyNames.includes(key);
473
+ html += '<div class="setup-step">';
474
+ html += '<div class="step-check ' + (done ? "done" : "") + '">' + (done ? "&#10003;" : "") + '</div>';
475
+ html += '<span>Add ' + key + ' to vault</span>';
476
+ html += '</div>';
477
+ }
478
+
479
+ // Setup instructions from the definition
480
+ if (int.setupSteps) {
481
+ for (const step of int.setupSteps) {
482
+ if (step.toLowerCase().includes("add ") && step.toLowerCase().includes(" to the vault")) continue;
483
+ html += '<div class="setup-step">';
484
+ html += '<div class="step-check"></div>';
485
+ html += '<span>' + step + '</span>';
486
+ html += '</div>';
487
+ }
488
+ }
489
+
490
+ // OAuth connect button
491
+ if (int.oauthRoute && int.configured && !int.authenticated) {
492
+ html += '<button class="connect-btn" data-oauth="' + int.oauthRoute + '">Connect</button>';
493
+ }
494
+
495
+ html += '</div>';
496
+ }
497
+
498
+ html += '</div>';
499
+ }
500
+ }
501
+
502
+ panel.innerHTML = html;
503
+
504
+ // Attach toggle handlers
505
+ panel.querySelectorAll(".setup-toggle").forEach(el => {
506
+ el.addEventListener("click", () => {
507
+ const target = document.getElementById("setup-" + el.dataset.svc);
508
+ if (target) target.classList.toggle("open");
509
+ el.textContent = target.classList.contains("open") ? "\u25B2 Setup Steps" : "\u25BC Setup Steps";
510
+ });
511
+ });
512
+
513
+ // Attach connect button handlers
514
+ panel.querySelectorAll(".connect-btn").forEach(btn => {
515
+ btn.addEventListener("click", () => {
516
+ window.open(btn.dataset.oauth, "_blank");
517
+ });
518
+ });
519
+ }
520
+
521
+ // --- Render capabilities panel ---
522
+ function renderCapabilities(data) {
523
+ const panel = document.getElementById("caps-panel");
524
+ if (!data) {
525
+ panel.innerHTML = '<div class="error-msg">Failed to load capabilities</div>';
526
+ return;
527
+ }
528
+
529
+ const caps = data.capabilities || [];
530
+
531
+ // Group by pattern
532
+ const groups = {
533
+ action: { title: "Action Blocks", items: [] },
534
+ context: { title: "Context Providers", items: [] },
535
+ meta: { title: "Meta", items: [] }
536
+ };
537
+
538
+ for (const cap of caps) {
539
+ const pattern = (cap.pattern || cap.tag || "").toLowerCase();
540
+ if (pattern.includes("action") || cap.tag?.includes("ACTION")) {
541
+ groups.action.items.push(cap);
542
+ } else if (pattern.includes("context") || cap.id?.includes("context")) {
543
+ groups.context.items.push(cap);
544
+ } else {
545
+ groups.meta.items.push(cap);
546
+ }
547
+ }
548
+
549
+ // Toggleable capabilities (these can be switched on/off via settings)
550
+ const toggleable = new Set(["browser", "email", "docs", "calendar"]);
551
+
552
+ let html = "";
553
+ for (const [, group] of Object.entries(groups)) {
554
+ if (group.items.length === 0) continue;
555
+
556
+ html += '<div class="cap-group">';
557
+ html += '<div class="cap-group-title">' + group.title + '</div>';
558
+
559
+ for (const cap of group.items) {
560
+ const enabled = cap.enabled !== false;
561
+ const dotClass = enabled ? "green" : "gray";
562
+ const canToggle = toggleable.has(cap.id);
563
+
564
+ html += '<div class="cap-row">';
565
+ html += '<div class="status-dot ' + dotClass + '"></div>';
566
+ html += '<div class="cap-id">' + cap.id + '</div>';
567
+ if (cap.tag) {
568
+ html += '<div class="cap-tag">' + cap.tag + '</div>';
569
+ }
570
+ if (canToggle) {
571
+ html += '<label class="toggle">';
572
+ html += '<input type="checkbox" ' + (enabled ? "checked" : "") + ' data-cap-id="' + cap.id + '">';
573
+ html += '<span class="toggle-slider"></span>';
574
+ html += '</label>';
575
+ }
576
+ html += '</div>';
577
+ }
578
+
579
+ html += '</div>';
580
+ }
581
+
582
+ if (!html) {
583
+ html = '<div class="loading">No capabilities registered</div>';
584
+ }
585
+
586
+ panel.innerHTML = html;
587
+
588
+ // Attach toggle handlers
589
+ panel.querySelectorAll('input[data-cap-id]').forEach(input => {
590
+ input.addEventListener("change", async () => {
591
+ const capId = input.dataset.capId;
592
+ const enabled = input.checked;
593
+ try {
594
+ await fetch("/api/settings", {
595
+ method: "PUT",
596
+ headers: { "Content-Type": "application/json" },
597
+ body: JSON.stringify({ capabilities: { [capId]: enabled } })
598
+ });
599
+ await refresh();
600
+ } catch (err) {
601
+ // Revert on failure
602
+ input.checked = !enabled;
603
+ }
604
+ });
605
+ });
606
+ }
607
+
608
+ // --- OAuth callback listeners ---
609
+ window.addEventListener("message", async (e) => {
610
+ if (e.data === "google-connected" || e.data === "slack-connected") {
611
+ await refresh();
612
+ }
613
+ });
614
+
615
+ // --- Refresh everything ---
616
+ async function refresh() {
617
+ currentData = await fetchData();
618
+ renderServices(currentData);
619
+ renderCapabilities(currentData);
620
+ }
621
+
622
+ // Initial load
623
+ refresh();
624
+ })();
625
+ </script>
626
+ </body>
627
+ </html>