@tablation/crew 0.123.1 → 0.124.0
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 +34 -6
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -406,7 +406,7 @@ function registerCodeServer(worktree, url, server = INTEL_SERVER_NAME) {
|
|
|
406
406
|
|
|
407
407
|
// src/intel-serena.ts
|
|
408
408
|
import { spawn, spawnSync } from "child_process";
|
|
409
|
-
import { closeSync, cpSync, existsSync as existsSync6, mkdirSync as mkdirSync4, openSync, readFileSync as readFileSync4, rmSync, writeFileSync as writeFileSync4 } from "fs";
|
|
409
|
+
import { closeSync, cpSync, existsSync as existsSync6, mkdirSync as mkdirSync4, openSync, readFileSync as readFileSync4, rmSync, symlinkSync, writeFileSync as writeFileSync4 } from "fs";
|
|
410
410
|
import { dirname as dirname3, join as join5 } from "path";
|
|
411
411
|
|
|
412
412
|
// src/ports.ts
|
|
@@ -575,6 +575,10 @@ function startSerena(d, s) {
|
|
|
575
575
|
const p = serenaPaths(s.stateDir, s.route, String(s.ticket));
|
|
576
576
|
try {
|
|
577
577
|
prepareFolder(d, p.home, p.project, s.worktree);
|
|
578
|
+
if (s.languageServers && d.exists(s.languageServers) && d.link) {
|
|
579
|
+
const dest = join5(p.home, "language_servers");
|
|
580
|
+
if (!d.exists(dest)) d.link(s.languageServers, dest);
|
|
581
|
+
}
|
|
578
582
|
const mainCache = join5(p.mainProject, "cache");
|
|
579
583
|
const cache = join5(p.project, "cache");
|
|
580
584
|
if (!d.exists(cache) && d.exists(mainCache)) d.copyDir(mainCache, cache);
|
|
@@ -625,6 +629,7 @@ function realSerenaDeps(onPath2, extraEnv = process.env) {
|
|
|
625
629
|
spawnDetached: detached,
|
|
626
630
|
// `&&` so the stamp exists only for an index that finished; a killed one is retried next start.
|
|
627
631
|
spawnIndex: (args, env, log, stamp, stampText) => detached("sh", ["-c", 'serena "$@" && printf %s "$STAMP_TEXT" > "$STAMP_FILE"', "serena", ...args], { ...env, STAMP_FILE: stamp, STAMP_TEXT: stampText }, log),
|
|
632
|
+
link: (target, path) => symlinkSync(target, path),
|
|
628
633
|
alive: (pid) => {
|
|
629
634
|
try {
|
|
630
635
|
process.kill(pid, 0);
|
|
@@ -12681,6 +12686,10 @@ var SANDBOX_CLAUDE_SHA256 = {
|
|
|
12681
12686
|
};
|
|
12682
12687
|
var SANDBOX_UID = 1e3;
|
|
12683
12688
|
var CREW_PREFIX = "/opt/crew";
|
|
12689
|
+
var SANDBOX_UV_VERSION = "0.13.6";
|
|
12690
|
+
var SANDBOX_SERENA_VERSION = "2.1.0";
|
|
12691
|
+
var SERENA_IMAGE_HOME = `${CREW_PREFIX}/serena`;
|
|
12692
|
+
var SERENA_LANGUAGE_SERVERS_ENV = "CREW_SERENA_LANGUAGE_SERVERS";
|
|
12684
12693
|
var SANDBOX_RETRY_AFTER_MS = 60 * 60 * 1e3;
|
|
12685
12694
|
var KEEP_TAGS = 2;
|
|
12686
12695
|
var CREDENTIAL_HELPER = `#!/bin/sh
|
|
@@ -12717,6 +12726,21 @@ function claudeInstallCommand() {
|
|
|
12717
12726
|
`${CREW_PREFIX}/bin/claude --version | grep -F "${SANDBOX_CLAUDE_VERSION}"`
|
|
12718
12727
|
].join("; ");
|
|
12719
12728
|
}
|
|
12729
|
+
function serenaInstallCommand() {
|
|
12730
|
+
return [
|
|
12731
|
+
`python3 -m venv ${CREW_PREFIX}/uv-venv`,
|
|
12732
|
+
`${CREW_PREFIX}/uv-venv/bin/pip install --no-cache-dir uv==${SANDBOX_UV_VERSION}`,
|
|
12733
|
+
`ln -sf ${CREW_PREFIX}/uv-venv/bin/uv ${CREW_PREFIX}/bin/uv`,
|
|
12734
|
+
`UV_TOOL_DIR=${CREW_PREFIX}/uv/tools UV_TOOL_BIN_DIR=${CREW_PREFIX}/bin UV_PYTHON_INSTALL_DIR=${CREW_PREFIX}/uv/python UV_CACHE_DIR=${CREW_PREFIX}/cache/uv ${CREW_PREFIX}/bin/uv tool install -p 3.13 serena-agent==${SANDBOX_SERENA_VERSION}`,
|
|
12735
|
+
`${CREW_PREFIX}/bin/serena --help >/dev/null`
|
|
12736
|
+
].join("; ");
|
|
12737
|
+
}
|
|
12738
|
+
function serenaWarmCommand() {
|
|
12739
|
+
return [
|
|
12740
|
+
`mkdir -p ${SERENA_IMAGE_HOME}`,
|
|
12741
|
+
`SERENA_HOME=${SERENA_IMAGE_HOME} serena project index ${WARM_DIR}`
|
|
12742
|
+
].join("; ");
|
|
12743
|
+
}
|
|
12720
12744
|
function baseLayer() {
|
|
12721
12745
|
const dockerfile = [
|
|
12722
12746
|
`FROM ${SANDBOX_BASE_IMAGE}`,
|
|
@@ -12725,18 +12749,20 @@ function baseLayer() {
|
|
|
12725
12749
|
].join("\n");
|
|
12726
12750
|
return { name: "base", tag: `crew-sandbox-base:${hash({ SANDBOX_BASE_IMAGE, SANDBOX_OPENSHELL_VERSION })}`, dockerfile, files: {} };
|
|
12727
12751
|
}
|
|
12728
|
-
function crewLayer(base) {
|
|
12752
|
+
function crewLayer(base, intel) {
|
|
12729
12753
|
const files = { "credential-helper": CREDENTIAL_HELPER, "mcp.json": MCP_CONFIG };
|
|
12730
12754
|
const env = Object.entries(CREW_ENV).map(([k, v]) => `${k}=${v}`).join(" ");
|
|
12731
12755
|
const dockerfile = [
|
|
12732
12756
|
`FROM ${base.tag}`,
|
|
12733
12757
|
"USER root",
|
|
12734
|
-
run2(
|
|
12758
|
+
run2(`apt-get update && apt-get install -y --no-install-recommends ca-certificates curl git${intel ? " python3 python3-venv nodejs" : ""} && rm -rf /var/lib/apt/lists/*`),
|
|
12735
12759
|
`COPY credential-helper ${CREW_PREFIX}/bin/credential-helper`,
|
|
12736
12760
|
`COPY mcp.json ${CREW_PREFIX}/mcp/mcp.json`,
|
|
12737
12761
|
run2(claudeInstallCommand()),
|
|
12762
|
+
...intel ? [run2(`mkdir -p ${CREW_PREFIX}/cache && ${serenaInstallCommand()}`)] : [],
|
|
12738
12763
|
run2(`chmod 0755 ${CREW_PREFIX}/bin/credential-helper && git config --system credential.helper ${CREW_PREFIX}/bin/credential-helper`),
|
|
12739
12764
|
run2(`mkdir -p ${CREW_PREFIX}/cache ${CREW_PREFIX}/pnpm-store ${CREW_PREFIX}/pnpm /sandbox && chown -R ${SANDBOX_UID}:${SANDBOX_UID} ${CREW_PREFIX} /sandbox`),
|
|
12765
|
+
...intel ? [`ENV ${SERENA_LANGUAGE_SERVERS_ENV}=${SERENA_IMAGE_HOME}/language_servers UV_PYTHON_INSTALL_DIR=${CREW_PREFIX}/uv/python`] : [],
|
|
12740
12766
|
`ENV ${env} PATH=${CREW_PREFIX}/pnpm:${CREW_PREFIX}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin`,
|
|
12741
12767
|
`LABEL io.crew.sandbox.layer="crew" io.crew.sandbox.claude="${SANDBOX_CLAUDE_VERSION}"`,
|
|
12742
12768
|
""
|
|
@@ -12790,6 +12816,7 @@ function repoLayer(repo, decl, crew, warm) {
|
|
|
12790
12816
|
lines2.push(`COPY --chown=${SANDBOX_UID}:${SANDBOX_UID} warm/ ${WARM_DIR}/`, `WORKDIR ${WARM_DIR}`);
|
|
12791
12817
|
}
|
|
12792
12818
|
for (const step of decl.setup) lines2.push(run2(step));
|
|
12819
|
+
if (warming && decl.intel) lines2.push(run2(serenaWarmCommand()));
|
|
12793
12820
|
if (warming) lines2.push("WORKDIR /sandbox", run2(`rm -rf ${WARM_DIR}`));
|
|
12794
12821
|
lines2.push(`LABEL io.crew.sandbox.layer="repo" io.crew.sandbox.repo=${JSON.stringify(repo)}`, "");
|
|
12795
12822
|
const dockerfile = lines2.join("\n");
|
|
@@ -12797,7 +12824,7 @@ function repoLayer(repo, decl, crew, warm) {
|
|
|
12797
12824
|
}
|
|
12798
12825
|
function planSandbox(repo, decl, warm = {}) {
|
|
12799
12826
|
const base = baseLayer();
|
|
12800
|
-
const crew = crewLayer(base);
|
|
12827
|
+
const crew = crewLayer(base, decl.intel);
|
|
12801
12828
|
const layer = repoLayer(repo, decl, crew, warm);
|
|
12802
12829
|
return { repo, tag: layer.tag, claude: SANDBOX_CLAUDE_VERSION, layers: [base, crew, layer] };
|
|
12803
12830
|
}
|
|
@@ -25400,7 +25427,7 @@ ${changed2.map((c) => ` - ${c}
|
|
|
25400
25427
|
warm = readWarmFiles(r.dir, `${r.config.branch.remote}/${r.config.branch.base}`, r.config.sandbox.warm ?? []);
|
|
25401
25428
|
} catch {
|
|
25402
25429
|
}
|
|
25403
|
-
out.set(r.name, { name: r.name, decl: r.config.sandbox, warm });
|
|
25430
|
+
out.set(r.name, { name: r.name, decl: intelFlavor(r.config.hooks.intel) === "serena" ? { ...r.config.sandbox, intel: "serena" } : r.config.sandbox, warm });
|
|
25404
25431
|
}
|
|
25405
25432
|
}
|
|
25406
25433
|
return [...out.values()];
|
|
@@ -28845,7 +28872,8 @@ ${where.join("\n")}`);
|
|
|
28845
28872
|
route: routeP.route,
|
|
28846
28873
|
ticket: Number(/(\d+)$/.exec(env.CREW_TICKET ?? "")?.[1] ?? 0),
|
|
28847
28874
|
worktree: cwd,
|
|
28848
|
-
mainCheckout: repoP.dir
|
|
28875
|
+
mainCheckout: repoP.dir,
|
|
28876
|
+
languageServers: process.env.CREW_SERENA_LANGUAGE_SERVERS
|
|
28849
28877
|
});
|
|
28850
28878
|
}
|
|
28851
28879
|
if (name === "intel" && lspFlavor(script)) return null;
|
package/package.json
CHANGED