@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/index.js CHANGED
@@ -671,10 +671,18 @@ import { render } from "ink";
671
671
  import { createElement } from "react";
672
672
 
673
673
  // src/tui/App.tsx
674
- import { Box as Box12 } from "ink";
675
- import { useCallback as useCallback2, useMemo as useMemo2, useState as useState7 } from "react";
674
+ import { Box as Box16, Text as Text17, useInput as useInput7 } from "ink";
675
+ import { useCallback as useCallback2, useMemo as useMemo2, useState as useState8 } from "react";
676
676
  import { randomUUID as randomUUID2 } from "crypto";
677
677
 
678
+ // src/version.ts
679
+ import { createRequire } from "module";
680
+ function packageVersion() {
681
+ const require2 = createRequire(import.meta.url);
682
+ const pkg = require2("../package.json");
683
+ return pkg.version;
684
+ }
685
+
678
686
  // src/tui/input/Editor.tsx
679
687
  import { Box, Text, useInput } from "ink";
680
688
  import { useReducer, useState } from "react";
@@ -1028,15 +1036,9 @@ function renderLine(line, cursorCol) {
1028
1036
  ] });
1029
1037
  }
1030
1038
 
1031
- // src/tui/header/Header.tsx
1039
+ // src/tui/chrome/TopLine.tsx
1032
1040
  import { Box as Box2, Text as Text3 } from "ink";
1033
1041
 
1034
- // src/tui/session/agentic.ts
1035
- var AGENTIC_TENANT_LOCK2 = "mintral";
1036
- function isAgenticTenantMismatch(mode, tenant) {
1037
- return mode === "agentic" && tenant !== AGENTIC_TENANT_LOCK2;
1038
- }
1039
-
1040
1042
  // src/tui/transcript/Spinner.tsx
1041
1043
  import { Text as Text2 } from "ink";
1042
1044
  import { useEffect, useState as useState2 } from "react";
@@ -1057,129 +1059,421 @@ function Spinner(props) {
1057
1059
  return /* @__PURE__ */ jsx2(Text2, { color: props.color, children: FRAMES[frame] });
1058
1060
  }
1059
1061
 
1060
- // src/tui/header/Header.tsx
1061
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1062
- var SEPARATOR = " \xB7 ";
1063
- function Header(props) {
1064
- const { meta, streaming, pendingApprovals } = props;
1065
- const shortConv = meta.conversationId.slice(0, 8);
1066
- const agenticWarn = isAgenticTenantMismatch(meta.mode, meta.tenantId);
1067
- const chips = [];
1068
- chips.push(/* @__PURE__ */ jsxs2(Text3, { children: [
1069
- "tenant=",
1070
- meta.tenantId
1071
- ] }, "tenant"));
1072
- chips.push(/* @__PURE__ */ jsxs2(Text3, { children: [
1073
- "user=",
1074
- meta.userId
1075
- ] }, "user"));
1076
- chips.push(/* @__PURE__ */ jsxs2(Text3, { children: [
1077
- "conv=",
1078
- shortConv
1079
- ] }, "conv"));
1080
- chips.push(
1081
- /* @__PURE__ */ jsxs2(Text3, { color: agenticWarn ? "yellow" : void 0, children: [
1082
- agenticWarn ? "\u26A0 " : "",
1083
- "mode=",
1084
- meta.mode
1085
- ] }, "mode")
1062
+ // src/tui/theme/ThemeProvider.tsx
1063
+ import { createContext, useContext, useMemo, useState as useState3 } from "react";
1064
+
1065
+ // src/tui/theme/themes.ts
1066
+ var DARK_THEME = {
1067
+ accent: "cyan",
1068
+ assistant: "white",
1069
+ user: "cyan",
1070
+ dim: "gray",
1071
+ warn: "yellow",
1072
+ err: "red",
1073
+ ok: "green",
1074
+ border: "gray",
1075
+ prompt: "cyan",
1076
+ spinner: "cyan"
1077
+ };
1078
+ var LIGHT_THEME = {
1079
+ accent: "blue",
1080
+ assistant: "black",
1081
+ user: "blue",
1082
+ dim: "gray",
1083
+ warn: "yellow",
1084
+ err: "red",
1085
+ ok: "green",
1086
+ border: "gray",
1087
+ prompt: "blue",
1088
+ spinner: "blue"
1089
+ };
1090
+ var HIGH_CONTRAST_THEME = {
1091
+ accent: "white",
1092
+ assistant: "white",
1093
+ user: "white",
1094
+ dim: "white",
1095
+ warn: "yellow",
1096
+ err: "red",
1097
+ ok: "green",
1098
+ border: "white",
1099
+ prompt: "white",
1100
+ spinner: "white"
1101
+ };
1102
+ var BUILTIN_THEMES = {
1103
+ dark: DARK_THEME,
1104
+ light: LIGHT_THEME,
1105
+ "high-contrast": HIGH_CONTRAST_THEME
1106
+ };
1107
+ var DEFAULT_THEME_NAME = "dark";
1108
+ function builtinThemeNames() {
1109
+ return Object.keys(BUILTIN_THEMES).sort();
1110
+ }
1111
+
1112
+ // src/tui/theme/ThemeProvider.tsx
1113
+ import { jsx as jsx3 } from "react/jsx-runtime";
1114
+ var ThemeContext = createContext({
1115
+ theme: DARK_THEME,
1116
+ setTheme: () => void 0
1117
+ });
1118
+ function ThemeProvider(props) {
1119
+ const [theme, setTheme] = useState3(
1120
+ props.initialTheme ?? DARK_THEME
1086
1121
  );
1087
- chips.push(/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: meta.baseUrl }, "url"));
1088
- if (meta.profileName) {
1089
- chips.push(/* @__PURE__ */ jsxs2(Text3, { dimColor: true, children: [
1090
- "profile=",
1091
- meta.profileName
1092
- ] }, "profile"));
1093
- }
1094
- if (pendingApprovals > 0) {
1095
- chips.push(
1096
- /* @__PURE__ */ jsxs2(Text3, { color: "yellow", children: [
1097
- "approvals=",
1098
- pendingApprovals
1099
- ] }, "appr")
1100
- );
1101
- }
1102
- if (typeof props.turns === "number") {
1103
- chips.push(/* @__PURE__ */ jsxs2(Text3, { dimColor: true, children: [
1104
- "turns=",
1105
- props.turns
1106
- ] }, "turns"));
1107
- }
1108
- if (typeof props.approxTokens === "number") {
1109
- const pct = typeof props.contextPercent === "number" ? ` (${props.contextPercent}%)` : "";
1110
- chips.push(
1111
- /* @__PURE__ */ jsxs2(Text3, { dimColor: true, children: [
1112
- "ctx\u2248",
1113
- props.approxTokens,
1114
- "tok",
1115
- pct
1116
- ] }, "tok")
1117
- );
1118
- }
1119
- if (props.usageTotals && (props.usageTotals.inputTokens > 0 || props.usageTotals.outputTokens > 0)) {
1120
- const u = props.usageTotals;
1122
+ const value = useMemo(
1123
+ () => ({ theme, setTheme }),
1124
+ [theme]
1125
+ );
1126
+ return /* @__PURE__ */ jsx3(ThemeContext.Provider, { value, children: props.children });
1127
+ }
1128
+ function useTheme() {
1129
+ return useContext(ThemeContext);
1130
+ }
1131
+
1132
+ // src/tui/chrome/TopLine.tsx
1133
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
1134
+ function TopLine(props) {
1135
+ const { theme } = useTheme();
1136
+ const shortConv = props.meta.conversationId.slice(0, 8);
1137
+ return /* @__PURE__ */ jsxs2(Box2, { paddingX: 1, children: [
1138
+ /* @__PURE__ */ jsxs2(Text3, { color: theme.dim, children: [
1139
+ "\u2387 ",
1140
+ props.meta.tenantId,
1141
+ " \xB7 ",
1142
+ props.meta.userId,
1143
+ " \xB7 conv ",
1144
+ shortConv
1145
+ ] }),
1146
+ props.streaming ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
1147
+ /* @__PURE__ */ jsx4(Text3, { color: theme.dim, children: " " }),
1148
+ /* @__PURE__ */ jsx4(Spinner, { color: theme.spinner })
1149
+ ] }) : null
1150
+ ] });
1151
+ }
1152
+
1153
+ // src/tui/chrome/TipLine.tsx
1154
+ import { Box as Box3, Text as Text4 } from "ink";
1155
+ import { jsx as jsx5 } from "react/jsx-runtime";
1156
+ var TIPS = [
1157
+ "Tip: type / to see available commands.",
1158
+ "Tip: ctrl+r resumes a saved session.",
1159
+ "Tip: ctrl+t switches the color theme.",
1160
+ "Tip: /save stores this conversation for later.",
1161
+ "Tip: /export writes the conversation as markdown."
1162
+ ];
1163
+ function TipLine(props) {
1164
+ const { theme } = useTheme();
1165
+ const tip = TIPS[props.tipIndex % TIPS.length];
1166
+ return /* @__PURE__ */ jsx5(Box3, { paddingX: 1, children: /* @__PURE__ */ jsx5(Text4, { color: theme.dim, children: tip }) });
1167
+ }
1168
+
1169
+ // src/tui/chrome/FooterLine.tsx
1170
+ import { Box as Box4, Text as Text5 } from "ink";
1171
+ import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
1172
+ function FooterLine(props) {
1173
+ const { theme } = useTheme();
1174
+ const segments = [];
1175
+ segments.push(`turns ${props.turns}`);
1176
+ segments.push(`ctx\u2248${props.approxTokens}tok (${props.contextPercent}%)`);
1177
+ const u = props.usageTotals;
1178
+ if (u && (u.inputTokens > 0 || u.outputTokens > 0)) {
1121
1179
  const cost = u.costUsd > 0 ? ` $${u.costUsd.toFixed(4)}` : "";
1122
- chips.push(
1123
- /* @__PURE__ */ jsxs2(Text3, { dimColor: true, children: [
1124
- "usage=",
1125
- u.inputTokens,
1126
- "\u2192",
1127
- u.outputTokens,
1128
- cost
1129
- ] }, "usage")
1130
- );
1180
+ segments.push(`${u.inputTokens}\u2192${u.outputTokens}${cost}`);
1131
1181
  }
1132
- if (streaming) {
1133
- chips.push(/* @__PURE__ */ jsx3(Spinner, { color: "cyan" }, "spinner"));
1182
+ segments.push(props.baseUrl);
1183
+ if (props.profileName) {
1184
+ segments.push(`profile ${props.profileName}`);
1134
1185
  }
1135
- 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}`)) });
1186
+ return /* @__PURE__ */ jsxs3(Box4, { paddingX: 1, justifyContent: "flex-end", children: [
1187
+ props.pendingApprovals > 0 ? /* @__PURE__ */ jsxs3(Text5, { color: theme.warn, children: [
1188
+ "approvals ",
1189
+ props.pendingApprovals,
1190
+ " \xB7 "
1191
+ ] }) : null,
1192
+ /* @__PURE__ */ jsx6(Text5, { color: theme.dim, children: segments.join(" \xB7 ") })
1193
+ ] });
1136
1194
  }
1137
- function interpose(nodes, sep) {
1138
- const out = [];
1139
- nodes.forEach((node, i) => {
1140
- if (i > 0) out.push(sep(i));
1141
- out.push(node);
1142
- });
1143
- return out;
1195
+
1196
+ // src/tui/chrome/InputFrame.tsx
1197
+ import { Box as Box5, Text as Text6 } from "ink";
1198
+
1199
+ // src/tui/hooks/useTerminalWidth.ts
1200
+ import { useStdout } from "ink";
1201
+ import { useEffect as useEffect2, useState as useState4 } from "react";
1202
+ var FALLBACK_COLUMNS = 80;
1203
+ var MIN_COLUMNS = 20;
1204
+ function useTerminalWidth() {
1205
+ const { stdout } = useStdout();
1206
+ const [columns, setColumns] = useState4(
1207
+ stdout?.columns ?? FALLBACK_COLUMNS
1208
+ );
1209
+ useEffect2(() => {
1210
+ if (!stdout) return;
1211
+ const onResize = () => {
1212
+ setColumns(stdout.columns ?? FALLBACK_COLUMNS);
1213
+ };
1214
+ stdout.on("resize", onResize);
1215
+ return () => {
1216
+ stdout.off("resize", onResize);
1217
+ };
1218
+ }, [stdout]);
1219
+ return Math.max(MIN_COLUMNS, columns);
1220
+ }
1221
+ var FALLBACK_ROWS = 24;
1222
+ var MIN_ROWS = 10;
1223
+ function useTerminalRows() {
1224
+ const { stdout } = useStdout();
1225
+ const [rows, setRows] = useState4(stdout?.rows ?? FALLBACK_ROWS);
1226
+ useEffect2(() => {
1227
+ if (!stdout) return;
1228
+ const onResize = () => {
1229
+ setRows(stdout.rows ?? FALLBACK_ROWS);
1230
+ };
1231
+ stdout.on("resize", onResize);
1232
+ return () => {
1233
+ stdout.off("resize", onResize);
1234
+ };
1235
+ }, [stdout]);
1236
+ return Math.max(MIN_ROWS, rows);
1237
+ }
1238
+
1239
+ // src/tui/chrome/InputFrame.tsx
1240
+ import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
1241
+ function InputFrame(props) {
1242
+ const cols = useTerminalWidth();
1243
+ const { theme } = useTheme();
1244
+ return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", width: cols, children: [
1245
+ /* @__PURE__ */ jsx7(
1246
+ Box5,
1247
+ {
1248
+ borderStyle: "round",
1249
+ borderColor: theme.border,
1250
+ borderBottom: false,
1251
+ paddingX: 1,
1252
+ children: props.children
1253
+ }
1254
+ ),
1255
+ /* @__PURE__ */ jsx7(
1256
+ BottomBorder,
1257
+ {
1258
+ cols,
1259
+ label: props.label,
1260
+ warn: props.labelWarn ?? false
1261
+ }
1262
+ )
1263
+ ] });
1264
+ }
1265
+ function BottomBorder(props) {
1266
+ const { theme } = useTheme();
1267
+ const visibleLabel = props.warn ? `\u26A0 ${props.label}` : props.label;
1268
+ const labelText = ` ${visibleLabel} `;
1269
+ const fill = props.cols - 2 - labelText.length - 2;
1270
+ if (fill < 1) {
1271
+ return /* @__PURE__ */ jsxs4(Text6, { color: theme.border, children: [
1272
+ "\u2570",
1273
+ "\u2500".repeat(Math.max(0, props.cols - 2)),
1274
+ "\u256F"
1275
+ ] });
1276
+ }
1277
+ return /* @__PURE__ */ jsxs4(Text6, { children: [
1278
+ /* @__PURE__ */ jsxs4(Text6, { color: theme.border, children: [
1279
+ "\u2570",
1280
+ "\u2500".repeat(fill)
1281
+ ] }),
1282
+ /* @__PURE__ */ jsx7(Text6, { color: props.warn ? theme.warn : theme.dim, children: labelText }),
1283
+ /* @__PURE__ */ jsx7(Text6, { color: theme.border, children: "\u2500\u2500\u256F" })
1284
+ ] });
1144
1285
  }
1145
1286
 
1146
- // src/tui/transcript/Transcript.tsx
1287
+ // src/tui/chrome/WelcomeCard.tsx
1147
1288
  import { Box as Box6, Text as Text7 } from "ink";
1289
+ import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
1290
+ var LOGO = [
1291
+ [
1292
+ { text: "\u2880", tone: "accent" },
1293
+ { text: "\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800", tone: "accent" },
1294
+ { text: "\u28C0", tone: "accent" },
1295
+ { text: "\u28E4\u28E4\u28C0", tone: "warn" },
1296
+ { text: "\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800", tone: "accent" },
1297
+ { text: "\u2840", tone: "accent" }
1298
+ ],
1299
+ [
1300
+ { text: "\u2800", tone: "accent" },
1301
+ { text: "\u28BF\u28F6\u28F6\u28E4\u28E4\u28F0", tone: "accent" },
1302
+ { text: "\u28B6\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28F7", tone: "warn" },
1303
+ { text: "\u28C6\u28E4\u28E4\u28F6\u28F6\u287F", tone: "accent" },
1304
+ { text: "\u2800", tone: "accent" }
1305
+ ],
1306
+ [
1307
+ { text: "\u2800", tone: "accent" },
1308
+ { text: "\u2808\u281B\u28DB\u289B\u28DB\u28DB\u285B\u283A", tone: "accent" },
1309
+ { text: "\u28BF\u28FF\u28FF\u287F", tone: "warn" },
1310
+ { text: "\u281F\u281B\u28DB\u28DB\u28DB\u28DB\u281B\u2801", tone: "accent" },
1311
+ { text: "\u2800", tone: "accent" }
1312
+ ],
1313
+ [
1314
+ { text: "\u2800", tone: "accent" },
1315
+ { text: "\u2880\u28FF\u28FF", tone: "accent" },
1316
+ { text: "\u28FF\u289F\u28DB\u28DB\u28BF\u28E6", tone: "face" },
1317
+ { text: "\u28CC\u28E1", tone: "accent" },
1318
+ { text: "\u28F4\u287E\u28DB\u28DB\u287F\u28FF", tone: "face" },
1319
+ { text: "\u28FF\u28F7", tone: "accent" },
1320
+ { text: "\u2800\u2800", tone: "accent" }
1321
+ ],
1322
+ [
1323
+ { text: "\u2800", tone: "accent" },
1324
+ { text: "\u28F8\u28FF", tone: "accent" },
1325
+ { text: "\u28FF", tone: "face" },
1326
+ { text: "\u28B3", tone: "accent" },
1327
+ { text: "\u287F", tone: "warn" },
1328
+ { text: "\u286F", tone: "accent" },
1329
+ { text: "\u2819\u28F7", tone: "warn" },
1330
+ { text: "\u28BB\u28FF\u28FF\u285F", tone: "face" },
1331
+ { text: "\u28FE\u280B", tone: "warn" },
1332
+ { text: "\u28BD", tone: "accent" },
1333
+ { text: "\u28BB", tone: "warn" },
1334
+ { text: "\u28FD", tone: "accent" },
1335
+ { text: "\u28FF", tone: "face" },
1336
+ { text: "\u28FF\u2847", tone: "accent" },
1337
+ { text: "\u2800", tone: "accent" }
1338
+ ],
1339
+ [
1340
+ { text: "\u2800", tone: "accent" },
1341
+ { text: "\u28BB\u28FF", tone: "accent" },
1342
+ { text: "\u28FF", tone: "face" },
1343
+ { text: "\u285C\u28E7\u28C0\u28E0\u287F", tone: "warn" },
1344
+ { text: "\u28FC\u287F\u28FF\u28E7", tone: "face" },
1345
+ { text: "\u28BF\u28C4\u28E0\u287E", tone: "warn" },
1346
+ { text: "\u28FB", tone: "accent" },
1347
+ { text: "\u28FF", tone: "face" },
1348
+ { text: "\u28FF\u2847", tone: "accent" },
1349
+ { text: "\u2800", tone: "accent" }
1350
+ ],
1351
+ [
1352
+ { text: "\u2800", tone: "accent" },
1353
+ { text: "\u2818\u28FF\u28FF", tone: "accent" },
1354
+ { text: "\u28FF\u28F6\u28EF\u28F7\u28FE\u285F", tone: "face" },
1355
+ { text: "\u2801\u28EC", tone: "accent" },
1356
+ { text: "\u28FB\u28F7\u28FE\u28FF\u28FE\u28FF", tone: "face" },
1357
+ { text: "\u28FF\u287F", tone: "accent" },
1358
+ { text: "\u2800\u2800", tone: "accent" }
1359
+ ],
1360
+ [
1361
+ { text: "\u2800\u2800", tone: "accent" },
1362
+ { text: "\u2818\u28BF\u28FF\u28FF", tone: "accent" },
1363
+ { text: "\u28FF\u28FF\u28FF\u28FF", tone: "face" },
1364
+ { text: "\u2844\u28A1", tone: "accent" },
1365
+ { text: "\u28FF\u28FF\u28FF\u28FF", tone: "face" },
1366
+ { text: "\u28FF\u28FF\u281F\u2801", tone: "accent" },
1367
+ { text: "\u2800\u2800", tone: "accent" }
1368
+ ],
1369
+ [
1370
+ { text: "\u2800\u2800\u2800\u2800", tone: "accent" },
1371
+ { text: "\u2819\u283B\u28BF\u28FF\u28FF", tone: "accent" },
1372
+ { text: "\u28FF\u28FF\u28FF\u28FF", tone: "face" },
1373
+ { text: "\u28FF\u28FF\u287F\u281F\u2801", tone: "accent" },
1374
+ { text: "\u2800\u2800\u2800\u2800", tone: "accent" }
1375
+ ],
1376
+ [
1377
+ { text: "\u2800\u2800\u2800\u2800\u2800\u2800\u2800", tone: "accent" },
1378
+ { text: "\u2808\u2819\u281B\u281B\u281B\u281B\u2809\u2801", tone: "accent" },
1379
+ { text: "\u2800\u2800\u2800\u2800\u2800\u2800\u2800", tone: "accent" }
1380
+ ]
1381
+ ];
1382
+ var MENU = [
1383
+ { label: "Resume session", shortcut: "ctrl+r" },
1384
+ { label: "Switch theme", shortcut: "ctrl+t" },
1385
+ { label: "Help", shortcut: "ctrl+g (/help)" },
1386
+ { label: "Quit", shortcut: "ctrl+q" }
1387
+ ];
1388
+ var CHROME_ROWS = 6;
1389
+ var CARD_ROWS = 14;
1390
+ function WelcomeCard(props) {
1391
+ const cols = useTerminalWidth();
1392
+ const rows = useTerminalRows();
1393
+ const { theme } = useTheme();
1394
+ return /* @__PURE__ */ jsx8(
1395
+ Box6,
1396
+ {
1397
+ flexDirection: "column",
1398
+ justifyContent: "center",
1399
+ height: Math.max(CARD_ROWS + 1, rows - CHROME_ROWS),
1400
+ children: /* @__PURE__ */ jsxs5(
1401
+ Box6,
1402
+ {
1403
+ borderStyle: "round",
1404
+ borderColor: theme.border,
1405
+ width: Math.min(cols, 64),
1406
+ alignSelf: "center",
1407
+ paddingX: 2,
1408
+ paddingY: 1,
1409
+ flexDirection: "row",
1410
+ children: [
1411
+ /* @__PURE__ */ jsx8(Box6, { flexDirection: "column", marginRight: 3, children: LOGO.map((row, i) => /* @__PURE__ */ jsx8(Text7, { children: row.map((seg, j) => /* @__PURE__ */ jsx8(
1412
+ Text7,
1413
+ {
1414
+ color: seg.tone === "warn" ? theme.warn : seg.tone === "face" ? theme.assistant : theme.accent,
1415
+ children: seg.text
1416
+ },
1417
+ j
1418
+ )) }, i)) }),
1419
+ /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", flexGrow: 1, children: [
1420
+ /* @__PURE__ */ jsxs5(Box6, { children: [
1421
+ /* @__PURE__ */ jsx8(Text7, { color: theme.accent, bold: true, children: "miot chat" }),
1422
+ /* @__PURE__ */ jsxs5(Text7, { color: theme.dim, children: [
1423
+ " v",
1424
+ props.version
1425
+ ] })
1426
+ ] }),
1427
+ /* @__PURE__ */ jsx8(Box6, { height: 1 }),
1428
+ MENU.map((item) => /* @__PURE__ */ jsxs5(Box6, { justifyContent: "space-between", children: [
1429
+ /* @__PURE__ */ jsx8(Text7, { children: item.label }),
1430
+ /* @__PURE__ */ jsx8(Text7, { color: theme.dim, children: item.shortcut })
1431
+ ] }, item.label))
1432
+ ] })
1433
+ ]
1434
+ }
1435
+ )
1436
+ }
1437
+ );
1438
+ }
1439
+
1440
+ // src/tui/transcript/Transcript.tsx
1441
+ import { Box as Box10, Text as Text11 } from "ink";
1148
1442
 
1149
1443
  // src/tui/transcript/AssistantTurn.tsx
1150
- import { Box as Box3, Text as Text4 } from "ink";
1151
- import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1444
+ import { Box as Box7, Text as Text8 } from "ink";
1445
+ import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
1152
1446
  function AssistantTurn(props) {
1153
1447
  const { text, status } = props.item;
1154
1448
  const color = status === "failed" ? "red" : status === "complete" ? "green" : "white";
1155
- return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "row", marginTop: 1, children: [
1156
- status === "streaming" ? /* @__PURE__ */ jsxs3(Fragment2, { children: [
1157
- /* @__PURE__ */ jsx4(Spinner, { color: "cyan" }),
1158
- /* @__PURE__ */ jsxs3(Text4, { color, bold: true, children: [
1449
+ return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", marginTop: 1, children: [
1450
+ status === "streaming" ? /* @__PURE__ */ jsxs6(Fragment3, { children: [
1451
+ /* @__PURE__ */ jsx9(Spinner, { color: "cyan" }),
1452
+ /* @__PURE__ */ jsxs6(Text8, { color, bold: true, children: [
1159
1453
  " ",
1160
1454
  "miot",
1161
1455
  " "
1162
1456
  ] })
1163
- ] }) : /* @__PURE__ */ jsxs3(Text4, { color, bold: true, children: [
1457
+ ] }) : /* @__PURE__ */ jsxs6(Text8, { color, bold: true, children: [
1164
1458
  status === "failed" ? "\u2717 " : "\u2713 ",
1165
1459
  "miot",
1166
1460
  " "
1167
1461
  ] }),
1168
- /* @__PURE__ */ jsx4(Text4, { color, children: text })
1462
+ /* @__PURE__ */ jsx9(Text8, { color, children: text })
1169
1463
  ] });
1170
1464
  }
1171
1465
 
1172
1466
  // src/tui/transcript/ToolCall.tsx
1173
- import { Box as Box4, Text as Text5 } from "ink";
1174
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1467
+ import { Box as Box8, Text as Text9 } from "ink";
1468
+ import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
1175
1469
  function ToolCall(props) {
1176
1470
  const { name, status, message } = props.item;
1177
1471
  const color = status === "failed" ? "red" : status === "ok" ? "green" : "yellow";
1178
1472
  const glyph = status === "running" ? null : status === "ok" ? "\u2713" : "\u2717";
1179
- return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "row", children: [
1180
- /* @__PURE__ */ jsx5(Text5, { color, children: glyph !== null ? `${glyph} ` : "" }),
1181
- status === "running" ? /* @__PURE__ */ jsx5(Spinner, { color }) : null,
1182
- /* @__PURE__ */ jsxs4(Text5, { color, children: [
1473
+ return /* @__PURE__ */ jsxs7(Box8, { flexDirection: "row", children: [
1474
+ /* @__PURE__ */ jsx10(Text9, { color, children: glyph !== null ? `${glyph} ` : "" }),
1475
+ status === "running" ? /* @__PURE__ */ jsx10(Spinner, { color }) : null,
1476
+ /* @__PURE__ */ jsxs7(Text9, { color, children: [
1183
1477
  " ",
1184
1478
  "tool: ",
1185
1479
  name,
@@ -1189,24 +1483,24 @@ function ToolCall(props) {
1189
1483
  }
1190
1484
 
1191
1485
  // src/tui/transcript/UserTurn.tsx
1192
- import { Box as Box5, Text as Text6 } from "ink";
1193
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1486
+ import { Box as Box9, Text as Text10 } from "ink";
1487
+ import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
1194
1488
  function UserTurn(props) {
1195
1489
  const { text } = props.item;
1196
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", marginTop: 1, children: [
1197
- /* @__PURE__ */ jsxs5(Text6, { color: "cyan", bold: true, children: [
1490
+ return /* @__PURE__ */ jsxs8(Box9, { flexDirection: "row", marginTop: 1, children: [
1491
+ /* @__PURE__ */ jsxs8(Text10, { color: "cyan", bold: true, children: [
1198
1492
  "you",
1199
1493
  " "
1200
1494
  ] }),
1201
- /* @__PURE__ */ jsx6(Text6, { children: text })
1495
+ /* @__PURE__ */ jsx11(Text10, { children: text })
1202
1496
  ] });
1203
1497
  }
1204
1498
 
1205
1499
  // src/tui/transcript/Transcript.tsx
1206
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1500
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
1207
1501
  function Transcript(props) {
1208
1502
  const activeChainIdx = props.isStreaming ? findActiveChainIndex(props.items) : -1;
1209
- return /* @__PURE__ */ jsx7(Box6, { flexDirection: "column", children: props.items.map((item, i) => /* @__PURE__ */ jsx7(
1503
+ return /* @__PURE__ */ jsx12(Box10, { flexDirection: "column", children: props.items.map((item, i) => /* @__PURE__ */ jsx12(
1210
1504
  TranscriptItemView,
1211
1505
  {
1212
1506
  item,
@@ -1231,38 +1525,38 @@ function TranscriptItemView(props) {
1231
1525
  const { item, isActive } = props;
1232
1526
  switch (item.kind) {
1233
1527
  case "user":
1234
- return /* @__PURE__ */ jsx7(UserTurn, { item });
1528
+ return /* @__PURE__ */ jsx12(UserTurn, { item });
1235
1529
  case "assistant":
1236
- return /* @__PURE__ */ jsx7(AssistantTurn, { item });
1530
+ return /* @__PURE__ */ jsx12(AssistantTurn, { item });
1237
1531
  case "tool":
1238
- return /* @__PURE__ */ jsx7(ToolCall, { item });
1532
+ return /* @__PURE__ */ jsx12(ToolCall, { item });
1239
1533
  case "route":
1240
- return /* @__PURE__ */ jsx7(ChainRow, { prefix: "route:", isActive, children: item.route });
1534
+ return /* @__PURE__ */ jsx12(ChainRow, { prefix: "route:", isActive, children: item.route });
1241
1535
  case "agent":
1242
- return /* @__PURE__ */ jsx7(ChainRow, { prefix: "agent:", isActive, children: item.agent });
1536
+ return /* @__PURE__ */ jsx12(ChainRow, { prefix: "agent:", isActive, children: item.agent });
1243
1537
  case "thinking":
1244
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "row", children: [
1245
- /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: " \u22EE " }),
1246
- /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: item.text })
1538
+ return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "row", children: [
1539
+ /* @__PURE__ */ jsx12(Text11, { dimColor: true, children: " \u22EE " }),
1540
+ /* @__PURE__ */ jsx12(Text11, { dimColor: true, children: item.text })
1247
1541
  ] });
1248
1542
  case "plan":
1249
- return /* @__PURE__ */ jsx7(ChainRow, { prefix: "plan:", isActive, children: item.message });
1543
+ return /* @__PURE__ */ jsx12(ChainRow, { prefix: "plan:", isActive, children: item.message });
1250
1544
  case "freshness":
1251
- return /* @__PURE__ */ jsxs6(Text7, { color: "yellow", children: [
1545
+ return /* @__PURE__ */ jsxs9(Text11, { color: "yellow", children: [
1252
1546
  "\u26A0 ",
1253
1547
  item.message
1254
1548
  ] });
1255
1549
  case "artifact":
1256
- return /* @__PURE__ */ jsx7(ChainRow, { prefix: "artifact:", isActive, children: item.artifactKind });
1550
+ return /* @__PURE__ */ jsx12(ChainRow, { prefix: "artifact:", isActive, children: item.artifactKind });
1257
1551
  case "system":
1258
- return /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: item.text });
1552
+ return /* @__PURE__ */ jsx12(Text11, { dimColor: true, children: item.text });
1259
1553
  }
1260
1554
  }
1261
1555
  function ChainRow(props) {
1262
1556
  if (props.isActive) {
1263
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "row", children: [
1264
- /* @__PURE__ */ jsx7(Spinner, { color: "cyan" }),
1265
- /* @__PURE__ */ jsxs6(Text7, { color: "cyan", bold: true, children: [
1557
+ return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "row", children: [
1558
+ /* @__PURE__ */ jsx12(Spinner, { color: "cyan" }),
1559
+ /* @__PURE__ */ jsxs9(Text11, { color: "cyan", bold: true, children: [
1266
1560
  " ",
1267
1561
  props.prefix,
1268
1562
  " ",
@@ -1270,7 +1564,7 @@ function ChainRow(props) {
1270
1564
  ] })
1271
1565
  ] });
1272
1566
  }
1273
- return /* @__PURE__ */ jsxs6(Text7, { dimColor: true, children: [
1567
+ return /* @__PURE__ */ jsxs9(Text11, { dimColor: true, children: [
1274
1568
  "\xB7 ",
1275
1569
  props.prefix,
1276
1570
  " ",
@@ -1279,7 +1573,7 @@ function ChainRow(props) {
1279
1573
  }
1280
1574
 
1281
1575
  // src/tui/modals/ContextModal.tsx
1282
- import { Box as Box7, Text as Text8, useInput as useInput2 } from "ink";
1576
+ import { Box as Box11, Text as Text12, useInput as useInput2 } from "ink";
1283
1577
 
1284
1578
  // src/tui/session/selectors.ts
1285
1579
  function isStreaming(state) {
@@ -1331,7 +1625,7 @@ function contextPercent(state) {
1331
1625
  }
1332
1626
 
1333
1627
  // src/tui/modals/ContextModal.tsx
1334
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1628
+ import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
1335
1629
  function ContextModal(props) {
1336
1630
  const { session, lastRunId } = props;
1337
1631
  useInput2(
@@ -1356,24 +1650,24 @@ function ContextModal(props) {
1356
1650
  "pending approvals",
1357
1651
  String(session.pendingApprovals.length)
1358
1652
  ]);
1359
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1360
- /* @__PURE__ */ jsx8(Text8, { bold: true, children: "session context" }),
1361
- fields.map(([key, value]) => /* @__PURE__ */ jsxs7(Text8, { children: [
1653
+ return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1654
+ /* @__PURE__ */ jsx13(Text12, { bold: true, children: "session context" }),
1655
+ fields.map(([key, value]) => /* @__PURE__ */ jsxs10(Text12, { children: [
1362
1656
  key.padEnd(18),
1363
1657
  " ",
1364
1658
  value
1365
1659
  ] }, key)),
1366
- /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "esc/enter to close" })
1660
+ /* @__PURE__ */ jsx13(Text12, { dimColor: true, children: "esc/enter to close" })
1367
1661
  ] });
1368
1662
  }
1369
1663
 
1370
1664
  // src/tui/modals/ResumePicker.tsx
1371
- import { Box as Box8, Text as Text9, useInput as useInput3 } from "ink";
1372
- import { useState as useState3 } from "react";
1373
- import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1665
+ import { Box as Box12, Text as Text13, useInput as useInput3 } from "ink";
1666
+ import { useState as useState5 } from "react";
1667
+ import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
1374
1668
  function ResumePicker(props) {
1375
1669
  const maxRows = props.maxRows ?? 10;
1376
- const [index, setIndex] = useState3(0);
1670
+ const [index, setIndex] = useState5(0);
1377
1671
  const summaries = props.summaries;
1378
1672
  const cap = Math.max(0, summaries.length - 1);
1379
1673
  useInput3(
@@ -1398,23 +1692,23 @@ function ResumePicker(props) {
1398
1692
  { isActive: props.isFocused ?? true }
1399
1693
  );
1400
1694
  if (summaries.length === 0) {
1401
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1402
- /* @__PURE__ */ jsx9(Text9, { bold: true, children: "resume session" }),
1403
- /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "(no saved sessions)" }),
1404
- /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "esc to close" })
1695
+ return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1696
+ /* @__PURE__ */ jsx14(Text13, { bold: true, children: "resume session" }),
1697
+ /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "(no saved sessions)" }),
1698
+ /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "esc to close" })
1405
1699
  ] });
1406
1700
  }
1407
1701
  const visible = summaries.slice(0, maxRows);
1408
1702
  const truncated = summaries.length - visible.length;
1409
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1410
- /* @__PURE__ */ jsx9(Text9, { bold: true, children: "resume session" }),
1411
- visible.map((s, i) => /* @__PURE__ */ jsx9(Text9, { inverse: i === index, children: summarize(s) }, s.id)),
1412
- truncated > 0 ? /* @__PURE__ */ jsxs8(Text9, { dimColor: true, children: [
1703
+ return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1704
+ /* @__PURE__ */ jsx14(Text13, { bold: true, children: "resume session" }),
1705
+ visible.map((s, i) => /* @__PURE__ */ jsx14(Text13, { inverse: i === index, children: summarize(s) }, s.id)),
1706
+ truncated > 0 ? /* @__PURE__ */ jsxs11(Text13, { dimColor: true, children: [
1413
1707
  "\u2026 ",
1414
1708
  truncated,
1415
1709
  " more"
1416
1710
  ] }) : null,
1417
- /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "\u2191\u2193 navigate \xB7 enter select \xB7 esc cancel" })
1711
+ /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "\u2191\u2193 navigate \xB7 enter select \xB7 esc cancel" })
1418
1712
  ] });
1419
1713
  }
1420
1714
  function summarize(s) {
@@ -1430,62 +1724,13 @@ function truncate(text, max) {
1430
1724
  }
1431
1725
 
1432
1726
  // src/tui/modals/ThemePicker.tsx
1433
- import { Box as Box9, Text as Text10, useInput as useInput4 } from "ink";
1434
- import { useState as useState4 } from "react";
1435
-
1436
- // src/tui/theme/themes.ts
1437
- var DARK_THEME = {
1438
- accent: "cyan",
1439
- assistant: "white",
1440
- user: "cyan",
1441
- dim: "gray",
1442
- warn: "yellow",
1443
- err: "red",
1444
- ok: "green",
1445
- border: "gray",
1446
- prompt: "cyan",
1447
- spinner: "cyan"
1448
- };
1449
- var LIGHT_THEME = {
1450
- accent: "blue",
1451
- assistant: "black",
1452
- user: "blue",
1453
- dim: "gray",
1454
- warn: "yellow",
1455
- err: "red",
1456
- ok: "green",
1457
- border: "gray",
1458
- prompt: "blue",
1459
- spinner: "blue"
1460
- };
1461
- var HIGH_CONTRAST_THEME = {
1462
- accent: "white",
1463
- assistant: "white",
1464
- user: "white",
1465
- dim: "white",
1466
- warn: "yellow",
1467
- err: "red",
1468
- ok: "green",
1469
- border: "white",
1470
- prompt: "white",
1471
- spinner: "white"
1472
- };
1473
- var BUILTIN_THEMES = {
1474
- dark: DARK_THEME,
1475
- light: LIGHT_THEME,
1476
- "high-contrast": HIGH_CONTRAST_THEME
1477
- };
1478
- var DEFAULT_THEME_NAME = "dark";
1479
- function builtinThemeNames() {
1480
- return Object.keys(BUILTIN_THEMES).sort();
1481
- }
1482
-
1483
- // src/tui/modals/ThemePicker.tsx
1484
- import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1727
+ import { Box as Box13, Text as Text14, useInput as useInput4 } from "ink";
1728
+ import { useState as useState6 } from "react";
1729
+ import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
1485
1730
  function ThemePicker(props) {
1486
1731
  const names = builtinThemeNames();
1487
1732
  const initial = props.initialName ? Math.max(0, names.indexOf(props.initialName)) : 0;
1488
- const [index, setIndex] = useState4(initial);
1733
+ const [index, setIndex] = useState6(initial);
1489
1734
  const cap = names.length - 1;
1490
1735
  useInput4(
1491
1736
  (_input, key) => {
@@ -1508,23 +1753,23 @@ function ThemePicker(props) {
1508
1753
  },
1509
1754
  { isActive: props.isFocused ?? true }
1510
1755
  );
1511
- return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1512
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "theme" }),
1756
+ return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1757
+ /* @__PURE__ */ jsx15(Text14, { bold: true, children: "theme" }),
1513
1758
  names.map((name, i) => {
1514
1759
  const t = BUILTIN_THEMES[name];
1515
1760
  const sample = t ? `accent=${t.accent} user=${t.user}` : "";
1516
- return /* @__PURE__ */ jsxs9(Text10, { inverse: i === index, children: [
1761
+ return /* @__PURE__ */ jsxs12(Text14, { inverse: i === index, children: [
1517
1762
  name.padEnd(15),
1518
1763
  " ",
1519
1764
  sample
1520
1765
  ] }, name);
1521
1766
  }),
1522
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "\u2191\u2193 navigate \xB7 enter apply \xB7 esc cancel" })
1767
+ /* @__PURE__ */ jsx15(Text14, { dimColor: true, children: "\u2191\u2193 navigate \xB7 enter apply \xB7 esc cancel" })
1523
1768
  ] });
1524
1769
  }
1525
1770
 
1526
1771
  // src/tui/modals/ApprovalModal.tsx
1527
- import { Box as Box10, Text as Text11, useInput as useInput5 } from "ink";
1772
+ import { Box as Box14, Text as Text15, useInput as useInput5 } from "ink";
1528
1773
 
1529
1774
  // src/tui/session/approvals.ts
1530
1775
  var APPROVALS_UI_ENV = "MIOT_CHAT_APPROVALS_UI";
@@ -1536,7 +1781,7 @@ function isApprovalsUiEnabled(env = process.env) {
1536
1781
  var APPROVAL_REPLY_PLACEHOLDER = "approval reply not yet supported by harness";
1537
1782
 
1538
1783
  // src/tui/modals/ApprovalModal.tsx
1539
- import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
1784
+ import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
1540
1785
  function ApprovalModal(props) {
1541
1786
  const { approval, onResolve } = props;
1542
1787
  useInput5(
@@ -1549,22 +1794,22 @@ function ApprovalModal(props) {
1549
1794
  { isActive: props.isFocused ?? true }
1550
1795
  );
1551
1796
  const data = JSON.stringify(approval.data, null, 2);
1552
- return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1553
- /* @__PURE__ */ jsx11(Text11, { bold: true, color: "yellow", children: "approval requested" }),
1554
- /* @__PURE__ */ jsx11(Text11, { children: approval.message || "(no message)" }),
1555
- /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: data }),
1556
- /* @__PURE__ */ jsx11(Text11, { children: "[Y] approve [N] deny [Esc] later" }),
1557
- /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: APPROVAL_REPLY_PLACEHOLDER })
1797
+ return /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1798
+ /* @__PURE__ */ jsx16(Text15, { bold: true, color: "yellow", children: "approval requested" }),
1799
+ /* @__PURE__ */ jsx16(Text15, { children: approval.message || "(no message)" }),
1800
+ /* @__PURE__ */ jsx16(Text15, { dimColor: true, children: data }),
1801
+ /* @__PURE__ */ jsx16(Text15, { children: "[Y] approve [N] deny [Esc] later" }),
1802
+ /* @__PURE__ */ jsx16(Text15, { dimColor: true, children: APPROVAL_REPLY_PLACEHOLDER })
1558
1803
  ] });
1559
1804
  }
1560
1805
 
1561
1806
  // src/tui/modals/RunsPicker.tsx
1562
- import { Box as Box11, Text as Text12, useInput as useInput6 } from "ink";
1563
- import { useState as useState5 } from "react";
1564
- import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
1807
+ import { Box as Box15, Text as Text16, useInput as useInput6 } from "ink";
1808
+ import { useState as useState7 } from "react";
1809
+ import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
1565
1810
  function RunsPicker(props) {
1566
1811
  const maxRows = props.maxRows ?? 10;
1567
- const [index, setIndex] = useState5(0);
1812
+ const [index, setIndex] = useState7(0);
1568
1813
  const cap = Math.max(0, props.runs.length - 1);
1569
1814
  useInput6(
1570
1815
  (_input, key) => {
@@ -1588,23 +1833,23 @@ function RunsPicker(props) {
1588
1833
  { isActive: props.isFocused ?? true }
1589
1834
  );
1590
1835
  if (props.runs.length === 0) {
1591
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1592
- /* @__PURE__ */ jsx12(Text12, { bold: true, children: "recent runs" }),
1593
- /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "(no runs in this session)" }),
1594
- /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "esc to close" })
1836
+ return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1837
+ /* @__PURE__ */ jsx17(Text16, { bold: true, children: "recent runs" }),
1838
+ /* @__PURE__ */ jsx17(Text16, { dimColor: true, children: "(no runs in this session)" }),
1839
+ /* @__PURE__ */ jsx17(Text16, { dimColor: true, children: "esc to close" })
1595
1840
  ] });
1596
1841
  }
1597
1842
  const visible = props.runs.slice(0, maxRows);
1598
1843
  const truncated = props.runs.length - visible.length;
1599
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1600
- /* @__PURE__ */ jsx12(Text12, { bold: true, children: "recent runs" }),
1601
- visible.map((r, i) => /* @__PURE__ */ jsx12(Text12, { inverse: i === index, children: formatRow(r) }, r.runId)),
1602
- truncated > 0 ? /* @__PURE__ */ jsxs11(Text12, { dimColor: true, children: [
1844
+ return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [
1845
+ /* @__PURE__ */ jsx17(Text16, { bold: true, children: "recent runs" }),
1846
+ visible.map((r, i) => /* @__PURE__ */ jsx17(Text16, { inverse: i === index, children: formatRow(r) }, r.runId)),
1847
+ truncated > 0 ? /* @__PURE__ */ jsxs14(Text16, { dimColor: true, children: [
1603
1848
  "\u2026 ",
1604
1849
  truncated,
1605
1850
  " more"
1606
1851
  ] }) : null,
1607
- /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "\u2191\u2193 navigate \xB7 enter replay \xB7 esc cancel" })
1852
+ /* @__PURE__ */ jsx17(Text16, { dimColor: true, children: "\u2191\u2193 navigate \xB7 enter replay \xB7 esc cancel" })
1608
1853
  ] });
1609
1854
  }
1610
1855
  function formatRow(r) {
@@ -1643,27 +1888,6 @@ function findPrecedingPrompt(items, startAt) {
1643
1888
  return null;
1644
1889
  }
1645
1890
 
1646
- // src/tui/theme/ThemeProvider.tsx
1647
- import { createContext, useContext, useMemo, useState as useState6 } from "react";
1648
- import { jsx as jsx13 } from "react/jsx-runtime";
1649
- var ThemeContext = createContext({
1650
- theme: DARK_THEME,
1651
- setTheme: () => void 0
1652
- });
1653
- function ThemeProvider(props) {
1654
- const [theme, setTheme] = useState6(
1655
- props.initialTheme ?? DARK_THEME
1656
- );
1657
- const value = useMemo(
1658
- () => ({ theme, setTheme }),
1659
- [theme]
1660
- );
1661
- return /* @__PURE__ */ jsx13(ThemeContext.Provider, { value, children: props.children });
1662
- }
1663
- function useTheme() {
1664
- return useContext(ThemeContext);
1665
- }
1666
-
1667
1891
  // src/tui/theme/loadUserTheme.ts
1668
1892
  function loadUserTheme(config) {
1669
1893
  if (config === void 0 || config === null) {
@@ -1695,8 +1919,14 @@ function resolveByName(name) {
1695
1919
  };
1696
1920
  }
1697
1921
 
1922
+ // src/tui/session/agentic.ts
1923
+ var AGENTIC_TENANT_LOCK2 = "mintral";
1924
+ function isAgenticTenantMismatch(mode, tenant) {
1925
+ return mode === "agentic" && tenant !== AGENTIC_TENANT_LOCK2;
1926
+ }
1927
+
1698
1928
  // src/tui/useSession.ts
1699
- import { useCallback, useEffect as useEffect2, useReducer as useReducer2, useRef } from "react";
1929
+ import { useCallback, useEffect as useEffect3, useReducer as useReducer2, useRef } from "react";
1700
1930
  import { appendFileSync, mkdirSync as mkdirSync3 } from "fs";
1701
1931
  import { dirname as dirname3 } from "path";
1702
1932
 
@@ -2178,7 +2408,7 @@ function useSession(opts) {
2178
2408
  () => initialSession(opts.initial, opts.ctx)
2179
2409
  );
2180
2410
  const stateRef = useRef(state);
2181
- useEffect2(() => {
2411
+ useEffect3(() => {
2182
2412
  stateRef.current = state;
2183
2413
  }, [state]);
2184
2414
  const abortRef = useRef(null);
@@ -2771,14 +3001,13 @@ function lastUserPrompt(state) {
2771
3001
  }
2772
3002
 
2773
3003
  // src/tui/App.tsx
2774
- import { Text as Text13 } from "ink";
2775
- import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
3004
+ import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
2776
3005
  function App(props) {
2777
3006
  const themeResult = useMemo2(
2778
3007
  () => loadUserTheme(props.config.theme),
2779
3008
  [props.config.theme]
2780
3009
  );
2781
- return /* @__PURE__ */ jsx14(ThemeProvider, { initialTheme: themeResult.theme, children: /* @__PURE__ */ jsx14(AppInner, { ...props, themeWarning: themeResult.warning }) });
3010
+ return /* @__PURE__ */ jsx18(ThemeProvider, { initialTheme: themeResult.theme, children: /* @__PURE__ */ jsx18(AppInner, { ...props, themeWarning: themeResult.warning }) });
2782
3011
  }
2783
3012
  function AppInner(props) {
2784
3013
  const home = props.home ?? defaultMiotChatHome();
@@ -2798,8 +3027,8 @@ function AppInner(props) {
2798
3027
  client: props.client
2799
3028
  });
2800
3029
  const { setTheme } = useTheme();
2801
- const [extraItems, setExtraItems] = useState7([]);
2802
- const [modal, setModalState] = useState7({ spec: null });
3030
+ const [extraItems, setExtraItems] = useState8([]);
3031
+ const [modal, setModalState] = useState8({ spec: null });
2803
3032
  const registry = useMemo2(() => {
2804
3033
  const reg = new SlashRegistry();
2805
3034
  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);
@@ -2857,6 +3086,13 @@ function AppInner(props) {
2857
3086
  appendSystem
2858
3087
  ]
2859
3088
  );
3089
+ useInput7((input, key) => {
3090
+ if (!key.ctrl || modal.spec !== null) return;
3091
+ if (input === "r") void dispatchSlash("/resume");
3092
+ else if (input === "t") void dispatchSlash("/theme");
3093
+ else if (input === "g") void dispatchSlash("/help");
3094
+ else if (input === "q") void dispatchSlash("/exit");
3095
+ });
2860
3096
  const handleSubmit = useCallback2(
2861
3097
  (text) => {
2862
3098
  if (text.trim().startsWith("/")) {
@@ -2877,16 +3113,21 @@ function AppInner(props) {
2877
3113
  );
2878
3114
  const modalSpec = modal.spec;
2879
3115
  const editorActive = modalSpec === null;
2880
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
2881
- props.themeWarning ? /* @__PURE__ */ jsx14(Box12, { paddingX: 1, children: /* @__PURE__ */ jsx14(SystemNote, { text: `theme: ${props.themeWarning}` }) }) : null,
2882
- /* @__PURE__ */ jsx14(
3116
+ const version = useMemo2(() => packageVersion(), []);
3117
+ const showWelcome = allItems.length === 0 && modalSpec === null;
3118
+ const meta = session.state.meta;
3119
+ const agenticWarn = isAgenticTenantMismatch(meta.mode, meta.tenantId);
3120
+ return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", children: [
3121
+ props.themeWarning ? /* @__PURE__ */ jsx18(Box16, { paddingX: 1, children: /* @__PURE__ */ jsx18(SystemNote, { text: `theme: ${props.themeWarning}` }) }) : null,
3122
+ /* @__PURE__ */ jsx18(TopLine, { meta, streaming: isStreaming(session.state) }),
3123
+ showWelcome ? /* @__PURE__ */ jsx18(WelcomeCard, { version }) : /* @__PURE__ */ jsx18(
2883
3124
  Transcript,
2884
3125
  {
2885
3126
  items: allItems,
2886
3127
  isStreaming: isStreaming(session.state)
2887
3128
  }
2888
3129
  ),
2889
- modalSpec?.kind === "context" ? /* @__PURE__ */ jsx14(
3130
+ modalSpec?.kind === "context" ? /* @__PURE__ */ jsx18(
2890
3131
  ContextModal,
2891
3132
  {
2892
3133
  session: session.state,
@@ -2894,7 +3135,7 @@ function AppInner(props) {
2894
3135
  onClose: closeModal
2895
3136
  }
2896
3137
  ) : null,
2897
- modalSpec?.kind === "resume" ? /* @__PURE__ */ jsx14(
3138
+ modalSpec?.kind === "resume" ? /* @__PURE__ */ jsx18(
2898
3139
  ResumePicker,
2899
3140
  {
2900
3141
  summaries: listSessions(home),
@@ -2907,7 +3148,7 @@ function AppInner(props) {
2907
3148
  onCancel: closeModal
2908
3149
  }
2909
3150
  ) : null,
2910
- modalSpec?.kind === "theme" ? /* @__PURE__ */ jsx14(
3151
+ modalSpec?.kind === "theme" ? /* @__PURE__ */ jsx18(
2911
3152
  ThemePicker,
2912
3153
  {
2913
3154
  initialName: typeof modalSpec.payload?.name === "string" ? modalSpec.payload.name : void 0,
@@ -2922,7 +3163,7 @@ function AppInner(props) {
2922
3163
  onCancel: closeModal
2923
3164
  }
2924
3165
  ) : null,
2925
- modalSpec?.kind === "approval" && isApprovalsUiEnabled() && session.state.pendingApprovals.length > 0 ? /* @__PURE__ */ jsx14(
3166
+ modalSpec?.kind === "approval" && isApprovalsUiEnabled() && session.state.pendingApprovals.length > 0 ? /* @__PURE__ */ jsx18(
2926
3167
  ApprovalModal,
2927
3168
  {
2928
3169
  approval: session.state.pendingApprovals[0],
@@ -2932,7 +3173,7 @@ function AppInner(props) {
2932
3173
  }
2933
3174
  }
2934
3175
  ) : null,
2935
- modalSpec?.kind === "runs" ? /* @__PURE__ */ jsx14(
3176
+ modalSpec?.kind === "runs" ? /* @__PURE__ */ jsx18(
2936
3177
  RunsPickerWrapped,
2937
3178
  {
2938
3179
  state: session.state,
@@ -2943,27 +3184,28 @@ function AppInner(props) {
2943
3184
  onCancel: closeModal
2944
3185
  }
2945
3186
  ) : null,
2946
- /* @__PURE__ */ jsx14(
2947
- Header,
3187
+ /* @__PURE__ */ jsx18(TipLine, { tipIndex: turnCount(session.state) }),
3188
+ /* @__PURE__ */ jsx18(InputFrame, { label: `miot \xB7 ${meta.mode}`, labelWarn: agenticWarn, children: /* @__PURE__ */ jsx18(Editor, { onSubmit: handleSubmit, isFocused: editorActive }) }),
3189
+ /* @__PURE__ */ jsx18(
3190
+ FooterLine,
2948
3191
  {
2949
- meta: session.state.meta,
2950
- streaming: isStreaming(session.state),
2951
- pendingApprovals: pendingApprovalCount(session.state),
2952
3192
  turns: turnCount(session.state),
2953
3193
  approxTokens: approxTokenCount(session.state),
2954
3194
  contextPercent: contextPercent(session.state),
2955
- usageTotals: session.state.usageTotals
3195
+ usageTotals: session.state.usageTotals,
3196
+ baseUrl: meta.baseUrl,
3197
+ profileName: meta.profileName,
3198
+ pendingApprovals: pendingApprovalCount(session.state)
2956
3199
  }
2957
- ),
2958
- /* @__PURE__ */ jsx14(Editor, { onSubmit: handleSubmit, isFocused: editorActive })
3200
+ )
2959
3201
  ] });
2960
3202
  }
2961
3203
  function RunsPickerWrapped(props) {
2962
3204
  const runs = summarizeRuns(props.state);
2963
- return /* @__PURE__ */ jsx14(RunsPicker, { runs, onSelect: props.onSelect, onCancel: props.onCancel });
3205
+ return /* @__PURE__ */ jsx18(RunsPicker, { runs, onSelect: props.onSelect, onCancel: props.onCancel });
2964
3206
  }
2965
3207
  function SystemNote(props) {
2966
- return /* @__PURE__ */ jsx14(Box12, { children: /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: props.text }) });
3208
+ return /* @__PURE__ */ jsx18(Box16, { children: /* @__PURE__ */ jsx18(Text17, { dimColor: true, children: props.text }) });
2967
3209
  }
2968
3210
 
2969
3211
  // src/tui/runTui.ts