dsh-live-voice-debugger 0.4.1 → 0.5.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.
- package/ARCHITECTURE.md +1 -1
- package/lib/client.js +332 -53
- package/package.json +2 -2
package/ARCHITECTURE.md
CHANGED
|
@@ -4,6 +4,6 @@ This public, optional client plugin builds separately from Live Voice. It contri
|
|
|
4
4
|
|
|
5
5
|
The panel samples current state at a selectable 1, 2, 5, 10 or 20 Hz (default 10). State and event panes scroll independently. Event recording can be paused independently from live state sampling and the entire event history can be cleared. Resuming recording starts from the current baseline without replaying changes that occurred while paused. Changing the sampling rate preserves the history. While connected, coordinator notifications produce a bounded 200-entry state-difference history filterable by module. This is an initial inspector, not a complete semantic event logger: changes hidden inside an adapter can only be sampled, and native recognition internals remain unavailable. No audio is retained. Free-form text is hidden by default and can be inspected explicitly in memory, never persisted. Closing the panel releases subscriptions and timers.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
For normal use, install the prebuilt npm package with `npx dsh plugin add --profile web dsh-live-voice-debugger`. Generated `lib/` directories are ignored and never committed. For local development, build before linking: build from the repository root with `pnpm build`, or build this package with `pnpm --filter dsh-live-voice-debugger build`. The generated client/server entries land in lib, not in the main client bundle. For local installation, add the packages/live-voice-debugger directory as a separate DSH plugin using the supported plugin manager; both the main plugin's diagnostic bridge and this plugin must be loaded. Then open Settings → Live Voice → Developer and open the separate inspector window (allow site popups if blocked). Publication is explicit through the npm workflow. Configure npm Trusted Publishing for this package with workflow publish.yml and environment npm. Select the debugger-only target when the aligned main version already exists. Publishing both packages is sequential, not atomic.
|
|
8
8
|
|
|
9
9
|
Tests deliver simulated activity, processing and final results through the real coordinator callback boundary; PCM chunks are supplied through the HTTP adapter's fake Web Audio input. They assert the same diagnostic projection that the panel reads. The panel itself never injects test events into live capture or playback.
|
package/lib/client.js
CHANGED
|
@@ -34,17 +34,249 @@ __export(apply_exports, {
|
|
|
34
34
|
inject: () => inject
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(apply_exports);
|
|
37
|
+
var import_react22 = __toESM(require("react"), 1);
|
|
38
|
+
|
|
39
|
+
// ../live-voice/src/shared/design-system/buttons/IconButton.tsx
|
|
40
|
+
var import_react2 = __toESM(require("react"), 1);
|
|
41
|
+
|
|
42
|
+
// ../live-voice/src/shared/design-system/icons/Icon.tsx
|
|
43
|
+
var import_react = __toESM(require("react"), 1);
|
|
44
|
+
|
|
45
|
+
// ../live-voice/src/shared/design-system/icons/icons.ts
|
|
46
|
+
var iconPaths = {
|
|
47
|
+
conversation: "M4 3h16v13H8l-4 4V3M8 7h8M8 11h5",
|
|
48
|
+
keyboard: "M3 6h18v12H3V6M7 10h.01M11 10h.01M15 10h.01M18 10h.01M7 14h10",
|
|
49
|
+
headphones: "M3 14v-3a9 9 0 0 1 18 0v3M3 12h4v8H3v-8M17 12h4v8h-4v-8",
|
|
50
|
+
commands: "M3 6l2 2 3-4M11 6h10M3 14l2 2 3-4M11 14h10M11 20h10",
|
|
51
|
+
bug: "M8 8h8v9a4 4 0 0 1-8 0V8M9 8V6a3 3 0 0 1 6 0v2M3 9l5 2M16 11l5-2M3 16h5M16 16h5M5 22l3-3M16 19l3 3",
|
|
52
|
+
meeting: "M8 3a3 3 0 1 0 0 6 3 3 0 0 0 0-6M16 4a3 3 0 1 0 0 6 3 3 0 0 0 0-6M2 20v-3a6 6 0 0 1 12 0v3M16 13a5 5 0 0 1 6 5v2",
|
|
53
|
+
meetingOff: "M8 3a3 3 0 1 0 0 6 3 3 0 0 0 0-6M16 4a3 3 0 1 0 0 6 3 3 0 0 0 0-6M2 20v-3a6 6 0 0 1 12 0v3M17 16l5 5M22 16l-5 5",
|
|
54
|
+
mic: "M9 5a3 3 0 0 1 6 0v7a3 3 0 0 1-6 0V5M6 10v2a6 6 0 0 0 12 0v-2M12 18v4M8 22h8",
|
|
55
|
+
micOff: "M9 9v3a3 3 0 0 0 5.12 2.12M15 9V5a3 3 0 0 0-5.64-1.42M6 10v2a6 6 0 0 0 9.5 4.88M18 10v2a6 6 0 0 1-.5 2.4M12 18v4M8 22h8M3 3l18 18",
|
|
56
|
+
speaker: "M3 9h4l6-5v16l-6-5H3V9M17 8a6 6 0 0 1 0 8M20 5a10 10 0 0 1 0 14",
|
|
57
|
+
speakerOff: "M3 9h4l6-5v16l-6-5H3V9M17 9l5 6M22 9l-5 6",
|
|
58
|
+
pause: "M8 5v14M16 5v14",
|
|
59
|
+
play: "M7 4l13 8-13 8z",
|
|
60
|
+
stop: "M6 6h12v12H6z",
|
|
61
|
+
skipNext: "M5 5l10 7-10 7V5M19 5v14",
|
|
62
|
+
skipPrevious: "M19 5l-10 7 10 7V5M5 5v14",
|
|
63
|
+
send: "M3 11.5L21 3l-8.5 18-2-7.5L3 11.5zm7.5 2L21 3",
|
|
64
|
+
queue: "M5 6h14M5 12h10M5 18h6M18 15v6M15 18h6",
|
|
65
|
+
settings: "M4 7h16M4 17h16M8 4v6M16 14v6",
|
|
66
|
+
filter: "M3 5h18l-7 8v6l-4 2v-8L3 5z",
|
|
67
|
+
link: "M10 13a5 5 0 0 0 7.07 0l3-3a5 5 0 0 0-7.07-7.07l-1.7 1.7M14 11a5 5 0 0 0-7.07 0l-3 3a5 5 0 0 0 7.07 7.07l1.7-1.7",
|
|
68
|
+
chevron: "M6 9l6 6 6-6",
|
|
69
|
+
clock: "M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18M12 7v5l3 2",
|
|
70
|
+
close: "M6 6l12 12M18 6 6 18"
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// ../live-voice/src/shared/design-system/icons/Icon.tsx
|
|
74
|
+
function Icon({ name, className }) {
|
|
75
|
+
return /* @__PURE__ */ import_react.default.createElement(
|
|
76
|
+
"svg",
|
|
77
|
+
{
|
|
78
|
+
className,
|
|
79
|
+
viewBox: "0 0 24 24",
|
|
80
|
+
fill: "none",
|
|
81
|
+
stroke: "currentColor",
|
|
82
|
+
strokeWidth: 1.8,
|
|
83
|
+
strokeLinecap: "round",
|
|
84
|
+
strokeLinejoin: "round",
|
|
85
|
+
"aria-hidden": true
|
|
86
|
+
},
|
|
87
|
+
/* @__PURE__ */ import_react.default.createElement("path", { d: iconPaths[name] })
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ../live-voice/src/shared/design-system/buttons/PillButton.tsx
|
|
37
92
|
var import_react3 = __toESM(require("react"), 1);
|
|
93
|
+
|
|
94
|
+
// ../live-voice/src/shared/design-system/buttons/ToggleButton.tsx
|
|
95
|
+
var import_react4 = __toESM(require("react"), 1);
|
|
96
|
+
|
|
97
|
+
// ../live-voice/src/shared/design-system/feedback/ErrorMessage.tsx
|
|
98
|
+
var import_react5 = __toESM(require("react"), 1);
|
|
99
|
+
|
|
100
|
+
// ../live-voice/src/shared/design-system/feedback/StatusBadge.tsx
|
|
101
|
+
var import_react6 = __toESM(require("react"), 1);
|
|
102
|
+
|
|
103
|
+
// ../live-voice/src/shared/design-system/feedback/StatusMessage.tsx
|
|
104
|
+
var import_react7 = __toESM(require("react"), 1);
|
|
105
|
+
|
|
106
|
+
// ../live-voice/src/shared/design-system/feedback/Hint.tsx
|
|
107
|
+
var import_react8 = __toESM(require("react"), 1);
|
|
108
|
+
function Hint({
|
|
109
|
+
label,
|
|
110
|
+
children,
|
|
111
|
+
id: suppliedId
|
|
112
|
+
}) {
|
|
113
|
+
const generatedId = import_react8.default.useId();
|
|
114
|
+
const id = suppliedId || generatedId;
|
|
115
|
+
const [open, setOpen] = import_react8.default.useState(false);
|
|
116
|
+
const trigger = import_react8.default.useRef(null);
|
|
117
|
+
const bubble = import_react8.default.useRef(null);
|
|
118
|
+
const hovered = import_react8.default.useRef(false);
|
|
119
|
+
const focused = import_react8.default.useRef(false);
|
|
120
|
+
const timer = import_react8.default.useRef(void 0);
|
|
121
|
+
const cancel = () => clearTimeout(timer.current);
|
|
122
|
+
const closeLater = () => {
|
|
123
|
+
cancel();
|
|
124
|
+
timer.current = setTimeout(() => {
|
|
125
|
+
if (!hovered.current && !focused.current) setOpen(false);
|
|
126
|
+
}, 120);
|
|
127
|
+
};
|
|
128
|
+
import_react8.default.useEffect(() => () => clearTimeout(timer.current), []);
|
|
129
|
+
import_react8.default.useLayoutEffect(() => {
|
|
130
|
+
const node = bubble.current;
|
|
131
|
+
if (!open || !node || !trigger.current) return;
|
|
132
|
+
node.showPopover?.();
|
|
133
|
+
const position = () => {
|
|
134
|
+
const anchor = trigger.current.getBoundingClientRect();
|
|
135
|
+
const rect = node.getBoundingClientRect();
|
|
136
|
+
node.style.left = Math.max(12, Math.min(anchor.left, window.innerWidth - rect.width - 12)) + "px";
|
|
137
|
+
const below = anchor.bottom + 8;
|
|
138
|
+
node.style.top = Math.max(
|
|
139
|
+
12,
|
|
140
|
+
below + rect.height <= window.innerHeight - 12 ? below : anchor.top - rect.height - 8
|
|
141
|
+
) + "px";
|
|
142
|
+
};
|
|
143
|
+
position();
|
|
144
|
+
const dismiss = (e) => {
|
|
145
|
+
if (e.key === "Escape") {
|
|
146
|
+
e.stopPropagation();
|
|
147
|
+
setOpen(false);
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
const outside = (e) => {
|
|
151
|
+
if (!node.contains(e.target) && !trigger.current?.contains(e.target))
|
|
152
|
+
setOpen(false);
|
|
153
|
+
};
|
|
154
|
+
document.addEventListener("keydown", dismiss, true);
|
|
155
|
+
document.addEventListener("pointerdown", outside, true);
|
|
156
|
+
window.addEventListener("resize", position);
|
|
157
|
+
window.addEventListener("scroll", position, true);
|
|
158
|
+
return () => {
|
|
159
|
+
node.hidePopover?.();
|
|
160
|
+
document.removeEventListener("keydown", dismiss, true);
|
|
161
|
+
document.removeEventListener("pointerdown", outside, true);
|
|
162
|
+
window.removeEventListener("resize", position);
|
|
163
|
+
window.removeEventListener("scroll", position, true);
|
|
164
|
+
};
|
|
165
|
+
}, [open]);
|
|
166
|
+
return /* @__PURE__ */ import_react8.default.createElement(
|
|
167
|
+
"span",
|
|
168
|
+
{
|
|
169
|
+
className: "dlv-hint",
|
|
170
|
+
onMouseEnter: () => {
|
|
171
|
+
hovered.current = true;
|
|
172
|
+
cancel();
|
|
173
|
+
setOpen(true);
|
|
174
|
+
},
|
|
175
|
+
onMouseLeave: () => {
|
|
176
|
+
hovered.current = false;
|
|
177
|
+
closeLater();
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
/* @__PURE__ */ import_react8.default.createElement(
|
|
181
|
+
"button",
|
|
182
|
+
{
|
|
183
|
+
ref: trigger,
|
|
184
|
+
type: "button",
|
|
185
|
+
className: "dlv-hint-trigger",
|
|
186
|
+
"aria-label": label,
|
|
187
|
+
"aria-describedby": open ? id : void 0,
|
|
188
|
+
"aria-expanded": open,
|
|
189
|
+
onFocus: () => {
|
|
190
|
+
focused.current = true;
|
|
191
|
+
cancel();
|
|
192
|
+
setOpen(true);
|
|
193
|
+
},
|
|
194
|
+
onBlur: () => {
|
|
195
|
+
focused.current = false;
|
|
196
|
+
closeLater();
|
|
197
|
+
},
|
|
198
|
+
onClick: () => setOpen(true)
|
|
199
|
+
},
|
|
200
|
+
"?"
|
|
201
|
+
),
|
|
202
|
+
/* @__PURE__ */ import_react8.default.createElement(
|
|
203
|
+
"span",
|
|
204
|
+
{
|
|
205
|
+
ref: bubble,
|
|
206
|
+
id,
|
|
207
|
+
role: "tooltip",
|
|
208
|
+
popover: "manual",
|
|
209
|
+
hidden: !open,
|
|
210
|
+
className: "dlv-hint-bubble"
|
|
211
|
+
},
|
|
212
|
+
children
|
|
213
|
+
)
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// ../live-voice/src/shared/design-system/forms/CheckboxField.tsx
|
|
218
|
+
var import_react9 = __toESM(require("react"), 1);
|
|
219
|
+
|
|
220
|
+
// ../live-voice/src/shared/design-system/forms/NumberField.tsx
|
|
221
|
+
var import_react11 = __toESM(require("react"), 1);
|
|
222
|
+
|
|
223
|
+
// ../live-voice/src/shared/design-system/forms/DraftField.tsx
|
|
224
|
+
var import_react10 = __toESM(require("react"), 1);
|
|
225
|
+
|
|
226
|
+
// ../live-voice/src/shared/design-system/forms/SelectField.tsx
|
|
227
|
+
var import_react12 = __toESM(require("react"), 1);
|
|
228
|
+
|
|
229
|
+
// ../live-voice/src/shared/design-system/forms/TextAreaField.tsx
|
|
230
|
+
var import_react13 = __toESM(require("react"), 1);
|
|
231
|
+
|
|
232
|
+
// ../live-voice/src/shared/design-system/forms/TextField.tsx
|
|
233
|
+
var import_react14 = __toESM(require("react"), 1);
|
|
234
|
+
|
|
235
|
+
// ../live-voice/src/shared/design-system/layout/SettingsCard.tsx
|
|
236
|
+
var import_react15 = __toESM(require("react"), 1);
|
|
237
|
+
|
|
238
|
+
// ../live-voice/src/shared/design-system/layout/SettingsSection.tsx
|
|
239
|
+
var import_react17 = __toESM(require("react"), 1);
|
|
240
|
+
|
|
241
|
+
// ../live-voice/src/shared/design-system/layout/SettingsSectionBody.tsx
|
|
242
|
+
var import_react16 = __toESM(require("react"), 1);
|
|
243
|
+
|
|
244
|
+
// ../live-voice/src/shared/design-system/layout/SettingsSubcard.tsx
|
|
245
|
+
var import_react18 = __toESM(require("react"), 1);
|
|
246
|
+
|
|
247
|
+
// ../live-voice/src/shared/design-system/layout/SettingsTabs.tsx
|
|
248
|
+
var import_react19 = __toESM(require("react"), 1);
|
|
249
|
+
|
|
250
|
+
// src/apply.tsx
|
|
38
251
|
var import_client = require("react-dom/client");
|
|
39
252
|
|
|
40
253
|
// src/DebuggerPanel.tsx
|
|
41
|
-
var
|
|
254
|
+
var import_react21 = __toESM(require("react"), 1);
|
|
42
255
|
|
|
43
256
|
// ../live-voice/src/modules/core/diagnostics.ts
|
|
44
257
|
var DIAGNOSTIC_KEY = /* @__PURE__ */ Symbol.for("dsh-live-voice.diagnostics.v1");
|
|
45
258
|
var DIAGNOSTIC_CHANGED = "dsh-live-voice:diagnostics-changed";
|
|
46
259
|
|
|
47
260
|
// src/inspector.ts
|
|
261
|
+
function semantic(module2, value) {
|
|
262
|
+
if (value == null) return null;
|
|
263
|
+
if (module2 === "vadRuntime")
|
|
264
|
+
return {
|
|
265
|
+
status: value.status ?? null,
|
|
266
|
+
workerActive: value.workerActive ?? null,
|
|
267
|
+
activeSources: value.activeSources ?? null,
|
|
268
|
+
assets: value.assets ?? null
|
|
269
|
+
};
|
|
270
|
+
const omitted = {
|
|
271
|
+
capture: ["level"],
|
|
272
|
+
vad: ["probability", "silenceMs"],
|
|
273
|
+
chunker: ["bufferedSamples", "bufferedChunks", "silenceSamples", "durationMs"]
|
|
274
|
+
};
|
|
275
|
+
if (!omitted[module2]) return value;
|
|
276
|
+
const result = { ...value };
|
|
277
|
+
for (const key of omitted[module2]) delete result[key];
|
|
278
|
+
return result;
|
|
279
|
+
}
|
|
48
280
|
function createInspector(source, now = Date.now, limit = 200) {
|
|
49
281
|
let previous = null;
|
|
50
282
|
let sequence = 0;
|
|
@@ -56,22 +288,56 @@ function createInspector(source, now = Date.now, limit = 200) {
|
|
|
56
288
|
previous = next;
|
|
57
289
|
return;
|
|
58
290
|
}
|
|
291
|
+
const append = (sessionId, module2, before, after) => {
|
|
292
|
+
if (!previous || JSON.stringify(before) === JSON.stringify(after)) return;
|
|
293
|
+
entries.push({
|
|
294
|
+
sequence: ++sequence,
|
|
295
|
+
timeMs: now(),
|
|
296
|
+
sessionId,
|
|
297
|
+
module: module2,
|
|
298
|
+
level: module2.endsWith("error") && after?.present ? "error" : "debug",
|
|
299
|
+
before,
|
|
300
|
+
after
|
|
301
|
+
});
|
|
302
|
+
};
|
|
303
|
+
append(
|
|
304
|
+
null,
|
|
305
|
+
"vadRuntime",
|
|
306
|
+
semantic("vadRuntime", previous?.vadRuntime),
|
|
307
|
+
semantic("vadRuntime", next?.vadRuntime)
|
|
308
|
+
);
|
|
309
|
+
for (const sourceId of /* @__PURE__ */ new Set([
|
|
310
|
+
...Object.keys(previous?.audioSources ?? {}),
|
|
311
|
+
...Object.keys(next?.audioSources ?? {})
|
|
312
|
+
])) {
|
|
313
|
+
const old = previous?.audioSources?.[sourceId];
|
|
314
|
+
const current = next?.audioSources?.[sourceId];
|
|
315
|
+
if (sourceId === "vad") {
|
|
316
|
+
append(
|
|
317
|
+
null,
|
|
318
|
+
"audioSources.vad",
|
|
319
|
+
semantic("vadRuntime", old),
|
|
320
|
+
semantic("vadRuntime", current)
|
|
321
|
+
);
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
for (const module2 of /* @__PURE__ */ new Set([...Object.keys(old ?? {}), ...Object.keys(current ?? {})])) {
|
|
325
|
+
append(
|
|
326
|
+
null,
|
|
327
|
+
"audioSources." + sourceId + "." + module2,
|
|
328
|
+
semantic(module2, old?.[module2]),
|
|
329
|
+
semantic(module2, current?.[module2])
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
59
333
|
for (const [sessionId, session] of Object.entries(next?.sessions ?? {})) {
|
|
60
334
|
for (const [module2, value] of Object.entries(session)) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
timeMs: now(),
|
|
68
|
-
sessionId,
|
|
69
|
-
module: module2,
|
|
70
|
-
level: module2 === "error" && value?.present ? "error" : "debug",
|
|
71
|
-
before: before ?? null,
|
|
72
|
-
after: normalized
|
|
73
|
-
});
|
|
74
|
-
}
|
|
335
|
+
append(
|
|
336
|
+
sessionId,
|
|
337
|
+
module2,
|
|
338
|
+
semantic(module2, previous?.sessions?.[sessionId]?.[module2]),
|
|
339
|
+
semantic(module2, value)
|
|
340
|
+
);
|
|
75
341
|
}
|
|
76
342
|
}
|
|
77
343
|
entries = entries.slice(-Math.max(1, limit));
|
|
@@ -106,7 +372,7 @@ function createInspector(source, now = Date.now, limit = 200) {
|
|
|
106
372
|
}
|
|
107
373
|
|
|
108
374
|
// src/StateTree.tsx
|
|
109
|
-
var
|
|
375
|
+
var import_react20 = __toESM(require("react"), 1);
|
|
110
376
|
function StateTree({
|
|
111
377
|
name,
|
|
112
378
|
value,
|
|
@@ -114,9 +380,9 @@ function StateTree({
|
|
|
114
380
|
depth = 0
|
|
115
381
|
}) {
|
|
116
382
|
if (value === null || typeof value !== "object")
|
|
117
|
-
return /* @__PURE__ */
|
|
383
|
+
return /* @__PURE__ */ import_react20.default.createElement("div", { className: "dlvd-leaf" }, /* @__PURE__ */ import_react20.default.createElement("code", null, name), /* @__PURE__ */ import_react20.default.createElement("span", { "data-kind": typeof value }, String(value)));
|
|
118
384
|
const entries = Object.entries(value);
|
|
119
|
-
return /* @__PURE__ */
|
|
385
|
+
return /* @__PURE__ */ import_react20.default.createElement("details", { className: "dlvd-branch", open: depth < 3 }, /* @__PURE__ */ import_react20.default.createElement("summary", null, /* @__PURE__ */ import_react20.default.createElement("code", null, name), /* @__PURE__ */ import_react20.default.createElement("small", null, Array.isArray(value) ? "[" + entries.length + "]" : "{" + entries.length + "}")), entries.slice(0, 100).map(([key, child]) => /* @__PURE__ */ import_react20.default.createElement(StateTree, { key, name: key, value: child, omitted, depth: depth + 1 })), entries.length > 100 && /* @__PURE__ */ import_react20.default.createElement("p", null, omitted));
|
|
120
386
|
}
|
|
121
387
|
|
|
122
388
|
// src/DebuggerPanel.tsx
|
|
@@ -125,17 +391,17 @@ function DebuggerPanel({
|
|
|
125
391
|
onClose,
|
|
126
392
|
target = window
|
|
127
393
|
}) {
|
|
128
|
-
const [frozen, setFrozen] =
|
|
129
|
-
const [refreshHz, setRefreshHz] =
|
|
130
|
-
const updateRef =
|
|
131
|
-
const [content, setContent] =
|
|
132
|
-
const [module2, setModule] =
|
|
133
|
-
const [view, setView] =
|
|
134
|
-
const [failed, setFailed] =
|
|
135
|
-
const [eventsPaused, setEventsPaused] =
|
|
136
|
-
const pausedRef =
|
|
137
|
-
const inspectorRef =
|
|
138
|
-
|
|
394
|
+
const [frozen, setFrozen] = import_react21.default.useState(false);
|
|
395
|
+
const [refreshHz, setRefreshHz] = import_react21.default.useState(10);
|
|
396
|
+
const updateRef = import_react21.default.useRef(null);
|
|
397
|
+
const [content, setContent] = import_react21.default.useState(false);
|
|
398
|
+
const [module2, setModule] = import_react21.default.useState("");
|
|
399
|
+
const [view, setView] = import_react21.default.useState(null);
|
|
400
|
+
const [failed, setFailed] = import_react21.default.useState(false);
|
|
401
|
+
const [eventsPaused, setEventsPaused] = import_react21.default.useState(false);
|
|
402
|
+
const pausedRef = import_react21.default.useRef(false);
|
|
403
|
+
const inspectorRef = import_react21.default.useRef(null);
|
|
404
|
+
import_react21.default.useEffect(() => {
|
|
139
405
|
if (frozen) return;
|
|
140
406
|
let inspector = null;
|
|
141
407
|
let source = null;
|
|
@@ -168,13 +434,13 @@ function DebuggerPanel({
|
|
|
168
434
|
inspectorRef.current = null;
|
|
169
435
|
};
|
|
170
436
|
}, [frozen, content, target]);
|
|
171
|
-
|
|
437
|
+
import_react21.default.useEffect(() => {
|
|
172
438
|
if (frozen) return;
|
|
173
439
|
const timer = setInterval(() => updateRef.current?.(), 1e3 / refreshHz);
|
|
174
440
|
return () => clearInterval(timer);
|
|
175
441
|
}, [frozen, refreshHz]);
|
|
176
442
|
const modules = [...new Set(view?.transitions.map((entry) => entry.module) ?? [])].sort();
|
|
177
|
-
return /* @__PURE__ */
|
|
443
|
+
return /* @__PURE__ */ import_react21.default.createElement("aside", { className: "dlvd-panel", "aria-label": copy.title }, /* @__PURE__ */ import_react21.default.createElement("header", null, /* @__PURE__ */ import_react21.default.createElement("strong", null, copy.title), /* @__PURE__ */ import_react21.default.createElement("span", null, refreshHz, " Hz"), /* @__PURE__ */ import_react21.default.createElement("button", { type: "button", onClick: onClose, "aria-label": copy.close }, "\xD7")), /* @__PURE__ */ import_react21.default.createElement("p", null, copy.help), /* @__PURE__ */ import_react21.default.createElement("div", { className: "dlvd-toolbar" }, /* @__PURE__ */ import_react21.default.createElement("label", null, copy.refreshRate, /* @__PURE__ */ import_react21.default.createElement("select", { value: refreshHz, onChange: (event) => setRefreshHz(Number(event.target.value)) }, [1, 2, 5, 10, 20].map((hz) => /* @__PURE__ */ import_react21.default.createElement("option", { key: hz, value: hz }, hz, " Hz")))), /* @__PURE__ */ import_react21.default.createElement("button", { type: "button", onClick: () => setFrozen(!frozen) }, frozen ? copy.resume : copy.freeze), /* @__PURE__ */ import_react21.default.createElement("label", null, /* @__PURE__ */ import_react21.default.createElement(
|
|
178
444
|
"input",
|
|
179
445
|
{
|
|
180
446
|
type: "checkbox",
|
|
@@ -185,7 +451,7 @@ function DebuggerPanel({
|
|
|
185
451
|
setContent(event.target.checked);
|
|
186
452
|
}
|
|
187
453
|
}
|
|
188
|
-
), copy.content)), failed ? /* @__PURE__ */
|
|
454
|
+
), copy.content)), failed ? /* @__PURE__ */ import_react21.default.createElement("p", { role: "alert" }, copy.error) : !view ? /* @__PURE__ */ import_react21.default.createElement("p", { role: "status" }, copy.waiting) : /* @__PURE__ */ import_react21.default.createElement("div", { className: "dlvd-columns" }, /* @__PURE__ */ import_react21.default.createElement("section", { className: "dlvd-state-pane", "aria-label": copy.states }, /* @__PURE__ */ import_react21.default.createElement("h3", null, copy.states), /* @__PURE__ */ import_react21.default.createElement("div", { className: "dlvd-scroll", tabIndex: 0 }, /* @__PURE__ */ import_react21.default.createElement(StateTree, { name: "context", value: view.state, omitted: copy.omitted }))), /* @__PURE__ */ import_react21.default.createElement("section", { className: "dlvd-event-pane", "aria-label": copy.transitions }, /* @__PURE__ */ import_react21.default.createElement("h3", null, copy.transitions), /* @__PURE__ */ import_react21.default.createElement("div", { className: "dlvd-toolbar" }, /* @__PURE__ */ import_react21.default.createElement(
|
|
189
455
|
"button",
|
|
190
456
|
{
|
|
191
457
|
type: "button",
|
|
@@ -198,7 +464,7 @@ function DebuggerPanel({
|
|
|
198
464
|
}
|
|
199
465
|
},
|
|
200
466
|
eventsPaused ? copy.eventsResume : copy.eventsPause
|
|
201
|
-
), /* @__PURE__ */
|
|
467
|
+
), /* @__PURE__ */ import_react21.default.createElement(
|
|
202
468
|
"button",
|
|
203
469
|
{
|
|
204
470
|
type: "button",
|
|
@@ -208,7 +474,7 @@ function DebuggerPanel({
|
|
|
208
474
|
}
|
|
209
475
|
},
|
|
210
476
|
copy.eventsClear
|
|
211
|
-
)), /* @__PURE__ */
|
|
477
|
+
)), /* @__PURE__ */ import_react21.default.createElement("label", null, copy.filter, /* @__PURE__ */ import_react21.default.createElement("select", { value: module2, onChange: (event) => setModule(event.target.value) }, /* @__PURE__ */ import_react21.default.createElement("option", { value: "" }, copy.all), modules.map((name) => /* @__PURE__ */ import_react21.default.createElement("option", { key: name }, name)))), /* @__PURE__ */ import_react21.default.createElement("div", { className: "dlvd-history dlvd-scroll", tabIndex: 0 }, view.transitions.filter((entry) => !module2 || entry.module === module2).slice().reverse().map((entry) => /* @__PURE__ */ import_react21.default.createElement("details", { key: entry.sequence, "data-level": entry.level }, /* @__PURE__ */ import_react21.default.createElement("summary", null, /* @__PURE__ */ import_react21.default.createElement("small", null, new Date(entry.timeMs).toLocaleTimeString()), " ", /* @__PURE__ */ import_react21.default.createElement("code", null, entry.sessionId, " / ", entry.module)), /* @__PURE__ */ import_react21.default.createElement(StateTree, { name: "before", value: entry.before, omitted: copy.omitted }), /* @__PURE__ */ import_react21.default.createElement(StateTree, { name: "after", value: entry.after, omitted: copy.omitted }))), !view.transitions.length && /* @__PURE__ */ import_react21.default.createElement("p", null, copy.empty)))));
|
|
212
478
|
}
|
|
213
479
|
|
|
214
480
|
// src/locales.ts
|
|
@@ -220,6 +486,7 @@ var dictionaries = {
|
|
|
220
486
|
close: "Close debugger",
|
|
221
487
|
content: "Inspect text content (sensitive)",
|
|
222
488
|
developer: "Developer",
|
|
489
|
+
diagnostics: "Diagnostics",
|
|
223
490
|
empty: "No transitions recorded yet.",
|
|
224
491
|
error: "Diagnostic source failed.",
|
|
225
492
|
eventsClear: "Clear events",
|
|
@@ -243,6 +510,7 @@ var dictionaries = {
|
|
|
243
510
|
close: "Fechar debugger",
|
|
244
511
|
content: "Inspecionar conte\xFAdo de texto (sens\xEDvel)",
|
|
245
512
|
developer: "Desenvolvedor",
|
|
513
|
+
diagnostics: "Diagn\xF3stico",
|
|
246
514
|
empty: "Nenhuma transi\xE7\xE3o registrada ainda.",
|
|
247
515
|
error: "A fonte de diagn\xF3stico falhou.",
|
|
248
516
|
eventsClear: "Limpar eventos",
|
|
@@ -266,6 +534,7 @@ var dictionaries = {
|
|
|
266
534
|
close: "Cerrar depurador",
|
|
267
535
|
content: "Inspeccionar contenido de texto (sensible)",
|
|
268
536
|
developer: "Desarrollador",
|
|
537
|
+
diagnostics: "Diagn\xF3stico",
|
|
269
538
|
empty: "Todav\xEDa no hay transiciones registradas.",
|
|
270
539
|
error: "La fuente de diagn\xF3stico fall\xF3.",
|
|
271
540
|
eventsClear: "Borrar eventos",
|
|
@@ -289,6 +558,7 @@ var dictionaries = {
|
|
|
289
558
|
close: "Fermer le d\xE9bogueur",
|
|
290
559
|
content: "Inspecter le texte (sensible)",
|
|
291
560
|
developer: "D\xE9veloppeur",
|
|
561
|
+
diagnostics: "Diagnostic",
|
|
292
562
|
empty: "Aucune transition enregistr\xE9e.",
|
|
293
563
|
error: "La source de diagnostic a \xE9chou\xE9.",
|
|
294
564
|
eventsClear: "Effacer les \xE9v\xE9nements",
|
|
@@ -312,6 +582,7 @@ var dictionaries = {
|
|
|
312
582
|
close: "\u0921\u0940\u092C\u0917\u0930 \u092C\u0902\u0926 \u0915\u0930\u0947\u0902",
|
|
313
583
|
content: "\u091F\u0947\u0915\u094D\u0938\u094D\u091F \u0938\u093E\u092E\u0917\u094D\u0930\u0940 \u0926\u0947\u0916\u0947\u0902 (\u0938\u0902\u0935\u0947\u0926\u0928\u0936\u0940\u0932)",
|
|
314
584
|
developer: "\u0921\u0947\u0935\u0932\u092A\u0930",
|
|
585
|
+
diagnostics: "\u0928\u093F\u0926\u093E\u0928",
|
|
315
586
|
empty: "\u0905\u092D\u0940 \u0915\u094B\u0908 \u091F\u094D\u0930\u093E\u0902\u091C\u093C\u093F\u0936\u0928 \u0926\u0930\u094D\u091C \u0928\u0939\u0940\u0902 \u0939\u0948\u0964",
|
|
316
587
|
error: "\u0921\u093E\u092F\u0917\u094D\u0928\u094B\u0938\u094D\u091F\u093F\u0915 \u0938\u094D\u0930\u094B\u0924 \u0935\u093F\u092B\u0932 \u0939\u0941\u0906\u0964",
|
|
317
588
|
eventsClear: "\u0907\u0935\u0947\u0902\u091F \u0938\u093E\u092B\u093C \u0915\u0930\u0947\u0902",
|
|
@@ -335,6 +606,7 @@ var dictionaries = {
|
|
|
335
606
|
close: "\u5173\u95ED\u8C03\u8BD5\u5668",
|
|
336
607
|
content: "\u67E5\u770B\u6587\u672C\u5185\u5BB9\uFF08\u654F\u611F\uFF09",
|
|
337
608
|
developer: "\u5F00\u53D1\u8005",
|
|
609
|
+
diagnostics: "\u8BCA\u65AD",
|
|
338
610
|
empty: "\u5C1A\u672A\u8BB0\u5F55\u72B6\u6001\u8F6C\u6362\u3002",
|
|
339
611
|
error: "\u8BCA\u65AD\u6570\u636E\u6E90\u5931\u8D25\u3002",
|
|
340
612
|
eventsClear: "\u6E05\u9664\u4E8B\u4EF6",
|
|
@@ -356,13 +628,26 @@ var dictionaries = {
|
|
|
356
628
|
|
|
357
629
|
// src/styles.ts
|
|
358
630
|
var styles = `
|
|
359
|
-
.dlvd-columns{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:16px;flex:1;min-height:0;overflow:hidden}.dlvd-state-pane,.dlvd-event-pane{display:flex;flex-direction:column;min-width:0;min-height:0;overflow:hidden}.dlvd-event-pane{border-left:1px solid #
|
|
631
|
+
.dlvd-columns{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:16px;flex:1;min-height:0;overflow:hidden}.dlvd-state-pane,.dlvd-event-pane{display:flex;flex-direction:column;min-width:0;min-height:0;overflow:hidden}.dlvd-event-pane{border-left:1px solid var(--dsw-alias-border-l1, #ffffff0f);padding-left:16px}.dlvd-columns h3{margin:0 0 10px}.dlvd-scroll{flex:1;min-height:0;overflow:auto;overscroll-behavior:contain;scrollbar-gutter:stable;padding-right:8px}.dlvd-scroll:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary, #7aaaff);outline-offset:-2px}.dlvd-history summary{overflow-wrap:anywhere}.dlvd-panel>header,.dlvd-panel>p,.dlvd-panel>.dlvd-toolbar{flex-shrink:0}
|
|
360
632
|
|
|
361
|
-
.dlvd-window{margin:0;background
|
|
362
|
-
.dlvd-panel{position:fixed;right:16px;top:16px;width:min(520px,calc(100vw - 32px));height:80vh;max-height:80vh;overflow:hidden;display:flex;flex-direction:column;z-index:1000;padding:16px;border:1px solid #
|
|
363
|
-
.dlvd-panel header{display:flex;align-items:center;gap:12px;position:sticky;top:-16px;background
|
|
633
|
+
.dlvd-window{margin:0;background:var(--dsw-alias-bg-base, #151517);color:var(--dsw-alias-label-primary, #f9fafb);color-scheme:var(--dlvd-color-scheme, dark)}.dlvd-window .dlvd-panel{position:static;width:100%;height:100dvh;max-height:none;min-width:0;resize:none;border:0;border-radius:0;box-shadow:none}
|
|
634
|
+
.dlvd-panel{position:fixed;right:16px;top:16px;width:min(520px,calc(100vw - 32px));height:80vh;max-height:80vh;overflow:hidden;display:flex;flex-direction:column;z-index:1000;padding:16px;border:1px solid var(--dsw-alias-border-l2, #ffffff1f);border-radius:14px;background:var(--dsw-alias-bg-base, #151517);color:var(--dsw-alias-label-primary, #f9fafb);box-shadow:0 12px 40px #0008;font:13px/1.6 system-ui;resize:both;min-width:280px;box-sizing:border-box;color-scheme:var(--dlvd-color-scheme, dark)}
|
|
635
|
+
.dlvd-panel header{display:flex;align-items:center;gap:12px;position:sticky;top:-16px;background:var(--dsw-alias-bg-base, #151517);padding:8px 0;z-index:1}.dlvd-panel header strong{flex:1}.dlvd-panel button,.dlvd-panel select{background:var(--dsw-alias-bg-layer-1, #232324);color:var(--dsw-alias-label-primary, #f9fafb);border:1px solid var(--dsw-alias-border-l2, #ffffff1f);border-radius:6px;padding:5px 9px;cursor:pointer}.dlvd-panel button:focus-visible,.dlvd-panel summary:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary, #7aaaff)}.dlvd-toolbar{display:flex;gap:12px;align-items:center;flex-wrap:wrap;margin-bottom:12px}.dlvd-panel p{color:var(--dsw-alias-label-tertiary, #adb2b8)}.dlvd-branch{margin-left:10px;border-left:1px solid var(--dsw-alias-border-l1, #ffffff0f);padding-left:9px}.dlvd-branch summary{cursor:pointer;padding:3px 0}.dlvd-panel small{color:var(--dsw-alias-label-tertiary, #adb2b8);margin-left:8px}.dlvd-leaf{display:flex;gap:12px;justify-content:space-between;padding:2px 0;overflow-wrap:anywhere}.dlvd-leaf code{color:var(--dsw-alias-label-secondary, #cfd3d6)}.dlvd-leaf span{white-space:pre-wrap;text-align:right;max-width:65%}.dlvd-leaf [data-kind=boolean]{color:var(--dsw-alias-label-primary, #f9fafb)}.dlvd-leaf [data-kind=number]{color:var(--dsw-alias-label-primary, #f9fafb)}.dlvd-history{margin-top:12px}.dlvd-history>details{border-top:1px solid var(--dsw-alias-border-l1, #ffffff0f);padding:6px 0}.dlvd-history [data-level=error]{border-left:3px solid var(--dsw-alias-state-error-primary, #f25a5a);padding-left:8px}
|
|
636
|
+
.dlvd-panel button,.dlvd-panel select{font:inherit}.dlvd-panel button:hover{background:var(--dsw-alias-interactive-bg-hover, #ffffff14)}.dlvd-panel select:focus-visible,.dlvd-panel input:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary, #7aaaff);outline-offset:2px}.dlvd-panel input{accent-color:var(--dsw-alias-state-business-primary, #7aaaff)}.dlvd-scroll{scrollbar-color:var(--dsw-alias-scrollbar-bg-l1, #3c3c3d) transparent}.dlvd-panel [data-kind=boolean],.dlvd-panel [data-kind=number]{font-variant-numeric:tabular-nums}
|
|
364
637
|
`;
|
|
365
638
|
|
|
639
|
+
// src/theme.ts
|
|
640
|
+
function syncDebuggerTheme(source, destination) {
|
|
641
|
+
const theme = source.getComputedStyle(source.document.body);
|
|
642
|
+
const target = destination.documentElement.style;
|
|
643
|
+
for (const name of Array.from(theme)) {
|
|
644
|
+
if (name.startsWith("--dsw-alias-")) target.setProperty(name, theme.getPropertyValue(name));
|
|
645
|
+
}
|
|
646
|
+
const scheme = theme.colorScheme;
|
|
647
|
+
target.setProperty("--dlvd-color-scheme", scheme && scheme !== "normal" ? scheme : "dark");
|
|
648
|
+
destination.body.style.fontFamily = theme.fontFamily || "system-ui";
|
|
649
|
+
}
|
|
650
|
+
|
|
366
651
|
// ../live-voice/src/modules/core/developerExtension.ts
|
|
367
652
|
var DEVELOPER_KEY = /* @__PURE__ */ Symbol.for("dsh-live-voice.developer.v1");
|
|
368
653
|
var DEVELOPER_CHANGED = "dsh-live-voice:developer-changed";
|
|
@@ -415,12 +700,12 @@ function apply(ctx) {
|
|
|
415
700
|
notify();
|
|
416
701
|
};
|
|
417
702
|
function Host() {
|
|
418
|
-
|
|
703
|
+
import_react22.default.useSyncExternalStore(localeSubscribe, localeSnapshot);
|
|
419
704
|
const labels = copy();
|
|
420
|
-
|
|
705
|
+
import_react22.default.useEffect(() => {
|
|
421
706
|
if (popup && !popup.closed) popup.document.title = labels.title;
|
|
422
707
|
}, [labels.title]);
|
|
423
|
-
return /* @__PURE__ */
|
|
708
|
+
return /* @__PURE__ */ import_react22.default.createElement(DebuggerPanel, { copy: labels, target: window, onClose: () => queueMicrotask(close) });
|
|
424
709
|
}
|
|
425
710
|
const open = () => {
|
|
426
711
|
if (popup && !popup.closed) {
|
|
@@ -446,6 +731,7 @@ function apply(ctx) {
|
|
|
446
731
|
doc.title = copy().title;
|
|
447
732
|
doc.body.replaceChildren();
|
|
448
733
|
doc.body.className = "dlvd-window";
|
|
734
|
+
syncDebuggerTheme(window, doc);
|
|
449
735
|
const style = doc.createElement("style");
|
|
450
736
|
style.textContent = styles;
|
|
451
737
|
doc.head.appendChild(style);
|
|
@@ -453,10 +739,11 @@ function apply(ctx) {
|
|
|
453
739
|
container.dataset.plugin = namespace;
|
|
454
740
|
doc.body.appendChild(container);
|
|
455
741
|
root = (0, import_client.createRoot)(container);
|
|
456
|
-
root.render(/* @__PURE__ */
|
|
742
|
+
root.render(/* @__PURE__ */ import_react22.default.createElement(Host, null));
|
|
457
743
|
enabled = true;
|
|
458
744
|
closedTimer = setInterval(() => {
|
|
459
745
|
if (popup?.closed) close();
|
|
746
|
+
else if (popup) syncDebuggerTheme(window, popup.document);
|
|
460
747
|
}, 250);
|
|
461
748
|
notify();
|
|
462
749
|
} catch {
|
|
@@ -467,18 +754,10 @@ function apply(ctx) {
|
|
|
467
754
|
}
|
|
468
755
|
};
|
|
469
756
|
function Settings() {
|
|
470
|
-
const
|
|
471
|
-
|
|
472
|
-
import_react3.default.useSyncExternalStore(localeSubscribe, localeSnapshot);
|
|
757
|
+
const failed = import_react22.default.useSyncExternalStore(subscribe, () => blocked);
|
|
758
|
+
import_react22.default.useSyncExternalStore(localeSubscribe, localeSnapshot);
|
|
473
759
|
const labels = copy();
|
|
474
|
-
return /* @__PURE__ */
|
|
475
|
-
"input",
|
|
476
|
-
{
|
|
477
|
-
type: "checkbox",
|
|
478
|
-
checked: active,
|
|
479
|
-
onChange: (event) => event.target.checked ? open() : close()
|
|
480
|
-
}
|
|
481
|
-
), labels.activate), failed && /* @__PURE__ */ import_react3.default.createElement("p", { role: "alert" }, labels.popupBlocked));
|
|
760
|
+
return /* @__PURE__ */ import_react22.default.createElement("div", { className: "dlv-diagnostics-launcher" }, /* @__PURE__ */ import_react22.default.createElement("button", { type: "button", className: "dlv-diagnostics-button", onClick: open }, /* @__PURE__ */ import_react22.default.createElement(Icon, { name: "bug" }), labels.diagnostics), /* @__PURE__ */ import_react22.default.createElement(Hint, { label: labels.diagnostics }, labels.activate), failed && /* @__PURE__ */ import_react22.default.createElement("p", { role: "alert" }, labels.popupBlocked));
|
|
482
761
|
}
|
|
483
762
|
ctx.effect(
|
|
484
763
|
() => publishDeveloperExtension(window, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-live-voice-debugger",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Optional read-only state inspector for DSH Live Voice.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
"repository": {
|
|
41
41
|
"type": "git",
|
|
42
|
-
"url": "git+https://github.com/
|
|
42
|
+
"url": "git+https://github.com/wads-dev/dsh-live-voice.git",
|
|
43
43
|
"directory": "packages/live-voice-debugger"
|
|
44
44
|
}
|
|
45
45
|
}
|