kob-cli 1.0.21 → 1.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/ui/code-tui.tsx +160 -2
package/package.json
CHANGED
package/src/ui/code-tui.tsx
CHANGED
|
@@ -1248,10 +1248,148 @@ function InputBox({ onSubmit, mode, onModeChange, visionSupported, placeholder,
|
|
|
1248
1248
|
);
|
|
1249
1249
|
}
|
|
1250
1250
|
|
|
1251
|
+
// ============================================================================
|
|
1252
|
+
// HELP SCREEN — full-screen overlay shown by /help
|
|
1253
|
+
// A self-contained beginner's manual. Closes on Esc, Enter, or q.
|
|
1254
|
+
// ============================================================================
|
|
1255
|
+
function HelpScreen({ onClose }: { onClose: () => void }) {
|
|
1256
|
+
useInput((input, key) => {
|
|
1257
|
+
if (key.escape || key.return || input === 'q') {
|
|
1258
|
+
onClose();
|
|
1259
|
+
}
|
|
1260
|
+
}, { isActive: true });
|
|
1261
|
+
|
|
1262
|
+
return (
|
|
1263
|
+
<Box
|
|
1264
|
+
flexDirection="column"
|
|
1265
|
+
borderStyle="round"
|
|
1266
|
+
borderColor={c.brand}
|
|
1267
|
+
paddingX={2}
|
|
1268
|
+
paddingY={1}
|
|
1269
|
+
marginTop={1}
|
|
1270
|
+
>
|
|
1271
|
+
{/* Header */}
|
|
1272
|
+
<Box>
|
|
1273
|
+
<Text color={c.brand} bold>? /help</Text>
|
|
1274
|
+
<Text color={c.textDim}> </Text>
|
|
1275
|
+
<Text color={c.text} bold>KOB CLI · beginner's guide</Text>
|
|
1276
|
+
<Box flexGrow={1} />
|
|
1277
|
+
<Text color={c.textDim}>Esc / Enter / q to close</Text>
|
|
1278
|
+
</Box>
|
|
1279
|
+
|
|
1280
|
+
{/* Getting started */}
|
|
1281
|
+
<Box marginTop={1} flexDirection="column">
|
|
1282
|
+
<Text color={c.accent} bold>◆ Getting started</Text>
|
|
1283
|
+
<Box marginLeft={2} flexDirection="column">
|
|
1284
|
+
<Box>
|
|
1285
|
+
<Text color={c.brand}>/config</Text>
|
|
1286
|
+
<Text color={c.textMuted}> set API key, model, base URL → </Text>
|
|
1287
|
+
<Text color={c.text}>.env</Text>
|
|
1288
|
+
</Box>
|
|
1289
|
+
<Box>
|
|
1290
|
+
<Text color={c.brand}>/models</Text>
|
|
1291
|
+
<Text color={c.textMuted}> pick a model from the catalog</Text>
|
|
1292
|
+
</Box>
|
|
1293
|
+
<Box>
|
|
1294
|
+
<Text color={c.brand}>/help</Text>
|
|
1295
|
+
<Text color={c.textMuted}> show this guide</Text>
|
|
1296
|
+
</Box>
|
|
1297
|
+
</Box>
|
|
1298
|
+
</Box>
|
|
1299
|
+
|
|
1300
|
+
{/* Modes */}
|
|
1301
|
+
<Box marginTop={1} flexDirection="column">
|
|
1302
|
+
<Text color={c.accent} bold>◆ Modes (press </Text>
|
|
1303
|
+
<Text color={c.pink}>Tab</Text>
|
|
1304
|
+
<Text color={c.accent} bold> to cycle)</Text>
|
|
1305
|
+
<Box marginLeft={2} flexDirection="column">
|
|
1306
|
+
{MODES.map((m) => (
|
|
1307
|
+
<Box key={m.key}>
|
|
1308
|
+
<Text color={m.color} bold>{m.icon} {m.label}</Text>
|
|
1309
|
+
<Text color={c.textDim}> [{m.shortcut}] </Text>
|
|
1310
|
+
<Text color={c.textMuted}>{m.description}</Text>
|
|
1311
|
+
</Box>
|
|
1312
|
+
))}
|
|
1313
|
+
</Box>
|
|
1314
|
+
</Box>
|
|
1315
|
+
|
|
1316
|
+
{/* While typing */}
|
|
1317
|
+
<Box marginTop={1} flexDirection="column">
|
|
1318
|
+
<Text color={c.accent} bold>◆ While typing</Text>
|
|
1319
|
+
<Box marginLeft={2} flexDirection="column">
|
|
1320
|
+
<Box>
|
|
1321
|
+
<Text color={c.yellow}>Esc</Text>
|
|
1322
|
+
<Text color={c.textMuted}> clear input</Text>
|
|
1323
|
+
</Box>
|
|
1324
|
+
<Box>
|
|
1325
|
+
<Text color={c.green}>⏎</Text>
|
|
1326
|
+
<Text color={c.textMuted}> submit</Text>
|
|
1327
|
+
</Box>
|
|
1328
|
+
<Box>
|
|
1329
|
+
<Text color={c.pink}>↑</Text>
|
|
1330
|
+
<Text color={c.textMuted}> </Text>
|
|
1331
|
+
<Text color={c.pink}>↓</Text>
|
|
1332
|
+
<Text color={c.textMuted}> scroll history (line by line)</Text>
|
|
1333
|
+
</Box>
|
|
1334
|
+
<Box>
|
|
1335
|
+
<Text color={c.pink}>PgUp</Text>
|
|
1336
|
+
<Text color={c.textMuted}> </Text>
|
|
1337
|
+
<Text color={c.pink}>PgDn</Text>
|
|
1338
|
+
<Text color={c.textMuted}> scroll history (page)</Text>
|
|
1339
|
+
</Box>
|
|
1340
|
+
<Box>
|
|
1341
|
+
<Text color={c.pink}>g</Text>
|
|
1342
|
+
<Text color={c.textMuted}> </Text>
|
|
1343
|
+
<Text color={c.pink}>G</Text>
|
|
1344
|
+
<Text color={c.textMuted}> jump to oldest / latest</Text>
|
|
1345
|
+
</Box>
|
|
1346
|
+
</Box>
|
|
1347
|
+
</Box>
|
|
1348
|
+
|
|
1349
|
+
{/* Session */}
|
|
1350
|
+
<Box marginTop={1} flexDirection="column">
|
|
1351
|
+
<Text color={c.accent} bold>◆ Session</Text>
|
|
1352
|
+
<Box marginLeft={2} flexDirection="column">
|
|
1353
|
+
<Box>
|
|
1354
|
+
<Text color={c.brand}>/clear</Text>
|
|
1355
|
+
<Text color={c.textMuted}> forget chat history</Text>
|
|
1356
|
+
</Box>
|
|
1357
|
+
<Box>
|
|
1358
|
+
<Text color={c.brand}>/reset</Text>
|
|
1359
|
+
<Text color={c.textMuted}> reset model to .env default</Text>
|
|
1360
|
+
</Box>
|
|
1361
|
+
<Box>
|
|
1362
|
+
<Text color={c.brand}>/exit</Text>
|
|
1363
|
+
<Text color={c.textMuted}> quit KOB CLI</Text>
|
|
1364
|
+
</Box>
|
|
1365
|
+
</Box>
|
|
1366
|
+
</Box>
|
|
1367
|
+
|
|
1368
|
+
{/* Tips */}
|
|
1369
|
+
<Box marginTop={1} flexDirection="column">
|
|
1370
|
+
<Text color={c.yellow} bold>◆ First time?</Text>
|
|
1371
|
+
<Box marginLeft={2} flexDirection="column">
|
|
1372
|
+
<Text color={c.textMuted}>1. Run </Text>
|
|
1373
|
+
<Text color={c.brand}>/config</Text>
|
|
1374
|
+
<Text color={c.textMuted}> to paste your KOB API key and pick a model.</Text>
|
|
1375
|
+
<Text color={c.textMuted}>2. Type a task, pick a mode with </Text>
|
|
1376
|
+
<Text color={c.pink}>Tab</Text>
|
|
1377
|
+
<Text color={c.textMuted}>, press </Text>
|
|
1378
|
+
<Text color={c.green}>⏎</Text>
|
|
1379
|
+
<Text color={c.textMuted}>.</Text>
|
|
1380
|
+
<Text color={c.textMuted}>3. In </Text>
|
|
1381
|
+
<Text color={c.green}>Code</Text>
|
|
1382
|
+
<Text color={c.textMuted}> mode the agent can write files and run shell commands.</Text>
|
|
1383
|
+
</Box>
|
|
1384
|
+
</Box>
|
|
1385
|
+
</Box>
|
|
1386
|
+
);
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1251
1389
|
// ============================================================================
|
|
1252
1390
|
// BOTTOM BAR
|
|
1253
1391
|
// ============================================================================
|
|
1254
|
-
function BottomBar({ phase, mode }: { phase: Phase; mode: Mode }) {
|
|
1392
|
+
function BottomBar({ phase, mode, isFirstStart }: { phase: Phase; mode: Mode; isFirstStart: boolean }) {
|
|
1255
1393
|
const modeInfo = getMode(mode);
|
|
1256
1394
|
return (
|
|
1257
1395
|
<Box
|
|
@@ -1261,7 +1399,7 @@ function BottomBar({ phase, mode }: { phase: Phase; mode: Mode }) {
|
|
|
1261
1399
|
paddingX={1}
|
|
1262
1400
|
justifyContent="space-between"
|
|
1263
1401
|
>
|
|
1264
|
-
<Box>
|
|
1402
|
+
<Box flexWrap="wrap">
|
|
1265
1403
|
<Text color={c.green}>⏎ </Text>
|
|
1266
1404
|
<Text color={c.textDim}>submit</Text>
|
|
1267
1405
|
<Text color={c.borderDim}> · </Text>
|
|
@@ -1274,6 +1412,12 @@ function BottomBar({ phase, mode }: { phase: Phase; mode: Mode }) {
|
|
|
1274
1412
|
<Text color={c.brand}>/models</Text>
|
|
1275
1413
|
<Text color={c.textDim}> switch</Text>
|
|
1276
1414
|
<Text color={c.borderDim}> · </Text>
|
|
1415
|
+
<Text color={c.accent}>/config</Text>
|
|
1416
|
+
<Text color={c.textDim}> {isFirstStart ? 'for first start' : 'edit'}</Text>
|
|
1417
|
+
<Text color={c.borderDim}> · </Text>
|
|
1418
|
+
<Text color={c.accent}>/help</Text>
|
|
1419
|
+
<Text color={c.textDim}> guide</Text>
|
|
1420
|
+
<Text color={c.borderDim}> · </Text>
|
|
1277
1421
|
<Text color={c.accent}>Ctrl+C</Text>
|
|
1278
1422
|
<Text color={c.textDim}> quit</Text>
|
|
1279
1423
|
</Box>
|
|
@@ -1308,12 +1452,26 @@ function CodeEngine() {
|
|
|
1308
1452
|
const [model, setModel] = useState<string>(formatV2Model('DeepSeek', initialConfig.modelId));
|
|
1309
1453
|
const [palette, setPalette] = useState<null | 'models'>(null);
|
|
1310
1454
|
const [configOpen, setConfigOpen] = useState<boolean>(false);
|
|
1455
|
+
const [helpOpen, setHelpOpen] = useState<boolean>(false);
|
|
1311
1456
|
const [banner, setBanner] = useState<string | null>(null);
|
|
1312
1457
|
const messagesRef = useRef<{ role: string; content: string }[]>([]);
|
|
1313
1458
|
const modeRef = useRef<Mode>(mode);
|
|
1314
1459
|
const exchangesLenRef = useRef<number>(0);
|
|
1315
1460
|
const configRef = useRef(initialConfig);
|
|
1316
1461
|
|
|
1462
|
+
// "First start" = no .env file at the project root. The user is running
|
|
1463
|
+
// KOB CLI for the very first time (or in a fresh clone), so we surface
|
|
1464
|
+
// the /config hint more prominently.
|
|
1465
|
+
const isFirstStart = (() => {
|
|
1466
|
+
try {
|
|
1467
|
+
const fs = require('fs') as typeof import('fs');
|
|
1468
|
+
const path = require('path') as typeof import('path');
|
|
1469
|
+
return !fs.existsSync(path.join(process.cwd(), '.env'));
|
|
1470
|
+
} catch {
|
|
1471
|
+
return false;
|
|
1472
|
+
}
|
|
1473
|
+
})();
|
|
1474
|
+
|
|
1317
1475
|
const showBanner = useCallback((msg: string, ms = 2200) => {
|
|
1318
1476
|
setBanner(msg);
|
|
1319
1477
|
setTimeout(() => setBanner((cur) => (cur === msg ? null : cur)), ms);
|