{ lib, src, stdenv, symlinkJoin, bun, codexPackage ? null, claudeCodePackage ? null, makeBinaryWrapper, node-gyp, nodejs, opencodePackage ? null, python3, writableTmpDirAsHomeHook, withClaudeCode ? false, withCodex ? false, withOpencode ? false, }: let common = import ../common.nix { inherit lib stdenv bun nodejs writableTmpDirAsHomeHook ; }; serverPackageJson = lib.importJSON "${src}/apps/server/package.json"; pname = "t3code-server"; version = serverPackageJson.version; basePackage = stdenv.mkDerivation (finalAttrs: { inherit pname version; inherit src; strictDeps = true; nodeModules = common.mkNodeModules { inherit (finalAttrs) pname version src; outputHash = "sha256-eXNOHRuNv9XFhXmsFtkunZswtRPd8gzJB1Jdw2DxYZY="; filters = [ "." "./apps/server" "./apps/web" "./packages/client-runtime" "./packages/contracts" "./packages/effect-acp" "./packages/effect-codex-app-server" "./packages/shared" ]; }; runtimeNodeModules = common.mkNodeModules { inherit (finalAttrs) pname version src; outputHash = "sha256-EcUsCt8liYnmzsDXzdwfLbMEk4/OYHB6DkcjjvmTWEM="; installFlags = [ "--production" ]; filters = [ "." "./apps/server" "./apps/web" "./packages/client-runtime" "./packages/contracts" "./packages/effect-acp" "./packages/effect-codex-app-server" "./packages/shared" ]; }; nativeBuildInputs = [ bun makeBinaryWrapper node-gyp nodejs python3 writableTmpDirAsHomeHook ]; configurePhase = common.mkNodePtyConfigurePhase { nodeModules = finalAttrs.nodeModules; }; buildPhase = '' runHook preBuild export HOME="$TMPDIR" export BUN_INSTALL_CACHE_DIR="$(mktemp -d)" bun run --cwd apps/web build bun run --cwd apps/server build runHook postBuild ''; installPhase = '' runHook preInstall mkdir -p "$out/libexec/t3code/apps/server" mkdir -p "$out/libexec/t3code/apps" mkdir -p "$out/libexec/t3code/packages" cp -R --no-preserve=mode ${finalAttrs.runtimeNodeModules} "$out/libexec/t3code/node_modules" chmod -R u+rwX "$out/libexec/t3code/node_modules" rm -rf "$out/libexec/t3code/node_modules/node-pty" cp -R --no-preserve=mode node_modules/node-pty "$out/libexec/t3code/node_modules/" cp -R --no-preserve=mode apps/server/dist "$out/libexec/t3code/apps/server/" cp -R --no-preserve=mode apps/web "$out/libexec/t3code/apps/" cp -R --no-preserve=mode packages/client-runtime "$out/libexec/t3code/packages/" cp -R --no-preserve=mode packages/contracts "$out/libexec/t3code/packages/" cp -R --no-preserve=mode packages/effect-acp "$out/libexec/t3code/packages/" cp -R --no-preserve=mode packages/effect-codex-app-server "$out/libexec/t3code/packages/" cp -R --no-preserve=mode packages/shared "$out/libexec/t3code/packages/" makeWrapper ${lib.getExe nodejs} "$out/bin/t3" \ --add-flags "$out/libexec/t3code/apps/server/dist/bin.mjs" runHook postInstall ''; meta = { description = "T3 Code web/server app"; homepage = "https://github.com/pingdotgg/t3code"; license = lib.licenses.mit; mainProgram = "t3"; platforms = lib.platforms.unix; sourceProvenance = with lib.sourceTypes; [fromSource]; }; }); withAgentPath = withCodex || withClaudeCode || withOpencode; agentPath = lib.makeBinPath ( lib.optionals withCodex [codexPackage] ++ lib.optionals withClaudeCode [claudeCodePackage] ++ lib.optionals withOpencode [opencodePackage] ); in assert lib.assertMsg (!withCodex || codexPackage != null) "withCodex requires a codex package"; assert lib.assertMsg (!withClaudeCode || claudeCodePackage != null) "withClaudeCode requires a claudeCode package"; assert lib.assertMsg (!withOpencode || opencodePackage != null) "withOpencode requires an opencode package"; if withAgentPath then symlinkJoin { inherit pname version; name = "${pname}-${version}"; paths = [basePackage]; nativeBuildInputs = [makeBinaryWrapper]; postBuild = '' wrapProgram "$out/bin/t3" \ --prefix PATH : "${agentPath}" ''; meta = basePackage.meta; } else basePackage