mirror of
https://github.com/nix-community/home-manager.git
synced 2026-06-05 21:02:51 +00:00
antigravity-cli: rename gemini-cli module
This commit is contained in:
2
.github/labeler.yml
vendored
2
.github/labeler.yml
vendored
@@ -10,7 +10,7 @@
|
|||||||
- modules/programs/claude-code.nix
|
- modules/programs/claude-code.nix
|
||||||
- modules/programs/codex.nix
|
- modules/programs/codex.nix
|
||||||
- modules/programs/fabric-ai.nix
|
- modules/programs/fabric-ai.nix
|
||||||
- modules/programs/gemini-cli.nix
|
- modules/programs/antigravity-cli.nix
|
||||||
- modules/programs/mcp.nix
|
- modules/programs/mcp.nix
|
||||||
- modules/programs/mistral-vibe.nix
|
- modules/programs/mistral-vibe.nix
|
||||||
- modules/programs/mods.nix
|
- modules/programs/mods.nix
|
||||||
|
|||||||
498
modules/programs/antigravity-cli.nix
Normal file
498
modules/programs/antigravity-cli.nix
Normal file
@@ -0,0 +1,498 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
cfg = config.programs.antigravity-cli;
|
||||||
|
|
||||||
|
jsonFormat = pkgs.formats.json { };
|
||||||
|
tomlFormat = pkgs.formats.toml { };
|
||||||
|
|
||||||
|
isStorePathString =
|
||||||
|
content: builtins.isString content && lib.hasPrefix "${builtins.storeDir}/" content;
|
||||||
|
|
||||||
|
isPathLikeContent = content: lib.isPath content || isStorePathString content;
|
||||||
|
|
||||||
|
transformMcpServer =
|
||||||
|
server:
|
||||||
|
removeAttrs server [
|
||||||
|
"httpUrl"
|
||||||
|
"url"
|
||||||
|
]
|
||||||
|
// lib.optionalAttrs (server ? httpUrl) {
|
||||||
|
serverUrl = server.httpUrl;
|
||||||
|
}
|
||||||
|
// lib.optionalAttrs (server ? url) {
|
||||||
|
serverUrl = server.url;
|
||||||
|
};
|
||||||
|
|
||||||
|
transformMcpServers = lib.mapAttrs (_name: transformMcpServer);
|
||||||
|
|
||||||
|
commandSkillName = lib.replaceStrings [ "/" ] [ ":" ];
|
||||||
|
|
||||||
|
in
|
||||||
|
{
|
||||||
|
meta.maintainers = [ lib.maintainers.rrvsh ];
|
||||||
|
|
||||||
|
imports = [
|
||||||
|
(lib.mkRenamedOptionModule [ "programs" "gemini-cli" ] [ "programs" "antigravity-cli" ])
|
||||||
|
];
|
||||||
|
|
||||||
|
options.programs.antigravity-cli = {
|
||||||
|
enable = lib.mkEnableOption "Antigravity CLI";
|
||||||
|
|
||||||
|
package = lib.mkPackageOption pkgs "antigravity-cli" {
|
||||||
|
nullable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
useLegacyGeminiConfig = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Whether to write configuration to the legacy Gemini CLI locations.
|
||||||
|
|
||||||
|
This is enabled automatically when
|
||||||
|
{option}`programs.antigravity-cli.package` is a `gemini-cli` package.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
enableMcpIntegration = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Whether to integrate the MCP servers config from
|
||||||
|
{option}`programs.mcp.servers` into
|
||||||
|
{option}`programs.antigravity-cli.mcpServers`.
|
||||||
|
|
||||||
|
Note: Any servers already present in
|
||||||
|
{option}`programs.antigravity-cli.mcpServers`
|
||||||
|
is not overridden by servers present under the same
|
||||||
|
name in {option}`programs.mcp.servers`
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
settings = lib.mkOption {
|
||||||
|
inherit (jsonFormat) type;
|
||||||
|
default = { };
|
||||||
|
example = {
|
||||||
|
colorScheme = "tokyo night";
|
||||||
|
altScreenMode = "always";
|
||||||
|
toolPermission = "proceed-in-sandbox";
|
||||||
|
artifactReviewPolicy = "agent-decides";
|
||||||
|
};
|
||||||
|
description = ''
|
||||||
|
Configuration written to
|
||||||
|
{file}`~/.gemini/antigravity-cli/settings.json`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
mcpServers = lib.mkOption {
|
||||||
|
inherit (jsonFormat) type;
|
||||||
|
default = { };
|
||||||
|
example = {
|
||||||
|
github = {
|
||||||
|
serverUrl = "https://api.githubcopilot.com/mcp/";
|
||||||
|
};
|
||||||
|
filesystem = {
|
||||||
|
command = "npx";
|
||||||
|
args = [
|
||||||
|
"-y"
|
||||||
|
"@modelcontextprotocol/server-filesystem"
|
||||||
|
"/tmp"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
description = ''
|
||||||
|
MCP server configuration written to
|
||||||
|
{file}`~/.gemini/config/mcp_config.json`.
|
||||||
|
|
||||||
|
Remote servers use `serverUrl`; `url` and `httpUrl` are accepted
|
||||||
|
for migration and converted automatically.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
commands =
|
||||||
|
let
|
||||||
|
commandType = lib.types.submodule {
|
||||||
|
freeformType = lib.types.str;
|
||||||
|
options = {
|
||||||
|
prompt = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = ''
|
||||||
|
The prompt that will be sent to the Gemini model when the command is executed.
|
||||||
|
This can be a single-line or multi-line string.
|
||||||
|
The special placeholder {{args}} will be replaced with the text the user typed after the command name.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
description = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = ''
|
||||||
|
A brief, one-line description of what the command does.
|
||||||
|
This text will be displayed next to your command in the /help menu.
|
||||||
|
If you omit this field, a generic description will be generated from the filename.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
lib.mkOption {
|
||||||
|
type = lib.types.attrsOf commandType;
|
||||||
|
default = { };
|
||||||
|
description = ''
|
||||||
|
An attribute set of Gemini CLI custom commands to migrate to
|
||||||
|
Antigravity CLI global skills.
|
||||||
|
|
||||||
|
The name of the attribute set will be the name of each generated
|
||||||
|
skill directory.
|
||||||
|
'';
|
||||||
|
example = lib.literalExpression ''
|
||||||
|
changelog = {
|
||||||
|
prompt =
|
||||||
|
'''
|
||||||
|
Your task is to parse the `<version>`, `<change_type>`, and `<message>` from their input and use the `write_file` tool to correctly update the `CHANGELOG.md` file.
|
||||||
|
''';
|
||||||
|
description = "Adds a new entry to the project's CHANGELOG.md file.";
|
||||||
|
};
|
||||||
|
"git/fix" = { # Becomes /git:fix
|
||||||
|
prompt = "Please analyze the staged git changes and provide a code fix for the issue described here: {{args}}.";
|
||||||
|
description = "Generates a fix for a given GitHub issue.";
|
||||||
|
};
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
permissions = lib.mkOption {
|
||||||
|
type = lib.types.nullOr (
|
||||||
|
lib.types.submodule {
|
||||||
|
options = {
|
||||||
|
allow = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.str;
|
||||||
|
default = [ ];
|
||||||
|
description = ''
|
||||||
|
Permissions to allow without prompting.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
deny = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.str;
|
||||||
|
default = [ ];
|
||||||
|
description = ''
|
||||||
|
Permissions to deny without prompting.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
ask = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.str;
|
||||||
|
default = [ ];
|
||||||
|
description = ''
|
||||||
|
Permissions to ask before using.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
Antigravity CLI fine-grained permissions written to
|
||||||
|
{option}`programs.antigravity-cli.settings.permissions`.
|
||||||
|
'';
|
||||||
|
example = lib.literalExpression ''
|
||||||
|
{
|
||||||
|
allow = [ "command(git)" ];
|
||||||
|
deny = [ "command(rm -rf)" ];
|
||||||
|
ask = [ "command(*)" ];
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
policies = lib.mkOption {
|
||||||
|
type = lib.types.attrsOf (lib.types.either lib.types.path tomlFormat.type);
|
||||||
|
default = { };
|
||||||
|
description = ''
|
||||||
|
An attribute set of Gemini CLI policy definitions to create in
|
||||||
|
{file}`~/.gemini/policies/` when
|
||||||
|
{option}`programs.antigravity-cli.package` is a `gemini-cli`
|
||||||
|
package.
|
||||||
|
|
||||||
|
Antigravity CLI configures permissions in
|
||||||
|
{option}`programs.antigravity-cli.settings.permissions` or
|
||||||
|
{option}`programs.antigravity-cli.permissions`.
|
||||||
|
'';
|
||||||
|
example = lib.literalExpression ''
|
||||||
|
{
|
||||||
|
"my-rules" = {
|
||||||
|
rule = [
|
||||||
|
{
|
||||||
|
toolName = "run_shell_command";
|
||||||
|
commandPrefix = "git ";
|
||||||
|
decision = "ask_user";
|
||||||
|
priority = 100;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
"other-rules" = ./path/to/rules.toml;
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
defaultModel = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.str;
|
||||||
|
default = null;
|
||||||
|
example = "gemini-2.5-flash";
|
||||||
|
description = ''
|
||||||
|
The default model to use for the CLI.
|
||||||
|
Will be set as $GEMINI_MODEL when configured.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
context = lib.mkOption {
|
||||||
|
type = lib.types.attrsOf (lib.types.either lib.types.lines lib.types.path);
|
||||||
|
default = { };
|
||||||
|
example = lib.literalExpression ''
|
||||||
|
{
|
||||||
|
GEMINI = '''
|
||||||
|
# Global Context
|
||||||
|
|
||||||
|
You are a helpful AI assistant for software development.
|
||||||
|
|
||||||
|
## Coding Standards
|
||||||
|
|
||||||
|
- Follow consistent code style
|
||||||
|
- Write clear comments
|
||||||
|
- Test your changes
|
||||||
|
''';
|
||||||
|
|
||||||
|
AGENTS = ./path/to/agents.md;
|
||||||
|
|
||||||
|
CONTEXT = '''
|
||||||
|
Additional context instructions here.
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
description = ''
|
||||||
|
Global context(s) for Antigravity CLI.
|
||||||
|
|
||||||
|
The attribute name becomes the filename, with a {file}`.md`
|
||||||
|
extension added automatically. Each value is either:
|
||||||
|
- Inline content as a string
|
||||||
|
- A path to a file containing the content
|
||||||
|
|
||||||
|
The configured files are written to {file}`~/.gemini/`.
|
||||||
|
|
||||||
|
Note: You can customize which context file names Antigravity CLI looks for by setting
|
||||||
|
`settings.context.fileName`. For example:
|
||||||
|
```nix
|
||||||
|
settings = {
|
||||||
|
context.fileName = ["AGENTS.md", "CONTEXT.md", "GEMINI.md"];
|
||||||
|
};
|
||||||
|
```
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
skills = lib.mkOption {
|
||||||
|
type = lib.types.either (lib.types.attrsOf (lib.types.either lib.types.lines lib.types.path)) lib.types.path;
|
||||||
|
default = { };
|
||||||
|
example = lib.literalExpression ''
|
||||||
|
{
|
||||||
|
xlsx = ./skills/xlsx/SKILL.md;
|
||||||
|
data-analysis = ./skills/data-analysis;
|
||||||
|
pdf-processing = '''
|
||||||
|
---
|
||||||
|
name: pdf-processing
|
||||||
|
description: Extract text and tables from PDF files, fill forms, merge documents. Use when working with PDF files or when the user mentions PDFs, forms, or document extraction.
|
||||||
|
---
|
||||||
|
|
||||||
|
# PDF Processing
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
Use pdfplumber to extract text from PDFs:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import pdfplumber
|
||||||
|
|
||||||
|
with pdfplumber.open("document.pdf") as pdf:
|
||||||
|
text = pdf.pages[0].extract_text()
|
||||||
|
```
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
description = ''
|
||||||
|
Custom skills for Antigravity CLI.
|
||||||
|
|
||||||
|
This option can be either:
|
||||||
|
- An attribute set defining skills
|
||||||
|
- A path to a directory containing skill folders
|
||||||
|
|
||||||
|
If an attribute set is used, the attribute name becomes the
|
||||||
|
skill directory name, and the value is either:
|
||||||
|
- Inline content as a string (creates `~/.gemini/config/skills/<name>/SKILL.md`)
|
||||||
|
- A path to a file (creates `~/.gemini/config/skills/<name>/SKILL.md`)
|
||||||
|
- A path to a directory (symlinks `~/.gemini/config/skills/<name>/` to that directory)
|
||||||
|
|
||||||
|
If a path is used, it is expected to contain one folder per
|
||||||
|
skill name, each containing a {file}`SKILL.md`. The directory is
|
||||||
|
symlinked to {file}`~/.gemini/config/skills/`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config =
|
||||||
|
let
|
||||||
|
useGeminiConfig =
|
||||||
|
cfg.useLegacyGeminiConfig || (cfg.package != null && lib.getName cfg.package == "gemini-cli");
|
||||||
|
antigravitySkillsDir = ".gemini/config/skills";
|
||||||
|
geminiSkillsDir = ".gemini/skills";
|
||||||
|
antigravitySettings = lib.recursiveUpdate (lib.optionalAttrs (cfg.permissions != null) {
|
||||||
|
inherit (cfg) permissions;
|
||||||
|
}) (removeAttrs cfg.settings [ "mcpServers" ]);
|
||||||
|
legacyMcpServers = lib.optionalAttrs (cfg.settings ? mcpServers) cfg.settings.mcpServers;
|
||||||
|
mcpServers = lib.recursiveUpdate legacyMcpServers cfg.mcpServers;
|
||||||
|
geminiSettings =
|
||||||
|
lib.recursiveUpdate
|
||||||
|
(lib.optionalAttrs (cfg.permissions != null) {
|
||||||
|
inherit (cfg) permissions;
|
||||||
|
})
|
||||||
|
(lib.recursiveUpdate cfg.settings (lib.optionalAttrs (mcpServers != { }) { inherit mcpServers; }));
|
||||||
|
in
|
||||||
|
lib.mkIf cfg.enable (
|
||||||
|
lib.mkMerge [
|
||||||
|
{
|
||||||
|
home = {
|
||||||
|
packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||||
|
sessionVariables = lib.mkIf (cfg.defaultModel != null) {
|
||||||
|
GEMINI_MODEL = cfg.defaultModel;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
home.file = lib.mapAttrs' (
|
||||||
|
n: v: lib.nameValuePair ".gemini/${n}.md" (if lib.isPath v then { source = v; } else { text = v; })
|
||||||
|
) cfg.context;
|
||||||
|
}
|
||||||
|
(lib.mkIf useGeminiConfig {
|
||||||
|
programs.antigravity-cli.settings.mcpServers = lib.mkIf (
|
||||||
|
cfg.enableMcpIntegration && config.programs.mcp.enable
|
||||||
|
) (lib.mapAttrs (_n: lib.mkDefault) config.programs.mcp.servers);
|
||||||
|
|
||||||
|
home.file =
|
||||||
|
lib.optionalAttrs (geminiSettings != { }) {
|
||||||
|
".gemini/settings.json".source = jsonFormat.generate "gemini-cli-settings.json" geminiSettings;
|
||||||
|
}
|
||||||
|
// lib.mapAttrs' (
|
||||||
|
n: v:
|
||||||
|
lib.nameValuePair ".gemini/commands/${n}.toml" {
|
||||||
|
source = tomlFormat.generate "gemini-cli-command-${n}.toml" {
|
||||||
|
inherit (v) description prompt;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
) cfg.commands
|
||||||
|
// lib.mapAttrs' (
|
||||||
|
n: v:
|
||||||
|
lib.nameValuePair ".gemini/policies/${n}.toml" {
|
||||||
|
source =
|
||||||
|
if isPathLikeContent v then v else tomlFormat.generate "gemini-cli-policy-${n}.toml" v;
|
||||||
|
}
|
||||||
|
) cfg.policies
|
||||||
|
// (
|
||||||
|
if isPathLikeContent cfg.skills then
|
||||||
|
{
|
||||||
|
"${geminiSkillsDir}" = {
|
||||||
|
source = cfg.skills;
|
||||||
|
recursive = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
lib.mapAttrs' (
|
||||||
|
n: v:
|
||||||
|
if isPathLikeContent v && lib.pathIsDirectory v then
|
||||||
|
lib.nameValuePair "${geminiSkillsDir}/${n}" {
|
||||||
|
source = v;
|
||||||
|
recursive = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
lib.nameValuePair "${geminiSkillsDir}/${n}/SKILL.md" (
|
||||||
|
if isPathLikeContent v then { source = v; } else { text = v; }
|
||||||
|
)
|
||||||
|
) cfg.skills
|
||||||
|
);
|
||||||
|
})
|
||||||
|
(lib.mkIf (!useGeminiConfig) {
|
||||||
|
programs.antigravity-cli.mcpServers =
|
||||||
|
lib.mkIf (cfg.enableMcpIntegration && config.programs.mcp.enable)
|
||||||
|
(lib.mapAttrs (_n: server: lib.mkDefault (transformMcpServer server)) config.programs.mcp.servers);
|
||||||
|
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = cfg.policies == { };
|
||||||
|
message = ''
|
||||||
|
`programs.antigravity-cli.policies` is only supported when
|
||||||
|
`programs.antigravity-cli.package` is a `gemini-cli` package.
|
||||||
|
Antigravity CLI configures permissions in
|
||||||
|
`programs.antigravity-cli.settings.permissions` or
|
||||||
|
`programs.antigravity-cli.permissions`.
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
home.file =
|
||||||
|
lib.optionalAttrs (antigravitySettings != { }) {
|
||||||
|
".gemini/antigravity-cli/settings.json".source =
|
||||||
|
jsonFormat.generate "antigravity-cli-settings.json" antigravitySettings;
|
||||||
|
}
|
||||||
|
// lib.optionalAttrs (mcpServers != { }) {
|
||||||
|
".gemini/config/mcp_config.json".source = jsonFormat.generate "antigravity-cli-mcp-config.json" {
|
||||||
|
mcpServers = transformMcpServers mcpServers;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// lib.mapAttrs' (
|
||||||
|
n: v:
|
||||||
|
let
|
||||||
|
skillName = commandSkillName n;
|
||||||
|
in
|
||||||
|
lib.nameValuePair "${antigravitySkillsDir}/${skillName}/SKILL.md" {
|
||||||
|
text = ''
|
||||||
|
---
|
||||||
|
name: ${skillName}
|
||||||
|
description: ${v.description}
|
||||||
|
---
|
||||||
|
|
||||||
|
${v.prompt}
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
) cfg.commands
|
||||||
|
// (
|
||||||
|
if isPathLikeContent cfg.skills then
|
||||||
|
{
|
||||||
|
"${antigravitySkillsDir}" = {
|
||||||
|
source = cfg.skills;
|
||||||
|
recursive = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
lib.mapAttrs' (
|
||||||
|
n: v:
|
||||||
|
if isPathLikeContent v && lib.pathIsDirectory v then
|
||||||
|
lib.nameValuePair "${antigravitySkillsDir}/${n}" {
|
||||||
|
source = v;
|
||||||
|
recursive = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
lib.nameValuePair "${antigravitySkillsDir}/${n}/SKILL.md" (
|
||||||
|
if isPathLikeContent v then { source = v; } else { text = v; }
|
||||||
|
)
|
||||||
|
) cfg.skills
|
||||||
|
);
|
||||||
|
})
|
||||||
|
{
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = !isPathLikeContent cfg.skills || lib.pathIsDirectory cfg.skills;
|
||||||
|
message = "`programs.antigravity-cli.skills` must be a directory when set to a path";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,314 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
cfg = config.programs.gemini-cli;
|
|
||||||
|
|
||||||
jsonFormat = pkgs.formats.json { };
|
|
||||||
tomlFormat = pkgs.formats.toml { };
|
|
||||||
in
|
|
||||||
{
|
|
||||||
meta.maintainers = [ lib.maintainers.rrvsh ];
|
|
||||||
|
|
||||||
options.programs.gemini-cli = {
|
|
||||||
enable = lib.mkEnableOption "gemini-cli";
|
|
||||||
|
|
||||||
package = lib.mkPackageOption pkgs "gemini-cli" { nullable = true; };
|
|
||||||
|
|
||||||
enableMcpIntegration = lib.mkOption {
|
|
||||||
type = lib.types.bool;
|
|
||||||
default = false;
|
|
||||||
description = ''
|
|
||||||
Whether to integrate the MCP servers config from
|
|
||||||
{option}`programs.mcp.servers` into
|
|
||||||
{option}`programs.gemini-cli.settings.mcpServers`.
|
|
||||||
|
|
||||||
Note: Any servers already present in
|
|
||||||
{option}`programs.gemini-cli.settings.mcpServers`
|
|
||||||
is not overridden by servers present under the same
|
|
||||||
name in {option}`programs.mcp.servers`
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
settings = lib.mkOption {
|
|
||||||
inherit (jsonFormat) type;
|
|
||||||
default = { };
|
|
||||||
example = {
|
|
||||||
ui.theme = "Default";
|
|
||||||
general = {
|
|
||||||
vimMode = true;
|
|
||||||
preferredEditor = "nvim";
|
|
||||||
previewFeatures = true;
|
|
||||||
};
|
|
||||||
ide.enabled = true;
|
|
||||||
privacy.usageStatisticsEnabled = false;
|
|
||||||
tools.autoAccept = false;
|
|
||||||
context.loadMemoryFromIncludeDirectories = true;
|
|
||||||
security.auth.selectedType = "oauth-personal";
|
|
||||||
};
|
|
||||||
description = "JSON config for gemini-cli";
|
|
||||||
};
|
|
||||||
|
|
||||||
commands =
|
|
||||||
let
|
|
||||||
commandType = lib.types.submodule {
|
|
||||||
freeformType = lib.types.str;
|
|
||||||
options = {
|
|
||||||
prompt = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
description = ''
|
|
||||||
The prompt that will be sent to the Gemini model when the command is executed.
|
|
||||||
This can be a single-line or multi-line string.
|
|
||||||
The special placeholder {{args}} will be replaced with the text the user typed after the command name.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
description = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
description = ''
|
|
||||||
A brief, one-line description of what the command does.
|
|
||||||
This text will be displayed next to your command in the /help menu.
|
|
||||||
If you omit this field, a generic description will be generated from the filename.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
in
|
|
||||||
lib.mkOption {
|
|
||||||
type = lib.types.attrsOf commandType;
|
|
||||||
default = { };
|
|
||||||
description = ''
|
|
||||||
An attribute set of custom commands that will be globally available.
|
|
||||||
The name of the attribute set will be the name of each command.
|
|
||||||
You may use subdirectories to create namespaced commands, such as `git/fix` becoming `/git:fix`.
|
|
||||||
See https://github.com/google-gemini/gemini-cli/blob/main/docs/cli/commands.md#custom-commands for more information.
|
|
||||||
'';
|
|
||||||
example = lib.literalExpression ''
|
|
||||||
changelog = {
|
|
||||||
prompt =
|
|
||||||
'''
|
|
||||||
Your task is to parse the `<version>`, `<change_type>`, and `<message>` from their input and use the `write_file` tool to correctly update the `CHANGELOG.md` file.
|
|
||||||
''';
|
|
||||||
description = "Adds a new entry to the project's CHANGELOG.md file.";
|
|
||||||
};
|
|
||||||
"git/fix" = { # Becomes /git:fix
|
|
||||||
prompt = "Please analyze the staged git changes and provide a code fix for the issue described here: {{args}}.";
|
|
||||||
description = "Generates a fix for a given GitHub issue.";
|
|
||||||
};
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
policies = lib.mkOption {
|
|
||||||
type = lib.types.attrsOf (lib.types.either lib.types.path tomlFormat.type);
|
|
||||||
default = { };
|
|
||||||
description = ''
|
|
||||||
An attribute set of policy definitions to create in `~/.gemini/policies/`.
|
|
||||||
The attribute name becomes the filename with `.toml` extension automatically added.
|
|
||||||
The value can be either an attribute set representing the TOML policy or a path to a TOML file.
|
|
||||||
'';
|
|
||||||
example = lib.literalExpression ''
|
|
||||||
{
|
|
||||||
"my-rules" = {
|
|
||||||
rule = [
|
|
||||||
{
|
|
||||||
toolName = "run_shell_command";
|
|
||||||
commandPrefix = "git ";
|
|
||||||
decision = "ask_user";
|
|
||||||
priority = 100;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
"other-rules" = ./path/to/rules.toml;
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
defaultModel = lib.mkOption {
|
|
||||||
type = lib.types.nullOr lib.types.str;
|
|
||||||
default = null;
|
|
||||||
example = "gemini-2.5-flash";
|
|
||||||
description = ''
|
|
||||||
The default model to use for the CLI.
|
|
||||||
Will be set as $GEMINI_MODEL when configured.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
context = lib.mkOption {
|
|
||||||
type = lib.types.attrsOf (lib.types.either lib.types.lines lib.types.path);
|
|
||||||
default = { };
|
|
||||||
example = lib.literalExpression ''
|
|
||||||
{
|
|
||||||
GEMINI = '''
|
|
||||||
# Global Context
|
|
||||||
|
|
||||||
You are a helpful AI assistant for software development.
|
|
||||||
|
|
||||||
## Coding Standards
|
|
||||||
|
|
||||||
- Follow consistent code style
|
|
||||||
- Write clear comments
|
|
||||||
- Test your changes
|
|
||||||
''';
|
|
||||||
|
|
||||||
AGENTS = ./path/to/agents.md;
|
|
||||||
|
|
||||||
CONTEXT = '''
|
|
||||||
Additional context instructions here.
|
|
||||||
''';
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
description = ''
|
|
||||||
Global context(s) for gemini-cli.
|
|
||||||
|
|
||||||
The attribute name becomes the filename, with a {file}`.md`
|
|
||||||
extension added automatically. Each value is either:
|
|
||||||
- Inline content as a string
|
|
||||||
- A path to a file containing the content
|
|
||||||
|
|
||||||
The configured files are written to {file}`~/.gemini/`.
|
|
||||||
|
|
||||||
Note: You can customize which context file names gemini-cli looks for by setting
|
|
||||||
`settings.context.fileName`. For example:
|
|
||||||
```nix
|
|
||||||
settings = {
|
|
||||||
context.fileName = ["AGENTS.md", "CONTEXT.md", "GEMINI.md"];
|
|
||||||
};
|
|
||||||
```
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
skills = lib.mkOption {
|
|
||||||
type = lib.types.either (lib.types.attrsOf (lib.types.either lib.types.lines lib.types.path)) lib.types.path;
|
|
||||||
default = { };
|
|
||||||
example = lib.literalExpression ''
|
|
||||||
{
|
|
||||||
xlsx = ./skills/xlsx/SKILL.md;
|
|
||||||
data-analysis = ./skills/data-analysis;
|
|
||||||
pdf-processing = '''
|
|
||||||
---
|
|
||||||
name: pdf-processing
|
|
||||||
description: Extract text and tables from PDF files, fill forms, merge documents. Use when working with PDF files or when the user mentions PDFs, forms, or document extraction.
|
|
||||||
---
|
|
||||||
|
|
||||||
# PDF Processing
|
|
||||||
|
|
||||||
## Quick start
|
|
||||||
|
|
||||||
Use pdfplumber to extract text from PDFs:
|
|
||||||
|
|
||||||
```python
|
|
||||||
import pdfplumber
|
|
||||||
|
|
||||||
with pdfplumber.open("document.pdf") as pdf:
|
|
||||||
text = pdf.pages[0].extract_text()
|
|
||||||
```
|
|
||||||
''';
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
description = ''
|
|
||||||
Custom skills for gemini-cli.
|
|
||||||
|
|
||||||
This option can be either:
|
|
||||||
- An attribute set defining skills
|
|
||||||
- A path to a directory containing skill folders
|
|
||||||
|
|
||||||
If an attribute set is used, the attribute name becomes the
|
|
||||||
skill directory name, and the value is either:
|
|
||||||
- Inline content as a string (creates `~/.gemini/skills/<name>/SKILL.md`)
|
|
||||||
- A path to a file (creates `~/.gemini/skills/<name>/SKILL.md`)
|
|
||||||
- A path to a directory (symlinks `~/.gemini/skills/<name>/` to that directory)
|
|
||||||
|
|
||||||
If a path is used, it is expected to contain one folder per
|
|
||||||
skill name, each containing a {file}`SKILL.md`. The directory is
|
|
||||||
symlinked to {file}`~/.gemini/skills/`.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config =
|
|
||||||
let
|
|
||||||
isStorePathString =
|
|
||||||
content: builtins.isString content && lib.hasPrefix "${builtins.storeDir}/" content;
|
|
||||||
isPathLikeContent = content: lib.isPath content || isStorePathString content;
|
|
||||||
in
|
|
||||||
lib.mkIf cfg.enable (
|
|
||||||
lib.mkMerge [
|
|
||||||
{
|
|
||||||
programs.gemini-cli.settings.mcpServers = lib.mkIf (
|
|
||||||
cfg.enableMcpIntegration && config.programs.mcp.enable
|
|
||||||
) (lib.mapAttrs (_n: lib.mkDefault) config.programs.mcp.servers);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
home = {
|
|
||||||
packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
|
||||||
file.".gemini/settings.json" = lib.mkIf (cfg.settings != { }) {
|
|
||||||
source = jsonFormat.generate "gemini-cli-settings.json" cfg.settings;
|
|
||||||
};
|
|
||||||
sessionVariables = lib.mkIf (cfg.defaultModel != null) {
|
|
||||||
GEMINI_MODEL = cfg.defaultModel;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
{
|
|
||||||
home.file = lib.mapAttrs' (
|
|
||||||
n: v: lib.nameValuePair ".gemini/${n}.md" (if lib.isPath v then { source = v; } else { text = v; })
|
|
||||||
) cfg.context;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
home.file = lib.mapAttrs' (
|
|
||||||
n: v:
|
|
||||||
lib.nameValuePair ".gemini/commands/${n}.toml" {
|
|
||||||
source = tomlFormat.generate "gemini-cli-command-${n}.toml" {
|
|
||||||
inherit (v) description prompt;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
) cfg.commands;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
home.file = lib.mapAttrs' (
|
|
||||||
n: v:
|
|
||||||
lib.nameValuePair ".gemini/policies/${n}.toml" {
|
|
||||||
source =
|
|
||||||
if builtins.isPath v || builtins.isString v || lib.isDerivation v then
|
|
||||||
v
|
|
||||||
else
|
|
||||||
tomlFormat.generate "gemini-cli-policy-${n}.toml" v;
|
|
||||||
}
|
|
||||||
) cfg.policies;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
assertions = [
|
|
||||||
{
|
|
||||||
assertion = !isPathLikeContent cfg.skills || lib.pathIsDirectory cfg.skills;
|
|
||||||
message = "`programs.gemini-cli.skills` must be a directory when set to a path";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
{
|
|
||||||
home.file =
|
|
||||||
if isPathLikeContent cfg.skills then
|
|
||||||
{
|
|
||||||
".gemini/skills" = {
|
|
||||||
source = cfg.skills;
|
|
||||||
recursive = true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
lib.mapAttrs' (
|
|
||||||
n: v:
|
|
||||||
if isPathLikeContent v && lib.pathIsDirectory v then
|
|
||||||
lib.nameValuePair ".gemini/skills/${n}" {
|
|
||||||
source = v;
|
|
||||||
recursive = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
lib.nameValuePair ".gemini/skills/${n}/SKILL.md" (
|
|
||||||
if isPathLikeContent v then { source = v; } else { text = v; }
|
|
||||||
)
|
|
||||||
) cfg.skills;
|
|
||||||
}
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
61
tests/modules/programs/antigravity-cli-legacy/context.nix
Normal file
61
tests/modules/programs/antigravity-cli-legacy/context.nix
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
options,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
{
|
||||||
|
programs.gemini-cli = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.writeShellScriptBin "gemini-cli" "";
|
||||||
|
context = {
|
||||||
|
# Test inline content
|
||||||
|
GEMINI = ''
|
||||||
|
# Global Context
|
||||||
|
|
||||||
|
You are a helpful AI assistant for software development.
|
||||||
|
|
||||||
|
## Coding Standards
|
||||||
|
|
||||||
|
- Follow consistent code style
|
||||||
|
- Write clear comments
|
||||||
|
- Test your changes
|
||||||
|
'';
|
||||||
|
# Test file path
|
||||||
|
AGENTS = ./context.md;
|
||||||
|
# Test another inline content
|
||||||
|
CONTEXT = ''
|
||||||
|
Additional context for specialized tasks.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
settings = {
|
||||||
|
context.fileName = [
|
||||||
|
"AGENTS.md"
|
||||||
|
"CONTEXT.md"
|
||||||
|
"GEMINI.md"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
test.asserts.warnings.expected = [
|
||||||
|
"The option `programs.gemini-cli' defined in ${lib.showFiles options.programs.gemini-cli.files} has been renamed to `programs.antigravity-cli'."
|
||||||
|
];
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
assertFileExists home-files/.gemini/GEMINI.md
|
||||||
|
assertFileContent home-files/.gemini/GEMINI.md \
|
||||||
|
${./context-inline.md}
|
||||||
|
|
||||||
|
assertFileExists home-files/.gemini/AGENTS.md
|
||||||
|
assertFileContent home-files/.gemini/AGENTS.md \
|
||||||
|
${./context.md}
|
||||||
|
|
||||||
|
assertFileExists home-files/.gemini/CONTEXT.md
|
||||||
|
assertFileContent home-files/.gemini/CONTEXT.md \
|
||||||
|
${./context-additional.md}
|
||||||
|
|
||||||
|
assertFileExists home-path/etc/profile.d/hm-session-vars.sh
|
||||||
|
assertFileNotRegex home-path/etc/profile.d/hm-session-vars.sh \
|
||||||
|
"GEMINI_MODEL"
|
||||||
|
'';
|
||||||
|
}
|
||||||
@@ -6,4 +6,5 @@
|
|||||||
gemini-cli-skills-store-path-dir = ./skills-store-path-dir.nix;
|
gemini-cli-skills-store-path-dir = ./skills-store-path-dir.nix;
|
||||||
gemini-cli-skills-path-not-directory = ./skills-path-not-directory.nix;
|
gemini-cli-skills-path-not-directory = ./skills-path-not-directory.nix;
|
||||||
gemini-cli-mcp-servers = ./mcp.nix;
|
gemini-cli-mcp-servers = ./mcp.nix;
|
||||||
|
gemini-cli-policies = ./policies.nix;
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,15 @@
|
|||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
options,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
{
|
{
|
||||||
programs = {
|
programs = {
|
||||||
gemini-cli = {
|
gemini-cli = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
package = pkgs.writeShellScriptBin "gemini-cli" "";
|
||||||
enableMcpIntegration = true;
|
enableMcpIntegration = true;
|
||||||
settings = {
|
settings = {
|
||||||
theme = "Default";
|
theme = "Default";
|
||||||
@@ -9,6 +17,9 @@
|
|||||||
mcpServers = {
|
mcpServers = {
|
||||||
github = {
|
github = {
|
||||||
url = "https://api.githubcopilot.com/mcp/";
|
url = "https://api.githubcopilot.com/mcp/";
|
||||||
|
env = {
|
||||||
|
url = "https://token.example/env";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
filesystem = {
|
filesystem = {
|
||||||
command = "npx";
|
command = "npx";
|
||||||
@@ -47,9 +58,15 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
test.asserts.warnings.expected = [
|
||||||
|
"The option `programs.gemini-cli' defined in ${lib.showFiles options.programs.gemini-cli.files} has been renamed to `programs.antigravity-cli'."
|
||||||
|
];
|
||||||
|
|
||||||
nmt.script = ''
|
nmt.script = ''
|
||||||
assertFileExists home-files/.gemini/settings.json
|
assertFileExists home-files/.gemini/settings.json
|
||||||
assertFileRegex home-files/.gemini/settings.json '"github"'
|
assertFileRegex home-files/.gemini/settings.json '"github"'
|
||||||
|
assertFileRegex home-files/.gemini/settings.json '"url"'
|
||||||
|
assertFileRegex home-files/.gemini/settings.json 'https://token.example/env'
|
||||||
assertFileRegex home-files/.gemini/settings.json '"filesystem"'
|
assertFileRegex home-files/.gemini/settings.json '"filesystem"'
|
||||||
assertFileRegex home-files/.gemini/settings.json '"database"'
|
assertFileRegex home-files/.gemini/settings.json '"database"'
|
||||||
assertFileNotRegex home-files/.gemini/settings.json '"other-tmp"'
|
assertFileNotRegex home-files/.gemini/settings.json '"other-tmp"'
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
[[rule]]
|
[[rule]]
|
||||||
commandPrefix = "git "
|
toolName = "run_shell_command"
|
||||||
|
commandPrefix = "nix "
|
||||||
decision = "ask_user"
|
decision = "ask_user"
|
||||||
priority = 100
|
priority = 100
|
||||||
toolName = "run_shell_command"
|
|
||||||
44
tests/modules/programs/antigravity-cli-legacy/policies.nix
Normal file
44
tests/modules/programs/antigravity-cli-legacy/policies.nix
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
options,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
{
|
||||||
|
programs.gemini-cli = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.writeShellScriptBin "gemini-cli" "";
|
||||||
|
policies = {
|
||||||
|
"my-rules" = {
|
||||||
|
rule = [
|
||||||
|
{
|
||||||
|
toolName = "run_shell_command";
|
||||||
|
commandPrefix = "git ";
|
||||||
|
decision = "ask_user";
|
||||||
|
priority = 100;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
"other-rules" = ./other-rules.toml;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
test.asserts.warnings.expected = [
|
||||||
|
"The option `programs.gemini-cli' defined in ${lib.showFiles options.programs.gemini-cli.files} has been renamed to `programs.antigravity-cli'."
|
||||||
|
];
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
assertFileExists home-files/.gemini/policies/my-rules.toml
|
||||||
|
assertFileRegex home-files/.gemini/policies/my-rules.toml \
|
||||||
|
'toolName = "run_shell_command"'
|
||||||
|
assertFileRegex home-files/.gemini/policies/my-rules.toml \
|
||||||
|
'commandPrefix = "git "'
|
||||||
|
|
||||||
|
assertFileExists home-files/.gemini/policies/other-rules.toml
|
||||||
|
assertFileRegex home-files/.gemini/policies/other-rules.toml \
|
||||||
|
'toolName = "run_shell_command"'
|
||||||
|
assertFileRegex home-files/.gemini/policies/other-rules.toml \
|
||||||
|
'commandPrefix = "nix "'
|
||||||
|
'';
|
||||||
|
}
|
||||||
17
tests/modules/programs/antigravity-cli-legacy/settings.json
Normal file
17
tests/modules/programs/antigravity-cli-legacy/settings.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"autoAccept": true,
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"command(git)"
|
||||||
|
],
|
||||||
|
"ask": [
|
||||||
|
"command(*)"
|
||||||
|
],
|
||||||
|
"deny": [
|
||||||
|
"command(rm -rf)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"preferredEditor": "nvim",
|
||||||
|
"theme": "Default",
|
||||||
|
"vimMode": true
|
||||||
|
}
|
||||||
@@ -1,6 +1,14 @@
|
|||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
options,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
{
|
{
|
||||||
programs.gemini-cli = {
|
programs.gemini-cli = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
package = pkgs.writeShellScriptBin "gemini-cli" "";
|
||||||
defaultModel = "gemini-2.5-flash";
|
defaultModel = "gemini-2.5-flash";
|
||||||
settings = {
|
settings = {
|
||||||
theme = "Default";
|
theme = "Default";
|
||||||
@@ -20,32 +28,30 @@
|
|||||||
description = "Generates a fix for a given GitHub issue.";
|
description = "Generates a fix for a given GitHub issue.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
policies = {
|
permissions = {
|
||||||
"my-rules" = {
|
allow = [ "command(git)" ];
|
||||||
rule = [
|
deny = [ "command(rm -rf)" ];
|
||||||
{
|
ask = [ "command(*)" ];
|
||||||
toolName = "run_shell_command";
|
|
||||||
commandPrefix = "git ";
|
|
||||||
decision = "ask_user";
|
|
||||||
priority = 100;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
"other-rules" = ./other-rules.toml;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
test.asserts.warnings.expected = [
|
||||||
|
"The option `programs.gemini-cli' defined in ${lib.showFiles options.programs.gemini-cli.files} has been renamed to `programs.antigravity-cli'."
|
||||||
|
];
|
||||||
|
|
||||||
nmt.script = ''
|
nmt.script = ''
|
||||||
assertFileExists home-files/.gemini/settings.json
|
assertFileExists home-files/.gemini/settings.json
|
||||||
assertFileContent home-files/.gemini/settings.json \
|
assertFileContent home-files/.gemini/settings.json \
|
||||||
${./settings.json}
|
${./settings.json}
|
||||||
assertFileContent home-files/.gemini/commands/changelog.toml \
|
assertFileExists home-files/.gemini/commands/changelog.toml
|
||||||
${./changelog.toml}
|
assertFileRegex home-files/.gemini/commands/changelog.toml \
|
||||||
assertFileContent home-files/.gemini/commands/git/fix.toml \
|
'prompt ='
|
||||||
${./fix.toml}
|
assertFileRegex home-files/.gemini/commands/changelog.toml \
|
||||||
assertFileContent home-files/.gemini/policies/my-rules.toml \
|
"Adds a new entry to the project's CHANGELOG.md file."
|
||||||
${./my-rules.toml}
|
assertFileExists home-files/.gemini/commands/git/fix.toml
|
||||||
assertFileContent home-files/.gemini/policies/other-rules.toml \
|
assertFileRegex home-files/.gemini/commands/git/fix.toml \
|
||||||
${./other-rules.toml}
|
'prompt ='
|
||||||
|
assertFileRegex home-files/.gemini/commands/git/fix.toml \
|
||||||
|
'Generates a fix for a given GitHub issue.'
|
||||||
|
|
||||||
assertFileExists home-path/etc/profile.d/hm-session-vars.sh
|
assertFileExists home-path/etc/profile.d/hm-session-vars.sh
|
||||||
assertFileContains home-path/etc/profile.d/hm-session-vars.sh \
|
assertFileContains home-path/etc/profile.d/hm-session-vars.sh \
|
||||||
@@ -1,9 +1,21 @@
|
|||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
options,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
{
|
{
|
||||||
programs.gemini-cli = {
|
programs.gemini-cli = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
package = pkgs.writeShellScriptBin "gemini-cli" "";
|
||||||
skills = ./skills;
|
skills = ./skills;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
test.asserts.warnings.expected = [
|
||||||
|
"The option `programs.gemini-cli' defined in ${lib.showFiles options.programs.gemini-cli.files} has been renamed to `programs.antigravity-cli'."
|
||||||
|
];
|
||||||
|
|
||||||
nmt.script = ''
|
nmt.script = ''
|
||||||
assertFileExists home-files/.gemini/skills/xlsx/SKILL.md
|
assertFileExists home-files/.gemini/skills/xlsx/SKILL.md
|
||||||
assertLinkExists home-files/.gemini/skills/xlsx/SKILL.md
|
assertLinkExists home-files/.gemini/skills/xlsx/SKILL.md
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
options,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
{
|
||||||
|
programs.gemini-cli = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.writeShellScriptBin "gemini-cli" "";
|
||||||
|
skills = ./skills/xlsx/SKILL.md;
|
||||||
|
};
|
||||||
|
|
||||||
|
test.asserts.warnings.expected = [
|
||||||
|
"The option `programs.gemini-cli' defined in ${lib.showFiles options.programs.gemini-cli.files} has been renamed to `programs.antigravity-cli'."
|
||||||
|
];
|
||||||
|
|
||||||
|
test.asserts.assertions.expected = [
|
||||||
|
"`programs.antigravity-cli.skills` must be a directory when set to a path"
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -1,4 +1,9 @@
|
|||||||
{ pkgs, ... }:
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
options,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
src = pkgs.writeTextDir "skills/external-skill/SKILL.md" ''
|
src = pkgs.writeTextDir "skills/external-skill/SKILL.md" ''
|
||||||
@@ -8,9 +13,14 @@ in
|
|||||||
{
|
{
|
||||||
programs.gemini-cli = {
|
programs.gemini-cli = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
package = pkgs.writeShellScriptBin "gemini-cli" "";
|
||||||
skills = "${src}/skills";
|
skills = "${src}/skills";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
test.asserts.warnings.expected = [
|
||||||
|
"The option `programs.gemini-cli' defined in ${lib.showFiles options.programs.gemini-cli.files} has been renamed to `programs.antigravity-cli'."
|
||||||
|
];
|
||||||
|
|
||||||
nmt.script = ''
|
nmt.script = ''
|
||||||
assertFileExists home-files/.gemini/skills/external-skill/SKILL.md
|
assertFileExists home-files/.gemini/skills/external-skill/SKILL.md
|
||||||
assertLinkExists home-files/.gemini/skills/external-skill/SKILL.md
|
assertLinkExists home-files/.gemini/skills/external-skill/SKILL.md
|
||||||
@@ -1,6 +1,14 @@
|
|||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
options,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
{
|
{
|
||||||
programs.gemini-cli = {
|
programs.gemini-cli = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
package = pkgs.writeShellScriptBin "gemini-cli" "";
|
||||||
skills = {
|
skills = {
|
||||||
xlsx = ./skills/xlsx/SKILL.md;
|
xlsx = ./skills/xlsx/SKILL.md;
|
||||||
data-analysis = ./skills/data-analysis;
|
data-analysis = ./skills/data-analysis;
|
||||||
@@ -25,6 +33,10 @@
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
test.asserts.warnings.expected = [
|
||||||
|
"The option `programs.gemini-cli' defined in ${lib.showFiles options.programs.gemini-cli.files} has been renamed to `programs.antigravity-cli'."
|
||||||
|
];
|
||||||
|
|
||||||
nmt.script = ''
|
nmt.script = ''
|
||||||
assertFileExists home-files/.gemini/skills/xlsx/SKILL.md
|
assertFileExists home-files/.gemini/skills/xlsx/SKILL.md
|
||||||
assertFileContent home-files/.gemini/skills/xlsx/SKILL.md \
|
assertFileContent home-files/.gemini/skills/xlsx/SKILL.md \
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Additional context for specialized tasks.
|
||||||
9
tests/modules/programs/antigravity-cli/context-inline.md
Normal file
9
tests/modules/programs/antigravity-cli/context-inline.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Global Context
|
||||||
|
|
||||||
|
You are a helpful AI assistant for software development.
|
||||||
|
|
||||||
|
## Coding Standards
|
||||||
|
|
||||||
|
- Follow consistent code style
|
||||||
|
- Write clear comments
|
||||||
|
- Test your changes
|
||||||
9
tests/modules/programs/antigravity-cli/context.md
Normal file
9
tests/modules/programs/antigravity-cli/context.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Global Context
|
||||||
|
|
||||||
|
You are a helpful AI assistant for software development.
|
||||||
|
|
||||||
|
## Coding Standards
|
||||||
|
|
||||||
|
- Follow consistent code style
|
||||||
|
- Write clear comments
|
||||||
|
- Test your changes
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
programs.gemini-cli = {
|
programs.antigravity-cli = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
package = pkgs.writeShellScriptBin "antigravity-cli" "";
|
||||||
context = {
|
context = {
|
||||||
# Test inline content
|
# Test inline content
|
||||||
GEMINI = ''
|
GEMINI = ''
|
||||||
12
tests/modules/programs/antigravity-cli/default.nix
Normal file
12
tests/modules/programs/antigravity-cli/default.nix
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
antigravity-cli-settings = ./settings.nix;
|
||||||
|
antigravity-cli-context = ./context.nix;
|
||||||
|
antigravity-cli-skills = ./skills.nix;
|
||||||
|
antigravity-cli-skills-dir = ./skills-dir.nix;
|
||||||
|
antigravity-cli-skills-store-path-dir = ./skills-store-path-dir.nix;
|
||||||
|
antigravity-cli-skills-path-not-directory = ./skills-path-not-directory.nix;
|
||||||
|
antigravity-cli-mcp-servers = ./mcp.nix;
|
||||||
|
antigravity-cli-policies-removed = ./policies-removed.nix;
|
||||||
|
antigravity-cli-gemini-package-paths = ./gemini-package-paths.nix;
|
||||||
|
antigravity-cli-legacy-gemini-config = ./legacy-gemini-config.nix;
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
programs.antigravity-cli = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.writeShellScriptBin "gemini-cli" "";
|
||||||
|
settings.theme = "Default";
|
||||||
|
commands.review = {
|
||||||
|
prompt = "Review current changes.";
|
||||||
|
description = "Reviews current changes.";
|
||||||
|
};
|
||||||
|
skills.audit = ''
|
||||||
|
---
|
||||||
|
name: audit
|
||||||
|
description: Audit code changes.
|
||||||
|
---
|
||||||
|
|
||||||
|
Audit code changes.
|
||||||
|
'';
|
||||||
|
policies.commands.rule = [
|
||||||
|
{
|
||||||
|
toolName = "run_shell_command";
|
||||||
|
commandPrefix = "git ";
|
||||||
|
decision = "ask_user";
|
||||||
|
priority = 100;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
assertFileExists home-files/.gemini/settings.json
|
||||||
|
assertPathNotExists home-files/.gemini/antigravity-cli/settings.json
|
||||||
|
assertFileExists home-files/.gemini/commands/review.toml
|
||||||
|
assertFileExists home-files/.gemini/skills/audit/SKILL.md
|
||||||
|
assertFileExists home-files/.gemini/policies/commands.toml
|
||||||
|
assertPathNotExists home-files/.gemini/config/skills/review/SKILL.md
|
||||||
|
assertPathNotExists home-files/.gemini/config/mcp_config.json
|
||||||
|
'';
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
programs.antigravity-cli = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.writeShellScriptBin "antigravity-cli" "";
|
||||||
|
useLegacyGeminiConfig = true;
|
||||||
|
settings.theme = "Default";
|
||||||
|
mcpServers.github.serverUrl = "https://api.githubcopilot.com/mcp/";
|
||||||
|
commands.review = {
|
||||||
|
prompt = "Review current changes.";
|
||||||
|
description = "Reviews current changes.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
assertFileExists home-files/.gemini/settings.json
|
||||||
|
assertFileExists home-files/.gemini/commands/review.toml
|
||||||
|
assertFileRegex home-files/.gemini/settings.json '"github"'
|
||||||
|
assertPathNotExists home-files/.gemini/antigravity-cli/settings.json
|
||||||
|
assertPathNotExists home-files/.gemini/config/mcp_config.json
|
||||||
|
assertPathNotExists home-files/.gemini/config/skills/review/SKILL.md
|
||||||
|
'';
|
||||||
|
}
|
||||||
66
tests/modules/programs/antigravity-cli/mcp.nix
Normal file
66
tests/modules/programs/antigravity-cli/mcp.nix
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
programs = {
|
||||||
|
antigravity-cli = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.writeShellScriptBin "antigravity-cli" "";
|
||||||
|
enableMcpIntegration = true;
|
||||||
|
settings = {
|
||||||
|
colorScheme = "terminal";
|
||||||
|
toolPermission = "request-review";
|
||||||
|
};
|
||||||
|
mcpServers = {
|
||||||
|
github = {
|
||||||
|
url = "https://api.githubcopilot.com/mcp/";
|
||||||
|
env = {
|
||||||
|
url = "https://token.example/env";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
filesystem = {
|
||||||
|
command = "npx";
|
||||||
|
args = [
|
||||||
|
"-y"
|
||||||
|
"@modelcontextprotocol/server-filesystem"
|
||||||
|
"/tmp"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
mcp = {
|
||||||
|
enable = true;
|
||||||
|
servers = {
|
||||||
|
filesystem = {
|
||||||
|
command = "npx";
|
||||||
|
args = [
|
||||||
|
"-y"
|
||||||
|
"@modelcontextprotocol/server-filesystem"
|
||||||
|
"/other-tmp"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
database = {
|
||||||
|
command = "npx";
|
||||||
|
args = [
|
||||||
|
"-y"
|
||||||
|
"@bytebase/dbhub"
|
||||||
|
"--dsn"
|
||||||
|
"postgresql://user:pass@localhost:5432/db"
|
||||||
|
];
|
||||||
|
env = {
|
||||||
|
DATABASE_URL = "postgresql://user:pass@localhost:5432/db";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
nmt.script = ''
|
||||||
|
assertFileExists home-files/.gemini/config/mcp_config.json
|
||||||
|
assertFileRegex home-files/.gemini/config/mcp_config.json '"github"'
|
||||||
|
assertFileRegex home-files/.gemini/config/mcp_config.json '"serverUrl"'
|
||||||
|
assertFileRegex home-files/.gemini/config/mcp_config.json '"url"'
|
||||||
|
assertFileRegex home-files/.gemini/config/mcp_config.json 'https://token.example/env'
|
||||||
|
assertFileRegex home-files/.gemini/config/mcp_config.json '"filesystem"'
|
||||||
|
assertFileRegex home-files/.gemini/config/mcp_config.json '"database"'
|
||||||
|
assertFileNotRegex home-files/.gemini/config/mcp_config.json '"other-tmp"'
|
||||||
|
'';
|
||||||
|
}
|
||||||
28
tests/modules/programs/antigravity-cli/policies-removed.nix
Normal file
28
tests/modules/programs/antigravity-cli/policies-removed.nix
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
_:
|
||||||
|
|
||||||
|
{
|
||||||
|
programs.antigravity-cli = {
|
||||||
|
enable = true;
|
||||||
|
package = null;
|
||||||
|
policies."my-rules" = {
|
||||||
|
rule = [
|
||||||
|
{
|
||||||
|
toolName = "run_shell_command";
|
||||||
|
commandPrefix = "git ";
|
||||||
|
decision = "ask_user";
|
||||||
|
priority = 100;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
test.asserts.assertions.expected = [
|
||||||
|
''
|
||||||
|
`programs.antigravity-cli.policies` is only supported when
|
||||||
|
`programs.antigravity-cli.package` is a `gemini-cli` package.
|
||||||
|
Antigravity CLI configures permissions in
|
||||||
|
`programs.antigravity-cli.settings.permissions` or
|
||||||
|
`programs.antigravity-cli.permissions`.
|
||||||
|
''
|
||||||
|
];
|
||||||
|
}
|
||||||
17
tests/modules/programs/antigravity-cli/settings.json
Normal file
17
tests/modules/programs/antigravity-cli/settings.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"altScreenMode": "always",
|
||||||
|
"artifactReviewPolicy": "agent-decides",
|
||||||
|
"colorScheme": "tokyo night",
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"command(git)"
|
||||||
|
],
|
||||||
|
"ask": [
|
||||||
|
"command(*)"
|
||||||
|
],
|
||||||
|
"deny": [
|
||||||
|
"command(rm -rf)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"toolPermission": "proceed-in-sandbox"
|
||||||
|
}
|
||||||
51
tests/modules/programs/antigravity-cli/settings.nix
Normal file
51
tests/modules/programs/antigravity-cli/settings.nix
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
programs.antigravity-cli = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.writeShellScriptBin "antigravity-cli" "";
|
||||||
|
defaultModel = "gemini-2.5-flash";
|
||||||
|
settings = {
|
||||||
|
colorScheme = "tokyo night";
|
||||||
|
altScreenMode = "always";
|
||||||
|
toolPermission = "proceed-in-sandbox";
|
||||||
|
artifactReviewPolicy = "agent-decides";
|
||||||
|
};
|
||||||
|
commands = {
|
||||||
|
changelog = {
|
||||||
|
prompt = ''
|
||||||
|
Your task is to parse the `<version>`, `<change_type>`, and `<message>` from their input and use the `write_file` tool to correctly update the `CHANGELOG.md` file.
|
||||||
|
'';
|
||||||
|
description = "Adds a new entry to the project's CHANGELOG.md file.";
|
||||||
|
};
|
||||||
|
"git/fix" = {
|
||||||
|
prompt = "Please analyze the staged git changes and provide a code fix for the issue described here: {{args}}.";
|
||||||
|
description = "Generates a fix for a given GitHub issue.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
permissions = {
|
||||||
|
allow = [ "command(git)" ];
|
||||||
|
deny = [ "command(rm -rf)" ];
|
||||||
|
ask = [ "command(*)" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
nmt.script = ''
|
||||||
|
assertFileExists home-files/.gemini/antigravity-cli/settings.json
|
||||||
|
assertFileContent home-files/.gemini/antigravity-cli/settings.json \
|
||||||
|
${./settings.json}
|
||||||
|
assertFileExists home-files/.gemini/config/skills/changelog/SKILL.md
|
||||||
|
assertFileRegex home-files/.gemini/config/skills/changelog/SKILL.md \
|
||||||
|
'name: changelog'
|
||||||
|
assertFileRegex home-files/.gemini/config/skills/changelog/SKILL.md \
|
||||||
|
"Adds a new entry to the project's CHANGELOG.md file."
|
||||||
|
assertFileExists home-files/.gemini/config/skills/git:fix/SKILL.md
|
||||||
|
assertFileRegex home-files/.gemini/config/skills/git:fix/SKILL.md \
|
||||||
|
'name: git:fix'
|
||||||
|
assertFileRegex home-files/.gemini/config/skills/git:fix/SKILL.md \
|
||||||
|
'Generates a fix for a given GitHub issue.'
|
||||||
|
|
||||||
|
assertFileExists home-path/etc/profile.d/hm-session-vars.sh
|
||||||
|
assertFileContains home-path/etc/profile.d/hm-session-vars.sh \
|
||||||
|
'export GEMINI_MODEL="gemini-2.5-flash"'
|
||||||
|
'';
|
||||||
|
}
|
||||||
26
tests/modules/programs/antigravity-cli/skills-dir.nix
Normal file
26
tests/modules/programs/antigravity-cli/skills-dir.nix
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
programs.antigravity-cli = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.writeShellScriptBin "antigravity-cli" "";
|
||||||
|
skills = ./skills;
|
||||||
|
};
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
assertFileExists home-files/.gemini/config/skills/xlsx/SKILL.md
|
||||||
|
assertLinkExists home-files/.gemini/config/skills/xlsx/SKILL.md
|
||||||
|
assertFileContent home-files/.gemini/config/skills/xlsx/SKILL.md \
|
||||||
|
${./skills/xlsx/SKILL.md}
|
||||||
|
|
||||||
|
assertFileExists home-files/.gemini/config/skills/data-analysis/SKILL.md
|
||||||
|
assertLinkExists home-files/.gemini/config/skills/data-analysis/SKILL.md
|
||||||
|
assertFileContent home-files/.gemini/config/skills/data-analysis/SKILL.md \
|
||||||
|
${./skills/data-analysis/SKILL.md}
|
||||||
|
|
||||||
|
assertFileExists home-files/.gemini/config/skills/pdf-processing/SKILL.md
|
||||||
|
assertLinkExists home-files/.gemini/config/skills/pdf-processing/SKILL.md
|
||||||
|
assertFileContent home-files/.gemini/config/skills/pdf-processing/SKILL.md \
|
||||||
|
${./skills/pdf-processing/SKILL.md}
|
||||||
|
'';
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
programs.antigravity-cli = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.writeShellScriptBin "antigravity-cli" "";
|
||||||
|
skills = ./skills/xlsx/SKILL.md;
|
||||||
|
};
|
||||||
|
|
||||||
|
test.asserts.assertions.expected = [
|
||||||
|
"`programs.antigravity-cli.skills` must be a directory when set to a path"
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
src = pkgs.writeTextDir "skills/external-skill/SKILL.md" ''
|
||||||
|
# External Skill
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
programs.antigravity-cli = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.writeShellScriptBin "antigravity-cli" "";
|
||||||
|
skills = "${src}/skills";
|
||||||
|
};
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
assertFileExists home-files/.gemini/config/skills/external-skill/SKILL.md
|
||||||
|
assertLinkExists home-files/.gemini/config/skills/external-skill/SKILL.md
|
||||||
|
assertFileContent home-files/.gemini/config/skills/external-skill/SKILL.md \
|
||||||
|
"${src}/skills/external-skill/SKILL.md"
|
||||||
|
'';
|
||||||
|
}
|
||||||
44
tests/modules/programs/antigravity-cli/skills.nix
Normal file
44
tests/modules/programs/antigravity-cli/skills.nix
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
programs.antigravity-cli = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.writeShellScriptBin "antigravity-cli" "";
|
||||||
|
skills = {
|
||||||
|
xlsx = ./skills/xlsx/SKILL.md;
|
||||||
|
data-analysis = ./skills/data-analysis;
|
||||||
|
pdf-processing = ''
|
||||||
|
---
|
||||||
|
name: pdf-processing
|
||||||
|
description: Extract text and tables from PDF files, fill forms, merge documents. Use when working with PDF files or when the user mentions PDFs, forms, or document extraction.
|
||||||
|
---
|
||||||
|
|
||||||
|
# PDF Processing
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
Use pdfplumber to extract text from PDFs:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import pdfplumber
|
||||||
|
|
||||||
|
with pdfplumber.open("document.pdf") as pdf:
|
||||||
|
text = pdf.pages[0].extract_text()
|
||||||
|
```
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
nmt.script = ''
|
||||||
|
assertFileExists home-files/.gemini/config/skills/xlsx/SKILL.md
|
||||||
|
assertFileContent home-files/.gemini/config/skills/xlsx/SKILL.md \
|
||||||
|
${./skills/xlsx/SKILL.md}
|
||||||
|
|
||||||
|
assertFileExists home-files/.gemini/config/skills/data-analysis/SKILL.md
|
||||||
|
assertFileContent home-files/.gemini/config/skills/data-analysis/SKILL.md \
|
||||||
|
${./skills/data-analysis/SKILL.md}
|
||||||
|
|
||||||
|
assertFileExists home-files/.gemini/config/skills/pdf-processing/SKILL.md
|
||||||
|
assertFileContent home-files/.gemini/config/skills/pdf-processing/SKILL.md \
|
||||||
|
${./skills/pdf-processing/SKILL.md}
|
||||||
|
'';
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
name: data-analysis
|
||||||
|
description: Do some data analysis
|
||||||
|
---
|
||||||
|
|
||||||
|
# Data Analysis
|
||||||
|
|
||||||
|
Use good data analytics tools for analysis 👍
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
name: pdf-processing
|
||||||
|
description: Extract text and tables from PDF files, fill forms, merge documents. Use when working with PDF files or when the user mentions PDFs, forms, or document extraction.
|
||||||
|
---
|
||||||
|
|
||||||
|
# PDF Processing
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
Use pdfplumber to extract text from PDFs:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import pdfplumber
|
||||||
|
|
||||||
|
with pdfplumber.open("document.pdf") as pdf:
|
||||||
|
text = pdf.pages[0].extract_text()
|
||||||
|
```
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
name: xlsx
|
||||||
|
description: Handling xlsx files correctly
|
||||||
|
---
|
||||||
|
|
||||||
|
# XLSX Handling
|
||||||
|
|
||||||
|
Use the python library called `openpyxl` to handle these files
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
description = "Adds a new entry to the project's CHANGELOG.md file."
|
|
||||||
prompt = "Your task is to parse the `<version>`, `<change_type>`, and `<message>` from their input and use the `write_file` tool to correctly update the `CHANGELOG.md` file.\n"
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
description = "Generates a fix for a given GitHub issue."
|
|
||||||
prompt = "Please analyze the staged git changes and provide a code fix for the issue described here: {{args}}."
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
[[rule]]
|
|
||||||
toolName = "read_file"
|
|
||||||
decision = "allow"
|
|
||||||
priority = 50
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"autoAccept": true,
|
|
||||||
"preferredEditor": "nvim",
|
|
||||||
"theme": "Default",
|
|
||||||
"vimMode": true
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
programs.gemini-cli = {
|
|
||||||
enable = true;
|
|
||||||
skills = ./skills/xlsx/SKILL.md;
|
|
||||||
};
|
|
||||||
|
|
||||||
test.asserts.assertions.expected = [
|
|
||||||
"`programs.gemini-cli.skills` must be a directory when set to a path"
|
|
||||||
];
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user