@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.
- package/dist/cli.js +272 -104
- 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
|
|
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(
|
|
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
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
3519
|
+
writeUnknownCommandError(command);
|
|
3352
3520
|
process.exitCode = 1;
|
|
3353
3521
|
}
|