@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.
- package/dist/cli.js +121 -64
- 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(
|
|
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(
|
|
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
|
-
|
|
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
|
|
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",
|
|
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(
|
|
4401
|
-
throw new GitError(`git clone ${
|
|
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 (
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
7390
|
-
return `${
|
|
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 =
|
|
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 =
|
|
8043
|
+
if (ageSeconds <= DIGEST_MAX_AGE_SECONDS) digest = readFileSync12(digestPath2, "utf8");
|
|
7998
8044
|
}
|
|
7999
|
-
const common = usesCommon ?
|
|
8000
|
-
const brief =
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
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) ?
|
|
9448
|
-
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
14295
|
+
const raw = existsSync24(resolvedPath) ? JSON.parse(readFileSync18(resolvedPath, "utf8")) : {};
|
|
14239
14296
|
raw.agentSkills = result.agentSkills;
|
|
14240
14297
|
mkdirSync13(dirOf(resolvedPath), { recursive: true });
|
|
14241
|
-
|
|
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 =
|
|
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(
|
|
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(
|
|
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
|
-
|
|
14410
|
+
writeFileSync14(resolvedFile, `${JSON.stringify(raw, null, 2)}
|
|
14354
14411
|
`);
|
|
14355
14412
|
}
|
|
14356
14413
|
}
|
|
14357
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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