From a21428e482f3f8098f78c9be8336d14345036d38 Mon Sep 17 00:00:00 2001 From: Padreug Date: Sun, 24 May 2026 23:01:37 +0200 Subject: [PATCH] chore: scaffold dev-env module (options + config + lib stubs) default.nix composes the three sub-modules. options.nix declares the public surface (projects, regtest, fakewallet, tmux) so consumers can wire values today even though config.nix is empty. lib.nix reserves dev-env-scoped helpers separate from the global lnbits-sensei.lib. Co-Authored-By: Claude Opus 4.7 (1M context) --- modules/dev-env/config.nix | 29 +++++++ modules/dev-env/default.nix | 16 ++++ modules/dev-env/lib.nix | 32 +++++++ modules/dev-env/options.nix | 161 ++++++++++++++++++++++++++++++++++++ 4 files changed, 238 insertions(+) create mode 100644 modules/dev-env/config.nix create mode 100644 modules/dev-env/default.nix create mode 100644 modules/dev-env/lib.nix create mode 100644 modules/dev-env/options.nix diff --git a/modules/dev-env/config.nix b/modules/dev-env/config.nix new file mode 100644 index 0000000..5342d27 --- /dev/null +++ b/modules/dev-env/config.nix @@ -0,0 +1,29 @@ +# lnbits-sensei dev-env — wire-up. +# +# Skeleton-only. The substantive pass will: +# - install the regtest.sh / fakewallet.sh wrappers on PATH +# - render a /etc/dev-env/config.sh consumed by the loose bash +# helpers (worktree nav, upstream-PR helper) +# - emit systemd.user units for any long-running pieces +# - hook into config.lnbits-sensei.git.remotes to drive the +# bootstrap script's remote reconciliation +# +# Empty body for now so the module composes cleanly. +{ + config, + lib, + pkgs, + ... +}: + +let + inherit (lib) mkIf; + cfg = config.lnbits-sensei.devEnv; +in +{ + config = mkIf cfg.enable { + # TODO(skeleton): wire scripts, systemd units, and the + # /etc/dev-env/config.sh render here. See omnixy + # modules/dev-env/config.nix for the reference shape. + }; +} diff --git a/modules/dev-env/default.nix b/modules/dev-env/default.nix new file mode 100644 index 0000000..2fb4945 --- /dev/null +++ b/modules/dev-env/default.nix @@ -0,0 +1,16 @@ +# lnbits-sensei dev-env — entry point. +# +# Composes the dev-env sub-modules (option schema, helpers, wire-up). +# The dev-env module owns the workflow surface area: worktree +# management, navigation helpers, the regtest stack wrapper, the +# FakeWallet symmetric-no-op wrapper, and tmux session presets. +# +# It only configures tools — it never materializes repos on disk. +# That is the job of the user-invoked bootstrap script (later pass). +{ + imports = [ + ./options.nix + ./lib.nix + ./config.nix + ]; +} diff --git a/modules/dev-env/lib.nix b/modules/dev-env/lib.nix new file mode 100644 index 0000000..565278d --- /dev/null +++ b/modules/dev-env/lib.nix @@ -0,0 +1,32 @@ +# lnbits-sensei dev-env — helpers. +# +# Skeleton-only. Place dev-env-internal helpers here (project path +# resolution, worktree-path expansion, remote-URL canonicalisation) +# rather than in the global `lnbits-sensei.lib` so they're scoped to +# the dev-env module and don't pollute the public helper namespace. +{ config, lib, ... }: + +let + inherit (lib) mkOption types; + + helpers = { + # Resolve a project's on-disk root given a project name. + # projectRoot = name: "${config.lnbits-sensei.devEnv.root}/${name}"; + projectRoot = _name: throw "dev-env.lib.projectRoot: not yet implemented"; + + # Resolve a worktree path: //. + worktreePath = + _project: _worktree: throw "dev-env.lib.worktreePath: not yet implemented"; + }; +in +{ + options.lnbits-sensei.devEnv.lib = mkOption { + type = types.attrs; + internal = true; + description = "dev-env-internal helpers (see modules/dev-env/lib.nix)."; + }; + + config = { + lnbits-sensei.devEnv.lib = helpers; + }; +} diff --git a/modules/dev-env/options.nix b/modules/dev-env/options.nix new file mode 100644 index 0000000..160e165 --- /dev/null +++ b/modules/dev-env/options.nix @@ -0,0 +1,161 @@ +# lnbits-sensei dev-env — option schema. +# +# Skeleton-only. Declares the option surface so consumers can wire +# values today and the substantive implementation can land later +# without churning the public API. +{ config, lib, ... }: + +let + inherit (lib) mkEnableOption mkOption types; + + # One entry in dev-env.projects. A project is a git repo with one or + # more worktrees (or a single clone if `isClone = true`). Worktrees + # are derived from a bare repo at `${dev-env.root}/repos/.git` + # by default. + projectType = types.submodule ( + { name, ... }: + { + options = { + url = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Origin URL for this project. May be an upstream URL, a + personal fork, or a private mirror — the dev-env bootstrap + script reconciles the rest of the remote topology from + `lnbits-sensei.git.remotes`. + ''; + example = "https://github.com/lnbits/lnbits"; + }; + + worktrees = mkOption { + type = types.attrsOf ( + types.submodule { + options = { + branch = mkOption { + type = types.str; + description = "Branch to check out in this worktree."; + }; + }; + } + ); + default = { }; + description = '' + Worktrees to materialize for this project, keyed by + worktree name. Each becomes a directory under the project + root. + ''; + example = lib.literalExpression '' + { + main = { branch = "main"; }; + dev = { branch = "dev"; }; + } + ''; + }; + + isClone = mkEnableOption '' + Treat as a plain clone rather than a bare-repo + worktrees + set. Use for projects you won't have multiple simultaneous + branches checked out for + ''; + }; + } + ); + + # One entry in dev-env.tmux.sessions. Mirrors the omnixy shape so + # the `dev-tm ` launcher can ship later with a familiar API. + tmuxSessionType = types.submodule { + options = { + cwd = mkOption { + type = types.nullOr types.str; + default = null; + description = "Session-default cwd, relative to dev-env.root."; + }; + windows = mkOption { + type = types.listOf ( + types.submodule { + options = { + name = mkOption { type = types.str; }; + cwd = mkOption { + type = types.nullOr types.str; + default = null; + }; + cmd = mkOption { + type = types.nullOr types.str; + default = null; + description = "Command to run in the window on creation."; + }; + }; + } + ); + default = [ ]; + }; + }; + }; +in +{ + options.lnbits-sensei.devEnv = { + enable = mkEnableOption "lnbits-sensei dev-env tooling"; + + root = mkOption { + type = types.str; + default = "/home/${config.lnbits-sensei.user or "user"}/dev"; + defaultText = "/home/\${config.lnbits-sensei.user}/dev"; + description = '' + Root directory for the dev environment. Worktrees and project + clones live under this prefix; bare repos under + `''${root}/repos/`. + ''; + }; + + projects = mkOption { + type = types.attrsOf projectType; + default = { }; + description = '' + Hand-authored project list. Consumed by the bootstrap script + (later pass) to materialize repos and worktrees on disk. + ''; + }; + + regtest = { + enable = mkEnableOption '' + Bitcoin/Lightning regtest docker stack. Wraps an upstream + fork of `lnbits/legend-regtest-enviroment` (LND + CLN + + Eclair + bitcoind + electrs). Implies a container engine — + the substantive pass will gate this on a containers feature + ''; + + repoUrl = mkOption { + type = types.str; + default = "https://github.com/lnbits/legend-regtest-enviroment"; + description = '' + Git URL of the regtest docker-compose repo. Cloned by the + dev-env bootstrap script. Point at your own fork if you've + customised the stack. + ''; + }; + }; + + fakewallet = { + enable = mkEnableOption '' + FakeWallet dev mode helpers. Installs the symmetric `fakewallet` + wrapper script (a no-op for parity with `regtest up`) so the + dev experience is identical whether you're on the default + FakeWallet path or the full regtest stack + ''; + }; + + tmux = { + enable = mkEnableOption "declarative tmux session launcher"; + + sessions = mkOption { + type = types.attrsOf tmuxSessionType; + default = { }; + description = '' + Named tmux session layouts. The launcher script (later pass) + reads these at runtime and recreates the session. + ''; + }; + }; + }; +}