@rallycry/conveyor-agent 10.13.58 → 10.13.60

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.
@@ -3301,6 +3301,10 @@ var FIREBASE_EMULATOR_COMMAND = [
3301
3301
  EOF
3302
3302
  exec firebase emulators:start --only=auth --project=rally-cry-dev`
3303
3303
  ];
3304
+ var FIREBASE_EMULATOR_ENV = {
3305
+ METADATA_SERVER_DETECTION: "none",
3306
+ GOOGLE_APPLICATION_CREDENTIALS: "/dev/null"
3307
+ };
3304
3308
  var CATALOG = {
3305
3309
  postgresql: {
3306
3310
  name: "postgresql",
@@ -3386,6 +3390,10 @@ var CATALOG = {
3386
3390
  requests: { cpuMillicores: 25, memoryMi: 32, ephemeralMi: 256 },
3387
3391
  limits: { cpuMillicores: 50, memoryMi: 64, ephemeralMi: 256 }
3388
3392
  },
3393
+ connectionEnv: {
3394
+ REDIS_URL: "redis://redis:6379",
3395
+ AUTH_REDIS_URL: "redis://redis:6379"
3396
+ },
3389
3397
  statefulBake: false,
3390
3398
  // Redis holds no baked state, so the bake runs the stock image CMD.
3391
3399
  bake: {},
@@ -3431,6 +3439,9 @@ var CATALOG = {
3431
3439
  requests: { cpuMillicores: 500, memoryMi: 1024, ephemeralMi: 256 },
3432
3440
  limits: { cpuMillicores: 2e3, memoryMi: 1024, ephemeralMi: 256 }
3433
3441
  },
3442
+ connectionEnv: {
3443
+ ELASTICSEARCH_URL: "http://elasticsearch:9200"
3444
+ },
3434
3445
  statefulBake: true,
3435
3446
  bake: {
3436
3447
  // No lock-clearing command at bake time: the bake starts from the stock
@@ -3500,8 +3511,7 @@ var CATALOG = {
3500
3511
  // for this container only: google-auth-library skips metadata detection
3501
3512
  // and finds no key file, firebase-tools logs "not authenticated" and
3502
3513
  // starts the emulator immediately. The agent container keeps its WI.
3503
- METADATA_SERVER_DETECTION: "none",
3504
- GOOGLE_APPLICATION_CREDENTIALS: "/dev/null"
3514
+ ...FIREBASE_EMULATOR_ENV
3505
3515
  },
3506
3516
  resources: {
3507
3517
  requests: { cpuMillicores: 100, memoryMi: 256, ephemeralMi: 256 },
@@ -3523,8 +3533,18 @@ var CATALOG = {
3523
3533
  // The emulator writes its config at startup, so the bake needs the same
3524
3534
  // inline command the runtime uses.
3525
3535
  command: FIREBASE_EMULATOR_COMMAND,
3536
+ environment: FIREBASE_EMULATOR_ENV,
3526
3537
  healthcheck: {
3527
- test: ["CMD-SHELL", "wget -qO- http://localhost:9099/ >/dev/null 2>&1 || exit 1"],
3538
+ // Probe with node, the one runtime this image guarantees. The image
3539
+ // (`andreysenov/firebase-tools`) is a slim Node image that ships
3540
+ // NEITHER `wget` NOR `curl`, so the `wget -qO- …` probe this replaced
3541
+ // exited 127 on every attempt: a healthy emulator burned all 20 retries
3542
+ // and every bake reported it unhealthy. See the catalog invariant in
3543
+ // `service-definitions.test.ts`, which also executes this probe.
3544
+ test: [
3545
+ "CMD-SHELL",
3546
+ `node -e "fetch('http://localhost:9099/').then((response) => process.exit(response.ok ? 0 : 1)).catch(() => process.exit(1))"`
3547
+ ],
3528
3548
  intervalSec: 3,
3529
3549
  timeoutSec: 5,
3530
3550
  retries: 20
@@ -3896,7 +3916,7 @@ var ClaudeCodeHarness = class {
3896
3916
  // src/harness/pty/session.ts
3897
3917
  import { randomUUID } from "crypto";
3898
3918
  import { mkdtemp, mkdir as mkdir3, rm as rm2, writeFile as writeFile5 } from "fs/promises";
3899
- import { join as join5, dirname } from "path";
3919
+ import { join as join6, dirname } from "path";
3900
3920
 
3901
3921
  // src/harness/opencode/plugin.ts
3902
3922
  import { writeFile } from "fs/promises";
@@ -5344,15 +5364,64 @@ async function startToolServers(mcpServers, tempDir) {
5344
5364
  // src/harness/pty/credentials.ts
5345
5365
  import { chmod as chmod2, mkdir as mkdir2, readFile, rm, writeFile as writeFile4 } from "fs/promises";
5346
5366
  import { homedir as homedir2 } from "os";
5367
+ import { join as join5 } from "path";
5368
+
5369
+ // src/harness/pty/credentials-marker.ts
5370
+ import { createHash } from "crypto";
5347
5371
  import { join as join4 } from "path";
5372
+ function conveyorCredentialsMarkerPath() {
5373
+ return join4(claudeConfigHome(), ".conveyor-credentials.json");
5374
+ }
5375
+ function tokenFingerprint(accessToken) {
5376
+ return createHash("sha256").update(accessToken).digest("hex");
5377
+ }
5378
+ function buildCredentialsMarker(accessToken, now, previousHash) {
5379
+ const accessTokenSha256 = tokenFingerprint(accessToken);
5380
+ return JSON.stringify({
5381
+ accessTokenSha256,
5382
+ ...previousHash && previousHash !== accessTokenSha256 ? { previousAccessTokenSha256: previousHash } : {},
5383
+ writtenAt: now
5384
+ });
5385
+ }
5386
+ function parseCredentialsMarker(raw) {
5387
+ if (!raw || raw.trim() === "") return [];
5388
+ try {
5389
+ const parsed = JSON.parse(raw);
5390
+ if (typeof parsed !== "object" || parsed === null) return [];
5391
+ const record = parsed;
5392
+ return [record.accessTokenSha256, record.previousAccessTokenSha256].filter(
5393
+ (hash) => typeof hash === "string" && hash.length > 0
5394
+ );
5395
+ } catch {
5396
+ return [];
5397
+ }
5398
+ }
5399
+
5400
+ // src/harness/pty/credentials.ts
5348
5401
  var SYNTH_TOKEN_TTL_MS = 365 * 24 * 60 * 60 * 1e3;
5349
5402
  var REFRESH_SKEW_MS = 30 * 24 * 60 * 60 * 1e3;
5350
5403
  function claudeCredentialsPath() {
5351
- return join4(claudeConfigHome(), ".credentials.json");
5404
+ return join5(claudeConfigHome(), ".credentials.json");
5352
5405
  }
5353
5406
  function isConveyorCloudEnv(env = process.env) {
5354
5407
  return Boolean(env.CLAUDESPACE_NAME || env.CODESPACE_NAME || env.CODESPACES);
5355
5408
  }
5409
+ function parseClaudeOauthEnv(blob) {
5410
+ if (!blob) return null;
5411
+ try {
5412
+ const parsed = JSON.parse(Buffer.from(blob, "base64").toString("utf8"));
5413
+ if (typeof parsed !== "object" || parsed === null) return null;
5414
+ const record = parsed;
5415
+ if (typeof record.access !== "string" || record.access === "") return null;
5416
+ return {
5417
+ access: record.access,
5418
+ refresh: typeof record.refresh === "string" && record.refresh ? record.refresh : void 0,
5419
+ expires: typeof record.expires === "number" ? record.expires : void 0
5420
+ };
5421
+ } catch {
5422
+ return null;
5423
+ }
5424
+ }
5356
5425
  function parseClaudeAiOauth(raw) {
5357
5426
  if (!raw || raw.trim() === "") return null;
5358
5427
  try {
@@ -5370,28 +5439,54 @@ function parseClaudeAiOauth(raw) {
5370
5439
  return null;
5371
5440
  }
5372
5441
  }
5373
- function buildSynthesizedCredentials(token, now) {
5442
+ var LOGIN_SCOPES = [
5443
+ "user:inference",
5444
+ "user:profile",
5445
+ "user:sessions:claude_code",
5446
+ "user:mcp_servers",
5447
+ "user:file_upload"
5448
+ ];
5449
+ var LEGACY_SCOPES = ["user:inference", "user:profile"];
5450
+ function buildCredentialsFile(material, now) {
5451
+ const refresh = material.refresh;
5374
5452
  return JSON.stringify({
5375
5453
  claudeAiOauth: {
5376
- accessToken: token,
5377
- expiresAt: now + SYNTH_TOKEN_TTL_MS,
5378
- scopes: ["user:inference", "user:profile"],
5454
+ accessToken: material.access,
5455
+ ...refresh ? { refreshToken: refresh } : {},
5456
+ // With a refresh token the CLI can recover from a real expiry, so report
5457
+ // the true one. Without, claim a far-future expiry (see SYNTH_TOKEN_TTL_MS)
5458
+ // because a refresh attempt would be unrecoverable.
5459
+ expiresAt: refresh && material.expires ? material.expires : now + SYNTH_TOKEN_TTL_MS,
5460
+ scopes: refresh ? LOGIN_SCOPES : LEGACY_SCOPES,
5379
5461
  subscriptionType: "max"
5380
5462
  }
5381
5463
  });
5382
5464
  }
5465
+ function buildSynthesizedCredentials(token, now) {
5466
+ return buildCredentialsFile({ access: token }, now);
5467
+ }
5468
+ function isConveyorOwnedCredentials(existing, markerHashes) {
5469
+ const hasRefresh = typeof existing.refreshToken === "string" && existing.refreshToken.length > 0;
5470
+ if (!hasRefresh) return true;
5471
+ if (markerHashes.length === 0) return false;
5472
+ if (typeof existing.accessToken !== "string") return false;
5473
+ return markerHashes.includes(tokenFingerprint(existing.accessToken));
5474
+ }
5383
5475
  function planCredentialsWrite(input) {
5384
5476
  if (!input.isCloud) return { action: "skip", reason: "not-cloud" };
5385
- if (!input.token) return { action: "skip", reason: "no-token" };
5386
- const contents = buildSynthesizedCredentials(input.token, input.now);
5477
+ const material = parseClaudeOauthEnv(input.oauthBlob) ?? (input.token ? { access: input.token } : null);
5478
+ if (!material) return { action: "skip", reason: "no-token" };
5479
+ const markerHashes = parseCredentialsMarker(input.markerRaw ?? null);
5480
+ const contents = buildCredentialsFile(material, input.now);
5481
+ const marker = buildCredentialsMarker(material.access, input.now, markerHashes[0] ?? null);
5387
5482
  const existing = parseClaudeAiOauth(input.existingRaw);
5388
- if (!existing) return { action: "write", contents };
5389
- if (typeof existing.refreshToken === "string" && existing.refreshToken.length > 0) {
5483
+ if (!existing) return { action: "write", contents, marker };
5484
+ if (!isConveyorOwnedCredentials(existing, markerHashes)) {
5390
5485
  return { action: "skip", reason: "foreign-credentials" };
5391
5486
  }
5392
- const fresh = existing.accessToken === input.token && typeof existing.expiresAt === "number" && existing.expiresAt > input.now + REFRESH_SKEW_MS;
5487
+ const fresh = material.refresh ? existing.accessToken === material.access : existing.accessToken === material.access && typeof existing.expiresAt === "number" && existing.expiresAt > input.now + REFRESH_SKEW_MS;
5393
5488
  if (fresh) return { action: "skip", reason: "current" };
5394
- return { action: "write", contents };
5489
+ return { action: "write", contents, marker };
5395
5490
  }
5396
5491
  async function readRaw(path2) {
5397
5492
  try {
@@ -5446,19 +5541,25 @@ function fsWriteIo(path2, mode) {
5446
5541
  async function ensureClaudeCredentials(env = process.env) {
5447
5542
  const isCloud = isConveyorCloudEnv(env);
5448
5543
  const token = env.CLAUDE_CODE_OAUTH_TOKEN;
5449
- if (isCloud && token) {
5450
- await sanitizeApprovedApiKeys(token);
5544
+ const material = parseClaudeOauthEnv(env.CONVEYOR_CLAUDE_OAUTH);
5545
+ const accessToken = material?.access ?? token;
5546
+ if (isCloud && accessToken) {
5547
+ await sanitizeApprovedApiKeys(accessToken);
5451
5548
  }
5452
5549
  try {
5453
5550
  const path2 = claudeCredentialsPath();
5551
+ const markerPath = conveyorCredentialsMarkerPath();
5454
5552
  const plan = planCredentialsWrite({
5455
5553
  isCloud,
5456
5554
  token,
5555
+ oauthBlob: env.CONVEYOR_CLAUDE_OAUTH,
5457
5556
  existingRaw: await readRaw(path2),
5557
+ markerRaw: await readRaw(markerPath),
5458
5558
  now: Date.now()
5459
5559
  });
5460
5560
  if (plan.action === "skip") return;
5461
5561
  await mkdir2(claudeConfigHome(), { recursive: true });
5562
+ await writeWithReadBackRetry(fsWriteIo(markerPath, 384), plan.marker);
5462
5563
  const verified = await writeWithReadBackRetry(fsWriteIo(path2, 384), plan.contents);
5463
5564
  if (!verified) {
5464
5565
  process.stderr.write(
@@ -5511,7 +5612,7 @@ async function sanitizeApprovedApiKeys(oauthToken) {
5511
5612
  }
5512
5613
  function claudeJsonPath() {
5513
5614
  const configDir = process.env.CLAUDE_CONFIG_DIR;
5514
- return configDir ? join4(configDir, ".claude.json") : join4(homedir2(), ".claude.json");
5615
+ return configDir ? join5(configDir, ".claude.json") : join5(homedir2(), ".claude.json");
5515
5616
  }
5516
5617
  function asRecord(value) {
5517
5618
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
@@ -5604,7 +5705,7 @@ function planClaudeJsonSeed(existingRaw, trustCwd, oauthIdentity) {
5604
5705
  return changed ? JSON.stringify(config) : null;
5605
5706
  }
5606
5707
  function conveyorOauthMarkerPath() {
5607
- return join4(claudeConfigHome(), "conveyor-oauth-account.json");
5708
+ return join5(claudeConfigHome(), "conveyor-oauth-account.json");
5608
5709
  }
5609
5710
  function parseOauthIdentity(raw) {
5610
5711
  if (!raw || raw.trim() === "") return null;
@@ -5669,11 +5770,13 @@ async function removeConveyorCredentials(env = process.env) {
5669
5770
  try {
5670
5771
  if (!isConveyorCloudEnv(env)) return;
5671
5772
  const path2 = claudeCredentialsPath();
5773
+ const markerPath = conveyorCredentialsMarkerPath();
5672
5774
  const existing = parseClaudeAiOauth(await readRaw(path2));
5673
- if (existing && typeof existing.refreshToken === "string" && existing.refreshToken.length > 0) {
5775
+ if (existing && !isConveyorOwnedCredentials(existing, parseCredentialsMarker(await readRaw(markerPath)))) {
5674
5776
  return;
5675
5777
  }
5676
5778
  await rm(path2, { force: true });
5779
+ await rm(markerPath, { force: true });
5677
5780
  } catch (err) {
5678
5781
  const message = err instanceof Error ? err.message : String(err);
5679
5782
  process.stderr.write(`[conveyor-agent] claude credentials removal failed: ${message}
@@ -6059,7 +6162,7 @@ var PtySession = class {
6059
6162
  const { settingsPath, socketPath } = await this.startStructuredEventSources(sessionId);
6060
6163
  await this.spawn(settingsPath, socketPath);
6061
6164
  } else {
6062
- this.tempDir = await mkdtemp(join5(sessionTempBase(), "conveyor-pty-"));
6165
+ this.tempDir = await mkdtemp(join6(sessionTempBase(), "conveyor-pty-"));
6063
6166
  await this.spawn();
6064
6167
  this.pushEvent({
6065
6168
  type: "system",
@@ -6104,7 +6207,7 @@ var PtySession = class {
6104
6207
  * moment it is known, which is how the runner learns the resume target.
6105
6208
  */
6106
6209
  async startOpenCodeEventSources() {
6107
- this.tempDir = await mkdtemp(join5(sessionTempBase(), "conveyor-pty-"));
6210
+ this.tempDir = await mkdtemp(join6(sessionTempBase(), "conveyor-pty-"));
6108
6211
  const { servers, entries } = await startToolServers(
6109
6212
  this.options.mcpServers ?? {},
6110
6213
  this.tempDir
@@ -6114,7 +6217,7 @@ var PtySession = class {
6114
6217
  let instructionsPath;
6115
6218
  const systemPrompt = this.options.appendSystemPrompt;
6116
6219
  if (systemPrompt && systemPrompt.trim() !== "") {
6117
- instructionsPath = join5(this.tempDir, "conveyor-instructions.md");
6220
+ instructionsPath = join6(this.tempDir, "conveyor-instructions.md");
6118
6221
  await writeFile5(instructionsPath, systemPrompt, "utf8");
6119
6222
  }
6120
6223
  this.opencodeSource = new OpenCodeEventSource(
@@ -6153,8 +6256,8 @@ var PtySession = class {
6153
6256
  * paths spawn() must wire into the child's argv/env.
6154
6257
  */
6155
6258
  async startStructuredEventSources(sessionId) {
6156
- this.tempDir = await mkdtemp(join5(sessionTempBase(), "conveyor-pty-"));
6157
- const socketPath = join5(this.tempDir, "hook.sock");
6259
+ this.tempDir = await mkdtemp(join6(sessionTempBase(), "conveyor-pty-"));
6260
+ const socketPath = join6(this.tempDir, "hook.sock");
6158
6261
  this.socket = new HookSocketServer(
6159
6262
  socketPath,
6160
6263
  (progress) => this.handleProgress(progress),
@@ -6743,7 +6846,7 @@ var PtySession = class {
6743
6846
  // src/harness/pty/config-home-health.ts
6744
6847
  import { lstat, mkdir as mkdir4, symlink, unlink as unlink2 } from "fs/promises";
6745
6848
  import { homedir as homedir3 } from "os";
6746
- import { join as join6 } from "path";
6849
+ import { join as join7 } from "path";
6747
6850
  var MOUNT_DISCONNECT_CODES = /* @__PURE__ */ new Set(["ENOTCONN", "EIO", "ESTALE", "ENXIO"]);
6748
6851
  var MOUNT_DISCONNECT_MESSAGES = [
6749
6852
  "socket is not connected",
@@ -6759,10 +6862,10 @@ function isMountDisconnectError(err) {
6759
6862
  return MOUNT_DISCONNECT_MESSAGES.some((needle) => lower.includes(needle));
6760
6863
  }
6761
6864
  function podLocalConfigHome() {
6762
- return join6(homedir3(), ".claude-local");
6865
+ return join7(homedir3(), ".claude-local");
6763
6866
  }
6764
6867
  function sharedConfigHomePath() {
6765
- return join6(homedir3(), ".claude");
6868
+ return join7(homedir3(), ".claude");
6766
6869
  }
6767
6870
  function isConfigHomeFallbackActive() {
6768
6871
  return claudeConfigHome() === podLocalConfigHome();
@@ -6793,7 +6896,7 @@ async function repointSharedConfigHomeSymlink(fallback, log) {
6793
6896
  }
6794
6897
  async function isConfigHomeMountDead(cwd) {
6795
6898
  try {
6796
- await mkdir4(join6(claudeConfigHome(), "projects", projectSlug(cwd)), { recursive: true });
6899
+ await mkdir4(join7(claudeConfigHome(), "projects", projectSlug(cwd)), { recursive: true });
6797
6900
  return false;
6798
6901
  } catch (err) {
6799
6902
  return isMountDisconnectError(err);
@@ -6802,7 +6905,7 @@ async function isConfigHomeMountDead(cwd) {
6802
6905
  async function ensureUsableClaudeConfigHome(cwd, log) {
6803
6906
  const configHome = claudeConfigHome();
6804
6907
  try {
6805
- await mkdir4(join6(configHome, "projects", projectSlug(cwd)), { recursive: true });
6908
+ await mkdir4(join7(configHome, "projects", projectSlug(cwd)), { recursive: true });
6806
6909
  return { configHome, fellBack: false };
6807
6910
  } catch (err) {
6808
6911
  if (!isMountDisconnectError(err)) throw err;
@@ -6816,7 +6919,7 @@ async function ensureUsableClaudeConfigHome(cwd, log) {
6816
6919
  }
6817
6920
  );
6818
6921
  process.env.CLAUDE_CONFIG_DIR = fallback;
6819
- await mkdir4(join6(fallback, "projects", projectSlug(cwd)), { recursive: true });
6922
+ await mkdir4(join7(fallback, "projects", projectSlug(cwd)), { recursive: true });
6820
6923
  await repointSharedConfigHomeSymlink(fallback, log);
6821
6924
  return { configHome: fallback, fellBack: true };
6822
6925
  }
@@ -7172,7 +7275,7 @@ import { spawn } from "child_process";
7172
7275
 
7173
7276
  // src/harness/pty/adapters/types.ts
7174
7277
  import { accessSync, constants, statSync } from "fs";
7175
- import { join as join7 } from "path";
7278
+ import { join as join8 } from "path";
7176
7279
  var TuiUnavailableError = class extends Error {
7177
7280
  constructor(tui, message) {
7178
7281
  super(message);
@@ -7196,7 +7299,7 @@ function findOnPath(binary, env = process.env) {
7196
7299
  }
7197
7300
  for (const dir of (env.PATH ?? "").split(":")) {
7198
7301
  if (!dir) continue;
7199
- const candidate = join7(dir, binary);
7302
+ const candidate = join8(dir, binary);
7200
7303
  if (isExecutable(candidate)) return candidate;
7201
7304
  }
7202
7305
  return null;
@@ -7204,18 +7307,18 @@ function findOnPath(binary, env = process.env) {
7204
7307
 
7205
7308
  // src/harness/pty/adapters/opencode-auth.ts
7206
7309
  import { promises as fs } from "fs";
7207
- import { dirname as dirname2, join as join8 } from "path";
7310
+ import { dirname as dirname2, join as join9 } from "path";
7208
7311
  import { homedir as homedir4 } from "os";
7209
7312
  var logger = createServiceLogger("opencode-auth");
7210
7313
  var OPENCODE_CODEX_PLUGIN = "opencode-openai-codex-auth@4.4.0";
7211
7314
  var PLUGIN_PACKAGE = "opencode-openai-codex-auth";
7212
7315
  function opencodeAuthPath(env) {
7213
- const dataHome = env.XDG_DATA_HOME ?? join8(env.HOME ?? homedir4(), ".local", "share");
7214
- return join8(dataHome, "opencode", "auth.json");
7316
+ const dataHome = env.XDG_DATA_HOME ?? join9(env.HOME ?? homedir4(), ".local", "share");
7317
+ return join9(dataHome, "opencode", "auth.json");
7215
7318
  }
7216
7319
  function opencodeConfigPath(env) {
7217
- const configHome = env.XDG_CONFIG_HOME ?? join8(env.HOME ?? homedir4(), ".config");
7218
- return join8(configHome, "opencode", "opencode.json");
7320
+ const configHome = env.XDG_CONFIG_HOME ?? join9(env.HOME ?? homedir4(), ".config");
7321
+ return join9(configHome, "opencode", "opencode.json");
7219
7322
  }
7220
7323
  function parseOauthSeed(b64) {
7221
7324
  if (!b64) return null;
@@ -7393,7 +7496,7 @@ function buildOpenCodeConfigContent(input) {
7393
7496
 
7394
7497
  // src/harness/opencode/index.ts
7395
7498
  import { mkdtemp as mkdtemp2, rm as rm3, writeFile as writeFile6 } from "fs/promises";
7396
- import { join as join9 } from "path";
7499
+ import { join as join10 } from "path";
7397
7500
  var MAX_STDERR_TAIL = 4e3;
7398
7501
  var OpenCodeHeadlessHarness = class {
7399
7502
  /** NDJSON from `--format json` is a trusted structured source. */
@@ -7415,7 +7518,7 @@ var OpenCodeHeadlessHarness = class {
7415
7518
  const prompt = await collectPrompt(opts.prompt);
7416
7519
  const binary = resolveOpenCodeBinary(process.env);
7417
7520
  await prepareOpenCodeCredentials(process.env);
7418
- this.tempDir = await mkdtemp2(join9(sessionTempBase(), "opencode-headless-"));
7521
+ this.tempDir = await mkdtemp2(join10(sessionTempBase(), "opencode-headless-"));
7419
7522
  const { servers, entries } = await startToolServers(
7420
7523
  opts.options.mcpServers ?? {},
7421
7524
  this.tempDir
@@ -7497,7 +7600,7 @@ var OpenCodeHeadlessHarness = class {
7497
7600
  */
7498
7601
  async writeSystemPrompt(text) {
7499
7602
  if (!text || text.trim() === "") return null;
7500
- const path2 = join9(this.tempDir, "conveyor-instructions.md");
7603
+ const path2 = join10(this.tempDir, "conveyor-instructions.md");
7501
7604
  await writeFile6(path2, text, "utf8");
7502
7605
  return path2;
7503
7606
  }
@@ -7961,7 +8064,7 @@ function wrapBridgeWithDirectStream(inner, reporter, options = {}) {
7961
8064
  }
7962
8065
 
7963
8066
  // src/execution/query-executor.ts
7964
- import { createHash } from "crypto";
8067
+ import { createHash as createHash2 } from "crypto";
7965
8068
  import { existsSync as existsSync2, readFileSync as readFileSync2, truncateSync } from "fs";
7966
8069
 
7967
8070
  // src/execution/chat-instructions.ts
@@ -11257,7 +11360,7 @@ function buildMutationTools(connection, config) {
11257
11360
  }
11258
11361
 
11259
11362
  // src/tools/attachment-tools.ts
11260
- import { basename, extname, isAbsolute, join as join10 } from "path";
11363
+ import { basename, extname, isAbsolute, join as join11 } from "path";
11261
11364
  var MIME_BY_EXT = {
11262
11365
  ".png": "image/png",
11263
11366
  ".jpg": "image/jpeg",
@@ -11308,7 +11411,7 @@ ${snippet}`;
11308
11411
  function buildUploadAttachmentTool(connection, config) {
11309
11412
  return defineContractTool(uploadAttachmentContract, async ({ path: path2, title, tags }) => {
11310
11413
  try {
11311
- const filePath = isAbsolute(path2) ? path2 : join10(config.workspaceDir, path2);
11414
+ const filePath = isAbsolute(path2) ? path2 : join11(config.workspaceDir, path2);
11312
11415
  const mimeType = inferMimeType(filePath);
11313
11416
  const info = await statWorkspacePath(filePath);
11314
11417
  if (!info.isFile) {
@@ -11820,7 +11923,7 @@ import { z as z16 } from "zod";
11820
11923
 
11821
11924
  // src/execution/context-path-verifier.ts
11822
11925
  import { readFile as readFile2 } from "fs/promises";
11823
- import { isAbsolute as isAbsolute2, join as join11, normalize } from "path";
11926
+ import { isAbsolute as isAbsolute2, join as join12, normalize } from "path";
11824
11927
  var PROBLEM_TEXT = {
11825
11928
  not_found: "does not exist in the repo",
11826
11929
  expected_folder: "is a file, not a folder \u2014 use type 'file', 'rule', or 'doc'",
@@ -11865,7 +11968,7 @@ async function verifyContextPaths(links, workspaceDir) {
11865
11968
  problems.push({ type: link.type, path: link.path, reason: shape });
11866
11969
  continue;
11867
11970
  }
11868
- const absolutePath = join11(workspaceDir, toRelativePath(link.path));
11971
+ const absolutePath = join12(workspaceDir, toRelativePath(link.path));
11869
11972
  const stat = await statWorkspacePath(absolutePath);
11870
11973
  const wantsDirectory = expectsDirectory(link.type);
11871
11974
  if (!stat.exists) {
@@ -12994,6 +13097,7 @@ function applyCycledKeyEnv(envVars, env = process.env) {
12994
13097
  for (const [key, value] of Object.entries(envVars)) {
12995
13098
  env[key] = value;
12996
13099
  }
13100
+ if (!envVars.CONVEYOR_CLAUDE_OAUTH) delete env.CONVEYOR_CLAUDE_OAUTH;
12997
13101
  if (envVars.CLAUDE_CODE_OAUTH_TOKEN) {
12998
13102
  delete env.ANTHROPIC_API_KEY;
12999
13103
  if (!envVars.CONVEYOR_AGENT_KEY) delete env.CONVEYOR_AGENT_KEY;
@@ -13472,7 +13576,7 @@ function buildHooks(host) {
13472
13576
  };
13473
13577
  }
13474
13578
  function taskIdToSessionUuid(lineageKey) {
13475
- const hash = createHash("sha256").update(lineageKey).digest("hex");
13579
+ const hash = createHash2("sha256").update(lineageKey).digest("hex");
13476
13580
  return `${hash.slice(0, 8)}-${hash.slice(8, 12)}-8${hash.slice(13, 16)}-a${hash.slice(17, 20)}-${hash.slice(20, 32)}`;
13477
13581
  }
13478
13582
  function sessionLineageKey(taskId, agentMode, runnerMode) {
@@ -16178,6 +16282,7 @@ var SessionRunner = class _SessionRunner {
16178
16282
  }
16179
16283
  });
16180
16284
  this.connection.onApiKeyUpdate((data) => {
16285
+ delete process.env.CONVEYOR_CLAUDE_OAUTH;
16181
16286
  if (data.isSubscription) {
16182
16287
  process.env.CLAUDE_CODE_OAUTH_TOKEN = data.apiKey;
16183
16288
  delete process.env.ANTHROPIC_API_KEY;
@@ -16329,12 +16434,12 @@ var SessionRunner = class _SessionRunner {
16329
16434
  };
16330
16435
 
16331
16436
  // src/setup/config.ts
16332
- import { join as join12 } from "path";
16437
+ import { join as join13 } from "path";
16333
16438
  var DEVCONTAINER_PATH = ".devcontainer/conveyor/devcontainer.json";
16334
16439
  var DEVCONTAINER_PORT_DENY_LIST = /* @__PURE__ */ new Set([5432, 6379, 9200]);
16335
16440
  async function loadForwardPorts(workspaceDir) {
16336
16441
  try {
16337
- const raw = await readWorkspaceFile(join12(workspaceDir, DEVCONTAINER_PATH));
16442
+ const raw = await readWorkspaceFile(join13(workspaceDir, DEVCONTAINER_PATH));
16338
16443
  const parsed = JSON.parse(raw);
16339
16444
  const ports = (parsed.forwardPorts ?? []).filter(
16340
16445
  (p) => typeof p === "number" && !DEVCONTAINER_PORT_DENY_LIST.has(p)
@@ -16398,6 +16503,8 @@ export {
16398
16503
  PtyHarness,
16399
16504
  resolveTuiKindFromEnv,
16400
16505
  resolveTuiAdapter,
16506
+ readWorkspaceBytes,
16507
+ statWorkspacePath,
16401
16508
  workspacePathExists,
16402
16509
  GIT_TIMEOUT_MS,
16403
16510
  hasUncommittedChanges,
@@ -16422,4 +16529,4 @@ export {
16422
16529
  loadConveyorConfig,
16423
16530
  unshallowRepo
16424
16531
  };
16425
- //# sourceMappingURL=chunk-HYP7BK2B.js.map
16532
+ //# sourceMappingURL=chunk-VF5BSGN4.js.map