@rallycry/conveyor-agent 10.13.59 → 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.
@@ -3535,6 +3535,12 @@ var CATALOG = {
3535
3535
  command: FIREBASE_EMULATOR_COMMAND,
3536
3536
  environment: FIREBASE_EMULATOR_ENV,
3537
3537
  healthcheck: {
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.
3538
3544
  test: [
3539
3545
  "CMD-SHELL",
3540
3546
  `node -e "fetch('http://localhost:9099/').then((response) => process.exit(response.ok ? 0 : 1)).catch(() => process.exit(1))"`
@@ -3910,7 +3916,7 @@ var ClaudeCodeHarness = class {
3910
3916
  // src/harness/pty/session.ts
3911
3917
  import { randomUUID } from "crypto";
3912
3918
  import { mkdtemp, mkdir as mkdir3, rm as rm2, writeFile as writeFile5 } from "fs/promises";
3913
- import { join as join5, dirname } from "path";
3919
+ import { join as join6, dirname } from "path";
3914
3920
 
3915
3921
  // src/harness/opencode/plugin.ts
3916
3922
  import { writeFile } from "fs/promises";
@@ -5358,15 +5364,64 @@ async function startToolServers(mcpServers, tempDir) {
5358
5364
  // src/harness/pty/credentials.ts
5359
5365
  import { chmod as chmod2, mkdir as mkdir2, readFile, rm, writeFile as writeFile4 } from "fs/promises";
5360
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";
5361
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
5362
5401
  var SYNTH_TOKEN_TTL_MS = 365 * 24 * 60 * 60 * 1e3;
5363
5402
  var REFRESH_SKEW_MS = 30 * 24 * 60 * 60 * 1e3;
5364
5403
  function claudeCredentialsPath() {
5365
- return join4(claudeConfigHome(), ".credentials.json");
5404
+ return join5(claudeConfigHome(), ".credentials.json");
5366
5405
  }
5367
5406
  function isConveyorCloudEnv(env = process.env) {
5368
5407
  return Boolean(env.CLAUDESPACE_NAME || env.CODESPACE_NAME || env.CODESPACES);
5369
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
+ }
5370
5425
  function parseClaudeAiOauth(raw) {
5371
5426
  if (!raw || raw.trim() === "") return null;
5372
5427
  try {
@@ -5384,28 +5439,54 @@ function parseClaudeAiOauth(raw) {
5384
5439
  return null;
5385
5440
  }
5386
5441
  }
5387
- 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;
5388
5452
  return JSON.stringify({
5389
5453
  claudeAiOauth: {
5390
- accessToken: token,
5391
- expiresAt: now + SYNTH_TOKEN_TTL_MS,
5392
- 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,
5393
5461
  subscriptionType: "max"
5394
5462
  }
5395
5463
  });
5396
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
+ }
5397
5475
  function planCredentialsWrite(input) {
5398
5476
  if (!input.isCloud) return { action: "skip", reason: "not-cloud" };
5399
- if (!input.token) return { action: "skip", reason: "no-token" };
5400
- 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);
5401
5482
  const existing = parseClaudeAiOauth(input.existingRaw);
5402
- if (!existing) return { action: "write", contents };
5403
- if (typeof existing.refreshToken === "string" && existing.refreshToken.length > 0) {
5483
+ if (!existing) return { action: "write", contents, marker };
5484
+ if (!isConveyorOwnedCredentials(existing, markerHashes)) {
5404
5485
  return { action: "skip", reason: "foreign-credentials" };
5405
5486
  }
5406
- 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;
5407
5488
  if (fresh) return { action: "skip", reason: "current" };
5408
- return { action: "write", contents };
5489
+ return { action: "write", contents, marker };
5409
5490
  }
5410
5491
  async function readRaw(path2) {
5411
5492
  try {
@@ -5460,19 +5541,25 @@ function fsWriteIo(path2, mode) {
5460
5541
  async function ensureClaudeCredentials(env = process.env) {
5461
5542
  const isCloud = isConveyorCloudEnv(env);
5462
5543
  const token = env.CLAUDE_CODE_OAUTH_TOKEN;
5463
- if (isCloud && token) {
5464
- 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);
5465
5548
  }
5466
5549
  try {
5467
5550
  const path2 = claudeCredentialsPath();
5551
+ const markerPath = conveyorCredentialsMarkerPath();
5468
5552
  const plan = planCredentialsWrite({
5469
5553
  isCloud,
5470
5554
  token,
5555
+ oauthBlob: env.CONVEYOR_CLAUDE_OAUTH,
5471
5556
  existingRaw: await readRaw(path2),
5557
+ markerRaw: await readRaw(markerPath),
5472
5558
  now: Date.now()
5473
5559
  });
5474
5560
  if (plan.action === "skip") return;
5475
5561
  await mkdir2(claudeConfigHome(), { recursive: true });
5562
+ await writeWithReadBackRetry(fsWriteIo(markerPath, 384), plan.marker);
5476
5563
  const verified = await writeWithReadBackRetry(fsWriteIo(path2, 384), plan.contents);
5477
5564
  if (!verified) {
5478
5565
  process.stderr.write(
@@ -5525,7 +5612,7 @@ async function sanitizeApprovedApiKeys(oauthToken) {
5525
5612
  }
5526
5613
  function claudeJsonPath() {
5527
5614
  const configDir = process.env.CLAUDE_CONFIG_DIR;
5528
- return configDir ? join4(configDir, ".claude.json") : join4(homedir2(), ".claude.json");
5615
+ return configDir ? join5(configDir, ".claude.json") : join5(homedir2(), ".claude.json");
5529
5616
  }
5530
5617
  function asRecord(value) {
5531
5618
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
@@ -5618,7 +5705,7 @@ function planClaudeJsonSeed(existingRaw, trustCwd, oauthIdentity) {
5618
5705
  return changed ? JSON.stringify(config) : null;
5619
5706
  }
5620
5707
  function conveyorOauthMarkerPath() {
5621
- return join4(claudeConfigHome(), "conveyor-oauth-account.json");
5708
+ return join5(claudeConfigHome(), "conveyor-oauth-account.json");
5622
5709
  }
5623
5710
  function parseOauthIdentity(raw) {
5624
5711
  if (!raw || raw.trim() === "") return null;
@@ -5683,11 +5770,13 @@ async function removeConveyorCredentials(env = process.env) {
5683
5770
  try {
5684
5771
  if (!isConveyorCloudEnv(env)) return;
5685
5772
  const path2 = claudeCredentialsPath();
5773
+ const markerPath = conveyorCredentialsMarkerPath();
5686
5774
  const existing = parseClaudeAiOauth(await readRaw(path2));
5687
- if (existing && typeof existing.refreshToken === "string" && existing.refreshToken.length > 0) {
5775
+ if (existing && !isConveyorOwnedCredentials(existing, parseCredentialsMarker(await readRaw(markerPath)))) {
5688
5776
  return;
5689
5777
  }
5690
5778
  await rm(path2, { force: true });
5779
+ await rm(markerPath, { force: true });
5691
5780
  } catch (err) {
5692
5781
  const message = err instanceof Error ? err.message : String(err);
5693
5782
  process.stderr.write(`[conveyor-agent] claude credentials removal failed: ${message}
@@ -6073,7 +6162,7 @@ var PtySession = class {
6073
6162
  const { settingsPath, socketPath } = await this.startStructuredEventSources(sessionId);
6074
6163
  await this.spawn(settingsPath, socketPath);
6075
6164
  } else {
6076
- this.tempDir = await mkdtemp(join5(sessionTempBase(), "conveyor-pty-"));
6165
+ this.tempDir = await mkdtemp(join6(sessionTempBase(), "conveyor-pty-"));
6077
6166
  await this.spawn();
6078
6167
  this.pushEvent({
6079
6168
  type: "system",
@@ -6118,7 +6207,7 @@ var PtySession = class {
6118
6207
  * moment it is known, which is how the runner learns the resume target.
6119
6208
  */
6120
6209
  async startOpenCodeEventSources() {
6121
- this.tempDir = await mkdtemp(join5(sessionTempBase(), "conveyor-pty-"));
6210
+ this.tempDir = await mkdtemp(join6(sessionTempBase(), "conveyor-pty-"));
6122
6211
  const { servers, entries } = await startToolServers(
6123
6212
  this.options.mcpServers ?? {},
6124
6213
  this.tempDir
@@ -6128,7 +6217,7 @@ var PtySession = class {
6128
6217
  let instructionsPath;
6129
6218
  const systemPrompt = this.options.appendSystemPrompt;
6130
6219
  if (systemPrompt && systemPrompt.trim() !== "") {
6131
- instructionsPath = join5(this.tempDir, "conveyor-instructions.md");
6220
+ instructionsPath = join6(this.tempDir, "conveyor-instructions.md");
6132
6221
  await writeFile5(instructionsPath, systemPrompt, "utf8");
6133
6222
  }
6134
6223
  this.opencodeSource = new OpenCodeEventSource(
@@ -6167,8 +6256,8 @@ var PtySession = class {
6167
6256
  * paths spawn() must wire into the child's argv/env.
6168
6257
  */
6169
6258
  async startStructuredEventSources(sessionId) {
6170
- this.tempDir = await mkdtemp(join5(sessionTempBase(), "conveyor-pty-"));
6171
- const socketPath = join5(this.tempDir, "hook.sock");
6259
+ this.tempDir = await mkdtemp(join6(sessionTempBase(), "conveyor-pty-"));
6260
+ const socketPath = join6(this.tempDir, "hook.sock");
6172
6261
  this.socket = new HookSocketServer(
6173
6262
  socketPath,
6174
6263
  (progress) => this.handleProgress(progress),
@@ -6757,7 +6846,7 @@ var PtySession = class {
6757
6846
  // src/harness/pty/config-home-health.ts
6758
6847
  import { lstat, mkdir as mkdir4, symlink, unlink as unlink2 } from "fs/promises";
6759
6848
  import { homedir as homedir3 } from "os";
6760
- import { join as join6 } from "path";
6849
+ import { join as join7 } from "path";
6761
6850
  var MOUNT_DISCONNECT_CODES = /* @__PURE__ */ new Set(["ENOTCONN", "EIO", "ESTALE", "ENXIO"]);
6762
6851
  var MOUNT_DISCONNECT_MESSAGES = [
6763
6852
  "socket is not connected",
@@ -6773,10 +6862,10 @@ function isMountDisconnectError(err) {
6773
6862
  return MOUNT_DISCONNECT_MESSAGES.some((needle) => lower.includes(needle));
6774
6863
  }
6775
6864
  function podLocalConfigHome() {
6776
- return join6(homedir3(), ".claude-local");
6865
+ return join7(homedir3(), ".claude-local");
6777
6866
  }
6778
6867
  function sharedConfigHomePath() {
6779
- return join6(homedir3(), ".claude");
6868
+ return join7(homedir3(), ".claude");
6780
6869
  }
6781
6870
  function isConfigHomeFallbackActive() {
6782
6871
  return claudeConfigHome() === podLocalConfigHome();
@@ -6807,7 +6896,7 @@ async function repointSharedConfigHomeSymlink(fallback, log) {
6807
6896
  }
6808
6897
  async function isConfigHomeMountDead(cwd) {
6809
6898
  try {
6810
- await mkdir4(join6(claudeConfigHome(), "projects", projectSlug(cwd)), { recursive: true });
6899
+ await mkdir4(join7(claudeConfigHome(), "projects", projectSlug(cwd)), { recursive: true });
6811
6900
  return false;
6812
6901
  } catch (err) {
6813
6902
  return isMountDisconnectError(err);
@@ -6816,7 +6905,7 @@ async function isConfigHomeMountDead(cwd) {
6816
6905
  async function ensureUsableClaudeConfigHome(cwd, log) {
6817
6906
  const configHome = claudeConfigHome();
6818
6907
  try {
6819
- await mkdir4(join6(configHome, "projects", projectSlug(cwd)), { recursive: true });
6908
+ await mkdir4(join7(configHome, "projects", projectSlug(cwd)), { recursive: true });
6820
6909
  return { configHome, fellBack: false };
6821
6910
  } catch (err) {
6822
6911
  if (!isMountDisconnectError(err)) throw err;
@@ -6830,7 +6919,7 @@ async function ensureUsableClaudeConfigHome(cwd, log) {
6830
6919
  }
6831
6920
  );
6832
6921
  process.env.CLAUDE_CONFIG_DIR = fallback;
6833
- await mkdir4(join6(fallback, "projects", projectSlug(cwd)), { recursive: true });
6922
+ await mkdir4(join7(fallback, "projects", projectSlug(cwd)), { recursive: true });
6834
6923
  await repointSharedConfigHomeSymlink(fallback, log);
6835
6924
  return { configHome: fallback, fellBack: true };
6836
6925
  }
@@ -7186,7 +7275,7 @@ import { spawn } from "child_process";
7186
7275
 
7187
7276
  // src/harness/pty/adapters/types.ts
7188
7277
  import { accessSync, constants, statSync } from "fs";
7189
- import { join as join7 } from "path";
7278
+ import { join as join8 } from "path";
7190
7279
  var TuiUnavailableError = class extends Error {
7191
7280
  constructor(tui, message) {
7192
7281
  super(message);
@@ -7210,7 +7299,7 @@ function findOnPath(binary, env = process.env) {
7210
7299
  }
7211
7300
  for (const dir of (env.PATH ?? "").split(":")) {
7212
7301
  if (!dir) continue;
7213
- const candidate = join7(dir, binary);
7302
+ const candidate = join8(dir, binary);
7214
7303
  if (isExecutable(candidate)) return candidate;
7215
7304
  }
7216
7305
  return null;
@@ -7218,18 +7307,18 @@ function findOnPath(binary, env = process.env) {
7218
7307
 
7219
7308
  // src/harness/pty/adapters/opencode-auth.ts
7220
7309
  import { promises as fs } from "fs";
7221
- import { dirname as dirname2, join as join8 } from "path";
7310
+ import { dirname as dirname2, join as join9 } from "path";
7222
7311
  import { homedir as homedir4 } from "os";
7223
7312
  var logger = createServiceLogger("opencode-auth");
7224
7313
  var OPENCODE_CODEX_PLUGIN = "opencode-openai-codex-auth@4.4.0";
7225
7314
  var PLUGIN_PACKAGE = "opencode-openai-codex-auth";
7226
7315
  function opencodeAuthPath(env) {
7227
- const dataHome = env.XDG_DATA_HOME ?? join8(env.HOME ?? homedir4(), ".local", "share");
7228
- 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");
7229
7318
  }
7230
7319
  function opencodeConfigPath(env) {
7231
- const configHome = env.XDG_CONFIG_HOME ?? join8(env.HOME ?? homedir4(), ".config");
7232
- 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");
7233
7322
  }
7234
7323
  function parseOauthSeed(b64) {
7235
7324
  if (!b64) return null;
@@ -7407,7 +7496,7 @@ function buildOpenCodeConfigContent(input) {
7407
7496
 
7408
7497
  // src/harness/opencode/index.ts
7409
7498
  import { mkdtemp as mkdtemp2, rm as rm3, writeFile as writeFile6 } from "fs/promises";
7410
- import { join as join9 } from "path";
7499
+ import { join as join10 } from "path";
7411
7500
  var MAX_STDERR_TAIL = 4e3;
7412
7501
  var OpenCodeHeadlessHarness = class {
7413
7502
  /** NDJSON from `--format json` is a trusted structured source. */
@@ -7429,7 +7518,7 @@ var OpenCodeHeadlessHarness = class {
7429
7518
  const prompt = await collectPrompt(opts.prompt);
7430
7519
  const binary = resolveOpenCodeBinary(process.env);
7431
7520
  await prepareOpenCodeCredentials(process.env);
7432
- this.tempDir = await mkdtemp2(join9(sessionTempBase(), "opencode-headless-"));
7521
+ this.tempDir = await mkdtemp2(join10(sessionTempBase(), "opencode-headless-"));
7433
7522
  const { servers, entries } = await startToolServers(
7434
7523
  opts.options.mcpServers ?? {},
7435
7524
  this.tempDir
@@ -7511,7 +7600,7 @@ var OpenCodeHeadlessHarness = class {
7511
7600
  */
7512
7601
  async writeSystemPrompt(text) {
7513
7602
  if (!text || text.trim() === "") return null;
7514
- const path2 = join9(this.tempDir, "conveyor-instructions.md");
7603
+ const path2 = join10(this.tempDir, "conveyor-instructions.md");
7515
7604
  await writeFile6(path2, text, "utf8");
7516
7605
  return path2;
7517
7606
  }
@@ -7975,7 +8064,7 @@ function wrapBridgeWithDirectStream(inner, reporter, options = {}) {
7975
8064
  }
7976
8065
 
7977
8066
  // src/execution/query-executor.ts
7978
- import { createHash } from "crypto";
8067
+ import { createHash as createHash2 } from "crypto";
7979
8068
  import { existsSync as existsSync2, readFileSync as readFileSync2, truncateSync } from "fs";
7980
8069
 
7981
8070
  // src/execution/chat-instructions.ts
@@ -11271,7 +11360,7 @@ function buildMutationTools(connection, config) {
11271
11360
  }
11272
11361
 
11273
11362
  // src/tools/attachment-tools.ts
11274
- import { basename, extname, isAbsolute, join as join10 } from "path";
11363
+ import { basename, extname, isAbsolute, join as join11 } from "path";
11275
11364
  var MIME_BY_EXT = {
11276
11365
  ".png": "image/png",
11277
11366
  ".jpg": "image/jpeg",
@@ -11322,7 +11411,7 @@ ${snippet}`;
11322
11411
  function buildUploadAttachmentTool(connection, config) {
11323
11412
  return defineContractTool(uploadAttachmentContract, async ({ path: path2, title, tags }) => {
11324
11413
  try {
11325
- const filePath = isAbsolute(path2) ? path2 : join10(config.workspaceDir, path2);
11414
+ const filePath = isAbsolute(path2) ? path2 : join11(config.workspaceDir, path2);
11326
11415
  const mimeType = inferMimeType(filePath);
11327
11416
  const info = await statWorkspacePath(filePath);
11328
11417
  if (!info.isFile) {
@@ -11834,7 +11923,7 @@ import { z as z16 } from "zod";
11834
11923
 
11835
11924
  // src/execution/context-path-verifier.ts
11836
11925
  import { readFile as readFile2 } from "fs/promises";
11837
- import { isAbsolute as isAbsolute2, join as join11, normalize } from "path";
11926
+ import { isAbsolute as isAbsolute2, join as join12, normalize } from "path";
11838
11927
  var PROBLEM_TEXT = {
11839
11928
  not_found: "does not exist in the repo",
11840
11929
  expected_folder: "is a file, not a folder \u2014 use type 'file', 'rule', or 'doc'",
@@ -11879,7 +11968,7 @@ async function verifyContextPaths(links, workspaceDir) {
11879
11968
  problems.push({ type: link.type, path: link.path, reason: shape });
11880
11969
  continue;
11881
11970
  }
11882
- const absolutePath = join11(workspaceDir, toRelativePath(link.path));
11971
+ const absolutePath = join12(workspaceDir, toRelativePath(link.path));
11883
11972
  const stat = await statWorkspacePath(absolutePath);
11884
11973
  const wantsDirectory = expectsDirectory(link.type);
11885
11974
  if (!stat.exists) {
@@ -13008,6 +13097,7 @@ function applyCycledKeyEnv(envVars, env = process.env) {
13008
13097
  for (const [key, value] of Object.entries(envVars)) {
13009
13098
  env[key] = value;
13010
13099
  }
13100
+ if (!envVars.CONVEYOR_CLAUDE_OAUTH) delete env.CONVEYOR_CLAUDE_OAUTH;
13011
13101
  if (envVars.CLAUDE_CODE_OAUTH_TOKEN) {
13012
13102
  delete env.ANTHROPIC_API_KEY;
13013
13103
  if (!envVars.CONVEYOR_AGENT_KEY) delete env.CONVEYOR_AGENT_KEY;
@@ -13486,7 +13576,7 @@ function buildHooks(host) {
13486
13576
  };
13487
13577
  }
13488
13578
  function taskIdToSessionUuid(lineageKey) {
13489
- const hash = createHash("sha256").update(lineageKey).digest("hex");
13579
+ const hash = createHash2("sha256").update(lineageKey).digest("hex");
13490
13580
  return `${hash.slice(0, 8)}-${hash.slice(8, 12)}-8${hash.slice(13, 16)}-a${hash.slice(17, 20)}-${hash.slice(20, 32)}`;
13491
13581
  }
13492
13582
  function sessionLineageKey(taskId, agentMode, runnerMode) {
@@ -16192,6 +16282,7 @@ var SessionRunner = class _SessionRunner {
16192
16282
  }
16193
16283
  });
16194
16284
  this.connection.onApiKeyUpdate((data) => {
16285
+ delete process.env.CONVEYOR_CLAUDE_OAUTH;
16195
16286
  if (data.isSubscription) {
16196
16287
  process.env.CLAUDE_CODE_OAUTH_TOKEN = data.apiKey;
16197
16288
  delete process.env.ANTHROPIC_API_KEY;
@@ -16343,12 +16434,12 @@ var SessionRunner = class _SessionRunner {
16343
16434
  };
16344
16435
 
16345
16436
  // src/setup/config.ts
16346
- import { join as join12 } from "path";
16437
+ import { join as join13 } from "path";
16347
16438
  var DEVCONTAINER_PATH = ".devcontainer/conveyor/devcontainer.json";
16348
16439
  var DEVCONTAINER_PORT_DENY_LIST = /* @__PURE__ */ new Set([5432, 6379, 9200]);
16349
16440
  async function loadForwardPorts(workspaceDir) {
16350
16441
  try {
16351
- const raw = await readWorkspaceFile(join12(workspaceDir, DEVCONTAINER_PATH));
16442
+ const raw = await readWorkspaceFile(join13(workspaceDir, DEVCONTAINER_PATH));
16352
16443
  const parsed = JSON.parse(raw);
16353
16444
  const ports = (parsed.forwardPorts ?? []).filter(
16354
16445
  (p) => typeof p === "number" && !DEVCONTAINER_PORT_DENY_LIST.has(p)
@@ -16438,4 +16529,4 @@ export {
16438
16529
  loadConveyorConfig,
16439
16530
  unshallowRepo
16440
16531
  };
16441
- //# sourceMappingURL=chunk-JCRP6K6T.js.map
16532
+ //# sourceMappingURL=chunk-VF5BSGN4.js.map