@basou/cli 0.10.0 → 0.11.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/index.js CHANGED
@@ -2259,19 +2259,19 @@ function parseInterval(value) {
2259
2259
  return seconds;
2260
2260
  }
2261
2261
  function abortableSleep(ms, signal) {
2262
- return new Promise((resolve3) => {
2262
+ return new Promise((resolve4) => {
2263
2263
  if (signal.aborted) {
2264
- resolve3();
2264
+ resolve4();
2265
2265
  return;
2266
2266
  }
2267
2267
  let timer;
2268
2268
  const onAbort = () => {
2269
2269
  clearTimeout(timer);
2270
- resolve3();
2270
+ resolve4();
2271
2271
  };
2272
2272
  timer = setTimeout(() => {
2273
2273
  signal.removeEventListener("abort", onAbort);
2274
- resolve3();
2274
+ resolve4();
2275
2275
  }, ms);
2276
2276
  signal.addEventListener("abort", onAbort, { once: true });
2277
2277
  });
@@ -2411,14 +2411,92 @@ async function assertWorkspaceInitialized6(basouRoot) {
2411
2411
  }
2412
2412
  }
2413
2413
 
2414
+ // src/commands/report.ts
2415
+ import { isAbsolute, resolve as resolve3 } from "path";
2416
+ import {
2417
+ assertBasouRootSafe as assertBasouRootSafe8,
2418
+ basouPaths as basouPaths8,
2419
+ findErrorCode as findErrorCode8,
2420
+ renderReport,
2421
+ resolveRepositoryRoot as resolveRepositoryRoot9,
2422
+ writeMarkdownFile as writeMarkdownFile4
2423
+ } from "@basou/core";
2424
+ function registerReportCommand(program2) {
2425
+ const report = program2.command("report").description(
2426
+ "Generate a work report \u2014 a shareable export explaining the work in this workspace"
2427
+ );
2428
+ report.command("generate").description("Generate a work report from the current workspace state").option("--out <path>", "Write the markdown report to a file instead of stdout").option("--json", "Emit the structured report data as JSON to stdout").option("--title <text>", "Subject line shown in the report header").option("-v, --verbose", "Show error causes").action(async (opts) => {
2429
+ await runReportGenerate(opts);
2430
+ });
2431
+ }
2432
+ async function runReportGenerate(options, ctx = {}) {
2433
+ try {
2434
+ await doRunReportGenerate(options, ctx);
2435
+ } catch (error) {
2436
+ renderCliError(error, { verbose: isVerbose(options) });
2437
+ process.exitCode = 1;
2438
+ }
2439
+ }
2440
+ async function doRunReportGenerate(options, ctx) {
2441
+ const cwd = ctx.cwd ?? process.cwd();
2442
+ const repositoryRoot = await resolveRepositoryRootForReport(cwd);
2443
+ const paths = basouPaths8(repositoryRoot);
2444
+ await assertWorkspaceInitialized7(paths.root);
2445
+ const nowIso = (ctx.nowProvider?.() ?? /* @__PURE__ */ new Date()).toISOString();
2446
+ const result = await renderReport({
2447
+ paths,
2448
+ nowIso,
2449
+ ...options.title !== void 0 ? { title: options.title } : {},
2450
+ onWarning: (w, sid) => printReplayWarning(w, sid),
2451
+ onSessionSkip: (sid, reason) => printSessionSkip(sid, reason),
2452
+ onTaskSkip: (taskId, reason) => printTaskSkip(taskId, reason)
2453
+ });
2454
+ if (options.out !== void 0) {
2455
+ const outPath = isAbsolute(options.out) ? options.out : resolve3(cwd, options.out);
2456
+ await writeMarkdownFile4(outPath, result.body);
2457
+ const { sessions, decisions, tasks } = result.data;
2458
+ console.error(
2459
+ `Wrote report to ${options.out} (sessions: ${sessions.total}, decisions: ${decisions.count}, tasks: ${tasks.total})`
2460
+ );
2461
+ }
2462
+ if (options.json === true) {
2463
+ console.log(JSON.stringify(result.data, null, 2));
2464
+ } else if (options.out === void 0) {
2465
+ console.log(result.body);
2466
+ }
2467
+ }
2468
+ async function resolveRepositoryRootForReport(cwd) {
2469
+ try {
2470
+ return await resolveRepositoryRoot9(cwd);
2471
+ } catch (error) {
2472
+ if (error instanceof Error && error.message === "Not a git repository") {
2473
+ throw new Error(
2474
+ "Not a git repository. Run 'git init' first, then re-run 'basou report generate'.",
2475
+ { cause: error }
2476
+ );
2477
+ }
2478
+ throw error;
2479
+ }
2480
+ }
2481
+ async function assertWorkspaceInitialized7(basouRoot) {
2482
+ try {
2483
+ await assertBasouRootSafe8(basouRoot);
2484
+ } catch (error) {
2485
+ if (findErrorCode8(error, "ENOENT")) {
2486
+ throw new Error("Workspace not initialized. Run 'basou init' first.");
2487
+ }
2488
+ throw error;
2489
+ }
2490
+ }
2491
+
2414
2492
  // src/commands/run.ts
2415
2493
  import { mkdir as mkdir2 } from "fs/promises";
2416
2494
  import { homedir as homedir4 } from "os";
2417
2495
  import { join as join5 } from "path";
2418
2496
  import {
2419
2497
  acquireLock as acquireLock4,
2420
- assertBasouRootSafe as assertBasouRootSafe8,
2421
- basouPaths as basouPaths8,
2498
+ assertBasouRootSafe as assertBasouRootSafe9,
2499
+ basouPaths as basouPaths9,
2422
2500
  ChildProcessRunner as ChildProcessRunner2,
2423
2501
  claudeCodeAdapterMetadata,
2424
2502
  appendChainedEvent as coreAppendChainedEvent2,
@@ -2430,7 +2508,7 @@ import {
2430
2508
  readManifest as readManifest4,
2431
2509
  readYamlFile as readYamlFile3,
2432
2510
  resolveClaudeCodeCommand,
2433
- resolveRepositoryRoot as resolveRepositoryRoot9,
2511
+ resolveRepositoryRoot as resolveRepositoryRoot10,
2434
2512
  SessionSchema as SessionSchema2,
2435
2513
  sanitizeRelatedFiles,
2436
2514
  sanitizeWorkingDirectory as sanitizeWorkingDirectory2,
@@ -2463,8 +2541,8 @@ async function runClaudeCode(args, options, ctx = {}) {
2463
2541
  const { command } = await resolveCommand();
2464
2542
  const cwd = options.cwd ?? process.cwd();
2465
2543
  const repoRoot = await resolveRepositoryRootForRun(cwd);
2466
- const paths = basouPaths8(repoRoot);
2467
- await assertBasouRootSafe8(paths.root);
2544
+ const paths = basouPaths9(repoRoot);
2545
+ await assertBasouRootSafe9(paths.root);
2468
2546
  const manifest = await readManifest4(paths);
2469
2547
  const sessionId = prefixedUlid4("ses");
2470
2548
  const sessionDir = join5(paths.sessions, sessionId);
@@ -2803,7 +2881,7 @@ async function finalizeSessionAsFailed2(paths, sessionDir, sessionId, appendEven
2803
2881
  }
2804
2882
  async function resolveRepositoryRootForRun(cwd) {
2805
2883
  try {
2806
- return await resolveRepositoryRoot9(cwd);
2884
+ return await resolveRepositoryRoot10(cwd);
2807
2885
  } catch (error) {
2808
2886
  if (error instanceof Error && error.message === "Not a git repository") {
2809
2887
  throw new Error("Not a git repository. Run 'git init' first, then re-run 'basou run'.", {
@@ -2816,21 +2894,21 @@ async function resolveRepositoryRootForRun(cwd) {
2816
2894
 
2817
2895
  // src/commands/session.ts
2818
2896
  import { readFile as readFile2 } from "fs/promises";
2819
- import { basename as basename3, isAbsolute, join as join6, relative as relative2 } from "path";
2897
+ import { basename as basename3, isAbsolute as isAbsolute2, join as join6, relative as relative2 } from "path";
2820
2898
  import {
2821
2899
  acquireLock as acquireLock5,
2822
2900
  appendEventToExistingSession as appendEventToExistingSession2,
2823
- assertBasouRootSafe as assertBasouRootSafe9,
2824
- basouPaths as basouPaths9,
2901
+ assertBasouRootSafe as assertBasouRootSafe10,
2902
+ basouPaths as basouPaths10,
2825
2903
  enumerateSessionDirs as enumerateSessionDirs2,
2826
- findErrorCode as findErrorCode8,
2904
+ findErrorCode as findErrorCode9,
2827
2905
  importSessionFromJson as importSessionFromJson2,
2828
2906
  loadSessionEntries,
2829
2907
  readAllEvents,
2830
2908
  readManifest as readManifest5,
2831
2909
  readYamlFile as readYamlFile4,
2832
2910
  rechainSessionInPlace,
2833
- resolveRepositoryRoot as resolveRepositoryRoot10,
2911
+ resolveRepositoryRoot as resolveRepositoryRoot11,
2834
2912
  resolveSessionId as resolveSessionId2,
2835
2913
  resolveTaskId,
2836
2914
  SessionImportPayloadSchema as SessionImportPayloadSchema2,
@@ -2841,15 +2919,7 @@ import {
2841
2919
  import { InvalidArgumentError as InvalidArgumentError3 } from "commander";
2842
2920
 
2843
2921
  // src/lib/format-duration.ts
2844
- function formatDurationMs(ms) {
2845
- const totalSeconds = Math.round(ms / 1e3);
2846
- const hours = Math.floor(totalSeconds / 3600);
2847
- const minutes = Math.floor(totalSeconds % 3600 / 60);
2848
- const seconds = totalSeconds % 60;
2849
- if (hours > 0) return `${hours}h ${String(minutes).padStart(2, "0")}m`;
2850
- if (minutes > 0) return `${minutes}m ${String(seconds).padStart(2, "0")}s`;
2851
- return `${seconds}s`;
2852
- }
2922
+ import { formatDurationMs } from "@basou/core";
2853
2923
 
2854
2924
  // src/commands/session.ts
2855
2925
  var SES_PREFIX3 = "ses_";
@@ -2895,8 +2965,8 @@ async function runSessionList(options, ctx = {}) {
2895
2965
  async function doRunSessionList(options, ctx) {
2896
2966
  const cwd = ctx.cwd ?? process.cwd();
2897
2967
  const repositoryRoot = await resolveRepositoryRootForSession(cwd, "list");
2898
- const paths = basouPaths9(repositoryRoot);
2899
- await assertWorkspaceInitialized7(paths.root);
2968
+ const paths = basouPaths10(repositoryRoot);
2969
+ await assertWorkspaceInitialized8(paths.root);
2900
2970
  const now = /* @__PURE__ */ new Date();
2901
2971
  const records = (await loadSessionEntries(paths, {
2902
2972
  now,
@@ -2947,8 +3017,8 @@ async function runSessionShow(idInput, options, ctx = {}) {
2947
3017
  async function doRunSessionShow(idInput, options, ctx) {
2948
3018
  const cwd = ctx.cwd ?? process.cwd();
2949
3019
  const repositoryRoot = await resolveRepositoryRootForSession(cwd, "show");
2950
- const paths = basouPaths9(repositoryRoot);
2951
- await assertWorkspaceInitialized7(paths.root);
3020
+ const paths = basouPaths10(repositoryRoot);
3021
+ await assertWorkspaceInitialized8(paths.root);
2952
3022
  const sessionId = await resolveSessionId2(paths, idInput);
2953
3023
  const sessionDir = join6(paths.sessions, sessionId);
2954
3024
  const sessionYamlPath = join6(sessionDir, "session.yaml");
@@ -2957,7 +3027,7 @@ async function doRunSessionShow(idInput, options, ctx) {
2957
3027
  const raw = await readYamlFile4(sessionYamlPath);
2958
3028
  session = SessionSchema3.parse(raw);
2959
3029
  } catch (error) {
2960
- if (findErrorCode8(error, "ENOENT")) {
3030
+ if (findErrorCode9(error, "ENOENT")) {
2961
3031
  throw new Error(`Session not found: ${idInput}`);
2962
3032
  }
2963
3033
  throw new Error("Failed to read session", { cause: error });
@@ -3072,7 +3142,7 @@ function formatSessionWork(session, events, now) {
3072
3142
  }
3073
3143
  function formatWorkingDir(workingDir, repositoryRoot, options) {
3074
3144
  if (options.fullPath === true) return workingDir;
3075
- if (!isAbsolute(workingDir)) {
3145
+ if (!isAbsolute2(workingDir)) {
3076
3146
  if (workingDir === ".") return "<repository_root>";
3077
3147
  return workingDir;
3078
3148
  }
@@ -3192,7 +3262,7 @@ function maxLen2(values, floor) {
3192
3262
  }
3193
3263
  async function resolveRepositoryRootForSession(cwd, subcmd) {
3194
3264
  try {
3195
- return await resolveRepositoryRoot10(cwd);
3265
+ return await resolveRepositoryRoot11(cwd);
3196
3266
  } catch (error) {
3197
3267
  if (error instanceof Error && error.message === "Not a git repository") {
3198
3268
  throw new Error(
@@ -3203,11 +3273,11 @@ async function resolveRepositoryRootForSession(cwd, subcmd) {
3203
3273
  throw error;
3204
3274
  }
3205
3275
  }
3206
- async function assertWorkspaceInitialized7(basouRoot) {
3276
+ async function assertWorkspaceInitialized8(basouRoot) {
3207
3277
  try {
3208
- await assertBasouRootSafe9(basouRoot);
3278
+ await assertBasouRootSafe10(basouRoot);
3209
3279
  } catch (error) {
3210
- if (findErrorCode8(error, "ENOENT")) {
3280
+ if (findErrorCode9(error, "ENOENT")) {
3211
3281
  throw new Error("Workspace not initialized. Run 'basou init' first.");
3212
3282
  }
3213
3283
  throw error;
@@ -3245,8 +3315,8 @@ async function runSessionImport(options, ctx = {}) {
3245
3315
  async function doRunSessionImport(options, ctx) {
3246
3316
  const cwd = ctx.cwd ?? process.cwd();
3247
3317
  const repositoryRoot = await resolveRepositoryRootForSession(cwd, "import");
3248
- const paths = basouPaths9(repositoryRoot);
3249
- await assertWorkspaceInitialized7(paths.root);
3318
+ const paths = basouPaths10(repositoryRoot);
3319
+ await assertWorkspaceInitialized8(paths.root);
3250
3320
  const manifest = await readManifest5(paths);
3251
3321
  const rawBody = await readInputFile(options.from);
3252
3322
  const json = parseJsonStrict(rawBody);
@@ -3276,10 +3346,10 @@ async function readInputFile(path) {
3276
3346
  try {
3277
3347
  return await readFile2(path, "utf8");
3278
3348
  } catch (error) {
3279
- if (findErrorCode8(error, "ENOENT")) {
3349
+ if (findErrorCode9(error, "ENOENT")) {
3280
3350
  throw new Error("Import source not found", { cause: error });
3281
3351
  }
3282
- if (findErrorCode8(error, "EISDIR")) {
3352
+ if (findErrorCode9(error, "EISDIR")) {
3283
3353
  throw new Error("Import source is not a file", { cause: error });
3284
3354
  }
3285
3355
  throw new Error("Failed to read import source", { cause: error });
@@ -3359,8 +3429,8 @@ async function doRunSessionNote(sessionIdInput, options, ctx) {
3359
3429
  }
3360
3430
  const cwd = ctx.cwd ?? process.cwd();
3361
3431
  const repositoryRoot = await resolveRepositoryRootForSession(cwd, "note");
3362
- const paths = basouPaths9(repositoryRoot);
3363
- await assertWorkspaceInitialized7(paths.root);
3432
+ const paths = basouPaths10(repositoryRoot);
3433
+ await assertWorkspaceInitialized8(paths.root);
3364
3434
  const sessionId = await resolveSessionId2(paths, sessionIdInput);
3365
3435
  const body = hasBody ? options.body : await readNoteFile(options.fromFile);
3366
3436
  if (body.length === 0) {
@@ -3393,10 +3463,10 @@ async function readNoteFile(path) {
3393
3463
  try {
3394
3464
  return await readFile2(path, "utf8");
3395
3465
  } catch (error) {
3396
- if (findErrorCode8(error, "ENOENT")) {
3466
+ if (findErrorCode9(error, "ENOENT")) {
3397
3467
  throw new Error("Note source not found", { cause: error });
3398
3468
  }
3399
- if (findErrorCode8(error, "EISDIR")) {
3469
+ if (findErrorCode9(error, "EISDIR")) {
3400
3470
  throw new Error("Note source is not a file", { cause: error });
3401
3471
  }
3402
3472
  throw new Error("Failed to read note source", { cause: error });
@@ -3441,8 +3511,8 @@ async function doRunSessionRechain(options, ctx) {
3441
3511
  }
3442
3512
  const cwd = ctx.cwd ?? process.cwd();
3443
3513
  const repositoryRoot = await resolveRepositoryRootForSession(cwd, "rechain");
3444
- const paths = basouPaths9(repositoryRoot);
3445
- await assertWorkspaceInitialized7(paths.root);
3514
+ const paths = basouPaths10(repositoryRoot);
3515
+ await assertWorkspaceInitialized8(paths.root);
3446
3516
  const sessionIds = options.session !== void 0 ? [await resolveSessionId2(paths, options.session)] : await enumerateSessionDirs2(paths);
3447
3517
  const dryRun = options.dryRun === true;
3448
3518
  const rows = [];
@@ -3495,11 +3565,11 @@ function renderRechainRow(row, dryRun) {
3495
3565
 
3496
3566
  // src/commands/stats.ts
3497
3567
  import {
3498
- assertBasouRootSafe as assertBasouRootSafe10,
3499
- basouPaths as basouPaths10,
3568
+ assertBasouRootSafe as assertBasouRootSafe11,
3569
+ basouPaths as basouPaths11,
3500
3570
  computeWorkStats,
3501
- findErrorCode as findErrorCode9,
3502
- resolveRepositoryRoot as resolveRepositoryRoot11
3571
+ findErrorCode as findErrorCode10,
3572
+ resolveRepositoryRoot as resolveRepositoryRoot12
3503
3573
  } from "@basou/core";
3504
3574
  function registerStatsCommand(program2) {
3505
3575
  program2.command("stats").description("Report how much the AI worked (output volume + time proxies) across sessions").option("--by-source", "Break the totals down by session source kind").option("--by-day", "Break billable time and volume down by calendar day").option("--json", "Output the full stats as JSON").option("-v, --verbose", "Show error causes").action(async (options) => {
@@ -3517,8 +3587,8 @@ async function runStats(options, ctx = {}) {
3517
3587
  async function doRunStats(options, ctx) {
3518
3588
  const cwd = ctx.cwd ?? process.cwd();
3519
3589
  const repositoryRoot = await resolveRepositoryRootForStats(cwd);
3520
- const paths = basouPaths10(repositoryRoot);
3521
- await assertWorkspaceInitialized8(paths.root);
3590
+ const paths = basouPaths11(repositoryRoot);
3591
+ await assertWorkspaceInitialized9(paths.root);
3522
3592
  const now = ctx.nowProvider?.() ?? /* @__PURE__ */ new Date();
3523
3593
  const result = await computeWorkStats({
3524
3594
  paths,
@@ -3602,7 +3672,7 @@ function formatInt(n) {
3602
3672
  }
3603
3673
  async function resolveRepositoryRootForStats(cwd) {
3604
3674
  try {
3605
- return await resolveRepositoryRoot11(cwd);
3675
+ return await resolveRepositoryRoot12(cwd);
3606
3676
  } catch (error) {
3607
3677
  if (error instanceof Error && error.message === "Not a git repository") {
3608
3678
  throw new Error("Not a git repository. Run 'git init' first, then re-run 'basou stats'.", {
@@ -3612,11 +3682,11 @@ async function resolveRepositoryRootForStats(cwd) {
3612
3682
  throw error;
3613
3683
  }
3614
3684
  }
3615
- async function assertWorkspaceInitialized8(basouRoot) {
3685
+ async function assertWorkspaceInitialized9(basouRoot) {
3616
3686
  try {
3617
- await assertBasouRootSafe10(basouRoot);
3687
+ await assertBasouRootSafe11(basouRoot);
3618
3688
  } catch (error) {
3619
- if (findErrorCode9(error, "ENOENT")) {
3689
+ if (findErrorCode10(error, "ENOENT")) {
3620
3690
  throw new Error("Workspace not initialized. Run 'basou init' first.");
3621
3691
  }
3622
3692
  throw error;
@@ -3625,12 +3695,12 @@ async function assertWorkspaceInitialized8(basouRoot) {
3625
3695
 
3626
3696
  // src/commands/status.ts
3627
3697
  import {
3628
- assertBasouRootSafe as assertBasouRootSafe11,
3629
- basouPaths as basouPaths11,
3698
+ assertBasouRootSafe as assertBasouRootSafe12,
3699
+ basouPaths as basouPaths12,
3630
3700
  buildStatusSnapshot,
3631
- findErrorCode as findErrorCode10,
3701
+ findErrorCode as findErrorCode11,
3632
3702
  readManifest as readManifest6,
3633
- resolveRepositoryRoot as resolveRepositoryRoot12,
3703
+ resolveRepositoryRoot as resolveRepositoryRoot13,
3634
3704
  writeStatus
3635
3705
  } from "@basou/core";
3636
3706
  function registerStatusCommand(program2) {
@@ -3649,11 +3719,11 @@ async function runStatus(options, ctx = {}) {
3649
3719
  async function doRunStatus(options, ctx) {
3650
3720
  const cwd = ctx.cwd ?? process.cwd();
3651
3721
  const repositoryRoot = await resolveRepositoryRootForStatus(cwd);
3652
- const paths = basouPaths11(repositoryRoot);
3722
+ const paths = basouPaths12(repositoryRoot);
3653
3723
  try {
3654
- await assertBasouRootSafe11(paths.root);
3724
+ await assertBasouRootSafe12(paths.root);
3655
3725
  } catch (error) {
3656
- if (findErrorCode10(error, "ENOENT")) {
3726
+ if (findErrorCode11(error, "ENOENT")) {
3657
3727
  throw new Error("Workspace not initialized. Run 'basou init' first.");
3658
3728
  }
3659
3729
  throw error;
@@ -3662,7 +3732,7 @@ async function doRunStatus(options, ctx) {
3662
3732
  try {
3663
3733
  manifest = await readManifest6(paths);
3664
3734
  } catch (error) {
3665
- if (findErrorCode10(error, "ENOENT")) {
3735
+ if (findErrorCode11(error, "ENOENT")) {
3666
3736
  throw new Error("Workspace not initialized. Run 'basou init' first.");
3667
3737
  }
3668
3738
  throw new Error("Failed to read workspace manifest", { cause: error });
@@ -3686,7 +3756,7 @@ function renderTextStatus(s) {
3686
3756
  }
3687
3757
  async function resolveRepositoryRootForStatus(cwd) {
3688
3758
  try {
3689
- return await resolveRepositoryRoot12(cwd);
3759
+ return await resolveRepositoryRoot13(cwd);
3690
3760
  } catch (error) {
3691
3761
  if (error instanceof Error && error.message === "Not a git repository") {
3692
3762
  throw new Error("Not a git repository. Run 'git init' first, then re-run 'basou status'.", {
@@ -3702,13 +3772,13 @@ import { readFile as readFile3 } from "fs/promises";
3702
3772
  import { join as join7 } from "path";
3703
3773
  import {
3704
3774
  archiveTask,
3705
- assertBasouRootSafe as assertBasouRootSafe12,
3706
- basouPaths as basouPaths12,
3775
+ assertBasouRootSafe as assertBasouRootSafe13,
3776
+ basouPaths as basouPaths13,
3707
3777
  createTaskWithEvent,
3708
3778
  deleteTask,
3709
3779
  editTask,
3710
3780
  enumerateArchivedTaskIds,
3711
- findErrorCode as findErrorCode11,
3781
+ findErrorCode as findErrorCode12,
3712
3782
  loadSessionEntries as loadSessionEntries2,
3713
3783
  loadTaskEntries,
3714
3784
  prefixedUlid as prefixedUlid5,
@@ -3719,7 +3789,7 @@ import {
3719
3789
  reconcileTask,
3720
3790
  refreshTaskLinkedSessions,
3721
3791
  replayEvents as replayEvents2,
3722
- resolveRepositoryRoot as resolveRepositoryRoot13,
3792
+ resolveRepositoryRoot as resolveRepositoryRoot14,
3723
3793
  resolveSessionId as resolveSessionId3,
3724
3794
  resolveTaskId as resolveTaskId2,
3725
3795
  TaskStatusSchema,
@@ -3805,8 +3875,8 @@ async function doRunTaskNew(options, ctx) {
3805
3875
  }
3806
3876
  const cwd = ctx.cwd ?? process.cwd();
3807
3877
  const repositoryRoot = await resolveRepositoryRootForTask(cwd, "new");
3808
- const paths = basouPaths12(repositoryRoot);
3809
- await assertWorkspaceInitialized9(paths.root);
3878
+ const paths = basouPaths13(repositoryRoot);
3879
+ await assertWorkspaceInitialized10(paths.root);
3810
3880
  const description = options.description !== void 0 ? options.description : options.fromFile !== void 0 ? await readDescriptionFile(options.fromFile) : "";
3811
3881
  const now = ctx.nowProvider !== void 0 ? ctx.nowProvider() : /* @__PURE__ */ new Date();
3812
3882
  const occurredAt = now.toISOString();
@@ -3914,8 +3984,8 @@ async function runTaskList(options, ctx = {}) {
3914
3984
  async function doRunTaskList(options, ctx) {
3915
3985
  const cwd = ctx.cwd ?? process.cwd();
3916
3986
  const repositoryRoot = await resolveRepositoryRootForTask(cwd, "list");
3917
- const paths = basouPaths12(repositoryRoot);
3918
- await assertWorkspaceInitialized9(paths.root);
3987
+ const paths = basouPaths13(repositoryRoot);
3988
+ await assertWorkspaceInitialized10(paths.root);
3919
3989
  const entries = await loadTaskEntries(paths, {
3920
3990
  onSkip: (id, reason) => printTaskSkip(id, reason)
3921
3991
  });
@@ -4018,8 +4088,8 @@ async function runTaskShow(idInput, options, ctx = {}) {
4018
4088
  async function doRunTaskShow(idInput, options, ctx) {
4019
4089
  const cwd = ctx.cwd ?? process.cwd();
4020
4090
  const repositoryRoot = await resolveRepositoryRootForTask(cwd, "show");
4021
- const paths = basouPaths12(repositoryRoot);
4022
- await assertWorkspaceInitialized9(paths.root);
4091
+ const paths = basouPaths13(repositoryRoot);
4092
+ await assertWorkspaceInitialized10(paths.root);
4023
4093
  const taskId = await resolveTaskId2(paths, idInput, { includeArchived: true });
4024
4094
  const { doc, archived } = await readTaskFileWithArchiveFallback(paths, taskId);
4025
4095
  const sessions = await loadSessionEntries2(paths, { now: /* @__PURE__ */ new Date() });
@@ -4162,8 +4232,8 @@ async function doRunTaskStatus(taskIdInput, newStatusInput, options, ctx) {
4162
4232
  const newStatus = parseTaskStatusPositional(newStatusInput);
4163
4233
  const cwd = ctx.cwd ?? process.cwd();
4164
4234
  const repositoryRoot = await resolveRepositoryRootForTask(cwd, "status");
4165
- const paths = basouPaths12(repositoryRoot);
4166
- await assertWorkspaceInitialized9(paths.root);
4235
+ const paths = basouPaths13(repositoryRoot);
4236
+ await assertWorkspaceInitialized10(paths.root);
4167
4237
  const taskId = await resolveTaskId2(paths, taskIdInput);
4168
4238
  const now = ctx.nowProvider !== void 0 ? ctx.nowProvider() : /* @__PURE__ */ new Date();
4169
4239
  const occurredAt = now.toISOString();
@@ -4239,8 +4309,8 @@ async function runTaskReconcile(options, ctx = {}) {
4239
4309
  async function doRunTaskReconcile(options, ctx) {
4240
4310
  const cwd = ctx.cwd ?? process.cwd();
4241
4311
  const repositoryRoot = await resolveRepositoryRootForTask(cwd, "reconcile");
4242
- const paths = basouPaths12(repositoryRoot);
4243
- await assertWorkspaceInitialized9(paths.root);
4312
+ const paths = basouPaths13(repositoryRoot);
4313
+ await assertWorkspaceInitialized10(paths.root);
4244
4314
  const manifest = await readManifest7(paths);
4245
4315
  const nowProvider = ctx.nowProvider ?? (() => /* @__PURE__ */ new Date());
4246
4316
  const write = options.write === true;
@@ -4419,8 +4489,8 @@ async function doRunTaskRefreshLinkage(taskIdInput, options, ctx) {
4419
4489
  }
4420
4490
  const cwd = ctx.cwd ?? process.cwd();
4421
4491
  const repositoryRoot = await resolveRepositoryRootForTask(cwd, "refresh-linkage");
4422
- const paths = basouPaths12(repositoryRoot);
4423
- await assertWorkspaceInitialized9(paths.root);
4492
+ const paths = basouPaths13(repositoryRoot);
4493
+ await assertWorkspaceInitialized10(paths.root);
4424
4494
  const manifest = await readManifest7(paths);
4425
4495
  const taskId = await resolveTaskId2(paths, taskIdInput);
4426
4496
  const nowProvider = ctx.nowProvider ?? (() => /* @__PURE__ */ new Date());
@@ -4499,8 +4569,8 @@ async function doRunTaskEdit(taskIdInput, options, ctx) {
4499
4569
  }
4500
4570
  const cwd = ctx.cwd ?? process.cwd();
4501
4571
  const repositoryRoot = await resolveRepositoryRootForTask(cwd, "edit");
4502
- const paths = basouPaths12(repositoryRoot);
4503
- await assertWorkspaceInitialized9(paths.root);
4572
+ const paths = basouPaths13(repositoryRoot);
4573
+ await assertWorkspaceInitialized10(paths.root);
4504
4574
  const manifest = await readManifest7(paths);
4505
4575
  const taskId = await resolveTaskId2(paths, taskIdInput);
4506
4576
  const now = ctx.nowProvider !== void 0 ? ctx.nowProvider() : /* @__PURE__ */ new Date();
@@ -4555,8 +4625,8 @@ async function doRunTaskDelete(taskIdInput, options, ctx) {
4555
4625
  }
4556
4626
  const cwd = ctx.cwd ?? process.cwd();
4557
4627
  const repositoryRoot = await resolveRepositoryRootForTask(cwd, "delete");
4558
- const paths = basouPaths12(repositoryRoot);
4559
- await assertWorkspaceInitialized9(paths.root);
4628
+ const paths = basouPaths13(repositoryRoot);
4629
+ await assertWorkspaceInitialized10(paths.root);
4560
4630
  const manifest = await readManifest7(paths);
4561
4631
  const taskId = await resolveTaskId2(paths, taskIdInput);
4562
4632
  if (options.yes !== true) {
@@ -4600,8 +4670,8 @@ async function doRunTaskArchive(taskIdInput, options, ctx) {
4600
4670
  }
4601
4671
  const cwd = ctx.cwd ?? process.cwd();
4602
4672
  const repositoryRoot = await resolveRepositoryRootForTask(cwd, "archive");
4603
- const paths = basouPaths12(repositoryRoot);
4604
- await assertWorkspaceInitialized9(paths.root);
4673
+ const paths = basouPaths13(repositoryRoot);
4674
+ await assertWorkspaceInitialized10(paths.root);
4605
4675
  const manifest = await readManifest7(paths);
4606
4676
  const taskId = await resolveTaskId2(paths, taskIdInput);
4607
4677
  if (options.yes !== true) {
@@ -4716,10 +4786,10 @@ async function readDescriptionFile(path) {
4716
4786
  try {
4717
4787
  return await readFile3(path, "utf8");
4718
4788
  } catch (error) {
4719
- if (findErrorCode11(error, "ENOENT")) {
4789
+ if (findErrorCode12(error, "ENOENT")) {
4720
4790
  throw new Error("Description source not found", { cause: error });
4721
4791
  }
4722
- if (findErrorCode11(error, "EISDIR")) {
4792
+ if (findErrorCode12(error, "EISDIR")) {
4723
4793
  throw new Error("Description source is not a file", { cause: error });
4724
4794
  }
4725
4795
  throw new Error("Failed to read description source", { cause: error });
@@ -4727,7 +4797,7 @@ async function readDescriptionFile(path) {
4727
4797
  }
4728
4798
  async function resolveRepositoryRootForTask(cwd, subcmd) {
4729
4799
  try {
4730
- return await resolveRepositoryRoot13(cwd);
4800
+ return await resolveRepositoryRoot14(cwd);
4731
4801
  } catch (error) {
4732
4802
  if (error instanceof Error && error.message === "Not a git repository") {
4733
4803
  throw new Error(
@@ -4738,11 +4808,11 @@ async function resolveRepositoryRootForTask(cwd, subcmd) {
4738
4808
  throw error;
4739
4809
  }
4740
4810
  }
4741
- async function assertWorkspaceInitialized9(basouRoot) {
4811
+ async function assertWorkspaceInitialized10(basouRoot) {
4742
4812
  try {
4743
- await assertBasouRootSafe12(basouRoot);
4813
+ await assertBasouRootSafe13(basouRoot);
4744
4814
  } catch (error) {
4745
- if (findErrorCode11(error, "ENOENT")) {
4815
+ if (findErrorCode12(error, "ENOENT")) {
4746
4816
  throw new Error("Workspace not initialized. Run 'basou init' first.");
4747
4817
  }
4748
4818
  throw error;
@@ -4830,11 +4900,11 @@ function maxLen3(values, floor) {
4830
4900
 
4831
4901
  // src/commands/verify.ts
4832
4902
  import {
4833
- assertBasouRootSafe as assertBasouRootSafe13,
4834
- basouPaths as basouPaths13,
4903
+ assertBasouRootSafe as assertBasouRootSafe14,
4904
+ basouPaths as basouPaths14,
4835
4905
  enumerateSessionDirs as enumerateSessionDirs3,
4836
- findErrorCode as findErrorCode12,
4837
- resolveRepositoryRoot as resolveRepositoryRoot14,
4906
+ findErrorCode as findErrorCode13,
4907
+ resolveRepositoryRoot as resolveRepositoryRoot15,
4838
4908
  resolveSessionId as resolveSessionId4,
4839
4909
  verifyEventsChain
4840
4910
  } from "@basou/core";
@@ -4857,8 +4927,8 @@ async function doRunVerify(options, ctx) {
4857
4927
  }
4858
4928
  const cwd = ctx.cwd ?? process.cwd();
4859
4929
  const repositoryRoot = await resolveRepositoryRootForVerify(cwd);
4860
- const paths = basouPaths13(repositoryRoot);
4861
- await assertWorkspaceInitialized10(paths.root);
4930
+ const paths = basouPaths14(repositoryRoot);
4931
+ await assertWorkspaceInitialized11(paths.root);
4862
4932
  const sessionIds = options.session !== void 0 ? [await resolveSessionId4(paths, options.session)] : await enumerateSessionDirs3(paths);
4863
4933
  const rows = [];
4864
4934
  for (const sessionId of sessionIds) {
@@ -4905,7 +4975,7 @@ function renderVerdict(row) {
4905
4975
  }
4906
4976
  async function resolveRepositoryRootForVerify(cwd) {
4907
4977
  try {
4908
- return await resolveRepositoryRoot14(cwd);
4978
+ return await resolveRepositoryRoot15(cwd);
4909
4979
  } catch (error) {
4910
4980
  if (error instanceof Error && error.message === "Not a git repository") {
4911
4981
  throw new Error("Not a git repository. Run 'git init' first, then re-run 'basou verify'.", {
@@ -4915,11 +4985,11 @@ async function resolveRepositoryRootForVerify(cwd) {
4915
4985
  throw error;
4916
4986
  }
4917
4987
  }
4918
- async function assertWorkspaceInitialized10(basouRoot) {
4988
+ async function assertWorkspaceInitialized11(basouRoot) {
4919
4989
  try {
4920
- await assertBasouRootSafe13(basouRoot);
4990
+ await assertBasouRootSafe14(basouRoot);
4921
4991
  } catch (error) {
4922
- if (findErrorCode12(error, "ENOENT")) {
4992
+ if (findErrorCode13(error, "ENOENT")) {
4923
4993
  throw new Error("Workspace not initialized. Run 'basou init' first.");
4924
4994
  }
4925
4995
  throw error;
@@ -4928,7 +4998,7 @@ async function assertWorkspaceInitialized10(basouRoot) {
4928
4998
 
4929
4999
  // src/commands/view.ts
4930
5000
  import { spawn } from "child_process";
4931
- import { assertBasouRootSafe as assertBasouRootSafe14, basouPaths as basouPaths14, findErrorCode as findErrorCode14, resolveRepositoryRoot as resolveRepositoryRoot15 } from "@basou/core";
5001
+ import { assertBasouRootSafe as assertBasouRootSafe15, basouPaths as basouPaths15, findErrorCode as findErrorCode15, resolveRepositoryRoot as resolveRepositoryRoot16 } from "@basou/core";
4932
5002
  import { InvalidArgumentError as InvalidArgumentError5 } from "commander";
4933
5003
 
4934
5004
  // src/lib/view-server.ts
@@ -4937,7 +5007,7 @@ import { join as join8 } from "path";
4937
5007
  import {
4938
5008
  computeWorkStats as computeWorkStats2,
4939
5009
  enumerateApprovals as enumerateApprovals2,
4940
- findErrorCode as findErrorCode13,
5010
+ findErrorCode as findErrorCode14,
4941
5011
  isLazyExpired as isLazyExpired2,
4942
5012
  loadApproval as loadApproval2,
4943
5013
  loadSessionEntries as loadSessionEntries3,
@@ -5410,7 +5480,7 @@ function startViewServer(opts) {
5410
5480
  };
5411
5481
  let boundPort = port;
5412
5482
  const getPort = () => boundPort;
5413
- return new Promise((resolve3, reject) => {
5483
+ return new Promise((resolve4, reject) => {
5414
5484
  const server = createServer((req, res) => {
5415
5485
  handleRequest(req, res, deps, getPort, runExclusive).catch((error) => {
5416
5486
  sendError(res, error instanceof HttpError ? error.status : 500, pathlessMessage(error));
@@ -5421,7 +5491,7 @@ function startViewServer(opts) {
5421
5491
  const address = server.address();
5422
5492
  boundPort = isAddressInfo(address) ? address.port : port;
5423
5493
  server.off("error", reject);
5424
- resolve3({
5494
+ resolve4({
5425
5495
  url: `http://${host}:${boundPort}`,
5426
5496
  port: boundPort,
5427
5497
  close: () => closeServer(server)
@@ -5433,8 +5503,8 @@ function isAddressInfo(value) {
5433
5503
  return value !== null && typeof value === "object";
5434
5504
  }
5435
5505
  function closeServer(server) {
5436
- return new Promise((resolve3) => {
5437
- server.close(() => resolve3());
5506
+ return new Promise((resolve4) => {
5507
+ server.close(() => resolve4());
5438
5508
  server.closeAllConnections();
5439
5509
  });
5440
5510
  }
@@ -5539,7 +5609,7 @@ async function overview(deps) {
5539
5609
  try {
5540
5610
  manifest = await readManifest8(deps.paths);
5541
5611
  } catch (error) {
5542
- if (findErrorCode13(error, "ENOENT")) {
5612
+ if (findErrorCode14(error, "ENOENT")) {
5543
5613
  return { initialized: false, repoRoot: deps.repoRoot };
5544
5614
  }
5545
5615
  throw error;
@@ -5754,8 +5824,8 @@ async function runView(options, ctx = {}) {
5754
5824
  async function doRunView(options, ctx) {
5755
5825
  const cwd = ctx.cwd ?? process.cwd();
5756
5826
  const repositoryRoot = await resolveRepositoryRootForView(cwd);
5757
- const paths = basouPaths14(repositoryRoot);
5758
- await assertWorkspaceInitialized11(paths.root);
5827
+ const paths = basouPaths15(repositoryRoot);
5828
+ await assertWorkspaceInitialized12(paths.root);
5759
5829
  const deps = {
5760
5830
  paths,
5761
5831
  repoRoot: repositoryRoot,
@@ -5786,7 +5856,7 @@ async function startListening(port, deps) {
5786
5856
  try {
5787
5857
  return await startViewServer({ port, deps });
5788
5858
  } catch (error) {
5789
- if (findErrorCode14(error, "EADDRINUSE")) {
5859
+ if (findErrorCode15(error, "EADDRINUSE")) {
5790
5860
  throw new Error(`Port ${port} is already in use. Pass --port <n> to choose another.`, {
5791
5861
  cause: error
5792
5862
  });
@@ -5809,7 +5879,7 @@ function openInBrowser(url, override) {
5809
5879
  }
5810
5880
  }
5811
5881
  function waitForShutdown(signal) {
5812
- return new Promise((resolve3) => {
5882
+ return new Promise((resolve4) => {
5813
5883
  const cleanup = () => {
5814
5884
  process.off("SIGINT", onSignal);
5815
5885
  process.off("SIGTERM", onSignal);
@@ -5817,18 +5887,18 @@ function waitForShutdown(signal) {
5817
5887
  };
5818
5888
  const onSignal = () => {
5819
5889
  cleanup();
5820
- resolve3();
5890
+ resolve4();
5821
5891
  };
5822
5892
  const onAbort = () => {
5823
5893
  cleanup();
5824
- resolve3();
5894
+ resolve4();
5825
5895
  };
5826
5896
  process.on("SIGINT", onSignal);
5827
5897
  process.on("SIGTERM", onSignal);
5828
5898
  if (signal !== void 0) {
5829
5899
  if (signal.aborted) {
5830
5900
  cleanup();
5831
- resolve3();
5901
+ resolve4();
5832
5902
  return;
5833
5903
  }
5834
5904
  signal.addEventListener("abort", onAbort);
@@ -5837,7 +5907,7 @@ function waitForShutdown(signal) {
5837
5907
  }
5838
5908
  async function resolveRepositoryRootForView(cwd) {
5839
5909
  try {
5840
- return await resolveRepositoryRoot15(cwd);
5910
+ return await resolveRepositoryRoot16(cwd);
5841
5911
  } catch (error) {
5842
5912
  if (error instanceof Error && error.message === "Not a git repository") {
5843
5913
  throw new Error("Not a git repository. Run 'git init' first, then re-run 'basou view'.", {
@@ -5847,11 +5917,11 @@ async function resolveRepositoryRootForView(cwd) {
5847
5917
  throw error;
5848
5918
  }
5849
5919
  }
5850
- async function assertWorkspaceInitialized11(basouRoot) {
5920
+ async function assertWorkspaceInitialized12(basouRoot) {
5851
5921
  try {
5852
- await assertBasouRootSafe14(basouRoot);
5922
+ await assertBasouRootSafe15(basouRoot);
5853
5923
  } catch (error) {
5854
- if (findErrorCode14(error, "ENOENT")) {
5924
+ if (findErrorCode15(error, "ENOENT")) {
5855
5925
  throw new Error("Workspace not initialized. Run 'basou init' first.");
5856
5926
  }
5857
5927
  throw error;
@@ -5880,6 +5950,7 @@ function buildProgram() {
5880
5950
  registerTaskCommand(program2);
5881
5951
  registerHandoffCommand(program2);
5882
5952
  registerDecisionsCommand(program2);
5953
+ registerReportCommand(program2);
5883
5954
  return program2;
5884
5955
  }
5885
5956