Wrap T3 Code apps with optional agent CLI paths

- Split base desktop/server derivations from wrapper layers
- Add optional PATH injection for codex, claudeCode, and opencode
- Update flake inputs and lock entries for nixpkgs/llm-agents
This commit is contained in:
2026-04-28 12:47:38 +03:00
parent 71c3a101dd
commit cd931c951e
6 changed files with 102 additions and 54 deletions
Generated
+18 -4
View File
@@ -101,9 +101,7 @@
"blueprint": "blueprint", "blueprint": "blueprint",
"bun2nix": "bun2nix", "bun2nix": "bun2nix",
"flake-parts": "flake-parts", "flake-parts": "flake-parts",
"nixpkgs": [ "nixpkgs": "nixpkgs",
"nixpkgs"
],
"systems": "systems", "systems": "systems",
"treefmt-nix": "treefmt-nix" "treefmt-nix": "treefmt-nix"
}, },
@@ -122,6 +120,22 @@
} }
}, },
"nixpkgs": { "nixpkgs": {
"locked": {
"lastModified": 1776949667,
"narHash": "sha256-GMSVw35Q+294GlrTUKlx087E31z7KurReQ1YHSKp5iw=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "01fbdeef22b76df85ea168fbfe1bfd9e63681b30",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1776734388, "lastModified": 1776734388,
"narHash": "sha256-vl3dkhlE5gzsItuHoEMVe+DlonsK+0836LIRDnm6MXQ=", "narHash": "sha256-vl3dkhlE5gzsItuHoEMVe+DlonsK+0836LIRDnm6MXQ=",
@@ -140,7 +154,7 @@
"root": { "root": {
"inputs": { "inputs": {
"llm-agents": "llm-agents", "llm-agents": "llm-agents",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs_2",
"t3code": "t3code" "t3code": "t3code"
} }
}, },
+1 -4
View File
@@ -3,10 +3,7 @@
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
llm-agents = { llm-agents.url = "github:numtide/llm-agents.nix";
url = "github:numtide/llm-agents.nix";
inputs.nixpkgs.follows = "nixpkgs";
};
t3code.url = "github:pingdotgg/t3code"; t3code.url = "github:pingdotgg/t3code";
t3code.flake = false; t3code.flake = false;
}; };
+20 -16
View File
@@ -60,25 +60,25 @@ in {
''; '';
buildPhase = '' buildPhase = ''
runHook preBuild runHook preBuild
export HOME="$TMPDIR" export HOME="$TMPDIR"
export BUN_INSTALL_CACHE_DIR="$(mktemp -d)" export BUN_INSTALL_CACHE_DIR="$(mktemp -d)"
${extraEnv} ${extraEnv}
bun install \ bun install \
--frozen-lockfile \ --frozen-lockfile \
--ignore-scripts \ --ignore-scripts \
--backend=copyfile \ --backend=copyfile \
--linker=hoisted \ --linker=hoisted \
--no-progress \ --no-progress \
${renderBunInstallFlags installFlags} ${renderBunInstallFlags installFlags}
${renderBunFilters filters} ${renderBunFilters filters}
bun --bun ${./scripts/canonicalize-node-modules.ts} bun --bun ${./scripts/canonicalize-node-modules.ts}
bun --bun ${./scripts/normalize-bun-binaries.ts} bun --bun ${./scripts/normalize-bun-binaries.ts}
runHook postBuild runHook postBuild
''; '';
installPhase = '' installPhase = ''
@@ -109,7 +109,11 @@ ${renderBunFilters filters}
mkdir -p ./node_modules mkdir -p ./node_modules
cp -R ${nodeModules}/. ./node_modules/ cp -R ${nodeModules}/. ./node_modules/
chmod -R u+rwX node_modules chmod -R u+rwX node_modules
if [ ${if chmodBins then "true" else "false"} = true ] && [ -d node_modules/.bin ]; then if [ ${
if chmodBins
then "true"
else "false"
} = true ] && [ -d node_modules/.bin ]; then
chmod -R u+x node_modules/.bin chmod -R u+x node_modules/.bin
fi fi
patchShebangs node_modules patchShebangs node_modules
-1
View File
@@ -49,7 +49,6 @@
export npm_config_build_from_source=true export npm_config_build_from_source=true
''; '';
}; };
in { in {
inherit inherit
t3codeNodeModulesBase t3codeNodeModulesBase
+36 -16
View File
@@ -3,6 +3,7 @@
src, src,
asar, asar,
stdenv, stdenv,
symlinkJoin,
bun, bun,
codex ? null, codex ? null,
claudeCode ? null, claudeCode ? null,
@@ -35,11 +36,7 @@
pname = "t3code-desktop"; pname = "t3code-desktop";
version = desktopPackageJson.version; version = desktopPackageJson.version;
in basePackage = stdenv.mkDerivation (finalAttrs: {
assert lib.assertMsg (!withCodex || codex != null) "withCodex requires a codex package";
assert lib.assertMsg (!withClaudeCode || claudeCode != null) "withClaudeCode requires a claudeCode package";
assert lib.assertMsg (!withOpencode || opencode != null) "withOpencode requires an opencode package";
stdenv.mkDerivation (finalAttrs: {
inherit pname version; inherit pname version;
inherit src; inherit src;
@@ -178,16 +175,9 @@ in
--set-default ELECTRON_FORCE_IS_PACKAGED 1 \ --set-default ELECTRON_FORCE_IS_PACKAGED 1 \
--set-default ELECTRON_IS_DEV 0 \ --set-default ELECTRON_IS_DEV 0 \
--prefix PATH : ${lib.makeBinPath [ --prefix PATH : ${lib.makeBinPath [
git git
xdg-utils xdg-utils
]} \ ]} \
${lib.optionalString withCodex ''
--prefix PATH : "${lib.makeBinPath [ codex ]}" \
''}${lib.optionalString withClaudeCode ''
--prefix PATH : "${lib.makeBinPath [ claudeCode ]}" \
''}${lib.optionalString withOpencode ''
--prefix PATH : "${lib.makeBinPath [ opencode ]}" \
''} \
--add-flags "$out/share/${pname}/resources/app.asar" --add-flags "$out/share/${pname}/resources/app.asar"
export out export out
@@ -205,4 +195,34 @@ in
platforms = ["x86_64-linux"]; platforms = ["x86_64-linux"];
sourceProvenance = with lib.sourceTypes; [fromSource]; sourceProvenance = with lib.sourceTypes; [fromSource];
}; };
}) });
withAgentPath = withCodex || withClaudeCode || withOpencode;
agentPath = lib.makeBinPath (
lib.optionals withCodex [codex]
++ lib.optionals withClaudeCode [claudeCode]
++ lib.optionals withOpencode [opencode]
);
in
assert lib.assertMsg (!withCodex || codex != null) "withCodex requires a codex package";
assert lib.assertMsg (!withClaudeCode || claudeCode != null) "withClaudeCode requires a claudeCode package";
assert lib.assertMsg (!withOpencode || opencode != null) "withOpencode requires an opencode package";
if withAgentPath
then
symlinkJoin {
inherit pname version;
name = "${pname}-${version}";
paths = [basePackage];
nativeBuildInputs = [makeWrapper];
postBuild = ''
wrapProgram "$out/bin/t3code" \
--prefix PATH : "${agentPath}"
rm -f "$out/share/applications/t3code.desktop"
install -Dm644 ${basePackage}/share/applications/t3code.desktop \
"$out/share/applications/t3code.desktop"
substituteInPlace "$out/share/applications/t3code.desktop" \
--replace-fail "${basePackage}/bin/t3code" "$out/bin/t3code"
'';
meta = basePackage.meta;
}
else basePackage
+27 -13
View File
@@ -2,6 +2,7 @@
lib, lib,
src, src,
stdenv, stdenv,
symlinkJoin,
bun, bun,
codex ? null, codex ? null,
claudeCode ? null, claudeCode ? null,
@@ -28,11 +29,7 @@
pname = "t3code-server"; pname = "t3code-server";
version = serverPackageJson.version; version = serverPackageJson.version;
in basePackage = stdenv.mkDerivation (finalAttrs: {
assert lib.assertMsg (!withCodex || codex != null) "withCodex requires a codex package";
assert lib.assertMsg (!withClaudeCode || claudeCode != null) "withClaudeCode requires a claudeCode package";
assert lib.assertMsg (!withOpencode || opencode != null) "withOpencode requires an opencode package";
stdenv.mkDerivation (finalAttrs: {
inherit pname version; inherit pname version;
inherit src; inherit src;
@@ -116,13 +113,6 @@ in
cp -R --no-preserve=mode packages/shared "$out/libexec/t3code/packages/" cp -R --no-preserve=mode packages/shared "$out/libexec/t3code/packages/"
makeWrapper ${lib.getExe nodejs} "$out/bin/t3" \ makeWrapper ${lib.getExe nodejs} "$out/bin/t3" \
${lib.optionalString withCodex ''
--prefix PATH : "${lib.makeBinPath [ codex ]}" \
''}${lib.optionalString withClaudeCode ''
--prefix PATH : "${lib.makeBinPath [ claudeCode ]}" \
''}${lib.optionalString withOpencode ''
--prefix PATH : "${lib.makeBinPath [ opencode ]}" \
''} \
--add-flags "$out/libexec/t3code/apps/server/dist/bin.mjs" --add-flags "$out/libexec/t3code/apps/server/dist/bin.mjs"
runHook postInstall runHook postInstall
@@ -136,4 +126,28 @@ in
platforms = lib.platforms.unix; platforms = lib.platforms.unix;
sourceProvenance = with lib.sourceTypes; [fromSource]; sourceProvenance = with lib.sourceTypes; [fromSource];
}; };
}) });
withAgentPath = withCodex || withClaudeCode || withOpencode;
agentPath = lib.makeBinPath (
lib.optionals withCodex [codex]
++ lib.optionals withClaudeCode [claudeCode]
++ lib.optionals withOpencode [opencode]
);
in
assert lib.assertMsg (!withCodex || codex != null) "withCodex requires a codex package";
assert lib.assertMsg (!withClaudeCode || claudeCode != null) "withClaudeCode requires a claudeCode package";
assert lib.assertMsg (!withOpencode || opencode != 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