11/**
22 * Nix Package Manager
33 *
4- * Submits packages to nixpkgs via Pull Request .
5- * Target repo: NixOS/nixpkgs
4+ * Submits packages to a custom flake repository (profullstack/pairux-nix) .
5+ * Users can install via: nix profile install github:profullstack/pairux-nix
66 */
77
88import { BasePackageManager } from './base.js' ;
99import type { ReleaseInfo , SubmissionResult } from './types.js' ;
1010
11- const NIXPKGS_OWNER = 'NixOS ' ;
12- const NIXPKGS_REPO = 'nixpkgs ' ;
11+ const FLAKE_OWNER = 'profullstack ' ;
12+ const FLAKE_REPO = 'pairux-nix ' ;
1313const PACKAGE_NAME = 'pairux' ;
1414
1515export class NixPackageManager extends BasePackageManager {
@@ -24,20 +24,18 @@ export class NixPackageManager extends BasePackageManager {
2424
2525 async checkExisting ( version : string ) : Promise < boolean > {
2626 try {
27- // Check if there's already an open PR for this version
28- const prs = await this . githubRequest < { title : string } [ ] > (
29- `/repos/${ NIXPKGS_OWNER } /${ NIXPKGS_REPO } /pulls?state=open&per_page=100`
30- ) ;
31-
32- return prs . some (
33- ( pr ) => pr . title . toLowerCase ( ) . includes ( PACKAGE_NAME ) && pr . title . includes ( version )
34- ) ;
27+ // Check if the version is already in our flake repo
28+ const file = await this . getFileContent ( FLAKE_OWNER , FLAKE_REPO , 'flake.nix' ) ;
29+ if ( ! file ) return false ;
30+
31+ // Check if version is in the flake
32+ return file . content . includes ( `version = "${ version } "` ) ;
3533 } catch {
3634 return false ;
3735 }
3836 }
3937
40- generateManifest ( release : ReleaseInfo ) : Promise < string > {
38+ generateManifest ( release : ReleaseInfo ) : Promise < Record < string , string > > {
4139 // Find assets for different architectures
4240 const x86AppImage = this . findAsset (
4341 release ,
@@ -46,98 +44,178 @@ export class NixPackageManager extends BasePackageManager {
4644
4745 const x86Sha256 = release . checksums . get ( x86AppImage ?. name ?? '' ) ?? '' ;
4846
49- // Generate Nix expression
50- const nixExpr = `{ lib
51- , appimageTools
52- , fetchurl
53- }:
47+ // Generate flake.nix
48+ const flakeNix = `{
49+ description = "PairUX - Collaborative screen sharing with remote control";
50+
51+ inputs = {
52+ nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
53+ flake-utils.url = "github:numtide/flake-utils";
54+ };
55+
56+ outputs = { self, nixpkgs, flake-utils }:
57+ flake-utils.lib.eachSystem [ "x86_64-linux" ] (system:
58+ let
59+ pkgs = nixpkgs.legacyPackages.\${system};
60+ pname = "${ PACKAGE_NAME } ";
61+ version = "${ release . version } ";
62+
63+ src = pkgs.fetchurl {
64+ url = "https://github.com/profullstack/pairux.com/releases/download/v\${version}/PairUX-\${version}-x86_64.AppImage";
65+ sha256 = "${ x86Sha256 !== '' ? x86Sha256 : 'sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=' } ";
66+ };
67+
68+ appimageContents = pkgs.appimageTools.extractType2 { inherit pname version src; };
69+ in
70+ {
71+ packages = {
72+ default = pkgs.appimageTools.wrapType2 {
73+ inherit pname version src;
74+
75+ extraInstallCommands = ''
76+ install -m 444 -D \${appimageContents}/pairux.desktop $out/share/applications/pairux.desktop
77+ install -m 444 -D \${appimageContents}/usr/share/icons/hicolor/512x512/apps/pairux.png \\
78+ $out/share/icons/hicolor/512x512/apps/pairux.png 2>/dev/null || true
79+ substituteInPlace $out/share/applications/pairux.desktop \\
80+ --replace 'Exec=AppRun' 'Exec=pairux' 2>/dev/null || true
81+ '';
82+
83+ meta = with pkgs.lib; {
84+ description = "Collaborative screen sharing with remote control";
85+ longDescription = ''
86+ PairUX is a collaborative screen sharing application with simultaneous
87+ remote mouse and keyboard control. Like Screenhero, but open source.
88+ Perfect for pair programming, remote support, and collaboration.
89+ '';
90+ homepage = "https://pairux.com";
91+ changelog = "https://github.com/profullstack/pairux.com/releases/tag/v\${version}";
92+ license = licenses.mit;
93+ maintainers = [ ];
94+ platforms = [ "x86_64-linux" ];
95+ mainProgram = "pairux";
96+ sourceProvenance = with sourceTypes; [ binaryNativeCode ];
97+ };
98+ };
99+
100+ ${ PACKAGE_NAME } = self.packages.\${system}.default;
101+ };
102+
103+ apps.default = {
104+ type = "app";
105+ program = "\${self.packages.\${system}.default}/bin/pairux";
106+ };
107+ }
108+ );
109+ }
110+ ` ;
111+
112+ // Generate README
113+ const readme = `# PairUX Nix Flake
114+
115+ Nix flake for [PairUX](https://pairux.com) - Collaborative screen sharing with remote control.
116+
117+ ## Installation
118+
119+ ### Using flakes (recommended)
120+
121+ \`\`\`bash
122+ # Install directly
123+ nix profile install github:profullstack/pairux-nix
124+
125+ # Or run without installing
126+ nix run github:profullstack/pairux-nix
127+ \`\`\`
54128
55- let
56- pname = "${ PACKAGE_NAME } ";
57- version = "${ release . version } ";
129+ ### Using nix-shell
58130
59- src = fetchurl {
60- url = "https://github.com/profullstack/pairux.com/releases/download/v\${version}/PairUX-\${version}-x86_64.AppImage";
61- sha256 = "${ x86Sha256 !== '' ? x86Sha256 : 'sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=' } ";
131+ \`\`\`bash
132+ nix-shell -p "(builtins.getFlake \\"github:profullstack/pairux-nix\\").packages.x86_64-linux.default"
133+ \`\`\`
134+
135+ ### NixOS configuration
136+
137+ Add to your \`flake.nix\`:
138+
139+ \`\`\`nix
140+ {
141+ inputs = {
142+ nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
143+ pairux.url = "github:profullstack/pairux-nix";
62144 };
63145
64- appimageContents = appimageTools.extractType2 { inherit pname version src; };
65- in
66- appimageTools.wrapType2 {
67- inherit pname version src;
68-
69- extraInstallCommands = ''
70- install -m 444 -D \${appimageContents}/pairux.desktop $out/share/applications/pairux.desktop
71- install -m 444 -D \${appimageContents}/usr/share/icons/hicolor/512x512/apps/pairux.png \\
72- $out/share/icons/hicolor/512x512/apps/pairux.png
73- substituteInPlace $out/share/applications/pairux.desktop \\
74- --replace 'Exec=AppRun' 'Exec=pairux'
75- '';
76-
77- meta = with lib; {
78- description = "Collaborative screen sharing with remote control";
79- longDescription = ''
80- PairUX is a collaborative screen sharing application with simultaneous
81- remote mouse and keyboard control. Like Screenhero, but open source.
82- Perfect for pair programming, remote support, and collaboration.
83- '';
84- homepage = "https://pairux.com";
85- changelog = "https://github.com/profullstack/pairux.com/releases/tag/v\${version}";
86- license = licenses.mit;
87- maintainers = with maintainers; [ ];
88- platforms = [ "x86_64-linux" ];
89- mainProgram = "pairux";
90- sourceProvenance = with sourceTypes; [ binaryNativeCode ];
146+ outputs = { self, nixpkgs, pairux }: {
147+ nixosConfigurations.yourhostname = nixpkgs.lib.nixosSystem {
148+ modules = [
149+ ({ pkgs, ... }: {
150+ environment.systemPackages = [
151+ pairux.packages.\${pkgs.system}.default
152+ ];
153+ })
154+ ];
155+ };
91156 };
92157}
158+ \`\`\`
159+
160+ ## Version
161+
162+ Current version: ${ release . version }
163+
164+ ## License
165+
166+ MIT
93167` ;
94168
95- return Promise . resolve ( nixExpr ) ;
169+ return Promise . resolve ( {
170+ 'flake.nix' : flakeNix ,
171+ 'README.md' : readme ,
172+ } ) ;
96173 }
97174
98175 async submit ( release : ReleaseInfo , dryRun = false ) : Promise < SubmissionResult > {
99- // Check if PR already exists
176+ // Check if already exists
100177 if ( await this . checkExisting ( release . version ) ) {
101178 return {
102179 packageManager : this . name ,
103180 status : 'skipped' ,
104- message : `PR for version ${ release . version } already exists in nixpkgs ` ,
181+ message : `Version ${ release . version } already exists in Nix flake ` ,
105182 alreadyExists : true ,
106183 } ;
107184 }
108185
109- const nixExpr = await this . generateManifest ( release ) ;
186+ const files = await this . generateManifest ( release ) ;
110187
111188 if ( dryRun ) {
112- this . logger . info ( 'Dry run - generated Nix expression:' ) ;
113- console . log ( nixExpr ) ;
189+ this . logger . info ( 'Dry run - generated Nix flake files:' ) ;
190+ for ( const [ path , content ] of Object . entries ( files ) ) {
191+ this . logger . info ( `\n--- ${ path } ---` ) ;
192+ console . log ( content ) ;
193+ }
114194 return {
115195 packageManager : this . name ,
116196 status : 'skipped' ,
117- message : 'Dry run - Nix expression generated' ,
197+ message : 'Dry run - flake files generated' ,
118198 } ;
119199 }
120200
121- // For nixpkgs, we need to fork and create PR
122- // This is more complex - we'll create the expression and guide the user
123- this . logger . info ( 'Nix package submission requires manual PR to nixpkgs.' ) ;
124- this . logger . info ( 'Generated Nix expression:' ) ;
125- console . log ( nixExpr ) ;
126- this . logger . info ( '' ) ;
127- this . logger . info ( 'To submit to nixpkgs:' ) ;
128- this . logger . info ( '1. Fork https://github.com/NixOS/nixpkgs' ) ;
129- this . logger . info ( '2. Create pkgs/by-name/pa/pairux/package.nix with the above content' ) ;
130- this . logger . info ( '3. Test locally with: nix-build -A pairux' ) ;
131- this . logger . info ( '4. Submit a PR following nixpkgs contribution guidelines' ) ;
132-
133- this . logger . info ( '' ) ;
134- this . logger . info ( 'Alternatively, users can install via flake:' ) ;
135- this . logger . info ( ' nix profile install github:profullstack/pairux-nix' ) ;
136-
137- return {
138- packageManager : this . name ,
139- status : 'skipped' ,
140- message : 'Nix expression generated - manual submission to nixpkgs required' ,
141- } ;
201+ // Ensure flake repo exists
202+ await this . ensureRepo (
203+ FLAKE_OWNER ,
204+ FLAKE_REPO ,
205+ 'Nix flake for PairUX - collaborative screen sharing'
206+ ) ;
207+
208+ // Submit directly to the flake repo
209+ const githubFiles = Object . entries ( files ) . map ( ( [ path , content ] ) => ( {
210+ path,
211+ content,
212+ } ) ) ;
213+
214+ return this . submitDirect (
215+ FLAKE_OWNER ,
216+ FLAKE_REPO ,
217+ githubFiles ,
218+ `Update pairux to ${ release . version } `
219+ ) ;
142220 }
143221}
0 commit comments