diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 44f11bf580d21..25324e1cdd8e6 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -375,8 +375,6 @@ jobs:
TEST_PACKAGES: ${{ needs.changes.outputs.test_packages }}
run: |
set -o pipefail
- # LastCode scripts invoke CLIs that require Node ^24.13.1.
- vp env use 24.13.1
filters=(--filter '!t3' --filter '!@t3tools/monorepo' --filter '!@t3tools/web')
if [[ -n "$TEST_PACKAGES" ]]; then
filters=()
diff --git a/.github/workflows/server-test-pilot-worker.yml b/.github/workflows/server-test-pilot-worker.yml
index ae7b51e4300a6..b559d4d17c755 100644
--- a/.github/workflows/server-test-pilot-worker.yml
+++ b/.github/workflows/server-test-pilot-worker.yml
@@ -31,9 +31,9 @@ jobs:
install-args: --frozen-lockfile
- name: Select checkpoint pilot Node runtime
run: |
- vp env use 24.13.1
- echo 'VP_NODE_VERSION=24.13.1' >> "$GITHUB_ENV"
- vp env exec --node 24.13.1 node -p 'require("node:path").dirname(process.execPath)' >> "$GITHUB_PATH"
+ vp env use 26.12.1
+ echo 'VP_NODE_VERSION=26.12.1' >> "$GITHUB_ENV"
+ vp env exec --node 26.12.1 node -p 'require("node:path").dirname(process.execPath)' >> "$GITHUB_PATH"
- name: Install Chromium and system dependencies
run: node apps/server/node_modules/playwright-core/cli.js install --with-deps --only-shell chromium
- name: Run uncached cohort
diff --git a/README.md b/README.md
index b55a27143bf20..118246303b1b7 100644
--- a/README.md
+++ b/README.md
@@ -29,7 +29,7 @@ git clone git@github.com:YOUR_GITHUB_USER/LastCode.git ~/projects/lastCode
cd ~/projects/lastCode
git switch lastcode/main
git remote add upstream https://github.com/pingdotgg/t3code.git
-mise exec node@24.13.1 -- node scripts/lastcode-setup.mjs \
+mise exec node@26.12.1 -- node scripts/lastcode-setup.mjs \
--enable-nightly-writes \
--checkpoint-interval-seconds "$LASTCODE_CHECKPOINT_INTERVAL_SECONDS"
```
diff --git a/apps/server/src/cli/projectActionReconciliation.test.ts b/apps/server/src/cli/projectActionReconciliation.test.ts
index ced809b9c1a45..1e15d97c2bc71 100644
--- a/apps/server/src/cli/projectActionReconciliation.test.ts
+++ b/apps/server/src/cli/projectActionReconciliation.test.ts
@@ -11,14 +11,14 @@ import {
const waitDeclaration = {
id: "lc-wait-for-checkpoint",
name: "Wait for Checkpoint",
- command: "mise exec node@24.13.1 -- node scripts/lastcode-wait-for-checkpoint.ts",
+ command: "mise exec node@26.12.1 -- node scripts/lastcode-wait-for-checkpoint.ts",
icon: "test" as const,
};
const quickDeclaration = {
id: "lc-local-ci",
name: "Run Quick CI",
- command: "mise exec node@24.13.1 -- node scripts/lastcode-local-ci.ts --quick",
+ command: "mise exec node@26.12.1 -- node scripts/lastcode-local-ci.ts --quick",
icon: "test" as const,
};
diff --git a/docs/lastcode/nightly-workflow.md b/docs/lastcode/nightly-workflow.md
index 28ce48eb5c136..2e4ea7a7c6292 100644
--- a/docs/lastcode/nightly-workflow.md
+++ b/docs/lastcode/nightly-workflow.md
@@ -480,7 +480,7 @@ the dedicated automation worktree in `~/.lastcode/dashboard.json`, so the
command works from any directory without depending on a human development
worktree. Installation fails instead of recording the current checkout when the
automation worktree is missing. The installed launcher uses the repository's
-pinned Node 24 runtime through `mise`, independent of the shell's default Node.
+pinned Node runtime through `mise`, independent of the shell's default Node.
Show the latest eight checkpoint activities, or choose another count:
diff --git a/docs/lastcode/release.md b/docs/lastcode/release.md
index f44872a117bdc..43d3d40411463 100644
--- a/docs/lastcode/release.md
+++ b/docs/lastcode/release.md
@@ -475,7 +475,7 @@ For an authorized local Apple Silicon build, first select one exact installable
checkpoint or revision in the requesting thread's worktree:
```bash
-MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node "$T3CODE_PROJECT_ROOT/scripts/lastcode-build-local-package.ts" select \
+MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node "$T3CODE_PROJECT_ROOT/scripts/lastcode-build-local-package.ts" select \
--tag lastcode/revision/v0.0.34-nightly.20260825.1185.3
```
diff --git a/docs/lastcode/setup.md b/docs/lastcode/setup.md
index 93d6282009de3..bb4439e03d296 100644
--- a/docs/lastcode/setup.md
+++ b/docs/lastcode/setup.md
@@ -53,7 +53,7 @@ git remote add upstream https://github.com/pingdotgg/t3code.git
Run the guarded bootstrap from the checkout:
```bash
-MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node scripts/lastcode-setup.mjs \
+MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node scripts/lastcode-setup.mjs \
--enable-nightly-writes \
--checkpoint-daily-at "$LASTCODE_CHECKPOINT_DAILY_AT" \
--checkpoint-time-zone "$LASTCODE_CHECKPOINT_TIME_ZONE"
diff --git a/package.json b/package.json
index fcb4de21add29..77bd697c69483 100644
--- a/package.json
+++ b/package.json
@@ -58,29 +58,29 @@
"dist:desktop:win:arm64": "node scripts/build-desktop-artifact.ts --platform win --target nsis --arch arm64",
"dist:desktop:win:x64": "node scripts/build-desktop-artifact.ts --platform win --target nsis --arch x64",
"release:smoke": "node scripts/release-smoke.ts",
- "lastcode:checkpoint": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node scripts/lastcode-checkpoint.ts",
- "lastcode:carry-set": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node scripts/lastcode-carry-set.ts",
- "lastcode:checkpoints": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node scripts/lastcode-checkpoints.mjs",
- "lastcode:build": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node scripts/lastcode-build.mjs",
- "lastcode:install": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node scripts/lastcode-install.mjs",
- "lastcode:intel-build": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node scripts/lastcode-build-intel-package.ts",
- "lastcode:intel-stage": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node scripts/lastcode-intel-stage.mjs",
- "lastcode:managed-checkout": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node scripts/lastcode-managed-checkout.mjs",
- "lastcode:project-actions": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node scripts/lastcode-project-actions.mjs",
- "lastcode:headless-service": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node scripts/lastcode-headless-service.mjs",
- "lastcode:setup": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node scripts/lastcode-setup.mjs",
- "lastcode:checkpoint:service": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node scripts/lastcode-nightly-service.ts",
- "lastcode:build:mac:arm64": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node scripts/lastcode-build-mac.ts --arch arm64",
- "lastcode:build:mac:x64": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node scripts/lastcode-build-mac.ts --arch x64",
- "lastcode:ci": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node scripts/lastcode-local-ci.ts --full",
- "lastcode:ci:quick": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node scripts/lastcode-local-ci.ts --quick",
- "lastcode:merge": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node scripts/lastcode-merge.ts",
+ "lastcode:checkpoint": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node scripts/lastcode-checkpoint.ts",
+ "lastcode:carry-set": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node scripts/lastcode-carry-set.ts",
+ "lastcode:checkpoints": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node scripts/lastcode-checkpoints.mjs",
+ "lastcode:build": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node scripts/lastcode-build.mjs",
+ "lastcode:install": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node scripts/lastcode-install.mjs",
+ "lastcode:intel-build": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node scripts/lastcode-build-intel-package.ts",
+ "lastcode:intel-stage": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node scripts/lastcode-intel-stage.mjs",
+ "lastcode:managed-checkout": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node scripts/lastcode-managed-checkout.mjs",
+ "lastcode:project-actions": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node scripts/lastcode-project-actions.mjs",
+ "lastcode:headless-service": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node scripts/lastcode-headless-service.mjs",
+ "lastcode:setup": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node scripts/lastcode-setup.mjs",
+ "lastcode:checkpoint:service": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node scripts/lastcode-nightly-service.ts",
+ "lastcode:build:mac:arm64": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node scripts/lastcode-build-mac.ts --arch arm64",
+ "lastcode:build:mac:x64": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node scripts/lastcode-build-mac.ts --arch x64",
+ "lastcode:ci": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node scripts/lastcode-local-ci.ts --full",
+ "lastcode:ci:quick": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node scripts/lastcode-local-ci.ts --quick",
+ "lastcode:merge": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node scripts/lastcode-merge.ts",
"lastcode:docs:check": "node scripts/lastcode-docs-features.ts --check",
"lastcode:docs:readme": "node scripts/lastcode-docs-features.ts --write-readme",
- "lastcode:docs:fixtures": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node scripts/lastcode-public-doc-fixtures.ts",
+ "lastcode:docs:fixtures": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node scripts/lastcode-public-doc-fixtures.ts",
"clean": "rm -rf node_modules apps/*/node_modules packages/*/node_modules apps/*/dist apps/*/dist-electron packages/*/dist .vite-plus apps/*/.vite-plus packages/*/.vite-plus",
"sync:repos": "node scripts/sync-reference-repos.ts",
- "lastcode:pr-gates": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node scripts/lastcode-pr-gates.ts"
+ "lastcode:pr-gates": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node scripts/lastcode-pr-gates.ts"
},
"devDependencies": {
"@coderabbitai/config": "1.2.0",
diff --git a/scripts/lastcode-build.mjs b/scripts/lastcode-build.mjs
index 63114c87f4848..afdfcef4e7c81 100644
--- a/scripts/lastcode-build.mjs
+++ b/scripts/lastcode-build.mjs
@@ -144,7 +144,7 @@ function shellQuote(value) {
}
export function renderLauncher(modulePath) {
- return `#!/bin/sh\n# ${BUILD_MANAGED_MARKER}\nexec env MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node ${shellQuote(modulePath)} "$@"\n`;
+ return `#!/bin/sh\n# ${BUILD_MANAGED_MARKER}\nexec env MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node ${shellQuote(modulePath)} "$@"\n`;
}
function runGit(repoRoot, args) {
@@ -392,7 +392,7 @@ export function installCommandAssets(automationWorktree, home) {
);
replaceManagedSymlink(exposed, target);
- console.log(`Installed ${target} with the pinned Node 24 runtime`);
+ console.log(`Installed ${target} with the pinned Node runtime`);
console.log(`Exposed on PATH as ${exposed}`);
}
diff --git a/scripts/lastcode-build.test.mjs b/scripts/lastcode-build.test.mjs
index 8da2ebd417d57..8a5da27bc4833 100644
--- a/scripts/lastcode-build.test.mjs
+++ b/scripts/lastcode-build.test.mjs
@@ -314,7 +314,7 @@ describe("LastCode userland build command", () => {
it("launches with the repository's pinned Node runtime", () => {
expect(renderLauncher("/tmp/Last Code/lastcode-build.mjs")).toContain(
- "env MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node '/tmp/Last Code/lastcode-build.mjs' \"$@\"",
+ "env MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node '/tmp/Last Code/lastcode-build.mjs' \"$@\"",
);
});
});
diff --git a/scripts/lastcode-checkpoints.mjs b/scripts/lastcode-checkpoints.mjs
index 15633ed786b25..a73b7c15170a3 100644
--- a/scripts/lastcode-checkpoints.mjs
+++ b/scripts/lastcode-checkpoints.mjs
@@ -756,7 +756,7 @@ function readCarryReplayPlan(worktree) {
}
export function renderLauncher(modulePath) {
- return `#!/bin/sh\nexec env MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node ${shellQuote(modulePath)} "$@"\n`;
+ return `#!/bin/sh\nexec env MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node ${shellQuote(modulePath)} "$@"\n`;
}
function installCommand(repoRoot, home) {
@@ -790,7 +790,7 @@ function installCommand(repoRoot, home) {
NodeFS.unlinkSync(exposed);
}
NodeFS.symlinkSync(target, exposed);
- console.log(`Installed ${target} with the pinned Node 24 runtime`);
+ console.log(`Installed ${target} with the pinned Node runtime`);
console.log(`Exposed on PATH as ${exposed}`);
}
diff --git a/scripts/lastcode-checkpoints.test.mjs b/scripts/lastcode-checkpoints.test.mjs
index 41774e0174fde..11d4a3f2dad62 100644
--- a/scripts/lastcode-checkpoints.test.mjs
+++ b/scripts/lastcode-checkpoints.test.mjs
@@ -185,7 +185,7 @@ describe("LastCode checkpoint dashboard", () => {
NodeFS.rmSync(directory, { recursive: true, force: true });
}
expect(renderLauncher("/tmp/Last Code/checkpoints.mjs")).toContain(
- "env MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node '/tmp/Last Code/checkpoints.mjs' \"$@\"",
+ "env MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node '/tmp/Last Code/checkpoints.mjs' \"$@\"",
);
});
diff --git a/scripts/lastcode-ci-workflow.test.ts b/scripts/lastcode-ci-workflow.test.ts
index 850ee648aeb9e..acdaec68f401d 100644
--- a/scripts/lastcode-ci-workflow.test.ts
+++ b/scripts/lastcode-ci-workflow.test.ts
@@ -252,7 +252,7 @@ describe("LastCode GitHub CI workflow", () => {
it.each([
{ packages: "", filters: ["!t3", "!@t3tools/monorepo", "!@t3tools/web"] },
{ packages: "@t3tools/scripts", filters: ["@t3tools/scripts"] },
- ])("selects the supported Node before testing packages '$packages'", ({ packages, filters }) => {
+ ])("tests packages '$packages' on the project Node", ({ packages, filters }) => {
const steps = asRecord(asRecord(asRecord(parse(workflow))?.jobs)?.test)?.steps;
if (!Array.isArray(steps)) throw new Error("CI test job is missing its steps.");
const script = steps.map(asRecord).find((step) => step?.name === "Test")?.run;
@@ -265,7 +265,6 @@ describe("LastCode GitHub CI workflow", () => {
);
expect(result.status, result.stderr).toBe(0);
expect(result.stdout.trim().split("\n")).toEqual([
- "env use 24.13.1",
`run --parallel --concurrency-limit 4 ${filters.map((filter) => `--filter ${filter}`).join(" ")} test`,
]);
});
diff --git a/scripts/lastcode-install.mjs b/scripts/lastcode-install.mjs
index 0eca24ff579a2..6b24247455781 100644
--- a/scripts/lastcode-install.mjs
+++ b/scripts/lastcode-install.mjs
@@ -34,7 +34,7 @@ function shellQuote(value) {
}
export function renderLauncher(modulePath) {
- return `#!/bin/sh\n# ${INSTALL_MANAGED_MARKER}\nexec env MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node ${shellQuote(modulePath)} "$@"\n`;
+ return `#!/bin/sh\n# ${INSTALL_MANAGED_MARKER}\nexec env MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node ${shellQuote(modulePath)} "$@"\n`;
}
export function parseOptions(argv) {
@@ -959,7 +959,7 @@ export function installCommand(home) {
NodeFS.writeFileSync(target, renderLauncher(moduleTarget), { encoding: "utf8", mode: 0o755 });
NodeFS.chmodSync(target, 0o755);
replaceManagedSymlink(exposed, target);
- console.log(`Installed ${target} with the pinned Node 24 runtime`);
+ console.log(`Installed ${target} with the pinned Node runtime`);
console.log(`Exposed on PATH as ${exposed}`);
}
diff --git a/scripts/lastcode-install.test.mjs b/scripts/lastcode-install.test.mjs
index f0bf41bd778d0..87346b46ebf52 100644
--- a/scripts/lastcode-install.test.mjs
+++ b/scripts/lastcode-install.test.mjs
@@ -985,7 +985,7 @@ describe("LastCode userland install command", () => {
it("launches with the repository's pinned Node runtime", () => {
expect(renderLauncher("/tmp/Last Code/lastcode-install.mjs")).toContain(
- "env MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node '/tmp/Last Code/lastcode-install.mjs' \"$@\"",
+ "env MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node '/tmp/Last Code/lastcode-install.mjs' \"$@\"",
);
});
diff --git a/scripts/lastcode-intel-release.test.mjs b/scripts/lastcode-intel-release.test.mjs
index 0d28931defcea..589c718a1934d 100644
--- a/scripts/lastcode-intel-release.test.mjs
+++ b/scripts/lastcode-intel-release.test.mjs
@@ -180,7 +180,7 @@ describe("immutable Intel release validation", () => {
id: "lc-build-intel-package",
name: "Build Intel package (macOS)",
command:
- "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node scripts/lastcode-build-intel-package.ts run",
+ "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node scripts/lastcode-build-intel-package.ts run",
icon: "build",
});
const automationCheckout = workflow.slice(
diff --git a/scripts/lastcode-local-ci.test.ts b/scripts/lastcode-local-ci.test.ts
index 2b586ac1a4bd5..74fe6108929fc 100644
--- a/scripts/lastcode-local-ci.test.ts
+++ b/scripts/lastcode-local-ci.test.ts
@@ -305,11 +305,16 @@ describe("lastcode-local-ci", () => {
expect(hook).toContain("lastcode:ci:quick -- --pre-push");
});
- it("requires the repository's supported Node release line", () => {
+ it("requires engines.node, or ^24.13.1 during the transition", () => {
+ const enginesNode: string = JSON.parse(
+ NodeFS.readFileSync(NodePath.join(import.meta.dirname, "..", "package.json"), "utf8"),
+ ).engines.node;
+ expect(() => assertSupportedNodeVersion(enginesNode)).not.toThrow();
expect(() => assertSupportedNodeVersion("24.13.1")).not.toThrow();
expect(() => assertSupportedNodeVersion("24.99.0")).not.toThrow();
- expect(() => assertSupportedNodeVersion("24.13.0")).toThrow("Node ^24.13.1");
- expect(() => assertSupportedNodeVersion("26.7.0")).toThrow("Node ^24.13.1");
+ expect(() => assertSupportedNodeVersion("24.13.0")).toThrow(`Node ${enginesNode}`);
+ expect(() => assertSupportedNodeVersion("26.7.0")).toThrow(`Node ${enginesNode}`);
+ expect(() => assertSupportedNodeVersion("25.0.0")).toThrow(`Node ${enginesNode}`);
});
it("defaults to the full gate and supports the quick pre-push gate", () => {
@@ -330,6 +335,7 @@ describe("lastcode-local-ci", () => {
prePush: false,
requireLocal: true,
});
+ expect(parseLocalCiOptions(["--full", "--quick"]).mode).toBe("quick");
expect(() => parseLocalCiOptions(["--require-local"])).toThrow("only supported with --quick");
expect(() => parseLocalCiOptions(["--full", "--pre-push"])).toThrow(
"only supported with --quick",
diff --git a/scripts/lastcode-local-update.mjs b/scripts/lastcode-local-update.mjs
index 58a15277a4464..741c6d7efe7b7 100644
--- a/scripts/lastcode-local-update.mjs
+++ b/scripts/lastcode-local-update.mjs
@@ -771,10 +771,14 @@ function resolveMise(home) {
}
export function resolveMiseNodeExecutable(cwd, mise, runCommand = run) {
- const installRoot = runCommand(cwd, mise, ["where", "node@24.13.1"]);
+ // Older installable tags can require a different tooling runtime than engines.node.
+ const manifest = JSON.parse(NodeFS.readFileSync(NodePath.join(cwd, "package.json"), "utf8"));
+ const nodeTool = manifest.scripts["lastcode:ci"].match(/\bnode@\d+\.\d+\.\d+\b/u)?.[0];
+ if (!nodeTool) throw new Error("The target tag's lastcode:ci command must pin a Node runtime.");
+ const installRoot = runCommand(cwd, mise, ["where", nodeTool]);
const executable = NodePath.join(installRoot, "bin", "node");
if (!NodeFS.existsSync(executable)) {
- throw new Error(`mise did not provide the expected Node 24 executable at ${executable}.`);
+ throw new Error(`mise did not provide the expected ${nodeTool} executable at ${executable}.`);
}
return executable;
}
diff --git a/scripts/lastcode-local-update.test.ts b/scripts/lastcode-local-update.test.ts
index 6153081e3e094..0398e63e5a62e 100644
--- a/scripts/lastcode-local-update.test.ts
+++ b/scripts/lastcode-local-update.test.ts
@@ -175,15 +175,26 @@ describe("lastcode-local-update", () => {
try {
NodeFS.mkdirSync(NodePath.dirname(executable), { recursive: true });
NodeFS.writeFileSync(executable, "");
- assert.equal(
- resolveMiseNodeExecutable("/build", "/mise", (cwd, command, args) => {
- assert.equal(cwd, "/build");
- assert.equal(command, "/mise");
- assert.deepEqual(args, ["where", "node@24.13.1"]);
- return root;
- }),
- executable,
- );
+ for (const version of ["26.12.1", "24.13.1"]) {
+ NodeFS.writeFileSync(
+ NodePath.join(root, "package.json"),
+ JSON.stringify({
+ engines: { node: "26.12.1" },
+ scripts: {
+ "lastcode:ci": `MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@${version} -- node scripts/lastcode-local-ci.ts --full`,
+ },
+ }),
+ );
+ assert.equal(
+ resolveMiseNodeExecutable(root, "/mise", (cwd, command, args) => {
+ assert.equal(cwd, root);
+ assert.equal(command, "/mise");
+ assert.deepEqual(args, ["where", `node@${version}`]);
+ return root;
+ }),
+ executable,
+ );
+ }
} finally {
NodeFS.rmSync(root, { recursive: true, force: true });
}
diff --git a/scripts/lastcode-main-write-lock.test.ts b/scripts/lastcode-main-write-lock.test.ts
index a942d71a373ac..4bc9e1a5c6ec8 100644
--- a/scripts/lastcode-main-write-lock.test.ts
+++ b/scripts/lastcode-main-write-lock.test.ts
@@ -363,6 +363,7 @@ JS`,
vi.stubEnv("FIXTURE_REAL_GIT", realGit);
vi.stubEnv("PATH", `${bin}${NodePath.delimiter}${process.env.PATH ?? ""}`);
const hooks = NodePath.join(f.first, ".git", "hooks");
+ f.git(f.first, ["config", "core.hooksPath", hooks]);
NodeFS.copyFileSync(
NodePath.join(import.meta.dirname, "..", ".vite-hooks", "pre-push"),
NodePath.join(hooks, "lastcode-pre-push"),
diff --git a/scripts/lastcode-nightly-service.test.ts b/scripts/lastcode-nightly-service.test.ts
index cec1551603800..34eb86de3ccf6 100644
--- a/scripts/lastcode-nightly-service.test.ts
+++ b/scripts/lastcode-nightly-service.test.ts
@@ -49,14 +49,14 @@ it("renders the deployment-defined interval in a source-only launch agent", () =
const plist = renderLaunchAgentPlist({
repoRoot: "/Users/example/LastCode & experiments",
logDirectory: "/Users/example/.lastcode/automation",
- nodePath: "/Users/example/.local/share/mise/installs/node/24.13.1/bin/node",
+ nodePath: "/Users/example/.local/share/mise/installs/node/26.12.1/bin/node",
schedule: { kind: "interval", intervalSeconds: 1234 },
scheduleHelperPath: "/Users/example/.lastcode/automation/bin/schedule helper.mjs",
supervisorPath: "/Users/example/.lastcode/automation/bin/checkpoint supervisor.mjs",
});
expect(plist).toContain("1234");
- expect(plist).toContain("node/24.13.1/bin/node");
+ expect(plist).toContain("node/26.12.1/bin/node");
expect(plist).toContain("checkpoint supervisor.mjs");
expect(plist).not.toContain("/bin/zsh");
expect(plist).not.toContain("/usr/bin/env");
diff --git a/scripts/lastcode-node-launch.test.ts b/scripts/lastcode-node-launch.test.ts
index 302e54bef3100..f47ea511bc49b 100644
--- a/scripts/lastcode-node-launch.test.ts
+++ b/scripts/lastcode-node-launch.test.ts
@@ -13,31 +13,46 @@ const projectConfig = JSON.parse(
NodeFS.readFileSync(new URL("../t3.json", import.meta.url), "utf8"),
) as { scripts: Array<{ name: string; command: string }> };
-function withLaunchFixture(run: (fixture: ReturnType) => void) {
+function withLaunchFixture(
+ run: (fixture: ReturnType) => void,
+ targetVersion = "26.12.1",
+) {
const root = NodeFS.realpathSync(
NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "lastcode node launch ")),
);
try {
- run(createLaunchFixture(root));
+ run(createLaunchFixture(root, targetVersion));
} finally {
NodeFS.rmSync(root, { recursive: true, force: true });
}
}
-function createLaunchFixture(root: string) {
+function createLaunchFixture(root: string, targetVersion: string) {
const cwd = NodePath.join(root, "checkout with spaces");
const projectRoot = NodePath.join(root, "primary checkout with spaces");
const pinnedBin = NodePath.join(root, "pinned bin");
+ const legacyBin = NodePath.join(root, "legacy pinned bin");
const ambientBin = NodePath.join(root, "ambient bin");
const toolBin = NodePath.join(root, "external tools");
const checkoutBin = NodePath.join(cwd, "node_modules", ".bin");
- for (const directory of [cwd, projectRoot, pinnedBin, ambientBin, toolBin, checkoutBin]) {
+ for (const directory of [
+ cwd,
+ projectRoot,
+ pinnedBin,
+ legacyBin,
+ ambientBin,
+ toolBin,
+ checkoutBin,
+ ]) {
NodeFS.mkdirSync(directory, { recursive: true });
}
const pinnedNode = NodePath.join(pinnedBin, "node");
+ const legacyNode = NodePath.join(legacyBin, "node");
// A copied executable gives process.execPath an observable identity independent of PATH shims.
NodeFS.copyFileSync(process.execPath, pinnedNode);
NodeFS.chmodSync(pinnedNode, 0o755);
+ NodeFS.copyFileSync(process.execPath, legacyNode);
+ NodeFS.chmodSync(legacyNode, 0o755);
const writeExecutable = (path: string, source: string) => {
NodeFS.writeFileSync(path, source, { mode: 0o755 });
};
@@ -50,18 +65,31 @@ function createLaunchFixture(root: string) {
writeExecutable(
NodePath.join(toolBin, "mise"),
`#!/bin/sh
-[ "$1" = exec ] && [ "$2" = node@24.13.1 ] && [ "$3" = -- ] || exit 90
+[ "$1" = exec ] && [ "$3" = -- ] || exit 90
+case "$2" in
+ node@26.12.1) selected="$FIXTURE_PINNED_BIN" ;;
+ node@24.13.1) selected="$FIXTURE_LEGACY_BIN" ;;
+ *) exit 90 ;;
+esac
shift 3
# Model mise restoring pristine PATH entries unless aggressive activation is explicit.
if [ "$MISE_ACTIVATE_AGGRESSIVE" = 1 ]; then
- PATH="$FIXTURE_PINNED_BIN:$FIXTURE_CHECKOUT_BIN:$FIXTURE_AMBIENT_BIN:/usr/bin:/bin"
+ PATH="$selected:$FIXTURE_CHECKOUT_BIN:$FIXTURE_TOOL_BIN:$FIXTURE_AMBIENT_BIN:/usr/bin:/bin"
else
- PATH="$FIXTURE_AMBIENT_BIN:$FIXTURE_CHECKOUT_BIN:$FIXTURE_PINNED_BIN:/usr/bin:/bin"
+ PATH="$FIXTURE_AMBIENT_BIN:$FIXTURE_CHECKOUT_BIN:$FIXTURE_TOOL_BIN:$selected:/usr/bin:/bin"
fi
export PATH
exec "$@"
`,
);
+ NodeFS.writeFileSync(
+ NodePath.join(cwd, "package.json"),
+ JSON.stringify({
+ scripts: {
+ "lastcode:ci": `MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@${targetVersion} -- node scripts/lastcode-local-ci.ts --full`,
+ },
+ }),
+ );
const leaf = `const { spawnSync } = require('node:child_process');
const path = require('node:path');
const grandchild = spawnSync('node', ['-e', 'console.log(JSON.stringify({ executable: process.execPath, version: process.version }))'], { encoding: 'utf8' });
@@ -82,6 +110,7 @@ process.exit(Number(name === process.env.FIXTURE_FAIL_LEAF ? process.env.FIXTURE
return {
cwd,
pinnedNode,
+ ciNode: targetVersion === "24.13.1" ? legacyNode : pinnedNode,
run(command: string, args: string[], failLeaf: string, exitCode: number) {
const env: NodeJS.ProcessEnv = {
...process.env,
@@ -91,6 +120,8 @@ process.exit(Number(name === process.env.FIXTURE_FAIL_LEAF ? process.env.FIXTURE
MISE_ACTIVATE_AGGRESSIVE: "0",
T3CODE_PROJECT_ROOT: projectRoot,
FIXTURE_PINNED_BIN: pinnedBin,
+ FIXTURE_LEGACY_BIN: legacyBin,
+ FIXTURE_TOOL_BIN: toolBin,
FIXTURE_AMBIENT_BIN: ambientBin,
FIXTURE_CHECKOUT_BIN: checkoutBin,
FIXTURE_AMBIENT_NODE: process.execPath,
@@ -133,10 +164,12 @@ function expectPinned(
records: ReturnType["run"]>,
) {
for (const record of records) {
- expect(record.executable).toBe(fixture.pinnedNode);
+ const expectedNode =
+ record.name === "lastcode-local-ci.ts" ? fixture.ciNode : fixture.pinnedNode;
+ expect(record.executable).toBe(expectedNode);
expect(record.version).toBe(process.version);
expect(record.cwd).toBe(NodeFS.realpathSync(fixture.cwd));
- expect(record.grandchild).toEqual({ executable: fixture.pinnedNode, version: process.version });
+ expect(record.grandchild).toEqual({ executable: expectedNode, version: process.version });
}
}
@@ -158,21 +191,44 @@ describe("saved LastCode Node launchers", () => {
});
it.each([
- { failLeaf: "", exitCode: 0, runsCi: true },
- { failLeaf: "prepare-dependencies.ts", exitCode: 29, runsCi: false },
- { failLeaf: "lastcode-local-ci.ts", exitCode: 31, runsCi: true },
+ { targetVersion: "26.12.1", mode: "--quick", failLeaf: "", exitCode: 0, runsCi: true },
+ {
+ targetVersion: "26.12.1",
+ mode: "--quick",
+ failLeaf: "prepare-dependencies.ts",
+ exitCode: 29,
+ runsCi: false,
+ },
+ {
+ targetVersion: "26.12.1",
+ mode: "--quick",
+ failLeaf: "lastcode-local-ci.ts",
+ exitCode: 31,
+ runsCi: true,
+ },
+ { targetVersion: "24.13.1", mode: "--quick", failLeaf: "", exitCode: 0, runsCi: true },
+ { targetVersion: "24.13.1", mode: "--full", failLeaf: "", exitCode: 0, runsCi: true },
+ {
+ targetVersion: "24.13.1",
+ mode: "--full",
+ failLeaf: "lastcode-local-ci.ts",
+ exitCode: 31,
+ runsCi: true,
+ },
])(
- "pins Run Quick CI preparation and execution ($failLeaf, exit $exitCode)",
- ({ failLeaf, exitCode, runsCi }) => {
+ "pins preparation and uses target Node $targetVersion for $mode ($failLeaf, exit $exitCode)",
+ ({ targetVersion, mode, failLeaf, exitCode, runsCi }) => {
withLaunchFixture((fixture) => {
- const command = projectConfig.scripts.find(({ name }) => name === "Run Quick CI")!.command;
+ const command = projectConfig.scripts
+ .find(({ name }) => name === "Run Quick CI")!
+ .command.replace("--quick", mode);
const records = fixture.run(command, [], failLeaf, exitCode);
+ expectPinned(fixture, records);
expect(records.map(({ name, args }) => ({ name, args }))).toEqual([
{ name: "prepare-dependencies.ts", args: ["--for-ci"] },
- ...(runsCi ? [{ name: "lastcode-local-ci.ts", args: ["--quick"] }] : []),
+ ...(runsCi ? [{ name: "lastcode-local-ci.ts", args: ["--full", mode] }] : []),
]);
- expectPinned(fixture, records);
- });
+ }, targetVersion);
},
);
});
diff --git a/scripts/lastcode-setup.mjs b/scripts/lastcode-setup.mjs
index 42278eebdf9a2..13e10f0ee5d14 100644
--- a/scripts/lastcode-setup.mjs
+++ b/scripts/lastcode-setup.mjs
@@ -225,7 +225,7 @@ function main(argv) {
const options = parseOptions(argv);
if (options.help) {
console.log(
- "Usage: MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node scripts/lastcode-setup.mjs --enable-nightly-writes (--checkpoint-interval-seconds | --checkpoint-daily-at --checkpoint-time-zone ) [--trusted-project-action ]... [--dry-run]",
+ "Usage: MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node scripts/lastcode-setup.mjs --enable-nightly-writes (--checkpoint-interval-seconds | --checkpoint-daily-at --checkpoint-time-zone ) [--trusted-project-action ]... [--dry-run]",
);
console.log();
console.log(
diff --git a/scripts/lib/lastcode-git.ts b/scripts/lib/lastcode-git.ts
index f6669e3571154..15eec379cfaf5 100644
--- a/scripts/lib/lastcode-git.ts
+++ b/scripts/lib/lastcode-git.ts
@@ -1,6 +1,7 @@
// @effect-diagnostics nodeBuiltinImport:off -- Host-side Git helpers shared by local CI and the guarded merge.
// No installed dependencies: lastcode:merge runs from checkouts without node_modules.
import * as NodeChildProcess from "node:child_process";
+import * as NodeFS from "node:fs";
import * as NodePath from "node:path";
import { CiCommandFailure } from "./lastcode-ci-process.ts";
@@ -37,14 +38,22 @@ export function cleanGitEnvironment(
);
}
+const PROJECT_NODE_VERSION: string = JSON.parse(
+ NodeFS.readFileSync(NodePath.join(import.meta.dirname, "..", "..", "package.json"), "utf8"),
+).engines.node;
+
+// Transition: saved Project Actions in Settings still launch through `mise exec node@24.13.1`.
+// Remove the ^24.13.1 branch once they launch with the `engines.node` version.
+function isTransitionalNode24(major: number, minor: number, patch: number): boolean {
+ return major === 24 && (minor > 13 || (minor === 13 && patch >= 1));
+}
+
export function assertSupportedNodeVersion(version = process.versions.node): void {
const [major = 0, minor = 0, patch = 0] = version.split(".").map(Number);
- const supported = major === 24 && (minor > 13 || (minor === 13 && patch >= 1));
- if (!supported) {
- throw new Error(
- `LastCode local CI requires Node ^24.13.1, received ${version}. Run it through the package script so mise selects the project runtime.`,
- );
- }
+ if (version === PROJECT_NODE_VERSION || isTransitionalNode24(major, minor, patch)) return;
+ throw new Error(
+ `LastCode local CI requires Node ${PROJECT_NODE_VERSION} (root package.json engines.node) or ^24.13.1, received ${version}. Run it through the package script so mise selects the project runtime.`,
+ );
}
export function runProcess(
diff --git a/scripts/lib/server-test-pilot.mjs b/scripts/lib/server-test-pilot.mjs
index 2c8b46575c0d7..d254d6c41b460 100644
--- a/scripts/lib/server-test-pilot.mjs
+++ b/scripts/lib/server-test-pilot.mjs
@@ -3,7 +3,7 @@ import * as NodeAssert from "node:assert/strict";
const transferTest = "integration/transferBudgetV2.integration.test.ts";
export function assertPilotRuntime(version) {
- NodeAssert.equal(version, "v24.13.1", "Pilot requires checkpoint Node v24.13.1");
+ NodeAssert.equal(version, "v26.12.1", "Pilot requires checkpoint Node v26.12.1");
}
function strictFingerprint({ cpu: _cpu, ...identity }) {
diff --git a/scripts/lib/server-test-pilot.test.mjs b/scripts/lib/server-test-pilot.test.mjs
index 443471a67bdf9..d41ee643c980b 100644
--- a/scripts/lib/server-test-pilot.test.mjs
+++ b/scripts/lib/server-test-pilot.test.mjs
@@ -11,8 +11,8 @@ function fixture() {
cohort,
fingerprint: {
candidate: "candidate",
- node: "v24.13.1",
- testNode: "v24.13.1",
+ node: "v26.12.1",
+ testNode: "v26.12.1",
cpu: "CPU family A",
cpus: 4,
memoryGiB: 16,
@@ -79,7 +79,7 @@ it("accepts complete disjoint cohorts and rejects unusable benchmark evidence",
r[1].fingerprint[field] = "other";
}),
(r) => {
- for (const receipt of r) receipt.fingerprint.node = receipt.fingerprint.testNode = "v26.12.1";
+ for (const receipt of r) receipt.fingerprint.node = receipt.fingerprint.testNode = "v24.13.1";
},
(r) => {
r[1].discovery = ["other"];
diff --git a/scripts/prepare-dependencies.test.mjs b/scripts/prepare-dependencies.test.mjs
index f5a52892a94db..270ee8f62f3f9 100644
--- a/scripts/prepare-dependencies.test.mjs
+++ b/scripts/prepare-dependencies.test.mjs
@@ -13,7 +13,7 @@ const declarations = JSON.parse(
function declaredLauncher(name) {
const command = declarations.find((declaration) => declaration.name === name)?.command;
const match = command?.match(
- /^MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24\.13\.1 -- node -e "([^"]+)"$/,
+ /^MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26\.12\.1 -- node -e "([^"]+)"$/,
);
NodeAssert.ok(match, `${name} must use the pinned Node inline launcher`);
return match[1];
@@ -22,7 +22,12 @@ function declaredLauncher(name) {
function runDeclaredLauncher(name, target, anchor, env = {}) {
return NodeChildProcess.spawnSync(process.execPath, ["-e", declaredLauncher(name)], {
cwd: target,
- env: { ...process.env, T3CODE_PROJECT_ROOT: anchor, ...env },
+ env: {
+ ...process.env,
+ PATH: `${NodePath.dirname(process.execPath)}${NodePath.delimiter}${process.env.PATH ?? ""}`,
+ T3CODE_PROJECT_ROOT: anchor,
+ ...env,
+ },
encoding: "utf8",
});
}
@@ -177,6 +182,10 @@ function launcherFixture() {
NodePath.join(target, "scripts", "lastcode-local-ci.ts"),
child("ci", "FIXTURE_CI_STATUS"),
);
+ NodeFS.writeFileSync(
+ NodePath.join(target, "package.json"),
+ JSON.stringify({ scripts: { "lastcode:ci": "node scripts/lastcode-local-ci.ts --full" } }),
+ );
return { target, anchor };
}
@@ -211,7 +220,7 @@ it("declared CI launcher stops after preparation failure and propagates CI failu
.map((line) => JSON.parse(line)),
[
{ kind: "prepare", cwd: target, args: ["--for-ci"] },
- { kind: "ci", cwd: target, args: ["--quick"] },
+ { kind: "ci", cwd: target, args: ["--full", "--quick"] },
],
);
const success = runDeclaredLauncher("Run Quick CI", target, anchor);
diff --git a/scripts/server-test-pilot.ts b/scripts/server-test-pilot.ts
index 1bca38551e5c5..79c177bab85cf 100644
--- a/scripts/server-test-pilot.ts
+++ b/scripts/server-test-pilot.ts
@@ -8,7 +8,7 @@ import * as NodePath from "node:path";
import * as NodeURL from "node:url";
import { shardedTestFiles } from "./lib/sharded-tests.ts";
-NodeAssert.equal(process.version, "v24.13.1", "Pilot driver requires checkpoint Node v24.13.1");
+NodeAssert.equal(process.version, "v26.12.1", "Pilot driver requires checkpoint Node v26.12.1");
const root = NodePath.resolve(import.meta.dirname, "..");
const server = NodePath.join(root, "apps/server");
@@ -75,7 +75,7 @@ const result = NodeChildProcess.spawnSync(
...process.env,
VP_REMOTE_CACHE: "off",
VP_REMOTE_CACHE_URL: "",
- VP_NODE_VERSION: "24.13.1",
+ VP_NODE_VERSION: "26.12.1",
T3CODE_SERVER_PILOT_RUNTIME_PATH: runtimePath,
T3CODE_TRANSFER_BUDGET_REPORT_PATH: NodePath.join(output, "transfer.md"),
T3CODE_TRANSFER_BUDGET_RESULT_PATH: NodePath.join(output, "transfer.json"),
diff --git a/t3.json b/t3.json
index b8afad7f0871a..769953797f71d 100644
--- a/t3.json
+++ b/t3.json
@@ -10,38 +10,38 @@
},
{
"name": "Setup Worktree",
- "command": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node -e \"const r=require('node:child_process').spawnSync(process.execPath,[require('node:path').join(process.env.T3CODE_PROJECT_ROOT,'scripts','setup-worktree.ts')],{stdio:'inherit'});if(r.error)console.error(r.error.message);process.exit(r.status??1);\"",
+ "command": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node -e \"const r=require('node:child_process').spawnSync(process.execPath,[require('node:path').join(process.env.T3CODE_PROJECT_ROOT,'scripts','setup-worktree.ts')],{stdio:'inherit'});if(r.error)console.error(r.error.message);process.exit(r.status??1);\"",
"icon": "configure",
"runOnWorktreeCreate": true
},
{
"id": "lc-prepare-dependencies",
"name": "Prepare Dependencies",
- "command": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node -e \"const r=require('node:child_process').spawnSync(process.execPath,[require('node:path').join(process.env.T3CODE_PROJECT_ROOT,'scripts','prepare-dependencies.ts')],{stdio:'inherit'});if(r.error)console.error(r.error.message);process.exit(r.status??1);\"",
+ "command": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node -e \"const r=require('node:child_process').spawnSync(process.execPath,[require('node:path').join(process.env.T3CODE_PROJECT_ROOT,'scripts','prepare-dependencies.ts')],{stdio:'inherit'});if(r.error)console.error(r.error.message);process.exit(r.status??1);\"",
"icon": "configure"
},
{
"id": "lc-wait-for-checkpoint",
"name": "Wait for Checkpoint",
- "command": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node \"$T3CODE_PROJECT_ROOT/scripts/lastcode-wait-for-checkpoint.ts\"",
+ "command": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node \"$T3CODE_PROJECT_ROOT/scripts/lastcode-wait-for-checkpoint.ts\"",
"icon": "test"
},
{
"id": "lc-local-ci",
"name": "Run Quick CI",
- "command": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node -e \"for(const args of [[require('node:path').join(process.env.T3CODE_PROJECT_ROOT,'scripts','prepare-dependencies.ts'),'--for-ci'],['scripts/lastcode-local-ci.ts','--quick']]){const r=require('node:child_process').spawnSync(process.execPath,args,{stdio:'inherit'});if(r.error)console.error(r.error.message);if(r.status===0)continue;process.exit(r.status??1);}\"",
+ "command": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node -e \"for(const [command,args] of [[process.execPath,[require('node:path').join(process.env.T3CODE_PROJECT_ROOT,'scripts','prepare-dependencies.ts'),'--for-ci']],['/bin/sh',['-c',JSON.parse(require('node:fs').readFileSync('package.json','utf8')).scripts['lastcode:ci']+' --quick']]]){const r=require('node:child_process').spawnSync(command,args,{stdio:'inherit'});if(r.error)console.error(r.error.message);if(r.status===0)continue;process.exit(r.status??1);}\"",
"icon": "test"
},
{
"id": "lc-build-local-package",
"name": "Build Local Package",
- "command": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node \"$T3CODE_PROJECT_ROOT/scripts/lastcode-build-local-package.ts\" run",
+ "command": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node \"$T3CODE_PROJECT_ROOT/scripts/lastcode-build-local-package.ts\" run",
"icon": "build"
},
{
"id": "lc-build-intel-package",
"name": "Build Intel package (macOS)",
- "command": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@24.13.1 -- node scripts/lastcode-build-intel-package.ts run",
+ "command": "MISE_ACTIVATE_AGGRESSIVE=1 mise exec node@26.12.1 -- node scripts/lastcode-build-intel-package.ts run",
"icon": "build"
}
]