@echothink-ui/developer 0.1.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 (56) hide show
  1. package/README.md +5 -0
  2. package/dist/components/APIExplorer.d.ts +2 -0
  3. package/dist/components/BranchSelector.d.ts +2 -0
  4. package/dist/components/CodeBlock.d.ts +2 -0
  5. package/dist/components/CodeEditor.d.ts +2 -0
  6. package/dist/components/CommitList.d.ts +2 -0
  7. package/dist/components/DiffTable.d.ts +2 -0
  8. package/dist/components/DiffViewer.d.ts +2 -0
  9. package/dist/components/EventPayloadViewer.d.ts +2 -0
  10. package/dist/components/GitRepositoryPanel.d.ts +2 -0
  11. package/dist/components/JSONViewer.d.ts +2 -0
  12. package/dist/components/LogConsole.d.ts +2 -0
  13. package/dist/components/PullRequestPanel.d.ts +2 -0
  14. package/dist/components/RequestResponseViewer.d.ts +2 -0
  15. package/dist/components/SchemaViewer.d.ts +2 -0
  16. package/dist/components/TerminalPanel.d.ts +2 -0
  17. package/dist/components/TraceTimeline.d.ts +2 -0
  18. package/dist/components/WebhookEventViewer.d.ts +2 -0
  19. package/dist/components/YAMLViewer.d.ts +2 -0
  20. package/dist/components/devUtils.d.ts +10 -0
  21. package/dist/components/types.d.ts +196 -0
  22. package/dist/index.cjs +2627 -0
  23. package/dist/index.cjs.map +1 -0
  24. package/dist/index.css +3651 -0
  25. package/dist/index.css.map +1 -0
  26. package/dist/index.d.ts +22 -0
  27. package/dist/index.js +2572 -0
  28. package/dist/index.js.map +1 -0
  29. package/package.json +43 -0
  30. package/src/components/APIExplorer.tsx +205 -0
  31. package/src/components/BranchSelector.tsx +54 -0
  32. package/src/components/CodeBlock.tsx +127 -0
  33. package/src/components/CodeEditor.tsx +95 -0
  34. package/src/components/CommitList.tsx +100 -0
  35. package/src/components/DiffTable.tsx +288 -0
  36. package/src/components/DiffViewer.tsx +145 -0
  37. package/src/components/EventPayloadViewer.tsx +91 -0
  38. package/src/components/GitRepositoryPanel.tsx +73 -0
  39. package/src/components/JSONViewer.tsx +189 -0
  40. package/src/components/LogConsole.tsx +160 -0
  41. package/src/components/PullRequestPanel.test.tsx +52 -0
  42. package/src/components/PullRequestPanel.tsx +215 -0
  43. package/src/components/RequestResponseViewer.test.tsx +45 -0
  44. package/src/components/RequestResponseViewer.tsx +169 -0
  45. package/src/components/SchemaViewer.tsx +157 -0
  46. package/src/components/TerminalPanel.test.tsx +33 -0
  47. package/src/components/TerminalPanel.tsx +134 -0
  48. package/src/components/TraceTimeline.test.tsx +63 -0
  49. package/src/components/TraceTimeline.tsx +207 -0
  50. package/src/components/WebhookEventViewer.test.tsx +57 -0
  51. package/src/components/WebhookEventViewer.tsx +184 -0
  52. package/src/components/YAMLViewer.tsx +207 -0
  53. package/src/components/devUtils.ts +81 -0
  54. package/src/components/types.ts +230 -0
  55. package/src/index.tsx +72 -0
  56. package/src/styles.css +4296 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,2627 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.tsx
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ APIExplorer: () => APIExplorer,
34
+ BranchSelector: () => BranchSelector,
35
+ CodeBlock: () => CodeBlock,
36
+ CodeEditor: () => CodeEditor,
37
+ CommitList: () => CommitList,
38
+ DeveloperComponentNames: () => DeveloperComponentNames,
39
+ DiffTable: () => DiffTable,
40
+ DiffViewer: () => DiffViewer,
41
+ EventPayloadViewer: () => EventPayloadViewer,
42
+ GitRepositoryPanel: () => GitRepositoryPanel,
43
+ JSONViewer: () => JSONViewer,
44
+ LogConsole: () => LogConsole,
45
+ PullRequestPanel: () => PullRequestPanel,
46
+ RequestResponseViewer: () => RequestResponseViewer,
47
+ SchemaViewer: () => SchemaViewer,
48
+ TerminalPanel: () => TerminalPanel,
49
+ TraceTimeline: () => TraceTimeline,
50
+ WebhookEventViewer: () => WebhookEventViewer,
51
+ YAMLViewer: () => YAMLViewer
52
+ });
53
+ module.exports = __toCommonJS(index_exports);
54
+
55
+ // src/components/APIExplorer.tsx
56
+ var React = __toESM(require("react"), 1);
57
+ var import_core = require("@echothink-ui/core");
58
+
59
+ // src/components/devUtils.ts
60
+ function splitLines(value) {
61
+ return value.length ? value.replace(/\r\n/g, "\n").split("\n") : [""];
62
+ }
63
+ function buildLineDiff(before, after) {
64
+ const a = splitDiffLines(before);
65
+ const b = splitDiffLines(after);
66
+ const table = Array.from({ length: a.length + 1 }, () => Array(b.length + 1).fill(0));
67
+ for (let i2 = a.length - 1; i2 >= 0; i2 -= 1) {
68
+ for (let j2 = b.length - 1; j2 >= 0; j2 -= 1) {
69
+ table[i2][j2] = a[i2] === b[j2] ? (table[i2 + 1]?.[j2 + 1] ?? 0) + 1 : Math.max(table[i2 + 1]?.[j2] ?? 0, table[i2]?.[j2 + 1] ?? 0);
70
+ }
71
+ }
72
+ const lines = [];
73
+ let i = 0;
74
+ let j = 0;
75
+ let beforeLine = 1;
76
+ let afterLine = 1;
77
+ while (i < a.length && j < b.length) {
78
+ if (a[i] === b[j]) {
79
+ lines.push({ type: "equal", beforeLine, afterLine, text: a[i] ?? "" });
80
+ i += 1;
81
+ j += 1;
82
+ beforeLine += 1;
83
+ afterLine += 1;
84
+ } else if ((table[i + 1]?.[j] ?? 0) >= (table[i]?.[j + 1] ?? 0)) {
85
+ lines.push({ type: "remove", beforeLine, text: a[i] ?? "" });
86
+ i += 1;
87
+ beforeLine += 1;
88
+ } else {
89
+ lines.push({ type: "add", afterLine, text: b[j] ?? "" });
90
+ j += 1;
91
+ afterLine += 1;
92
+ }
93
+ }
94
+ while (i < a.length) {
95
+ lines.push({ type: "remove", beforeLine, text: a[i] ?? "" });
96
+ i += 1;
97
+ beforeLine += 1;
98
+ }
99
+ while (j < b.length) {
100
+ lines.push({ type: "add", afterLine, text: b[j] ?? "" });
101
+ j += 1;
102
+ afterLine += 1;
103
+ }
104
+ return lines;
105
+ }
106
+ function splitDiffLines(value) {
107
+ const lines = value.length ? value.replace(/\r\n/g, "\n").split("\n") : [];
108
+ return lines.length > 1 && lines[lines.length - 1] === "" ? lines.slice(0, -1) : lines;
109
+ }
110
+ function formatUnknown(value) {
111
+ if (typeof value === "string") return value;
112
+ if (value == null) return "";
113
+ try {
114
+ return JSON.stringify(value, null, 2);
115
+ } catch {
116
+ return String(value);
117
+ }
118
+ }
119
+ function compactSha(sha) {
120
+ return sha.length > 10 ? sha.slice(0, 10) : sha;
121
+ }
122
+
123
+ // src/components/APIExplorer.tsx
124
+ var import_jsx_runtime = require("react/jsx-runtime");
125
+ function APIExplorer({
126
+ endpoints,
127
+ selectedId,
128
+ onSelect,
129
+ onSend,
130
+ className,
131
+ ...props
132
+ }) {
133
+ const [internalId, setInternalId] = React.useState(selectedId ?? endpoints[0]?.id);
134
+ const selected = endpoints.find((endpoint) => endpoint.id === (selectedId ?? internalId)) ?? endpoints[0];
135
+ const [method, setMethod] = React.useState(selected?.method ?? "GET");
136
+ const [path, setPath] = React.useState(selected?.path ?? "");
137
+ const [headers, setHeaders] = React.useState(() => formatEndpointValue(selected?.headers, "{}"));
138
+ const [body, setBody] = React.useState(() => formatEndpointValue(selected?.body, ""));
139
+ const [response, setResponse] = React.useState({ status: "idle" });
140
+ const headerError = validateHeaderJson(headers);
141
+ React.useEffect(() => {
142
+ if (!selected) return;
143
+ setMethod(selected.method);
144
+ setPath(selected.path);
145
+ setHeaders(formatEndpointValue(selected.headers, "{}"));
146
+ setBody(formatEndpointValue(selected.body, ""));
147
+ }, [selected?.id]);
148
+ const choose = (endpoint) => {
149
+ setInternalId(endpoint.id);
150
+ onSelect?.(endpoint.id);
151
+ };
152
+ const send = async () => {
153
+ if (headerError || !path.trim()) return;
154
+ const request = { endpointId: selected?.id, method, path, headers, body };
155
+ setResponse({ status: "loading" });
156
+ try {
157
+ const result = await onSend?.(request);
158
+ setResponse({ status: "success", value: result ?? { ok: true, request } });
159
+ } catch (error) {
160
+ setResponse({ status: "error", value: formatError(error) });
161
+ }
162
+ };
163
+ const isLoading = response.status === "loading";
164
+ const responseStateLabel = response.status === "idle" ? "Ready" : response.status;
165
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
166
+ "section",
167
+ {
168
+ ...props,
169
+ className: `eth-dev-api-explorer ${className ?? ""}`,
170
+ "data-eth-component": "APIExplorer",
171
+ children: [
172
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("nav", { className: "eth-dev-api-explorer__nav", "aria-label": "Endpoints", children: [
173
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "eth-dev-api-explorer__nav-heading", children: [
174
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Endpoints" }),
175
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: endpoints.length })
176
+ ] }),
177
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "eth-dev-api-explorer__endpoint-list", children: endpoints.length ? endpoints.map((endpoint) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
178
+ "button",
179
+ {
180
+ type: "button",
181
+ "aria-current": selected?.id === endpoint.id,
182
+ onClick: () => choose(endpoint),
183
+ children: [
184
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
185
+ "span",
186
+ {
187
+ className: `eth-dev-api-explorer__method eth-dev-api-explorer__method--${methodToken(endpoint.method)}`,
188
+ children: endpoint.method
189
+ }
190
+ ),
191
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "eth-dev-api-explorer__endpoint-copy", children: [
192
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: endpoint.path }),
193
+ endpoint.summary ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { children: endpoint.summary }) : null
194
+ ] })
195
+ ]
196
+ },
197
+ endpoint.id
198
+ )) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "eth-dev-api-explorer__empty", children: "No endpoints configured." }) })
199
+ ] }),
200
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
201
+ "form",
202
+ {
203
+ className: "eth-dev-api-explorer__request",
204
+ onSubmit: (event) => {
205
+ event.preventDefault();
206
+ void send();
207
+ },
208
+ children: [
209
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", { className: "eth-dev-api-explorer__request-header", children: [
210
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
211
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: "Request" }),
212
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: selected?.summary ?? "Custom endpoint" })
213
+ ] }),
214
+ selected ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: selected.id }) : null
215
+ ] }),
216
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "eth-dev-api-explorer__method-path", children: [
217
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_core.FormField, { label: "Method", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
218
+ import_core.Select,
219
+ {
220
+ value: method,
221
+ options: ["GET", "POST", "PUT", "PATCH", "DELETE"].map((item) => ({
222
+ value: item,
223
+ label: item
224
+ })),
225
+ onChange: (event) => setMethod(event.currentTarget.value)
226
+ }
227
+ ) }),
228
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_core.FormField, { label: "Path", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_core.TextInput, { value: path, onChange: (event) => setPath(event.currentTarget.value) }) })
229
+ ] }),
230
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_core.FormField, { label: "Headers", error: headerError, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
231
+ import_core.Textarea,
232
+ {
233
+ className: "eth-dev-api-explorer__code-field",
234
+ value: headers,
235
+ onChange: (event) => setHeaders(event.currentTarget.value),
236
+ rows: 5
237
+ }
238
+ ) }),
239
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_core.FormField, { label: "Body", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
240
+ import_core.Textarea,
241
+ {
242
+ className: "eth-dev-api-explorer__code-field",
243
+ value: body,
244
+ onChange: (event) => setBody(event.currentTarget.value),
245
+ rows: 8
246
+ }
247
+ ) }),
248
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "eth-dev-api-explorer__actions", children: [
249
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
250
+ method,
251
+ " ",
252
+ path || "/"
253
+ ] }),
254
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_core.Button, { type: "submit", loading: isLoading, disabled: Boolean(headerError) || !path.trim(), children: "Send" })
255
+ ] })
256
+ ]
257
+ }
258
+ ),
259
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "eth-dev-api-explorer__response", "aria-live": "polite", "aria-busy": isLoading, children: [
260
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", { className: "eth-dev-api-explorer__response-header", children: [
261
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: "Response" }),
262
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
263
+ "span",
264
+ {
265
+ className: `eth-dev-api-explorer__response-state eth-dev-api-explorer__response-state--${response.status}`,
266
+ children: responseStateLabel
267
+ }
268
+ )
269
+ ] }),
270
+ response.status === "idle" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "eth-dev-api-explorer__response-empty", children: "No response yet." }) : response.status === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "eth-dev-api-explorer__response-empty", children: "Waiting for response." }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: formatUnknown(response.value) }) })
271
+ ] })
272
+ ]
273
+ }
274
+ );
275
+ }
276
+ function formatEndpointValue(value, fallback) {
277
+ if (value == null) return fallback;
278
+ if (typeof value === "string") return value;
279
+ return formatUnknown(value);
280
+ }
281
+ function validateHeaderJson(value) {
282
+ const trimmed = value.trim();
283
+ if (!trimmed) return null;
284
+ try {
285
+ const parsed = JSON.parse(trimmed);
286
+ if (!parsed || Array.isArray(parsed) || typeof parsed !== "object") {
287
+ return "Headers must be a JSON object.";
288
+ }
289
+ } catch {
290
+ return "Headers must be valid JSON.";
291
+ }
292
+ return null;
293
+ }
294
+ function formatError(error) {
295
+ if (error instanceof Error) {
296
+ return { error: error.message };
297
+ }
298
+ return error;
299
+ }
300
+ function methodToken(method) {
301
+ return method.toLowerCase().replace(/[^a-z0-9-]/g, "");
302
+ }
303
+
304
+ // src/components/BranchSelector.tsx
305
+ var import_core2 = require("@echothink-ui/core");
306
+ var import_jsx_runtime2 = require("react/jsx-runtime");
307
+ function BranchSelector({
308
+ branches,
309
+ value,
310
+ onChange,
311
+ className,
312
+ disabled,
313
+ labelText = "Branch",
314
+ helperText,
315
+ density = "compact",
316
+ ...props
317
+ }) {
318
+ const hasBranches = branches.length > 0;
319
+ const branchCountLabel = branches.length === 1 ? "1 branch available" : `${branches.length} branches available`;
320
+ const resolvedHelperText = helperText === void 0 ? hasBranches ? branchCountLabel : "No branches available" : helperText;
321
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
322
+ import_core2.Select,
323
+ {
324
+ ...props,
325
+ className: [
326
+ "eth-dev-branch-selector",
327
+ !hasBranches && "eth-dev-branch-selector--empty",
328
+ className
329
+ ].filter(Boolean).join(" "),
330
+ "data-eth-component": "BranchSelector",
331
+ density,
332
+ disabled: disabled || !hasBranches,
333
+ helperText: resolvedHelperText,
334
+ labelText,
335
+ value: hasBranches ? value : "",
336
+ options: hasBranches ? branches.map((branch) => ({ value: branch, label: branch })) : [{ value: "", label: "No branches available", disabled: true }],
337
+ onChange: (event) => {
338
+ if (hasBranches) {
339
+ onChange?.(event.currentTarget.value);
340
+ }
341
+ }
342
+ }
343
+ );
344
+ }
345
+
346
+ // src/components/CodeBlock.tsx
347
+ var React2 = __toESM(require("react"), 1);
348
+ var import_icons_react = require("@carbon/icons-react");
349
+ var import_core3 = require("@echothink-ui/core");
350
+ var import_jsx_runtime3 = require("react/jsx-runtime");
351
+ var keywordPattern = /\b(?:async|await|break|case|catch|class|const|continue|default|else|export|extends|false|finally|for|from|function|if|import|interface|let|new|null|return|throw|true|try|type|undefined|var|while)\b/;
352
+ var tokenPattern = /\/\/.*|\/\*.*?\*\/|"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|`(?:\\.|[^`\\])*`|\b\d+(?:\.\d+)?\b|\b(?:async|await|break|case|catch|class|const|continue|default|else|export|extends|false|finally|for|from|function|if|import|interface|let|new|null|return|throw|true|try|type|undefined|var|while)\b/g;
353
+ function getTokenKind(token) {
354
+ if (token.startsWith("//") || token.startsWith("/*")) return "comment";
355
+ if (token.startsWith('"') || token.startsWith("'") || token.startsWith("`")) return "string";
356
+ if (/^\d/.test(token)) return "number";
357
+ if (keywordPattern.test(token)) return "keyword";
358
+ return "plain";
359
+ }
360
+ function renderCodeLine(line) {
361
+ const parts = [];
362
+ let lastIndex = 0;
363
+ tokenPattern.lastIndex = 0;
364
+ for (let match = tokenPattern.exec(line); match; match = tokenPattern.exec(line)) {
365
+ const token = match[0];
366
+ if (match.index > lastIndex) {
367
+ parts.push(line.slice(lastIndex, match.index));
368
+ }
369
+ const kind = getTokenKind(token);
370
+ parts.push(
371
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
372
+ "span",
373
+ {
374
+ className: `eth-dev-code-block__token eth-dev-code-block__token--${kind}`,
375
+ children: token
376
+ },
377
+ `${match.index}-${token}`
378
+ )
379
+ );
380
+ lastIndex = match.index + token.length;
381
+ }
382
+ if (lastIndex < line.length) {
383
+ parts.push(line.slice(lastIndex));
384
+ }
385
+ return parts.length ? parts : line;
386
+ }
387
+ function CodeBlock({
388
+ code,
389
+ language = "text",
390
+ showLineNumbers = false,
391
+ className,
392
+ ...props
393
+ }) {
394
+ const [copied, setCopied] = React2.useState(false);
395
+ const resetTimer = React2.useRef(void 0);
396
+ const lines = splitLines(code);
397
+ React2.useEffect(() => {
398
+ return () => {
399
+ if (resetTimer.current !== void 0 && typeof window !== "undefined") {
400
+ window.clearTimeout(resetTimer.current);
401
+ }
402
+ };
403
+ }, []);
404
+ const copy = React2.useCallback(() => {
405
+ if (typeof navigator === "undefined" || !navigator.clipboard) return;
406
+ void navigator.clipboard.writeText(code).then(() => {
407
+ if (typeof window !== "undefined") {
408
+ setCopied(true);
409
+ if (resetTimer.current !== void 0) {
410
+ window.clearTimeout(resetTimer.current);
411
+ }
412
+ resetTimer.current = window.setTimeout(() => setCopied(false), 1200);
413
+ }
414
+ }).catch(() => {
415
+ setCopied(false);
416
+ });
417
+ }, [code]);
418
+ const normalizedLanguage = language.trim() || "text";
419
+ const languageClass = normalizedLanguage.toLowerCase().replace(/[^a-z0-9_-]/g, "-");
420
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
421
+ "section",
422
+ {
423
+ ...props,
424
+ className: `eth-dev-code-block ${showLineNumbers ? "eth-dev-code-block--numbered" : ""} ${className ?? ""}`,
425
+ "data-eth-component": "CodeBlock",
426
+ "data-language": normalizedLanguage,
427
+ children: [
428
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("header", { className: "eth-dev-code-block__header", children: [
429
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "eth-dev-code-block__language", children: normalizedLanguage }),
430
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
431
+ import_core3.IconButton,
432
+ {
433
+ className: "eth-dev-code-block__copy-button",
434
+ label: copied ? "Copied" : "Copy code",
435
+ intent: "ghost",
436
+ density: "compact",
437
+ icon: copied ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_icons_react.Checkmark, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_icons_react.Copy, { size: 16 }),
438
+ onClick: copy
439
+ }
440
+ ),
441
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "eth-dev-code-block__copy-status", "aria-live": "polite", children: copied ? "Code copied" : "" })
442
+ ] }),
443
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("pre", { className: `eth-dev-code-block__pre language-${languageClass}`, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("code", { className: "eth-dev-code-block__code", children: lines.map((line, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "eth-dev-code-block__line", children: [
444
+ showLineNumbers ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "eth-dev-code-block__gutter", "aria-hidden": true, children: index + 1 }) : null,
445
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "eth-dev-code-block__line-code", children: renderCodeLine(line) })
446
+ ] }, index)) }) })
447
+ ]
448
+ }
449
+ );
450
+ }
451
+
452
+ // src/components/CodeEditor.tsx
453
+ var React3 = __toESM(require("react"), 1);
454
+ var import_jsx_runtime4 = require("react/jsx-runtime");
455
+ function CodeEditor({
456
+ value,
457
+ onChange,
458
+ language = "text",
459
+ readonly,
460
+ readOnly,
461
+ schemaRef,
462
+ className,
463
+ disabled,
464
+ onScroll,
465
+ rows,
466
+ wrap,
467
+ "aria-describedby": ariaDescribedBy,
468
+ "aria-invalid": ariaInvalid,
469
+ "aria-label": ariaLabel,
470
+ ...props
471
+ }) {
472
+ const lines = splitLines(value);
473
+ const isReadonly = readonly ?? readOnly ?? false;
474
+ const isInvalid = ariaInvalid === true || ariaInvalid === "true" || ariaInvalid === "grammar" || ariaInvalid === "spelling";
475
+ const languageLabel = language || "text";
476
+ const lineCount = lines.length;
477
+ const visibleRows = rows ?? Math.min(Math.max(lineCount, 8), 16);
478
+ const statusId = React3.useId();
479
+ const gutterRef = React3.useRef(null);
480
+ const describedBy = [ariaDescribedBy, statusId].filter(Boolean).join(" ") || void 0;
481
+ const modeLabel = disabled ? "Disabled" : isReadonly ? "Read-only" : "Editable";
482
+ const handleScroll = (event) => {
483
+ if (gutterRef.current) {
484
+ gutterRef.current.scrollTop = event.currentTarget.scrollTop;
485
+ }
486
+ onScroll?.(event);
487
+ };
488
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
489
+ "section",
490
+ {
491
+ className: `eth-dev-code-editor ${className ?? ""}`,
492
+ "data-eth-component": "CodeEditor",
493
+ "data-language": language,
494
+ "data-readonly": isReadonly ? "true" : void 0,
495
+ "data-disabled": disabled ? "true" : void 0,
496
+ "data-invalid": isInvalid ? "true" : void 0,
497
+ "data-schema-ref": schemaRef,
498
+ children: [
499
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("header", { className: "eth-dev-code-editor__header", children: [
500
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "eth-dev-code-editor__heading", children: [
501
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "eth-dev-code-editor__title", children: "Code editor" }),
502
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "eth-dev-code-editor__language", children: languageLabel })
503
+ ] }),
504
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "eth-dev-code-editor__badges", "aria-hidden": "true", children: [
505
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "eth-dev-code-editor__badge", children: modeLabel }),
506
+ schemaRef ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "eth-dev-code-editor__badge", children: schemaRef }) : null
507
+ ] })
508
+ ] }),
509
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "eth-dev-code-editor__body", children: [
510
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref: gutterRef, className: "eth-dev-code-editor__gutter", "aria-hidden": "true", children: lines.map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: index + 1 }, index)) }),
511
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
512
+ "textarea",
513
+ {
514
+ ...props,
515
+ "aria-describedby": describedBy,
516
+ "aria-invalid": ariaInvalid,
517
+ "aria-label": ariaLabel ?? `${languageLabel} code editor`,
518
+ value,
519
+ disabled,
520
+ readOnly: isReadonly,
521
+ rows: visibleRows,
522
+ spellCheck: false,
523
+ wrap: wrap ?? "off",
524
+ className: "eth-dev-code-editor__textarea",
525
+ onChange: (event) => onChange?.(event.currentTarget.value),
526
+ onScroll: handleScroll
527
+ }
528
+ )
529
+ ] }),
530
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("footer", { id: statusId, className: "eth-dev-code-editor__footer", children: [
531
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: modeLabel }),
532
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
533
+ lineCount,
534
+ " ",
535
+ lineCount === 1 ? "line" : "lines",
536
+ " / ",
537
+ value.length,
538
+ " chars"
539
+ ] })
540
+ ] })
541
+ ]
542
+ }
543
+ );
544
+ }
545
+
546
+ // src/components/CommitList.tsx
547
+ var import_core4 = require("@echothink-ui/core");
548
+ var import_data = require("@echothink-ui/data");
549
+ var import_jsx_runtime5 = require("react/jsx-runtime");
550
+ function authorInitials(author) {
551
+ const parts = author.trim().split(/\s+/).filter(Boolean);
552
+ if (!parts.length) return "?";
553
+ if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
554
+ return `${parts[0][0]}${parts[parts.length - 1][0]}`.toUpperCase();
555
+ }
556
+ function CommitList({ commits, className, ...props }) {
557
+ const latestCommit = commits[0];
558
+ const authorCount = new Set(commits.map((commit) => commit.author)).size;
559
+ const columns = [
560
+ {
561
+ key: "sha",
562
+ header: "SHA",
563
+ width: "8.5rem",
564
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { className: "eth-dev-commit-list__sha", title: row.sha, children: compactSha(row.sha) })
565
+ },
566
+ {
567
+ key: "message",
568
+ header: "Message",
569
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "eth-dev-commit-list__message", title: row.message, children: row.message })
570
+ },
571
+ {
572
+ key: "author",
573
+ header: "Author",
574
+ width: "12rem",
575
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "eth-dev-commit-list__author", children: [
576
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "eth-dev-commit-list__avatar", "aria-hidden": "true", children: authorInitials(row.author) }),
577
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "eth-dev-commit-list__author-name", children: row.author })
578
+ ] })
579
+ },
580
+ {
581
+ key: "date",
582
+ header: "Date",
583
+ width: "10rem",
584
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "eth-dev-commit-list__date", children: row.date })
585
+ }
586
+ ];
587
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
588
+ "section",
589
+ {
590
+ ...props,
591
+ "aria-label": props["aria-label"] ?? "Commit history",
592
+ className: `eth-dev-commit-list ${className ?? ""}`,
593
+ "data-eth-component": "CommitList",
594
+ children: [
595
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("header", { className: "eth-dev-commit-list__header", children: [
596
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "eth-dev-commit-list__heading", children: [
597
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: "Source control" }),
598
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { children: "Commit history" })
599
+ ] }),
600
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("dl", { className: "eth-dev-commit-list__summary", "aria-label": "Commit history summary", children: [
601
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
602
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Commits" }),
603
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: commits.length })
604
+ ] }),
605
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
606
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Authors" }),
607
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: authorCount })
608
+ ] }),
609
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
610
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Latest" }),
611
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: latestCommit ? compactSha(latestCommit.sha) : "None" })
612
+ ] })
613
+ ] })
614
+ ] }),
615
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
616
+ import_data.DataTable,
617
+ {
618
+ rows: commits,
619
+ columns,
620
+ rowKey: "sha",
621
+ density: "compact",
622
+ className: "eth-dev-commit-list__table",
623
+ emptyState: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
624
+ import_core4.EmptyState,
625
+ {
626
+ title: "No commits",
627
+ description: "Commit history will appear when this branch receives changes."
628
+ }
629
+ )
630
+ }
631
+ )
632
+ ]
633
+ }
634
+ );
635
+ }
636
+
637
+ // src/components/DiffTable.tsx
638
+ var React4 = __toESM(require("react"), 1);
639
+ var import_core5 = require("@echothink-ui/core");
640
+ var import_jsx_runtime6 = require("react/jsx-runtime");
641
+ var changeTypes = /* @__PURE__ */ new Set([
642
+ "added",
643
+ "modified",
644
+ "removed",
645
+ "renamed",
646
+ "unchanged",
647
+ "conflict"
648
+ ]);
649
+ function getNumeric(row, keys) {
650
+ for (const key of keys) {
651
+ const value = row[key];
652
+ if (typeof value === "number" && Number.isFinite(value)) return value;
653
+ if (typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value))) {
654
+ return Number(value);
655
+ }
656
+ }
657
+ return 0;
658
+ }
659
+ function getPath(row) {
660
+ const value = row.afterPath ?? row.path ?? row.file ?? row.name;
661
+ return typeof value === "string" && value.trim() ? value : "Unknown file";
662
+ }
663
+ function getPreviousPath(row) {
664
+ const value = row.beforePath ?? row.previousPath;
665
+ return typeof value === "string" && value.trim() ? value : void 0;
666
+ }
667
+ function normalizeChangeType(value) {
668
+ if (typeof value !== "string") return void 0;
669
+ const normalized = value.trim().toLowerCase().replace(/[_\s]+/g, "-");
670
+ if (normalized === "delete" || normalized === "deleted" || normalized === "deletion") {
671
+ return "removed";
672
+ }
673
+ if (normalized === "add" || normalized === "created" || normalized === "create") {
674
+ return "added";
675
+ }
676
+ if (normalized === "rename" || normalized === "moved") {
677
+ return "renamed";
678
+ }
679
+ return changeTypes.has(normalized) ? normalized : void 0;
680
+ }
681
+ function inferChangeType(row) {
682
+ const explicit = normalizeChangeType(row.changeType ?? row.status ?? row.kind ?? row.type);
683
+ if (explicit) return explicit;
684
+ if (getPreviousPath(row) && getPreviousPath(row) !== getPath(row)) return "renamed";
685
+ const added = getAdded(row);
686
+ const removed = getRemoved(row);
687
+ if (added > 0 && removed > 0) return "modified";
688
+ if (added > 0) return "added";
689
+ if (removed > 0) return "removed";
690
+ return "unchanged";
691
+ }
692
+ function getAdded(row) {
693
+ return getNumeric(row, ["added", "additions", "linesAdded", "insertions"]);
694
+ }
695
+ function getRemoved(row) {
696
+ return getNumeric(row, ["removed", "deletions", "deleted", "linesRemoved"]);
697
+ }
698
+ function changeLabel(type) {
699
+ if (type === "added") return "Added";
700
+ if (type === "removed") return "Removed";
701
+ if (type === "renamed") return "Renamed";
702
+ if (type === "unchanged") return "Unchanged";
703
+ if (type === "conflict") return "Conflict";
704
+ return "Modified";
705
+ }
706
+ function formatAdded(value) {
707
+ return value > 0 ? `+${value}` : "0";
708
+ }
709
+ function formatRemoved(value) {
710
+ return value > 0 ? `-${value}` : "0";
711
+ }
712
+ function formatNet(value) {
713
+ if (value > 0) return `+${value}`;
714
+ if (value < 0) return String(value);
715
+ return "0";
716
+ }
717
+ function defaultSummary(row, type) {
718
+ const hunks = getNumeric(row, ["hunks", "sections"]);
719
+ if (typeof row.summary !== "undefined") return row.summary;
720
+ if (type === "renamed") return "Path changed";
721
+ if (type === "unchanged") return "No line changes";
722
+ if (type === "conflict") return "Review required";
723
+ if (hunks > 0) return `${hunks} ${hunks === 1 ? "hunk" : "hunks"}`;
724
+ return "Line changes";
725
+ }
726
+ function DiffTable({
727
+ rows,
728
+ mode = "side-by-side",
729
+ title = "Diff summary",
730
+ subtitle,
731
+ showSummary = true,
732
+ emptyState,
733
+ className,
734
+ "aria-label": ariaLabel,
735
+ ...props
736
+ }) {
737
+ const totals = React4.useMemo(
738
+ () => rows.reduce(
739
+ (acc, row) => {
740
+ const type = inferChangeType(row);
741
+ acc.added += getAdded(row);
742
+ acc.removed += getRemoved(row);
743
+ if (type !== "unchanged") acc.changed += 1;
744
+ return acc;
745
+ },
746
+ { added: 0, removed: 0, changed: 0 }
747
+ ),
748
+ [rows]
749
+ );
750
+ const effectiveSubtitle = subtitle ?? `${totals.changed} of ${rows.length} files changed, ${totals.added} additions, ${totals.removed} deletions`;
751
+ const label = ariaLabel ?? (typeof title === "string" ? title : "Diff summary");
752
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
753
+ "section",
754
+ {
755
+ ...props,
756
+ className: [
757
+ "eth-dev-diff-table",
758
+ `eth-dev-diff-table--${mode}`,
759
+ rows.length ? void 0 : "eth-dev-diff-table--empty",
760
+ className
761
+ ].filter(Boolean).join(" "),
762
+ "data-eth-component": "DiffTable",
763
+ "aria-label": label,
764
+ children: [
765
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("header", { className: "eth-dev-diff-table__header", children: [
766
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "eth-dev-diff-table__heading", children: [
767
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { children: title }),
768
+ effectiveSubtitle ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: effectiveSubtitle }) : null
769
+ ] }),
770
+ showSummary ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("dl", { className: "eth-dev-diff-table__summary", "aria-label": "Diff totals", children: [
771
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
772
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dt", { children: "Files" }),
773
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dd", { children: totals.changed })
774
+ ] }),
775
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
776
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dt", { children: "Added" }),
777
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dd", { className: "eth-dev-diff-table__summary-value--added", children: formatAdded(totals.added) })
778
+ ] }),
779
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
780
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dt", { children: "Removed" }),
781
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dd", { className: "eth-dev-diff-table__summary-value--removed", children: formatRemoved(totals.removed) })
782
+ ] })
783
+ ] }) : null
784
+ ] }),
785
+ rows.length ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "eth-dev-diff-table__viewport", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("table", { className: "eth-dev-diff-table__table", children: [
786
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("caption", { className: "eth-dev-diff-table__caption", children: label }),
787
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("tr", { children: [
788
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("th", { scope: "col", children: "File" }),
789
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("th", { scope: "col", children: "State" }),
790
+ mode === "inline" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("th", { scope: "col", children: "Changes" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
791
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("th", { scope: "col", children: "Added" }),
792
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("th", { scope: "col", children: "Removed" }),
793
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("th", { scope: "col", children: "Net" })
794
+ ] }),
795
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("th", { scope: "col", children: "Summary" })
796
+ ] }) }),
797
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("tbody", { children: rows.map((row, index) => {
798
+ const added = getAdded(row);
799
+ const removed = getRemoved(row);
800
+ const type = inferChangeType(row);
801
+ const path = getPath(row);
802
+ const previousPath = getPreviousPath(row);
803
+ const key = row.id ?? `${path}-${index}`;
804
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("tr", { className: `eth-dev-diff-table__row--${type}`, children: [
805
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("th", { scope: "row", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "eth-dev-diff-table__file", children: [
806
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: path }),
807
+ previousPath && previousPath !== path ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
808
+ "was ",
809
+ previousPath
810
+ ] }) : null
811
+ ] }) }),
812
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
813
+ "span",
814
+ {
815
+ className: `eth-dev-diff-table__state eth-dev-diff-table__state--${type}`,
816
+ children: changeLabel(type)
817
+ }
818
+ ) }),
819
+ mode === "inline" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "eth-dev-diff-table__inline-delta", children: [
820
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
821
+ "span",
822
+ {
823
+ className: "eth-dev-diff-table__count eth-dev-diff-table__count--added",
824
+ "aria-label": `${added} added lines`,
825
+ children: formatAdded(added)
826
+ }
827
+ ),
828
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
829
+ "span",
830
+ {
831
+ className: "eth-dev-diff-table__count eth-dev-diff-table__count--removed",
832
+ "aria-label": `${removed} removed lines`,
833
+ children: formatRemoved(removed)
834
+ }
835
+ )
836
+ ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
837
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
838
+ "span",
839
+ {
840
+ className: "eth-dev-diff-table__count eth-dev-diff-table__count--added",
841
+ "aria-label": `${added} added lines`,
842
+ children: formatAdded(added)
843
+ }
844
+ ) }),
845
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
846
+ "span",
847
+ {
848
+ className: "eth-dev-diff-table__count eth-dev-diff-table__count--removed",
849
+ "aria-label": `${removed} removed lines`,
850
+ children: formatRemoved(removed)
851
+ }
852
+ ) }),
853
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "eth-dev-diff-table__count", children: formatNet(added - removed) }) })
854
+ ] }),
855
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "eth-dev-diff-table__row-summary", children: defaultSummary(row, type) }) })
856
+ ] }, key);
857
+ }) })
858
+ ] }) }) : emptyState ?? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
859
+ import_core5.EmptyState,
860
+ {
861
+ title: "No diff rows",
862
+ description: "No files have line-level changes in this comparison."
863
+ }
864
+ )
865
+ ]
866
+ }
867
+ );
868
+ }
869
+
870
+ // src/components/DiffViewer.tsx
871
+ var React5 = __toESM(require("react"), 1);
872
+ var import_core6 = require("@echothink-ui/core");
873
+ var import_jsx_runtime7 = require("react/jsx-runtime");
874
+ function DiffViewer({
875
+ before,
876
+ after,
877
+ mode = "inline",
878
+ language,
879
+ className,
880
+ ...props
881
+ }) {
882
+ const [viewMode, setViewMode] = React5.useState(mode);
883
+ const diff = React5.useMemo(() => buildLineDiff(before, after), [before, after]);
884
+ const counts = React5.useMemo(
885
+ () => ({
886
+ additions: diff.filter((line) => line.type === "add").length,
887
+ deletions: diff.filter((line) => line.type === "remove").length
888
+ }),
889
+ [diff]
890
+ );
891
+ const languageLabel = language?.trim() || "diff";
892
+ React5.useEffect(() => setViewMode(mode), [mode]);
893
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
894
+ "section",
895
+ {
896
+ ...props,
897
+ className: `eth-dev-diff-viewer eth-dev-diff-viewer--${viewMode} ${className ?? ""}`.trim(),
898
+ "aria-label": props["aria-label"] ?? `${languageLabel} diff viewer`,
899
+ "data-eth-component": "DiffViewer",
900
+ "data-language": languageLabel,
901
+ children: [
902
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("header", { className: "eth-dev-diff-viewer__header", children: [
903
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "eth-dev-diff-viewer__heading", children: [
904
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "eth-dev-diff-viewer__language", children: languageLabel }),
905
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "eth-dev-diff-viewer__mode", children: viewMode === "inline" ? "Inline" : "Side by side" })
906
+ ] }),
907
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "eth-dev-diff-viewer__summary", "aria-label": "Diff summary", children: [
908
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "eth-dev-diff-viewer__stat eth-dev-diff-viewer__stat--add", children: [
909
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: counts.additions }),
910
+ " additions"
911
+ ] }),
912
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "eth-dev-diff-viewer__stat eth-dev-diff-viewer__stat--remove", children: [
913
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: counts.deletions }),
914
+ " deletions"
915
+ ] })
916
+ ] }),
917
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "eth-dev-diff-viewer__view-switch", role: "group", "aria-label": "Diff view mode", children: [
918
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
919
+ import_core6.Button,
920
+ {
921
+ intent: viewMode === "inline" ? "primary" : "secondary",
922
+ density: "compact",
923
+ "aria-pressed": viewMode === "inline",
924
+ onClick: () => setViewMode("inline"),
925
+ children: "Inline"
926
+ }
927
+ ),
928
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
929
+ import_core6.Button,
930
+ {
931
+ intent: viewMode === "side-by-side" ? "primary" : "secondary",
932
+ density: "compact",
933
+ "aria-pressed": viewMode === "side-by-side",
934
+ onClick: () => setViewMode("side-by-side"),
935
+ children: "Side by side"
936
+ }
937
+ )
938
+ ] })
939
+ ] }),
940
+ viewMode === "inline" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
941
+ "pre",
942
+ {
943
+ className: `eth-dev-diff-viewer__inline language-${toLanguageClass(languageLabel)}`,
944
+ "aria-label": "Inline diff",
945
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { className: "eth-dev-diff-viewer__code", children: diff.map((line, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DiffLineView, { line }, index)) })
946
+ }
947
+ ) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "eth-dev-diff-viewer__split", role: "table", "aria-label": "Side-by-side diff", children: [
948
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { role: "rowgroup", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "eth-dev-diff-viewer__split-header", role: "row", children: [
949
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { role: "columnheader", children: "Before" }),
950
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { role: "columnheader", children: "After" })
951
+ ] }) }),
952
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "eth-dev-diff-viewer__split-body", role: "rowgroup", children: diff.map((line, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
953
+ "div",
954
+ {
955
+ className: `eth-dev-diff-viewer__split-row eth-dev-diff-viewer__split-row--${line.type}`,
956
+ role: "row",
957
+ children: [
958
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DiffCell, { side: "before", line }),
959
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DiffCell, { side: "after", line })
960
+ ]
961
+ },
962
+ index
963
+ )) })
964
+ ] })
965
+ ]
966
+ }
967
+ );
968
+ }
969
+ function DiffLineView({ line }) {
970
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: `eth-dev-diff-viewer__line eth-dev-diff-viewer__line--${line.type}`, children: [
971
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "eth-dev-diff-viewer__gutter", children: line.beforeLine ?? line.afterLine ?? "" }),
972
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "eth-dev-diff-viewer__marker", children: lineMarker(line.type) }),
973
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "eth-dev-diff-viewer__content", children: line.text || " " })
974
+ ] });
975
+ }
976
+ function DiffCell({ side, line }) {
977
+ const empty = side === "before" && line.type === "add" || side === "after" && line.type === "remove";
978
+ const lineNumber = side === "before" ? line.beforeLine : line.afterLine;
979
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
980
+ "pre",
981
+ {
982
+ className: `eth-dev-diff-viewer__cell eth-dev-diff-viewer__cell--${empty ? "empty" : line.type}`,
983
+ role: "cell",
984
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("code", { className: "eth-dev-diff-viewer__cell-code", children: [
985
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "eth-dev-diff-viewer__gutter", children: empty ? "" : lineNumber ?? "" }),
986
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "eth-dev-diff-viewer__marker", children: empty ? " " : lineMarker(line.type) }),
987
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "eth-dev-diff-viewer__content", children: empty ? " " : line.text || " " })
988
+ ] })
989
+ }
990
+ );
991
+ }
992
+ function lineMarker(type) {
993
+ if (type === "add") return "+";
994
+ if (type === "remove") return "-";
995
+ return " ";
996
+ }
997
+ function toLanguageClass(language) {
998
+ return language.toLowerCase().replace(/[^a-z0-9_-]/g, "-");
999
+ }
1000
+
1001
+ // src/components/JSONViewer.tsx
1002
+ var React6 = __toESM(require("react"), 1);
1003
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1004
+ function JSONViewer({
1005
+ value,
1006
+ defaultExpandedDepth = 2,
1007
+ className,
1008
+ ...props
1009
+ }) {
1010
+ const [view, setView] = React6.useState("tree");
1011
+ const treeTabRef = React6.useRef(null);
1012
+ const rawTabRef = React6.useRef(null);
1013
+ const treeTabId = React6.useId();
1014
+ const rawTabId = React6.useId();
1015
+ const treePanelId = React6.useId();
1016
+ const rawPanelId = React6.useId();
1017
+ const selectView = (nextView, shouldFocus = false) => {
1018
+ setView(nextView);
1019
+ if (shouldFocus) {
1020
+ window.requestAnimationFrame(() => {
1021
+ (nextView === "tree" ? treeTabRef : rawTabRef).current?.focus();
1022
+ });
1023
+ }
1024
+ };
1025
+ const onTabKeyDown = (event) => {
1026
+ if (event.key === "ArrowLeft" || event.key === "Home") {
1027
+ event.preventDefault();
1028
+ selectView("tree", true);
1029
+ } else if (event.key === "ArrowRight" || event.key === "End") {
1030
+ event.preventDefault();
1031
+ selectView("raw", true);
1032
+ }
1033
+ };
1034
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1035
+ "section",
1036
+ {
1037
+ ...props,
1038
+ className: `eth-dev-json-viewer ${className ?? ""}`,
1039
+ "data-eth-component": "JSONViewer",
1040
+ children: [
1041
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("header", { className: "eth-dev-json-viewer__tabs", role: "tablist", "aria-label": "JSON view mode", children: [
1042
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1043
+ "button",
1044
+ {
1045
+ "aria-controls": treePanelId,
1046
+ "aria-selected": view === "tree",
1047
+ className: "eth-dev-json-viewer__tab",
1048
+ id: treeTabId,
1049
+ ref: treeTabRef,
1050
+ role: "tab",
1051
+ tabIndex: view === "tree" ? 0 : -1,
1052
+ type: "button",
1053
+ onClick: () => selectView("tree"),
1054
+ onKeyDown: onTabKeyDown,
1055
+ children: "Tree"
1056
+ }
1057
+ ),
1058
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1059
+ "button",
1060
+ {
1061
+ "aria-controls": rawPanelId,
1062
+ "aria-selected": view === "raw",
1063
+ className: "eth-dev-json-viewer__tab",
1064
+ id: rawTabId,
1065
+ ref: rawTabRef,
1066
+ role: "tab",
1067
+ tabIndex: view === "raw" ? 0 : -1,
1068
+ type: "button",
1069
+ onClick: () => selectView("raw"),
1070
+ onKeyDown: onTabKeyDown,
1071
+ children: "Raw"
1072
+ }
1073
+ )
1074
+ ] }),
1075
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1076
+ "div",
1077
+ {
1078
+ "aria-labelledby": treeTabId,
1079
+ className: "eth-dev-json-viewer__tree",
1080
+ hidden: view !== "tree",
1081
+ id: treePanelId,
1082
+ role: "tabpanel",
1083
+ tabIndex: 0,
1084
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "eth-dev-json-viewer__tree-body", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(JSONNode, { name: "root", value, depth: 0, expandedDepth: defaultExpandedDepth }) })
1085
+ }
1086
+ ),
1087
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1088
+ "pre",
1089
+ {
1090
+ "aria-labelledby": rawTabId,
1091
+ className: "eth-dev-json-viewer__raw",
1092
+ hidden: view !== "raw",
1093
+ id: rawPanelId,
1094
+ role: "tabpanel",
1095
+ tabIndex: 0,
1096
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("code", { children: formatRawValue(value) })
1097
+ }
1098
+ )
1099
+ ]
1100
+ }
1101
+ );
1102
+ }
1103
+ function JSONNode({
1104
+ name,
1105
+ value,
1106
+ depth,
1107
+ expandedDepth
1108
+ }) {
1109
+ if (value === null || typeof value !== "object") {
1110
+ const type = leafType(value);
1111
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "eth-dev-json-viewer__leaf", children: [
1112
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "eth-dev-json-viewer__key", children: name }),
1113
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "eth-dev-json-viewer__punctuation", children: ":" }),
1114
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: `eth-dev-json-viewer__value eth-dev-json-viewer__value--${type}`, children: formatLeafValue(value) })
1115
+ ] });
1116
+ }
1117
+ const entries = Array.isArray(value) ? value.map((item, index) => [String(index), item]) : Object.entries(value);
1118
+ const isArray = Array.isArray(value);
1119
+ const collectionMeta = isArray ? `[${entries.length}]` : `{${entries.length}}`;
1120
+ if (entries.length === 0) {
1121
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "eth-dev-json-viewer__leaf eth-dev-json-viewer__leaf--empty", children: [
1122
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "eth-dev-json-viewer__key", children: name }),
1123
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "eth-dev-json-viewer__node-meta", children: isArray ? "[]" : "{}" })
1124
+ ] });
1125
+ }
1126
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("details", { open: depth < expandedDepth, className: "eth-dev-json-viewer__branch", children: [
1127
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("summary", { children: [
1128
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "eth-dev-json-viewer__disclosure", "aria-hidden": "true" }),
1129
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "eth-dev-json-viewer__summary-label", children: name }),
1130
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "eth-dev-json-viewer__node-meta", children: collectionMeta })
1131
+ ] }),
1132
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "eth-dev-json-viewer__children", children: entries.map(([key, child]) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1133
+ JSONNode,
1134
+ {
1135
+ name: key,
1136
+ value: child,
1137
+ depth: depth + 1,
1138
+ expandedDepth
1139
+ },
1140
+ key
1141
+ )) })
1142
+ ] });
1143
+ }
1144
+ function leafType(value) {
1145
+ if (value === null) return "null";
1146
+ return typeof value;
1147
+ }
1148
+ function formatRawValue(value) {
1149
+ try {
1150
+ const formatted = JSON.stringify(value, null, 2);
1151
+ if (typeof formatted === "string") return formatted;
1152
+ } catch {
1153
+ }
1154
+ return formatLeafValue(value);
1155
+ }
1156
+ function formatLeafValue(value) {
1157
+ if (typeof value === "string") return JSON.stringify(value);
1158
+ if (typeof value === "undefined") return "undefined";
1159
+ if (typeof value === "symbol") return value.toString();
1160
+ if (typeof value === "function") return "[Function]";
1161
+ if (value === null) return "null";
1162
+ try {
1163
+ return JSON.stringify(value);
1164
+ } catch {
1165
+ return String(value);
1166
+ }
1167
+ }
1168
+
1169
+ // src/components/EventPayloadViewer.tsx
1170
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1171
+ function EventPayloadViewer({
1172
+ eventId,
1173
+ payload,
1174
+ className,
1175
+ "aria-label": ariaLabel,
1176
+ ...props
1177
+ }) {
1178
+ const summary = describePayload(payload);
1179
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1180
+ "section",
1181
+ {
1182
+ ...props,
1183
+ className: `eth-dev-event-payload-viewer ${className ?? ""}`,
1184
+ "aria-label": ariaLabel ?? (eventId ? `Event payload ${eventId}` : "Event payload"),
1185
+ "data-eth-component": "EventPayloadViewer",
1186
+ children: [
1187
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("header", { className: "eth-dev-event-payload-viewer__header", children: [
1188
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "eth-dev-event-payload-viewer__heading", children: [
1189
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Event payload" }),
1190
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h3", { children: eventId ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("code", { children: eventId }) : "Payload" })
1191
+ ] }),
1192
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("dl", { className: "eth-dev-event-payload-viewer__summary", "aria-label": "Payload summary", children: [
1193
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
1194
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("dt", { children: "Root" }),
1195
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("dd", { children: summary.root })
1196
+ ] }),
1197
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
1198
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("dt", { children: summary.countLabel }),
1199
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("dd", { children: summary.countValue })
1200
+ ] }),
1201
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
1202
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("dt", { children: "Size" }),
1203
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("dd", { children: summary.size })
1204
+ ] })
1205
+ ] })
1206
+ ] }),
1207
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(JSONViewer, { className: "eth-dev-event-payload-viewer__json", value: payload, defaultExpandedDepth: 3 })
1208
+ ]
1209
+ }
1210
+ );
1211
+ }
1212
+ function describePayload(value) {
1213
+ const text = serializePayload(value);
1214
+ if (Array.isArray(value)) {
1215
+ return {
1216
+ root: "array",
1217
+ countLabel: "Items",
1218
+ countValue: String(value.length),
1219
+ size: formatPayloadSize(text.length)
1220
+ };
1221
+ }
1222
+ if (value !== null && typeof value === "object") {
1223
+ return {
1224
+ root: "object",
1225
+ countLabel: "Fields",
1226
+ countValue: String(Object.keys(value).length),
1227
+ size: formatPayloadSize(text.length)
1228
+ };
1229
+ }
1230
+ return {
1231
+ root: value === null ? "null" : typeof value,
1232
+ countLabel: "Shape",
1233
+ countValue: "scalar",
1234
+ size: formatPayloadSize(text.length)
1235
+ };
1236
+ }
1237
+ function serializePayload(value) {
1238
+ if (typeof value === "string") return value;
1239
+ if (typeof value === "undefined") return "";
1240
+ try {
1241
+ return JSON.stringify(value, null, 2) ?? "";
1242
+ } catch {
1243
+ return String(value);
1244
+ }
1245
+ }
1246
+ function formatPayloadSize(size) {
1247
+ if (size < 1e3) return `${size} B`;
1248
+ if (size < 1e3 * 1e3) return `${(size / 1e3).toFixed(1)} KB`;
1249
+ return `${(size / (1e3 * 1e3)).toFixed(1)} MB`;
1250
+ }
1251
+
1252
+ // src/components/GitRepositoryPanel.tsx
1253
+ var import_icons_react2 = require("@carbon/icons-react");
1254
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1255
+ function GitRepositoryPanel({ repo, className, ...props }) {
1256
+ const summaryItems = [
1257
+ {
1258
+ label: "Default branch",
1259
+ value: repo.defaultBranch,
1260
+ icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_icons_react2.Branch, { size: 16 }),
1261
+ valueClassName: "eth-dev-git-repository-panel__metric-value--code"
1262
+ },
1263
+ {
1264
+ label: "Open PRs",
1265
+ value: String(repo.openPrCount ?? 0),
1266
+ icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_icons_react2.PullRequest, { size: 16 })
1267
+ },
1268
+ {
1269
+ label: "Commits",
1270
+ value: String(repo.commitCount ?? 0),
1271
+ icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_icons_react2.Commit, { size: 16 })
1272
+ },
1273
+ {
1274
+ label: "Last commit",
1275
+ value: repo.lastCommitAt ?? "No activity",
1276
+ icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_icons_react2.Time, { size: 16 }),
1277
+ valueClassName: "eth-dev-git-repository-panel__metric-value--code"
1278
+ }
1279
+ ];
1280
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1281
+ "section",
1282
+ {
1283
+ ...props,
1284
+ "aria-label": props["aria-label"] ?? `${repo.name} repository summary`,
1285
+ className: `eth-dev-git-repository-panel ${className ?? ""}`,
1286
+ "data-eth-component": "GitRepositoryPanel",
1287
+ children: [
1288
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("header", { className: "eth-dev-git-repository-panel__header", children: [
1289
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "eth-dev-git-repository-panel__identity", children: [
1290
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "eth-dev-git-repository-panel__icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_icons_react2.GitRepo, { size: 20 }) }),
1291
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "eth-dev-git-repository-panel__heading", children: [
1292
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { children: "Repository" }),
1293
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h3", { children: repo.name }),
1294
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("a", { className: "eth-dev-git-repository-panel__url", href: repo.url, title: repo.url, children: repo.url })
1295
+ ] })
1296
+ ] }),
1297
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1298
+ "a",
1299
+ {
1300
+ className: "eth-dev-git-repository-panel__action",
1301
+ href: repo.url,
1302
+ "aria-label": `Open ${repo.name} repository`,
1303
+ children: [
1304
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Open repository" }),
1305
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_icons_react2.Launch, { size: 16, "aria-hidden": "true" })
1306
+ ]
1307
+ }
1308
+ )
1309
+ ] }),
1310
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("dl", { className: "eth-dev-git-repository-panel__metrics", "aria-label": "Repository metrics", children: summaryItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "eth-dev-git-repository-panel__metric", children: [
1311
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("dt", { children: [
1312
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { "aria-hidden": "true", children: item.icon }),
1313
+ item.label
1314
+ ] }),
1315
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("dd", { className: item.valueClassName, children: item.value })
1316
+ ] }, item.label)) })
1317
+ ]
1318
+ }
1319
+ );
1320
+ }
1321
+
1322
+ // src/components/LogConsole.tsx
1323
+ var import_icons_react3 = require("@carbon/icons-react");
1324
+ var import_core7 = require("@echothink-ui/core");
1325
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1326
+ var levelAliases = {
1327
+ debug: "debug",
1328
+ error: "error",
1329
+ err: "error",
1330
+ fatal: "error",
1331
+ info: "info",
1332
+ notice: "info",
1333
+ stderr: "stderr",
1334
+ stdout: "stdout",
1335
+ trace: "debug",
1336
+ warn: "warn",
1337
+ warning: "warn"
1338
+ };
1339
+ function getEntryLevel(entry) {
1340
+ return (entry.level ?? entry.stream ?? "info").toString();
1341
+ }
1342
+ function getEntryTone(entry) {
1343
+ return levelAliases[getEntryLevel(entry).toLowerCase()] ?? "info";
1344
+ }
1345
+ function isWarning(entry) {
1346
+ return getEntryTone(entry) === "warn";
1347
+ }
1348
+ function isError(entry) {
1349
+ const tone = getEntryTone(entry);
1350
+ return tone === "error" || tone === "stderr";
1351
+ }
1352
+ function formatLevel(entry) {
1353
+ return getEntryLevel(entry).toUpperCase();
1354
+ }
1355
+ function formatMessage(entry) {
1356
+ return entry.message ?? entry.text ?? "";
1357
+ }
1358
+ function LogConsole({
1359
+ entries,
1360
+ onPause,
1361
+ streaming = false,
1362
+ filters,
1363
+ className,
1364
+ role = "region",
1365
+ "aria-label": ariaLabel = "Streaming log console",
1366
+ "aria-labelledby": ariaLabelledBy,
1367
+ ...props
1368
+ }) {
1369
+ const warningCount = entries.filter(isWarning).length;
1370
+ const errorCount = entries.filter(isError).length;
1371
+ const latestEntry = entries[entries.length - 1];
1372
+ const latestTimestamp = latestEntry?.timestamp ?? "No activity";
1373
+ const hasToolbar = Boolean(filters || onPause);
1374
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1375
+ "section",
1376
+ {
1377
+ ...props,
1378
+ role,
1379
+ "aria-label": ariaLabelledBy ? void 0 : ariaLabel,
1380
+ "aria-labelledby": ariaLabelledBy,
1381
+ className: `eth-dev-log-console ${streaming ? "eth-dev-log-console--streaming" : "eth-dev-log-console--paused"} ${className ?? ""}`,
1382
+ "data-eth-component": "LogConsole",
1383
+ children: [
1384
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("header", { className: "eth-dev-log-console__header", children: [
1385
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "eth-dev-log-console__heading", children: [
1386
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "eth-dev-log-console__eyebrow", children: "Developer console" }),
1387
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h3", { children: "Streaming logs" }),
1388
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("p", { children: [
1389
+ entries.length,
1390
+ " ",
1391
+ entries.length === 1 ? "entry" : "entries",
1392
+ " buffered from the active stream."
1393
+ ] })
1394
+ ] }),
1395
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "eth-dev-log-console__status", "aria-live": "polite", children: [
1396
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_core7.Badge, { severity: streaming ? "success" : "neutral", children: streaming ? "Streaming" : "Paused" }),
1397
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: errorCount ? `${errorCount} errors` : "No errors" })
1398
+ ] })
1399
+ ] }),
1400
+ hasToolbar ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "eth-dev-log-console__toolbar", role: "toolbar", "aria-label": "Log controls", children: [
1401
+ filters ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "eth-dev-log-console__filters", children: filters }) : null,
1402
+ onPause ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1403
+ import_core7.Button,
1404
+ {
1405
+ intent: streaming ? "secondary" : "primary",
1406
+ density: "compact",
1407
+ icon: streaming ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_icons_react3.Pause, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_icons_react3.Play, { size: 16 }),
1408
+ onClick: onPause,
1409
+ children: streaming ? "Pause stream" : "Resume stream"
1410
+ }
1411
+ ) : null
1412
+ ] }) : null,
1413
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("dl", { className: "eth-dev-log-console__summary", "aria-label": "Log summary", children: [
1414
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
1415
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("dt", { children: "Entries" }),
1416
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("dd", { children: entries.length })
1417
+ ] }),
1418
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
1419
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("dt", { children: "Warnings" }),
1420
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("dd", { children: warningCount })
1421
+ ] }),
1422
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
1423
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("dt", { children: "Errors" }),
1424
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("dd", { children: errorCount })
1425
+ ] }),
1426
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
1427
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("dt", { children: "Latest" }),
1428
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("dd", { children: latestTimestamp })
1429
+ ] })
1430
+ ] }),
1431
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "eth-dev-log-console__viewport", children: entries.length ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1432
+ "div",
1433
+ {
1434
+ className: "eth-dev-log-console__entries",
1435
+ role: "log",
1436
+ "aria-live": streaming ? "polite" : "off",
1437
+ "aria-relevant": "additions text",
1438
+ "aria-atomic": "false",
1439
+ children: entries.map((entry) => {
1440
+ const tone = getEntryTone(entry);
1441
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1442
+ "div",
1443
+ {
1444
+ className: `eth-dev-log-console__entry eth-dev-log-console__entry--${tone}`,
1445
+ children: [
1446
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("time", { className: "eth-dev-log-console__timestamp", children: entry.timestamp ?? "--:--:--" }),
1447
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "eth-dev-log-console__level", children: formatLevel(entry) }),
1448
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "eth-dev-log-console__source", children: entry.source ?? entry.stream ?? "system" }),
1449
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", { className: "eth-dev-log-console__message", children: formatMessage(entry) })
1450
+ ]
1451
+ },
1452
+ entry.id
1453
+ );
1454
+ })
1455
+ }
1456
+ ) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "eth-dev-log-console__empty", role: "status", children: [
1457
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h4", { children: "No log entries" }),
1458
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { children: "Events will appear here when the stream receives output." })
1459
+ ] }) })
1460
+ ]
1461
+ }
1462
+ );
1463
+ }
1464
+
1465
+ // src/components/PullRequestPanel.tsx
1466
+ var React7 = __toESM(require("react"), 1);
1467
+ var import_icons_react4 = require("@carbon/icons-react");
1468
+ var import_core8 = require("@echothink-ui/core");
1469
+ var import_data2 = require("@echothink-ui/data");
1470
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1471
+ function formatState(state) {
1472
+ const normalized = state.trim();
1473
+ if (!normalized) return "Unknown";
1474
+ return normalized.split(/[\s_-]+/).map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1).toLowerCase()}`).join(" ");
1475
+ }
1476
+ function stateClassName(state) {
1477
+ const normalized = state.trim().toLowerCase();
1478
+ if (["open", "opened", "ready"].includes(normalized)) {
1479
+ return "eth-dev-pull-request-panel__state--open";
1480
+ }
1481
+ if (["merged", "approved"].includes(normalized)) {
1482
+ return "eth-dev-pull-request-panel__state--merged";
1483
+ }
1484
+ if (["closed", "rejected", "blocked"].includes(normalized)) {
1485
+ return "eth-dev-pull-request-panel__state--closed";
1486
+ }
1487
+ if (["draft", "pending"].includes(normalized)) {
1488
+ return "eth-dev-pull-request-panel__state--draft";
1489
+ }
1490
+ return "eth-dev-pull-request-panel__state--unknown";
1491
+ }
1492
+ function PullRequestPanel({
1493
+ pr,
1494
+ onApprove,
1495
+ onComment,
1496
+ className,
1497
+ ...props
1498
+ }) {
1499
+ const [comment, setComment] = React7.useState("");
1500
+ const titleId = React7.useId().replace(/:/g, "");
1501
+ const filesTitleId = React7.useId().replace(/:/g, "");
1502
+ const files = pr.files ?? [];
1503
+ const reviewers = pr.reviewers?.length ? pr.reviewers.join(", ") : "No reviewers";
1504
+ const additions = files.reduce((sum, file) => sum + file.additions, 0);
1505
+ const deletions = files.reduce((sum, file) => sum + file.deletions, 0);
1506
+ const formattedState = formatState(pr.state);
1507
+ const ariaLabel = props["aria-label"] ?? (props["aria-labelledby"] ? void 0 : `Pull request ${pr.title}`);
1508
+ const columns = [
1509
+ {
1510
+ key: "path",
1511
+ header: "File",
1512
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("code", { className: "eth-dev-pull-request-panel__file-path", title: row.path, children: row.path })
1513
+ },
1514
+ {
1515
+ key: "additions",
1516
+ header: "Additions",
1517
+ align: "end",
1518
+ width: "7rem",
1519
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "eth-dev-pull-request-panel__count eth-dev-pull-request-panel__count--added", children: [
1520
+ "+",
1521
+ row.additions
1522
+ ] })
1523
+ },
1524
+ {
1525
+ key: "deletions",
1526
+ header: "Deletions",
1527
+ align: "end",
1528
+ width: "7rem",
1529
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "eth-dev-pull-request-panel__count eth-dev-pull-request-panel__count--removed", children: [
1530
+ "-",
1531
+ row.deletions
1532
+ ] })
1533
+ }
1534
+ ];
1535
+ const submitComment = (event) => {
1536
+ event.preventDefault();
1537
+ const nextComment = comment.trim();
1538
+ if (!nextComment) return;
1539
+ onComment?.(nextComment);
1540
+ setComment("");
1541
+ };
1542
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1543
+ "section",
1544
+ {
1545
+ ...props,
1546
+ "aria-label": ariaLabel,
1547
+ className: `eth-dev-pull-request-panel ${className ?? ""}`,
1548
+ "data-eth-component": "PullRequestPanel",
1549
+ role: "region",
1550
+ children: [
1551
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("header", { className: "eth-dev-pull-request-panel__header", children: [
1552
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "eth-dev-pull-request-panel__identity", children: [
1553
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "eth-dev-pull-request-panel__icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_icons_react4.PullRequest, { size: 20 }) }),
1554
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "eth-dev-pull-request-panel__heading", children: [
1555
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("p", { children: [
1556
+ "Pull request ",
1557
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { children: [
1558
+ "#",
1559
+ pr.id
1560
+ ] })
1561
+ ] }),
1562
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h3", { id: titleId, children: pr.title }),
1563
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "eth-dev-pull-request-panel__meta", children: [
1564
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1565
+ "span",
1566
+ {
1567
+ className: `eth-dev-pull-request-panel__state ${stateClassName(pr.state)}`,
1568
+ children: formattedState
1569
+ }
1570
+ ),
1571
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { children: [
1572
+ "by ",
1573
+ pr.author
1574
+ ] })
1575
+ ] })
1576
+ ] })
1577
+ ] }),
1578
+ onApprove ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1579
+ import_core8.Button,
1580
+ {
1581
+ "aria-label": "Approve pull request",
1582
+ className: "eth-dev-pull-request-panel__approve",
1583
+ density: "compact",
1584
+ icon: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_icons_react4.Checkmark, { size: 16 }),
1585
+ intent: "success",
1586
+ onClick: onApprove,
1587
+ children: "Approve"
1588
+ }
1589
+ ) : null
1590
+ ] }),
1591
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "eth-dev-pull-request-panel__body", children: [
1592
+ pr.body ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "eth-dev-pull-request-panel__description", children: pr.body }) : null,
1593
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("dl", { className: "eth-dev-pull-request-panel__metrics", "aria-label": "Pull request summary", children: [
1594
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
1595
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("dt", { children: "Reviewers" }),
1596
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("dd", { title: reviewers, children: reviewers })
1597
+ ] }),
1598
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
1599
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("dt", { children: "Commits" }),
1600
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("dd", { children: pr.commits ?? 0 })
1601
+ ] }),
1602
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
1603
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("dt", { children: "Files changed" }),
1604
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("dd", { children: files.length })
1605
+ ] }),
1606
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
1607
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("dt", { children: "Line delta" }),
1608
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("dd", { children: [
1609
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "eth-dev-pull-request-panel__count eth-dev-pull-request-panel__count--added", children: [
1610
+ "+",
1611
+ additions
1612
+ ] }),
1613
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { "aria-hidden": "true", children: " / " }),
1614
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "eth-dev-pull-request-panel__count eth-dev-pull-request-panel__count--removed", children: [
1615
+ "-",
1616
+ deletions
1617
+ ] })
1618
+ ] })
1619
+ ] })
1620
+ ] })
1621
+ ] }),
1622
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("section", { className: "eth-dev-pull-request-panel__files", "aria-labelledby": filesTitleId, children: [
1623
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "eth-dev-pull-request-panel__files-header", children: [
1624
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h4", { id: filesTitleId, children: "Changed files" }),
1625
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { children: [
1626
+ files.length,
1627
+ " files"
1628
+ ] })
1629
+ ] }),
1630
+ files.length ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1631
+ import_data2.DataTable,
1632
+ {
1633
+ "aria-label": "Changed files",
1634
+ className: "eth-dev-pull-request-panel__table",
1635
+ columns,
1636
+ density: "compact",
1637
+ rowKey: "path",
1638
+ rows: files
1639
+ }
1640
+ ) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1641
+ import_core8.EmptyState,
1642
+ {
1643
+ title: "No file changes",
1644
+ description: "Changed files will appear when this pull request has a diff."
1645
+ }
1646
+ )
1647
+ ] }),
1648
+ onComment ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1649
+ "form",
1650
+ {
1651
+ "aria-label": "Review comment form",
1652
+ className: "eth-dev-pull-request-panel__comment",
1653
+ onSubmit: submitComment,
1654
+ children: [
1655
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1656
+ import_core8.Textarea,
1657
+ {
1658
+ helperText: "Add a blocking question, approval note, or evidence reference.",
1659
+ labelText: "Review comment",
1660
+ onChange: (event) => setComment(event.currentTarget.value),
1661
+ placeholder: "Reference tests, policy checks, or follow-up questions.",
1662
+ rows: 4,
1663
+ value: comment
1664
+ }
1665
+ ),
1666
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "eth-dev-pull-request-panel__comment-footer", children: [
1667
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: "Comment will be attached to this pull request." }),
1668
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1669
+ import_core8.Button,
1670
+ {
1671
+ "aria-label": "Submit review comment",
1672
+ density: "compact",
1673
+ disabled: !comment.trim(),
1674
+ intent: "secondary",
1675
+ type: "submit",
1676
+ children: "Comment"
1677
+ }
1678
+ )
1679
+ ] })
1680
+ ]
1681
+ }
1682
+ ) : null
1683
+ ]
1684
+ }
1685
+ );
1686
+ }
1687
+
1688
+ // src/components/RequestResponseViewer.tsx
1689
+ var React8 = __toESM(require("react"), 1);
1690
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1691
+ var tabs = [
1692
+ { id: "request-headers", label: "Request headers", emptyLabel: "No request headers." },
1693
+ { id: "request-body", label: "Request body", emptyLabel: "No request body." },
1694
+ { id: "response-headers", label: "Response headers", emptyLabel: "No response headers." },
1695
+ { id: "response-body", label: "Response body", emptyLabel: "No response body." }
1696
+ ];
1697
+ function RequestResponseViewer({
1698
+ request,
1699
+ response,
1700
+ className,
1701
+ "aria-label": ariaLabel,
1702
+ ...props
1703
+ }) {
1704
+ const [tab, setTab] = React8.useState("request-headers");
1705
+ const tabRefs = React8.useRef([]);
1706
+ const generatedId = React8.useId().replace(/:/g, "");
1707
+ const activeIndex = Math.max(
1708
+ tabs.findIndex((item) => item.id === tab),
1709
+ 0
1710
+ );
1711
+ const regionLabel = `${request.method} ${request.url} ${response.status}`;
1712
+ const durationLabel = typeof response.durationMs === "number" ? `${response.durationMs} ms` : "Duration unavailable";
1713
+ const selectTab = (nextIndex, shouldFocus = false) => {
1714
+ const nextTab = tabs[nextIndex] ?? tabs[0];
1715
+ setTab(nextTab.id);
1716
+ if (shouldFocus) {
1717
+ window.requestAnimationFrame(() => tabRefs.current[nextIndex]?.focus());
1718
+ }
1719
+ };
1720
+ const onTabKeyDown = (event) => {
1721
+ if (event.key === "ArrowLeft") {
1722
+ event.preventDefault();
1723
+ selectTab((activeIndex - 1 + tabs.length) % tabs.length, true);
1724
+ } else if (event.key === "ArrowRight") {
1725
+ event.preventDefault();
1726
+ selectTab((activeIndex + 1) % tabs.length, true);
1727
+ } else if (event.key === "Home") {
1728
+ event.preventDefault();
1729
+ selectTab(0, true);
1730
+ } else if (event.key === "End") {
1731
+ event.preventDefault();
1732
+ selectTab(tabs.length - 1, true);
1733
+ }
1734
+ };
1735
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1736
+ "section",
1737
+ {
1738
+ ...props,
1739
+ "aria-label": ariaLabel ?? regionLabel,
1740
+ className: `eth-dev-request-response-viewer ${className ?? ""}`.trim(),
1741
+ "data-eth-component": "RequestResponseViewer",
1742
+ children: [
1743
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("header", { className: "eth-dev-request-response-viewer__header", children: [
1744
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "eth-dev-request-response-viewer__request", children: [
1745
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1746
+ "span",
1747
+ {
1748
+ className: `eth-dev-request-response-viewer__method eth-dev-request-response-viewer__method--${tokenize(request.method)}`,
1749
+ children: request.method
1750
+ }
1751
+ ),
1752
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("code", { title: request.url, children: request.url })
1753
+ ] }),
1754
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("dl", { className: "eth-dev-request-response-viewer__meta", "aria-label": "HTTP response summary", children: [
1755
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
1756
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dt", { children: "Status" }),
1757
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1758
+ "dd",
1759
+ {
1760
+ className: `eth-dev-request-response-viewer__status eth-dev-request-response-viewer__status--${statusTone(response.status)}`,
1761
+ children: response.status
1762
+ }
1763
+ )
1764
+ ] }),
1765
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
1766
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dt", { children: "Time" }),
1767
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dd", { children: durationLabel })
1768
+ ] })
1769
+ ] })
1770
+ ] }),
1771
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1772
+ "div",
1773
+ {
1774
+ className: "eth-dev-request-response-viewer__tabs",
1775
+ role: "tablist",
1776
+ "aria-label": "HTTP message sections",
1777
+ children: tabs.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1778
+ "button",
1779
+ {
1780
+ "aria-controls": `${generatedId}-${item.id}-panel`,
1781
+ "aria-selected": tab === item.id,
1782
+ className: "eth-dev-request-response-viewer__tab",
1783
+ id: `${generatedId}-${item.id}-tab`,
1784
+ ref: (node) => {
1785
+ tabRefs.current[index] = node;
1786
+ },
1787
+ role: "tab",
1788
+ tabIndex: tab === item.id ? 0 : -1,
1789
+ type: "button",
1790
+ onClick: () => selectTab(index),
1791
+ onKeyDown: onTabKeyDown,
1792
+ children: item.label
1793
+ },
1794
+ item.id
1795
+ ))
1796
+ }
1797
+ ),
1798
+ tabs.map((item) => {
1799
+ const content = contentFor(item.id, request, response);
1800
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1801
+ "pre",
1802
+ {
1803
+ "aria-labelledby": `${generatedId}-${item.id}-tab`,
1804
+ className: `eth-dev-request-response-viewer__panel ${content ? "" : "eth-dev-request-response-viewer__panel--empty"}`.trim(),
1805
+ hidden: tab !== item.id,
1806
+ id: `${generatedId}-${item.id}-panel`,
1807
+ role: "tabpanel",
1808
+ tabIndex: tab === item.id ? 0 : -1,
1809
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("code", { children: content || item.emptyLabel })
1810
+ },
1811
+ item.id
1812
+ );
1813
+ })
1814
+ ]
1815
+ }
1816
+ );
1817
+ }
1818
+ function contentFor(tab, request, response) {
1819
+ switch (tab) {
1820
+ case "request-headers":
1821
+ return formatHeaders(request.headers);
1822
+ case "request-body":
1823
+ return formatUnknown(request.body);
1824
+ case "response-headers":
1825
+ return formatHeaders(response.headers);
1826
+ case "response-body":
1827
+ return formatUnknown(response.body);
1828
+ }
1829
+ }
1830
+ function formatHeaders(headers) {
1831
+ if (!headers || Object.keys(headers).length === 0) return "";
1832
+ return formatUnknown(headers);
1833
+ }
1834
+ function statusTone(status) {
1835
+ if (status >= 200 && status < 300) return "success";
1836
+ if (status >= 300 && status < 400) return "redirect";
1837
+ if (status >= 400 && status < 500) return "warning";
1838
+ if (status >= 500) return "error";
1839
+ return "neutral";
1840
+ }
1841
+ function tokenize(value) {
1842
+ return value.toLowerCase().replace(/[^a-z0-9-]/g, "");
1843
+ }
1844
+
1845
+ // src/components/SchemaViewer.tsx
1846
+ var React9 = __toESM(require("react"), 1);
1847
+ var import_icons_react5 = require("@carbon/icons-react");
1848
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1849
+ function SchemaViewer({
1850
+ schema,
1851
+ validationState,
1852
+ className,
1853
+ ...props
1854
+ }) {
1855
+ const stats = React9.useMemo(() => collectSchemaStats(schema), [schema]);
1856
+ const tone = normalizeValidationState(validationState);
1857
+ const status = getStatusConfig(tone, stats);
1858
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1859
+ "section",
1860
+ {
1861
+ ...props,
1862
+ className: `eth-dev-schema-viewer ${className ?? ""}`,
1863
+ "data-eth-component": "SchemaViewer",
1864
+ "data-validation-state": tone,
1865
+ children: [
1866
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("header", { className: "eth-dev-schema-viewer__status", children: [
1867
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "eth-dev-schema-viewer__status-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(StatusIcon, { tone }) }),
1868
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "eth-dev-schema-viewer__status-copy", children: [
1869
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "eth-dev-schema-viewer__status-title", children: status.title }),
1870
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "eth-dev-schema-viewer__status-description", children: status.description })
1871
+ ] }),
1872
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("dl", { className: "eth-dev-schema-viewer__stats", "aria-label": "Schema summary", children: [
1873
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
1874
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("dt", { children: "Keys" }),
1875
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("dd", { children: stats.topLevelKeys })
1876
+ ] }),
1877
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
1878
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("dt", { children: "Properties" }),
1879
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("dd", { children: stats.properties })
1880
+ ] }),
1881
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
1882
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("dt", { children: "Required" }),
1883
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("dd", { children: stats.required })
1884
+ ] })
1885
+ ] })
1886
+ ] }),
1887
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(JSONViewer, { className: "eth-dev-schema-viewer__json", value: schema, defaultExpandedDepth: 2 })
1888
+ ]
1889
+ }
1890
+ );
1891
+ }
1892
+ function normalizeValidationState(validationState) {
1893
+ if (validationState === "valid" || validationState === "invalid" || validationState === "warning") {
1894
+ return validationState;
1895
+ }
1896
+ return "unknown";
1897
+ }
1898
+ function getStatusConfig(tone, stats) {
1899
+ const summary = `${stats.nodes} nodes inspected across ${stats.properties} properties`;
1900
+ switch (tone) {
1901
+ case "valid":
1902
+ return {
1903
+ title: "Schema valid",
1904
+ description: summary
1905
+ };
1906
+ case "invalid":
1907
+ return {
1908
+ title: "Schema invalid",
1909
+ description: "Review schema structure and validation rules before publishing."
1910
+ };
1911
+ case "warning":
1912
+ return {
1913
+ title: "Schema warning",
1914
+ description: "Schema is readable, but validation reported conditions that need review."
1915
+ };
1916
+ default:
1917
+ return {
1918
+ title: "Schema status unknown",
1919
+ description: summary
1920
+ };
1921
+ }
1922
+ }
1923
+ function collectSchemaStats(schema) {
1924
+ const stats = {
1925
+ nodes: 0,
1926
+ topLevelKeys: isPlainObject(schema) ? Object.keys(schema).length : Array.isArray(schema) ? schema.length : 1,
1927
+ properties: 0,
1928
+ required: 0
1929
+ };
1930
+ const seen = /* @__PURE__ */ new WeakSet();
1931
+ const visit = (node, key) => {
1932
+ stats.nodes += 1;
1933
+ if (Array.isArray(node)) {
1934
+ if (seen.has(node)) {
1935
+ return;
1936
+ }
1937
+ seen.add(node);
1938
+ if (key === "required" && node.every((item) => typeof item === "string")) {
1939
+ stats.required += node.length;
1940
+ }
1941
+ node.forEach((item) => visit(item));
1942
+ return;
1943
+ }
1944
+ if (!isPlainObject(node) || seen.has(node)) {
1945
+ return;
1946
+ }
1947
+ seen.add(node);
1948
+ if (isPlainObject(node.properties)) {
1949
+ stats.properties += Object.keys(node.properties).length;
1950
+ }
1951
+ Object.entries(node).forEach(([entryKey, entryValue]) => visit(entryValue, entryKey));
1952
+ };
1953
+ visit(schema);
1954
+ return stats;
1955
+ }
1956
+ function isPlainObject(value) {
1957
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1958
+ }
1959
+ function StatusIcon({ tone }) {
1960
+ if (tone === "valid") {
1961
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_icons_react5.CheckmarkFilled, { size: 20 });
1962
+ }
1963
+ if (tone === "invalid") {
1964
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_icons_react5.ErrorFilled, { size: 20 });
1965
+ }
1966
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_icons_react5.WarningFilled, { size: 20 });
1967
+ }
1968
+
1969
+ // src/components/TerminalPanel.tsx
1970
+ var React10 = __toESM(require("react"), 1);
1971
+ var import_icons_react6 = require("@carbon/icons-react");
1972
+ var import_core9 = require("@echothink-ui/core");
1973
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1974
+ function TerminalPanel({
1975
+ lines,
1976
+ prompt = "$",
1977
+ onCommand,
1978
+ disabled,
1979
+ className,
1980
+ role = "region",
1981
+ "aria-label": ariaLabel = "Sandbox terminal",
1982
+ "aria-labelledby": ariaLabelledBy,
1983
+ ...props
1984
+ }) {
1985
+ const [command, setCommand] = React10.useState("");
1986
+ const inputId = React10.useId();
1987
+ const errorCount = lines.filter((line) => line.stream === "stderr").length;
1988
+ const canSubmit = !disabled && command.trim().length > 0;
1989
+ const statusLabel2 = disabled ? "Input disabled" : "Sandboxed";
1990
+ const panelClassName = [
1991
+ "eth-dev-terminal-panel",
1992
+ disabled ? "eth-dev-terminal-panel--disabled" : "",
1993
+ className ?? ""
1994
+ ].filter(Boolean).join(" ");
1995
+ const submit = (event) => {
1996
+ event.preventDefault();
1997
+ if (!canSubmit) return;
1998
+ onCommand?.(command);
1999
+ setCommand("");
2000
+ };
2001
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2002
+ "section",
2003
+ {
2004
+ ...props,
2005
+ className: panelClassName,
2006
+ "data-eth-component": "TerminalPanel",
2007
+ role,
2008
+ "aria-label": ariaLabelledBy ? void 0 : ariaLabel,
2009
+ "aria-labelledby": ariaLabelledBy,
2010
+ children: [
2011
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("header", { className: "eth-dev-terminal-panel__header", children: [
2012
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "eth-dev-terminal-panel__heading", children: [
2013
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "eth-dev-terminal-panel__eyebrow", children: "Developer terminal" }),
2014
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h3", { children: "Sandbox terminal" }),
2015
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { children: "Review command output and send scoped commands into the configured sandbox." })
2016
+ ] }),
2017
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "eth-dev-terminal-panel__status", "aria-live": "polite", children: [
2018
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "eth-dev-terminal-panel__status-indicator", "aria-hidden": "true" }),
2019
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: statusLabel2 })
2020
+ ] })
2021
+ ] }),
2022
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("dl", { className: "eth-dev-terminal-panel__summary", "aria-label": "Terminal summary", children: [
2023
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
2024
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dt", { children: "Lines" }),
2025
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dd", { children: lines.length })
2026
+ ] }),
2027
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
2028
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dt", { children: "Stderr" }),
2029
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dd", { children: errorCount })
2030
+ ] }),
2031
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
2032
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dt", { children: "Prompt" }),
2033
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dd", { children: prompt })
2034
+ ] })
2035
+ ] }),
2036
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "eth-dev-terminal-panel__viewport", children: lines.length ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2037
+ "pre",
2038
+ {
2039
+ className: "eth-dev-terminal-panel__output",
2040
+ role: "log",
2041
+ "aria-label": "Terminal output",
2042
+ "aria-live": "polite",
2043
+ "aria-relevant": "additions text",
2044
+ "aria-atomic": "false",
2045
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("code", { className: "eth-dev-terminal-panel__output-code", children: lines.map((line) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2046
+ "span",
2047
+ {
2048
+ className: `eth-dev-terminal-panel__line eth-dev-terminal-panel__line--${line.stream}`,
2049
+ children: [
2050
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2051
+ "span",
2052
+ {
2053
+ className: "eth-dev-terminal-panel__stream",
2054
+ "aria-label": line.stream === "stderr" ? "Standard error" : "Standard output",
2055
+ children: line.stream === "stderr" ? "ERR" : "OUT"
2056
+ }
2057
+ ),
2058
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "eth-dev-terminal-panel__line-text", children: line.text })
2059
+ ]
2060
+ },
2061
+ line.id
2062
+ )) })
2063
+ }
2064
+ ) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "eth-dev-terminal-panel__empty", role: "status", children: [
2065
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h4", { children: "No terminal output" }),
2066
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { children: "Command output will appear here when the sandbox emits data." })
2067
+ ] }) }),
2068
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("form", { className: "eth-dev-terminal-panel__input", onSubmit: submit, children: [
2069
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("label", { className: "eth-dev-terminal-panel__visually-hidden", htmlFor: inputId, children: "Terminal command" }),
2070
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "eth-dev-terminal-panel__prompt", "aria-hidden": "true", children: prompt }),
2071
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2072
+ "input",
2073
+ {
2074
+ id: inputId,
2075
+ value: command,
2076
+ disabled,
2077
+ onChange: (event) => setCommand(event.currentTarget.value),
2078
+ autoComplete: "off",
2079
+ spellCheck: false,
2080
+ placeholder: disabled ? "Input disabled" : "Type a command"
2081
+ }
2082
+ ),
2083
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2084
+ import_core9.Button,
2085
+ {
2086
+ type: "submit",
2087
+ density: "compact",
2088
+ intent: "primary",
2089
+ icon: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_icons_react6.Play, { size: 16 }),
2090
+ disabled: !canSubmit,
2091
+ "aria-label": "Run command",
2092
+ children: "Run"
2093
+ }
2094
+ )
2095
+ ] })
2096
+ ]
2097
+ }
2098
+ );
2099
+ }
2100
+
2101
+ // src/components/TraceTimeline.tsx
2102
+ var React11 = __toESM(require("react"), 1);
2103
+ var import_core10 = require("@echothink-ui/core");
2104
+ var import_jsx_runtime16 = require("react/jsx-runtime");
2105
+ function TraceTimeline({
2106
+ spans,
2107
+ className,
2108
+ role = "region",
2109
+ "aria-label": ariaLabel = "Trace timeline",
2110
+ "aria-labelledby": ariaLabelledBy,
2111
+ ...props
2112
+ }) {
2113
+ const timeline = React11.useMemo(() => buildTimeline(spans), [spans]);
2114
+ const issueCount = spans.filter((span) => isIssueStatus(getSpanStatus(span))).length;
2115
+ const activeCount = spans.filter((span) => isActiveStatus(getSpanStatus(span))).length;
2116
+ const services = new Set(spans.flatMap((span) => span.service ? [span.service] : []));
2117
+ const serviceCount = services.size;
2118
+ const describedServiceCount = spans.length ? serviceCount || 1 : 0;
2119
+ const traceDescription = spans.length ? `${spans.length} spans across ${describedServiceCount} service${describedServiceCount === 1 ? "" : "s"}.` : "No spans have been recorded for this trace window.";
2120
+ const healthLabel = issueCount ? `${issueCount} ${issueCount === 1 ? "issue" : "issues"}` : activeCount ? `${activeCount} active` : "All complete";
2121
+ const healthSeverity = issueCount ? "danger" : activeCount ? "info" : "success";
2122
+ const rootClassName = ["eth-dev-trace-timeline", className].filter(Boolean).join(" ");
2123
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
2124
+ "section",
2125
+ {
2126
+ ...props,
2127
+ "aria-label": ariaLabelledBy ? void 0 : ariaLabel,
2128
+ "aria-labelledby": ariaLabelledBy,
2129
+ className: rootClassName,
2130
+ "data-eth-component": "TraceTimeline",
2131
+ role,
2132
+ children: [
2133
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("header", { className: "eth-dev-trace-timeline__header", children: [
2134
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "eth-dev-trace-timeline__heading", children: [
2135
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "eth-dev-trace-timeline__eyebrow", children: "Distributed trace" }),
2136
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h3", { children: "Trace timeline" }),
2137
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { children: traceDescription })
2138
+ ] }),
2139
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_core10.Badge, { severity: healthSeverity, children: healthLabel })
2140
+ ] }),
2141
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("dl", { className: "eth-dev-trace-timeline__summary", "aria-label": "Trace summary", children: [
2142
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
2143
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("dt", { children: "Spans" }),
2144
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("dd", { children: spans.length })
2145
+ ] }),
2146
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
2147
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("dt", { children: "Window" }),
2148
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("dd", { children: formatDuration(timeline.total) })
2149
+ ] }),
2150
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
2151
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("dt", { children: "Issues" }),
2152
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("dd", { children: issueCount ? `${issueCount} ${issueCount === 1 ? "issue" : "issues"}` : "0" })
2153
+ ] }),
2154
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
2155
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("dt", { children: "Services" }),
2156
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("dd", { children: serviceCount })
2157
+ ] })
2158
+ ] }),
2159
+ spans.length ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "eth-dev-trace-timeline__viewport", children: [
2160
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "eth-dev-trace-timeline__axis", "aria-hidden": "true", children: [
2161
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { children: "Span" }),
2162
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "eth-dev-trace-timeline__axis-scale", children: [
2163
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { children: "0 ms" }),
2164
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { children: formatDuration(timeline.total / 2) }),
2165
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { children: formatDuration(timeline.total) })
2166
+ ] })
2167
+ ] }),
2168
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "eth-dev-trace-timeline__rows", role: "list", "aria-label": "Trace spans", children: timeline.items.map(({ span, start, end, depth }) => {
2169
+ const status = getSpanStatus(span);
2170
+ const startOffset = start - timeline.min;
2171
+ const duration = end - start;
2172
+ const left = startOffset / timeline.total * 100;
2173
+ const width = Math.max(1, duration / timeline.total * 100);
2174
+ const spanLabel = formatSpanLabel(span, status, startOffset, duration);
2175
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
2176
+ "article",
2177
+ {
2178
+ className: `eth-dev-trace-timeline__row eth-dev-trace-timeline__row--${status}`,
2179
+ role: "listitem",
2180
+ style: {
2181
+ "--eth-dev-trace-indent": `${depth}rem`,
2182
+ "--eth-dev-trace-left": `${left}%`,
2183
+ "--eth-dev-trace-width": `${width}%`
2184
+ },
2185
+ children: [
2186
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "eth-dev-trace-timeline__label", children: [
2187
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "eth-dev-trace-timeline__span-title", children: [
2188
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_core10.StatusDot, { status, label: (0, import_core10.statusLabel)(status) }),
2189
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("strong", { children: span.name })
2190
+ ] }),
2191
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "eth-dev-trace-timeline__span-meta", children: [
2192
+ span.service ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { children: span.service }) : null,
2193
+ span.parentId ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { children: [
2194
+ "Parent ",
2195
+ span.parentId
2196
+ ] }) : null,
2197
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { children: formatDuration(duration) })
2198
+ ] })
2199
+ ] }),
2200
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "eth-dev-trace-timeline__track", role: "img", "aria-label": spanLabel, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2201
+ "span",
2202
+ {
2203
+ "aria-hidden": "true",
2204
+ className: `eth-dev-trace-timeline__bar eth-dev-trace-timeline__bar--${status}`,
2205
+ title: spanLabel
2206
+ }
2207
+ ) })
2208
+ ]
2209
+ },
2210
+ span.id
2211
+ );
2212
+ }) })
2213
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "eth-dev-trace-timeline__empty", role: "status", children: [
2214
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h4", { children: "No spans recorded" }),
2215
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { children: "Trace spans will appear here when instrumentation emits timing data." })
2216
+ ] })
2217
+ ]
2218
+ }
2219
+ );
2220
+ }
2221
+ function buildTimeline(spans) {
2222
+ if (!spans.length) return { items: [], min: 0, total: 0 };
2223
+ const spansById = new Map(spans.map((span) => [span.id, span]));
2224
+ const depthById = /* @__PURE__ */ new Map();
2225
+ const depthFor = (span, seen = /* @__PURE__ */ new Set()) => {
2226
+ if (depthById.has(span.id)) return depthById.get(span.id) ?? 0;
2227
+ if (!span.parentId || seen.has(span.id)) {
2228
+ depthById.set(span.id, 0);
2229
+ return 0;
2230
+ }
2231
+ const parent = spansById.get(span.parentId);
2232
+ const depth = parent ? depthFor(parent, new Set(seen).add(span.id)) + 1 : 0;
2233
+ depthById.set(span.id, depth);
2234
+ return depth;
2235
+ };
2236
+ const items = spans.map((span, index) => {
2237
+ const start = Number.isFinite(span.startMs) ? span.startMs : index * 10;
2238
+ const duration = Number.isFinite(span.durationMs) ? Math.max(span.durationMs, 1) : 1;
2239
+ return { span, start, end: start + duration, depth: depthFor(span) };
2240
+ }).sort((a, b) => a.start - b.start || a.span.name.localeCompare(b.span.name));
2241
+ const min = Math.min(...items.map((item) => item.start));
2242
+ const max = Math.max(...items.map((item) => item.end));
2243
+ return { items, min, total: Math.max(max - min, 1) };
2244
+ }
2245
+ function getSpanStatus(span) {
2246
+ return span.status ?? "running";
2247
+ }
2248
+ function isActiveStatus(status) {
2249
+ return status === "running" || status === "in-progress";
2250
+ }
2251
+ function isIssueStatus(status) {
2252
+ return status === "failed" || status === "blocked" || status === "warning" || status === "stale";
2253
+ }
2254
+ function formatSpanLabel(span, status, startOffset, duration) {
2255
+ return `${span.name}${span.service ? ` in ${span.service}` : ""}, ${(0, import_core10.statusLabel)(
2256
+ status
2257
+ )}, starts at ${formatDuration(startOffset)}, duration ${formatDuration(duration)}`;
2258
+ }
2259
+ function formatDuration(ms) {
2260
+ if (!Number.isFinite(ms) || ms <= 0) return "0 ms";
2261
+ if (ms < 1e3) return `${Math.round(ms)} ms`;
2262
+ const seconds = ms / 1e3;
2263
+ const precision = seconds < 10 ? 2 : 1;
2264
+ return `${seconds.toFixed(precision).replace(/\.?0+$/, "")} s`;
2265
+ }
2266
+
2267
+ // src/components/WebhookEventViewer.tsx
2268
+ var import_core11 = require("@echothink-ui/core");
2269
+ var import_data3 = require("@echothink-ui/data");
2270
+ var import_jsx_runtime17 = require("react/jsx-runtime");
2271
+ function WebhookEventViewer({
2272
+ events,
2273
+ onRetry,
2274
+ className,
2275
+ "aria-label": ariaLabel,
2276
+ ...props
2277
+ }) {
2278
+ const failedCount = events.filter(
2279
+ (event) => webhookStatusTone(event.status) === "danger"
2280
+ ).length;
2281
+ const retryCount = events.reduce((total, event) => total + event.retries, 0);
2282
+ const columns = [
2283
+ {
2284
+ key: "id",
2285
+ header: "Event",
2286
+ width: "16rem",
2287
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "eth-dev-webhook-event-viewer__event", children: [
2288
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("code", { title: row.id, children: row.id }),
2289
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: payloadEventLabel(row.payload) })
2290
+ ] })
2291
+ },
2292
+ {
2293
+ key: "url",
2294
+ header: "Endpoint",
2295
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("code", { className: "eth-dev-webhook-event-viewer__url", title: row.url, children: row.url })
2296
+ },
2297
+ {
2298
+ key: "status",
2299
+ header: "Status",
2300
+ width: "9rem",
2301
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_core11.Badge, { severity: webhookStatusTone(row.status), children: formatWebhookStatus(row.status) })
2302
+ },
2303
+ {
2304
+ key: "retries",
2305
+ header: "Retries",
2306
+ align: "end",
2307
+ width: "6.5rem",
2308
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "eth-dev-webhook-event-viewer__count", children: row.retries })
2309
+ },
2310
+ {
2311
+ key: "deliveredAt",
2312
+ header: "Delivered",
2313
+ width: "10rem",
2314
+ render: (row) => row.deliveredAt ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("time", { className: "eth-dev-webhook-event-viewer__time", children: row.deliveredAt }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "eth-dev-webhook-event-viewer__missing", children: "Not delivered" })
2315
+ }
2316
+ ];
2317
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
2318
+ "section",
2319
+ {
2320
+ ...props,
2321
+ "aria-label": ariaLabel ?? "Webhook deliveries",
2322
+ className: `eth-dev-webhook-event-viewer ${className ?? ""}`.trim(),
2323
+ "data-eth-component": "WebhookEventViewer",
2324
+ children: [
2325
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("header", { className: "eth-dev-webhook-event-viewer__header", children: [
2326
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "eth-dev-webhook-event-viewer__heading", children: [
2327
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { children: "Webhook events" }),
2328
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("h3", { children: "Webhook deliveries" })
2329
+ ] }),
2330
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
2331
+ "dl",
2332
+ {
2333
+ className: "eth-dev-webhook-event-viewer__summary",
2334
+ "aria-label": "Webhook delivery summary",
2335
+ children: [
2336
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
2337
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("dt", { children: "Events" }),
2338
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("dd", { children: pluralize(events.length, "event") })
2339
+ ] }),
2340
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
2341
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("dt", { children: "Failed" }),
2342
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("dd", { children: pluralize(failedCount, "failed", "failed") })
2343
+ ] }),
2344
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
2345
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("dt", { children: "Retries" }),
2346
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("dd", { children: pluralize(retryCount, "retry", "retries") })
2347
+ ] })
2348
+ ]
2349
+ }
2350
+ )
2351
+ ] }),
2352
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2353
+ import_data3.DataTable,
2354
+ {
2355
+ rows: events,
2356
+ columns,
2357
+ rowKey: "id",
2358
+ density: "compact",
2359
+ className: "eth-dev-webhook-event-viewer__table",
2360
+ "aria-label": "Webhook delivery events",
2361
+ rowActions: onRetry ? (row) => isRetryableWebhookStatus(row.status) ? [
2362
+ {
2363
+ id: `retry-${row.id}`,
2364
+ label: "Retry",
2365
+ onSelect: () => onRetry(row.id)
2366
+ }
2367
+ ] : [] : void 0,
2368
+ emptyState: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2369
+ import_core11.EmptyState,
2370
+ {
2371
+ title: "No webhook events",
2372
+ description: "Delivery attempts and retry outcomes will appear here when webhooks fire."
2373
+ }
2374
+ )
2375
+ }
2376
+ )
2377
+ ]
2378
+ }
2379
+ );
2380
+ }
2381
+ function webhookStatusTone(status) {
2382
+ const token = normalizeWebhookStatus(status);
2383
+ if (["delivered", "success", "succeeded", "completed", "ok"].includes(token)) {
2384
+ return "success";
2385
+ }
2386
+ if (isRetryableWebhookStatus(token)) return "danger";
2387
+ if (["retrying", "queued", "pending", "running", "in-progress"].includes(token)) {
2388
+ return "info";
2389
+ }
2390
+ if (["warning", "throttled", "rate-limited"].includes(token)) {
2391
+ return "warning";
2392
+ }
2393
+ return "neutral";
2394
+ }
2395
+ function isRetryableWebhookStatus(status) {
2396
+ return ["failed", "error", "timeout", "timed-out", "undelivered"].includes(
2397
+ normalizeWebhookStatus(status)
2398
+ );
2399
+ }
2400
+ function normalizeWebhookStatus(status) {
2401
+ return status.trim().toLowerCase().replace(/_/g, "-");
2402
+ }
2403
+ function formatWebhookStatus(status) {
2404
+ const normalized = normalizeWebhookStatus(status);
2405
+ if (!normalized) return "Unknown";
2406
+ if (normalized === "ok") return "OK";
2407
+ return normalized.split("-").filter(Boolean).map((part) => part[0].toUpperCase() + part.slice(1)).join(" ");
2408
+ }
2409
+ function payloadEventLabel(payload) {
2410
+ if (payload && typeof payload === "object") {
2411
+ const record = payload;
2412
+ const eventName = record.event ?? record.type ?? record.name;
2413
+ if (typeof eventName === "string" && eventName.trim()) return eventName;
2414
+ }
2415
+ return "Webhook event";
2416
+ }
2417
+ function pluralize(count, singular, plural = `${singular}s`) {
2418
+ return `${count} ${count === 1 ? singular : plural}`;
2419
+ }
2420
+
2421
+ // src/components/YAMLViewer.tsx
2422
+ var React12 = __toESM(require("react"), 1);
2423
+ var import_icons_react7 = require("@carbon/icons-react");
2424
+ var import_core12 = require("@echothink-ui/core");
2425
+ var import_jsx_runtime18 = require("react/jsx-runtime");
2426
+ function countYamlEntries(lines) {
2427
+ return lines.filter(
2428
+ (line) => /^\s*(?:-\s+)?[\w.-]+\s*:/.test(line) || /^\s*-\s+\S/.test(line)
2429
+ ).length;
2430
+ }
2431
+ function getScalarClass(value) {
2432
+ if (/^["'].*["']$/.test(value)) return "string";
2433
+ if (/^(?:true|false)$/i.test(value)) return "boolean";
2434
+ if (/^(?:null|~)$/i.test(value)) return "null";
2435
+ if (/^-?\d+(?:\.\d+)?$/.test(value)) return "number";
2436
+ return "plain";
2437
+ }
2438
+ function renderScalar(value) {
2439
+ if (!value) return null;
2440
+ const commentIndex = value.search(/(^|\s)#/);
2441
+ const scalar = commentIndex >= 0 ? value.slice(0, commentIndex) : value;
2442
+ const comment = commentIndex >= 0 ? value.slice(commentIndex) : "";
2443
+ const scalarClass = getScalarClass(scalar.trim());
2444
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
2445
+ scalar ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2446
+ "span",
2447
+ {
2448
+ className: `eth-dev-yaml-viewer__token eth-dev-yaml-viewer__token--${scalarClass}`,
2449
+ children: scalar
2450
+ }
2451
+ ) : null,
2452
+ comment ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "eth-dev-yaml-viewer__token eth-dev-yaml-viewer__token--comment", children: comment }) : null
2453
+ ] });
2454
+ }
2455
+ function renderYamlLine(line) {
2456
+ if (!line.trim()) return line;
2457
+ if (/^\s*#/.test(line)) {
2458
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "eth-dev-yaml-viewer__token eth-dev-yaml-viewer__token--comment", children: line });
2459
+ }
2460
+ const keyMatch = line.match(/^(\s*)(-\s+)?([\w.-]+)(\s*:)(.*)$/);
2461
+ if (keyMatch) {
2462
+ const [, indent, listMarker = "", key, separator, rest] = keyMatch;
2463
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
2464
+ indent,
2465
+ listMarker ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "eth-dev-yaml-viewer__token eth-dev-yaml-viewer__token--marker", children: listMarker }) : null,
2466
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "eth-dev-yaml-viewer__token eth-dev-yaml-viewer__token--key", children: key }),
2467
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "eth-dev-yaml-viewer__token eth-dev-yaml-viewer__token--punctuation", children: separator }),
2468
+ renderScalar(rest)
2469
+ ] });
2470
+ }
2471
+ const listMatch = line.match(/^(\s*)(-\s+)(.*)$/);
2472
+ if (listMatch) {
2473
+ const [, indent, marker, rest] = listMatch;
2474
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
2475
+ indent,
2476
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "eth-dev-yaml-viewer__token eth-dev-yaml-viewer__token--marker", children: marker }),
2477
+ renderScalar(rest)
2478
+ ] });
2479
+ }
2480
+ return renderScalar(line) ?? line;
2481
+ }
2482
+ function YAMLViewer({
2483
+ value,
2484
+ editable = false,
2485
+ onChange,
2486
+ className,
2487
+ "aria-label": ariaLabel,
2488
+ ...props
2489
+ }) {
2490
+ const [copied, setCopied] = React12.useState(false);
2491
+ const resetTimer = React12.useRef(void 0);
2492
+ const lines = splitLines(value);
2493
+ const lineCount = lines.length;
2494
+ const entryCount = countYamlEntries(lines);
2495
+ const modeLabel = editable ? "Editable" : "Read-only";
2496
+ const viewerLabel = ariaLabel ?? (editable ? "YAML editor" : "YAML document");
2497
+ React12.useEffect(() => {
2498
+ return () => {
2499
+ if (resetTimer.current !== void 0 && typeof window !== "undefined") {
2500
+ window.clearTimeout(resetTimer.current);
2501
+ }
2502
+ };
2503
+ }, []);
2504
+ const copy = React12.useCallback(() => {
2505
+ if (typeof navigator === "undefined" || !navigator.clipboard) return;
2506
+ void navigator.clipboard.writeText(value).then(() => {
2507
+ if (typeof window !== "undefined") {
2508
+ setCopied(true);
2509
+ if (resetTimer.current !== void 0) {
2510
+ window.clearTimeout(resetTimer.current);
2511
+ }
2512
+ resetTimer.current = window.setTimeout(() => setCopied(false), 1200);
2513
+ }
2514
+ }).catch(() => {
2515
+ setCopied(false);
2516
+ });
2517
+ }, [value]);
2518
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
2519
+ "section",
2520
+ {
2521
+ ...props,
2522
+ "aria-label": viewerLabel,
2523
+ className: `eth-dev-yaml-viewer ${className ?? ""}`.trim(),
2524
+ "data-eth-component": "YAMLViewer",
2525
+ "data-editable": editable ? "true" : void 0,
2526
+ children: [
2527
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("header", { className: "eth-dev-yaml-viewer__header", children: [
2528
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "eth-dev-yaml-viewer__heading", children: [
2529
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "eth-dev-yaml-viewer__eyebrow", children: "YAML" }),
2530
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "eth-dev-yaml-viewer__title", children: editable ? "YAML editor" : "YAML document" })
2531
+ ] }),
2532
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
2533
+ "div",
2534
+ {
2535
+ className: "eth-dev-yaml-viewer__meta",
2536
+ role: "group",
2537
+ "aria-label": "YAML document metadata",
2538
+ children: [
2539
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "eth-dev-yaml-viewer__badge", children: modeLabel }),
2540
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "eth-dev-yaml-viewer__badge", children: [
2541
+ lineCount,
2542
+ " ",
2543
+ lineCount === 1 ? "line" : "lines"
2544
+ ] }),
2545
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "eth-dev-yaml-viewer__badge", children: [
2546
+ entryCount,
2547
+ " ",
2548
+ entryCount === 1 ? "entry" : "entries"
2549
+ ] }),
2550
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2551
+ import_core12.IconButton,
2552
+ {
2553
+ className: "eth-dev-yaml-viewer__copy-button",
2554
+ label: copied ? "Copied YAML" : "Copy YAML",
2555
+ intent: "ghost",
2556
+ density: "compact",
2557
+ icon: copied ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_icons_react7.Checkmark, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_icons_react7.Copy, { size: 16 }),
2558
+ onClick: copy
2559
+ }
2560
+ ),
2561
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "eth-dev-yaml-viewer__copy-status", "aria-live": "polite", children: copied ? "YAML copied" : "" })
2562
+ ]
2563
+ }
2564
+ )
2565
+ ] }),
2566
+ editable ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2567
+ CodeEditor,
2568
+ {
2569
+ value,
2570
+ onChange,
2571
+ language: "yaml",
2572
+ className: "eth-dev-yaml-viewer__editor",
2573
+ "aria-label": viewerLabel
2574
+ }
2575
+ ) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("pre", { className: "eth-dev-yaml-viewer__pre", "aria-label": viewerLabel, tabIndex: 0, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("code", { className: "eth-dev-yaml-viewer__code", children: lines.map((line, index) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "eth-dev-yaml-viewer__line", children: [
2576
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "eth-dev-yaml-viewer__gutter", "aria-hidden": "true", children: index + 1 }),
2577
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "eth-dev-yaml-viewer__line-code", children: renderYamlLine(line) })
2578
+ ] }, index)) }) })
2579
+ ]
2580
+ }
2581
+ );
2582
+ }
2583
+
2584
+ // src/index.tsx
2585
+ var DeveloperComponentNames = [
2586
+ "CodeBlock",
2587
+ "CodeEditor",
2588
+ "DiffTable",
2589
+ "DiffViewer",
2590
+ "JSONViewer",
2591
+ "YAMLViewer",
2592
+ "SchemaViewer",
2593
+ "APIExplorer",
2594
+ "EventPayloadViewer",
2595
+ "LogConsole",
2596
+ "TerminalPanel",
2597
+ "TraceTimeline",
2598
+ "RequestResponseViewer",
2599
+ "WebhookEventViewer",
2600
+ "GitRepositoryPanel",
2601
+ "PullRequestPanel",
2602
+ "CommitList",
2603
+ "BranchSelector"
2604
+ ];
2605
+ // Annotate the CommonJS export names for ESM import in node:
2606
+ 0 && (module.exports = {
2607
+ APIExplorer,
2608
+ BranchSelector,
2609
+ CodeBlock,
2610
+ CodeEditor,
2611
+ CommitList,
2612
+ DeveloperComponentNames,
2613
+ DiffTable,
2614
+ DiffViewer,
2615
+ EventPayloadViewer,
2616
+ GitRepositoryPanel,
2617
+ JSONViewer,
2618
+ LogConsole,
2619
+ PullRequestPanel,
2620
+ RequestResponseViewer,
2621
+ SchemaViewer,
2622
+ TerminalPanel,
2623
+ TraceTimeline,
2624
+ WebhookEventViewer,
2625
+ YAMLViewer
2626
+ });
2627
+ //# sourceMappingURL=index.cjs.map