@microboxlabs/miot-chat 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/cli.js +512 -272
  2. package/dist/index.js +511 -269
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import { createRequire } from "module";
5
4
  import { Command } from "commander";
6
5
 
7
6
  // src/commands/ask.ts
@@ -861,10 +860,18 @@ import { render } from "ink";
861
860
  import { createElement } from "react";
862
861
 
863
862
  // src/tui/App.tsx
864
- import { Box as Box12 } from "ink";
865
- import { useCallback as useCallback2, useMemo as useMemo2, useState as useState7 } from "react";
863
+ import { Box as Box16, Text as Text17, useInput as useInput7 } from "ink";
864
+ import { useCallback as useCallback2, useMemo as useMemo2, useState as useState8 } from "react";
866
865
  import { randomUUID as randomUUID3 } from "crypto";
867
866
 
867
+ // src/version.ts
868
+ import { createRequire } from "module";
869
+ function packageVersion() {
870
+ const require2 = createRequire(import.meta.url);
871
+ const pkg = require2("../package.json");
872
+ return pkg.version;
873
+ }
874
+
868
875
  // src/tui/input/Editor.tsx
869
876
  import { Box, Text, useInput } from "ink";
870
877
  import { useReducer, useState } from "react";
@@ -1218,15 +1225,9 @@ function renderLine(line, cursorCol) {
1218
1225
  ] });
1219
1226
  }
1220
1227
 
1221
- // src/tui/header/Header.tsx
1228
+ // src/tui/chrome/TopLine.tsx
1222
1229
  import { Box as Box2, Text as Text3 } from "ink";
1223
1230
 
1224
- // src/tui/session/agentic.ts
1225
- var AGENTIC_TENANT_LOCK2 = "mintral";
1226
- function isAgenticTenantMismatch(mode, tenant) {
1227
- return mode === "agentic" && tenant !== AGENTIC_TENANT_LOCK2;
1228
- }
1229
-
1230
1231
  // src/tui/transcript/Spinner.tsx
1231
1232
  import { Text as Text2 } from "ink";
1232
1233
  import { useEffect, useState as useState2 } from "react";
@@ -1247,129 +1248,421 @@ function Spinner(props) {
1247
1248
  return /* @__PURE__ */ jsx2(Text2, { color: props.color, children: FRAMES[frame] });
1248
1249
  }
1249
1250
 
1250
- // src/tui/header/Header.tsx
1251
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1252
- var SEPARATOR = " \xB7 ";
1253
- function Header(props) {
1254
- const { meta, streaming, pendingApprovals } = props;
1255
- const shortConv = meta.conversationId.slice(0, 8);
1256
- const agenticWarn = isAgenticTenantMismatch(meta.mode, meta.tenantId);
1257
- const chips = [];
1258
- chips.push(/* @__PURE__ */ jsxs2(Text3, { children: [
1259
- "tenant=",
1260
- meta.tenantId
1261
- ] }, "tenant"));
1262
- chips.push(/* @__PURE__ */ jsxs2(Text3, { children: [
1263
- "user=",
1264
- meta.userId
1265
- ] }, "user"));
1266
- chips.push(/* @__PURE__ */ jsxs2(Text3, { children: [
1267
- "conv=",
1268
- shortConv
1269
- ] }, "conv"));
1270
- chips.push(
1271
- /* @__PURE__ */ jsxs2(Text3, { color: agenticWarn ? "yellow" : void 0, children: [
1272
- agenticWarn ? "\u26A0 " : "",
1273
- "mode=",
1274
- meta.mode
1275
- ] }, "mode")
1251
+ // src/tui/theme/ThemeProvider.tsx
1252
+ import { createContext, useContext, useMemo, useState as useState3 } from "react";
1253
+
1254
+ // src/tui/theme/themes.ts
1255
+ var DARK_THEME = {
1256
+ accent: "cyan",
1257
+ assistant: "white",
1258
+ user: "cyan",
1259
+ dim: "gray",
1260
+ warn: "yellow",
1261
+ err: "red",
1262
+ ok: "green",
1263
+ border: "gray",
1264
+ prompt: "cyan",
1265
+ spinner: "cyan"
1266
+ };
1267
+ var LIGHT_THEME = {
1268
+ accent: "blue",
1269
+ assistant: "black",
1270
+ user: "blue",
1271
+ dim: "gray",
1272
+ warn: "yellow",
1273
+ err: "red",
1274
+ ok: "green",
1275
+ border: "gray",
1276
+ prompt: "blue",
1277
+ spinner: "blue"
1278
+ };
1279
+ var HIGH_CONTRAST_THEME = {
1280
+ accent: "white",
1281
+ assistant: "white",
1282
+ user: "white",
1283
+ dim: "white",
1284
+ warn: "yellow",
1285
+ err: "red",
1286
+ ok: "green",
1287
+ border: "white",
1288
+ prompt: "white",
1289
+ spinner: "white"
1290
+ };
1291
+ var BUILTIN_THEMES = {
1292
+ dark: DARK_THEME,
1293
+ light: LIGHT_THEME,
1294
+ "high-contrast": HIGH_CONTRAST_THEME
1295
+ };
1296
+ var DEFAULT_THEME_NAME = "dark";
1297
+ function builtinThemeNames() {
1298
+ return Object.keys(BUILTIN_THEMES).sort();
1299
+ }
1300
+
1301
+ // src/tui/theme/ThemeProvider.tsx
1302
+ import { jsx as jsx3 } from "react/jsx-runtime";
1303
+ var ThemeContext = createContext({
1304
+ theme: DARK_THEME,
1305
+ setTheme: () => void 0
1306
+ });
1307
+ function ThemeProvider(props) {
1308
+ const [theme, setTheme] = useState3(
1309
+ props.initialTheme ?? DARK_THEME
1276
1310
  );
1277
- chips.push(/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: meta.baseUrl }, "url"));
1278
- if (meta.profileName) {
1279
- chips.push(/* @__PURE__ */ jsxs2(Text3, { dimColor: true, children: [
1280
- "profile=",
1281
- meta.profileName
1282
- ] }, "profile"));
1283
- }
1284
- if (pendingApprovals > 0) {
1285
- chips.push(
1286
- /* @__PURE__ */ jsxs2(Text3, { color: "yellow", children: [
1287
- "approvals=",
1288
- pendingApprovals
1289
- ] }, "appr")
1290
- );
1291
- }
1292
- if (typeof props.turns === "number") {
1293
- chips.push(/* @__PURE__ */ jsxs2(Text3, { dimColor: true, children: [
1294
- "turns=",
1295
- props.turns
1296
- ] }, "turns"));
1297
- }
1298
- if (typeof props.approxTokens === "number") {
1299
- const pct = typeof props.contextPercent === "number" ? ` (${props.contextPercent}%)` : "";
1300
- chips.push(
1301
- /* @__PURE__ */ jsxs2(Text3, { dimColor: true, children: [
1302
- "ctx\u2248",
1303
- props.approxTokens,
1304
- "tok",
1305
- pct
1306
- ] }, "tok")
1307
- );
1308
- }
1309
- if (props.usageTotals && (props.usageTotals.inputTokens > 0 || props.usageTotals.outputTokens > 0)) {
1310
- const u = props.usageTotals;
1311
+ const value = useMemo(
1312
+ () => ({ theme, setTheme }),
1313
+ [theme]
1314
+ );
1315
+ return /* @__PURE__ */ jsx3(ThemeContext.Provider, { value, children: props.children });
1316
+ }
1317
+ function useTheme() {
1318
+ return useContext(ThemeContext);
1319
+ }
1320
+
1321
+ // src/tui/chrome/TopLine.tsx
1322
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
1323
+ function TopLine(props) {
1324
+ const { theme } = useTheme();
1325
+ const shortConv = props.meta.conversationId.slice(0, 8);
1326
+ return /* @__PURE__ */ jsxs2(Box2, { paddingX: 1, children: [
1327
+ /* @__PURE__ */ jsxs2(Text3, { color: theme.dim, children: [
1328
+ "\u2387 ",
1329
+ props.meta.tenantId,
1330
+ " \xB7 ",
1331
+ props.meta.userId,
1332
+ " \xB7 conv ",
1333
+ shortConv
1334
+ ] }),
1335
+ props.streaming ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
1336
+ /* @__PURE__ */ jsx4(Text3, { color: theme.dim, children: " " }),
1337
+ /* @__PURE__ */ jsx4(Spinner, { color: theme.spinner })
1338
+ ] }) : null
1339
+ ] });
1340
+ }
1341
+
1342
+ // src/tui/chrome/TipLine.tsx
1343
+ import { Box as Box3, Text as Text4 } from "ink";
1344
+ import { jsx as jsx5 } from "react/jsx-runtime";
1345
+ var TIPS = [
1346
+ "Tip: type / to see available commands.",
1347
+ "Tip: ctrl+r resumes a saved session.",
1348
+ "Tip: ctrl+t switches the color theme.",
1349
+ "Tip: /save stores this conversation for later.",
1350
+ "Tip: /export writes the conversation as markdown."
1351
+ ];
1352
+ function TipLine(props) {
1353
+ const { theme } = useTheme();
1354
+ const tip = TIPS[props.tipIndex % TIPS.length];
1355
+ return /* @__PURE__ */ jsx5(Box3, { paddingX: 1, children: /* @__PURE__ */ jsx5(Text4, { color: theme.dim, children: tip }) });
1356
+ }
1357
+
1358
+ // src/tui/chrome/FooterLine.tsx
1359
+ import { Box as Box4, Text as Text5 } from "ink";
1360
+ import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
1361
+ function FooterLine(props) {
1362
+ const { theme } = useTheme();
1363
+ const segments = [];
1364
+ segments.push(`turns ${props.turns}`);
1365
+ segments.push(`ctx\u2248${props.approxTokens}tok (${props.contextPercent}%)`);
1366
+ const u = props.usageTotals;
1367
+ if (u && (u.inputTokens > 0 || u.outputTokens > 0)) {
1311
1368
  const cost = u.costUsd > 0 ? ` $${u.costUsd.toFixed(4)}` : "";
1312
- chips.push(
1313
- /* @__PURE__ */ jsxs2(Text3, { dimColor: true, children: [
1314
- "usage=",
1315
- u.inputTokens,
1316
- "\u2192",
1317
- u.outputTokens,
1318
- cost
1319
- ] }, "usage")
1320
- );
1369
+ segments.push(`${u.inputTokens}\u2192${u.outputTokens}${cost}`);
1321
1370
  }
1322
- if (streaming) {
1323
- chips.push(/* @__PURE__ */ jsx3(Spinner, { color: "cyan" }, "spinner"));
1371
+ segments.push(props.baseUrl);
1372
+ if (props.profileName) {
1373
+ segments.push(`profile ${props.profileName}`);
1324
1374
  }
1325
- return /* @__PURE__ */ jsx3(Box2, { borderStyle: "round", paddingX: 1, flexDirection: "row", flexWrap: "wrap", children: interpose(chips, (i) => /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: SEPARATOR }, `sep-${i}`)) });
1375
+ return /* @__PURE__ */ jsxs3(Box4, { paddingX: 1, justifyContent: "flex-end", children: [
1376
+ props.pendingApprovals > 0 ? /* @__PURE__ */ jsxs3(Text5, { color: theme.warn, children: [
1377
+ "approvals ",
1378
+ props.pendingApprovals,
1379
+ " \xB7 "
1380
+ ] }) : null,
1381
+ /* @__PURE__ */ jsx6(Text5, { color: theme.dim, children: segments.join(" \xB7 ") })
1382
+ ] });
1326
1383
  }
1327
- function interpose(nodes, sep) {
1328
- const out = [];
1329
- nodes.forEach((node, i) => {
1330
- if (i > 0) out.push(sep(i));
1331
- out.push(node);
1332
- });
1333
- return out;
1384
+
1385
+ // src/tui/chrome/InputFrame.tsx
1386
+ import { Box as Box5, Text as Text6 } from "ink";
1387
+
1388
+ // src/tui/hooks/useTerminalWidth.ts
1389
+ import { useStdout } from "ink";
1390
+ import { useEffect as useEffect2, useState as useState4 } from "react";
1391
+ var FALLBACK_COLUMNS = 80;
1392
+ var MIN_COLUMNS = 20;
1393
+ function useTerminalWidth() {
1394
+ const { stdout } = useStdout();
1395
+ const [columns, setColumns] = useState4(
1396
+ stdout?.columns ?? FALLBACK_COLUMNS
1397
+ );
1398
+ useEffect2(() => {
1399
+ if (!stdout) return;
1400
+ const onResize = () => {
1401
+ setColumns(stdout.columns ?? FALLBACK_COLUMNS);
1402
+ };
1403
+ stdout.on("resize", onResize);
1404
+ return () => {
1405
+ stdout.off("resize", onResize);
1406
+ };
1407
+ }, [stdout]);
1408
+ return Math.max(MIN_COLUMNS, columns);
1409
+ }
1410
+ var FALLBACK_ROWS = 24;
1411
+ var MIN_ROWS = 10;
1412
+ function useTerminalRows() {
1413
+ const { stdout } = useStdout();
1414
+ const [rows, setRows] = useState4(stdout?.rows ?? FALLBACK_ROWS);
1415
+ useEffect2(() => {
1416
+ if (!stdout) return;
1417
+ const onResize = () => {
1418
+ setRows(stdout.rows ?? FALLBACK_ROWS);
1419
+ };
1420
+ stdout.on("resize", onResize);
1421
+ return () => {
1422
+ stdout.off("resize", onResize);
1423
+ };
1424
+ }, [stdout]);
1425
+ return Math.max(MIN_ROWS, rows);
1426
+ }
1427
+
1428
+ // src/tui/chrome/InputFrame.tsx
1429
+ import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
1430
+ function InputFrame(props) {
1431
+ const cols = useTerminalWidth();
1432
+ const { theme } = useTheme();
1433
+ return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", width: cols, children: [
1434
+ /* @__PURE__ */ jsx7(
1435
+ Box5,
1436
+ {
1437
+ borderStyle: "round",
1438
+ borderColor: theme.border,
1439
+ borderBottom: false,
1440
+ paddingX: 1,
1441
+ children: props.children
1442
+ }
1443
+ ),
1444
+ /* @__PURE__ */ jsx7(
1445
+ BottomBorder,
1446
+ {
1447
+ cols,
1448
+ label: props.label,
1449
+ warn: props.labelWarn ?? false
1450
+ }
1451
+ )
1452
+ ] });
1453
+ }
1454
+ function BottomBorder(props) {
1455
+ const { theme } = useTheme();
1456
+ const visibleLabel = props.warn ? `\u26A0 ${props.label}` : props.label;
1457
+ const labelText = ` ${visibleLabel} `;
1458
+ const fill = props.cols - 2 - labelText.length - 2;
1459
+ if (fill < 1) {
1460
+ return /* @__PURE__ */ jsxs4(Text6, { color: theme.border, children: [
1461
+ "\u2570",
1462
+ "\u2500".repeat(Math.max(0, props.cols - 2)),
1463
+ "\u256F"
1464
+ ] });
1465
+ }
1466
+ return /* @__PURE__ */ jsxs4(Text6, { children: [
1467
+ /* @__PURE__ */ jsxs4(Text6, { color: theme.border, children: [
1468
+ "\u2570",
1469
+ "\u2500".repeat(fill)
1470
+ ] }),
1471
+ /* @__PURE__ */ jsx7(Text6, { color: props.warn ? theme.warn : theme.dim, children: labelText }),
1472
+ /* @__PURE__ */ jsx7(Text6, { color: theme.border, children: "\u2500\u2500\u256F" })
1473
+ ] });
1334
1474
  }
1335
1475
 
1336
- // src/tui/transcript/Transcript.tsx
1476
+ // src/tui/chrome/WelcomeCard.tsx
1337
1477
  import { Box as Box6, Text as Text7 } from "ink";
1478
+ import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
1479
+ var LOGO = [
1480
+ [
1481
+ { text: "\u2880", tone: "accent" },
1482
+ { text: "\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800", tone: "accent" },
1483
+ { text: "\u28C0", tone: "accent" },
1484
+ { text: "\u28E4\u28E4\u28C0", tone: "warn" },
1485
+ { text: "\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800", tone: "accent" },
1486
+ { text: "\u2840", tone: "accent" }
1487
+ ],
1488
+ [
1489
+ { text: "\u2800", tone: "accent" },
1490
+ { text: "\u28BF\u28F6\u28F6\u28E4\u28E4\u28F0", tone: "accent" },
1491
+ { text: "\u28B6\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28F7", tone: "warn" },
1492
+ { text: "\u28C6\u28E4\u28E4\u28F6\u28F6\u287F", tone: "accent" },
1493
+ { text: "\u2800", tone: "accent" }
1494
+ ],
1495
+ [
1496
+ { text: "\u2800", tone: "accent" },
1497
+ { text: "\u2808\u281B\u28DB\u289B\u28DB\u28DB\u285B\u283A", tone: "accent" },
1498
+ { text: "\u28BF\u28FF\u28FF\u287F", tone: "warn" },
1499
+ { text: "\u281F\u281B\u28DB\u28DB\u28DB\u28DB\u281B\u2801", tone: "accent" },
1500
+ { text: "\u2800", tone: "accent" }
1501
+ ],
1502
+ [
1503
+ { text: "\u2800", tone: "accent" },
1504
+ { text: "\u2880\u28FF\u28FF", tone: "accent" },
1505
+ { text: "\u28FF\u289F\u28DB\u28DB\u28BF\u28E6", tone: "face" },
1506
+ { text: "\u28CC\u28E1", tone: "accent" },
1507
+ { text: "\u28F4\u287E\u28DB\u28DB\u287F\u28FF", tone: "face" },
1508
+ { text: "\u28FF\u28F7", tone: "accent" },
1509
+ { text: "\u2800\u2800", tone: "accent" }
1510
+ ],
1511
+ [
1512
+ { text: "\u2800", tone: "accent" },
1513
+ { text: "\u28F8\u28FF", tone: "accent" },
1514
+ { text: "\u28FF", tone: "face" },
1515
+ { text: "\u28B3", tone: "accent" },
1516
+ { text: "\u287F", tone: "warn" },
1517
+ { text: "\u286F", tone: "accent" },
1518
+ { text: "\u2819\u28F7", tone: "warn" },
1519
+ { text: "\u28BB\u28FF\u28FF\u285F", tone: "face" },
1520
+ { text: "\u28FE\u280B", tone: "warn" },
1521
+ { text: "\u28BD", tone: "accent" },
1522
+ { text: "\u28BB", tone: "warn" },
1523
+ { text: "\u28FD", tone: "accent" },
1524
+ { text: "\u28FF", tone: "face" },
1525
+ { text: "\u28FF\u2847", tone: "accent" },
1526
+ { text: "\u2800", tone: "accent" }
1527
+ ],
1528
+ [
1529
+ { text: "\u2800", tone: "accent" },
1530
+ { text: "\u28BB\u28FF", tone: "accent" },
1531
+ { text: "\u28FF", tone: "face" },
1532
+ { text: "\u285C\u28E7\u28C0\u28E0\u287F", tone: "warn" },
1533
+ { text: "\u28FC\u287F\u28FF\u28E7", tone: "face" },
1534
+ { text: "\u28BF\u28C4\u28E0\u287E", tone: "warn" },
1535
+ { text: "\u28FB", tone: "accent" },
1536
+ { text: "\u28FF", tone: "face" },
1537
+ { text: "\u28FF\u2847", tone: "accent" },
1538
+ { text: "\u2800", tone: "accent" }
1539
+ ],
1540
+ [
1541
+ { text: "\u2800", tone: "accent" },
1542
+ { text: "\u2818\u28FF\u28FF", tone: "accent" },
1543
+ { text: "\u28FF\u28F6\u28EF\u28F7\u28FE\u285F", tone: "face" },
1544
+ { text: "\u2801\u28EC", tone: "accent" },
1545
+ { text: "\u28FB\u28F7\u28FE\u28FF\u28FE\u28FF", tone: "face" },
1546
+ { text: "\u28FF\u287F", tone: "accent" },
1547
+ { text: "\u2800\u2800", tone: "accent" }
1548
+ ],
1549
+ [
1550
+ { text: "\u2800\u2800", tone: "accent" },
1551
+ { text: "\u2818\u28BF\u28FF\u28FF", tone: "accent" },
1552
+ { text: "\u28FF\u28FF\u28FF\u28FF", tone: "face" },
1553
+ { text: "\u2844\u28A1", tone: "accent" },
1554
+ { text: "\u28FF\u28FF\u28FF\u28FF", tone: "face" },
1555
+ { text: "\u28FF\u28FF\u281F\u2801", tone: "accent" },
1556
+ { text: "\u2800\u2800", tone: "accent" }
1557
+ ],
1558
+ [
1559
+ { text: "\u2800\u2800\u2800\u2800", tone: "accent" },
1560
+ { text: "\u2819\u283B\u28BF\u28FF\u28FF", tone: "accent" },
1561
+ { text: "\u28FF\u28FF\u28FF\u28FF", tone: "face" },
1562
+ { text: "\u28FF\u28FF\u287F\u281F\u2801", tone: "accent" },
1563
+ { text: "\u2800\u2800\u2800\u2800", tone: "accent" }
1564
+ ],
1565
+ [
1566
+ { text: "\u2800\u2800\u2800\u2800\u2800\u2800\u2800", tone: "accent" },
1567
+ { text: "\u2808\u2819\u281B\u281B\u281B\u281B\u2809\u2801", tone: "accent" },
1568
+ { text: "\u2800\u2800\u2800\u2800\u2800\u2800\u2800", tone: "accent" }
1569
+ ]
1570
+ ];
1571
+ var MENU = [
1572
+ { label: "Resume session", shortcut: "ctrl+r" },
1573
+ { label: "Switch theme", shortcut: "ctrl+t" },
1574
+ { label: "Help", shortcut: "ctrl+g (/help)" },
1575
+ { label: "Quit", shortcut: "ctrl+q" }
1576
+ ];
1577
+ var CHROME_ROWS = 6;
1578
+ var CARD_ROWS = 14;
1579
+ function WelcomeCard(props) {
1580
+ const cols = useTerminalWidth();
1581
+ const rows = useTerminalRows();
1582
+ const { theme } = useTheme();
1583
+ return /* @__PURE__ */ jsx8(
1584
+ Box6,
1585
+ {
1586
+ flexDirection: "column",
1587
+ justifyContent: "center",
1588
+ height: Math.max(CARD_ROWS + 1, rows - CHROME_ROWS),
1589
+ children: /* @__PURE__ */ jsxs5(
1590
+ Box6,
1591
+ {
1592
+ borderStyle: "round",
1593
+ borderColor: theme.border,
1594
+ width: Math.min(cols, 64),
1595
+ alignSelf: "center",
1596
+ paddingX: 2,
1597
+ paddingY: 1,
1598
+ flexDirection: "row",
1599
+ children: [
1600
+ /* @__PURE__ */ jsx8(Box6, { flexDirection: "column", marginRight: 3, children: LOGO.map((row, i) => /* @__PURE__ */ jsx8(Text7, { children: row.map((seg, j) => /* @__PURE__ */ jsx8(
1601
+ Text7,
1602
+ {
1603
+ color: seg.tone === "warn" ? theme.warn : seg.tone === "face" ? theme.assistant : theme.accent,
1604
+ children: seg.text
1605
+ },
1606
+ j
1607
+ )) }, i)) }),
1608
+ /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", flexGrow: 1, children: [
1609
+ /* @__PURE__ */ jsxs5(Box6, { children: [
1610
+ /* @__PURE__ */ jsx8(Text7, { color: theme.accent, bold: true, children: "miot chat" }),
1611
+ /* @__PURE__ */ jsxs5(Text7, { color: theme.dim, children: [
1612
+ " v",
1613
+ props.version
1614
+ ] })
1615
+ ] }),
1616
+ /* @__PURE__ */ jsx8(Box6, { height: 1 }),
1617
+ MENU.map((item) => /* @__PURE__ */ jsxs5(Box6, { justifyContent: "space-between", children: [
1618
+ /* @__PURE__ */ jsx8(Text7, { children: item.label }),
1619
+ /* @__PURE__ */ jsx8(Text7, { color: theme.dim, children: item.shortcut })
1620
+ ] }, item.label))
1621
+ ] })
1622
+ ]
1623
+ }
1624
+ )
1625
+ }
1626
+ );
1627
+ }
1628
+
1629
+ // src/tui/transcript/Transcript.tsx
1630
+ import { Box as Box10, Text as Text11 } from "ink";
1338
1631
 
1339
1632
  // src/tui/transcript/AssistantTurn.tsx
1340
- import { Box as Box3, Text as Text4 } from "ink";
1341
- import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1633
+ import { Box as Box7, Text as Text8 } from "ink";
1634
+ import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
1342
1635
  function AssistantTurn(props) {
1343
1636
  const { text, status } = props.item;
1344
1637
  const color = status === "failed" ? "red" : status === "complete" ? "green" : "white";
1345
- return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "row", marginTop: 1, children: [
1346
- status === "streaming" ? /* @__PURE__ */ jsxs3(Fragment2, { children: [
1347
- /* @__PURE__ */ jsx4(Spinner, { color: "cyan" }),
1348
- /* @__PURE__ */ jsxs3(Text4, { color, bold: true, children: [
1638
+ return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", marginTop: 1, children: [
1639
+ status === "streaming" ? /* @__PURE__ */ jsxs6(Fragment3, { children: [
1640
+ /* @__PURE__ */ jsx9(Spinner, { color: "cyan" }),
1641
+ /* @__PURE__ */ jsxs6(Text8, { color, bold: true, children: [
1349
1642
  " ",
1350
1643
  "miot",
1351
1644
  " "
1352
1645
  ] })
1353
- ] }) : /* @__PURE__ */ jsxs3(Text4, { color, bold: true, children: [
1646
+ ] }) : /* @__PURE__ */ jsxs6(Text8, { color, bold: true, children: [
1354
1647
  status === "failed" ? "\u2717 " : "\u2713 ",
1355
1648
  "miot",
1356
1649
  " "
1357
1650
  ] }),
1358
- /* @__PURE__ */ jsx4(Text4, { color, children: text })
1651
+ /* @__PURE__ */ jsx9(Text8, { color, children: text })
1359
1652
  ] });
1360
1653
  }
1361
1654
 
1362
1655
  // src/tui/transcript/ToolCall.tsx
1363
- import { Box as Box4, Text as Text5 } from "ink";
1364
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1656
+ import { Box as Box8, Text as Text9 } from "ink";
1657
+ import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
1365
1658
  function ToolCall(props) {
1366
1659
  const { name, status, message } = props.item;
1367
1660
  const color = status === "failed" ? "red" : status === "ok" ? "green" : "yellow";
1368
1661
  const glyph = status === "running" ? null : status === "ok" ? "\u2713" : "\u2717";
1369
- return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "row", children: [
1370
- /* @__PURE__ */ jsx5(Text5, { color, children: glyph !== null ? `${glyph} ` : "" }),
1371
- status === "running" ? /* @__PURE__ */ jsx5(Spinner, { color }) : null,
1372
- /* @__PURE__ */ jsxs4(Text5, { color, children: [
1662
+ return /* @__PURE__ */ jsxs7(Box8, { flexDirection: "row", children: [
1663
+ /* @__PURE__ */ jsx10(Text9, { color, children: glyph !== null ? `${glyph} ` : "" }),
1664
+ status === "running" ? /* @__PURE__ */ jsx10(Spinner, { color }) : null,
1665
+ /* @__PURE__ */ jsxs7(Text9, { color, children: [
1373
1666
  " ",
1374
1667
  "tool: ",
1375
1668
  name,
@@ -1379,24 +1672,24 @@ function ToolCall(props) {
1379
1672
  }
1380
1673
 
1381
1674
  // src/tui/transcript/UserTurn.tsx
1382
- import { Box as Box5, Text as Text6 } from "ink";
1383
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1675
+ import { Box as Box9, Text as Text10 } from "ink";
1676
+ import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
1384
1677
  function UserTurn(props) {
1385
1678
  const { text } = props.item;
1386
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", marginTop: 1, children: [
1387
- /* @__PURE__ */ jsxs5(Text6, { color: "cyan", bold: true, children: [
1679
+ return /* @__PURE__ */ jsxs8(Box9, { flexDirection: "row", marginTop: 1, children: [
1680
+ /* @__PURE__ */ jsxs8(Text10, { color: "cyan", bold: true, children: [
1388
1681
  "you",
1389
1682
  " "
1390
1683
  ] }),
1391
- /* @__PURE__ */ jsx6(Text6, { children: text })
1684
+ /* @__PURE__ */ jsx11(Text10, { children: text })
1392
1685
  ] });
1393
1686
  }
1394
1687
 
1395
1688
  // src/tui/transcript/Transcript.tsx
1396
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1689
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
1397
1690
  function Transcript(props) {
1398
1691
  const activeChainIdx = props.isStreaming ? findActiveChainIndex(props.items) : -1;
1399
- return /* @__PURE__ */ jsx7(Box6, { flexDirection: "column", children: props.items.map((item, i) => /* @__PURE__ */ jsx7(
1692
+ return /* @__PURE__ */ jsx12(Box10, { flexDirection: "column", children: props.items.map((item, i) => /* @__PURE__ */ jsx12(
1400
1693
  TranscriptItemView,
1401
1694
  {
1402
1695
  item,
@@ -1421,38 +1714,38 @@ function TranscriptItemView(props) {
1421
1714
  const { item, isActive } = props;
1422
1715
  switch (item.kind) {
1423
1716
  case "user":
1424
- return /* @__PURE__ */ jsx7(UserTurn, { item });
1717
+ return /* @__PURE__ */ jsx12(UserTurn, { item });
1425
1718
  case "assistant":
1426
- return /* @__PURE__ */ jsx7(AssistantTurn, { item });
1719
+ return /* @__PURE__ */ jsx12(AssistantTurn, { item });
1427
1720
  case "tool":
1428
- return /* @__PURE__ */ jsx7(ToolCall, { item });
1721
+ return /* @__PURE__ */ jsx12(ToolCall, { item });
1429
1722
  case "route":
1430
- return /* @__PURE__ */ jsx7(ChainRow, { prefix: "route:", isActive, children: item.route });
1723
+ return /* @__PURE__ */ jsx12(ChainRow, { prefix: "route:", isActive, children: item.route });
1431
1724
  case "agent":
1432
- return /* @__PURE__ */ jsx7(ChainRow, { prefix: "agent:", isActive, children: item.agent });
1725
+ return /* @__PURE__ */ jsx12(ChainRow, { prefix: "agent:", isActive, children: item.agent });
1433
1726
  case "thinking":
1434
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "row", children: [
1435
- /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: " \u22EE " }),
1436
- /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: item.text })
1727
+ return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "row", children: [
1728
+ /* @__PURE__ */ jsx12(Text11, { dimColor: true, children: " \u22EE " }),
1729
+ /* @__PURE__ */ jsx12(Text11, { dimColor: true, children: item.text })
1437
1730
  ] });
1438
1731
  case "plan":
1439
- return /* @__PURE__ */ jsx7(ChainRow, { prefix: "plan:", isActive, children: item.message });
1732
+ return /* @__PURE__ */ jsx12(ChainRow, { prefix: "plan:", isActive, children: item.message });
1440
1733
  case "freshness":
1441
- return /* @__PURE__ */ jsxs6(Text7, { color: "yellow", children: [
1734
+ return /* @__PURE__ */ jsxs9(Text11, { color: "yellow", children: [
1442
1735
  "\u26A0 ",
1443
1736
  item.message
1444
1737
  ] });
1445
1738
  case "artifact":
1446
- return /* @__PURE__ */ jsx7(ChainRow, { prefix: "artifact:", isActive, children: item.artifactKind });
1739
+ return /* @__PURE__ */ jsx12(ChainRow, { prefix: "artifact:", isActive, children: item.artifactKind });
1447
1740
  case "system":
1448
- return /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: item.text });
1741
+ return /* @__PURE__ */ jsx12(Text11, { dimColor: true, children: item.text });
1449
1742
  }
1450
1743
  }
1451
1744
  function ChainRow(props) {
1452
1745
  if (props.isActive) {
1453
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "row", children: [
1454
- /* @__PURE__ */ jsx7(Spinner, { color: "cyan" }),
1455
- /* @__PURE__ */ jsxs6(Text7, { color: "cyan", bold: true, children: [
1746
+ return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "row", children: [
1747
+ /* @__PURE__ */ jsx12(Spinner, { color: "cyan" }),
1748
+ /* @__PURE__ */ jsxs9(Text11, { color: "cyan", bold: true, children: [
1456
1749
  " ",
1457
1750
  props.prefix,
1458
1751
  " ",
@@ -1460,7 +1753,7 @@ function ChainRow(props) {
1460
1753
  ] })
1461
1754
  ] });
1462
1755
  }
1463
- return /* @__PURE__ */ jsxs6(Text7, { dimColor: true, children: [
1756
+ return /* @__PURE__ */ jsxs9(Text11, { dimColor: true, children: [
1464
1757
  "\xB7 ",
1465
1758
  props.prefix,
1466
1759
  " ",
@@ -1469,7 +1762,7 @@ function ChainRow(props) {
1469
1762
  }
1470
1763
 
1471
1764
  // src/tui/modals/ContextModal.tsx
1472
- import { Box as Box7, Text as Text8, useInput as useInput2 } from "ink";
1765
+ import { Box as Box11, Text as Text12, useInput as useInput2 } from "ink";
1473
1766
 
1474
1767
  // src/tui/session/selectors.ts
1475
1768
  function isStreaming(state) {
@@ -1521,7 +1814,7 @@ function contextPercent(state) {
1521
1814
  }
1522
1815
 
1523
1816
  // src/tui/modals/ContextModal.tsx
1524
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1817
+ import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
1525
1818
  function ContextModal(props) {
1526
1819
  const { session, lastRunId } = props;
1527
1820
  useInput2(
@@ -1546,24 +1839,24 @@ function ContextModal(props) {
1546
1839
  "pending approvals",
1547
1840
  String(session.pendingApprovals.length)
1548
1841
  ]);
1549
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1550
- /* @__PURE__ */ jsx8(Text8, { bold: true, children: "session context" }),
1551
- fields.map(([key, value]) => /* @__PURE__ */ jsxs7(Text8, { children: [
1842
+ return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1843
+ /* @__PURE__ */ jsx13(Text12, { bold: true, children: "session context" }),
1844
+ fields.map(([key, value]) => /* @__PURE__ */ jsxs10(Text12, { children: [
1552
1845
  key.padEnd(18),
1553
1846
  " ",
1554
1847
  value
1555
1848
  ] }, key)),
1556
- /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "esc/enter to close" })
1849
+ /* @__PURE__ */ jsx13(Text12, { dimColor: true, children: "esc/enter to close" })
1557
1850
  ] });
1558
1851
  }
1559
1852
 
1560
1853
  // src/tui/modals/ResumePicker.tsx
1561
- import { Box as Box8, Text as Text9, useInput as useInput3 } from "ink";
1562
- import { useState as useState3 } from "react";
1563
- import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1854
+ import { Box as Box12, Text as Text13, useInput as useInput3 } from "ink";
1855
+ import { useState as useState5 } from "react";
1856
+ import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
1564
1857
  function ResumePicker(props) {
1565
1858
  const maxRows = props.maxRows ?? 10;
1566
- const [index, setIndex] = useState3(0);
1859
+ const [index, setIndex] = useState5(0);
1567
1860
  const summaries = props.summaries;
1568
1861
  const cap = Math.max(0, summaries.length - 1);
1569
1862
  useInput3(
@@ -1588,23 +1881,23 @@ function ResumePicker(props) {
1588
1881
  { isActive: props.isFocused ?? true }
1589
1882
  );
1590
1883
  if (summaries.length === 0) {
1591
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1592
- /* @__PURE__ */ jsx9(Text9, { bold: true, children: "resume session" }),
1593
- /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "(no saved sessions)" }),
1594
- /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "esc to close" })
1884
+ return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1885
+ /* @__PURE__ */ jsx14(Text13, { bold: true, children: "resume session" }),
1886
+ /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "(no saved sessions)" }),
1887
+ /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "esc to close" })
1595
1888
  ] });
1596
1889
  }
1597
1890
  const visible = summaries.slice(0, maxRows);
1598
1891
  const truncated = summaries.length - visible.length;
1599
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1600
- /* @__PURE__ */ jsx9(Text9, { bold: true, children: "resume session" }),
1601
- visible.map((s, i) => /* @__PURE__ */ jsx9(Text9, { inverse: i === index, children: summarize(s) }, s.id)),
1602
- truncated > 0 ? /* @__PURE__ */ jsxs8(Text9, { dimColor: true, children: [
1892
+ return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1893
+ /* @__PURE__ */ jsx14(Text13, { bold: true, children: "resume session" }),
1894
+ visible.map((s, i) => /* @__PURE__ */ jsx14(Text13, { inverse: i === index, children: summarize(s) }, s.id)),
1895
+ truncated > 0 ? /* @__PURE__ */ jsxs11(Text13, { dimColor: true, children: [
1603
1896
  "\u2026 ",
1604
1897
  truncated,
1605
1898
  " more"
1606
1899
  ] }) : null,
1607
- /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "\u2191\u2193 navigate \xB7 enter select \xB7 esc cancel" })
1900
+ /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "\u2191\u2193 navigate \xB7 enter select \xB7 esc cancel" })
1608
1901
  ] });
1609
1902
  }
1610
1903
  function summarize(s) {
@@ -1620,62 +1913,13 @@ function truncate(text, max) {
1620
1913
  }
1621
1914
 
1622
1915
  // src/tui/modals/ThemePicker.tsx
1623
- import { Box as Box9, Text as Text10, useInput as useInput4 } from "ink";
1624
- import { useState as useState4 } from "react";
1625
-
1626
- // src/tui/theme/themes.ts
1627
- var DARK_THEME = {
1628
- accent: "cyan",
1629
- assistant: "white",
1630
- user: "cyan",
1631
- dim: "gray",
1632
- warn: "yellow",
1633
- err: "red",
1634
- ok: "green",
1635
- border: "gray",
1636
- prompt: "cyan",
1637
- spinner: "cyan"
1638
- };
1639
- var LIGHT_THEME = {
1640
- accent: "blue",
1641
- assistant: "black",
1642
- user: "blue",
1643
- dim: "gray",
1644
- warn: "yellow",
1645
- err: "red",
1646
- ok: "green",
1647
- border: "gray",
1648
- prompt: "blue",
1649
- spinner: "blue"
1650
- };
1651
- var HIGH_CONTRAST_THEME = {
1652
- accent: "white",
1653
- assistant: "white",
1654
- user: "white",
1655
- dim: "white",
1656
- warn: "yellow",
1657
- err: "red",
1658
- ok: "green",
1659
- border: "white",
1660
- prompt: "white",
1661
- spinner: "white"
1662
- };
1663
- var BUILTIN_THEMES = {
1664
- dark: DARK_THEME,
1665
- light: LIGHT_THEME,
1666
- "high-contrast": HIGH_CONTRAST_THEME
1667
- };
1668
- var DEFAULT_THEME_NAME = "dark";
1669
- function builtinThemeNames() {
1670
- return Object.keys(BUILTIN_THEMES).sort();
1671
- }
1672
-
1673
- // src/tui/modals/ThemePicker.tsx
1674
- import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1916
+ import { Box as Box13, Text as Text14, useInput as useInput4 } from "ink";
1917
+ import { useState as useState6 } from "react";
1918
+ import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
1675
1919
  function ThemePicker(props) {
1676
1920
  const names = builtinThemeNames();
1677
1921
  const initial = props.initialName ? Math.max(0, names.indexOf(props.initialName)) : 0;
1678
- const [index, setIndex] = useState4(initial);
1922
+ const [index, setIndex] = useState6(initial);
1679
1923
  const cap = names.length - 1;
1680
1924
  useInput4(
1681
1925
  (_input, key) => {
@@ -1698,23 +1942,23 @@ function ThemePicker(props) {
1698
1942
  },
1699
1943
  { isActive: props.isFocused ?? true }
1700
1944
  );
1701
- return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1702
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "theme" }),
1945
+ return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1946
+ /* @__PURE__ */ jsx15(Text14, { bold: true, children: "theme" }),
1703
1947
  names.map((name, i) => {
1704
1948
  const t = BUILTIN_THEMES[name];
1705
1949
  const sample = t ? `accent=${t.accent} user=${t.user}` : "";
1706
- return /* @__PURE__ */ jsxs9(Text10, { inverse: i === index, children: [
1950
+ return /* @__PURE__ */ jsxs12(Text14, { inverse: i === index, children: [
1707
1951
  name.padEnd(15),
1708
1952
  " ",
1709
1953
  sample
1710
1954
  ] }, name);
1711
1955
  }),
1712
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "\u2191\u2193 navigate \xB7 enter apply \xB7 esc cancel" })
1956
+ /* @__PURE__ */ jsx15(Text14, { dimColor: true, children: "\u2191\u2193 navigate \xB7 enter apply \xB7 esc cancel" })
1713
1957
  ] });
1714
1958
  }
1715
1959
 
1716
1960
  // src/tui/modals/ApprovalModal.tsx
1717
- import { Box as Box10, Text as Text11, useInput as useInput5 } from "ink";
1961
+ import { Box as Box14, Text as Text15, useInput as useInput5 } from "ink";
1718
1962
 
1719
1963
  // src/tui/session/approvals.ts
1720
1964
  var APPROVALS_UI_ENV = "MIOT_CHAT_APPROVALS_UI";
@@ -1726,7 +1970,7 @@ function isApprovalsUiEnabled(env = process.env) {
1726
1970
  var APPROVAL_REPLY_PLACEHOLDER = "approval reply not yet supported by harness";
1727
1971
 
1728
1972
  // src/tui/modals/ApprovalModal.tsx
1729
- import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
1973
+ import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
1730
1974
  function ApprovalModal(props) {
1731
1975
  const { approval, onResolve } = props;
1732
1976
  useInput5(
@@ -1739,22 +1983,22 @@ function ApprovalModal(props) {
1739
1983
  { isActive: props.isFocused ?? true }
1740
1984
  );
1741
1985
  const data = JSON.stringify(approval.data, null, 2);
1742
- return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1743
- /* @__PURE__ */ jsx11(Text11, { bold: true, color: "yellow", children: "approval requested" }),
1744
- /* @__PURE__ */ jsx11(Text11, { children: approval.message || "(no message)" }),
1745
- /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: data }),
1746
- /* @__PURE__ */ jsx11(Text11, { children: "[Y] approve [N] deny [Esc] later" }),
1747
- /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: APPROVAL_REPLY_PLACEHOLDER })
1986
+ return /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1987
+ /* @__PURE__ */ jsx16(Text15, { bold: true, color: "yellow", children: "approval requested" }),
1988
+ /* @__PURE__ */ jsx16(Text15, { children: approval.message || "(no message)" }),
1989
+ /* @__PURE__ */ jsx16(Text15, { dimColor: true, children: data }),
1990
+ /* @__PURE__ */ jsx16(Text15, { children: "[Y] approve [N] deny [Esc] later" }),
1991
+ /* @__PURE__ */ jsx16(Text15, { dimColor: true, children: APPROVAL_REPLY_PLACEHOLDER })
1748
1992
  ] });
1749
1993
  }
1750
1994
 
1751
1995
  // src/tui/modals/RunsPicker.tsx
1752
- import { Box as Box11, Text as Text12, useInput as useInput6 } from "ink";
1753
- import { useState as useState5 } from "react";
1754
- import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
1996
+ import { Box as Box15, Text as Text16, useInput as useInput6 } from "ink";
1997
+ import { useState as useState7 } from "react";
1998
+ import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
1755
1999
  function RunsPicker(props) {
1756
2000
  const maxRows = props.maxRows ?? 10;
1757
- const [index, setIndex] = useState5(0);
2001
+ const [index, setIndex] = useState7(0);
1758
2002
  const cap = Math.max(0, props.runs.length - 1);
1759
2003
  useInput6(
1760
2004
  (_input, key) => {
@@ -1778,23 +2022,23 @@ function RunsPicker(props) {
1778
2022
  { isActive: props.isFocused ?? true }
1779
2023
  );
1780
2024
  if (props.runs.length === 0) {
1781
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1782
- /* @__PURE__ */ jsx12(Text12, { bold: true, children: "recent runs" }),
1783
- /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "(no runs in this session)" }),
1784
- /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "esc to close" })
2025
+ return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
2026
+ /* @__PURE__ */ jsx17(Text16, { bold: true, children: "recent runs" }),
2027
+ /* @__PURE__ */ jsx17(Text16, { dimColor: true, children: "(no runs in this session)" }),
2028
+ /* @__PURE__ */ jsx17(Text16, { dimColor: true, children: "esc to close" })
1785
2029
  ] });
1786
2030
  }
1787
2031
  const visible = props.runs.slice(0, maxRows);
1788
2032
  const truncated = props.runs.length - visible.length;
1789
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1790
- /* @__PURE__ */ jsx12(Text12, { bold: true, children: "recent runs" }),
1791
- visible.map((r, i) => /* @__PURE__ */ jsx12(Text12, { inverse: i === index, children: formatRow(r) }, r.runId)),
1792
- truncated > 0 ? /* @__PURE__ */ jsxs11(Text12, { dimColor: true, children: [
2033
+ return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
2034
+ /* @__PURE__ */ jsx17(Text16, { bold: true, children: "recent runs" }),
2035
+ visible.map((r, i) => /* @__PURE__ */ jsx17(Text16, { inverse: i === index, children: formatRow(r) }, r.runId)),
2036
+ truncated > 0 ? /* @__PURE__ */ jsxs14(Text16, { dimColor: true, children: [
1793
2037
  "\u2026 ",
1794
2038
  truncated,
1795
2039
  " more"
1796
2040
  ] }) : null,
1797
- /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "\u2191\u2193 navigate \xB7 enter replay \xB7 esc cancel" })
2041
+ /* @__PURE__ */ jsx17(Text16, { dimColor: true, children: "\u2191\u2193 navigate \xB7 enter replay \xB7 esc cancel" })
1798
2042
  ] });
1799
2043
  }
1800
2044
  function formatRow(r) {
@@ -1833,27 +2077,6 @@ function findPrecedingPrompt(items, startAt) {
1833
2077
  return null;
1834
2078
  }
1835
2079
 
1836
- // src/tui/theme/ThemeProvider.tsx
1837
- import { createContext, useContext, useMemo, useState as useState6 } from "react";
1838
- import { jsx as jsx13 } from "react/jsx-runtime";
1839
- var ThemeContext = createContext({
1840
- theme: DARK_THEME,
1841
- setTheme: () => void 0
1842
- });
1843
- function ThemeProvider(props) {
1844
- const [theme, setTheme] = useState6(
1845
- props.initialTheme ?? DARK_THEME
1846
- );
1847
- const value = useMemo(
1848
- () => ({ theme, setTheme }),
1849
- [theme]
1850
- );
1851
- return /* @__PURE__ */ jsx13(ThemeContext.Provider, { value, children: props.children });
1852
- }
1853
- function useTheme() {
1854
- return useContext(ThemeContext);
1855
- }
1856
-
1857
2080
  // src/tui/theme/loadUserTheme.ts
1858
2081
  function loadUserTheme(config) {
1859
2082
  if (config === void 0 || config === null) {
@@ -1885,8 +2108,14 @@ function resolveByName(name) {
1885
2108
  };
1886
2109
  }
1887
2110
 
2111
+ // src/tui/session/agentic.ts
2112
+ var AGENTIC_TENANT_LOCK2 = "mintral";
2113
+ function isAgenticTenantMismatch(mode, tenant) {
2114
+ return mode === "agentic" && tenant !== AGENTIC_TENANT_LOCK2;
2115
+ }
2116
+
1888
2117
  // src/tui/useSession.ts
1889
- import { useCallback, useEffect as useEffect2, useReducer as useReducer2, useRef } from "react";
2118
+ import { useCallback, useEffect as useEffect3, useReducer as useReducer2, useRef } from "react";
1890
2119
  import { appendFileSync, mkdirSync as mkdirSync3 } from "fs";
1891
2120
  import { dirname as dirname3 } from "path";
1892
2121
 
@@ -2368,7 +2597,7 @@ function useSession(opts) {
2368
2597
  () => initialSession(opts.initial, opts.ctx)
2369
2598
  );
2370
2599
  const stateRef = useRef(state);
2371
- useEffect2(() => {
2600
+ useEffect3(() => {
2372
2601
  stateRef.current = state;
2373
2602
  }, [state]);
2374
2603
  const abortRef = useRef(null);
@@ -2961,14 +3190,13 @@ function lastUserPrompt(state) {
2961
3190
  }
2962
3191
 
2963
3192
  // src/tui/App.tsx
2964
- import { Text as Text13 } from "ink";
2965
- import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
3193
+ import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
2966
3194
  function App(props) {
2967
3195
  const themeResult = useMemo2(
2968
3196
  () => loadUserTheme(props.config.theme),
2969
3197
  [props.config.theme]
2970
3198
  );
2971
- return /* @__PURE__ */ jsx14(ThemeProvider, { initialTheme: themeResult.theme, children: /* @__PURE__ */ jsx14(AppInner, { ...props, themeWarning: themeResult.warning }) });
3199
+ return /* @__PURE__ */ jsx18(ThemeProvider, { initialTheme: themeResult.theme, children: /* @__PURE__ */ jsx18(AppInner, { ...props, themeWarning: themeResult.warning }) });
2972
3200
  }
2973
3201
  function AppInner(props) {
2974
3202
  const home = props.home ?? defaultMiotChatHome();
@@ -2988,8 +3216,8 @@ function AppInner(props) {
2988
3216
  client: props.client
2989
3217
  });
2990
3218
  const { setTheme } = useTheme();
2991
- const [extraItems, setExtraItems] = useState7([]);
2992
- const [modal, setModalState] = useState7({ spec: null });
3219
+ const [extraItems, setExtraItems] = useState8([]);
3220
+ const [modal, setModalState] = useState8({ spec: null });
2993
3221
  const registry = useMemo2(() => {
2994
3222
  const reg = new SlashRegistry();
2995
3223
  reg.register(helpCommand).register(clearCommand).register(resetCommand).register(exitCommand).register(modeCommand).register(tenantCommand).register(userCommand).register(saveCommand).register(contextCommand).register(whoamiCommand).register(themeCommand).register(resumeCommand).register(exportCommand).register(runsCommand).register(approveCommand);
@@ -3047,6 +3275,13 @@ function AppInner(props) {
3047
3275
  appendSystem
3048
3276
  ]
3049
3277
  );
3278
+ useInput7((input, key) => {
3279
+ if (!key.ctrl || modal.spec !== null) return;
3280
+ if (input === "r") void dispatchSlash("/resume");
3281
+ else if (input === "t") void dispatchSlash("/theme");
3282
+ else if (input === "g") void dispatchSlash("/help");
3283
+ else if (input === "q") void dispatchSlash("/exit");
3284
+ });
3050
3285
  const handleSubmit = useCallback2(
3051
3286
  (text) => {
3052
3287
  if (text.trim().startsWith("/")) {
@@ -3067,16 +3302,21 @@ function AppInner(props) {
3067
3302
  );
3068
3303
  const modalSpec = modal.spec;
3069
3304
  const editorActive = modalSpec === null;
3070
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
3071
- props.themeWarning ? /* @__PURE__ */ jsx14(Box12, { paddingX: 1, children: /* @__PURE__ */ jsx14(SystemNote, { text: `theme: ${props.themeWarning}` }) }) : null,
3072
- /* @__PURE__ */ jsx14(
3305
+ const version2 = useMemo2(() => packageVersion(), []);
3306
+ const showWelcome = allItems.length === 0 && modalSpec === null;
3307
+ const meta = session.state.meta;
3308
+ const agenticWarn = isAgenticTenantMismatch(meta.mode, meta.tenantId);
3309
+ return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", children: [
3310
+ props.themeWarning ? /* @__PURE__ */ jsx18(Box16, { paddingX: 1, children: /* @__PURE__ */ jsx18(SystemNote, { text: `theme: ${props.themeWarning}` }) }) : null,
3311
+ /* @__PURE__ */ jsx18(TopLine, { meta, streaming: isStreaming(session.state) }),
3312
+ showWelcome ? /* @__PURE__ */ jsx18(WelcomeCard, { version: version2 }) : /* @__PURE__ */ jsx18(
3073
3313
  Transcript,
3074
3314
  {
3075
3315
  items: allItems,
3076
3316
  isStreaming: isStreaming(session.state)
3077
3317
  }
3078
3318
  ),
3079
- modalSpec?.kind === "context" ? /* @__PURE__ */ jsx14(
3319
+ modalSpec?.kind === "context" ? /* @__PURE__ */ jsx18(
3080
3320
  ContextModal,
3081
3321
  {
3082
3322
  session: session.state,
@@ -3084,7 +3324,7 @@ function AppInner(props) {
3084
3324
  onClose: closeModal
3085
3325
  }
3086
3326
  ) : null,
3087
- modalSpec?.kind === "resume" ? /* @__PURE__ */ jsx14(
3327
+ modalSpec?.kind === "resume" ? /* @__PURE__ */ jsx18(
3088
3328
  ResumePicker,
3089
3329
  {
3090
3330
  summaries: listSessions(home),
@@ -3097,7 +3337,7 @@ function AppInner(props) {
3097
3337
  onCancel: closeModal
3098
3338
  }
3099
3339
  ) : null,
3100
- modalSpec?.kind === "theme" ? /* @__PURE__ */ jsx14(
3340
+ modalSpec?.kind === "theme" ? /* @__PURE__ */ jsx18(
3101
3341
  ThemePicker,
3102
3342
  {
3103
3343
  initialName: typeof modalSpec.payload?.name === "string" ? modalSpec.payload.name : void 0,
@@ -3112,7 +3352,7 @@ function AppInner(props) {
3112
3352
  onCancel: closeModal
3113
3353
  }
3114
3354
  ) : null,
3115
- modalSpec?.kind === "approval" && isApprovalsUiEnabled() && session.state.pendingApprovals.length > 0 ? /* @__PURE__ */ jsx14(
3355
+ modalSpec?.kind === "approval" && isApprovalsUiEnabled() && session.state.pendingApprovals.length > 0 ? /* @__PURE__ */ jsx18(
3116
3356
  ApprovalModal,
3117
3357
  {
3118
3358
  approval: session.state.pendingApprovals[0],
@@ -3122,7 +3362,7 @@ function AppInner(props) {
3122
3362
  }
3123
3363
  }
3124
3364
  ) : null,
3125
- modalSpec?.kind === "runs" ? /* @__PURE__ */ jsx14(
3365
+ modalSpec?.kind === "runs" ? /* @__PURE__ */ jsx18(
3126
3366
  RunsPickerWrapped,
3127
3367
  {
3128
3368
  state: session.state,
@@ -3133,27 +3373,28 @@ function AppInner(props) {
3133
3373
  onCancel: closeModal
3134
3374
  }
3135
3375
  ) : null,
3136
- /* @__PURE__ */ jsx14(
3137
- Header,
3376
+ /* @__PURE__ */ jsx18(TipLine, { tipIndex: turnCount(session.state) }),
3377
+ /* @__PURE__ */ jsx18(InputFrame, { label: `miot \xB7 ${meta.mode}`, labelWarn: agenticWarn, children: /* @__PURE__ */ jsx18(Editor, { onSubmit: handleSubmit, isFocused: editorActive }) }),
3378
+ /* @__PURE__ */ jsx18(
3379
+ FooterLine,
3138
3380
  {
3139
- meta: session.state.meta,
3140
- streaming: isStreaming(session.state),
3141
- pendingApprovals: pendingApprovalCount(session.state),
3142
3381
  turns: turnCount(session.state),
3143
3382
  approxTokens: approxTokenCount(session.state),
3144
3383
  contextPercent: contextPercent(session.state),
3145
- usageTotals: session.state.usageTotals
3384
+ usageTotals: session.state.usageTotals,
3385
+ baseUrl: meta.baseUrl,
3386
+ profileName: meta.profileName,
3387
+ pendingApprovals: pendingApprovalCount(session.state)
3146
3388
  }
3147
- ),
3148
- /* @__PURE__ */ jsx14(Editor, { onSubmit: handleSubmit, isFocused: editorActive })
3389
+ )
3149
3390
  ] });
3150
3391
  }
3151
3392
  function RunsPickerWrapped(props) {
3152
3393
  const runs = summarizeRuns(props.state);
3153
- return /* @__PURE__ */ jsx14(RunsPicker, { runs, onSelect: props.onSelect, onCancel: props.onCancel });
3394
+ return /* @__PURE__ */ jsx18(RunsPicker, { runs, onSelect: props.onSelect, onCancel: props.onCancel });
3154
3395
  }
3155
3396
  function SystemNote(props) {
3156
- return /* @__PURE__ */ jsx14(Box12, { children: /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: props.text }) });
3397
+ return /* @__PURE__ */ jsx18(Box16, { children: /* @__PURE__ */ jsx18(Text17, { dimColor: true, children: props.text }) });
3157
3398
  }
3158
3399
 
3159
3400
  // src/tui/runTui.ts
@@ -3278,8 +3519,7 @@ async function runMiotChat(opts) {
3278
3519
  }
3279
3520
 
3280
3521
  // src/cli.ts
3281
- var require2 = createRequire(import.meta.url);
3282
- var { version } = require2("../package.json");
3522
+ var version = packageVersion();
3283
3523
  var program = new Command();
3284
3524
  program.name("miot-chat").description(
3285
3525
  "Copilot-style agentic chat CLI for miot-harness (SSE streaming)."