@hesed/webui 0.2.0 → 0.2.2

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 (161) hide show
  1. package/README.md +2 -2
  2. package/dist/lib/server.js +4 -2
  3. package/dist/web/BUILD_ID +1 -0
  4. package/dist/web/app-path-routes-manifest.json +5 -0
  5. package/dist/web/build-manifest.json +20 -0
  6. package/dist/web/cache/.previewinfo +1 -0
  7. package/dist/web/cache/.rscinfo +1 -0
  8. package/dist/web/cache/.tsbuildinfo +1 -0
  9. package/dist/web/cache/config.json +7 -0
  10. package/dist/web/diagnostics/build-diagnostics.json +6 -0
  11. package/dist/web/diagnostics/framework.json +1 -0
  12. package/dist/web/diagnostics/route-bundle-stats.json +27 -0
  13. package/dist/web/export-marker.json +6 -0
  14. package/dist/web/fallback-build-manifest.json +13 -0
  15. package/dist/web/images-manifest.json +68 -0
  16. package/dist/web/next-minimal-server.js.nft.json +1 -0
  17. package/dist/web/next-server.js.nft.json +1 -0
  18. package/dist/web/package.json +1 -0
  19. package/dist/web/prerender-manifest.json +85 -0
  20. package/dist/web/required-server-files.js +333 -0
  21. package/dist/web/required-server-files.json +333 -0
  22. package/dist/web/routes-manifest.json +63 -0
  23. package/dist/web/server/app/_global-error/page/app-paths-manifest.json +3 -0
  24. package/dist/web/server/app/_global-error/page/build-manifest.json +16 -0
  25. package/dist/web/server/app/_global-error/page/next-font-manifest.json +6 -0
  26. package/dist/web/server/app/_global-error/page/react-loadable-manifest.json +1 -0
  27. package/dist/web/server/app/_global-error/page/server-reference-manifest.json +4 -0
  28. package/dist/web/server/app/_global-error/page.js +9 -0
  29. package/dist/web/server/app/_global-error/page.js.map +5 -0
  30. package/dist/web/server/app/_global-error/page.js.nft.json +1 -0
  31. package/dist/web/server/app/_global-error/page_client-reference-manifest.js +3 -0
  32. package/dist/web/server/app/_global-error.html +1 -0
  33. package/dist/web/server/app/_global-error.meta +15 -0
  34. package/dist/web/server/app/_global-error.rsc +14 -0
  35. package/dist/web/server/app/_global-error.segments/__PAGE__.segment.rsc +5 -0
  36. package/dist/web/server/app/_global-error.segments/_full.segment.rsc +14 -0
  37. package/dist/web/server/app/_global-error.segments/_head.segment.rsc +5 -0
  38. package/dist/web/server/app/_global-error.segments/_index.segment.rsc +5 -0
  39. package/dist/web/server/app/_global-error.segments/_tree.segment.rsc +1 -0
  40. package/dist/web/server/app/_not-found/page/app-paths-manifest.json +3 -0
  41. package/dist/web/server/app/_not-found/page/build-manifest.json +16 -0
  42. package/dist/web/server/app/_not-found/page/next-font-manifest.json +6 -0
  43. package/dist/web/server/app/_not-found/page/react-loadable-manifest.json +1 -0
  44. package/dist/web/server/app/_not-found/page/server-reference-manifest.json +4 -0
  45. package/dist/web/server/app/_not-found/page.js +12 -0
  46. package/dist/web/server/app/_not-found/page.js.map +5 -0
  47. package/dist/web/server/app/_not-found/page.js.nft.json +1 -0
  48. package/dist/web/server/app/_not-found/page_client-reference-manifest.js +3 -0
  49. package/dist/web/server/app/_not-found.html +1 -0
  50. package/dist/web/server/app/_not-found.meta +16 -0
  51. package/dist/web/server/app/_not-found.rsc +16 -0
  52. package/dist/web/server/app/_not-found.segments/_full.segment.rsc +16 -0
  53. package/dist/web/server/app/_not-found.segments/_head.segment.rsc +5 -0
  54. package/dist/web/server/app/_not-found.segments/_index.segment.rsc +6 -0
  55. package/dist/web/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +5 -0
  56. package/dist/web/server/app/_not-found.segments/_not-found.segment.rsc +5 -0
  57. package/dist/web/server/app/_not-found.segments/_tree.segment.rsc +2 -0
  58. package/dist/web/server/app/index.html +1 -0
  59. package/dist/web/server/app/index.meta +14 -0
  60. package/dist/web/server/app/index.rsc +18 -0
  61. package/dist/web/server/app/index.segments/__PAGE__.segment.rsc +9 -0
  62. package/dist/web/server/app/index.segments/_full.segment.rsc +18 -0
  63. package/dist/web/server/app/index.segments/_head.segment.rsc +5 -0
  64. package/dist/web/server/app/index.segments/_index.segment.rsc +6 -0
  65. package/dist/web/server/app/index.segments/_tree.segment.rsc +2 -0
  66. package/dist/web/server/app/page/app-paths-manifest.json +3 -0
  67. package/dist/web/server/app/page/build-manifest.json +16 -0
  68. package/dist/web/server/app/page/next-font-manifest.json +6 -0
  69. package/dist/web/server/app/page/react-loadable-manifest.json +1 -0
  70. package/dist/web/server/app/page/server-reference-manifest.json +4 -0
  71. package/dist/web/server/app/page.js +13 -0
  72. package/dist/web/server/app/page.js.map +5 -0
  73. package/dist/web/server/app/page.js.nft.json +1 -0
  74. package/dist/web/server/app/page_client-reference-manifest.js +3 -0
  75. package/dist/web/server/app-paths-manifest.json +5 -0
  76. package/dist/web/server/chunks/ssr/[root-of-the-server]__0100oqz._.js +19 -0
  77. package/dist/web/server/chunks/ssr/[root-of-the-server]__0100oqz._.js.map +1 -0
  78. package/dist/web/server/chunks/ssr/[root-of-the-server]__03bqxv9._.js +33 -0
  79. package/dist/web/server/chunks/ssr/[root-of-the-server]__03bqxv9._.js.map +1 -0
  80. package/dist/web/server/chunks/ssr/[root-of-the-server]__10hrvcf._.js +3 -0
  81. package/dist/web/server/chunks/ssr/[root-of-the-server]__10hrvcf._.js.map +1 -0
  82. package/dist/web/server/chunks/ssr/[root-of-the-server]__10riywf._.js +3 -0
  83. package/dist/web/server/chunks/ssr/[root-of-the-server]__10riywf._.js.map +1 -0
  84. package/dist/web/server/chunks/ssr/[root-of-the-server]__17sw5v1._.js +3 -0
  85. package/dist/web/server/chunks/ssr/[root-of-the-server]__17sw5v1._.js.map +1 -0
  86. package/dist/web/server/chunks/ssr/[root-of-the-server]__1my83lt._.js +33 -0
  87. package/dist/web/server/chunks/ssr/[root-of-the-server]__1my83lt._.js.map +1 -0
  88. package/dist/web/server/chunks/ssr/[root-of-the-server]__1ujipwi._.js +3 -0
  89. package/dist/web/server/chunks/ssr/[root-of-the-server]__1ujipwi._.js.map +1 -0
  90. package/dist/web/server/chunks/ssr/[turbopack]_runtime.js +903 -0
  91. package/dist/web/server/chunks/ssr/[turbopack]_runtime.js.map +11 -0
  92. package/dist/web/server/chunks/ssr/node_modules_0h91jdk._.js +33 -0
  93. package/dist/web/server/chunks/ssr/node_modules_0h91jdk._.js.map +1 -0
  94. package/dist/web/server/chunks/ssr/node_modules_next_dist_1vgd_ru._.js +6 -0
  95. package/dist/web/server/chunks/ssr/node_modules_next_dist_1vgd_ru._.js.map +1 -0
  96. package/dist/web/server/chunks/ssr/node_modules_next_dist_client_components_0wpq8j3._.js +3 -0
  97. package/dist/web/server/chunks/ssr/node_modules_next_dist_client_components_0wpq8j3._.js.map +1 -0
  98. package/dist/web/server/chunks/ssr/node_modules_next_dist_client_components_builtin_forbidden_0symwr9.js +3 -0
  99. package/dist/web/server/chunks/ssr/node_modules_next_dist_client_components_builtin_forbidden_0symwr9.js.map +1 -0
  100. package/dist/web/server/chunks/ssr/node_modules_next_dist_client_components_builtin_global-error_0-o-goa.js +3 -0
  101. package/dist/web/server/chunks/ssr/node_modules_next_dist_client_components_builtin_global-error_0-o-goa.js.map +1 -0
  102. package/dist/web/server/chunks/ssr/node_modules_next_dist_client_components_builtin_unauthorized_0l_sp0x.js +3 -0
  103. package/dist/web/server/chunks/ssr/node_modules_next_dist_client_components_builtin_unauthorized_0l_sp0x.js.map +1 -0
  104. package/dist/web/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_13nn6g7.js +4 -0
  105. package/dist/web/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_13nn6g7.js.map +1 -0
  106. package/dist/web/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_19--w_z.js +4 -0
  107. package/dist/web/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_19--w_z.js.map +1 -0
  108. package/dist/web/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_1o7-715.js +4 -0
  109. package/dist/web/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_1o7-715.js.map +1 -0
  110. package/dist/web/server/chunks/ssr/web_0iag39l._.js +3 -0
  111. package/dist/web/server/chunks/ssr/web_0iag39l._.js.map +1 -0
  112. package/dist/web/server/chunks/ssr/web__next-internal_server_app__global-error_page_actions_0crg1np.js +3 -0
  113. package/dist/web/server/chunks/ssr/web__next-internal_server_app__global-error_page_actions_0crg1np.js.map +1 -0
  114. package/dist/web/server/chunks/ssr/web__next-internal_server_app__not-found_page_actions_19z2-pv.js +3 -0
  115. package/dist/web/server/chunks/ssr/web__next-internal_server_app__not-found_page_actions_19z2-pv.js.map +1 -0
  116. package/dist/web/server/chunks/ssr/web__next-internal_server_app_page_actions_1xcff7h.js +3 -0
  117. package/dist/web/server/chunks/ssr/web__next-internal_server_app_page_actions_1xcff7h.js.map +1 -0
  118. package/dist/web/server/chunks/ssr/web_app_page_tsx_1-p0-hs._.js +3 -0
  119. package/dist/web/server/chunks/ssr/web_app_page_tsx_1-p0-hs._.js.map +1 -0
  120. package/dist/web/server/functions-config-manifest.json +4 -0
  121. package/dist/web/server/interception-route-rewrite-manifest.js +1 -0
  122. package/dist/web/server/middleware-build-manifest.js +20 -0
  123. package/dist/web/server/middleware-manifest.json +6 -0
  124. package/dist/web/server/next-font-manifest.js +1 -0
  125. package/dist/web/server/next-font-manifest.json +6 -0
  126. package/dist/web/server/pages/404.html +1 -0
  127. package/dist/web/server/pages/500.html +1 -0
  128. package/dist/web/server/pages-manifest.json +4 -0
  129. package/dist/web/server/prefetch-hints.json +1 -0
  130. package/dist/web/server/server-reference-manifest.js +1 -0
  131. package/dist/web/server/server-reference-manifest.json +5 -0
  132. package/dist/web/static/PDMigBNKG7RenqXyfgiNr/_buildManifest.js +11 -0
  133. package/dist/web/static/PDMigBNKG7RenqXyfgiNr/_clientMiddlewareManifest.js +1 -0
  134. package/dist/web/static/PDMigBNKG7RenqXyfgiNr/_ssgManifest.js +1 -0
  135. package/dist/web/static/chunks/0atut6a2uuyid.js +5 -0
  136. package/dist/web/static/chunks/0cz1d0mv5g_q7.js +1 -0
  137. package/dist/web/static/chunks/158myu8e_yme3.js +1 -0
  138. package/dist/web/static/chunks/1_v5h-yjbgzno.js +1 -0
  139. package/dist/web/static/chunks/1bnss_1e9svpl.css +1 -0
  140. package/dist/web/static/chunks/1jq4o6yq14o4c.js +31 -0
  141. package/dist/web/static/chunks/28o7f8wux_ygy.js +1 -0
  142. package/dist/web/static/chunks/2nykiepra7i1k.js +1 -0
  143. package/dist/web/static/chunks/turbopack-3i0d1wb0b07u8.js +1 -0
  144. package/dist/web/trace +1 -0
  145. package/dist/web/trace-build +1 -0
  146. package/dist/web/turbopack +0 -0
  147. package/dist/web/types/cache-life.d.ts +145 -0
  148. package/dist/web/types/routes.d.ts +57 -0
  149. package/dist/web/types/validator.ts +61 -0
  150. package/oclif.manifest.json +1 -1
  151. package/package.json +5 -10
  152. package/web/next.config.mjs +11 -6
  153. package/web/app/globals.css +0 -381
  154. package/web/app/layout.tsx +0 -20
  155. package/web/app/page.tsx +0 -57
  156. package/web/components/command-detail.tsx +0 -159
  157. package/web/components/command-list.tsx +0 -105
  158. package/web/components/theme-provider.tsx +0 -12
  159. package/web/components/theme-toggle.tsx +0 -62
  160. package/web/lib/types.ts +0 -77
  161. package/web/tsconfig.json +0 -23
@@ -1,381 +0,0 @@
1
- /* Light mode (default) */
2
- :root {
3
- --bg: #ffffff;
4
- --panel: #f6f8fa;
5
- --panel-2: #eaeef2;
6
- --border: #d0d7de;
7
- --text: #1f2328;
8
- --muted: #57606a;
9
- --accent: #0969da;
10
- --accent-hover: #0550ae;
11
- --green: #1a7f37;
12
- --red: #d1242f;
13
- --output-bg: #f6f8fa;
14
- --mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
15
- }
16
-
17
- /* Dark mode */
18
- .dark {
19
- --bg: #0d1117;
20
- --panel: #161b22;
21
- --panel-2: #1c2128;
22
- --border: #30363d;
23
- --text: #e6edf3;
24
- --muted: #8b949e;
25
- --accent: #2f81f7;
26
- --accent-hover: #4a90ff;
27
- --green: #3fb950;
28
- --red: #f85149;
29
- --output-bg: #010409;
30
- }
31
-
32
- * {
33
- box-sizing: border-box;
34
- }
35
-
36
- html,
37
- body {
38
- margin: 0;
39
- padding: 0;
40
- height: 100%;
41
- background: var(--bg);
42
- color: var(--text);
43
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
44
- font-size: 14px;
45
- }
46
-
47
- .app {
48
- display: grid;
49
- grid-template-columns: 320px 1fr;
50
- height: 100vh;
51
- }
52
-
53
- .sidebar {
54
- border-right: 1px solid var(--border);
55
- background: var(--panel);
56
- display: flex;
57
- flex-direction: column;
58
- min-height: 0;
59
- }
60
-
61
- .sidebar-header {
62
- padding: 16px;
63
- border-bottom: 1px solid var(--border);
64
- }
65
-
66
- .brand-row {
67
- display: flex;
68
- align-items: baseline;
69
- justify-content: space-between;
70
- margin-bottom: 12px;
71
- }
72
-
73
- .brand {
74
- font-weight: 700;
75
- font-size: 16px;
76
- display: flex;
77
- align-items: baseline;
78
- gap: 8px;
79
- }
80
-
81
- .brand small {
82
- color: var(--muted);
83
- font-weight: 400;
84
- font-size: 12px;
85
- }
86
-
87
- .theme-toggle {
88
- display: flex;
89
- align-items: center;
90
- justify-content: center;
91
- width: 28px;
92
- height: 28px;
93
- border-radius: 6px;
94
- border: 1px solid var(--border);
95
- background: transparent;
96
- color: var(--muted);
97
- cursor: pointer;
98
- transition:
99
- color 0.15s,
100
- background 0.15s,
101
- border-color 0.15s;
102
- flex-shrink: 0;
103
- }
104
-
105
- .theme-toggle:hover {
106
- color: var(--text);
107
- background: var(--panel-2);
108
- border-color: var(--text);
109
- }
110
-
111
- .theme-toggle-placeholder {
112
- width: 28px;
113
- height: 28px;
114
- }
115
-
116
- .search {
117
- width: 100%;
118
- padding: 8px 10px;
119
- background: var(--bg);
120
- border: 1px solid var(--border);
121
- border-radius: 6px;
122
- color: var(--text);
123
- font-size: 13px;
124
- }
125
-
126
- .search:focus {
127
- outline: none;
128
- border-color: var(--accent);
129
- }
130
-
131
- .topic-filter {
132
- display: grid;
133
- grid-template-columns: auto 1fr;
134
- align-items: center;
135
- gap: 8px;
136
- margin-top: 10px;
137
- }
138
-
139
- .topic-filter label,
140
- .topic-heading {
141
- color: var(--muted);
142
- font-size: 11px;
143
- font-weight: 600;
144
- text-transform: uppercase;
145
- letter-spacing: 0.06em;
146
- }
147
-
148
- .topic-filter select {
149
- min-width: 0;
150
- padding: 7px 9px;
151
- background: var(--bg);
152
- border: 1px solid var(--border);
153
- border-radius: 6px;
154
- color: var(--text);
155
- font-size: 12px;
156
- }
157
-
158
- .topic-filter select:focus {
159
- outline: none;
160
- border-color: var(--accent);
161
- }
162
-
163
- .command-list {
164
- overflow-y: auto;
165
- flex: 1;
166
- padding: 8px;
167
- }
168
-
169
- .command-group + .command-group {
170
- margin-top: 10px;
171
- }
172
-
173
- .topic-heading {
174
- display: flex;
175
- justify-content: space-between;
176
- padding: 6px 10px 4px;
177
- }
178
-
179
- .command-item {
180
- width: 100%;
181
- text-align: left;
182
- background: transparent;
183
- border: none;
184
- color: var(--text);
185
- padding: 8px 10px;
186
- border-radius: 6px;
187
- cursor: pointer;
188
- display: block;
189
- font-size: 13px;
190
- }
191
-
192
- .command-item:hover {
193
- background: var(--panel-2);
194
- }
195
-
196
- .command-item.active {
197
- background: var(--accent);
198
- color: #fff;
199
- }
200
-
201
- .command-item .cmd-id {
202
- font-family: var(--mono);
203
- font-weight: 600;
204
- }
205
-
206
- .command-item .cmd-summary {
207
- display: block;
208
- color: var(--muted);
209
- font-size: 11px;
210
- margin-top: 2px;
211
- white-space: nowrap;
212
- overflow: hidden;
213
- text-overflow: ellipsis;
214
- }
215
-
216
- .command-item.active .cmd-summary {
217
- color: rgba(255, 255, 255, 0.8);
218
- }
219
-
220
- .main {
221
- overflow-y: auto;
222
- padding: 28px 32px;
223
- min-height: 0;
224
- }
225
-
226
- .empty {
227
- color: var(--muted);
228
- margin-top: 80px;
229
- text-align: center;
230
- }
231
-
232
- .detail h1 {
233
- font-family: var(--mono);
234
- font-size: 22px;
235
- margin: 0 0 6px;
236
- }
237
-
238
- .detail .desc {
239
- color: var(--muted);
240
- white-space: pre-wrap;
241
- margin-bottom: 20px;
242
- line-height: 1.5;
243
- }
244
-
245
- .section-title {
246
- text-transform: uppercase;
247
- letter-spacing: 0.06em;
248
- font-size: 11px;
249
- color: var(--muted);
250
- margin: 22px 0 10px;
251
- }
252
-
253
- .field {
254
- margin-bottom: 14px;
255
- }
256
-
257
- .field label {
258
- display: block;
259
- font-family: var(--mono);
260
- font-size: 13px;
261
- margin-bottom: 4px;
262
- }
263
-
264
- .field label .req {
265
- color: var(--red);
266
- margin-left: 4px;
267
- }
268
-
269
- .field .hint {
270
- color: var(--muted);
271
- font-size: 12px;
272
- margin: 2px 0 6px;
273
- }
274
-
275
- .field input[type='text'],
276
- .field select {
277
- width: 100%;
278
- padding: 7px 9px;
279
- background: var(--bg);
280
- border: 1px solid var(--border);
281
- border-radius: 6px;
282
- color: var(--text);
283
- font-family: var(--mono);
284
- font-size: 13px;
285
- }
286
-
287
- .field input:focus,
288
- .field select:focus {
289
- outline: none;
290
- border-color: var(--accent);
291
- }
292
-
293
- .checkbox-row {
294
- display: flex;
295
- align-items: center;
296
- gap: 8px;
297
- }
298
-
299
- .checkbox-row input {
300
- width: 16px;
301
- height: 16px;
302
- }
303
-
304
- .preview {
305
- background: var(--panel);
306
- border: 1px solid var(--border);
307
- border-radius: 6px;
308
- padding: 10px 12px;
309
- font-family: var(--mono);
310
- font-size: 13px;
311
- color: var(--green);
312
- margin-bottom: 16px;
313
- word-break: break-all;
314
- }
315
-
316
- .run-btn {
317
- background: var(--accent);
318
- color: #fff;
319
- border: none;
320
- padding: 10px 20px;
321
- border-radius: 6px;
322
- font-size: 14px;
323
- font-weight: 600;
324
- cursor: pointer;
325
- }
326
-
327
- .run-btn:hover {
328
- background: var(--accent-hover);
329
- }
330
-
331
- .run-btn:disabled {
332
- opacity: 0.6;
333
- cursor: not-allowed;
334
- }
335
-
336
- .output {
337
- margin-top: 20px;
338
- }
339
-
340
- .output pre {
341
- background: var(--output-bg);
342
- border: 1px solid var(--border);
343
- border-radius: 6px;
344
- padding: 14px;
345
- font-family: var(--mono);
346
- font-size: 12.5px;
347
- line-height: 1.5;
348
- white-space: pre-wrap;
349
- word-break: break-word;
350
- max-height: 50vh;
351
- overflow-y: auto;
352
- }
353
-
354
- .status {
355
- display: inline-flex;
356
- align-items: center;
357
- gap: 6px;
358
- font-size: 12px;
359
- font-weight: 600;
360
- margin-bottom: 8px;
361
- }
362
-
363
- .status.ok {
364
- color: var(--green);
365
- }
366
-
367
- .status.err {
368
- color: var(--red);
369
- }
370
-
371
- .badge {
372
- font-size: 10px;
373
- font-family: var(--mono);
374
- background: var(--panel-2);
375
- border: 1px solid var(--border);
376
- color: var(--muted);
377
- padding: 1px 6px;
378
- border-radius: 999px;
379
- margin-left: 8px;
380
- vertical-align: middle;
381
- }
@@ -1,20 +0,0 @@
1
- import type {Metadata} from 'next'
2
- import type {ReactNode} from 'react'
3
-
4
- import './globals.css'
5
- import {ThemeProvider} from '../components/theme-provider'
6
-
7
- export const metadata: Metadata = {
8
- description: 'Browse and run sdkck commands from your browser',
9
- title: 'sdkck web UI',
10
- }
11
-
12
- export default function RootLayout({children}: {children: ReactNode}) {
13
- return (
14
- <html lang="en" suppressHydrationWarning>
15
- <body>
16
- <ThemeProvider>{children}</ThemeProvider>
17
- </body>
18
- </html>
19
- )
20
- }
package/web/app/page.tsx DELETED
@@ -1,57 +0,0 @@
1
- 'use client'
2
-
3
- import {useEffect, useState} from 'react'
4
-
5
- import type {CommandsResponse} from '../lib/types'
6
-
7
- import {CommandDetail} from '../components/command-detail'
8
- import {CommandList} from '../components/command-list'
9
-
10
- export default function Page() {
11
- const [data, setData] = useState<CommandsResponse | null>(null)
12
- const [error, setError] = useState<null | string>(null)
13
- const [query, setQuery] = useState('')
14
- const [selectedId, setSelectedId] = useState<string>()
15
-
16
- useEffect(() => {
17
- fetch('/api/commands')
18
- .then((res) => res.json())
19
- .then((json: CommandsResponse) => setData(json))
20
- .catch((error_) => setError(String(error_)))
21
- }, [])
22
-
23
- if (error) {
24
- return <div className="empty">Failed to load commands: {error}</div>
25
- }
26
-
27
- if (!data) {
28
- return <div className="empty">Loading commands…</div>
29
- }
30
-
31
- const selected = data.commands.find((c) => c.id === selectedId)
32
-
33
- return (
34
- <div className="app">
35
- <CommandList
36
- bin={data.bin}
37
- commands={data.commands}
38
- onSelect={setSelectedId}
39
- query={query}
40
- selectedId={selectedId}
41
- setQuery={setQuery}
42
- version={data.version}
43
- />
44
- <main className="main">
45
- {selected ? (
46
- <CommandDetail bin={data.bin} command={selected} key={selected.id} />
47
- ) : (
48
- <div className="empty">
49
- Select a command from the left to view its options and run it.
50
- <br />
51
- {data.commands.length} commands available.
52
- </div>
53
- )}
54
- </main>
55
- </div>
56
- )
57
- }
@@ -1,159 +0,0 @@
1
- 'use client'
2
-
3
- import {useMemo, useState} from 'react'
4
-
5
- import {buildArgv, type CommandMeta, type RunResult} from '../lib/types'
6
-
7
- export function CommandDetail({bin, command}: {bin: string; command: CommandMeta}) {
8
- const [argValues, setArgValues] = useState<Record<string, string>>({})
9
- const [flagValues, setFlagValues] = useState<Record<string, boolean | string>>({})
10
- const [result, setResult] = useState<null | RunResult>(null)
11
- const [running, setRunning] = useState(false)
12
-
13
- const argv = useMemo(() => buildArgv(command, argValues, flagValues), [command, argValues, flagValues])
14
- const preview = `${bin || 'sdkck'} ${command.id}${argv.length > 0 ? ' ' + argv.join(' ') : ''}`
15
-
16
- async function run() {
17
- setRunning(true)
18
- setResult(null)
19
- try {
20
- const res = await fetch('/api/run', {
21
- body: JSON.stringify({argv, id: command.id}),
22
- headers: {'content-type': 'application/json'},
23
- method: 'POST',
24
- })
25
- setResult((await res.json()) as RunResult)
26
- } catch (error) {
27
- setResult({durationMs: 0, error: String(error), output: String(error), success: false})
28
- } finally {
29
- setRunning(false)
30
- }
31
- }
32
-
33
- return (
34
- <div className="detail">
35
- <h1>
36
- {command.id}
37
- {command.pluginName && <span className="badge">{command.pluginName}</span>}
38
- </h1>
39
- {(command.description || command.summary) && <p className="desc">{command.description ?? command.summary}</p>}
40
-
41
- {command.args.length > 0 && (
42
- <>
43
- <div className="section-title">Arguments</div>
44
- {command.args.map((arg) => (
45
- <div className="field" key={arg.name}>
46
- <label htmlFor={`arg-${arg.name}`}>
47
- {arg.name}
48
- {arg.required && <span className="req">*</span>}
49
- </label>
50
- {arg.description && <div className="hint">{arg.description}</div>}
51
- {arg.options ? (
52
- <select
53
- id={`arg-${arg.name}`}
54
- onChange={(e) => setArgValues((v) => ({...v, [arg.name]: e.target.value}))}
55
- value={argValues[arg.name] ?? ''}
56
- >
57
- <option value="">— choose —</option>
58
- {arg.options.map((opt) => (
59
- <option key={opt} value={opt}>
60
- {opt}
61
- </option>
62
- ))}
63
- </select>
64
- ) : (
65
- <input
66
- id={`arg-${arg.name}`}
67
- onChange={(e) => setArgValues((v) => ({...v, [arg.name]: e.target.value}))}
68
- placeholder={arg.default ? String(arg.default) : ''}
69
- type="text"
70
- value={argValues[arg.name] ?? ''}
71
- />
72
- )}
73
- </div>
74
- ))}
75
- </>
76
- )}
77
-
78
- {command.flags.length > 0 && (
79
- <>
80
- <div className="section-title">Flags</div>
81
- {command.flags.map((flag) =>
82
- flag.type === 'boolean' ? (
83
- <div className="field checkbox-row" key={flag.name}>
84
- <input
85
- checked={flagValues[flag.name] === true}
86
- id={`flag-${flag.name}`}
87
- onChange={(e) => setFlagValues((v) => ({...v, [flag.name]: e.target.checked}))}
88
- type="checkbox"
89
- />
90
- <label htmlFor={`flag-${flag.name}`}>
91
- --{flag.name}
92
- {flag.description ? (
93
- <span className="hint" style={{display: 'inline', marginLeft: 8}}>
94
- {flag.description}
95
- </span>
96
- ) : null}
97
- </label>
98
- </div>
99
- ) : (
100
- <div className="field" key={flag.name}>
101
- <label htmlFor={`flag-${flag.name}`}>
102
- --{flag.name}
103
- {flag.char ? ` (-${flag.char})` : ''}
104
- {flag.required && <span className="req">*</span>}
105
- {flag.multiple && <span className="badge">multiple</span>}
106
- </label>
107
- {flag.description && <div className="hint">{flag.description}</div>}
108
- {flag.options ? (
109
- <select
110
- id={`flag-${flag.name}`}
111
- onChange={(e) => setFlagValues((v) => ({...v, [flag.name]: e.target.value}))}
112
- value={(flagValues[flag.name] as string) ?? ''}
113
- >
114
- <option value="">— choose —</option>
115
- {flag.options.map((opt) => (
116
- <option key={opt} value={opt}>
117
- {opt}
118
- </option>
119
- ))}
120
- </select>
121
- ) : (
122
- <input
123
- id={`flag-${flag.name}`}
124
- onChange={(e) => setFlagValues((v) => ({...v, [flag.name]: e.target.value}))}
125
- placeholder={
126
- flag.default === undefined
127
- ? flag.multiple
128
- ? 'comma,separated,values'
129
- : ''
130
- : String(flag.default)
131
- }
132
- type="text"
133
- value={(flagValues[flag.name] as string) ?? ''}
134
- />
135
- )}
136
- </div>
137
- ),
138
- )}
139
- </>
140
- )}
141
-
142
- <div className="section-title">Command</div>
143
- <div className="preview">$ {preview}</div>
144
-
145
- <button className="run-btn" disabled={running} onClick={run} type="button">
146
- {running ? 'Running…' : 'Run command'}
147
- </button>
148
-
149
- {result && (
150
- <div className="output">
151
- <div className={`status ${result.success ? 'ok' : 'err'}`}>
152
- {result.success ? '✓ Success' : '✗ Failed'} · {result.durationMs}ms
153
- </div>
154
- <pre>{result.output || '(no output)'}</pre>
155
- </div>
156
- )}
157
- </div>
158
- )
159
- }
@@ -1,105 +0,0 @@
1
- 'use client'
2
-
3
- import {useMemo, useState} from 'react'
4
-
5
- import type {CommandMeta} from '../lib/types'
6
-
7
- import {ThemeToggle} from './theme-toggle'
8
-
9
- export function CommandList({
10
- bin,
11
- commands,
12
- onSelect,
13
- query,
14
- selectedId,
15
- setQuery,
16
- version,
17
- }: {
18
- bin: string
19
- commands: CommandMeta[]
20
- onSelect: (id: string) => void
21
- query: string
22
- selectedId?: string
23
- setQuery: (q: string) => void
24
- version: string
25
- }) {
26
- const [topic, setTopic] = useState('all')
27
- const topics = useMemo(() => {
28
- const counts = new Map<string, number>()
29
- for (const command of commands) {
30
- const commandTopic = command.id.split(':', 1)[0]
31
- counts.set(commandTopic, (counts.get(commandTopic) ?? 0) + 1)
32
- }
33
-
34
- return [...counts].sort(([a], [b]) => a.localeCompare(b))
35
- }, [commands])
36
-
37
- const filtered = commands.filter((cmd) => {
38
- if (topic !== 'all' && cmd.id.split(':', 1)[0] !== topic) return false
39
- if (!query) return true
40
- const haystack = `${cmd.id} ${cmd.summary ?? ''} ${cmd.description ?? ''}`.toLowerCase()
41
- return query
42
- .toLowerCase()
43
- .split(/\s+/)
44
- .every((term) => haystack.includes(term))
45
- })
46
-
47
- return (
48
- <aside className="sidebar">
49
- <div className="sidebar-header">
50
- <div className="brand-row">
51
- <div className="brand">
52
- {bin || 'sdkck'} <small>web UI · v{version}</small>
53
- </div>
54
- <ThemeToggle />
55
- </div>
56
- <input
57
- aria-label="Filter commands"
58
- className="search"
59
- onChange={(e) => setQuery(e.target.value)}
60
- placeholder="Filter commands…"
61
- type="text"
62
- value={query}
63
- />
64
- <div className="topic-filter">
65
- <label htmlFor="topic">Topic</label>
66
- <select id="topic" onChange={(event) => setTopic(event.target.value)} value={topic}>
67
- <option value="all">All topics ({commands.length})</option>
68
- {topics.map(([name, count]) => (
69
- <option key={name} value={name}>
70
- {name} ({count})
71
- </option>
72
- ))}
73
- </select>
74
- </div>
75
- </div>
76
- <nav className="command-list">
77
- {filtered.length === 0 && <div className="empty">No commands match.</div>}
78
- {topics.map(([name]) => {
79
- const topicCommands = filtered.filter((command) => command.id.split(':', 1)[0] === name)
80
- if (topicCommands.length === 0) return null
81
-
82
- return (
83
- <section className="command-group" key={name}>
84
- <div className="topic-heading">
85
- <span>{name}</span>
86
- <span>{topicCommands.length}</span>
87
- </div>
88
- {topicCommands.map((cmd) => (
89
- <button
90
- className={`command-item${cmd.id === selectedId ? ' active' : ''}`}
91
- key={cmd.id}
92
- onClick={() => onSelect(cmd.id)}
93
- type="button"
94
- >
95
- <span className="cmd-id">{cmd.id}</span>
96
- <span className="cmd-summary">{cmd.summary ?? cmd.description ?? ''}</span>
97
- </button>
98
- ))}
99
- </section>
100
- )
101
- })}
102
- </nav>
103
- </aside>
104
- )
105
- }