Rename package directories to match t3code outputs

- Move server and desktop Nix packages under `packages/t3code-*`
- Update flake outputs and README references to the new names
This commit is contained in:
2026-04-25 12:49:38 +03:00
parent 0cf92db43b
commit d13dbbaedd
6 changed files with 29 additions and 31 deletions
@@ -0,0 +1,97 @@
#!/usr/bin/env node
import * as FS from "node:fs";
import * as Path from "node:path";
class BuildNixDesktopPackageError extends Error {
constructor(message) {
super(message);
this.name = "BuildNixDesktopPackageError";
}
}
function parseArgs(argv) {
let outputDir;
for (let index = 0; index < argv.length; index += 1) {
const arg = argv[index];
if (arg === "--output-dir") {
outputDir = argv[index + 1];
index += 1;
}
}
if (!outputDir) {
throw new BuildNixDesktopPackageError("Missing required --output-dir argument.");
}
return { outputDir };
}
function assertPathExists(path, description) {
if (!FS.existsSync(path)) {
throw new BuildNixDesktopPackageError(
`Missing ${description} at ${path}. Run 'bun run build:desktop' first.`,
);
}
}
function readJson(path) {
return JSON.parse(FS.readFileSync(path, "utf8"));
}
function main() {
const { outputDir } = parseArgs(process.argv.slice(2));
const repoRoot = process.cwd();
const packagedAppDir = Path.resolve(repoRoot, outputDir);
const rootPackageJson = readJson(Path.join(repoRoot, "package.json"));
const desktopPackageJson = readJson(Path.join(repoRoot, "apps/desktop/package.json"));
const serverPackageJson = readJson(Path.join(repoRoot, "apps/server/package.json"));
const desktopDistDir = Path.join(repoRoot, "apps/desktop/dist-electron");
const desktopResourcesDir = Path.join(repoRoot, "apps/desktop/resources");
const serverDistDir = Path.join(repoRoot, "apps/server/dist");
const bundledClientIndex = Path.join(serverDistDir, "client/index.html");
assertPathExists(desktopDistDir, "desktop bundle");
assertPathExists(Path.join(desktopDistDir, "main.cjs"), "desktop main entry");
assertPathExists(Path.join(desktopDistDir, "preload.cjs"), "desktop preload entry");
assertPathExists(desktopResourcesDir, "desktop resources");
assertPathExists(serverDistDir, "server bundle");
assertPathExists(Path.join(serverDistDir, "bin.mjs"), "server entry");
assertPathExists(bundledClientIndex, "bundled desktop web client");
FS.rmSync(packagedAppDir, { recursive: true, force: true });
FS.mkdirSync(Path.join(packagedAppDir, "apps/desktop"), { recursive: true });
FS.mkdirSync(Path.join(packagedAppDir, "apps/server"), { recursive: true });
FS.cpSync(desktopDistDir, Path.join(packagedAppDir, "apps/desktop/dist-electron"), {
recursive: true,
});
FS.cpSync(desktopResourcesDir, Path.join(packagedAppDir, "apps/desktop/resources"), {
recursive: true,
});
FS.cpSync(serverDistDir, Path.join(packagedAppDir, "apps/server/dist"), {
recursive: true,
});
const packageJson = {
name: "t3code",
version: serverPackageJson.version ?? desktopPackageJson.version,
private: true,
description: "T3 Code desktop build",
author: "T3 Tools",
main: "apps/desktop/dist-electron/main.cjs",
t3codeCommitHash: "unknown",
packageManager: rootPackageJson.packageManager,
};
FS.writeFileSync(
Path.join(packagedAppDir, "package.json"),
`${JSON.stringify(packageJson, null, 2)}\n`,
"utf8",
);
}
main();
+164
View File
@@ -0,0 +1,164 @@
{
lib,
src,
asar,
stdenv,
bun,
copyDesktopItems,
electron_40,
gcc,
git,
gnumake,
makeDesktopItem,
makeWrapper,
node-gyp,
nodejs,
pkg-config,
python3,
writableTmpDirAsHomeHook,
xdg-utils,
}: let
common = import ../common.nix {
inherit
lib
stdenv
bun
nodejs
writableTmpDirAsHomeHook
;
};
desktopPackageJson = lib.importJSON "${src}/apps/desktop/package.json";
pname = "t3code-desktop";
version = desktopPackageJson.version;
desktopItem = makeDesktopItem {
name = "t3code";
desktopName = "T3 Code";
exec = "t3code %U";
icon = "t3code";
categories = ["Development"];
startupWMClass = "t3code";
};
in
stdenv.mkDerivation (finalAttrs: {
inherit pname version;
inherit src;
strictDeps = true;
patches = [./desktop-nix-autoupdate.patch];
nodeModules = common.mkNodeModules {
inherit (finalAttrs) pname version src;
outputHash = "sha256-vOCDwW/t7CbqHyeDE6Nvnlq0c9NO5T/2h1NJKLERGSs=";
filters = [
"."
"./apps/desktop"
"./apps/server"
"./apps/web"
"./packages/client-runtime"
"./packages/contracts"
"./packages/effect-acp"
"./packages/effect-codex-app-server"
"./packages/shared"
];
impureEnvVars =
lib.fetchers.proxyImpureEnvVars
++ [
"GIT_PROXY_COMMAND"
"SOCKS_SERVER"
];
extraNativeBuildInputs = [
gcc
gnumake
pkg-config
python3
];
extraEnv = ''
export ELECTRON_SKIP_BINARY_DOWNLOAD=1
export PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1
export npm_config_build_from_source=true
'';
};
nativeBuildInputs = [
asar
bun
copyDesktopItems
gcc
gnumake
makeWrapper
node-gyp
nodejs
pkg-config
python3
writableTmpDirAsHomeHook
];
desktopItems = [desktopItem];
env = {
ELECTRON_SKIP_BINARY_DOWNLOAD = "1";
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD = "1";
npm_config_build_from_source = "true";
npm_config_nodedir = "${nodejs}";
};
configurePhase = common.mkNodePtyConfigurePhase {
nodeModules = finalAttrs.nodeModules;
chmodBins = true;
};
buildPhase = ''
runHook preBuild
export HOME="$TMPDIR"
export BUN_INSTALL_CACHE_DIR="$(mktemp -d)"
bun run build:desktop
node ${./build-nix-desktop-package.mjs} --output-dir packaged-app
cp -R node_modules packaged-app/node_modules
chmod -R u+rwX packaged-app/node_modules
patchShebangs packaged-app/node_modules
find packaged-app/node_modules -xtype l -delete
rm -rf packaged-app/node_modules/electron
rm -f packaged-app/node_modules/.bin/electron
asar pack --unpack='{*.node}' packaged-app packaged-app.asar
runHook postBuild
'';
installPhase = ''
runHook preInstall
install -d "$out/share/${pname}/resources"
install -Dm644 packaged-app.asar "$out/share/${pname}/resources/app.asar"
if [ -d packaged-app.asar.unpacked ]; then
cp -R packaged-app.asar.unpacked "$out/share/${pname}/resources/"
fi
install -Dm644 apps/desktop/resources/icon.png \
"$out/share/icons/hicolor/512x512/apps/t3code.png"
makeWrapper ${lib.getExe electron_40} "$out/bin/t3code" \
--set T3CODE_DISABLE_AUTO_UPDATE 1 \
--set-default ELECTRON_FORCE_IS_PACKAGED 1 \
--set-default ELECTRON_IS_DEV 0 \
--prefix PATH : ${lib.makeBinPath [
git
xdg-utils
]} \
--add-flags "$out/share/${pname}/resources/app.asar"
runHook postInstall
'';
meta = {
description = "T3 Code desktop app";
homepage = "https://github.com/pingdotgg/t3code";
license = lib.licenses.mit;
mainProgram = "t3code";
platforms = ["x86_64-linux"];
sourceProvenance = with lib.sourceTypes; [fromSource];
};
})
@@ -0,0 +1,37 @@
diff --git a/apps/desktop/src/updateState.test.ts b/apps/desktop/src/updateState.test.ts
index c2bb4ba1..181c4d55 100644
--- a/apps/desktop/src/updateState.test.ts
+++ b/apps/desktop/src/updateState.test.ts
@@ -116,6 +116,19 @@ describe("getAutoUpdateDisabledReason", () => {
).toContain("T3CODE_DISABLE_AUTO_UPDATE");
});
+ it("explains that env-disabled updates can come from package-managed installs", () => {
+ expect(
+ getAutoUpdateDisabledReason({
+ isDevelopment: false,
+ isPackaged: true,
+ platform: "linux",
+ appImage: undefined,
+ disabledByEnv: true,
+ hasUpdateFeedConfig: true,
+ }),
+ ).toContain("Nix");
+ });
+
it("reports linux non-AppImage builds as disabled", () => {
expect(
getAutoUpdateDisabledReason({
diff --git a/apps/desktop/src/updateState.ts b/apps/desktop/src/updateState.ts
index 928bb408..9ebdf331 100644
--- a/apps/desktop/src/updateState.ts
+++ b/apps/desktop/src/updateState.ts
@@ -43,7 +43,7 @@ export function getAutoUpdateDisabledReason(args: {
return "Automatic updates are only available in packaged production builds.";
}
if (args.disabledByEnv) {
- return "Automatic updates are disabled by the T3CODE_DISABLE_AUTO_UPDATE setting.";
+ return "Automatic updates are disabled by the T3CODE_DISABLE_AUTO_UPDATE setting, which is used for package-managed installs such as Nix.";
}
if (args.platform === "linux" && !args.appImage) {
return "Automatic updates on Linux require running the AppImage build.";