Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/server/src/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* of evaluation) loads; everything else defers to the real CLI in ./binCli.ts.
*/
import { isEntrypoint } from "./entrypoint.ts";
import { enableCliCompileCache } from "./cliCompileCache.ts";

if (
isEntrypoint({
Expand Down Expand Up @@ -35,6 +36,7 @@ if (
const { runAcpMcpCliFastPath } = await import("./mcp/AcpMcpStdioBridge.ts");
await runAcpMcpCliFastPath(command, process.argv.slice(3));
} else {
enableCliCompileCache();
// Windows desktop launches without stdin; attach before reading, except on fast paths using pipes.
const { attachConsoleStdin } = await import("./cli/consoleStdin.ts");
attachConsoleStdin();
Expand Down
69 changes: 69 additions & 0 deletions apps/server/src/cliCompileCache.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// @effect-diagnostics nodeBuiltinImport:off -- Resolves the real CLI entrypoint for subprocess tests.
import * as NodeURL from "node:url";
import * as NodeServices from "@effect/platform-node/NodeServices";
import { expect, it } from "@effect/vitest";
import * as Effect from "effect/Effect";
import * as FileSystem from "effect/FileSystem";
import * as Stream from "effect/Stream";
import { ChildProcess, ChildProcessSpawner } from "effect/process";

it.live("enables CLI caching while respecting overrides and unavailable storage", () =>
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
const root = yield* fs.makeTempDirectoryScoped({ prefix: "t3-cli-cache-test-" });
const report = `import { getCompileCacheDir, registerHooks } from 'node:module'; registerHooks({ resolve(specifier, context, nextResolve) { if (specifier === './binCli.ts') console.error('CACHE=' + (getCompileCacheDir() ?? 'disabled')); return nextResolve(specifier, context); } });`;
const run = Effect.fn("cliCompileCache.test.run")(function* (env: Record<string, string>) {
const child = yield* spawner.spawn(
ChildProcess.make(
process.execPath,
[
"--experimental-strip-types",
"--import",
`data:text/javascript,${encodeURIComponent(report)}`,
NodeURL.fileURLToPath(new URL("./bin.ts", import.meta.url)),
"--help",
],
{
env: {
XDG_CACHE_HOME: `${root}/cache`,
T3CODE_HOME: `${root}/home`,
NODE_COMPILE_CACHE: undefined,
NODE_DISABLE_COMPILE_CACHE: undefined,
APPIMAGE: "",
...env,
},
},
),
);
return yield* Effect.all(
{
stdout: child.stdout.pipe(Stream.decodeText(), Stream.mkString),
stderr: child.stderr.pipe(Stream.decodeText(), Stream.mkString),
exitCode: child.exitCode.pipe(Effect.map(Number)),
},
{ concurrency: "unbounded" },
);
}, Effect.scoped);
const normal = yield* run({});
expect(normal.exitCode).toBe(0);
expect(normal.stderr.replaceAll("\\", "/")).toContain(
`CACHE=${root}/cache/t3code/compile-cache`.replaceAll("\\", "/"),
);
const appImage = yield* run({ APPIMAGE: `${root}/T3Code.AppImage` });
expect(appImage.exitCode).toBe(0);
expect(appImage.stderr).toContain("CACHE=disabled");
const existing = yield* run({ NODE_COMPILE_CACHE: `${root}/explicit` });
expect(existing.exitCode).toBe(0);
expect(existing.stderr.replaceAll("\\", "/")).toContain(
`${root}/explicit`.replaceAll("\\", "/"),
);
const disabled = yield* run({ NODE_DISABLE_COMPILE_CACHE: "1" });
expect(disabled.exitCode).toBe(0);
expect(disabled.stderr).toContain("CACHE=disabled");
yield* fs.writeFileString(`${root}/blocked`, "not a directory");
const unavailable = yield* run({ XDG_CACHE_HOME: `${root}/blocked` });
expect(unavailable.exitCode).toBe(0);
expect(unavailable.stderr).toContain("CACHE=disabled");
}).pipe(Effect.scoped, Effect.provide(NodeServices.layer)),
);
17 changes: 17 additions & 0 deletions apps/server/src/cliCompileCache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// @effect-diagnostics nodeBuiltinImport:off -- Runs before the CLI's Effect runtime loads.
import * as NodeModule from "node:module";
import * as NodeOS from "node:os";
import * as NodePath from "node:path";
import * as NodeSea from "node:sea";

export function enableCliCompileCache(): void {
try {
// AppImage paths change each launch; SEA has no separate modules to cache.
if (process.env.APPIMAGE || NodeSea.isSea()) return;
const cacheRoot =
process.env.XDG_CACHE_HOME ||
// oxlint-disable-next-line t3code/no-global-process-runtime -- Runs before the CLI's Effect runtime loads.
(process.platform === "linux" ? NodePath.join(NodeOS.homedir(), ".cache") : NodeOS.tmpdir());
NodeModule.enableCompileCache(NodePath.join(cacheRoot, "t3code", "compile-cache"));
} catch {}
}
Loading