@tablation/crew 0.126.10 → 0.126.12
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 +84 -36
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -6353,7 +6353,7 @@ function attentionProblems(items, already) {
|
|
|
6353
6353
|
}
|
|
6354
6354
|
|
|
6355
6355
|
// src/sandbox-image.ts
|
|
6356
|
-
import { createHash as
|
|
6356
|
+
import { createHash as createHash7 } from "crypto";
|
|
6357
6357
|
import { spawn as spawn5 } from "child_process";
|
|
6358
6358
|
import { execFileSync as execFileSync8 } from "child_process";
|
|
6359
6359
|
import { existsSync as existsSync30, mkdirSync as mkdirSync19, readFileSync as readFileSync27, renameSync as renameSync3, writeFileSync as writeFileSync20, rmSync as rmSync15 } from "fs";
|
|
@@ -6363,7 +6363,7 @@ import { tmpdir as tmpdir3 } from "os";
|
|
|
6363
6363
|
|
|
6364
6364
|
// src/passenger-containers.ts
|
|
6365
6365
|
import { execFileSync as execFileSync7 } from "child_process";
|
|
6366
|
-
import { createHash as
|
|
6366
|
+
import { createHash as createHash6 } from "crypto";
|
|
6367
6367
|
|
|
6368
6368
|
// src/sandbox-cache.ts
|
|
6369
6369
|
import { execFile as execFile2 } from "child_process";
|
|
@@ -6383,7 +6383,7 @@ import { readFileSync as readFileSync25, existsSync as existsSync26, statSync as
|
|
|
6383
6383
|
import { StringDecoder } from "string_decoder";
|
|
6384
6384
|
import { finished } from "stream/promises";
|
|
6385
6385
|
import { join as join29, dirname as dirname14, basename as basename9 } from "path";
|
|
6386
|
-
import { createHash as
|
|
6386
|
+
import { createHash as createHash5 } from "crypto";
|
|
6387
6387
|
|
|
6388
6388
|
// src/state.ts
|
|
6389
6389
|
import { readFileSync as readFileSync19, writeFileSync as writeFileSync14, existsSync as existsSync19, mkdirSync as mkdirSync13, rmSync as rmSync10, statSync as statSync7, readdirSync as readdirSync5 } from "fs";
|
|
@@ -10682,6 +10682,7 @@ function skillMarkerWarnings(promptsDir, personaPrompts) {
|
|
|
10682
10682
|
// src/runner.ts
|
|
10683
10683
|
import { spawn as spawn3, execFile, execFileSync as execFileSync6 } from "child_process";
|
|
10684
10684
|
import { mkdtempSync, mkdirSync as mkdirSync17, writeFileSync as writeFileSync18, rmSync as rmSync14 } from "fs";
|
|
10685
|
+
import { createHash as createHash4 } from "crypto";
|
|
10685
10686
|
import { tmpdir as tmpdir2 } from "os";
|
|
10686
10687
|
import { basename as basename8, dirname as dirname13, join as join28 } from "path";
|
|
10687
10688
|
import { promisify } from "util";
|
|
@@ -10777,8 +10778,9 @@ function shQuote2(s) {
|
|
|
10777
10778
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
10778
10779
|
}
|
|
10779
10780
|
function sandboxName(plan, now = Date.now()) {
|
|
10780
|
-
const
|
|
10781
|
-
|
|
10781
|
+
const h = createHash4("sha256").update([plan.route, plan.role, plan.ticket ?? ""].join("\0")).digest();
|
|
10782
|
+
const tag = (h.readUInt32BE(0) % 36 ** 6).toString(36).padStart(6, "0");
|
|
10783
|
+
return `crew-${tag}${now.toString(36).slice(-8).padStart(8, "0")}`;
|
|
10782
10784
|
}
|
|
10783
10785
|
var SandboxRunner = class {
|
|
10784
10786
|
kind = "sandbox";
|
|
@@ -10941,7 +10943,8 @@ function runnerFor(kind, sandbox) {
|
|
|
10941
10943
|
function runnerOfSidecar(sc) {
|
|
10942
10944
|
return sc.runner === "sandbox" ? new SandboxRunner(sc.sandboxBin ? { bin: sc.sandboxBin } : {}) : new HostRunner();
|
|
10943
10945
|
}
|
|
10944
|
-
|
|
10946
|
+
var PROBE_CREATE_TIMEOUT_MS = 12e4;
|
|
10947
|
+
function checkSandboxRunner(cfg = {}, run3 = (b, a, t) => execFileSync6(b, a, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: t ?? 15e3 })) {
|
|
10945
10948
|
const bin = cfg.bin ?? DEFAULT_SANDBOX_CONFIG.bin;
|
|
10946
10949
|
let version;
|
|
10947
10950
|
try {
|
|
@@ -10958,6 +10961,21 @@ function checkSandboxRunner(cfg = {}, run3 = (b, a) => execFileSync6(b, a, { enc
|
|
|
10958
10961
|
detail: `${version}: the gateway does not answer (${(err3.stderr || err3.message).trim().split("\n").filter(Boolean).slice(0, 2).join(" / ")}). Start it; on Docker Desktop its docker section needs supervisor_network_mode = "bridge", and allow_driver_config = true for the cache volume mount.`
|
|
10959
10962
|
};
|
|
10960
10963
|
}
|
|
10964
|
+
const probe = sandboxName({ route: "doctor", role: "dev", ticket: void 0 });
|
|
10965
|
+
try {
|
|
10966
|
+
run3(bin, ["sandbox", "create", "--name", probe, "--detach", "--", "sleep", "60"], PROBE_CREATE_TIMEOUT_MS);
|
|
10967
|
+
} catch (e) {
|
|
10968
|
+
const err3 = e;
|
|
10969
|
+
if (err3.code === "ETIMEDOUT" || err3.killed) {
|
|
10970
|
+
return { ok: false, detail: `${version}: creating a probe sandbox named ${probe} timed out after ${PROBE_CREATE_TIMEOUT_MS / 1e3} s; the gateway may still be pulling its images on a first create, so run crew doctor again` };
|
|
10971
|
+
}
|
|
10972
|
+
return { ok: false, detail: `${version}: the gateway refused a probe sandbox named ${probe} (${(err3.stderr || err3.message).trim().split("\n").filter(Boolean).slice(0, 2).join(" / ")})` };
|
|
10973
|
+
} finally {
|
|
10974
|
+
try {
|
|
10975
|
+
run3(bin, ["sandbox", "delete", probe]);
|
|
10976
|
+
} catch {
|
|
10977
|
+
}
|
|
10978
|
+
}
|
|
10961
10979
|
return { ok: true, detail: version };
|
|
10962
10980
|
}
|
|
10963
10981
|
|
|
@@ -11144,7 +11162,7 @@ function planAgentRun(o) {
|
|
|
11144
11162
|
brief: expanded.text,
|
|
11145
11163
|
digest
|
|
11146
11164
|
});
|
|
11147
|
-
const promptSha =
|
|
11165
|
+
const promptSha = createHash5("sha256").update(expanded.text).digest("hex");
|
|
11148
11166
|
const streamsDir = join29(o.stateDir, "streams");
|
|
11149
11167
|
const base = `${routeLabel}-${o.role}-${o.cycle}${o.runId ? `-${o.runId}` : ""}`;
|
|
11150
11168
|
const seat = resolveSeat(o.ship, o.route, o.role, o.agentPersona ?? (o.agentModel ? { model: o.agentModel } : {}), o.repo);
|
|
@@ -12097,8 +12115,8 @@ async function mintMissingSeatKeys(route2, o) {
|
|
|
12097
12115
|
const resolved = route2.resolved;
|
|
12098
12116
|
const doFetch = o.fetchImpl ?? fetch;
|
|
12099
12117
|
const targets = [
|
|
12100
|
-
...SEAT_KEY_ROLES.filter((r) => resolved.seats[r]).map((role) => ({ role, agentId: seatAgentId(route2, role) })),
|
|
12101
|
-
...resolved.releaseSeat ? [{ role: "release", agentId: resolved.releaseAgentId }] : []
|
|
12118
|
+
...SEAT_KEY_ROLES.filter((r) => resolved.seats[r]).map((role) => ({ role, agentId: seatAgentId(route2, role), actorRecordId: resolved.seats[role] })),
|
|
12119
|
+
...resolved.releaseSeat ? [{ role: "release", agentId: resolved.releaseAgentId, actorRecordId: resolved.releaseSeat }] : []
|
|
12102
12120
|
];
|
|
12103
12121
|
let store;
|
|
12104
12122
|
try {
|
|
@@ -12127,7 +12145,7 @@ async function mintMissingSeatKeys(route2, o) {
|
|
|
12127
12145
|
return targets.map(({ role, agentId }) => agentId ? { role, action: "failed", detail } : { role, action: "no_agent" });
|
|
12128
12146
|
}
|
|
12129
12147
|
}
|
|
12130
|
-
for (const { role, agentId } of targets) {
|
|
12148
|
+
for (const { role, agentId, actorRecordId } of targets) {
|
|
12131
12149
|
if (!agentId) {
|
|
12132
12150
|
out.push({ role, action: "no_agent" });
|
|
12133
12151
|
continue;
|
|
@@ -12149,7 +12167,7 @@ async function mintMissingSeatKeys(route2, o) {
|
|
|
12149
12167
|
"Content-Type": "application/json",
|
|
12150
12168
|
"User-Agent": o.userAgent ?? "Mozilla/5.0 TablationCrewAgent/1.0"
|
|
12151
12169
|
},
|
|
12152
|
-
body: JSON.stringify({ name: `crew ${o.shipName ?? "ship"} ${role}
|
|
12170
|
+
body: JSON.stringify({ name: `crew ${o.shipName ?? "ship"} ${role}`, ...actorRecordId ? { actorRecordId } : {} })
|
|
12153
12171
|
});
|
|
12154
12172
|
if (res.status === 403) {
|
|
12155
12173
|
out.push({ role, action: "forbidden" });
|
|
@@ -12220,8 +12238,8 @@ async function revokeSeatKeys(route2, o) {
|
|
|
12220
12238
|
const resolved = route2.resolved;
|
|
12221
12239
|
const doFetch = o.fetchImpl ?? fetch;
|
|
12222
12240
|
const targets = [
|
|
12223
|
-
...SEAT_KEY_ROLES.filter((r) => resolved.seats[r]).map((role) => ({ role, agentId: seatAgentId(route2, role) })),
|
|
12224
|
-
...resolved.releaseSeat ? [{ role: "release", agentId: resolved.releaseAgentId }] : []
|
|
12241
|
+
...SEAT_KEY_ROLES.filter((r) => resolved.seats[r]).map((role) => ({ role, agentId: seatAgentId(route2, role), actorRecordId: resolved.seats[role] })),
|
|
12242
|
+
...resolved.releaseSeat ? [{ role: "release", agentId: resolved.releaseAgentId, actorRecordId: resolved.releaseSeat }] : []
|
|
12225
12243
|
];
|
|
12226
12244
|
let store;
|
|
12227
12245
|
try {
|
|
@@ -12751,12 +12769,12 @@ function containerNameFor(workspaceId) {
|
|
|
12751
12769
|
return `crew-passenger-${workspaceId}`;
|
|
12752
12770
|
}
|
|
12753
12771
|
function portFor(workspaceId, base = 28765, span = 1e3) {
|
|
12754
|
-
const digest =
|
|
12772
|
+
const digest = createHash6("sha256").update(workspaceId).digest();
|
|
12755
12773
|
return base + digest.readUInt32BE(0) % span;
|
|
12756
12774
|
}
|
|
12757
12775
|
function mountsDigest(mounts, image) {
|
|
12758
12776
|
const sorted2 = [...mounts].sort((a, b) => a.containerPath.localeCompare(b.containerPath));
|
|
12759
|
-
return
|
|
12777
|
+
return createHash6("sha256").update(JSON.stringify({ mounts: sorted2, image })).digest("hex").slice(0, 16);
|
|
12760
12778
|
}
|
|
12761
12779
|
function planContainers(cfg) {
|
|
12762
12780
|
const byWorkspace = /* @__PURE__ */ new Map();
|
|
@@ -12959,7 +12977,7 @@ echo "password=$CREW_FORGE_TOKEN"
|
|
|
12959
12977
|
`;
|
|
12960
12978
|
var MCP_CONFIG = `${JSON.stringify({ mcpServers: {} }, null, 2)}
|
|
12961
12979
|
`;
|
|
12962
|
-
var hash = (parts) =>
|
|
12980
|
+
var hash = (parts) => createHash7("sha256").update(JSON.stringify(parts)).digest("hex").slice(0, 12);
|
|
12963
12981
|
var slug = (s) => s.toLowerCase().replace(/[^a-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
|
|
12964
12982
|
var run2 = (cmd) => `RUN ["/bin/bash", "-c", ${JSON.stringify(`set -euo pipefail; ${cmd}`)}]`;
|
|
12965
12983
|
var CREW_ENV = {
|
|
@@ -13577,7 +13595,7 @@ function doctorSelftestLines(stored, toolchains) {
|
|
|
13577
13595
|
// src/cli.ts
|
|
13578
13596
|
import { resolve as resolve7, dirname as dirname34, join as join56, basename as basename16 } from "path";
|
|
13579
13597
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
13580
|
-
import { hostname as
|
|
13598
|
+
import { hostname as hostname5, homedir as homedir11 } from "os";
|
|
13581
13599
|
import { spawnSync as spawnSync11 } from "child_process";
|
|
13582
13600
|
import { parse as parseYaml2 } from "yaml";
|
|
13583
13601
|
|
|
@@ -14384,13 +14402,13 @@ import { hostname as hostname3 } from "os";
|
|
|
14384
14402
|
|
|
14385
14403
|
// src/machine-id.ts
|
|
14386
14404
|
import { execFileSync as execFileSync10 } from "child_process";
|
|
14387
|
-
import { createHash as
|
|
14405
|
+
import { createHash as createHash8 } from "crypto";
|
|
14388
14406
|
import { existsSync as existsSync33, mkdirSync as mkdirSync24, readFileSync as readFileSync32, writeFileSync as writeFileSync25 } from "fs";
|
|
14389
14407
|
import { dirname as dirname19, join as join37 } from "path";
|
|
14390
14408
|
function machineIdPathFor(stateDir) {
|
|
14391
14409
|
return join37(stateDir, "machine-id");
|
|
14392
14410
|
}
|
|
14393
|
-
var sha256 = (s) =>
|
|
14411
|
+
var sha256 = (s) => createHash8("sha256").update(s).digest("hex");
|
|
14394
14412
|
function readRawMachineId(platform2 = process.platform) {
|
|
14395
14413
|
try {
|
|
14396
14414
|
if (platform2 === "darwin") {
|
|
@@ -17445,7 +17463,7 @@ function flagWizardAnswers(f, env) {
|
|
|
17445
17463
|
// src/release-run.ts
|
|
17446
17464
|
import { readFileSync as readFileSync36, writeFileSync as writeFileSync31, existsSync as existsSync39, copyFileSync, mkdirSync as mkdirSync28, mkdtempSync as mkdtempSync3, rmSync as rmSync19 } from "fs";
|
|
17447
17465
|
import { dirname as dirname24, join as join43 } from "path";
|
|
17448
|
-
import { tmpdir as tmpdir5 } from "os";
|
|
17466
|
+
import { tmpdir as tmpdir5, hostname as hostname4 } from "os";
|
|
17449
17467
|
|
|
17450
17468
|
// src/release.ts
|
|
17451
17469
|
function describeUnplaceable(unplaceable, verifiedStatus) {
|
|
@@ -18132,6 +18150,17 @@ async function confirmExternalReleased(o, closures) {
|
|
|
18132
18150
|
return { ...c, confirmed, version };
|
|
18133
18151
|
});
|
|
18134
18152
|
}
|
|
18153
|
+
var mergeFailed = (r) => typeof r === "object" && ("conflict" in r || "error" in r);
|
|
18154
|
+
function ensureCommitterIdentity(o) {
|
|
18155
|
+
if (gitOk(o.cwd, ["var", "GIT_COMMITTER_IDENT"])) return;
|
|
18156
|
+
const ship = hostname4().split(".")[0] || "ship";
|
|
18157
|
+
git(o.cwd, ["config", "user.name", `Crew (${ship})`]);
|
|
18158
|
+
git(o.cwd, ["config", "user.email", `crew@${ship}`]);
|
|
18159
|
+
o.emit.warn(`no git committer identity here \u2014 set a checkout-local one, Crew (${ship}), for the release commit`);
|
|
18160
|
+
}
|
|
18161
|
+
function isConflict(message, unmergedPaths) {
|
|
18162
|
+
return unmergedPaths.length > 0 || /CONFLICT \(|Automatic merge failed|unmerged (files|paths)/i.test(message);
|
|
18163
|
+
}
|
|
18135
18164
|
function mergeOne(o, c) {
|
|
18136
18165
|
const subject = c.entries[0] ?? `${c.ticket.title ?? c.ticket.issue_id} (${c.ticket.issue_id})`;
|
|
18137
18166
|
if (o.dryRun) {
|
|
@@ -18139,7 +18168,11 @@ function mergeOne(o, c) {
|
|
|
18139
18168
|
return { applied: true };
|
|
18140
18169
|
}
|
|
18141
18170
|
const before = headSha(o.cwd);
|
|
18171
|
+
const clearFailure = () => {
|
|
18172
|
+
o.attention?.clear(`release_merge_failed:${o.scope ?? "release"}`);
|
|
18173
|
+
};
|
|
18142
18174
|
try {
|
|
18175
|
+
ensureCommitterIdentity(o);
|
|
18143
18176
|
git(o.cwd, ["merge", "--squash", c.branch]);
|
|
18144
18177
|
if (!git(o.cwd, ["diff", "--cached", "--name-only"])) {
|
|
18145
18178
|
git(o.cwd, ["reset", "--hard", before]);
|
|
@@ -18147,6 +18180,7 @@ function mergeOne(o, c) {
|
|
|
18147
18180
|
`${c.branch} is already contained in the integration branch \u2014 nothing to apply`,
|
|
18148
18181
|
{ ticket: c.ticket.issue_id }
|
|
18149
18182
|
);
|
|
18183
|
+
clearFailure();
|
|
18150
18184
|
return "noop";
|
|
18151
18185
|
}
|
|
18152
18186
|
const tip = gitOk(o.cwd, ["rev-parse", "--verify", "-q", `${c.branch}^{commit}`]);
|
|
@@ -18158,12 +18192,25 @@ ${BRANCH_TIP_TRAILER}: ${tip}` : "";
|
|
|
18158
18192
|
Closes ${c.ticket.issue_id}.${trailer}`]);
|
|
18159
18193
|
const sha = headSha(o.cwd);
|
|
18160
18194
|
o.emit.emit(`merged ${c.branch}`, { ticket: c.ticket.issue_id });
|
|
18195
|
+
clearFailure();
|
|
18161
18196
|
return { applied: true, sha };
|
|
18162
18197
|
} catch (e) {
|
|
18163
18198
|
const paths = (gitOk(o.cwd, ["diff", "--name-only", "--diff-filter=U"]) ?? "").split("\n").filter(Boolean);
|
|
18164
18199
|
gitOk(o.cwd, ["reset", "--hard", before]);
|
|
18165
|
-
|
|
18166
|
-
|
|
18200
|
+
const message = e.message;
|
|
18201
|
+
o.emit.error(`could not merge ${c.branch}: ${message}`, { ticket: c.ticket.issue_id });
|
|
18202
|
+
if (!isConflict(message, paths)) {
|
|
18203
|
+
if (o.attention) {
|
|
18204
|
+
void o.attention.raise({
|
|
18205
|
+
kind: "release_merge_failed",
|
|
18206
|
+
key: `release_merge_failed:${o.scope ?? "release"}`,
|
|
18207
|
+
message: `${o.scope ?? "release"}: could not merge ${c.branch} (${c.ticket.issue_id}) \u2014 not a conflict, so the ticket stays verified and is retried: ${message.slice(0, 400)}`,
|
|
18208
|
+
since: (/* @__PURE__ */ new Date()).toISOString()
|
|
18209
|
+
});
|
|
18210
|
+
}
|
|
18211
|
+
return { error: message };
|
|
18212
|
+
}
|
|
18213
|
+
return { conflict: { candidate: c, paths, message } };
|
|
18167
18214
|
}
|
|
18168
18215
|
}
|
|
18169
18216
|
async function bump(o, size) {
|
|
@@ -18558,7 +18605,7 @@ async function isolateAndRetry(o, name, output, merged, preMerge, decision, fres
|
|
|
18558
18605
|
for (const c of applied) {
|
|
18559
18606
|
gitOk(o.cwd, ["reset", "--hard", preMerge]);
|
|
18560
18607
|
const m = mergeOne(o, c);
|
|
18561
|
-
if (
|
|
18608
|
+
if (mergeFailed(m)) continue;
|
|
18562
18609
|
const r = await hook(o, name);
|
|
18563
18610
|
if (r && r.code !== 0) {
|
|
18564
18611
|
o.emit.warn(`${c.branch} fails the ${name} hook on its own`, { ticket: c.ticket.issue_id });
|
|
@@ -18570,8 +18617,8 @@ async function isolateAndRetry(o, name, output, merged, preMerge, decision, fres
|
|
|
18570
18617
|
for (const [i, j] of pairs) {
|
|
18571
18618
|
gitOk(o.cwd, ["reset", "--hard", preMerge]);
|
|
18572
18619
|
const a = mergeOne(o, applied[i]);
|
|
18573
|
-
const b =
|
|
18574
|
-
if (
|
|
18620
|
+
const b = mergeFailed(a) ? a : mergeOne(o, applied[j]);
|
|
18621
|
+
if (mergeFailed(b)) continue;
|
|
18575
18622
|
const r = await hook(o, name);
|
|
18576
18623
|
if (r && r.code !== 0) {
|
|
18577
18624
|
o.emit.warn(`${applied[j].branch} fails the ${name} hook together with ${applied[i].branch}`, { ticket: applied[j].ticket.issue_id });
|
|
@@ -18588,7 +18635,7 @@ async function isolateAndRetry(o, name, output, merged, preMerge, decision, fres
|
|
|
18588
18635
|
let clean = true;
|
|
18589
18636
|
for (const c of applied.slice(0, mid)) {
|
|
18590
18637
|
const m = mergeOne(o, c);
|
|
18591
|
-
if (
|
|
18638
|
+
if (mergeFailed(m)) {
|
|
18592
18639
|
clean = false;
|
|
18593
18640
|
break;
|
|
18594
18641
|
}
|
|
@@ -18659,6 +18706,7 @@ async function mergeAndRelease(o, decision, fresh, releaseBranch, isolated = fal
|
|
|
18659
18706
|
conflicts.push(r.conflict);
|
|
18660
18707
|
continue;
|
|
18661
18708
|
}
|
|
18709
|
+
if (typeof r === "object" && "error" in r) continue;
|
|
18662
18710
|
if (typeof r === "object" && r.applied) {
|
|
18663
18711
|
applied++;
|
|
18664
18712
|
c.sha = r.sha;
|
|
@@ -20572,7 +20620,7 @@ async function runAgentsSync(target, o) {
|
|
|
20572
20620
|
}
|
|
20573
20621
|
|
|
20574
20622
|
// src/logbook.ts
|
|
20575
|
-
import { createHash as
|
|
20623
|
+
import { createHash as createHash9 } from "crypto";
|
|
20576
20624
|
import { TablationClient as TablationClient4 } from "@tablation/client";
|
|
20577
20625
|
var LogbookError = class extends Error {
|
|
20578
20626
|
};
|
|
@@ -20658,7 +20706,7 @@ async function showLogEntry(route2, entryId, opts = {}) {
|
|
|
20658
20706
|
};
|
|
20659
20707
|
}
|
|
20660
20708
|
const prompt = appendAdditions(match.prompt ?? "", match.prompt_additions);
|
|
20661
|
-
const actualSha =
|
|
20709
|
+
const actualSha = createHash9("sha256").update(prompt).digest("hex");
|
|
20662
20710
|
const exact = !!entry.prompt_sha && actualSha === entry.prompt_sha;
|
|
20663
20711
|
return {
|
|
20664
20712
|
entry,
|
|
@@ -22240,7 +22288,7 @@ function shipIdentityJson(s) {
|
|
|
22240
22288
|
}
|
|
22241
22289
|
|
|
22242
22290
|
// src/mcp-endpoint-registry.ts
|
|
22243
|
-
import { createHash as
|
|
22291
|
+
import { createHash as createHash10 } from "crypto";
|
|
22244
22292
|
function endpointsUrl(api, workspaceId, id) {
|
|
22245
22293
|
const base = `${api.baseUrl.replace(/\/+$/, "")}/api/workspaces/${workspaceId}/mcp-endpoints`;
|
|
22246
22294
|
return id ? `${base}/${id}` : base;
|
|
@@ -22310,7 +22358,7 @@ async function probeEndpointAccess(api, workspaceId) {
|
|
|
22310
22358
|
}
|
|
22311
22359
|
var REGISTER_MCP_ENDPOINTS_HINT = "give this key's role the REGISTER_MCP_ENDPOINTS capability, e.g. via the group that holds the Crew project role";
|
|
22312
22360
|
function registrationKey(url, mcpSecret, controlUrl) {
|
|
22313
|
-
return
|
|
22361
|
+
return createHash10("sha256").update(`${url}
|
|
22314
22362
|
${mcpSecret ?? ""}
|
|
22315
22363
|
${controlUrl ?? ""}`).digest("hex").slice(0, 16);
|
|
22316
22364
|
}
|
|
@@ -23693,7 +23741,7 @@ async function buildEnvironment(route2, ship, ticket) {
|
|
|
23693
23741
|
}
|
|
23694
23742
|
|
|
23695
23743
|
// src/control-api.ts
|
|
23696
|
-
import { createHash as
|
|
23744
|
+
import { createHash as createHash11 } from "crypto";
|
|
23697
23745
|
import {
|
|
23698
23746
|
chmodSync as chmodSync4,
|
|
23699
23747
|
closeSync as closeSync6,
|
|
@@ -23953,7 +24001,7 @@ var ControlAuth = class {
|
|
|
23953
24001
|
if (!token) return "unauthorized";
|
|
23954
24002
|
for (const k of this.o.shipKeys()) if (k && secretsMatch(token, k)) return "ok";
|
|
23955
24003
|
const now = (this.o.now ?? Date.now)();
|
|
23956
|
-
const id =
|
|
24004
|
+
const id = createHash11("sha256").update(token).digest("hex");
|
|
23957
24005
|
const hit = this.cache.get(id);
|
|
23958
24006
|
if (hit && now - hit.at < (this.o.cacheMs ?? 6e4)) return hit.verdict;
|
|
23959
24007
|
const verdict = await this.ask(token);
|
|
@@ -23974,7 +24022,7 @@ var ControlAuth = class {
|
|
|
23974
24022
|
for (const k of this.o.shipKeys()) if (k && secretsMatch(token, k)) return "ok";
|
|
23975
24023
|
for (const k of this.o.workspaceSecrets?.(workspaceId) ?? []) if (k && secretsMatch(token, k)) return "ok";
|
|
23976
24024
|
const now = (this.o.now ?? Date.now)();
|
|
23977
|
-
const id = `${workspaceId}:${
|
|
24025
|
+
const id = `${workspaceId}:${createHash11("sha256").update(token).digest("hex")}`;
|
|
23978
24026
|
const hit = this.cache.get(id);
|
|
23979
24027
|
if (hit && now - hit.at < (this.o.cacheMs ?? 6e4)) return hit.verdict;
|
|
23980
24028
|
const verdict = await this.ask(token, [workspaceId]);
|
|
@@ -25367,7 +25415,7 @@ if (command === "passenger-sync-daemon") {
|
|
|
25367
25415
|
};
|
|
25368
25416
|
if (command === "connect" && !flag("sign-out") && usesFlagAnswers(wizardFlags, connectIsTTY) && shouldRunWizard({ isTTY: true, crewHome: CREW_HOME })) {
|
|
25369
25417
|
const flagged = flagWizardAnswers(wizardFlags, {
|
|
25370
|
-
hostname:
|
|
25418
|
+
hostname: hostname5(),
|
|
25371
25419
|
platform: hostPlatform(),
|
|
25372
25420
|
pathEnv: process.env.PATH ?? "",
|
|
25373
25421
|
nodePath: process.execPath,
|
|
@@ -25392,7 +25440,7 @@ if (command === "passenger-sync-daemon") {
|
|
|
25392
25440
|
let answers;
|
|
25393
25441
|
try {
|
|
25394
25442
|
answers = await runWizard(prompter, {
|
|
25395
|
-
hostname:
|
|
25443
|
+
hostname: hostname5(),
|
|
25396
25444
|
platform: hostPlatform(),
|
|
25397
25445
|
pathEnv: process.env.PATH ?? "",
|
|
25398
25446
|
nodePath: process.execPath,
|
|
@@ -27949,7 +27997,7 @@ ${reconstruction.prompt}
|
|
|
27949
27997
|
let result;
|
|
27950
27998
|
try {
|
|
27951
27999
|
result = await loginWithDeviceCode(`${baseUrl}/api`, {
|
|
27952
|
-
deviceName: `crew on ${
|
|
28000
|
+
deviceName: `crew on ${hostname5()}`,
|
|
27953
28001
|
// Lets the approval page preselect the workspace this connect is for.
|
|
27954
28002
|
// A bare `crew connect` has none and passes nothing.
|
|
27955
28003
|
...workspace ? { workspaceSlug: workspace } : {},
|
package/package.json
CHANGED