codeam-cli 2.4.29 → 2.4.31

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 (31) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/index.js +132 -114
  3. package/dist/vendor/node-pty/lib/conpty_console_list_agent.js +16 -0
  4. package/dist/vendor/node-pty/lib/eventEmitter2.js +47 -0
  5. package/dist/vendor/node-pty/lib/index.js +52 -0
  6. package/dist/vendor/node-pty/lib/interfaces.js +7 -0
  7. package/dist/vendor/node-pty/lib/shared/conout.js +11 -0
  8. package/dist/vendor/node-pty/lib/terminal.js +190 -0
  9. package/dist/vendor/node-pty/lib/types.js +7 -0
  10. package/dist/vendor/node-pty/lib/unixTerminal.js +346 -0
  11. package/dist/vendor/node-pty/lib/utils.js +39 -0
  12. package/dist/vendor/node-pty/lib/windowsConoutConnection.js +125 -0
  13. package/dist/vendor/node-pty/lib/windowsPtyAgent.js +320 -0
  14. package/dist/vendor/node-pty/lib/windowsTerminal.js +199 -0
  15. package/dist/vendor/node-pty/lib/worker/conoutSocketWorker.js +22 -0
  16. package/dist/vendor/node-pty/package.json +64 -0
  17. package/dist/vendor/node-pty/prebuilds/win32-arm64/conpty/OpenConsole.exe +0 -0
  18. package/dist/vendor/node-pty/prebuilds/win32-arm64/conpty/conpty.dll +0 -0
  19. package/dist/vendor/node-pty/prebuilds/win32-arm64/conpty.node +0 -0
  20. package/dist/vendor/node-pty/prebuilds/win32-arm64/conpty_console_list.node +0 -0
  21. package/dist/vendor/node-pty/prebuilds/win32-arm64/pty.node +0 -0
  22. package/dist/vendor/node-pty/prebuilds/win32-arm64/winpty-agent.exe +0 -0
  23. package/dist/vendor/node-pty/prebuilds/win32-arm64/winpty.dll +0 -0
  24. package/dist/vendor/node-pty/prebuilds/win32-x64/conpty/OpenConsole.exe +0 -0
  25. package/dist/vendor/node-pty/prebuilds/win32-x64/conpty/conpty.dll +0 -0
  26. package/dist/vendor/node-pty/prebuilds/win32-x64/conpty.node +0 -0
  27. package/dist/vendor/node-pty/prebuilds/win32-x64/conpty_console_list.node +0 -0
  28. package/dist/vendor/node-pty/prebuilds/win32-x64/pty.node +0 -0
  29. package/dist/vendor/node-pty/prebuilds/win32-x64/winpty-agent.exe +0 -0
  30. package/dist/vendor/node-pty/prebuilds/win32-x64/winpty.dll +0 -0
  31. package/package.json +3 -5
package/CHANGELOG.md CHANGED
@@ -4,6 +4,18 @@ All notable changes to `codeam-cli` are documented here.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [2.4.30] — 2026-05-05
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** Pin node-pty ^1.1.0 + graceful pipe fallback if ConPTY fails (v2.4.30)
12
+
13
+ ## [2.4.29] — 2026-05-05
14
+
15
+ ### Added
16
+
17
+ - **cli:** Auto-install Claude Code if missing on first launch (v2.4.29)
18
+
7
19
  ## [2.4.28] — 2026-05-05
8
20
 
9
21
  ### Fixed
package/dist/index.js CHANGED
@@ -521,7 +521,7 @@ var require_windowsPtyAgent = __commonJS({
521
521
  exports2.argsToCommandLine = exports2.WindowsPtyAgent = void 0;
522
522
  var fs9 = require("fs");
523
523
  var os8 = require("os");
524
- var path14 = require("path");
524
+ var path15 = require("path");
525
525
  var child_process_1 = require("child_process");
526
526
  var net_1 = require("net");
527
527
  var windowsConoutConnection_1 = require_windowsConoutConnection();
@@ -557,7 +557,7 @@ var require_windowsPtyAgent = __commonJS({
557
557
  }
558
558
  }
559
559
  this._ptyNative = this._useConpty ? conptyNative : winptyNative;
560
- cwd = path14.resolve(cwd);
560
+ cwd = path15.resolve(cwd);
561
561
  var commandLine = argsToCommandLine(file, args2);
562
562
  var term;
563
563
  if (this._useConpty) {
@@ -679,7 +679,7 @@ var require_windowsPtyAgent = __commonJS({
679
679
  WindowsPtyAgent2.prototype._getConsoleProcessList = function() {
680
680
  var _this = this;
681
681
  return new Promise(function(resolve2) {
682
- var agent = child_process_1.fork(path14.join(__dirname, "conpty_console_list_agent"), [_this._innerPid.toString()]);
682
+ var agent = child_process_1.fork(path15.join(__dirname, "conpty_console_list_agent"), [_this._innerPid.toString()]);
683
683
  agent.on("message", function(message) {
684
684
  clearTimeout(timeout);
685
685
  resolve2(message.consoleProcessList);
@@ -1013,14 +1013,14 @@ var require_unixTerminal = __commonJS({
1013
1013
  Object.defineProperty(exports2, "__esModule", { value: true });
1014
1014
  exports2.UnixTerminal = void 0;
1015
1015
  var fs9 = require("fs");
1016
- var path14 = require("path");
1016
+ var path15 = require("path");
1017
1017
  var tty = require("tty");
1018
1018
  var terminal_1 = require_terminal();
1019
1019
  var utils_1 = require_utils();
1020
1020
  var native = utils_1.loadNativeModule("pty");
1021
1021
  var pty = native.module;
1022
1022
  var helperPath = native.dir + "/spawn-helper";
1023
- helperPath = path14.resolve(__dirname, helperPath);
1023
+ helperPath = path15.resolve(__dirname, helperPath);
1024
1024
  helperPath = helperPath.replace("app.asar", "app.asar.unpacked");
1025
1025
  helperPath = helperPath.replace("node_modules.asar", "node_modules.asar.unpacked");
1026
1026
  var DEFAULT_FILE = "sh";
@@ -1392,7 +1392,7 @@ var require_src = __commonJS({
1392
1392
  // src/commands/start.ts
1393
1393
  var fs7 = __toESM(require("fs"));
1394
1394
  var os6 = __toESM(require("os"));
1395
- var path8 = __toESM(require("path"));
1395
+ var path9 = __toESM(require("path"));
1396
1396
  var import_crypto = require("crypto");
1397
1397
  var import_child_process5 = require("child_process");
1398
1398
  var import_picocolors2 = __toESM(require("picocolors"));
@@ -1482,7 +1482,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
1482
1482
  // package.json
1483
1483
  var package_default = {
1484
1484
  name: "codeam-cli",
1485
- version: "2.4.29",
1485
+ version: "2.4.31",
1486
1486
  description: "Remote control Claude Code (and other AI coding agents) from your mobile phone. Pair your device, send prompts, stream responses in real-time, and approve commands \u2014 from anywhere.",
1487
1487
  main: "dist/index.js",
1488
1488
  bin: {
@@ -1495,7 +1495,7 @@ var package_default = {
1495
1495
  "LICENSE"
1496
1496
  ],
1497
1497
  scripts: {
1498
- build: "tsup",
1498
+ build: "tsup && node scripts/vendor-node-pty.js",
1499
1499
  dev: "tsup --watch",
1500
1500
  test: "vitest run",
1501
1501
  typecheck: "tsc --noEmit",
@@ -1556,14 +1556,12 @@ var package_default = {
1556
1556
  ws: "^8.18.0",
1557
1557
  zod: "^4.3.6"
1558
1558
  },
1559
- optionalDependencies: {
1560
- "node-pty": "^1.0.0"
1561
- },
1562
1559
  devDependencies: {
1563
1560
  "@codeagent/shared": "*",
1564
1561
  "@types/node": "^22.0.0",
1565
1562
  "@types/qrcode-terminal": "^0.12.0",
1566
1563
  "@types/ws": "^8.5.0",
1564
+ "node-pty": "^1.1.0",
1567
1565
  tsup: "^8.0.0",
1568
1566
  typescript: "^6.0.3",
1569
1567
  vitest: "^4.1.5"
@@ -2262,11 +2260,18 @@ var WindowsPtyStrategy = class {
2262
2260
  };
2263
2261
 
2264
2262
  // src/services/pty/windows-conpty.strategy.ts
2263
+ var path4 = __toESM(require("path"));
2265
2264
  function loadNodePty() {
2265
+ const vendoredPath = path4.join(__dirname, "vendor", "node-pty");
2266
2266
  try {
2267
- return require_lib();
2268
- } catch {
2269
- return null;
2267
+ return require(vendoredPath);
2268
+ } catch (vendorErr) {
2269
+ try {
2270
+ return require_lib();
2271
+ } catch {
2272
+ void vendorErr;
2273
+ return null;
2274
+ }
2270
2275
  }
2271
2276
  }
2272
2277
  var WindowsConPtyStrategy = class _WindowsConPtyStrategy {
@@ -2291,31 +2296,19 @@ var WindowsConPtyStrategy = class _WindowsConPtyStrategy {
2291
2296
  return new _WindowsConPtyStrategy(opts, lib);
2292
2297
  }
2293
2298
  spawn(cmd, cwd, args2 = []) {
2294
- try {
2295
- this.pty = this.lib.spawn(cmd, args2, {
2296
- name: "xterm-256color",
2297
- cols: 220,
2298
- rows: 50,
2299
- cwd,
2300
- env: {
2301
- ...process.env,
2302
- TERM: "xterm-256color",
2303
- FORCE_COLOR: "1"
2304
- },
2305
- useConpty: true,
2306
- conptyInheritCursor: false
2307
- });
2308
- } catch (err) {
2309
- const msg = err instanceof Error ? err.message : String(err);
2310
- console.error(
2311
- `
2312
- \u2717 Failed to launch Claude Code via ConPTY: ${msg}
2313
- Make sure claude is installed: npm install -g @anthropic-ai/claude-code
2314
- `
2315
- );
2316
- this.opts.onExit(1);
2317
- return;
2318
- }
2299
+ this.pty = this.lib.spawn(cmd, args2, {
2300
+ name: "xterm-256color",
2301
+ cols: 220,
2302
+ rows: 50,
2303
+ cwd,
2304
+ env: {
2305
+ ...process.env,
2306
+ TERM: "xterm-256color",
2307
+ FORCE_COLOR: "1"
2308
+ },
2309
+ useConpty: true,
2310
+ conptyInheritCursor: false
2311
+ });
2319
2312
  this.dataSub = this.pty.onData((data) => {
2320
2313
  process.stdout.write(data);
2321
2314
  this.opts.onData(data);
@@ -2367,7 +2360,7 @@ var WindowsConPtyStrategy = class _WindowsConPtyStrategy {
2367
2360
 
2368
2361
  // src/services/claude-installer.ts
2369
2362
  var import_child_process3 = require("child_process");
2370
- var path4 = __toESM(require("path"));
2363
+ var path5 = __toESM(require("path"));
2371
2364
  var os4 = __toESM(require("os"));
2372
2365
 
2373
2366
  // ../../node_modules/@clack/prompts/dist/index.mjs
@@ -4285,14 +4278,14 @@ function probeInstallDirs() {
4285
4278
  const home = os4.homedir();
4286
4279
  if (process.platform === "win32") {
4287
4280
  return [
4288
- path4.join(home, ".claude", "local"),
4289
- path4.join(home, "AppData", "Local", "AnthropicClaude"),
4290
- path4.join(home, "AppData", "Local", "Programs", "AnthropicClaude")
4281
+ path5.join(home, ".claude", "local"),
4282
+ path5.join(home, "AppData", "Local", "AnthropicClaude"),
4283
+ path5.join(home, "AppData", "Local", "Programs", "AnthropicClaude")
4291
4284
  ];
4292
4285
  }
4293
4286
  return [
4294
- path4.join(home, ".local", "bin"),
4295
- path4.join(home, ".claude", "local"),
4287
+ path5.join(home, ".local", "bin"),
4288
+ path5.join(home, ".claude", "local"),
4296
4289
  "/usr/local/bin"
4297
4290
  ];
4298
4291
  }
@@ -4301,7 +4294,7 @@ function isAvailable() {
4301
4294
  }
4302
4295
  function augmentPath() {
4303
4296
  const dirs = probeInstallDirs();
4304
- const sep2 = path4.delimiter;
4297
+ const sep2 = path5.delimiter;
4305
4298
  const current = process.env.PATH ?? "";
4306
4299
  const existing = new Set(current.split(sep2).filter(Boolean));
4307
4300
  const additions = dirs.filter((d3) => !existing.has(d3));
@@ -4362,27 +4355,18 @@ async function ensureClaudeInstalled() {
4362
4355
  var ClaudeService = class {
4363
4356
  constructor(opts) {
4364
4357
  this.opts = opts;
4365
- const strategyOpts = {
4358
+ this.strategyOpts = {
4366
4359
  onData: opts.onData ?? (() => {
4367
4360
  }),
4368
4361
  onExit: opts.onExit
4369
4362
  };
4370
- if (process.platform === "win32") {
4371
- const conpty = WindowsConPtyStrategy.tryCreate(strategyOpts);
4372
- if (conpty) {
4373
- this.strategy = conpty;
4374
- } else {
4375
- console.error(
4376
- '\n \u26A0 Windows: node-pty unavailable, falling back to pipe mode.\n Claude Code may exit immediately with "no stdin data" / "--print" errors.\n Install build tools or run codeam-cli inside WSL for the best experience.\n'
4377
- );
4378
- this.strategy = new WindowsPtyStrategy(strategyOpts);
4379
- }
4380
- } else {
4381
- this.strategy = new UnixPtyStrategy(strategyOpts);
4382
- }
4383
4363
  }
4384
4364
  opts;
4385
- strategy;
4365
+ // Strategy is selected lazily inside spawn() so we can fall back from
4366
+ // ConPTY → legacy pipe at runtime if the native binding fails to load.
4367
+ // Methods called before spawn() (e.g. early kill/SIGINT) no-op safely.
4368
+ strategy = null;
4369
+ strategyOpts;
4386
4370
  async spawn() {
4387
4371
  if (!findInPath("claude") && !findInPath("claude-code")) {
4388
4372
  const installed = await ensureClaudeInstalled();
@@ -4399,7 +4383,36 @@ var ClaudeService = class {
4399
4383
  }
4400
4384
  }
4401
4385
  const claudeCmd = findInPath("claude") ? "claude" : "claude-code";
4402
- this.strategy.spawn(claudeCmd, this.opts.cwd);
4386
+ if (process.platform === "win32") {
4387
+ const conpty = WindowsConPtyStrategy.tryCreate(this.strategyOpts);
4388
+ if (conpty) {
4389
+ try {
4390
+ conpty.spawn(claudeCmd, this.opts.cwd);
4391
+ this.strategy = conpty;
4392
+ return;
4393
+ } catch (err) {
4394
+ const msg = err instanceof Error ? err.message : String(err);
4395
+ try {
4396
+ conpty.dispose();
4397
+ } catch {
4398
+ }
4399
+ console.error(`
4400
+ \u26A0 ConPTY launch failed (${msg.split("\n")[0]})`);
4401
+ console.error(" Falling back to pipe mode (limited interactivity)\u2026\n");
4402
+ }
4403
+ } else {
4404
+ console.error(
4405
+ '\n \u26A0 Windows: node-pty unavailable, falling back to pipe mode.\n Claude may exit with "no stdin data" / "--print" errors.\n Reinstall the CLI to fetch the prebuilt ConPTY binary, or run inside WSL.\n'
4406
+ );
4407
+ }
4408
+ const pipe = new WindowsPtyStrategy(this.strategyOpts);
4409
+ pipe.spawn(claudeCmd, this.opts.cwd);
4410
+ this.strategy = pipe;
4411
+ return;
4412
+ }
4413
+ const unix = new UnixPtyStrategy(this.strategyOpts);
4414
+ unix.spawn(claudeCmd, this.opts.cwd);
4415
+ this.strategy = unix;
4403
4416
  }
4404
4417
  /**
4405
4418
  * Send a command to Claude's stdin (remote control from mobile).
@@ -4415,8 +4428,10 @@ var ClaudeService = class {
4415
4428
  * a fresh event-loop tick, after React has flushed the text into input state.
4416
4429
  */
4417
4430
  sendCommand(text) {
4418
- this.strategy.write(text);
4419
- setTimeout(() => this.strategy.write("\r"), 50);
4431
+ if (!this.strategy) return;
4432
+ const s = this.strategy;
4433
+ s.write(text);
4434
+ setTimeout(() => s.write("\r"), 50);
4420
4435
  }
4421
4436
  /**
4422
4437
  * Navigate a React Ink selector to the given 0-based target index and confirm.
@@ -4437,40 +4452,43 @@ var ClaudeService = class {
4437
4452
  * ENTER_MS after the last arrow.
4438
4453
  */
4439
4454
  selectOption(targetIndex, fromIndex = 0) {
4455
+ if (!this.strategy) return;
4456
+ const s = this.strategy;
4440
4457
  const delta = targetIndex - fromIndex;
4441
4458
  const steps = Math.abs(delta);
4442
4459
  const arrow = delta >= 0 ? "\x1B[B" : "\x1B[A";
4443
4460
  const ARROW_MS = 80;
4444
4461
  const ENTER_MS = 200;
4445
4462
  if (steps === 0) {
4446
- this.strategy.write("\r");
4463
+ s.write("\r");
4447
4464
  return;
4448
4465
  }
4449
4466
  for (let i = 0; i < steps; i++) {
4450
4467
  setTimeout(() => {
4451
- this.strategy.write(arrow);
4468
+ s.write(arrow);
4452
4469
  }, i * ARROW_MS);
4453
4470
  }
4454
4471
  setTimeout(() => {
4455
- this.strategy.write("\r");
4472
+ s.write("\r");
4456
4473
  }, steps * ARROW_MS + ENTER_MS);
4457
4474
  }
4458
4475
  /** Send Escape key to Claude (cancels interactive prompts). */
4459
4476
  sendEscape() {
4460
- this.strategy.write("\x1B");
4477
+ this.strategy?.write("\x1B");
4461
4478
  }
4462
4479
  /** Send Ctrl+C to Claude. */
4463
4480
  interrupt() {
4464
- this.strategy.write("");
4481
+ this.strategy?.write("");
4465
4482
  }
4466
4483
  kill() {
4467
- this.strategy.kill();
4484
+ this.strategy?.kill();
4468
4485
  }
4469
4486
  /**
4470
4487
  * Kill the current Claude process and relaunch it resuming the given session.
4471
4488
  * Pass auto=true to add --dangerously-skip-permissions (no confirmation prompts).
4472
4489
  */
4473
4490
  restart(sessionId, auto = false) {
4491
+ if (!this.strategy) return;
4474
4492
  const claudeCmd = findInPath("claude") ? "claude" : "claude-code";
4475
4493
  this.strategy.kill();
4476
4494
  const args2 = ["--resume", sessionId];
@@ -5157,7 +5175,7 @@ function _sendOutputChunk(url, headers, payload) {
5157
5175
 
5158
5176
  // src/services/history.service.ts
5159
5177
  var fs4 = __toESM(require("fs"));
5160
- var path5 = __toESM(require("path"));
5178
+ var path6 = __toESM(require("path"));
5161
5179
  var os5 = __toESM(require("os"));
5162
5180
  var https3 = __toESM(require("https"));
5163
5181
  var http3 = __toESM(require("http"));
@@ -5313,7 +5331,7 @@ var HistoryService = class {
5313
5331
  return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
5314
5332
  }
5315
5333
  get projectDir() {
5316
- return path5.join(os5.homedir(), ".claude", "projects", encodeCwd(this.cwd));
5334
+ return path6.join(os5.homedir(), ".claude", "projects", encodeCwd(this.cwd));
5317
5335
  }
5318
5336
  /** Set the current Claude conversation ID (extracted from /cost command or session start) */
5319
5337
  setCurrentConversationId(id) {
@@ -5325,7 +5343,7 @@ var HistoryService = class {
5325
5343
  /** Return the current message count in the active conversation. */
5326
5344
  getCurrentMessageCount() {
5327
5345
  if (!this.currentConversationId) return 0;
5328
- const filePath = path5.join(this.projectDir, `${this.currentConversationId}.jsonl`);
5346
+ const filePath = path6.join(this.projectDir, `${this.currentConversationId}.jsonl`);
5329
5347
  return parseJsonl(filePath).length;
5330
5348
  }
5331
5349
  /**
@@ -5336,7 +5354,7 @@ var HistoryService = class {
5336
5354
  const deadline = Date.now() + timeoutMs;
5337
5355
  while (Date.now() < deadline) {
5338
5356
  if (!this.currentConversationId) return null;
5339
- const filePath = path5.join(this.projectDir, `${this.currentConversationId}.jsonl`);
5357
+ const filePath = path6.join(this.projectDir, `${this.currentConversationId}.jsonl`);
5340
5358
  const messages = parseJsonl(filePath);
5341
5359
  if (messages.length > previousCount) {
5342
5360
  for (let i = messages.length - 1; i >= previousCount; i--) {
@@ -5353,13 +5371,13 @@ var HistoryService = class {
5353
5371
  try {
5354
5372
  const files = fs4.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
5355
5373
  try {
5356
- return { name: e.name, mtime: fs4.statSync(path5.join(dir, e.name)).mtimeMs };
5374
+ return { name: e.name, mtime: fs4.statSync(path6.join(dir, e.name)).mtimeMs };
5357
5375
  } catch {
5358
5376
  return { name: e.name, mtime: 0 };
5359
5377
  }
5360
5378
  }).sort((a, b) => b.mtime - a.mtime);
5361
5379
  if (files.length > 0) {
5362
- this.currentConversationId = path5.basename(files[0].name, ".jsonl");
5380
+ this.currentConversationId = path6.basename(files[0].name, ".jsonl");
5363
5381
  }
5364
5382
  } catch {
5365
5383
  }
@@ -5397,7 +5415,7 @@ var HistoryService = class {
5397
5415
  }
5398
5416
  const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
5399
5417
  try {
5400
- return { name: e.name, mtime: fs4.statSync(path5.join(dir, e.name)).mtimeMs };
5418
+ return { name: e.name, mtime: fs4.statSync(path6.join(dir, e.name)).mtimeMs };
5401
5419
  } catch {
5402
5420
  return { name: e.name, mtime: 0 };
5403
5421
  }
@@ -5405,7 +5423,7 @@ var HistoryService = class {
5405
5423
  if (files.length === 0) return null;
5406
5424
  const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
5407
5425
  if (!files.some((f) => f.name === targetFile)) return null;
5408
- return this.extractUsageFromFile(path5.join(dir, targetFile));
5426
+ return this.extractUsageFromFile(path6.join(dir, targetFile));
5409
5427
  }
5410
5428
  extractUsageFromFile(filePath) {
5411
5429
  let raw;
@@ -5457,7 +5475,7 @@ var HistoryService = class {
5457
5475
  try {
5458
5476
  files = fs4.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
5459
5477
  try {
5460
- return fs4.statSync(path5.join(projectDir, f)).mtimeMs >= monthStartMs;
5478
+ return fs4.statSync(path6.join(projectDir, f)).mtimeMs >= monthStartMs;
5461
5479
  } catch {
5462
5480
  return false;
5463
5481
  }
@@ -5468,7 +5486,7 @@ var HistoryService = class {
5468
5486
  for (const file of files) {
5469
5487
  let raw;
5470
5488
  try {
5471
- raw = fs4.readFileSync(path5.join(projectDir, file), "utf8");
5489
+ raw = fs4.readFileSync(path6.join(projectDir, file), "utf8");
5472
5490
  } catch {
5473
5491
  continue;
5474
5492
  }
@@ -5510,8 +5528,8 @@ var HistoryService = class {
5510
5528
  const sessions2 = [];
5511
5529
  for (const entry of entries) {
5512
5530
  if (!entry.isFile() || !entry.name.endsWith(".jsonl")) continue;
5513
- const id = path5.basename(entry.name, ".jsonl");
5514
- const filePath = path5.join(dir, entry.name);
5531
+ const id = path6.basename(entry.name, ".jsonl");
5532
+ const filePath = path6.join(dir, entry.name);
5515
5533
  let mtime = Date.now();
5516
5534
  try {
5517
5535
  mtime = fs4.statSync(filePath).mtimeMs;
@@ -5552,7 +5570,7 @@ var HistoryService = class {
5552
5570
  * showing an empty conversation.
5553
5571
  */
5554
5572
  async loadConversation(sessionId) {
5555
- const filePath = path5.join(this.projectDir, `${sessionId}.jsonl`);
5573
+ const filePath = path6.join(this.projectDir, `${sessionId}.jsonl`);
5556
5574
  const messages = parseJsonl(filePath);
5557
5575
  if (messages.length === 0) return;
5558
5576
  const totalBatches = Math.ceil(messages.length / CONVERSATION_BATCH_SIZE);
@@ -5608,7 +5626,7 @@ function parsePayload(schema, raw) {
5608
5626
 
5609
5627
  // src/services/file-ops.service.ts
5610
5628
  var fs5 = __toESM(require("fs/promises"));
5611
- var path6 = __toESM(require("path"));
5629
+ var path7 = __toESM(require("path"));
5612
5630
  var MAX_FILE_BYTES = 5 * 1024 * 1024;
5613
5631
  var MAX_WALK_DEPTH = 6;
5614
5632
  var MAX_VISITED_DIRS = 5e3;
@@ -5643,8 +5661,8 @@ var SUBDIR_IGNORE = /* @__PURE__ */ new Set([
5643
5661
  "__pycache__"
5644
5662
  ]);
5645
5663
  function isUnder(parent, candidate) {
5646
- const rel = path6.relative(parent, candidate);
5647
- return rel === "" || !rel.startsWith("..") && !path6.isAbsolute(rel);
5664
+ const rel = path7.relative(parent, candidate);
5665
+ return rel === "" || !rel.startsWith("..") && !path7.isAbsolute(rel);
5648
5666
  }
5649
5667
  async function isExistingFile(absPath) {
5650
5668
  try {
@@ -5667,7 +5685,7 @@ async function walkForSuffix(dir, needleVariants, depth, ctx) {
5667
5685
  }
5668
5686
  for (const e of entries) {
5669
5687
  if (!e.isFile()) continue;
5670
- const full = path6.join(dir, e.name);
5688
+ const full = path7.join(dir, e.name);
5671
5689
  if (needleVariants.some((needle) => full.endsWith(needle))) {
5672
5690
  ctx.matches.push(full);
5673
5691
  if (ctx.matches.length >= ctx.cap) return;
@@ -5677,21 +5695,21 @@ async function walkForSuffix(dir, needleVariants, depth, ctx) {
5677
5695
  if (!e.isDirectory()) continue;
5678
5696
  if (SUBDIR_IGNORE.has(e.name)) continue;
5679
5697
  if (e.name.startsWith(".") && SUBDIR_IGNORE.has(e.name)) continue;
5680
- await walkForSuffix(path6.join(dir, e.name), needleVariants, depth + 1, ctx);
5698
+ await walkForSuffix(path7.join(dir, e.name), needleVariants, depth + 1, ctx);
5681
5699
  if (ctx.matches.length >= ctx.cap) return;
5682
5700
  }
5683
5701
  }
5684
5702
  async function findFile(rawPath) {
5685
5703
  const cwd = process.cwd();
5686
- if (path6.isAbsolute(rawPath)) {
5687
- const abs = path6.normalize(rawPath);
5704
+ if (path7.isAbsolute(rawPath)) {
5705
+ const abs = path7.normalize(rawPath);
5688
5706
  if (isUnder(cwd, abs) && await isExistingFile(abs)) return abs;
5689
5707
  }
5690
- const direct = path6.resolve(cwd, rawPath);
5708
+ const direct = path7.resolve(cwd, rawPath);
5691
5709
  if (isUnder(cwd, direct) && await isExistingFile(direct)) return direct;
5692
- const normalized = path6.normalize(rawPath).replace(/^[./\\]+/, "");
5710
+ const normalized = path7.normalize(rawPath).replace(/^[./\\]+/, "");
5693
5711
  const needles = [
5694
- `${path6.sep}${normalized}`,
5712
+ `${path7.sep}${normalized}`,
5695
5713
  `/${normalized}`
5696
5714
  ].filter((v, i, a) => a.indexOf(v) === i);
5697
5715
  const ctx = { visited: 0, matches: [], cap: 16 };
@@ -5705,7 +5723,7 @@ async function findWriteTarget(rawPath) {
5705
5723
  const found = await findFile(rawPath);
5706
5724
  if (found) return found;
5707
5725
  const cwd = process.cwd();
5708
- const fallback = path6.isAbsolute(rawPath) ? path6.normalize(rawPath) : path6.resolve(cwd, rawPath);
5726
+ const fallback = path7.isAbsolute(rawPath) ? path7.normalize(rawPath) : path7.resolve(cwd, rawPath);
5709
5727
  if (!isUnder(cwd, fallback)) return null;
5710
5728
  return fallback;
5711
5729
  }
@@ -5745,7 +5763,7 @@ async function writeProjectFile(rawPath, content) {
5745
5763
  if (Buffer.byteLength(content, "utf-8") > MAX_FILE_BYTES) {
5746
5764
  return { error: "Content too large." };
5747
5765
  }
5748
- await fs5.mkdir(path6.dirname(abs), { recursive: true });
5766
+ await fs5.mkdir(path7.dirname(abs), { recursive: true });
5749
5767
  await fs5.writeFile(abs, content, "utf-8");
5750
5768
  return { ok: true };
5751
5769
  } catch (e) {
@@ -5758,7 +5776,7 @@ async function writeProjectFile(rawPath, content) {
5758
5776
  var import_child_process4 = require("child_process");
5759
5777
  var import_util = require("util");
5760
5778
  var fs6 = __toESM(require("fs/promises"));
5761
- var path7 = __toESM(require("path"));
5779
+ var path8 = __toESM(require("path"));
5762
5780
  var execFileP = (0, import_util.promisify)(import_child_process4.execFile);
5763
5781
  var PROJECT_IGNORE = /* @__PURE__ */ new Set([
5764
5782
  "node_modules",
@@ -5816,12 +5834,12 @@ async function listProjectFiles(opts = {}) {
5816
5834
  return;
5817
5835
  }
5818
5836
  if (PROJECT_IGNORE.has(e.name)) continue;
5819
- const full = path7.join(dir, e.name);
5837
+ const full = path8.join(dir, e.name);
5820
5838
  if (e.isDirectory()) {
5821
5839
  if (depth >= 12) continue;
5822
5840
  await walk(full, depth + 1);
5823
5841
  } else if (e.isFile()) {
5824
- const rel = path7.relative(root, full);
5842
+ const rel = path8.relative(root, full);
5825
5843
  if (q2 && !rel.toLowerCase().includes(q2) && !e.name.toLowerCase().includes(q2)) {
5826
5844
  continue;
5827
5845
  }
@@ -5929,7 +5947,7 @@ async function gitStatus(cwd) {
5929
5947
  let hasMergeInProgress = false;
5930
5948
  try {
5931
5949
  const gitDir = (await git(["rev-parse", "--git-dir"], root)).stdout.trim();
5932
- const mergeHead = path7.isAbsolute(gitDir) ? path7.join(gitDir, "MERGE_HEAD") : path7.join(root, gitDir, "MERGE_HEAD");
5950
+ const mergeHead = path8.isAbsolute(gitDir) ? path8.join(gitDir, "MERGE_HEAD") : path8.join(root, gitDir, "MERGE_HEAD");
5933
5951
  await fs6.access(mergeHead);
5934
5952
  hasMergeInProgress = true;
5935
5953
  } catch {
@@ -6007,7 +6025,7 @@ async function gitResolve(file, side, cwd) {
6007
6025
  function saveFilesTemp(files) {
6008
6026
  return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
6009
6027
  const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
6010
- const tmpPath = path8.join(os6.tmpdir(), `codeam-${(0, import_crypto.randomUUID)()}-${safeName}`);
6028
+ const tmpPath = path9.join(os6.tmpdir(), `codeam-${(0, import_crypto.randomUUID)()}-${safeName}`);
6011
6029
  fs7.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
6012
6030
  return tmpPath;
6013
6031
  });
@@ -6081,7 +6099,7 @@ try:
6081
6099
  sys.exit((st>>8)&0xFF)
6082
6100
  except Exception:sys.exit(0)
6083
6101
  `;
6084
- const helperPath = path8.join(os6.tmpdir(), "codeam-quota-helper.py");
6102
+ const helperPath = path9.join(os6.tmpdir(), "codeam-quota-helper.py");
6085
6103
  fs7.writeFileSync(helperPath, helperScript, { mode: 420 });
6086
6104
  const python = findInPath("python3") ?? findInPath("python");
6087
6105
  if (!python) {
@@ -6684,7 +6702,7 @@ async function logout() {
6684
6702
  var import_child_process10 = require("child_process");
6685
6703
  var fs8 = __toESM(require("fs"));
6686
6704
  var os7 = __toESM(require("os"));
6687
- var path13 = __toESM(require("path"));
6705
+ var path14 = __toESM(require("path"));
6688
6706
  var import_util6 = require("util");
6689
6707
  var import_picocolors9 = __toESM(require("picocolors"));
6690
6708
 
@@ -6692,7 +6710,7 @@ var import_picocolors9 = __toESM(require("picocolors"));
6692
6710
  var import_child_process6 = require("child_process");
6693
6711
  var import_util2 = require("util");
6694
6712
  var import_picocolors7 = __toESM(require("picocolors"));
6695
- var path9 = __toESM(require("path"));
6713
+ var path10 = __toESM(require("path"));
6696
6714
  var execFileP2 = (0, import_util2.promisify)(import_child_process6.execFile);
6697
6715
  var MAX_BUFFER = 8 * 1024 * 1024;
6698
6716
  function resetStdinForChild() {
@@ -7181,7 +7199,7 @@ var GitHubCodespacesProvider = class {
7181
7199
  });
7182
7200
  }
7183
7201
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
7184
- const remoteDir = path9.posix.dirname(remotePath);
7202
+ const remoteDir = path10.posix.dirname(remotePath);
7185
7203
  const parts = [
7186
7204
  `mkdir -p ${shellQuote(remoteDir)}`,
7187
7205
  `cat > ${shellQuote(remotePath)}`
@@ -7251,7 +7269,7 @@ function shellQuote(s) {
7251
7269
  // src/services/providers/gitpod.ts
7252
7270
  var import_child_process7 = require("child_process");
7253
7271
  var import_util3 = require("util");
7254
- var path10 = __toESM(require("path"));
7272
+ var path11 = __toESM(require("path"));
7255
7273
  var import_picocolors8 = __toESM(require("picocolors"));
7256
7274
  var execFileP3 = (0, import_util3.promisify)(import_child_process7.execFile);
7257
7275
  var MAX_BUFFER2 = 8 * 1024 * 1024;
@@ -7491,7 +7509,7 @@ var GitpodProvider = class {
7491
7509
  });
7492
7510
  }
7493
7511
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
7494
- const remoteDir = path10.posix.dirname(remotePath);
7512
+ const remoteDir = path11.posix.dirname(remotePath);
7495
7513
  const parts = [
7496
7514
  `mkdir -p ${shellQuote2(remoteDir)}`,
7497
7515
  `cat > ${shellQuote2(remotePath)}`
@@ -7527,7 +7545,7 @@ function shellQuote2(s) {
7527
7545
  // src/services/providers/gitlab-workspaces.ts
7528
7546
  var import_child_process8 = require("child_process");
7529
7547
  var import_util4 = require("util");
7530
- var path11 = __toESM(require("path"));
7548
+ var path12 = __toESM(require("path"));
7531
7549
  var execFileP4 = (0, import_util4.promisify)(import_child_process8.execFile);
7532
7550
  var MAX_BUFFER3 = 8 * 1024 * 1024;
7533
7551
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -7787,7 +7805,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
7787
7805
  }
7788
7806
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
7789
7807
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
7790
- const remoteDir = path11.posix.dirname(remotePath);
7808
+ const remoteDir = path12.posix.dirname(remotePath);
7791
7809
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
7792
7810
  if (options.mode != null) {
7793
7811
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -7855,7 +7873,7 @@ function shellQuote3(s) {
7855
7873
  // src/services/providers/railway.ts
7856
7874
  var import_child_process9 = require("child_process");
7857
7875
  var import_util5 = require("util");
7858
- var path12 = __toESM(require("path"));
7876
+ var path13 = __toESM(require("path"));
7859
7877
  var execFileP5 = (0, import_util5.promisify)(import_child_process9.execFile);
7860
7878
  var MAX_BUFFER4 = 8 * 1024 * 1024;
7861
7879
  function resetStdinForChild4() {
@@ -8091,7 +8109,7 @@ var RailwayProvider = class {
8091
8109
  if (!projectId || !serviceId) {
8092
8110
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
8093
8111
  }
8094
- const remoteDir = path12.posix.dirname(remotePath);
8112
+ const remoteDir = path13.posix.dirname(remotePath);
8095
8113
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
8096
8114
  if (options.mode != null) {
8097
8115
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -8283,7 +8301,7 @@ async function deploy() {
8283
8301
  process.exit(1);
8284
8302
  }
8285
8303
  }
8286
- const localClaudeDir = path13.join(os7.homedir(), ".claude");
8304
+ const localClaudeDir = path14.join(os7.homedir(), ".claude");
8287
8305
  const localCredsKind = await detectLocalClaudeCredentials(localClaudeDir);
8288
8306
  let bridged = "none";
8289
8307
  if (localCredsKind !== "none") {
@@ -8381,7 +8399,7 @@ async function deploy() {
8381
8399
  }
8382
8400
  }
8383
8401
  if (bridged !== "none") {
8384
- const localClaudeJson = path13.join(os7.homedir(), ".claude.json");
8402
+ const localClaudeJson = path14.join(os7.homedir(), ".claude.json");
8385
8403
  if (fs8.existsSync(localClaudeJson)) {
8386
8404
  try {
8387
8405
  const contents = fs8.readFileSync(localClaudeJson);
@@ -8574,7 +8592,7 @@ async function runRemoteClaudeLogin(provider, workspaceId) {
8574
8592
  }
8575
8593
  }
8576
8594
  async function detectLocalClaudeCredentials(localClaudeDir) {
8577
- if (fs8.existsSync(path13.join(localClaudeDir, ".credentials.json"))) {
8595
+ if (fs8.existsSync(path14.join(localClaudeDir, ".credentials.json"))) {
8578
8596
  return "flat-file";
8579
8597
  }
8580
8598
  if (process.platform === "darwin") {
@@ -8607,7 +8625,7 @@ async function verifyClaudeAuth(provider, workspaceId) {
8607
8625
  }
8608
8626
  }
8609
8627
  async function bridgeClaudeCredentials(provider, workspaceId, localClaudeDir) {
8610
- const fileBased = path13.join(localClaudeDir, ".credentials.json");
8628
+ const fileBased = path14.join(localClaudeDir, ".credentials.json");
8611
8629
  if (fs8.existsSync(fileBased)) return "flat-file";
8612
8630
  if (process.platform === "darwin") {
8613
8631
  try {