terminal-pilot 0.0.48 → 0.0.50

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 (84) hide show
  1. package/dist/cli.js +584 -163
  2. package/dist/cli.js.map +4 -4
  3. package/dist/commands/close-session.js.map +1 -1
  4. package/dist/commands/create-session.js.map +1 -1
  5. package/dist/commands/daemon-runtime.js.map +1 -1
  6. package/dist/commands/fill.js.map +1 -1
  7. package/dist/commands/get-session.js.map +1 -1
  8. package/dist/commands/index.js +61 -11
  9. package/dist/commands/index.js.map +4 -4
  10. package/dist/commands/install.js +65 -15
  11. package/dist/commands/install.js.map +4 -4
  12. package/dist/commands/installer.js +21 -7
  13. package/dist/commands/installer.js.map +2 -2
  14. package/dist/commands/list-sessions.js.map +1 -1
  15. package/dist/commands/press-key.js.map +1 -1
  16. package/dist/commands/read-history.js.map +1 -1
  17. package/dist/commands/read-screen.js.map +1 -1
  18. package/dist/commands/resize.js.map +1 -1
  19. package/dist/commands/runtime.js.map +1 -1
  20. package/dist/commands/screenshot.js.map +1 -1
  21. package/dist/commands/send-signal.js.map +1 -1
  22. package/dist/commands/type.js.map +1 -1
  23. package/dist/commands/uninstall.js +21 -7
  24. package/dist/commands/uninstall.js.map +2 -2
  25. package/dist/commands/wait-for-exit.js.map +1 -1
  26. package/dist/commands/wait-for.js.map +1 -1
  27. package/dist/composition.json +6 -1
  28. package/dist/testing/cli-repl.js +584 -163
  29. package/dist/testing/cli-repl.js.map +4 -4
  30. package/dist/testing/qa-cli.js +584 -163
  31. package/dist/testing/qa-cli.js.map +4 -4
  32. package/node_modules/@poe-code/agent-defs/README.md +14 -1
  33. package/node_modules/@poe-code/agent-defs/dist/agents/claude-code.js +2 -1
  34. package/node_modules/@poe-code/agent-defs/dist/agents/claude-desktop.js +1 -0
  35. package/node_modules/@poe-code/agent-defs/dist/agents/codex.js +2 -1
  36. package/node_modules/@poe-code/agent-defs/dist/agents/cursor.js +1 -0
  37. package/node_modules/@poe-code/agent-defs/dist/agents/gemini-cli.js +2 -1
  38. package/node_modules/@poe-code/agent-defs/dist/agents/goose.js +1 -0
  39. package/node_modules/@poe-code/agent-defs/dist/agents/kimi.js +2 -1
  40. package/node_modules/@poe-code/agent-defs/dist/agents/opencode.js +2 -1
  41. package/node_modules/@poe-code/agent-defs/dist/agents/pi.js +2 -1
  42. package/node_modules/@poe-code/agent-defs/dist/agents/poe-agent.js +1 -0
  43. package/node_modules/@poe-code/agent-defs/dist/capabilities.d.ts +14 -0
  44. package/node_modules/@poe-code/agent-defs/dist/capabilities.js +63 -0
  45. package/node_modules/@poe-code/agent-defs/dist/index.d.ts +2 -1
  46. package/node_modules/@poe-code/agent-defs/dist/index.js +1 -0
  47. package/node_modules/@poe-code/agent-defs/dist/registry.js +3 -0
  48. package/node_modules/@poe-code/agent-defs/dist/types.d.ts +7 -0
  49. package/node_modules/@poe-code/agent-skill-config/dist/apply.d.ts +2 -0
  50. package/node_modules/@poe-code/agent-skill-config/dist/apply.js +18 -14
  51. package/node_modules/@poe-code/agent-skill-config/dist/bridge-active-skills.js +3 -1
  52. package/node_modules/@poe-code/agent-skill-config/dist/configs.d.ts +2 -0
  53. package/node_modules/@poe-code/agent-skill-config/dist/configs.js +2 -1
  54. package/node_modules/@poe-code/frontmatter/README.md +3 -0
  55. package/node_modules/@poe-code/frontmatter/dist/index.d.ts +1 -1
  56. package/node_modules/@poe-code/frontmatter/dist/index.js +1 -1
  57. package/node_modules/@poe-code/frontmatter/dist/parse.d.ts +9 -0
  58. package/node_modules/@poe-code/frontmatter/dist/parse.js +16 -0
  59. package/node_modules/@poe-code/user-error/README.md +56 -0
  60. package/node_modules/@poe-code/user-error/dist/index.d.ts +17 -0
  61. package/node_modules/@poe-code/user-error/dist/index.js +21 -0
  62. package/node_modules/@poe-code/user-error/package.json +24 -0
  63. package/node_modules/toolcraft-design/dist/acp/components.d.ts +8 -1
  64. package/node_modules/toolcraft-design/dist/acp/components.js +11 -6
  65. package/node_modules/toolcraft-design/dist/acp/index.d.ts +1 -0
  66. package/node_modules/toolcraft-design/dist/components/command-errors.d.ts +2 -0
  67. package/node_modules/toolcraft-design/dist/components/command-errors.js +8 -2
  68. package/node_modules/toolcraft-design/dist/components/help-formatter-plain.js +61 -25
  69. package/node_modules/toolcraft-design/dist/components/help-formatter.d.ts +15 -0
  70. package/node_modules/toolcraft-design/dist/components/help-formatter.js +128 -29
  71. package/node_modules/toolcraft-design/dist/components/index.d.ts +3 -3
  72. package/node_modules/toolcraft-design/dist/components/index.js +2 -2
  73. package/node_modules/toolcraft-design/dist/components/table.d.ts +1 -0
  74. package/node_modules/toolcraft-design/dist/components/table.js +52 -5
  75. package/node_modules/toolcraft-design/dist/components/template.d.ts +9 -0
  76. package/node_modules/toolcraft-design/dist/components/template.js +27 -2
  77. package/node_modules/toolcraft-design/dist/help-formatter.d.ts +2 -2
  78. package/node_modules/toolcraft-design/dist/help-formatter.js +1 -1
  79. package/node_modules/toolcraft-design/dist/index.d.ts +4 -4
  80. package/node_modules/toolcraft-design/dist/index.js +3 -3
  81. package/node_modules/toolcraft-design/dist/prompts/interactive/core.d.ts +5 -0
  82. package/node_modules/toolcraft-design/dist/prompts/interactive/core.js +15 -1
  83. package/node_modules/toolcraft-design/dist/prompts/primitives/spinner.js +1 -1
  84. package/package.json +5 -3
package/dist/cli.js CHANGED
@@ -1567,26 +1567,68 @@ function splitWords(value) {
1567
1567
  }
1568
1568
  return words;
1569
1569
  }
1570
- function wrapWords(value, width) {
1571
- const words = splitWords(value);
1570
+ function leadingWhitespaceWidth(value) {
1571
+ let index = 0;
1572
+ while (index < value.length && isWhitespace(value[index])) {
1573
+ index += 1;
1574
+ }
1575
+ return { prefix: value.slice(0, index), rest: value.slice(index) };
1576
+ }
1577
+ function takeVisiblePrefix(value, width) {
1578
+ let visible = 0;
1579
+ let index = 0;
1580
+ while (index < value.length) {
1581
+ const controlEnd = readControlSequence(value, index);
1582
+ if (controlEnd !== void 0) {
1583
+ index = controlEnd;
1584
+ continue;
1585
+ }
1586
+ const segment = graphemeSegmenter.segment(value.slice(index))[Symbol.iterator]().next().value;
1587
+ const cluster = segment?.segment ?? value[index] ?? "";
1588
+ const nextWidth = clusterWidth(cluster);
1589
+ if (visible > 0 && visible + nextWidth > width) {
1590
+ break;
1591
+ }
1592
+ visible += nextWidth;
1593
+ index += cluster.length || 1;
1594
+ }
1595
+ return { prefix: value.slice(0, index), rest: value.slice(index) };
1596
+ }
1597
+ function wrapWords(value, width, continuationWidth = width) {
1598
+ const { prefix, rest } = leadingWhitespaceWidth(value);
1599
+ const prefixWidth = visibleWidth(prefix);
1600
+ const firstContentWidth = Math.max(1, width - prefixWidth);
1601
+ const words = splitWords(rest);
1572
1602
  if (words.length === 0) {
1573
- return [""];
1603
+ return [prefix];
1574
1604
  }
1575
1605
  const lines = [];
1576
1606
  let line = "";
1607
+ let isFirstLine = true;
1577
1608
  for (const word of words) {
1578
- if (!line) {
1579
- line = word;
1580
- continue;
1581
- }
1582
- if (visibleWidth(line) + 1 + visibleWidth(word) <= width) {
1609
+ const limit = isFirstLine ? firstContentWidth : continuationWidth;
1610
+ if (line && visibleWidth(line) + 1 + visibleWidth(word) <= limit) {
1583
1611
  line += ` ${word}`;
1584
1612
  continue;
1585
1613
  }
1586
- lines.push(line);
1587
- line = word;
1614
+ if (line) {
1615
+ lines.push(isFirstLine ? `${prefix}${line}` : line);
1616
+ isFirstLine = false;
1617
+ line = "";
1618
+ }
1619
+ let remaining = word;
1620
+ while (visibleWidth(remaining) > (isFirstLine ? firstContentWidth : continuationWidth)) {
1621
+ const chunk = takeVisiblePrefix(
1622
+ remaining,
1623
+ isFirstLine ? firstContentWidth : continuationWidth
1624
+ );
1625
+ lines.push(isFirstLine ? `${prefix}${chunk.prefix}` : chunk.prefix);
1626
+ isFirstLine = false;
1627
+ remaining = chunk.rest;
1628
+ }
1629
+ line = remaining;
1588
1630
  }
1589
- lines.push(line);
1631
+ lines.push(isFirstLine ? `${prefix}${line}` : line);
1590
1632
  return lines;
1591
1633
  }
1592
1634
  function validateLayoutValue(value, name) {
@@ -1614,37 +1656,90 @@ function formatColumns(opts) {
1614
1656
  validateLayoutValue(indent, "indent");
1615
1657
  const maxLeftContentWidth = Math.max(...rows.map((row) => visibleWidth(row.left)));
1616
1658
  const leftWidth = clamp(maxLeftContentWidth + gap, minLeftWidth, maxLeftWidth);
1617
- const rightWidth = Math.max(20, totalWidth - leftWidth - indent);
1659
+ const rightWidth = Math.max(1, totalWidth - leftWidth - indent);
1660
+ const leftWrapWidth = Math.max(1, totalWidth - indent);
1618
1661
  const firstIndent = " ".repeat(indent);
1619
1662
  const continuationIndent = " ".repeat(indent + leftWidth);
1620
1663
  return rows.flatMap((row) => {
1664
+ const leftLeading = leadingWhitespaceWidth(row.left).prefix;
1665
+ const leftHangIndent = " ".repeat(indent + visibleWidth(leftLeading) + 2);
1666
+ const leftLines = wrapWords(
1667
+ row.left,
1668
+ leftWrapWidth,
1669
+ Math.max(1, totalWidth - visibleWidth(leftHangIndent))
1670
+ );
1621
1671
  if (row.right.length === 0) {
1622
- return [`${firstIndent}${row.left}`];
1672
+ return leftLines.map(
1673
+ (line, index) => index === 0 ? `${firstIndent}${line}` : `${leftHangIndent}${line}`
1674
+ );
1623
1675
  }
1624
1676
  const rightLines = wrapWords(row.right, rightWidth);
1625
- if (visibleWidth(row.left) >= leftWidth) {
1626
- return [
1627
- `${firstIndent}${row.left}`,
1628
- ...rightLines.map((line) => `${continuationIndent}${line}`)
1629
- ];
1630
- }
1631
- const firstLine = `${firstIndent}${padEndVisible(row.left, leftWidth)}${rightLines[0]}`;
1632
- const continuationLines = rightLines.slice(1).map((line) => `${continuationIndent}${line}`);
1633
- return [firstLine, ...continuationLines];
1677
+ const leftFitsInColumn = visibleWidth(row.left) < leftWidth;
1678
+ if (leftFitsInColumn && leftLines.length === 1) {
1679
+ const firstLine = `${firstIndent}${padEndVisible(leftLines[0] ?? "", leftWidth)}${rightLines[0]}`;
1680
+ const continuationLines = rightLines.slice(1).map((line) => `${continuationIndent}${line}`);
1681
+ return [firstLine, ...continuationLines];
1682
+ }
1683
+ const renderedLeft = leftLines.map(
1684
+ (line, index) => index === 0 ? `${firstIndent}${line}` : `${leftHangIndent}${line}`
1685
+ );
1686
+ const renderedRight = rightLines.map((line) => `${continuationIndent}${line}`);
1687
+ return [...renderedLeft, ...renderedRight];
1634
1688
  }).join("\n");
1635
1689
  }
1690
+ function styleHelpToken(token) {
1691
+ switch (token.role) {
1692
+ case "command":
1693
+ return text.command(token.text);
1694
+ case "argument":
1695
+ return styleArgumentToken(token.text);
1696
+ case "option":
1697
+ return text.option(token.text);
1698
+ case "dim":
1699
+ return styleDim(token.text);
1700
+ case "literal":
1701
+ return token.text;
1702
+ }
1703
+ }
1704
+ function styleArgumentToken(content) {
1705
+ const format = resolveOutputFormat();
1706
+ if (format === "markdown" && content.startsWith("<") && content.endsWith(">")) {
1707
+ return text.argument(content.slice(1, -1));
1708
+ }
1709
+ if (format === "json") {
1710
+ return content;
1711
+ }
1712
+ return text.argument(content);
1713
+ }
1714
+ function styleDim(content) {
1715
+ const format = resolveOutputFormat();
1716
+ if (format === "json" || format === "markdown") {
1717
+ return content;
1718
+ }
1719
+ return typography.dim(content);
1720
+ }
1721
+ function joinHelpTokens(tokens) {
1722
+ return tokens.map((token) => token.text).join("");
1723
+ }
1724
+ function renderHelpTokens(tokens) {
1725
+ return tokens.map((token) => styleHelpToken(token)).join("");
1726
+ }
1636
1727
  function formatCommandList(commands) {
1637
1728
  return formatColumns({
1638
- rows: commands.map((cmd) => ({
1639
- left: `${" ".repeat((cmd.depth ?? 0) * 2)}${text.command(cmd.name)}`,
1640
- right: cmd.description
1641
- }))
1729
+ rows: commands.map((cmd) => {
1730
+ const depthPrefix = " ".repeat((cmd.depth ?? 0) * 2);
1731
+ const styledName = cmd.nameTokens !== void 0 && cmd.nameTokens.length > 0 ? renderHelpTokens(cmd.nameTokens) : text.command(cmd.name);
1732
+ return {
1733
+ left: `${depthPrefix}${styledName}`,
1734
+ right: cmd.description
1735
+ };
1736
+ })
1642
1737
  });
1643
1738
  }
1644
1739
  function formatOptionList(options) {
1645
1740
  return formatColumns({
1646
1741
  rows: options.map((opt) => ({
1647
- left: text.option(opt.flags),
1742
+ left: opt.flagTokens !== void 0 && opt.flagTokens.length > 0 ? renderHelpTokens(opt.flagTokens) : text.option(opt.flags),
1648
1743
  right: opt.description
1649
1744
  }))
1650
1745
  });
@@ -1714,26 +1809,47 @@ function splitWords2(value) {
1714
1809
  }
1715
1810
  return words;
1716
1811
  }
1717
- function wrapWords2(value, width) {
1718
- const words = splitWords2(value);
1812
+ function leadingWhitespace(value) {
1813
+ let index = 0;
1814
+ while (index < value.length && isWhitespace2(value[index])) {
1815
+ index += 1;
1816
+ }
1817
+ return { prefix: value.slice(0, index), rest: value.slice(index) };
1818
+ }
1819
+ function takePrefix(value, width) {
1820
+ return { prefix: value.slice(0, width), rest: value.slice(width) };
1821
+ }
1822
+ function wrapWords2(value, width, continuationWidth = width) {
1823
+ const { prefix, rest } = leadingWhitespace(value);
1824
+ const firstContentWidth = Math.max(1, width - prefix.length);
1825
+ const words = splitWords2(rest);
1719
1826
  if (words.length === 0) {
1720
- return [""];
1827
+ return [prefix];
1721
1828
  }
1722
1829
  const lines = [];
1723
1830
  let line = "";
1831
+ let isFirstLine = true;
1724
1832
  for (const word of words) {
1725
- if (!line) {
1726
- line = word;
1727
- continue;
1728
- }
1729
- if (line.length + 1 + word.length <= width) {
1833
+ const limit = isFirstLine ? firstContentWidth : continuationWidth;
1834
+ if (line && line.length + 1 + word.length <= limit) {
1730
1835
  line += ` ${word}`;
1731
1836
  continue;
1732
1837
  }
1733
- lines.push(line);
1734
- line = word;
1838
+ if (line) {
1839
+ lines.push(isFirstLine ? `${prefix}${line}` : line);
1840
+ isFirstLine = false;
1841
+ line = "";
1842
+ }
1843
+ let remaining = word;
1844
+ while (remaining.length > (isFirstLine ? firstContentWidth : continuationWidth)) {
1845
+ const chunk = takePrefix(remaining, isFirstLine ? firstContentWidth : continuationWidth);
1846
+ lines.push(isFirstLine ? `${prefix}${chunk.prefix}` : chunk.prefix);
1847
+ isFirstLine = false;
1848
+ remaining = chunk.rest;
1849
+ }
1850
+ line = remaining;
1735
1851
  }
1736
- lines.push(line);
1852
+ lines.push(isFirstLine ? `${prefix}${line}` : line);
1737
1853
  return lines;
1738
1854
  }
1739
1855
  function formatColumns2(opts) {
@@ -1751,29 +1867,44 @@ function formatColumns2(opts) {
1751
1867
  const indent = opts.indent ?? 2;
1752
1868
  const maxLeftContentWidth = Math.max(...rows.map((row) => row.left.length));
1753
1869
  const leftWidth = clamp2(maxLeftContentWidth + gap, minLeftWidth, maxLeftWidth);
1754
- const rightWidth = Math.max(20, totalWidth - leftWidth - indent);
1870
+ const rightWidth = Math.max(1, totalWidth - leftWidth - indent);
1871
+ const leftWrapWidth = Math.max(1, totalWidth - indent);
1755
1872
  const firstIndent = " ".repeat(indent);
1756
1873
  const continuationIndent = " ".repeat(indent + leftWidth);
1757
1874
  return rows.flatMap((row) => {
1875
+ let leftLeadingWidth = 0;
1876
+ while (leftLeadingWidth < row.left.length && isWhitespace2(row.left[leftLeadingWidth])) {
1877
+ leftLeadingWidth += 1;
1878
+ }
1879
+ const leftHangIndent = " ".repeat(indent + leftLeadingWidth + 2);
1880
+ const leftLines = wrapWords2(
1881
+ row.left,
1882
+ leftWrapWidth,
1883
+ Math.max(1, totalWidth - leftHangIndent.length)
1884
+ );
1758
1885
  if (row.right.length === 0) {
1759
- return [`${firstIndent}${row.left}`];
1886
+ return leftLines.map(
1887
+ (line, index) => index === 0 ? `${firstIndent}${line}` : `${leftHangIndent}${line}`
1888
+ );
1760
1889
  }
1761
1890
  const rightLines = wrapWords2(row.right, rightWidth);
1762
- if (row.left.length >= leftWidth) {
1763
- return [
1764
- `${firstIndent}${row.left}`,
1765
- ...rightLines.map((line) => `${continuationIndent}${line}`)
1766
- ];
1767
- }
1768
- const firstLine = `${firstIndent}${padEndVisible2(row.left, leftWidth)}${rightLines[0]}`;
1769
- const continuationLines = rightLines.slice(1).map((line) => `${continuationIndent}${line}`);
1770
- return [firstLine, ...continuationLines];
1891
+ const leftFitsInColumn = row.left.length < leftWidth;
1892
+ if (leftFitsInColumn && leftLines.length === 1) {
1893
+ const firstLine = `${firstIndent}${padEndVisible2(leftLines[0] ?? "", leftWidth)}${rightLines[0]}`;
1894
+ const continuationLines = rightLines.slice(1).map((line) => `${continuationIndent}${line}`);
1895
+ return [firstLine, ...continuationLines];
1896
+ }
1897
+ const renderedLeft = leftLines.map(
1898
+ (line, index) => index === 0 ? `${firstIndent}${line}` : `${leftHangIndent}${line}`
1899
+ );
1900
+ const renderedRight = rightLines.map((line) => `${continuationIndent}${line}`);
1901
+ return [...renderedLeft, ...renderedRight];
1771
1902
  }).join("\n");
1772
1903
  }
1773
1904
  function formatCommandList2(commands) {
1774
1905
  return formatColumns2({
1775
1906
  rows: commands.map((cmd) => ({
1776
- left: `${" ".repeat((cmd.depth ?? 0) * 2)}${cmd.name}`,
1907
+ left: `${" ".repeat((cmd.depth ?? 0) * 2)}${cmd.nameTokens !== void 0 && cmd.nameTokens.length > 0 ? joinHelpTokens(cmd.nameTokens) : cmd.name}`,
1777
1908
  right: cmd.description
1778
1909
  }))
1779
1910
  });
@@ -1781,7 +1912,7 @@ function formatCommandList2(commands) {
1781
1912
  function formatOptionList2(options) {
1782
1913
  return formatColumns2({
1783
1914
  rows: options.map((opt) => ({
1784
- left: opt.flags,
1915
+ left: opt.flagTokens !== void 0 && opt.flagTokens.length > 0 ? joinHelpTokens(opt.flagTokens) : opt.flags,
1785
1916
  right: opt.description
1786
1917
  }))
1787
1918
  });
@@ -1790,6 +1921,7 @@ function formatOptionList2(options) {
1790
1921
  // ../toolcraft-design/src/components/table.ts
1791
1922
  var reset2 = "\x1B[0m";
1792
1923
  var ellipsis = "\u2026";
1924
+ var minCellWidth = 4;
1793
1925
  var graphemeSegmenter2 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
1794
1926
  function getCell(row, name) {
1795
1927
  return Object.prototype.hasOwnProperty.call(row, name) ? row[name] ?? "" : "";
@@ -1923,6 +2055,39 @@ function computeColumns(columns) {
1923
2055
  width: getColumnWidth(column)
1924
2056
  }));
1925
2057
  }
2058
+ function frameWidth(columnCount) {
2059
+ return columnCount * 3 + 1;
2060
+ }
2061
+ function budgetColumns(columns, maxWidth) {
2062
+ if (maxWidth === void 0) {
2063
+ return columns;
2064
+ }
2065
+ const available = maxWidth - frameWidth(columns.length);
2066
+ const contentWidth = (cap2) => columns.reduce((total, column) => total + Math.min(column.width, cap2), 0);
2067
+ if (columns.reduce((total, column) => total + column.width, 0) <= available) {
2068
+ return columns;
2069
+ }
2070
+ let cap = minCellWidth;
2071
+ while (contentWidth(cap + 1) <= available) {
2072
+ cap += 1;
2073
+ }
2074
+ const budgeted = columns.map((column) => ({ ...column, width: Math.min(column.width, cap) }));
2075
+ let slack = available - contentWidth(cap);
2076
+ while (slack > 0) {
2077
+ const growable = budgeted.filter((column, index) => column.width < columns[index].width);
2078
+ if (growable.length === 0) {
2079
+ break;
2080
+ }
2081
+ for (const column of growable) {
2082
+ if (slack === 0) {
2083
+ break;
2084
+ }
2085
+ column.width += 1;
2086
+ slack -= 1;
2087
+ }
2088
+ }
2089
+ return budgeted;
2090
+ }
1926
2091
  function renderBorder(columns, theme, parts) {
1927
2092
  const horizontal = theme.muted("\u2500");
1928
2093
  const segments = columns.map((column) => horizontal.repeat(column.width + 2));
@@ -2007,14 +2172,15 @@ function renderTableTerminal(options) {
2007
2172
  }
2008
2173
  const separatorOptions = options;
2009
2174
  const includeRowSeparators = separatorOptions.rowSeparator === true || separatorOptions.rowSeparators === true;
2010
- const top = renderBorder(computedColumns, theme, { left: "\u250C", mid: "\u252C", right: "\u2510" });
2175
+ const budgetedColumns = budgetColumns(computedColumns, options.maxWidth ?? process.stdout.columns);
2176
+ const top = renderBorder(budgetedColumns, theme, { left: "\u250C", mid: "\u252C", right: "\u2510" });
2011
2177
  const header = renderTerminalRow(
2012
- computedColumns.map((column) => theme.header(column.title)),
2013
- computedColumns,
2178
+ budgetedColumns.map((column) => theme.header(column.title)),
2179
+ budgetedColumns,
2014
2180
  theme
2015
2181
  );
2016
- const headerBottom = renderBorder(computedColumns, theme, { left: "\u251C", mid: "\u253C", right: "\u2524" });
2017
- const bottom = renderBorder(computedColumns, theme, { left: "\u2514", mid: "\u2534", right: "\u2518" });
2182
+ const headerBottom = renderBorder(budgetedColumns, theme, { left: "\u251C", mid: "\u253C", right: "\u2524" });
2183
+ const bottom = renderBorder(budgetedColumns, theme, { left: "\u2514", mid: "\u2534", right: "\u2518" });
2018
2184
  const renderedRows = [];
2019
2185
  for (const [index, row] of rows.entries()) {
2020
2186
  if (includeRowSeparators && index > 0) {
@@ -2022,8 +2188,8 @@ function renderTableTerminal(options) {
2022
2188
  }
2023
2189
  renderedRows.push(
2024
2190
  renderTerminalRow(
2025
- computedColumns.map((column) => getCell(row, column.name)),
2026
- computedColumns,
2191
+ budgetedColumns.map((column) => getCell(row, column.name)),
2192
+ budgetedColumns,
2027
2193
  theme
2028
2194
  )
2029
2195
  );
@@ -2116,6 +2282,19 @@ ${options.theme.muted(options.badges.map((badge) => badge[0] + badge.slice(1).to
2116
2282
 
2117
2283
  // ../toolcraft-design/src/components/template.ts
2118
2284
  var MAX_PARTIAL_DEPTH = 100;
2285
+ var MAX_TAG_EXCERPT_LENGTH = 40;
2286
+ var TemplateParseError = class extends Error {
2287
+ description;
2288
+ line;
2289
+ column;
2290
+ constructor(description, position) {
2291
+ super(`${description} at line ${position.line}, column ${position.column}`);
2292
+ this.name = "TemplateParseError";
2293
+ this.description = description;
2294
+ this.line = position.line;
2295
+ this.column = position.column;
2296
+ }
2297
+ };
2119
2298
  var HTML_ESCAPE = {
2120
2299
  "&": "&amp;",
2121
2300
  "<": "&lt;",
@@ -2222,13 +2401,13 @@ function parseTag(template, open) {
2222
2401
  if (template.startsWith("{{{", open)) {
2223
2402
  const close2 = template.indexOf("}}}", open + 3);
2224
2403
  if (close2 === -1) {
2225
- throw new Error("Unclosed unescaped tag");
2404
+ throw unclosedTagError(template, open, "}}}");
2226
2405
  }
2227
2406
  return { kind: "unescaped", name: template.slice(open + 3, close2).trim(), end: close2 + 3 };
2228
2407
  }
2229
2408
  const close = template.indexOf("}}", open + 2);
2230
2409
  if (close === -1) {
2231
- throw new Error("Unclosed tag");
2410
+ throw unclosedTagError(template, open, "}}");
2232
2411
  }
2233
2412
  const raw = template.slice(open + 2, close).trim();
2234
2413
  const sigil = raw[0];
@@ -2243,6 +2422,16 @@ function parseTag(template, open) {
2243
2422
  if (sigil === "=" && raw.endsWith("=")) return { kind: "delimiter", name, end };
2244
2423
  return { kind: "name", name: raw, end };
2245
2424
  }
2425
+ function unclosedTagError(template, open, expected) {
2426
+ const before = template.slice(0, open);
2427
+ const lineEnd = template.indexOf("\n", open);
2428
+ const opened = template.slice(open, lineEnd === -1 ? template.length : lineEnd).trimEnd();
2429
+ const tag = opened.length > MAX_TAG_EXCERPT_LENGTH ? `${opened.slice(0, MAX_TAG_EXCERPT_LENGTH)}...` : opened;
2430
+ return new TemplateParseError(`Unclosed tag "${tag}": expected "${expected}"`, {
2431
+ line: before.split("\n").length,
2432
+ column: open - (before.lastIndexOf("\n") + 1) + 1
2433
+ });
2434
+ }
2246
2435
  function getStandalone(template, tagStart, tagEnd, kind) {
2247
2436
  if (!["section", "inverted", "close", "comment", "partial", "delimiter"].includes(kind)) {
2248
2437
  return void 0;
@@ -2814,6 +3003,15 @@ var cursor = {
2814
3003
  var erase = {
2815
3004
  down: "\x1B[J"
2816
3005
  };
3006
+ function nonTtyPromptMessage(argv = process.argv) {
3007
+ const tokens = [];
3008
+ for (const arg of argv.slice(2)) {
3009
+ if (arg.startsWith("-")) break;
3010
+ tokens.push(arg);
3011
+ }
3012
+ const retry = [...tokens, "--yes"].join(" ");
3013
+ return `Interactive prompt requires a TTY. Re-run with \`${retry}\` to accept defaults non-interactively, or set POE_NO_PROMPT=1 in CI.`;
3014
+ }
2817
3015
  var Prompt = class extends EventEmitter {
2818
3016
  state = "initial";
2819
3017
  value;
@@ -2884,7 +3082,7 @@ var Prompt = class extends EventEmitter {
2884
3082
  });
2885
3083
  }
2886
3084
  promptNonTty() {
2887
- return Promise.reject(new Error("Interactive prompt requires a TTY. Set POE_NO_PROMPT=1 to accept defaults non-interactively."));
3085
+ return Promise.reject(new Error(nonTtyPromptMessage()));
2888
3086
  }
2889
3087
  readNonTtyLine() {
2890
3088
  return new Promise((resolve) => {
@@ -3408,6 +3606,9 @@ var UserError = class extends Error {
3408
3606
  this.name = "UserError";
3409
3607
  }
3410
3608
  };
3609
+ function isUserError(error3) {
3610
+ return error3 instanceof UserError || error3 instanceof Error && error3.name === "UserError";
3611
+ }
3411
3612
  var ToolcraftBugError = class extends Error {
3412
3613
  constructor(message2) {
3413
3614
  super(message2);
@@ -5049,6 +5250,9 @@ function compactUrl(value) {
5049
5250
  return value;
5050
5251
  }
5051
5252
  }
5253
+ function stackedList(value) {
5254
+ return value.map((entry) => displayScalar(entry)).join("\n") || "\u2014";
5255
+ }
5052
5256
  function displayRowValue(value) {
5053
5257
  return isUrl(value) ? compactUrl(value) : displayScalar(value);
5054
5258
  }
@@ -5074,7 +5278,7 @@ function renderObjectCard(result, primitives, title) {
5074
5278
  const scalarRows = directScalarRows(result);
5075
5279
  const nestedSections = directObjectSections(result);
5076
5280
  const arrayObjectSections = directArrayObjectSections(result);
5077
- const listRows = Object.entries(result).filter(([, value]) => Array.isArray(value) && !isNonEmptyArrayOfObjects(value)).map(([key, value]) => ({ label: humanizeKey(key), value: displayScalar(value) }));
5281
+ const listRows = Object.entries(result).filter(([, value]) => Array.isArray(value) && !isNonEmptyArrayOfObjects(value)).map(([key, value]) => ({ label: humanizeKey(key), value: stackedList(value) }));
5078
5282
  return renderDetailCard({
5079
5283
  theme: primitives.getTheme(),
5080
5284
  title,
@@ -5776,6 +5980,13 @@ function formatOptionFlags(field, globalLongOptionFlags) {
5776
5980
  }
5777
5981
  return [`-${field.shortFlag}`, field.optionFlag, ...field.longAliases].join(", ");
5778
5982
  }
5983
+ function formatMissingParameterMessage(field) {
5984
+ const message2 = `Missing required parameter "${field.displayPath}".`;
5985
+ if (field.schema.kind !== "enum") {
5986
+ return message2;
5987
+ }
5988
+ return `${message2} Expected one of: ${field.schema.values.map((value) => String(value)).join(", ")}.`;
5989
+ }
5779
5990
  function formatPositionalToken(field) {
5780
5991
  const optionalPositional = field.optional || field.hasDefault;
5781
5992
  if (field.variadicPosition === true) {
@@ -6257,12 +6468,31 @@ function appendHelpMetadata(description, metadata) {
6257
6468
  return description;
6258
6469
  }
6259
6470
  if (description.length === 0) {
6260
- return `(${metadata.join(", ")})`;
6471
+ return metadata.map((entry) => `(${entry})`).join(" ");
6472
+ }
6473
+ return `${description} ${metadata.map((entry) => `(${entry})`).join(" ")}`;
6474
+ }
6475
+ function normalizeHelpEchoKey(value) {
6476
+ let normalized = "";
6477
+ for (const character of value.trim().toLowerCase()) {
6478
+ if (character !== " " && character !== " " && character !== "\n" && character !== "\r" && character !== "_" && character !== "." && character !== "-") {
6479
+ normalized += character;
6480
+ }
6261
6481
  }
6262
- return `${description} (${metadata.join(", ")})`;
6482
+ return normalized;
6483
+ }
6484
+ function isEchoHelpDescription(description, name) {
6485
+ if (description.length === 0) {
6486
+ return false;
6487
+ }
6488
+ return normalizeHelpEchoKey(description) === normalizeHelpEchoKey(name);
6489
+ }
6490
+ function suppressEchoHelpDescription(description, name) {
6491
+ return isEchoHelpDescription(description, name) ? "" : description;
6263
6492
  }
6264
6493
  function formatHelpFieldDescription(field) {
6265
- const description = field.description ?? field.displayPath;
6494
+ const rawDescription = field.description ?? field.displayPath;
6495
+ const description = suppressEchoHelpDescription(rawDescription, field.displayPath);
6266
6496
  const metadata = [];
6267
6497
  if (field.schema.kind === "enum" && field.schema.values.length <= 8) {
6268
6498
  const values = field.schema.values.map((value) => String(value)).join(", ");
@@ -6411,13 +6641,21 @@ function formatDynamicHelpMetadata(field) {
6411
6641
  }
6412
6642
  return metadata;
6413
6643
  }
6644
+ function createHelpOptionRow(flags, description) {
6645
+ return {
6646
+ flags,
6647
+ flagTokens: tokenizeHelpFlags(flags),
6648
+ description
6649
+ };
6650
+ }
6414
6651
  function collectDynamicObjectHelpRows(schema, casing, optionPrefix, displayPrefix, metadata) {
6415
6652
  const rows = [];
6416
6653
  for (const [key, rawChildSchema] of Object.entries(schema.shape)) {
6417
6654
  const childSchema = unwrapOptional2(rawChildSchema);
6418
6655
  const optionFlag = `${optionPrefix}.${formatSegment(key, casing)}`;
6419
6656
  const displayPath = `${displayPrefix}.${key}`;
6420
- const description = childSchema.description ?? displayPath;
6657
+ const rawDescription = childSchema.description ?? displayPath;
6658
+ const description = suppressEchoHelpDescription(rawDescription, displayPath);
6421
6659
  if (childSchema.kind === "object") {
6422
6660
  rows.push(
6423
6661
  ...collectDynamicObjectHelpRows(childSchema, casing, optionFlag, displayPath, metadata)
@@ -6425,24 +6663,26 @@ function collectDynamicObjectHelpRows(schema, casing, optionPrefix, displayPrefi
6425
6663
  continue;
6426
6664
  }
6427
6665
  if (childSchema.kind === "record") {
6428
- rows.push({
6429
- flags: `${optionFlag}.<key> <${describeDynamicFieldType({
6430
- ...{
6431
- id: displayPath,
6432
- path: [],
6433
- displayPath,
6434
- optionPath: [],
6435
- optionPathDisplay: `${displayPath}.<key>`,
6436
- optionFlag: `${optionFlag}.<key>`,
6437
- optional: false,
6438
- hasDefault: false,
6439
- defaultValue: void 0,
6440
- requiredWhenActive: false,
6441
- schema: childSchema
6442
- }
6443
- })}>`,
6444
- description: appendHelpMetadata(description, metadata)
6445
- });
6666
+ rows.push(
6667
+ createHelpOptionRow(
6668
+ `${optionFlag}.<key> <${describeDynamicFieldType({
6669
+ ...{
6670
+ id: displayPath,
6671
+ path: [],
6672
+ displayPath,
6673
+ optionPath: [],
6674
+ optionPathDisplay: `${displayPath}.<key>`,
6675
+ optionFlag: `${optionFlag}.<key>`,
6676
+ optional: false,
6677
+ hasDefault: false,
6678
+ defaultValue: void 0,
6679
+ requiredWhenActive: false,
6680
+ schema: childSchema
6681
+ }
6682
+ })}>`,
6683
+ appendHelpMetadata(description, metadata)
6684
+ )
6685
+ );
6446
6686
  continue;
6447
6687
  }
6448
6688
  if (childSchema.kind === "array" && unwrapOptional2(childSchema.item).kind === "object") {
@@ -6457,13 +6697,15 @@ function collectDynamicObjectHelpRows(schema, casing, optionPrefix, displayPrefi
6457
6697
  );
6458
6698
  continue;
6459
6699
  }
6460
- rows.push({
6461
- flags: childSchema.kind === "boolean" ? childSchema.default === true ? `--no-${optionFlag.slice(2)}` : optionFlag : `${optionFlag} <${describeHelpValueToken(childSchema, {
6462
- displayPath,
6463
- optionFlag
6464
- })}>`,
6465
- description: appendHelpMetadata(description, metadata)
6466
- });
6700
+ rows.push(
6701
+ createHelpOptionRow(
6702
+ childSchema.kind === "boolean" ? childSchema.default === true ? `--no-${optionFlag.slice(2)}` : optionFlag : `${optionFlag} <${describeHelpValueToken(childSchema, {
6703
+ displayPath,
6704
+ optionFlag
6705
+ })}>`,
6706
+ appendHelpMetadata(description, metadata)
6707
+ )
6708
+ );
6467
6709
  }
6468
6710
  return rows;
6469
6711
  }
@@ -6494,17 +6736,22 @@ function formatDynamicHelpFields(field, casing) {
6494
6736
  }
6495
6737
  }
6496
6738
  return [
6497
- {
6498
- flags: `${field.optionFlag} <${describeDynamicFieldType(field)}>`,
6499
- description: appendHelpMetadata(field.description ?? field.optionPathDisplay, metadata)
6500
- }
6739
+ createHelpOptionRow(
6740
+ `${field.optionFlag} <${describeDynamicFieldType(field)}>`,
6741
+ appendHelpMetadata(
6742
+ suppressEchoHelpDescription(
6743
+ field.description ?? field.optionPathDisplay,
6744
+ field.optionPathDisplay
6745
+ ),
6746
+ metadata
6747
+ )
6748
+ )
6501
6749
  ];
6502
6750
  }
6503
6751
  function formatSecretRows(secrets) {
6504
- return Object.values(secrets).map((secret) => ({
6505
- flags: secret.env,
6506
- description: formatSecretDescription(secret)
6507
- }));
6752
+ return Object.values(secrets).map(
6753
+ (secret) => createHelpOptionRow(secret.env, formatSecretDescription(secret))
6754
+ );
6508
6755
  }
6509
6756
  function formatSecretDescription(secret) {
6510
6757
  if (secret.description !== void 0 && secret.description.length > 0) {
@@ -6532,20 +6779,82 @@ function formatExampleRows(examples, breadcrumb, rootUsageName) {
6532
6779
  ${formatExampleCommand(breadcrumb, rootUsageName, example.params)}`
6533
6780
  );
6534
6781
  }
6535
- function wrapOptionalCommandParameterToken(token, optional) {
6536
- return optional ? `[${token}]` : token;
6782
+ var MAX_INLINE_OPTIONAL_PARAMETER_TOKENS = 8;
6783
+ var DEFAULT_HELP_TOTAL_WIDTH = 100;
6784
+ function tokenizeHelpFlags(flags) {
6785
+ const tokens = [];
6786
+ let index = 0;
6787
+ while (index < flags.length) {
6788
+ if (flags[index] === " ") {
6789
+ let end2 = index + 1;
6790
+ while (end2 < flags.length && flags[end2] === " ") {
6791
+ end2 += 1;
6792
+ }
6793
+ tokens.push({ text: flags.slice(index, end2), role: "literal" });
6794
+ index = end2;
6795
+ continue;
6796
+ }
6797
+ if (flags[index] === "[" || flags[index] === "]") {
6798
+ tokens.push({ text: flags[index], role: "dim" });
6799
+ index += 1;
6800
+ continue;
6801
+ }
6802
+ if (flags[index] === "<") {
6803
+ const close = flags.indexOf(">", index);
6804
+ if (close === -1) {
6805
+ tokens.push({ text: flags.slice(index), role: "literal" });
6806
+ break;
6807
+ }
6808
+ tokens.push({ text: flags.slice(index, close + 1), role: "argument" });
6809
+ index = close + 1;
6810
+ continue;
6811
+ }
6812
+ if (flags.startsWith("--", index) || flags[index] === "-" && flags[index + 1] !== void 0 && flags[index + 1] !== "-") {
6813
+ let end2 = index + 1;
6814
+ while (end2 < flags.length && flags[end2] !== " " && flags[end2] !== "[" && flags[end2] !== "]" && flags[end2] !== "<") {
6815
+ end2 += 1;
6816
+ }
6817
+ tokens.push({ text: flags.slice(index, end2), role: "option" });
6818
+ index = end2;
6819
+ continue;
6820
+ }
6821
+ let end = index + 1;
6822
+ while (end < flags.length && flags[end] !== " " && flags[end] !== "[" && flags[end] !== "]" && flags[end] !== "<") {
6823
+ end += 1;
6824
+ }
6825
+ const piece = flags.slice(index, end);
6826
+ tokens.push({
6827
+ text: piece,
6828
+ role: piece.includes("|") ? "literal" : piece.startsWith("+") ? "dim" : "literal"
6829
+ });
6830
+ index = end;
6831
+ }
6832
+ return tokens;
6833
+ }
6834
+ function wrapOptionalParameterTokens(tokens, optional) {
6835
+ if (!optional) {
6836
+ return tokens;
6837
+ }
6838
+ return [{ text: "[", role: "dim" }, ...tokens, { text: "]", role: "dim" }];
6839
+ }
6840
+ function createCommandParameterToken(text3, optional) {
6841
+ return {
6842
+ text: optional ? `[${text3}]` : text3,
6843
+ optional,
6844
+ tokens: wrapOptionalParameterTokens(tokenizeHelpFlags(text3), optional)
6845
+ };
6537
6846
  }
6538
6847
  function formatCommandDynamicParameterTokens(field, casing) {
6539
6848
  const optional = field.optional || field.hasDefault;
6540
6849
  return formatDynamicHelpFields(field, casing).map(
6541
- (row) => wrapOptionalCommandParameterToken(row.flags, optional)
6850
+ (row) => createCommandParameterToken(row.flags, optional)
6542
6851
  );
6543
6852
  }
6544
6853
  function formatCommandParameterTokens(command, casing, globalLongOptionFlags) {
6545
6854
  const collected = collectFields(command.params, casing, globalLongOptionFlags);
6546
6855
  const fields = assignPositionals(collected.fields, command.positional);
6547
6856
  return fields.filter((field) => field.global !== true).map(
6548
- (field) => wrapOptionalCommandParameterToken(
6857
+ (field) => createCommandParameterToken(
6549
6858
  formatCommandParameterFieldFlags(field, globalLongOptionFlags),
6550
6859
  field.positionalIndex === void 0 && (field.optional || field.hasDefault)
6551
6860
  )
@@ -6553,30 +6862,65 @@ function formatCommandParameterTokens(command, casing, globalLongOptionFlags) {
6553
6862
  collected.dynamicFields.flatMap((field) => formatCommandDynamicParameterTokens(field, casing))
6554
6863
  );
6555
6864
  }
6556
- function formatCommandRowName(node, casing, globalLongOptionFlags) {
6865
+ function collapseOptionalParameterTokens(parameterTokens, inlineWidthBudget = Number.POSITIVE_INFINITY) {
6866
+ const optionalCount = parameterTokens.filter((token) => token.optional).length;
6867
+ if (optionalCount === 0) {
6868
+ return parameterTokens;
6869
+ }
6870
+ const inlineWidth = parameterTokens.reduce((total, token) => total + token.text.length + 1, 0);
6871
+ if (optionalCount <= MAX_INLINE_OPTIONAL_PARAMETER_TOKENS && inlineWidth <= inlineWidthBudget) {
6872
+ return parameterTokens;
6873
+ }
6874
+ const required = parameterTokens.filter((token) => !token.optional);
6875
+ const collapsedText = `+${optionalCount} options`;
6876
+ return [
6877
+ ...required,
6878
+ {
6879
+ text: `[${collapsedText}]`,
6880
+ optional: true,
6881
+ tokens: [
6882
+ { text: "[", role: "dim" },
6883
+ { text: collapsedText, role: "dim" },
6884
+ { text: "]", role: "dim" }
6885
+ ]
6886
+ }
6887
+ ];
6888
+ }
6889
+ function formatCommandRowNameTokens(node, casing, globalLongOptionFlags) {
6557
6890
  const baseName = node.aliases.length === 0 ? node.name : `${node.name} (${node.aliases.join(", ")})`;
6558
- const parameterTokens = node.kind === "command" ? formatCommandParameterTokens(node, casing, globalLongOptionFlags) : [];
6559
- const name = parameterTokens.length === 0 ? baseName : `${baseName} ${parameterTokens.join(" ")}`;
6560
- return name;
6891
+ const nameTokens = [{ text: baseName, role: "command" }];
6892
+ const inlineWidthBudget = Math.max(
6893
+ 0,
6894
+ (process.stdout.columns ?? DEFAULT_HELP_TOTAL_WIDTH) - 2 - baseName.length
6895
+ );
6896
+ const parameterTokens = node.kind === "command" ? collapseOptionalParameterTokens(
6897
+ formatCommandParameterTokens(node, casing, globalLongOptionFlags),
6898
+ inlineWidthBudget
6899
+ ) : [];
6900
+ for (const token of parameterTokens) {
6901
+ nameTokens.push({ text: " ", role: "literal" }, ...token.tokens);
6902
+ }
6903
+ const name = parameterTokens.length === 0 ? baseName : `${baseName} ${parameterTokens.map((token) => token.text).join(" ")}`;
6904
+ return { name, nameTokens };
6561
6905
  }
6562
6906
  function formatCommandRows(group, scope, casing, globalLongOptionFlags, help) {
6563
- if (help === "concise") {
6564
- return getHelpChildren(group, scope).map((child) => ({
6565
- name: formatCommandRowName(child, casing, globalLongOptionFlags),
6566
- description: child.description ?? "",
6907
+ const toRow = (child, depth) => {
6908
+ const { name, nameTokens } = formatCommandRowNameTokens(child, casing, globalLongOptionFlags);
6909
+ return {
6910
+ name,
6911
+ nameTokens,
6912
+ description: suppressEchoHelpDescription(child.description ?? "", child.name),
6567
6913
  kind: child.kind,
6568
- depth: 0
6569
- }));
6914
+ depth
6915
+ };
6916
+ };
6917
+ if (help === "concise") {
6918
+ return getHelpChildren(group, scope).map((child) => toRow(child, 0));
6570
6919
  }
6571
6920
  const rows = [];
6572
6921
  const visit = (node, depth) => {
6573
6922
  for (const child of getHelpChildren(node, scope)) {
6574
- rows.push({
6575
- name: formatCommandRowName(child, casing, globalLongOptionFlags),
6576
- description: child.description ?? "",
6577
- kind: child.kind,
6578
- depth
6579
- });
6923
+ rows.push(toRow(child, depth));
6580
6924
  if (child.kind === "group") {
6581
6925
  visit(child, depth + 1);
6582
6926
  }
@@ -6602,10 +6946,10 @@ function formatGlobalOptionsLine(ctx) {
6602
6946
  if (ctx.showVersion) {
6603
6947
  flags.push("--version");
6604
6948
  }
6605
- return flags.length > 0 ? `${text.section("Options:")} ${flags.join(" ")}` : "";
6949
+ return flags.length > 0 ? `${text.section("Global Options:")} ${flags.join(" ")}` : "";
6606
6950
  }
6607
6951
  function formatLeafGlobalOptionsLine(ctx) {
6608
- return ctx.controls.verbose ? `${text.section("Options:")} -v, --verbose` : "";
6952
+ return ctx.controls.verbose ? `${text.section("Global Options:")} -v, --verbose` : "";
6609
6953
  }
6610
6954
  function collectSchemaGlobalFieldRows(group, scope, casing, globalLongOptionFlags) {
6611
6955
  const seen = /* @__PURE__ */ new Map();
@@ -6623,10 +6967,13 @@ function collectSchemaGlobalFieldRows(group, scope, casing, globalLongOptionFlag
6623
6967
  if (seen.has(dedupeKey)) {
6624
6968
  continue;
6625
6969
  }
6626
- seen.set(dedupeKey, {
6627
- flags: formatHelpFieldFlags(field, globalLongOptionFlags),
6628
- description: formatHelpFieldDescription(field)
6629
- });
6970
+ seen.set(
6971
+ dedupeKey,
6972
+ createHelpOptionRow(
6973
+ formatHelpFieldFlags(field, globalLongOptionFlags),
6974
+ formatHelpFieldDescription(field)
6975
+ )
6976
+ );
6630
6977
  }
6631
6978
  return;
6632
6979
  }
@@ -6646,6 +6993,18 @@ function formatHelpCommandList(rows) {
6646
6993
  function formatHelpOptionList(rows) {
6647
6994
  return process.stdout.isTTY !== true ? help_formatter_plain_exports.formatOptionList(rows) : formatOptionList(rows);
6648
6995
  }
6996
+ function sortLeafHelpOptionFields(fields) {
6997
+ const required = [];
6998
+ const optional = [];
6999
+ for (const field of fields) {
7000
+ if (!field.optional && !field.hasDefault) {
7001
+ required.push(field);
7002
+ continue;
7003
+ }
7004
+ optional.push(field);
7005
+ }
7006
+ return [...required, ...optional];
7007
+ }
6649
7008
  function buildUsageLine(breadcrumb, rootUsageName, suffix) {
6650
7009
  const visibleBreadcrumb = breadcrumb.filter((segment) => segment.length > 0);
6651
7010
  const usageBreadcrumb = breadcrumb[0] === "" ? [rootUsageName, ...visibleBreadcrumb] : visibleBreadcrumb;
@@ -6655,15 +7014,37 @@ function buildUsageLine(breadcrumb, rootUsageName, suffix) {
6655
7014
  }
6656
7015
  function formatGroupUsageSuffix(group, scope, casing, globalLongOptionFlags) {
6657
7016
  if (group.default !== void 0 && group.default.hidden === true && group.default.scope.includes(scope)) {
6658
- const parameterTokens = formatCommandParameterTokens(
6659
- group.default,
6660
- casing,
6661
- globalLongOptionFlags
7017
+ const parameterTokens = collapseOptionalParameterTokens(
7018
+ formatCommandParameterTokens(group.default, casing, globalLongOptionFlags)
6662
7019
  );
6663
- return ["[command]", "[OPTIONS]", ...parameterTokens].join(" ");
7020
+ return ["[command]", "[OPTIONS]", ...parameterTokens.map((token) => token.text)].join(" ");
6664
7021
  }
6665
7022
  return "[command] [OPTIONS]";
6666
7023
  }
7024
+ function formatHelpDrillDownFooter(rootUsageName) {
7025
+ return text.muted(`Run ${rootUsageName} <command> --help for full options.`);
7026
+ }
7027
+ function formatStyledUsageLine(usageLine) {
7028
+ const parts = usageLine.split(" ").filter((part) => part.length > 0);
7029
+ if (parts.length === 0) {
7030
+ return text.usageCommand(usageLine);
7031
+ }
7032
+ const commandEnd = parts.findIndex(
7033
+ (part) => part.startsWith("-") || part.startsWith("[") || part.startsWith("<")
7034
+ );
7035
+ const commandParts = commandEnd === -1 ? parts : parts.slice(0, commandEnd);
7036
+ const argParts = commandEnd === -1 ? [] : parts.slice(commandEnd);
7037
+ const command = commandParts.join(" ");
7038
+ if (argParts.length === 0) {
7039
+ return text.usageCommand(command);
7040
+ }
7041
+ return `${text.usageCommand(command)} ${renderHelpTokens(
7042
+ argParts.flatMap((part, index) => [
7043
+ ...index === 0 ? [] : [{ text: " ", role: "literal" }],
7044
+ ...tokenizeHelpFlags(part)
7045
+ ])
7046
+ )}`;
7047
+ }
6667
7048
  function renderGroupHelp(group, breadcrumb, scope, casing, globalOptions, rootUsageName, isRoot) {
6668
7049
  const sections = [];
6669
7050
  const globalLongOptionFlags = getGlobalLongOptionFlags(
@@ -6679,7 +7060,7 @@ function renderGroupHelp(group, breadcrumb, scope, casing, globalOptions, rootUs
6679
7060
  globalOptions.controls.help
6680
7061
  );
6681
7062
  if (commandRows.length > 0) {
6682
- sections.push(`${text.sectionHeader("Commands")}
7063
+ sections.push(`${text.section("Commands:")}
6683
7064
  ${formatHelpCommandList(commandRows)}`);
6684
7065
  }
6685
7066
  if (isRoot) {
@@ -6692,7 +7073,7 @@ ${formatHelpCommandList(commandRows)}`);
6692
7073
  const builtInLine = formatGlobalOptionsLine(globalOptions);
6693
7074
  if (schemaGlobalRows.length > 0) {
6694
7075
  sections.push(
6695
- `${text.sectionHeader("Options")}
7076
+ `${text.section("Options:")}
6696
7077
  ${formatHelpOptionList(schemaGlobalRows)}
6697
7078
  ${builtInLine}`
6698
7079
  );
@@ -6700,6 +7081,9 @@ ${builtInLine}`
6700
7081
  sections.push(builtInLine);
6701
7082
  }
6702
7083
  }
7084
+ if (commandRows.length > 0) {
7085
+ sections.push(formatHelpDrillDownFooter(rootUsageName));
7086
+ }
6703
7087
  return renderHelpDocument({
6704
7088
  breadcrumb,
6705
7089
  rootUsageName,
@@ -6722,12 +7106,21 @@ function renderLeafHelp(command, breadcrumb, casing, globalOptions, rootUsageNam
6722
7106
  );
6723
7107
  const collected = collectFields(command.params, casing, globalLongOptionFlags);
6724
7108
  const fields = assignPositionals(collected.fields, command.positional);
6725
- const optionRows = fields.filter((field) => field.global !== true).map((field) => ({
6726
- flags: formatHelpFieldFlags(field, globalLongOptionFlags),
6727
- description: formatHelpFieldDescription(field)
6728
- })).concat(collected.dynamicFields.flatMap((field) => formatDynamicHelpFields(field, casing)));
7109
+ const localFields = fields.filter((field) => field.global !== true);
7110
+ const toHelpRow = (field) => createHelpOptionRow(
7111
+ formatHelpFieldFlags(field, globalLongOptionFlags),
7112
+ formatHelpFieldDescription(field)
7113
+ );
7114
+ const argumentRows = localFields.filter((field) => field.positionalIndex !== void 0).map(toHelpRow);
7115
+ const optionRows = sortLeafHelpOptionFields(
7116
+ localFields.filter((field) => field.positionalIndex === void 0)
7117
+ ).map(toHelpRow).concat(collected.dynamicFields.flatMap((field) => formatDynamicHelpFields(field, casing)));
7118
+ if (argumentRows.length > 0) {
7119
+ sections.push(`${text.section("Arguments:")}
7120
+ ${formatHelpOptionList(argumentRows)}`);
7121
+ }
6729
7122
  if (optionRows.length > 0) {
6730
- sections.push(`${text.sectionHeader("Options")}
7123
+ sections.push(`${text.section("Options:")}
6731
7124
  ${formatHelpOptionList(optionRows)}`);
6732
7125
  }
6733
7126
  const builtInLine = formatLeafGlobalOptionsLine(globalOptions);
@@ -6737,13 +7130,13 @@ ${formatHelpOptionList(optionRows)}`);
6737
7130
  const secretRows = formatSecretRows(command.secrets);
6738
7131
  if (secretRows.length > 0) {
6739
7132
  sections.push(
6740
- `${text.sectionHeader("Secrets (environment)")}
7133
+ `${text.section("Secrets (environment):")}
6741
7134
  ${formatHelpOptionList(secretRows)}`
6742
7135
  );
6743
7136
  }
6744
7137
  if (command.examples.length > 0) {
6745
7138
  sections.push(
6746
- `${text.sectionHeader("Examples")}
7139
+ `${text.section("Examples:")}
6747
7140
  ${formatExampleRows(command.examples, breadcrumb, rootUsageName).join("\n")}`
6748
7141
  );
6749
7142
  }
@@ -6865,7 +7258,7 @@ function renderHelpDocument(input) {
6865
7258
  if (remainingDescription.length > 0) {
6866
7259
  lines.push(remainingDescription, "");
6867
7260
  }
6868
- lines.push(`Usage: ${text.usageCommand(input.usageLine)}`, "");
7261
+ lines.push(`Usage: ${formatStyledUsageLine(input.usageLine)}`, "");
6869
7262
  if (input.requiresAuth) {
6870
7263
  lines.push("Requires: authentication");
6871
7264
  }
@@ -6949,7 +7342,9 @@ function createNodeCommand(node, casing, globalLongOptionFlags, execute, presets
6949
7342
  }
6950
7343
  for (const field of fields) {
6951
7344
  if (field.positionalIndex !== void 0) {
6952
- command.argument(formatPositionalToken(field));
7345
+ command.argument(
7346
+ field.variadicPosition === true ? `[${field.displayPath}...]` : `[${field.displayPath}]`
7347
+ );
6953
7348
  continue;
6954
7349
  }
6955
7350
  for (const option of createOption(field, globalLongOptionFlags)) {
@@ -7784,11 +8179,11 @@ function writeRichHeader(title) {
7784
8179
  function isHumanInLoopPending(result) {
7785
8180
  return typeof result === "object" && result !== null && result.status === "pending-approval" && typeof result.approvalId === "string" && typeof result.message === "string" && typeof result.enqueuedAt === "string";
7786
8181
  }
7787
- function renderHumanInLoopPending(pending) {
8182
+ function renderHumanInLoopPending(pending, rootUsageName) {
7788
8183
  process.stdout.write(
7789
8184
  `\u2713 Queued for human approval (id: ${pending.approvalId})
7790
8185
  Message: ${pending.message}
7791
- Track: toolcraft approvals show ${pending.approvalId}
8186
+ Track: ${rootUsageName} approvals show --approval-id ${pending.approvalId}
7792
8187
  `
7793
8188
  );
7794
8189
  }
@@ -7892,7 +8287,7 @@ function parseOptionFieldValue(field, value, errors) {
7892
8287
  }
7893
8288
  return { ok: true, value: parsedValue };
7894
8289
  } catch (error3) {
7895
- if (error3 instanceof UserError || error3 instanceof InvalidArgumentError) {
8290
+ if (isUserError(error3) || error3 instanceof InvalidArgumentError) {
7896
8291
  errors.push({
7897
8292
  path: field.displayPath,
7898
8293
  message: error3.message
@@ -8474,7 +8869,7 @@ async function resolveParams(fields, dynamicFields, variants, positionalValues,
8474
8869
  }
8475
8870
  errors.push({
8476
8871
  path: field.displayPath,
8477
- message: `Missing required parameter "${field.displayPath}".`
8872
+ message: formatMissingParameterMessage(field)
8478
8873
  });
8479
8874
  continue;
8480
8875
  }
@@ -8525,7 +8920,7 @@ function getResolvedFlags(command) {
8525
8920
  const flags = command.optsWithGlobals();
8526
8921
  return flags;
8527
8922
  }
8528
- async function executeCommand(state, services, requirementOptions, runtimeFetch, humanInLoop, runtimeEnv, runtimeFs, outputEmitter, outputFormats, promptStreams, diagnosticsOptions, onErrorReportContext) {
8923
+ async function executeCommand(state, rootUsageName, services, requirementOptions, runtimeFetch, humanInLoop, runtimeEnv, runtimeFs, outputEmitter, outputFormats, promptStreams, diagnosticsOptions, onErrorReportContext) {
8529
8924
  const logger2 = createLogger(outputEmitter);
8530
8925
  const optionValues = state.actionCommand.optsWithGlobals();
8531
8926
  const resolvedFlags = optionValues;
@@ -8681,7 +9076,7 @@ async function executeCommand(state, services, requirementOptions, runtimeFetch,
8681
9076
  writeRichHeader(`${state.command.name} (fixture)`);
8682
9077
  }
8683
9078
  if (isHumanInLoopPending(result)) {
8684
- renderHumanInLoopPending(result);
9079
+ renderHumanInLoopPending(result, rootUsageName);
8685
9080
  return;
8686
9081
  }
8687
9082
  const renderStatus = renderCLIResult(
@@ -8924,7 +9319,7 @@ function renderHttpError(error3, options) {
8924
9319
  async function handleRunError(error3, options) {
8925
9320
  const logger2 = createLogger(options.outputEmitter);
8926
9321
  await withOutputFormat2(options.output, async () => {
8927
- if (error3 instanceof UserError) {
9322
+ if (isUserError(error3)) {
8928
9323
  renderCliErrorPattern(
8929
9324
  options.userErrorPattern === "definition" ? {
8930
9325
  kind: "definition",
@@ -9240,11 +9635,9 @@ function getDefaultCommanderCommandName(command) {
9240
9635
  function configureCommanderSuggestionOutput(command) {
9241
9636
  command.exitOverride();
9242
9637
  command.configureOutput({
9243
- outputError: (message2, write2) => {
9244
- if (message2.includes("unknown command") || message2.includes("unknown option")) {
9245
- return;
9246
- }
9247
- write2(message2);
9638
+ // Every Commander error throws through exitOverride and is rendered once by handleRunError
9639
+ // in the design-system error pattern; writing it here as well double-reports one mistake.
9640
+ outputError: () => {
9248
9641
  }
9249
9642
  });
9250
9643
  command.commands.forEach((child) => configureCommanderSuggestionOutput(child));
@@ -9317,6 +9710,7 @@ async function runCLI(roots, options = {}) {
9317
9710
  resolvedCommandPath = formatCliCommandPath(state.commandPath);
9318
9711
  await executeCommand(
9319
9712
  state,
9713
+ rootUsageName,
9320
9714
  servicesWithBuiltIns,
9321
9715
  requirementOptions,
9322
9716
  runtimeFetch,
@@ -11060,7 +11454,7 @@ var claudeCodeAgent = {
11060
11454
  id: "claude-code",
11061
11455
  name: "claude-code",
11062
11456
  label: "Claude Code",
11063
- summary: "Configure Claude Code to route through Poe.",
11457
+ summary: "Anthropic's agentic coding tool for the terminal.",
11064
11458
  aliases: ["claude"],
11065
11459
  binaryName: "claude",
11066
11460
  apiShapes: ["anthropic-messages"],
@@ -11070,6 +11464,7 @@ var claudeCodeAgent = {
11070
11464
  }
11071
11465
  },
11072
11466
  configPath: "~/.claude.json",
11467
+ capabilities: ["spawn", "configure", "install", "test", "skill", "mcp"],
11073
11468
  branding: {
11074
11469
  colors: {
11075
11470
  dark: "#C15F3C",
@@ -11090,6 +11485,7 @@ var claudeDesktopAgent = {
11090
11485
  linux: "~/.config/Claude/claude_desktop_config.json",
11091
11486
  win32: "~/AppData/Roaming/Claude/claude_desktop_config.json"
11092
11487
  },
11488
+ capabilities: ["mcp"],
11093
11489
  branding: {
11094
11490
  colors: {
11095
11491
  dark: "#D97757",
@@ -11103,7 +11499,7 @@ var codexAgent = {
11103
11499
  id: "codex",
11104
11500
  name: "codex",
11105
11501
  label: "Codex",
11106
- summary: "Configure Codex to use Poe as the model provider.",
11502
+ summary: "OpenAI's coding agent for the terminal.",
11107
11503
  binaryName: "codex",
11108
11504
  apiShapes: ["openai-responses"],
11109
11505
  otelCapture: {
@@ -11117,6 +11513,7 @@ var codexAgent = {
11117
11513
  ]
11118
11514
  },
11119
11515
  configPath: "~/.codex/config.toml",
11516
+ capabilities: ["spawn", "configure", "install", "test", "skill", "mcp"],
11120
11517
  branding: {
11121
11518
  colors: {
11122
11519
  dark: "#D5D9DF",
@@ -11134,6 +11531,7 @@ var cursorAgent = {
11134
11531
  summary: "Cursor's CLI coding agent.",
11135
11532
  binaryName: "cursor-agent",
11136
11533
  configPath: "~/.cursor/mcp.json",
11534
+ capabilities: ["spawn", "configure", "install", "test", "skill", "mcp"],
11137
11535
  branding: {
11138
11536
  colors: {
11139
11537
  dark: "#FFFFFF",
@@ -11148,10 +11546,11 @@ var geminiCliAgent = {
11148
11546
  name: "gemini-cli",
11149
11547
  aliases: ["gemini"],
11150
11548
  label: "Gemini CLI",
11151
- summary: "Configure Google's Gemini CLI to use a compatible Google generations API.",
11549
+ summary: "Google's open-source AI agent for the terminal.",
11152
11550
  binaryName: "gemini",
11153
11551
  configPath: "~/.gemini/settings.json",
11154
11552
  apiShapes: ["google-generations"],
11553
+ capabilities: ["spawn", "configure", "install", "test", "skill"],
11155
11554
  branding: {
11156
11555
  colors: {
11157
11556
  dark: "#8AB4F8",
@@ -11165,7 +11564,7 @@ var openCodeAgent = {
11165
11564
  id: "opencode",
11166
11565
  name: "opencode",
11167
11566
  label: "OpenCode CLI",
11168
- summary: "Configure OpenCode CLI to use the Poe API.",
11567
+ summary: "Open-source AI coding agent for the terminal.",
11169
11568
  binaryName: "opencode",
11170
11569
  apiShapes: ["openai-chat-completions"],
11171
11570
  otelCapture: {
@@ -11174,6 +11573,7 @@ var openCodeAgent = {
11174
11573
  }
11175
11574
  },
11176
11575
  configPath: "~/.config/opencode/opencode.json",
11576
+ capabilities: ["spawn", "configure", "install", "test", "skill", "mcp"],
11177
11577
  branding: {
11178
11578
  colors: {
11179
11579
  dark: "#4A4F55",
@@ -11187,11 +11587,12 @@ var kimiAgent = {
11187
11587
  id: "kimi",
11188
11588
  name: "kimi",
11189
11589
  label: "Kimi",
11190
- summary: "Configure Kimi CLI to use Poe API",
11590
+ summary: "Moonshot AI's coding agent for the terminal.",
11191
11591
  aliases: ["kimi-cli"],
11192
11592
  binaryName: "kimi",
11193
11593
  apiShapes: ["openai-chat-completions"],
11194
11594
  configPath: "~/.kimi/mcp.json",
11595
+ capabilities: ["spawn", "configure", "install", "test", "mcp"],
11195
11596
  branding: {
11196
11597
  colors: {
11197
11598
  dark: "#7B68EE",
@@ -11210,6 +11611,7 @@ var gooseAgent = {
11210
11611
  apiShapes: ["openai-chat-completions"],
11211
11612
  otelCapture: {},
11212
11613
  configPath: "~/.config/goose/config.yaml",
11614
+ capabilities: ["spawn", "configure", "install", "test", "skill", "mcp"],
11213
11615
  branding: {
11214
11616
  colors: {
11215
11617
  dark: "#FF6B35",
@@ -11224,8 +11626,9 @@ var piAgent = {
11224
11626
  name: "pi",
11225
11627
  aliases: ["pi-agent"],
11226
11628
  label: "Pi",
11227
- summary: "Pi coding agent (spawn-only; uses local Pi auth/settings).",
11629
+ summary: "Minimal AI coding agent for the terminal.",
11228
11630
  binaryName: "pi",
11631
+ capabilities: ["spawn"],
11229
11632
  branding: {
11230
11633
  colors: {
11231
11634
  dark: "#F2F2F2",
@@ -11242,6 +11645,7 @@ var poeAgentAgent = {
11242
11645
  summary: "Run one-shot prompts with the built-in Poe agent runtime.",
11243
11646
  apiShapes: ["openai-responses", "openai-chat-completions"],
11244
11647
  configPath: "~/.poe-code/config.json",
11648
+ capabilities: ["configure"],
11245
11649
  branding: {
11246
11650
  colors: {
11247
11651
  dark: "#A465F7",
@@ -11258,6 +11662,9 @@ function freezeAgent(agent) {
11258
11662
  if (agent.apiShapes !== void 0) {
11259
11663
  Object.freeze(agent.apiShapes);
11260
11664
  }
11665
+ if (agent.capabilities !== void 0) {
11666
+ Object.freeze(agent.capabilities);
11667
+ }
11261
11668
  if (agent.otelCapture?.env !== void 0) {
11262
11669
  Object.freeze(agent.otelCapture.env);
11263
11670
  }
@@ -11321,7 +11728,8 @@ var agentSkillConfigs = {
11321
11728
  },
11322
11729
  goose: {
11323
11730
  globalSkillDir: "~/.agents/skills",
11324
- localSkillDir: ".agents/skills"
11731
+ localSkillDir: ".agents/skills",
11732
+ dirNote: "Goose discovers skills from the shared .agents/skills convention, not a goose-specific directory."
11325
11733
  }
11326
11734
  };
11327
11735
  var supportedAgents = Object.freeze(Object.keys(agentSkillConfigs));
@@ -12695,6 +13103,16 @@ async function executeMutation(mutation, context, options) {
12695
13103
  }
12696
13104
  }
12697
13105
 
13106
+ // ../user-error/src/index.ts
13107
+ var UserError2 = class extends Error {
13108
+ hint;
13109
+ constructor(message2, options) {
13110
+ super(message2, options);
13111
+ this.name = "UserError";
13112
+ this.hint = options?.hint;
13113
+ }
13114
+ };
13115
+
12698
13116
  // ../agent-skill-config/src/error-codes.ts
12699
13117
  function hasOwnErrorCode4(error3, code) {
12700
13118
  return error3 instanceof Error && Object.prototype.hasOwnProperty.call(error3, "code") && error3.code === code;
@@ -12746,8 +13164,11 @@ async function installSkill(agentId, skill, options) {
12746
13164
  const skillFilePath = `${skillFolderPath}/SKILL.md`;
12747
13165
  const displayPath = `${scope === "global" ? config2.globalSkillDir : config2.localSkillDir}/${skill.name}/SKILL.md`;
12748
13166
  const absoluteSkillPath = `${scope === "global" ? options.homeDir : options.cwd}/${skillFilePath.slice(2)}`;
12749
- if (await pathExists2(options.fs, absoluteSkillPath)) {
12750
- throw new Error(`Skill already exists: ${displayPath}`);
13167
+ if (!options.force && await pathExists2(options.fs, absoluteSkillPath)) {
13168
+ throw new UserError2(
13169
+ `Skill already exists: ${displayPath}
13170
+ Re-run with --force to overwrite it, or remove it first.`
13171
+ );
12751
13172
  }
12752
13173
  await runMutations(
12753
13174
  [
@@ -14825,7 +15246,7 @@ function sleep2(ms) {
14825
15246
  // src/cli.ts
14826
15247
  configureTheme({ brand: "green", label: "Terminal Pilot" });
14827
15248
  function getBundledPackageVersion() {
14828
- return true ? "0.0.48" : void 0;
15249
+ return true ? "0.0.50" : void 0;
14829
15250
  }
14830
15251
  var pilotOptionsWithValues = /* @__PURE__ */ new Set([
14831
15252
  "--session",