@popcomputer/structured-chat 0.1.0 → 0.2.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 (50) hide show
  1. package/LICENSE +0 -1
  2. package/README.md +175 -108
  3. package/dist/adapters/openai-compatible-model.d.ts +4 -4
  4. package/dist/adapters/openai-compatible-model.js +33 -31
  5. package/dist/core/answer.d.ts +13 -13
  6. package/dist/core/answer.js +21 -12
  7. package/dist/core/chat.d.ts +12 -15
  8. package/dist/core/chat.js +36 -27
  9. package/dist/core/collect-stage.d.ts +28 -15
  10. package/dist/core/collect-stage.js +58 -37
  11. package/dist/core/command.d.ts +1 -1
  12. package/dist/core/command.js +1 -1
  13. package/dist/core/debug-protocol.d.ts +126 -0
  14. package/dist/core/debug-protocol.js +19 -0
  15. package/dist/core/debug.d.ts +103 -0
  16. package/dist/core/debug.js +276 -0
  17. package/dist/core/json-value.d.ts +1 -1
  18. package/dist/core/json-value.js +8 -1
  19. package/dist/core/model-guard.d.ts +2 -3
  20. package/dist/core/model-guard.js +4 -4
  21. package/dist/core/model.d.ts +15 -19
  22. package/dist/core/model.js +22 -10
  23. package/dist/core/protocol.d.ts +84 -79
  24. package/dist/core/protocol.js +18 -12
  25. package/dist/core/question.js +17 -15
  26. package/dist/core/repair.js +1 -1
  27. package/dist/core/session.d.ts +22 -28
  28. package/dist/core/session.js +16 -7
  29. package/dist/core/stage-name.d.ts +1 -1
  30. package/dist/core/stage-name.js +1 -1
  31. package/dist/core/stage.d.ts +4 -4
  32. package/dist/core/stage.js +11 -8
  33. package/dist/core/tool-set.js +6 -6
  34. package/dist/core/tool.d.ts +36 -39
  35. package/dist/core/tool.js +58 -31
  36. package/dist/core/view.d.ts +64 -39
  37. package/dist/core/view.js +12 -15
  38. package/dist/index.d.ts +2 -0
  39. package/dist/index.js +2 -0
  40. package/dist/integrations/assistant-ui-debug.d.ts +25 -0
  41. package/dist/integrations/assistant-ui-debug.js +1162 -0
  42. package/dist/integrations/assistant-ui.d.ts +10 -3
  43. package/dist/integrations/assistant-ui.js +48 -18
  44. package/dist/testing/in-memory-session-store.js +1 -1
  45. package/dist/testing/scenario.js +6 -6
  46. package/examples/answer-modes.ts +60 -49
  47. package/examples/prompt-injection-policy.ts +20 -20
  48. package/examples/resource-search.ts +104 -0
  49. package/package.json +15 -3
  50. package/examples/agency-search.ts +0 -101
@@ -0,0 +1,1162 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useEffect, useId, useMemo, useState, useSyncExternalStore, } from "react";
3
+ /** Create one isolated structured-chat debug snapshot store. */
4
+ export const createStructuredChatDebugStore = () => {
5
+ let current = null;
6
+ const listeners = new Set();
7
+ return {
8
+ receive: (snapshot) => {
9
+ if (Object.is(snapshot, current)) {
10
+ return;
11
+ }
12
+ current = snapshot;
13
+ for (const listener of listeners) {
14
+ try {
15
+ listener();
16
+ }
17
+ catch {
18
+ // One faulty preview consumer must not leave later panels stale.
19
+ }
20
+ }
21
+ },
22
+ subscribe: (listener) => {
23
+ listeners.add(listener);
24
+ return () => {
25
+ listeners.delete(listener);
26
+ };
27
+ },
28
+ getSnapshot: () => current,
29
+ };
30
+ };
31
+ const panelCss = `
32
+ .pcsc-debug {
33
+ --pcsc-ease-out: cubic-bezier(.23, 1, .32, 1);
34
+
35
+ --pcsc-bg: rgba(16, 17, 20, .94);
36
+ --pcsc-raised: #17191d;
37
+ --pcsc-well: #1c1f24;
38
+ --pcsc-hover: rgba(255, 255, 255, .04);
39
+ --pcsc-border: #23262c;
40
+ --pcsc-border-strong: #30343c;
41
+ --pcsc-text: #eceef1;
42
+ --pcsc-text-2: #9aa0aa;
43
+ --pcsc-text-3: #6a707a;
44
+
45
+ --pcsc-accent: #7f9cf5;
46
+ --pcsc-accent-soft: rgba(127, 156, 245, .1);
47
+ --pcsc-ok: #5ec99b;
48
+ --pcsc-ok-muted: rgba(94, 201, 155, .4);
49
+ --pcsc-warn: #e0b34a;
50
+ --pcsc-warn-soft: rgba(224, 179, 74, .09);
51
+
52
+ --pcsc-shadow:
53
+ 0 1px 2px rgba(0, 0, 0, .3),
54
+ 0 8px 24px -8px rgba(0, 0, 0, .5),
55
+ 0 32px 56px -16px rgba(0, 0, 0, .45);
56
+
57
+ position: fixed;
58
+ z-index: 2147483000;
59
+ width: min(360px, calc(100vw - 32px));
60
+ max-height: min(720px, calc(100dvh - 32px));
61
+ overflow: hidden;
62
+ isolation: isolate;
63
+ color: var(--pcsc-text);
64
+ background: var(--pcsc-bg);
65
+ border: 1px solid var(--pcsc-border);
66
+ border-radius: 12px;
67
+ box-shadow: var(--pcsc-shadow);
68
+ backdrop-filter: blur(20px);
69
+ -webkit-backdrop-filter: blur(20px);
70
+ font: 400 12px/1.5 ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
71
+ font-variant-numeric: tabular-nums;
72
+ letter-spacing: -.003em;
73
+ color-scheme: dark;
74
+ }
75
+
76
+ .pcsc-debug,
77
+ .pcsc-debug * {
78
+ box-sizing: border-box;
79
+ }
80
+
81
+ .pcsc-debug[data-position="top-left"] {
82
+ top: max(16px, env(safe-area-inset-top, 0px));
83
+ left: max(16px, env(safe-area-inset-left, 0px));
84
+ }
85
+
86
+ .pcsc-debug[data-position="top-right"] {
87
+ top: max(16px, env(safe-area-inset-top, 0px));
88
+ right: max(16px, env(safe-area-inset-right, 0px));
89
+ }
90
+
91
+ .pcsc-debug[data-position="bottom-left"] {
92
+ bottom: max(16px, env(safe-area-inset-bottom, 0px));
93
+ left: max(16px, env(safe-area-inset-left, 0px));
94
+ }
95
+
96
+ .pcsc-debug[data-position="bottom-right"] {
97
+ right: max(16px, env(safe-area-inset-right, 0px));
98
+ bottom: max(16px, env(safe-area-inset-bottom, 0px));
99
+ }
100
+
101
+ .pcsc-debug[data-theme="light"] {
102
+ --pcsc-bg: rgba(255, 255, 255, .94);
103
+ --pcsc-raised: #f7f8f9;
104
+ --pcsc-well: #f1f3f5;
105
+ --pcsc-hover: rgba(0, 0, 0, .035);
106
+ --pcsc-border: #e4e6ea;
107
+ --pcsc-border-strong: #d2d6dc;
108
+ --pcsc-text: #16181c;
109
+ --pcsc-text-2: #5b616b;
110
+ --pcsc-text-3: #868d97;
111
+
112
+ --pcsc-accent: #4f5bd5;
113
+ --pcsc-accent-soft: rgba(79, 91, 213, .06);
114
+ --pcsc-ok: #2f9e6f;
115
+ --pcsc-ok-muted: rgba(47, 158, 111, .4);
116
+ --pcsc-warn: #9a7011;
117
+ --pcsc-warn-soft: rgba(154, 112, 17, .08);
118
+
119
+ --pcsc-shadow:
120
+ 0 1px 2px rgba(16, 18, 22, .06),
121
+ 0 8px 24px -8px rgba(16, 18, 22, .12),
122
+ 0 32px 56px -16px rgba(16, 18, 22, .14);
123
+
124
+ color-scheme: light;
125
+ }
126
+
127
+ @media (prefers-color-scheme: light) {
128
+ .pcsc-debug[data-theme="system"] {
129
+ --pcsc-bg: rgba(255, 255, 255, .94);
130
+ --pcsc-raised: #f7f8f9;
131
+ --pcsc-well: #f1f3f5;
132
+ --pcsc-hover: rgba(0, 0, 0, .035);
133
+ --pcsc-border: #e4e6ea;
134
+ --pcsc-border-strong: #d2d6dc;
135
+ --pcsc-text: #16181c;
136
+ --pcsc-text-2: #5b616b;
137
+ --pcsc-text-3: #868d97;
138
+
139
+ --pcsc-accent: #4f5bd5;
140
+ --pcsc-accent-soft: rgba(79, 91, 213, .06);
141
+ --pcsc-ok: #2f9e6f;
142
+ --pcsc-ok-muted: rgba(47, 158, 111, .4);
143
+ --pcsc-warn: #9a7011;
144
+ --pcsc-warn-soft: rgba(154, 112, 17, .08);
145
+
146
+ --pcsc-shadow:
147
+ 0 1px 2px rgba(16, 18, 22, .06),
148
+ 0 8px 24px -8px rgba(16, 18, 22, .12),
149
+ 0 32px 56px -16px rgba(16, 18, 22, .14);
150
+
151
+ color-scheme: light;
152
+ }
153
+ }
154
+
155
+ /* ---------- collapsed ---------- */
156
+
157
+ .pcsc-debug[data-open="false"] {
158
+ width: 40px;
159
+ height: 40px;
160
+ border-radius: 999px;
161
+ }
162
+
163
+ .pcsc-debug[data-open="false"] .pcsc-debug__header {
164
+ min-height: 38px;
165
+ padding: 0;
166
+ border-bottom: 0;
167
+ }
168
+
169
+ .pcsc-debug[data-open="false"] .pcsc-debug__mark,
170
+ .pcsc-debug[data-open="false"] .pcsc-debug__title,
171
+ .pcsc-debug[data-open="false"] .pcsc-debug__copy {
172
+ display: none;
173
+ }
174
+
175
+ .pcsc-debug[data-open="false"] .pcsc-debug__actions {
176
+ width: 38px;
177
+ height: 38px;
178
+ }
179
+
180
+ .pcsc-debug[data-open="false"] .pcsc-debug__toggle {
181
+ width: 38px;
182
+ height: 38px;
183
+ color: var(--pcsc-text-2);
184
+ border-radius: 999px;
185
+ }
186
+
187
+ /* ---------- header ---------- */
188
+
189
+ .pcsc-debug__header {
190
+ display: flex;
191
+ min-height: 48px;
192
+ align-items: center;
193
+ gap: 10px;
194
+ padding: 8px 8px 8px 14px;
195
+ border-bottom: 1px solid var(--pcsc-border);
196
+ }
197
+
198
+ .pcsc-debug__mark {
199
+ display: grid;
200
+ flex: 0 0 auto;
201
+ place-items: center;
202
+ color: var(--pcsc-text-3);
203
+ }
204
+
205
+ .pcsc-debug__mark .pcsc-debug__icon {
206
+ width: 16px;
207
+ height: 16px;
208
+ }
209
+
210
+ .pcsc-debug__title {
211
+ min-width: 0;
212
+ flex: 1;
213
+ }
214
+
215
+ .pcsc-debug__title > h2,
216
+ .pcsc-debug__title > span {
217
+ display: block;
218
+ overflow: hidden;
219
+ text-overflow: ellipsis;
220
+ white-space: nowrap;
221
+ }
222
+
223
+ .pcsc-debug__title h2 {
224
+ padding: 0;
225
+ margin: 0;
226
+ font-size: 13px;
227
+ font-weight: 600;
228
+ letter-spacing: -.012em;
229
+ }
230
+
231
+ .pcsc-debug__title span {
232
+ color: var(--pcsc-text-3);
233
+ font-size: 11px;
234
+ }
235
+
236
+ .pcsc-debug__status-dot {
237
+ display: inline-block;
238
+ width: 5px;
239
+ height: 5px;
240
+ margin-right: 6px;
241
+ border-radius: 999px;
242
+ background: var(--pcsc-accent);
243
+ vertical-align: 1px;
244
+ }
245
+
246
+ .pcsc-debug[data-chat-status="complete"] .pcsc-debug__status-dot {
247
+ background: var(--pcsc-ok);
248
+ }
249
+
250
+ .pcsc-debug__actions {
251
+ display: flex;
252
+ align-items: center;
253
+ gap: 2px;
254
+ }
255
+
256
+ /* ---------- controls ---------- */
257
+
258
+ .pcsc-debug button {
259
+ display: inline-grid;
260
+ width: 32px;
261
+ height: 32px;
262
+ padding: 0;
263
+ place-items: center;
264
+ color: var(--pcsc-text-3);
265
+ background: transparent;
266
+ border: 0;
267
+ border-radius: 8px;
268
+ font: inherit;
269
+ cursor: pointer;
270
+ touch-action: manipulation;
271
+ -webkit-tap-highlight-color: transparent;
272
+ transform-origin: center;
273
+ transition:
274
+ color 120ms ease,
275
+ background-color 120ms ease,
276
+ transform 140ms var(--pcsc-ease-out);
277
+ }
278
+
279
+ @media (hover: hover) and (pointer: fine) {
280
+ .pcsc-debug button:hover:not(:disabled) {
281
+ color: var(--pcsc-text);
282
+ background: var(--pcsc-hover);
283
+ }
284
+ }
285
+
286
+ .pcsc-debug button:active:not(:disabled) {
287
+ transform: scale(.96);
288
+ }
289
+
290
+ .pcsc-debug button:focus-visible,
291
+ .pcsc-debug summary:focus-visible {
292
+ outline: 2px solid var(--pcsc-accent);
293
+ outline-offset: -2px;
294
+ }
295
+
296
+ .pcsc-debug button:disabled {
297
+ opacity: .4;
298
+ cursor: not-allowed;
299
+ }
300
+
301
+ .pcsc-debug__icon {
302
+ width: 16px;
303
+ height: 16px;
304
+ fill: none;
305
+ stroke: currentColor;
306
+ stroke-linecap: round;
307
+ stroke-linejoin: round;
308
+ stroke-width: 1.6;
309
+ }
310
+
311
+ .pcsc-debug__copy-glyph {
312
+ display: grid;
313
+ place-items: center;
314
+ opacity: 1;
315
+ transform: scale(1);
316
+ transition:
317
+ opacity 120ms ease,
318
+ transform 140ms var(--pcsc-ease-out);
319
+ }
320
+
321
+ @starting-style {
322
+ .pcsc-debug__copy-glyph {
323
+ opacity: 0;
324
+ transform: scale(.94);
325
+ }
326
+ }
327
+
328
+ .pcsc-debug__toggle .pcsc-debug__toggle-glyph {
329
+ transition: transform 160ms var(--pcsc-ease-out);
330
+ }
331
+
332
+ .pcsc-debug__toggle-chevron {
333
+ transform: rotate(180deg);
334
+ }
335
+
336
+ /* ---------- body ---------- */
337
+
338
+ .pcsc-debug__body {
339
+ max-height: calc(min(720px, 100dvh - 32px) - 48px);
340
+ overflow: auto;
341
+ padding: 4px 8px 8px;
342
+ overscroll-behavior: contain;
343
+ scrollbar-gutter: stable;
344
+ scrollbar-color: var(--pcsc-border-strong) transparent;
345
+ scrollbar-width: thin;
346
+ }
347
+
348
+ .pcsc-debug__flow-heading,
349
+ .pcsc-debug__footer {
350
+ display: flex;
351
+ align-items: center;
352
+ justify-content: space-between;
353
+ gap: 12px;
354
+ }
355
+
356
+ .pcsc-debug__flow-heading {
357
+ padding: 10px 6px 8px;
358
+ color: var(--pcsc-text-3);
359
+ font-size: 10px;
360
+ font-weight: 600;
361
+ letter-spacing: .07em;
362
+ text-transform: uppercase;
363
+ }
364
+
365
+ .pcsc-debug__step-count {
366
+ color: var(--pcsc-text-3);
367
+ font-size: 10px;
368
+ font-weight: 600;
369
+ letter-spacing: .07em;
370
+ }
371
+
372
+ .pcsc-debug__stage-list {
373
+ display: grid;
374
+ gap: 2px;
375
+ }
376
+
377
+ .pcsc-debug details,
378
+ .pcsc-debug summary {
379
+ margin: 0;
380
+ }
381
+
382
+ .pcsc-debug summary {
383
+ list-style: none;
384
+ -webkit-tap-highlight-color: transparent;
385
+ }
386
+
387
+ .pcsc-debug summary::-webkit-details-marker {
388
+ display: none;
389
+ }
390
+
391
+ /* ---------- stage ---------- */
392
+
393
+ .pcsc-debug__stage {
394
+ position: relative;
395
+ background: transparent;
396
+ border: 1px solid transparent;
397
+ border-radius: 8px;
398
+ }
399
+
400
+ .pcsc-debug__stage[data-status="current"] {
401
+ background: var(--pcsc-raised);
402
+ border-color: var(--pcsc-border);
403
+ }
404
+
405
+ .pcsc-debug__stage-summary {
406
+ display: flex;
407
+ min-height: 40px;
408
+ align-items: center;
409
+ gap: 10px;
410
+ padding: 0 12px;
411
+ border-radius: 7px;
412
+ cursor: pointer;
413
+ user-select: none;
414
+ }
415
+
416
+ @media (hover: hover) and (pointer: fine) {
417
+ .pcsc-debug__stage-summary:hover,
418
+ .pcsc-debug__answer-summary:hover,
419
+ .pcsc-debug__raw > summary:hover {
420
+ background: var(--pcsc-hover);
421
+ }
422
+ }
423
+
424
+ .pcsc-debug__stage-title {
425
+ min-width: 0;
426
+ flex: 1 1 0;
427
+ overflow: hidden;
428
+ color: var(--pcsc-text-2);
429
+ font-size: 13px;
430
+ font-weight: 600;
431
+ letter-spacing: -.012em;
432
+ text-overflow: ellipsis;
433
+ white-space: nowrap;
434
+ }
435
+
436
+ .pcsc-debug__stage[data-status="current"] .pcsc-debug__stage-title {
437
+ color: var(--pcsc-text);
438
+ }
439
+
440
+ .pcsc-debug__stage-meta {
441
+ flex: 0 0 auto;
442
+ color: var(--pcsc-text-3);
443
+ font-size: 11px;
444
+ font-weight: 500;
445
+ white-space: nowrap;
446
+ }
447
+
448
+ .pcsc-debug__stage[data-status="current"] .pcsc-debug__stage-meta {
449
+ color: var(--pcsc-accent);
450
+ }
451
+
452
+ /* ---------- status marks ---------- */
453
+
454
+ .pcsc-debug__status-icon {
455
+ display: grid;
456
+ width: 16px;
457
+ height: 16px;
458
+ flex: 0 0 auto;
459
+ place-items: center;
460
+ color: var(--pcsc-text-3);
461
+ }
462
+
463
+ .pcsc-debug__status-icon .pcsc-debug__icon {
464
+ width: 13px;
465
+ height: 13px;
466
+ stroke-width: 2;
467
+ }
468
+
469
+ .pcsc-debug__status-icon[data-status="complete"],
470
+ .pcsc-debug__status-icon[data-status="answered"] {
471
+ color: var(--pcsc-ok);
472
+ }
473
+
474
+ .pcsc-debug__status-icon[data-status="current"],
475
+ .pcsc-debug__status-icon[data-status="asked"] {
476
+ color: var(--pcsc-accent);
477
+ }
478
+
479
+ .pcsc-debug__state-dot {
480
+ width: 6px;
481
+ height: 6px;
482
+ border-radius: 999px;
483
+ background: currentColor;
484
+ }
485
+
486
+ .pcsc-debug__status-icon[data-status="not-asked"] .pcsc-debug__state-dot {
487
+ background: transparent;
488
+ box-shadow: inset 0 0 0 1.5px currentColor;
489
+ }
490
+
491
+ .pcsc-debug__stage-number {
492
+ font-size: 10px;
493
+ font-weight: 600;
494
+ }
495
+
496
+ /* ---------- meter ---------- */
497
+
498
+ .pcsc-debug__meter {
499
+ display: flex;
500
+ height: 3px;
501
+ gap: 2px;
502
+ margin: 10px 12px;
503
+ }
504
+
505
+ .pcsc-debug__meter-segment {
506
+ min-width: 2px;
507
+ flex: 1;
508
+ background: var(--pcsc-border-strong);
509
+ border-radius: 999px;
510
+ }
511
+
512
+ .pcsc-debug__meter-segment[data-status="answered"] {
513
+ background: var(--pcsc-ok-muted);
514
+ }
515
+
516
+ .pcsc-debug__meter-segment[data-status="asked"] {
517
+ background: var(--pcsc-accent);
518
+ }
519
+
520
+ /* ---------- notice ---------- */
521
+
522
+ .pcsc-debug__notice {
523
+ display: flex;
524
+ align-items: center;
525
+ gap: 8px;
526
+ padding: 6px 10px;
527
+ margin: 0 12px 10px;
528
+ color: var(--pcsc-warn);
529
+ background: var(--pcsc-warn-soft);
530
+ border-radius: 6px;
531
+ font-size: 11px;
532
+ }
533
+
534
+ .pcsc-debug__notice-dot {
535
+ width: 5px;
536
+ height: 5px;
537
+ flex: 0 0 auto;
538
+ border-radius: 999px;
539
+ background: currentColor;
540
+ }
541
+
542
+ /* ---------- answers ---------- */
543
+
544
+ .pcsc-debug__answers {
545
+ border-top: 1px solid var(--pcsc-border);
546
+ }
547
+
548
+ .pcsc-debug__answer + .pcsc-debug__answer {
549
+ border-top: 1px solid var(--pcsc-border);
550
+ }
551
+
552
+ .pcsc-debug__answer-summary {
553
+ display: flex;
554
+ min-height: 34px;
555
+ align-items: center;
556
+ gap: 10px;
557
+ padding: 0 12px;
558
+ cursor: pointer;
559
+ user-select: none;
560
+ }
561
+
562
+ .pcsc-debug__answer-title {
563
+ min-width: 0;
564
+ flex: 1 1 0;
565
+ overflow: hidden;
566
+ color: var(--pcsc-text);
567
+ font-size: 12px;
568
+ font-weight: 500;
569
+ text-overflow: ellipsis;
570
+ white-space: nowrap;
571
+ }
572
+
573
+ .pcsc-debug__answer[data-status="not-asked"] .pcsc-debug__answer-title {
574
+ color: var(--pcsc-text-2);
575
+ }
576
+
577
+ .pcsc-debug__answer-preview {
578
+ max-width: 150px;
579
+ flex: 0 0 auto;
580
+ overflow: hidden;
581
+ color: var(--pcsc-text-2);
582
+ font: 400 11px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
583
+ text-align: right;
584
+ text-overflow: ellipsis;
585
+ white-space: nowrap;
586
+ }
587
+
588
+ .pcsc-debug__answer-preview[data-status="asked"] {
589
+ color: var(--pcsc-accent);
590
+ font-family: inherit;
591
+ font-size: 11px;
592
+ font-weight: 500;
593
+ }
594
+
595
+ .pcsc-debug__answer-preview[data-status="not-asked"] {
596
+ color: var(--pcsc-text-3);
597
+ }
598
+
599
+ .pcsc-debug__answer-body {
600
+ display: grid;
601
+ gap: 14px;
602
+ padding: 2px 12px 14px 38px;
603
+ color: var(--pcsc-text-2);
604
+ }
605
+
606
+ /* ---------- data ---------- */
607
+
608
+ .pcsc-debug__description,
609
+ .pcsc-debug__supporting-text,
610
+ .pcsc-debug__quote {
611
+ margin: 0;
612
+ }
613
+
614
+ .pcsc-debug__description {
615
+ color: var(--pcsc-text-2);
616
+ font-size: 12px;
617
+ }
618
+
619
+ .pcsc-debug__datum {
620
+ display: grid;
621
+ gap: 6px;
622
+ }
623
+
624
+ .pcsc-debug__datum-label {
625
+ color: var(--pcsc-text-3);
626
+ font-size: 10px;
627
+ font-weight: 600;
628
+ letter-spacing: .07em;
629
+ text-transform: uppercase;
630
+ }
631
+
632
+ .pcsc-debug__datum[data-highlighted="true"] .pcsc-debug__question-copy {
633
+ color: var(--pcsc-text);
634
+ background: var(--pcsc-accent-soft);
635
+ }
636
+
637
+ .pcsc-debug__value,
638
+ .pcsc-debug__quote,
639
+ .pcsc-debug__question-copy {
640
+ padding: 8px 10px;
641
+ color: var(--pcsc-text);
642
+ background: var(--pcsc-well);
643
+ border-radius: 6px;
644
+ overflow-wrap: anywhere;
645
+ }
646
+
647
+ .pcsc-debug__value {
648
+ max-height: 180px;
649
+ overflow: auto;
650
+ margin: 0;
651
+ white-space: pre-wrap;
652
+ font: 400 11px/1.6 ui-monospace, SFMono-Regular, Menlo, monospace;
653
+ }
654
+
655
+ .pcsc-debug__value--plain {
656
+ font: 500 12px/1.5 ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
657
+ }
658
+
659
+ .pcsc-debug__quote {
660
+ color: var(--pcsc-text-2);
661
+ font-size: 12px;
662
+ font-style: normal;
663
+ }
664
+
665
+ .pcsc-debug__question-copy {
666
+ margin: 0;
667
+ font-size: 12px;
668
+ }
669
+
670
+ .pcsc-debug__supporting-text {
671
+ color: var(--pcsc-text-3);
672
+ font-size: 11px;
673
+ }
674
+
675
+ .pcsc-debug__choices,
676
+ .pcsc-debug__actions-list {
677
+ display: flex;
678
+ flex-wrap: wrap;
679
+ gap: 4px;
680
+ padding: 0;
681
+ margin: 2px 0 0;
682
+ list-style: none;
683
+ }
684
+
685
+ .pcsc-debug__choice,
686
+ .pcsc-debug__action {
687
+ padding: 3px 8px;
688
+ color: var(--pcsc-text-2);
689
+ background: var(--pcsc-well);
690
+ border-radius: 999px;
691
+ font-size: 11px;
692
+ }
693
+
694
+ .pcsc-debug__rule {
695
+ display: flex;
696
+ align-items: baseline;
697
+ justify-content: space-between;
698
+ gap: 12px;
699
+ color: var(--pcsc-text-3);
700
+ font-size: 11px;
701
+ }
702
+
703
+ .pcsc-debug__rule code {
704
+ color: var(--pcsc-text-2);
705
+ font: 400 11px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
706
+ }
707
+
708
+ /* ---------- disclosure ---------- */
709
+
710
+ .pcsc-debug__chevron {
711
+ display: grid;
712
+ width: 12px;
713
+ height: 12px;
714
+ flex: 0 0 auto;
715
+ place-items: center;
716
+ color: var(--pcsc-text-3);
717
+ transform-origin: center;
718
+ transition: transform 160ms var(--pcsc-ease-out);
719
+ }
720
+
721
+ .pcsc-debug__chevron .pcsc-debug__icon {
722
+ width: 12px;
723
+ height: 12px;
724
+ }
725
+
726
+ .pcsc-debug__toggle-glyph {
727
+ display: grid;
728
+ width: 16px;
729
+ height: 16px;
730
+ place-items: center;
731
+ transform-origin: center;
732
+ }
733
+
734
+ .pcsc-debug details[open] > summary .pcsc-debug__chevron {
735
+ transform: rotate(180deg);
736
+ }
737
+
738
+ .pcsc-debug__stage-body {
739
+ padding-top: 2px;
740
+ border-top: 1px solid var(--pcsc-border);
741
+ }
742
+
743
+ .pcsc-debug__stage-content {
744
+ display: grid;
745
+ gap: 14px;
746
+ padding: 12px 12px 14px;
747
+ }
748
+
749
+ .pcsc-debug__definition {
750
+ border-top: 1px solid var(--pcsc-border);
751
+ }
752
+
753
+ .pcsc-debug__definition > summary {
754
+ display: flex;
755
+ min-height: 30px;
756
+ align-items: center;
757
+ justify-content: space-between;
758
+ gap: 8px;
759
+ color: var(--pcsc-text-3);
760
+ cursor: pointer;
761
+ font-size: 11px;
762
+ user-select: none;
763
+ }
764
+
765
+ @media (hover: hover) and (pointer: fine) {
766
+ .pcsc-debug__definition > summary:hover {
767
+ color: var(--pcsc-text-2);
768
+ }
769
+ }
770
+
771
+ .pcsc-debug__definition-body {
772
+ display: grid;
773
+ gap: 14px;
774
+ padding: 4px 0 4px;
775
+ }
776
+
777
+ .pcsc-debug__raw {
778
+ margin-top: 8px !important;
779
+ border-top: 1px solid var(--pcsc-border);
780
+ }
781
+
782
+ .pcsc-debug__raw > summary {
783
+ display: flex;
784
+ min-height: 36px;
785
+ align-items: center;
786
+ justify-content: space-between;
787
+ gap: 8px;
788
+ padding: 0 6px;
789
+ color: var(--pcsc-text-3);
790
+ border-radius: 6px;
791
+ cursor: pointer;
792
+ font-size: 11px;
793
+ user-select: none;
794
+ }
795
+
796
+ .pcsc-debug__json {
797
+ max-height: 240px;
798
+ overflow: auto;
799
+ padding: 10px;
800
+ margin: 0 0 8px;
801
+ color: var(--pcsc-text-2);
802
+ background: var(--pcsc-well);
803
+ border-radius: 6px;
804
+ white-space: pre-wrap;
805
+ overflow-wrap: anywhere;
806
+ font: 400 10px/1.6 ui-monospace, SFMono-Regular, Menlo, monospace;
807
+ }
808
+
809
+ /* ---------- footer / empty ---------- */
810
+
811
+ .pcsc-debug__footer {
812
+ min-height: 30px;
813
+ padding: 0 6px;
814
+ color: var(--pcsc-text-3);
815
+ font-size: 11px;
816
+ }
817
+
818
+ .pcsc-debug__copy-status {
819
+ min-width: 42px;
820
+ color: var(--pcsc-text-2);
821
+ text-align: right;
822
+ }
823
+
824
+ .pcsc-debug__empty {
825
+ display: grid;
826
+ min-height: 132px;
827
+ place-items: center;
828
+ align-content: center;
829
+ gap: 8px;
830
+ padding: 24px;
831
+ text-align: center;
832
+ }
833
+
834
+ .pcsc-debug__empty-mark {
835
+ display: grid;
836
+ width: 32px;
837
+ height: 32px;
838
+ place-items: center;
839
+ color: var(--pcsc-text-3);
840
+ background: var(--pcsc-well);
841
+ border-radius: 8px;
842
+ }
843
+
844
+ .pcsc-debug__empty strong {
845
+ color: var(--pcsc-text);
846
+ font-size: 12px;
847
+ font-weight: 600;
848
+ }
849
+
850
+ .pcsc-debug__empty span {
851
+ color: var(--pcsc-text-3);
852
+ font-size: 11px;
853
+ }
854
+
855
+ .pcsc-debug__sr-only {
856
+ position: absolute;
857
+ width: 1px;
858
+ height: 1px;
859
+ padding: 0;
860
+ overflow: hidden;
861
+ clip: rect(0, 0, 0, 0);
862
+ white-space: nowrap;
863
+ border: 0;
864
+ }
865
+
866
+ /* ---------- responsive ---------- */
867
+
868
+ @media (max-width: 480px) {
869
+ .pcsc-debug[data-open="true"] {
870
+ right: max(8px, env(safe-area-inset-right, 0px)) !important;
871
+ bottom: max(8px, env(safe-area-inset-bottom, 0px)) !important;
872
+ left: max(8px, env(safe-area-inset-left, 0px)) !important;
873
+ top: auto !important;
874
+ width: auto;
875
+ max-height: calc(100dvh - 16px);
876
+ }
877
+
878
+ .pcsc-debug[data-open="false"] {
879
+ right: max(8px, env(safe-area-inset-right, 0px)) !important;
880
+ bottom: max(8px, env(safe-area-inset-bottom, 0px)) !important;
881
+ left: auto !important;
882
+ top: auto !important;
883
+ }
884
+
885
+ .pcsc-debug__body {
886
+ max-height: calc(100dvh - 64px);
887
+ }
888
+
889
+ .pcsc-debug[data-open="true"] button {
890
+ width: 36px;
891
+ height: 36px;
892
+ }
893
+
894
+ .pcsc-debug__answer-summary,
895
+ .pcsc-debug__stage-summary {
896
+ min-height: 40px;
897
+ }
898
+ }
899
+
900
+ @media (prefers-reduced-motion: reduce) {
901
+ .pcsc-debug button:active:not(:disabled) {
902
+ transform: none;
903
+ }
904
+
905
+ .pcsc-debug__toggle .pcsc-debug__toggle-glyph,
906
+ .pcsc-debug__chevron {
907
+ transition: none;
908
+ }
909
+
910
+ .pcsc-debug__copy-glyph {
911
+ transform: none;
912
+ transition: opacity 100ms ease;
913
+ }
914
+ }
915
+ `;
916
+ const FlowIcon = ({ className = "pcsc-debug__icon" }) => (_jsxs("svg", { className: className, viewBox: "0 0 20 20", "aria-hidden": "true", children: [_jsx("path", { d: "M5 4.5h10M5 10h10M5 15.5h10" }), _jsx("circle", { cx: "7.5", cy: "4.5", r: "1.5" }), _jsx("circle", { cx: "12.5", cy: "10", r: "1.5" }), _jsx("circle", { cx: "9", cy: "15.5", r: "1.5" })] }));
917
+ const CopyIcon = ({ className = "pcsc-debug__icon" }) => (_jsxs("svg", { className: className, viewBox: "0 0 20 20", "aria-hidden": "true", children: [_jsx("rect", { x: "6.5", y: "6.5", width: "9", height: "9", rx: "2" }), _jsx("path", { d: "M13.5 6.5V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v6.5a2 2 0 0 0 2 2h1.5" })] }));
918
+ const CheckIcon = ({ className = "pcsc-debug__icon" }) => (_jsx("svg", { className: className, viewBox: "0 0 20 20", "aria-hidden": "true", children: _jsx("path", { d: "m5 10.5 3.1 3L15 6.8" }) }));
919
+ const ChevronIcon = ({ className = "pcsc-debug__chevron" }) => (_jsx("span", { className: className, "aria-hidden": "true", children: _jsx("svg", { className: "pcsc-debug__icon", viewBox: "0 0 20 20", children: _jsx("path", { d: "m6 8 4 4 4-4" }) }) }));
920
+ const humanizeIdentifier = (identifier) => identifier
921
+ .replace(/([a-z0-9])([A-Z])/gu, "$1 $2")
922
+ .split(/[\s_-]+/u)
923
+ .filter((part) => part.length > 0)
924
+ .map((part) => part.length <= 3
925
+ ? part.toUpperCase()
926
+ : `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`)
927
+ .join(" ");
928
+ const stageKindLabel = (stage) => {
929
+ switch (stage._tag) {
930
+ case "CollectStage":
931
+ return "Questions";
932
+ case "ToolStage":
933
+ return "Actions";
934
+ case "CommandStage":
935
+ return "Final Step";
936
+ }
937
+ };
938
+ const stageStatusLabel = (status) => {
939
+ switch (status) {
940
+ case "complete":
941
+ return "Complete";
942
+ case "current":
943
+ return "Current Step";
944
+ case "upcoming":
945
+ return "Upcoming";
946
+ }
947
+ };
948
+ const fieldStateName = (state) => {
949
+ switch (state._tag) {
950
+ case "Accepted":
951
+ return "answered";
952
+ case "Asked":
953
+ return "asked";
954
+ case "Missing":
955
+ return "not-asked";
956
+ }
957
+ };
958
+ const fieldStateLabel = (state) => {
959
+ switch (state._tag) {
960
+ case "Accepted":
961
+ return "Answered";
962
+ case "Asked":
963
+ return "Awaiting Answer";
964
+ case "Missing":
965
+ return "Not Asked";
966
+ }
967
+ };
968
+ const answerModeLabel = (mode) => {
969
+ switch (mode) {
970
+ case "semantic":
971
+ return "Natural language";
972
+ case "explicit":
973
+ return "Direct response";
974
+ case "confirmed":
975
+ return "Confirmation";
976
+ }
977
+ };
978
+ const StageStatusIcon = ({ stage }) => (_jsx("span", { className: "pcsc-debug__status-icon", "data-status": stage.status, "aria-hidden": "true", children: stage.status === "complete" ? (_jsx(CheckIcon, {})) : (_jsx("span", { className: "pcsc-debug__stage-number", children: stage.index + 1 })) }));
979
+ const FieldStatusIcon = ({ state }) => {
980
+ const stateName = fieldStateName(state);
981
+ return (_jsx("span", { className: "pcsc-debug__status-icon", "data-status": stateName, "aria-hidden": "true", children: stateName === "answered" ? (_jsx(CheckIcon, {})) : (_jsx("span", { className: "pcsc-debug__state-dot" })) }));
982
+ };
983
+ const ChoiceList = ({ choices }) => choices.length === 0 ? null : (_jsx("ul", { className: "pcsc-debug__choices", "aria-label": "Suggested choices", children: choices.map((choice) => (_jsx("li", { className: "pcsc-debug__choice", children: choice }, choice))) }));
984
+ const questionContent = (question) => {
985
+ switch (question._tag) {
986
+ case "FixedQuestion":
987
+ return _jsx("p", { className: "pcsc-debug__question-copy", children: question.text });
988
+ case "AdaptiveQuestion":
989
+ return (_jsxs(_Fragment, { children: [_jsx("p", { className: "pcsc-debug__question-copy", children: question.fallback }), _jsxs("p", { className: "pcsc-debug__supporting-text", children: ["Intent: ", question.goal] })] }));
990
+ case "AdaptiveChoiceQuestion":
991
+ return (_jsxs(_Fragment, { children: [_jsx("p", { className: "pcsc-debug__question-copy", children: question.prompt }), _jsxs("p", { className: "pcsc-debug__supporting-text", children: ["Suggests ", question.minimumOptions, "\u2013", question.maximumOptions, " choices"] }), _jsx(ChoiceList, { choices: question.fallbackOptions })] }));
992
+ case "ChoiceQuestion":
993
+ return (_jsxs(_Fragment, { children: [_jsx("p", { className: "pcsc-debug__question-copy", children: question.text }), _jsx(ChoiceList, { choices: question.options.map(({ label }) => label) })] }));
994
+ }
995
+ };
996
+ const QuestionDetails = ({ question }) => (_jsxs("section", { className: "pcsc-debug__datum", children: [_jsx("span", { className: "pcsc-debug__datum-label", children: "Planned Question" }), questionContent(question)] }));
997
+ const IssuedQuestionDetails = ({ issuedQuestion, highlighted = false, }) => (_jsxs("section", { className: "pcsc-debug__datum", "data-highlighted": highlighted, children: [_jsx("span", { className: "pcsc-debug__datum-label", children: "First Asked As" }), _jsx("p", { className: "pcsc-debug__question-copy", children: issuedQuestion.text }), _jsxs("p", { className: "pcsc-debug__supporting-text", children: ["First recorded in assistant message ", issuedQuestion.messageIndex + 1] })] }));
998
+ const EvidenceDetails = ({ evidence, }) => (_jsxs("section", { className: "pcsc-debug__datum", children: [_jsx("span", { className: "pcsc-debug__datum-label", children: "Based On" }), evidence === null ? (_jsx("p", { className: "pcsc-debug__supporting-text", children: "Source text is not included in this preview." })) : (_jsxs(_Fragment, { children: [_jsx("blockquote", { className: "pcsc-debug__quote", children: evidence.quote }), _jsxs("p", { className: "pcsc-debug__supporting-text", children: ["User message ", evidence.messageIndex + 1] })] }))] }));
999
+ const answerValuePreview = (value) => {
1000
+ if (value === "") {
1001
+ return "Empty";
1002
+ }
1003
+ if (value === true || value === false) {
1004
+ return value ? "Yes" : "No";
1005
+ }
1006
+ if (value === null) {
1007
+ return "Null";
1008
+ }
1009
+ if (Array.isArray(value)) {
1010
+ return `[${value.length}]`;
1011
+ }
1012
+ if (value instanceof Object) {
1013
+ return `{${Object.keys(value).length}}`;
1014
+ }
1015
+ return String(value);
1016
+ };
1017
+ /**
1018
+ * Summarize one field for the right-hand column of a collapsed row.
1019
+ *
1020
+ * The column is narrow, so it carries a scannable token rather than prose.
1021
+ * Full questions, values, and evidence stay in the expanded body.
1022
+ */
1023
+ const fieldPreview = (field) => {
1024
+ switch (field.state._tag) {
1025
+ case "Accepted":
1026
+ return answerValuePreview(field.state.value);
1027
+ case "Asked":
1028
+ return "Awaiting";
1029
+ case "Missing":
1030
+ return "\u2014";
1031
+ }
1032
+ };
1033
+ const AnswerValue = ({ value }) => {
1034
+ if (value instanceof Object) {
1035
+ return (_jsx("pre", { className: "pcsc-debug__value", translate: "no", children: JSON.stringify(value, null, 2) }));
1036
+ }
1037
+ if (value === "") {
1038
+ return (_jsx("p", { className: "pcsc-debug__value pcsc-debug__value--plain", children: "Empty answer" }));
1039
+ }
1040
+ if (value === true || value === false) {
1041
+ return (_jsx("p", { className: "pcsc-debug__value pcsc-debug__value--plain", children: value ? "Yes" : "No" }));
1042
+ }
1043
+ if (value === null) {
1044
+ return (_jsx("p", { className: "pcsc-debug__value pcsc-debug__value--plain", children: "Null" }));
1045
+ }
1046
+ return (_jsx("p", { className: "pcsc-debug__value pcsc-debug__value--plain", children: String(value) }));
1047
+ };
1048
+ const FieldStateDetails = ({ field, highlightIssuedQuestion, }) => {
1049
+ switch (field.state._tag) {
1050
+ case "Missing":
1051
+ return (_jsx("p", { className: "pcsc-debug__supporting-text", children: "This answer has not been requested yet." }));
1052
+ case "Asked":
1053
+ return (_jsx(IssuedQuestionDetails, { highlighted: highlightIssuedQuestion, issuedQuestion: field.state.issuedQuestion }));
1054
+ case "Accepted":
1055
+ return (_jsxs(_Fragment, { children: [_jsxs("section", { className: "pcsc-debug__datum", children: [_jsx("span", { className: "pcsc-debug__datum-label", children: "Answer" }), _jsx(AnswerValue, { value: field.state.value })] }), _jsx(EvidenceDetails, { evidence: field.state.evidence }), field.state.issuedQuestion === null ? null : (_jsx(IssuedQuestionDetails, { issuedQuestion: field.state.issuedQuestion }))] }));
1056
+ }
1057
+ };
1058
+ const AnswerDefinition = ({ field }) => (_jsxs("details", { className: "pcsc-debug__definition", children: [_jsxs("summary", { children: [_jsx("span", { children: "Definition" }), _jsx(ChevronIcon, {})] }), _jsxs("div", { className: "pcsc-debug__definition-body", children: [_jsxs("section", { className: "pcsc-debug__datum", children: [_jsx("span", { className: "pcsc-debug__datum-label", children: "Purpose" }), _jsx("p", { className: "pcsc-debug__description", children: field.description })] }), _jsx(QuestionDetails, { question: field.question }), _jsxs("div", { className: "pcsc-debug__rule", children: [_jsx("span", { children: "Schema Key" }), _jsx("code", { translate: "no", children: field.field })] }), _jsxs("div", { className: "pcsc-debug__rule", children: [_jsx("span", { children: "Answer Rule" }), _jsx("code", { children: answerModeLabel(field.mode) })] })] })] }));
1059
+ const AnswerDetails = ({ field, isFocusedAnswer, }) => {
1060
+ const stateName = fieldStateName(field.state);
1061
+ return (_jsxs("details", { className: "pcsc-debug__answer", "data-focused-answer": isFocusedAnswer ? "true" : undefined, "data-status": stateName, open: isFocusedAnswer, children: [_jsxs("summary", { className: "pcsc-debug__answer-summary", children: [_jsx(FieldStatusIcon, { state: field.state }), _jsxs("span", { className: "pcsc-debug__answer-title", children: [humanizeIdentifier(field.field), _jsx("span", { className: "pcsc-debug__sr-only", children: `, ${fieldStateLabel(field.state)}` })] }), _jsx("span", { className: "pcsc-debug__answer-preview", "data-status": stateName, children: fieldPreview(field) }), _jsx(ChevronIcon, {})] }), _jsxs("div", { className: "pcsc-debug__answer-body", children: [_jsx(FieldStateDetails, { field: field, highlightIssuedQuestion: isFocusedAnswer }), _jsx(AnswerDefinition, { field: field })] })] }));
1062
+ };
1063
+ /** Right-aligned stage metric: progress where it exists, otherwise the kind. */
1064
+ const stageMetaLabel = (stage) => stage._tag === "CollectStage"
1065
+ ? `${stage.satisfiedFields}/${stage.totalFields}`
1066
+ : stageKindLabel(stage);
1067
+ const StageSummary = ({ stage }) => (_jsxs("summary", { className: "pcsc-debug__stage-summary", children: [_jsx(StageStatusIcon, { stage: stage }), _jsxs("span", { className: "pcsc-debug__stage-title", children: [humanizeIdentifier(stage.name), _jsx("span", { className: "pcsc-debug__sr-only", children: `, ${stageKindLabel(stage)}, ${stageStatusLabel(stage.status)}` })] }), _jsx("span", { className: "pcsc-debug__stage-meta", children: stageMetaLabel(stage) }), _jsx(ChevronIcon, {})] }));
1068
+ const RepairNotice = ({ repairPending }) => repairPending ? (_jsxs("div", { className: "pcsc-debug__notice", children: [_jsx("span", { className: "pcsc-debug__notice-dot", "aria-hidden": "true" }), "This step needs review before continuing"] })) : null;
1069
+ const mostRecentlyFirstAskedField = (fields) => {
1070
+ let mostRecent = null;
1071
+ let mostRecentMessageIndex = -1;
1072
+ for (const field of fields) {
1073
+ if (field.state._tag === "Asked" &&
1074
+ field.state.issuedQuestion.messageIndex > mostRecentMessageIndex) {
1075
+ mostRecent = field;
1076
+ mostRecentMessageIndex = field.state.issuedQuestion.messageIndex;
1077
+ }
1078
+ }
1079
+ return mostRecent;
1080
+ };
1081
+ const CollectStageDetails = ({ stage }) => {
1082
+ const focusedAnswer = stage.status === "current"
1083
+ ? mostRecentlyFirstAskedField(stage.fields)
1084
+ : null;
1085
+ return (_jsxs("details", { className: "pcsc-debug__stage", "data-status": stage.status, "aria-current": stage.status === "current" ? "step" : undefined, open: stage.status === "current", children: [_jsx(StageSummary, { stage: stage }), _jsxs("div", { className: "pcsc-debug__stage-body", children: [_jsx("h3", { className: "pcsc-debug__sr-only", children: "Required Answers" }), _jsx("div", { className: "pcsc-debug__meter", role: "progressbar", "aria-label": `${stage.satisfiedFields} of ${stage.totalFields} answered`, "aria-valuemin": 0, "aria-valuemax": stage.totalFields, "aria-valuenow": stage.satisfiedFields, children: stage.fields.map((field) => (_jsx("span", { className: "pcsc-debug__meter-segment", "data-status": fieldStateName(field.state), "aria-hidden": "true" }, field.field))) }), _jsx(RepairNotice, { repairPending: stage.repairPending }), _jsx("div", { className: "pcsc-debug__answers", children: stage.fields.map((field) => (_jsx(AnswerDetails, { field: field, isFocusedAnswer: field === focusedAnswer }, field.field))) })] })] }));
1086
+ };
1087
+ const ToolStageDetails = ({ stage, }) => (_jsxs("details", { className: "pcsc-debug__stage", "data-status": stage.status, "aria-current": stage.status === "current" ? "step" : undefined, open: stage.status === "current", children: [_jsx(StageSummary, { stage: stage }), _jsxs("div", { className: "pcsc-debug__stage-body", children: [_jsx(RepairNotice, { repairPending: stage.repairPending }), _jsxs("div", { className: "pcsc-debug__stage-content", children: [_jsxs("section", { className: "pcsc-debug__datum", children: [_jsx("span", { className: "pcsc-debug__datum-label", children: "Available Actions" }), _jsx("ul", { className: "pcsc-debug__actions-list", children: stage.tools.map((tool) => (_jsx("li", { className: "pcsc-debug__action", children: humanizeIdentifier(tool) }, tool))) })] }), _jsx("p", { className: "pcsc-debug__supporting-text", children: stage.afterExecution === "stay"
1088
+ ? "This step stays open after each action."
1089
+ : "The conversation completes after this action runs." })] })] })] }));
1090
+ const CommandStageDetails = ({ stage, }) => (_jsxs("details", { className: "pcsc-debug__stage", "data-status": stage.status, "aria-current": stage.status === "current" ? "step" : undefined, open: stage.status === "current", children: [_jsx(StageSummary, { stage: stage }), _jsxs("div", { className: "pcsc-debug__stage-body", children: [_jsx(RepairNotice, { repairPending: stage.repairPending }), _jsx("div", { className: "pcsc-debug__stage-content", children: _jsxs("section", { className: "pcsc-debug__datum", children: [_jsx("span", { className: "pcsc-debug__datum-label", children: "Final Action" }), _jsx("p", { className: "pcsc-debug__question-copy", children: humanizeIdentifier(stage.command) })] }) })] })] }));
1091
+ const StageDetails = ({ stage }) => {
1092
+ switch (stage._tag) {
1093
+ case "CollectStage":
1094
+ return _jsx(CollectStageDetails, { stage: stage });
1095
+ case "ToolStage":
1096
+ return _jsx(ToolStageDetails, { stage: stage });
1097
+ case "CommandStage":
1098
+ return _jsx(CommandStageDetails, { stage: stage });
1099
+ }
1100
+ };
1101
+ const snapshotAnnouncement = (snapshot) => {
1102
+ if (snapshot === null) {
1103
+ return "Waiting for the first reply.";
1104
+ }
1105
+ const stage = snapshot.stages.find(({ index }) => index === snapshot.currentStage.index);
1106
+ const stageName = humanizeIdentifier(snapshot.currentStage.name);
1107
+ if (stage?._tag === "CollectStage") {
1108
+ return `${stageName} is current. ${stage.satisfiedFields} of ${stage.totalFields} required answers are answered.`;
1109
+ }
1110
+ return `${stageName} is the current step.`;
1111
+ };
1112
+ /** Render one fixed, accessible inspector for the latest debug snapshot. */
1113
+ export const StructuredChatDebugPanel = ({ store, position = "bottom-right", theme = "system", defaultOpen = true, }) => {
1114
+ const snapshot = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
1115
+ const [open, setOpen] = useState(defaultOpen);
1116
+ const [copyFeedback, setCopyFeedback] = useState({
1117
+ _tag: "Idle",
1118
+ });
1119
+ const contentId = useId();
1120
+ const rawJson = useMemo(() => (snapshot === null ? "" : JSON.stringify(snapshot, null, 2)), [snapshot]);
1121
+ const copyStatus = copyFeedback._tag === "Idle" || copyFeedback.json !== rawJson
1122
+ ? "idle"
1123
+ : copyFeedback._tag === "Copied"
1124
+ ? "copied"
1125
+ : "failed";
1126
+ useEffect(() => {
1127
+ if (copyStatus === "idle") {
1128
+ return;
1129
+ }
1130
+ const timeoutId = window.setTimeout(() => {
1131
+ setCopyFeedback({ _tag: "Idle" });
1132
+ }, 1600);
1133
+ return () => {
1134
+ window.clearTimeout(timeoutId);
1135
+ };
1136
+ }, [copyStatus]);
1137
+ const copyJson = async () => {
1138
+ const jsonToCopy = rawJson;
1139
+ try {
1140
+ if (navigator.clipboard === undefined) {
1141
+ setCopyFeedback({ _tag: "Failed", json: jsonToCopy });
1142
+ return;
1143
+ }
1144
+ await navigator.clipboard.writeText(jsonToCopy);
1145
+ setCopyFeedback({ _tag: "Copied", json: jsonToCopy });
1146
+ }
1147
+ catch {
1148
+ setCopyFeedback({ _tag: "Failed", json: jsonToCopy });
1149
+ }
1150
+ };
1151
+ return (_jsxs(_Fragment, { children: [_jsx("style", { children: panelCss }), _jsxs("aside", { className: "pcsc-debug", "data-open": open, "data-position": position, "data-theme": theme, "data-chat-status": snapshot?.status ?? "waiting", "aria-label": "Structured chat debug inspector", children: [_jsx("span", { className: "pcsc-debug__sr-only", role: "status", "aria-atomic": "true", children: snapshotAnnouncement(snapshot) }), _jsxs("header", { className: "pcsc-debug__header", children: [_jsx("span", { className: "pcsc-debug__mark", "aria-hidden": "true", children: _jsx(FlowIcon, {}) }), _jsxs("div", { className: "pcsc-debug__title", children: [_jsx("h2", { children: snapshot === null
1152
+ ? "Chat Flow"
1153
+ : humanizeIdentifier(snapshot.chat.name) }), _jsx("span", { children: snapshot === null ? ("Waiting for a reply") : (_jsxs(_Fragment, { children: [_jsx("span", { className: "pcsc-debug__status-dot", "aria-hidden": "true" }), snapshot.status === "complete" ? "Complete" : "In Progress", ` · Version ${snapshot.chat.version}`] })) })] }), _jsxs("div", { className: "pcsc-debug__actions", children: [_jsx("button", { className: "pcsc-debug__copy", type: "button", disabled: snapshot === null, onClick: () => {
1154
+ void copyJson();
1155
+ }, "aria-label": "Copy debug state as JSON", title: copyStatus === "copied" ? "Copied" : "Copy State", children: _jsx("span", { className: "pcsc-debug__copy-glyph", children: copyStatus === "copied" ? _jsx(CheckIcon, {}) : _jsx(CopyIcon, {}) }, copyStatus) }), _jsx("button", { className: "pcsc-debug__toggle", type: "button", onClick: () => {
1156
+ setOpen((current) => !current);
1157
+ }, "aria-expanded": open, "aria-controls": contentId, "aria-label": open ? "Collapse debug panel" : "Expand debug panel", children: open ? (_jsx(ChevronIcon, { className: "pcsc-debug__toggle-glyph pcsc-debug__toggle-chevron" })) : (_jsx(FlowIcon, {})) })] })] }), _jsxs("div", { id: contentId, className: "pcsc-debug__body", hidden: !open, children: [snapshot === null ? (_jsxs("div", { className: "pcsc-debug__empty", children: [_jsx("span", { className: "pcsc-debug__empty-mark", "aria-hidden": "true", children: _jsx(FlowIcon, {}) }), _jsx("strong", { children: "Ready for the first reply" }), _jsx("span", { children: "The conversation map will appear here." })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "pcsc-debug__flow-heading", children: [_jsx("span", { children: "Conversation Flow" }), _jsxs("span", { className: "pcsc-debug__step-count", children: ["Step ", snapshot.currentStage.index + 1, " of ", snapshot.stages.length] })] }), _jsx("div", { className: "pcsc-debug__stage-list", "aria-label": "Chat stages", children: snapshot.stages.map((stage) => (_jsx(StageDetails, { stage: stage }, `${stage.index}:${stage.name}`))) }), _jsxs("details", { className: "pcsc-debug__raw", children: [_jsxs("summary", { children: [_jsx("span", { children: "Raw State" }), _jsx(ChevronIcon, {})] }), _jsx("pre", { className: "pcsc-debug__json", translate: "no", children: rawJson })] })] })), _jsxs("footer", { className: "pcsc-debug__footer", children: [_jsx("span", { children: "Preview \u00B7 includes chat answers" }), _jsx("span", { className: "pcsc-debug__copy-status", role: "status", "aria-live": "polite", children: copyStatus === "copied"
1158
+ ? "Copied"
1159
+ : copyStatus === "failed"
1160
+ ? "Copy failed · use Raw State"
1161
+ : "" })] })] })] })] }));
1162
+ };