@tablation/crew 0.46.0 → 0.46.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/cli.js +121 -64
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1963,6 +1963,11 @@ var ROLE_LABEL = {
1963
1963
  };
1964
1964
  var ConfigError = class extends Error {
1965
1965
  };
1966
+ function parseCloneScheme(v) {
1967
+ if (v === void 0 || v === null || v === "") return void 0;
1968
+ if (v === "ssh" || v === "https") return v;
1969
+ throw new ConfigError(`ship.cloneScheme must be "ssh" or "https", got ${JSON.stringify(v)}`);
1970
+ }
1966
1971
  var SHIP_KEYS = /* @__PURE__ */ new Set([
1967
1972
  "name",
1968
1973
  "platform",
@@ -1987,7 +1992,8 @@ var SHIP_KEYS = /* @__PURE__ */ new Set([
1987
1992
  "relayPort",
1988
1993
  "relayHttpPort",
1989
1994
  "relayPublicDomain",
1990
- "passengerImage"
1995
+ "passengerImage",
1996
+ "cloneScheme"
1991
1997
  ]);
1992
1998
  var ROUTE_KEYS = /* @__PURE__ */ new Set([
1993
1999
  "route",
@@ -2355,7 +2361,8 @@ Create the first of those:
2355
2361
  relayPort: shipRaw.relayPort !== void 0 ? Number(shipRaw.relayPort) : 2222,
2356
2362
  relayHttpPort: shipRaw.relayHttpPort !== void 0 ? Number(shipRaw.relayHttpPort) : 443,
2357
2363
  relayPublicDomain: shipRaw.relayPublicDomain ? String(shipRaw.relayPublicDomain) : void 0,
2358
- passengerImage: shipRaw.passengerImage ? String(shipRaw.passengerImage) : void 0
2364
+ passengerImage: shipRaw.passengerImage ? String(shipRaw.passengerImage) : void 0,
2365
+ cloneScheme: parseCloneScheme(shipRaw.cloneScheme)
2359
2366
  },
2360
2367
  routes,
2361
2368
  crewHome,
@@ -4020,17 +4027,22 @@ import {
4020
4027
  closeSync as closeSync2,
4021
4028
  writeSync,
4022
4029
  statSync as statSync4,
4023
- unlinkSync as unlinkSync2
4030
+ unlinkSync as unlinkSync2,
4031
+ readFileSync as readFileSync9,
4032
+ writeFileSync as writeFileSync6
4024
4033
  } from "fs";
4025
4034
  import { dirname as dirname5, basename as basename4 } from "path";
4026
4035
  var GitError = class extends Error {
4027
4036
  };
4037
+ function streamText(x) {
4038
+ return String(x ?? "").trim();
4039
+ }
4028
4040
  function gitRaw(cwd, args) {
4029
4041
  try {
4030
4042
  return execFileSync("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
4031
4043
  } catch (e) {
4032
4044
  const err = e;
4033
- const why = [err.stderr, err.stdout].map((x) => (x ?? "").trim()).filter(Boolean).join(" / ");
4045
+ const why = [err.stderr, err.stdout].map(streamText).filter(Boolean).join(" / ");
4034
4046
  throw new GitError(`git ${args.join(" ")}: ${why || err.message.trim()}`);
4035
4047
  }
4036
4048
  }
@@ -4039,7 +4051,7 @@ function git(cwd, args) {
4039
4051
  return execFileSync("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
4040
4052
  } catch (e) {
4041
4053
  const err = e;
4042
- const why = [err.stderr, err.stdout].map((x) => (x ?? "").trim()).filter(Boolean).join(" / ");
4054
+ const why = [err.stderr, err.stdout].map(streamText).filter(Boolean).join(" / ");
4043
4055
  throw new GitError(`git ${args.join(" ")}: ${why || err.message.trim()}`);
4044
4056
  }
4045
4057
  }
@@ -4382,10 +4394,19 @@ function worktrees(cwd) {
4382
4394
  if (current.path) list.push({ path: current.path, branch: current.branch ?? null, prunable: current.prunable ?? false });
4383
4395
  return list;
4384
4396
  }
4385
- function cloneUrlFor(remote) {
4386
- return `git@github.com:${remote}.git`;
4397
+ function cloneUrlFor(remote, opts = {}) {
4398
+ const origin = opts.originUrl?.trim() ?? "";
4399
+ const scheme = /^https?:\/\//i.test(origin) ? "https" : /^(git@|ssh:\/\/)/i.test(origin) ? "ssh" : opts.scheme ?? "ssh";
4400
+ return scheme === "https" ? `https://github.com/${remote}.git` : `git@github.com:${remote}.git`;
4387
4401
  }
4388
- function ensureRepoCheckout(dir, remote) {
4402
+ function originUrlOf(dir, remoteName) {
4403
+ try {
4404
+ return git(dir, ["remote", "get-url", remoteName]) || null;
4405
+ } catch {
4406
+ return null;
4407
+ }
4408
+ }
4409
+ function ensureRepoCheckout(dir, remote, opts = {}) {
4389
4410
  if (existsSync9(`${dir}/.git`)) return false;
4390
4411
  if (!remote) {
4391
4412
  throw new GitError(
@@ -4393,12 +4414,13 @@ function ensureRepoCheckout(dir, remote) {
4393
4414
  );
4394
4415
  }
4395
4416
  mkdirSync5(dirname5(dir), { recursive: true });
4417
+ const url = cloneUrlFor(remote, opts);
4396
4418
  try {
4397
- execFileSync("git", ["clone", cloneUrlFor(remote), dir], { stdio: ["ignore", "pipe", "pipe"] });
4419
+ execFileSync("git", ["clone", url, dir], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
4398
4420
  } catch (e) {
4399
4421
  const err = e;
4400
- const why = [err.stderr, err.stdout].map((x) => (x ?? "").trim()).filter(Boolean).join(" / ");
4401
- throw new GitError(`git clone ${cloneUrlFor(remote)} ${dir}: ${why || err.message.trim()}`);
4422
+ const why = [err.stderr, err.stdout].map(streamText).filter(Boolean).join(" / ");
4423
+ throw new GitError(`git clone ${url} ${dir}: ${why || err.message.trim()}`);
4402
4424
  }
4403
4425
  return true;
4404
4426
  }
@@ -4445,10 +4467,31 @@ function acquireCheckoutLock(dir, timeoutMs = 3e4) {
4445
4467
  }
4446
4468
  }
4447
4469
  }
4448
- function syncPassengerCheckout(dir, githubRemote, gitRemoteName, base) {
4470
+ function syncPassengerCheckout(dir, githubRemote, gitRemoteName, base, clone = {}) {
4449
4471
  const release = acquireCheckoutLock(dir);
4450
4472
  try {
4451
- if (ensureRepoCheckout(dir, githubRemote)) {
4473
+ if (!existsSync9(`${dir}/.git`) && githubRemote) {
4474
+ const url = cloneUrlFor(githubRemote, clone);
4475
+ const marker = cloneFailureMarker(dir);
4476
+ if (existsSync9(marker) && readFileSync9(marker, "utf8").split("\n")[0] === url) {
4477
+ return { action: "clone-failed", detail: readFileSync9(marker, "utf8").split("\n").slice(1).join("\n"), repeat: true };
4478
+ }
4479
+ try {
4480
+ ensureRepoCheckout(dir, githubRemote, clone);
4481
+ } catch (e) {
4482
+ if (!(e instanceof GitError)) throw e;
4483
+ writeFileSync6(marker, `${url}
4484
+ ${e.message}`);
4485
+ return { action: "clone-failed", detail: e.message, repeat: false };
4486
+ }
4487
+ try {
4488
+ unlinkSync2(marker);
4489
+ } catch {
4490
+ }
4491
+ if (currentBranch(dir) !== base) git(dir, ["checkout", base]);
4492
+ return { action: "cloned", detail: `cloned ${githubRemote} into ${dir}` };
4493
+ }
4494
+ if (ensureRepoCheckout(dir, githubRemote, clone)) {
4452
4495
  if (currentBranch(dir) !== base) git(dir, ["checkout", base]);
4453
4496
  return { action: "cloned", detail: `cloned ${githubRemote} into ${dir}` };
4454
4497
  }
@@ -4457,6 +4500,9 @@ function syncPassengerCheckout(dir, githubRemote, gitRemoteName, base) {
4457
4500
  release();
4458
4501
  }
4459
4502
  }
4503
+ function cloneFailureMarker(dir) {
4504
+ return `${dir}.clone-failed`;
4505
+ }
4460
4506
 
4461
4507
  // src/ship-attention.ts
4462
4508
  var RELEASE_STALE_AFTER_INTERVALS = 3;
@@ -6220,7 +6266,7 @@ function materializeBranchForTicket(dir, cfg, t, role) {
6220
6266
  }
6221
6267
 
6222
6268
  // src/poll.ts
6223
- import { writeFileSync as writeFileSync6 } from "fs";
6269
+ import { writeFileSync as writeFileSync7 } from "fs";
6224
6270
  import { join as join10 } from "path";
6225
6271
 
6226
6272
  // src/stalled.ts
@@ -6560,7 +6606,7 @@ function writeDigest(o, d, role, stateDir) {
6560
6606
  };
6561
6607
  const text = role === "qa" ? qaDigest(input) : buildingDigest(input);
6562
6608
  const path = digestPath(stateDir, routeSlug(o.route.route), role);
6563
- writeFileSync6(path, text);
6609
+ writeFileSync7(path, text);
6564
6610
  o.emit.emit(`queue digest written for ${role} (${Buffer.byteLength(text)} bytes)`, {
6565
6611
  data: { role, bytes: Buffer.byteLength(text) }
6566
6612
  });
@@ -6944,7 +6990,7 @@ var alreadyReported = (ticket, g, events) => events.some((e) => e.record_id ===
6944
6990
 
6945
6991
  // src/agent.ts
6946
6992
  import { spawn as spawn2 } from "child_process";
6947
- import { readFileSync as readFileSync11, existsSync as existsSync12, statSync as statSync5, mkdirSync as mkdirSync6, writeFileSync as writeFileSync7, createWriteStream } from "fs";
6993
+ import { readFileSync as readFileSync12, existsSync as existsSync12, statSync as statSync5, mkdirSync as mkdirSync6, writeFileSync as writeFileSync8, createWriteStream } from "fs";
6948
6994
  import { finished } from "stream/promises";
6949
6995
  import { join as join13, dirname as dirname6 } from "path";
6950
6996
  import { createHash as createHash2 } from "crypto";
@@ -7361,13 +7407,13 @@ function expandSkillMarkers(text, lookup, opts = {}) {
7361
7407
  }
7362
7408
 
7363
7409
  // src/skills.ts
7364
- import { readFileSync as readFileSync10, readdirSync as readdirSync3, existsSync as existsSync11 } from "fs";
7410
+ import { readFileSync as readFileSync11, readdirSync as readdirSync3, existsSync as existsSync11 } from "fs";
7365
7411
  import { join as join12 } from "path";
7366
7412
  import { parse as parseYaml } from "yaml";
7367
7413
  import { TablationClient as TablationClient3, StaleWriteError as StaleWriteError8, TablationApiError as TablationApiError2 } from "@tablation/client";
7368
7414
 
7369
7415
  // src/agents.ts
7370
- import { readFileSync as readFileSync9, existsSync as existsSync10 } from "fs";
7416
+ import { readFileSync as readFileSync10, existsSync as existsSync10 } from "fs";
7371
7417
  import { join as join11 } from "path";
7372
7418
  import { TablationClient as TablationClient2, StaleWriteError as StaleWriteError7, TablationApiError } from "@tablation/client";
7373
7419
  var PERSONA_NAME = {
@@ -7384,10 +7430,10 @@ var AgentsSyncError = class extends Error {
7384
7430
  function personaDefaultPrompt(promptsDir, role) {
7385
7431
  const briefPath = join11(promptsDir, "personas", `lane-${role}.md`);
7386
7432
  if (!existsSync10(briefPath)) throw new AgentsSyncError(`no brief at ${briefPath}`);
7387
- if (SELF_CONTAINED_ROLES.has(role)) return readFileSync9(briefPath, "utf8");
7433
+ if (SELF_CONTAINED_ROLES.has(role)) return readFileSync10(briefPath, "utf8");
7388
7434
  const commonPath = join11(promptsDir, "personas", "common.md");
7389
- if (!existsSync10(commonPath)) return readFileSync9(briefPath, "utf8");
7390
- return `${readFileSync9(commonPath, "utf8")}${readFileSync9(briefPath, "utf8")}`;
7435
+ if (!existsSync10(commonPath)) return readFileSync10(briefPath, "utf8");
7436
+ return `${readFileSync10(commonPath, "utf8")}${readFileSync10(briefPath, "utf8")}`;
7391
7437
  }
7392
7438
  async function resolveAgentId(route, role, opts) {
7393
7439
  const cached = route.resolved?.agentPersonas?.[role]?.agentId;
@@ -7733,7 +7779,7 @@ function describeCrewLink(o) {
7733
7779
  var SkillSyncError = class extends Error {
7734
7780
  };
7735
7781
  function parseSkillFile(path) {
7736
- const text = readFileSync10(path, "utf8");
7782
+ const text = readFileSync11(path, "utf8");
7737
7783
  const match = /^---\n([\s\S]*?)\n---\n([\s\S]*)$/.exec(text);
7738
7784
  if (!match) throw new SkillSyncError(`${path}: missing YAML frontmatter (expected a leading --- block)`);
7739
7785
  const frontmatter = match[1];
@@ -7994,10 +8040,10 @@ function planAgentRun(o) {
7994
8040
  let ageSeconds;
7995
8041
  if (existsSync12(digestPath2)) {
7996
8042
  ageSeconds = Math.floor((now() - statSync5(digestPath2).mtimeMs) / 1e3);
7997
- if (ageSeconds <= DIGEST_MAX_AGE_SECONDS) digest = readFileSync11(digestPath2, "utf8");
8043
+ if (ageSeconds <= DIGEST_MAX_AGE_SECONDS) digest = readFileSync12(digestPath2, "utf8");
7998
8044
  }
7999
- const common = usesCommon ? readFileSync11(commonPath, "utf8") : "";
8000
- const brief = readFileSync11(briefPath, "utf8");
8045
+ const common = usesCommon ? readFileSync12(commonPath, "utf8") : "";
8046
+ const brief = readFileSync12(briefPath, "utf8");
8001
8047
  const effectiveCommon = o.divergedPrompt ? "" : common;
8002
8048
  const effectiveBrief = o.divergedPrompt ?? brief;
8003
8049
  const localSkills = new Map(listLocalSkills(o.route.promptsDir).map((s) => [s.name, s.prompt]));
@@ -8223,7 +8269,7 @@ function spawnAgent(plan, emit) {
8223
8269
  provider: plan.provider ?? LEGACY_TOOLCHAIN_PROVIDER
8224
8270
  };
8225
8271
  try {
8226
- writeFileSync7(`${plan.streamPath}.meta.json`, JSON.stringify({
8272
+ writeFileSync8(`${plan.streamPath}.meta.json`, JSON.stringify({
8227
8273
  route: plan.route,
8228
8274
  role: plan.role,
8229
8275
  ticket: plan.ticket ?? null,
@@ -8630,7 +8676,7 @@ async function retireRunWorktree(tracker, dir, cfg, t, role, seatId, shipName2,
8630
8676
 
8631
8677
  // src/connect-wizard.ts
8632
8678
  import { delimiter, dirname as dirname8, join as join16 } from "path";
8633
- import { accessSync as accessSync2, constants as constants2, existsSync as existsSync15, mkdirSync as mkdirSync7, writeFileSync as writeFileSync8 } from "fs";
8679
+ import { accessSync as accessSync2, constants as constants2, existsSync as existsSync15, mkdirSync as mkdirSync7, writeFileSync as writeFileSync9 } from "fs";
8634
8680
  import { stringify } from "yaml";
8635
8681
  var HOST_PASSENGERS_DOCS_URL = "https://crew.tablation.dev/host-passengers";
8636
8682
  function shouldRunWizard(opts) {
@@ -8715,7 +8761,7 @@ ${routeBlock}`;
8715
8761
  function writeNewConfig(path, text) {
8716
8762
  mkdirSync7(dirname8(path), { recursive: true });
8717
8763
  try {
8718
- writeFileSync8(path, text, { mode: 384, flag: "wx" });
8764
+ writeFileSync9(path, text, { mode: 384, flag: "wx" });
8719
8765
  return true;
8720
8766
  } catch (e) {
8721
8767
  if (e.code === "EEXIST") return false;
@@ -8747,7 +8793,7 @@ Wrote ${o.configPath}.
8747
8793
  }
8748
8794
 
8749
8795
  // src/release-run.ts
8750
- import { readFileSync as readFileSync12, writeFileSync as writeFileSync9, existsSync as existsSync16, copyFileSync, mkdirSync as mkdirSync8, mkdtempSync, rmSync as rmSync6 } from "fs";
8796
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync10, existsSync as existsSync16, copyFileSync, mkdirSync as mkdirSync8, mkdtempSync, rmSync as rmSync6 } from "fs";
8751
8797
  import { dirname as dirname9, join as join17 } from "path";
8752
8798
  import { tmpdir as tmpdir2 } from "os";
8753
8799
 
@@ -9412,7 +9458,7 @@ async function bump(o, size) {
9412
9458
  o.emit.error(`no ${o.repo.release.versionFiles[0]} to read a version from`);
9413
9459
  return null;
9414
9460
  }
9415
- const current = JSON.parse(readFileSync12(first, "utf8")).version;
9461
+ const current = JSON.parse(readFileSync13(first, "utf8")).version;
9416
9462
  if (!current) {
9417
9463
  o.emit.error(`no version field in ${o.repo.release.versionFiles[0]}`);
9418
9464
  return null;
@@ -9425,13 +9471,13 @@ async function bump(o, size) {
9425
9471
  return version;
9426
9472
  }
9427
9473
  for (const f of files) {
9428
- const src = readFileSync12(f, "utf8");
9474
+ const src = readFileSync13(f, "utf8");
9429
9475
  const out = src.replace(/("version"\s*:\s*")[^"]*(")/, `$1${version}$2`);
9430
9476
  if (out === src) {
9431
9477
  o.emit.error(`no version field in ${f}`);
9432
9478
  return null;
9433
9479
  }
9434
- writeFileSync9(f, out);
9480
+ writeFileSync10(f, out);
9435
9481
  }
9436
9482
  return version;
9437
9483
  }
@@ -9444,8 +9490,8 @@ function writeChangelog(o, version, entries) {
9444
9490
  o.emit.emit(`would prepend ${entries.length} entr(ies) to ${file}`);
9445
9491
  return;
9446
9492
  }
9447
- const existing = existsSync16(path) ? readFileSync12(path, "utf8") : "# Changelog\n";
9448
- writeFileSync9(path, insertChangelogSection(existing, section));
9493
+ const existing = existsSync16(path) ? readFileSync13(path, "utf8") : "# Changelog\n";
9494
+ writeFileSync10(path, insertChangelogSection(existing, section));
9449
9495
  }
9450
9496
  async function confirm(o, expected) {
9451
9497
  if (!o.repo.hooks.released) return void 0;
@@ -11414,13 +11460,13 @@ function planEventsSweep(stateDir, retentionDays, now = Date.now()) {
11414
11460
  }
11415
11461
 
11416
11462
  // src/cli.ts
11417
- import { readFileSync as readFileSync17, existsSync as existsSync24, mkdirSync as mkdirSync13, writeFileSync as writeFileSync13, unlinkSync as unlinkSync5, copyFileSync as copyFileSync2, renameSync as renameSync2, statSync as statSync9 } from "fs";
11463
+ import { readFileSync as readFileSync18, existsSync as existsSync24, mkdirSync as mkdirSync13, writeFileSync as writeFileSync14, unlinkSync as unlinkSync5, copyFileSync as copyFileSync2, renameSync as renameSync2, statSync as statSync9 } from "fs";
11418
11464
  import { createInterface } from "readline/promises";
11419
11465
  import { dirname as dirOf, resolve as resolvePath } from "path";
11420
11466
 
11421
11467
  // src/ssh-keys.ts
11422
11468
  import { execFileSync as execFileSync3 } from "child_process";
11423
- import { existsSync as existsSync20, mkdirSync as mkdirSync9, readFileSync as readFileSync13, chmodSync } from "fs";
11469
+ import { existsSync as existsSync20, mkdirSync as mkdirSync9, readFileSync as readFileSync14, chmodSync } from "fs";
11424
11470
  import { dirname as dirname11, join as join19 } from "path";
11425
11471
  var SshKeyError = class extends Error {
11426
11472
  };
@@ -11454,7 +11500,7 @@ function ensureShipSshKeypair(stateDir) {
11454
11500
  if (!existsSync20(publicKeyPath)) {
11455
11501
  throw new SshKeyError(`${privateKeyPath} exists but ${publicKeyPath} does not \u2014 regenerate or restore it`);
11456
11502
  }
11457
- const publicKey = readFileSync13(publicKeyPath, "utf8").trim();
11503
+ const publicKey = readFileSync14(publicKeyPath, "utf8").trim();
11458
11504
  return { privateKeyPath, publicKeyPath, publicKey };
11459
11505
  }
11460
11506
  function sshKeygenAvailable() {
@@ -11652,7 +11698,9 @@ function passengerCheckoutSyncSpecs(cfg, workspaceId) {
11652
11698
  dir: target.dir,
11653
11699
  remote: target.remote,
11654
11700
  gitRemoteName: effective.branch.remote,
11655
- base: effective.branch.base
11701
+ base: effective.branch.base,
11702
+ originUrl: ordinary ? originUrlOf(ordinary.dir, effective.branch.remote) : null,
11703
+ cloneScheme: cfg.ship.cloneScheme
11656
11704
  });
11657
11705
  }
11658
11706
  }
@@ -11662,13 +11710,13 @@ function syncAllPassengerCheckouts(cfg) {
11662
11710
  return passengerCheckoutSyncSpecs(cfg).map((spec) => ({
11663
11711
  name: spec.name,
11664
11712
  workspaceId: spec.workspaceId,
11665
- outcome: syncPassengerCheckout(spec.dir, spec.remote, spec.gitRemoteName, spec.base)
11713
+ outcome: syncPassengerCheckout(spec.dir, spec.remote, spec.gitRemoteName, spec.base, { originUrl: spec.originUrl, scheme: spec.cloneScheme })
11666
11714
  }));
11667
11715
  }
11668
11716
 
11669
11717
  // src/tunnel.ts
11670
11718
  import { spawn as spawn3 } from "child_process";
11671
- import { existsSync as existsSync21, mkdirSync as mkdirSync10, readFileSync as readFileSync14, writeFileSync as writeFileSync10, unlinkSync as unlinkSync3, readdirSync as readdirSync5 } from "fs";
11719
+ import { existsSync as existsSync21, mkdirSync as mkdirSync10, readFileSync as readFileSync15, writeFileSync as writeFileSync11, unlinkSync as unlinkSync3, readdirSync as readdirSync5 } from "fs";
11672
11720
  import { randomInt } from "crypto";
11673
11721
  import { join as join20 } from "path";
11674
11722
  var DEFAULT_SPAWN_OPTIONS = { stdio: "ignore", detached: true };
@@ -11743,7 +11791,7 @@ function readPersistedTunnel(stateDir, workspaceId) {
11743
11791
  const path = tunnelStatePath(stateDir, workspaceId);
11744
11792
  if (!existsSync21(path)) return void 0;
11745
11793
  try {
11746
- return JSON.parse(readFileSync14(path, "utf8"));
11794
+ return JSON.parse(readFileSync15(path, "utf8"));
11747
11795
  } catch {
11748
11796
  return void 0;
11749
11797
  }
@@ -11751,7 +11799,7 @@ function readPersistedTunnel(stateDir, workspaceId) {
11751
11799
  function writePersistedTunnel(stateDir, state) {
11752
11800
  const path = tunnelStatePath(stateDir, state.workspaceId);
11753
11801
  mkdirSync10(join20(stateDir, "passengers"), { recursive: true });
11754
- writeFileSync10(path, `${JSON.stringify(state, null, 2)}
11802
+ writeFileSync11(path, `${JSON.stringify(state, null, 2)}
11755
11803
  `);
11756
11804
  }
11757
11805
  function updatePersistedTunnel(stateDir, workspaceId, patch2) {
@@ -11970,7 +12018,7 @@ async function unregisterEndpoint(workspaceId, info, d) {
11970
12018
  import { createServer as createHttpServer } from "http";
11971
12019
  import { spawn as spawn4 } from "child_process";
11972
12020
  import { randomBytes } from "crypto";
11973
- import { existsSync as existsSync22, mkdirSync as mkdirSync11, readFileSync as readFileSync15, writeFileSync as writeFileSync11, unlinkSync as unlinkSync4, readdirSync as readdirSync6 } from "fs";
12021
+ import { existsSync as existsSync22, mkdirSync as mkdirSync11, readFileSync as readFileSync16, writeFileSync as writeFileSync12, unlinkSync as unlinkSync4, readdirSync as readdirSync6 } from "fs";
11974
12022
  import { join as join21 } from "path";
11975
12023
 
11976
12024
  // src/secret-compare.ts
@@ -12025,7 +12073,7 @@ function createSyncDaemonServer(targets, secret) {
12025
12073
  try {
12026
12074
  const synced = targets.map((t) => ({
12027
12075
  name: t.name,
12028
- outcome: syncPassengerCheckout(t.dir, t.remote, t.gitRemoteName, t.base)
12076
+ outcome: syncPassengerCheckout(t.dir, t.remote, t.gitRemoteName, t.base, { originUrl: t.originUrl, scheme: t.cloneScheme })
12029
12077
  }));
12030
12078
  res.writeHead(200, { "Content-Type": "application/json" }).end(JSON.stringify({ synced }));
12031
12079
  } catch (error) {
@@ -12066,7 +12114,7 @@ function readPersistedSyncDaemon(stateDir, workspaceId) {
12066
12114
  const path = syncDaemonStatePath(stateDir, workspaceId);
12067
12115
  if (!existsSync22(path)) return void 0;
12068
12116
  try {
12069
- return JSON.parse(readFileSync15(path, "utf8"));
12117
+ return JSON.parse(readFileSync16(path, "utf8"));
12070
12118
  } catch {
12071
12119
  return void 0;
12072
12120
  }
@@ -12074,7 +12122,7 @@ function readPersistedSyncDaemon(stateDir, workspaceId) {
12074
12122
  function writePersistedSyncDaemon(stateDir, state) {
12075
12123
  const path = syncDaemonStatePath(stateDir, state.workspaceId);
12076
12124
  mkdirSync11(join21(stateDir, "passengers"), { recursive: true });
12077
- writeFileSync11(path, `${JSON.stringify(state, null, 2)}
12125
+ writeFileSync12(path, `${JSON.stringify(state, null, 2)}
12078
12126
  `);
12079
12127
  }
12080
12128
  function removePersistedSyncDaemon(stateDir, workspaceId) {
@@ -12152,7 +12200,7 @@ function syncPassengerSyncDaemons(plans, cfg, stateDir, deps = {}) {
12152
12200
  }
12153
12201
 
12154
12202
  // src/daemon.ts
12155
- import { existsSync as existsSync23, mkdirSync as mkdirSync12, readFileSync as readFileSync16, readdirSync as readdirSync7, rmSync as rmSync8, statSync as statSync8, writeFileSync as writeFileSync12 } from "fs";
12203
+ import { existsSync as existsSync23, mkdirSync as mkdirSync12, readFileSync as readFileSync17, readdirSync as readdirSync7, rmSync as rmSync8, statSync as statSync8, writeFileSync as writeFileSync13 } from "fs";
12156
12204
  import { join as join22 } from "path";
12157
12205
  var DEFAULT_FLOOR_MS = 5e3;
12158
12206
  var DEFAULT_CEILING_MS = INTERVAL_SECONDS * 1e3;
@@ -12212,12 +12260,12 @@ function daemonStampFor(stateDir) {
12212
12260
  function noteDaemonStarted(stateDir, now = Date.now()) {
12213
12261
  mkdirSync12(stateDir, { recursive: true });
12214
12262
  rmSync8(reloadSentinelFor(stateDir), { force: true });
12215
- writeFileSync12(daemonStampFor(stateDir), `${JSON.stringify({ pid: process.pid, startedAt: now })}
12263
+ writeFileSync13(daemonStampFor(stateDir), `${JSON.stringify({ pid: process.pid, startedAt: now })}
12216
12264
  `);
12217
12265
  }
12218
12266
  function readDaemonStarted(stateDir) {
12219
12267
  try {
12220
- const v = JSON.parse(readFileSync16(daemonStampFor(stateDir), "utf8")).startedAt;
12268
+ const v = JSON.parse(readFileSync17(daemonStampFor(stateDir), "utf8")).startedAt;
12221
12269
  return typeof v === "number" ? v : null;
12222
12270
  } catch {
12223
12271
  return null;
@@ -12854,6 +12902,15 @@ if (command === "passenger-sync-daemon") {
12854
12902
  }
12855
12903
  try {
12856
12904
  for (const r of syncAllPassengerCheckouts(cfg)) {
12905
+ if (r.outcome.action === "clone-failed") {
12906
+ if (!r.outcome.repeat) {
12907
+ emit.warn(
12908
+ `passenger checkout for ${r.name} could not be cloned (not retried until its clone URL changes): ${r.outcome.detail}`,
12909
+ { step: "passengers", data: { workspaceId: r.workspaceId, repo: r.name } }
12910
+ );
12911
+ }
12912
+ continue;
12913
+ }
12857
12914
  if (r.outcome.action === "diverged" || r.outcome.action === "ff-failed") {
12858
12915
  emit.warn(
12859
12916
  `passenger checkout for ${r.name} is stale: ${r.outcome.detail}`,
@@ -13084,7 +13141,7 @@ if (command === "passenger-sync-daemon") {
13084
13141
  for (const a of plan.actions) {
13085
13142
  if (a.kind === "enable") {
13086
13143
  if (prompter && !await prompter.confirm(`Route ${a.route} passes every check \u2014 set enabled: true in ${cfg.configFile}?`, false)) continue;
13087
- writeFileSync13(cfg.configFile, planEnable(readFileSync17(cfg.configFile, "utf8"), a.route));
13144
+ writeFileSync14(cfg.configFile, planEnable(readFileSync18(cfg.configFile, "utf8"), a.route));
13088
13145
  enabledSound.add(a.route);
13089
13146
  changed2.push(`enabled route ${a.route} in ${cfg.configFile}`);
13090
13147
  } else {
@@ -14177,11 +14234,11 @@ ${changed2.map((c) => ` - ${c}
14177
14234
  `);
14178
14235
  if (!dryRun) {
14179
14236
  const resolvedPath = resolvedPathFor(cfg.ship.stateDir, target.route);
14180
- const raw = existsSync24(resolvedPath) ? JSON.parse(readFileSync17(resolvedPath, "utf8")) : {};
14237
+ const raw = existsSync24(resolvedPath) ? JSON.parse(readFileSync18(resolvedPath, "utf8")) : {};
14181
14238
  raw.agentPersonas = personaResult.agentPersonas;
14182
14239
  raw.agentSkills = skillResult.agentSkills;
14183
14240
  mkdirSync13(dirOf(resolvedPath), { recursive: true });
14184
- writeFileSync13(resolvedPath, `${JSON.stringify(raw, null, 2)}
14241
+ writeFileSync14(resolvedPath, `${JSON.stringify(raw, null, 2)}
14185
14242
  `);
14186
14243
  }
14187
14244
  if (!dryRun) {
@@ -14235,10 +14292,10 @@ ${changed2.map((c) => ` - ${c}
14235
14292
  `);
14236
14293
  if (!dryRun) {
14237
14294
  const resolvedPath = resolvedPathFor(cfg.ship.stateDir, target.route);
14238
- const raw = existsSync24(resolvedPath) ? JSON.parse(readFileSync17(resolvedPath, "utf8")) : {};
14295
+ const raw = existsSync24(resolvedPath) ? JSON.parse(readFileSync18(resolvedPath, "utf8")) : {};
14239
14296
  raw.agentSkills = result.agentSkills;
14240
14297
  mkdirSync13(dirOf(resolvedPath), { recursive: true });
14241
- writeFileSync13(resolvedPath, `${JSON.stringify(raw, null, 2)}
14298
+ writeFileSync14(resolvedPath, `${JSON.stringify(raw, null, 2)}
14242
14299
  `);
14243
14300
  }
14244
14301
  if (result.outcomes.some((o) => o.action === "diverged")) process.exitCode = 1;
@@ -14251,7 +14308,7 @@ ${changed2.map((c) => ` - ${c}
14251
14308
  process.exit(2);
14252
14309
  };
14253
14310
  if (sub !== "add" && sub !== "list") usage2();
14254
- const configText = readFileSync17(cfg.configFile, "utf8");
14311
+ const configText = readFileSync18(cfg.configFile, "utf8");
14255
14312
  let routeName = positional[2];
14256
14313
  let addPath = ".";
14257
14314
  let addName;
@@ -14275,7 +14332,7 @@ ${changed2.map((c) => ` - ${c}
14275
14332
  let resolvedRemotes;
14276
14333
  if (existsSync24(resolvedFile)) {
14277
14334
  try {
14278
- resolvedRemotes = JSON.parse(readFileSync17(resolvedFile, "utf8"));
14335
+ resolvedRemotes = JSON.parse(readFileSync18(resolvedFile, "utf8"));
14279
14336
  } catch {
14280
14337
  }
14281
14338
  }
@@ -14347,14 +14404,14 @@ ${changed2.map((c) => ` - ${c}
14347
14404
  process.stdout.write(`created Repos row ${String(rowPayload.name)} (${String(rowPayload.remote)}) ${created.id}
14348
14405
  `);
14349
14406
  if (existsSync24(resolvedFile)) {
14350
- const raw = JSON.parse(readFileSync17(resolvedFile, "utf8"));
14407
+ const raw = JSON.parse(readFileSync18(resolvedFile, "utf8"));
14351
14408
  raw.repoNames = { ...raw.repoNames, [created.id]: String(rowPayload.name) };
14352
14409
  raw.repoRemotes = { ...raw.repoRemotes, [created.id]: String(rowPayload.remote) };
14353
- writeFileSync13(resolvedFile, `${JSON.stringify(raw, null, 2)}
14410
+ writeFileSync14(resolvedFile, `${JSON.stringify(raw, null, 2)}
14354
14411
  `);
14355
14412
  }
14356
14413
  }
14357
- writeFileSync13(cfg.configFile, plan.text);
14414
+ writeFileSync14(cfg.configFile, plan.text);
14358
14415
  process.stdout.write(`added ${top} to ${routeName} as ${plan.mode === "dir" ? "dir" : `repos.${plan.name}`} in ${cfg.configFile}
14359
14416
  `);
14360
14417
  } catch (e) {
@@ -14596,7 +14653,7 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
14596
14653
  const hadPreviousFile = existsSync24(resolvedPath);
14597
14654
  if (hadPreviousFile) {
14598
14655
  try {
14599
- previous = JSON.parse(readFileSync17(resolvedPath, "utf8"));
14656
+ previous = JSON.parse(readFileSync18(resolvedPath, "utf8"));
14600
14657
  } catch {
14601
14658
  }
14602
14659
  }
@@ -14660,7 +14717,7 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
14660
14717
  mkdirSync13(dirname12(resolvedPath), { recursive: true });
14661
14718
  if (hadPreviousFile) copyFileSync2(resolvedPath, `${resolvedPath}.bak`);
14662
14719
  const tmpPath = `${resolvedPath}.tmp${process.pid}`;
14663
- writeFileSync13(tmpPath, `${JSON.stringify(resolved, null, 2)}
14720
+ writeFileSync14(tmpPath, `${JSON.stringify(resolved, null, 2)}
14664
14721
  `);
14665
14722
  renameSync2(tmpPath, resolvedPath);
14666
14723
  process.stderr.write(`Resolved ids written to ${resolvedPath}
@@ -14686,7 +14743,7 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
14686
14743
  `);
14687
14744
  } else {
14688
14745
  mkdirSync13(dirname12(apiKeyFile), { recursive: true });
14689
- writeFileSync13(apiKeyFile, `${apiKeyVar}=${apiKey}
14746
+ writeFileSync14(apiKeyFile, `${apiKeyVar}=${apiKey}
14690
14747
  `, { mode: 384 });
14691
14748
  process.stderr.write(`API key written to ${apiKeyFile}
14692
14749
  `);
@@ -15224,7 +15281,7 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
15224
15281
  break;
15225
15282
  }
15226
15283
  mkdirSync13(cfg.ship.stateDir, { recursive: true });
15227
- writeFileSync13(sentinel, `${(/* @__PURE__ */ new Date()).toISOString()}
15284
+ writeFileSync14(sentinel, `${(/* @__PURE__ */ new Date()).toISOString()}
15228
15285
  `);
15229
15286
  process.stdout.write("crew reload: requested \u2014 the daemon finishes its in-flight pass, then relaunches with the new config\n");
15230
15287
  if (flag("now") && control?.stopCommand && control.startCommand) {
@@ -15275,7 +15332,7 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
15275
15332
  }
15276
15333
  case "log": {
15277
15334
  try {
15278
- const text = readFileSync17(cfg.ship.logFile, "utf8").split("\n");
15335
+ const text = readFileSync18(cfg.ship.logFile, "utf8").split("\n");
15279
15336
  process.stdout.write(`${text.slice(-(Number(value("tail")) || 40)).join("\n")}
15280
15337
  `);
15281
15338
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tablation/crew",
3
- "version": "0.46.0",
3
+ "version": "0.46.1",
4
4
  "description": "A standing team of headless agents that picks work off a Tablation board, does it on a machine you control, and reports back.",
5
5
  "type": "module",
6
6
  "license": "MIT",