style: nix fmt (nixfmt-tree) + exclude generated config options
This commit is contained in:
parent
f8681411dd
commit
c3d3be60ac
@ -6,11 +6,18 @@
|
|||||||
flake-utils.url = "github:numtide/flake-utils";
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, flake-utils }:
|
outputs =
|
||||||
flake-utils.lib.eachDefaultSystem (system:
|
{
|
||||||
|
self,
|
||||||
|
nixpkgs,
|
||||||
|
flake-utils,
|
||||||
|
}:
|
||||||
|
flake-utils.lib.eachDefaultSystem (
|
||||||
|
system:
|
||||||
let
|
let
|
||||||
pkgs = import nixpkgs { inherit system; };
|
pkgs = import nixpkgs { inherit system; };
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
packages.default = pkgs.buildGoModule {
|
packages.default = pkgs.buildGoModule {
|
||||||
pname = "hello-world";
|
pname = "hello-world";
|
||||||
version = "0.1.0";
|
version = "0.1.0";
|
||||||
@ -27,8 +34,8 @@
|
|||||||
skills = [ ./skills/hello-world ];
|
skills = [ ./skills/hello-world ];
|
||||||
packages = [ self.packages.${system}.default ];
|
packages = [ self.packages.${system}.default ];
|
||||||
needs = {
|
needs = {
|
||||||
stateDirs = [];
|
stateDirs = [ ];
|
||||||
requiredEnv = [];
|
requiredEnv = [ ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,7 +51,11 @@
|
|||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
formatter = pkgs.nixfmt-tree;
|
formatter = pkgs.nixfmt-tree.override {
|
||||||
|
settings = {
|
||||||
|
global.excludes = [ "nix/generated/openclaw-config-options.nix" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
packages = packageSetStable // {
|
packages = packageSetStable // {
|
||||||
default = packageSetStable.openclaw;
|
default = packageSetStable.openclaw;
|
||||||
|
|||||||
@ -1,86 +1,97 @@
|
|||||||
{ lib, pkgs, stdenv, nodejs_22, openclawGateway }:
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
stdenv,
|
||||||
|
nodejs_22,
|
||||||
|
openclawGateway,
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
stubModule = { lib, ... }: {
|
stubModule =
|
||||||
options = {
|
{ lib, ... }:
|
||||||
assertions = lib.mkOption {
|
{
|
||||||
type = lib.types.listOf lib.types.attrs;
|
options = {
|
||||||
default = [];
|
assertions = lib.mkOption {
|
||||||
};
|
type = lib.types.listOf lib.types.attrs;
|
||||||
|
default = [ ];
|
||||||
|
};
|
||||||
|
|
||||||
home.homeDirectory = lib.mkOption {
|
home.homeDirectory = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = "/tmp";
|
default = "/tmp";
|
||||||
};
|
};
|
||||||
|
|
||||||
home.packages = lib.mkOption {
|
home.packages = lib.mkOption {
|
||||||
type = lib.types.listOf lib.types.anything;
|
type = lib.types.listOf lib.types.anything;
|
||||||
default = [];
|
default = [ ];
|
||||||
};
|
};
|
||||||
|
|
||||||
home.file = lib.mkOption {
|
home.file = lib.mkOption {
|
||||||
type = lib.types.attrs;
|
type = lib.types.attrs;
|
||||||
default = {};
|
default = { };
|
||||||
};
|
};
|
||||||
|
|
||||||
home.activation = lib.mkOption {
|
home.activation = lib.mkOption {
|
||||||
type = lib.types.attrs;
|
type = lib.types.attrs;
|
||||||
default = {};
|
default = { };
|
||||||
};
|
};
|
||||||
|
|
||||||
launchd.agents = lib.mkOption {
|
launchd.agents = lib.mkOption {
|
||||||
type = lib.types.attrs;
|
type = lib.types.attrs;
|
||||||
default = {};
|
default = { };
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.user.services = lib.mkOption {
|
systemd.user.services = lib.mkOption {
|
||||||
type = lib.types.attrs;
|
type = lib.types.attrs;
|
||||||
default = {};
|
default = { };
|
||||||
};
|
};
|
||||||
|
|
||||||
programs.git.enable = lib.mkOption {
|
programs.git.enable = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
lib = lib.mkOption {
|
lib = lib.mkOption {
|
||||||
type = lib.types.attrs;
|
type = lib.types.attrs;
|
||||||
default = {};
|
default = { };
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
moduleEval = lib.evalModules {
|
moduleEval = lib.evalModules {
|
||||||
modules = [
|
modules = [
|
||||||
stubModule
|
stubModule
|
||||||
../modules/home-manager/openclaw.nix
|
../modules/home-manager/openclaw.nix
|
||||||
({ lib, ... }: {
|
(
|
||||||
config = {
|
{ lib, ... }:
|
||||||
home.homeDirectory = "/tmp";
|
{
|
||||||
programs.git.enable = false;
|
config = {
|
||||||
lib.file.mkOutOfStoreSymlink = path: path;
|
home.homeDirectory = "/tmp";
|
||||||
programs.openclaw = {
|
programs.git.enable = false;
|
||||||
enable = true;
|
lib.file.mkOutOfStoreSymlink = path: path;
|
||||||
launchd.enable = false;
|
programs.openclaw = {
|
||||||
systemd.enable = false;
|
enable = true;
|
||||||
instances.default = {};
|
launchd.enable = false;
|
||||||
config = {
|
systemd.enable = false;
|
||||||
gateway = {
|
instances.default = { };
|
||||||
bind = "tailnet";
|
config = {
|
||||||
auth = {
|
gateway = {
|
||||||
mode = "token";
|
bind = "tailnet";
|
||||||
token = "test-token";
|
auth = {
|
||||||
};
|
mode = "token";
|
||||||
reload = {
|
token = "test-token";
|
||||||
mode = "hot";
|
};
|
||||||
debounceMs = 500;
|
reload = {
|
||||||
|
mode = "hot";
|
||||||
|
debounceMs = 500;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
discovery.mdns.mode = "minimal";
|
||||||
};
|
};
|
||||||
discovery.mdns.mode = "minimal";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
})
|
)
|
||||||
];
|
];
|
||||||
specialArgs = { inherit pkgs; };
|
specialArgs = { inherit pkgs; };
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,71 +1,80 @@
|
|||||||
{ lib, pkgs, stdenv }:
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
stdenv,
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
stubModule = { lib, ... }: {
|
stubModule =
|
||||||
options = {
|
{ lib, ... }:
|
||||||
assertions = lib.mkOption {
|
{
|
||||||
type = lib.types.listOf lib.types.attrs;
|
options = {
|
||||||
default = [];
|
assertions = lib.mkOption {
|
||||||
};
|
type = lib.types.listOf lib.types.attrs;
|
||||||
|
default = [ ];
|
||||||
|
};
|
||||||
|
|
||||||
home.homeDirectory = lib.mkOption {
|
home.homeDirectory = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = "/tmp";
|
default = "/tmp";
|
||||||
};
|
};
|
||||||
|
|
||||||
home.packages = lib.mkOption {
|
home.packages = lib.mkOption {
|
||||||
type = lib.types.listOf lib.types.anything;
|
type = lib.types.listOf lib.types.anything;
|
||||||
default = [];
|
default = [ ];
|
||||||
};
|
};
|
||||||
|
|
||||||
home.file = lib.mkOption {
|
home.file = lib.mkOption {
|
||||||
type = lib.types.attrs;
|
type = lib.types.attrs;
|
||||||
default = {};
|
default = { };
|
||||||
};
|
};
|
||||||
|
|
||||||
home.activation = lib.mkOption {
|
home.activation = lib.mkOption {
|
||||||
type = lib.types.attrs;
|
type = lib.types.attrs;
|
||||||
default = {};
|
default = { };
|
||||||
};
|
};
|
||||||
|
|
||||||
launchd.agents = lib.mkOption {
|
launchd.agents = lib.mkOption {
|
||||||
type = lib.types.attrs;
|
type = lib.types.attrs;
|
||||||
default = {};
|
default = { };
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.user.services = lib.mkOption {
|
systemd.user.services = lib.mkOption {
|
||||||
type = lib.types.attrs;
|
type = lib.types.attrs;
|
||||||
default = {};
|
default = { };
|
||||||
};
|
};
|
||||||
|
|
||||||
programs.git.enable = lib.mkOption {
|
programs.git.enable = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
lib = lib.mkOption {
|
lib = lib.mkOption {
|
||||||
type = lib.types.attrs;
|
type = lib.types.attrs;
|
||||||
default = {};
|
default = { };
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
eval = lib.evalModules {
|
eval = lib.evalModules {
|
||||||
modules = [
|
modules = [
|
||||||
stubModule
|
stubModule
|
||||||
../modules/home-manager/openclaw.nix
|
../modules/home-manager/openclaw.nix
|
||||||
({ lib, ... }: {
|
(
|
||||||
config = {
|
{ lib, ... }:
|
||||||
home.homeDirectory = "/tmp";
|
{
|
||||||
programs.git.enable = false;
|
config = {
|
||||||
lib.file.mkOutOfStoreSymlink = path: path;
|
home.homeDirectory = "/tmp";
|
||||||
programs.openclaw = {
|
programs.git.enable = false;
|
||||||
enable = true;
|
lib.file.mkOutOfStoreSymlink = path: path;
|
||||||
launchd.enable = false;
|
programs.openclaw = {
|
||||||
systemd.enable = true;
|
enable = true;
|
||||||
|
launchd.enable = false;
|
||||||
|
systemd.enable = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
})
|
)
|
||||||
];
|
];
|
||||||
specialArgs = { inherit pkgs; };
|
specialArgs = { inherit pkgs; };
|
||||||
};
|
};
|
||||||
|
|||||||
@ -8,7 +8,8 @@ in
|
|||||||
pkgs.testers.nixosTest {
|
pkgs.testers.nixosTest {
|
||||||
name = "openclaw-hm-activation";
|
name = "openclaw-hm-activation";
|
||||||
|
|
||||||
nodes.machine = { ... }:
|
nodes.machine =
|
||||||
|
{ ... }:
|
||||||
{
|
{
|
||||||
imports = [ home-manager.nixosModules.home-manager ];
|
imports = [ home-manager.nixosModules.home-manager ];
|
||||||
|
|
||||||
@ -23,7 +24,8 @@ pkgs.testers.nixosTest {
|
|||||||
home-manager = {
|
home-manager = {
|
||||||
useGlobalPkgs = true;
|
useGlobalPkgs = true;
|
||||||
useUserPackages = true;
|
useUserPackages = true;
|
||||||
users.alice = { lib, ... }:
|
users.alice =
|
||||||
|
{ lib, ... }:
|
||||||
{
|
{
|
||||||
imports = [ openclawModule ];
|
imports = [ openclawModule ];
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,8 @@
|
|||||||
{ lib, stdenv, openclawGateway }:
|
{
|
||||||
|
lib,
|
||||||
|
stdenv,
|
||||||
|
openclawGateway,
|
||||||
|
}:
|
||||||
|
|
||||||
stdenv.mkDerivation {
|
stdenv.mkDerivation {
|
||||||
pname = "openclaw-package-contents";
|
pname = "openclaw-package-contents";
|
||||||
|
|||||||
@ -1,4 +1,9 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
openclawLib = import ./lib.nix { inherit config lib pkgs; };
|
openclawLib = import ./lib.nix { inherit config lib pkgs; };
|
||||||
@ -19,7 +24,7 @@ let
|
|||||||
launchd = cfg.launchd;
|
launchd = cfg.launchd;
|
||||||
systemd = cfg.systemd;
|
systemd = cfg.systemd;
|
||||||
plugins = openclawLib.effectivePlugins;
|
plugins = openclawLib.effectivePlugins;
|
||||||
config = {};
|
config = { };
|
||||||
appDefaults = {
|
appDefaults = {
|
||||||
enable = true;
|
enable = true;
|
||||||
attachExistingOnly = true;
|
attachExistingOnly = true;
|
||||||
@ -32,20 +37,38 @@ let
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
instances = if cfg.instances != {}
|
instances =
|
||||||
then cfg.instances
|
if cfg.instances != { } then
|
||||||
else lib.optionalAttrs cfg.enable { default = defaultInstance; };
|
cfg.instances
|
||||||
|
else
|
||||||
|
lib.optionalAttrs cfg.enable { default = defaultInstance; };
|
||||||
|
|
||||||
enabledInstances = lib.filterAttrs (_: inst: inst.enable) instances;
|
enabledInstances = lib.filterAttrs (_: inst: inst.enable) instances;
|
||||||
|
|
||||||
plugins = import ./plugins.nix { inherit lib pkgs openclawLib enabledInstances; };
|
plugins = import ./plugins.nix {
|
||||||
|
inherit
|
||||||
files = import ./files.nix {
|
lib
|
||||||
inherit config lib pkgs openclawLib enabledInstances plugins;
|
pkgs
|
||||||
|
openclawLib
|
||||||
|
enabledInstances
|
||||||
|
;
|
||||||
};
|
};
|
||||||
|
|
||||||
stripNulls = value:
|
files = import ./files.nix {
|
||||||
if value == null then null
|
inherit
|
||||||
|
config
|
||||||
|
lib
|
||||||
|
pkgs
|
||||||
|
openclawLib
|
||||||
|
enabledInstances
|
||||||
|
plugins
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
|
stripNulls =
|
||||||
|
value:
|
||||||
|
if value == null then
|
||||||
|
null
|
||||||
else if builtins.isAttrs value then
|
else if builtins.isAttrs value then
|
||||||
lib.filterAttrs (_: v: v != null) (builtins.mapAttrs (_: stripNulls) value)
|
lib.filterAttrs (_: v: v != null) (builtins.mapAttrs (_: stripNulls) value)
|
||||||
else if builtins.isList value then
|
else if builtins.isList value then
|
||||||
@ -59,154 +82,183 @@ let
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
mkInstanceConfig = name: inst: let
|
mkInstanceConfig =
|
||||||
gatewayPackage =
|
name: inst:
|
||||||
if inst.gatewayPath != null then
|
let
|
||||||
pkgs.callPackage ../../packages/openclaw-gateway.nix {
|
gatewayPackage =
|
||||||
gatewaySrc = builtins.path {
|
if inst.gatewayPath != null then
|
||||||
path = inst.gatewayPath;
|
pkgs.callPackage ../../packages/openclaw-gateway.nix {
|
||||||
name = "openclaw-gateway-src";
|
gatewaySrc = builtins.path {
|
||||||
};
|
path = inst.gatewayPath;
|
||||||
pnpmDepsHash = inst.gatewayPnpmDepsHash;
|
name = "openclaw-gateway-src";
|
||||||
}
|
};
|
||||||
else
|
pnpmDepsHash = inst.gatewayPnpmDepsHash;
|
||||||
inst.package;
|
}
|
||||||
pluginPackages = plugins.pluginPackagesFor name;
|
|
||||||
pluginEnvAll = plugins.pluginEnvAllFor name;
|
|
||||||
mergedConfig0 = stripNulls (lib.recursiveUpdate (lib.recursiveUpdate baseConfig cfg.config) inst.config);
|
|
||||||
existingWorkspace = (((mergedConfig0.agents or {}).defaults or {}).workspace or null);
|
|
||||||
mergedConfig =
|
|
||||||
if (cfg.workspace.pinAgentDefaults or true) && existingWorkspace == null then
|
|
||||||
lib.recursiveUpdate mergedConfig0 { agents = { defaults = { workspace = inst.workspaceDir; }; }; }
|
|
||||||
else
|
|
||||||
mergedConfig0;
|
|
||||||
configJson = builtins.toJSON mergedConfig;
|
|
||||||
configFile = pkgs.writeText "openclaw-${name}.json" configJson;
|
|
||||||
gatewayWrapper = pkgs.writeShellScriptBin "openclaw-gateway-${name}" ''
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
if [ -n "${lib.makeBinPath pluginPackages}" ]; then
|
|
||||||
export PATH="${lib.makeBinPath pluginPackages}:$PATH"
|
|
||||||
fi
|
|
||||||
|
|
||||||
${lib.concatStringsSep "\n" (map (entry:
|
|
||||||
let
|
|
||||||
isFile = lib.hasSuffix "_FILE" entry.key;
|
|
||||||
in ''
|
|
||||||
if [ -f "${entry.value}" ]; then
|
|
||||||
if ${if isFile then "true" else "false"}; then
|
|
||||||
export ${entry.key}="${entry.value}"
|
|
||||||
else
|
|
||||||
rawValue="$("${lib.getExe' pkgs.coreutils "cat"}" "${entry.value}")"
|
|
||||||
if [ "''${rawValue#${entry.key}=}" != "$rawValue" ]; then
|
|
||||||
export ${entry.key}="''${rawValue#${entry.key}=}"
|
|
||||||
else
|
|
||||||
export ${entry.key}="$rawValue"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
export ${entry.key}="${entry.value}"
|
inst.package;
|
||||||
|
pluginPackages = plugins.pluginPackagesFor name;
|
||||||
|
pluginEnvAll = plugins.pluginEnvAllFor name;
|
||||||
|
mergedConfig0 = stripNulls (
|
||||||
|
lib.recursiveUpdate (lib.recursiveUpdate baseConfig cfg.config) inst.config
|
||||||
|
);
|
||||||
|
existingWorkspace = (((mergedConfig0.agents or { }).defaults or { }).workspace or null);
|
||||||
|
mergedConfig =
|
||||||
|
if (cfg.workspace.pinAgentDefaults or true) && existingWorkspace == null then
|
||||||
|
lib.recursiveUpdate mergedConfig0 {
|
||||||
|
agents = {
|
||||||
|
defaults = {
|
||||||
|
workspace = inst.workspaceDir;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mergedConfig0;
|
||||||
|
configJson = builtins.toJSON mergedConfig;
|
||||||
|
configFile = pkgs.writeText "openclaw-${name}.json" configJson;
|
||||||
|
gatewayWrapper = pkgs.writeShellScriptBin "openclaw-gateway-${name}" ''
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
if [ -n "${lib.makeBinPath pluginPackages}" ]; then
|
||||||
|
export PATH="${lib.makeBinPath pluginPackages}:$PATH"
|
||||||
fi
|
fi
|
||||||
'') pluginEnvAll)}
|
|
||||||
|
|
||||||
exec "${gatewayPackage}/bin/openclaw" "$@"
|
${lib.concatStringsSep "\n" (
|
||||||
'';
|
map (
|
||||||
appDefaults = lib.optionalAttrs (pkgs.stdenv.hostPlatform.isDarwin && inst.appDefaults.enable) {
|
entry:
|
||||||
attachExistingOnly = inst.appDefaults.attachExistingOnly;
|
let
|
||||||
gatewayPort = inst.gatewayPort;
|
isFile = lib.hasSuffix "_FILE" entry.key;
|
||||||
nixMode = inst.appDefaults.nixMode;
|
in
|
||||||
};
|
''
|
||||||
|
if [ -f "${entry.value}" ]; then
|
||||||
|
if ${if isFile then "true" else "false"}; then
|
||||||
|
export ${entry.key}="${entry.value}"
|
||||||
|
else
|
||||||
|
rawValue="$("${lib.getExe' pkgs.coreutils "cat"}" "${entry.value}")"
|
||||||
|
if [ "''${rawValue#${entry.key}=}" != "$rawValue" ]; then
|
||||||
|
export ${entry.key}="''${rawValue#${entry.key}=}"
|
||||||
|
else
|
||||||
|
export ${entry.key}="$rawValue"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
export ${entry.key}="${entry.value}"
|
||||||
|
fi
|
||||||
|
''
|
||||||
|
) pluginEnvAll
|
||||||
|
)}
|
||||||
|
|
||||||
appInstall = if !(pkgs.stdenv.hostPlatform.isDarwin && inst.app.install.enable && appPackage != null) then
|
exec "${gatewayPackage}/bin/openclaw" "$@"
|
||||||
null
|
'';
|
||||||
else {
|
appDefaults = lib.optionalAttrs (pkgs.stdenv.hostPlatform.isDarwin && inst.appDefaults.enable) {
|
||||||
name = lib.removePrefix "${homeDir}/" inst.app.install.path;
|
attachExistingOnly = inst.appDefaults.attachExistingOnly;
|
||||||
value = {
|
gatewayPort = inst.gatewayPort;
|
||||||
source = "${appPackage}/Applications/OpenClaw.app";
|
nixMode = inst.appDefaults.nixMode;
|
||||||
recursive = true;
|
|
||||||
force = true;
|
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
package = gatewayPackage;
|
appInstall =
|
||||||
in {
|
if !(pkgs.stdenv.hostPlatform.isDarwin && inst.app.install.enable && appPackage != null) then
|
||||||
homeFile = {
|
null
|
||||||
name = openclawLib.toRelative inst.configPath;
|
else
|
||||||
value = { text = configJson; };
|
{
|
||||||
};
|
name = lib.removePrefix "${homeDir}/" inst.app.install.path;
|
||||||
configFile = configFile;
|
value = {
|
||||||
configPath = inst.configPath;
|
source = "${appPackage}/Applications/OpenClaw.app";
|
||||||
|
recursive = true;
|
||||||
|
force = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
dirs = [ inst.stateDir inst.workspaceDir (builtins.dirOf inst.logPath) ];
|
package = gatewayPackage;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
homeFile = {
|
||||||
|
name = openclawLib.toRelative inst.configPath;
|
||||||
|
value = {
|
||||||
|
text = configJson;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
configFile = configFile;
|
||||||
|
configPath = inst.configPath;
|
||||||
|
|
||||||
launchdAgent = lib.optionalAttrs (pkgs.stdenv.hostPlatform.isDarwin && inst.launchd.enable) {
|
dirs = [
|
||||||
"${inst.launchd.label}" = {
|
inst.stateDir
|
||||||
enable = true;
|
inst.workspaceDir
|
||||||
config = {
|
(builtins.dirOf inst.logPath)
|
||||||
Label = inst.launchd.label;
|
];
|
||||||
ProgramArguments = [
|
|
||||||
"${gatewayWrapper}/bin/openclaw-gateway-${name}"
|
launchdAgent = lib.optionalAttrs (pkgs.stdenv.hostPlatform.isDarwin && inst.launchd.enable) {
|
||||||
"gateway"
|
"${inst.launchd.label}" = {
|
||||||
"--port"
|
enable = true;
|
||||||
"${toString inst.gatewayPort}"
|
config = {
|
||||||
];
|
Label = inst.launchd.label;
|
||||||
RunAtLoad = true;
|
ProgramArguments = [
|
||||||
KeepAlive = true;
|
"${gatewayWrapper}/bin/openclaw-gateway-${name}"
|
||||||
WorkingDirectory = inst.stateDir;
|
"gateway"
|
||||||
StandardOutPath = inst.logPath;
|
"--port"
|
||||||
StandardErrorPath = inst.logPath;
|
"${toString inst.gatewayPort}"
|
||||||
EnvironmentVariables = {
|
];
|
||||||
HOME = homeDir;
|
RunAtLoad = true;
|
||||||
OPENCLAW_CONFIG_PATH = inst.configPath;
|
KeepAlive = true;
|
||||||
OPENCLAW_STATE_DIR = inst.stateDir;
|
WorkingDirectory = inst.stateDir;
|
||||||
OPENCLAW_IMAGE_BACKEND = "sips";
|
StandardOutPath = inst.logPath;
|
||||||
OPENCLAW_NIX_MODE = "1";
|
StandardErrorPath = inst.logPath;
|
||||||
|
EnvironmentVariables = {
|
||||||
|
HOME = homeDir;
|
||||||
|
OPENCLAW_CONFIG_PATH = inst.configPath;
|
||||||
|
OPENCLAW_STATE_DIR = inst.stateDir;
|
||||||
|
OPENCLAW_IMAGE_BACKEND = "sips";
|
||||||
|
OPENCLAW_NIX_MODE = "1";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
systemdService = lib.optionalAttrs (pkgs.stdenv.hostPlatform.isLinux && inst.systemd.enable) {
|
systemdService = lib.optionalAttrs (pkgs.stdenv.hostPlatform.isLinux && inst.systemd.enable) {
|
||||||
"${inst.systemd.unitName}" = {
|
"${inst.systemd.unitName}" = {
|
||||||
Unit = {
|
Unit = {
|
||||||
Description = "OpenClaw gateway (${name})";
|
Description = "OpenClaw gateway (${name})";
|
||||||
};
|
};
|
||||||
Service = {
|
Service = {
|
||||||
ExecStart = "${gatewayWrapper}/bin/openclaw-gateway-${name} gateway --port ${toString inst.gatewayPort}";
|
ExecStart = "${gatewayWrapper}/bin/openclaw-gateway-${name} gateway --port ${toString inst.gatewayPort}";
|
||||||
WorkingDirectory = inst.stateDir;
|
WorkingDirectory = inst.stateDir;
|
||||||
Restart = "always";
|
Restart = "always";
|
||||||
RestartSec = "1s";
|
RestartSec = "1s";
|
||||||
Environment = [
|
Environment = [
|
||||||
"HOME=${homeDir}"
|
"HOME=${homeDir}"
|
||||||
"OPENCLAW_CONFIG_PATH=${inst.configPath}"
|
"OPENCLAW_CONFIG_PATH=${inst.configPath}"
|
||||||
"OPENCLAW_STATE_DIR=${inst.stateDir}"
|
"OPENCLAW_STATE_DIR=${inst.stateDir}"
|
||||||
"OPENCLAW_NIX_MODE=1"
|
"OPENCLAW_NIX_MODE=1"
|
||||||
];
|
];
|
||||||
StandardOutput = "append:${inst.logPath}";
|
StandardOutput = "append:${inst.logPath}";
|
||||||
StandardError = "append:${inst.logPath}";
|
StandardError = "append:${inst.logPath}";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
appDefaults = appDefaults;
|
appDefaults = appDefaults;
|
||||||
appInstall = appInstall;
|
appInstall = appInstall;
|
||||||
package = package;
|
package = package;
|
||||||
};
|
};
|
||||||
|
|
||||||
instanceConfigs = lib.mapAttrsToList mkInstanceConfig enabledInstances;
|
instanceConfigs = lib.mapAttrsToList mkInstanceConfig enabledInstances;
|
||||||
appInstalls = lib.filter (item: item != null) (map (item: item.appInstall) instanceConfigs);
|
appInstalls = lib.filter (item: item != null) (map (item: item.appInstall) instanceConfigs);
|
||||||
|
|
||||||
appDefaults = lib.foldl' (acc: item: lib.recursiveUpdate acc item.appDefaults) {} instanceConfigs;
|
appDefaults = lib.foldl' (acc: item: lib.recursiveUpdate acc item.appDefaults) { } instanceConfigs;
|
||||||
appDefaultsEnabled = lib.filterAttrs (_: inst: inst.appDefaults.enable) enabledInstances;
|
appDefaultsEnabled = lib.filterAttrs (_: inst: inst.appDefaults.enable) enabledInstances;
|
||||||
|
|
||||||
in {
|
in
|
||||||
config = lib.mkIf (cfg.enable || cfg.instances != {}) {
|
{
|
||||||
|
config = lib.mkIf (cfg.enable || cfg.instances != { }) {
|
||||||
assertions = [
|
assertions = [
|
||||||
{
|
{
|
||||||
assertion = lib.length (lib.attrNames appDefaultsEnabled) <= 1;
|
assertion = lib.length (lib.attrNames appDefaultsEnabled) <= 1;
|
||||||
message = "Only one OpenClaw instance may enable appDefaults.";
|
message = "Only one OpenClaw instance may enable appDefaults.";
|
||||||
}
|
}
|
||||||
] ++ files.documentsAssertions ++ files.skillAssertions ++ plugins.pluginAssertions ++ plugins.pluginSkillAssertions;
|
]
|
||||||
|
++ files.documentsAssertions
|
||||||
|
++ files.skillAssertions
|
||||||
|
++ plugins.pluginAssertions
|
||||||
|
++ plugins.pluginSkillAssertions;
|
||||||
|
|
||||||
home.packages = lib.unique (
|
home.packages = lib.unique (
|
||||||
(map (item: item.package) instanceConfigs)
|
(map (item: item.package) instanceConfigs)
|
||||||
@ -242,12 +294,20 @@ in {
|
|||||||
);
|
);
|
||||||
|
|
||||||
home.activation.openclawDirs = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
home.activation.openclawDirs = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
||||||
run --quiet ${lib.getExe' pkgs.coreutils "mkdir"} -p ${lib.concatStringsSep " " (lib.concatMap (item: item.dirs) instanceConfigs)}
|
run --quiet ${lib.getExe' pkgs.coreutils "mkdir"} -p ${
|
||||||
${lib.optionalString (plugins.pluginStateDirsAll != []) "run --quiet ${lib.getExe' pkgs.coreutils "mkdir"} -p ${lib.concatStringsSep " " plugins.pluginStateDirsAll}"}
|
lib.concatStringsSep " " (lib.concatMap (item: item.dirs) instanceConfigs)
|
||||||
|
}
|
||||||
|
${lib.optionalString (plugins.pluginStateDirsAll != [ ])
|
||||||
|
"run --quiet ${lib.getExe' pkgs.coreutils "mkdir"} -p ${lib.concatStringsSep " " plugins.pluginStateDirsAll}"
|
||||||
|
}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
home.activation.openclawConfigFiles = lib.hm.dag.entryAfter [ "openclawDirs" ] ''
|
home.activation.openclawConfigFiles = lib.hm.dag.entryAfter [ "openclawDirs" ] ''
|
||||||
${lib.concatStringsSep "\n" (map (item: "run --quiet ${lib.getExe' pkgs.coreutils "ln"} -sfn ${item.configFile} ${item.configPath}") instanceConfigs)}
|
${lib.concatStringsSep "\n" (
|
||||||
|
map (
|
||||||
|
item: "run --quiet ${lib.getExe' pkgs.coreutils "ln"} -sfn ${item.configFile} ${item.configPath}"
|
||||||
|
) instanceConfigs
|
||||||
|
)}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
home.activation.openclawPluginGuard = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
home.activation.openclawPluginGuard = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
||||||
@ -255,14 +315,22 @@ in {
|
|||||||
${plugins.pluginGuards}
|
${plugins.pluginGuards}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
home.activation.openclawAppDefaults = lib.mkIf (pkgs.stdenv.hostPlatform.isDarwin && appDefaults != {}) (
|
home.activation.openclawAppDefaults =
|
||||||
lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
lib.mkIf (pkgs.stdenv.hostPlatform.isDarwin && appDefaults != { })
|
||||||
# Nix mode + app defaults (OpenClaw.app)
|
(
|
||||||
/usr/bin/defaults write ai.openclaw.mac openclaw.nixMode -bool ${lib.boolToString (appDefaults.nixMode or true)}
|
lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
||||||
/usr/bin/defaults write ai.openclaw.mac openclaw.gateway.attachExistingOnly -bool ${lib.boolToString (appDefaults.attachExistingOnly or true)}
|
# Nix mode + app defaults (OpenClaw.app)
|
||||||
/usr/bin/defaults write ai.openclaw.mac gatewayPort -int ${toString (appDefaults.gatewayPort or 18789)}
|
/usr/bin/defaults write ai.openclaw.mac openclaw.nixMode -bool ${
|
||||||
''
|
lib.boolToString (appDefaults.nixMode or true)
|
||||||
);
|
}
|
||||||
|
/usr/bin/defaults write ai.openclaw.mac openclaw.gateway.attachExistingOnly -bool ${
|
||||||
|
lib.boolToString (appDefaults.attachExistingOnly or true)
|
||||||
|
}
|
||||||
|
/usr/bin/defaults write ai.openclaw.mac gatewayPort -int ${
|
||||||
|
toString (appDefaults.gatewayPort or 18789)
|
||||||
|
}
|
||||||
|
''
|
||||||
|
);
|
||||||
|
|
||||||
home.activation.openclawLaunchdRelink = lib.mkIf pkgs.stdenv.hostPlatform.isDarwin (
|
home.activation.openclawLaunchdRelink = lib.mkIf pkgs.stdenv.hostPlatform.isDarwin (
|
||||||
lib.hm.dag.entryAfter [ "linkGeneration" ] ''
|
lib.hm.dag.entryAfter [ "linkGeneration" ] ''
|
||||||
|
|||||||
@ -1,8 +1,19 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
(lib.mkRenamedOptionModule [ "programs" "openclaw" "firstParty" ] [ "programs" "openclaw" "bundledPlugins" ])
|
(lib.mkRenamedOptionModule
|
||||||
(lib.mkRenamedOptionModule [ "programs" "openclaw" "plugins" ] [ "programs" "openclaw" "customPlugins" ])
|
[ "programs" "openclaw" "firstParty" ]
|
||||||
|
[ "programs" "openclaw" "bundledPlugins" ]
|
||||||
|
)
|
||||||
|
(lib.mkRenamedOptionModule
|
||||||
|
[ "programs" "openclaw" "plugins" ]
|
||||||
|
[ "programs" "openclaw" "customPlugins" ]
|
||||||
|
)
|
||||||
./options.nix
|
./options.nix
|
||||||
./config.nix
|
./config.nix
|
||||||
];
|
];
|
||||||
|
|||||||
@ -1,4 +1,11 @@
|
|||||||
{ config, lib, pkgs, openclawLib, enabledInstances, plugins }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
openclawLib,
|
||||||
|
enabledInstances,
|
||||||
|
plugins,
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = openclawLib.cfg;
|
cfg = openclawLib.cfg;
|
||||||
@ -8,7 +15,8 @@ let
|
|||||||
documentsEnabled = cfg.documents != null;
|
documentsEnabled = cfg.documents != null;
|
||||||
instanceWorkspaceDirs = map (inst: resolvePath inst.workspaceDir) (lib.attrValues enabledInstances);
|
instanceWorkspaceDirs = map (inst: resolvePath inst.workspaceDir) (lib.attrValues enabledInstances);
|
||||||
|
|
||||||
renderSkill = skill:
|
renderSkill =
|
||||||
|
skill:
|
||||||
let
|
let
|
||||||
frontmatterLines = [
|
frontmatterLines = [
|
||||||
"---"
|
"---"
|
||||||
@ -24,15 +32,18 @@ let
|
|||||||
frontmatter = lib.concatStringsSep "\n" frontmatterLines;
|
frontmatter = lib.concatStringsSep "\n" frontmatterLines;
|
||||||
body = if skill ? body then skill.body else "";
|
body = if skill ? body then skill.body else "";
|
||||||
in
|
in
|
||||||
"${frontmatter}\n\n${body}\n";
|
"${frontmatter}\n\n${body}\n";
|
||||||
|
|
||||||
skillAssertions =
|
skillAssertions =
|
||||||
let
|
let
|
||||||
names = map (skill: skill.name) cfg.skills;
|
names = map (skill: skill.name) cfg.skills;
|
||||||
nameCounts = lib.foldl' (acc: name: acc // { "${name}" = (acc.${name} or 0) + 1; }) {} names;
|
nameCounts = lib.foldl' (acc: name: acc // { "${name}" = (acc.${name} or 0) + 1; }) { } names;
|
||||||
duplicateNames = lib.attrNames (lib.filterAttrs (_: v: v > 1) nameCounts);
|
duplicateNames = lib.attrNames (lib.filterAttrs (_: v: v > 1) nameCounts);
|
||||||
in
|
in
|
||||||
if duplicateNames == [] then [] else [
|
if duplicateNames == [ ] then
|
||||||
|
[ ]
|
||||||
|
else
|
||||||
|
[
|
||||||
{
|
{
|
||||||
assertion = false;
|
assertion = false;
|
||||||
message = "programs.openclaw.skills has duplicate names: ${lib.concatStringsSep ", " duplicateNames}";
|
message = "programs.openclaw.skills has duplicate names: ${lib.concatStringsSep ", " duplicateNames}";
|
||||||
@ -41,48 +52,56 @@ let
|
|||||||
|
|
||||||
skillFiles =
|
skillFiles =
|
||||||
let
|
let
|
||||||
entriesForInstance = instName: inst:
|
entriesForInstance =
|
||||||
|
instName: inst:
|
||||||
let
|
let
|
||||||
base = "${toRelative (resolvePath inst.workspaceDir)}/skills";
|
base = "${toRelative (resolvePath inst.workspaceDir)}/skills";
|
||||||
entryFor = skill:
|
entryFor =
|
||||||
|
skill:
|
||||||
let
|
let
|
||||||
mode = skill.mode or "symlink";
|
mode = skill.mode or "symlink";
|
||||||
source = if skill ? source && skill.source != null then resolvePath skill.source else null;
|
source = if skill ? source && skill.source != null then resolvePath skill.source else null;
|
||||||
in
|
in
|
||||||
if mode == "inline" then
|
if mode == "inline" then
|
||||||
{
|
{
|
||||||
name = "${base}/${skill.name}/SKILL.md";
|
name = "${base}/${skill.name}/SKILL.md";
|
||||||
value = { text = renderSkill skill; };
|
value = {
|
||||||
}
|
text = renderSkill skill;
|
||||||
else if mode == "copy" then
|
|
||||||
{
|
|
||||||
name = "${base}/${skill.name}";
|
|
||||||
value = {
|
|
||||||
source = builtins.path {
|
|
||||||
name = "openclaw-skill-${skill.name}";
|
|
||||||
path = source;
|
|
||||||
};
|
|
||||||
recursive = true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
name = "${base}/${skill.name}";
|
|
||||||
value = {
|
|
||||||
source = config.lib.file.mkOutOfStoreSymlink source;
|
|
||||||
recursive = true;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
pluginEntriesFor = p:
|
}
|
||||||
|
else if mode == "copy" then
|
||||||
|
{
|
||||||
|
name = "${base}/${skill.name}";
|
||||||
|
value = {
|
||||||
|
source = builtins.path {
|
||||||
|
name = "openclaw-skill-${skill.name}";
|
||||||
|
path = source;
|
||||||
|
};
|
||||||
|
recursive = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name = "${base}/${skill.name}";
|
||||||
|
value = {
|
||||||
|
source = config.lib.file.mkOutOfStoreSymlink source;
|
||||||
|
recursive = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
pluginEntriesFor =
|
||||||
|
p:
|
||||||
map (skillPath: {
|
map (skillPath: {
|
||||||
name = "${base}/${builtins.baseNameOf skillPath}";
|
name = "${base}/${builtins.baseNameOf skillPath}";
|
||||||
value = { source = skillPath; recursive = true; };
|
value = {
|
||||||
|
source = skillPath;
|
||||||
|
recursive = true;
|
||||||
|
};
|
||||||
}) p.skills;
|
}) p.skills;
|
||||||
pluginsForInstance = plugins.resolvedPluginsByInstance.${instName} or [];
|
pluginsForInstance = plugins.resolvedPluginsByInstance.${instName} or [ ];
|
||||||
in
|
in
|
||||||
(map entryFor cfg.skills) ++ (lib.flatten (map pluginEntriesFor pluginsForInstance));
|
(map entryFor cfg.skills) ++ (lib.flatten (map pluginEntriesFor pluginsForInstance));
|
||||||
in
|
in
|
||||||
lib.listToAttrs (lib.flatten (lib.mapAttrsToList entriesForInstance enabledInstances));
|
lib.listToAttrs (lib.flatten (lib.mapAttrsToList entriesForInstance enabledInstances));
|
||||||
|
|
||||||
documentsRequiredFiles = [
|
documentsRequiredFiles = [
|
||||||
"AGENTS.md"
|
"AGENTS.md"
|
||||||
@ -103,9 +122,9 @@ let
|
|||||||
let
|
let
|
||||||
extra = lib.filter (file: builtins.pathExists (cfg.documents + "/${file}")) documentsOptionalFiles;
|
extra = lib.filter (file: builtins.pathExists (cfg.documents + "/${file}")) documentsOptionalFiles;
|
||||||
in
|
in
|
||||||
documentsRequiredFiles ++ extra
|
documentsRequiredFiles ++ extra
|
||||||
else
|
else
|
||||||
[];
|
[ ];
|
||||||
|
|
||||||
documentsAssertions = lib.optionals documentsEnabled [
|
documentsAssertions = lib.optionals documentsEnabled [
|
||||||
{
|
{
|
||||||
@ -126,77 +145,74 @@ let
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
documentsGuard =
|
documentsGuard = lib.optionalString documentsEnabled (
|
||||||
lib.optionalString documentsEnabled (
|
let
|
||||||
let
|
guardLine = file: ''
|
||||||
guardLine = file: ''
|
if [ -e "${file}" ] && [ ! -L "${file}" ]; then
|
||||||
if [ -e "${file}" ] && [ ! -L "${file}" ]; then
|
echo "OpenClaw documents are managed by Nix. Please adopt ${file} into your documents directory and re-run." >&2
|
||||||
echo "OpenClaw documents are managed by Nix. Please adopt ${file} into your documents directory and re-run." >&2
|
exit 1
|
||||||
exit 1
|
fi
|
||||||
fi
|
'';
|
||||||
'';
|
guardForDir = dir: ''
|
||||||
guardForDir = dir: ''
|
${lib.concatStringsSep "\n" (map (name: guardLine "${dir}/${name}") documentsFileNames)}
|
||||||
${lib.concatStringsSep "\n" (map (name: guardLine "${dir}/${name}") documentsFileNames)}
|
'';
|
||||||
'';
|
in
|
||||||
in
|
lib.concatStringsSep "\n" (map guardForDir instanceWorkspaceDirs)
|
||||||
lib.concatStringsSep "\n" (map guardForDir instanceWorkspaceDirs)
|
);
|
||||||
);
|
|
||||||
|
|
||||||
toolsReport =
|
toolsReport =
|
||||||
if documentsEnabled then
|
if documentsEnabled then
|
||||||
let
|
let
|
||||||
toolNames = toolSets.toolNames or [];
|
toolNames = toolSets.toolNames or [ ];
|
||||||
renderPkgName = pkg:
|
renderPkgName = pkg: if pkg ? pname then pkg.pname else lib.getName pkg;
|
||||||
if pkg ? pname then pkg.pname else lib.getName pkg;
|
renderPlugin =
|
||||||
renderPlugin = plugin:
|
plugin:
|
||||||
let
|
let
|
||||||
pkgNames = map renderPkgName (lib.filter (p: p != null) plugin.packages);
|
pkgNames = map renderPkgName (lib.filter (p: p != null) plugin.packages);
|
||||||
pkgSuffix =
|
pkgSuffix = if pkgNames == [ ] then "" else " — " + (lib.concatStringsSep ", " pkgNames);
|
||||||
if pkgNames == []
|
in
|
||||||
then ""
|
"- " + plugin.name + pkgSuffix + " (" + plugin.source + ")";
|
||||||
else " — " + (lib.concatStringsSep ", " pkgNames);
|
pluginLinesFor =
|
||||||
in
|
instName: inst:
|
||||||
"- " + plugin.name + pkgSuffix + " (" + plugin.source + ")";
|
let
|
||||||
pluginLinesFor = instName: inst:
|
pluginsForInstance = plugins.resolvedPluginsByInstance.${instName} or [ ];
|
||||||
let
|
lines = if pluginsForInstance == [ ] then [ "- (none)" ] else map renderPlugin pluginsForInstance;
|
||||||
pluginsForInstance = plugins.resolvedPluginsByInstance.${instName} or [];
|
in
|
||||||
lines = if pluginsForInstance == [] then [ "- (none)" ] else map renderPlugin pluginsForInstance;
|
|
||||||
in
|
|
||||||
[
|
|
||||||
""
|
|
||||||
"### Instance: ${instName}"
|
|
||||||
] ++ lines;
|
|
||||||
reportLines =
|
|
||||||
[
|
[
|
||||||
"<!-- BEGIN NIX-REPORT -->"
|
|
||||||
""
|
""
|
||||||
"## Nix-managed tools"
|
"### Instance: ${instName}"
|
||||||
""
|
|
||||||
"### Built-in toolchain"
|
|
||||||
]
|
]
|
||||||
++ (if toolNames == [] then [ "- (none)" ] else map (name: "- " + name) toolNames)
|
++ lines;
|
||||||
++ [
|
reportLines = [
|
||||||
""
|
"<!-- BEGIN NIX-REPORT -->"
|
||||||
"## Nix-managed plugin report"
|
""
|
||||||
""
|
"## Nix-managed tools"
|
||||||
"Plugins enabled per instance (last-wins on name collisions):"
|
""
|
||||||
]
|
"### Built-in toolchain"
|
||||||
++ lib.concatLists (lib.mapAttrsToList pluginLinesFor enabledInstances)
|
]
|
||||||
++ [
|
++ (if toolNames == [ ] then [ "- (none)" ] else map (name: "- " + name) toolNames)
|
||||||
""
|
++ [
|
||||||
"Tools: batteries-included toolchain + plugin-provided CLIs."
|
""
|
||||||
""
|
"## Nix-managed plugin report"
|
||||||
"<!-- END NIX-REPORT -->"
|
""
|
||||||
];
|
"Plugins enabled per instance (last-wins on name collisions):"
|
||||||
|
]
|
||||||
|
++ lib.concatLists (lib.mapAttrsToList pluginLinesFor enabledInstances)
|
||||||
|
++ [
|
||||||
|
""
|
||||||
|
"Tools: batteries-included toolchain + plugin-provided CLIs."
|
||||||
|
""
|
||||||
|
"<!-- END NIX-REPORT -->"
|
||||||
|
];
|
||||||
reportText = lib.concatStringsSep "\n" reportLines;
|
reportText = lib.concatStringsSep "\n" reportLines;
|
||||||
in
|
in
|
||||||
pkgs.writeText "openclaw-tools-report.md" reportText
|
pkgs.writeText "openclaw-tools-report.md" reportText
|
||||||
else
|
else
|
||||||
null;
|
null;
|
||||||
|
|
||||||
toolsWithReport =
|
toolsWithReport =
|
||||||
if documentsEnabled then
|
if documentsEnabled then
|
||||||
pkgs.runCommand "openclaw-tools-with-report.md" {} ''
|
pkgs.runCommand "openclaw-tools-with-report.md" { } ''
|
||||||
cat ${cfg.documents + "/TOOLS.md"} > $out
|
cat ${cfg.documents + "/TOOLS.md"} > $out
|
||||||
echo "" >> $out
|
echo "" >> $out
|
||||||
cat ${toolsReport} >> $out
|
cat ${toolsReport} >> $out
|
||||||
@ -207,7 +223,8 @@ let
|
|||||||
documentsFiles =
|
documentsFiles =
|
||||||
if documentsEnabled then
|
if documentsEnabled then
|
||||||
let
|
let
|
||||||
mkDocFiles = dir:
|
mkDocFiles =
|
||||||
|
dir:
|
||||||
let
|
let
|
||||||
mkDoc = name: {
|
mkDoc = name: {
|
||||||
name = toRelative (dir + "/${name}");
|
name = toRelative (dir + "/${name}");
|
||||||
@ -216,18 +233,20 @@ let
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
lib.listToAttrs (map mkDoc documentsFileNames);
|
lib.listToAttrs (map mkDoc documentsFileNames);
|
||||||
in
|
in
|
||||||
lib.mkMerge (map mkDocFiles instanceWorkspaceDirs)
|
lib.mkMerge (map mkDocFiles instanceWorkspaceDirs)
|
||||||
else
|
else
|
||||||
{};
|
{ };
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
inherit
|
inherit
|
||||||
documentsEnabled
|
documentsEnabled
|
||||||
documentsAssertions
|
documentsAssertions
|
||||||
documentsGuard
|
documentsGuard
|
||||||
documentsFiles
|
documentsFiles
|
||||||
skillAssertions
|
skillAssertions
|
||||||
skillFiles;
|
skillFiles
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,8 @@
|
|||||||
{ config, lib, pkgs }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.programs.openclaw;
|
cfg = config.programs.openclaw;
|
||||||
@ -9,59 +13,62 @@ let
|
|||||||
toolNamesOverride = cfg.toolNames;
|
toolNamesOverride = cfg.toolNames;
|
||||||
excludeToolNames = effectiveExcludeTools;
|
excludeToolNames = effectiveExcludeTools;
|
||||||
};
|
};
|
||||||
toolOverridesEnabled = cfg.toolNames != null || effectiveExcludeTools != [];
|
toolOverridesEnabled = cfg.toolNames != null || effectiveExcludeTools != [ ];
|
||||||
toolSets = import ../../../tools/extended.nix ({ inherit pkgs; } // toolOverrides);
|
toolSets = import ../../../tools/extended.nix ({ inherit pkgs; } // toolOverrides);
|
||||||
defaultPackage =
|
defaultPackage =
|
||||||
if toolOverridesEnabled && cfg.package == pkgs.openclaw
|
if toolOverridesEnabled && cfg.package == pkgs.openclaw then
|
||||||
then (pkgs.openclawPackages.withTools toolOverrides).openclaw
|
(pkgs.openclawPackages.withTools toolOverrides).openclaw
|
||||||
else cfg.package;
|
else
|
||||||
|
cfg.package;
|
||||||
appPackage = if cfg.appPackage != null then cfg.appPackage else defaultPackage;
|
appPackage = if cfg.appPackage != null then cfg.appPackage else defaultPackage;
|
||||||
generatedConfigOptions = import ../../../generated/openclaw-config-options.nix { lib = lib; };
|
generatedConfigOptions = import ../../../generated/openclaw-config-options.nix { lib = lib; };
|
||||||
|
|
||||||
bundledPluginSources = let
|
bundledPluginSources =
|
||||||
stepieteRev = "983210e3b6e9285780e87f48ce9354b51a270e95";
|
|
||||||
stepieteNarHash = "sha256-fY8t41kMSHu2ovf89mIdvC7vkceroCwKxw/MKVn4rsE=";
|
|
||||||
stepiete = tool:
|
|
||||||
"github:openclaw/nix-steipete-tools?dir=tools/${tool}&rev=${stepieteRev}&narHash=${stepieteNarHash}";
|
|
||||||
in {
|
|
||||||
summarize = stepiete "summarize";
|
|
||||||
peekaboo = stepiete "peekaboo";
|
|
||||||
oracle = stepiete "oracle";
|
|
||||||
poltergeist = stepiete "poltergeist";
|
|
||||||
sag = stepiete "sag";
|
|
||||||
camsnap = stepiete "camsnap";
|
|
||||||
gogcli = stepiete "gogcli";
|
|
||||||
goplaces = stepiete "goplaces";
|
|
||||||
bird = stepiete "bird";
|
|
||||||
sonoscli = stepiete "sonoscli";
|
|
||||||
imsg = stepiete "imsg";
|
|
||||||
};
|
|
||||||
|
|
||||||
bundledPlugins = lib.filter (p: p != null) (lib.mapAttrsToList (name: source:
|
|
||||||
let
|
let
|
||||||
pluginCfg = cfg.bundledPlugins.${name};
|
stepieteRev = "983210e3b6e9285780e87f48ce9354b51a270e95";
|
||||||
|
stepieteNarHash = "sha256-fY8t41kMSHu2ovf89mIdvC7vkceroCwKxw/MKVn4rsE=";
|
||||||
|
stepiete =
|
||||||
|
tool:
|
||||||
|
"github:openclaw/nix-steipete-tools?dir=tools/${tool}&rev=${stepieteRev}&narHash=${stepieteNarHash}";
|
||||||
in
|
in
|
||||||
if (pluginCfg.enable or false) then {
|
{
|
||||||
inherit source;
|
summarize = stepiete "summarize";
|
||||||
config = pluginCfg.config or {};
|
peekaboo = stepiete "peekaboo";
|
||||||
} else null
|
oracle = stepiete "oracle";
|
||||||
) bundledPluginSources);
|
poltergeist = stepiete "poltergeist";
|
||||||
|
sag = stepiete "sag";
|
||||||
|
camsnap = stepiete "camsnap";
|
||||||
|
gogcli = stepiete "gogcli";
|
||||||
|
goplaces = stepiete "goplaces";
|
||||||
|
bird = stepiete "bird";
|
||||||
|
sonoscli = stepiete "sonoscli";
|
||||||
|
imsg = stepiete "imsg";
|
||||||
|
};
|
||||||
|
|
||||||
|
bundledPlugins = lib.filter (p: p != null) (
|
||||||
|
lib.mapAttrsToList (
|
||||||
|
name: source:
|
||||||
|
let
|
||||||
|
pluginCfg = cfg.bundledPlugins.${name};
|
||||||
|
in
|
||||||
|
if (pluginCfg.enable or false) then
|
||||||
|
{
|
||||||
|
inherit source;
|
||||||
|
config = pluginCfg.config or { };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
null
|
||||||
|
) bundledPluginSources
|
||||||
|
);
|
||||||
|
|
||||||
effectivePlugins = cfg.customPlugins ++ bundledPlugins;
|
effectivePlugins = cfg.customPlugins ++ bundledPlugins;
|
||||||
|
|
||||||
resolvePath = p:
|
resolvePath = p: if lib.hasPrefix "~/" p then "${homeDir}/${lib.removePrefix "~/" p}" else p;
|
||||||
if lib.hasPrefix "~/" p then
|
|
||||||
"${homeDir}/${lib.removePrefix "~/" p}"
|
|
||||||
else
|
|
||||||
p;
|
|
||||||
|
|
||||||
toRelative = p:
|
toRelative = p: if lib.hasPrefix "${homeDir}/" p then lib.removePrefix "${homeDir}/" p else p;
|
||||||
if lib.hasPrefix "${homeDir}/" p then
|
|
||||||
lib.removePrefix "${homeDir}/" p
|
|
||||||
else
|
|
||||||
p;
|
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
inherit
|
inherit
|
||||||
cfg
|
cfg
|
||||||
homeDir
|
homeDir
|
||||||
@ -75,5 +82,6 @@ in {
|
|||||||
bundledPlugins
|
bundledPlugins
|
||||||
effectivePlugins
|
effectivePlugins
|
||||||
resolvePath
|
resolvePath
|
||||||
toRelative;
|
toRelative
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,9 +17,11 @@
|
|||||||
|
|
||||||
stateDir = lib.mkOption {
|
stateDir = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = if name == "default"
|
default =
|
||||||
then "${openclawLib.homeDir}/.openclaw"
|
if name == "default" then
|
||||||
else "${openclawLib.homeDir}/.openclaw-${name}";
|
"${openclawLib.homeDir}/.openclaw"
|
||||||
|
else
|
||||||
|
"${openclawLib.homeDir}/.openclaw-${name}";
|
||||||
description = "State directory for this OpenClaw instance (logs, sessions, config).";
|
description = "State directory for this OpenClaw instance (logs, sessions, config).";
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -37,9 +39,11 @@
|
|||||||
|
|
||||||
logPath = lib.mkOption {
|
logPath = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = if name == "default"
|
default =
|
||||||
then "/tmp/openclaw/openclaw-gateway.log"
|
if name == "default" then
|
||||||
else "/tmp/openclaw/openclaw-gateway-${name}.log";
|
"/tmp/openclaw/openclaw-gateway.log"
|
||||||
|
else
|
||||||
|
"/tmp/openclaw/openclaw-gateway-${name}.log";
|
||||||
description = "Log path for this OpenClaw gateway instance.";
|
description = "Log path for this OpenClaw gateway instance.";
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -62,26 +66,28 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
plugins = lib.mkOption {
|
plugins = lib.mkOption {
|
||||||
type = lib.types.listOf (lib.types.submodule {
|
type = lib.types.listOf (
|
||||||
options = {
|
lib.types.submodule {
|
||||||
source = lib.mkOption {
|
options = {
|
||||||
type = lib.types.str;
|
source = lib.mkOption {
|
||||||
description = "Plugin source pointer (e.g., github:owner/repo or path:/...).";
|
type = lib.types.str;
|
||||||
|
description = "Plugin source pointer (e.g., github:owner/repo or path:/...).";
|
||||||
|
};
|
||||||
|
config = lib.mkOption {
|
||||||
|
type = lib.types.attrs;
|
||||||
|
default = { };
|
||||||
|
description = "Plugin-specific configuration (env/files/etc).";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
config = lib.mkOption {
|
}
|
||||||
type = lib.types.attrs;
|
);
|
||||||
default = {};
|
|
||||||
description = "Plugin-specific configuration (env/files/etc).";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
});
|
|
||||||
default = openclawLib.effectivePlugins;
|
default = openclawLib.effectivePlugins;
|
||||||
description = "Plugins enabled for this instance (includes first-party toggles).";
|
description = "Plugins enabled for this instance (includes first-party toggles).";
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkOption {
|
config = lib.mkOption {
|
||||||
type = lib.types.submodule { options = openclawLib.generatedConfigOptions; };
|
type = lib.types.submodule { options = openclawLib.generatedConfigOptions; };
|
||||||
default = {};
|
default = { };
|
||||||
description = "OpenClaw config (schema-typed).";
|
description = "OpenClaw config (schema-typed).";
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -93,9 +99,11 @@
|
|||||||
|
|
||||||
launchd.label = lib.mkOption {
|
launchd.label = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = if name == "default"
|
default =
|
||||||
then "com.steipete.openclaw.gateway"
|
if name == "default" then
|
||||||
else "com.steipete.openclaw.gateway.${name}";
|
"com.steipete.openclaw.gateway"
|
||||||
|
else
|
||||||
|
"com.steipete.openclaw.gateway.${name}";
|
||||||
description = "launchd label for this instance.";
|
description = "launchd label for this instance.";
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -107,9 +115,7 @@
|
|||||||
|
|
||||||
systemd.unitName = lib.mkOption {
|
systemd.unitName = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = if name == "default"
|
default = if name == "default" then "openclaw-gateway" else "openclaw-gateway-${name}";
|
||||||
then "openclaw-gateway"
|
|
||||||
else "openclaw-gateway-${name}";
|
|
||||||
description = "systemd user service unit name for this instance.";
|
description = "systemd user service unit name for this instance.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,9 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
openclawLib = import ./lib.nix { inherit config lib pkgs; };
|
openclawLib = import ./lib.nix { inherit config lib pkgs; };
|
||||||
@ -30,7 +35,11 @@ let
|
|||||||
description = "Optional openclaw metadata for the skill frontmatter.";
|
description = "Optional openclaw metadata for the skill frontmatter.";
|
||||||
};
|
};
|
||||||
mode = lib.mkOption {
|
mode = lib.mkOption {
|
||||||
type = lib.types.enum [ "symlink" "copy" "inline" ];
|
type = lib.types.enum [
|
||||||
|
"symlink"
|
||||||
|
"copy"
|
||||||
|
"inline"
|
||||||
|
];
|
||||||
default = "symlink";
|
default = "symlink";
|
||||||
description = "Install mode for the skill (symlink/copy/inline).";
|
description = "Install mode for the skill (symlink/copy/inline).";
|
||||||
};
|
};
|
||||||
@ -42,7 +51,8 @@ let
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
options.programs.openclaw = {
|
options.programs.openclaw = {
|
||||||
enable = lib.mkEnableOption "OpenClaw (batteries-included)";
|
enable = lib.mkEnableOption "OpenClaw (batteries-included)";
|
||||||
|
|
||||||
@ -60,7 +70,7 @@ in {
|
|||||||
|
|
||||||
excludeTools = lib.mkOption {
|
excludeTools = lib.mkOption {
|
||||||
type = lib.types.listOf lib.types.str;
|
type = lib.types.listOf lib.types.str;
|
||||||
default = [];
|
default = [ ];
|
||||||
description = "Tool names to remove from the built-in toolchain.";
|
description = "Tool names to remove from the built-in toolchain.";
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -104,54 +114,66 @@ in {
|
|||||||
|
|
||||||
skills = lib.mkOption {
|
skills = lib.mkOption {
|
||||||
type = lib.types.listOf mkSkillOption;
|
type = lib.types.listOf mkSkillOption;
|
||||||
default = [];
|
default = [ ];
|
||||||
description = "Declarative skills installed into each instance workspace.";
|
description = "Declarative skills installed into each instance workspace.";
|
||||||
};
|
};
|
||||||
|
|
||||||
customPlugins = lib.mkOption {
|
customPlugins = lib.mkOption {
|
||||||
type = lib.types.listOf (lib.types.submodule {
|
type = lib.types.listOf (
|
||||||
options = {
|
lib.types.submodule {
|
||||||
source = lib.mkOption {
|
options = {
|
||||||
type = lib.types.str;
|
source = lib.mkOption {
|
||||||
description = "Plugin source pointer (e.g., github:owner/repo or path:/...).";
|
type = lib.types.str;
|
||||||
|
description = "Plugin source pointer (e.g., github:owner/repo or path:/...).";
|
||||||
|
};
|
||||||
|
config = lib.mkOption {
|
||||||
|
type = lib.types.attrs;
|
||||||
|
default = { };
|
||||||
|
description = "Plugin-specific configuration (env/files/etc).";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
config = lib.mkOption {
|
}
|
||||||
type = lib.types.attrs;
|
);
|
||||||
default = {};
|
default = [ ];
|
||||||
description = "Plugin-specific configuration (env/files/etc).";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
});
|
|
||||||
default = [];
|
|
||||||
description = "Custom/community plugins (merged with bundled plugin toggles).";
|
description = "Custom/community plugins (merged with bundled plugin toggles).";
|
||||||
};
|
};
|
||||||
|
|
||||||
bundledPlugins = let
|
bundledPlugins =
|
||||||
mkPlugin = { name, defaultEnable ? false }: {
|
let
|
||||||
enable = lib.mkOption {
|
mkPlugin =
|
||||||
type = lib.types.bool;
|
{
|
||||||
default = defaultEnable;
|
name,
|
||||||
description = "Enable the ${name} plugin (bundled).";
|
defaultEnable ? false,
|
||||||
};
|
}:
|
||||||
config = lib.mkOption {
|
{
|
||||||
type = lib.types.attrs;
|
enable = lib.mkOption {
|
||||||
default = {};
|
type = lib.types.bool;
|
||||||
description = "Bundled plugin configuration passed through to ${name} (env/settings).";
|
default = defaultEnable;
|
||||||
|
description = "Enable the ${name} plugin (bundled).";
|
||||||
|
};
|
||||||
|
config = lib.mkOption {
|
||||||
|
type = lib.types.attrs;
|
||||||
|
default = { };
|
||||||
|
description = "Bundled plugin configuration passed through to ${name} (env/settings).";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
summarize = mkPlugin { name = "summarize"; };
|
||||||
|
peekaboo = mkPlugin { name = "peekaboo"; };
|
||||||
|
oracle = mkPlugin { name = "oracle"; };
|
||||||
|
poltergeist = mkPlugin { name = "poltergeist"; };
|
||||||
|
sag = mkPlugin { name = "sag"; };
|
||||||
|
camsnap = mkPlugin { name = "camsnap"; };
|
||||||
|
gogcli = mkPlugin { name = "gogcli"; };
|
||||||
|
goplaces = mkPlugin {
|
||||||
|
name = "goplaces";
|
||||||
|
defaultEnable = true;
|
||||||
};
|
};
|
||||||
|
bird = mkPlugin { name = "bird"; };
|
||||||
|
sonoscli = mkPlugin { name = "sonoscli"; };
|
||||||
|
imsg = mkPlugin { name = "imsg"; };
|
||||||
};
|
};
|
||||||
in {
|
|
||||||
summarize = mkPlugin { name = "summarize"; };
|
|
||||||
peekaboo = mkPlugin { name = "peekaboo"; };
|
|
||||||
oracle = mkPlugin { name = "oracle"; };
|
|
||||||
poltergeist = mkPlugin { name = "poltergeist"; };
|
|
||||||
sag = mkPlugin { name = "sag"; };
|
|
||||||
camsnap = mkPlugin { name = "camsnap"; };
|
|
||||||
gogcli = mkPlugin { name = "gogcli"; };
|
|
||||||
goplaces = mkPlugin { name = "goplaces"; defaultEnable = true; };
|
|
||||||
bird = mkPlugin { name = "bird"; };
|
|
||||||
sonoscli = mkPlugin { name = "sonoscli"; };
|
|
||||||
imsg = mkPlugin { name = "imsg"; };
|
|
||||||
};
|
|
||||||
|
|
||||||
launchd.enable = lib.mkOption {
|
launchd.enable = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.bool;
|
||||||
@ -179,7 +201,7 @@ in {
|
|||||||
|
|
||||||
instances = lib.mkOption {
|
instances = lib.mkOption {
|
||||||
type = lib.types.attrsOf (lib.types.submodule instanceModule);
|
type = lib.types.attrsOf (lib.types.submodule instanceModule);
|
||||||
default = {};
|
default = { };
|
||||||
description = "Named OpenClaw instances (prod/test).";
|
description = "Named OpenClaw instances (prod/test).";
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -199,7 +221,7 @@ in {
|
|||||||
|
|
||||||
config = lib.mkOption {
|
config = lib.mkOption {
|
||||||
type = lib.types.submodule { options = openclawLib.generatedConfigOptions; };
|
type = lib.types.submodule { options = openclawLib.generatedConfigOptions; };
|
||||||
default = {};
|
default = { };
|
||||||
description = "OpenClaw config (schema-typed).";
|
description = "OpenClaw config (schema-typed).";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,104 +1,124 @@
|
|||||||
{ lib, pkgs, openclawLib, enabledInstances }:
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
openclawLib,
|
||||||
|
enabledInstances,
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
resolvePath = openclawLib.resolvePath;
|
resolvePath = openclawLib.resolvePath;
|
||||||
toRelative = openclawLib.toRelative;
|
toRelative = openclawLib.toRelative;
|
||||||
|
|
||||||
resolvePlugin = plugin: let
|
resolvePlugin =
|
||||||
flake = builtins.getFlake plugin.source;
|
plugin:
|
||||||
system = pkgs.stdenv.hostPlatform.system;
|
|
||||||
openclawPluginRaw =
|
|
||||||
if flake ? openclawPlugin then flake.openclawPlugin
|
|
||||||
else throw "openclawPlugin missing in ${plugin.source}";
|
|
||||||
openclawPlugin =
|
|
||||||
if builtins.isFunction openclawPluginRaw
|
|
||||||
then openclawPluginRaw system
|
|
||||||
else openclawPluginRaw;
|
|
||||||
resolvedPlugin =
|
|
||||||
if openclawPlugin == null
|
|
||||||
then throw "openclawPlugin is null in ${plugin.source} for ${system}"
|
|
||||||
else openclawPlugin;
|
|
||||||
needs = resolvedPlugin.needs or {};
|
|
||||||
in {
|
|
||||||
source = plugin.source;
|
|
||||||
name = resolvedPlugin.name or (throw "openclawPlugin.name missing in ${plugin.source}");
|
|
||||||
skills = resolvedPlugin.skills or [];
|
|
||||||
packages = resolvedPlugin.packages or [];
|
|
||||||
needs = {
|
|
||||||
stateDirs = needs.stateDirs or [];
|
|
||||||
requiredEnv = needs.requiredEnv or [];
|
|
||||||
};
|
|
||||||
config = plugin.config or {};
|
|
||||||
};
|
|
||||||
|
|
||||||
resolvedPluginsByInstance =
|
|
||||||
lib.mapAttrs (instName: inst:
|
|
||||||
let
|
|
||||||
resolved = map resolvePlugin inst.plugins;
|
|
||||||
counts = lib.foldl' (acc: p:
|
|
||||||
acc // { "${p.name}" = (acc.${p.name} or 0) + 1; }
|
|
||||||
) {} resolved;
|
|
||||||
duplicates = lib.attrNames (lib.filterAttrs (_: v: v > 1) counts);
|
|
||||||
byName = lib.foldl' (acc: p: acc // { "${p.name}" = p; }) {} resolved;
|
|
||||||
ordered = lib.attrValues byName;
|
|
||||||
in
|
|
||||||
if duplicates == []
|
|
||||||
then ordered
|
|
||||||
else lib.warn
|
|
||||||
"programs.openclaw.instances.${instName}: duplicate plugin names detected (${lib.concatStringsSep ", " duplicates}); last entry wins."
|
|
||||||
ordered
|
|
||||||
) enabledInstances;
|
|
||||||
|
|
||||||
pluginPackagesFor = instName:
|
|
||||||
lib.flatten (map (p: p.packages) (resolvedPluginsByInstance.${instName} or []));
|
|
||||||
|
|
||||||
pluginPackagesAll =
|
|
||||||
lib.flatten (map pluginPackagesFor (lib.attrNames enabledInstances));
|
|
||||||
|
|
||||||
pluginStateDirsFor = instName:
|
|
||||||
let
|
let
|
||||||
dirs = lib.flatten (map (p: p.needs.stateDirs) (resolvedPluginsByInstance.${instName} or []));
|
flake = builtins.getFlake plugin.source;
|
||||||
|
system = pkgs.stdenv.hostPlatform.system;
|
||||||
|
openclawPluginRaw =
|
||||||
|
if flake ? openclawPlugin then
|
||||||
|
flake.openclawPlugin
|
||||||
|
else
|
||||||
|
throw "openclawPlugin missing in ${plugin.source}";
|
||||||
|
openclawPlugin =
|
||||||
|
if builtins.isFunction openclawPluginRaw then openclawPluginRaw system else openclawPluginRaw;
|
||||||
|
resolvedPlugin =
|
||||||
|
if openclawPlugin == null then
|
||||||
|
throw "openclawPlugin is null in ${plugin.source} for ${system}"
|
||||||
|
else
|
||||||
|
openclawPlugin;
|
||||||
|
needs = resolvedPlugin.needs or { };
|
||||||
in
|
in
|
||||||
map (dir: resolvePath ("~/" + dir)) dirs;
|
{
|
||||||
|
source = plugin.source;
|
||||||
|
name = resolvedPlugin.name or (throw "openclawPlugin.name missing in ${plugin.source}");
|
||||||
|
skills = resolvedPlugin.skills or [ ];
|
||||||
|
packages = resolvedPlugin.packages or [ ];
|
||||||
|
needs = {
|
||||||
|
stateDirs = needs.stateDirs or [ ];
|
||||||
|
requiredEnv = needs.requiredEnv or [ ];
|
||||||
|
};
|
||||||
|
config = plugin.config or { };
|
||||||
|
};
|
||||||
|
|
||||||
pluginStateDirsAll =
|
resolvedPluginsByInstance = lib.mapAttrs (
|
||||||
lib.flatten (map pluginStateDirsFor (lib.attrNames enabledInstances));
|
instName: inst:
|
||||||
|
|
||||||
pluginEnvFor = instName:
|
|
||||||
let
|
let
|
||||||
entries = resolvedPluginsByInstance.${instName} or [];
|
resolved = map resolvePlugin inst.plugins;
|
||||||
toPairs = p:
|
counts = lib.foldl' (acc: p: acc // { "${p.name}" = (acc.${p.name} or 0) + 1; }) { } resolved;
|
||||||
|
duplicates = lib.attrNames (lib.filterAttrs (_: v: v > 1) counts);
|
||||||
|
byName = lib.foldl' (acc: p: acc // { "${p.name}" = p; }) { } resolved;
|
||||||
|
ordered = lib.attrValues byName;
|
||||||
|
in
|
||||||
|
if duplicates == [ ] then
|
||||||
|
ordered
|
||||||
|
else
|
||||||
|
lib.warn "programs.openclaw.instances.${instName}: duplicate plugin names detected (${lib.concatStringsSep ", " duplicates}); last entry wins." ordered
|
||||||
|
) enabledInstances;
|
||||||
|
|
||||||
|
pluginPackagesFor =
|
||||||
|
instName: lib.flatten (map (p: p.packages) (resolvedPluginsByInstance.${instName} or [ ]));
|
||||||
|
|
||||||
|
pluginPackagesAll = lib.flatten (map pluginPackagesFor (lib.attrNames enabledInstances));
|
||||||
|
|
||||||
|
pluginStateDirsFor =
|
||||||
|
instName:
|
||||||
|
let
|
||||||
|
dirs = lib.flatten (map (p: p.needs.stateDirs) (resolvedPluginsByInstance.${instName} or [ ]));
|
||||||
|
in
|
||||||
|
map (dir: resolvePath ("~/" + dir)) dirs;
|
||||||
|
|
||||||
|
pluginStateDirsAll = lib.flatten (map pluginStateDirsFor (lib.attrNames enabledInstances));
|
||||||
|
|
||||||
|
pluginEnvFor =
|
||||||
|
instName:
|
||||||
|
let
|
||||||
|
entries = resolvedPluginsByInstance.${instName} or [ ];
|
||||||
|
toPairs =
|
||||||
|
p:
|
||||||
let
|
let
|
||||||
env = (p.config.env or {});
|
env = (p.config.env or { });
|
||||||
required = p.needs.requiredEnv;
|
required = p.needs.requiredEnv;
|
||||||
in
|
in
|
||||||
map (k: { key = k; value = env.${k} or ""; plugin = p.name; }) required;
|
map (k: {
|
||||||
|
key = k;
|
||||||
|
value = env.${k} or "";
|
||||||
|
plugin = p.name;
|
||||||
|
}) required;
|
||||||
in
|
in
|
||||||
lib.flatten (map toPairs entries);
|
lib.flatten (map toPairs entries);
|
||||||
|
|
||||||
pluginEnvAllFor = instName:
|
pluginEnvAllFor =
|
||||||
|
instName:
|
||||||
let
|
let
|
||||||
entries = resolvedPluginsByInstance.${instName} or [];
|
entries = resolvedPluginsByInstance.${instName} or [ ];
|
||||||
toPairs = p:
|
toPairs =
|
||||||
let env = (p.config.env or {});
|
p:
|
||||||
in map (k: { key = k; value = env.${k}; plugin = p.name; }) (lib.attrNames env);
|
let
|
||||||
|
env = (p.config.env or { });
|
||||||
|
in
|
||||||
|
map (k: {
|
||||||
|
key = k;
|
||||||
|
value = env.${k};
|
||||||
|
plugin = p.name;
|
||||||
|
}) (lib.attrNames env);
|
||||||
in
|
in
|
||||||
lib.flatten (map toPairs entries);
|
lib.flatten (map toPairs entries);
|
||||||
|
|
||||||
pluginAssertions =
|
pluginAssertions = lib.flatten (
|
||||||
lib.flatten (lib.mapAttrsToList (instName: inst:
|
lib.mapAttrsToList (
|
||||||
|
instName: inst:
|
||||||
let
|
let
|
||||||
plugins = resolvedPluginsByInstance.${instName} or [];
|
plugins = resolvedPluginsByInstance.${instName} or [ ];
|
||||||
envFor = p: (p.config.env or {});
|
envFor = p: (p.config.env or { });
|
||||||
missingFor = p:
|
missingFor = p: lib.filter (req: !(builtins.hasAttr req (envFor p))) p.needs.requiredEnv;
|
||||||
lib.filter (req: !(builtins.hasAttr req (envFor p))) p.needs.requiredEnv;
|
configMissingStateDir = p: (p.config.settings or { }) != { } && (p.needs.stateDirs or [ ]) == [ ];
|
||||||
configMissingStateDir = p:
|
mkAssertion =
|
||||||
(p.config.settings or {}) != {} && (p.needs.stateDirs or []) == [];
|
p:
|
||||||
mkAssertion = p:
|
|
||||||
let
|
let
|
||||||
missing = missingFor p;
|
missing = missingFor p;
|
||||||
in {
|
in
|
||||||
assertion = missing == [];
|
{
|
||||||
|
assertion = missing == [ ];
|
||||||
message = "programs.openclaw.instances.${instName}: plugin ${p.name} missing required env: ${lib.concatStringsSep ", " missing}";
|
message = "programs.openclaw.instances.${instName}: plugin ${p.name} missing required env: ${lib.concatStringsSep ", " missing}";
|
||||||
};
|
};
|
||||||
mkConfigAssertion = p: {
|
mkConfigAssertion = p: {
|
||||||
@ -106,75 +126,86 @@ let
|
|||||||
message = "programs.openclaw.instances.${instName}: plugin ${p.name} provides settings but declares no stateDirs (needed for config.json).";
|
message = "programs.openclaw.instances.${instName}: plugin ${p.name} provides settings but declares no stateDirs (needed for config.json).";
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
(map mkAssertion plugins) ++ (map mkConfigAssertion plugins)
|
(map mkAssertion plugins) ++ (map mkConfigAssertion plugins)
|
||||||
) enabledInstances);
|
) enabledInstances
|
||||||
|
);
|
||||||
|
|
||||||
pluginSkillsFiles =
|
pluginSkillsFiles =
|
||||||
let
|
let
|
||||||
entriesForInstance = instName: inst:
|
entriesForInstance =
|
||||||
|
instName: inst:
|
||||||
let
|
let
|
||||||
base = "${toRelative (resolvePath inst.workspaceDir)}/skills";
|
base = "${toRelative (resolvePath inst.workspaceDir)}/skills";
|
||||||
skillEntriesFor = p:
|
skillEntriesFor =
|
||||||
|
p:
|
||||||
map (skillPath: {
|
map (skillPath: {
|
||||||
name = "${base}/${builtins.baseNameOf skillPath}";
|
name = "${base}/${builtins.baseNameOf skillPath}";
|
||||||
value = { source = skillPath; recursive = true; };
|
value = {
|
||||||
|
source = skillPath;
|
||||||
|
recursive = true;
|
||||||
|
};
|
||||||
}) p.skills;
|
}) p.skills;
|
||||||
plugins = resolvedPluginsByInstance.${instName} or [];
|
plugins = resolvedPluginsByInstance.${instName} or [ ];
|
||||||
in
|
in
|
||||||
lib.flatten (map skillEntriesFor plugins);
|
lib.flatten (map skillEntriesFor plugins);
|
||||||
in
|
in
|
||||||
lib.listToAttrs (lib.flatten (lib.mapAttrsToList entriesForInstance enabledInstances));
|
lib.listToAttrs (lib.flatten (lib.mapAttrsToList entriesForInstance enabledInstances));
|
||||||
|
|
||||||
pluginConfigFiles =
|
pluginConfigFiles =
|
||||||
let
|
let
|
||||||
entryFor = instName: inst:
|
entryFor =
|
||||||
|
instName: inst:
|
||||||
let
|
let
|
||||||
plugins = resolvedPluginsByInstance.${instName} or [];
|
plugins = resolvedPluginsByInstance.${instName} or [ ];
|
||||||
mkEntries = p:
|
mkEntries =
|
||||||
|
p:
|
||||||
let
|
let
|
||||||
cfg = p.config.settings or {};
|
cfg = p.config.settings or { };
|
||||||
dir =
|
dir = if (p.needs.stateDirs or [ ]) == [ ] then null else lib.head (p.needs.stateDirs or [ ]);
|
||||||
if (p.needs.stateDirs or []) == []
|
|
||||||
then null
|
|
||||||
else lib.head (p.needs.stateDirs or []);
|
|
||||||
in
|
in
|
||||||
if cfg == {} then
|
if cfg == { } then
|
||||||
[]
|
[ ]
|
||||||
else
|
else
|
||||||
(if dir == null then
|
(
|
||||||
|
if dir == null then
|
||||||
throw "plugin ${p.name} provides settings but no stateDirs are defined"
|
throw "plugin ${p.name} provides settings but no stateDirs are defined"
|
||||||
else [
|
else
|
||||||
{
|
[
|
||||||
name = toRelative (resolvePath ("~/" + dir + "/config.json"));
|
{
|
||||||
value = { text = builtins.toJSON cfg; };
|
name = toRelative (resolvePath ("~/" + dir + "/config.json"));
|
||||||
}
|
value = {
|
||||||
]);
|
text = builtins.toJSON cfg;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
in
|
in
|
||||||
lib.flatten (map mkEntries plugins);
|
lib.flatten (map mkEntries plugins);
|
||||||
entries = lib.flatten (lib.mapAttrsToList entryFor enabledInstances);
|
entries = lib.flatten (lib.mapAttrsToList entryFor enabledInstances);
|
||||||
in
|
in
|
||||||
lib.listToAttrs entries;
|
lib.listToAttrs entries;
|
||||||
|
|
||||||
pluginSkillAssertions =
|
pluginSkillAssertions =
|
||||||
let
|
let
|
||||||
skillTargets =
|
skillTargets = lib.flatten (
|
||||||
lib.flatten (lib.concatLists (lib.mapAttrsToList (instName: inst:
|
lib.concatLists (
|
||||||
let
|
lib.mapAttrsToList (
|
||||||
base = "${toRelative (resolvePath inst.workspaceDir)}/skills";
|
instName: inst:
|
||||||
plugins = resolvedPluginsByInstance.${instName} or [];
|
let
|
||||||
in
|
base = "${toRelative (resolvePath inst.workspaceDir)}/skills";
|
||||||
map (p:
|
plugins = resolvedPluginsByInstance.${instName} or [ ];
|
||||||
map (skillPath:
|
in
|
||||||
"${base}/${p.name}/${builtins.baseNameOf skillPath}"
|
map (p: map (skillPath: "${base}/${p.name}/${builtins.baseNameOf skillPath}") p.skills) plugins
|
||||||
) p.skills
|
) enabledInstances
|
||||||
) plugins
|
)
|
||||||
) enabledInstances));
|
);
|
||||||
counts = lib.foldl' (acc: path:
|
counts = lib.foldl' (acc: path: acc // { "${path}" = (acc.${path} or 0) + 1; }) { } skillTargets;
|
||||||
acc // { "${path}" = (acc.${path} or 0) + 1; }
|
|
||||||
) {} skillTargets;
|
|
||||||
duplicates = lib.attrNames (lib.filterAttrs (_: v: v > 1) counts);
|
duplicates = lib.attrNames (lib.filterAttrs (_: v: v > 1) counts);
|
||||||
in
|
in
|
||||||
if duplicates == [] then [] else [
|
if duplicates == [ ] then
|
||||||
|
[ ]
|
||||||
|
else
|
||||||
|
[
|
||||||
{
|
{
|
||||||
assertion = false;
|
assertion = false;
|
||||||
message = "Duplicate skill paths detected: ${lib.concatStringsSep ", " duplicates}";
|
message = "Duplicate skill paths detected: ${lib.concatStringsSep ", " duplicates}";
|
||||||
@ -193,13 +224,14 @@ let
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
entriesForInstance = instName:
|
entriesForInstance =
|
||||||
map (entry: entry // { instance = instName; }) (pluginEnvFor instName);
|
instName: map (entry: entry // { instance = instName; }) (pluginEnvFor instName);
|
||||||
entries = lib.flatten (map entriesForInstance (lib.attrNames enabledInstances));
|
entries = lib.flatten (map entriesForInstance (lib.attrNames enabledInstances));
|
||||||
in
|
in
|
||||||
lib.concatStringsSep "\n" (map renderCheck entries);
|
lib.concatStringsSep "\n" (map renderCheck entries);
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
inherit
|
inherit
|
||||||
resolvedPluginsByInstance
|
resolvedPluginsByInstance
|
||||||
pluginPackagesFor
|
pluginPackagesFor
|
||||||
@ -212,5 +244,6 @@ in {
|
|||||||
pluginSkillsFiles
|
pluginSkillsFiles
|
||||||
pluginConfigFiles
|
pluginConfigFiles
|
||||||
pluginSkillAssertions
|
pluginSkillAssertions
|
||||||
pluginGuards;
|
pluginGuards
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,13 +2,18 @@ final: prev:
|
|||||||
let
|
let
|
||||||
packages = import ./packages { pkgs = prev; };
|
packages = import ./packages { pkgs = prev; };
|
||||||
toolNames = (import ./tools/extended.nix { pkgs = prev; }).toolNames;
|
toolNames = (import ./tools/extended.nix { pkgs = prev; }).toolNames;
|
||||||
withTools = { toolNamesOverride ? null, excludeToolNames ? [] }:
|
withTools =
|
||||||
|
{
|
||||||
|
toolNamesOverride ? null,
|
||||||
|
excludeToolNames ? [ ],
|
||||||
|
}:
|
||||||
import ./packages {
|
import ./packages {
|
||||||
pkgs = prev;
|
pkgs = prev;
|
||||||
inherit toolNamesOverride excludeToolNames;
|
inherit toolNamesOverride excludeToolNames;
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
packages // {
|
packages
|
||||||
|
// {
|
||||||
openclawPackages = packages // {
|
openclawPackages = packages // {
|
||||||
inherit toolNames withTools;
|
inherit toolNames withTools;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
{ pkgs
|
{
|
||||||
, sourceInfo ? import ../sources/openclaw-source.nix
|
pkgs,
|
||||||
, steipetePkgs ? {}
|
sourceInfo ? import ../sources/openclaw-source.nix,
|
||||||
, toolNamesOverride ? null
|
steipetePkgs ? { },
|
||||||
, excludeToolNames ? []
|
toolNamesOverride ? null,
|
||||||
|
excludeToolNames ? [ ],
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
isDarwin = pkgs.stdenv.hostPlatform.isDarwin;
|
isDarwin = pkgs.stdenv.hostPlatform.isDarwin;
|
||||||
@ -26,8 +27,10 @@ let
|
|||||||
openclaw-app = openclawApp;
|
openclaw-app = openclawApp;
|
||||||
extendedTools = toolSets.tools;
|
extendedTools = toolSets.tools;
|
||||||
};
|
};
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
openclaw-gateway = openclawGateway;
|
openclaw-gateway = openclawGateway;
|
||||||
openclaw = openclawBundle;
|
openclaw = openclawBundle;
|
||||||
openclaw-tools = openclawTools;
|
openclaw-tools = openclawTools;
|
||||||
} // (if isDarwin then { openclaw-app = openclawApp; } else {})
|
}
|
||||||
|
// (if isDarwin then { openclaw-app = openclawApp; } else { })
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
{ lib
|
{
|
||||||
, stdenvNoCC
|
lib,
|
||||||
, fetchzip
|
stdenvNoCC,
|
||||||
|
fetchzip,
|
||||||
}:
|
}:
|
||||||
|
|
||||||
stdenvNoCC.mkDerivation {
|
stdenvNoCC.mkDerivation {
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
{ lib
|
{
|
||||||
, buildEnv
|
lib,
|
||||||
, openclaw-gateway
|
buildEnv,
|
||||||
, openclaw-app ? null
|
openclaw-gateway,
|
||||||
, extendedTools ? []
|
openclaw-app ? null,
|
||||||
|
extendedTools ? [ ],
|
||||||
}:
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|||||||
@ -8,45 +8,55 @@
|
|||||||
nix-openclaw.url = "github:openclaw/nix-openclaw";
|
nix-openclaw.url = "github:openclaw/nix-openclaw";
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { nixpkgs, home-manager, nix-openclaw, ... }:
|
outputs =
|
||||||
|
{
|
||||||
|
nixpkgs,
|
||||||
|
home-manager,
|
||||||
|
nix-openclaw,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
system = "aarch64-darwin";
|
system = "aarch64-darwin";
|
||||||
pkgs = import nixpkgs {
|
pkgs = import nixpkgs {
|
||||||
inherit system;
|
inherit system;
|
||||||
overlays = [ nix-openclaw.overlays.default ];
|
overlays = [ nix-openclaw.overlays.default ];
|
||||||
};
|
};
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
homeConfigurations.hm-test = home-manager.lib.homeManagerConfiguration {
|
homeConfigurations.hm-test = home-manager.lib.homeManagerConfiguration {
|
||||||
inherit pkgs;
|
inherit pkgs;
|
||||||
modules = [
|
modules = [
|
||||||
nix-openclaw.homeManagerModules.openclaw
|
nix-openclaw.homeManagerModules.openclaw
|
||||||
({ ... }: {
|
(
|
||||||
home = {
|
{ ... }:
|
||||||
username = "runner";
|
{
|
||||||
homeDirectory = "/tmp/hm-activation-home";
|
home = {
|
||||||
stateVersion = "23.11";
|
username = "runner";
|
||||||
};
|
homeDirectory = "/tmp/hm-activation-home";
|
||||||
|
stateVersion = "23.11";
|
||||||
|
};
|
||||||
|
|
||||||
programs.openclaw = {
|
programs.openclaw = {
|
||||||
enable = true;
|
enable = true;
|
||||||
installApp = false;
|
installApp = false;
|
||||||
instances.default = {
|
instances.default = {
|
||||||
gatewayPort = 18999;
|
gatewayPort = 18999;
|
||||||
config = {
|
config = {
|
||||||
logging = {
|
logging = {
|
||||||
level = "debug";
|
level = "debug";
|
||||||
file = "/tmp/openclaw/openclaw-gateway.log";
|
file = "/tmp/openclaw/openclaw-gateway.log";
|
||||||
};
|
};
|
||||||
gateway = {
|
gateway = {
|
||||||
mode = "local";
|
mode = "local";
|
||||||
auth = {
|
auth = {
|
||||||
token = "hm-activation-test-token";
|
token = "hm-activation-test-token";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
})
|
)
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,19 +1,26 @@
|
|||||||
{ pkgs
|
{
|
||||||
, steipetePkgs ? {}
|
pkgs,
|
||||||
, toolNamesOverride ? null
|
steipetePkgs ? { },
|
||||||
, excludeToolNames ? []
|
toolNamesOverride ? null,
|
||||||
|
excludeToolNames ? [ ],
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
lib = pkgs.lib;
|
lib = pkgs.lib;
|
||||||
safe = list: builtins.filter (p: p != null) list;
|
safe = list: builtins.filter (p: p != null) list;
|
||||||
pickFrom = scope: name:
|
pickFrom =
|
||||||
|
scope: name:
|
||||||
if builtins.hasAttr name scope then
|
if builtins.hasAttr name scope then
|
||||||
let pkg = scope.${name}; in
|
let
|
||||||
|
pkg = scope.${name};
|
||||||
|
in
|
||||||
if lib.meta.availableOn pkgs.stdenv.hostPlatform pkg then pkg else null
|
if lib.meta.availableOn pkgs.stdenv.hostPlatform pkg then pkg else null
|
||||||
else
|
else
|
||||||
null;
|
null;
|
||||||
pick = name:
|
pick =
|
||||||
let fromSteipete = pickFrom steipetePkgs name; in
|
name:
|
||||||
|
let
|
||||||
|
fromSteipete = pickFrom steipetePkgs name;
|
||||||
|
in
|
||||||
if fromSteipete != null then fromSteipete else pickFrom pkgs name;
|
if fromSteipete != null then fromSteipete else pickFrom pkgs name;
|
||||||
ensure = names: safe (map pick names);
|
ensure = names: safe (map pick names);
|
||||||
|
|
||||||
@ -55,7 +62,8 @@ let
|
|||||||
toolNamesBase = if toolNamesOverride != null then toolNamesOverride else baseNames ++ extraNames;
|
toolNamesBase = if toolNamesOverride != null then toolNamesOverride else baseNames ++ extraNames;
|
||||||
toolNames = builtins.filter (name: !builtins.elem name excludeToolNames) toolNamesBase;
|
toolNames = builtins.filter (name: !builtins.elem name excludeToolNames) toolNamesBase;
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
tools = ensure toolNames;
|
tools = ensure toolNames;
|
||||||
toolNames = toolNames;
|
toolNames = toolNames;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,12 +8,22 @@
|
|||||||
nix-openclaw.url = "github:openclaw/nix-openclaw";
|
nix-openclaw.url = "github:openclaw/nix-openclaw";
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, home-manager, nix-openclaw }:
|
outputs =
|
||||||
|
{
|
||||||
|
self,
|
||||||
|
nixpkgs,
|
||||||
|
home-manager,
|
||||||
|
nix-openclaw,
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
# REPLACE: aarch64-darwin (Apple Silicon), x86_64-darwin (Intel), or x86_64-linux
|
# REPLACE: aarch64-darwin (Apple Silicon), x86_64-darwin (Intel), or x86_64-linux
|
||||||
system = "<system>";
|
system = "<system>";
|
||||||
pkgs = import nixpkgs { inherit system; overlays = [ nix-openclaw.overlays.default ]; };
|
pkgs = import nixpkgs {
|
||||||
in {
|
inherit system;
|
||||||
|
overlays = [ nix-openclaw.overlays.default ];
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
# REPLACE: <user> with your username (run `whoami`)
|
# REPLACE: <user> with your username (run `whoami`)
|
||||||
homeConfigurations."<user>" = home-manager.lib.homeManagerConfiguration {
|
homeConfigurations."<user>" = home-manager.lib.homeManagerConfiguration {
|
||||||
inherit pkgs;
|
inherit pkgs;
|
||||||
@ -47,7 +57,9 @@
|
|||||||
# REPLACE: your Telegram user ID (get from @userinfobot)
|
# REPLACE: your Telegram user ID (get from @userinfobot)
|
||||||
allowFrom = [ <allowFrom> ];
|
allowFrom = [ <allowFrom> ];
|
||||||
groups = {
|
groups = {
|
||||||
"*" = { requireMention = true; };
|
"*" = {
|
||||||
|
requireMention = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user