autotel-terminal 17.0.5 → 17.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +109 -58
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +109 -58
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +109 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +109 -58
- package/dist/index.js.map +1 -1
- package/package.json +6 -4
- package/src/ai/catalog.test.ts +18 -0
- package/src/ai/catalog.ts +16 -0
- package/src/ai/system-prompt.ts +16 -3
- package/src/ai/tools.test.ts +36 -0
- package/src/ai/tools.ts +46 -1
- package/src/ai/types.ts +3 -0
- package/src/cli.integration.test.ts +49 -0
- package/src/index.tsx +97 -82
- package/src/lib/dashboard-keymap.test.ts +18 -0
- package/src/lib/dashboard-keymap.ts +9 -1
- package/src/lib/format.test.ts +70 -0
- package/src/lib/format.ts +65 -0
package/dist/cli.cjs
CHANGED
|
@@ -10,6 +10,9 @@ var autotel = require('autotel');
|
|
|
10
10
|
var tracerProvider = require('autotel/tracer-provider');
|
|
11
11
|
var ai = require('ai');
|
|
12
12
|
var zod = require('zod');
|
|
13
|
+
var core = require('@json-render/core');
|
|
14
|
+
var catalog = require('@json-render/ink/catalog');
|
|
15
|
+
var ink$1 = require('@json-render/ink');
|
|
13
16
|
require('autotel/exporters');
|
|
14
17
|
var jsxRuntime = require('react/jsx-runtime');
|
|
15
18
|
|
|
@@ -828,17 +831,31 @@ You have tools to query the telemetry data precisely. Use them to answer questio
|
|
|
828
831
|
- getTraceDetail: deep dive into a specific trace
|
|
829
832
|
- searchSpans: search spans by name
|
|
830
833
|
- searchLogs: search logs by message content
|
|
834
|
+
- renderUI: display rich terminal UI (tables, charts, badges)
|
|
831
835
|
|
|
832
|
-
|
|
833
|
-
|
|
836
|
+
## Workflow
|
|
837
|
+
1. Use data tools first to gather data
|
|
838
|
+
2. Use renderUI to display structured results as tables, charts, or cards
|
|
839
|
+
3. Add a brief text explanation after the rendered UI
|
|
840
|
+
|
|
841
|
+
## When to use renderUI
|
|
842
|
+
Use renderUI for tables, comparisons, and metrics. Do NOT use it for short text answers.
|
|
843
|
+
|
|
844
|
+
renderUI spec format: { root: "id", elements: { "id": { type: "ComponentName", props: {...}, children: [] } } }
|
|
845
|
+
|
|
846
|
+
Components: Table (columns, rows), KeyValue (label, value), Badge (label, variant: success/error/warning/info), BarChart (data: [{label,value}]), Card (title, children), Heading (text), Divider, Text (text, color, bold), Box (flexDirection, children).
|
|
847
|
+
|
|
848
|
+
Table example: { type: "Table", props: { columns: [{ header: "Name", key: "name" }], rows: [{ name: "api" }] }, children: [] }
|
|
849
|
+
|
|
850
|
+
Keep text responses under 300 words.
|
|
834
851
|
Use specific span names, durations, and attribute values from the data.
|
|
835
|
-
Format for a narrow terminal column \u2014 use short paragraphs, not wide tables.
|
|
836
852
|
|
|
837
853
|
Current dashboard summary:
|
|
838
854
|
${contextJson}`;
|
|
839
855
|
}
|
|
856
|
+
var COMPONENT_NAMES = Object.keys(catalog.standardComponentDefinitions);
|
|
840
857
|
var t = ai.tool;
|
|
841
|
-
function createTelemetryTools(ctx) {
|
|
858
|
+
function createTelemetryTools(ctx, onRenderUI) {
|
|
842
859
|
return {
|
|
843
860
|
getOverviewStats: t({
|
|
844
861
|
description: "Get high-level stats: total spans, error count, average duration, p95 duration, and service count.",
|
|
@@ -1006,6 +1023,33 @@ function createTelemetryTools(ctx) {
|
|
|
1006
1023
|
attrs: l.attributes
|
|
1007
1024
|
}));
|
|
1008
1025
|
}
|
|
1026
|
+
}),
|
|
1027
|
+
renderUI: t({
|
|
1028
|
+
description: "Render rich terminal UI (tables, charts, badges) to display structured data. Use this when showing tabular data, comparisons, or metrics \u2014 not for short text answers. Available components: Table (columns + rows), KeyValue (key-value pairs), Badge (status labels: default/info/success/warning/error), BarChart (horizontal bars with labels), Card (grouped content with title), Heading (section title), Divider (separator), Text (styled text), Box (layout container).",
|
|
1029
|
+
parameters: zod.z.object({
|
|
1030
|
+
spec: zod.z.object({
|
|
1031
|
+
root: zod.z.string().describe("ID of the root element"),
|
|
1032
|
+
elements: zod.z.record(
|
|
1033
|
+
zod.z.string(),
|
|
1034
|
+
zod.z.object({
|
|
1035
|
+
type: zod.z.enum(COMPONENT_NAMES).describe("Component name"),
|
|
1036
|
+
props: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
|
|
1037
|
+
children: zod.z.array(zod.z.string()).describe("Child element keys")
|
|
1038
|
+
})
|
|
1039
|
+
).describe("Map of element ID to component definition")
|
|
1040
|
+
}).describe("json-render spec defining the UI to display")
|
|
1041
|
+
}),
|
|
1042
|
+
execute: async ({ spec }) => {
|
|
1043
|
+
const validation = core.validateSpec(spec);
|
|
1044
|
+
if (!validation.valid) {
|
|
1045
|
+
return {
|
|
1046
|
+
rendered: false,
|
|
1047
|
+
error: validation.issues.map((i) => i.message).join("; ")
|
|
1048
|
+
};
|
|
1049
|
+
}
|
|
1050
|
+
onRenderUI?.(spec);
|
|
1051
|
+
return { rendered: true };
|
|
1052
|
+
}
|
|
1009
1053
|
})
|
|
1010
1054
|
};
|
|
1011
1055
|
}
|
|
@@ -1072,11 +1116,11 @@ function Dashboard({
|
|
|
1072
1116
|
const throttleRef = react.useRef(null);
|
|
1073
1117
|
const pendingSpansRef = react.useRef([]);
|
|
1074
1118
|
const [logs, setLogs] = react.useState([]);
|
|
1075
|
-
const [aiActive, setAiActive] = react.useState(false);
|
|
1076
1119
|
const [aiMessages, setAiMessages] = react.useState([]);
|
|
1077
1120
|
const [aiInput, setAiInput] = react.useState("");
|
|
1078
1121
|
const [aiState, setAiState] = react.useState({ status: "unconfigured" });
|
|
1079
1122
|
const [aiInputMode, setAiInputMode] = react.useState(false);
|
|
1123
|
+
const [aiSpec, setAiSpec] = react.useState(null);
|
|
1080
1124
|
const aiModelRef = react.useRef(null);
|
|
1081
1125
|
const aiAbortRef = react.useRef(null);
|
|
1082
1126
|
react.useEffect(() => {
|
|
@@ -1289,6 +1333,7 @@ function Dashboard({
|
|
|
1289
1333
|
setAiInput("");
|
|
1290
1334
|
const abort = new AbortController();
|
|
1291
1335
|
aiAbortRef.current = abort;
|
|
1336
|
+
setAiSpec(null);
|
|
1292
1337
|
setAiState({ status: "streaming", abortController: abort });
|
|
1293
1338
|
const toolCtx = {
|
|
1294
1339
|
spans,
|
|
@@ -1298,7 +1343,7 @@ function Dashboard({
|
|
|
1298
1343
|
serviceStats,
|
|
1299
1344
|
errorSummaries
|
|
1300
1345
|
};
|
|
1301
|
-
const tools = createTelemetryTools(toolCtx);
|
|
1346
|
+
const tools = createTelemetryTools(toolCtx, (spec) => setAiSpec(spec));
|
|
1302
1347
|
const statsContext = JSON.stringify({
|
|
1303
1348
|
viewMode,
|
|
1304
1349
|
stats: {
|
|
@@ -1344,15 +1389,31 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
|
|
|
1344
1389
|
return updated;
|
|
1345
1390
|
});
|
|
1346
1391
|
}
|
|
1392
|
+
if (!fullText.trim()) {
|
|
1393
|
+
setAiMessages((prev) => {
|
|
1394
|
+
const updated = [...prev];
|
|
1395
|
+
const lastMsg = updated.at(-1);
|
|
1396
|
+
if (lastMsg?.role === "assistant" && !lastMsg.content.trim()) {
|
|
1397
|
+
updated[updated.length - 1] = {
|
|
1398
|
+
role: "assistant",
|
|
1399
|
+
content: "(No response from model \u2014 try a simpler question or a larger model)"
|
|
1400
|
+
};
|
|
1401
|
+
}
|
|
1402
|
+
return updated;
|
|
1403
|
+
});
|
|
1404
|
+
}
|
|
1347
1405
|
setAiState({ status: "idle" });
|
|
1348
1406
|
} catch (error) {
|
|
1349
1407
|
if (abort.signal.aborted) {
|
|
1350
1408
|
setAiState({ status: "idle" });
|
|
1351
1409
|
return;
|
|
1352
1410
|
}
|
|
1411
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
1412
|
+
process.stderr.write(`[autotel-terminal] AI error: ${errorMsg}
|
|
1413
|
+
`);
|
|
1353
1414
|
setAiState({
|
|
1354
1415
|
status: "error",
|
|
1355
|
-
message:
|
|
1416
|
+
message: errorMsg
|
|
1356
1417
|
});
|
|
1357
1418
|
} finally {
|
|
1358
1419
|
aiAbortRef.current = null;
|
|
@@ -1437,7 +1498,7 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
|
|
|
1437
1498
|
aiAbortRef.current?.abort();
|
|
1438
1499
|
} else {
|
|
1439
1500
|
setAiInputMode(false);
|
|
1440
|
-
|
|
1501
|
+
setViewMode("trace");
|
|
1441
1502
|
}
|
|
1442
1503
|
return;
|
|
1443
1504
|
}
|
|
@@ -1457,14 +1518,19 @@ Currently viewing trace ${drilldownTraceId}. This trace has ${drilldownSpans.len
|
|
|
1457
1518
|
return;
|
|
1458
1519
|
}
|
|
1459
1520
|
if (input === "a") {
|
|
1460
|
-
|
|
1461
|
-
|
|
1521
|
+
if (viewMode === "ai") {
|
|
1522
|
+
setViewMode("trace");
|
|
1462
1523
|
setAiInputMode(false);
|
|
1463
1524
|
} else {
|
|
1525
|
+
setViewMode("ai");
|
|
1464
1526
|
if (aiState.status !== "unconfigured") {
|
|
1465
1527
|
setAiInputMode(true);
|
|
1466
1528
|
}
|
|
1467
1529
|
}
|
|
1530
|
+
setSelected(0);
|
|
1531
|
+
setDrilldownTraceId(null);
|
|
1532
|
+
setDrilldownSelectedIndex(0);
|
|
1533
|
+
setDrilldownScrollOffset(0);
|
|
1468
1534
|
return;
|
|
1469
1535
|
}
|
|
1470
1536
|
if (key.escape) {
|
|
@@ -1772,7 +1838,7 @@ ${json}
|
|
|
1772
1838
|
{ isActive: isRawModeSupported }
|
|
1773
1839
|
);
|
|
1774
1840
|
const headerRight = recording ? "[Recording]" : paused ? "[Paused]" : "[Live]";
|
|
1775
|
-
const headerModeLabel = viewMode === "trace" ? "traces" : viewMode === "span" ? "spans" : viewMode === "log" ? "logs" : viewMode === "service-summary" ? "services" : viewMode === "topology" ? "topology" : "errors";
|
|
1841
|
+
const headerModeLabel = viewMode === "trace" ? "traces" : viewMode === "span" ? "spans" : viewMode === "log" ? "logs" : viewMode === "service-summary" ? "services" : viewMode === "topology" ? "topology" : viewMode === "ai" ? "AI" : "errors";
|
|
1776
1842
|
const showNewError = newErrorCount > 0;
|
|
1777
1843
|
function renderTreeRow(node, index) {
|
|
1778
1844
|
const isSel = drilldownTraceId != null && index === drilldownSelectedIndex;
|
|
@@ -1853,10 +1919,10 @@ ${json}
|
|
|
1853
1919
|
"\u2026"
|
|
1854
1920
|
] })
|
|
1855
1921
|
] }) : /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "row", justifyContent: "space-between", children: [
|
|
1856
|
-
/* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: drilldownTraceId == null ? "\u2191/\u2193 select \u2022 Enter open \u2022 Tab cycle tabs \u2022 Esc back \u2022
|
|
1857
|
-
/* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: viewMode === "trace" ? `traces ${filteredSummaries.length}/${traceSummaries.length}` : viewMode === "span" ? `spans ${filteredSpans.length}/${spans.length}` : viewMode === "service-summary" ? `services ${serviceStats.length}` : viewMode === "errors" ? `errors ${filteredErrorSummaries.length}/${errorSummaries.length}` : viewMode === "topology" ? `services ${serviceGraph.services.length} \xB7 edges ${serviceGraph.edges.length}` : `logs ${filteredLogs.length}/${logs.length}` })
|
|
1922
|
+
/* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: drilldownTraceId == null ? "\u2191/\u2193 select \u2022 Enter open \u2022 Tab cycle tabs \u2022 Esc back \u2022 t trace \u2022 l logs \u2022 a AI \u2022 ? help" : "\u2191/\u2193 select \u2022 Tab cycle tabs \u2022 Esc back \u2022 t trace \u2022 l logs \u2022 a AI \u2022 ? help" }),
|
|
1923
|
+
/* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: viewMode === "trace" ? `traces ${filteredSummaries.length}/${traceSummaries.length}` : viewMode === "span" ? `spans ${filteredSpans.length}/${spans.length}` : viewMode === "service-summary" ? `services ${serviceStats.length}` : viewMode === "errors" ? `errors ${filteredErrorSummaries.length}/${errorSummaries.length}` : viewMode === "topology" ? `services ${serviceGraph.services.length} \xB7 edges ${serviceGraph.edges.length}` : viewMode === "ai" ? `messages ${aiMessages.length}` : `logs ${filteredLogs.length}/${logs.length}` })
|
|
1858
1924
|
] }),
|
|
1859
|
-
showHelp && /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Views: t/l/v/E/G \u2022 Search: / \u2022 Filters: e/S/R/H/f/x \u2022 Capture: p/r/J \u2022
|
|
1925
|
+
showHelp && /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Views: t/l/v/E/G/a \u2022 Search: / \u2022 Filters: e/S/R/H/f/x \u2022 Capture: p/r/J \u2022 Clear: c" })
|
|
1860
1926
|
] }),
|
|
1861
1927
|
/* @__PURE__ */ jsxRuntime.jsx(ink.Box, { marginBottom: 0, children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: spanFilters.serviceName || spanFilters.route || spanFilters.statusGroup !== "all" || spanFilters.traceId ? `filters:${spanFilters.serviceName ? ` service=${spanFilters.serviceName}` : ""}${spanFilters.route ? ` route=${spanFilters.route}` : ""}${spanFilters.statusGroup && spanFilters.statusGroup !== "all" ? ` status=${spanFilters.statusGroup}` : ""}${spanFilters.traceId ? ` trace=${spanFilters.traceId.slice(0, 8)}\u2026` : ""}` : "filters: none" }) }),
|
|
1862
1928
|
viewMode === "topology" && /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, children: [
|
|
@@ -1867,7 +1933,34 @@ ${json}
|
|
|
1867
1933
|
return /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: hasErr ? "red" : void 0, children: line }, `topo-${i}`);
|
|
1868
1934
|
}) })
|
|
1869
1935
|
] }),
|
|
1870
|
-
viewMode
|
|
1936
|
+
viewMode === "ai" && /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, paddingY: 0, children: [
|
|
1937
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { marginBottom: 1, justifyContent: "space-between", children: [
|
|
1938
|
+
/* @__PURE__ */ jsxRuntime.jsx(ink.Text, { bold: true, children: "AI Assistant" }),
|
|
1939
|
+
/* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: aiState.status === "streaming" ? "(streaming...)" : aiState.status === "unconfigured" ? "(no provider)" : aiState.status === "error" ? "(error)" : "" })
|
|
1940
|
+
] }),
|
|
1941
|
+
aiState.status === "unconfigured" ? /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "column", children: [
|
|
1942
|
+
/* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "No AI provider configured." }),
|
|
1943
|
+
/* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Set AI_PROVIDER and AI_MODEL env vars, or start Ollama locally." }),
|
|
1944
|
+
/* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Press a to close this view." })
|
|
1945
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1946
|
+
aiMessages.length === 0 && aiState.status !== "error" && /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Ask a question about your telemetry data. Press Enter to send." }),
|
|
1947
|
+
aiMessages.slice(-10).map((msg, i) => /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { flexDirection: "column", marginBottom: msg.role === "assistant" ? 1 : 0, children: /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: msg.role === "user" ? "cyan" : void 0, children: [
|
|
1948
|
+
msg.role === "user" ? "> " : "",
|
|
1949
|
+
msg.content.slice(0, 1e3),
|
|
1950
|
+
msg.content.length > 1e3 ? "..." : ""
|
|
1951
|
+
] }) }, `ai-msg-${i}`)),
|
|
1952
|
+
aiSpec && /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { flexDirection: "column", marginBottom: 1, borderStyle: "single", borderColor: "gray", paddingX: 1, children: /* @__PURE__ */ jsxRuntime.jsx(ink$1.Renderer, { spec: aiSpec }) }),
|
|
1953
|
+
aiState.status === "error" && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: "red", children: [
|
|
1954
|
+
"Error: ",
|
|
1955
|
+
aiState.message
|
|
1956
|
+
] }),
|
|
1957
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { marginTop: 1, borderStyle: "single", borderColor: "cyan", paddingX: 1, children: [
|
|
1958
|
+
/* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: "cyan", children: "> " }),
|
|
1959
|
+
/* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: aiInput || (aiInputMode ? "(type your question)" : "(press a to focus)") })
|
|
1960
|
+
] })
|
|
1961
|
+
] })
|
|
1962
|
+
] }),
|
|
1963
|
+
viewMode !== "topology" && viewMode !== "ai" && (drilldownTraceId != null ? /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, paddingY: 0, children: [
|
|
1871
1964
|
/* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { marginBottom: 0, flexDirection: "column", children: [
|
|
1872
1965
|
/* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { bold: true, children: [
|
|
1873
1966
|
"Trace ",
|
|
@@ -2346,49 +2439,7 @@ ${json}
|
|
|
2346
2439
|
borderColor: "gray",
|
|
2347
2440
|
paddingX: 1,
|
|
2348
2441
|
paddingY: 0,
|
|
2349
|
-
children:
|
|
2350
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { marginBottom: 1, justifyContent: "space-between", children: [
|
|
2351
|
-
/* @__PURE__ */ jsxRuntime.jsx(ink.Text, { bold: true, children: "AI Assistant" }),
|
|
2352
|
-
/* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: aiState.status === "streaming" ? "(streaming...)" : aiState.status === "unconfigured" ? "(no provider)" : aiState.status === "error" ? "(error)" : "" })
|
|
2353
|
-
] }),
|
|
2354
|
-
aiState.status === "unconfigured" ? /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "column", children: [
|
|
2355
|
-
/* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "No AI provider configured." }),
|
|
2356
|
-
/* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Set AI_PROVIDER and AI_MODEL env vars, or start Ollama locally." }),
|
|
2357
|
-
/* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Press 'a' to close this panel." })
|
|
2358
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2359
|
-
aiMessages.length === 0 && aiState.status !== "error" && /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { dimColor: true, children: "Ask a question about your telemetry data. Press Enter to send." }),
|
|
2360
|
-
aiMessages.slice(-10).map((msg, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2361
|
-
ink.Box,
|
|
2362
|
-
{
|
|
2363
|
-
flexDirection: "column",
|
|
2364
|
-
marginBottom: msg.role === "assistant" ? 1 : 0,
|
|
2365
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: msg.role === "user" ? "cyan" : void 0, children: [
|
|
2366
|
-
msg.role === "user" ? "> " : "",
|
|
2367
|
-
msg.content.slice(0, 500),
|
|
2368
|
-
msg.content.length > 500 ? "..." : ""
|
|
2369
|
-
] })
|
|
2370
|
-
},
|
|
2371
|
-
i
|
|
2372
|
-
)),
|
|
2373
|
-
aiState.status === "error" && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: "red", children: [
|
|
2374
|
-
"Error: ",
|
|
2375
|
-
aiState.message
|
|
2376
|
-
] }),
|
|
2377
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2378
|
-
ink.Box,
|
|
2379
|
-
{
|
|
2380
|
-
marginTop: 1,
|
|
2381
|
-
borderStyle: "single",
|
|
2382
|
-
borderColor: "cyan",
|
|
2383
|
-
paddingX: 1,
|
|
2384
|
-
children: [
|
|
2385
|
-
/* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: "cyan", children: "> " }),
|
|
2386
|
-
/* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: aiInput || (aiInputMode ? "(type your question)" : "(press a to focus)") })
|
|
2387
|
-
]
|
|
2388
|
-
}
|
|
2389
|
-
)
|
|
2390
|
-
] })
|
|
2391
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2442
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2392
2443
|
/* @__PURE__ */ jsxRuntime.jsx(ink.Box, { marginBottom: 1, children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { bold: true, children: "Details" }) }),
|
|
2393
2444
|
viewMode === "errors" ? (() => {
|
|
2394
2445
|
const e = filteredErrorSummaries[selected] ?? null;
|