@0xtiby/toby 0.0.1 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +338 -286
- package/package.json +8 -5
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli.tsx
|
|
4
4
|
import meow from "meow";
|
|
5
|
-
import { render, Text as
|
|
5
|
+
import { render, Text as Text13 } from "ink";
|
|
6
6
|
|
|
7
7
|
// src/commands/plan.tsx
|
|
8
8
|
import { useState as useState3, useEffect as useEffect2, useMemo as useMemo2 } from "react";
|
|
@@ -1523,14 +1523,72 @@ function Build(flags2) {
|
|
|
1523
1523
|
}
|
|
1524
1524
|
|
|
1525
1525
|
// src/commands/init.tsx
|
|
1526
|
-
import { useState as
|
|
1527
|
-
import { Text as
|
|
1526
|
+
import { useState as useState6, useEffect as useEffect5 } from "react";
|
|
1527
|
+
import { Text as Text6, Box as Box6, useApp as useApp2 } from "ink";
|
|
1528
1528
|
import SelectInput from "ink-select-input";
|
|
1529
1529
|
import TextInput from "ink-text-input";
|
|
1530
1530
|
import fs7 from "fs";
|
|
1531
1531
|
import path7 from "path";
|
|
1532
|
-
import { detectAll
|
|
1532
|
+
import { detectAll } from "@0xtiby/spawner";
|
|
1533
|
+
|
|
1534
|
+
// src/hooks/useModels.ts
|
|
1535
|
+
import { useState as useState5, useEffect as useEffect4 } from "react";
|
|
1536
|
+
import { listModels } from "@0xtiby/spawner";
|
|
1537
|
+
var DEFAULT_ITEM = { label: "default", value: "default" };
|
|
1538
|
+
function useModels(cli2, options = {}) {
|
|
1539
|
+
const { enabled = true } = options;
|
|
1540
|
+
const [items, setItems] = useState5([DEFAULT_ITEM]);
|
|
1541
|
+
const [loading, setLoading] = useState5(enabled);
|
|
1542
|
+
const [error, setError] = useState5(null);
|
|
1543
|
+
useEffect4(() => {
|
|
1544
|
+
if (!enabled) {
|
|
1545
|
+
setLoading(false);
|
|
1546
|
+
return;
|
|
1547
|
+
}
|
|
1548
|
+
let cancelled = false;
|
|
1549
|
+
setLoading(true);
|
|
1550
|
+
setError(null);
|
|
1551
|
+
listModels({ cli: cli2, fallback: true }).then((models) => {
|
|
1552
|
+
if (!cancelled) {
|
|
1553
|
+
const mapped = models.map((m) => ({
|
|
1554
|
+
label: `${m.name} (${m.id})`,
|
|
1555
|
+
value: m.id
|
|
1556
|
+
}));
|
|
1557
|
+
setItems([DEFAULT_ITEM, ...mapped]);
|
|
1558
|
+
}
|
|
1559
|
+
}).catch((err) => {
|
|
1560
|
+
if (!cancelled) {
|
|
1561
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1562
|
+
console.warn(`Failed to load models for ${cli2}: ${message}`);
|
|
1563
|
+
setError(message);
|
|
1564
|
+
setItems([DEFAULT_ITEM]);
|
|
1565
|
+
}
|
|
1566
|
+
}).finally(() => {
|
|
1567
|
+
if (!cancelled) setLoading(false);
|
|
1568
|
+
});
|
|
1569
|
+
return () => {
|
|
1570
|
+
cancelled = true;
|
|
1571
|
+
};
|
|
1572
|
+
}, [cli2, enabled]);
|
|
1573
|
+
return { items, loading, error };
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
// src/components/LoadingSpinner.tsx
|
|
1577
|
+
import { Text as Text5, Box as Box5 } from "ink";
|
|
1578
|
+
import Spinner from "ink-spinner";
|
|
1533
1579
|
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1580
|
+
function LoadingSpinner({ message = "Loading..." }) {
|
|
1581
|
+
return /* @__PURE__ */ jsxs4(Box5, { children: [
|
|
1582
|
+
/* @__PURE__ */ jsx5(Spinner, { type: "dots" }),
|
|
1583
|
+
/* @__PURE__ */ jsxs4(Text5, { children: [
|
|
1584
|
+
" ",
|
|
1585
|
+
message
|
|
1586
|
+
] })
|
|
1587
|
+
] });
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
// src/commands/init.tsx
|
|
1591
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1534
1592
|
function createProject(selections, cwd = process.cwd()) {
|
|
1535
1593
|
const localDir = getLocalDir(cwd);
|
|
1536
1594
|
const configPath = path7.join(localDir, CONFIG_FILE);
|
|
@@ -1589,15 +1647,15 @@ function getInstalledClis(result) {
|
|
|
1589
1647
|
return Object.entries(result).filter(([, info]) => info.installed).map(([name]) => name);
|
|
1590
1648
|
}
|
|
1591
1649
|
function CliTable({ clis }) {
|
|
1592
|
-
return /* @__PURE__ */
|
|
1593
|
-
/* @__PURE__ */
|
|
1650
|
+
return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", marginBottom: 1, children: [
|
|
1651
|
+
/* @__PURE__ */ jsx6(Text6, { bold: true, children: "Detected CLIs:" }),
|
|
1594
1652
|
Object.entries(clis).map(
|
|
1595
|
-
([name, info]) => /* @__PURE__ */
|
|
1653
|
+
([name, info]) => /* @__PURE__ */ jsxs5(Text6, { children: [
|
|
1596
1654
|
" ",
|
|
1597
|
-
info.installed ? /* @__PURE__ */
|
|
1655
|
+
info.installed ? /* @__PURE__ */ jsx6(Text6, { color: "green", children: "\u2713" }) : /* @__PURE__ */ jsx6(Text6, { color: "red", children: "\u2717" }),
|
|
1598
1656
|
" ",
|
|
1599
|
-
/* @__PURE__ */
|
|
1600
|
-
info.installed && /* @__PURE__ */
|
|
1657
|
+
/* @__PURE__ */ jsx6(Text6, { bold: true, children: name }),
|
|
1658
|
+
info.installed && /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
|
|
1601
1659
|
" ",
|
|
1602
1660
|
info.version,
|
|
1603
1661
|
info.authenticated ? " (authenticated)" : " (not authenticated)"
|
|
@@ -1606,13 +1664,6 @@ function CliTable({ clis }) {
|
|
|
1606
1664
|
)
|
|
1607
1665
|
] });
|
|
1608
1666
|
}
|
|
1609
|
-
function modelItems(cli2) {
|
|
1610
|
-
const models = getKnownModels(cli2);
|
|
1611
|
-
return [
|
|
1612
|
-
{ label: "default", value: "default" },
|
|
1613
|
-
...models.map((m) => ({ label: `${m.name} (${m.id})`, value: m.id }))
|
|
1614
|
-
];
|
|
1615
|
-
}
|
|
1616
1667
|
function hasAllInitFlags(flags2) {
|
|
1617
1668
|
return flags2.planCli !== void 0 && flags2.planModel !== void 0 && flags2.buildCli !== void 0 && flags2.buildModel !== void 0 && flags2.specsDir !== void 0;
|
|
1618
1669
|
}
|
|
@@ -1623,8 +1674,8 @@ function NonInteractiveInit({ flags: flags2 }) {
|
|
|
1623
1674
|
const invalidCli = [planCli, buildCli].find(
|
|
1624
1675
|
(cli2) => !CLI_NAMES.includes(cli2)
|
|
1625
1676
|
);
|
|
1626
|
-
const [status, setStatus] =
|
|
1627
|
-
|
|
1677
|
+
const [status, setStatus] = useState6(invalidCli ? { type: "invalid_cli", cli: invalidCli } : { type: "detecting" });
|
|
1678
|
+
useEffect5(() => {
|
|
1628
1679
|
if (invalidCli) {
|
|
1629
1680
|
process.exitCode = 1;
|
|
1630
1681
|
exit();
|
|
@@ -1661,23 +1712,23 @@ function NonInteractiveInit({ flags: flags2 }) {
|
|
|
1661
1712
|
});
|
|
1662
1713
|
}, []);
|
|
1663
1714
|
if (status.type === "invalid_cli") {
|
|
1664
|
-
return /* @__PURE__ */
|
|
1715
|
+
return /* @__PURE__ */ jsx6(Text6, { color: "red", children: `\u2717 Unknown CLI: ${status.cli}. Must be one of: ${CLI_NAMES.join(", ")}` });
|
|
1665
1716
|
}
|
|
1666
1717
|
if (status.type === "detecting") {
|
|
1667
|
-
return /* @__PURE__ */
|
|
1718
|
+
return /* @__PURE__ */ jsx6(Text6, { children: "Detecting installed CLIs..." });
|
|
1668
1719
|
}
|
|
1669
1720
|
if (status.type === "error") {
|
|
1670
|
-
return /* @__PURE__ */
|
|
1721
|
+
return /* @__PURE__ */ jsx6(Text6, { color: "red", children: `\u2717 ${status.message}` });
|
|
1671
1722
|
}
|
|
1672
1723
|
const { result, selections } = status;
|
|
1673
|
-
return /* @__PURE__ */
|
|
1674
|
-
/* @__PURE__ */
|
|
1675
|
-
/* @__PURE__ */
|
|
1724
|
+
return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
|
|
1725
|
+
/* @__PURE__ */ jsx6(Text6, { color: "green", bold: true, children: "\u2713 Project initialized!" }),
|
|
1726
|
+
/* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
|
|
1676
1727
|
" created ",
|
|
1677
1728
|
path7.relative(process.cwd(), result.configPath)
|
|
1678
1729
|
] }),
|
|
1679
|
-
result.statusCreated && /* @__PURE__ */
|
|
1680
|
-
result.specsDirCreated && /* @__PURE__ */
|
|
1730
|
+
result.statusCreated && /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: " created .toby/status.json" }),
|
|
1731
|
+
result.specsDirCreated && /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
|
|
1681
1732
|
" created ",
|
|
1682
1733
|
selections.specsDir,
|
|
1683
1734
|
"/"
|
|
@@ -1686,16 +1737,16 @@ function NonInteractiveInit({ flags: flags2 }) {
|
|
|
1686
1737
|
}
|
|
1687
1738
|
function Init(flags2) {
|
|
1688
1739
|
if (hasAllInitFlags(flags2)) {
|
|
1689
|
-
return /* @__PURE__ */
|
|
1740
|
+
return /* @__PURE__ */ jsx6(NonInteractiveInit, { flags: flags2 });
|
|
1690
1741
|
}
|
|
1691
|
-
return /* @__PURE__ */
|
|
1742
|
+
return /* @__PURE__ */ jsx6(InteractiveInit, { version: flags2.version });
|
|
1692
1743
|
}
|
|
1693
1744
|
function InteractiveInit({ version: version2 }) {
|
|
1694
1745
|
const { exit } = useApp2();
|
|
1695
|
-
const [phase, setPhase] =
|
|
1696
|
-
const [clis, setClis] =
|
|
1697
|
-
const [installedClis, setInstalledClis] =
|
|
1698
|
-
const [selections, setSelections] =
|
|
1746
|
+
const [phase, setPhase] = useState6("detecting");
|
|
1747
|
+
const [clis, setClis] = useState6(null);
|
|
1748
|
+
const [installedClis, setInstalledClis] = useState6([]);
|
|
1749
|
+
const [selections, setSelections] = useState6({
|
|
1699
1750
|
planCli: "claude",
|
|
1700
1751
|
planModel: "default",
|
|
1701
1752
|
buildCli: "claude",
|
|
@@ -1703,10 +1754,12 @@ function InteractiveInit({ version: version2 }) {
|
|
|
1703
1754
|
specsDir: DEFAULT_SPECS_DIR,
|
|
1704
1755
|
verbose: false
|
|
1705
1756
|
});
|
|
1706
|
-
const [specsDirInput, setSpecsDirInput] =
|
|
1707
|
-
const [result, setResult] =
|
|
1708
|
-
const [error, setError] =
|
|
1709
|
-
|
|
1757
|
+
const [specsDirInput, setSpecsDirInput] = useState6(DEFAULT_SPECS_DIR);
|
|
1758
|
+
const [result, setResult] = useState6(null);
|
|
1759
|
+
const [error, setError] = useState6(null);
|
|
1760
|
+
const planModels = useModels(selections.planCli, { enabled: phase === "plan_model" });
|
|
1761
|
+
const buildModels = useModels(selections.buildCli, { enabled: phase === "build_model" });
|
|
1762
|
+
useEffect5(() => {
|
|
1710
1763
|
if (phase !== "detecting") return;
|
|
1711
1764
|
detectAll().then((detectResult) => {
|
|
1712
1765
|
setClis(detectResult);
|
|
@@ -1765,66 +1818,68 @@ function InteractiveInit({ version: version2 }) {
|
|
|
1765
1818
|
});
|
|
1766
1819
|
}
|
|
1767
1820
|
if (phase === "detecting") {
|
|
1768
|
-
return /* @__PURE__ */
|
|
1821
|
+
return /* @__PURE__ */ jsx6(Text6, { children: "Detecting installed CLIs..." });
|
|
1769
1822
|
}
|
|
1770
1823
|
if (phase === "no_cli") {
|
|
1771
|
-
return /* @__PURE__ */
|
|
1772
|
-
clis && /* @__PURE__ */
|
|
1773
|
-
/* @__PURE__ */
|
|
1774
|
-
/* @__PURE__ */
|
|
1775
|
-
/* @__PURE__ */
|
|
1776
|
-
/* @__PURE__ */
|
|
1824
|
+
return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
|
|
1825
|
+
clis && /* @__PURE__ */ jsx6(CliTable, { clis }),
|
|
1826
|
+
/* @__PURE__ */ jsx6(Text6, { color: "red", bold: true, children: "No AI CLIs found. Install one of the following:" }),
|
|
1827
|
+
/* @__PURE__ */ jsx6(Text6, { children: " \u2022 claude \u2014 npm install -g @anthropic-ai/claude-code" }),
|
|
1828
|
+
/* @__PURE__ */ jsx6(Text6, { children: " \u2022 codex \u2014 npm install -g @openai/codex" }),
|
|
1829
|
+
/* @__PURE__ */ jsx6(Text6, { children: " \u2022 opencode \u2014 go install github.com/opencode-ai/opencode@latest" })
|
|
1777
1830
|
] });
|
|
1778
1831
|
}
|
|
1779
1832
|
const cliItems = installedClis.map((name) => ({
|
|
1780
1833
|
label: `${name} \u2014 ${clis?.[name]?.version ?? "unknown"}`,
|
|
1781
1834
|
value: name
|
|
1782
1835
|
}));
|
|
1783
|
-
return /* @__PURE__ */
|
|
1784
|
-
/* @__PURE__ */
|
|
1836
|
+
return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
|
|
1837
|
+
/* @__PURE__ */ jsx6(Text6, { bold: true, children: `toby v${version2} \u2014 project setup
|
|
1785
1838
|
` }),
|
|
1786
|
-
clis && /* @__PURE__ */
|
|
1787
|
-
phase === "plan_cli" && /* @__PURE__ */
|
|
1788
|
-
/* @__PURE__ */
|
|
1789
|
-
/* @__PURE__ */
|
|
1839
|
+
clis && /* @__PURE__ */ jsx6(CliTable, { clis }),
|
|
1840
|
+
phase === "plan_cli" && /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
|
|
1841
|
+
/* @__PURE__ */ jsx6(Text6, { bold: true, children: "Select CLI for planning:" }),
|
|
1842
|
+
/* @__PURE__ */ jsx6(SelectInput, { items: cliItems, onSelect: handlePlanCliSelect })
|
|
1790
1843
|
] }),
|
|
1791
|
-
phase === "plan_model" && /* @__PURE__ */
|
|
1792
|
-
|
|
1844
|
+
phase === "plan_model" && planModels.loading && /* @__PURE__ */ jsx6(LoadingSpinner, { message: "Loading models..." }),
|
|
1845
|
+
phase === "plan_model" && !planModels.loading && /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
|
|
1846
|
+
/* @__PURE__ */ jsxs5(Text6, { bold: true, children: [
|
|
1793
1847
|
"Select model for planning (",
|
|
1794
1848
|
selections.planCli,
|
|
1795
1849
|
"):"
|
|
1796
1850
|
] }),
|
|
1797
|
-
/* @__PURE__ */
|
|
1851
|
+
/* @__PURE__ */ jsx6(
|
|
1798
1852
|
SelectInput,
|
|
1799
1853
|
{
|
|
1800
|
-
items:
|
|
1854
|
+
items: planModels.items,
|
|
1801
1855
|
onSelect: handlePlanModelSelect
|
|
1802
1856
|
}
|
|
1803
1857
|
)
|
|
1804
1858
|
] }),
|
|
1805
|
-
phase === "build_cli" && /* @__PURE__ */
|
|
1806
|
-
/* @__PURE__ */
|
|
1807
|
-
/* @__PURE__ */
|
|
1859
|
+
phase === "build_cli" && /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
|
|
1860
|
+
/* @__PURE__ */ jsx6(Text6, { bold: true, children: "Select CLI for building:" }),
|
|
1861
|
+
/* @__PURE__ */ jsx6(SelectInput, { items: cliItems, onSelect: handleBuildCliSelect })
|
|
1808
1862
|
] }),
|
|
1809
|
-
phase === "build_model" && /* @__PURE__ */
|
|
1810
|
-
|
|
1863
|
+
phase === "build_model" && buildModels.loading && /* @__PURE__ */ jsx6(LoadingSpinner, { message: "Loading models..." }),
|
|
1864
|
+
phase === "build_model" && !buildModels.loading && /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
|
|
1865
|
+
/* @__PURE__ */ jsxs5(Text6, { bold: true, children: [
|
|
1811
1866
|
"Select model for building (",
|
|
1812
1867
|
selections.buildCli,
|
|
1813
1868
|
"):"
|
|
1814
1869
|
] }),
|
|
1815
|
-
/* @__PURE__ */
|
|
1870
|
+
/* @__PURE__ */ jsx6(
|
|
1816
1871
|
SelectInput,
|
|
1817
1872
|
{
|
|
1818
|
-
items:
|
|
1873
|
+
items: buildModels.items,
|
|
1819
1874
|
onSelect: handleBuildModelSelect
|
|
1820
1875
|
}
|
|
1821
1876
|
)
|
|
1822
1877
|
] }),
|
|
1823
|
-
phase === "specs_dir" && /* @__PURE__ */
|
|
1824
|
-
/* @__PURE__ */
|
|
1825
|
-
/* @__PURE__ */
|
|
1826
|
-
/* @__PURE__ */
|
|
1827
|
-
/* @__PURE__ */
|
|
1878
|
+
phase === "specs_dir" && /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
|
|
1879
|
+
/* @__PURE__ */ jsx6(Text6, { bold: true, children: "Specs directory:" }),
|
|
1880
|
+
/* @__PURE__ */ jsxs5(Box6, { children: [
|
|
1881
|
+
/* @__PURE__ */ jsx6(Text6, { children: " > " }),
|
|
1882
|
+
/* @__PURE__ */ jsx6(
|
|
1828
1883
|
TextInput,
|
|
1829
1884
|
{
|
|
1830
1885
|
value: specsDirInput,
|
|
@@ -1834,10 +1889,10 @@ function InteractiveInit({ version: version2 }) {
|
|
|
1834
1889
|
)
|
|
1835
1890
|
] })
|
|
1836
1891
|
] }),
|
|
1837
|
-
phase === "verbose" && /* @__PURE__ */
|
|
1838
|
-
/* @__PURE__ */
|
|
1839
|
-
/* @__PURE__ */
|
|
1840
|
-
/* @__PURE__ */
|
|
1892
|
+
phase === "verbose" && /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
|
|
1893
|
+
/* @__PURE__ */ jsx6(Text6, { bold: true, children: "Verbose output:" }),
|
|
1894
|
+
/* @__PURE__ */ jsx6(Text6, { dimColor: true, children: " Show full CLI output including tool use and system events" }),
|
|
1895
|
+
/* @__PURE__ */ jsx6(
|
|
1841
1896
|
SelectInput,
|
|
1842
1897
|
{
|
|
1843
1898
|
items: [
|
|
@@ -1848,38 +1903,38 @@ function InteractiveInit({ version: version2 }) {
|
|
|
1848
1903
|
}
|
|
1849
1904
|
)
|
|
1850
1905
|
] }),
|
|
1851
|
-
phase === "done" && error && /* @__PURE__ */
|
|
1852
|
-
/* @__PURE__ */
|
|
1853
|
-
/* @__PURE__ */
|
|
1906
|
+
phase === "done" && error && /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", marginTop: 1, children: [
|
|
1907
|
+
/* @__PURE__ */ jsx6(Text6, { color: "red", bold: true, children: "\u2717 Initialization failed" }),
|
|
1908
|
+
/* @__PURE__ */ jsx6(Text6, { color: "red", children: ` ${error}` })
|
|
1854
1909
|
] }),
|
|
1855
|
-
phase === "done" && result && /* @__PURE__ */
|
|
1856
|
-
/* @__PURE__ */
|
|
1857
|
-
/* @__PURE__ */
|
|
1858
|
-
/* @__PURE__ */
|
|
1910
|
+
phase === "done" && result && /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", marginTop: 1, children: [
|
|
1911
|
+
/* @__PURE__ */ jsx6(Text6, { color: "green", bold: true, children: "\u2713 Project initialized!" }),
|
|
1912
|
+
/* @__PURE__ */ jsx6(Text6, { children: "" }),
|
|
1913
|
+
/* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
|
|
1859
1914
|
" created ",
|
|
1860
1915
|
path7.relative(process.cwd(), result.configPath)
|
|
1861
1916
|
] }),
|
|
1862
|
-
result.statusCreated && /* @__PURE__ */
|
|
1863
|
-
result.specsDirCreated && /* @__PURE__ */
|
|
1917
|
+
result.statusCreated && /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: " created .toby/status.json" }),
|
|
1918
|
+
result.specsDirCreated && /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
|
|
1864
1919
|
" created ",
|
|
1865
1920
|
selections.specsDir,
|
|
1866
1921
|
"/"
|
|
1867
1922
|
] }),
|
|
1868
|
-
/* @__PURE__ */
|
|
1869
|
-
/* @__PURE__ */
|
|
1870
|
-
/* @__PURE__ */
|
|
1923
|
+
/* @__PURE__ */ jsx6(Text6, { children: "" }),
|
|
1924
|
+
/* @__PURE__ */ jsx6(Text6, { bold: true, children: "Next steps:" }),
|
|
1925
|
+
/* @__PURE__ */ jsxs5(Text6, { children: [
|
|
1871
1926
|
" 1. Add spec files to ",
|
|
1872
1927
|
selections.specsDir,
|
|
1873
1928
|
"/"
|
|
1874
1929
|
] }),
|
|
1875
|
-
/* @__PURE__ */
|
|
1930
|
+
/* @__PURE__ */ jsxs5(Text6, { children: [
|
|
1876
1931
|
" 2. Run ",
|
|
1877
|
-
/* @__PURE__ */
|
|
1932
|
+
/* @__PURE__ */ jsx6(Text6, { color: "cyan", children: "toby plan" }),
|
|
1878
1933
|
" to plan a spec"
|
|
1879
1934
|
] }),
|
|
1880
|
-
/* @__PURE__ */
|
|
1935
|
+
/* @__PURE__ */ jsxs5(Text6, { children: [
|
|
1881
1936
|
" 3. Run ",
|
|
1882
|
-
/* @__PURE__ */
|
|
1937
|
+
/* @__PURE__ */ jsx6(Text6, { color: "cyan", children: "toby build" }),
|
|
1883
1938
|
" to build tasks"
|
|
1884
1939
|
] })
|
|
1885
1940
|
] })
|
|
@@ -1887,9 +1942,9 @@ function InteractiveInit({ version: version2 }) {
|
|
|
1887
1942
|
}
|
|
1888
1943
|
|
|
1889
1944
|
// src/commands/status.tsx
|
|
1890
|
-
import { Text as
|
|
1945
|
+
import { Text as Text7, Box as Box7 } from "ink";
|
|
1891
1946
|
import fs8 from "fs";
|
|
1892
|
-
import { jsx as
|
|
1947
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1893
1948
|
function formatDuration(startedAt, completedAt) {
|
|
1894
1949
|
if (!completedAt) return "\u2014";
|
|
1895
1950
|
const ms = new Date(completedAt).getTime() - new Date(startedAt).getTime();
|
|
@@ -1937,15 +1992,15 @@ function StatusTable({ rows }) {
|
|
|
1937
1992
|
};
|
|
1938
1993
|
const separator = `${"\u2500".repeat(colWidths.name + 2)}\u253C${"\u2500".repeat(colWidths.status + 2)}\u253C${"\u2500".repeat(colWidths.iterations + 2)}\u253C${"\u2500".repeat(colWidths.tokens + 2)}`;
|
|
1939
1994
|
const headerLine = ` ${pad(headers.name, colWidths.name)} \u2502 ${pad(headers.status, colWidths.status)} \u2502 ${pad(headers.iterations, colWidths.iterations)} \u2502 ${pad(headers.tokens, colWidths.tokens)} `;
|
|
1940
|
-
return /* @__PURE__ */
|
|
1941
|
-
/* @__PURE__ */
|
|
1942
|
-
/* @__PURE__ */
|
|
1943
|
-
rows.map((row) => /* @__PURE__ */
|
|
1995
|
+
return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", children: [
|
|
1996
|
+
/* @__PURE__ */ jsx7(Text7, { bold: true, children: headerLine }),
|
|
1997
|
+
/* @__PURE__ */ jsx7(Text7, { dimColor: true, children: separator }),
|
|
1998
|
+
rows.map((row) => /* @__PURE__ */ jsx7(Text7, { children: ` ${pad(row.name, colWidths.name)} \u2502 ${pad(row.status, colWidths.status)} \u2502 ${pad(String(row.iterations), colWidths.iterations)} \u2502 ${pad(String(row.tokens), colWidths.tokens)} ` }, row.name))
|
|
1944
1999
|
] });
|
|
1945
2000
|
}
|
|
1946
2001
|
function IterationTable({ rows }) {
|
|
1947
2002
|
if (rows.length === 0) {
|
|
1948
|
-
return /* @__PURE__ */
|
|
2003
|
+
return /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "No iterations yet" });
|
|
1949
2004
|
}
|
|
1950
2005
|
const headers = { index: "#", type: "Type", cli: "CLI", tokens: "Tokens", duration: "Duration", exitCode: "Exit" };
|
|
1951
2006
|
const w = {
|
|
@@ -1958,10 +2013,10 @@ function IterationTable({ rows }) {
|
|
|
1958
2013
|
};
|
|
1959
2014
|
const separator = `${"\u2500".repeat(w.index + 2)}\u253C${"\u2500".repeat(w.type + 2)}\u253C${"\u2500".repeat(w.cli + 2)}\u253C${"\u2500".repeat(w.tokens + 2)}\u253C${"\u2500".repeat(w.duration + 2)}\u253C${"\u2500".repeat(w.exitCode + 2)}`;
|
|
1960
2015
|
const headerLine = ` ${pad(headers.index, w.index)} \u2502 ${pad(headers.type, w.type)} \u2502 ${pad(headers.cli, w.cli)} \u2502 ${pad(headers.tokens, w.tokens)} \u2502 ${pad(headers.duration, w.duration)} \u2502 ${pad(headers.exitCode, w.exitCode)} `;
|
|
1961
|
-
return /* @__PURE__ */
|
|
1962
|
-
/* @__PURE__ */
|
|
1963
|
-
/* @__PURE__ */
|
|
1964
|
-
rows.map((row) => /* @__PURE__ */
|
|
2016
|
+
return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", children: [
|
|
2017
|
+
/* @__PURE__ */ jsx7(Text7, { bold: true, children: headerLine }),
|
|
2018
|
+
/* @__PURE__ */ jsx7(Text7, { dimColor: true, children: separator }),
|
|
2019
|
+
rows.map((row) => /* @__PURE__ */ jsx7(Text7, { children: ` ${pad(row.index, w.index)} \u2502 ${pad(row.type, w.type)} \u2502 ${pad(row.cli, w.cli)} \u2502 ${pad(row.tokens, w.tokens)} \u2502 ${pad(row.duration, w.duration)} \u2502 ${pad(row.exitCode, w.exitCode)} ` }, row.index))
|
|
1965
2020
|
] });
|
|
1966
2021
|
}
|
|
1967
2022
|
function DetailedView({ specName, cwd }) {
|
|
@@ -1969,7 +2024,7 @@ function DetailedView({ specName, cwd }) {
|
|
|
1969
2024
|
const specs = discoverSpecs(cwd, config);
|
|
1970
2025
|
const spec = findSpec(specs, specName);
|
|
1971
2026
|
if (!spec) {
|
|
1972
|
-
return /* @__PURE__ */
|
|
2027
|
+
return /* @__PURE__ */ jsxs6(Text7, { color: "red", children: [
|
|
1973
2028
|
"Spec not found: ",
|
|
1974
2029
|
specName
|
|
1975
2030
|
] });
|
|
@@ -1995,21 +2050,21 @@ function DetailedView({ specName, cwd }) {
|
|
|
1995
2050
|
(sum, iter) => sum + (iter.tokensUsed ?? 0),
|
|
1996
2051
|
0
|
|
1997
2052
|
);
|
|
1998
|
-
return /* @__PURE__ */
|
|
1999
|
-
statusWarning && /* @__PURE__ */
|
|
2000
|
-
/* @__PURE__ */
|
|
2001
|
-
/* @__PURE__ */
|
|
2053
|
+
return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", children: [
|
|
2054
|
+
statusWarning && /* @__PURE__ */ jsx7(Text7, { color: "yellow", children: statusWarning }),
|
|
2055
|
+
/* @__PURE__ */ jsx7(Text7, { bold: true, children: spec.name }),
|
|
2056
|
+
/* @__PURE__ */ jsxs6(Text7, { children: [
|
|
2002
2057
|
"Status: ",
|
|
2003
2058
|
entry.status
|
|
2004
2059
|
] }),
|
|
2005
|
-
/* @__PURE__ */
|
|
2006
|
-
/* @__PURE__ */
|
|
2007
|
-
/* @__PURE__ */
|
|
2008
|
-
/* @__PURE__ */
|
|
2060
|
+
/* @__PURE__ */ jsx7(Text7, { children: "" }),
|
|
2061
|
+
/* @__PURE__ */ jsx7(IterationTable, { rows: iterationRows }),
|
|
2062
|
+
/* @__PURE__ */ jsx7(Text7, { children: "" }),
|
|
2063
|
+
/* @__PURE__ */ jsxs6(Text7, { children: [
|
|
2009
2064
|
"Iterations: ",
|
|
2010
2065
|
entry.iterations.length
|
|
2011
2066
|
] }),
|
|
2012
|
-
/* @__PURE__ */
|
|
2067
|
+
/* @__PURE__ */ jsxs6(Text7, { children: [
|
|
2013
2068
|
"Tokens used: ",
|
|
2014
2069
|
totalTokens
|
|
2015
2070
|
] })
|
|
@@ -2019,43 +2074,43 @@ function Status({ spec, version: version2 }) {
|
|
|
2019
2074
|
const cwd = process.cwd();
|
|
2020
2075
|
const localDir = getLocalDir(cwd);
|
|
2021
2076
|
if (!fs8.existsSync(localDir)) {
|
|
2022
|
-
return /* @__PURE__ */
|
|
2023
|
-
/* @__PURE__ */
|
|
2024
|
-
/* @__PURE__ */
|
|
2077
|
+
return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", children: [
|
|
2078
|
+
/* @__PURE__ */ jsx7(Text7, { color: "red", bold: true, children: "Toby not initialized" }),
|
|
2079
|
+
/* @__PURE__ */ jsxs6(Text7, { children: [
|
|
2025
2080
|
"Run ",
|
|
2026
|
-
/* @__PURE__ */
|
|
2081
|
+
/* @__PURE__ */ jsx7(Text7, { color: "cyan", children: "toby init" }),
|
|
2027
2082
|
" to set up your project."
|
|
2028
2083
|
] })
|
|
2029
2084
|
] });
|
|
2030
2085
|
}
|
|
2031
2086
|
if (spec) {
|
|
2032
|
-
return /* @__PURE__ */
|
|
2087
|
+
return /* @__PURE__ */ jsx7(DetailedView, { specName: spec, cwd });
|
|
2033
2088
|
}
|
|
2034
2089
|
const { rows, warnings } = buildRows(cwd);
|
|
2035
2090
|
if (rows.length === 0) {
|
|
2036
|
-
return /* @__PURE__ */
|
|
2037
|
-
/* @__PURE__ */
|
|
2038
|
-
warnings.map((w) => /* @__PURE__ */
|
|
2039
|
-
/* @__PURE__ */
|
|
2091
|
+
return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", children: [
|
|
2092
|
+
/* @__PURE__ */ jsx7(Text7, { children: `toby v${version2}` }),
|
|
2093
|
+
warnings.map((w) => /* @__PURE__ */ jsx7(Text7, { color: "yellow", children: w }, w)),
|
|
2094
|
+
/* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "No specs found. Add .md files to your specs directory." })
|
|
2040
2095
|
] });
|
|
2041
2096
|
}
|
|
2042
|
-
return /* @__PURE__ */
|
|
2043
|
-
/* @__PURE__ */
|
|
2044
|
-
warnings.map((w) => /* @__PURE__ */
|
|
2045
|
-
/* @__PURE__ */
|
|
2046
|
-
/* @__PURE__ */
|
|
2097
|
+
return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", children: [
|
|
2098
|
+
/* @__PURE__ */ jsx7(Text7, { children: `toby v${version2}` }),
|
|
2099
|
+
warnings.map((w) => /* @__PURE__ */ jsx7(Text7, { color: "yellow", children: w }, w)),
|
|
2100
|
+
/* @__PURE__ */ jsx7(Text7, { children: "" }),
|
|
2101
|
+
/* @__PURE__ */ jsx7(StatusTable, { rows })
|
|
2047
2102
|
] });
|
|
2048
2103
|
}
|
|
2049
2104
|
|
|
2050
2105
|
// src/commands/config.tsx
|
|
2051
|
-
import { useState as
|
|
2052
|
-
import { Text as
|
|
2106
|
+
import { useState as useState7, useEffect as useEffect6 } from "react";
|
|
2107
|
+
import { Text as Text8, Box as Box8, useApp as useApp3 } from "ink";
|
|
2053
2108
|
import SelectInput2 from "ink-select-input";
|
|
2054
2109
|
import TextInput2 from "ink-text-input";
|
|
2055
2110
|
import fs9 from "fs";
|
|
2056
2111
|
import path8 from "path";
|
|
2057
|
-
import { detectAll as detectAll2
|
|
2058
|
-
import { Fragment as Fragment2, jsx as
|
|
2112
|
+
import { detectAll as detectAll2 } from "@0xtiby/spawner";
|
|
2113
|
+
import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2059
2114
|
var VALID_KEYS = {
|
|
2060
2115
|
"plan.cli": "string",
|
|
2061
2116
|
"plan.model": "string",
|
|
@@ -2122,28 +2177,28 @@ function readMergeWriteConfig(mutations) {
|
|
|
2122
2177
|
}
|
|
2123
2178
|
function ConfigGet({ configKey }) {
|
|
2124
2179
|
if (!(configKey in VALID_KEYS)) {
|
|
2125
|
-
return /* @__PURE__ */
|
|
2180
|
+
return /* @__PURE__ */ jsx8(Text8, { color: "red", children: `Unknown config key: ${configKey}
|
|
2126
2181
|
Valid keys: ${Object.keys(VALID_KEYS).join(", ")}` });
|
|
2127
2182
|
}
|
|
2128
2183
|
const cwd = process.cwd();
|
|
2129
2184
|
const localDir = getLocalDir(cwd);
|
|
2130
2185
|
if (!fs9.existsSync(localDir)) {
|
|
2131
|
-
return /* @__PURE__ */
|
|
2132
|
-
/* @__PURE__ */
|
|
2133
|
-
/* @__PURE__ */
|
|
2186
|
+
return /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", children: [
|
|
2187
|
+
/* @__PURE__ */ jsx8(Text8, { color: "red", bold: true, children: "No config found" }),
|
|
2188
|
+
/* @__PURE__ */ jsxs7(Text8, { children: [
|
|
2134
2189
|
"Run ",
|
|
2135
|
-
/* @__PURE__ */
|
|
2190
|
+
/* @__PURE__ */ jsx8(Text8, { color: "cyan", children: "toby init" }),
|
|
2136
2191
|
" to set up your project."
|
|
2137
2192
|
] })
|
|
2138
2193
|
] });
|
|
2139
2194
|
}
|
|
2140
2195
|
const config = loadConfig();
|
|
2141
2196
|
const value = getNestedValue(config, configKey);
|
|
2142
|
-
return /* @__PURE__ */
|
|
2197
|
+
return /* @__PURE__ */ jsx8(Text8, { children: String(value) });
|
|
2143
2198
|
}
|
|
2144
2199
|
function ConfigSet({ configKey, value }) {
|
|
2145
2200
|
if (!(configKey in VALID_KEYS)) {
|
|
2146
|
-
return /* @__PURE__ */
|
|
2201
|
+
return /* @__PURE__ */ jsx8(Text8, { color: "red", children: `Unknown config key: ${configKey}
|
|
2147
2202
|
Valid keys: ${Object.keys(VALID_KEYS).join(", ")}` });
|
|
2148
2203
|
}
|
|
2149
2204
|
const type = VALID_KEYS[configKey];
|
|
@@ -2151,7 +2206,7 @@ Valid keys: ${Object.keys(VALID_KEYS).join(", ")}` });
|
|
|
2151
2206
|
try {
|
|
2152
2207
|
parsed = parseValue(value, type);
|
|
2153
2208
|
} catch (err) {
|
|
2154
|
-
return /* @__PURE__ */
|
|
2209
|
+
return /* @__PURE__ */ jsx8(Text8, { color: "red", children: `Invalid value for ${configKey}: ${err.message}` });
|
|
2155
2210
|
}
|
|
2156
2211
|
const partial = {};
|
|
2157
2212
|
setNestedValue(partial, configKey, parsed);
|
|
@@ -2159,23 +2214,16 @@ Valid keys: ${Object.keys(VALID_KEYS).join(", ")}` });
|
|
|
2159
2214
|
ConfigSchema.parse({ ...partial });
|
|
2160
2215
|
} catch (err) {
|
|
2161
2216
|
const msg = err instanceof Error ? err.message : String(err);
|
|
2162
|
-
return /* @__PURE__ */
|
|
2217
|
+
return /* @__PURE__ */ jsx8(Text8, { color: "red", children: `Validation error for ${configKey}: ${msg}` });
|
|
2163
2218
|
}
|
|
2164
2219
|
try {
|
|
2165
2220
|
readMergeWriteConfig([{ key: configKey, value: parsed }]);
|
|
2166
2221
|
} catch (err) {
|
|
2167
2222
|
const code = err.code;
|
|
2168
2223
|
const msg = code === "EACCES" ? `Permission denied writing to ${path8.join(getLocalDir(process.cwd()), CONFIG_FILE)}` : `Failed to write config: ${err.message}`;
|
|
2169
|
-
return /* @__PURE__ */
|
|
2224
|
+
return /* @__PURE__ */ jsx8(Text8, { color: "red", children: msg });
|
|
2170
2225
|
}
|
|
2171
|
-
return /* @__PURE__ */
|
|
2172
|
-
}
|
|
2173
|
-
function modelItems2(cli2) {
|
|
2174
|
-
const models = getKnownModels2(cli2);
|
|
2175
|
-
return [
|
|
2176
|
-
{ label: "default", value: "default" },
|
|
2177
|
-
...models.map((m) => ({ label: `${m.name} (${m.id})`, value: m.id }))
|
|
2178
|
-
];
|
|
2226
|
+
return /* @__PURE__ */ jsx8(Text8, { color: "green", children: `Set ${configKey} = ${String(parsed)}` });
|
|
2179
2227
|
}
|
|
2180
2228
|
function configToEditorValues(config) {
|
|
2181
2229
|
return {
|
|
@@ -2222,9 +2270,9 @@ function pastPhase(current, target) {
|
|
|
2222
2270
|
return PHASE_ORDER[current] > PHASE_ORDER[target];
|
|
2223
2271
|
}
|
|
2224
2272
|
function CompletedField({ label, value }) {
|
|
2225
|
-
return /* @__PURE__ */
|
|
2273
|
+
return /* @__PURE__ */ jsxs7(Text8, { children: [
|
|
2226
2274
|
" ",
|
|
2227
|
-
/* @__PURE__ */
|
|
2275
|
+
/* @__PURE__ */ jsxs7(Text8, { dimColor: true, children: [
|
|
2228
2276
|
label,
|
|
2229
2277
|
":"
|
|
2230
2278
|
] }),
|
|
@@ -2234,9 +2282,9 @@ function CompletedField({ label, value }) {
|
|
|
2234
2282
|
}
|
|
2235
2283
|
function ConfigEditor({ version: version2 }) {
|
|
2236
2284
|
const { exit } = useApp3();
|
|
2237
|
-
const [phase, setPhase] =
|
|
2238
|
-
const [installedClis, setInstalledClis] =
|
|
2239
|
-
const [values, setValues] =
|
|
2285
|
+
const [phase, setPhase] = useState7("loading");
|
|
2286
|
+
const [installedClis, setInstalledClis] = useState7([]);
|
|
2287
|
+
const [values, setValues] = useState7({
|
|
2240
2288
|
planCli: "claude",
|
|
2241
2289
|
planModel: "default",
|
|
2242
2290
|
planIterations: 2,
|
|
@@ -2246,10 +2294,12 @@ function ConfigEditor({ version: version2 }) {
|
|
|
2246
2294
|
specsDir: "specs",
|
|
2247
2295
|
verbose: false
|
|
2248
2296
|
});
|
|
2249
|
-
const [iterInput, setIterInput] =
|
|
2250
|
-
const [specsDirInput, setSpecsDirInput] =
|
|
2251
|
-
const [saveError, setSaveError] =
|
|
2252
|
-
|
|
2297
|
+
const [iterInput, setIterInput] = useState7("");
|
|
2298
|
+
const [specsDirInput, setSpecsDirInput] = useState7("");
|
|
2299
|
+
const [saveError, setSaveError] = useState7(null);
|
|
2300
|
+
const planModels = useModels(values.planCli, { enabled: phase === "plan_model" });
|
|
2301
|
+
const buildModels = useModels(values.buildCli, { enabled: phase === "build_model" });
|
|
2302
|
+
useEffect6(() => {
|
|
2253
2303
|
if (phase !== "loading") return;
|
|
2254
2304
|
const config = loadConfig();
|
|
2255
2305
|
const initial = configToEditorValues(config);
|
|
@@ -2288,17 +2338,17 @@ function ConfigEditor({ version: version2 }) {
|
|
|
2288
2338
|
exit();
|
|
2289
2339
|
}
|
|
2290
2340
|
if (phase === "loading") {
|
|
2291
|
-
return /* @__PURE__ */
|
|
2341
|
+
return /* @__PURE__ */ jsx8(Text8, { children: "Loading configuration..." });
|
|
2292
2342
|
}
|
|
2293
2343
|
const planCliItems = cliItems();
|
|
2294
2344
|
const buildCliItems = cliItems();
|
|
2295
|
-
return /* @__PURE__ */
|
|
2296
|
-
/* @__PURE__ */
|
|
2345
|
+
return /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", children: [
|
|
2346
|
+
/* @__PURE__ */ jsx8(Text8, { bold: true, children: `toby v${version2} \u2014 config editor
|
|
2297
2347
|
` }),
|
|
2298
|
-
/* @__PURE__ */
|
|
2299
|
-
phase === "plan_cli" && /* @__PURE__ */
|
|
2300
|
-
/* @__PURE__ */
|
|
2301
|
-
/* @__PURE__ */
|
|
2348
|
+
/* @__PURE__ */ jsx8(Text8, { bold: true, color: "cyan", children: "Plan" }),
|
|
2349
|
+
phase === "plan_cli" && /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", children: [
|
|
2350
|
+
/* @__PURE__ */ jsx8(Text8, { children: " cli:" }),
|
|
2351
|
+
/* @__PURE__ */ jsx8(
|
|
2302
2352
|
SelectInput2,
|
|
2303
2353
|
{
|
|
2304
2354
|
items: planCliItems,
|
|
@@ -2310,14 +2360,15 @@ function ConfigEditor({ version: version2 }) {
|
|
|
2310
2360
|
}
|
|
2311
2361
|
)
|
|
2312
2362
|
] }),
|
|
2313
|
-
phase !== "plan_cli" && /* @__PURE__ */
|
|
2314
|
-
phase === "plan_model" && /* @__PURE__ */
|
|
2315
|
-
|
|
2316
|
-
/* @__PURE__ */
|
|
2363
|
+
phase !== "plan_cli" && /* @__PURE__ */ jsx8(CompletedField, { label: "cli", value: values.planCli }),
|
|
2364
|
+
phase === "plan_model" && planModels.loading && /* @__PURE__ */ jsx8(LoadingSpinner, { message: "Loading models..." }),
|
|
2365
|
+
phase === "plan_model" && !planModels.loading && /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", children: [
|
|
2366
|
+
/* @__PURE__ */ jsx8(Text8, { children: " model:" }),
|
|
2367
|
+
/* @__PURE__ */ jsx8(
|
|
2317
2368
|
SelectInput2,
|
|
2318
2369
|
{
|
|
2319
|
-
items:
|
|
2320
|
-
initialIndex: initialIndex(
|
|
2370
|
+
items: planModels.items,
|
|
2371
|
+
initialIndex: initialIndex(planModels.items, values.planModel),
|
|
2321
2372
|
onSelect: (item) => {
|
|
2322
2373
|
setValues((v) => ({ ...v, planModel: item.value }));
|
|
2323
2374
|
setIterInput(String(values.planIterations));
|
|
@@ -2326,10 +2377,10 @@ function ConfigEditor({ version: version2 }) {
|
|
|
2326
2377
|
}
|
|
2327
2378
|
)
|
|
2328
2379
|
] }),
|
|
2329
|
-
pastPhase(phase, "plan_model") && /* @__PURE__ */
|
|
2330
|
-
phase === "plan_iterations" && /* @__PURE__ */
|
|
2331
|
-
/* @__PURE__ */
|
|
2332
|
-
/* @__PURE__ */
|
|
2380
|
+
pastPhase(phase, "plan_model") && /* @__PURE__ */ jsx8(CompletedField, { label: "model", value: values.planModel }),
|
|
2381
|
+
phase === "plan_iterations" && /* @__PURE__ */ jsxs7(Box8, { children: [
|
|
2382
|
+
/* @__PURE__ */ jsx8(Text8, { children: " iterations: " }),
|
|
2383
|
+
/* @__PURE__ */ jsx8(
|
|
2333
2384
|
TextInput2,
|
|
2334
2385
|
{
|
|
2335
2386
|
value: iterInput,
|
|
@@ -2344,14 +2395,14 @@ function ConfigEditor({ version: version2 }) {
|
|
|
2344
2395
|
}
|
|
2345
2396
|
)
|
|
2346
2397
|
] }),
|
|
2347
|
-
pastPhase(phase, "plan_iterations") && /* @__PURE__ */
|
|
2348
|
-
pastPhase(phase, "plan_iterations") && /* @__PURE__ */
|
|
2349
|
-
/* @__PURE__ */
|
|
2350
|
-
/* @__PURE__ */
|
|
2398
|
+
pastPhase(phase, "plan_iterations") && /* @__PURE__ */ jsx8(CompletedField, { label: "iterations", value: String(values.planIterations) }),
|
|
2399
|
+
pastPhase(phase, "plan_iterations") && /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
2400
|
+
/* @__PURE__ */ jsx8(Text8, { children: "" }),
|
|
2401
|
+
/* @__PURE__ */ jsx8(Text8, { bold: true, color: "cyan", children: "Build" })
|
|
2351
2402
|
] }),
|
|
2352
|
-
phase === "build_cli" && /* @__PURE__ */
|
|
2353
|
-
/* @__PURE__ */
|
|
2354
|
-
/* @__PURE__ */
|
|
2403
|
+
phase === "build_cli" && /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", children: [
|
|
2404
|
+
/* @__PURE__ */ jsx8(Text8, { children: " cli:" }),
|
|
2405
|
+
/* @__PURE__ */ jsx8(
|
|
2355
2406
|
SelectInput2,
|
|
2356
2407
|
{
|
|
2357
2408
|
items: buildCliItems,
|
|
@@ -2363,14 +2414,15 @@ function ConfigEditor({ version: version2 }) {
|
|
|
2363
2414
|
}
|
|
2364
2415
|
)
|
|
2365
2416
|
] }),
|
|
2366
|
-
pastPhase(phase, "build_cli") && /* @__PURE__ */
|
|
2367
|
-
phase === "build_model" && /* @__PURE__ */
|
|
2368
|
-
|
|
2369
|
-
/* @__PURE__ */
|
|
2417
|
+
pastPhase(phase, "build_cli") && /* @__PURE__ */ jsx8(CompletedField, { label: "cli", value: values.buildCli }),
|
|
2418
|
+
phase === "build_model" && buildModels.loading && /* @__PURE__ */ jsx8(LoadingSpinner, { message: "Loading models..." }),
|
|
2419
|
+
phase === "build_model" && !buildModels.loading && /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", children: [
|
|
2420
|
+
/* @__PURE__ */ jsx8(Text8, { children: " model:" }),
|
|
2421
|
+
/* @__PURE__ */ jsx8(
|
|
2370
2422
|
SelectInput2,
|
|
2371
2423
|
{
|
|
2372
|
-
items:
|
|
2373
|
-
initialIndex: initialIndex(
|
|
2424
|
+
items: buildModels.items,
|
|
2425
|
+
initialIndex: initialIndex(buildModels.items, values.buildModel),
|
|
2374
2426
|
onSelect: (item) => {
|
|
2375
2427
|
setValues((v) => ({ ...v, buildModel: item.value }));
|
|
2376
2428
|
setIterInput(String(values.buildIterations));
|
|
@@ -2379,10 +2431,10 @@ function ConfigEditor({ version: version2 }) {
|
|
|
2379
2431
|
}
|
|
2380
2432
|
)
|
|
2381
2433
|
] }),
|
|
2382
|
-
pastPhase(phase, "build_model") && /* @__PURE__ */
|
|
2383
|
-
phase === "build_iterations" && /* @__PURE__ */
|
|
2384
|
-
/* @__PURE__ */
|
|
2385
|
-
/* @__PURE__ */
|
|
2434
|
+
pastPhase(phase, "build_model") && /* @__PURE__ */ jsx8(CompletedField, { label: "model", value: values.buildModel }),
|
|
2435
|
+
phase === "build_iterations" && /* @__PURE__ */ jsxs7(Box8, { children: [
|
|
2436
|
+
/* @__PURE__ */ jsx8(Text8, { children: " iterations: " }),
|
|
2437
|
+
/* @__PURE__ */ jsx8(
|
|
2386
2438
|
TextInput2,
|
|
2387
2439
|
{
|
|
2388
2440
|
value: iterInput,
|
|
@@ -2398,14 +2450,14 @@ function ConfigEditor({ version: version2 }) {
|
|
|
2398
2450
|
}
|
|
2399
2451
|
)
|
|
2400
2452
|
] }),
|
|
2401
|
-
pastPhase(phase, "build_iterations") && /* @__PURE__ */
|
|
2402
|
-
pastPhase(phase, "build_iterations") && /* @__PURE__ */
|
|
2403
|
-
/* @__PURE__ */
|
|
2404
|
-
/* @__PURE__ */
|
|
2453
|
+
pastPhase(phase, "build_iterations") && /* @__PURE__ */ jsx8(CompletedField, { label: "iterations", value: String(values.buildIterations) }),
|
|
2454
|
+
pastPhase(phase, "build_iterations") && /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
2455
|
+
/* @__PURE__ */ jsx8(Text8, { children: "" }),
|
|
2456
|
+
/* @__PURE__ */ jsx8(Text8, { bold: true, color: "cyan", children: "General" })
|
|
2405
2457
|
] }),
|
|
2406
|
-
phase === "specs_dir" && /* @__PURE__ */
|
|
2407
|
-
/* @__PURE__ */
|
|
2408
|
-
/* @__PURE__ */
|
|
2458
|
+
phase === "specs_dir" && /* @__PURE__ */ jsxs7(Box8, { children: [
|
|
2459
|
+
/* @__PURE__ */ jsx8(Text8, { children: " specsDir: " }),
|
|
2460
|
+
/* @__PURE__ */ jsx8(
|
|
2409
2461
|
TextInput2,
|
|
2410
2462
|
{
|
|
2411
2463
|
value: specsDirInput,
|
|
@@ -2418,10 +2470,10 @@ function ConfigEditor({ version: version2 }) {
|
|
|
2418
2470
|
}
|
|
2419
2471
|
)
|
|
2420
2472
|
] }),
|
|
2421
|
-
pastPhase(phase, "specs_dir") && /* @__PURE__ */
|
|
2422
|
-
phase === "verbose" && /* @__PURE__ */
|
|
2423
|
-
/* @__PURE__ */
|
|
2424
|
-
/* @__PURE__ */
|
|
2473
|
+
pastPhase(phase, "specs_dir") && /* @__PURE__ */ jsx8(CompletedField, { label: "specsDir", value: values.specsDir }),
|
|
2474
|
+
phase === "verbose" && /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", children: [
|
|
2475
|
+
/* @__PURE__ */ jsx8(Text8, { children: " verbose:" }),
|
|
2476
|
+
/* @__PURE__ */ jsx8(
|
|
2425
2477
|
SelectInput2,
|
|
2426
2478
|
{
|
|
2427
2479
|
items: [
|
|
@@ -2436,13 +2488,13 @@ function ConfigEditor({ version: version2 }) {
|
|
|
2436
2488
|
}
|
|
2437
2489
|
)
|
|
2438
2490
|
] }),
|
|
2439
|
-
phase === "done" && /* @__PURE__ */
|
|
2440
|
-
/* @__PURE__ */
|
|
2441
|
-
/* @__PURE__ */
|
|
2442
|
-
saveError ? /* @__PURE__ */
|
|
2491
|
+
phase === "done" && /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
2492
|
+
/* @__PURE__ */ jsx8(CompletedField, { label: "verbose", value: String(values.verbose) }),
|
|
2493
|
+
/* @__PURE__ */ jsx8(Text8, { children: "" }),
|
|
2494
|
+
saveError ? /* @__PURE__ */ jsxs7(Text8, { color: "red", bold: true, children: [
|
|
2443
2495
|
"\u2717 ",
|
|
2444
2496
|
saveError
|
|
2445
|
-
] }) : /* @__PURE__ */
|
|
2497
|
+
] }) : /* @__PURE__ */ jsx8(Text8, { color: "green", bold: true, children: "\u2713 Config saved" })
|
|
2446
2498
|
] })
|
|
2447
2499
|
] });
|
|
2448
2500
|
}
|
|
@@ -2470,7 +2522,7 @@ function ConfigSetBatch({ pairs }) {
|
|
|
2470
2522
|
}
|
|
2471
2523
|
if (errors.length > 0) {
|
|
2472
2524
|
process.exitCode = 1;
|
|
2473
|
-
return /* @__PURE__ */
|
|
2525
|
+
return /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", children: errors.map((e, i) => /* @__PURE__ */ jsx8(Text8, { color: "red", children: e }, i)) });
|
|
2474
2526
|
}
|
|
2475
2527
|
const partial = {};
|
|
2476
2528
|
for (const { key, value } of parsed) {
|
|
@@ -2481,7 +2533,7 @@ function ConfigSetBatch({ pairs }) {
|
|
|
2481
2533
|
} catch (err) {
|
|
2482
2534
|
process.exitCode = 1;
|
|
2483
2535
|
const msg = err instanceof Error ? err.message : String(err);
|
|
2484
|
-
return /* @__PURE__ */
|
|
2536
|
+
return /* @__PURE__ */ jsx8(Text8, { color: "red", children: `Validation error: ${msg}` });
|
|
2485
2537
|
}
|
|
2486
2538
|
try {
|
|
2487
2539
|
readMergeWriteConfig(parsed);
|
|
@@ -2489,12 +2541,12 @@ function ConfigSetBatch({ pairs }) {
|
|
|
2489
2541
|
process.exitCode = 1;
|
|
2490
2542
|
const code = err.code;
|
|
2491
2543
|
const msg = code === "EACCES" ? `Permission denied writing to ${path8.join(getLocalDir(process.cwd()), CONFIG_FILE)}` : `Failed to write config: ${err.message}`;
|
|
2492
|
-
return /* @__PURE__ */
|
|
2544
|
+
return /* @__PURE__ */ jsx8(Text8, { color: "red", children: msg });
|
|
2493
2545
|
}
|
|
2494
|
-
return /* @__PURE__ */
|
|
2546
|
+
return /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", children: parsed.map(({ key, value }) => /* @__PURE__ */ jsx8(Text8, { color: "green", children: `Set ${key} = ${String(value)}` }, key)) });
|
|
2495
2547
|
}
|
|
2496
2548
|
function UnknownSubcommand({ subcommand }) {
|
|
2497
|
-
return /* @__PURE__ */
|
|
2549
|
+
return /* @__PURE__ */ jsx8(Text8, { color: "red", children: `Unknown config subcommand: ${subcommand}
|
|
2498
2550
|
Usage: toby config [get <key> | set <key> <value>]` });
|
|
2499
2551
|
}
|
|
2500
2552
|
function Config({
|
|
@@ -2504,39 +2556,39 @@ function Config({
|
|
|
2504
2556
|
version: version2
|
|
2505
2557
|
}) {
|
|
2506
2558
|
if (subcommand && subcommand !== "get" && subcommand !== "set") {
|
|
2507
|
-
return /* @__PURE__ */
|
|
2508
|
-
/* @__PURE__ */
|
|
2509
|
-
/* @__PURE__ */
|
|
2510
|
-
/* @__PURE__ */
|
|
2559
|
+
return /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", children: [
|
|
2560
|
+
/* @__PURE__ */ jsx8(Text8, { children: `toby v${version2}` }),
|
|
2561
|
+
/* @__PURE__ */ jsx8(Text8, { children: "" }),
|
|
2562
|
+
/* @__PURE__ */ jsx8(UnknownSubcommand, { subcommand })
|
|
2511
2563
|
] });
|
|
2512
2564
|
}
|
|
2513
2565
|
if (subcommand === "get" && configKey) {
|
|
2514
|
-
return /* @__PURE__ */
|
|
2566
|
+
return /* @__PURE__ */ jsx8(ConfigGet, { configKey });
|
|
2515
2567
|
}
|
|
2516
2568
|
if (subcommand === "set" && configKey && value) {
|
|
2517
|
-
return /* @__PURE__ */
|
|
2569
|
+
return /* @__PURE__ */ jsx8(ConfigSet, { configKey, value });
|
|
2518
2570
|
}
|
|
2519
2571
|
if (subcommand === "set" && configKey && !value) {
|
|
2520
|
-
return /* @__PURE__ */
|
|
2572
|
+
return /* @__PURE__ */ jsx8(Text8, { color: "red", children: `Missing value for config set.
|
|
2521
2573
|
Usage: toby config set <key> <value>` });
|
|
2522
2574
|
}
|
|
2523
|
-
return /* @__PURE__ */
|
|
2524
|
-
/* @__PURE__ */
|
|
2525
|
-
/* @__PURE__ */
|
|
2526
|
-
/* @__PURE__ */
|
|
2527
|
-
/* @__PURE__ */
|
|
2528
|
-
/* @__PURE__ */
|
|
2529
|
-
Object.entries(VALID_KEYS).map(([key, type]) => /* @__PURE__ */
|
|
2575
|
+
return /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", children: [
|
|
2576
|
+
/* @__PURE__ */ jsx8(Text8, { children: `toby v${version2}` }),
|
|
2577
|
+
/* @__PURE__ */ jsx8(Text8, { children: "" }),
|
|
2578
|
+
/* @__PURE__ */ jsx8(Text8, { children: "Usage: toby config [get <key> | set <key> <value>]" }),
|
|
2579
|
+
/* @__PURE__ */ jsx8(Text8, { children: "" }),
|
|
2580
|
+
/* @__PURE__ */ jsx8(Text8, { bold: true, children: "Available keys:" }),
|
|
2581
|
+
Object.entries(VALID_KEYS).map(([key, type]) => /* @__PURE__ */ jsx8(Text8, { children: ` ${key} (${type})` }, key))
|
|
2530
2582
|
] });
|
|
2531
2583
|
}
|
|
2532
2584
|
|
|
2533
2585
|
// src/components/Welcome.tsx
|
|
2534
|
-
import { useState as
|
|
2535
|
-
import { Box as
|
|
2586
|
+
import { useState as useState9, useEffect as useEffect8, useMemo as useMemo5 } from "react";
|
|
2587
|
+
import { Box as Box12, Text as Text12, useApp as useApp4, useStdout as useStdout2 } from "ink";
|
|
2536
2588
|
|
|
2537
2589
|
// src/components/hamster/HamsterWheel.tsx
|
|
2538
|
-
import { useState as
|
|
2539
|
-
import { Box as
|
|
2590
|
+
import { useState as useState8, useEffect as useEffect7, useMemo as useMemo4 } from "react";
|
|
2591
|
+
import { Box as Box9, Text as Text9, useStdout } from "ink";
|
|
2540
2592
|
|
|
2541
2593
|
// src/components/hamster/palette.ts
|
|
2542
2594
|
var PALETTE = {
|
|
@@ -2695,7 +2747,7 @@ function generateWheelPixels(cx, cy, outerRadius, innerRadius, spokeAngle, aspec
|
|
|
2695
2747
|
}
|
|
2696
2748
|
|
|
2697
2749
|
// src/components/hamster/HamsterWheel.tsx
|
|
2698
|
-
import { jsx as
|
|
2750
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
2699
2751
|
function buildGrid(width, height) {
|
|
2700
2752
|
return Array.from(
|
|
2701
2753
|
{ length: height },
|
|
@@ -2778,9 +2830,9 @@ function HamsterWheel({
|
|
|
2778
2830
|
heightProp,
|
|
2779
2831
|
columns
|
|
2780
2832
|
);
|
|
2781
|
-
const [frame, setFrame] =
|
|
2782
|
-
const [spokeAngle, setSpokeAngle] =
|
|
2783
|
-
|
|
2833
|
+
const [frame, setFrame] = useState8(0);
|
|
2834
|
+
const [spokeAngle, setSpokeAngle] = useState8(0);
|
|
2835
|
+
useEffect7(() => {
|
|
2784
2836
|
if (speed === 0 || isStatic) return;
|
|
2785
2837
|
const interval = computeInterval(HAMSTER_BASE_INTERVAL, speed);
|
|
2786
2838
|
const id = setInterval(() => {
|
|
@@ -2788,7 +2840,7 @@ function HamsterWheel({
|
|
|
2788
2840
|
}, interval);
|
|
2789
2841
|
return () => clearInterval(id);
|
|
2790
2842
|
}, [speed, isStatic]);
|
|
2791
|
-
|
|
2843
|
+
useEffect7(() => {
|
|
2792
2844
|
if (speed === 0 || isStatic) return;
|
|
2793
2845
|
const interval = computeInterval(WHEEL_BASE_INTERVAL, speed);
|
|
2794
2846
|
const id = setInterval(() => {
|
|
@@ -2828,43 +2880,43 @@ function HamsterWheel({
|
|
|
2828
2880
|
return buildColorRuns(grid, resolvedWidth, resolvedHeight);
|
|
2829
2881
|
}, [resolvedWidth, resolvedHeight, frame, spokeAngle, isStatic]);
|
|
2830
2882
|
if (isStatic) {
|
|
2831
|
-
return /* @__PURE__ */
|
|
2883
|
+
return /* @__PURE__ */ jsx9(Text9, { children: " \u{1F439} toby" });
|
|
2832
2884
|
}
|
|
2833
|
-
return /* @__PURE__ */
|
|
2885
|
+
return /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", children: renderedRows.map((runs, y) => /* @__PURE__ */ jsx9(Text9, { children: runs.map((run, i) => /* @__PURE__ */ jsx9(Text9, { color: run.fg, backgroundColor: run.bg, children: run.char.repeat(run.length) }, i)) }, y)) });
|
|
2834
2886
|
}
|
|
2835
2887
|
|
|
2836
2888
|
// src/components/InfoPanel.tsx
|
|
2837
|
-
import { Box as
|
|
2838
|
-
import { jsx as
|
|
2889
|
+
import { Box as Box10, Text as Text10 } from "ink";
|
|
2890
|
+
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2839
2891
|
var formatTokens = (n) => new Intl.NumberFormat().format(n);
|
|
2840
2892
|
function StatRow({ label, value }) {
|
|
2841
|
-
return /* @__PURE__ */
|
|
2842
|
-
/* @__PURE__ */
|
|
2893
|
+
return /* @__PURE__ */ jsxs8(Box10, { children: [
|
|
2894
|
+
/* @__PURE__ */ jsxs8(Text10, { dimColor: true, children: [
|
|
2843
2895
|
String(label).padStart(9),
|
|
2844
2896
|
" "
|
|
2845
2897
|
] }),
|
|
2846
|
-
/* @__PURE__ */
|
|
2898
|
+
/* @__PURE__ */ jsx10(Text10, { children: value })
|
|
2847
2899
|
] });
|
|
2848
2900
|
}
|
|
2849
2901
|
function InfoPanel({ version: version2, stats }) {
|
|
2850
|
-
return /* @__PURE__ */
|
|
2851
|
-
/* @__PURE__ */
|
|
2902
|
+
return /* @__PURE__ */ jsxs8(Box10, { flexDirection: "column", children: [
|
|
2903
|
+
/* @__PURE__ */ jsxs8(Text10, { bold: true, color: "#f0a030", children: [
|
|
2852
2904
|
"toby v",
|
|
2853
2905
|
version2
|
|
2854
2906
|
] }),
|
|
2855
|
-
stats !== null && /* @__PURE__ */
|
|
2856
|
-
/* @__PURE__ */
|
|
2857
|
-
/* @__PURE__ */
|
|
2858
|
-
/* @__PURE__ */
|
|
2859
|
-
/* @__PURE__ */
|
|
2907
|
+
stats !== null && /* @__PURE__ */ jsxs8(Box10, { flexDirection: "column", marginTop: 1, children: [
|
|
2908
|
+
/* @__PURE__ */ jsx10(StatRow, { label: "Specs", value: stats.totalSpecs }),
|
|
2909
|
+
/* @__PURE__ */ jsx10(StatRow, { label: "Planned", value: stats.planned }),
|
|
2910
|
+
/* @__PURE__ */ jsx10(StatRow, { label: "Done", value: stats.done }),
|
|
2911
|
+
/* @__PURE__ */ jsx10(StatRow, { label: "Tokens", value: formatTokens(stats.totalTokens) })
|
|
2860
2912
|
] })
|
|
2861
2913
|
] });
|
|
2862
2914
|
}
|
|
2863
2915
|
|
|
2864
2916
|
// src/components/MainMenu.tsx
|
|
2865
|
-
import { Text as
|
|
2917
|
+
import { Text as Text11, Box as Box11 } from "ink";
|
|
2866
2918
|
import SelectInput3 from "ink-select-input";
|
|
2867
|
-
import { jsx as
|
|
2919
|
+
import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2868
2920
|
var MENU_ITEMS = [
|
|
2869
2921
|
{ label: "plan", value: "plan", description: "Plan specs with AI loop engine" },
|
|
2870
2922
|
{ label: "build", value: "build", description: "Build tasks one-per-spawn with AI" },
|
|
@@ -2872,16 +2924,16 @@ var MENU_ITEMS = [
|
|
|
2872
2924
|
{ label: "config", value: "config", description: "Manage configuration" }
|
|
2873
2925
|
];
|
|
2874
2926
|
function MenuItem({ isSelected = false, label, description }) {
|
|
2875
|
-
return /* @__PURE__ */
|
|
2876
|
-
/* @__PURE__ */
|
|
2877
|
-
description && /* @__PURE__ */
|
|
2927
|
+
return /* @__PURE__ */ jsxs9(Box11, { children: [
|
|
2928
|
+
/* @__PURE__ */ jsx11(Text11, { color: isSelected ? "blue" : void 0, children: label.padEnd(10) }),
|
|
2929
|
+
description && /* @__PURE__ */ jsxs9(Text11, { dimColor: true, children: [
|
|
2878
2930
|
"\u2014 ",
|
|
2879
2931
|
description
|
|
2880
2932
|
] })
|
|
2881
2933
|
] });
|
|
2882
2934
|
}
|
|
2883
2935
|
function MainMenu({ onSelect }) {
|
|
2884
|
-
return /* @__PURE__ */
|
|
2936
|
+
return /* @__PURE__ */ jsx11(Box11, { flexDirection: "column", children: /* @__PURE__ */ jsx11(
|
|
2885
2937
|
SelectInput3,
|
|
2886
2938
|
{
|
|
2887
2939
|
items: MENU_ITEMS,
|
|
@@ -2936,60 +2988,60 @@ function computeProjectStats(cwd) {
|
|
|
2936
2988
|
}
|
|
2937
2989
|
|
|
2938
2990
|
// src/components/Welcome.tsx
|
|
2939
|
-
import { jsx as
|
|
2991
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2940
2992
|
var NARROW_THRESHOLD = 60;
|
|
2941
2993
|
function Welcome({ version: version2 }) {
|
|
2942
2994
|
const { exit } = useApp4();
|
|
2943
2995
|
const { stdout } = useStdout2();
|
|
2944
|
-
const [selectedCommand, setSelectedCommand] =
|
|
2996
|
+
const [selectedCommand, setSelectedCommand] = useState9(null);
|
|
2945
2997
|
const stats = useMemo5(() => computeProjectStats(), []);
|
|
2946
2998
|
const isNarrow = (stdout.columns ?? 80) < NARROW_THRESHOLD;
|
|
2947
|
-
|
|
2999
|
+
useEffect8(() => {
|
|
2948
3000
|
if (selectedCommand === "status") {
|
|
2949
3001
|
const timer = setTimeout(() => exit(), 0);
|
|
2950
3002
|
return () => clearTimeout(timer);
|
|
2951
3003
|
}
|
|
2952
3004
|
}, [selectedCommand, exit]);
|
|
2953
3005
|
if (selectedCommand === "plan") {
|
|
2954
|
-
return /* @__PURE__ */
|
|
3006
|
+
return /* @__PURE__ */ jsx12(Plan, {});
|
|
2955
3007
|
}
|
|
2956
3008
|
if (selectedCommand === "build") {
|
|
2957
|
-
return /* @__PURE__ */
|
|
3009
|
+
return /* @__PURE__ */ jsx12(Build, {});
|
|
2958
3010
|
}
|
|
2959
3011
|
if (selectedCommand === "status") {
|
|
2960
|
-
return /* @__PURE__ */
|
|
3012
|
+
return /* @__PURE__ */ jsx12(Status, { version: version2 });
|
|
2961
3013
|
}
|
|
2962
3014
|
if (selectedCommand === "config") {
|
|
2963
|
-
return /* @__PURE__ */
|
|
3015
|
+
return /* @__PURE__ */ jsx12(ConfigEditor, { version: version2 });
|
|
2964
3016
|
}
|
|
2965
|
-
return /* @__PURE__ */
|
|
2966
|
-
isNarrow ? /* @__PURE__ */
|
|
2967
|
-
/* @__PURE__ */
|
|
3017
|
+
return /* @__PURE__ */ jsxs10(Box12, { flexDirection: "column", gap: 1, children: [
|
|
3018
|
+
isNarrow ? /* @__PURE__ */ jsxs10(Box12, { flexDirection: "column", children: [
|
|
3019
|
+
/* @__PURE__ */ jsxs10(Text12, { bold: true, color: "#f0a030", children: [
|
|
2968
3020
|
"\u{1F439} toby v",
|
|
2969
3021
|
version2
|
|
2970
3022
|
] }),
|
|
2971
|
-
stats !== null && /* @__PURE__ */
|
|
2972
|
-
/* @__PURE__ */
|
|
2973
|
-
/* @__PURE__ */
|
|
2974
|
-
/* @__PURE__ */
|
|
2975
|
-
/* @__PURE__ */
|
|
2976
|
-
/* @__PURE__ */
|
|
2977
|
-
/* @__PURE__ */
|
|
2978
|
-
/* @__PURE__ */
|
|
2979
|
-
/* @__PURE__ */
|
|
3023
|
+
stats !== null && /* @__PURE__ */ jsxs10(Text12, { children: [
|
|
3024
|
+
/* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "Specs: " }),
|
|
3025
|
+
/* @__PURE__ */ jsx12(Text12, { children: stats.totalSpecs }),
|
|
3026
|
+
/* @__PURE__ */ jsx12(Text12, { dimColor: true, children: " \xB7 Planned: " }),
|
|
3027
|
+
/* @__PURE__ */ jsx12(Text12, { children: stats.planned }),
|
|
3028
|
+
/* @__PURE__ */ jsx12(Text12, { dimColor: true, children: " \xB7 Done: " }),
|
|
3029
|
+
/* @__PURE__ */ jsx12(Text12, { children: stats.done }),
|
|
3030
|
+
/* @__PURE__ */ jsx12(Text12, { dimColor: true, children: " \xB7 Tokens: " }),
|
|
3031
|
+
/* @__PURE__ */ jsx12(Text12, { children: formatTokens(stats.totalTokens) })
|
|
2980
3032
|
] })
|
|
2981
|
-
] }) : /* @__PURE__ */
|
|
2982
|
-
/* @__PURE__ */
|
|
2983
|
-
/* @__PURE__ */
|
|
3033
|
+
] }) : /* @__PURE__ */ jsxs10(Box12, { flexDirection: "row", gap: 2, children: [
|
|
3034
|
+
/* @__PURE__ */ jsx12(HamsterWheel, {}),
|
|
3035
|
+
/* @__PURE__ */ jsx12(InfoPanel, { version: version2, stats })
|
|
2984
3036
|
] }),
|
|
2985
|
-
/* @__PURE__ */
|
|
3037
|
+
/* @__PURE__ */ jsx12(MainMenu, { onSelect: setSelectedCommand })
|
|
2986
3038
|
] });
|
|
2987
3039
|
}
|
|
2988
3040
|
|
|
2989
3041
|
// src/cli.tsx
|
|
2990
|
-
import { jsx as
|
|
3042
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
2991
3043
|
function Help({ version: version2 }) {
|
|
2992
|
-
return /* @__PURE__ */
|
|
3044
|
+
return /* @__PURE__ */ jsx13(Text13, { children: `toby v${version2} \u2014 AI-assisted development loop engine
|
|
2993
3045
|
|
|
2994
3046
|
Usage
|
|
2995
3047
|
$ toby <command> [options]
|
|
@@ -3010,7 +3062,7 @@ Spec Selection
|
|
|
3010
3062
|
--specs=<names> Alias for --spec` });
|
|
3011
3063
|
}
|
|
3012
3064
|
function UnknownCommand({ command: command2 }) {
|
|
3013
|
-
return /* @__PURE__ */
|
|
3065
|
+
return /* @__PURE__ */ jsx13(Text13, { color: "red", children: `Unknown command: ${command2}
|
|
3014
3066
|
Run "toby --help" for available commands.` });
|
|
3015
3067
|
}
|
|
3016
3068
|
var cli = meow(
|
|
@@ -3086,7 +3138,7 @@ var resolvedSpec = cli.flags.specs ?? cli.flags.spec;
|
|
|
3086
3138
|
var flags = { ...cli.flags, spec: resolvedSpec };
|
|
3087
3139
|
var commands = {
|
|
3088
3140
|
plan: {
|
|
3089
|
-
render: (flags2) => /* @__PURE__ */
|
|
3141
|
+
render: (flags2) => /* @__PURE__ */ jsx13(
|
|
3090
3142
|
Plan,
|
|
3091
3143
|
{
|
|
3092
3144
|
spec: flags2.spec,
|
|
@@ -3101,7 +3153,7 @@ var commands = {
|
|
|
3101
3153
|
waitForExit: true
|
|
3102
3154
|
},
|
|
3103
3155
|
build: {
|
|
3104
|
-
render: (flags2) => /* @__PURE__ */
|
|
3156
|
+
render: (flags2) => /* @__PURE__ */ jsx13(
|
|
3105
3157
|
Build,
|
|
3106
3158
|
{
|
|
3107
3159
|
spec: flags2.spec,
|
|
@@ -3116,7 +3168,7 @@ var commands = {
|
|
|
3116
3168
|
waitForExit: true
|
|
3117
3169
|
},
|
|
3118
3170
|
init: {
|
|
3119
|
-
render: (flags2, _input, version2) => /* @__PURE__ */
|
|
3171
|
+
render: (flags2, _input, version2) => /* @__PURE__ */ jsx13(
|
|
3120
3172
|
Init,
|
|
3121
3173
|
{
|
|
3122
3174
|
version: version2,
|
|
@@ -3131,17 +3183,17 @@ var commands = {
|
|
|
3131
3183
|
waitForExit: true
|
|
3132
3184
|
},
|
|
3133
3185
|
status: {
|
|
3134
|
-
render: (flags2, _input, version2) => /* @__PURE__ */
|
|
3186
|
+
render: (flags2, _input, version2) => /* @__PURE__ */ jsx13(Status, { spec: flags2.spec, version: version2 })
|
|
3135
3187
|
},
|
|
3136
3188
|
config: {
|
|
3137
3189
|
render: (_flags, input, version2) => {
|
|
3138
3190
|
const [, subcommand, ...rest] = input;
|
|
3139
|
-
if (!subcommand) return /* @__PURE__ */
|
|
3191
|
+
if (!subcommand) return /* @__PURE__ */ jsx13(ConfigEditor, { version: version2 });
|
|
3140
3192
|
if (subcommand === "set" && rest.some((arg) => arg.includes("="))) {
|
|
3141
|
-
return /* @__PURE__ */
|
|
3193
|
+
return /* @__PURE__ */ jsx13(ConfigSetBatch, { pairs: rest.filter((arg) => arg.includes("=")) });
|
|
3142
3194
|
}
|
|
3143
3195
|
const [configKey, value] = rest;
|
|
3144
|
-
return /* @__PURE__ */
|
|
3196
|
+
return /* @__PURE__ */ jsx13(
|
|
3145
3197
|
Config,
|
|
3146
3198
|
{
|
|
3147
3199
|
subcommand,
|
|
@@ -3158,10 +3210,10 @@ var version = cli.pkg.version ?? "0.0.0";
|
|
|
3158
3210
|
var [command] = cli.input;
|
|
3159
3211
|
if (!command) {
|
|
3160
3212
|
if (process.stdin.isTTY) {
|
|
3161
|
-
const app = render(/* @__PURE__ */
|
|
3213
|
+
const app = render(/* @__PURE__ */ jsx13(Welcome, { version }));
|
|
3162
3214
|
await app.waitUntilExit();
|
|
3163
3215
|
} else {
|
|
3164
|
-
render(/* @__PURE__ */
|
|
3216
|
+
render(/* @__PURE__ */ jsx13(Help, { version })).unmount();
|
|
3165
3217
|
}
|
|
3166
3218
|
} else if (command in commands) {
|
|
3167
3219
|
const entry = commands[command];
|
|
@@ -3172,6 +3224,6 @@ if (!command) {
|
|
|
3172
3224
|
app.unmount();
|
|
3173
3225
|
}
|
|
3174
3226
|
} else {
|
|
3175
|
-
render(/* @__PURE__ */
|
|
3227
|
+
render(/* @__PURE__ */ jsx13(UnknownCommand, { command })).unmount();
|
|
3176
3228
|
process.exitCode = 1;
|
|
3177
3229
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@0xtiby/toby",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "AI-assisted development loop engine CLI",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/0xtiby/toby.git"
|
|
8
|
+
},
|
|
5
9
|
"type": "module",
|
|
10
|
+
"packageManager": "pnpm@10.28.1",
|
|
6
11
|
"bin": {
|
|
7
12
|
"toby": "./dist/cli.js"
|
|
8
13
|
},
|
|
@@ -16,12 +21,10 @@
|
|
|
16
21
|
"scripts": {
|
|
17
22
|
"build": "tsup",
|
|
18
23
|
"dev": "tsup --watch",
|
|
19
|
-
"test": "vitest run"
|
|
20
|
-
"bootstrap": "bash scripts/bootstrap.sh",
|
|
21
|
-
"setup:branch-protection": "bash scripts/setup-branch-protection.sh"
|
|
24
|
+
"test": "vitest run"
|
|
22
25
|
},
|
|
23
26
|
"dependencies": {
|
|
24
|
-
"@0xtiby/spawner": "
|
|
27
|
+
"@0xtiby/spawner": "^1.1.0",
|
|
25
28
|
"ink": "^5.0.1",
|
|
26
29
|
"ink-select-input": "^6.2.0",
|
|
27
30
|
"ink-spinner": "^5.0.0",
|