@kingsoftcloud/agentkit-harness-ui 0.0.0-stage → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +116 -0
  3. package/README.md +292 -2
  4. package/markdown/build/build-markdown.cjs +66 -0
  5. package/markdown/dist/THIRD_PARTY_LICENSES.txt +2993 -0
  6. package/markdown/dist/markdown.css +1 -0
  7. package/markdown/dist/markdown.mjs +325 -0
  8. package/markdown/source/markdown-factory.mjs +613 -0
  9. package/markdown/source/markdown.css +288 -0
  10. package/markdown/source/table-factory.mjs +1588 -0
  11. package/markdown/source/table.css +487 -0
  12. package/package.json +96 -4
  13. package/src/activity-groups.mjs +74 -0
  14. package/src/browser-response-groups.mjs +57 -0
  15. package/src/command-output.mjs +57 -0
  16. package/src/components.mjs +9 -0
  17. package/src/context-markers.mjs +19 -0
  18. package/src/context-status.mjs +34 -0
  19. package/src/diff.mjs +240 -0
  20. package/src/explore-tool-call.mjs +139 -0
  21. package/src/file-preview.mjs +50 -0
  22. package/src/host/native-a2a.mjs +90 -0
  23. package/src/host/native-child-file-pane.mjs +49 -0
  24. package/src/host/native-child-pane.mjs +94 -0
  25. package/src/host/native-command-pane.mjs +64 -0
  26. package/src/host/native-run-panel.mjs +202 -0
  27. package/src/host/session-task-events.mjs +247 -0
  28. package/src/host/state/native-a2a.mjs +122 -0
  29. package/src/host/state/native-child-observation.mjs +35 -0
  30. package/src/host/state/native-children.mjs +93 -0
  31. package/src/host/state/native-outcome.mjs +35 -0
  32. package/src/host/state/native-recovery.mjs +187 -0
  33. package/src/host/state/native-runtime-route.mjs +26 -0
  34. package/src/host/state/native-session-stop.mjs +40 -0
  35. package/src/host/state/native-status-panel.mjs +23 -0
  36. package/src/host/state/native-task-read-model.mjs +89 -0
  37. package/src/host/state/task-links.mjs +40 -0
  38. package/src/host/task-timeline.mjs +185 -0
  39. package/src/index.mjs +52 -0
  40. package/src/input-preview.mjs +44 -0
  41. package/src/inspector.mjs +40 -0
  42. package/src/project.mjs +132 -0
  43. package/src/protocol.mjs +362 -0
  44. package/src/react-binding.mjs +486 -0
  45. package/src/reducer.mjs +355 -0
  46. package/src/renderers.mjs +644 -0
  47. package/src/status-panel.mjs +1156 -0
  48. package/src/styles.mjs +278 -0
  49. package/src/summary-playback.mjs +39 -0
  50. package/src/summary.mjs +160 -0
  51. package/src/terminal.mjs +157 -0
  52. package/src/tool-detail.mjs +208 -0
  53. package/src/tool-error.mjs +33 -0
  54. package/src/tool-identity.mjs +40 -0
  55. package/src/view.mjs +364 -0
  56. package/src/work-segments.mjs +41 -0
@@ -0,0 +1,487 @@
1
+ /* @kingsoftcloud/agentkit-harness-ui/markdown — table layer stylesheet.
2
+ *
3
+ * Ported from the reference Markdown table component:
4
+ * Tailwind utility classes are converted item-by-item to scoped CSS keyed on
5
+ * the ks-md-table-* classes emitted by table-factory.mjs. Table rules live
6
+ * under .ks-markdown so the shared theme tokens resolve; the portaled preview
7
+ * dialog renders into document.body (outside .ks-markdown) and therefore
8
+ * carries its own token set with explicit light/dark + prefers-color-scheme.
9
+ * No Tailwind dependency is introduced. */
10
+
11
+ /* ── table-specific tokens (extend the .ks-markdown palette) ──────────────── */
12
+
13
+ .ks-markdown {
14
+ --ks-fg-subtlest: #6e7681;
15
+ --ks-row-hover: rgba(175, 184, 193, 0.2);
16
+ }
17
+ .ks-markdown.ks-theme-dark {
18
+ --ks-fg-subtlest: #7d8590;
19
+ --ks-row-hover: rgba(177, 186, 196, 0.12);
20
+ }
21
+ @media (prefers-color-scheme: dark) {
22
+ .ks-markdown:not(.ks-theme-light) {
23
+ --ks-fg-subtlest: #7d8590;
24
+ --ks-row-hover: rgba(177, 186, 196, 0.12);
25
+ }
26
+ }
27
+
28
+ /* ── root: my-0 flex min-w-0 flex-col gap-2 ───────────────────────────────── */
29
+
30
+ .ks-markdown .ks-md-table-root {
31
+ margin-top: 0;
32
+ margin-bottom: 0;
33
+ display: flex;
34
+ min-width: 0;
35
+ flex-direction: column;
36
+ gap: 8px;
37
+ }
38
+
39
+ /* ── toolbar: flex items-center justify-end gap-1 ─────────────────────────── */
40
+
41
+ .ks-markdown .ks-md-table-toolbar {
42
+ display: flex;
43
+ align-items: center;
44
+ justify-content: flex-end;
45
+ gap: 4px;
46
+ flex-wrap: wrap;
47
+ }
48
+
49
+ /* ── ghost icon button (Button variant=ghost size=icon-md) ────────────────── */
50
+
51
+ .ks-markdown .ks-md-table-btn {
52
+ position: relative;
53
+ display: inline-flex;
54
+ align-items: center;
55
+ justify-content: center;
56
+ width: 28px;
57
+ height: 28px;
58
+ padding: 0;
59
+ border: 0;
60
+ border-radius: 6px;
61
+ background: transparent;
62
+ color: var(--ks-fg-muted);
63
+ cursor: pointer;
64
+ transition: background-color 120ms ease-out, color 120ms ease-out;
65
+ }
66
+ .ks-markdown .ks-md-table-btn:hover {
67
+ background: var(--ks-bg-soft);
68
+ color: var(--ks-fg);
69
+ }
70
+ .ks-markdown .ks-md-table-btn:focus-visible {
71
+ outline: 2px solid var(--ks-link);
72
+ outline-offset: 1px;
73
+ }
74
+ .ks-markdown .ks-md-table-btn[aria-pressed="true"] {
75
+ color: var(--ks-fg);
76
+ background: var(--ks-bg-soft);
77
+ }
78
+
79
+ /* ── tooltip via data-tip (replaces ControlHintTooltip) ───────────────────── */
80
+
81
+ .ks-markdown .ks-md-table-btn[data-tip]::after {
82
+ content: attr(data-tip);
83
+ position: absolute;
84
+ top: 100%;
85
+ left: 50%;
86
+ transform: translateX(-50%);
87
+ margin-top: 6px;
88
+ padding: 2px 6px;
89
+ border-radius: 4px;
90
+ background: var(--ks-fg);
91
+ color: var(--ks-bg);
92
+ font-size: 11px;
93
+ line-height: 1.4;
94
+ white-space: nowrap;
95
+ opacity: 0;
96
+ pointer-events: none;
97
+ transition: opacity 120ms ease-out;
98
+ z-index: 30;
99
+ }
100
+ .ks-markdown .ks-md-table-btn:hover[data-tip]::after,
101
+ .ks-markdown .ks-md-table-btn:focus-visible[data-tip]::after {
102
+ opacity: 1;
103
+ }
104
+
105
+ /* ── inline status region (replaces toast; never claims success on error) ── */
106
+
107
+ .ks-markdown .ks-md-table-status {
108
+ margin-left: 4px;
109
+ padding: 2px 6px;
110
+ border-radius: 4px;
111
+ font-size: 11px;
112
+ line-height: 1.4;
113
+ }
114
+ .ks-markdown .ks-md-table-status-success {
115
+ color: var(--ks-copied);
116
+ background: var(--ks-bg-soft);
117
+ }
118
+ .ks-markdown .ks-md-table-status-error {
119
+ color: #cf222e;
120
+ background: rgba(248, 81, 73, 0.12);
121
+ }
122
+ .ks-markdown.ks-theme-dark .ks-md-table-status-error {
123
+ color: #f85149;
124
+ background: rgba(248, 81, 73, 0.16);
125
+ }
126
+ @media (prefers-color-scheme: dark) {
127
+ .ks-markdown:not(.ks-theme-light) .ks-md-table-status-error {
128
+ color: #f85149;
129
+ background: rgba(248, 81, 73, 0.16);
130
+ }
131
+ }
132
+
133
+ /* ── frame: group/markdown-table-frame relative w-full ───────────────────── */
134
+
135
+ .ks-markdown .ks-md-table-frame {
136
+ position: relative;
137
+ width: 100%;
138
+ }
139
+
140
+ /* ── width container: min-w-full w-max + transition when not borrowing left ── */
141
+
142
+ .ks-markdown .ks-md-table-width {
143
+ min-width: 100%;
144
+ width: max-content;
145
+ }
146
+ .ks-markdown .ks-md-table-width-transition {
147
+ transition: max-width 200ms ease-out;
148
+ }
149
+ @media (prefers-reduced-motion: reduce) {
150
+ .ks-markdown .ks-md-table-width-transition {
151
+ transition: none;
152
+ }
153
+ }
154
+
155
+ /* ── viewport wrap: relative w-full overflow-hidden rounded-xl border ─────── */
156
+
157
+ .ks-markdown .ks-md-table-viewport-wrap {
158
+ position: relative;
159
+ width: 100%;
160
+ overflow: hidden;
161
+ border-radius: 12px;
162
+ border: 1px solid var(--ks-border);
163
+ }
164
+
165
+ /* ── scroll viewport: !scrollbar-hide w-full overflow-x-auto overflow-y-visible */
166
+
167
+ .ks-markdown .ks-md-table-scroll {
168
+ width: 100%;
169
+ overflow-x: auto;
170
+ overflow-y: visible;
171
+ scrollbar-width: none;
172
+ -ms-overflow-style: none;
173
+ }
174
+ .ks-markdown .ks-md-table-scroll::-webkit-scrollbar {
175
+ display: none;
176
+ width: 0;
177
+ height: 0;
178
+ }
179
+
180
+ /* ── table: w-max min-w-full border-separate border-spacing-0 text-ui-base ── */
181
+
182
+ .ks-markdown .ks-md-table {
183
+ width: max-content;
184
+ min-width: 100%;
185
+ border-collapse: separate;
186
+ border-spacing: 0;
187
+ font-size: 0.9375em;
188
+ }
189
+
190
+ .ks-markdown .ks-md-table-thead,
191
+ .ks-markdown .ks-md-table-tbody {
192
+ /* upstream attaches no classes; hooks reserved on the class for diagnostics */
193
+ }
194
+
195
+ /* ── tr: transition-colors last:[&>td]:border-b-0 hover:bg-hover/20 ──────── */
196
+
197
+ .ks-markdown .ks-md-table-tr {
198
+ transition: background-color 120ms ease-out;
199
+ }
200
+ .ks-markdown .ks-md-table-tr:hover {
201
+ background: var(--ks-row-hover);
202
+ }
203
+ .ks-markdown .ks-md-table-tr:last-child > .ks-md-table-td {
204
+ border-bottom: 0;
205
+ }
206
+
207
+ /* ── th: border-b px-3 py-2 text-left font-normal text-foreground-subtlest
208
+ * min-w-16 max-w-md whitespace-normal break-words ───────────────────── */
209
+
210
+ .ks-markdown .ks-md-table-th {
211
+ border-bottom: 1px solid var(--ks-border);
212
+ padding: 8px 12px;
213
+ text-align: left;
214
+ font-weight: 400;
215
+ color: var(--ks-fg-subtlest);
216
+ vertical-align: top;
217
+ min-width: 64px;
218
+ max-width: 448px;
219
+ white-space: normal;
220
+ overflow-wrap: break-word;
221
+ }
222
+
223
+ /* ── td: border-b px-3 py-2 text-foreground align-top
224
+ * min-w-16 max-w-md whitespace-normal break-words ───────────────────── */
225
+
226
+ .ks-markdown .ks-md-table-td {
227
+ border-bottom: 1px solid var(--ks-border);
228
+ padding: 8px 12px;
229
+ color: var(--ks-fg);
230
+ vertical-align: top;
231
+ min-width: 64px;
232
+ max-width: 448px;
233
+ white-space: normal;
234
+ overflow-wrap: break-word;
235
+ }
236
+
237
+ /* ── edge shadow: pointer-events-none absolute inset-y-0 z-10 w-6 + sides ── */
238
+
239
+ .ks-markdown .ks-md-table-edge-shadow {
240
+ pointer-events: none;
241
+ position: absolute;
242
+ top: 0;
243
+ bottom: 0;
244
+ z-index: 10;
245
+ width: 24px;
246
+ }
247
+ .ks-markdown .ks-md-table-edge-shadow[data-side="left"] {
248
+ left: 0;
249
+ border-radius: 12px 0 0 12px;
250
+ box-shadow: inset 12px 0 12px -12px color-mix(in srgb, black 15%, transparent);
251
+ }
252
+ .ks-markdown .ks-md-table-edge-shadow[data-side="right"] {
253
+ right: 0;
254
+ border-radius: 0 12px 12px 0;
255
+ box-shadow: inset -12px 0 12px -12px color-mix(in srgb, black 15%, transparent);
256
+ }
257
+
258
+ /* ── virtual scrollbar wrapper: pointer-events-none py-1 opacity-0
259
+ * transition-[width,opacity] + visible/hidden + sticky; frame-hover reveals */
260
+
261
+ .ks-markdown .ks-md-table-vbar {
262
+ pointer-events: none;
263
+ padding-top: 4px;
264
+ padding-bottom: 4px;
265
+ opacity: 0;
266
+ transition: width 200ms ease-out, opacity 200ms ease-out;
267
+ }
268
+ @media (prefers-reduced-motion: reduce) {
269
+ .ks-markdown .ks-md-table-vbar {
270
+ transition: none;
271
+ }
272
+ }
273
+ .ks-markdown .ks-md-table-vbar-hidden {
274
+ visibility: hidden;
275
+ }
276
+ .ks-markdown .ks-md-table-vbar-visible {
277
+ visibility: visible;
278
+ }
279
+ .ks-markdown .ks-md-table-frame:hover .ks-md-table-vbar-visible {
280
+ pointer-events: auto;
281
+ opacity: 1;
282
+ }
283
+ .ks-markdown .ks-md-table-vbar-sticky {
284
+ position: relative;
285
+ z-index: 20;
286
+ }
287
+
288
+ /* ── virtual track: mt-1 h-3.5 w-full touch-none rounded-full bg-foreground/3 ── */
289
+
290
+ .ks-markdown .ks-md-table-vtrack {
291
+ margin-top: 4px;
292
+ height: 14px;
293
+ width: 100%;
294
+ touch-action: none;
295
+ border-radius: 9999px;
296
+ background: color-mix(in srgb, var(--ks-fg) 3%, transparent);
297
+ }
298
+
299
+ /* ── virtual thumb: h-3 rounded-full bg-foreground/20 hover:bg-foreground/40 ── */
300
+
301
+ .ks-markdown .ks-md-table-vthumb {
302
+ height: 12px;
303
+ border-radius: 9999px;
304
+ background: color-mix(in srgb, var(--ks-fg) 20%, transparent);
305
+ transition: background-color 120ms ease-out;
306
+ cursor: grab;
307
+ }
308
+ .ks-markdown .ks-md-table-vthumb:hover {
309
+ background: color-mix(in srgb, var(--ks-fg) 40%, transparent);
310
+ }
311
+ .ks-markdown .ks-md-table-vthumb:active {
312
+ cursor: grabbing;
313
+ }
314
+
315
+ /* ── preview dialog (portaled to document.body — own token set) ──────────── */
316
+
317
+ .ks-md-table-dialog-overlay {
318
+ --ks-dlg-bg: #ffffff;
319
+ --ks-dlg-fg: #1f2328;
320
+ --ks-dlg-fg-muted: #59636e;
321
+ --ks-dlg-border: #d0d7de;
322
+ --ks-dlg-th-bg: #f6f8fa;
323
+ --ks-dlg-row-hover: rgba(175, 184, 193, 0.2);
324
+ position: fixed;
325
+ inset: 0;
326
+ z-index: 50;
327
+ display: flex;
328
+ align-items: center;
329
+ justify-content: center;
330
+ padding: 16px;
331
+ background: color-mix(in srgb, black 40%, transparent);
332
+ }
333
+ .ks-md-table-dialog-overlay.ks-theme-dark {
334
+ --ks-dlg-bg: #0d1117;
335
+ --ks-dlg-fg: #e6edf3;
336
+ --ks-dlg-fg-muted: #9198a1;
337
+ --ks-dlg-border: #30363d;
338
+ --ks-dlg-th-bg: #161b22;
339
+ --ks-dlg-row-hover: rgba(177, 186, 196, 0.12);
340
+ }
341
+ @media (prefers-color-scheme: dark) {
342
+ .ks-md-table-dialog-overlay:not(.ks-theme-light) {
343
+ --ks-dlg-bg: #0d1117;
344
+ --ks-dlg-fg: #e6edf3;
345
+ --ks-dlg-fg-muted: #9198a1;
346
+ --ks-dlg-border: #30363d;
347
+ --ks-dlg-th-bg: #161b22;
348
+ --ks-dlg-row-hover: rgba(177, 186, 196, 0.12);
349
+ }
350
+ }
351
+
352
+ /* Dialog content: flex max-h-[calc(100vh-2rem)] w-max max-w-[calc(100vw-2rem)]
353
+ * flex-col gap-3 overflow-hidden rounded-2xl p-4 + sm/md/lg breakpoints. */
354
+ .ks-md-table-dialog {
355
+ display: flex;
356
+ flex-direction: column;
357
+ gap: 12px;
358
+ max-height: calc(100vh - 2rem);
359
+ width: max-content;
360
+ max-width: calc(100vw - 2rem);
361
+ overflow: hidden;
362
+ border-radius: 16px;
363
+ padding: 16px;
364
+ background: var(--ks-dlg-bg);
365
+ border: 1px solid var(--ks-dlg-border);
366
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
367
+ }
368
+ @media (min-width: 640px) {
369
+ .ks-md-table-dialog {
370
+ max-height: calc(100vh - 8rem);
371
+ max-width: calc(100vw - 8rem);
372
+ }
373
+ }
374
+ @media (min-width: 768px) {
375
+ .ks-md-table-dialog {
376
+ min-width: 640px;
377
+ }
378
+ }
379
+ @media (min-width: 1024px) {
380
+ .ks-md-table-dialog {
381
+ min-width: 720px;
382
+ }
383
+ }
384
+
385
+ /* Dialog header: pr-8 (room for the close button). */
386
+ .ks-md-table-dialog-header {
387
+ position: relative;
388
+ padding-right: 32px;
389
+ display: flex;
390
+ flex-direction: column;
391
+ gap: 4px;
392
+ }
393
+ .ks-md-table-dialog-title {
394
+ margin: 0;
395
+ font-size: 1.125em;
396
+ font-weight: 600;
397
+ color: var(--ks-dlg-fg);
398
+ }
399
+ .ks-md-table-dialog-desc {
400
+ margin: 0;
401
+ font-size: 0.8125em;
402
+ color: var(--ks-dlg-fg-muted);
403
+ }
404
+ .ks-md-table-dialog-close {
405
+ position: absolute;
406
+ top: -2px;
407
+ right: -2px;
408
+ }
409
+ .ks-md-table-dialog-scroll {
410
+ min-height: 0;
411
+ overflow: auto;
412
+ border-radius: 12px;
413
+ border: 1px solid var(--ks-dlg-border);
414
+ background: var(--ks-dlg-bg);
415
+ }
416
+
417
+ /* The dialog's close button is outside .ks-markdown, so it needs its own rule. */
418
+ .ks-md-table-dialog .ks-md-table-btn {
419
+ position: relative;
420
+ display: inline-flex;
421
+ align-items: center;
422
+ justify-content: center;
423
+ width: 28px;
424
+ height: 28px;
425
+ padding: 0;
426
+ border: 0;
427
+ border-radius: 6px;
428
+ background: transparent;
429
+ color: var(--ks-dlg-fg-muted);
430
+ cursor: pointer;
431
+ transition: background-color 120ms ease-out, color 120ms ease-out;
432
+ }
433
+ .ks-md-table-dialog .ks-md-table-btn:hover {
434
+ background: color-mix(in srgb, var(--ks-dlg-fg) 8%, transparent);
435
+ color: var(--ks-dlg-fg);
436
+ }
437
+ .ks-md-table-dialog .ks-md-table-btn:focus-visible {
438
+ outline: 2px solid var(--ks-dlg-fg-muted);
439
+ outline-offset: 1px;
440
+ }
441
+
442
+ /* Preview table: same base as the main table + [&_th]:sticky top-0 z-10
443
+ * bg-background. Scoped to .ks-md-table-preview (only the preview table has it)
444
+ * and under the dialog (outside .ks-markdown). */
445
+ .ks-md-table-dialog .ks-md-table-preview {
446
+ width: max-content;
447
+ min-width: 100%;
448
+ border-collapse: separate;
449
+ border-spacing: 0;
450
+ font-size: 0.9375em;
451
+ }
452
+ .ks-md-table-dialog .ks-md-table-preview .ks-md-table-tr {
453
+ transition: background-color 120ms ease-out;
454
+ }
455
+ .ks-md-table-dialog .ks-md-table-preview .ks-md-table-tr:hover {
456
+ background: var(--ks-dlg-row-hover);
457
+ }
458
+ .ks-md-table-dialog .ks-md-table-preview .ks-md-table-tr:last-child > .ks-md-table-td {
459
+ border-bottom: 0;
460
+ }
461
+ .ks-md-table-dialog .ks-md-table-preview .ks-md-table-th {
462
+ position: sticky;
463
+ top: 0;
464
+ z-index: 10;
465
+ background: var(--ks-dlg-th-bg);
466
+ color: var(--ks-dlg-fg-muted);
467
+ font-weight: 400;
468
+ text-align: left;
469
+ vertical-align: top;
470
+ padding: 8px 12px;
471
+ min-width: 64px;
472
+ max-width: 448px;
473
+ white-space: normal;
474
+ overflow-wrap: break-word;
475
+ border-bottom: 1px solid var(--ks-dlg-border);
476
+ }
477
+ .ks-md-table-dialog .ks-md-table-preview .ks-md-table-td {
478
+ color: var(--ks-dlg-fg);
479
+ vertical-align: top;
480
+ text-align: left;
481
+ padding: 8px 12px;
482
+ min-width: 64px;
483
+ max-width: 448px;
484
+ white-space: normal;
485
+ overflow-wrap: break-word;
486
+ border-bottom: 1px solid var(--ks-dlg-border);
487
+ }
package/package.json CHANGED
@@ -1,6 +1,98 @@
1
1
  {
2
2
  "name": "@kingsoftcloud/agentkit-harness-ui",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.0.1",
4
+ "private": false,
5
+ "type": "module",
6
+ "description": "Reusable React task-process UI for AgentKit Native: an explicitly versioned event protocol, a pure state reducer, and an accessible timeline. No Studio/DSH/Python imports; React is a peer dependency.",
7
+ "exports": {
8
+ ".": "./src/index.mjs",
9
+ "./protocol": "./src/protocol.mjs",
10
+ "./reducer": "./src/reducer.mjs",
11
+ "./project": "./src/project.mjs",
12
+ "./tool-detail": "./src/tool-detail.mjs",
13
+ "./summary": "./src/summary.mjs",
14
+ "./diff": "./src/diff.mjs",
15
+ "./terminal": "./src/terminal.mjs",
16
+ "./renderers": "./src/renderers.mjs",
17
+ "./view": "./src/view.mjs",
18
+ "./components": "./src/components.mjs",
19
+ "./styles": "./src/styles.mjs",
20
+ "./react-binding": "./src/react-binding.mjs",
21
+ "./input-preview": "./src/input-preview.mjs",
22
+ "./inspector": "./src/inspector.mjs",
23
+ "./markdown": "./markdown/dist/markdown.mjs",
24
+ "./context-status": "./src/context-status.mjs",
25
+ "./status-panel": "./src/status-panel.mjs",
26
+ "./command-output": "./src/command-output.mjs",
27
+ "./file-preview": "./src/file-preview.mjs",
28
+ "./host/state/native-status-panel": "./src/host/state/native-status-panel.mjs",
29
+ "./host/state/native-child-observation": "./src/host/state/native-child-observation.mjs",
30
+ "./host/state/native-outcome": "./src/host/state/native-outcome.mjs",
31
+ "./host/state/task-links": "./src/host/state/task-links.mjs",
32
+ "./host/state/native-children": "./src/host/state/native-children.mjs",
33
+ "./host/state/native-recovery": "./src/host/state/native-recovery.mjs",
34
+ "./host/state/native-session-stop": "./src/host/state/native-session-stop.mjs",
35
+ "./host/task-timeline": "./src/host/task-timeline.mjs",
36
+ "./host/session-task-events": "./src/host/session-task-events.mjs",
37
+ "./host/native-command-pane": "./src/host/native-command-pane.mjs",
38
+ "./host/native-child-pane": "./src/host/native-child-pane.mjs",
39
+ "./host/native-child-file-pane": "./src/host/native-child-file-pane.mjs",
40
+ "./host/native-run-panel": "./src/host/native-run-panel.mjs",
41
+ "./host/native-a2a": "./src/host/native-a2a.mjs",
42
+ "./host/state/native-a2a": "./src/host/state/native-a2a.mjs",
43
+ "./host/state/native-task-read-model": "./src/host/state/native-task-read-model.mjs"
44
+ },
45
+ "files": [
46
+ "src",
47
+ "LICENSE",
48
+ "NOTICE",
49
+ "README.md",
50
+ "markdown/source",
51
+ "markdown/build",
52
+ "markdown/dist"
53
+ ],
54
+ "peerDependencies": {
55
+ "react": ">=18",
56
+ "react-dom": ">=18"
57
+ },
58
+ "peerDependenciesMeta": {
59
+ "react": {
60
+ "optional": true
61
+ },
62
+ "react-dom": {
63
+ "optional": true
64
+ }
65
+ },
66
+ "scripts": {
67
+ "test": "node --test test/*.test.mjs",
68
+ "build": "node markdown/build/build-markdown.cjs"
69
+ },
70
+ "license": "Apache-2.0",
71
+ "engines": {
72
+ "node": ">=22"
73
+ },
74
+ "devDependencies": {
75
+ "react": "18.3.1",
76
+ "react-dom": "18.3.1",
77
+ "streamdown": "2.5.0",
78
+ "@streamdown/cjk": "1.0.3",
79
+ "@shikijs/core": "4.0.2",
80
+ "@shikijs/langs": "4.0.2",
81
+ "@shikijs/themes": "4.0.2",
82
+ "@shikijs/engine-javascript": "4.0.2",
83
+ "esbuild": "0.27.7",
84
+ "typescript": "6.0.3"
85
+ },
86
+ "repository": {
87
+ "type": "git",
88
+ "url": "https://github.com/kingsoftcloud/ksadk-harness.git"
89
+ },
90
+ "homepage": "https://github.com/kingsoftcloud/ksadk-harness#readme",
91
+ "bugs": {
92
+ "url": "https://github.com/kingsoftcloud/ksadk-harness/issues"
93
+ },
94
+ "publishConfig": {
95
+ "access": "public",
96
+ "registry": "https://registry.npmjs.org"
97
+ }
98
+ }
@@ -0,0 +1,74 @@
1
+ import { toolIdentity } from './tool-identity.mjs';
2
+ import { isExploreToolCall, isExecuteToolCall, isShellToolCallAwaitingCommand } from './explore-tool-call.mjs';
3
+ import { extractCommand } from './terminal.mjs';
4
+ import { browserResponseGroups } from './browser-response-groups.mjs';
5
+
6
+ const changes = new Set(['edit', 'write', 'delete']);
7
+ function family(item, enableChangesGrouping) {
8
+ if (!['tool', 'tool-preview'].includes(item.kind) || item.child) return null;
9
+ const call = { kind: item.name, input: item.input };
10
+ return isExploreToolCall(call) ? 'explore' : isExecuteToolCall(call) ? 'terminal'
11
+ : enableChangesGrouping && changes.has(toolIdentity(item.name).family) ? 'changes' : null;
12
+ }
13
+
14
+ /** Match ZCode's Explore summary buckets; this is display, not a file-read receipt. */
15
+ function explorationBucket(item) {
16
+ const kind = toolIdentity(item.name).family;
17
+ if (kind === 'web-fetch') return 'web-fetch';
18
+ if (['search', 'web-search'].includes(kind)) return 'search';
19
+ if (kind === 'list') return 'list';
20
+ const command = extractCommand(item.input).toLowerCase();
21
+ if (/(^|\s)(rg|grep|ripgrep|git\s+grep)(\s|$)/i.test(command)) return 'search';
22
+ if (/(^|\s)(ls|find|tree|dir)(\s|$)/i.test(command)) return 'list';
23
+ return 'file';
24
+ }
25
+
26
+ function awaitingCommand(item) {
27
+ return (item.kind === 'tool' && ['scheduled', 'running'].includes(item.status)
28
+ || item.kind === 'tool-preview' && item.streaming)
29
+ && isShellToolCallAwaitingCommand({kind: item.name, input: item.input});
30
+ }
31
+
32
+ /** A group represents a visible work stage, not a tool execution. Like ZCode's
33
+ * buildAssistantWorkRenderItems, only the true tail of a running segment keeps
34
+ * its parent active between model calls. Child outcomes remain independent.
35
+ * Narrative, visible reasoning, context markers and child tasks are boundaries.
36
+ */
37
+ export function activityGroups(items, { stageTailIsRunning = false, enableChangesGrouping = false, enableBrowserGrouping = true } = {}) {
38
+ // A Shell input draft without a command is transparent to stage boundaries.
39
+ // Filter before counting/tail detection; keep the original event state intact.
40
+ items = items.filter(item => !awaitingCommand(item));
41
+ if (enableBrowserGrouping) items = browserResponseGroups(items, { stageTailIsRunning });
42
+ const result = [];
43
+ for (let index = 0; index < items.length;) {
44
+ const first = items[index++], group = family(first, enableChangesGrouping), children = [first];
45
+ if (group) while (index < items.length && family(items[index], enableChangesGrouping) === group) children.push(items[index++]);
46
+ if (children.length === 1) { result.push(first); continue; }
47
+ const counts = {};
48
+ for (const item of children) {
49
+ const kind = group === 'explore' ? explorationBucket(item) : toolIdentity(item.name).family;
50
+ counts[kind] = (counts[kind] ?? 0) + 1;
51
+ }
52
+ result.push({ kind: 'activity-group', id: `activity:${group}:${first.callId ?? first.id}`, family: group, children, counts,
53
+ active: stageTailIsRunning && index === items.length,
54
+ failed: children.filter(item => item.status === 'failed').length,
55
+ uncertain: children.filter(item => ['uncertain', 'interrupted', 'waiting'].includes(item.status)).length });
56
+ }
57
+ return result;
58
+ }
59
+
60
+ export function activityGroupSummary(group, locale) {
61
+ const zh = String(locale ?? '').startsWith('zh');
62
+ const units = zh ? { 'web-fetch': '次网页抓取', search: '搜索', list: '列表', file: '文件' }
63
+ : { 'web-fetch': 'fetch', search: 'search', list: 'list', file: 'file' };
64
+ const title = (zh ? { explore: '查阅', terminal: '终端', changes: '更改', browser: '浏览器' }
65
+ : { explore: 'Explore', terminal: 'Terminal', changes: 'Changes', browser: 'Browser' })[group.family];
66
+ const parts = group.family === 'explore'
67
+ ? Object.entries(units).filter(([key]) => group.counts[key])
68
+ .map(([key, unit]) => `${group.counts[key]} ${unit}${!zh && group.counts[key] !== 1 ? key === 'search' || key === 'web-fetch' ? 'es' : 's' : ''}`)
69
+ : [`${group.children.length} ${group.family === 'terminal' ? zh ? '个命令' : 'commands'
70
+ : group.family === 'browser' ? zh ? '次调用' : 'calls' : zh ? '次文件操作' : 'file operations'}`];
71
+ if (group.failed) parts.push(`${group.failed} ${zh ? '失败' : 'failed'}`);
72
+ if (group.uncertain) parts.push(`${group.uncertain} ${zh ? '待核对' : 'unconfirmed'}`);
73
+ return { title, detail: parts.join(', ') };
74
+ }