@kb-labs/studio-app 0.7.0 → 2.8.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 (175) hide show
  1. package/dist/index.html +1 -0
  2. package/dist/main.1d68e922.js +522 -0
  3. package/dist/main.1d68e922.js.map +1 -0
  4. package/dist/main.80b70197.css +2 -0
  5. package/dist/main.80b70197.css.map +1 -0
  6. package/dist/mf-manifest.json +241 -0
  7. package/dist/mf-stats.json +271 -0
  8. package/package.json +56 -39
  9. package/server.js +68 -0
  10. package/.env.example +0 -10
  11. package/UI-KIT-COMPONENTS.md +0 -783
  12. package/UI-KIT-PLAN.md +0 -326
  13. package/eslint-rules/no-direct-antd-import.js +0 -151
  14. package/eslint.config.ts +0 -27
  15. package/index.html +0 -17
  16. package/postcss.config.js +0 -7
  17. package/public/favicon.ico +0 -0
  18. package/rspack.config.mjs +0 -118
  19. package/src/App.tsx +0 -46
  20. package/src/components/devtools/devtools-log-feed.module.css +0 -165
  21. package/src/components/devtools/devtools-log-feed.tsx +0 -300
  22. package/src/components/devtools/devtools-panel.module.css +0 -121
  23. package/src/components/devtools/devtools-panel.tsx +0 -115
  24. package/src/components/empty-state.tsx +0 -28
  25. package/src/components/error-boundary.tsx +0 -210
  26. package/src/components/health-banner.module.css +0 -103
  27. package/src/components/health-banner.tsx +0 -134
  28. package/src/components/health-indicator.tsx +0 -12
  29. package/src/components/page-header.tsx +0 -49
  30. package/src/components/page-transition.tsx +0 -24
  31. package/src/components/role-switcher.tsx +0 -148
  32. package/src/components/run-badge.tsx +0 -13
  33. package/src/components/ui/icons.tsx +0 -509
  34. package/src/components/ui/index.ts +0 -25
  35. package/src/components/ui/kb-config-provider.tsx +0 -130
  36. package/src/components/ui/kb-header.module.css +0 -51
  37. package/src/components/ui/kb-header.tsx +0 -112
  38. package/src/components/ui/kb-notification-bell.module.css +0 -103
  39. package/src/components/ui/kb-notification-bell.tsx +0 -199
  40. package/src/components/ui/kb-page-layout.tsx +0 -66
  41. package/src/components/ui/kb-quick-search.module.css +0 -86
  42. package/src/components/ui/kb-quick-search.tsx +0 -196
  43. package/src/components/ui/kb-sidebar.module.css +0 -47
  44. package/src/components/ui/kb-sidebar.tsx +0 -196
  45. package/src/components/ui/kb-stat-card.module.css +0 -21
  46. package/src/components/ui/kb-stat-card.tsx +0 -22
  47. package/src/components/ui/kb-stat-grid.tsx +0 -22
  48. package/src/components/ui/kb-status-bar.module.css +0 -49
  49. package/src/components/ui/kb-status-bar.tsx +0 -145
  50. package/src/components/ui/kb-system-health-indicator.tsx +0 -229
  51. package/src/components/ui/kb-theme-toggle.tsx +0 -42
  52. package/src/components/ui/theme-adapter.ts +0 -812
  53. package/src/components/ui/theme-transition-overlay.tsx +0 -70
  54. package/src/components/ui/utils.ts +0 -6
  55. package/src/components/widget-error-boundary.tsx +0 -172
  56. package/src/config/env.ts +0 -5
  57. package/src/config/feature-flags.ts +0 -482
  58. package/src/config/studio.config.schema.ts +0 -88
  59. package/src/config/studio.config.ts +0 -84
  60. package/src/env.d.ts +0 -23
  61. package/src/hooks/use-command-palette.ts +0 -6
  62. package/src/hooks/use-devtools-store.ts +0 -25
  63. package/src/hooks/use-feature-flags.ts +0 -101
  64. package/src/index.css +0 -10
  65. package/src/layouts/dashboard-grid.tsx +0 -122
  66. package/src/layouts/index.ts +0 -12
  67. package/src/layouts/two-pane.tsx +0 -134
  68. package/src/main.tsx +0 -15
  69. package/src/modules/analytics/components/analytics-daily-stats-chart.tsx +0 -257
  70. package/src/modules/analytics/components/analytics-date-range-picker.tsx +0 -121
  71. package/src/modules/analytics/pages/analytics-cache-page.tsx +0 -285
  72. package/src/modules/analytics/pages/analytics-embeddings-page.tsx +0 -274
  73. package/src/modules/analytics/pages/analytics-events-page.tsx +0 -425
  74. package/src/modules/analytics/pages/analytics-llm-page.tsx +0 -434
  75. package/src/modules/analytics/pages/analytics-overview-page.tsx +0 -336
  76. package/src/modules/analytics/pages/analytics-page.tsx +0 -20
  77. package/src/modules/analytics/pages/analytics-storage-page.tsx +0 -344
  78. package/src/modules/analytics/pages/analytics-vectorstore-page.tsx +0 -279
  79. package/src/modules/analytics/routes/index.tsx +0 -133
  80. package/src/modules/analytics/utils/formatters.test.ts +0 -148
  81. package/src/modules/analytics/utils/formatters.ts +0 -100
  82. package/src/modules/auth/pages/login-page.module.css +0 -113
  83. package/src/modules/auth/pages/login-page.tsx +0 -80
  84. package/src/modules/auth/routes/index.tsx +0 -24
  85. package/src/modules/dashboard/components/ActivityTimelineWidget.tsx +0 -199
  86. package/src/modules/dashboard/components/AiInsightsWidget.tsx +0 -358
  87. package/src/modules/dashboard/components/AnimatedMetricCard.css +0 -88
  88. package/src/modules/dashboard/components/AnimatedMetricCard.tsx +0 -125
  89. package/src/modules/dashboard/components/HeroMetricCard.css +0 -114
  90. package/src/modules/dashboard/components/HeroMetricCard.tsx +0 -152
  91. package/src/modules/dashboard/components/HeroMetricsWidget.tsx +0 -146
  92. package/src/modules/dashboard/components/SystemResourcesWidget.tsx +0 -197
  93. package/src/modules/dashboard/components/dashboard-empty.tsx +0 -22
  94. package/src/modules/dashboard/components/dashboard-kpis-widget.tsx +0 -59
  95. package/src/modules/dashboard/components/dashboard-kpis.tsx +0 -13
  96. package/src/modules/dashboard/components/dashboard-latency-percentiles-widget.tsx +0 -85
  97. package/src/modules/dashboard/components/dashboard-metrics-widget.tsx +0 -78
  98. package/src/modules/dashboard/components/dashboard-plugins-widget.tsx +0 -67
  99. package/src/modules/dashboard/components/dashboard-requests-widget.tsx +0 -62
  100. package/src/modules/dashboard/layouts/dashboard-layout.tsx +0 -16
  101. package/src/modules/dashboard/pages/ai-insights-page.tsx +0 -563
  102. package/src/modules/dashboard/pages/dashboard-animations.css +0 -317
  103. package/src/modules/dashboard/pages/dashboard-page.tsx +0 -13
  104. package/src/modules/dashboard/routes/index.tsx +0 -70
  105. package/src/modules/observability/pages/devkit-page.tsx +0 -263
  106. package/src/modules/observability/pages/incident-detail-page.tsx +0 -571
  107. package/src/modules/observability/pages/incidents-page.tsx +0 -370
  108. package/src/modules/observability/pages/log-detail-page.tsx +0 -508
  109. package/src/modules/observability/pages/logs-page.tsx +0 -1129
  110. package/src/modules/observability/pages/prometheus-metrics-page.tsx +0 -486
  111. package/src/modules/observability/pages/state-broker-page.tsx +0 -229
  112. package/src/modules/observability/pages/system-events-page.tsx +0 -255
  113. package/src/modules/observability/routes/index.tsx +0 -133
  114. package/src/modules/plugins/components/marketplace-card.tsx +0 -153
  115. package/src/modules/plugins/components/plugin-ai-assistant-modal.tsx +0 -374
  116. package/src/modules/plugins/components/plugin-card.tsx +0 -136
  117. package/src/modules/plugins/components/plugin-detail/capabilities-summary.tsx +0 -101
  118. package/src/modules/plugins/components/plugin-detail/cli-commands-table.tsx +0 -101
  119. package/src/modules/plugins/components/plugin-detail/index.ts +0 -7
  120. package/src/modules/plugins/components/plugin-detail/jobs-table.tsx +0 -64
  121. package/src/modules/plugins/components/plugin-detail/permissions/env-permissions.tsx +0 -30
  122. package/src/modules/plugins/components/plugin-detail/permissions/filesystem-permissions.tsx +0 -68
  123. package/src/modules/plugins/components/plugin-detail/permissions/index.ts +0 -6
  124. package/src/modules/plugins/components/plugin-detail/permissions/network-permissions.tsx +0 -43
  125. package/src/modules/plugins/components/plugin-detail/permissions/platform-services.tsx +0 -242
  126. package/src/modules/plugins/components/plugin-detail/permissions/resource-quotas.tsx +0 -96
  127. package/src/modules/plugins/components/plugin-detail/permissions/shell-permissions.tsx +0 -55
  128. package/src/modules/plugins/components/plugin-detail/permissions-view.tsx +0 -47
  129. package/src/modules/plugins/components/plugin-detail/plugin-header.tsx +0 -169
  130. package/src/modules/plugins/components/plugin-detail/rest-routes-table.tsx +0 -159
  131. package/src/modules/plugins/components/plugin-detail/workflows-table.tsx +0 -40
  132. package/src/modules/plugins/components/plugin-grid.tsx +0 -20
  133. package/src/modules/plugins/components/plugin-table.tsx +0 -178
  134. package/src/modules/plugins/pages/marketplace-page.tsx +0 -200
  135. package/src/modules/plugins/pages/plugin-detail-page.tsx +0 -1145
  136. package/src/modules/plugins/routes/index.tsx +0 -48
  137. package/src/modules/plugins/utils/index.ts +0 -1
  138. package/src/modules/plugins/utils/schema-helpers.ts +0 -21
  139. package/src/modules/settings/components/api-routes-viewer.tsx +0 -415
  140. package/src/modules/settings/components/appearance-settings.tsx +0 -200
  141. package/src/modules/settings/components/configuration-settings.tsx +0 -321
  142. package/src/modules/settings/components/data-privacy-settings.tsx +0 -111
  143. package/src/modules/settings/components/experimental-settings.tsx +0 -243
  144. package/src/modules/settings/components/navigation-settings.tsx +0 -198
  145. package/src/modules/settings/components/notifications-settings.tsx +0 -40
  146. package/src/modules/settings/pages/settings-page.tsx +0 -298
  147. package/src/modules/settings/routes/index.tsx +0 -47
  148. package/src/pages/README-assistant.md +0 -91
  149. package/src/pages/login-page.tsx +0 -177
  150. package/src/pages/not-found-page.tsx +0 -85
  151. package/src/providers/auth-provider.tsx +0 -40
  152. package/src/providers/command-palette-provider.tsx +0 -193
  153. package/src/providers/data-sources-provider.tsx +0 -27
  154. package/src/providers/devtools-provider.tsx +0 -72
  155. package/src/providers/navigation-items-provider.tsx +0 -38
  156. package/src/providers/registry-v2-provider.tsx +0 -93
  157. package/src/providers/settings-provider.tsx +0 -158
  158. package/src/router.tsx +0 -302
  159. package/src/routes/helpers.tsx +0 -25
  160. package/src/routes/plugin-page-v2.tsx +0 -52
  161. package/src/routes/types.ts +0 -18
  162. package/src/styles/antd-overrides.css +0 -211
  163. package/src/styles/base.css +0 -190
  164. package/src/styles/settings.css +0 -75
  165. package/src/styles/variables.css +0 -94
  166. package/src/utils/analytics.ts +0 -183
  167. package/src/utils/apply-navigation-categories.ts +0 -83
  168. package/src/utils/commands.ts +0 -252
  169. package/src/utils/export.ts +0 -174
  170. package/src/utils/format-date.ts +0 -166
  171. package/src/utils/logger.ts +0 -110
  172. package/tailwind.config.ts +0 -13
  173. package/tsconfig.json +0 -13
  174. package/vitest-setup.ts +0 -1
  175. /package/{public → dist}/favicon.svg +0 -0
@@ -1,153 +0,0 @@
1
- import { useState } from 'react';
2
- import { UITooltip, UIButton, UIIcon } from '@kb-labs/studio-ui-kit';
3
- import type { PluginManifestEntry } from '@kb-labs/studio-data-client';
4
-
5
- interface MarketplaceCardProps {
6
- plugin: PluginManifestEntry;
7
- onClick: () => void;
8
- }
9
-
10
- const SURFACE_CONFIG = [
11
- { key: 'cli', label: 'CLI', color: '#6366f1', bg: 'rgba(99,102,241,0.10)', getCount: (m: any) => m.cli?.commands?.length ?? 0 },
12
- { key: 'studio', label: 'Studio', color: '#0c66ff', bg: 'rgba(12,102,255,0.10)', getCount: (m: any) => m.studio?.pages?.length ?? 0 },
13
- { key: 'rest', label: 'REST', color: '#10b981', bg: 'rgba(16,185,129,0.10)', getCount: (m: any) => m.rest?.routes?.length ?? 0 },
14
- { key: 'workflows', label: 'Workflows',color: '#8b5cf6', bg: 'rgba(139,92,246,0.10)', getCount: (m: any) => m.workflows?.handlers?.length ?? 0 },
15
- { key: 'jobs', label: 'Jobs', color: '#f59e0b', bg: 'rgba(245,158,11,0.10)', getCount: (m: any) => m.jobs?.handlers?.length ?? 0 },
16
- ];
17
-
18
- export function MarketplaceCard({ plugin, onClick }: MarketplaceCardProps) {
19
- const [hovered, setHovered] = useState(false);
20
- const { manifest } = plugin;
21
- const display = manifest.display;
22
-
23
- const surfaces = SURFACE_CONFIG.filter(s => s.getCount(manifest) > 0);
24
- const hasPermWarning = !!manifest.permissions;
25
- const hasError = plugin.validation && !plugin.validation.valid;
26
-
27
- const name = display?.name || manifest.id;
28
- const iconLetter = name.charAt(0).toUpperCase();
29
- const iconBg = stringToColor(manifest.id);
30
-
31
- return (
32
- <div
33
- onClick={onClick}
34
- onMouseEnter={() => setHovered(true)}
35
- onMouseLeave={() => setHovered(false)}
36
- style={{
37
- background: 'var(--bg-secondary)',
38
- border: `1px solid ${hovered ? 'var(--border-secondary)' : 'var(--border-primary)'}`,
39
- borderRadius: 12,
40
- padding: '20px',
41
- cursor: 'pointer',
42
- transition: 'border-color 150ms ease, box-shadow 150ms ease, transform 150ms ease',
43
- boxShadow: hovered ? '0 4px 16px rgba(0,0,0,0.08)' : '0 1px 3px rgba(0,0,0,0.04)',
44
- transform: hovered ? 'translateY(-1px)' : 'none',
45
- display: 'flex',
46
- flexDirection: 'column',
47
- gap: 14,
48
- height: '100%',
49
- boxSizing: 'border-box',
50
- }}
51
- >
52
- {/* Top: icon + status badge */}
53
- <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between' }}>
54
- <div style={{
55
- width: 44, height: 44, borderRadius: 11, flexShrink: 0,
56
- background: iconBg,
57
- display: 'flex', alignItems: 'center', justifyContent: 'center',
58
- fontSize: 18, fontWeight: 700, color: '#fff',
59
- fontFamily: 'var(--font-heading)',
60
- }}>
61
- {iconLetter}
62
- </div>
63
-
64
- {hasError ? (
65
- <StatusBadge color="#ff4d4f" bg="rgba(255,77,79,0.10)">Invalid</StatusBadge>
66
- ) : (
67
- <StatusBadge color="#52c41a" bg="rgba(82,196,26,0.10)">Installed</StatusBadge>
68
- )}
69
- </div>
70
-
71
- {/* Name + version */}
72
- <div>
73
- <div style={{
74
- fontSize: 15, fontWeight: 600, color: 'var(--text-primary)',
75
- lineHeight: 1.3, marginBottom: 3,
76
- fontFamily: 'var(--font-heading)',
77
- }}>
78
- {name}
79
- </div>
80
- <div style={{ fontSize: 12, color: 'var(--text-tertiary)' }}>
81
- v{manifest.version}
82
- </div>
83
- </div>
84
-
85
- {/* Description */}
86
- <div style={{
87
- fontSize: 13, color: 'var(--text-secondary)', lineHeight: 1.55,
88
- display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical',
89
- overflow: 'hidden', flex: 1,
90
- }}>
91
- {display?.description || 'No description'}
92
- </div>
93
-
94
- {/* Footer: surfaces + warning */}
95
- <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }}>
96
- <div style={{ display: 'flex', gap: 5, flexWrap: 'wrap' }}>
97
- {surfaces.map(s => (
98
- <UITooltip key={s.key} title={`${s.getCount(manifest)} ${s.label}`}>
99
- <span style={{
100
- fontSize: 11, fontWeight: 500, padding: '3px 8px',
101
- borderRadius: 20, color: s.color, background: s.bg,
102
- }}>
103
- {s.label}
104
- </span>
105
- </UITooltip>
106
- ))}
107
- </div>
108
-
109
- <div style={{ display: 'flex', alignItems: 'center', gap: 6, flexShrink: 0 }}>
110
- {hasPermWarning && (
111
- <UITooltip title="Requires permissions">
112
- <UIIcon name="WarningOutlined" style={{ fontSize: 13, color: 'var(--warning)' }} />
113
- </UITooltip>
114
- )}
115
- {hovered && (
116
- <UIButton
117
- size="small"
118
- style={{ fontSize: 12, height: 26, padding: '0 10px' }}
119
- onClick={e => { e.stopPropagation(); onClick(); }}
120
- >
121
- Open
122
- </UIButton>
123
- )}
124
- </div>
125
- </div>
126
- </div>
127
- );
128
- }
129
-
130
- function StatusBadge({ color, bg, children }: { color: string; bg: string; children: string }) {
131
- return (
132
- <span style={{
133
- fontSize: 11, fontWeight: 600, padding: '3px 9px',
134
- borderRadius: 20, color, background: bg,
135
- letterSpacing: '0.01em',
136
- }}>
137
- {children}
138
- </span>
139
- );
140
- }
141
-
142
- function stringToColor(str: string): string {
143
- const colors = [
144
- '#6366f1', '#0c66ff', '#10b981', '#8b5cf6',
145
- '#f59e0b', '#ef4444', '#06b6d4', '#ec4899',
146
- '#84cc16', '#f97316',
147
- ];
148
- let hash = 0;
149
- for (let i = 0; i < str.length; i++) {
150
- hash = str.charCodeAt(i) + ((hash << 5) - hash);
151
- }
152
- return colors[Math.abs(hash) % colors.length]!;
153
- }
@@ -1,374 +0,0 @@
1
- /**
2
- * AI Assistant Modal for Plugin Inspector
3
- *
4
- * Allows users to ask questions about a plugin and get AI-generated answers
5
- * based on the plugin's manifest.
6
- */
7
-
8
- import React, { useState } from 'react';
9
- import {
10
- UIModal,
11
- UIInputTextArea,
12
- UIButton,
13
- UISpace,
14
- UITypographyText,
15
- UICard,
16
- UISpin,
17
- UIAlert,
18
- UITag,
19
- UIDivider,
20
- UIRow,
21
- UICol,
22
- UIIcon,
23
- } from '@kb-labs/studio-ui-kit';
24
- import type { PluginAskResponse } from '@kb-labs/studio-data-client';
25
- import { UIMarkdownViewer } from '@kb-labs/studio-ui-kit';
26
-
27
- interface PluginAIAssistantModalProps {
28
- open: boolean;
29
- onClose: () => void;
30
- pluginId: string;
31
- pluginName: string;
32
- onAsk: (question: string) => Promise<PluginAskResponse>;
33
- }
34
-
35
- interface QAItem {
36
- question: string;
37
- answer: string;
38
- timestamp: Date;
39
- usage: {
40
- promptTokens: number;
41
- completionTokens: number;
42
- };
43
- }
44
-
45
- const QUESTION_TEMPLATES = [
46
- { label: 'What permissions?', value: 'What permissions does this plugin need and why?' },
47
- { label: 'Show CLI commands', value: 'What CLI commands does this plugin provide? List them with their flags and usage.' },
48
- { label: 'Show REST APIs', value: 'What REST API endpoints does this plugin expose? Describe their paths, methods, and purpose.' },
49
- { label: 'What does it do?', value: 'What does this plugin do? Explain its main features and use cases.' },
50
- { label: 'How to configure?', value: 'How do I configure this plugin? What options are available?' },
51
- { label: 'What files created?', value: 'What files or directories does this plugin create or modify?' },
52
- ];
53
-
54
- export function PluginAIAssistantModal({
55
- open,
56
- onClose,
57
- pluginId,
58
- pluginName,
59
- onAsk,
60
- }: PluginAIAssistantModalProps) {
61
- const [customQuestion, setCustomQuestion] = useState('');
62
- const [history, setHistory] = useState<QAItem[]>([]);
63
- const [loading, setLoading] = useState(false);
64
- const [error, setError] = useState<string | null>(null);
65
-
66
- const handleAsk = async (question: string) => {
67
- if (!question.trim()) {return;}
68
-
69
- setLoading(true);
70
- setError(null);
71
-
72
- try {
73
- const response = await onAsk(question);
74
-
75
- setHistory((prev) => [
76
- {
77
- question,
78
- answer: response.answer,
79
- timestamp: new Date(),
80
- usage: response.usage,
81
- },
82
- ...prev,
83
- ]);
84
- setCustomQuestion('');
85
- } catch (err) {
86
- setError(err instanceof Error ? err.message : 'Failed to get AI response');
87
- } finally {
88
- setLoading(false);
89
- }
90
- };
91
-
92
- const handleTemplateClick = (question: string) => {
93
- setCustomQuestion(question);
94
- };
95
-
96
- const handleSubmit = () => {
97
- handleAsk(customQuestion);
98
- };
99
-
100
- return (
101
- <UIModal
102
- title={
103
- <UISpace>
104
- <UIIcon name="RobotOutlined" />
105
- <span>AI Assistant</span>
106
- </UISpace>
107
- }
108
- open={open}
109
- onCancel={onClose}
110
- width={800}
111
- footer={[
112
- <UIButton key="cancel" onClick={onClose}>
113
- Close
114
- </UIButton>,
115
- <UIButton
116
- key="ask"
117
- variant="primary"
118
- icon={<UIIcon name="ThunderboltOutlined" />}
119
- loading={loading}
120
- onClick={handleSubmit}
121
- disabled={!customQuestion.trim()}
122
- >
123
- Ask Question
124
- </UIButton>,
125
- ]}
126
- >
127
- <UISpace direction="vertical" style={{ width: '100%' }} size="large">
128
- {/* Plugin Preview */}
129
- <UICard size="small" style={{ backgroundColor: '#fafafa' }}>
130
- <UIRow gutter={16}>
131
- <UICol span={12}>
132
- <UITypographyText type="secondary">Plugin:</UITypographyText>
133
- <div>
134
- <UITypographyText strong>{pluginName}</UITypographyText>
135
- </div>
136
- </UICol>
137
- <UICol span={12}>
138
- <UITypographyText type="secondary">Plugin ID:</UITypographyText>
139
- <div>
140
- <UITypographyText code style={{ fontSize: 12 }}>{pluginId}</UITypographyText>
141
- </div>
142
- </UICol>
143
- </UIRow>
144
- </UICard>
145
-
146
- {/* Quick Templates */}
147
- <div>
148
- <UITypographyText strong>Quick Questions:</UITypographyText>
149
- <div style={{ marginTop: 8 }}>
150
- <UISpace wrap>
151
- {QUESTION_TEMPLATES.map((template) => (
152
- <UIButton
153
- key={template.label}
154
- size="small"
155
- onClick={() => handleTemplateClick(template.value)}
156
- >
157
- {template.label}
158
- </UIButton>
159
- ))}
160
- </UISpace>
161
- </div>
162
- </div>
163
-
164
- <UIDivider style={{ margin: '8px 0' }} />
165
-
166
- {/* Custom Question */}
167
- <div>
168
- <UITypographyText strong>Your Question:</UITypographyText>
169
- <UIInputTextArea
170
- value={customQuestion}
171
- onChange={(e) => setCustomQuestion(e.target.value)}
172
- placeholder="Ask anything about this plugin... (e.g., 'How do I use this plugin?')"
173
- rows={3}
174
- style={{ marginTop: 8 }}
175
- onPressEnter={(e) => {
176
- if (e.ctrlKey || e.metaKey) {
177
- handleSubmit();
178
- }
179
- }}
180
- />
181
- <UITypographyText type="secondary" style={{ fontSize: 12, marginTop: 4, display: 'block' }}>
182
- Press Ctrl/Cmd + Enter to ask
183
- </UITypographyText>
184
- </div>
185
-
186
- {/* Error Display */}
187
- {error && (
188
- <UIAlert
189
- message="Error"
190
- description={error}
191
- variant="error"
192
- closable
193
- onClose={() => setError(null)}
194
- showIcon
195
- />
196
- )}
197
-
198
- {/* Loading State */}
199
- {loading && (
200
- <div style={{ textAlign: 'center', padding: '24px 0' }}>
201
- <UISpin tip="AI is thinking..." size="large" />
202
- </div>
203
- )}
204
-
205
- {/* Q&A History */}
206
- {history.length > 0 && !loading && (
207
- <div>
208
- <UIDivider orientation="left" style={{ margin: '16px 0 8px 0' }}>
209
- <UITypographyText strong>Conversation History</UITypographyText>
210
- </UIDivider>
211
- <UISpace direction="vertical" style={{ width: '100%' }} size="middle">
212
- {history.map((item, index) => (
213
- <UICard
214
- key={index}
215
- size="small"
216
- style={{
217
- backgroundColor: '#fafafa',
218
- }}
219
- >
220
- {/* Question */}
221
- <div style={{ marginBottom: 12 }}>
222
- <UISpace style={{ marginBottom: 4 }}>
223
- <UIIcon name="QuestionCircleOutlined" style={{ color: '#1890ff' }} />
224
- <UITypographyText strong>{item.question}</UITypographyText>
225
- </UISpace>
226
- </div>
227
-
228
- {/* Answer */}
229
- <div
230
- style={{
231
- background: '#fff',
232
- padding: 12,
233
- borderRadius: 4,
234
- border: '1px solid #e8e8e8',
235
- marginBottom: 8,
236
- }}
237
- >
238
- <UIMarkdownViewer content={item.answer} className="plugin-assistant-markdown" />
239
- </div>
240
-
241
- {/* Metadata */}
242
- <div style={{ textAlign: 'right' }}>
243
- <UISpace size="small">
244
- <UITag icon={<UIIcon name="ClockCircleOutlined" />} color="blue">
245
- {item.timestamp.toLocaleTimeString()}
246
- </UITag>
247
- <UITag color="green">
248
- {item.usage.promptTokens + item.usage.completionTokens} tokens
249
- </UITag>
250
- </UISpace>
251
- </div>
252
- </UICard>
253
- ))}
254
- </UISpace>
255
- </div>
256
- )}
257
-
258
- {/* Empty State */}
259
- {history.length === 0 && !loading && (
260
- <div
261
- style={{
262
- textAlign: 'center',
263
- padding: 40,
264
- backgroundColor: '#fafafa',
265
- borderRadius: 4,
266
- border: '1px dashed #d9d9d9',
267
- }}
268
- >
269
- <UIIcon name="RobotOutlined" style={{ fontSize: 48, color: '#d9d9d9', marginBottom: 16 }} />
270
- <div style={{ fontSize: 14, color: '#999' }}>
271
- Select a quick question or type your own to get started
272
- </div>
273
- </div>
274
- )}
275
- </UISpace>
276
-
277
- {/* Custom styles for markdown in modal context */}
278
- <style>{`
279
- .plugin-assistant-markdown {
280
- padding: 0;
281
- background: transparent;
282
- border-radius: 0;
283
- }
284
- .plugin-assistant-markdown p {
285
- margin: 0 0 8px 0;
286
- }
287
- .plugin-assistant-markdown p:last-child {
288
- margin-bottom: 0;
289
- }
290
- .plugin-assistant-markdown h1,
291
- .plugin-assistant-markdown h2,
292
- .plugin-assistant-markdown h3,
293
- .plugin-assistant-markdown h4 {
294
- margin-top: 12px;
295
- margin-bottom: 8px;
296
- font-size: 1em;
297
- font-weight: 600;
298
- border: none;
299
- padding: 0;
300
- }
301
- .plugin-assistant-markdown h1 {
302
- font-size: 1.15em;
303
- }
304
- .plugin-assistant-markdown h2 {
305
- font-size: 1.1em;
306
- }
307
- .plugin-assistant-markdown h3 {
308
- font-size: 1.05em;
309
- }
310
- .plugin-assistant-markdown ul,
311
- .plugin-assistant-markdown ol {
312
- margin: 8px 0;
313
- padding-left: 20px;
314
- }
315
- .plugin-assistant-markdown li {
316
- margin: 4px 0;
317
- }
318
- .plugin-assistant-markdown code {
319
- background: rgba(0, 0, 0, 0.06);
320
- padding: 2px 6px;
321
- border-radius: 4px;
322
- font-size: 0.9em;
323
- font-family: 'SF Mono', Menlo, Monaco, Consolas, monospace;
324
- }
325
- .plugin-assistant-markdown pre {
326
- background: #f5f5f5;
327
- padding: 12px 16px;
328
- border-radius: 6px;
329
- margin: 12px 0;
330
- overflow-x: auto;
331
- }
332
- .plugin-assistant-markdown pre code {
333
- background: none;
334
- padding: 0;
335
- font-size: 0.85em;
336
- }
337
- .plugin-assistant-markdown table {
338
- margin: 12px 0;
339
- font-size: 0.9em;
340
- width: 100%;
341
- border-collapse: collapse;
342
- }
343
- .plugin-assistant-markdown th,
344
- .plugin-assistant-markdown td {
345
- padding: 8px 12px;
346
- border: 1px solid #e8e8e8;
347
- text-align: left;
348
- }
349
- .plugin-assistant-markdown th {
350
- background: #fafafa;
351
- font-weight: 600;
352
- }
353
- .plugin-assistant-markdown blockquote {
354
- margin: 12px 0;
355
- padding: 8px 16px;
356
- border-left: 4px solid #1890ff;
357
- background: #f6f8fa;
358
- border-radius: 0 4px 4px 0;
359
- }
360
- .plugin-assistant-markdown strong {
361
- font-weight: 600;
362
- }
363
- .plugin-assistant-markdown a {
364
- color: #1890ff;
365
- }
366
- .plugin-assistant-markdown hr {
367
- margin: 16px 0;
368
- border: none;
369
- border-top: 1px solid #e8e8e8;
370
- }
371
- `}</style>
372
- </UIModal>
373
- );
374
- }
@@ -1,136 +0,0 @@
1
- import {
2
- UICard,
3
- UITag,
4
- UISpace,
5
- UITypographyText,
6
- UITypographyParagraph,
7
- UITooltip,
8
- UIIcon,
9
- } from '@kb-labs/studio-ui-kit';
10
- import type { PluginManifestEntry } from '@kb-labs/studio-data-client';
11
-
12
- interface PluginCardProps {
13
- plugin: PluginManifestEntry;
14
- onClick: () => void;
15
- }
16
-
17
- export function PluginCard({ plugin, onClick }: PluginCardProps) {
18
- const { manifest } = plugin;
19
- const display = manifest.display;
20
-
21
- const cliCount = manifest.cli?.commands.length ?? 0;
22
- const restCount = manifest.rest?.routes.length ?? 0;
23
- const workflowCount = manifest.workflows?.handlers.length ?? 0;
24
- const jobCount = manifest.jobs?.handlers.length ?? 0;
25
-
26
- const hasPermissions = !!manifest.permissions;
27
- const requiresPlatform = manifest.platform?.requires && manifest.platform.requires.length > 0;
28
- const hasValidationErrors = plugin.validation && !plugin.validation.valid;
29
-
30
- return (
31
- <UICard
32
- hoverable
33
- onClick={onClick}
34
- style={{ height: '100%', cursor: 'pointer' }}
35
- styles={{ body: { display: 'flex', flexDirection: 'column', height: '100%' } }}
36
- >
37
- <UISpace direction="vertical" size="small" style={{ width: '100%', flex: 1 }}>
38
- {/* Header: Icon + Name */}
39
- <UISpace align="center" style={{ width: '100%' }}>
40
- <span style={{ fontSize: 18, lineHeight: 1, flexShrink: 0, opacity: display?.icon ? 1 : 0.4 }}>
41
- {display?.icon || <UIIcon name="AppstoreOutlined" />}
42
- </span>
43
- <div style={{ flex: 1, minWidth: 0 }}>
44
- <UITypographyText strong style={{ fontSize: 14 }}>
45
- {display?.name || manifest.id}
46
- </UITypographyText>
47
- <br />
48
- <UITypographyText type="secondary" style={{ fontSize: 12 }}>
49
- v{manifest.version}
50
- </UITypographyText>
51
- </div>
52
- </UISpace>
53
-
54
- {/* Description */}
55
- {display?.description && (
56
- <UITypographyParagraph
57
- type="secondary"
58
- style={{
59
- fontSize: 13,
60
- marginBottom: 8,
61
- lineHeight: 1.4,
62
- }}
63
- ellipsis={{ rows: 2, tooltip: display.description }}
64
- >
65
- {display.description}
66
- </UITypographyParagraph>
67
- )}
68
-
69
- {/* Tags */}
70
- {display?.tags && display.tags.length > 0 && (
71
- <div style={{ marginBottom: 8 }}>
72
- {display.tags.slice(0, 3).map((tag) => (
73
- <UITag key={tag} style={{ fontSize: 11, marginBottom: 4 }}>
74
- {tag}
75
- </UITag>
76
- ))}
77
- {display.tags.length > 3 && (
78
- <UITag style={{ fontSize: 11 }}>+{display.tags.length - 3}</UITag>
79
- )}
80
- </div>
81
- )}
82
-
83
- {/* Capabilities */}
84
- <UISpace wrap size={4}>
85
- {cliCount > 0 && (
86
- <UITooltip title={`${cliCount} CLI command${cliCount > 1 ? 's' : ''}`}>
87
- <UITag icon={<UIIcon name="CodeOutlined" />} color="blue">
88
- {cliCount}
89
- </UITag>
90
- </UITooltip>
91
- )}
92
- {restCount > 0 && (
93
- <UITooltip title={`${restCount} REST route${restCount > 1 ? 's' : ''}`}>
94
- <UITag icon={<UIIcon name="ApiOutlined" />} color="green">
95
- {restCount}
96
- </UITag>
97
- </UITooltip>
98
- )}
99
- {workflowCount > 0 && (
100
- <UITooltip title={`${workflowCount} workflow${workflowCount > 1 ? 's' : ''}`}>
101
- <UITag icon={<UIIcon name="NodeIndexOutlined" />} color="purple">
102
- {workflowCount}
103
- </UITag>
104
- </UITooltip>
105
- )}
106
- {jobCount > 0 && (
107
- <UITooltip title={`${jobCount} scheduled job${jobCount > 1 ? 's' : ''}`}>
108
- <UITag icon={<UIIcon name="ClockCircleOutlined" />} color="orange">
109
- {jobCount}
110
- </UITag>
111
- </UITooltip>
112
- )}
113
- </UISpace>
114
-
115
- {/* Indicators */}
116
- <UISpace wrap size={4} style={{ marginTop: 'auto' }}>
117
- {hasValidationErrors && (
118
- <UITooltip title={`${plugin.validation!.errors.length} validation error${plugin.validation!.errors.length > 1 ? 's' : ''}`}>
119
- <UITag icon={<UIIcon name="CloseCircleOutlined" />} color="red" style={{ fontSize: 11 }}>Invalid</UITag>
120
- </UITooltip>
121
- )}
122
- {hasPermissions && (
123
- <UITooltip title="Requires permissions">
124
- <UITag icon={<UIIcon name="WarningOutlined" />} color="gold" style={{ fontSize: 11 }}>Permissions</UITag>
125
- </UITooltip>
126
- )}
127
- {requiresPlatform && (
128
- <UITooltip title={`Requires: ${manifest.platform!.requires!.join(', ')}`}>
129
- <UITag icon={<UIIcon name="CheckCircleOutlined" />} color="cyan" style={{ fontSize: 11 }}>Platform</UITag>
130
- </UITooltip>
131
- )}
132
- </UISpace>
133
- </UISpace>
134
- </UICard>
135
- );
136
- }