bertrand 0.20.1 → 0.22.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/README.md CHANGED
@@ -79,13 +79,14 @@ Shows a picker: start a fresh Claude conversation, or resume one of the prior co
79
79
  bertrand list
80
80
  ```
81
81
 
82
- Interactive picker showing all sessions with status badges.
82
+ Interactive picker showing all sessions with status badges. Add `--project <slug>` to list sessions from another project without switching the active one.
83
83
 
84
84
  ### Other commands
85
85
 
86
86
  | Command | Purpose |
87
87
  |---|---|
88
- | `bertrand log <session>` | Print the timeline event log for a session. |
88
+ | `bertrand log` | List sessions in the active project. Add `--project <slug>` to scope to a different project. |
89
+ | `bertrand log <session>` | Print the timeline event log for a session. Supports `--json` (includes `project: { slug, name }` for agent consumption) and `--project <slug>` for cross-project reads. |
89
90
  | `bertrand stats <session>` | Print materialized stats (duration, work/wait split, lines changed). |
90
91
  | `bertrand archive <name>` | Archive or unarchive a session. |
91
92
  | `bertrand serve` | Start the dashboard HTTP API on `:5200`. |
package/dist/bertrand.js CHANGED
@@ -15,6 +15,7 @@ var __export = (target, all) => {
15
15
  });
16
16
  };
17
17
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
18
+ var __require = import.meta.require;
18
19
 
19
20
  // src/lib/paths.ts
20
21
  import { homedir } from "os";
@@ -25,6 +26,7 @@ var init_paths = __esm(() => {
25
26
  root: join(homedir(), BERTRAND_DIR),
26
27
  hooks: join(homedir(), BERTRAND_DIR, "hooks"),
27
28
  sessions: join(homedir(), BERTRAND_DIR, "sessions"),
29
+ runtime: join(homedir(), BERTRAND_DIR, "run"),
28
30
  db: join(homedir(), BERTRAND_DIR, "bertrand.db"),
29
31
  syncEnv: join(homedir(), BERTRAND_DIR, "sync.env")
30
32
  };
@@ -651,6 +653,7 @@ var init_schema = __esm(() => {
651
653
  enum: ["active", "waiting", "paused", "archived"]
652
654
  }).notNull().default("paused"),
653
655
  summary: text("summary"),
656
+ rating: integer("rating"),
654
657
  pid: integer("pid"),
655
658
  startedAt: text("started_at").notNull().default(sql`(datetime('now'))`),
656
659
  endedAt: text("ended_at"),
@@ -3453,10 +3456,8 @@ function installExitHandlers() {
3453
3456
  const onSignal = (signal) => {
3454
3457
  if (isClaudeRunning())
3455
3458
  return;
3456
- process.exit(signal === "SIGINT" ? 130 : signal === "SIGHUP" ? 129 : 143);
3459
+ process.exit(signal === "SIGHUP" ? 129 : 143);
3457
3460
  };
3458
- process.on("SIGINT", onSignal);
3459
- process.on("SIGTERM", onSignal);
3460
3461
  process.on("SIGHUP", onSignal);
3461
3462
  }
3462
3463
  async function launch(opts) {
@@ -3568,6 +3569,7 @@ function finalizeSession(sessionId, conversationId, exitCode) {
3568
3569
  emitSessionEnded({ sessionId });
3569
3570
  computeAndPersist(sessionId);
3570
3571
  stopServerIfIdle();
3572
+ triggerBackgroundPush();
3571
3573
  }
3572
3574
  var liveSession = null, exitHandlersInstalled = false;
3573
3575
  var init_session = __esm(() => {
@@ -3582,27 +3584,56 @@ var init_session = __esm(() => {
3582
3584
  init_spawn_context();
3583
3585
  init_timing();
3584
3586
  init_server_lifecycle();
3587
+ init_trigger();
3585
3588
  });
3586
3589
 
3587
3590
  // src/tui/app.tsx
3588
3591
  import { spawn as spawn4 } from "child_process";
3589
3592
  import { existsSync as existsSync8, readFileSync as readFileSync8, unlinkSync as unlinkSync3 } from "fs";
3593
+ import { tmpdir } from "os";
3590
3594
  import { join as join9 } from "path";
3591
3595
  import { randomUUID as randomUUID2 } from "crypto";
3592
3596
  async function runScreen(screen, ...args) {
3593
- const tmpFile = `/tmp/bertrand-tui-${process.pid}-${Date.now()}.json`;
3597
+ const tmpFile = join9(tmpdir(), `bertrand-tui-${randomUUID2()}.json`);
3598
+ if (process.env.BERTRAND_DEBUG_TUI) {
3599
+ try {
3600
+ const { appendFileSync } = await import("fs");
3601
+ appendFileSync(process.env.BERTRAND_DEBUG_TUI, `--- parent runScreen("${screen}") at ${Date.now()} entry=${SCREEN_ENTRY}
3602
+ `);
3603
+ } catch {}
3604
+ }
3594
3605
  const child = spawn4("bun", ["run", SCREEN_ENTRY, screen, tmpFile, ...args], {
3595
- stdio: "inherit"
3596
- });
3597
- const exitCode = await new Promise((resolve) => {
3598
- child.on("exit", (code) => resolve(code ?? 1));
3606
+ stdio: "inherit",
3607
+ env: process.env
3599
3608
  });
3600
- if (exitCode !== 0) {
3601
- throw new Error(`TUI screen "${screen}" exited with code ${exitCode}`);
3609
+ const noopSignal = () => {};
3610
+ process.on("SIGINT", noopSignal);
3611
+ process.on("SIGTERM", noopSignal);
3612
+ let spawnError = null;
3613
+ try {
3614
+ const { code, signal } = await new Promise((resolve) => {
3615
+ child.on("error", (err) => {
3616
+ spawnError = err;
3617
+ resolve({ code: 1, signal: null });
3618
+ });
3619
+ child.on("exit", (c, s) => resolve({ code: c, signal: s }));
3620
+ });
3621
+ if (spawnError) {
3622
+ throw new Error(`Failed to launch TUI screen "${screen}": ${spawnError.message}`);
3623
+ }
3624
+ if (!existsSync8(tmpFile)) {
3625
+ const detail = signal ? `killed by ${signal}` : `exited with code ${code ?? "?"} without writing result`;
3626
+ throw new Error(`TUI screen "${screen}" ${detail}`);
3627
+ }
3628
+ return JSON.parse(readFileSync8(tmpFile, "utf-8"));
3629
+ } finally {
3630
+ process.removeListener("SIGINT", noopSignal);
3631
+ process.removeListener("SIGTERM", noopSignal);
3632
+ try {
3633
+ if (existsSync8(tmpFile))
3634
+ unlinkSync3(tmpFile);
3635
+ } catch {}
3602
3636
  }
3603
- const result = JSON.parse(readFileSync8(tmpFile, "utf-8"));
3604
- unlinkSync3(tmpFile);
3605
- return result;
3606
3637
  }
3607
3638
  async function startLaunchTui() {
3608
3639
  return runScreen("launch");
@@ -3615,9 +3646,6 @@ async function startExitTui(sessionId) {
3615
3646
  }
3616
3647
  async function startResumeTui(sessionId) {
3617
3648
  const conversations2 = getConversationsBySession(sessionId);
3618
- if (conversations2.length === 1) {
3619
- return { type: "conversation", conversationId: conversations2[0].id };
3620
- }
3621
3649
  if (conversations2.length === 0) {
3622
3650
  return { type: "new" };
3623
3651
  }
@@ -3739,14 +3767,18 @@ function parseSessionName(input) {
3739
3767
  throw new Error(`Session name must include at least one category: "category/session" (got "${trimmed}")`);
3740
3768
  }
3741
3769
  for (const segment of segments) {
3742
- if (!/^[a-z0-9][a-z0-9._-]*$/i.test(segment)) {
3770
+ if (!SEGMENT_PATTERN.test(segment)) {
3743
3771
  throw new Error(`Invalid segment "${segment}": must start with alphanumeric and contain only letters, digits, dots, underscores, or dashes`);
3744
3772
  }
3745
3773
  }
3746
- const slug = segments[segments.length - 1];
3747
- const categoryPath = segments.slice(0, -1).join("/");
3774
+ const categoryPath = segments[0];
3775
+ const slug = segments.slice(1).join("/");
3748
3776
  return { categoryPath, slug };
3749
3777
  }
3778
+ var SEGMENT_PATTERN;
3779
+ var init_parse_session_name = __esm(() => {
3780
+ SEGMENT_PATTERN = /^[a-z0-9][a-z0-9._-]*$/i;
3781
+ });
3750
3782
 
3751
3783
  // src/engine/recovery.ts
3752
3784
  function isProcessAlive2(pid) {
@@ -3782,21 +3814,34 @@ var init_recovery = __esm(() => {
3782
3814
 
3783
3815
  // src/cli/commands/launch.ts
3784
3816
  var exports_launch = {};
3817
+ function reportFatal(err) {
3818
+ const message = err instanceof Error ? err.message : String(err);
3819
+ console.error(`bertrand: ${message}`);
3820
+ if (process.env.BERTRAND_DEBUG && err instanceof Error && err.stack) {
3821
+ console.error(err.stack);
3822
+ }
3823
+ process.exit(1);
3824
+ }
3785
3825
  var init_launch = __esm(() => {
3786
3826
  init_router();
3787
3827
  init_app();
3828
+ init_parse_session_name();
3788
3829
  init_session();
3789
3830
  init_recovery();
3790
3831
  register("launch", async (args) => {
3791
- recoverStaleSessions();
3792
- const sessionName = args[0];
3793
- if (sessionName) {
3794
- const { categoryPath, slug } = parseSessionName(sessionName);
3795
- const sessionId = await launch({ categoryPath, slug });
3796
- await runSessionLoop(sessionId);
3797
- return;
3832
+ try {
3833
+ recoverStaleSessions();
3834
+ const sessionName = args[0];
3835
+ if (sessionName) {
3836
+ const { categoryPath, slug } = parseSessionName(sessionName);
3837
+ const sessionId = await launch({ categoryPath, slug });
3838
+ await runSessionLoop(sessionId);
3839
+ return;
3840
+ }
3841
+ await startTui();
3842
+ } catch (err) {
3843
+ reportFatal(err);
3798
3844
  }
3799
- await startTui();
3800
3845
  });
3801
3846
  });
3802
3847
 
@@ -3804,7 +3849,7 @@ var init_launch = __esm(() => {
3804
3849
  function quietHelper(bin) {
3805
3850
  return `bq() { ${bin} "$@" 2>/dev/null || true; }`;
3806
3851
  }
3807
- function waitingScript(bin) {
3852
+ function waitingScript(bin, runtimeDir) {
3808
3853
  return `#!/usr/bin/env bash
3809
3854
  # Hook: PreToolUse AskUserQuestion \u2192 enforce multiSelect, mark session as waiting
3810
3855
  ${quietHelper(bin)}
@@ -3829,7 +3874,7 @@ question="$(printf '%s' "$input" | grep -o '"question":"[^"]*"' | head -1 | cut
3829
3874
  [ -z "$question" ] && question="Waiting for input"
3830
3875
 
3831
3876
  # Clear working debounce marker so next resume\u2192working transition fires
3832
- rm -f "/tmp/bertrand-working-$sid"
3877
+ rm -f "${runtimeDir}/working-$sid"
3833
3878
 
3834
3879
  bq update --session-id "$sid" --event session.waiting --meta "$(jq -n --arg q "$question" --arg cid "$cid" '{question:$q, claude_id:$cid}')"
3835
3880
 
@@ -3850,7 +3895,7 @@ bq notify bertrand "$question" &
3850
3895
  wait
3851
3896
  `;
3852
3897
  }
3853
- function answeredScript(bin) {
3898
+ function answeredScript(bin, _runtimeDir) {
3854
3899
  return `#!/usr/bin/env bash
3855
3900
  # Hook: PostToolUse AskUserQuestion \u2192 mark session as active
3856
3901
  #
@@ -3904,7 +3949,7 @@ fi
3904
3949
  wait
3905
3950
  `;
3906
3951
  }
3907
- function activeScript(bin) {
3952
+ function activeScript(bin, runtimeDir) {
3908
3953
  return `#!/usr/bin/env bash
3909
3954
  # Hook: PreToolUse (catch-all) \u2192 flip waiting to active
3910
3955
  ${quietHelper(bin)}
@@ -3913,7 +3958,7 @@ sid="\${BERTRAND_SESSION:-}"
3913
3958
 
3914
3959
  # Debounce: skip if we already sent session.active within the last 5 seconds.
3915
3960
  # This avoids spawning bertrand (~31ms) on every tool call during rapid sequences.
3916
- marker="/tmp/bertrand-working-$sid"
3961
+ marker="${runtimeDir}/working-$sid"
3917
3962
  if [ -f "$marker" ]; then
3918
3963
  age=$(( $(date +%s) - $(stat -f%m "$marker" 2>/dev/null || echo 0) ))
3919
3964
  [ "$age" -lt 5 ] && exit 0
@@ -3930,7 +3975,7 @@ cid="\${BERTRAND_CLAUDE_ID:-}"
3930
3975
  bq update --session-id "$sid" --event session.active --meta "$(jq -n --arg cid "$cid" '{claude_id:$cid}')"
3931
3976
  `;
3932
3977
  }
3933
- function permissionWaitScript(bin) {
3978
+ function permissionWaitScript(bin, runtimeDir) {
3934
3979
  return `#!/usr/bin/env bash
3935
3980
  # Hook: PermissionRequest \u2192 mark pending, emit permission.request
3936
3981
  ${quietHelper(bin)}
@@ -3942,7 +3987,7 @@ ${EXTRACT_TOOL}
3942
3987
  [ "$tool" = "AskUserQuestion" ] && exit 0
3943
3988
 
3944
3989
  # Write marker so PostToolUse knows this was a real permission prompt (not auto-approved)
3945
- touch "/tmp/bertrand-perm-pending-$sid"
3990
+ touch "${runtimeDir}/perm-pending-$sid"
3946
3991
 
3947
3992
  # Extract detail from tool_input via grep (avoid jq for simple fields)
3948
3993
  detail=""
@@ -3960,7 +4005,7 @@ bq notify bertrand "Needs permission: $tool" &
3960
4005
  wait
3961
4006
  `;
3962
4007
  }
3963
- function permissionDoneScript(bin) {
4008
+ function permissionDoneScript(bin, runtimeDir) {
3964
4009
  return `#!/usr/bin/env bash
3965
4010
  # Hook: PostToolUse (catch-all)
3966
4011
  #
@@ -3985,7 +4030,7 @@ ${EXTRACT_TOOL}
3985
4030
  # Don't double-log: AskUserQuestion has its own waiting/answered events
3986
4031
  [ "$tool" = "AskUserQuestion" ] && exit 0
3987
4032
 
3988
- marker="/tmp/bertrand-perm-pending-$sid"
4033
+ marker="${runtimeDir}/perm-pending-$sid"
3989
4034
  had_marker=0
3990
4035
  if [ -f "$marker" ]; then
3991
4036
  had_marker=1
@@ -4044,7 +4089,7 @@ fi
4044
4089
  wait
4045
4090
  `;
4046
4091
  }
4047
- function userPromptScript(bin) {
4092
+ function userPromptScript(bin, _runtimeDir) {
4048
4093
  return `#!/usr/bin/env bash
4049
4094
  # Hook: UserPromptSubmit \u2192 record user free-text prompt
4050
4095
  ${quietHelper(bin)}
@@ -4060,7 +4105,7 @@ meta="$(printf '%s' "$input" | jq --arg cid "$cid" '{prompt: (.prompt // ""), cl
4060
4105
  bq update --session-id "$sid" --event user.prompt --meta "$meta"
4061
4106
  `;
4062
4107
  }
4063
- function doneScript(bin) {
4108
+ function doneScript(bin, _runtimeDir) {
4064
4109
  return `#!/usr/bin/env bash
4065
4110
  # Hook: Stop \u2192 mark session as paused
4066
4111
  ${quietHelper(bin)}
@@ -4102,9 +4147,10 @@ import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync5, chmodSync as
4102
4147
  import { join as join10 } from "path";
4103
4148
  function installHookScripts(bin) {
4104
4149
  mkdirSync7(paths.hooks, { recursive: true });
4150
+ mkdirSync7(paths.runtime, { recursive: true });
4105
4151
  for (const [filename, scriptFn] of Object.entries(HOOK_SCRIPTS)) {
4106
4152
  const filePath = join10(paths.hooks, filename);
4107
- writeFileSync5(filePath, scriptFn(bin));
4153
+ writeFileSync5(filePath, scriptFn(bin, paths.runtime));
4108
4154
  chmodSync2(filePath, 493);
4109
4155
  }
4110
4156
  console.log(`Installed ${Object.keys(HOOK_SCRIPTS).length} hook scripts to ${paths.hooks}`);
@@ -4293,6 +4339,7 @@ var init_init = __esm(() => {
4293
4339
  `);
4294
4340
  mkdirSync10(paths.root, { recursive: true });
4295
4341
  mkdirSync10(paths.hooks, { recursive: true });
4342
+ mkdirSync10(paths.runtime, { recursive: true });
4296
4343
  const active = resolveActiveProject();
4297
4344
  runMigrations(active.db);
4298
4345
  console.log(` Database: ${active.db}`);
@@ -4323,6 +4370,40 @@ Error: couldn't locate the bertrand binary on PATH.
4323
4370
  });
4324
4371
  });
4325
4372
 
4373
+ // src/lib/projects/cli-flag.ts
4374
+ function extractProjectFlag2(args) {
4375
+ const rest = [];
4376
+ let project;
4377
+ for (let i = 0;i < args.length; i++) {
4378
+ const a = args[i];
4379
+ if (a === "--project") {
4380
+ project = args[i + 1];
4381
+ i++;
4382
+ continue;
4383
+ }
4384
+ if (a.startsWith("--project=")) {
4385
+ project = a.slice("--project=".length);
4386
+ continue;
4387
+ }
4388
+ rest.push(a);
4389
+ }
4390
+ return { project, rest };
4391
+ }
4392
+ function applyProjectFlag(slug) {
4393
+ if (!slug)
4394
+ return;
4395
+ if (!projectExists(slug)) {
4396
+ console.error(`Unknown project: ${slug}. Run \`bertrand project list\` to see registered projects.`);
4397
+ process.exit(1);
4398
+ }
4399
+ process.env.BERTRAND_PROJECT = slug;
4400
+ _resetActiveProjectCache();
4401
+ }
4402
+ var init_cli_flag = __esm(() => {
4403
+ init_resolve();
4404
+ init_registry();
4405
+ });
4406
+
4326
4407
  // src/cli/commands/list.ts
4327
4408
  var exports_list = {};
4328
4409
  function buildRows(sessions2) {
@@ -4338,13 +4419,15 @@ function buildRows(sessions2) {
4338
4419
  });
4339
4420
  }
4340
4421
  function renderTable(rows) {
4422
+ const dim = "\x1B[2m";
4423
+ const reset = "\x1B[0m";
4424
+ const project = resolveActiveProject();
4425
+ console.log(`${dim}Project: ${project.slug} (${project.name})${reset}`);
4341
4426
  if (rows.length === 0) {
4342
4427
  console.log("No sessions found.");
4343
4428
  return;
4344
4429
  }
4345
4430
  const maxName = Math.max(...rows.map((r) => r.name.length), 4);
4346
- const dim = "\x1B[2m";
4347
- const reset = "\x1B[0m";
4348
4431
  console.log(`${dim}${" "} ${"NAME".padEnd(maxName)} ${"STATUS".padEnd(10)} ${"DURATION".padEnd(8)} ${"CONVOS".padEnd(6)} LAST ACTIVE${reset}`);
4349
4432
  for (const row of rows) {
4350
4433
  const dot = STATUS_DOTS[row.status] ?? "?";
@@ -4356,12 +4439,14 @@ function renderTable(rows) {
4356
4439
  }
4357
4440
  }
4358
4441
  function renderJson(rows) {
4442
+ const project = resolveActiveProject();
4359
4443
  const data = rows.map((r) => ({
4360
4444
  name: r.name,
4361
4445
  status: r.status,
4362
4446
  duration: r.duration,
4363
4447
  conversations: r.conversations,
4364
- updatedAt: r.updatedAt
4448
+ updatedAt: r.updatedAt,
4449
+ project: { slug: project.slug, name: project.name }
4365
4450
  }));
4366
4451
  console.log(JSON.stringify(data, null, 2));
4367
4452
  }
@@ -4372,6 +4457,8 @@ var init_list = __esm(() => {
4372
4457
  init_categories();
4373
4458
  init_stats();
4374
4459
  init_format();
4460
+ init_resolve();
4461
+ init_cli_flag();
4375
4462
  STATUS_DOTS = {
4376
4463
  active: "\x1B[32m\u25CF\x1B[0m",
4377
4464
  waiting: "\x1B[33m\u25CF\x1B[0m",
@@ -4380,10 +4467,12 @@ var init_list = __esm(() => {
4380
4467
  };
4381
4468
  alias("ls", "list");
4382
4469
  register("list", async (args) => {
4383
- const isJson = args.includes("--json");
4384
- const showAll = args.includes("--all") || args.includes("-a");
4385
- const categoryFlag = args.indexOf("--category");
4386
- const categoryPath = categoryFlag !== -1 ? args[categoryFlag + 1] : undefined;
4470
+ const { project: projectSlug, rest: argsWithoutProject } = extractProjectFlag2(args);
4471
+ applyProjectFlag(projectSlug);
4472
+ const isJson = argsWithoutProject.includes("--json");
4473
+ const showAll = argsWithoutProject.includes("--all") || argsWithoutProject.includes("-a");
4474
+ const categoryFlag = argsWithoutProject.indexOf("--category");
4475
+ const categoryPath = categoryFlag !== -1 ? argsWithoutProject[categoryFlag + 1] : undefined;
4387
4476
  let sessionRows;
4388
4477
  if (categoryPath) {
4389
4478
  const category = getCategoryByPath(categoryPath);
@@ -4643,7 +4732,9 @@ function ansi256(code, text2) {
4643
4732
  return `\x1B[38;5;${code}m${text2}${RESET}`;
4644
4733
  }
4645
4734
  function showAllSessions() {
4735
+ const project = resolveActiveProject();
4646
4736
  const rows = getAllSessions().sort((a, b) => new Date(b.session.updatedAt).getTime() - new Date(a.session.updatedAt).getTime());
4737
+ console.log(`${DIM}Project: ${project.slug} (${project.name})${RESET}`);
4647
4738
  if (rows.length === 0) {
4648
4739
  console.log("No sessions.");
4649
4740
  return;
@@ -4768,15 +4859,22 @@ function renderTimingFooter(sessionId) {
4768
4859
  lines.push(`${DIM}Duration: ${formatDuration(durationS * 1000)} \xB7 Claude: ${formatDuration(claudeWorkS * 1000)} (${activePctVal}%) \xB7 Wait: ${formatDuration(userWaitS * 1000)} (${100 - activePctVal}%)${RESET}`);
4769
4860
  return lines;
4770
4861
  }
4862
+ function renderBreadcrumb(projectSlug, projectName, sessionName) {
4863
+ const segments = sessionName.split("/").filter(Boolean);
4864
+ const trail = segments.join(` ${DIM}\u203A${RESET} `);
4865
+ return `${DIM}${projectSlug} (${projectName})${RESET} ${DIM}\xB7${RESET} ${BOLD}${trail}${RESET}`;
4866
+ }
4771
4867
  function showSessionLog(session, sessionName, isJson) {
4772
4868
  const sessionId = session.id;
4773
4869
  const rawEvents = getEventsBySession(sessionId);
4774
4870
  const enriched = enrichAll(rawEvents);
4775
4871
  const compacted = compact(enriched);
4872
+ const project = resolveActiveProject();
4776
4873
  if (isJson) {
4777
4874
  const stats = getSessionStats(sessionId);
4778
4875
  const conversations2 = getConversationsBySession(sessionId);
4779
4876
  console.log(JSON.stringify({
4877
+ project: { slug: project.slug, name: project.name },
4780
4878
  session: { ...session, name: sessionName },
4781
4879
  stats,
4782
4880
  conversations: conversations2,
@@ -4794,6 +4892,8 @@ function showSessionLog(session, sessionName, isJson) {
4794
4892
  }
4795
4893
  const segments = segmentByConversation(compacted);
4796
4894
  const allLines = [];
4895
+ allLines.push(renderBreadcrumb(project.slug, project.name, sessionName));
4896
+ allLines.push("");
4797
4897
  for (let i = 0;i < segments.length; i++) {
4798
4898
  const segLines = renderSegment(segments[i], i, segments.length);
4799
4899
  allLines.push(...segLines);
@@ -4814,7 +4914,10 @@ var init_log = __esm(() => {
4814
4914
  init_catalog();
4815
4915
  init_compact();
4816
4916
  init_timing();
4917
+ init_parse_session_name();
4817
4918
  init_format();
4919
+ init_resolve();
4920
+ init_cli_flag();
4818
4921
  STATUS_DOTS2 = {
4819
4922
  active: ansi(32, "\u25CF"),
4820
4923
  waiting: ansi(33, "\u25CF"),
@@ -4822,8 +4925,10 @@ var init_log = __esm(() => {
4822
4925
  archived: `${DIM}\u25CB${RESET}`
4823
4926
  };
4824
4927
  register("log", async (args) => {
4825
- const isJson = args.includes("--json");
4826
- const filteredArgs = args.filter((a) => !a.startsWith("--"));
4928
+ const { project: projectSlug, rest: argsWithoutProject } = extractProjectFlag2(args);
4929
+ applyProjectFlag(projectSlug);
4930
+ const isJson = argsWithoutProject.includes("--json");
4931
+ const filteredArgs = argsWithoutProject.filter((a) => !a.startsWith("--"));
4827
4932
  const target = filteredArgs[0];
4828
4933
  if (!target) {
4829
4934
  showAllSessions();
@@ -4968,6 +5073,7 @@ var init_stats2 = __esm(() => {
4968
5073
  init_events();
4969
5074
  init_timing();
4970
5075
  init_format();
5076
+ init_parse_session_name();
4971
5077
  ACTIVE_STATUSES2 = ["active", "waiting"];
4972
5078
  register("stats", async (args) => {
4973
5079
  const isJson = args.includes("--json");
@@ -5045,6 +5151,7 @@ var init_archive = __esm(() => {
5045
5151
  init_router();
5046
5152
  init_sessions();
5047
5153
  init_categories();
5154
+ init_parse_session_name();
5048
5155
  init_session_archive();
5049
5156
  register("archive", async (args) => {
5050
5157
  const isUndo = args.includes("--undo");