bertrand 0.22.0 → 0.22.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.
Files changed (2) hide show
  1. package/dist/bertrand.js +51 -29
  2. package/package.json +1 -1
package/dist/bertrand.js CHANGED
@@ -1363,6 +1363,8 @@ var init_update = __esm(() => {
1363
1363
 
1364
1364
  // src/lib/transcript.ts
1365
1365
  import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
1366
+ import { homedir as homedir2 } from "os";
1367
+ import { join as join6 } from "path";
1366
1368
  function getContextWindowSize(model) {
1367
1369
  for (const [prefix, size] of Object.entries(CONTEXT_WINDOW_SIZES)) {
1368
1370
  if (model.startsWith(prefix))
@@ -1370,6 +1372,13 @@ function getContextWindowSize(model) {
1370
1372
  }
1371
1373
  return 200000;
1372
1374
  }
1375
+ function claudeTranscriptPath(sessionId, cwd) {
1376
+ const dir = (cwd ?? process.cwd()).replace(/\//g, "-");
1377
+ return join6(homedir2(), ".claude", "projects", dir, `${sessionId}.jsonl`);
1378
+ }
1379
+ function claudeSessionExists(sessionId, cwd) {
1380
+ return existsSync5(claudeTranscriptPath(sessionId, cwd));
1381
+ }
1373
1382
  function getLatestAssistantTurn(filePath) {
1374
1383
  if (!existsSync5(filePath))
1375
1384
  return null;
@@ -1712,7 +1721,7 @@ class NoopAdapter {
1712
1721
 
1713
1722
  // src/terminal/index.ts
1714
1723
  import { readFileSync as readFileSync5 } from "fs";
1715
- import { join as join6 } from "path";
1724
+ import { join as join7 } from "path";
1716
1725
  function getTerminalAdapter() {
1717
1726
  if (cachedAdapter)
1718
1727
  return cachedAdapter;
@@ -1731,7 +1740,7 @@ function getTerminalAdapter() {
1731
1740
  }
1732
1741
  function readConfigTerminal() {
1733
1742
  try {
1734
- const config = JSON.parse(readFileSync5(join6(paths.root, "config.json"), "utf-8"));
1743
+ const config = JSON.parse(readFileSync5(join7(paths.root, "config.json"), "utf-8"));
1735
1744
  return config.terminal ?? null;
1736
1745
  } catch {
1737
1746
  return null;
@@ -2091,7 +2100,7 @@ var init_session_archive = __esm(() => {
2091
2100
  // src/server/index.ts
2092
2101
  import { execFile } from "child_process";
2093
2102
  import { existsSync as existsSync6 } from "fs";
2094
- import { join as join7 } from "path";
2103
+ import { join as join8 } from "path";
2095
2104
  function liveStats(sessionId) {
2096
2105
  return {
2097
2106
  sessionId,
@@ -2164,11 +2173,11 @@ function match(pathname, url) {
2164
2173
  }
2165
2174
  function findDashboardDir() {
2166
2175
  const candidates = [
2167
- join7(import.meta.dir, "dashboard"),
2168
- join7(import.meta.dir, "..", "dashboard")
2176
+ join8(import.meta.dir, "dashboard"),
2177
+ join8(import.meta.dir, "..", "dashboard")
2169
2178
  ];
2170
2179
  for (const dir of candidates) {
2171
- if (existsSync6(join7(dir, "index.html")))
2180
+ if (existsSync6(join8(dir, "index.html")))
2172
2181
  return dir;
2173
2182
  }
2174
2183
  return null;
@@ -2177,13 +2186,13 @@ async function serveDashboard(pathname) {
2177
2186
  if (!DASHBOARD_DIR)
2178
2187
  return null;
2179
2188
  const requested = pathname === "/" ? "/index.html" : pathname;
2180
- const filePath = join7(DASHBOARD_DIR, requested);
2189
+ const filePath = join8(DASHBOARD_DIR, requested);
2181
2190
  if (!filePath.startsWith(DASHBOARD_DIR))
2182
2191
  return null;
2183
2192
  const file = Bun.file(filePath);
2184
2193
  if (await file.exists())
2185
2194
  return new Response(file);
2186
- return new Response(Bun.file(join7(DASHBOARD_DIR, "index.html")));
2195
+ return new Response(Bun.file(join8(DASHBOARD_DIR, "index.html")));
2187
2196
  }
2188
2197
  function startServer(port = PORT) {
2189
2198
  const server = Bun.serve({
@@ -3342,7 +3351,7 @@ var init_spawn_context = __esm(() => {
3342
3351
  // src/lib/server-lifecycle.ts
3343
3352
  import { spawn as spawn3 } from "child_process";
3344
3353
  import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, unlinkSync as unlinkSync2 } from "fs";
3345
- import { join as join8 } from "path";
3354
+ import { join as join9 } from "path";
3346
3355
  function readPidFile() {
3347
3356
  try {
3348
3357
  const pid = Number(readFileSync7(deps.pidFile, "utf-8").trim());
@@ -3410,11 +3419,11 @@ var init_server_lifecycle = __esm(() => {
3410
3419
  init_paths();
3411
3420
  init_sessions();
3412
3421
  defaultDeps = {
3413
- pidFile: join8(paths.root, "server.pid"),
3422
+ pidFile: join9(paths.root, "server.pid"),
3414
3423
  port: Number(process.env.BERTRAND_PORT ?? 5200),
3415
3424
  resolveBin() {
3416
3425
  try {
3417
- const config = JSON.parse(readFileSync7(join8(paths.root, "config.json"), "utf-8"));
3426
+ const config = JSON.parse(readFileSync7(join9(paths.root, "config.json"), "utf-8"));
3418
3427
  return typeof config?.bin === "string" ? config.bin : null;
3419
3428
  } catch {
3420
3429
  return null;
@@ -3524,6 +3533,7 @@ async function resume(opts) {
3524
3533
  throw new Error(`Session not found: ${opts.sessionId}`);
3525
3534
  const category = getCategory(session.categoryId);
3526
3535
  const sessionName = category ? `${category.path}/${session.slug}` : session.name;
3536
+ const isFreshClaudeSession = !claudeSessionExists(opts.conversationId);
3527
3537
  updateSession(session.id, { status: "active", pid: process.pid });
3528
3538
  liveSession = { sessionId: session.id, claudeId: opts.conversationId };
3529
3539
  installExitHandlers();
@@ -3532,6 +3542,17 @@ async function resume(opts) {
3532
3542
  sessionId: session.id,
3533
3543
  conversationId: opts.conversationId
3534
3544
  });
3545
+ if (isFreshClaudeSession) {
3546
+ const spawnContext = await captureSpawnContext();
3547
+ emitClaudeStarted({
3548
+ sessionId: session.id,
3549
+ conversationId: opts.conversationId,
3550
+ model: spawnContext.model,
3551
+ claudeVersion: spawnContext.claudeVersion,
3552
+ git: spawnContext.git,
3553
+ cwd: spawnContext.cwd
3554
+ });
3555
+ }
3535
3556
  const categoryPath = category?.path ?? "";
3536
3557
  const siblingContext = buildSiblingContext(session.categoryId, categoryPath, session.id);
3537
3558
  const contract = buildContract(sessionName, siblingContext);
@@ -3541,7 +3562,7 @@ async function resume(opts) {
3541
3562
  sessionName,
3542
3563
  sessionSlug: session.slug,
3543
3564
  contract,
3544
- resume: true
3565
+ resume: !isFreshClaudeSession
3545
3566
  });
3546
3567
  finalizeSession(session.id, opts.conversationId, exitCode);
3547
3568
  return session.id;
@@ -3585,16 +3606,17 @@ var init_session = __esm(() => {
3585
3606
  init_timing();
3586
3607
  init_server_lifecycle();
3587
3608
  init_trigger();
3609
+ init_transcript();
3588
3610
  });
3589
3611
 
3590
3612
  // src/tui/app.tsx
3591
3613
  import { spawn as spawn4 } from "child_process";
3592
3614
  import { existsSync as existsSync8, readFileSync as readFileSync8, unlinkSync as unlinkSync3 } from "fs";
3593
3615
  import { tmpdir } from "os";
3594
- import { join as join9 } from "path";
3616
+ import { join as join10 } from "path";
3595
3617
  import { randomUUID as randomUUID2 } from "crypto";
3596
3618
  async function runScreen(screen, ...args) {
3597
- const tmpFile = join9(tmpdir(), `bertrand-tui-${randomUUID2()}.json`);
3619
+ const tmpFile = join10(tmpdir(), `bertrand-tui-${randomUUID2()}.json`);
3598
3620
  if (process.env.BERTRAND_DEBUG_TUI) {
3599
3621
  try {
3600
3622
  const { appendFileSync } = await import("fs");
@@ -3751,8 +3773,8 @@ var init_app = __esm(() => {
3751
3773
  init_create();
3752
3774
  init_resolve();
3753
3775
  SCREEN_ENTRY = (() => {
3754
- const built = join9(import.meta.dir, "run-screen.js");
3755
- return existsSync8(built) ? built : join9(import.meta.dir, "run-screen.tsx");
3776
+ const built = join10(import.meta.dir, "run-screen.js");
3777
+ return existsSync8(built) ? built : join10(import.meta.dir, "run-screen.tsx");
3756
3778
  })();
3757
3779
  });
3758
3780
 
@@ -4144,12 +4166,12 @@ var init_scripts = __esm(() => {
4144
4166
 
4145
4167
  // src/hooks/install.ts
4146
4168
  import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync5, chmodSync as chmodSync2 } from "fs";
4147
- import { join as join10 } from "path";
4169
+ import { join as join11 } from "path";
4148
4170
  function installHookScripts(bin) {
4149
4171
  mkdirSync7(paths.hooks, { recursive: true });
4150
4172
  mkdirSync7(paths.runtime, { recursive: true });
4151
4173
  for (const [filename, scriptFn] of Object.entries(HOOK_SCRIPTS)) {
4152
- const filePath = join10(paths.hooks, filename);
4174
+ const filePath = join11(paths.hooks, filename);
4153
4175
  writeFileSync5(filePath, scriptFn(bin, paths.runtime));
4154
4176
  chmodSync2(filePath, 493);
4155
4177
  }
@@ -4162,8 +4184,8 @@ var init_install = __esm(() => {
4162
4184
 
4163
4185
  // src/hooks/settings.ts
4164
4186
  import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, mkdirSync as mkdirSync8 } from "fs";
4165
- import { join as join11, dirname as dirname4 } from "path";
4166
- import { homedir as homedir2 } from "os";
4187
+ import { join as join12, dirname as dirname4 } from "path";
4188
+ import { homedir as homedir3 } from "os";
4167
4189
  function isBertrandGroup(group) {
4168
4190
  return group.hooks?.some((h) => h.command?.includes(".bertrand/hooks/")) ?? false;
4169
4191
  }
@@ -4187,7 +4209,7 @@ function installHookSettings() {
4187
4209
  var SETTINGS_PATH, BERTRAND_HOOKS;
4188
4210
  var init_settings = __esm(() => {
4189
4211
  init_paths();
4190
- SETTINGS_PATH = join11(homedir2(), ".claude", "settings.json");
4212
+ SETTINGS_PATH = join12(homedir3(), ".claude", "settings.json");
4191
4213
  BERTRAND_HOOKS = {
4192
4214
  PreToolUse: [
4193
4215
  {
@@ -4232,7 +4254,7 @@ var init_settings = __esm(() => {
4232
4254
 
4233
4255
  // src/lib/completions.ts
4234
4256
  import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync9 } from "fs";
4235
- import { join as join12 } from "path";
4257
+ import { join as join13 } from "path";
4236
4258
  function bashCompletion() {
4237
4259
  return `# bertrand bash completion
4238
4260
  _bertrand() {
@@ -4262,11 +4284,11 @@ function fishCompletion() {
4262
4284
  `;
4263
4285
  }
4264
4286
  function generateCompletions() {
4265
- const dir = join12(paths.root, "completions");
4287
+ const dir = join13(paths.root, "completions");
4266
4288
  mkdirSync9(dir, { recursive: true });
4267
- writeFileSync7(join12(dir, "bertrand.bash"), bashCompletion());
4268
- writeFileSync7(join12(dir, "_bertrand"), zshCompletion());
4269
- writeFileSync7(join12(dir, "bertrand.fish"), fishCompletion());
4289
+ writeFileSync7(join13(dir, "bertrand.bash"), bashCompletion());
4290
+ writeFileSync7(join13(dir, "_bertrand"), zshCompletion());
4291
+ writeFileSync7(join13(dir, "bertrand.fish"), fishCompletion());
4270
4292
  console.log(`Shell completions written to ${dir}`);
4271
4293
  console.log(" Add to your shell config:");
4272
4294
  console.log(` bash: source ${dir}/bertrand.bash`);
@@ -4297,7 +4319,7 @@ var init_completions = __esm(() => {
4297
4319
  var exports_init = {};
4298
4320
  import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync8, chmodSync as chmodSync3 } from "fs";
4299
4321
  import { execSync as execSync2 } from "child_process";
4300
- import { join as join13 } from "path";
4322
+ import { join as join14 } from "path";
4301
4323
  function detectTerminal() {
4302
4324
  try {
4303
4325
  execSync2("which wsh", { stdio: "ignore" });
@@ -4312,8 +4334,8 @@ function resolveBin() {
4312
4334
  return onPath;
4313
4335
  const entry = process.argv[1];
4314
4336
  if (entry && SOURCE_ENTRY.test(entry)) {
4315
- const launcherDir = join13(paths.root, "bin");
4316
- const launcher = join13(launcherDir, "bertrand-dev");
4337
+ const launcherDir = join14(paths.root, "bin");
4338
+ const launcher = join14(launcherDir, "bertrand-dev");
4317
4339
  mkdirSync10(launcherDir, { recursive: true });
4318
4340
  writeFileSync8(launcher, `#!/usr/bin/env bash
4319
4341
  exec ${process.execPath} ${JSON.stringify(entry)} "$@"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bertrand",
3
- "version": "0.22.0",
3
+ "version": "0.22.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },