@0xtiby/toby 1.1.0 → 1.2.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 +272 -104
  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 Text14 } from "ink";
5
+ import { render } from "ink";
6
6
 
7
7
  // src/commands/plan.tsx
8
8
  import { useState as useState3, useEffect as useEffect2, useMemo as useMemo2 } from "react";
@@ -112,6 +112,220 @@ function ensureLocalDir(cwd) {
112
112
  return dir;
113
113
  }
114
114
 
115
+ // src/lib/help.ts
116
+ var SPEC_FLAGS = [
117
+ { name: "--spec=<query>", description: "Target spec(s) by name, slug, number, or list" },
118
+ { name: "--specs=<names>", description: "Alias for --spec" },
119
+ { name: "--all", description: "Process all matching specs" },
120
+ { name: "--iterations=<n>", description: "Override iteration count" },
121
+ { name: "--verbose", description: "Show full CLI output" },
122
+ { name: "--transcript", description: "Save session transcript to file" },
123
+ { name: "--cli=<name>", description: "Override AI CLI (claude, codex, opencode)" },
124
+ { name: "--session=<name>", description: "Name the session for branch/PR naming" }
125
+ ];
126
+ var commandHelp = {
127
+ plan: {
128
+ summary: "Plan specs with AI loop engine",
129
+ usage: ["$ toby plan [options]"],
130
+ flags: SPEC_FLAGS,
131
+ examples: [
132
+ {
133
+ command: "toby plan --spec=auth --cli=claude --session=auth-feature",
134
+ description: 'Plan the auth spec using Claude, naming the session "auth-feature"'
135
+ },
136
+ {
137
+ command: "toby plan --spec=auth,payments --iterations=3 --verbose",
138
+ description: "Plan auth and payments specs with 3 iterations, showing full output"
139
+ },
140
+ {
141
+ command: "toby plan --all --transcript",
142
+ description: "Plan all pending specs and save a transcript of the session"
143
+ }
144
+ ]
145
+ },
146
+ build: {
147
+ summary: "Build tasks one-per-spawn with AI",
148
+ usage: ["$ toby build [options]"],
149
+ flags: SPEC_FLAGS,
150
+ examples: [
151
+ {
152
+ command: "toby build --spec=auth --cli=claude --session=auth-feature",
153
+ description: 'Build the auth spec using Claude, resuming "auth-feature"'
154
+ },
155
+ {
156
+ command: "toby build --all --iterations=5 --transcript",
157
+ description: "Build all planned specs with up to 5 iterations, saving transcripts"
158
+ },
159
+ {
160
+ command: "toby build --spec=2 --verbose",
161
+ description: "Build spec #2 with full CLI output visible"
162
+ }
163
+ ]
164
+ },
165
+ init: {
166
+ summary: "Initialize toby in current project",
167
+ usage: ["$ toby init [options]"],
168
+ flags: [
169
+ {
170
+ name: "--plan-cli=<name>",
171
+ description: "Set plan CLI (claude, codex, opencode)"
172
+ },
173
+ { name: "--plan-model=<id>", description: "Set plan model" },
174
+ {
175
+ name: "--build-cli=<name>",
176
+ description: "Set build CLI (claude, codex, opencode)"
177
+ },
178
+ { name: "--build-model=<id>", description: "Set build model" },
179
+ { name: "--specs-dir=<path>", description: "Set specs directory" },
180
+ {
181
+ name: "--verbose",
182
+ description: "Enable verbose output in config"
183
+ }
184
+ ],
185
+ examples: [
186
+ {
187
+ command: "toby init",
188
+ description: "Launch the interactive setup wizard"
189
+ },
190
+ {
191
+ command: "toby init --plan-cli=claude --build-cli=claude --specs-dir=specs",
192
+ description: "Non-interactive init with required flags (for CI/agents)"
193
+ },
194
+ {
195
+ command: "toby init --plan-cli=codex --build-cli=codex --specs-dir=specs --verbose",
196
+ description: "Initialize with Codex for both phases, verbose enabled"
197
+ }
198
+ ]
199
+ },
200
+ status: {
201
+ summary: "Show project status",
202
+ usage: ["$ toby status [options]"],
203
+ flags: [
204
+ {
205
+ name: "--spec=<query>",
206
+ description: "Show status for a specific spec by name, slug, or number"
207
+ }
208
+ ],
209
+ examples: [
210
+ {
211
+ command: "toby status",
212
+ description: "Show status overview for all specs in the project"
213
+ },
214
+ {
215
+ command: "toby status --spec=auth",
216
+ description: "Show detailed status for the auth spec"
217
+ }
218
+ ]
219
+ },
220
+ config: {
221
+ summary: "Manage configuration",
222
+ usage: [
223
+ "$ toby config Interactive config editor",
224
+ "$ toby config get <key> Show a config value (dot-notation)",
225
+ "$ toby config set <key> <value> Set a config value",
226
+ "$ toby config set <k>=<v> [<k>=<v>...] Batch set values"
227
+ ],
228
+ flags: [],
229
+ examples: [
230
+ {
231
+ command: "toby config",
232
+ description: "Open the interactive config editor"
233
+ },
234
+ {
235
+ command: "toby config get plan.cli",
236
+ description: "Show the configured plan CLI"
237
+ },
238
+ {
239
+ command: "toby config set plan.cli=claude build.iterations=5",
240
+ description: "Batch set plan CLI to claude and build iterations to 5"
241
+ }
242
+ ]
243
+ },
244
+ clean: {
245
+ summary: "Delete session transcripts",
246
+ usage: ["$ toby clean [options]"],
247
+ flags: [
248
+ {
249
+ name: "--force",
250
+ description: "Skip confirmation prompt (required in non-TTY)"
251
+ }
252
+ ],
253
+ examples: [
254
+ {
255
+ command: "toby clean",
256
+ description: "Delete all transcripts with confirmation prompt"
257
+ },
258
+ {
259
+ command: "toby clean --force",
260
+ description: "Delete all transcripts without confirmation (for CI/agents)"
261
+ }
262
+ ]
263
+ }
264
+ };
265
+ function formatCommandHelp(command2, help) {
266
+ const lines = [];
267
+ lines.push(`toby ${command2} \u2014 ${help.summary}`);
268
+ lines.push("");
269
+ lines.push("Usage");
270
+ for (const usage of help.usage) {
271
+ lines.push(` ${usage}`);
272
+ }
273
+ if (help.flags.length > 0) {
274
+ lines.push("");
275
+ lines.push("Options");
276
+ const maxName = Math.max(...help.flags.map((f) => f.name.length));
277
+ for (const flag of help.flags) {
278
+ lines.push(` ${flag.name.padEnd(maxName)} ${flag.description}`);
279
+ }
280
+ }
281
+ lines.push("");
282
+ lines.push("Examples");
283
+ const exampleBlocks = help.examples.map(
284
+ (ex) => ` $ ${ex.command}
285
+ ${ex.description}`
286
+ );
287
+ lines.push(exampleBlocks.join("\n\n"));
288
+ lines.push("");
289
+ return lines.join("\n");
290
+ }
291
+ function formatErrorWithHint(message, validValues, example) {
292
+ const lines = [];
293
+ if (validValues) {
294
+ lines.push(`\u2717 ${message}. Valid options: ${validValues.join(", ")}`);
295
+ } else {
296
+ lines.push(`\u2717 ${message}`);
297
+ }
298
+ if (example) {
299
+ lines.push("");
300
+ lines.push("Example:");
301
+ lines.push(` $ ${example}`);
302
+ }
303
+ lines.push("");
304
+ return lines.join("\n");
305
+ }
306
+ function formatGlobalHelp(version2) {
307
+ const maxCmd = Math.max(
308
+ ...Object.keys(commandHelp).map((c) => c.length)
309
+ );
310
+ const cmdLines = Object.entries(commandHelp).map(([name, h]) => ` ${name.padEnd(maxCmd)} ${h.summary}`).join("\n");
311
+ return [
312
+ `toby v${version2} \u2014 AI-assisted development loop engine`,
313
+ "",
314
+ "Usage",
315
+ " $ toby <command> [options]",
316
+ "",
317
+ "Commands",
318
+ cmdLines,
319
+ "",
320
+ "Options",
321
+ " --help Show help (use with a command for details)",
322
+ " --version Show version",
323
+ "",
324
+ "Run toby <command> --help for command-specific options and examples.",
325
+ ""
326
+ ].join("\n");
327
+ }
328
+
115
329
  // src/lib/config.ts
116
330
  function readConfigFile(filePath) {
117
331
  try {
@@ -154,7 +368,13 @@ function writeConfig(config, filePath) {
154
368
  }
155
369
  function validateCliName(cli2) {
156
370
  if (cli2 && !CLI_NAMES.includes(cli2)) {
157
- throw new Error(`Unknown CLI: ${cli2}. Must be one of: ${CLI_NAMES.join(", ")}`);
371
+ throw new Error(
372
+ formatErrorWithHint(
373
+ `Unknown CLI: ${cli2}`,
374
+ [...CLI_NAMES],
375
+ "toby plan --cli=claude --spec=auth"
376
+ )
377
+ );
158
378
  }
159
379
  }
160
380
  function resolveCommandConfig(config, command2, flags2 = {}) {
@@ -3152,107 +3372,43 @@ function Welcome({ version: version2 }) {
3152
3372
  ] });
3153
3373
  }
3154
3374
 
3375
+ // src/lib/cli-meta.ts
3376
+ var COMMAND_NAMES = Object.keys(commandHelp);
3377
+ var MEOW_FLAGS = {
3378
+ help: { type: "boolean", default: false },
3379
+ spec: { type: "string" },
3380
+ specs: { type: "string" },
3381
+ all: { type: "boolean", default: false },
3382
+ iterations: { type: "number" },
3383
+ verbose: { type: "boolean", default: false },
3384
+ transcript: { type: "boolean" },
3385
+ cli: { type: "string" },
3386
+ planCli: { type: "string" },
3387
+ planModel: { type: "string" },
3388
+ buildCli: { type: "string" },
3389
+ buildModel: { type: "string" },
3390
+ specsDir: { type: "string" },
3391
+ session: { type: "string" },
3392
+ force: { type: "boolean", default: false }
3393
+ };
3394
+ var MEOW_FLAG_NAMES = Object.keys(MEOW_FLAGS);
3395
+
3155
3396
  // src/cli.tsx
3156
3397
  import { jsx as jsx14 } from "react/jsx-runtime";
3157
- function Help({ version: version2 }) {
3158
- return /* @__PURE__ */ jsx14(Text14, { children: `toby v${version2} \u2014 AI-assisted development loop engine
3159
-
3160
- Usage
3161
- $ toby <command> [options]
3162
-
3163
- Commands
3164
- plan Plan specs with AI loop engine
3165
- build Build tasks one-per-spawn with AI
3166
- init Initialize toby in current project
3167
- status Show project status
3168
- config Manage configuration
3169
- clean Delete all transcript files
3170
-
3171
- Options
3172
- --help Show this help
3173
- --version Show version
3174
-
3175
- Spec Selection
3176
- --spec=<name> Single spec or comma-separated (e.g. --spec=auth,payments)
3177
- --specs=<names> Alias for --spec` });
3178
- }
3179
- function UnknownCommand({ command: command2 }) {
3180
- return /* @__PURE__ */ jsx14(Text14, { color: "red", children: `Unknown command: ${command2}
3181
- Run "toby --help" for available commands.` });
3182
- }
3183
- var cli = meow(
3184
- `
3185
- Usage
3186
- $ toby <command> [options]
3187
-
3188
- Commands
3189
- plan Plan specs with AI loop engine
3190
- build Build tasks one-per-spawn with AI
3191
- init Initialize toby in current project
3192
- status Show project status
3193
- config Manage configuration
3194
- clean Delete all transcript files
3195
-
3196
- Plan Options
3197
- --spec=<query> Target spec(s) by name, slug, number, or comma-separated list
3198
- --specs=<names> Alias for --spec with comma-separated specs
3199
- --all Plan all pending specs
3200
- --iterations=<n> Override iteration count
3201
- --verbose Show full CLI output
3202
- --transcript Save session transcript to file
3203
- --cli=<name> Override AI CLI (claude, codex, opencode)
3204
- --session=<name> Name the session for branch/PR naming
3205
-
3206
- Build Options
3207
- --spec=<query> Target spec(s) by name, slug, number, or comma-separated list
3208
- --specs=<names> Alias for --spec with comma-separated specs
3209
- --all Build all planned specs in order
3210
- --iterations=<n> Override max iteration count
3211
- --verbose Show full CLI output
3212
- --transcript Save session transcript to file
3213
- --cli=<name> Override AI CLI (claude, codex, opencode)
3214
- --session=<name> Name the session for branch/PR naming
3215
-
3216
- Status Options
3217
- --spec=<query> Show status for a spec by name, slug, or number
3218
-
3219
- Init Options
3220
- --plan-cli=<name> Set plan CLI (claude, codex, opencode)
3221
- --plan-model=<id> Set plan model
3222
- --build-cli=<name> Set build CLI (claude, codex, opencode)
3223
- --build-model=<id> Set build model
3224
- --specs-dir=<path> Set specs directory
3225
- --verbose Enable verbose output in config
3226
-
3227
- Config Subcommands
3228
- config Interactive config editor
3229
- config get <key> Show a config value (dot-notation)
3230
- config set <key> <value> Set a config value
3231
- config set <k>=<v> [<k>=<v>...] Batch set config values
3232
-
3233
- Clean Options
3234
- --force Skip confirmation prompt
3235
- `,
3236
- {
3237
- importMeta: import.meta,
3238
- flags: {
3239
- spec: { type: "string" },
3240
- specs: { type: "string" },
3241
- all: { type: "boolean", default: false },
3242
- iterations: { type: "number" },
3243
- verbose: { type: "boolean", default: false },
3244
- transcript: { type: "boolean" },
3245
- cli: { type: "string" },
3246
- planCli: { type: "string" },
3247
- planModel: { type: "string" },
3248
- buildCli: { type: "string" },
3249
- buildModel: { type: "string" },
3250
- specsDir: { type: "string" },
3251
- session: { type: "string" },
3252
- force: { type: "boolean", default: false }
3253
- }
3254
- }
3255
- );
3398
+ function writeUnknownCommandError(command2) {
3399
+ process.stderr.write(
3400
+ formatErrorWithHint(
3401
+ `Unknown command: ${command2}`,
3402
+ COMMAND_NAMES,
3403
+ "toby --help"
3404
+ )
3405
+ );
3406
+ }
3407
+ var cli = meow("", {
3408
+ importMeta: import.meta,
3409
+ autoHelp: false,
3410
+ flags: MEOW_FLAGS
3411
+ });
3256
3412
  ensureGlobalDir();
3257
3413
  var resolvedSpec = cli.flags.specs ?? cli.flags.spec;
3258
3414
  var flags = { ...cli.flags, spec: resolvedSpec };
@@ -3332,12 +3488,24 @@ var commands = {
3332
3488
  };
3333
3489
  var version = cli.pkg.version ?? "0.0.0";
3334
3490
  var [command] = cli.input;
3335
- if (!command) {
3491
+ if (cli.flags.help) {
3492
+ if (!command || command in commands) {
3493
+ if (command && command in commandHelp) {
3494
+ process.stdout.write(formatCommandHelp(command, commandHelp[command]));
3495
+ } else {
3496
+ process.stdout.write(formatGlobalHelp(version));
3497
+ }
3498
+ process.exitCode = 0;
3499
+ } else {
3500
+ writeUnknownCommandError(command);
3501
+ process.exitCode = 1;
3502
+ }
3503
+ } else if (!command) {
3336
3504
  if (process.stdin.isTTY) {
3337
3505
  const app = render(/* @__PURE__ */ jsx14(Welcome, { version }));
3338
3506
  await app.waitUntilExit();
3339
3507
  } else {
3340
- render(/* @__PURE__ */ jsx14(Help, { version })).unmount();
3508
+ process.stdout.write(formatGlobalHelp(version));
3341
3509
  }
3342
3510
  } else if (command in commands) {
3343
3511
  const entry = commands[command];
@@ -3348,6 +3516,6 @@ if (!command) {
3348
3516
  app.unmount();
3349
3517
  }
3350
3518
  } else {
3351
- render(/* @__PURE__ */ jsx14(UnknownCommand, { command })).unmount();
3519
+ writeUnknownCommandError(command);
3352
3520
  process.exitCode = 1;
3353
3521
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xtiby/toby",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "AI-assisted development loop engine CLI",
5
5
  "repository": {
6
6
  "type": "git",