@tablation/crew 0.126.0 → 0.126.2
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 +143 -80
- package/dist/sandbox-intel-bridge.cjs +29 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -794,7 +794,7 @@ function shellInitScript(shell) {
|
|
|
794
794
|
|
|
795
795
|
// src/config.ts
|
|
796
796
|
import { readFileSync as readFileSync15, existsSync as existsSync15 } from "fs";
|
|
797
|
-
import { resolve as resolve2, dirname as
|
|
797
|
+
import { resolve as resolve2, dirname as dirname8, isAbsolute as isAbsolute2, join as join17, basename as basename4 } from "path";
|
|
798
798
|
import { homedir as homedir6, tmpdir } from "os";
|
|
799
799
|
import { parse as parse2 } from "yaml";
|
|
800
800
|
|
|
@@ -2661,7 +2661,7 @@ function explain(ship, required) {
|
|
|
2661
2661
|
|
|
2662
2662
|
// src/repo-config.ts
|
|
2663
2663
|
import { readFileSync as readFileSync14, existsSync as existsSync14 } from "fs";
|
|
2664
|
-
import { join as join16, basename as basename3 } from "path";
|
|
2664
|
+
import { join as join16, basename as basename3, dirname as dirname7 } from "path";
|
|
2665
2665
|
import { parse } from "yaml";
|
|
2666
2666
|
|
|
2667
2667
|
// src/sandbox-policy.ts
|
|
@@ -2863,6 +2863,19 @@ var SPEC_VERSION = 1;
|
|
|
2863
2863
|
var REPO_CONFIG_FILENAMES = [".crew.yaml", ".crew.yml", ".crew.json"];
|
|
2864
2864
|
var RepoConfigError = class extends Error {
|
|
2865
2865
|
};
|
|
2866
|
+
function versionFileProblem(name, text2) {
|
|
2867
|
+
const remedy = `a version file that is not a JSON object with a string "version" needs hooks.bump instead of release.versionFiles (docs/REPO_SPEC.md)`;
|
|
2868
|
+
let doc;
|
|
2869
|
+
try {
|
|
2870
|
+
doc = JSON.parse(text2);
|
|
2871
|
+
} catch {
|
|
2872
|
+
return `release.versionFiles entry "${name}" is not a JSON document \u2014 ${remedy}`;
|
|
2873
|
+
}
|
|
2874
|
+
if (!doc || typeof doc !== "object" || Array.isArray(doc) || typeof doc.version !== "string") {
|
|
2875
|
+
return `release.versionFiles entry "${name}" has no string "version" field \u2014 ${remedy}`;
|
|
2876
|
+
}
|
|
2877
|
+
return null;
|
|
2878
|
+
}
|
|
2866
2879
|
var HOOK_NAMES = [
|
|
2867
2880
|
"test",
|
|
2868
2881
|
"build",
|
|
@@ -3197,6 +3210,22 @@ function parseRepoConfig(text2, file) {
|
|
|
3197
3210
|
if (versionFiles.length === 0) {
|
|
3198
3211
|
throw new RepoConfigError(`${file}: release.versionFiles cannot be empty`);
|
|
3199
3212
|
}
|
|
3213
|
+
if (versionFilesGiven) {
|
|
3214
|
+
for (const name of versionFiles) {
|
|
3215
|
+
const path = join16(dirname7(file), name);
|
|
3216
|
+
if (!existsSync14(path)) continue;
|
|
3217
|
+
let text3;
|
|
3218
|
+
try {
|
|
3219
|
+
text3 = readFileSync14(path, "utf8");
|
|
3220
|
+
} catch (e) {
|
|
3221
|
+
throw new RepoConfigError(
|
|
3222
|
+
`${file}: release.versionFiles entry "${name}" cannot be read (${e.code ?? "read error"})`
|
|
3223
|
+
);
|
|
3224
|
+
}
|
|
3225
|
+
const problem = versionFileProblem(name, text3);
|
|
3226
|
+
if (problem) throw new RepoConfigError(`${file}: ${problem}`);
|
|
3227
|
+
}
|
|
3228
|
+
}
|
|
3200
3229
|
const inspectorRaw = raw.periscope?.inspector;
|
|
3201
3230
|
if (inspectorRaw !== void 0 && inspectorRaw !== "proxy" && inspectorRaw !== "repo") {
|
|
3202
3231
|
throw new RepoConfigError(`${file}: periscope.inspector must be "proxy" or "repo"`);
|
|
@@ -3898,7 +3927,7 @@ function loadConfig(crewHome, configFile, opts = {}) {
|
|
|
3898
3927
|
` + configSearchPath(crewHome).map((c) => ` - ${c}`).join("\n") + `
|
|
3899
3928
|
|
|
3900
3929
|
Create the first of those:
|
|
3901
|
-
mkdir -p ${
|
|
3930
|
+
mkdir -p ${dirname8(defaultConfigPath())} && cp ${join17(crewHome, "crew.example.yaml")} ${defaultConfigPath()}`
|
|
3902
3931
|
);
|
|
3903
3932
|
}
|
|
3904
3933
|
let raw;
|
|
@@ -3908,7 +3937,7 @@ Create the first of those:
|
|
|
3908
3937
|
throw new ConfigError(`${file}: not valid YAML \u2014 ${e.message}`);
|
|
3909
3938
|
}
|
|
3910
3939
|
if (!raw || typeof raw !== "object") throw new ConfigError(`${file} is empty or not a mapping`);
|
|
3911
|
-
const base =
|
|
3940
|
+
const base = dirname8(file);
|
|
3912
3941
|
const missing = new Missing();
|
|
3913
3942
|
rejectUnknownKeys(raw, /* @__PURE__ */ new Set(["ship", "routes"]), "top-level", file);
|
|
3914
3943
|
const shipRaw = raw.ship ?? {};
|
|
@@ -4275,7 +4304,7 @@ function locateDir(cfg, dir, commonDirOf) {
|
|
|
4275
4304
|
const direct = find(target);
|
|
4276
4305
|
if (direct) return direct;
|
|
4277
4306
|
const common = commonDirOf?.(target);
|
|
4278
|
-
return common ? find(
|
|
4307
|
+
return common ? find(dirname8(resolve2(target, common))) : void 0;
|
|
4279
4308
|
}
|
|
4280
4309
|
function findRoute(cfg, route2) {
|
|
4281
4310
|
if (!route2) {
|
|
@@ -4717,7 +4746,7 @@ function recoveredFailureHeadlines(o, route2) {
|
|
|
4717
4746
|
}
|
|
4718
4747
|
|
|
4719
4748
|
// src/install.ts
|
|
4720
|
-
import { dirname as
|
|
4749
|
+
import { dirname as dirname9, join as join18, extname } from "path";
|
|
4721
4750
|
import { homedir as homedir7, userInfo } from "os";
|
|
4722
4751
|
import { accessSync as accessSync2, constants as constants2, existsSync as existsSync16, mkdirSync as mkdirSync11, readdirSync as readdirSync3, readFileSync as readFileSync16, statSync as statSync5, writeFileSync as writeFileSync12, unlinkSync, realpathSync } from "fs";
|
|
4723
4752
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
@@ -4762,7 +4791,7 @@ function schedulerLogFor(crewLog, job) {
|
|
|
4762
4791
|
return `${stem}.${suffix}${ext || ".log"}`;
|
|
4763
4792
|
}
|
|
4764
4793
|
function pathFor(ship) {
|
|
4765
|
-
const nodeBinDir =
|
|
4794
|
+
const nodeBinDir = dirname9(process.execPath);
|
|
4766
4795
|
const parts = [nodeBinDir];
|
|
4767
4796
|
if (ship.extraPath) parts.push(ship.extraPath);
|
|
4768
4797
|
parts.push("/usr/bin", "/bin", "/usr/sbin", "/sbin");
|
|
@@ -4784,7 +4813,7 @@ function dockerPathProblem(ship, shellPath = process.env.PATH ?? "") {
|
|
|
4784
4813
|
const schedulerPath = pathFor(ship);
|
|
4785
4814
|
if (findOnPath("docker", schedulerPath)) return void 0;
|
|
4786
4815
|
const inShell = findOnPath("docker", shellPath);
|
|
4787
|
-
return inShell ? `\`docker\` is not on the scheduler PATH (${schedulerPath}) but is at ${inShell} in your shell; add ${
|
|
4816
|
+
return inShell ? `\`docker\` is not on the scheduler PATH (${schedulerPath}) but is at ${inShell} in your shell; add ${dirname9(inShell)} to ship.extraPath in crew.yaml and run \`crew install\`` : `\`docker\` is not on the scheduler PATH (${schedulerPath}) or your shell PATH; install Docker, then add its directory to ship.extraPath in crew.yaml and run \`crew install\``;
|
|
4788
4817
|
}
|
|
4789
4818
|
var USER_INSTALL = { root: false, user: "" };
|
|
4790
4819
|
function installContext(env = process.env) {
|
|
@@ -5079,7 +5108,7 @@ async function applyInstall(plan, crewHome, dryRun, log) {
|
|
|
5079
5108
|
}
|
|
5080
5109
|
const before = existsSync16(path) ? readFileSync16(path, "utf8") : null;
|
|
5081
5110
|
if (before !== plan.unitContent[path]) changed2 = true;
|
|
5082
|
-
mkdirSync11(
|
|
5111
|
+
mkdirSync11(dirname9(path), { recursive: true });
|
|
5083
5112
|
writeFileSync12(path, plan.unitContent[path]);
|
|
5084
5113
|
log.emit(`wrote ${path}`);
|
|
5085
5114
|
}
|
|
@@ -5308,7 +5337,7 @@ import {
|
|
|
5308
5337
|
readdirSync as readdirSync4,
|
|
5309
5338
|
rmSync as rmSync9
|
|
5310
5339
|
} from "fs";
|
|
5311
|
-
import { dirname as
|
|
5340
|
+
import { dirname as dirname10, basename as basename5, join as join19 } from "path";
|
|
5312
5341
|
var GitError = class extends Error {
|
|
5313
5342
|
};
|
|
5314
5343
|
function streamText(x) {
|
|
@@ -5688,7 +5717,7 @@ function recoverStrandedReleaseCheckouts(cwd) {
|
|
|
5688
5717
|
if (line.startsWith("worktree ")) path = line.slice("worktree ".length);
|
|
5689
5718
|
else if (line.startsWith("branch refs/heads/crew/release-") && path) {
|
|
5690
5719
|
gitOk(cwd, ["worktree", "remove", "--force", path]);
|
|
5691
|
-
const root =
|
|
5720
|
+
const root = dirname10(path);
|
|
5692
5721
|
if (basename5(root).startsWith("crew-release-")) rmSync9(root, { recursive: true, force: true });
|
|
5693
5722
|
}
|
|
5694
5723
|
}
|
|
@@ -5768,7 +5797,7 @@ function ensureRepoCheckout(dir, remote, opts = {}) {
|
|
|
5768
5797
|
`${dir} does not exist and this repo has no discovered remote to clone from \u2014 re-run \`crew connect\`, or check out the repository yourself and point \`repos:\` at it`
|
|
5769
5798
|
);
|
|
5770
5799
|
}
|
|
5771
|
-
mkdirSync12(
|
|
5800
|
+
mkdirSync12(dirname10(dir), { recursive: true });
|
|
5772
5801
|
const url = cloneUrlFor(remote, opts);
|
|
5773
5802
|
try {
|
|
5774
5803
|
execFileSync5("git", ["clone", url, dir], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
@@ -5793,7 +5822,7 @@ function sleepSync(ms3) {
|
|
|
5793
5822
|
}
|
|
5794
5823
|
function acquireCheckoutLock(dir, timeoutMs = 3e4) {
|
|
5795
5824
|
const lockPath = checkoutLockPath(dir);
|
|
5796
|
-
mkdirSync12(
|
|
5825
|
+
mkdirSync12(dirname10(lockPath), { recursive: true });
|
|
5797
5826
|
const deadline = Date.now() + timeoutMs;
|
|
5798
5827
|
for (; ; ) {
|
|
5799
5828
|
try {
|
|
@@ -6305,7 +6334,7 @@ import { createHash as createHash6 } from "crypto";
|
|
|
6305
6334
|
import { spawn as spawn5 } from "child_process";
|
|
6306
6335
|
import { execFileSync as execFileSync8 } from "child_process";
|
|
6307
6336
|
import { existsSync as existsSync30, mkdirSync as mkdirSync19, readFileSync as readFileSync27, renameSync as renameSync3, writeFileSync as writeFileSync20, rmSync as rmSync15 } from "fs";
|
|
6308
|
-
import { dirname as
|
|
6337
|
+
import { dirname as dirname15, join as join32 } from "path";
|
|
6309
6338
|
import { fileURLToPath } from "url";
|
|
6310
6339
|
import { tmpdir as tmpdir3 } from "os";
|
|
6311
6340
|
|
|
@@ -6330,7 +6359,7 @@ import { spawnSync as spawnSync6 } from "child_process";
|
|
|
6330
6359
|
import { readFileSync as readFileSync25, existsSync as existsSync26, statSync as statSync8, mkdirSync as mkdirSync18, writeFileSync as writeFileSync19, createWriteStream, openSync as openSync4, closeSync as closeSync4, readSync } from "fs";
|
|
6331
6360
|
import { StringDecoder } from "string_decoder";
|
|
6332
6361
|
import { finished } from "stream/promises";
|
|
6333
|
-
import { join as join29, dirname as
|
|
6362
|
+
import { join as join29, dirname as dirname14, basename as basename9 } from "path";
|
|
6334
6363
|
import { createHash as createHash4 } from "crypto";
|
|
6335
6364
|
|
|
6336
6365
|
// src/state.ts
|
|
@@ -7235,7 +7264,7 @@ function renderEnvironment(i) {
|
|
|
7235
7264
|
|
|
7236
7265
|
// src/intel-bridge.ts
|
|
7237
7266
|
import { existsSync as existsSync20, mkdirSync as mkdirSync14, readFileSync as readFileSync20, rmSync as rmSync11, writeFileSync as writeFileSync15 } from "fs";
|
|
7238
|
-
import { dirname as
|
|
7267
|
+
import { dirname as dirname11, join as join22 } from "path";
|
|
7239
7268
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
7240
7269
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
7241
7270
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -7255,7 +7284,7 @@ function intelDir(stateDir, route2, ticket) {
|
|
|
7255
7284
|
}
|
|
7256
7285
|
var attachFilePath = (stateDir, route2, ticket) => join22(intelDir(stateDir, route2, ticket), "url");
|
|
7257
7286
|
function writeAttachFile(file, url) {
|
|
7258
|
-
mkdirSync14(
|
|
7287
|
+
mkdirSync14(dirname11(file), { recursive: true });
|
|
7259
7288
|
writeFileSync15(file, `${url}
|
|
7260
7289
|
`);
|
|
7261
7290
|
}
|
|
@@ -9300,7 +9329,7 @@ function holdWarnings(tickets, ships, contract, humanHolds, now = Date.now()) {
|
|
|
9300
9329
|
|
|
9301
9330
|
// src/run-worktree.ts
|
|
9302
9331
|
import { existsSync as existsSync22 } from "fs";
|
|
9303
|
-
import { dirname as
|
|
9332
|
+
import { dirname as dirname12, join as join24 } from "path";
|
|
9304
9333
|
var describeRunWorktreePlan = (p) => {
|
|
9305
9334
|
switch (p.action) {
|
|
9306
9335
|
case "cut-remote":
|
|
@@ -9357,7 +9386,7 @@ function planRunWorktree(dir, cfg, t, role, opts = {}) {
|
|
|
9357
9386
|
if (countCommits(existing.path, `${baseRef}..HEAD`) > 0) return { action: "leave-unpushed", path: existing.path, branch };
|
|
9358
9387
|
return { action: "recut", path: existing.path, branch, base: baseRef };
|
|
9359
9388
|
}
|
|
9360
|
-
const path = join24(
|
|
9389
|
+
const path = join24(dirname12(dir), worktreeForTicket(dir, cfg, t, role));
|
|
9361
9390
|
if (located?.where === "remote" || located && hasRemote && remoteBranchExists(dir, remote, located.branch)) {
|
|
9362
9391
|
return { action: "cut-remote", path, branch: located.branch };
|
|
9363
9392
|
}
|
|
@@ -10631,7 +10660,7 @@ function skillMarkerWarnings(promptsDir, personaPrompts) {
|
|
|
10631
10660
|
import { spawn as spawn3, execFile, execFileSync as execFileSync6 } from "child_process";
|
|
10632
10661
|
import { mkdtempSync, mkdirSync as mkdirSync17, writeFileSync as writeFileSync18, rmSync as rmSync14 } from "fs";
|
|
10633
10662
|
import { tmpdir as tmpdir2 } from "os";
|
|
10634
|
-
import { basename as basename8, dirname as
|
|
10663
|
+
import { basename as basename8, dirname as dirname13, join as join28 } from "path";
|
|
10635
10664
|
import { promisify } from "util";
|
|
10636
10665
|
|
|
10637
10666
|
// src/run-limit.ts
|
|
@@ -10760,7 +10789,7 @@ var SandboxRunner = class {
|
|
|
10760
10789
|
throw new Error(`cannot generate the sandbox policy: ${e.message}`);
|
|
10761
10790
|
}
|
|
10762
10791
|
policyFile = policyPathFor(plan.streamPath);
|
|
10763
|
-
mkdirSync17(
|
|
10792
|
+
mkdirSync17(dirname13(policyFile), { recursive: true });
|
|
10764
10793
|
writeFileSync18(policyFile, generated.yaml, { mode: 384 });
|
|
10765
10794
|
}
|
|
10766
10795
|
const create2 = ["sandbox", "create", "--name", name, "--detach"];
|
|
@@ -11022,7 +11051,7 @@ function codeBridgeFor(o, harness) {
|
|
|
11022
11051
|
"--clone",
|
|
11023
11052
|
o.ship.sandbox?.workDir ?? DEFAULT_SANDBOX_WORKDIR,
|
|
11024
11053
|
"--state-dir",
|
|
11025
|
-
|
|
11054
|
+
dirname14(SANDBOX_INTEL_DIR),
|
|
11026
11055
|
"--ticket",
|
|
11027
11056
|
number,
|
|
11028
11057
|
...seed ? ["--seed-cache", seed] : []
|
|
@@ -11036,7 +11065,7 @@ function codeBridgeFor(o, harness) {
|
|
|
11036
11065
|
bridge.files = [{ path: bridge.settingsFile, content: text2 }];
|
|
11037
11066
|
} else {
|
|
11038
11067
|
const file = join29(intelDir(o.stateDir, o.route.route, number), "gemini-settings.json");
|
|
11039
|
-
mkdirSync18(
|
|
11068
|
+
mkdirSync18(dirname14(file), { recursive: true });
|
|
11040
11069
|
writeFileSync19(file, text2);
|
|
11041
11070
|
bridge.settingsFile = file;
|
|
11042
11071
|
}
|
|
@@ -11259,7 +11288,7 @@ async function killForDeadline(kill, pid, emit, role, ticket, spawnedAt, limitMi
|
|
|
11259
11288
|
var withoutKey = ({ apiKey: _apiKey, ...rest }) => rest;
|
|
11260
11289
|
function openSink(path) {
|
|
11261
11290
|
try {
|
|
11262
|
-
mkdirSync18(
|
|
11291
|
+
mkdirSync18(dirname14(path), { recursive: true });
|
|
11263
11292
|
return createWriteStream(path, { flags: "a" });
|
|
11264
11293
|
} catch {
|
|
11265
11294
|
return void 0;
|
|
@@ -11611,7 +11640,7 @@ function spawnAgent(plan, emit, hintMoved) {
|
|
|
11611
11640
|
const id = identityOf(plan, adapter.harness);
|
|
11612
11641
|
let streamFd;
|
|
11613
11642
|
try {
|
|
11614
|
-
mkdirSync18(
|
|
11643
|
+
mkdirSync18(dirname14(plan.streamPath), { recursive: true });
|
|
11615
11644
|
streamFd = openSync4(plan.streamPath, "a");
|
|
11616
11645
|
} catch (e) {
|
|
11617
11646
|
void endSink(eventsSink);
|
|
@@ -12830,7 +12859,7 @@ var SANDBOX_UID = 1e3;
|
|
|
12830
12859
|
var CREW_PREFIX = "/opt/crew";
|
|
12831
12860
|
var SANDBOX_BRIDGE_PATH = `${CREW_PREFIX}/bin/intel-bridge`;
|
|
12832
12861
|
function readBridgeBundle() {
|
|
12833
|
-
const here =
|
|
12862
|
+
const here = dirname15(fileURLToPath(import.meta.url));
|
|
12834
12863
|
for (const p of [join32(here, "sandbox-intel-bridge.cjs"), join32(here, "..", "dist", "sandbox-intel-bridge.cjs")]) {
|
|
12835
12864
|
if (existsSync30(p)) return readFileSync27(p, "utf8");
|
|
12836
12865
|
}
|
|
@@ -13055,7 +13084,7 @@ async function buildSandboxImage(plan, deps) {
|
|
|
13055
13084
|
try {
|
|
13056
13085
|
writeFileSync20(join32(ctx, "Dockerfile"), layer.dockerfile);
|
|
13057
13086
|
for (const [name, content] of Object.entries(layer.files)) {
|
|
13058
|
-
mkdirSync19(
|
|
13087
|
+
mkdirSync19(dirname15(join32(ctx, name)), { recursive: true });
|
|
13059
13088
|
writeFileSync20(join32(ctx, name), content);
|
|
13060
13089
|
}
|
|
13061
13090
|
const code = await deps.run(["build", "--tag", layer.tag, "--file", join32(ctx, "Dockerfile"), ctx], logPath);
|
|
@@ -13468,7 +13497,7 @@ function doctorSelftestLines(stored, toolchains) {
|
|
|
13468
13497
|
}
|
|
13469
13498
|
|
|
13470
13499
|
// src/cli.ts
|
|
13471
|
-
import { resolve as resolve7, dirname as
|
|
13500
|
+
import { resolve as resolve7, dirname as dirname34, join as join55, basename as basename16 } from "path";
|
|
13472
13501
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
13473
13502
|
import { hostname as hostname4, homedir as homedir11 } from "os";
|
|
13474
13503
|
import { spawnSync as spawnSync11 } from "child_process";
|
|
@@ -13667,7 +13696,7 @@ function rosterMarkdown(roster, meId) {
|
|
|
13667
13696
|
|
|
13668
13697
|
// src/connect-resume.ts
|
|
13669
13698
|
import { mkdirSync as mkdirSync21, readFileSync as readFileSync29, rmSync as rmSync17, writeFileSync as writeFileSync22 } from "fs";
|
|
13670
|
-
import { dirname as
|
|
13699
|
+
import { dirname as dirname16, join as join34 } from "path";
|
|
13671
13700
|
function lastSessionFile(stateDir) {
|
|
13672
13701
|
return join34(stateDir, "connect-session.json");
|
|
13673
13702
|
}
|
|
@@ -13687,7 +13716,7 @@ function readPointers(stateDir) {
|
|
|
13687
13716
|
}
|
|
13688
13717
|
function writePointers(stateDir, pointers) {
|
|
13689
13718
|
const file = lastSessionFile(stateDir);
|
|
13690
|
-
mkdirSync21(
|
|
13719
|
+
mkdirSync21(dirname16(file), { recursive: true });
|
|
13691
13720
|
writeFileSync22(file, `${JSON.stringify(pointers, null, 2)}
|
|
13692
13721
|
`, { mode: 384 });
|
|
13693
13722
|
}
|
|
@@ -13774,7 +13803,7 @@ async function signOutSessions(o) {
|
|
|
13774
13803
|
|
|
13775
13804
|
// src/reset.ts
|
|
13776
13805
|
import { existsSync as existsSync32, mkdirSync as mkdirSync22, readFileSync as readFileSync30, readdirSync as readdirSync12, rmSync as rmSync18, statSync as statSync10, writeFileSync as writeFileSync23 } from "fs";
|
|
13777
|
-
import { dirname as
|
|
13806
|
+
import { dirname as dirname17, join as join35 } from "path";
|
|
13778
13807
|
import { hostFromUrl as hostFromUrl3 } from "@tablation/client";
|
|
13779
13808
|
function clonedCheckoutsFile(stateDir) {
|
|
13780
13809
|
return join35(stateDir, "cloned-checkouts.json");
|
|
@@ -13791,7 +13820,7 @@ function recordClonedCheckout(stateDir, dir) {
|
|
|
13791
13820
|
const known = readClonedCheckouts(stateDir);
|
|
13792
13821
|
if (known.includes(dir)) return;
|
|
13793
13822
|
const file = clonedCheckoutsFile(stateDir);
|
|
13794
|
-
mkdirSync22(
|
|
13823
|
+
mkdirSync22(dirname17(file), { recursive: true });
|
|
13795
13824
|
writeFileSync23(file, `${JSON.stringify([...known, dir], null, 2)}
|
|
13796
13825
|
`);
|
|
13797
13826
|
}
|
|
@@ -13974,7 +14003,7 @@ async function runDeprovision(o, fx, deps) {
|
|
|
13974
14003
|
// src/pool-member.ts
|
|
13975
14004
|
import { mkdirSync as mkdirSync23, readFileSync as readFileSync31, renameSync as renameSync4, writeFileSync as writeFileSync24 } from "fs";
|
|
13976
14005
|
import { homedir as homedir8 } from "os";
|
|
13977
|
-
import { dirname as
|
|
14006
|
+
import { dirname as dirname18, join as join36 } from "path";
|
|
13978
14007
|
var POOL_EXIT = { ok: 0, failed: 1, credential: 2 };
|
|
13979
14008
|
function backoffMs(attempt) {
|
|
13980
14009
|
return Math.min(6e4, 5e3 * 2 ** Math.max(0, attempt));
|
|
@@ -14218,7 +14247,7 @@ function fileMemberStore(dir) {
|
|
|
14218
14247
|
}
|
|
14219
14248
|
},
|
|
14220
14249
|
write(f) {
|
|
14221
|
-
mkdirSync23(
|
|
14250
|
+
mkdirSync23(dirname18(file), { recursive: true, mode: 448 });
|
|
14222
14251
|
const tmp = `${file}.tmp`;
|
|
14223
14252
|
writeFileSync24(tmp, `${JSON.stringify(f)}
|
|
14224
14253
|
`, { mode: 384 });
|
|
@@ -14279,7 +14308,7 @@ import { hostname as hostname3 } from "os";
|
|
|
14279
14308
|
import { execFileSync as execFileSync10 } from "child_process";
|
|
14280
14309
|
import { createHash as createHash7 } from "crypto";
|
|
14281
14310
|
import { existsSync as existsSync33, mkdirSync as mkdirSync24, readFileSync as readFileSync32, writeFileSync as writeFileSync25 } from "fs";
|
|
14282
|
-
import { dirname as
|
|
14311
|
+
import { dirname as dirname19, join as join37 } from "path";
|
|
14283
14312
|
function machineIdPathFor(stateDir) {
|
|
14284
14313
|
return join37(stateDir, "machine-id");
|
|
14285
14314
|
}
|
|
@@ -14313,7 +14342,7 @@ function ensureMachineId(stateDir, opts = {}) {
|
|
|
14313
14342
|
const raw = (opts.read ?? readRawMachineId)();
|
|
14314
14343
|
if (!raw) return void 0;
|
|
14315
14344
|
const hashed = sha256(raw);
|
|
14316
|
-
mkdirSync24(
|
|
14345
|
+
mkdirSync24(dirname19(path), { recursive: true });
|
|
14317
14346
|
writeFileSync25(path, `${hashed}
|
|
14318
14347
|
`, { mode: 384 });
|
|
14319
14348
|
return hashed;
|
|
@@ -16594,7 +16623,7 @@ async function resolveOne(tracker, t, seat, approvedStatus, buildingStatus, affi
|
|
|
16594
16623
|
|
|
16595
16624
|
// src/repo-refresh.ts
|
|
16596
16625
|
import { existsSync as existsSync37, mkdirSync as mkdirSync26, readFileSync as readFileSync35, writeFileSync as writeFileSync29 } from "fs";
|
|
16597
|
-
import { dirname as
|
|
16626
|
+
import { dirname as dirname21 } from "path";
|
|
16598
16627
|
var REFRESH_COOLDOWN_MS = 2 * 6e4;
|
|
16599
16628
|
var UNSERVABLE_PASSES_BEFORE_ATTENTION = 3;
|
|
16600
16629
|
var lastAsked = /* @__PURE__ */ new Map();
|
|
@@ -16626,7 +16655,7 @@ function persistRepoRows(stateDir, routeName, rows) {
|
|
|
16626
16655
|
if (!existsSync37(path)) return;
|
|
16627
16656
|
const raw = JSON.parse(readFileSync35(path, "utf8"));
|
|
16628
16657
|
applyRepoRows(raw, rows);
|
|
16629
|
-
mkdirSync26(
|
|
16658
|
+
mkdirSync26(dirname21(path), { recursive: true });
|
|
16630
16659
|
writeFileSync29(path, `${JSON.stringify(raw, null, 2)}
|
|
16631
16660
|
`);
|
|
16632
16661
|
}
|
|
@@ -17077,7 +17106,7 @@ Ship ${shipName2} found: ${problem}. The release refuses to squash a ref nobody
|
|
|
17077
17106
|
var localRefSkipReported = (ticket, problem, events) => events.some((e) => e.record_id === ticket.id && e.event_type === "local_ref_skip" && (e.message ?? "").includes(problem));
|
|
17078
17107
|
|
|
17079
17108
|
// src/connect-wizard.ts
|
|
17080
|
-
import { delimiter, dirname as
|
|
17109
|
+
import { delimiter, dirname as dirname22, join as join41 } from "path";
|
|
17081
17110
|
import { accessSync as accessSync3, constants as constants3, existsSync as existsSync38, mkdirSync as mkdirSync27, writeFileSync as writeFileSync30 } from "fs";
|
|
17082
17111
|
import { stringify as stringify3 } from "yaml";
|
|
17083
17112
|
var HOST_PASSENGERS_DOCS_URL = "https://crew.tablation.dev/host-passengers";
|
|
@@ -17126,9 +17155,9 @@ async function runWizard(p, env) {
|
|
|
17126
17155
|
if (entered && isExec(entered)) agentBin = entered;
|
|
17127
17156
|
else p.say(entered ? `${entered} is not an executable file.` : "A path is required.");
|
|
17128
17157
|
}
|
|
17129
|
-
const nodeDir =
|
|
17158
|
+
const nodeDir = dirname22(env.nodePath);
|
|
17130
17159
|
const pnpmPath = findOnPath2("pnpm", env.pathEnv, isExec);
|
|
17131
|
-
const baseDirs = [nodeDir, pnpmPath ?
|
|
17160
|
+
const baseDirs = [nodeDir, pnpmPath ? dirname22(pnpmPath) : void 0];
|
|
17132
17161
|
p.say(
|
|
17133
17162
|
`
|
|
17134
17163
|
Host Passengers lets this machine run the agent sessions that other people's
|
|
@@ -17139,7 +17168,7 @@ Tablation workspaces ask for, in a container. More: ${HOST_PASSENGERS_DOCS_URL}`
|
|
|
17139
17168
|
p.say("Docker is not available here, so nothing will be hosted until it is. Your answer is recorded anyway.");
|
|
17140
17169
|
}
|
|
17141
17170
|
const dockerPath = hostPassengers ? findOnPath2("docker", env.pathEnv, isExec) : void 0;
|
|
17142
|
-
const extraPath = deriveExtraPath([...baseDirs, dockerPath ?
|
|
17171
|
+
const extraPath = deriveExtraPath([...baseDirs, dockerPath ? dirname22(dockerPath) : void 0]);
|
|
17143
17172
|
if (extraPath) {
|
|
17144
17173
|
p.say(`Hooks will get ${extraPath} on their PATH (where node, pnpm${dockerPath ? " and docker" : ""} live).`);
|
|
17145
17174
|
}
|
|
@@ -17161,7 +17190,7 @@ routes:
|
|
|
17161
17190
|
${routeBlock}`;
|
|
17162
17191
|
}
|
|
17163
17192
|
function writeNewConfig(path, text2) {
|
|
17164
|
-
mkdirSync27(
|
|
17193
|
+
mkdirSync27(dirname22(path), { recursive: true });
|
|
17165
17194
|
try {
|
|
17166
17195
|
writeFileSync30(path, text2, { mode: 384, flag: "wx" });
|
|
17167
17196
|
return true;
|
|
@@ -17197,7 +17226,7 @@ Wrote ${o.configPath}.
|
|
|
17197
17226
|
// src/connect-json.ts
|
|
17198
17227
|
import { accessSync as accessSync4, constants as constants4 } from "fs";
|
|
17199
17228
|
import { homedir as homedir10 } from "os";
|
|
17200
|
-
import { dirname as
|
|
17229
|
+
import { dirname as dirname23, join as join42 } from "path";
|
|
17201
17230
|
import { delimiter as delimiter2 } from "path";
|
|
17202
17231
|
var CHOICE_EXIT_CODE = 3;
|
|
17203
17232
|
function createEmitter(json2, write) {
|
|
@@ -17263,7 +17292,7 @@ function flagWizardAnswers(f, env) {
|
|
|
17263
17292
|
const agentBin = f.agentBin ?? found?.bin;
|
|
17264
17293
|
const pnpmPath = findOnPath2("pnpm", env.pathEnv, isExec);
|
|
17265
17294
|
const dockerPath = f.hostPassengers ? findOnPath2("docker", env.pathEnv, isExec) : void 0;
|
|
17266
|
-
const extraPath = f.extraPath ?? deriveExtraPath([
|
|
17295
|
+
const extraPath = f.extraPath ?? deriveExtraPath([dirname23(env.nodePath), pnpmPath ? dirname23(pnpmPath) : void 0, dockerPath ? dirname23(dockerPath) : void 0]);
|
|
17267
17296
|
return {
|
|
17268
17297
|
answers: {
|
|
17269
17298
|
name: f.shipName?.trim() || env.hostname,
|
|
@@ -17278,7 +17307,7 @@ function flagWizardAnswers(f, env) {
|
|
|
17278
17307
|
|
|
17279
17308
|
// src/release-run.ts
|
|
17280
17309
|
import { readFileSync as readFileSync36, writeFileSync as writeFileSync31, existsSync as existsSync39, copyFileSync, mkdirSync as mkdirSync28, mkdtempSync as mkdtempSync3, rmSync as rmSync19 } from "fs";
|
|
17281
|
-
import { dirname as
|
|
17310
|
+
import { dirname as dirname24, join as join43 } from "path";
|
|
17282
17311
|
import { tmpdir as tmpdir5 } from "os";
|
|
17283
17312
|
|
|
17284
17313
|
// src/release.ts
|
|
@@ -18025,7 +18054,13 @@ async function bump(o, size) {
|
|
|
18025
18054
|
o.emit.error(`no ${o.repo.release.versionFiles[0]} to read a version from`);
|
|
18026
18055
|
return null;
|
|
18027
18056
|
}
|
|
18028
|
-
const
|
|
18057
|
+
const firstText = readFileSync36(first, "utf8");
|
|
18058
|
+
const problem = versionFileProblem(o.repo.release.versionFiles[0], firstText);
|
|
18059
|
+
if (problem) {
|
|
18060
|
+
o.emit.error(problem);
|
|
18061
|
+
return null;
|
|
18062
|
+
}
|
|
18063
|
+
const current = JSON.parse(firstText).version;
|
|
18029
18064
|
if (!current) {
|
|
18030
18065
|
o.emit.error(`no version field in ${o.repo.release.versionFiles[0]}`);
|
|
18031
18066
|
return null;
|
|
@@ -18164,7 +18199,7 @@ function openReleaseCheckout(o) {
|
|
|
18164
18199
|
for (const f of o.repo.worktrees.copy) {
|
|
18165
18200
|
const src = join43(o.cwd, f);
|
|
18166
18201
|
if (!existsSync39(src)) continue;
|
|
18167
|
-
mkdirSync28(
|
|
18202
|
+
mkdirSync28(dirname24(join43(dir, f)), { recursive: true });
|
|
18168
18203
|
copyFileSync(src, join43(dir, f));
|
|
18169
18204
|
}
|
|
18170
18205
|
return { dir, branch, close };
|
|
@@ -18493,6 +18528,20 @@ async function mergeAndRelease(o, decision, fresh, releaseBranch, isolated = fal
|
|
|
18493
18528
|
}
|
|
18494
18529
|
merged.push(c);
|
|
18495
18530
|
}
|
|
18531
|
+
if (applied > 0 && !o.dryRun && !o.mergeOnly && o.reloadRepo) {
|
|
18532
|
+
const changed2 = gitOk(o.cwd, ["diff", "--name-only", preMerge, "HEAD", "--", ...REPO_CONFIG_FILENAMES]);
|
|
18533
|
+
if (changed2) {
|
|
18534
|
+
try {
|
|
18535
|
+
const next = o.reloadRepo(o.cwd);
|
|
18536
|
+
if (next) {
|
|
18537
|
+
o = { ...o, repo: next };
|
|
18538
|
+
o.emit.emit(`${changed2.split("\n")[0]} changed in this release \u2014 continuing under the merged contract`);
|
|
18539
|
+
}
|
|
18540
|
+
} catch (e) {
|
|
18541
|
+
o.emit.warn(`could not re-read the merged repo config: ${e.message}; releasing under the earlier one`);
|
|
18542
|
+
}
|
|
18543
|
+
}
|
|
18544
|
+
}
|
|
18496
18545
|
if (o.mergeOnly) {
|
|
18497
18546
|
o.emit.emit(`merge only: ${merged.length} branch(es) merged, not releasing`);
|
|
18498
18547
|
return { merged, conflicts, unbuildable, deployed: false, stopped: "merge only", decision };
|
|
@@ -18517,7 +18566,8 @@ async function mergeAndRelease(o, decision, fresh, releaseBranch, isolated = fal
|
|
|
18517
18566
|
o.emit.emit("nothing to release");
|
|
18518
18567
|
return { merged, conflicts, unbuildable, deployed: false, stopped: "nothing to release", decision };
|
|
18519
18568
|
}
|
|
18520
|
-
|
|
18569
|
+
const waiting = decision.merges.some((c) => c.skipReason === "already-merged" && c.mergedSha);
|
|
18570
|
+
if (merged.length === 0 && decision.unseeded && !waiting && !o.force) {
|
|
18521
18571
|
o.emit.emit(
|
|
18522
18572
|
`nothing merged, and ${o.repo.branch.base} carries no release tag to compare against \u2014 nothing to release`
|
|
18523
18573
|
);
|
|
@@ -19489,7 +19539,7 @@ function nextRoles(decision, ran) {
|
|
|
19489
19539
|
|
|
19490
19540
|
// src/ship-name.ts
|
|
19491
19541
|
import { existsSync as existsSync41, mkdirSync as mkdirSync29, readFileSync as readFileSync37, renameSync as renameSync5, writeFileSync as writeFileSync32 } from "fs";
|
|
19492
|
-
import { dirname as
|
|
19542
|
+
import { dirname as dirname25 } from "path";
|
|
19493
19543
|
import { parseDocument as parseDocument5 } from "yaml";
|
|
19494
19544
|
var ShipNameError = class extends Error {
|
|
19495
19545
|
};
|
|
@@ -19568,7 +19618,7 @@ function writeSyncedName(resolvedFile, name) {
|
|
|
19568
19618
|
}
|
|
19569
19619
|
if (raw.shipName === name) return;
|
|
19570
19620
|
raw.shipName = name;
|
|
19571
|
-
mkdirSync29(
|
|
19621
|
+
mkdirSync29(dirname25(resolvedFile), { recursive: true });
|
|
19572
19622
|
const tmp = `${resolvedFile}.tmp${process.pid}`;
|
|
19573
19623
|
writeFileSync32(tmp, `${JSON.stringify(raw, null, 2)}
|
|
19574
19624
|
`);
|
|
@@ -20262,7 +20312,7 @@ function describeCapability(i) {
|
|
|
20262
20312
|
|
|
20263
20313
|
// src/agents-sync-run.ts
|
|
20264
20314
|
import { existsSync as existsSync42, mkdirSync as mkdirSync30, readFileSync as readFileSync38, writeFileSync as writeFileSync33 } from "fs";
|
|
20265
|
-
import { dirname as
|
|
20315
|
+
import { dirname as dirname26 } from "path";
|
|
20266
20316
|
async function runAgentsSync(target, o) {
|
|
20267
20317
|
const dryRun = o.dryRun ?? false;
|
|
20268
20318
|
const force = o.force ?? false;
|
|
@@ -20299,7 +20349,7 @@ async function runAgentsSync(target, o) {
|
|
|
20299
20349
|
raw.agentPersonas = personaResult.agentPersonas;
|
|
20300
20350
|
if (skillResult) raw.agentSkills = skillResult.agentSkills;
|
|
20301
20351
|
if (personaResult.releaseAgentId) raw.releaseAgentId = personaResult.releaseAgentId;
|
|
20302
|
-
mkdirSync30(
|
|
20352
|
+
mkdirSync30(dirname26(resolvedPath), { recursive: true });
|
|
20303
20353
|
writeFileSync33(resolvedPath, `${JSON.stringify(raw, null, 2)}
|
|
20304
20354
|
`);
|
|
20305
20355
|
if (target.resolved) {
|
|
@@ -20922,7 +20972,7 @@ ${run3.err}` });
|
|
|
20922
20972
|
}
|
|
20923
20973
|
|
|
20924
20974
|
// src/sample-ticket.ts
|
|
20925
|
-
import { basename as basename12, dirname as
|
|
20975
|
+
import { basename as basename12, dirname as dirname27, join as join44 } from "path";
|
|
20926
20976
|
var SAMPLE_REPO = "crew-sample";
|
|
20927
20977
|
var SAMPLE_REMOTE = `local/${SAMPLE_REPO}`;
|
|
20928
20978
|
var SAMPLE_MARKER = "sample: true";
|
|
@@ -20945,7 +20995,7 @@ has something safe to work on: its test and build hooks always pass, it has no
|
|
|
20945
20995
|
remote, and \`crew sample-ticket --remove\` deletes it.
|
|
20946
20996
|
`;
|
|
20947
20997
|
function sampleDir(existing, reposBase, workspace) {
|
|
20948
|
-
if (existing.length > 0) return join44(
|
|
20998
|
+
if (existing.length > 0) return join44(dirname27(existing[0]), SAMPLE_REPO);
|
|
20949
20999
|
return join44(reposBase, workspace, SAMPLE_REPO);
|
|
20950
21000
|
}
|
|
20951
21001
|
var SAMPLE_TITLE = "Sample: add a documented `greet` function with a test";
|
|
@@ -20991,7 +21041,7 @@ function planSampleTicket(i) {
|
|
|
20991
21041
|
|
|
20992
21042
|
// src/worktree-sweep.ts
|
|
20993
21043
|
import { existsSync as existsSync43, readFileSync as readFileSync40, readdirSync as readdirSync14 } from "fs";
|
|
20994
|
-
import { basename as basename13, dirname as
|
|
21044
|
+
import { basename as basename13, dirname as dirname28, join as join45, resolve as resolve5 } from "path";
|
|
20995
21045
|
function planWorktreeSweep(target, tickets, contract) {
|
|
20996
21046
|
const terminal = new Set(contract.statuses.resolved.filter((s) => s !== contract.statuses.verified));
|
|
20997
21047
|
const verified = contract.statuses.verified;
|
|
@@ -21055,7 +21105,7 @@ function worktreeTicketNumbers(target) {
|
|
|
21055
21105
|
return [...nums];
|
|
21056
21106
|
}
|
|
21057
21107
|
function siblingWorktreeDirs(target) {
|
|
21058
|
-
const parent =
|
|
21108
|
+
const parent = dirname28(target.dir.replace(/[/\\]+$/, ""));
|
|
21059
21109
|
const stem = `${basename13(target.dir.replace(/[/\\]+$/, ""))}-`;
|
|
21060
21110
|
const registered = new Set(worktrees(target.dir).map((w) => resolve5(w.path)));
|
|
21061
21111
|
let names;
|
|
@@ -21907,7 +21957,7 @@ import { dirname as dirOf2, resolve as resolvePath } from "path";
|
|
|
21907
21957
|
// src/ssh-keys.ts
|
|
21908
21958
|
import { execFileSync as execFileSync13 } from "child_process";
|
|
21909
21959
|
import { existsSync as existsSync46, mkdirSync as mkdirSync32, readFileSync as readFileSync42, chmodSync as chmodSync3 } from "fs";
|
|
21910
|
-
import { dirname as
|
|
21960
|
+
import { dirname as dirname29, join as join49 } from "path";
|
|
21911
21961
|
var SshKeyError = class extends Error {
|
|
21912
21962
|
};
|
|
21913
21963
|
function shipSshKeyPathFor(stateDir) {
|
|
@@ -21917,7 +21967,7 @@ function ensureShipSshKeypair(stateDir) {
|
|
|
21917
21967
|
const privateKeyPath = shipSshKeyPathFor(stateDir);
|
|
21918
21968
|
const publicKeyPath = `${privateKeyPath}.pub`;
|
|
21919
21969
|
if (!existsSync46(privateKeyPath)) {
|
|
21920
|
-
mkdirSync32(
|
|
21970
|
+
mkdirSync32(dirname29(privateKeyPath), { recursive: true });
|
|
21921
21971
|
try {
|
|
21922
21972
|
execFileSync13("ssh-keygen", [
|
|
21923
21973
|
"-t",
|
|
@@ -22109,7 +22159,7 @@ import { join as join50 } from "path";
|
|
|
22109
22159
|
|
|
22110
22160
|
// src/passenger-mirror.ts
|
|
22111
22161
|
import { mkdirSync as mkdirSync33 } from "fs";
|
|
22112
|
-
import { dirname as
|
|
22162
|
+
import { dirname as dirname30 } from "path";
|
|
22113
22163
|
function mirrorRepoOf(spec) {
|
|
22114
22164
|
const fromOrigin = spec.originUrl ? parseRemote(spec.originUrl) : null;
|
|
22115
22165
|
if (fromOrigin) return fromOrigin;
|
|
@@ -22127,7 +22177,7 @@ async function materializeMirrorCheckouts(specs, cacheFor = (s) => new SandboxCa
|
|
|
22127
22177
|
continue;
|
|
22128
22178
|
}
|
|
22129
22179
|
try {
|
|
22130
|
-
const parent =
|
|
22180
|
+
const parent = dirname30(spec.dir);
|
|
22131
22181
|
mkdirSync33(parent, { recursive: true });
|
|
22132
22182
|
mkdirSync33(spec.dir, { recursive: true });
|
|
22133
22183
|
const r = await cacheFor(spec).materialize(repo, spec.base, parent, spec.name);
|
|
@@ -22333,7 +22383,7 @@ import { createServer, request as httpRequest } from "http";
|
|
|
22333
22383
|
import { request as httpsRequest } from "https";
|
|
22334
22384
|
import { connect as netConnect } from "net";
|
|
22335
22385
|
import { connect as tlsConnect } from "tls";
|
|
22336
|
-
import { dirname as
|
|
22386
|
+
import { dirname as dirname31, isAbsolute as isAbsolute4 } from "path";
|
|
22337
22387
|
import { brotliDecompressSync, gunzipSync, inflateSync } from "zlib";
|
|
22338
22388
|
|
|
22339
22389
|
// src/periscope-inspector.ts
|
|
@@ -22447,7 +22497,7 @@ function parsePointedBody(raw) {
|
|
|
22447
22497
|
return entry;
|
|
22448
22498
|
}
|
|
22449
22499
|
function appendPointed(file, entry, now = /* @__PURE__ */ new Date()) {
|
|
22450
|
-
mkdirSync35(
|
|
22500
|
+
mkdirSync35(dirname31(file), { recursive: true });
|
|
22451
22501
|
appendFileSync3(file, `${JSON.stringify({ ...entry, at: now.toISOString() })}
|
|
22452
22502
|
`);
|
|
22453
22503
|
}
|
|
@@ -23465,7 +23515,7 @@ import {
|
|
|
23465
23515
|
} from "fs";
|
|
23466
23516
|
import { createConnection } from "net";
|
|
23467
23517
|
import { createServer as createServer2 } from "http";
|
|
23468
|
-
import { basename as basename14, dirname as
|
|
23518
|
+
import { basename as basename14, dirname as dirname32, join as join52 } from "path";
|
|
23469
23519
|
import { execFile as execFile3, spawn as spawn12 } from "child_process";
|
|
23470
23520
|
|
|
23471
23521
|
// src/periscope-control.ts
|
|
@@ -23781,7 +23831,7 @@ function candidates(live, rotated) {
|
|
|
23781
23831
|
const out = [live];
|
|
23782
23832
|
if (!rotated) return out;
|
|
23783
23833
|
try {
|
|
23784
|
-
for (const n of readdirSync18(
|
|
23834
|
+
for (const n of readdirSync18(dirname32(live))) if (ROTATED_EVENTS_RE.test(n)) out.push(join52(dirname32(live), n));
|
|
23785
23835
|
} catch {
|
|
23786
23836
|
}
|
|
23787
23837
|
return out;
|
|
@@ -23941,7 +23991,7 @@ async function tailReply(path, q2, rotated, abort) {
|
|
|
23941
23991
|
const deadline = Date.now() + Math.min(wait, MAX_WAIT_SECONDS) * 1e3;
|
|
23942
23992
|
let r = readTail(path, { after, tail: tail3, rotated });
|
|
23943
23993
|
while (after && !r.lines.length && !r.reset && Date.now() < deadline && !abort.aborted) {
|
|
23944
|
-
await waitForChange(
|
|
23994
|
+
await waitForChange(dirname32(path), deadline - Date.now(), abort);
|
|
23945
23995
|
r = readTail(path, { after: r.cursor, rotated });
|
|
23946
23996
|
}
|
|
23947
23997
|
return reply2(200, r);
|
|
@@ -24131,7 +24181,7 @@ function crewJson(args, timeoutMs = 6e4) {
|
|
|
24131
24181
|
|
|
24132
24182
|
// src/periscope-mcp.ts
|
|
24133
24183
|
import { lstat, mkdir, readdir, readFile, readlink, realpath, rm, stat, writeFile } from "fs/promises";
|
|
24134
|
-
import { basename as basename15, dirname as
|
|
24184
|
+
import { basename as basename15, dirname as dirname33, isAbsolute as isAbsolute5, join as join54, relative as relative2, resolve as resolve6, sep } from "path";
|
|
24135
24185
|
import { z } from "zod";
|
|
24136
24186
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
24137
24187
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
@@ -24269,10 +24319,10 @@ async function realAncestor(p) {
|
|
|
24269
24319
|
}
|
|
24270
24320
|
if (isLink) {
|
|
24271
24321
|
if (++hops > 40) throw new PathRefusal(`too many symbolic links resolving ${p}`);
|
|
24272
|
-
cur = resolve6(
|
|
24322
|
+
cur = resolve6(dirname33(cur), await readlink(cur));
|
|
24273
24323
|
continue;
|
|
24274
24324
|
}
|
|
24275
|
-
const parent =
|
|
24325
|
+
const parent = dirname33(cur);
|
|
24276
24326
|
if (parent === cur) throw new PathRefusal(`cannot resolve ${p}`);
|
|
24277
24327
|
tail3.push(basename15(cur));
|
|
24278
24328
|
cur = parent;
|
|
@@ -24383,7 +24433,7 @@ function createPeriscopeMcpServer(d, sc) {
|
|
|
24383
24433
|
if (Buffer.byteLength(content) > MAX_WRITE_BYTES) return text(`content exceeds ${MAX_WRITE_BYTES} bytes`, true);
|
|
24384
24434
|
const abs = await inTree(path);
|
|
24385
24435
|
if (abs === await realpath(root)) return text("path must name a file", true);
|
|
24386
|
-
await mkdir(
|
|
24436
|
+
await mkdir(dirname33(abs), { recursive: true });
|
|
24387
24437
|
await inTree(path);
|
|
24388
24438
|
await writeFile(abs, content);
|
|
24389
24439
|
return text(`Wrote ${Buffer.byteLength(content)} bytes to ${await rel(abs)}`);
|
|
@@ -24423,7 +24473,7 @@ function createPeriscopeMcpServer(d, sc) {
|
|
|
24423
24473
|
inputSchema: { path: z.string() },
|
|
24424
24474
|
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false }
|
|
24425
24475
|
}, async ({ path }) => {
|
|
24426
|
-
const parent = await inTree(
|
|
24476
|
+
const parent = await inTree(dirname33(path) === "" ? "." : dirname33(path));
|
|
24427
24477
|
const abs = join54(parent, basename15(path));
|
|
24428
24478
|
if (basename15(path) === ".git" || abs === parent) return text("path must name a file", true);
|
|
24429
24479
|
const st = await lstat(abs).catch(() => void 0);
|
|
@@ -24545,7 +24595,7 @@ function findPeriscope(sidecars, segment) {
|
|
|
24545
24595
|
}
|
|
24546
24596
|
|
|
24547
24597
|
// src/cli.ts
|
|
24548
|
-
var CREW_HOME = isCompiledBinary(import.meta.url) ?
|
|
24598
|
+
var CREW_HOME = isCompiledBinary(import.meta.url) ? dirname34(process.execPath) : resolve7(dirname34(fileURLToPath2(import.meta.url)), "..");
|
|
24549
24599
|
var RELEASE_LOCK_TTL_MS = 20 * 60 * 1e3;
|
|
24550
24600
|
var CYCLE_SECONDS2 = 120;
|
|
24551
24601
|
var STALE_CYCLES = 3;
|
|
@@ -25828,6 +25878,13 @@ ${changed2.map((c) => ` - ${c}
|
|
|
25828
25878
|
const outcome = await runRelease({
|
|
25829
25879
|
cwd: target.dir,
|
|
25830
25880
|
repo,
|
|
25881
|
+
reloadRepo: (dir) => resolveRepoConfig(loadRepoConfig(dir), {
|
|
25882
|
+
hooks: { ...c.hooks, ...o?.hooks },
|
|
25883
|
+
labels: { ...c.labels, ...o?.labels },
|
|
25884
|
+
release: mergeRouteRelease(c.release, o?.release),
|
|
25885
|
+
branch: { ...c.branch, ...o?.branch },
|
|
25886
|
+
worktrees: { prefix: shipWorktreePrefixFor(c), nameOverride: o?.worktreeName }
|
|
25887
|
+
}, dir),
|
|
25831
25888
|
contract: tracker.contract,
|
|
25832
25889
|
tickets,
|
|
25833
25890
|
blockerInfo,
|
|
@@ -25872,7 +25929,12 @@ ${changed2.map((c) => ` - ${c}
|
|
|
25872
25929
|
tracker.contract,
|
|
25873
25930
|
outcome.stampFrom ?? outcome.decision.lastReleased,
|
|
25874
25931
|
outcome.decision.head,
|
|
25875
|
-
new Map(
|
|
25932
|
+
new Map([
|
|
25933
|
+
// Squashed onto an untagged base by an earlier cycle: no release range
|
|
25934
|
+
// names it, so the first release carries it out here (CREW-2925).
|
|
25935
|
+
...outcome.decision.merges.filter((m) => m.skipReason === "already-merged" && m.mergedSha).map((m) => [m.ticket.issue_id, m.mergedSha]),
|
|
25936
|
+
...outcome.merged.map((m) => [m.ticket.issue_id, m.sha])
|
|
25937
|
+
])
|
|
25876
25938
|
);
|
|
25877
25939
|
if (plan.length) await applyStamp(tracker, plan, outcome.version, tracker.contract, remit, dryRun, target.dir);
|
|
25878
25940
|
} else if (outcome.stopped) {
|
|
@@ -27082,7 +27144,7 @@ ${cu.tail.trimEnd()}
|
|
|
27082
27144
|
const found = cfg.routes.find((r) => r.route === routeArg);
|
|
27083
27145
|
if (!found) throw new ReposError(`no route "${routeArg}" in the config (have: ${cfg.routes.map((r) => r.route).join(", ") || "none"})`);
|
|
27084
27146
|
const named2 = value("route") ? void 0 : positional[3];
|
|
27085
|
-
const dir = named2 ? repoDirOf(configText,
|
|
27147
|
+
const dir = named2 ? repoDirOf(configText, dirname34(cfg.configFile), found.route, named2) : resolvePath(positional[value("route") ? 2 : 3] ?? ".");
|
|
27086
27148
|
const target = reposOf(found).find((t) => resolvePath(t.dir) === dir || t.name === named2);
|
|
27087
27149
|
const o = target ? found.repoOverrides[target.name] : void 0;
|
|
27088
27150
|
runReposCheck(dir, {
|
|
@@ -27106,7 +27168,7 @@ ${cu.tail.trimEnd()}
|
|
|
27106
27168
|
if (sub === "hooks") {
|
|
27107
27169
|
try {
|
|
27108
27170
|
const a = parseHooksArgs(positional.slice(2), routeNamesOf(configText));
|
|
27109
|
-
const dir = repoDirOf(configText,
|
|
27171
|
+
const dir = repoDirOf(configText, dirname34(cfg.configFile), a.route, a.name);
|
|
27110
27172
|
if (!existsSync51(dir)) throw new ReposError(`${dir} does not exist on disk`);
|
|
27111
27173
|
const files = { exists: (r) => existsSync51(resolvePath(dir, r)), list: (r) => {
|
|
27112
27174
|
try {
|
|
@@ -27273,7 +27335,7 @@ ${cu.tail.trimEnd()}
|
|
|
27273
27335
|
}
|
|
27274
27336
|
const originOf = (dir) => gitOk(dir, ["remote", "get-url", "origin"]) ?? void 0;
|
|
27275
27337
|
const text2 = configText;
|
|
27276
|
-
const base =
|
|
27338
|
+
const base = dirname34(cfg.configFile);
|
|
27277
27339
|
const isCheckout = (d) => existsSync51(`${d}/.git`);
|
|
27278
27340
|
try {
|
|
27279
27341
|
if (sub === "list") {
|
|
@@ -27288,7 +27350,8 @@ ${cu.tail.trimEnd()}
|
|
|
27288
27350
|
isCheckout,
|
|
27289
27351
|
repoHasHooks: (d) => REPO_CONFIG_FILENAMES.some((f) => {
|
|
27290
27352
|
try {
|
|
27291
|
-
|
|
27353
|
+
const path = resolvePath(d, f);
|
|
27354
|
+
return Object.keys(parseRepoConfig(readFileSync46(path, "utf8"), path).hooks).length > 0;
|
|
27292
27355
|
} catch {
|
|
27293
27356
|
return false;
|
|
27294
27357
|
}
|
|
@@ -27951,7 +28014,7 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
|
|
|
27951
28014
|
process.stderr.write(`(dry run) would write resolved ids to ${resolvedPath}
|
|
27952
28015
|
`);
|
|
27953
28016
|
} else {
|
|
27954
|
-
mkdirSync38(
|
|
28017
|
+
mkdirSync38(dirname34(resolvedPath), { recursive: true });
|
|
27955
28018
|
if (hadPreviousFile) copyFileSync2(resolvedPath, `${resolvedPath}.bak`);
|
|
27956
28019
|
const tmpPath = `${resolvedPath}.tmp${process.pid}`;
|
|
27957
28020
|
writeFileSync38(tmpPath, `${JSON.stringify(resolved, null, 2)}
|
|
@@ -28000,7 +28063,7 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
|
|
|
28000
28063
|
process.stderr.write(`(dry run) would write the minted API key to ${apiKeyFile}
|
|
28001
28064
|
`);
|
|
28002
28065
|
} else {
|
|
28003
|
-
mkdirSync38(
|
|
28066
|
+
mkdirSync38(dirname34(apiKeyFile), { recursive: true });
|
|
28004
28067
|
writeFileSync38(apiKeyFile, `${apiKeyVar}=${apiKey}
|
|
28005
28068
|
`, { mode: 384 });
|
|
28006
28069
|
process.stderr.write(`API key written to ${apiKeyFile}
|
|
@@ -29473,7 +29536,7 @@ ${where.join("\n")}`);
|
|
|
29473
29536
|
if (!route2.resolved) fail2(`route ${route2.route} is not connected \u2014 run \`crew connect\` first`);
|
|
29474
29537
|
const tracker = new Tracker(route2, cfg.ship);
|
|
29475
29538
|
const configText = readFileSync46(cfg.configFile, "utf8");
|
|
29476
|
-
const cfgBase =
|
|
29539
|
+
const cfgBase = dirname34(cfg.configFile);
|
|
29477
29540
|
const configured2 = configuredRepos(configText, route2.route, cfgBase);
|
|
29478
29541
|
const dir = configured2.find((r) => r.name === SAMPLE_REPO)?.dir ?? sampleDir(configured2.map((r) => r.dir), route2.reposBasePath, route2.route.split("/")[0]);
|
|
29479
29542
|
const resolvedFile = resolvedPathFor(cfg.ship.stateDir, route2.route);
|
|
@@ -24682,6 +24682,19 @@ var SPEC_VERSION = 1;
|
|
|
24682
24682
|
var REPO_CONFIG_FILENAMES = [".crew.yaml", ".crew.yml", ".crew.json"];
|
|
24683
24683
|
var RepoConfigError = class extends Error {
|
|
24684
24684
|
};
|
|
24685
|
+
function versionFileProblem(name, text) {
|
|
24686
|
+
const remedy = `a version file that is not a JSON object with a string "version" needs hooks.bump instead of release.versionFiles (docs/REPO_SPEC.md)`;
|
|
24687
|
+
let doc;
|
|
24688
|
+
try {
|
|
24689
|
+
doc = JSON.parse(text);
|
|
24690
|
+
} catch {
|
|
24691
|
+
return `release.versionFiles entry "${name}" is not a JSON document \u2014 ${remedy}`;
|
|
24692
|
+
}
|
|
24693
|
+
if (!doc || typeof doc !== "object" || Array.isArray(doc) || typeof doc.version !== "string") {
|
|
24694
|
+
return `release.versionFiles entry "${name}" has no string "version" field \u2014 ${remedy}`;
|
|
24695
|
+
}
|
|
24696
|
+
return null;
|
|
24697
|
+
}
|
|
24685
24698
|
var HOOK_NAMES = [
|
|
24686
24699
|
"test",
|
|
24687
24700
|
"build",
|
|
@@ -25015,6 +25028,22 @@ function parseRepoConfig(text, file) {
|
|
|
25015
25028
|
if (versionFiles.length === 0) {
|
|
25016
25029
|
throw new RepoConfigError(`${file}: release.versionFiles cannot be empty`);
|
|
25017
25030
|
}
|
|
25031
|
+
if (versionFilesGiven) {
|
|
25032
|
+
for (const name of versionFiles) {
|
|
25033
|
+
const path = (0, import_node_path6.join)((0, import_node_path6.dirname)(file), name);
|
|
25034
|
+
if (!(0, import_node_fs5.existsSync)(path)) continue;
|
|
25035
|
+
let text2;
|
|
25036
|
+
try {
|
|
25037
|
+
text2 = (0, import_node_fs5.readFileSync)(path, "utf8");
|
|
25038
|
+
} catch (e) {
|
|
25039
|
+
throw new RepoConfigError(
|
|
25040
|
+
`${file}: release.versionFiles entry "${name}" cannot be read (${e.code ?? "read error"})`
|
|
25041
|
+
);
|
|
25042
|
+
}
|
|
25043
|
+
const problem = versionFileProblem(name, text2);
|
|
25044
|
+
if (problem) throw new RepoConfigError(`${file}: ${problem}`);
|
|
25045
|
+
}
|
|
25046
|
+
}
|
|
25018
25047
|
const inspectorRaw = raw.periscope?.inspector;
|
|
25019
25048
|
if (inspectorRaw !== void 0 && inspectorRaw !== "proxy" && inspectorRaw !== "repo") {
|
|
25020
25049
|
throw new RepoConfigError(`${file}: periscope.inspector must be "proxy" or "repo"`);
|
package/package.json
CHANGED