@tuned-tensor/cli 0.7.0 → 0.8.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.
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  import { spawn as spawn4 } from "child_process";
5
5
  import { constants as osConstants2 } from "os";
6
6
  import { Command } from "commander";
7
- import chalk8 from "chalk";
7
+ import chalk9 from "chalk";
8
8
 
9
9
  // src/client.ts
10
10
  import { readFileSync as readFileSync2, statSync } from "fs";
@@ -345,7 +345,7 @@ function createAgentClient(opts) {
345
345
  }
346
346
 
347
347
  // src/agent.ts
348
- import chalk2 from "chalk";
348
+ import chalk3 from "chalk";
349
349
 
350
350
  // src/shell.ts
351
351
  import chalk from "chalk";
@@ -353,6 +353,7 @@ import { stat as stat2 } from "fs/promises";
353
353
  import { homedir as homedir3 } from "os";
354
354
  import { isAbsolute as isAbsolute2, resolve as resolve2 } from "path";
355
355
  import { createInterface } from "readline";
356
+ import { stripVTControlCharacters } from "util";
356
357
 
357
358
  // src/command-catalog.ts
358
359
  var CLOUD = ["cloud"];
@@ -948,6 +949,34 @@ function errorMessage(error) {
948
949
  var successMark = () => chalk.green("\u2713");
949
950
  var errorMark = () => chalk.red("\u2717");
950
951
  var accent = chalk.hex("#8B5CF6");
952
+ var ANSI_BOLD = "\x1B[1m";
953
+ var ANSI_BOLD_OFF = "\x1B[22m";
954
+ var ANSI_CLEAR_LINE = "\x1B[2K";
955
+ var ANSI_CLEAR_TO_END = "\x1B[K";
956
+ var ANSI_CURSOR_UP = "\x1B[1A";
957
+ var ANSI_RESET = "\x1B[0m";
958
+ function inputColorCodes() {
959
+ if (chalk.level === 0) return null;
960
+ if (chalk.level === 1) {
961
+ return {
962
+ background: "\x1B[100m",
963
+ accent: "\x1B[95m",
964
+ text: "\x1B[97m"
965
+ };
966
+ }
967
+ if (chalk.level === 2) {
968
+ return {
969
+ background: "\x1B[48;5;238m",
970
+ accent: "\x1B[38;5;183m",
971
+ text: "\x1B[38;5;255m"
972
+ };
973
+ }
974
+ return {
975
+ background: "\x1B[48;2;50;52;67m",
976
+ accent: "\x1B[38;2;196;181;253m",
977
+ text: "\x1B[38;2;245;243;255m"
978
+ };
979
+ }
951
980
  var DETAIL_LABEL_WIDTH = 15;
952
981
  function styleDetailLines(lines) {
953
982
  return lines.map((line) => {
@@ -1012,30 +1041,49 @@ function helpText(mode, query, palette = false) {
1012
1041
  function activeModelLabel(snapshot) {
1013
1042
  return snapshot.mode === "local" ? snapshot.context.local.activeModelId ?? "base" : snapshot.context.spec?.baseModel ?? "\u2014";
1014
1043
  }
1015
- function logoRows() {
1016
- const muted = chalk.dim("\u2588\u2588");
1017
- return [
1018
- `${chalk.hex("#A78BFA")("\u2588\u2588")} ${muted} ${muted}`,
1019
- `${muted} ${accent("\u2588\u2588")} ${muted}`,
1020
- `${muted} ${muted} ${chalk.hex("#7C3AED")("\u2588\u2588")}`
1021
- ];
1022
- }
1023
1044
  function renderShellBanner(snapshot) {
1024
1045
  const spec = snapshot.context.spec?.name ?? snapshot.context.spec?.path ?? "no spec";
1025
- const heading = snapshot.version ? `${accent.bold("Tuned Tensor")} ${chalk.dim(`v${snapshot.version}`)}` : accent.bold("Tuned Tensor");
1026
- const textRows = [
1046
+ const heading = snapshot.version ? `${accent.bold("tt")} ${chalk.dim(`v${snapshot.version}`)}` : accent.bold("tt");
1047
+ const lines = [
1027
1048
  heading,
1028
- `${chalk.bold(snapshot.mode)} \xB7 ${snapshot.context.projectName} \xB7 ${spec} \xB7 model ${activeModelLabel(snapshot)}`,
1029
- chalk.dim("Ask TT anything \xB7 known commands run directly \xB7 /help for more")
1049
+ chalk.dim(
1050
+ `${snapshot.mode} \xB7 ${snapshot.context.projectName} \xB7 ${spec} \xB7 model ${activeModelLabel(snapshot)}`
1051
+ ),
1052
+ chalk.dim("ctrl+c stop/clear \xB7 ctrl+d exit \xB7 /help commands \xB7 tab complete"),
1053
+ "",
1054
+ chalk.dim("Ask TT anything. Known commands run directly.")
1030
1055
  ];
1031
- const logo = logoRows();
1032
- const lines = textRows.map((row, index) => `${logo[index]} ${row}`);
1033
1056
  return `${lines.join("\n")}
1034
1057
 
1035
1058
  `;
1036
1059
  }
1037
- function renderShellPrompt(snapshot) {
1038
- return `${accent("tt")} ${chalk.bold(snapshot.mode)} ${chalk.dim(snapshot.context.projectName)} \u203A `;
1060
+ function renderShellPrompt() {
1061
+ return `${accent.bold("\u203A")} `;
1062
+ }
1063
+ function renderSubmittedShellInput(input, columns) {
1064
+ const colors = inputColorCodes();
1065
+ if (!colors) return "";
1066
+ const safeInput = stripVTControlCharacters(input).replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f]/g, "");
1067
+ if (columns && Array.from(`\u203A ${safeInput}`).length >= columns) return "";
1068
+ return [
1069
+ ANSI_CURSOR_UP,
1070
+ "\r",
1071
+ ANSI_CLEAR_LINE,
1072
+ colors.background,
1073
+ colors.accent,
1074
+ ANSI_BOLD,
1075
+ "\u203A",
1076
+ ANSI_BOLD_OFF,
1077
+ colors.text,
1078
+ " ",
1079
+ safeInput,
1080
+ ANSI_CLEAR_TO_END,
1081
+ ANSI_RESET,
1082
+ "\r\n"
1083
+ ].join("");
1084
+ }
1085
+ function resetShellPromptStyle() {
1086
+ return "";
1039
1087
  }
1040
1088
  var TunedTensorShellSession = class _TunedTensorShellSession {
1041
1089
  constructor(runner, io, agent, env, contextProvider, version, initialContext) {
@@ -1082,7 +1130,7 @@ var TunedTensorShellSession = class _TunedTensorShellSession {
1082
1130
  };
1083
1131
  }
1084
1132
  prompt() {
1085
- return renderShellPrompt(this.snapshot());
1133
+ return renderShellPrompt();
1086
1134
  }
1087
1135
  banner() {
1088
1136
  return renderShellBanner(this.snapshot());
@@ -1312,10 +1360,12 @@ async function startInteractiveShell(options) {
1312
1360
  });
1313
1361
  readline.on("SIGINT", () => {
1314
1362
  if (session.interruptAgent()) {
1315
- output.write("\n");
1363
+ output.write(`${resetShellPromptStyle()}
1364
+ `);
1316
1365
  return;
1317
1366
  }
1318
- output.write("\n");
1367
+ output.write(`${resetShellPromptStyle()}
1368
+ `);
1319
1369
  readline?.setPrompt(session.prompt());
1320
1370
  readline?.write(null, { ctrl: true, name: "u" });
1321
1371
  });
@@ -1324,15 +1374,21 @@ async function startInteractiveShell(options) {
1324
1374
  readline.prompt();
1325
1375
  try {
1326
1376
  for await (const line of readline) {
1377
+ output.write(renderSubmittedShellInput(
1378
+ line,
1379
+ output.columns
1380
+ ));
1327
1381
  const action = await session.handleLine(line);
1328
1382
  if (action === "exit") {
1329
1383
  readline.close();
1330
1384
  break;
1331
1385
  }
1386
+ output.write("\n");
1332
1387
  readline.setPrompt(session.prompt());
1333
1388
  readline.prompt();
1334
1389
  }
1335
1390
  } finally {
1391
+ output.write(resetShellPromptStyle());
1336
1392
  readline.close();
1337
1393
  }
1338
1394
  }
@@ -1345,10 +1401,127 @@ function shouldStartInteractiveShell(options) {
1345
1401
  return options.args.length === 0 && options.stdinIsTTY === true && options.stdoutIsTTY === true && !ciEnabled(env.CI) && env.TERM !== "dumb";
1346
1402
  }
1347
1403
 
1348
- // src/agent.ts
1404
+ // src/terminal-markdown.ts
1405
+ import chalk2 from "chalk";
1406
+ import { stripVTControlCharacters as stripVTControlCharacters2 } from "util";
1349
1407
  var accent2 = chalk2.hex("#8B5CF6");
1350
- var successMark2 = () => chalk2.green("\u2713");
1351
- var errorMark2 = () => chalk2.red("\u2717");
1408
+ function sanitizeTerminalText(text2) {
1409
+ return stripVTControlCharacters2(text2).replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f]/g, "");
1410
+ }
1411
+ function closingDelimiter(text2, delimiter, from) {
1412
+ return text2.indexOf(delimiter, from + delimiter.length);
1413
+ }
1414
+ function renderInlineMarkdown(text2) {
1415
+ let rendered = "";
1416
+ let index = 0;
1417
+ while (index < text2.length) {
1418
+ if (text2[index] === "\\" && index + 1 < text2.length) {
1419
+ rendered += text2[index + 1];
1420
+ index += 2;
1421
+ continue;
1422
+ }
1423
+ if (text2[index] === "[") {
1424
+ const link = text2.slice(index).match(/^\[([^\]]+)]\(([^)]+)\)/);
1425
+ if (link) {
1426
+ rendered += `${chalk2.underline(renderInlineMarkdown(link[1]))}${chalk2.dim(` (${link[2]})`)}`;
1427
+ index += link[0].length;
1428
+ continue;
1429
+ }
1430
+ }
1431
+ const strong = text2.startsWith("**", index) ? "**" : text2.startsWith("__", index) ? "__" : null;
1432
+ if (strong) {
1433
+ const close = closingDelimiter(text2, strong, index);
1434
+ if (close > index + strong.length) {
1435
+ rendered += chalk2.bold(
1436
+ renderInlineMarkdown(text2.slice(index + strong.length, close))
1437
+ );
1438
+ index = close + strong.length;
1439
+ continue;
1440
+ }
1441
+ }
1442
+ if (text2[index] === "`") {
1443
+ const close = closingDelimiter(text2, "`", index);
1444
+ if (close > index + 1) {
1445
+ rendered += chalk2.cyan(text2.slice(index + 1, close));
1446
+ index = close + 1;
1447
+ continue;
1448
+ }
1449
+ }
1450
+ const emphasis = text2[index] === "*" || text2[index] === "_" ? text2[index] : null;
1451
+ if (emphasis) {
1452
+ const close = closingDelimiter(text2, emphasis, index);
1453
+ if (close > index + 1) {
1454
+ rendered += chalk2.italic(
1455
+ renderInlineMarkdown(text2.slice(index + 1, close))
1456
+ );
1457
+ index = close + 1;
1458
+ continue;
1459
+ }
1460
+ }
1461
+ rendered += text2[index];
1462
+ index += 1;
1463
+ }
1464
+ return rendered;
1465
+ }
1466
+ function renderMarkdownLine(line, inCodeBlock) {
1467
+ if (inCodeBlock) return chalk2.cyan(` ${line}`);
1468
+ const heading = line.match(/^\s{0,3}#{1,6}\s+(.+)$/);
1469
+ if (heading) return chalk2.bold(renderInlineMarkdown(heading[1]));
1470
+ const bullet = line.match(/^(\s*)[-+*]\s+(.+)$/);
1471
+ if (bullet) {
1472
+ return `${bullet[1]}${accent2("\u2022")} ${renderInlineMarkdown(bullet[2])}`;
1473
+ }
1474
+ const numbered = line.match(/^(\s*)(\d+)[.)]\s+(.+)$/);
1475
+ if (numbered) {
1476
+ return `${numbered[1]}${accent2(`${numbered[2]}.`)} ${renderInlineMarkdown(numbered[3])}`;
1477
+ }
1478
+ const quote = line.match(/^\s*>\s?(.*)$/);
1479
+ if (quote) return `${chalk2.dim("\u2502")} ${chalk2.italic(renderInlineMarkdown(quote[1]))}`;
1480
+ if (/^\s{0,3}([-*_])(?:\s*\1){2,}\s*$/.test(line)) {
1481
+ return chalk2.dim("\u2500".repeat(32));
1482
+ }
1483
+ return renderInlineMarkdown(line);
1484
+ }
1485
+ var StreamingTerminalMarkdown = class {
1486
+ pending = "";
1487
+ inCodeBlock = false;
1488
+ push(delta) {
1489
+ this.pending += delta;
1490
+ let rendered = "";
1491
+ let newline = this.pending.indexOf("\n");
1492
+ while (newline !== -1) {
1493
+ const line = this.pending.slice(0, newline).replace(/\r$/, "");
1494
+ this.pending = this.pending.slice(newline + 1);
1495
+ rendered += `${this.renderLine(line)}
1496
+ `;
1497
+ newline = this.pending.indexOf("\n");
1498
+ }
1499
+ return rendered;
1500
+ }
1501
+ flush() {
1502
+ if (!this.pending) return "";
1503
+ const line = this.pending.replace(/\r$/, "");
1504
+ this.pending = "";
1505
+ return this.renderLine(line);
1506
+ }
1507
+ reset() {
1508
+ this.pending = "";
1509
+ this.inCodeBlock = false;
1510
+ }
1511
+ renderLine(line) {
1512
+ const safeLine = sanitizeTerminalText(line);
1513
+ if (/^\s*```/.test(safeLine)) {
1514
+ this.inCodeBlock = !this.inCodeBlock;
1515
+ return "";
1516
+ }
1517
+ return renderMarkdownLine(safeLine, this.inCodeBlock);
1518
+ }
1519
+ };
1520
+
1521
+ // src/agent.ts
1522
+ var accent3 = chalk3.hex("#8B5CF6");
1523
+ var successMark2 = () => chalk3.green("\u2713");
1524
+ var errorMark2 = () => chalk3.red("\u2717");
1352
1525
  function isRecord(value) {
1353
1526
  return value !== null && typeof value === "object" && !Array.isArray(value);
1354
1527
  }
@@ -1357,25 +1530,25 @@ function stringValue2(value) {
1357
1530
  }
1358
1531
  function helpText2() {
1359
1532
  return [
1360
- accent2.bold("Agent commands"),
1533
+ accent3.bold("Agent commands"),
1361
1534
  "",
1362
- ` ${accent2("/new".padEnd(22))} Start a new conversation.`,
1363
- ` ${accent2("/threads".padEnd(22))} List recent conversations.`,
1364
- ` ${accent2("/resume <id>".padEnd(22))} Resume a conversation by ID or prefix.`,
1365
- ` ${accent2("/approve [id]".padEnd(22))} Approve a proposed action.`,
1366
- ` ${accent2("/reject [id]".padEnd(22))} Reject a proposed action.`,
1367
- ` ${accent2("/status".padEnd(22))} Show the active conversation.`,
1368
- ` ${accent2("/clear".padEnd(22))} Clear the terminal.`,
1369
- ` ${accent2("/exit".padEnd(22))} Exit the agent.`,
1535
+ ` ${accent3("/new".padEnd(22))} Start a new conversation.`,
1536
+ ` ${accent3("/threads".padEnd(22))} List recent conversations.`,
1537
+ ` ${accent3("/resume <id>".padEnd(22))} Resume a conversation by ID or prefix.`,
1538
+ ` ${accent3("/approve [id]".padEnd(22))} Approve a proposed action.`,
1539
+ ` ${accent3("/reject [id]".padEnd(22))} Reject a proposed action.`,
1540
+ ` ${accent3("/status".padEnd(22))} Show the active conversation.`,
1541
+ ` ${accent3("/clear".padEnd(22))} Clear the terminal.`,
1542
+ ` ${accent3("/exit".padEnd(22))} Exit the agent.`,
1370
1543
  "",
1371
- chalk2.dim(
1544
+ chalk3.dim(
1372
1545
  "Everything else is sent to the Tuned Tensor agent; known TT commands still run directly in the shell."
1373
1546
  ),
1374
1547
  ""
1375
1548
  ].join("\n");
1376
1549
  }
1377
1550
  function formatThread(thread, activeId) {
1378
- const active = thread.id === activeId ? accent2("\u25CF") : chalk2.dim("\u25CB");
1551
+ const active = thread.id === activeId ? accent3("\u25CF") : chalk3.dim("\u25CB");
1379
1552
  const time = thread.last_message_at ?? thread.updated_at ?? thread.created_at;
1380
1553
  const date = new Date(time);
1381
1554
  const dateLabel = Number.isNaN(date.getTime()) ? "" : date.toLocaleString([], {
@@ -1384,7 +1557,7 @@ function formatThread(thread, activeId) {
1384
1557
  hour: "2-digit",
1385
1558
  minute: "2-digit"
1386
1559
  });
1387
- return `${active} ${chalk2.dim(thread.id.slice(0, 8))} ${thread.title} ${chalk2.dim(dateLabel)}`;
1560
+ return `${active} ${chalk3.dim(thread.id.slice(0, 8))} ${thread.title} ${chalk3.dim(dateLabel)}`;
1388
1561
  }
1389
1562
  function actionFromPayload(payload) {
1390
1563
  const value = isRecord(payload.action) ? payload.action : isRecord(payload.approval) ? payload.approval : payload;
@@ -1422,7 +1595,9 @@ var TunedTensorAgentSession = class {
1422
1595
  pendingActions = /* @__PURE__ */ new Map();
1423
1596
  activeRequest = null;
1424
1597
  responseStarted = false;
1598
+ reasoningActive = false;
1425
1599
  lineOpen = false;
1600
+ responseMarkdown = new StreamingTerminalMarkdown();
1426
1601
  get busy() {
1427
1602
  return this.activeRequest !== null;
1428
1603
  }
@@ -1440,15 +1615,29 @@ var TunedTensorAgentSession = class {
1440
1615
  endOpenLine() {
1441
1616
  if (this.lineOpen) this.options.io.write("\n");
1442
1617
  this.lineOpen = false;
1618
+ this.reasoningActive = false;
1619
+ }
1620
+ writeRenderedResponse(rendered) {
1621
+ if (!rendered) return;
1622
+ if (!this.responseStarted) {
1623
+ this.options.io.write(`
1624
+ ${accent3.bold("tt")} `);
1625
+ this.responseStarted = true;
1626
+ }
1627
+ this.options.io.write(rendered);
1628
+ this.lineOpen = !rendered.endsWith("\n");
1629
+ }
1630
+ flushResponse() {
1631
+ this.writeRenderedResponse(this.responseMarkdown.flush());
1443
1632
  }
1444
1633
  renderAction(action) {
1445
1634
  this.endOpenLine();
1446
1635
  this.options.io.write(
1447
1636
  `
1448
- ${chalk2.yellow.bold("Approval required")} ${chalk2.dim(action.id.slice(0, 8))}
1637
+ ${chalk3.yellow.bold("Approval required")} ${chalk3.dim(action.id.slice(0, 8))}
1449
1638
  `
1450
1639
  );
1451
- this.options.io.write(`${chalk2.bold(action.title)} ${chalk2.yellow(`[${action.risk} risk]`)}
1640
+ this.options.io.write(`${chalk3.bold(action.title)} ${chalk3.yellow(`[${action.risk} risk]`)}
1452
1641
  `);
1453
1642
  if (action.summary) this.options.io.write(`${action.summary}
1454
1643
  `);
@@ -1459,12 +1648,12 @@ ${chalk2.yellow.bold("Approval required")} ${chalk2.dim(action.id.slice(0, 8))}
1459
1648
  arguments: action.arguments ?? null,
1460
1649
  preview: action.preview ?? null
1461
1650
  };
1462
- this.options.io.write(`${chalk2.bold("Proposed action")}
1651
+ this.options.io.write(`${chalk3.bold("Proposed action")}
1463
1652
  `);
1464
1653
  this.options.io.write(`${formatJson(technical)}
1465
1654
  `);
1466
1655
  this.options.io.write(
1467
- chalk2.dim("Use /approve or /reject. The action will not run without approval.") + "\n"
1656
+ chalk3.dim("Use /approve or /reject. The action will not run without approval.") + "\n"
1468
1657
  );
1469
1658
  }
1470
1659
  renderEvent(event) {
@@ -1472,32 +1661,46 @@ ${chalk2.yellow.bold("Approval required")} ${chalk2.dim(action.id.slice(0, 8))}
1472
1661
  if (event.type === "text_delta") {
1473
1662
  const delta = stringValue2(payload.delta) ?? stringValue2(payload.text) ?? stringValue2(payload.content);
1474
1663
  if (!delta) return;
1475
- if (!this.responseStarted) {
1476
- this.options.io.write(`${accent2.bold("TT")} `);
1477
- this.responseStarted = true;
1478
- this.lineOpen = true;
1664
+ if (this.reasoningActive) {
1665
+ this.endOpenLine();
1666
+ this.options.io.write("\n");
1479
1667
  }
1480
- this.options.io.write(delta);
1668
+ this.writeRenderedResponse(this.responseMarkdown.push(delta));
1669
+ return;
1670
+ }
1671
+ if (event.type === "reasoning_delta") {
1672
+ const delta = stringValue2(payload.delta) ?? stringValue2(payload.text) ?? stringValue2(payload.content);
1673
+ if (!delta) return;
1674
+ if (!this.reasoningActive) {
1675
+ this.flushResponse();
1676
+ this.endOpenLine();
1677
+ this.options.io.write("\n");
1678
+ this.reasoningActive = true;
1679
+ }
1680
+ this.options.io.write(chalk3.dim.italic(delta));
1481
1681
  this.lineOpen = !delta.endsWith("\n");
1482
1682
  return;
1483
1683
  }
1484
1684
  if (event.type === "tool_call") {
1685
+ this.flushResponse();
1485
1686
  this.endOpenLine();
1486
1687
  const name = stringValue2(payload.name) ?? stringValue2(isRecord(payload.tool_call) ? payload.tool_call.name : null) ?? "tool";
1487
- this.options.io.write(chalk2.dim(` \u25CB ${name}
1688
+ this.options.io.write(chalk3.dim(` \u25CB ${name}
1488
1689
  `));
1489
1690
  return;
1490
1691
  }
1491
1692
  if (event.type === "tool_result") {
1693
+ this.flushResponse();
1492
1694
  this.endOpenLine();
1493
1695
  const failed = payload.status === "error" || Boolean(payload.error);
1494
1696
  this.options.io.write(
1495
- chalk2.dim(` ${failed ? chalk2.red("\u2717") : chalk2.green("\u2713")} Tool ${failed ? "failed" : "complete"}
1697
+ chalk3.dim(` ${failed ? chalk3.red("\u2717") : chalk3.green("\u2713")} Tool ${failed ? "failed" : "complete"}
1496
1698
  `)
1497
1699
  );
1498
1700
  return;
1499
1701
  }
1500
1702
  if (event.type === "approval_required") {
1703
+ this.flushResponse();
1501
1704
  const action = actionFromPayload(payload);
1502
1705
  if (!action) return;
1503
1706
  this.pendingActions.set(action.id, action);
@@ -1505,11 +1708,13 @@ ${chalk2.yellow.bold("Approval required")} ${chalk2.dim(action.id.slice(0, 8))}
1505
1708
  return;
1506
1709
  }
1507
1710
  if (event.type === "action_started") {
1711
+ this.flushResponse();
1508
1712
  this.endOpenLine();
1509
- this.options.io.write(chalk2.dim(" \u25CB Running approved action\u2026\n"));
1713
+ this.options.io.write(chalk3.dim(" \u25CB Running approved action\u2026\n"));
1510
1714
  return;
1511
1715
  }
1512
1716
  if (event.type === "action_result") {
1717
+ this.flushResponse();
1513
1718
  this.endOpenLine();
1514
1719
  const failed = payload.status === "failed" || Boolean(payload.error);
1515
1720
  this.options.io.write(
@@ -1519,6 +1724,7 @@ ${chalk2.yellow.bold("Approval required")} ${chalk2.dim(action.id.slice(0, 8))}
1519
1724
  return;
1520
1725
  }
1521
1726
  if (event.type === "error") {
1727
+ this.flushResponse();
1522
1728
  this.endOpenLine();
1523
1729
  const message = stringValue2(payload.message) ?? stringValue2(payload.error) ?? "The agent could not complete this request.";
1524
1730
  this.options.io.writeError(`${errorMark2()} ${message}
@@ -1538,25 +1744,31 @@ ${chalk2.yellow.bold("Approval required")} ${chalk2.dim(action.id.slice(0, 8))}
1538
1744
  const controller = new AbortController();
1539
1745
  this.activeRequest = controller;
1540
1746
  this.responseStarted = false;
1747
+ this.reasoningActive = false;
1541
1748
  this.lineOpen = false;
1749
+ this.responseMarkdown.reset();
1542
1750
  try {
1543
1751
  const result = await operation(controller.signal);
1752
+ this.flushResponse();
1544
1753
  this.endOpenLine();
1545
1754
  for (const action of result.actions) {
1546
1755
  this.pendingActions.set(action.id, action);
1547
1756
  }
1548
1757
  return result;
1549
1758
  } catch (error) {
1759
+ this.flushResponse();
1550
1760
  this.endOpenLine();
1551
1761
  if (controller.signal.aborted) {
1552
- this.options.io.write(chalk2.dim("Response stopped.\n"));
1762
+ this.options.io.write(chalk3.dim("Response stopped.\n"));
1553
1763
  return null;
1554
1764
  }
1555
1765
  throw error;
1556
1766
  } finally {
1557
1767
  this.activeRequest = null;
1558
1768
  this.responseStarted = false;
1769
+ this.reasoningActive = false;
1559
1770
  this.lineOpen = false;
1771
+ this.responseMarkdown.reset();
1560
1772
  }
1561
1773
  }
1562
1774
  async send(prompt) {
@@ -1634,7 +1846,7 @@ ${chalk2.yellow.bold("Approval required")} ${chalk2.dim(action.id.slice(0, 8))}
1634
1846
  if (args.length > 0) throw new Error("/threads does not accept arguments.");
1635
1847
  const threads = await this.options.client.listThreads();
1636
1848
  if (threads.length === 0) {
1637
- this.options.io.write(chalk2.dim("No conversations yet.\n"));
1849
+ this.options.io.write(chalk3.dim("No conversations yet.\n"));
1638
1850
  return "continue";
1639
1851
  }
1640
1852
  this.options.io.write(
@@ -1672,10 +1884,10 @@ ${chalk2.yellow.bold("Approval required")} ${chalk2.dim(action.id.slice(0, 8))}
1672
1884
  if (args.length > 0) throw new Error("/status does not accept arguments.");
1673
1885
  this.options.io.write(
1674
1886
  this.thread ? `${formatThread(this.thread, this.thread.id)}
1675
- ` : chalk2.dim("New conversation; send a message to create it.\n")
1887
+ ` : chalk3.dim("New conversation; send a message to create it.\n")
1676
1888
  );
1677
1889
  this.options.io.write(
1678
- chalk2.dim(`${this.pendingActions.size} pending approval(s).
1890
+ chalk3.dim(`${this.pendingActions.size} pending approval(s).
1679
1891
  `)
1680
1892
  );
1681
1893
  return "continue";
@@ -1860,7 +2072,7 @@ function unknownProjectSpecKeys(raw) {
1860
2072
  }
1861
2073
 
1862
2074
  // src/output.ts
1863
- import chalk3 from "chalk";
2075
+ import chalk4 from "chalk";
1864
2076
  import Table from "cli-table3";
1865
2077
  var jsonMode = false;
1866
2078
  function setJsonMode(enabled) {
@@ -1874,7 +2086,7 @@ function printJson(data) {
1874
2086
  }
1875
2087
  function printTable(headers, rows2, meta) {
1876
2088
  const table = new Table({
1877
- head: headers.map((h) => chalk3.bold.cyan(h)),
2089
+ head: headers.map((h) => chalk4.bold.cyan(h)),
1878
2090
  style: { head: [], border: [] }
1879
2091
  });
1880
2092
  for (const row of rows2) {
@@ -1884,7 +2096,7 @@ function printTable(headers, rows2, meta) {
1884
2096
  if (meta) {
1885
2097
  const totalPages = Math.ceil(meta.total / meta.per_page);
1886
2098
  console.log(
1887
- chalk3.dim(
2099
+ chalk4.dim(
1888
2100
  `
1889
2101
  Page ${meta.page}/${totalPages} (${meta.total} total)`
1890
2102
  )
@@ -1895,17 +2107,17 @@ function printDetail(fields) {
1895
2107
  const maxLabel = Math.max(...fields.map(([l]) => l.length));
1896
2108
  for (const [label, value] of fields) {
1897
2109
  const paddedLabel = label.padEnd(maxLabel);
1898
- console.log(`${chalk3.bold.cyan(paddedLabel)} ${value ?? chalk3.dim("\u2014")}`);
2110
+ console.log(`${chalk4.bold.cyan(paddedLabel)} ${value ?? chalk4.dim("\u2014")}`);
1899
2111
  }
1900
2112
  }
1901
2113
  function printSuccess(message) {
1902
- console.log(chalk3.green("\u2713") + " " + message);
2114
+ console.log(chalk4.green("\u2713") + " " + message);
1903
2115
  }
1904
2116
  function printWarning(message) {
1905
- console.log(chalk3.yellow("!") + " " + message);
2117
+ console.log(chalk4.yellow("!") + " " + message);
1906
2118
  }
1907
2119
  function printError(message) {
1908
- console.error(chalk3.red("\u2717") + " " + message);
2120
+ console.error(chalk4.red("\u2717") + " " + message);
1909
2121
  }
1910
2122
  function reportError(err) {
1911
2123
  const isApi = err instanceof ApiError;
@@ -1930,19 +2142,19 @@ function formatDate(iso) {
1930
2142
  }
1931
2143
  function formatStatus(status2) {
1932
2144
  const map = {
1933
- completed: chalk3.green,
1934
- running: chalk3.blue,
1935
- training: chalk3.blue,
1936
- evaluating: chalk3.blue,
1937
- preparing: chalk3.yellow,
1938
- pending: chalk3.yellow,
1939
- uploading: chalk3.yellow,
1940
- failed: chalk3.red,
1941
- cancelled: chalk3.dim,
1942
- validated: chalk3.green,
1943
- invalid: chalk3.red
2145
+ completed: chalk4.green,
2146
+ running: chalk4.blue,
2147
+ training: chalk4.blue,
2148
+ evaluating: chalk4.blue,
2149
+ preparing: chalk4.yellow,
2150
+ pending: chalk4.yellow,
2151
+ uploading: chalk4.yellow,
2152
+ failed: chalk4.red,
2153
+ cancelled: chalk4.dim,
2154
+ validated: chalk4.green,
2155
+ invalid: chalk4.red
1944
2156
  };
1945
- const colorFn = map[status2] || chalk3.white;
2157
+ const colorFn = map[status2] || chalk4.white;
1946
2158
  return colorFn(status2);
1947
2159
  }
1948
2160
  function truncate(str, max) {
@@ -2785,7 +2997,7 @@ async function executeLocalCommand(args, options = {}) {
2785
2997
  import { createInterface as createInterface2 } from "readline/promises";
2786
2998
  import { stdin, stdout } from "process";
2787
2999
  import { Writable } from "stream";
2788
- import chalk4 from "chalk";
3000
+ import chalk5 from "chalk";
2789
3001
  async function promptForApiKey(input = stdin, output = stdout) {
2790
3002
  if (input.isTTY !== true || output.isTTY !== true) {
2791
3003
  throw new Error(
@@ -2827,9 +3039,9 @@ function registerAuthCommands(parent) {
2827
3039
  const settingsUrl = `${DEFAULT_BASE_URL}/dashboard/settings`;
2828
3040
  console.log();
2829
3041
  console.log(
2830
- ` To get your API key, go to ${chalk4.bold("Settings \u2192 API Keys")} in the Tuned Tensor dashboard:`
3042
+ ` To get your API key, go to ${chalk5.bold("Settings \u2192 API Keys")} in the Tuned Tensor dashboard:`
2831
3043
  );
2832
- console.log(` ${chalk4.cyan.underline(settingsUrl)}`);
3044
+ console.log(` ${chalk5.cyan.underline(settingsUrl)}`);
2833
3045
  console.log();
2834
3046
  apiKey = await promptForApiKey();
2835
3047
  }
@@ -6293,7 +6505,7 @@ function registerModelsCommands(parent) {
6293
6505
  }
6294
6506
 
6295
6507
  // src/commands/balance.ts
6296
- import chalk5 from "chalk";
6508
+ import chalk6 from "chalk";
6297
6509
  var KIND_LABELS = {
6298
6510
  signup_bonus: "Signup bonus",
6299
6511
  topup: "Top-up",
@@ -6308,8 +6520,8 @@ function formatCents3(cents) {
6308
6520
  return `${sign}$${(abs / 100).toFixed(2)}`;
6309
6521
  }
6310
6522
  function formatSigned(cents) {
6311
- if (cents > 0) return chalk5.green(`+${formatCents3(cents)}`);
6312
- if (cents < 0) return chalk5.red(formatCents3(cents));
6523
+ if (cents > 0) return chalk6.green(`+${formatCents3(cents)}`);
6524
+ if (cents < 0) return chalk6.red(formatCents3(cents));
6313
6525
  return formatCents3(cents);
6314
6526
  }
6315
6527
  function registerBalanceCommands(parent) {
@@ -6324,7 +6536,7 @@ function registerBalanceCommands(parent) {
6324
6536
  return printJson({ balance, transactions });
6325
6537
  }
6326
6538
  const lowBalance = balance.balance_cents < 100;
6327
- const balanceLine = lowBalance ? chalk5.red(formatCents3(balance.balance_cents)) + chalk5.dim(" (low)") : chalk5.bold.green(formatCents3(balance.balance_cents));
6539
+ const balanceLine = lowBalance ? chalk6.red(formatCents3(balance.balance_cents)) + chalk6.dim(" (low)") : chalk6.bold.green(formatCents3(balance.balance_cents));
6328
6540
  printDetail([
6329
6541
  ["Credits", balanceLine],
6330
6542
  [
@@ -6339,7 +6551,7 @@ function registerBalanceCommands(parent) {
6339
6551
  ]);
6340
6552
  if (transactions && transactions.length > 0) {
6341
6553
  console.log(`
6342
- ${chalk5.bold("Recent transactions")}`);
6554
+ ${chalk6.bold("Recent transactions")}`);
6343
6555
  printTable(
6344
6556
  ["Date", "Type", "Amount", "Balance", "Reference"],
6345
6557
  transactions.map((row) => [
@@ -6347,19 +6559,19 @@ ${chalk5.bold("Recent transactions")}`);
6347
6559
  KIND_LABELS[row.kind] ?? row.kind,
6348
6560
  formatSigned(row.amount_cents),
6349
6561
  formatCents3(row.balance_after_cents),
6350
- row.reference_id ? shortId(row.reference_id) : chalk5.dim("\u2014")
6562
+ row.reference_id ? shortId(row.reference_id) : chalk6.dim("\u2014")
6351
6563
  ])
6352
6564
  );
6353
6565
  } else {
6354
6566
  console.log(
6355
6567
  `
6356
- ${chalk5.dim("No transactions yet \u2014 run `tt topup` to add credits.")}`
6568
+ ${chalk6.dim("No transactions yet \u2014 run `tt topup` to add credits.")}`
6357
6569
  );
6358
6570
  }
6359
6571
  if (lowBalance) {
6360
6572
  console.log(
6361
6573
  `
6362
- ${formatStatus("preparing")} ${chalk5.yellow(
6574
+ ${formatStatus("preparing")} ${chalk6.yellow(
6363
6575
  "Run `tt topup` to add more credits before starting a run."
6364
6576
  )}`
6365
6577
  );
@@ -6368,7 +6580,7 @@ ${formatStatus("preparing")} ${chalk5.yellow(
6368
6580
  }
6369
6581
 
6370
6582
  // src/commands/topup.ts
6371
- import chalk6 from "chalk";
6583
+ import chalk7 from "chalk";
6372
6584
  import open from "open";
6373
6585
  var PRESETS_USD = [10, 25, 50, 100];
6374
6586
  var MIN_USD = 5;
@@ -6407,9 +6619,9 @@ function registerTopupCommands(parent) {
6407
6619
  "amount is required in --json mode (use --amount <usd>)"
6408
6620
  );
6409
6621
  }
6410
- console.log(chalk6.bold("Add credits via Stripe Checkout"));
6622
+ console.log(chalk7.bold("Add credits via Stripe Checkout"));
6411
6623
  console.log(
6412
- chalk6.dim(
6624
+ chalk7.dim(
6413
6625
  `Quick picks: ${PRESETS_USD.map((n) => `$${n}`).join(", ")}`
6414
6626
  )
6415
6627
  );
@@ -6436,8 +6648,8 @@ function registerTopupCommands(parent) {
6436
6648
  }
6437
6649
  const url = data.checkout_url;
6438
6650
  console.log(
6439
- `${chalk6.bold("Checkout URL:")} ${chalk6.cyan(url)}
6440
- ` + chalk6.dim("Complete the payment to credit your account.")
6651
+ `${chalk7.bold("Checkout URL:")} ${chalk7.cyan(url)}
6652
+ ` + chalk7.dim("Complete the payment to credit your account.")
6441
6653
  );
6442
6654
  if (options.open !== false) {
6443
6655
  try {
@@ -6445,7 +6657,7 @@ function registerTopupCommands(parent) {
6445
6657
  printSuccess("Opened Stripe Checkout in your browser.");
6446
6658
  } catch {
6447
6659
  console.log(
6448
- chalk6.yellow(
6660
+ chalk7.yellow(
6449
6661
  "Could not open browser automatically \u2014 copy the URL above."
6450
6662
  )
6451
6663
  );
@@ -6455,7 +6667,7 @@ function registerTopupCommands(parent) {
6455
6667
  }
6456
6668
 
6457
6669
  // src/commands/eval.ts
6458
- import chalk7 from "chalk";
6670
+ import chalk8 from "chalk";
6459
6671
 
6460
6672
  // src/eval/rules.ts
6461
6673
  function validateSpec(spec) {
@@ -6620,7 +6832,7 @@ function registerEvalCommand(parent) {
6620
6832
  const spec = loadSpec(cmdOpts.file);
6621
6833
  const validation = validateSpec(spec);
6622
6834
  if (!isJsonMode()) {
6623
- console.log(chalk7.dim(`
6835
+ console.log(chalk8.dim(`
6624
6836
  Spec: ${cmdOpts.file}
6625
6837
  `));
6626
6838
  }
@@ -6635,10 +6847,10 @@ Spec: ${cmdOpts.file}
6635
6847
  });
6636
6848
  }
6637
6849
  function printValidation(checks) {
6638
- console.log(chalk7.bold("Spec Validation"));
6850
+ console.log(chalk8.bold("Spec Validation"));
6639
6851
  for (const check of checks) {
6640
- const icon = check.passed ? chalk7.green("\u2713") : chalk7.red("\u2717");
6641
- const msg = check.message ? chalk7.dim(` \u2014 ${check.message}`) : "";
6852
+ const icon = check.passed ? chalk8.green("\u2713") : chalk8.red("\u2717");
6853
+ const msg = check.message ? chalk8.dim(` \u2014 ${check.message}`) : "";
6642
6854
  console.log(` ${icon} ${check.name}${msg}`);
6643
6855
  }
6644
6856
  }
@@ -6823,7 +7035,7 @@ function createProgram(version, runtime = {}) {
6823
7035
  if (root.json) setJsonMode(true);
6824
7036
  if (root.color === false) {
6825
7037
  process.env.FORCE_COLOR = "0";
6826
- chalk8.level = 0;
7038
+ chalk9.level = 0;
6827
7039
  }
6828
7040
  });
6829
7041
  registerAuthCommands(program);
@@ -6856,12 +7068,12 @@ function createProgram(version, runtime = {}) {
6856
7068
  `);
6857
7069
  return;
6858
7070
  }
6859
- output.write(`${chalk8.bold.cyan("Tuned Tensor status")}
7071
+ output.write(`${chalk9.bold.cyan("Tuned Tensor status")}
6860
7072
  `);
6861
7073
  output.write(`${formatShellStatus(context, target).join("\n")}
6862
7074
 
6863
7075
  `);
6864
- output.write(`${chalk8.bold("Context")}
7076
+ output.write(`${chalk9.bold("Context")}
6865
7077
  `);
6866
7078
  output.write(
6867
7079
  `${formatShellContext(
@@ -6875,7 +7087,7 @@ function createProgram(version, runtime = {}) {
6875
7087
  program.command("local").description("Run the local CUDA training and model workflow").helpOption(false).allowUnknownOption().argument("[args...]", "TT Local command and arguments").action(async (args) => {
6876
7088
  const root = program.opts();
6877
7089
  const passthrough = extractPassthroughOptions(args, root);
6878
- if (!passthrough.color) chalk8.level = 0;
7090
+ if (!passthrough.color) chalk9.level = 0;
6879
7091
  const result = await invokeLocal(
6880
7092
  passthrough.args.length > 0 ? passthrough.args : ["--help"],
6881
7093
  {
@@ -6989,7 +7201,7 @@ async function runCli(version, runtime = {}) {
6989
7201
  }
6990
7202
 
6991
7203
  // src/index.ts
6992
- runCli("0.7.0").catch((err) => {
7204
+ runCli("0.8.1").catch((err) => {
6993
7205
  reportError(err);
6994
7206
  process.exit(1);
6995
7207
  });