Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,15 @@ launchctl-ollama: ## Restart ollama launchd agent.
##@ Systemd Services (Linux)

.PHONY: systemctl
systemctl: systemctl-clawdbot systemctl-code-syncer systemctl-dotfiles-updater systemctl-ollama ## Restart all systemd user services.
systemctl: systemctl-cliproxyapi systemctl-clawdbot systemctl-code-syncer systemctl-dotfiles-updater systemctl-ollama ## Restart all systemd user services.

.PHONY: systemctl-cliproxyapi
systemctl-cliproxyapi: ## Pull latest image and restart cliproxyapi systemd user service.
@echo "🔄 Pulling latest cliproxyapi image..."
@docker pull eceasy/cli-proxy-api:latest || true
@echo "🔄 Restarting cliproxyapi..."
@systemctl --user restart cliproxyapi.service || true
@echo "✅ cliproxyapi restarted"

.PHONY: systemctl-clawdbot
systemctl-clawdbot: ## Restart clawdbot gateway systemd user service.
Expand Down
42 changes: 42 additions & 0 deletions config/ccs/accounts.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"version": 1,
"providers": {
"agy": {
"default": "shunkakinoki@gmail.com",
"accounts": {
"shunkakinoki@gmail.com": {
"email": "shunkakinoki@gmail.com",
"nickname": "shunkakinoki",
"tokenFile": "antigravity-shunkakinoki_gmail_com.json",
"createdAt": "2026-01-17T00:00:00.000Z",
"lastUsedAt": "2026-01-17T19:28:18.251Z",
"tier": "paid"
}
}
},
"gemini": {
"default": "shunkakinoki@gmail.com",
"accounts": {
"shunkakinoki@gmail.com": {
"email": "shunkakinoki@gmail.com",
"nickname": "shunkakinoki",
"tokenFile": "gemini-shunkakinoki@gmail.com-gen-lang-client-0359793614.json",
Comment on lines +10 to +23

Copilot AI Jan 17, 2026

Copy link

Choose a reason for hiding this comment

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

The email address in the tokenFile is inconsistent with the format used in other providers. For the gemini provider, the tokenFile uses "@" symbol ("gemini-shunkakinoki@gmail.com-gen-lang-client-0359793614.json"), while for the agy provider it uses an underscore-separated format ("antigravity-shunkakinoki_gmail_com.json"). This inconsistency could lead to confusion when managing token files. Consider standardizing the token file naming convention across all providers.

Copilot uses AI. Check for mistakes.
"createdAt": "2026-01-12T00:00:00.000Z",
"lastUsedAt": "2026-01-12T00:00:00.000Z"
}
}
},
"codex": {
"default": "shunkakinoki@gmail.com",
"accounts": {
"shunkakinoki@gmail.com": {
"email": "shunkakinoki@gmail.com",
"nickname": "shunkakinoki",
"tokenFile": "codex-shunkakinoki@gmail.com.json",
"createdAt": "2025-12-18T00:00:00.000Z",
"lastUsedAt": "2025-12-18T00:00:00.000Z"
}
}
}
}
}
Comment on lines +1 to +42

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

security-high high

Committing a file with hardcoded personal information like your email address and nickname is a security risk, as it exposes Personally Identifiable Information (PII). It also makes the configuration harder to maintain and less portable. It's much better to generate this file dynamically from your Nix configuration, using variables that are already defined elsewhere (like config.accounts.email.accounts.Gmail.address). This file should be removed after applying the suggested change in config/ccs/default.nix.

Comment on lines +1 to +42

Copilot AI Jan 17, 2026

Copy link

Choose a reason for hiding this comment

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

This configuration file contains a personal email address (shunkakinoki@gmail.com) which appears to be developer-specific rather than a placeholder or example value. If this is meant to be a shared configuration template, consider using placeholder values like "user@example.com" or add documentation indicating that users need to replace these values with their own credentials. If this is personal configuration that should not be shared, it should not be committed to version control.

Copilot uses AI. Check for mistakes.
10 changes: 10 additions & 0 deletions config/ccs/agy.settings.template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"env": {
"ANTHROPIC_BASE_URL": "http://127.0.0.1:8317/api/provider/agy",
"ANTHROPIC_AUTH_TOKEN": "__CLIPROXY_API_KEY__",
"ANTHROPIC_MODEL": "claude-opus-4-5-thinking",
"ANTHROPIC_DEFAULT_OPUS_MODEL": "claude-opus-4-5-thinking",
"ANTHROPIC_DEFAULT_SONNET_MODEL": "claude-opus-4-5-thinking",
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "claude-sonnet-4-5"
}
}
39 changes: 39 additions & 0 deletions config/ccs/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{ config, lib, pkgs, ... }:
let
dotfilesDir = "${config.home.homeDirectory}/dotfiles";
in
{
# CCS (Claude Code Switcher) account registry
# Maps OAuth token files to registered accounts for cliproxy providers
# Token files are stored separately in ~/.ccs/cliproxy/auth/ (not managed here as they contain secrets)
# Note: Using mkOutOfStoreSymlink with absolute path so CCS can write to the file (updates lastUsedAt)
home.file.".ccs/cliproxy/accounts.json" = {
source = config.lib.file.mkOutOfStoreSymlink "${dotfilesDir}/config/ccs/accounts.json";
force = true;
};

# Hydrate CCS settings templates with secrets from .env
# ANTHROPIC_AUTH_TOKEN is substituted from CLIPROXY_API_KEY at activation time
home.activation.hydrateCcsSettings = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
ENV_FILE="${dotfilesDir}/.env"
TEMPLATE="${dotfilesDir}/config/ccs/agy.settings.template.json"
OUTPUT="${config.home.homeDirectory}/.ccs/agy.settings.json"

if [ -f "$ENV_FILE" ] && [ -f "$TEMPLATE" ]; then
# Source .env to get CLIPROXY_API_KEY
set -a
. "$ENV_FILE"
set +a

# Substitute placeholder and write output
if [ -n "$CLIPROXY_API_KEY" ]; then
${pkgs.gnused}/bin/sed \
-e "s|__CLIPROXY_API_KEY__|$CLIPROXY_API_KEY|g" \
"$TEMPLATE" > "$OUTPUT"

@cubic-dev-ai cubic-dev-ai Bot Jan 17, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: Secret CLIPROXY_API_KEY is written to ~/.ccs/agy.settings.json without enforcing restrictive permissions, likely creating a world-readable secrets file.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At config/ccs/default.nix, line 32:

<comment>Secret CLIPROXY_API_KEY is written to ~/.ccs/agy.settings.json without enforcing restrictive permissions, likely creating a world-readable secrets file.</comment>

<file context>
@@ -11,4 +11,29 @@ in
+      if [ -n "$CLIPROXY_API_KEY" ]; then
+        ${pkgs.gnused}/bin/sed \
+          -e "s|__CLIPROXY_API_KEY__|$CLIPROXY_API_KEY|g" \
+          "$TEMPLATE" > "$OUTPUT"
+        $VERBOSE_ECHO "Hydrated CCS agy.settings.json with CLIPROXY_API_KEY"
+      else
</file context>
Fix with Cubic

$VERBOSE_ECHO "Hydrated CCS agy.settings.json with CLIPROXY_API_KEY"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's look at the actual file and its context
cat -n config/ccs/default.nix | head -50

Repository: shunkakinoki/dotfiles

Length of output: 1895


🏁 Script executed:

# Search for CLIPROXY_API_KEY to understand its source and usage
rg "CLIPROXY_API_KEY" -B 3 -A 3

Repository: shunkakinoki/dotfiles

Length of output: 7940


🏁 Script executed:

# Check the full script context in the file
sed -n '1,50p' config/ccs/default.nix

Repository: shunkakinoki/dotfiles

Length of output: 1622


🏁 Script executed:

# Look for test cases or documentation about CLIPROXY_API_KEY format
rg "CLIPROXY_API_KEY.*=" -A 2 -B 2 | head -50

Repository: shunkakinoki/dotfiles

Length of output: 816


🏁 Script executed:

# Check if there are any examples or documentation files
fd -e md -e txt | xargs grep -l CLIPROXY_API_KEY 2>/dev/null

Repository: shunkakinoki/dotfiles

Length of output: 49


🏁 Script executed:

# Look for similar sed escaping patterns in the codebase
rg "sed.*\\\$.*-e.*s\|" -A 2 -B 2

Repository: shunkakinoki/dotfiles

Length of output: 47


Escape special characters in CLIPROXY_API_KEY before sed substitution, but correct the escaping approach.

The concern about sed special characters is valid: if the API key contains & or \, the substitution will fail or produce incorrect JSON. However, the proposed fix is flawed—it attempts to escape / characters (unnecessary since the delimiter is |) using malformed syntax.

For sed replacement text, only & (which represents the matched string) and \ (escape char) need escaping. The correct approach:

Correct fix (escape & and backslash for sed replacement)
      if [ -n "$CLIPROXY_API_KEY" ]; then
+       escaped_key="$(printf '%s' "$CLIPROXY_API_KEY" | ${pkgs.gnused}/bin/sed -e 's/[&\]/\\&/g')"
        ${pkgs.gnused}/bin/sed \
-         -e "s|__CLIPROXY_API_KEY__|$CLIPROXY_API_KEY|g" \
+         -e "s|__CLIPROXY_API_KEY__|${escaped_key}|g" \
          "$TEMPLATE" > "$OUTPUT"

Also confirm: what is the expected character set for CLIPROXY_API_KEY? Is it documented anywhere that it's restricted to alphanumeric characters and hyphens?

📝 Committable suggestion

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

Suggested change
# Substitute placeholder and write output
if [ -n "$CLIPROXY_API_KEY" ]; then
${pkgs.gnused}/bin/sed \
-e "s|__CLIPROXY_API_KEY__|$CLIPROXY_API_KEY|g" \
"$TEMPLATE" > "$OUTPUT"
$VERBOSE_ECHO "Hydrated CCS agy.settings.json with CLIPROXY_API_KEY"
# Substitute placeholder and write output
if [ -n "$CLIPROXY_API_KEY" ]; then
escaped_key="$(printf '%s' "$CLIPROXY_API_KEY" | ${pkgs.gnused}/bin/sed -e 's/[&\]/\\&/g')"
${pkgs.gnused}/bin/sed \
-e "s|__CLIPROXY_API_KEY__|${escaped_key}|g" \
"$TEMPLATE" > "$OUTPUT"
$VERBOSE_ECHO "Hydrated CCS agy.settings.json with CLIPROXY_API_KEY"
🤖 Prompt for AI Agents
In `@config/ccs/default.nix` around lines 28 - 33, The sed substitution for
CLIPROXY_API_KEY must escape characters that are special in sed replacement text
(backslash and ampersand) before running ${pkgs.gnused}/bin/sed; update the
block that writes "$TEMPLATE" -> "$OUTPUT" to first transform CLIPROXY_API_KEY
(e.g., via POSIX shell parameter expansion or a small helper) replacing '\' with
'\\' and '&' with '\&', then use that escaped variable in the sed -e
"s|__CLIPROXY_API_KEY__|$ESCAPED_CLIPROXY_API_KEY|g" invocation and keep the
existing '|' delimiter (so '/' need not be escaped); ensure you reference
CLIPROXY_API_KEY when creating ESCAPED_CLIPROXY_API_KEY and retain VERBOSE_ECHO
for the log message.

else
$VERBOSE_ECHO "Warning: CLIPROXY_API_KEY not set in .env, skipping agy.settings.json hydration"
fi
fi
'';
}
3 changes: 2 additions & 1 deletion config/cliproxyapi/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ remote-management:
# Disable the bundled management control panel asset download and HTTP route when true.
disable-control-panel: false
# Authentication directory (supports ~ for home directory). If you use Windows, please set the directory like this: `C:/cli-proxy-api/`
auth-dir: "~/.cli-proxy-api"
# Use objectstore/auths subdirectory to avoid duplicate scanning (root-level files are legacy)
auth-dir: "~/.cli-proxy-api/objectstore/auths"
Comment on lines +15 to +16

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Search for migration documentation or guides related to this change
rg -i "migration\|migrate" --type=md --type=txt -A 2 -B 2

Repository: shunkakinoki/dotfiles

Length of output: 47


🏁 Script executed:

# Check for objectstore/auths references in documentation
rg "objectstore/auths|cli-proxy-api" --type=md --type=txt --type=nix -C 2

Repository: shunkakinoki/dotfiles

Length of output: 3185


🏁 Script executed:

# Check the actual YAML file for context and formatting
cat -n config/cliproxyapi/config.yaml | head -30

Repository: shunkakinoki/dotfiles

Length of output: 1807


🏁 Script executed:

# Look for README or migration guides in the repo
fd -t f -i "readme\|migration\|changelog" -E node_modules

Repository: shunkakinoki/dotfiles

Length of output: 47


Add migration guidance for legacy auth files.

The README documents that ~/.cli-proxy-api/objectstore/auths is the intended auth cache directory. However, your comment references "root-level files are legacy" without documenting how users with existing auth files at ~/.cli-proxy-api/ should migrate them. Add a note in the README or commit message clarifying the migration path, or confirm this is only for fresh setups.

🤖 Prompt for AI Agents
In `@config/cliproxyapi/config.yaml` around lines 15 - 16, Update the project
documentation to add explicit migration guidance for legacy auth files
referenced by the config key auth-dir (value
"~/.cli-proxy-api/objectstore/auths"): state whether this new directory is only
for fresh setups or required for all users, describe how to detect legacy files
at "~/.cli-proxy-api/" and provide a simple migration command sequence (e.g.,
move/backup into the new objectstore/auths subdirectory), and include any
post-migration steps or troubleshooting notes so users know how to verify the
migrated auth files work with the CLI proxy API.

Comment on lines +15 to +16

Copilot AI Jan 17, 2026

Copy link

Choose a reason for hiding this comment

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

The comment states "Use objectstore/auths subdirectory to avoid duplicate scanning (root-level files are legacy)", but this explanation is vague. Consider clarifying what "duplicate scanning" refers to and why root-level files are considered legacy. This would help future maintainers understand the rationale for this directory structure change.

Copilot uses AI. Check for mistakes.
# API keys for client authentication (optional - leave commented for open access)
# api-keys:
# - "__CLIPROXY_API_KEY__"
Expand Down
1 change: 1 addition & 0 deletions config/default.nix
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[
./amp
./ccs
./cliproxyapi
./codex
./crush
Expand Down
10 changes: 10 additions & 0 deletions home-manager/services/cliproxyapi/scripts/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@ if [ -f "$TEMPLATE" ]; then
-e "s|^# - \"__CLIPROXY_API_KEY__\"| - \"${CLIPROXY_API_KEY}\"|" \
"$CONFIG"
fi

# Disable AMP on Linux (causes routing issues with antigravity provider)
if [ "$(uname)" = "Linux" ]; then
@sed@ -i \
-e "s|^ampcode:|# ampcode:|" \
-e "s|^ upstream-url:|# upstream-url:|" \
-e "s|^ upstream-api-key:|# upstream-api-key:|" \
-e "s|^ restrict-management-to-localhost:|# restrict-management-to-localhost:|" \
"$CONFIG"
fi
fi

cd "$CONFIG_DIR"
Expand Down
Loading