@cam5/baby-bird 0.1.0 → 0.1.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 CHANGED
@@ -16,18 +16,20 @@ import {
16
16
  projectConfigPath,
17
17
  relativeTime,
18
18
  resolveLlm,
19
+ supports256Colors,
20
+ wrap,
19
21
  writeMaybePaged,
20
22
  writeStdout
21
- } from "./chunk-RWSCST2I.js";
23
+ } from "./chunk-7ALXKEST.js";
22
24
 
23
25
  // src/cli/main.ts
24
26
  import { Command, InvalidArgumentError } from "commander";
25
- import pc4 from "picocolors";
27
+ import pc5 from "picocolors";
26
28
 
27
29
  // package.json
28
30
  var package_default = {
29
31
  name: "@cam5/baby-bird",
30
- version: "0.1.0",
32
+ version: "0.1.1",
31
33
  description: "Guided code tours for git changes, on the command line.",
32
34
  license: "MIT",
33
35
  type: "module",
@@ -73,6 +75,7 @@ var package_default = {
73
75
  },
74
76
  dependencies: {
75
77
  commander: "^15.0.0",
78
+ lowlight: "^3.3.0",
76
79
  picocolors: "^1.1.1",
77
80
  zod: "^4.6.2"
78
81
  },
@@ -101,6 +104,8 @@ function flagsToOverrides(flags) {
101
104
  else if (flags.color === false) o.render = { color: "never" };
102
105
  if (flags.cache === false) o.cache = { enabled: false };
103
106
  if (flags.pager === false) o.render = { ...o.render ?? {}, pager: "never" };
107
+ if (flags.highlight === false) o.render = { ...o.render ?? {}, highlight: "never" };
108
+ if (flags.theme) o.render = { ...o.render ?? {}, theme: flags.theme };
104
109
  return o;
105
110
  }
106
111
  async function openSession(flags, opts) {
@@ -126,6 +131,11 @@ function resolveColor(mode) {
126
131
  if (mode === "never") return false;
127
132
  return Boolean(process.stdout.isTTY) && process.env.TERM !== "dumb";
128
133
  }
134
+ function resolveHighlight(mode, colorEnabled) {
135
+ if (!colorEnabled || mode === "never") return false;
136
+ if (mode === "always") return true;
137
+ return supports256Colors();
138
+ }
129
139
  function terminalWidth(configured, stream = process.stdout) {
130
140
  return configured ?? (stream.columns || 80);
131
141
  }
@@ -227,11 +237,239 @@ Run \`bb config\` to see the effective configuration and available presets.
227
237
  `);
228
238
  }
229
239
 
240
+ // src/cli/progress.ts
241
+ import pc4 from "picocolors";
242
+ var SPINNER = ["\u2722", "\u2733", "\u2736", "\u273B", "\u273D", "\u273B", "\u2736", "\u2733"];
243
+ var VERBS = ["Hatching", "Pecking", "Nesting", "Chirping", "Preening", "Fledging", "Brooding", "Warbling", "Peeping"];
244
+ var THINKING_TAIL_CHARS = 2e3;
245
+ var VERB_INTERVAL_MS = 7500;
246
+ var LiveProgress = class {
247
+ constructor(stream, opts) {
248
+ this.stream = stream;
249
+ this.opts = opts;
250
+ this.now = opts.now ?? Date.now;
251
+ this.startedAt = this.now();
252
+ this.verbs = opts.verb ? [opts.verb] : opts.verbs && opts.verbs.length ? opts.verbs : shuffle(VERBS);
253
+ this.windowLines = opts.windowLines ?? 5;
254
+ }
255
+ stream;
256
+ opts;
257
+ phaseLabel = "";
258
+ stage = "prep";
259
+ thinking = "";
260
+ pulses = 0;
261
+ answer = "";
262
+ titles = [];
263
+ notices = [];
264
+ outputBytes = 0;
265
+ usage = {};
266
+ startedAt;
267
+ frameIndex = 0;
268
+ lastLines = 0;
269
+ timer = null;
270
+ stopped = false;
271
+ verbs;
272
+ now;
273
+ windowLines;
274
+ onSigint = () => {
275
+ this.stop();
276
+ process.exit(130);
277
+ };
278
+ start() {
279
+ this.stream.write("\x1B[?25l");
280
+ process.once("SIGINT", this.onSigint);
281
+ this.timer = setInterval(() => {
282
+ this.frameIndex++;
283
+ this.render();
284
+ }, this.opts.frameMs ?? 80);
285
+ this.timer.unref?.();
286
+ this.render();
287
+ }
288
+ phase(label) {
289
+ this.phaseLabel = label;
290
+ if (/^asking/i.test(label)) {
291
+ this.stage = "thinking";
292
+ this.thinking = "";
293
+ this.pulses = 0;
294
+ this.answer = "";
295
+ this.titles = [];
296
+ this.notices = [];
297
+ this.outputBytes = 0;
298
+ } else if (this.stage !== "prep") {
299
+ this.stage = "prep";
300
+ }
301
+ this.render();
302
+ }
303
+ llm(event) {
304
+ switch (event.type) {
305
+ case "thinking":
306
+ this.thinking += event.text;
307
+ this.stage = "thinking";
308
+ break;
309
+ case "thinking-pulse":
310
+ this.pulses++;
311
+ this.stage = "thinking";
312
+ break;
313
+ case "answer-start":
314
+ this.answer = "";
315
+ this.titles = [];
316
+ break;
317
+ case "notice":
318
+ this.notices.push(event.text);
319
+ break;
320
+ case "text":
321
+ this.answer += event.text;
322
+ this.titles = extractTitles(this.answer);
323
+ this.stage = "writing";
324
+ break;
325
+ case "output":
326
+ this.outputBytes = event.bytes;
327
+ this.stage = "output";
328
+ break;
329
+ case "usage":
330
+ if (event.outputTokens !== void 0) this.usage.outputTokens = event.outputTokens;
331
+ if (event.thinkingTokens !== void 0) this.usage.thinkingTokens = event.thinkingTokens;
332
+ if (event.model !== void 0) this.usage.model = event.model;
333
+ break;
334
+ default:
335
+ break;
336
+ }
337
+ }
338
+ /** The lines that make up the current status block. */
339
+ frame() {
340
+ const c = pc4.createColors(this.opts.color);
341
+ const width = Math.max(30, this.opts.width);
342
+ const spin = c.magenta(SPINNER[this.frameIndex % SPINNER.length]);
343
+ const elapsed = this.elapsed();
344
+ const fit = (s) => s.length > width - 1 ? s.slice(0, width - 2) + "\u2026" : s;
345
+ const lines = [];
346
+ switch (this.stage) {
347
+ case "prep":
348
+ lines.push(`${spin} ${fit(this.phaseLabel || "Starting")}\u2026 ${c.dim(elapsed)}`);
349
+ break;
350
+ case "thinking": {
351
+ const meta = [elapsed, this.phaseLabel.replace(/^asking\s+/i, "")].filter(Boolean).join(" \xB7 ");
352
+ lines.push(`${spin} ${this.verb()}\u2026 ${c.dim(meta)}`);
353
+ for (const n of this.notices.slice(-1)) lines.push(` ${c.yellow("\u21BB")} ${c.yellow(fit(n).slice(0, width - 4))}`);
354
+ if (this.thinking) {
355
+ const tail = this.thinking.slice(-THINKING_TAIL_CHARS).replace(/\s+/g, " ").trim();
356
+ const wrapped = wrap(tail, width - 4).slice(-this.windowLines);
357
+ for (const l of wrapped) lines.push(` ${c.dim("\u2502")} ${c.dim(l)}`);
358
+ } else if (this.pulses > 0) {
359
+ const room = Math.max(8, width - 16);
360
+ const n = this.pulses % (room + 1);
361
+ lines.push(` ${c.dim("\u2502")} ${c.dim("reasoning")} ${c.magenta("\xB7".repeat(n))}`);
362
+ }
363
+ break;
364
+ }
365
+ case "writing": {
366
+ const n = Math.max(0, this.titles.length - 1);
367
+ lines.push(`${spin} Writing the tour\u2026 ${c.dim(`${elapsed} \xB7 ${n} section${n === 1 ? "" : "s"} so far`)}`);
368
+ for (const note of this.notices.slice(-1)) lines.push(` ${c.yellow("\u21BB")} ${c.yellow(fit(note).slice(0, width - 4))}`);
369
+ const [tourTitle, ...sections] = this.titles;
370
+ const items = [];
371
+ if (tourTitle) items.push(` \u{1F423} ${c.bold(fit(tourTitle).slice(0, width - 6))}`);
372
+ sections.forEach((t) => items.push(` ${c.green("\u2713")} ${fit(t).slice(0, width - 5)}`));
373
+ for (const l of items.slice(-this.windowLines)) lines.push(l);
374
+ break;
375
+ }
376
+ case "output":
377
+ lines.push(`${spin} ${this.verb()}\u2026 ${c.dim(`${elapsed} \xB7 ${formatBytes(this.outputBytes)} received`)}`);
378
+ break;
379
+ }
380
+ return lines;
381
+ }
382
+ render() {
383
+ if (this.stopped) return;
384
+ const lines = this.frame();
385
+ this.stream.write(this.erase() + lines.join("\n") + "\n");
386
+ this.lastLines = lines.length;
387
+ }
388
+ /** Clear the block, restore the cursor, and optionally leave a final line behind. */
389
+ stop(finalLine) {
390
+ if (this.stopped) return;
391
+ this.stopped = true;
392
+ if (this.timer) clearInterval(this.timer);
393
+ process.removeListener("SIGINT", this.onSigint);
394
+ this.stream.write(this.erase() + (finalLine ? finalLine + "\n" : "") + "\x1B[?25h");
395
+ this.lastLines = 0;
396
+ }
397
+ /** A one-line summary of the model call, for the final line. */
398
+ summary() {
399
+ const c = pc4.createColors(this.opts.color);
400
+ const parts = [`Hatched in ${this.elapsed()}`];
401
+ if (this.usage.outputTokens) {
402
+ parts.push(`${formatCount(this.usage.outputTokens)} tokens${this.usage.thinkingTokens ? ` (${formatCount(this.usage.thinkingTokens)} thinking)` : ""}`);
403
+ }
404
+ if (this.usage.model) parts.push(this.usage.model);
405
+ return c.dim(`\u273B ${parts.join(" \xB7 ")}`);
406
+ }
407
+ /** The current verb; rotates every verbIntervalMs so long waits do not stare at one word. */
408
+ verb() {
409
+ const step = Math.floor((this.now() - this.startedAt) / (this.opts.verbIntervalMs ?? VERB_INTERVAL_MS));
410
+ return this.verbs[step % this.verbs.length];
411
+ }
412
+ elapsed() {
413
+ const s = Math.max(0, Math.round((this.now() - this.startedAt) / 1e3));
414
+ return s >= 60 ? `${Math.floor(s / 60)}m ${s % 60}s` : `${s}s`;
415
+ }
416
+ erase() {
417
+ return this.lastLines ? `\x1B[${this.lastLines}A\x1B[0J` : "";
418
+ }
419
+ };
420
+ function extractTitles(text) {
421
+ const out = [];
422
+ for (const m of text.matchAll(/"title"\s*:\s*"((?:[^"\\]|\\.)*)"/g)) {
423
+ out.push(m[1].replace(/\\(["\\/bfnrt]|u[0-9a-fA-F]{4})/g, (_, esc) => {
424
+ switch (esc[0]) {
425
+ case '"':
426
+ return '"';
427
+ case "\\":
428
+ return "\\";
429
+ case "/":
430
+ return "/";
431
+ case "n":
432
+ return "\n";
433
+ case "t":
434
+ return " ";
435
+ case "u":
436
+ return String.fromCharCode(parseInt(esc.slice(1), 16));
437
+ default:
438
+ return "";
439
+ }
440
+ }));
441
+ }
442
+ return out;
443
+ }
444
+ function loggingProgress(log) {
445
+ return {
446
+ phase: (label) => log(label),
447
+ llm: () => {
448
+ }
449
+ };
450
+ }
451
+ function shuffle(items) {
452
+ const out = [...items];
453
+ for (let i = out.length - 1; i > 0; i--) {
454
+ const j = Math.floor(Math.random() * (i + 1));
455
+ [out[i], out[j]] = [out[j], out[i]];
456
+ }
457
+ return out;
458
+ }
459
+ function formatBytes(n) {
460
+ return n < 1024 ? `${n} B` : `${(n / 1024).toFixed(1)} KB`;
461
+ }
462
+ function formatCount(n) {
463
+ return n >= 1e3 ? `${(n / 1e3).toFixed(1)}k` : String(n);
464
+ }
465
+
230
466
  // src/cli/tour.ts
231
467
  async function tourCommand(rangeArg, flags) {
232
468
  const session = await openSession(flags, { requireRepo: true });
233
469
  if (!session.root) throw new NotARepoError(session.cwd);
234
470
  const { config } = session.loaded;
471
+ const live = flags.progress !== false && !flags.debug && Boolean(process.stderr.isTTY) && !flags.dumpPrompt;
472
+ const progress = live ? new LiveProgress(process.stderr, { color: session.colorEnabled, width: terminalWidth(null, process.stderr) }) : loggingProgress(session.debug);
235
473
  const options = {
236
474
  cwd: session.root,
237
475
  config,
@@ -240,14 +478,23 @@ async function tourCommand(rangeArg, flags) {
240
478
  refresh: flags.refresh,
241
479
  noCache: flags.cache === false,
242
480
  debug: session.debug,
243
- warn: session.warn
481
+ warn: session.warn,
482
+ progress
244
483
  };
245
- const prepared = await prepareTour(options);
246
- if (flags.dumpPrompt) {
247
- await writeStdout(prepared.built.prompt.endsWith("\n") ? prepared.built.prompt : prepared.built.prompt + "\n");
248
- return;
484
+ if (progress instanceof LiveProgress) progress.start();
485
+ let result;
486
+ try {
487
+ const prepared = await prepareTour(options);
488
+ if (flags.dumpPrompt) {
489
+ await writeStdout(prepared.built.prompt.endsWith("\n") ? prepared.built.prompt : prepared.built.prompt + "\n");
490
+ return;
491
+ }
492
+ result = await generateTour(options, prepared);
493
+ } catch (err) {
494
+ if (progress instanceof LiveProgress) progress.stop();
495
+ throw err;
249
496
  }
250
- const result = await generateTour(options, prepared);
497
+ if (progress instanceof LiveProgress) progress.stop(result.fromCache ? void 0 : progress.summary());
251
498
  if (flags.json) {
252
499
  await writeStdout(JSON.stringify(result.tour, null, 2) + "\n");
253
500
  return;
@@ -257,7 +504,9 @@ async function tourCommand(rangeArg, flags) {
257
504
  color: session.colorEnabled,
258
505
  width: terminalWidth(config.render.width),
259
506
  section: flags.section,
260
- fromCache: result.fromCache
507
+ fromCache: result.fromCache,
508
+ highlight: resolveHighlight(config.render.highlight, session.colorEnabled),
509
+ theme: config.render.theme
261
510
  });
262
511
  await writeMaybePaged(output, {
263
512
  mode: config.render.pager,
@@ -280,8 +529,11 @@ process.stdout.on("error", (err) => {
280
529
  throw err;
281
530
  });
282
531
  var program = new Command();
283
- program.name("bb").description("Guided code tours for git changes, on the command line.").version(package_default.version, "-V, --version").configureOutput({ outputError: (str, write) => write(pc4.red(str)) }).showHelpAfterError("(run with --help for usage)");
284
- addGlobalFlags(program).argument("[range]", "what to tour: A..B, A...B, or a single ref (compared at its merge-base with HEAD)").option("-w, --working", "tour uncommitted changes in the working tree (tracked and untracked)").option("-s, --staged", "tour staged changes only").option("--section <n>", "render only section <n>", positiveInt).option("--json", "print the tour as JSON instead of rendering it").option("--dump-prompt", "print the prompt that would be sent to the model and exit").option("--refresh", "ignore a cached tour and regenerate it").option("--no-cache", "neither read nor write the tour cache").option("--no-pager", "never pipe output through a pager").addHelpText(
532
+ program.name("bb").description("Guided code tours for git changes, on the command line.").version(package_default.version, "-V, --version").configureOutput({ outputError: (str, write) => write(pc5.red(str)) }).showHelpAfterError("(run with --help for usage)");
533
+ addGlobalFlags(program).argument("[range]", "what to tour: A..B, A...B, or a single ref (compared at its merge-base with HEAD)").option("-w, --working", "tour uncommitted changes in the working tree (tracked and untracked)").option("-s, --staged", "tour staged changes only").option("--section <n>", "render only section <n>", positiveInt).option("--json", "print the tour as JSON instead of rendering it").option("--dump-prompt", "print the prompt that would be sent to the model and exit").option("--refresh", "ignore a cached tour and regenerate it").option("--no-cache", "neither read nor write the tour cache").option("--no-pager", "never pipe output through a pager").option("--no-highlight", "plain green/red excerpts instead of syntax colors with tinted rows").option("--theme <name>", "background tint palette for added/removed lines: dark or light", (v) => {
534
+ if (v !== "dark" && v !== "light") throw new InvalidArgumentError("must be dark or light");
535
+ return v;
536
+ }).option("--no-progress", "do not show the live status block while generating").addHelpText(
285
537
  "after",
286
538
  `
287
539
  Examples:
@@ -305,21 +557,21 @@ addGlobalFlags(program.command("init").description("write a starter .baby-bird/c
305
557
  program.parseAsync(process.argv).catch((err) => {
306
558
  const debug = process.argv.includes("--debug");
307
559
  if (err instanceof BbError) {
308
- process.stderr.write(pc4.red(`error: ${err.message}
560
+ process.stderr.write(pc5.red(`error: ${err.message}
309
561
  `));
310
- if (err.hint) process.stderr.write(pc4.dim(`${err.hint}
562
+ if (err.hint) process.stderr.write(pc5.dim(`${err.hint}
311
563
  `));
312
- if (debug && err instanceof BadLlmOutputError) process.stderr.write(pc4.dim(`--- raw model output ---
564
+ if (debug && err instanceof BadLlmOutputError) process.stderr.write(pc5.dim(`--- raw model output ---
313
565
  ${err.raw}
314
566
  `));
315
- if (debug && err.cause) process.stderr.write(pc4.dim(`${String(err.cause.stack ?? err.cause)}
567
+ if (debug && err.cause) process.stderr.write(pc5.dim(`${String(err.cause.stack ?? err.cause)}
316
568
  `));
317
569
  process.exitCode = err.exitCode;
318
570
  return;
319
571
  }
320
- process.stderr.write(pc4.red(`error: ${err.message ?? String(err)}
572
+ process.stderr.write(pc5.red(`error: ${err.message ?? String(err)}
321
573
  `));
322
- if (debug && err.stack) process.stderr.write(pc4.dim(`${err.stack}
574
+ if (debug && err.stack) process.stderr.write(pc5.dim(`${err.stack}
323
575
  `));
324
576
  process.exitCode = 1;
325
577
  });
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/main.ts","../package.json","../src/cli/cache-cmd.ts","../src/cli/shared.ts","../src/cli/config-cmd.ts","../src/cli/init-cmd.ts","../src/cli/tour.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command, InvalidArgumentError } from 'commander';\nimport pc from 'picocolors';\nimport pkg from '../../package.json' with { type: 'json' };\nimport { BadLlmOutputError, BbError } from '../core/errors.js';\nimport { cacheClearCommand, cacheLsCommand, cachePathCommand } from './cache-cmd.js';\nimport { configCommand } from './config-cmd.js';\nimport { initCommand } from './init-cmd.js';\nimport { tourCommand } from './tour.js';\n\nfunction positiveInt(value: string): number {\n const n = Number(value);\n if (!Number.isInteger(n) || n < 1) throw new InvalidArgumentError('must be a positive integer');\n return n;\n}\n\nfunction addGlobalFlags(cmd: Command): Command {\n return cmd\n .option('-C, --cwd <dir>', 'run as if started in <dir>')\n .option('--preset <name>', 'LLM preset to use (see `bb config`)')\n .option('--color', 'force colored output')\n .option('--no-color', 'disable colored output')\n .option('--debug', 'print diagnostics (resolved range, prompt size, raw model output) to stderr');\n}\n\n// A reader that quits early (`bb | head`) is a normal end, not a crash.\nprocess.stdout.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EPIPE') process.exit(0);\n throw err;\n});\n\nconst program = new Command();\n\nprogram\n .name('bb')\n .description('Guided code tours for git changes, on the command line.')\n .version(pkg.version, '-V, --version')\n .configureOutput({ outputError: (str, write) => write(pc.red(str)) })\n .showHelpAfterError('(run with --help for usage)');\n\naddGlobalFlags(program)\n .argument('[range]', 'what to tour: A..B, A...B, or a single ref (compared at its merge-base with HEAD)')\n .option('-w, --working', 'tour uncommitted changes in the working tree (tracked and untracked)')\n .option('-s, --staged', 'tour staged changes only')\n .option('--section <n>', 'render only section <n>', positiveInt)\n .option('--json', 'print the tour as JSON instead of rendering it')\n .option('--dump-prompt', 'print the prompt that would be sent to the model and exit')\n .option('--refresh', 'ignore a cached tour and regenerate it')\n .option('--no-cache', 'neither read nor write the tour cache')\n .option('--no-pager', 'never pipe output through a pager')\n .addHelpText(\n 'after',\n `\nExamples:\n bb tour the current branch (dirty tree, PR base, nearest branch, or default branch)\n bb main..feature tour an explicit range\n bb HEAD~3 tour the last three commits\n bb --staged tour what you are about to commit\n bb --section 2 show only the second section\n bb --json | jq machine-readable output\n bb --preset claude-sonnet --refresh\n`,\n )\n .action(async (range: string | undefined, flags) => {\n await tourCommand(range, flags);\n });\n\nconst cache = program.command('cache').description('manage cached tours');\naddGlobalFlags(cache.command('ls').description('list cached tours')).action(cacheLsCommand);\naddGlobalFlags(cache.command('clear').description('delete all cached tours')).action(cacheClearCommand);\naddGlobalFlags(cache.command('path').description('print the cache directory')).action(cachePathCommand);\n\naddGlobalFlags(program.command('config').description('show the effective configuration, its sources, and available presets'))\n .option('--json', 'print only the effective config as JSON')\n .action(configCommand);\n\naddGlobalFlags(program.command('init').description('write a starter .baby-bird/config.json in this repository'))\n .option('--force', 'overwrite an existing project config')\n .action(initCommand);\n\nprogram.parseAsync(process.argv).catch((err: unknown) => {\n const debug = process.argv.includes('--debug');\n if (err instanceof BbError) {\n process.stderr.write(pc.red(`error: ${err.message}\\n`));\n if (err.hint) process.stderr.write(pc.dim(`${err.hint}\\n`));\n if (debug && err instanceof BadLlmOutputError) process.stderr.write(pc.dim(`--- raw model output ---\\n${err.raw}\\n`));\n if (debug && err.cause) process.stderr.write(pc.dim(`${String((err.cause as Error).stack ?? err.cause)}\\n`));\n process.exitCode = err.exitCode;\n return;\n }\n process.stderr.write(pc.red(`error: ${(err as Error).message ?? String(err)}\\n`));\n if (debug && (err as Error).stack) process.stderr.write(pc.dim(`${(err as Error).stack}\\n`));\n process.exitCode = 1;\n});\n","{\n \"name\": \"@cam5/baby-bird\",\n \"version\": \"0.1.0\",\n \"description\": \"Guided code tours for git changes, on the command line.\",\n \"license\": \"MIT\",\n \"type\": \"module\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/cam5/baby-bird.git\"\n },\n \"keywords\": [\n \"git\",\n \"code-review\",\n \"diff\",\n \"llm\",\n \"cli\",\n \"code-tour\"\n ],\n \"bin\": {\n \"bb\": \"dist/cli.js\",\n \"baby-bird\": \"dist/cli.js\"\n },\n \"main\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\"\n }\n },\n \"files\": [\n \"dist\",\n \"README.md\"\n ],\n \"engines\": {\n \"node\": \">=22\"\n },\n \"packageManager\": \"pnpm@10.33.0\",\n \"scripts\": {\n \"dev\": \"tsx src/cli/main.ts\",\n \"build\": \"tsup\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"typecheck\": \"tsc --noEmit\",\n \"prepublishOnly\": \"pnpm typecheck && pnpm test && pnpm build\"\n },\n \"dependencies\": {\n \"commander\": \"^15.0.0\",\n \"picocolors\": \"^1.1.1\",\n \"zod\": \"^4.6.2\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^22.20.2\",\n \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.23.13\",\n \"typescript\": \"^5.9.3\",\n \"vitest\": \"^5.0.0\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n","import pc from 'picocolors';\nimport { TourCache } from '../core/cache.js';\nimport { describeSource, relativeTime } from '../render/cli.js';\nimport { openSession, type GlobalFlags } from './shared.js';\n\nexport async function cacheLsCommand(flags: GlobalFlags): Promise<void> {\n const session = await openSession(flags, { requireRepo: false });\n const c = pc.createColors(session.colorEnabled);\n const cache = new TourCache(session.loaded.cacheDir);\n const entries = await cache.list();\n if (entries.length === 0) {\n process.stdout.write(`No cached tours in ${cache.toursDir}\\n`);\n return;\n }\n for (const e of entries) {\n const t = e.tour;\n process.stdout.write(\n `${c.dim(e.key.slice(0, 12))} ${relativeTime(t.generatedAt).padEnd(12)} ${c.bold(t.title)}\\n` +\n `${' '.repeat(14)}${c.dim(describeSource(t.source))}${t.generator.preset ? c.dim(` · ${t.generator.preset}`) : ''}\\n`,\n );\n }\n}\n\nexport async function cacheClearCommand(flags: GlobalFlags): Promise<void> {\n const session = await openSession(flags, { requireRepo: false });\n const cache = new TourCache(session.loaded.cacheDir);\n const n = await cache.clear();\n process.stdout.write(`Removed ${n} cached tour${n === 1 ? '' : 's'} from ${cache.toursDir}\\n`);\n}\n\nexport async function cachePathCommand(flags: GlobalFlags): Promise<void> {\n const session = await openSession(flags, { requireRepo: false });\n process.stdout.write(new TourCache(session.loaded.cacheDir).toursDir + '\\n');\n}\n","import pc from 'picocolors';\nimport { resolve } from 'node:path';\nimport type { PartialConfig } from '../core/config.js';\nimport { loadConfig, type LoadedConfig } from '../core/config.js';\nimport { gitRoot } from '../git/exec.js';\n\nexport interface GlobalFlags {\n cwd?: string;\n debug?: boolean;\n color?: boolean;\n preset?: string;\n cache?: boolean;\n pager?: boolean;\n}\n\nexport interface Session {\n /** Directory the user pointed at (resolved). */\n cwd: string;\n /** Git root, or null when not in a repository. */\n root: string | null;\n loaded: LoadedConfig;\n debug: (msg: string) => void;\n warn: (msg: string) => void;\n colorEnabled: boolean;\n}\n\nexport function flagsToOverrides(flags: GlobalFlags): PartialConfig {\n const o: PartialConfig = {};\n if (flags.preset) o.llm = { preset: flags.preset };\n if (flags.color === true) o.render = { color: 'always' };\n else if (flags.color === false) o.render = { color: 'never' };\n if (flags.cache === false) o.cache = { enabled: false };\n if (flags.pager === false) o.render = { ...(o.render ?? {}), pager: 'never' };\n return o;\n}\n\nexport async function openSession(flags: GlobalFlags, opts: { requireRepo: boolean }): Promise<Session> {\n const cwd = resolve(flags.cwd ?? process.cwd());\n let root: string | null = null;\n try {\n root = await gitRoot(cwd);\n } catch (err) {\n if (opts.requireRepo) throw err;\n }\n const loaded = await loadConfig({ gitRoot: root, env: process.env, overrides: flagsToOverrides(flags) });\n const colorEnabled = resolveColor(loaded.config.render.color);\n const c = pc.createColors(colorEnabled);\n const debug = flags.debug ? (msg: string) => process.stderr.write(c.dim(`[bb] ${msg}\\n`)) : () => {};\n const warn = (msg: string) => process.stderr.write(c.yellow(`warning: ${msg}\\n`));\n return { cwd, root, loaded, debug, warn, colorEnabled };\n}\n\nexport function resolveColor(mode: 'auto' | 'always' | 'never'): boolean {\n if (mode === 'always') return true;\n if (mode === 'never') return false;\n return Boolean(process.stdout.isTTY) && process.env.TERM !== 'dumb';\n}\n\nexport function terminalWidth(configured: number | null, stream: { columns?: number } = process.stdout): number {\n return configured ?? (stream.columns || 80);\n}\n","import pc from 'picocolors';\nimport { allPresets, resolveLlm } from '../core/config.js';\nimport { ConfigError } from '../core/errors.js';\nimport { CommandProvider } from '../llm/command.js';\nimport { openSession, type GlobalFlags } from './shared.js';\n\nexport async function configCommand(flags: GlobalFlags & { json?: boolean }): Promise<void> {\n const session = await openSession(flags, { requireRepo: false });\n const { config, layers, cacheDir } = session.loaded;\n\n if (flags.json) {\n process.stdout.write(JSON.stringify(config, null, 2) + '\\n');\n return;\n }\n\n const c = pc.createColors(session.colorEnabled);\n const out: string[] = [];\n out.push(c.bold('Layers') + c.dim(' (later layers win; objects merge, arrays replace)'));\n for (const layer of layers) {\n const status = layer.found ? c.green('applied') : c.dim('not found');\n const where = layer.path ?? (layer.detail || (layer.name === 'defaults' ? 'built-in' : layer.name === 'flags' ? 'command line' : ''));\n out.push(` ${layer.name.padEnd(8)} ${status.padEnd(session.colorEnabled ? 18 : 9)} ${c.dim(where)}`);\n }\n out.push(` cache dir: ${cacheDir}`);\n out.push('');\n\n out.push(c.bold('LLM'));\n try {\n const llm = resolveLlm(config);\n const provider = new CommandProvider({ command: llm.command, promptVia: llm.promptVia, timeoutMs: llm.timeoutMs });\n out.push(` preset: ${llm.preset ?? c.dim('(custom command)')}`);\n out.push(` command: ${provider.describe()}`);\n out.push(` prompt: via ${llm.promptVia}`);\n } catch (err) {\n out.push(` ${c.red((err as ConfigError).message)}`);\n }\n out.push('');\n\n out.push(c.bold('Presets'));\n const presets = allPresets(config);\n const width = Math.max(...Object.keys(presets).map((k) => k.length));\n for (const [name, preset] of Object.entries(presets).sort(([a], [b]) => a.localeCompare(b))) {\n const custom = name in config.llm.presets ? c.dim(' (yours)') : '';\n out.push(` ${name.padEnd(width)} ${preset.description ?? c.dim(preset.command.join(' '))}${custom}`);\n }\n out.push('');\n\n out.push(c.bold('Effective config'));\n out.push(JSON.stringify(config, null, 2).split('\\n').map((l) => ' ' + l).join('\\n'));\n process.stdout.write(out.join('\\n') + '\\n');\n}\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { projectConfigPath } from '../core/config.js';\nimport { NotARepoError, UsageError } from '../core/errors.js';\nimport { openSession, type GlobalFlags } from './shared.js';\n\nconst STARTER = {\n llm: { preset: 'claude' },\n codehost: { provider: 'gh' },\n};\n\nexport async function initCommand(flags: GlobalFlags & { force?: boolean }): Promise<void> {\n const session = await openSession(flags, { requireRepo: true });\n if (!session.root) throw new NotARepoError(session.cwd);\n const path = projectConfigPath(session.root);\n const existing = session.loaded.layers.find((l) => l.name === 'project');\n if (existing?.found && !flags.force) {\n throw new UsageError(`${path} already exists.`, 'Pass --force to overwrite it.');\n }\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, JSON.stringify(STARTER, null, 2) + '\\n', 'utf8');\n process.stdout.write(`Wrote ${path}\\nRun \\`bb config\\` to see the effective configuration and available presets.\\n`);\n}\n","import { NotARepoError } from '../core/errors.js';\nimport { generateTour, prepareTour } from '../core/tour.js';\nimport { CliRenderer } from '../render/cli.js';\nimport { writeMaybePaged, writeStdout } from '../render/pager.js';\nimport { openSession, terminalWidth, type GlobalFlags } from './shared.js';\n\nexport interface TourFlags extends GlobalFlags {\n working?: boolean;\n staged?: boolean;\n section?: number;\n json?: boolean;\n dumpPrompt?: boolean;\n refresh?: boolean;\n}\n\nexport async function tourCommand(rangeArg: string | undefined, flags: TourFlags): Promise<void> {\n const session = await openSession(flags, { requireRepo: true });\n if (!session.root) throw new NotARepoError(session.cwd);\n const { config } = session.loaded;\n\n const options = {\n cwd: session.root,\n config,\n cacheDir: session.loaded.cacheDir,\n range: { arg: rangeArg, working: flags.working, staged: flags.staged },\n refresh: flags.refresh,\n noCache: flags.cache === false,\n debug: session.debug,\n warn: session.warn,\n };\n\n const prepared = await prepareTour(options);\n if (flags.dumpPrompt) {\n await writeStdout(prepared.built.prompt.endsWith('\\n') ? prepared.built.prompt : prepared.built.prompt + '\\n');\n return;\n }\n\n const result = await generateTour(options, prepared);\n\n if (flags.json) {\n await writeStdout(JSON.stringify(result.tour, null, 2) + '\\n');\n return;\n }\n\n const renderer = new CliRenderer();\n const output = renderer.render(result.tour, {\n color: session.colorEnabled,\n width: terminalWidth(config.render.width),\n section: flags.section,\n fromCache: result.fromCache,\n });\n await writeMaybePaged(output, {\n mode: config.render.pager,\n isTTY: Boolean(process.stdout.isTTY),\n rows: process.stdout.rows ?? 24,\n });\n}\n"],"mappings":"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","names":["pc","pc","pc","cache","pc","pc","pc"]}
1
+ {"version":3,"sources":["../src/cli/main.ts","../package.json","../src/cli/cache-cmd.ts","../src/cli/shared.ts","../src/cli/config-cmd.ts","../src/cli/init-cmd.ts","../src/cli/progress.ts","../src/cli/tour.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command, InvalidArgumentError } from 'commander';\nimport pc from 'picocolors';\nimport pkg from '../../package.json' with { type: 'json' };\nimport { BadLlmOutputError, BbError } from '../core/errors.js';\nimport { cacheClearCommand, cacheLsCommand, cachePathCommand } from './cache-cmd.js';\nimport { configCommand } from './config-cmd.js';\nimport { initCommand } from './init-cmd.js';\nimport { tourCommand } from './tour.js';\n\nfunction positiveInt(value: string): number {\n const n = Number(value);\n if (!Number.isInteger(n) || n < 1) throw new InvalidArgumentError('must be a positive integer');\n return n;\n}\n\nfunction addGlobalFlags(cmd: Command): Command {\n return cmd\n .option('-C, --cwd <dir>', 'run as if started in <dir>')\n .option('--preset <name>', 'LLM preset to use (see `bb config`)')\n .option('--color', 'force colored output')\n .option('--no-color', 'disable colored output')\n .option('--debug', 'print diagnostics (resolved range, prompt size, raw model output) to stderr');\n}\n\n// A reader that quits early (`bb | head`) is a normal end, not a crash.\nprocess.stdout.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EPIPE') process.exit(0);\n throw err;\n});\n\nconst program = new Command();\n\nprogram\n .name('bb')\n .description('Guided code tours for git changes, on the command line.')\n .version(pkg.version, '-V, --version')\n .configureOutput({ outputError: (str, write) => write(pc.red(str)) })\n .showHelpAfterError('(run with --help for usage)');\n\naddGlobalFlags(program)\n .argument('[range]', 'what to tour: A..B, A...B, or a single ref (compared at its merge-base with HEAD)')\n .option('-w, --working', 'tour uncommitted changes in the working tree (tracked and untracked)')\n .option('-s, --staged', 'tour staged changes only')\n .option('--section <n>', 'render only section <n>', positiveInt)\n .option('--json', 'print the tour as JSON instead of rendering it')\n .option('--dump-prompt', 'print the prompt that would be sent to the model and exit')\n .option('--refresh', 'ignore a cached tour and regenerate it')\n .option('--no-cache', 'neither read nor write the tour cache')\n .option('--no-pager', 'never pipe output through a pager')\n .option('--no-highlight', 'plain green/red excerpts instead of syntax colors with tinted rows')\n .option('--theme <name>', 'background tint palette for added/removed lines: dark or light', (v: string) => {\n if (v !== 'dark' && v !== 'light') throw new InvalidArgumentError('must be dark or light');\n return v;\n })\n .option('--no-progress', 'do not show the live status block while generating')\n .addHelpText(\n 'after',\n `\nExamples:\n bb tour the current branch (dirty tree, PR base, nearest branch, or default branch)\n bb main..feature tour an explicit range\n bb HEAD~3 tour the last three commits\n bb --staged tour what you are about to commit\n bb --section 2 show only the second section\n bb --json | jq machine-readable output\n bb --preset claude-sonnet --refresh\n`,\n )\n .action(async (range: string | undefined, flags) => {\n await tourCommand(range, flags);\n });\n\nconst cache = program.command('cache').description('manage cached tours');\naddGlobalFlags(cache.command('ls').description('list cached tours')).action(cacheLsCommand);\naddGlobalFlags(cache.command('clear').description('delete all cached tours')).action(cacheClearCommand);\naddGlobalFlags(cache.command('path').description('print the cache directory')).action(cachePathCommand);\n\naddGlobalFlags(program.command('config').description('show the effective configuration, its sources, and available presets'))\n .option('--json', 'print only the effective config as JSON')\n .action(configCommand);\n\naddGlobalFlags(program.command('init').description('write a starter .baby-bird/config.json in this repository'))\n .option('--force', 'overwrite an existing project config')\n .action(initCommand);\n\nprogram.parseAsync(process.argv).catch((err: unknown) => {\n const debug = process.argv.includes('--debug');\n if (err instanceof BbError) {\n process.stderr.write(pc.red(`error: ${err.message}\\n`));\n if (err.hint) process.stderr.write(pc.dim(`${err.hint}\\n`));\n if (debug && err instanceof BadLlmOutputError) process.stderr.write(pc.dim(`--- raw model output ---\\n${err.raw}\\n`));\n if (debug && err.cause) process.stderr.write(pc.dim(`${String((err.cause as Error).stack ?? err.cause)}\\n`));\n process.exitCode = err.exitCode;\n return;\n }\n process.stderr.write(pc.red(`error: ${(err as Error).message ?? String(err)}\\n`));\n if (debug && (err as Error).stack) process.stderr.write(pc.dim(`${(err as Error).stack}\\n`));\n process.exitCode = 1;\n});\n","{\n \"name\": \"@cam5/baby-bird\",\n \"version\": \"0.1.1\",\n \"description\": \"Guided code tours for git changes, on the command line.\",\n \"license\": \"MIT\",\n \"type\": \"module\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/cam5/baby-bird.git\"\n },\n \"keywords\": [\n \"git\",\n \"code-review\",\n \"diff\",\n \"llm\",\n \"cli\",\n \"code-tour\"\n ],\n \"bin\": {\n \"bb\": \"dist/cli.js\",\n \"baby-bird\": \"dist/cli.js\"\n },\n \"main\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\"\n }\n },\n \"files\": [\n \"dist\",\n \"README.md\"\n ],\n \"engines\": {\n \"node\": \">=22\"\n },\n \"packageManager\": \"pnpm@10.33.0\",\n \"scripts\": {\n \"dev\": \"tsx src/cli/main.ts\",\n \"build\": \"tsup\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"typecheck\": \"tsc --noEmit\",\n \"prepublishOnly\": \"pnpm typecheck && pnpm test && pnpm build\"\n },\n \"dependencies\": {\n \"commander\": \"^15.0.0\",\n \"lowlight\": \"^3.3.0\",\n \"picocolors\": \"^1.1.1\",\n \"zod\": \"^4.6.2\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^22.20.2\",\n \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.23.13\",\n \"typescript\": \"^5.9.3\",\n \"vitest\": \"^5.0.0\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n","import pc from 'picocolors';\nimport { TourCache } from '../core/cache.js';\nimport { describeSource, relativeTime } from '../render/cli.js';\nimport { openSession, type GlobalFlags } from './shared.js';\n\nexport async function cacheLsCommand(flags: GlobalFlags): Promise<void> {\n const session = await openSession(flags, { requireRepo: false });\n const c = pc.createColors(session.colorEnabled);\n const cache = new TourCache(session.loaded.cacheDir);\n const entries = await cache.list();\n if (entries.length === 0) {\n process.stdout.write(`No cached tours in ${cache.toursDir}\\n`);\n return;\n }\n for (const e of entries) {\n const t = e.tour;\n process.stdout.write(\n `${c.dim(e.key.slice(0, 12))} ${relativeTime(t.generatedAt).padEnd(12)} ${c.bold(t.title)}\\n` +\n `${' '.repeat(14)}${c.dim(describeSource(t.source))}${t.generator.preset ? c.dim(` · ${t.generator.preset}`) : ''}\\n`,\n );\n }\n}\n\nexport async function cacheClearCommand(flags: GlobalFlags): Promise<void> {\n const session = await openSession(flags, { requireRepo: false });\n const cache = new TourCache(session.loaded.cacheDir);\n const n = await cache.clear();\n process.stdout.write(`Removed ${n} cached tour${n === 1 ? '' : 's'} from ${cache.toursDir}\\n`);\n}\n\nexport async function cachePathCommand(flags: GlobalFlags): Promise<void> {\n const session = await openSession(flags, { requireRepo: false });\n process.stdout.write(new TourCache(session.loaded.cacheDir).toursDir + '\\n');\n}\n","import pc from 'picocolors';\nimport { resolve } from 'node:path';\nimport type { PartialConfig } from '../core/config.js';\nimport { loadConfig, type LoadedConfig } from '../core/config.js';\nimport { gitRoot } from '../git/exec.js';\nimport { supports256Colors } from '../render/highlight.js';\n\nexport interface GlobalFlags {\n cwd?: string;\n debug?: boolean;\n color?: boolean;\n preset?: string;\n cache?: boolean;\n pager?: boolean;\n highlight?: boolean;\n theme?: 'dark' | 'light';\n}\n\nexport interface Session {\n /** Directory the user pointed at (resolved). */\n cwd: string;\n /** Git root, or null when not in a repository. */\n root: string | null;\n loaded: LoadedConfig;\n debug: (msg: string) => void;\n warn: (msg: string) => void;\n colorEnabled: boolean;\n}\n\nexport function flagsToOverrides(flags: GlobalFlags): PartialConfig {\n const o: PartialConfig = {};\n if (flags.preset) o.llm = { preset: flags.preset };\n if (flags.color === true) o.render = { color: 'always' };\n else if (flags.color === false) o.render = { color: 'never' };\n if (flags.cache === false) o.cache = { enabled: false };\n if (flags.pager === false) o.render = { ...(o.render ?? {}), pager: 'never' };\n if (flags.highlight === false) o.render = { ...(o.render ?? {}), highlight: 'never' };\n if (flags.theme) o.render = { ...(o.render ?? {}), theme: flags.theme };\n return o;\n}\n\nexport async function openSession(flags: GlobalFlags, opts: { requireRepo: boolean }): Promise<Session> {\n const cwd = resolve(flags.cwd ?? process.cwd());\n let root: string | null = null;\n try {\n root = await gitRoot(cwd);\n } catch (err) {\n if (opts.requireRepo) throw err;\n }\n const loaded = await loadConfig({ gitRoot: root, env: process.env, overrides: flagsToOverrides(flags) });\n const colorEnabled = resolveColor(loaded.config.render.color);\n const c = pc.createColors(colorEnabled);\n const debug = flags.debug ? (msg: string) => process.stderr.write(c.dim(`[bb] ${msg}\\n`)) : () => {};\n const warn = (msg: string) => process.stderr.write(c.yellow(`warning: ${msg}\\n`));\n return { cwd, root, loaded, debug, warn, colorEnabled };\n}\n\nexport function resolveColor(mode: 'auto' | 'always' | 'never'): boolean {\n if (mode === 'always') return true;\n if (mode === 'never') return false;\n return Boolean(process.stdout.isTTY) && process.env.TERM !== 'dumb';\n}\n\nexport function resolveHighlight(mode: 'auto' | 'always' | 'never', colorEnabled: boolean): boolean {\n if (!colorEnabled || mode === 'never') return false;\n if (mode === 'always') return true;\n return supports256Colors();\n}\n\nexport function terminalWidth(configured: number | null, stream: { columns?: number } = process.stdout): number {\n return configured ?? (stream.columns || 80);\n}\n","import pc from 'picocolors';\nimport { allPresets, resolveLlm } from '../core/config.js';\nimport { ConfigError } from '../core/errors.js';\nimport { CommandProvider } from '../llm/command.js';\nimport { openSession, type GlobalFlags } from './shared.js';\n\nexport async function configCommand(flags: GlobalFlags & { json?: boolean }): Promise<void> {\n const session = await openSession(flags, { requireRepo: false });\n const { config, layers, cacheDir } = session.loaded;\n\n if (flags.json) {\n process.stdout.write(JSON.stringify(config, null, 2) + '\\n');\n return;\n }\n\n const c = pc.createColors(session.colorEnabled);\n const out: string[] = [];\n out.push(c.bold('Layers') + c.dim(' (later layers win; objects merge, arrays replace)'));\n for (const layer of layers) {\n const status = layer.found ? c.green('applied') : c.dim('not found');\n const where = layer.path ?? (layer.detail || (layer.name === 'defaults' ? 'built-in' : layer.name === 'flags' ? 'command line' : ''));\n out.push(` ${layer.name.padEnd(8)} ${status.padEnd(session.colorEnabled ? 18 : 9)} ${c.dim(where)}`);\n }\n out.push(` cache dir: ${cacheDir}`);\n out.push('');\n\n out.push(c.bold('LLM'));\n try {\n const llm = resolveLlm(config);\n const provider = new CommandProvider({ command: llm.command, promptVia: llm.promptVia, timeoutMs: llm.timeoutMs });\n out.push(` preset: ${llm.preset ?? c.dim('(custom command)')}`);\n out.push(` command: ${provider.describe()}`);\n out.push(` prompt: via ${llm.promptVia}`);\n } catch (err) {\n out.push(` ${c.red((err as ConfigError).message)}`);\n }\n out.push('');\n\n out.push(c.bold('Presets'));\n const presets = allPresets(config);\n const width = Math.max(...Object.keys(presets).map((k) => k.length));\n for (const [name, preset] of Object.entries(presets).sort(([a], [b]) => a.localeCompare(b))) {\n const custom = name in config.llm.presets ? c.dim(' (yours)') : '';\n out.push(` ${name.padEnd(width)} ${preset.description ?? c.dim(preset.command.join(' '))}${custom}`);\n }\n out.push('');\n\n out.push(c.bold('Effective config'));\n out.push(JSON.stringify(config, null, 2).split('\\n').map((l) => ' ' + l).join('\\n'));\n process.stdout.write(out.join('\\n') + '\\n');\n}\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { projectConfigPath } from '../core/config.js';\nimport { NotARepoError, UsageError } from '../core/errors.js';\nimport { openSession, type GlobalFlags } from './shared.js';\n\nconst STARTER = {\n llm: { preset: 'claude' },\n codehost: { provider: 'gh' },\n};\n\nexport async function initCommand(flags: GlobalFlags & { force?: boolean }): Promise<void> {\n const session = await openSession(flags, { requireRepo: true });\n if (!session.root) throw new NotARepoError(session.cwd);\n const path = projectConfigPath(session.root);\n const existing = session.loaded.layers.find((l) => l.name === 'project');\n if (existing?.found && !flags.force) {\n throw new UsageError(`${path} already exists.`, 'Pass --force to overwrite it.');\n }\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, JSON.stringify(STARTER, null, 2) + '\\n', 'utf8');\n process.stdout.write(`Wrote ${path}\\nRun \\`bb config\\` to see the effective configuration and available presets.\\n`);\n}\n","import pc from 'picocolors';\nimport type { ProgressSink } from '../core/progress.js';\nimport type { LlmEvent } from '../llm/provider.js';\nimport { wrap } from '../render/cli.js';\n\nconst SPINNER = ['✢', '✳', '✶', '✻', '✽', '✻', '✶', '✳'];\nconst VERBS = ['Hatching', 'Pecking', 'Nesting', 'Chirping', 'Preening', 'Fledging', 'Brooding', 'Warbling', 'Peeping'];\nconst THINKING_TAIL_CHARS = 2000;\nconst VERB_INTERVAL_MS = 7500;\n\nexport interface LiveProgressOptions {\n color: boolean;\n width: number;\n /** How many lines of thinking / section titles to show under the status line. */\n windowLines?: number;\n now?: () => number;\n /** Pin a single verb (tests). */\n verb?: string;\n /** Verbs to rotate through; the built-in list is used, shuffled, when omitted. */\n verbs?: string[];\n /** How often the verb changes. */\n verbIntervalMs?: number;\n frameMs?: number;\n}\n\ninterface Usage {\n outputTokens?: number;\n thinkingTokens?: number;\n model?: string;\n}\n\ntype Stage = 'prep' | 'thinking' | 'writing' | 'output';\n\n/**\n * In-place status block on a TTY: a spinner line plus a small window showing\n * the model's reasoning as it streams, then section titles as the answer forms.\n */\nexport class LiveProgress implements ProgressSink {\n private phaseLabel = '';\n private stage: Stage = 'prep';\n private thinking = '';\n private pulses = 0;\n private answer = '';\n private titles: string[] = [];\n private notices: string[] = [];\n private outputBytes = 0;\n private usage: Usage = {};\n private readonly startedAt: number;\n private frameIndex = 0;\n private lastLines = 0;\n private timer: NodeJS.Timeout | null = null;\n private stopped = false;\n private readonly verbs: string[];\n private readonly now: () => number;\n private readonly windowLines: number;\n private readonly onSigint = () => {\n this.stop();\n process.exit(130);\n };\n\n constructor(\n private readonly stream: { write(chunk: string): boolean },\n private readonly opts: LiveProgressOptions,\n ) {\n this.now = opts.now ?? Date.now;\n this.startedAt = this.now();\n this.verbs = opts.verb ? [opts.verb] : opts.verbs && opts.verbs.length ? opts.verbs : shuffle(VERBS);\n this.windowLines = opts.windowLines ?? 5;\n }\n\n start(): void {\n this.stream.write('\\x1b[?25l');\n process.once('SIGINT', this.onSigint);\n this.timer = setInterval(() => {\n this.frameIndex++;\n this.render();\n }, this.opts.frameMs ?? 80);\n this.timer.unref?.();\n this.render();\n }\n\n phase(label: string): void {\n this.phaseLabel = label;\n if (/^asking/i.test(label)) {\n this.stage = 'thinking';\n this.thinking = '';\n this.pulses = 0;\n this.answer = '';\n this.titles = [];\n this.notices = [];\n this.outputBytes = 0;\n } else if (this.stage !== 'prep') {\n this.stage = 'prep';\n }\n this.render();\n }\n\n llm(event: LlmEvent): void {\n switch (event.type) {\n case 'thinking':\n this.thinking += event.text;\n this.stage = 'thinking'; // thinking after a rejected answer comes back into view\n break;\n case 'thinking-pulse':\n this.pulses++;\n this.stage = 'thinking';\n break;\n case 'answer-start':\n this.answer = '';\n this.titles = [];\n break;\n case 'notice':\n this.notices.push(event.text);\n break;\n case 'text':\n this.answer += event.text;\n this.titles = extractTitles(this.answer);\n this.stage = 'writing';\n break;\n case 'output':\n this.outputBytes = event.bytes;\n this.stage = 'output';\n break;\n case 'usage':\n if (event.outputTokens !== undefined) this.usage.outputTokens = event.outputTokens;\n if (event.thinkingTokens !== undefined) this.usage.thinkingTokens = event.thinkingTokens;\n if (event.model !== undefined) this.usage.model = event.model;\n break;\n default:\n break;\n }\n }\n\n /** The lines that make up the current status block. */\n frame(): string[] {\n const c = pc.createColors(this.opts.color);\n const width = Math.max(30, this.opts.width);\n const spin = c.magenta(SPINNER[this.frameIndex % SPINNER.length]!);\n const elapsed = this.elapsed();\n const fit = (s: string) => (s.length > width - 1 ? s.slice(0, width - 2) + '…' : s);\n const lines: string[] = [];\n\n switch (this.stage) {\n case 'prep':\n lines.push(`${spin} ${fit(this.phaseLabel || 'Starting')}… ${c.dim(elapsed)}`);\n break;\n case 'thinking': {\n const meta = [elapsed, this.phaseLabel.replace(/^asking\\s+/i, '')].filter(Boolean).join(' · ');\n lines.push(`${spin} ${this.verb()}… ${c.dim(meta)}`);\n for (const n of this.notices.slice(-1)) lines.push(` ${c.yellow('↻')} ${c.yellow(fit(n).slice(0, width - 4))}`);\n if (this.thinking) {\n const tail = this.thinking.slice(-THINKING_TAIL_CHARS).replace(/\\s+/g, ' ').trim();\n const wrapped = wrap(tail, width - 4).slice(-this.windowLines);\n for (const l of wrapped) lines.push(` ${c.dim('│')} ${c.dim(l)}`);\n } else if (this.pulses > 0) {\n // The runner reports reasoning heartbeats without text: show a trail that grows with each one.\n const room = Math.max(8, width - 16);\n const n = this.pulses % (room + 1);\n lines.push(` ${c.dim('│')} ${c.dim('reasoning')} ${c.magenta('·'.repeat(n))}`);\n }\n break;\n }\n case 'writing': {\n const n = Math.max(0, this.titles.length - 1);\n lines.push(`${spin} Writing the tour… ${c.dim(`${elapsed} · ${n} section${n === 1 ? '' : 's'} so far`)}`);\n for (const note of this.notices.slice(-1)) lines.push(` ${c.yellow('↻')} ${c.yellow(fit(note).slice(0, width - 4))}`);\n const [tourTitle, ...sections] = this.titles;\n const items: string[] = [];\n if (tourTitle) items.push(` 🐣 ${c.bold(fit(tourTitle).slice(0, width - 6))}`);\n sections.forEach((t) => items.push(` ${c.green('✓')} ${fit(t).slice(0, width - 5)}`));\n for (const l of items.slice(-this.windowLines)) lines.push(l);\n break;\n }\n case 'output':\n lines.push(`${spin} ${this.verb()}… ${c.dim(`${elapsed} · ${formatBytes(this.outputBytes)} received`)}`);\n break;\n }\n return lines;\n }\n\n render(): void {\n if (this.stopped) return;\n const lines = this.frame();\n this.stream.write(this.erase() + lines.join('\\n') + '\\n');\n this.lastLines = lines.length;\n }\n\n /** Clear the block, restore the cursor, and optionally leave a final line behind. */\n stop(finalLine?: string): void {\n if (this.stopped) return;\n this.stopped = true;\n if (this.timer) clearInterval(this.timer);\n process.removeListener('SIGINT', this.onSigint);\n this.stream.write(this.erase() + (finalLine ? finalLine + '\\n' : '') + '\\x1b[?25h');\n this.lastLines = 0;\n }\n\n /** A one-line summary of the model call, for the final line. */\n summary(): string {\n const c = pc.createColors(this.opts.color);\n const parts = [`Hatched in ${this.elapsed()}`];\n if (this.usage.outputTokens) {\n parts.push(`${formatCount(this.usage.outputTokens)} tokens${this.usage.thinkingTokens ? ` (${formatCount(this.usage.thinkingTokens)} thinking)` : ''}`);\n }\n if (this.usage.model) parts.push(this.usage.model);\n return c.dim(`✻ ${parts.join(' · ')}`);\n }\n\n /** The current verb; rotates every verbIntervalMs so long waits do not stare at one word. */\n private verb(): string {\n const step = Math.floor((this.now() - this.startedAt) / (this.opts.verbIntervalMs ?? VERB_INTERVAL_MS));\n return this.verbs[step % this.verbs.length]!;\n }\n\n private elapsed(): string {\n const s = Math.max(0, Math.round((this.now() - this.startedAt) / 1000));\n return s >= 60 ? `${Math.floor(s / 60)}m ${s % 60}s` : `${s}s`;\n }\n\n private erase(): string {\n return this.lastLines ? `\\x1b[${this.lastLines}A\\x1b[0J` : '';\n }\n}\n\n/** Every \"title\" string value in a (possibly partial) JSON document, in order. */\nexport function extractTitles(text: string): string[] {\n const out: string[] = [];\n for (const m of text.matchAll(/\"title\"\\s*:\\s*\"((?:[^\"\\\\]|\\\\.)*)\"/g)) {\n out.push(m[1]!.replace(/\\\\([\"\\\\/bfnrt]|u[0-9a-fA-F]{4})/g, (_, esc: string) => {\n switch (esc[0]) {\n case '\"': return '\"';\n case '\\\\': return '\\\\';\n case '/': return '/';\n case 'n': return '\\n';\n case 't': return '\\t';\n case 'u': return String.fromCharCode(parseInt(esc.slice(1), 16));\n default: return '';\n }\n }));\n }\n return out;\n}\n\n/** A sink that logs phases as plain lines (used with --debug or without a TTY). */\nexport function loggingProgress(log: (msg: string) => void): ProgressSink {\n return {\n phase: (label) => log(label),\n llm: () => {},\n };\n}\n\nfunction shuffle<T>(items: readonly T[]): T[] {\n const out = [...items];\n for (let i = out.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [out[i], out[j]] = [out[j]!, out[i]!];\n }\n return out;\n}\n\nfunction formatBytes(n: number): string {\n return n < 1024 ? `${n} B` : `${(n / 1024).toFixed(1)} KB`;\n}\n\nfunction formatCount(n: number): string {\n return n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n);\n}\n","import { NotARepoError } from '../core/errors.js';\nimport { generateTour, prepareTour } from '../core/tour.js';\nimport { CliRenderer } from '../render/cli.js';\nimport { writeMaybePaged, writeStdout } from '../render/pager.js';\nimport { LiveProgress, loggingProgress } from './progress.js';\nimport { openSession, resolveHighlight, terminalWidth, type GlobalFlags } from './shared.js';\n\nexport interface TourFlags extends GlobalFlags {\n working?: boolean;\n staged?: boolean;\n section?: number;\n json?: boolean;\n dumpPrompt?: boolean;\n refresh?: boolean;\n progress?: boolean;\n}\n\nexport async function tourCommand(rangeArg: string | undefined, flags: TourFlags): Promise<void> {\n const session = await openSession(flags, { requireRepo: true });\n if (!session.root) throw new NotARepoError(session.cwd);\n const { config } = session.loaded;\n\n const live = flags.progress !== false && !flags.debug && Boolean(process.stderr.isTTY) && !flags.dumpPrompt;\n const progress = live\n ? new LiveProgress(process.stderr, { color: session.colorEnabled, width: terminalWidth(null, process.stderr) })\n : loggingProgress(session.debug);\n\n const options = {\n cwd: session.root,\n config,\n cacheDir: session.loaded.cacheDir,\n range: { arg: rangeArg, working: flags.working, staged: flags.staged },\n refresh: flags.refresh,\n noCache: flags.cache === false,\n debug: session.debug,\n warn: session.warn,\n progress,\n };\n\n if (progress instanceof LiveProgress) progress.start();\n let result: Awaited<ReturnType<typeof generateTour>>;\n try {\n const prepared = await prepareTour(options);\n if (flags.dumpPrompt) {\n await writeStdout(prepared.built.prompt.endsWith('\\n') ? prepared.built.prompt : prepared.built.prompt + '\\n');\n return;\n }\n result = await generateTour(options, prepared);\n } catch (err) {\n if (progress instanceof LiveProgress) progress.stop();\n throw err;\n }\n if (progress instanceof LiveProgress) progress.stop(result.fromCache ? undefined : progress.summary());\n\n if (flags.json) {\n await writeStdout(JSON.stringify(result.tour, null, 2) + '\\n');\n return;\n }\n\n const renderer = new CliRenderer();\n const output = renderer.render(result.tour, {\n color: session.colorEnabled,\n width: terminalWidth(config.render.width),\n section: flags.section,\n fromCache: result.fromCache,\n highlight: resolveHighlight(config.render.highlight, session.colorEnabled),\n theme: config.render.theme,\n });\n await writeMaybePaged(output, {\n mode: config.render.pager,\n isTTY: Boolean(process.stdout.isTTY),\n rows: process.stdout.rows ?? 24,\n });\n}\n"],"mappings":"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","names":["pc","pc","pc","cache","pc","pc","pc","pc","pc"]}