Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Example environment secrets consumed by home-manager/modules/secret
# Copy to home-manager/.env and provide real values. The .env file stays local.
MY_SECRET=replace-me
# GITHUB_TOKEN=ghp_your_token_here
145 changes: 145 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,150 @@ tags
# Ignore
result
ref

.direnv/
.env

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Snowpack dependency directory (https://snowpack.dev/)
web_modules/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional stylelint cache
.stylelintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variable files
.env
.env.*
!.env.example

# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache

# Next.js build output
.next
out

# Nuxt.js build / generate output
.nuxt
dist
.output

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# vuepress v2.x temp and cache directory
.temp
.cache

# Sveltekit cache directory
.svelte-kit/

# vitepress build output
**/.vitepress/dist

# vitepress cache directory
**/.vitepress/cache

# Docusaurus cache and generated files
.docusaurus

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# Firebase cache directory
.firebase/

# TernJS port file
.tern-port

# Stores VSCode versions used for testing VSCode extensions
.vscode-test

# yarn v3
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions

# Vite files
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
.vite/
.env
.env.local
52 changes: 52 additions & 0 deletions README-nix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Nix + dream2nix setup

This repo can build and expose all CLI tools declared in `package.json` using the exact versions from the lockfile, via [dream2nix].

## Prerequisites
- Nix installed
- Flakes enabled (see Nix docs)

## Typical usage

Build the tools as a package:
```bash
nix build .#node-tools
# The result symlink contains bin/ with your CLI tools
ls -l result/bin
```

Open a dev shell with Node and tools on PATH:

```bash
nix develop
# then run your tools, e.g.
tsc --version
prettier --version
eslint_d --version
```

Use in Home Manager (example):

```nix
{ pkgs, ... }:
{
home.packages = [
(builtins.getFlake ".").packages.${builtins.currentSystem}.node-tools

Copilot AI Sep 26, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using builtins.getFlake with a relative path in Home Manager configuration is not recommended as it creates impure evaluations. Consider using a proper flake input or absolute path reference instead.

Suggested change
(builtins.getFlake ".").packages.${builtins.currentSystem}.node-tools
inputs.nodeToolsFlake.packages.${pkgs.system}.node-tools

Copilot uses AI. Check for mistakes.
];
}
```
Comment on lines +30 to +37

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The Home Manager example uses (builtins.getFlake "."), which relies on the current working directory. This is not a robust pattern for consuming flakes. A more idiomatic approach is to add the flake as an input to the user's configuration.

I recommend updating the example to demonstrate this more common and robust pattern. For example:

"To use these packages in your Home Manager configuration, first add this repository as an input to your flake.nix:

# flake.nix
inputs.my-tools = {
  url = "github:shunkakinoki/dotfiles"; # Or the path to this repo
};

Then, you can add the package to home.packages in your Home Manager module:

# home-manager.nix
{ pkgs, inputs, ... }:
{
  home.packages = [
    inputs.my-tools.packages.${pkgs.system}.node-tools
  ];
}
```"


## Notes

* Versions are pinned by the lockfile (`package-lock.json`, `yarn.lock`, or `pnpm-lock.yaml`).
* If you change dependencies, update the lockfile, then rebuild.
* If your package has native deps, dream2nix will build them; ensure required system libs are available in nixpkgs.

## Troubleshooting

* **Missing lockfile**: generate one (`npm i`, `pnpm i`, or `yarn install`) before running `nix build`.
Comment thread
shunkakinoki marked this conversation as resolved.
Resolved
* **Postinstall script fails**: check logs from `nix build`; you may need to add system libraries or patch scripts.
* **Bins missing**: ensure the dependency actually exposes a `bin` entry in its `package.json`.

[dream2nix]: https://github.com/nix-community/dream2nix

103 changes: 103 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 10 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@
};

perSystem =
{ ... }:
{ system, pkgs, ... }:
{
treefmt = {
projectRootFile = "flake.nix";
Expand All @@ -139,6 +139,15 @@
yamlfmt.enable = true;
};
};

devShells.default = pkgs.mkShell {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For creating development shells that don't require a C/C++ compiler toolchain, it's better to use pkgs.mkShellNoCC instead of pkgs.mkShell. mkShell adds the standard environment (stdenv), which includes many build-time dependencies like GCC. mkShellNoCC creates a more lightweight shell, which is sufficient here since you are only adding Node.js and related tools to the PATH.

          devShells.default = pkgs.mkShellNoCC {

packages = [ pkgs.nodejs_20 ];
shellHook = ''
# Enable Corepack so Yarn/PNPM versions follow packageManager field
corepack enable || true

Copilot AI Sep 26, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using || true to suppress command failures can hide legitimate errors. Consider using a more explicit error handling approach or checking if corepack is available before enabling it.

Suggested change
corepack enable || true
if command -v corepack >/dev/null 2>&1; then
corepack enable
else
echo "Warning: 'corepack' not found. Yarn/PNPM version management may not work as expected."
fi

Copilot uses AI. Check for mistakes.
echo "Dev shell ready: Node.js + pnpm available via corepack."
'';
};
};
};
}
1 change: 1 addition & 0 deletions home-manager/modules/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
./crush
./dust
./ghostty
./npm-globals
./opencode
./serena
]
25 changes: 25 additions & 0 deletions home-manager/modules/npm-globals/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{ config, lib, pkgs, ... }:
{
# Install npm global packages from package.json using home-manager activation
home.activation.installNpmGlobals = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
export PATH=${pkgs.nodejs_20}/bin:${pkgs.corepack}/bin:$PATH
export PNPM_HOME="$HOME/.local/share/pnpm"

# Enable corepack for pnpm
${pkgs.corepack}/bin/corepack enable

# Install global packages from package.json if it exists
PACKAGE_JSON="${config.home.homeDirectory}/dotfiles/package.json"
if [ -f "$PACKAGE_JSON" ]; then
echo "Installing npm global packages from package.json..."
cd "${config.home.homeDirectory}/dotfiles"
Comment on lines +8 to +17

Copilot AI Oct 3, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hardcoded 'dotfiles' directory path assumes a specific repository name and location. This reduces portability if the repository is cloned to a different directory name.

Suggested change
# Install npm global packages from package.json using home-manager activation
home.activation.installNpmGlobals = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
export PATH=${pkgs.bun}/bin:$PATH
export BUN_INSTALL="$HOME/.bun"
# Install global packages from package.json if it exists
PACKAGE_JSON="${config.home.homeDirectory}/dotfiles/package.json"
if [ -f "$PACKAGE_JSON" ]; then
echo "Installing npm global packages from package.json using bun..."
cd "${config.home.homeDirectory}/dotfiles"
# Optionally allow configuring the dotfiles directory location
dotfilesDirectory = config.dotfilesDirectory or "${config.home.homeDirectory}/dotfiles";
# Install npm global packages from package.json using home-manager activation
home.activation.installNpmGlobals = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
export PATH=${pkgs.bun}/bin:$PATH
export BUN_INSTALL="$HOME/.bun"
# Install global packages from package.json if it exists
PACKAGE_JSON="${dotfilesDirectory}/package.json"
if [ -f "$PACKAGE_JSON" ]; then
echo "Installing npm global packages from package.json using bun..."
cd "${dotfilesDirectory}"

Copilot uses AI. Check for mistakes.
${pkgs.corepack}/bin/pnpm install --global \
$(${pkgs.jq}/bin/jq -r '.dependencies | keys[]' "$PACKAGE_JSON") 2>/dev/null || true

Copilot AI Oct 3, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The command silently ignores all errors with 2>/dev/null || true, which could hide legitimate installation failures. Consider logging errors or using more specific error handling.

Suggested change
$(${pkgs.jq}/bin/jq -r '.dependencies | keys[]' "$PACKAGE_JSON") 2>/dev/null || true
$(${pkgs.jq}/bin/jq -r '.dependencies | keys[]' "$PACKAGE_JSON")
if [ $? -ne 0 ]; then
echo "Error: Failed to install npm global packages from package.json using bun." >&2
fi

Copilot uses AI. Check for mistakes.

Copilot AI Oct 3, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The command suppresses all errors with 2>/dev/null || true, which could hide important installation failures. Consider logging errors or providing more specific error handling.

Suggested change
$(${pkgs.jq}/bin/jq -r '.dependencies | keys[]' "$PACKAGE_JSON") 2>/dev/null || true
$(${pkgs.jq}/bin/jq -r '.dependencies | keys[]' "$PACKAGE_JSON") 2>>"$HOME/.bun-install-errors.log"

Copilot uses AI. Check for mistakes.
fi
'';
Comment on lines +9 to +21

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Improve error handling and robustness in activation script.

The activation script has several concerns:

  1. Line 9: corepack enable runs without checking if it succeeds
  2. Line 17: 2>/dev/null || true suppresses all errors, hiding:
    • Invalid JSON in package.json
    • Failed pnpm installations
    • Missing dependencies
  3. Line 15: cd could fail if dotfiles directory doesn't exist
  4. Performance: Activation runs on every home-manager switch, potentially reinstalling packages unnecessarily

Consider these improvements:

     home.activation.installNpmGlobals = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
       export PATH=${pkgs.nodejs_20}/bin:${pkgs.corepack}/bin:$PATH
       export PNPM_HOME="$HOME/.local/share/pnpm"

       # Enable corepack for pnpm
-      ${pkgs.corepack}/bin/corepack enable
+      if ! ${pkgs.corepack}/bin/corepack enable; then
+        echo "Warning: Failed to enable corepack" >&2
+      fi

       # Install global packages from package.json if it exists
       PACKAGE_JSON="${config.home.homeDirectory}/dotfiles/package.json"
       if [ -f "$PACKAGE_JSON" ]; then
         echo "Installing npm global packages from package.json..."
-        cd "${config.home.homeDirectory}/dotfiles"
-        ${pkgs.corepack}/bin/pnpm install --global \
-          $(${pkgs.jq}/bin/jq -r '.dependencies | keys[]' "$PACKAGE_JSON") 2>/dev/null || true
+        PACKAGES=$(${pkgs.jq}/bin/jq -r '.dependencies | keys[]' "$PACKAGE_JSON" 2>&1)
+        if [ $? -ne 0 ]; then
+          echo "Warning: Failed to parse package.json: $PACKAGES" >&2
+        elif [ -n "$PACKAGES" ]; then
+          if ! ${pkgs.corepack}/bin/pnpm install --global $PACKAGES; then
+            echo "Warning: Some packages failed to install" >&2
+          fi
+        fi
       fi
     '';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
home.activation.installNpmGlobals = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
export PATH=${pkgs.nodejs_20}/bin:${pkgs.corepack}/bin:$PATH
export PNPM_HOME="$HOME/.local/share/pnpm"
# Enable corepack for pnpm
${pkgs.corepack}/bin/corepack enable
# Install global packages from package.json if it exists
PACKAGE_JSON="${config.home.homeDirectory}/dotfiles/package.json"
if [ -f "$PACKAGE_JSON" ]; then
echo "Installing npm global packages from package.json..."
cd "${config.home.homeDirectory}/dotfiles"
${pkgs.corepack}/bin/pnpm install --global \
$(${pkgs.jq}/bin/jq -r '.dependencies | keys[]' "$PACKAGE_JSON") 2>/dev/null || true
fi
'';
home.activation.installNpmGlobals = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
export PATH=${pkgs.nodejs_20}/bin:${pkgs.corepack}/bin:$PATH
export PNPM_HOME="$HOME/.local/share/pnpm"
# Enable corepack for pnpm
if ! ${pkgs.corepack}/bin/corepack enable; then
echo "Warning: Failed to enable corepack" >&2
fi
# Install global packages from package.json if it exists
PACKAGE_JSON="${config.home.homeDirectory}/dotfiles/package.json"
if [ -f "$PACKAGE_JSON" ]; then
echo "Installing npm global packages from package.json..."
PACKAGES=$(${pkgs.jq}/bin/jq -r '.dependencies | keys[]' "$PACKAGE_JSON" 2>&1)
if [ $? -ne 0 ]; then
echo "Warning: Failed to parse package.json: $PACKAGES" >&2
elif [ -n "$PACKAGES" ]; then
if ! ${pkgs.corepack}/bin/pnpm install --global $PACKAGES; then
echo "Warning: Some packages failed to install" >&2
fi
fi
fi
'';
🤖 Prompt for AI Agents
In home-manager/modules/npm-globals/default.nix around lines 4 to 19, the
activation script runs corepack without checking its exit status, blindly cds
into dotfiles, silences all errors from jq/pnpm (hiding invalid JSON and install
failures), and may re-run installs on every switch; update the script to (1)
check the exit code of `${pkgs.corepack}/bin/corepack enable` and log+exit on
failure, (2) verify the dotfiles directory exists before cd and skip with a
logged message if missing, (3) validate PACKAGE_JSON with `${pkgs.jq}` and fail
gracefully when JSON is invalid (log the jq error instead of redirecting to
/dev/null), (4) run `${pkgs.corepack}/bin/pnpm install --global` and capture its
exit code, logging any failures instead of using `|| true`, and (5) avoid
unnecessary reinstalls by adding a cheap guard (e.g., check for a
lockfile/marker or verify installed packages with `pnpm list -g` before running
install) so activation is idempotent and failures are visible.


# Add pnpm bin to PATH
home.sessionPath = [
"$HOME/.local/share/pnpm"
];
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Add proper module structure with options and conditional configuration.

The module directly sets home.activation and home.sessionPath without declaring any options or providing an enable switch. Following Home Manager conventions and coding guidelines, modules should:

  1. Declare options (typically options.modules.npm-globals.enable with mkEnableOption)
  2. Gate configuration with mkIf cfg.enable
  3. Document the module's purpose and options

Based on coding guidelines.

Apply this structure:

 { config, lib, pkgs, ... }:
+let
+  cfg = config.modules.npm-globals;
+in
 {
+  options.modules.npm-globals = {
+    enable = lib.mkEnableOption "npm global package management via pnpm";
+    
+    packageJsonPath = lib.mkOption {
+      type = lib.types.str;
+      default = "${config.home.homeDirectory}/dotfiles/package.json";
+      description = "Path to package.json containing global dependencies";
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
     # Install npm global packages from package.json using home-manager activation
     home.activation.installNpmGlobals = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
       export PATH=${pkgs.nodejs_20}/bin:${pkgs.corepack}/bin:$PATH
       export PNPM_HOME="$HOME/.local/share/pnpm"

       # Enable corepack for pnpm
       ${pkgs.corepack}/bin/corepack enable

       # Install global packages from package.json if it exists
-      PACKAGE_JSON="${config.home.homeDirectory}/dotfiles/package.json"
+      PACKAGE_JSON="${cfg.packageJsonPath}"
       if [ -f "$PACKAGE_JSON" ]; then
         echo "Installing npm global packages from package.json..."
-        cd "${config.home.homeDirectory}/dotfiles"
+        cd "$(dirname "$PACKAGE_JSON")"
         ${pkgs.corepack}/bin/pnpm install --global \
           $(${pkgs.jq}/bin/jq -r '.dependencies | keys[]' "$PACKAGE_JSON") 2>/dev/null || true
       fi
     '';

     # Add pnpm bin to PATH
     home.sessionPath = [
       "$HOME/.local/share/pnpm"
     ];
+  };
 }
🤖 Prompt for AI Agents
home-manager/modules/npm-globals/default.nix lines 1-25: the module currently
mutates home.activation and home.sessionPath unconditionally; add a proper
module structure by declaring an options attribute (e.g.,
options.modules.npm-globals.enable using lib.mkEnableOption with a helpful
description and default false), then wrap all configuration
(home.activation.installNpmGlobals and home.sessionPath additions) inside
lib.mkIf cfg.enable so they only apply when enabled; ensure the module returns a
config attribute (e.g., config = { ... } or use lib.mkIf to conditionally merge
into config.home.*) and include a short docstring in the option to explain the
purpose.

17 changes: 17 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "dotfiles",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"packageManager": "pnpm@10.15.1",
"dependencies": {
"@github/copilot": "^0.0.333",
"open-composer": "0.8.5"
}
}
2 changes: 1 addition & 1 deletion rules
Submodule rules updated from b140aa to bf5e1f
Loading