@0xtiby/toby 1.0.1 → 1.1.0

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 (2) hide show
  1. package/dist/cli.js +197 -73
  2. package/package.json +1 -1
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 Text13 } from "ink";
5
+ import { render, Text as Text14 } from "ink";
6
6
 
7
7
  // src/commands/plan.tsx
8
8
  import { useState as useState3, useEffect as useEffect2, useMemo as useMemo2 } from "react";
@@ -80,6 +80,7 @@ var LOCAL_TOBY_DIR = ".toby";
80
80
  var DEFAULT_SPECS_DIR = "specs";
81
81
  var STATUS_FILE = "status.json";
82
82
  var CONFIG_FILE = "config.json";
83
+ var TRANSCRIPTS_DIR = "transcripts";
83
84
  function getGlobalDir() {
84
85
  return path.join(os.homedir(), GLOBAL_TOBY_DIR);
85
86
  }
@@ -567,7 +568,6 @@ var AbortError = class extends Error {
567
568
  // src/lib/transcript.ts
568
569
  import fs6 from "fs";
569
570
  import path6 from "path";
570
- var TRANSCRIPTS_DIR = "transcripts";
571
571
  function formatTimestamp() {
572
572
  const now = /* @__PURE__ */ new Date();
573
573
  const pad2 = (n, len = 2) => String(n).padStart(len, "0");
@@ -2582,13 +2582,127 @@ Usage: toby config set <key> <value>` });
2582
2582
  ] });
2583
2583
  }
2584
2584
 
2585
+ // src/commands/clean.tsx
2586
+ import { useState as useState8, useEffect as useEffect7, useMemo as useMemo4 } from "react";
2587
+ import { Text as Text9, useApp as useApp4, useInput as useInput2 } from "ink";
2588
+
2589
+ // src/lib/clean.ts
2590
+ import path9 from "path";
2591
+ import fs10 from "fs";
2592
+ function listTranscripts(cwd) {
2593
+ const dir = path9.join(getLocalDir(cwd), TRANSCRIPTS_DIR);
2594
+ let entries;
2595
+ try {
2596
+ entries = fs10.readdirSync(dir, { withFileTypes: true });
2597
+ } catch {
2598
+ return [];
2599
+ }
2600
+ return entries.filter((e) => e.isFile()).map((e) => path9.join(dir, e.name));
2601
+ }
2602
+ function deleteTranscripts(files) {
2603
+ let deleted = 0;
2604
+ for (const file of files) {
2605
+ try {
2606
+ fs10.unlinkSync(file);
2607
+ deleted++;
2608
+ } catch {
2609
+ }
2610
+ }
2611
+ return deleted;
2612
+ }
2613
+ function executeClean(cwd) {
2614
+ const files = listTranscripts(cwd);
2615
+ if (files.length === 0) {
2616
+ return { deleted: 0, failed: 0, total: 0 };
2617
+ }
2618
+ const deleted = deleteTranscripts(files);
2619
+ return { deleted, failed: files.length - deleted, total: files.length };
2620
+ }
2621
+
2622
+ // src/commands/clean.tsx
2623
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
2624
+ function computeInitial(force) {
2625
+ const files = listTranscripts();
2626
+ if (files.length === 0) {
2627
+ return { phase: "empty", fileCount: 0, result: null };
2628
+ }
2629
+ if (!process.stdin.isTTY && !force) {
2630
+ return { phase: "error", fileCount: files.length, result: null };
2631
+ }
2632
+ if (force) {
2633
+ const r = executeClean();
2634
+ return { phase: "done", fileCount: files.length, result: r };
2635
+ }
2636
+ return { phase: "confirming", fileCount: files.length, result: null };
2637
+ }
2638
+ function Clean({ force }) {
2639
+ const { exit } = useApp4();
2640
+ const initial = useMemo4(() => computeInitial(force), [force]);
2641
+ useEffect7(() => {
2642
+ if (initial.phase === "error") {
2643
+ process.exitCode = 1;
2644
+ }
2645
+ }, [initial.phase]);
2646
+ const [phase, setPhase] = useState8(initial.phase);
2647
+ const [result, setResult] = useState8(initial.result);
2648
+ useEffect7(() => {
2649
+ if (phase === "empty" || phase === "done" || phase === "cancelled" || phase === "error") {
2650
+ const timer = setTimeout(() => exit(), 100);
2651
+ return () => clearTimeout(timer);
2652
+ }
2653
+ }, [phase, exit]);
2654
+ useInput2((input, key) => {
2655
+ if (phase !== "confirming") return;
2656
+ if (input === "y" || key.return) {
2657
+ const r = executeClean();
2658
+ setResult(r);
2659
+ setPhase("done");
2660
+ } else if (input === "n" || key.escape) {
2661
+ setPhase("cancelled");
2662
+ }
2663
+ });
2664
+ if (phase === "error") {
2665
+ return /* @__PURE__ */ jsx9(Text9, { color: "red", children: "Error: Use --force to clean transcripts in non-interactive mode." });
2666
+ }
2667
+ if (phase === "empty") {
2668
+ return /* @__PURE__ */ jsx9(Text9, { children: "No transcripts to clean." });
2669
+ }
2670
+ if (phase === "confirming") {
2671
+ return /* @__PURE__ */ jsxs8(Text9, { children: [
2672
+ "Found ",
2673
+ initial.fileCount,
2674
+ " transcript files. Delete all? [Y/n]"
2675
+ ] });
2676
+ }
2677
+ if (phase === "done" && result) {
2678
+ if (result.failed > 0) {
2679
+ return /* @__PURE__ */ jsxs8(Text9, { children: [
2680
+ "Deleted ",
2681
+ result.deleted,
2682
+ " transcript files. Failed to delete ",
2683
+ result.failed,
2684
+ " files."
2685
+ ] });
2686
+ }
2687
+ return /* @__PURE__ */ jsxs8(Text9, { children: [
2688
+ "Deleted ",
2689
+ result.deleted,
2690
+ " transcript files."
2691
+ ] });
2692
+ }
2693
+ if (phase === "cancelled") {
2694
+ return /* @__PURE__ */ jsx9(Text9, { children: "Clean cancelled." });
2695
+ }
2696
+ return null;
2697
+ }
2698
+
2585
2699
  // src/components/Welcome.tsx
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";
2700
+ import { useState as useState10, useEffect as useEffect9, useMemo as useMemo6 } from "react";
2701
+ import { Box as Box12, Text as Text13, useApp as useApp5, useStdout as useStdout2 } from "ink";
2588
2702
 
2589
2703
  // src/components/hamster/HamsterWheel.tsx
2590
- import { useState as useState8, useEffect as useEffect7, useMemo as useMemo4 } from "react";
2591
- import { Box as Box9, Text as Text9, useStdout } from "ink";
2704
+ import { useState as useState9, useEffect as useEffect8, useMemo as useMemo5 } from "react";
2705
+ import { Box as Box9, Text as Text10, useStdout } from "ink";
2592
2706
 
2593
2707
  // src/components/hamster/palette.ts
2594
2708
  var PALETTE = {
@@ -2747,7 +2861,7 @@ function generateWheelPixels(cx, cy, outerRadius, innerRadius, spokeAngle, aspec
2747
2861
  }
2748
2862
 
2749
2863
  // src/components/hamster/HamsterWheel.tsx
2750
- import { jsx as jsx9 } from "react/jsx-runtime";
2864
+ import { jsx as jsx10 } from "react/jsx-runtime";
2751
2865
  function buildGrid(width, height) {
2752
2866
  return Array.from(
2753
2867
  { length: height },
@@ -2830,9 +2944,9 @@ function HamsterWheel({
2830
2944
  heightProp,
2831
2945
  columns
2832
2946
  );
2833
- const [frame, setFrame] = useState8(0);
2834
- const [spokeAngle, setSpokeAngle] = useState8(0);
2835
- useEffect7(() => {
2947
+ const [frame, setFrame] = useState9(0);
2948
+ const [spokeAngle, setSpokeAngle] = useState9(0);
2949
+ useEffect8(() => {
2836
2950
  if (speed === 0 || isStatic) return;
2837
2951
  const interval = computeInterval(HAMSTER_BASE_INTERVAL, speed);
2838
2952
  const id = setInterval(() => {
@@ -2840,7 +2954,7 @@ function HamsterWheel({
2840
2954
  }, interval);
2841
2955
  return () => clearInterval(id);
2842
2956
  }, [speed, isStatic]);
2843
- useEffect7(() => {
2957
+ useEffect8(() => {
2844
2958
  if (speed === 0 || isStatic) return;
2845
2959
  const interval = computeInterval(WHEEL_BASE_INTERVAL, speed);
2846
2960
  const id = setInterval(() => {
@@ -2848,7 +2962,7 @@ function HamsterWheel({
2848
2962
  }, interval);
2849
2963
  return () => clearInterval(id);
2850
2964
  }, [speed, isStatic]);
2851
- const renderedRows = useMemo4(() => {
2965
+ const renderedRows = useMemo5(() => {
2852
2966
  if (isStatic) return [];
2853
2967
  const grid = buildGrid(resolvedWidth, resolvedHeight);
2854
2968
  const { cx, cy, outerRadius, innerRadius } = computeWheelGeometry(
@@ -2880,43 +2994,43 @@ function HamsterWheel({
2880
2994
  return buildColorRuns(grid, resolvedWidth, resolvedHeight);
2881
2995
  }, [resolvedWidth, resolvedHeight, frame, spokeAngle, isStatic]);
2882
2996
  if (isStatic) {
2883
- return /* @__PURE__ */ jsx9(Text9, { children: " \u{1F439} toby" });
2997
+ return /* @__PURE__ */ jsx10(Text10, { children: " \u{1F439} toby" });
2884
2998
  }
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)) });
2999
+ return /* @__PURE__ */ jsx10(Box9, { flexDirection: "column", children: renderedRows.map((runs, y) => /* @__PURE__ */ jsx10(Text10, { children: runs.map((run, i) => /* @__PURE__ */ jsx10(Text10, { color: run.fg, backgroundColor: run.bg, children: run.char.repeat(run.length) }, i)) }, y)) });
2886
3000
  }
2887
3001
 
2888
3002
  // src/components/InfoPanel.tsx
2889
- import { Box as Box10, Text as Text10 } from "ink";
2890
- import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
3003
+ import { Box as Box10, Text as Text11 } from "ink";
3004
+ import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
2891
3005
  var formatTokens = (n) => new Intl.NumberFormat().format(n);
2892
3006
  function StatRow({ label, value }) {
2893
- return /* @__PURE__ */ jsxs8(Box10, { children: [
2894
- /* @__PURE__ */ jsxs8(Text10, { dimColor: true, children: [
3007
+ return /* @__PURE__ */ jsxs9(Box10, { children: [
3008
+ /* @__PURE__ */ jsxs9(Text11, { dimColor: true, children: [
2895
3009
  String(label).padStart(9),
2896
3010
  " "
2897
3011
  ] }),
2898
- /* @__PURE__ */ jsx10(Text10, { children: value })
3012
+ /* @__PURE__ */ jsx11(Text11, { children: value })
2899
3013
  ] });
2900
3014
  }
2901
3015
  function InfoPanel({ version: version2, stats }) {
2902
- return /* @__PURE__ */ jsxs8(Box10, { flexDirection: "column", children: [
2903
- /* @__PURE__ */ jsxs8(Text10, { bold: true, color: "#f0a030", children: [
3016
+ return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", children: [
3017
+ /* @__PURE__ */ jsxs9(Text11, { bold: true, color: "#f0a030", children: [
2904
3018
  "toby v",
2905
3019
  version2
2906
3020
  ] }),
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) })
3021
+ stats !== null && /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", marginTop: 1, children: [
3022
+ /* @__PURE__ */ jsx11(StatRow, { label: "Specs", value: stats.totalSpecs }),
3023
+ /* @__PURE__ */ jsx11(StatRow, { label: "Planned", value: stats.planned }),
3024
+ /* @__PURE__ */ jsx11(StatRow, { label: "Done", value: stats.done }),
3025
+ /* @__PURE__ */ jsx11(StatRow, { label: "Tokens", value: formatTokens(stats.totalTokens) })
2912
3026
  ] })
2913
3027
  ] });
2914
3028
  }
2915
3029
 
2916
3030
  // src/components/MainMenu.tsx
2917
- import { Text as Text11, Box as Box11 } from "ink";
3031
+ import { Text as Text12, Box as Box11 } from "ink";
2918
3032
  import SelectInput3 from "ink-select-input";
2919
- import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
3033
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
2920
3034
  var MENU_ITEMS = [
2921
3035
  { label: "plan", value: "plan", description: "Plan specs with AI loop engine" },
2922
3036
  { label: "build", value: "build", description: "Build tasks one-per-spawn with AI" },
@@ -2924,16 +3038,16 @@ var MENU_ITEMS = [
2924
3038
  { label: "config", value: "config", description: "Manage configuration" }
2925
3039
  ];
2926
3040
  function MenuItem({ isSelected = false, label, description }) {
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: [
3041
+ return /* @__PURE__ */ jsxs10(Box11, { children: [
3042
+ /* @__PURE__ */ jsx12(Text12, { color: isSelected ? "blue" : void 0, children: label.padEnd(10) }),
3043
+ description && /* @__PURE__ */ jsxs10(Text12, { dimColor: true, children: [
2930
3044
  "\u2014 ",
2931
3045
  description
2932
3046
  ] })
2933
3047
  ] });
2934
3048
  }
2935
3049
  function MainMenu({ onSelect }) {
2936
- return /* @__PURE__ */ jsx11(Box11, { flexDirection: "column", children: /* @__PURE__ */ jsx11(
3050
+ return /* @__PURE__ */ jsx12(Box11, { flexDirection: "column", children: /* @__PURE__ */ jsx12(
2937
3051
  SelectInput3,
2938
3052
  {
2939
3053
  items: MENU_ITEMS,
@@ -2944,9 +3058,9 @@ function MainMenu({ onSelect }) {
2944
3058
  }
2945
3059
 
2946
3060
  // src/lib/stats.ts
2947
- import fs10 from "fs";
3061
+ import fs11 from "fs";
2948
3062
  function computeProjectStats(cwd) {
2949
- if (!fs10.existsSync(getLocalDir(cwd))) {
3063
+ if (!fs11.existsSync(getLocalDir(cwd))) {
2950
3064
  return null;
2951
3065
  }
2952
3066
  let statusData;
@@ -2988,60 +3102,60 @@ function computeProjectStats(cwd) {
2988
3102
  }
2989
3103
 
2990
3104
  // src/components/Welcome.tsx
2991
- import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
3105
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
2992
3106
  var NARROW_THRESHOLD = 60;
2993
3107
  function Welcome({ version: version2 }) {
2994
- const { exit } = useApp4();
3108
+ const { exit } = useApp5();
2995
3109
  const { stdout } = useStdout2();
2996
- const [selectedCommand, setSelectedCommand] = useState9(null);
2997
- const stats = useMemo5(() => computeProjectStats(), []);
3110
+ const [selectedCommand, setSelectedCommand] = useState10(null);
3111
+ const stats = useMemo6(() => computeProjectStats(), []);
2998
3112
  const isNarrow = (stdout.columns ?? 80) < NARROW_THRESHOLD;
2999
- useEffect8(() => {
3113
+ useEffect9(() => {
3000
3114
  if (selectedCommand === "status") {
3001
3115
  const timer = setTimeout(() => exit(), 0);
3002
3116
  return () => clearTimeout(timer);
3003
3117
  }
3004
3118
  }, [selectedCommand, exit]);
3005
3119
  if (selectedCommand === "plan") {
3006
- return /* @__PURE__ */ jsx12(Plan, {});
3120
+ return /* @__PURE__ */ jsx13(Plan, {});
3007
3121
  }
3008
3122
  if (selectedCommand === "build") {
3009
- return /* @__PURE__ */ jsx12(Build, {});
3123
+ return /* @__PURE__ */ jsx13(Build, {});
3010
3124
  }
3011
3125
  if (selectedCommand === "status") {
3012
- return /* @__PURE__ */ jsx12(Status, { version: version2 });
3126
+ return /* @__PURE__ */ jsx13(Status, { version: version2 });
3013
3127
  }
3014
3128
  if (selectedCommand === "config") {
3015
- return /* @__PURE__ */ jsx12(ConfigEditor, { version: version2 });
3129
+ return /* @__PURE__ */ jsx13(ConfigEditor, { version: version2 });
3016
3130
  }
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: [
3131
+ return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", gap: 1, children: [
3132
+ isNarrow ? /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", children: [
3133
+ /* @__PURE__ */ jsxs11(Text13, { bold: true, color: "#f0a030", children: [
3020
3134
  "\u{1F439} toby v",
3021
3135
  version2
3022
3136
  ] }),
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) })
3137
+ stats !== null && /* @__PURE__ */ jsxs11(Text13, { children: [
3138
+ /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: "Specs: " }),
3139
+ /* @__PURE__ */ jsx13(Text13, { children: stats.totalSpecs }),
3140
+ /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: " \xB7 Planned: " }),
3141
+ /* @__PURE__ */ jsx13(Text13, { children: stats.planned }),
3142
+ /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: " \xB7 Done: " }),
3143
+ /* @__PURE__ */ jsx13(Text13, { children: stats.done }),
3144
+ /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: " \xB7 Tokens: " }),
3145
+ /* @__PURE__ */ jsx13(Text13, { children: formatTokens(stats.totalTokens) })
3032
3146
  ] })
3033
- ] }) : /* @__PURE__ */ jsxs10(Box12, { flexDirection: "row", gap: 2, children: [
3034
- /* @__PURE__ */ jsx12(HamsterWheel, {}),
3035
- /* @__PURE__ */ jsx12(InfoPanel, { version: version2, stats })
3147
+ ] }) : /* @__PURE__ */ jsxs11(Box12, { flexDirection: "row", gap: 2, children: [
3148
+ /* @__PURE__ */ jsx13(HamsterWheel, {}),
3149
+ /* @__PURE__ */ jsx13(InfoPanel, { version: version2, stats })
3036
3150
  ] }),
3037
- /* @__PURE__ */ jsx12(MainMenu, { onSelect: setSelectedCommand })
3151
+ /* @__PURE__ */ jsx13(MainMenu, { onSelect: setSelectedCommand })
3038
3152
  ] });
3039
3153
  }
3040
3154
 
3041
3155
  // src/cli.tsx
3042
- import { jsx as jsx13 } from "react/jsx-runtime";
3156
+ import { jsx as jsx14 } from "react/jsx-runtime";
3043
3157
  function Help({ version: version2 }) {
3044
- return /* @__PURE__ */ jsx13(Text13, { children: `toby v${version2} \u2014 AI-assisted development loop engine
3158
+ return /* @__PURE__ */ jsx14(Text14, { children: `toby v${version2} \u2014 AI-assisted development loop engine
3045
3159
 
3046
3160
  Usage
3047
3161
  $ toby <command> [options]
@@ -3052,6 +3166,7 @@ Commands
3052
3166
  init Initialize toby in current project
3053
3167
  status Show project status
3054
3168
  config Manage configuration
3169
+ clean Delete all transcript files
3055
3170
 
3056
3171
  Options
3057
3172
  --help Show this help
@@ -3062,7 +3177,7 @@ Spec Selection
3062
3177
  --specs=<names> Alias for --spec` });
3063
3178
  }
3064
3179
  function UnknownCommand({ command: command2 }) {
3065
- return /* @__PURE__ */ jsx13(Text13, { color: "red", children: `Unknown command: ${command2}
3180
+ return /* @__PURE__ */ jsx14(Text14, { color: "red", children: `Unknown command: ${command2}
3066
3181
  Run "toby --help" for available commands.` });
3067
3182
  }
3068
3183
  var cli = meow(
@@ -3076,6 +3191,7 @@ Commands
3076
3191
  init Initialize toby in current project
3077
3192
  status Show project status
3078
3193
  config Manage configuration
3194
+ clean Delete all transcript files
3079
3195
 
3080
3196
  Plan Options
3081
3197
  --spec=<query> Target spec(s) by name, slug, number, or comma-separated list
@@ -3113,6 +3229,9 @@ Config Subcommands
3113
3229
  config get <key> Show a config value (dot-notation)
3114
3230
  config set <key> <value> Set a config value
3115
3231
  config set <k>=<v> [<k>=<v>...] Batch set config values
3232
+
3233
+ Clean Options
3234
+ --force Skip confirmation prompt
3116
3235
  `,
3117
3236
  {
3118
3237
  importMeta: import.meta,
@@ -3129,7 +3248,8 @@ Config Subcommands
3129
3248
  buildCli: { type: "string" },
3130
3249
  buildModel: { type: "string" },
3131
3250
  specsDir: { type: "string" },
3132
- session: { type: "string" }
3251
+ session: { type: "string" },
3252
+ force: { type: "boolean", default: false }
3133
3253
  }
3134
3254
  }
3135
3255
  );
@@ -3138,7 +3258,7 @@ var resolvedSpec = cli.flags.specs ?? cli.flags.spec;
3138
3258
  var flags = { ...cli.flags, spec: resolvedSpec };
3139
3259
  var commands = {
3140
3260
  plan: {
3141
- render: (flags2) => /* @__PURE__ */ jsx13(
3261
+ render: (flags2) => /* @__PURE__ */ jsx14(
3142
3262
  Plan,
3143
3263
  {
3144
3264
  spec: flags2.spec,
@@ -3153,7 +3273,7 @@ var commands = {
3153
3273
  waitForExit: true
3154
3274
  },
3155
3275
  build: {
3156
- render: (flags2) => /* @__PURE__ */ jsx13(
3276
+ render: (flags2) => /* @__PURE__ */ jsx14(
3157
3277
  Build,
3158
3278
  {
3159
3279
  spec: flags2.spec,
@@ -3168,7 +3288,7 @@ var commands = {
3168
3288
  waitForExit: true
3169
3289
  },
3170
3290
  init: {
3171
- render: (flags2, _input, version2) => /* @__PURE__ */ jsx13(
3291
+ render: (flags2, _input, version2) => /* @__PURE__ */ jsx14(
3172
3292
  Init,
3173
3293
  {
3174
3294
  version: version2,
@@ -3183,17 +3303,21 @@ var commands = {
3183
3303
  waitForExit: true
3184
3304
  },
3185
3305
  status: {
3186
- render: (flags2, _input, version2) => /* @__PURE__ */ jsx13(Status, { spec: flags2.spec, version: version2 })
3306
+ render: (flags2, _input, version2) => /* @__PURE__ */ jsx14(Status, { spec: flags2.spec, version: version2 })
3307
+ },
3308
+ clean: {
3309
+ render: (flags2) => /* @__PURE__ */ jsx14(Clean, { force: flags2.force }),
3310
+ waitForExit: true
3187
3311
  },
3188
3312
  config: {
3189
3313
  render: (_flags, input, version2) => {
3190
3314
  const [, subcommand, ...rest] = input;
3191
- if (!subcommand) return /* @__PURE__ */ jsx13(ConfigEditor, { version: version2 });
3315
+ if (!subcommand) return /* @__PURE__ */ jsx14(ConfigEditor, { version: version2 });
3192
3316
  if (subcommand === "set" && rest.some((arg) => arg.includes("="))) {
3193
- return /* @__PURE__ */ jsx13(ConfigSetBatch, { pairs: rest.filter((arg) => arg.includes("=")) });
3317
+ return /* @__PURE__ */ jsx14(ConfigSetBatch, { pairs: rest.filter((arg) => arg.includes("=")) });
3194
3318
  }
3195
3319
  const [configKey, value] = rest;
3196
- return /* @__PURE__ */ jsx13(
3320
+ return /* @__PURE__ */ jsx14(
3197
3321
  Config,
3198
3322
  {
3199
3323
  subcommand,
@@ -3210,10 +3334,10 @@ var version = cli.pkg.version ?? "0.0.0";
3210
3334
  var [command] = cli.input;
3211
3335
  if (!command) {
3212
3336
  if (process.stdin.isTTY) {
3213
- const app = render(/* @__PURE__ */ jsx13(Welcome, { version }));
3337
+ const app = render(/* @__PURE__ */ jsx14(Welcome, { version }));
3214
3338
  await app.waitUntilExit();
3215
3339
  } else {
3216
- render(/* @__PURE__ */ jsx13(Help, { version })).unmount();
3340
+ render(/* @__PURE__ */ jsx14(Help, { version })).unmount();
3217
3341
  }
3218
3342
  } else if (command in commands) {
3219
3343
  const entry = commands[command];
@@ -3224,6 +3348,6 @@ if (!command) {
3224
3348
  app.unmount();
3225
3349
  }
3226
3350
  } else {
3227
- render(/* @__PURE__ */ jsx13(UnknownCommand, { command })).unmount();
3351
+ render(/* @__PURE__ */ jsx14(UnknownCommand, { command })).unmount();
3228
3352
  process.exitCode = 1;
3229
3353
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xtiby/toby",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "AI-assisted development loop engine CLI",
5
5
  "repository": {
6
6
  "type": "git",