Skip to content

Commit b90ed16

Browse files
committed
support gateway_url
1 parent 7655913 commit b90ed16

File tree

2 files changed

+89
-0
lines changed

2 files changed

+89
-0
lines changed

scripts/bash/common.sh

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,35 @@
11
#!/usr/bin/env bash
22
# Common functions and variables for all scripts
33

4+
# Load gateway configuration and export helper environment variables
5+
load_gateway_config() {
6+
local repo_root="$1"
7+
local config_dir="$repo_root/.specify/config"
8+
local env_file="$config_dir/gateway.env"
9+
10+
if [[ -f "$env_file" ]]; then
11+
# shellcheck disable=SC1090
12+
source "$env_file"
13+
fi
14+
15+
if [[ -n "${SPECIFY_GATEWAY_URL:-}" ]]; then
16+
export SPECIFY_GATEWAY_URL
17+
export SPECIFY_GATEWAY_ACTIVE="true"
18+
[[ -z "${ANTHROPIC_BASE_URL:-}" ]] && export ANTHROPIC_BASE_URL="$SPECIFY_GATEWAY_URL"
19+
[[ -z "${GEMINI_BASE_URL:-}" ]] && export GEMINI_BASE_URL="$SPECIFY_GATEWAY_URL"
20+
[[ -z "${OPENAI_BASE_URL:-}" ]] && export OPENAI_BASE_URL="$SPECIFY_GATEWAY_URL"
21+
else
22+
export SPECIFY_GATEWAY_ACTIVE="false"
23+
if [[ -z "${SPECIFY_SUPPRESS_GATEWAY_WARNING:-}" ]]; then
24+
echo "[specify] Warning: Gateway URL not configured. Set SPECIFY_GATEWAY_URL in .specify/config/gateway.env." >&2
25+
fi
26+
fi
27+
28+
if [[ -n "${SPECIFY_GATEWAY_TOKEN:-}" ]]; then
29+
export SPECIFY_GATEWAY_TOKEN
30+
fi
31+
}
32+
433
# Get repository root, with fallback for non-git repositories
534
get_repo_root() {
635
if git rev-parse --show-toplevel >/dev/null 2>&1; then
@@ -85,6 +114,7 @@ get_feature_dir() { echo "$1/specs/$2"; }
85114

86115
get_feature_paths() {
87116
local repo_root=$(get_repo_root)
117+
load_gateway_config "$repo_root"
88118
local current_branch=$(get_current_branch)
89119
local has_git_repo="false"
90120

src/specify_cli/__init__.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,53 @@ def download_and_extract_template(project_path: Path, ai_assistant: str, script_
759759
return project_path
760760

761761

762+
def ensure_gateway_config(
763+
project_path: Path,
764+
selected_ai: str,
765+
*,
766+
tracker: StepTracker | None = None,
767+
gateway_url: str | None = None,
768+
gateway_token: str | None = None,
769+
suppress_warning: bool | None = None,
770+
) -> None:
771+
"""Create gateway config template and optionally auto-write base URL env guidance."""
772+
config_dir = project_path / ".specify" / "config"
773+
config_dir.mkdir(parents=True, exist_ok=True)
774+
env_path = config_dir / "gateway.env"
775+
776+
was_existing = env_path.exists()
777+
778+
if was_existing and not any([gateway_url, gateway_token, suppress_warning]):
779+
return
780+
781+
lines = [
782+
"# Central LLM gateway configuration",
783+
"# Populate SPECIFY_GATEWAY_URL with your proxy endpoint.",
784+
"# Populate SPECIFY_GATEWAY_TOKEN if authentication is required.",
785+
f"SPECIFY_GATEWAY_URL={gateway_url or ''}",
786+
f"SPECIFY_GATEWAY_TOKEN={gateway_token or ''}",
787+
"# Set SPECIFY_SUPPRESS_GATEWAY_WARNING=true to silence CLI warnings.",
788+
"SPECIFY_SUPPRESS_GATEWAY_WARNING=" + ("true" if suppress_warning else ""),
789+
]
790+
791+
# Assistant guidance comments
792+
assistant_comments = {
793+
"claude": "# Claude Code uses ANTHROPIC_BASE_URL; the CLI will export it automatically when SPECIFY_GATEWAY_URL is set.",
794+
"gemini": "# Gemini CLI uses GEMINI_BASE_URL; the CLI will export it automatically when SPECIFY_GATEWAY_URL is set.",
795+
"qwen": "# Qwen/Codex style CLIs use OPENAI_BASE_URL; the CLI will export it automatically when SPECIFY_GATEWAY_URL is set.",
796+
"opencode": "# OpenCode can reference the gateway via {env:SPECIFY_GATEWAY_URL} in opencode.json.",
797+
}
798+
799+
if selected_ai in assistant_comments:
800+
lines.append(assistant_comments[selected_ai])
801+
802+
env_path.write_text("\n".join(lines) + "\n")
803+
804+
if tracker:
805+
tracker.add("gateway", "Create gateway configuration")
806+
tracker.complete("gateway", "updated" if was_existing else "scaffolded template")
807+
808+
762809
def ensure_executable_scripts(project_path: Path, tracker: StepTracker | None = None) -> None:
763810
"""Ensure POSIX .sh scripts under .specify/scripts (recursively) have execute bits (no-op on Windows)."""
764811
if os.name == "nt":
@@ -816,6 +863,9 @@ def init(
816863
debug: bool = typer.Option(False, "--debug", help="Show verbose diagnostic output for network and extraction failures"),
817864
github_token: str = typer.Option(None, "--github-token", help="GitHub token to use for API requests (or set GH_TOKEN or GITHUB_TOKEN environment variable)"),
818865
team_ai_directives: str = typer.Option(None, "--team-ai-directive", "--team-ai-directives", help="Clone or update a team-ai-directives repository into .specify/memory"),
866+
gateway_url: str = typer.Option(None, "--gateway-url", help="Optional central LLM gateway base URL (populates .specify/config/gateway.env)"),
867+
gateway_token: str = typer.Option(None, "--gateway-token", help="Optional token used when calling the central LLM gateway"),
868+
gateway_suppress_warning: bool = typer.Option(False, "--gateway-suppress-warning", help="Suppress gateway missing warnings for this project"),
819869
):
820870
"""
821871
Initialize a new Specify project from the latest template.
@@ -848,6 +898,7 @@ def init(
848898
specify init --here
849899
specify init --here --force # Skip confirmation when current directory not empty
850900
specify init my-project --team-ai-directive https://github.com/my-org/team-ai-directives.git
901+
specify init my-project --gateway-url https://llm-proxy.internal --gateway-token $TOKEN
851902
"""
852903
# Show banner first
853904
show_banner()
@@ -1056,6 +1107,14 @@ def init(
10561107

10571108
# Ensure scripts are executable (POSIX)
10581109
ensure_executable_scripts(project_path, tracker=tracker)
1110+
ensure_gateway_config(
1111+
project_path,
1112+
selected_ai,
1113+
tracker=tracker,
1114+
gateway_url=gateway_url,
1115+
gateway_token=gateway_token,
1116+
suppress_warning=gateway_suppress_warning,
1117+
)
10591118

10601119
if team_ai_directives and team_ai_directives.strip():
10611120
tracker.start("directives", "syncing")

0 commit comments

Comments
 (0)