@zhin.js/console 1.0.50 → 1.0.52

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 (67) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +22 -0
  3. package/browser.tsconfig.json +19 -0
  4. package/client/src/components/PageHeader.tsx +26 -0
  5. package/client/src/components/ui/accordion.tsx +2 -1
  6. package/client/src/components/ui/badge.tsx +1 -3
  7. package/client/src/components/ui/scroll-area.tsx +5 -2
  8. package/client/src/components/ui/select.tsx +7 -3
  9. package/client/src/components/ui/separator.tsx +5 -2
  10. package/client/src/components/ui/tabs.tsx +4 -2
  11. package/client/src/layouts/dashboard.tsx +223 -121
  12. package/client/src/main.tsx +34 -34
  13. package/client/src/pages/bot-detail/MessageBody.tsx +110 -0
  14. package/client/src/pages/bot-detail/date-utils.ts +8 -0
  15. package/client/src/pages/bot-detail/index.tsx +798 -0
  16. package/client/src/pages/bot-detail/types.ts +92 -0
  17. package/client/src/pages/bot-detail/useBotConsole.tsx +600 -0
  18. package/client/src/pages/bots.tsx +111 -73
  19. package/client/src/pages/database/constants.ts +16 -0
  20. package/client/src/pages/database/database-page.tsx +170 -0
  21. package/client/src/pages/database/document-collection-view.tsx +155 -0
  22. package/client/src/pages/database/index.tsx +1 -0
  23. package/client/src/pages/database/json-field.tsx +11 -0
  24. package/client/src/pages/database/kv-bucket-view.tsx +169 -0
  25. package/client/src/pages/database/related-table-view.tsx +221 -0
  26. package/client/src/pages/env.tsx +38 -28
  27. package/client/src/pages/files/code-editor.tsx +85 -0
  28. package/client/src/pages/files/editor-constants.ts +9 -0
  29. package/client/src/pages/files/file-editor.tsx +133 -0
  30. package/client/src/pages/files/file-icons.tsx +25 -0
  31. package/client/src/pages/files/files-page.tsx +92 -0
  32. package/client/src/pages/files/hljs-global.d.ts +10 -0
  33. package/client/src/pages/files/index.tsx +1 -0
  34. package/client/src/pages/files/language.ts +18 -0
  35. package/client/src/pages/files/tree-node.tsx +69 -0
  36. package/client/src/pages/files/use-hljs-theme.ts +23 -0
  37. package/client/src/pages/logs.tsx +77 -22
  38. package/client/src/style.css +144 -0
  39. package/client/src/utils/parseComposerContent.ts +57 -0
  40. package/client/tailwind.config.js +1 -0
  41. package/client/tsconfig.json +3 -1
  42. package/dist/assets/index-COKXlFo2.js +124 -0
  43. package/dist/assets/style-kkLO-vsa.css +3 -0
  44. package/dist/client.js +4262 -1
  45. package/dist/index.html +2 -2
  46. package/dist/radix-ui.js +1261 -1262
  47. package/dist/react-dom-client.js +2243 -2240
  48. package/dist/react-dom.js +15 -15
  49. package/dist/style.css +1 -3
  50. package/lib/index.js +1010 -81
  51. package/lib/transform.js +16 -2
  52. package/lib/websocket.js +845 -28
  53. package/node.tsconfig.json +18 -0
  54. package/package.json +15 -16
  55. package/src/bin.ts +24 -0
  56. package/src/bot-db-models.ts +74 -0
  57. package/src/bot-hub.ts +240 -0
  58. package/src/bot-persistence.ts +270 -0
  59. package/src/build.ts +90 -0
  60. package/src/dev.ts +107 -0
  61. package/src/index.ts +337 -0
  62. package/src/transform.ts +199 -0
  63. package/src/websocket.ts +1369 -0
  64. package/client/src/pages/database.tsx +0 -708
  65. package/client/src/pages/files.tsx +0 -470
  66. package/client/src/pages/login-assist.tsx +0 -225
  67. package/dist/index.js +0 -124
@@ -35,6 +35,15 @@
35
35
  --sidebar-accent-foreground: 240 5.9% 10%;
36
36
  --sidebar-border: 220 13% 91%;
37
37
  --sidebar-ring: 240 5.9% 10%;
38
+ /* Bot 详情 IM 区(参考 Telegram Web A 间距与层次) */
39
+ --im-list-bg: 228 24% 97%;
40
+ --im-chat-bg: 228 30% 98%;
41
+ --im-bubble-in: 0 0% 100%;
42
+ --im-bubble-out: 213 82% 51%;
43
+ --im-bubble-out-fg: 0 0% 100%;
44
+ --im-date-bg: 0 0% 100%;
45
+ --im-date-fg: 222 12% 40%;
46
+ --im-at: 213 90% 42%;
38
47
  }
39
48
 
40
49
  .dark {
@@ -65,6 +74,14 @@
65
74
  --sidebar-accent-foreground: 240 4.8% 95.9%;
66
75
  --sidebar-border: 240 3.7% 15.9%;
67
76
  --sidebar-ring: 240 4.9% 83.9%;
77
+ --im-list-bg: 222 14% 11%;
78
+ --im-chat-bg: 222 16% 8%;
79
+ --im-bubble-in: 215 14% 17%;
80
+ --im-bubble-out: 213 65% 48%;
81
+ --im-bubble-out-fg: 0 0% 100%;
82
+ --im-date-bg: 215 14% 16%;
83
+ --im-date-fg: 215 12% 72%;
84
+ --im-at: 204 100% 68%;
68
85
  }
69
86
  }
70
87
 
@@ -220,6 +237,117 @@
220
237
  overflow: hidden;
221
238
  }
222
239
 
240
+ /* 机器人详情:三栏 IM 布局 */
241
+ .im-layout {
242
+ padding: 0;
243
+ gap: 0;
244
+ height: calc(100vh - 42px - 2rem);
245
+ border-radius: var(--radius);
246
+ border: 1px solid hsl(var(--border));
247
+ background: hsl(var(--background));
248
+ }
249
+
250
+ .im-layout .channel-sidebar {
251
+ border: none;
252
+ border-radius: 0;
253
+ background: hsl(var(--im-list-bg));
254
+ border-right: 1px solid hsl(var(--border) / 0.65);
255
+ }
256
+
257
+ .im-main-split {
258
+ flex: 1;
259
+ display: flex;
260
+ min-width: 0;
261
+ min-height: 0;
262
+ height: 100%;
263
+ overflow: hidden;
264
+ }
265
+
266
+ .im-center {
267
+ flex: 1;
268
+ display: flex;
269
+ flex-direction: column;
270
+ min-width: 0;
271
+ min-height: 0;
272
+ background: hsl(var(--im-chat-bg));
273
+ }
274
+
275
+ .im-right-panel {
276
+ width: min(300px, 32vw);
277
+ flex-shrink: 0;
278
+ display: none;
279
+ flex-direction: column;
280
+ border-left: 1px solid hsl(var(--border) / 0.65);
281
+ background: hsl(var(--card));
282
+ }
283
+
284
+ @media (min-width: 900px) {
285
+ .im-right-panel.im-right-visible {
286
+ display: flex;
287
+ }
288
+ }
289
+
290
+ .im-date-pill {
291
+ align-self: center;
292
+ margin: 0.5rem 0;
293
+ padding: 0.2rem 0.65rem;
294
+ border-radius: 9999px;
295
+ font-size: 0.72rem;
296
+ font-weight: 500;
297
+ color: hsl(var(--im-date-fg));
298
+ background: hsl(var(--im-date-bg));
299
+ box-shadow: 0 0 0 1px hsl(var(--border) / 0.45);
300
+ }
301
+
302
+ .im-bubble-in {
303
+ max-width: min(78%, 28rem);
304
+ border-radius: 0.65rem 0.65rem 0.65rem 0.2rem;
305
+ padding: 0.45rem 0.65rem 0.5rem;
306
+ background: hsl(var(--im-bubble-in));
307
+ box-shadow: 0 1px 0 hsl(var(--border) / 0.35);
308
+ }
309
+
310
+ .im-bubble-out {
311
+ max-width: min(78%, 28rem);
312
+ border-radius: 0.65rem 0.65rem 0.2rem 0.65rem;
313
+ padding: 0.45rem 0.65rem 0.5rem;
314
+ background: hsl(var(--im-bubble-out));
315
+ color: hsl(var(--im-bubble-out-fg));
316
+ box-shadow: 0 1px 0 hsl(0 0% 0% / 0.12);
317
+ }
318
+
319
+ .im-bubble-out .im-meta,
320
+ .im-bubble-out .text-muted-foreground {
321
+ color: hsl(var(--im-bubble-out-fg) / 0.85);
322
+ }
323
+
324
+ .im-bubble-out .im-at {
325
+ color: hsl(var(--im-bubble-out-fg) / 0.95);
326
+ text-decoration: underline;
327
+ text-underline-offset: 2px;
328
+ }
329
+
330
+ .im-composer {
331
+ border-top: 1px solid hsl(var(--border) / 0.7);
332
+ background: hsl(var(--card));
333
+ }
334
+
335
+ .im-chat-header {
336
+ flex-shrink: 0;
337
+ border-bottom: 1px solid hsl(var(--border) / 0.65);
338
+ background: hsl(var(--card));
339
+ }
340
+
341
+ .im-at {
342
+ color: hsl(var(--im-at));
343
+ }
344
+
345
+ .menu-item.im-row-compact {
346
+ padding: 0.4rem 0.55rem;
347
+ border-radius: 0.45rem;
348
+ gap: 0.55rem;
349
+ }
350
+
223
351
  .rich-text-editor {
224
352
  font-family: inherit;
225
353
  transition: border-color 200ms cubic-bezier(0.4, 0, 0.2, 1);
@@ -251,6 +379,22 @@
251
379
  display: block;
252
380
  }
253
381
 
382
+ .rich-text-editor .editor-video,
383
+ .rich-text-editor .editor-audio {
384
+ display: inline-flex;
385
+ align-items: center;
386
+ gap: 4px;
387
+ padding: 4px 10px;
388
+ margin: 2px 0;
389
+ border-radius: 6px;
390
+ border: 1px solid hsl(var(--border));
391
+ background: hsl(var(--muted) / 0.45);
392
+ font-size: 0.8rem;
393
+ vertical-align: middle;
394
+ user-select: none;
395
+ cursor: default;
396
+ }
397
+
254
398
  .rich-text-editor .editor-at {
255
399
  display: inline-flex;
256
400
  align-items: center;
@@ -0,0 +1,57 @@
1
+ /** 与机器人消息段结构一致,供解析/规范化使用 */
2
+ export type MessageContent = Array<{ type: string; data?: Record<string, unknown> }>
3
+
4
+ /**
5
+ * 解析输入框文本为消息段(与沙盒约定一致)。
6
+ * 支持 [@名称]、[face:id]、[image:url]、[video:url]、[audio:url]
7
+ */
8
+ export function parseComposerToSegments(text: string): MessageContent {
9
+ const segments: MessageContent = []
10
+ const regex =
11
+ /\[@([^\]]+)\]|\[face:(\d+)\]|\[image:([^\]]+)\]|\[video:([^\]]+)\]|\[audio:([^\]]+)\]/g
12
+ let lastIndex = 0
13
+ let match: RegExpExecArray | null
14
+ while ((match = regex.exec(text)) !== null) {
15
+ if (match.index > lastIndex) {
16
+ const t = text.substring(lastIndex, match.index)
17
+ if (t) segments.push({ type: 'text', data: { text: t } })
18
+ }
19
+ if (match[1]) segments.push({ type: 'at', data: { qq: match[1], name: match[1] } })
20
+ else if (match[2]) segments.push({ type: 'face', data: { id: parseInt(match[2], 10) } })
21
+ else if (match[3]) segments.push({ type: 'image', data: { url: match[3] } })
22
+ else if (match[4]) segments.push({ type: 'video', data: { url: match[4] } })
23
+ else if (match[5]) segments.push({ type: 'audio', data: { url: match[5] } })
24
+ lastIndex = regex.lastIndex
25
+ }
26
+ if (lastIndex < text.length) {
27
+ const r = text.substring(lastIndex)
28
+ if (r) segments.push({ type: 'text', data: { text: r } })
29
+ }
30
+ return segments.length > 0 ? segments : [{ type: 'text', data: { text } }]
31
+ }
32
+
33
+ export function hasRenderableComposerSegments(segments: MessageContent): boolean {
34
+ if (!segments.length) return false
35
+ return segments.some((s) => {
36
+ if (s.type === 'text') return Boolean(String(s.data?.text ?? '').trim())
37
+ return true
38
+ })
39
+ }
40
+
41
+ /** 统一 WS 推送 / 收件箱里的 content(数组、JSON 字符串、纯文本) */
42
+ export function normalizeInboundContent(raw: unknown): MessageContent {
43
+ if (Array.isArray(raw)) {
44
+ return raw as MessageContent
45
+ }
46
+ if (typeof raw === 'string') {
47
+ if (!raw.trim()) return []
48
+ try {
49
+ const p = JSON.parse(raw) as unknown
50
+ if (Array.isArray(p)) return p as MessageContent
51
+ } catch {
52
+ /* 非 JSON */
53
+ }
54
+ return [{ type: 'text', data: { text: raw } }]
55
+ }
56
+ return []
57
+ }
@@ -18,6 +18,7 @@ export default {
18
18
  `${cwd}/node_modules/@zhin.js/*/client/**/*.{js,ts,jsx,tsx}`,
19
19
  `${cwd}/node_modules/@zhin.js/*/dist/**/*.{js,ts,jsx,tsx}`,
20
20
  `${cwd}/plugins/*/client/**/*.{js,ts,jsx,tsx}`,
21
+ `${cwd}/plugins/**/client/**/*.{js,ts,jsx,tsx}`,
21
22
  `${cwd}/client/**/*.{js,ts,jsx,tsx}`,
22
23
  ].filter(Boolean),
23
24
  theme: {
@@ -12,5 +12,7 @@
12
12
  "paths": {
13
13
  "@/*": ["src/*"]
14
14
  }
15
- }
15
+ },
16
+ "include": ["src/**/*", "src/**/*.tsx"],
17
+ "exclude": ["node_modules", "dist"]
16
18
  }