terminal-pilot 0.0.48 → 0.0.49

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 (80) 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/toolcraft-design/dist/acp/components.d.ts +8 -1
  60. package/node_modules/toolcraft-design/dist/acp/components.js +11 -6
  61. package/node_modules/toolcraft-design/dist/acp/index.d.ts +1 -0
  62. package/node_modules/toolcraft-design/dist/components/command-errors.d.ts +2 -0
  63. package/node_modules/toolcraft-design/dist/components/command-errors.js +8 -2
  64. package/node_modules/toolcraft-design/dist/components/help-formatter-plain.js +61 -25
  65. package/node_modules/toolcraft-design/dist/components/help-formatter.d.ts +15 -0
  66. package/node_modules/toolcraft-design/dist/components/help-formatter.js +128 -29
  67. package/node_modules/toolcraft-design/dist/components/index.d.ts +3 -3
  68. package/node_modules/toolcraft-design/dist/components/index.js +2 -2
  69. package/node_modules/toolcraft-design/dist/components/table.d.ts +1 -0
  70. package/node_modules/toolcraft-design/dist/components/table.js +52 -5
  71. package/node_modules/toolcraft-design/dist/components/template.d.ts +9 -0
  72. package/node_modules/toolcraft-design/dist/components/template.js +27 -2
  73. package/node_modules/toolcraft-design/dist/help-formatter.d.ts +2 -2
  74. package/node_modules/toolcraft-design/dist/help-formatter.js +1 -1
  75. package/node_modules/toolcraft-design/dist/index.d.ts +4 -4
  76. package/node_modules/toolcraft-design/dist/index.js +3 -3
  77. package/node_modules/toolcraft-design/dist/prompts/interactive/core.d.ts +5 -0
  78. package/node_modules/toolcraft-design/dist/prompts/interactive/core.js +15 -1
  79. package/node_modules/toolcraft-design/dist/prompts/primitives/spinner.js +1 -1
  80. package/package.json +4 -3
@@ -1643,26 +1643,68 @@ function splitWords(value) {
1643
1643
  }
1644
1644
  return words;
1645
1645
  }
1646
- function wrapWords(value, width) {
1647
- const words = splitWords(value);
1646
+ function leadingWhitespaceWidth(value) {
1647
+ let index = 0;
1648
+ while (index < value.length && isWhitespace(value[index])) {
1649
+ index += 1;
1650
+ }
1651
+ return { prefix: value.slice(0, index), rest: value.slice(index) };
1652
+ }
1653
+ function takeVisiblePrefix(value, width) {
1654
+ let visible = 0;
1655
+ let index = 0;
1656
+ while (index < value.length) {
1657
+ const controlEnd = readControlSequence(value, index);
1658
+ if (controlEnd !== void 0) {
1659
+ index = controlEnd;
1660
+ continue;
1661
+ }
1662
+ const segment = graphemeSegmenter.segment(value.slice(index))[Symbol.iterator]().next().value;
1663
+ const cluster = segment?.segment ?? value[index] ?? "";
1664
+ const nextWidth = clusterWidth(cluster);
1665
+ if (visible > 0 && visible + nextWidth > width) {
1666
+ break;
1667
+ }
1668
+ visible += nextWidth;
1669
+ index += cluster.length || 1;
1670
+ }
1671
+ return { prefix: value.slice(0, index), rest: value.slice(index) };
1672
+ }
1673
+ function wrapWords(value, width, continuationWidth = width) {
1674
+ const { prefix, rest } = leadingWhitespaceWidth(value);
1675
+ const prefixWidth = visibleWidth(prefix);
1676
+ const firstContentWidth = Math.max(1, width - prefixWidth);
1677
+ const words = splitWords(rest);
1648
1678
  if (words.length === 0) {
1649
- return [""];
1679
+ return [prefix];
1650
1680
  }
1651
1681
  const lines = [];
1652
1682
  let line = "";
1683
+ let isFirstLine = true;
1653
1684
  for (const word of words) {
1654
- if (!line) {
1655
- line = word;
1656
- continue;
1657
- }
1658
- if (visibleWidth(line) + 1 + visibleWidth(word) <= width) {
1685
+ const limit = isFirstLine ? firstContentWidth : continuationWidth;
1686
+ if (line && visibleWidth(line) + 1 + visibleWidth(word) <= limit) {
1659
1687
  line += ` ${word}`;
1660
1688
  continue;
1661
1689
  }
1662
- lines.push(line);
1663
- line = word;
1690
+ if (line) {
1691
+ lines.push(isFirstLine ? `${prefix}${line}` : line);
1692
+ isFirstLine = false;
1693
+ line = "";
1694
+ }
1695
+ let remaining = word;
1696
+ while (visibleWidth(remaining) > (isFirstLine ? firstContentWidth : continuationWidth)) {
1697
+ const chunk = takeVisiblePrefix(
1698
+ remaining,
1699
+ isFirstLine ? firstContentWidth : continuationWidth
1700
+ );
1701
+ lines.push(isFirstLine ? `${prefix}${chunk.prefix}` : chunk.prefix);
1702
+ isFirstLine = false;
1703
+ remaining = chunk.rest;
1704
+ }
1705
+ line = remaining;
1664
1706
  }
1665
- lines.push(line);
1707
+ lines.push(isFirstLine ? `${prefix}${line}` : line);
1666
1708
  return lines;
1667
1709
  }
1668
1710
  function validateLayoutValue(value, name) {
@@ -1690,37 +1732,90 @@ function formatColumns(opts) {
1690
1732
  validateLayoutValue(indent, "indent");
1691
1733
  const maxLeftContentWidth = Math.max(...rows.map((row) => visibleWidth(row.left)));
1692
1734
  const leftWidth = clamp(maxLeftContentWidth + gap, minLeftWidth, maxLeftWidth);
1693
- const rightWidth = Math.max(20, totalWidth - leftWidth - indent);
1735
+ const rightWidth = Math.max(1, totalWidth - leftWidth - indent);
1736
+ const leftWrapWidth = Math.max(1, totalWidth - indent);
1694
1737
  const firstIndent = " ".repeat(indent);
1695
1738
  const continuationIndent = " ".repeat(indent + leftWidth);
1696
1739
  return rows.flatMap((row) => {
1740
+ const leftLeading = leadingWhitespaceWidth(row.left).prefix;
1741
+ const leftHangIndent = " ".repeat(indent + visibleWidth(leftLeading) + 2);
1742
+ const leftLines = wrapWords(
1743
+ row.left,
1744
+ leftWrapWidth,
1745
+ Math.max(1, totalWidth - visibleWidth(leftHangIndent))
1746
+ );
1697
1747
  if (row.right.length === 0) {
1698
- return [`${firstIndent}${row.left}`];
1748
+ return leftLines.map(
1749
+ (line, index) => index === 0 ? `${firstIndent}${line}` : `${leftHangIndent}${line}`
1750
+ );
1699
1751
  }
1700
1752
  const rightLines = wrapWords(row.right, rightWidth);
1701
- if (visibleWidth(row.left) >= leftWidth) {
1702
- return [
1703
- `${firstIndent}${row.left}`,
1704
- ...rightLines.map((line) => `${continuationIndent}${line}`)
1705
- ];
1706
- }
1707
- const firstLine = `${firstIndent}${padEndVisible(row.left, leftWidth)}${rightLines[0]}`;
1708
- const continuationLines = rightLines.slice(1).map((line) => `${continuationIndent}${line}`);
1709
- return [firstLine, ...continuationLines];
1753
+ const leftFitsInColumn = visibleWidth(row.left) < leftWidth;
1754
+ if (leftFitsInColumn && leftLines.length === 1) {
1755
+ const firstLine = `${firstIndent}${padEndVisible(leftLines[0] ?? "", leftWidth)}${rightLines[0]}`;
1756
+ const continuationLines = rightLines.slice(1).map((line) => `${continuationIndent}${line}`);
1757
+ return [firstLine, ...continuationLines];
1758
+ }
1759
+ const renderedLeft = leftLines.map(
1760
+ (line, index) => index === 0 ? `${firstIndent}${line}` : `${leftHangIndent}${line}`
1761
+ );
1762
+ const renderedRight = rightLines.map((line) => `${continuationIndent}${line}`);
1763
+ return [...renderedLeft, ...renderedRight];
1710
1764
  }).join("\n");
1711
1765
  }
1766
+ function styleHelpToken(token) {
1767
+ switch (token.role) {
1768
+ case "command":
1769
+ return text.command(token.text);
1770
+ case "argument":
1771
+ return styleArgumentToken(token.text);
1772
+ case "option":
1773
+ return text.option(token.text);
1774
+ case "dim":
1775
+ return styleDim(token.text);
1776
+ case "literal":
1777
+ return token.text;
1778
+ }
1779
+ }
1780
+ function styleArgumentToken(content) {
1781
+ const format = resolveOutputFormat();
1782
+ if (format === "markdown" && content.startsWith("<") && content.endsWith(">")) {
1783
+ return text.argument(content.slice(1, -1));
1784
+ }
1785
+ if (format === "json") {
1786
+ return content;
1787
+ }
1788
+ return text.argument(content);
1789
+ }
1790
+ function styleDim(content) {
1791
+ const format = resolveOutputFormat();
1792
+ if (format === "json" || format === "markdown") {
1793
+ return content;
1794
+ }
1795
+ return typography.dim(content);
1796
+ }
1797
+ function joinHelpTokens(tokens) {
1798
+ return tokens.map((token) => token.text).join("");
1799
+ }
1800
+ function renderHelpTokens(tokens) {
1801
+ return tokens.map((token) => styleHelpToken(token)).join("");
1802
+ }
1712
1803
  function formatCommandList(commands) {
1713
1804
  return formatColumns({
1714
- rows: commands.map((cmd) => ({
1715
- left: `${" ".repeat((cmd.depth ?? 0) * 2)}${text.command(cmd.name)}`,
1716
- right: cmd.description
1717
- }))
1805
+ rows: commands.map((cmd) => {
1806
+ const depthPrefix = " ".repeat((cmd.depth ?? 0) * 2);
1807
+ const styledName = cmd.nameTokens !== void 0 && cmd.nameTokens.length > 0 ? renderHelpTokens(cmd.nameTokens) : text.command(cmd.name);
1808
+ return {
1809
+ left: `${depthPrefix}${styledName}`,
1810
+ right: cmd.description
1811
+ };
1812
+ })
1718
1813
  });
1719
1814
  }
1720
1815
  function formatOptionList(options) {
1721
1816
  return formatColumns({
1722
1817
  rows: options.map((opt) => ({
1723
- left: text.option(opt.flags),
1818
+ left: opt.flagTokens !== void 0 && opt.flagTokens.length > 0 ? renderHelpTokens(opt.flagTokens) : text.option(opt.flags),
1724
1819
  right: opt.description
1725
1820
  }))
1726
1821
  });
@@ -1790,26 +1885,47 @@ function splitWords2(value) {
1790
1885
  }
1791
1886
  return words;
1792
1887
  }
1793
- function wrapWords2(value, width) {
1794
- const words = splitWords2(value);
1888
+ function leadingWhitespace(value) {
1889
+ let index = 0;
1890
+ while (index < value.length && isWhitespace2(value[index])) {
1891
+ index += 1;
1892
+ }
1893
+ return { prefix: value.slice(0, index), rest: value.slice(index) };
1894
+ }
1895
+ function takePrefix(value, width) {
1896
+ return { prefix: value.slice(0, width), rest: value.slice(width) };
1897
+ }
1898
+ function wrapWords2(value, width, continuationWidth = width) {
1899
+ const { prefix, rest } = leadingWhitespace(value);
1900
+ const firstContentWidth = Math.max(1, width - prefix.length);
1901
+ const words = splitWords2(rest);
1795
1902
  if (words.length === 0) {
1796
- return [""];
1903
+ return [prefix];
1797
1904
  }
1798
1905
  const lines = [];
1799
1906
  let line = "";
1907
+ let isFirstLine = true;
1800
1908
  for (const word of words) {
1801
- if (!line) {
1802
- line = word;
1803
- continue;
1804
- }
1805
- if (line.length + 1 + word.length <= width) {
1909
+ const limit = isFirstLine ? firstContentWidth : continuationWidth;
1910
+ if (line && line.length + 1 + word.length <= limit) {
1806
1911
  line += ` ${word}`;
1807
1912
  continue;
1808
1913
  }
1809
- lines.push(line);
1810
- line = word;
1914
+ if (line) {
1915
+ lines.push(isFirstLine ? `${prefix}${line}` : line);
1916
+ isFirstLine = false;
1917
+ line = "";
1918
+ }
1919
+ let remaining = word;
1920
+ while (remaining.length > (isFirstLine ? firstContentWidth : continuationWidth)) {
1921
+ const chunk = takePrefix(remaining, isFirstLine ? firstContentWidth : continuationWidth);
1922
+ lines.push(isFirstLine ? `${prefix}${chunk.prefix}` : chunk.prefix);
1923
+ isFirstLine = false;
1924
+ remaining = chunk.rest;
1925
+ }
1926
+ line = remaining;
1811
1927
  }
1812
- lines.push(line);
1928
+ lines.push(isFirstLine ? `${prefix}${line}` : line);
1813
1929
  return lines;
1814
1930
  }
1815
1931
  function formatColumns2(opts) {
@@ -1827,29 +1943,44 @@ function formatColumns2(opts) {
1827
1943
  const indent = opts.indent ?? 2;
1828
1944
  const maxLeftContentWidth = Math.max(...rows.map((row) => row.left.length));
1829
1945
  const leftWidth = clamp2(maxLeftContentWidth + gap, minLeftWidth, maxLeftWidth);
1830
- const rightWidth = Math.max(20, totalWidth - leftWidth - indent);
1946
+ const rightWidth = Math.max(1, totalWidth - leftWidth - indent);
1947
+ const leftWrapWidth = Math.max(1, totalWidth - indent);
1831
1948
  const firstIndent = " ".repeat(indent);
1832
1949
  const continuationIndent = " ".repeat(indent + leftWidth);
1833
1950
  return rows.flatMap((row) => {
1951
+ let leftLeadingWidth = 0;
1952
+ while (leftLeadingWidth < row.left.length && isWhitespace2(row.left[leftLeadingWidth])) {
1953
+ leftLeadingWidth += 1;
1954
+ }
1955
+ const leftHangIndent = " ".repeat(indent + leftLeadingWidth + 2);
1956
+ const leftLines = wrapWords2(
1957
+ row.left,
1958
+ leftWrapWidth,
1959
+ Math.max(1, totalWidth - leftHangIndent.length)
1960
+ );
1834
1961
  if (row.right.length === 0) {
1835
- return [`${firstIndent}${row.left}`];
1962
+ return leftLines.map(
1963
+ (line, index) => index === 0 ? `${firstIndent}${line}` : `${leftHangIndent}${line}`
1964
+ );
1836
1965
  }
1837
1966
  const rightLines = wrapWords2(row.right, rightWidth);
1838
- if (row.left.length >= leftWidth) {
1839
- return [
1840
- `${firstIndent}${row.left}`,
1841
- ...rightLines.map((line) => `${continuationIndent}${line}`)
1842
- ];
1843
- }
1844
- const firstLine = `${firstIndent}${padEndVisible2(row.left, leftWidth)}${rightLines[0]}`;
1845
- const continuationLines = rightLines.slice(1).map((line) => `${continuationIndent}${line}`);
1846
- return [firstLine, ...continuationLines];
1967
+ const leftFitsInColumn = row.left.length < leftWidth;
1968
+ if (leftFitsInColumn && leftLines.length === 1) {
1969
+ const firstLine = `${firstIndent}${padEndVisible2(leftLines[0] ?? "", leftWidth)}${rightLines[0]}`;
1970
+ const continuationLines = rightLines.slice(1).map((line) => `${continuationIndent}${line}`);
1971
+ return [firstLine, ...continuationLines];
1972
+ }
1973
+ const renderedLeft = leftLines.map(
1974
+ (line, index) => index === 0 ? `${firstIndent}${line}` : `${leftHangIndent}${line}`
1975
+ );
1976
+ const renderedRight = rightLines.map((line) => `${continuationIndent}${line}`);
1977
+ return [...renderedLeft, ...renderedRight];
1847
1978
  }).join("\n");
1848
1979
  }
1849
1980
  function formatCommandList2(commands) {
1850
1981
  return formatColumns2({
1851
1982
  rows: commands.map((cmd) => ({
1852
- left: `${" ".repeat((cmd.depth ?? 0) * 2)}${cmd.name}`,
1983
+ left: `${" ".repeat((cmd.depth ?? 0) * 2)}${cmd.nameTokens !== void 0 && cmd.nameTokens.length > 0 ? joinHelpTokens(cmd.nameTokens) : cmd.name}`,
1853
1984
  right: cmd.description
1854
1985
  }))
1855
1986
  });
@@ -1857,7 +1988,7 @@ function formatCommandList2(commands) {
1857
1988
  function formatOptionList2(options) {
1858
1989
  return formatColumns2({
1859
1990
  rows: options.map((opt) => ({
1860
- left: opt.flags,
1991
+ left: opt.flagTokens !== void 0 && opt.flagTokens.length > 0 ? joinHelpTokens(opt.flagTokens) : opt.flags,
1861
1992
  right: opt.description
1862
1993
  }))
1863
1994
  });
@@ -1866,6 +1997,7 @@ function formatOptionList2(options) {
1866
1997
  // ../toolcraft-design/src/components/table.ts
1867
1998
  var reset2 = "\x1B[0m";
1868
1999
  var ellipsis = "\u2026";
2000
+ var minCellWidth = 4;
1869
2001
  var graphemeSegmenter2 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
1870
2002
  function getCell(row, name) {
1871
2003
  return Object.prototype.hasOwnProperty.call(row, name) ? row[name] ?? "" : "";
@@ -1999,6 +2131,39 @@ function computeColumns(columns) {
1999
2131
  width: getColumnWidth(column)
2000
2132
  }));
2001
2133
  }
2134
+ function frameWidth(columnCount) {
2135
+ return columnCount * 3 + 1;
2136
+ }
2137
+ function budgetColumns(columns, maxWidth) {
2138
+ if (maxWidth === void 0) {
2139
+ return columns;
2140
+ }
2141
+ const available = maxWidth - frameWidth(columns.length);
2142
+ const contentWidth = (cap2) => columns.reduce((total, column) => total + Math.min(column.width, cap2), 0);
2143
+ if (columns.reduce((total, column) => total + column.width, 0) <= available) {
2144
+ return columns;
2145
+ }
2146
+ let cap = minCellWidth;
2147
+ while (contentWidth(cap + 1) <= available) {
2148
+ cap += 1;
2149
+ }
2150
+ const budgeted = columns.map((column) => ({ ...column, width: Math.min(column.width, cap) }));
2151
+ let slack = available - contentWidth(cap);
2152
+ while (slack > 0) {
2153
+ const growable = budgeted.filter((column, index) => column.width < columns[index].width);
2154
+ if (growable.length === 0) {
2155
+ break;
2156
+ }
2157
+ for (const column of growable) {
2158
+ if (slack === 0) {
2159
+ break;
2160
+ }
2161
+ column.width += 1;
2162
+ slack -= 1;
2163
+ }
2164
+ }
2165
+ return budgeted;
2166
+ }
2002
2167
  function renderBorder(columns, theme, parts) {
2003
2168
  const horizontal = theme.muted("\u2500");
2004
2169
  const segments = columns.map((column) => horizontal.repeat(column.width + 2));
@@ -2083,14 +2248,15 @@ function renderTableTerminal(options) {
2083
2248
  }
2084
2249
  const separatorOptions = options;
2085
2250
  const includeRowSeparators = separatorOptions.rowSeparator === true || separatorOptions.rowSeparators === true;
2086
- const top = renderBorder(computedColumns, theme, { left: "\u250C", mid: "\u252C", right: "\u2510" });
2251
+ const budgetedColumns = budgetColumns(computedColumns, options.maxWidth ?? process.stdout.columns);
2252
+ const top = renderBorder(budgetedColumns, theme, { left: "\u250C", mid: "\u252C", right: "\u2510" });
2087
2253
  const header = renderTerminalRow(
2088
- computedColumns.map((column) => theme.header(column.title)),
2089
- computedColumns,
2254
+ budgetedColumns.map((column) => theme.header(column.title)),
2255
+ budgetedColumns,
2090
2256
  theme
2091
2257
  );
2092
- const headerBottom = renderBorder(computedColumns, theme, { left: "\u251C", mid: "\u253C", right: "\u2524" });
2093
- const bottom = renderBorder(computedColumns, theme, { left: "\u2514", mid: "\u2534", right: "\u2518" });
2258
+ const headerBottom = renderBorder(budgetedColumns, theme, { left: "\u251C", mid: "\u253C", right: "\u2524" });
2259
+ const bottom = renderBorder(budgetedColumns, theme, { left: "\u2514", mid: "\u2534", right: "\u2518" });
2094
2260
  const renderedRows = [];
2095
2261
  for (const [index, row] of rows.entries()) {
2096
2262
  if (includeRowSeparators && index > 0) {
@@ -2098,8 +2264,8 @@ function renderTableTerminal(options) {
2098
2264
  }
2099
2265
  renderedRows.push(
2100
2266
  renderTerminalRow(
2101
- computedColumns.map((column) => getCell(row, column.name)),
2102
- computedColumns,
2267
+ budgetedColumns.map((column) => getCell(row, column.name)),
2268
+ budgetedColumns,
2103
2269
  theme
2104
2270
  )
2105
2271
  );
@@ -2192,6 +2358,19 @@ ${options.theme.muted(options.badges.map((badge) => badge[0] + badge.slice(1).to
2192
2358
 
2193
2359
  // ../toolcraft-design/src/components/template.ts
2194
2360
  var MAX_PARTIAL_DEPTH = 100;
2361
+ var MAX_TAG_EXCERPT_LENGTH = 40;
2362
+ var TemplateParseError = class extends Error {
2363
+ description;
2364
+ line;
2365
+ column;
2366
+ constructor(description, position) {
2367
+ super(`${description} at line ${position.line}, column ${position.column}`);
2368
+ this.name = "TemplateParseError";
2369
+ this.description = description;
2370
+ this.line = position.line;
2371
+ this.column = position.column;
2372
+ }
2373
+ };
2195
2374
  var HTML_ESCAPE = {
2196
2375
  "&": "&amp;",
2197
2376
  "<": "&lt;",
@@ -2298,13 +2477,13 @@ function parseTag(template, open) {
2298
2477
  if (template.startsWith("{{{", open)) {
2299
2478
  const close2 = template.indexOf("}}}", open + 3);
2300
2479
  if (close2 === -1) {
2301
- throw new Error("Unclosed unescaped tag");
2480
+ throw unclosedTagError(template, open, "}}}");
2302
2481
  }
2303
2482
  return { kind: "unescaped", name: template.slice(open + 3, close2).trim(), end: close2 + 3 };
2304
2483
  }
2305
2484
  const close = template.indexOf("}}", open + 2);
2306
2485
  if (close === -1) {
2307
- throw new Error("Unclosed tag");
2486
+ throw unclosedTagError(template, open, "}}");
2308
2487
  }
2309
2488
  const raw = template.slice(open + 2, close).trim();
2310
2489
  const sigil = raw[0];
@@ -2319,6 +2498,16 @@ function parseTag(template, open) {
2319
2498
  if (sigil === "=" && raw.endsWith("=")) return { kind: "delimiter", name, end };
2320
2499
  return { kind: "name", name: raw, end };
2321
2500
  }
2501
+ function unclosedTagError(template, open, expected) {
2502
+ const before = template.slice(0, open);
2503
+ const lineEnd = template.indexOf("\n", open);
2504
+ const opened = template.slice(open, lineEnd === -1 ? template.length : lineEnd).trimEnd();
2505
+ const tag = opened.length > MAX_TAG_EXCERPT_LENGTH ? `${opened.slice(0, MAX_TAG_EXCERPT_LENGTH)}...` : opened;
2506
+ return new TemplateParseError(`Unclosed tag "${tag}": expected "${expected}"`, {
2507
+ line: before.split("\n").length,
2508
+ column: open - (before.lastIndexOf("\n") + 1) + 1
2509
+ });
2510
+ }
2322
2511
  function getStandalone(template, tagStart, tagEnd, kind) {
2323
2512
  if (!["section", "inverted", "close", "comment", "partial", "delimiter"].includes(kind)) {
2324
2513
  return void 0;
@@ -2890,6 +3079,15 @@ var cursor = {
2890
3079
  var erase = {
2891
3080
  down: "\x1B[J"
2892
3081
  };
3082
+ function nonTtyPromptMessage(argv = process.argv) {
3083
+ const tokens = [];
3084
+ for (const arg of argv.slice(2)) {
3085
+ if (arg.startsWith("-")) break;
3086
+ tokens.push(arg);
3087
+ }
3088
+ const retry = [...tokens, "--yes"].join(" ");
3089
+ return `Interactive prompt requires a TTY. Re-run with \`${retry}\` to accept defaults non-interactively, or set POE_NO_PROMPT=1 in CI.`;
3090
+ }
2893
3091
  var Prompt = class extends EventEmitter {
2894
3092
  state = "initial";
2895
3093
  value;
@@ -2960,7 +3158,7 @@ var Prompt = class extends EventEmitter {
2960
3158
  });
2961
3159
  }
2962
3160
  promptNonTty() {
2963
- return Promise.reject(new Error("Interactive prompt requires a TTY. Set POE_NO_PROMPT=1 to accept defaults non-interactively."));
3161
+ return Promise.reject(new Error(nonTtyPromptMessage()));
2964
3162
  }
2965
3163
  readNonTtyLine() {
2966
3164
  return new Promise((resolve) => {
@@ -3484,6 +3682,9 @@ var UserError = class extends Error {
3484
3682
  this.name = "UserError";
3485
3683
  }
3486
3684
  };
3685
+ function isUserError(error3) {
3686
+ return error3 instanceof UserError || error3 instanceof Error && error3.name === "UserError";
3687
+ }
3487
3688
  var ToolcraftBugError = class extends Error {
3488
3689
  constructor(message2) {
3489
3690
  super(message2);
@@ -5125,6 +5326,9 @@ function compactUrl(value) {
5125
5326
  return value;
5126
5327
  }
5127
5328
  }
5329
+ function stackedList(value) {
5330
+ return value.map((entry) => displayScalar(entry)).join("\n") || "\u2014";
5331
+ }
5128
5332
  function displayRowValue(value) {
5129
5333
  return isUrl(value) ? compactUrl(value) : displayScalar(value);
5130
5334
  }
@@ -5150,7 +5354,7 @@ function renderObjectCard(result, primitives, title) {
5150
5354
  const scalarRows = directScalarRows(result);
5151
5355
  const nestedSections = directObjectSections(result);
5152
5356
  const arrayObjectSections = directArrayObjectSections(result);
5153
- const listRows = Object.entries(result).filter(([, value]) => Array.isArray(value) && !isNonEmptyArrayOfObjects(value)).map(([key, value]) => ({ label: humanizeKey(key), value: displayScalar(value) }));
5357
+ const listRows = Object.entries(result).filter(([, value]) => Array.isArray(value) && !isNonEmptyArrayOfObjects(value)).map(([key, value]) => ({ label: humanizeKey(key), value: stackedList(value) }));
5154
5358
  return renderDetailCard({
5155
5359
  theme: primitives.getTheme(),
5156
5360
  title,
@@ -5852,6 +6056,13 @@ function formatOptionFlags(field, globalLongOptionFlags) {
5852
6056
  }
5853
6057
  return [`-${field.shortFlag}`, field.optionFlag, ...field.longAliases].join(", ");
5854
6058
  }
6059
+ function formatMissingParameterMessage(field) {
6060
+ const message2 = `Missing required parameter "${field.displayPath}".`;
6061
+ if (field.schema.kind !== "enum") {
6062
+ return message2;
6063
+ }
6064
+ return `${message2} Expected one of: ${field.schema.values.map((value) => String(value)).join(", ")}.`;
6065
+ }
5855
6066
  function formatPositionalToken(field) {
5856
6067
  const optionalPositional = field.optional || field.hasDefault;
5857
6068
  if (field.variadicPosition === true) {
@@ -6333,12 +6544,31 @@ function appendHelpMetadata(description, metadata) {
6333
6544
  return description;
6334
6545
  }
6335
6546
  if (description.length === 0) {
6336
- return `(${metadata.join(", ")})`;
6547
+ return metadata.map((entry) => `(${entry})`).join(" ");
6548
+ }
6549
+ return `${description} ${metadata.map((entry) => `(${entry})`).join(" ")}`;
6550
+ }
6551
+ function normalizeHelpEchoKey(value) {
6552
+ let normalized = "";
6553
+ for (const character of value.trim().toLowerCase()) {
6554
+ if (character !== " " && character !== " " && character !== "\n" && character !== "\r" && character !== "_" && character !== "." && character !== "-") {
6555
+ normalized += character;
6556
+ }
6337
6557
  }
6338
- return `${description} (${metadata.join(", ")})`;
6558
+ return normalized;
6559
+ }
6560
+ function isEchoHelpDescription(description, name) {
6561
+ if (description.length === 0) {
6562
+ return false;
6563
+ }
6564
+ return normalizeHelpEchoKey(description) === normalizeHelpEchoKey(name);
6565
+ }
6566
+ function suppressEchoHelpDescription(description, name) {
6567
+ return isEchoHelpDescription(description, name) ? "" : description;
6339
6568
  }
6340
6569
  function formatHelpFieldDescription(field) {
6341
- const description = field.description ?? field.displayPath;
6570
+ const rawDescription = field.description ?? field.displayPath;
6571
+ const description = suppressEchoHelpDescription(rawDescription, field.displayPath);
6342
6572
  const metadata = [];
6343
6573
  if (field.schema.kind === "enum" && field.schema.values.length <= 8) {
6344
6574
  const values = field.schema.values.map((value) => String(value)).join(", ");
@@ -6487,13 +6717,21 @@ function formatDynamicHelpMetadata(field) {
6487
6717
  }
6488
6718
  return metadata;
6489
6719
  }
6720
+ function createHelpOptionRow(flags, description) {
6721
+ return {
6722
+ flags,
6723
+ flagTokens: tokenizeHelpFlags(flags),
6724
+ description
6725
+ };
6726
+ }
6490
6727
  function collectDynamicObjectHelpRows(schema, casing, optionPrefix, displayPrefix, metadata) {
6491
6728
  const rows = [];
6492
6729
  for (const [key, rawChildSchema] of Object.entries(schema.shape)) {
6493
6730
  const childSchema = unwrapOptional2(rawChildSchema);
6494
6731
  const optionFlag = `${optionPrefix}.${formatSegment(key, casing)}`;
6495
6732
  const displayPath = `${displayPrefix}.${key}`;
6496
- const description = childSchema.description ?? displayPath;
6733
+ const rawDescription = childSchema.description ?? displayPath;
6734
+ const description = suppressEchoHelpDescription(rawDescription, displayPath);
6497
6735
  if (childSchema.kind === "object") {
6498
6736
  rows.push(
6499
6737
  ...collectDynamicObjectHelpRows(childSchema, casing, optionFlag, displayPath, metadata)
@@ -6501,24 +6739,26 @@ function collectDynamicObjectHelpRows(schema, casing, optionPrefix, displayPrefi
6501
6739
  continue;
6502
6740
  }
6503
6741
  if (childSchema.kind === "record") {
6504
- rows.push({
6505
- flags: `${optionFlag}.<key> <${describeDynamicFieldType({
6506
- ...{
6507
- id: displayPath,
6508
- path: [],
6509
- displayPath,
6510
- optionPath: [],
6511
- optionPathDisplay: `${displayPath}.<key>`,
6512
- optionFlag: `${optionFlag}.<key>`,
6513
- optional: false,
6514
- hasDefault: false,
6515
- defaultValue: void 0,
6516
- requiredWhenActive: false,
6517
- schema: childSchema
6518
- }
6519
- })}>`,
6520
- description: appendHelpMetadata(description, metadata)
6521
- });
6742
+ rows.push(
6743
+ createHelpOptionRow(
6744
+ `${optionFlag}.<key> <${describeDynamicFieldType({
6745
+ ...{
6746
+ id: displayPath,
6747
+ path: [],
6748
+ displayPath,
6749
+ optionPath: [],
6750
+ optionPathDisplay: `${displayPath}.<key>`,
6751
+ optionFlag: `${optionFlag}.<key>`,
6752
+ optional: false,
6753
+ hasDefault: false,
6754
+ defaultValue: void 0,
6755
+ requiredWhenActive: false,
6756
+ schema: childSchema
6757
+ }
6758
+ })}>`,
6759
+ appendHelpMetadata(description, metadata)
6760
+ )
6761
+ );
6522
6762
  continue;
6523
6763
  }
6524
6764
  if (childSchema.kind === "array" && unwrapOptional2(childSchema.item).kind === "object") {
@@ -6533,13 +6773,15 @@ function collectDynamicObjectHelpRows(schema, casing, optionPrefix, displayPrefi
6533
6773
  );
6534
6774
  continue;
6535
6775
  }
6536
- rows.push({
6537
- flags: childSchema.kind === "boolean" ? childSchema.default === true ? `--no-${optionFlag.slice(2)}` : optionFlag : `${optionFlag} <${describeHelpValueToken(childSchema, {
6538
- displayPath,
6539
- optionFlag
6540
- })}>`,
6541
- description: appendHelpMetadata(description, metadata)
6542
- });
6776
+ rows.push(
6777
+ createHelpOptionRow(
6778
+ childSchema.kind === "boolean" ? childSchema.default === true ? `--no-${optionFlag.slice(2)}` : optionFlag : `${optionFlag} <${describeHelpValueToken(childSchema, {
6779
+ displayPath,
6780
+ optionFlag
6781
+ })}>`,
6782
+ appendHelpMetadata(description, metadata)
6783
+ )
6784
+ );
6543
6785
  }
6544
6786
  return rows;
6545
6787
  }
@@ -6570,17 +6812,22 @@ function formatDynamicHelpFields(field, casing) {
6570
6812
  }
6571
6813
  }
6572
6814
  return [
6573
- {
6574
- flags: `${field.optionFlag} <${describeDynamicFieldType(field)}>`,
6575
- description: appendHelpMetadata(field.description ?? field.optionPathDisplay, metadata)
6576
- }
6815
+ createHelpOptionRow(
6816
+ `${field.optionFlag} <${describeDynamicFieldType(field)}>`,
6817
+ appendHelpMetadata(
6818
+ suppressEchoHelpDescription(
6819
+ field.description ?? field.optionPathDisplay,
6820
+ field.optionPathDisplay
6821
+ ),
6822
+ metadata
6823
+ )
6824
+ )
6577
6825
  ];
6578
6826
  }
6579
6827
  function formatSecretRows(secrets) {
6580
- return Object.values(secrets).map((secret) => ({
6581
- flags: secret.env,
6582
- description: formatSecretDescription(secret)
6583
- }));
6828
+ return Object.values(secrets).map(
6829
+ (secret) => createHelpOptionRow(secret.env, formatSecretDescription(secret))
6830
+ );
6584
6831
  }
6585
6832
  function formatSecretDescription(secret) {
6586
6833
  if (secret.description !== void 0 && secret.description.length > 0) {
@@ -6608,20 +6855,82 @@ function formatExampleRows(examples, breadcrumb, rootUsageName) {
6608
6855
  ${formatExampleCommand(breadcrumb, rootUsageName, example.params)}`
6609
6856
  );
6610
6857
  }
6611
- function wrapOptionalCommandParameterToken(token, optional) {
6612
- return optional ? `[${token}]` : token;
6858
+ var MAX_INLINE_OPTIONAL_PARAMETER_TOKENS = 8;
6859
+ var DEFAULT_HELP_TOTAL_WIDTH = 100;
6860
+ function tokenizeHelpFlags(flags) {
6861
+ const tokens = [];
6862
+ let index = 0;
6863
+ while (index < flags.length) {
6864
+ if (flags[index] === " ") {
6865
+ let end2 = index + 1;
6866
+ while (end2 < flags.length && flags[end2] === " ") {
6867
+ end2 += 1;
6868
+ }
6869
+ tokens.push({ text: flags.slice(index, end2), role: "literal" });
6870
+ index = end2;
6871
+ continue;
6872
+ }
6873
+ if (flags[index] === "[" || flags[index] === "]") {
6874
+ tokens.push({ text: flags[index], role: "dim" });
6875
+ index += 1;
6876
+ continue;
6877
+ }
6878
+ if (flags[index] === "<") {
6879
+ const close = flags.indexOf(">", index);
6880
+ if (close === -1) {
6881
+ tokens.push({ text: flags.slice(index), role: "literal" });
6882
+ break;
6883
+ }
6884
+ tokens.push({ text: flags.slice(index, close + 1), role: "argument" });
6885
+ index = close + 1;
6886
+ continue;
6887
+ }
6888
+ if (flags.startsWith("--", index) || flags[index] === "-" && flags[index + 1] !== void 0 && flags[index + 1] !== "-") {
6889
+ let end2 = index + 1;
6890
+ while (end2 < flags.length && flags[end2] !== " " && flags[end2] !== "[" && flags[end2] !== "]" && flags[end2] !== "<") {
6891
+ end2 += 1;
6892
+ }
6893
+ tokens.push({ text: flags.slice(index, end2), role: "option" });
6894
+ index = end2;
6895
+ continue;
6896
+ }
6897
+ let end = index + 1;
6898
+ while (end < flags.length && flags[end] !== " " && flags[end] !== "[" && flags[end] !== "]" && flags[end] !== "<") {
6899
+ end += 1;
6900
+ }
6901
+ const piece = flags.slice(index, end);
6902
+ tokens.push({
6903
+ text: piece,
6904
+ role: piece.includes("|") ? "literal" : piece.startsWith("+") ? "dim" : "literal"
6905
+ });
6906
+ index = end;
6907
+ }
6908
+ return tokens;
6909
+ }
6910
+ function wrapOptionalParameterTokens(tokens, optional) {
6911
+ if (!optional) {
6912
+ return tokens;
6913
+ }
6914
+ return [{ text: "[", role: "dim" }, ...tokens, { text: "]", role: "dim" }];
6915
+ }
6916
+ function createCommandParameterToken(text3, optional) {
6917
+ return {
6918
+ text: optional ? `[${text3}]` : text3,
6919
+ optional,
6920
+ tokens: wrapOptionalParameterTokens(tokenizeHelpFlags(text3), optional)
6921
+ };
6613
6922
  }
6614
6923
  function formatCommandDynamicParameterTokens(field, casing) {
6615
6924
  const optional = field.optional || field.hasDefault;
6616
6925
  return formatDynamicHelpFields(field, casing).map(
6617
- (row) => wrapOptionalCommandParameterToken(row.flags, optional)
6926
+ (row) => createCommandParameterToken(row.flags, optional)
6618
6927
  );
6619
6928
  }
6620
6929
  function formatCommandParameterTokens(command, casing, globalLongOptionFlags) {
6621
6930
  const collected = collectFields(command.params, casing, globalLongOptionFlags);
6622
6931
  const fields = assignPositionals(collected.fields, command.positional);
6623
6932
  return fields.filter((field) => field.global !== true).map(
6624
- (field) => wrapOptionalCommandParameterToken(
6933
+ (field) => createCommandParameterToken(
6625
6934
  formatCommandParameterFieldFlags(field, globalLongOptionFlags),
6626
6935
  field.positionalIndex === void 0 && (field.optional || field.hasDefault)
6627
6936
  )
@@ -6629,30 +6938,65 @@ function formatCommandParameterTokens(command, casing, globalLongOptionFlags) {
6629
6938
  collected.dynamicFields.flatMap((field) => formatCommandDynamicParameterTokens(field, casing))
6630
6939
  );
6631
6940
  }
6632
- function formatCommandRowName(node, casing, globalLongOptionFlags) {
6941
+ function collapseOptionalParameterTokens(parameterTokens, inlineWidthBudget = Number.POSITIVE_INFINITY) {
6942
+ const optionalCount = parameterTokens.filter((token) => token.optional).length;
6943
+ if (optionalCount === 0) {
6944
+ return parameterTokens;
6945
+ }
6946
+ const inlineWidth = parameterTokens.reduce((total, token) => total + token.text.length + 1, 0);
6947
+ if (optionalCount <= MAX_INLINE_OPTIONAL_PARAMETER_TOKENS && inlineWidth <= inlineWidthBudget) {
6948
+ return parameterTokens;
6949
+ }
6950
+ const required = parameterTokens.filter((token) => !token.optional);
6951
+ const collapsedText = `+${optionalCount} options`;
6952
+ return [
6953
+ ...required,
6954
+ {
6955
+ text: `[${collapsedText}]`,
6956
+ optional: true,
6957
+ tokens: [
6958
+ { text: "[", role: "dim" },
6959
+ { text: collapsedText, role: "dim" },
6960
+ { text: "]", role: "dim" }
6961
+ ]
6962
+ }
6963
+ ];
6964
+ }
6965
+ function formatCommandRowNameTokens(node, casing, globalLongOptionFlags) {
6633
6966
  const baseName = node.aliases.length === 0 ? node.name : `${node.name} (${node.aliases.join(", ")})`;
6634
- const parameterTokens = node.kind === "command" ? formatCommandParameterTokens(node, casing, globalLongOptionFlags) : [];
6635
- const name = parameterTokens.length === 0 ? baseName : `${baseName} ${parameterTokens.join(" ")}`;
6636
- return name;
6967
+ const nameTokens = [{ text: baseName, role: "command" }];
6968
+ const inlineWidthBudget = Math.max(
6969
+ 0,
6970
+ (process.stdout.columns ?? DEFAULT_HELP_TOTAL_WIDTH) - 2 - baseName.length
6971
+ );
6972
+ const parameterTokens = node.kind === "command" ? collapseOptionalParameterTokens(
6973
+ formatCommandParameterTokens(node, casing, globalLongOptionFlags),
6974
+ inlineWidthBudget
6975
+ ) : [];
6976
+ for (const token of parameterTokens) {
6977
+ nameTokens.push({ text: " ", role: "literal" }, ...token.tokens);
6978
+ }
6979
+ const name = parameterTokens.length === 0 ? baseName : `${baseName} ${parameterTokens.map((token) => token.text).join(" ")}`;
6980
+ return { name, nameTokens };
6637
6981
  }
6638
6982
  function formatCommandRows(group, scope, casing, globalLongOptionFlags, help) {
6639
- if (help === "concise") {
6640
- return getHelpChildren(group, scope).map((child) => ({
6641
- name: formatCommandRowName(child, casing, globalLongOptionFlags),
6642
- description: child.description ?? "",
6983
+ const toRow = (child, depth) => {
6984
+ const { name, nameTokens } = formatCommandRowNameTokens(child, casing, globalLongOptionFlags);
6985
+ return {
6986
+ name,
6987
+ nameTokens,
6988
+ description: suppressEchoHelpDescription(child.description ?? "", child.name),
6643
6989
  kind: child.kind,
6644
- depth: 0
6645
- }));
6990
+ depth
6991
+ };
6992
+ };
6993
+ if (help === "concise") {
6994
+ return getHelpChildren(group, scope).map((child) => toRow(child, 0));
6646
6995
  }
6647
6996
  const rows = [];
6648
6997
  const visit = (node, depth) => {
6649
6998
  for (const child of getHelpChildren(node, scope)) {
6650
- rows.push({
6651
- name: formatCommandRowName(child, casing, globalLongOptionFlags),
6652
- description: child.description ?? "",
6653
- kind: child.kind,
6654
- depth
6655
- });
6999
+ rows.push(toRow(child, depth));
6656
7000
  if (child.kind === "group") {
6657
7001
  visit(child, depth + 1);
6658
7002
  }
@@ -6678,10 +7022,10 @@ function formatGlobalOptionsLine(ctx) {
6678
7022
  if (ctx.showVersion) {
6679
7023
  flags.push("--version");
6680
7024
  }
6681
- return flags.length > 0 ? `${text.section("Options:")} ${flags.join(" ")}` : "";
7025
+ return flags.length > 0 ? `${text.section("Global Options:")} ${flags.join(" ")}` : "";
6682
7026
  }
6683
7027
  function formatLeafGlobalOptionsLine(ctx) {
6684
- return ctx.controls.verbose ? `${text.section("Options:")} -v, --verbose` : "";
7028
+ return ctx.controls.verbose ? `${text.section("Global Options:")} -v, --verbose` : "";
6685
7029
  }
6686
7030
  function collectSchemaGlobalFieldRows(group, scope, casing, globalLongOptionFlags) {
6687
7031
  const seen = /* @__PURE__ */ new Map();
@@ -6699,10 +7043,13 @@ function collectSchemaGlobalFieldRows(group, scope, casing, globalLongOptionFlag
6699
7043
  if (seen.has(dedupeKey)) {
6700
7044
  continue;
6701
7045
  }
6702
- seen.set(dedupeKey, {
6703
- flags: formatHelpFieldFlags(field, globalLongOptionFlags),
6704
- description: formatHelpFieldDescription(field)
6705
- });
7046
+ seen.set(
7047
+ dedupeKey,
7048
+ createHelpOptionRow(
7049
+ formatHelpFieldFlags(field, globalLongOptionFlags),
7050
+ formatHelpFieldDescription(field)
7051
+ )
7052
+ );
6706
7053
  }
6707
7054
  return;
6708
7055
  }
@@ -6722,6 +7069,18 @@ function formatHelpCommandList(rows) {
6722
7069
  function formatHelpOptionList(rows) {
6723
7070
  return process.stdout.isTTY !== true ? help_formatter_plain_exports.formatOptionList(rows) : formatOptionList(rows);
6724
7071
  }
7072
+ function sortLeafHelpOptionFields(fields) {
7073
+ const required = [];
7074
+ const optional = [];
7075
+ for (const field of fields) {
7076
+ if (!field.optional && !field.hasDefault) {
7077
+ required.push(field);
7078
+ continue;
7079
+ }
7080
+ optional.push(field);
7081
+ }
7082
+ return [...required, ...optional];
7083
+ }
6725
7084
  function buildUsageLine(breadcrumb, rootUsageName, suffix) {
6726
7085
  const visibleBreadcrumb = breadcrumb.filter((segment) => segment.length > 0);
6727
7086
  const usageBreadcrumb = breadcrumb[0] === "" ? [rootUsageName, ...visibleBreadcrumb] : visibleBreadcrumb;
@@ -6731,15 +7090,37 @@ function buildUsageLine(breadcrumb, rootUsageName, suffix) {
6731
7090
  }
6732
7091
  function formatGroupUsageSuffix(group, scope, casing, globalLongOptionFlags) {
6733
7092
  if (group.default !== void 0 && group.default.hidden === true && group.default.scope.includes(scope)) {
6734
- const parameterTokens = formatCommandParameterTokens(
6735
- group.default,
6736
- casing,
6737
- globalLongOptionFlags
7093
+ const parameterTokens = collapseOptionalParameterTokens(
7094
+ formatCommandParameterTokens(group.default, casing, globalLongOptionFlags)
6738
7095
  );
6739
- return ["[command]", "[OPTIONS]", ...parameterTokens].join(" ");
7096
+ return ["[command]", "[OPTIONS]", ...parameterTokens.map((token) => token.text)].join(" ");
6740
7097
  }
6741
7098
  return "[command] [OPTIONS]";
6742
7099
  }
7100
+ function formatHelpDrillDownFooter(rootUsageName) {
7101
+ return text.muted(`Run ${rootUsageName} <command> --help for full options.`);
7102
+ }
7103
+ function formatStyledUsageLine(usageLine) {
7104
+ const parts = usageLine.split(" ").filter((part) => part.length > 0);
7105
+ if (parts.length === 0) {
7106
+ return text.usageCommand(usageLine);
7107
+ }
7108
+ const commandEnd = parts.findIndex(
7109
+ (part) => part.startsWith("-") || part.startsWith("[") || part.startsWith("<")
7110
+ );
7111
+ const commandParts = commandEnd === -1 ? parts : parts.slice(0, commandEnd);
7112
+ const argParts = commandEnd === -1 ? [] : parts.slice(commandEnd);
7113
+ const command = commandParts.join(" ");
7114
+ if (argParts.length === 0) {
7115
+ return text.usageCommand(command);
7116
+ }
7117
+ return `${text.usageCommand(command)} ${renderHelpTokens(
7118
+ argParts.flatMap((part, index) => [
7119
+ ...index === 0 ? [] : [{ text: " ", role: "literal" }],
7120
+ ...tokenizeHelpFlags(part)
7121
+ ])
7122
+ )}`;
7123
+ }
6743
7124
  function renderGroupHelp(group, breadcrumb, scope, casing, globalOptions, rootUsageName, isRoot) {
6744
7125
  const sections = [];
6745
7126
  const globalLongOptionFlags = getGlobalLongOptionFlags(
@@ -6755,7 +7136,7 @@ function renderGroupHelp(group, breadcrumb, scope, casing, globalOptions, rootUs
6755
7136
  globalOptions.controls.help
6756
7137
  );
6757
7138
  if (commandRows.length > 0) {
6758
- sections.push(`${text.sectionHeader("Commands")}
7139
+ sections.push(`${text.section("Commands:")}
6759
7140
  ${formatHelpCommandList(commandRows)}`);
6760
7141
  }
6761
7142
  if (isRoot) {
@@ -6768,7 +7149,7 @@ ${formatHelpCommandList(commandRows)}`);
6768
7149
  const builtInLine = formatGlobalOptionsLine(globalOptions);
6769
7150
  if (schemaGlobalRows.length > 0) {
6770
7151
  sections.push(
6771
- `${text.sectionHeader("Options")}
7152
+ `${text.section("Options:")}
6772
7153
  ${formatHelpOptionList(schemaGlobalRows)}
6773
7154
  ${builtInLine}`
6774
7155
  );
@@ -6776,6 +7157,9 @@ ${builtInLine}`
6776
7157
  sections.push(builtInLine);
6777
7158
  }
6778
7159
  }
7160
+ if (commandRows.length > 0) {
7161
+ sections.push(formatHelpDrillDownFooter(rootUsageName));
7162
+ }
6779
7163
  return renderHelpDocument({
6780
7164
  breadcrumb,
6781
7165
  rootUsageName,
@@ -6798,12 +7182,21 @@ function renderLeafHelp(command, breadcrumb, casing, globalOptions, rootUsageNam
6798
7182
  );
6799
7183
  const collected = collectFields(command.params, casing, globalLongOptionFlags);
6800
7184
  const fields = assignPositionals(collected.fields, command.positional);
6801
- const optionRows = fields.filter((field) => field.global !== true).map((field) => ({
6802
- flags: formatHelpFieldFlags(field, globalLongOptionFlags),
6803
- description: formatHelpFieldDescription(field)
6804
- })).concat(collected.dynamicFields.flatMap((field) => formatDynamicHelpFields(field, casing)));
7185
+ const localFields = fields.filter((field) => field.global !== true);
7186
+ const toHelpRow = (field) => createHelpOptionRow(
7187
+ formatHelpFieldFlags(field, globalLongOptionFlags),
7188
+ formatHelpFieldDescription(field)
7189
+ );
7190
+ const argumentRows = localFields.filter((field) => field.positionalIndex !== void 0).map(toHelpRow);
7191
+ const optionRows = sortLeafHelpOptionFields(
7192
+ localFields.filter((field) => field.positionalIndex === void 0)
7193
+ ).map(toHelpRow).concat(collected.dynamicFields.flatMap((field) => formatDynamicHelpFields(field, casing)));
7194
+ if (argumentRows.length > 0) {
7195
+ sections.push(`${text.section("Arguments:")}
7196
+ ${formatHelpOptionList(argumentRows)}`);
7197
+ }
6805
7198
  if (optionRows.length > 0) {
6806
- sections.push(`${text.sectionHeader("Options")}
7199
+ sections.push(`${text.section("Options:")}
6807
7200
  ${formatHelpOptionList(optionRows)}`);
6808
7201
  }
6809
7202
  const builtInLine = formatLeafGlobalOptionsLine(globalOptions);
@@ -6813,13 +7206,13 @@ ${formatHelpOptionList(optionRows)}`);
6813
7206
  const secretRows = formatSecretRows(command.secrets);
6814
7207
  if (secretRows.length > 0) {
6815
7208
  sections.push(
6816
- `${text.sectionHeader("Secrets (environment)")}
7209
+ `${text.section("Secrets (environment):")}
6817
7210
  ${formatHelpOptionList(secretRows)}`
6818
7211
  );
6819
7212
  }
6820
7213
  if (command.examples.length > 0) {
6821
7214
  sections.push(
6822
- `${text.sectionHeader("Examples")}
7215
+ `${text.section("Examples:")}
6823
7216
  ${formatExampleRows(command.examples, breadcrumb, rootUsageName).join("\n")}`
6824
7217
  );
6825
7218
  }
@@ -6941,7 +7334,7 @@ function renderHelpDocument(input) {
6941
7334
  if (remainingDescription.length > 0) {
6942
7335
  lines.push(remainingDescription, "");
6943
7336
  }
6944
- lines.push(`Usage: ${text.usageCommand(input.usageLine)}`, "");
7337
+ lines.push(`Usage: ${formatStyledUsageLine(input.usageLine)}`, "");
6945
7338
  if (input.requiresAuth) {
6946
7339
  lines.push("Requires: authentication");
6947
7340
  }
@@ -7025,7 +7418,9 @@ function createNodeCommand(node, casing, globalLongOptionFlags, execute, presets
7025
7418
  }
7026
7419
  for (const field of fields) {
7027
7420
  if (field.positionalIndex !== void 0) {
7028
- command.argument(formatPositionalToken(field));
7421
+ command.argument(
7422
+ field.variadicPosition === true ? `[${field.displayPath}...]` : `[${field.displayPath}]`
7423
+ );
7029
7424
  continue;
7030
7425
  }
7031
7426
  for (const option of createOption(field, globalLongOptionFlags)) {
@@ -7860,11 +8255,11 @@ function writeRichHeader(title) {
7860
8255
  function isHumanInLoopPending(result) {
7861
8256
  return typeof result === "object" && result !== null && result.status === "pending-approval" && typeof result.approvalId === "string" && typeof result.message === "string" && typeof result.enqueuedAt === "string";
7862
8257
  }
7863
- function renderHumanInLoopPending(pending) {
8258
+ function renderHumanInLoopPending(pending, rootUsageName) {
7864
8259
  process.stdout.write(
7865
8260
  `\u2713 Queued for human approval (id: ${pending.approvalId})
7866
8261
  Message: ${pending.message}
7867
- Track: toolcraft approvals show ${pending.approvalId}
8262
+ Track: ${rootUsageName} approvals show --approval-id ${pending.approvalId}
7868
8263
  `
7869
8264
  );
7870
8265
  }
@@ -7968,7 +8363,7 @@ function parseOptionFieldValue(field, value, errors) {
7968
8363
  }
7969
8364
  return { ok: true, value: parsedValue };
7970
8365
  } catch (error3) {
7971
- if (error3 instanceof UserError || error3 instanceof InvalidArgumentError) {
8366
+ if (isUserError(error3) || error3 instanceof InvalidArgumentError) {
7972
8367
  errors.push({
7973
8368
  path: field.displayPath,
7974
8369
  message: error3.message
@@ -8550,7 +8945,7 @@ async function resolveParams(fields, dynamicFields, variants, positionalValues,
8550
8945
  }
8551
8946
  errors.push({
8552
8947
  path: field.displayPath,
8553
- message: `Missing required parameter "${field.displayPath}".`
8948
+ message: formatMissingParameterMessage(field)
8554
8949
  });
8555
8950
  continue;
8556
8951
  }
@@ -8601,7 +8996,7 @@ function getResolvedFlags(command) {
8601
8996
  const flags = command.optsWithGlobals();
8602
8997
  return flags;
8603
8998
  }
8604
- async function executeCommand(state, services, requirementOptions, runtimeFetch, humanInLoop, runtimeEnv, runtimeFs, outputEmitter, outputFormats, promptStreams, diagnosticsOptions, onErrorReportContext) {
8999
+ async function executeCommand(state, rootUsageName, services, requirementOptions, runtimeFetch, humanInLoop, runtimeEnv, runtimeFs, outputEmitter, outputFormats, promptStreams, diagnosticsOptions, onErrorReportContext) {
8605
9000
  const logger2 = createLogger(outputEmitter);
8606
9001
  const optionValues = state.actionCommand.optsWithGlobals();
8607
9002
  const resolvedFlags = optionValues;
@@ -8757,7 +9152,7 @@ async function executeCommand(state, services, requirementOptions, runtimeFetch,
8757
9152
  writeRichHeader(`${state.command.name} (fixture)`);
8758
9153
  }
8759
9154
  if (isHumanInLoopPending(result)) {
8760
- renderHumanInLoopPending(result);
9155
+ renderHumanInLoopPending(result, rootUsageName);
8761
9156
  return;
8762
9157
  }
8763
9158
  const renderStatus = renderCLIResult(
@@ -9000,7 +9395,7 @@ function renderHttpError(error3, options) {
9000
9395
  async function handleRunError(error3, options) {
9001
9396
  const logger2 = createLogger(options.outputEmitter);
9002
9397
  await withOutputFormat2(options.output, async () => {
9003
- if (error3 instanceof UserError) {
9398
+ if (isUserError(error3)) {
9004
9399
  renderCliErrorPattern(
9005
9400
  options.userErrorPattern === "definition" ? {
9006
9401
  kind: "definition",
@@ -9316,11 +9711,9 @@ function getDefaultCommanderCommandName(command) {
9316
9711
  function configureCommanderSuggestionOutput(command) {
9317
9712
  command.exitOverride();
9318
9713
  command.configureOutput({
9319
- outputError: (message2, write2) => {
9320
- if (message2.includes("unknown command") || message2.includes("unknown option")) {
9321
- return;
9322
- }
9323
- write2(message2);
9714
+ // Every Commander error throws through exitOverride and is rendered once by handleRunError
9715
+ // in the design-system error pattern; writing it here as well double-reports one mistake.
9716
+ outputError: () => {
9324
9717
  }
9325
9718
  });
9326
9719
  command.commands.forEach((child) => configureCommanderSuggestionOutput(child));
@@ -9393,6 +9786,7 @@ async function runCLI(roots, options = {}) {
9393
9786
  resolvedCommandPath = formatCliCommandPath(state.commandPath);
9394
9787
  await executeCommand(
9395
9788
  state,
9789
+ rootUsageName,
9396
9790
  servicesWithBuiltIns,
9397
9791
  requirementOptions,
9398
9792
  runtimeFetch,
@@ -11063,7 +11457,7 @@ var claudeCodeAgent = {
11063
11457
  id: "claude-code",
11064
11458
  name: "claude-code",
11065
11459
  label: "Claude Code",
11066
- summary: "Configure Claude Code to route through Poe.",
11460
+ summary: "Anthropic's agentic coding tool for the terminal.",
11067
11461
  aliases: ["claude"],
11068
11462
  binaryName: "claude",
11069
11463
  apiShapes: ["anthropic-messages"],
@@ -11073,6 +11467,7 @@ var claudeCodeAgent = {
11073
11467
  }
11074
11468
  },
11075
11469
  configPath: "~/.claude.json",
11470
+ capabilities: ["spawn", "configure", "install", "test", "skill", "mcp"],
11076
11471
  branding: {
11077
11472
  colors: {
11078
11473
  dark: "#C15F3C",
@@ -11093,6 +11488,7 @@ var claudeDesktopAgent = {
11093
11488
  linux: "~/.config/Claude/claude_desktop_config.json",
11094
11489
  win32: "~/AppData/Roaming/Claude/claude_desktop_config.json"
11095
11490
  },
11491
+ capabilities: ["mcp"],
11096
11492
  branding: {
11097
11493
  colors: {
11098
11494
  dark: "#D97757",
@@ -11106,7 +11502,7 @@ var codexAgent = {
11106
11502
  id: "codex",
11107
11503
  name: "codex",
11108
11504
  label: "Codex",
11109
- summary: "Configure Codex to use Poe as the model provider.",
11505
+ summary: "OpenAI's coding agent for the terminal.",
11110
11506
  binaryName: "codex",
11111
11507
  apiShapes: ["openai-responses"],
11112
11508
  otelCapture: {
@@ -11120,6 +11516,7 @@ var codexAgent = {
11120
11516
  ]
11121
11517
  },
11122
11518
  configPath: "~/.codex/config.toml",
11519
+ capabilities: ["spawn", "configure", "install", "test", "skill", "mcp"],
11123
11520
  branding: {
11124
11521
  colors: {
11125
11522
  dark: "#D5D9DF",
@@ -11137,6 +11534,7 @@ var cursorAgent = {
11137
11534
  summary: "Cursor's CLI coding agent.",
11138
11535
  binaryName: "cursor-agent",
11139
11536
  configPath: "~/.cursor/mcp.json",
11537
+ capabilities: ["spawn", "configure", "install", "test", "skill", "mcp"],
11140
11538
  branding: {
11141
11539
  colors: {
11142
11540
  dark: "#FFFFFF",
@@ -11151,10 +11549,11 @@ var geminiCliAgent = {
11151
11549
  name: "gemini-cli",
11152
11550
  aliases: ["gemini"],
11153
11551
  label: "Gemini CLI",
11154
- summary: "Configure Google's Gemini CLI to use a compatible Google generations API.",
11552
+ summary: "Google's open-source AI agent for the terminal.",
11155
11553
  binaryName: "gemini",
11156
11554
  configPath: "~/.gemini/settings.json",
11157
11555
  apiShapes: ["google-generations"],
11556
+ capabilities: ["spawn", "configure", "install", "test", "skill"],
11158
11557
  branding: {
11159
11558
  colors: {
11160
11559
  dark: "#8AB4F8",
@@ -11168,7 +11567,7 @@ var openCodeAgent = {
11168
11567
  id: "opencode",
11169
11568
  name: "opencode",
11170
11569
  label: "OpenCode CLI",
11171
- summary: "Configure OpenCode CLI to use the Poe API.",
11570
+ summary: "Open-source AI coding agent for the terminal.",
11172
11571
  binaryName: "opencode",
11173
11572
  apiShapes: ["openai-chat-completions"],
11174
11573
  otelCapture: {
@@ -11177,6 +11576,7 @@ var openCodeAgent = {
11177
11576
  }
11178
11577
  },
11179
11578
  configPath: "~/.config/opencode/opencode.json",
11579
+ capabilities: ["spawn", "configure", "install", "test", "skill", "mcp"],
11180
11580
  branding: {
11181
11581
  colors: {
11182
11582
  dark: "#4A4F55",
@@ -11190,11 +11590,12 @@ var kimiAgent = {
11190
11590
  id: "kimi",
11191
11591
  name: "kimi",
11192
11592
  label: "Kimi",
11193
- summary: "Configure Kimi CLI to use Poe API",
11593
+ summary: "Moonshot AI's coding agent for the terminal.",
11194
11594
  aliases: ["kimi-cli"],
11195
11595
  binaryName: "kimi",
11196
11596
  apiShapes: ["openai-chat-completions"],
11197
11597
  configPath: "~/.kimi/mcp.json",
11598
+ capabilities: ["spawn", "configure", "install", "test", "mcp"],
11198
11599
  branding: {
11199
11600
  colors: {
11200
11601
  dark: "#7B68EE",
@@ -11213,6 +11614,7 @@ var gooseAgent = {
11213
11614
  apiShapes: ["openai-chat-completions"],
11214
11615
  otelCapture: {},
11215
11616
  configPath: "~/.config/goose/config.yaml",
11617
+ capabilities: ["spawn", "configure", "install", "test", "skill", "mcp"],
11216
11618
  branding: {
11217
11619
  colors: {
11218
11620
  dark: "#FF6B35",
@@ -11227,8 +11629,9 @@ var piAgent = {
11227
11629
  name: "pi",
11228
11630
  aliases: ["pi-agent"],
11229
11631
  label: "Pi",
11230
- summary: "Pi coding agent (spawn-only; uses local Pi auth/settings).",
11632
+ summary: "Minimal AI coding agent for the terminal.",
11231
11633
  binaryName: "pi",
11634
+ capabilities: ["spawn"],
11232
11635
  branding: {
11233
11636
  colors: {
11234
11637
  dark: "#F2F2F2",
@@ -11245,6 +11648,7 @@ var poeAgentAgent = {
11245
11648
  summary: "Run one-shot prompts with the built-in Poe agent runtime.",
11246
11649
  apiShapes: ["openai-responses", "openai-chat-completions"],
11247
11650
  configPath: "~/.poe-code/config.json",
11651
+ capabilities: ["configure"],
11248
11652
  branding: {
11249
11653
  colors: {
11250
11654
  dark: "#A465F7",
@@ -11261,6 +11665,9 @@ function freezeAgent(agent) {
11261
11665
  if (agent.apiShapes !== void 0) {
11262
11666
  Object.freeze(agent.apiShapes);
11263
11667
  }
11668
+ if (agent.capabilities !== void 0) {
11669
+ Object.freeze(agent.capabilities);
11670
+ }
11264
11671
  if (agent.otelCapture?.env !== void 0) {
11265
11672
  Object.freeze(agent.otelCapture.env);
11266
11673
  }
@@ -11324,7 +11731,8 @@ var agentSkillConfigs = {
11324
11731
  },
11325
11732
  goose: {
11326
11733
  globalSkillDir: "~/.agents/skills",
11327
- localSkillDir: ".agents/skills"
11734
+ localSkillDir: ".agents/skills",
11735
+ dirNote: "Goose discovers skills from the shared .agents/skills convention, not a goose-specific directory."
11328
11736
  }
11329
11737
  };
11330
11738
  var supportedAgents = Object.freeze(Object.keys(agentSkillConfigs));
@@ -12698,6 +13106,16 @@ async function executeMutation(mutation, context, options) {
12698
13106
  }
12699
13107
  }
12700
13108
 
13109
+ // ../user-error/src/index.ts
13110
+ var UserError2 = class extends Error {
13111
+ hint;
13112
+ constructor(message2, options) {
13113
+ super(message2, options);
13114
+ this.name = "UserError";
13115
+ this.hint = options?.hint;
13116
+ }
13117
+ };
13118
+
12701
13119
  // ../agent-skill-config/src/error-codes.ts
12702
13120
  function hasOwnErrorCode4(error3, code) {
12703
13121
  return error3 instanceof Error && Object.prototype.hasOwnProperty.call(error3, "code") && error3.code === code;
@@ -12749,8 +13167,11 @@ async function installSkill(agentId, skill, options) {
12749
13167
  const skillFilePath = `${skillFolderPath}/SKILL.md`;
12750
13168
  const displayPath = `${scope === "global" ? config2.globalSkillDir : config2.localSkillDir}/${skill.name}/SKILL.md`;
12751
13169
  const absoluteSkillPath = `${scope === "global" ? options.homeDir : options.cwd}/${skillFilePath.slice(2)}`;
12752
- if (await pathExists2(options.fs, absoluteSkillPath)) {
12753
- throw new Error(`Skill already exists: ${displayPath}`);
13170
+ if (!options.force && await pathExists2(options.fs, absoluteSkillPath)) {
13171
+ throw new UserError2(
13172
+ `Skill already exists: ${displayPath}
13173
+ Re-run with --force to overwrite it, or remove it first.`
13174
+ );
12754
13175
  }
12755
13176
  await runMutations(
12756
13177
  [
@@ -14828,7 +15249,7 @@ function sleep2(ms) {
14828
15249
  // src/cli.ts
14829
15250
  configureTheme({ brand: "green", label: "Terminal Pilot" });
14830
15251
  function getBundledPackageVersion() {
14831
- return true ? "0.0.48" : void 0;
15252
+ return true ? "0.0.49" : void 0;
14832
15253
  }
14833
15254
  var pilotOptionsWithValues = /* @__PURE__ */ new Set([
14834
15255
  "--session",