From ca250b8d6b76bdb0f6e9688558b7892d7ef2b958 Mon Sep 17 00:00:00 2001 From: skulidropek <66840575+skulidropek@users.noreply.github.com> Date: Wed, 25 Mar 2026 22:49:42 +0000 Subject: [PATCH] feat(core): use public api url in managed prompts --- docker-compose.api.yml | 1 + packages/api/README.md | 1 + .../tests/docker-git/entrypoint-auth.test.ts | 14 +++++++++++++ .../src/core/templates-entrypoint/agent.ts | 11 ++++++++-- .../lib/src/core/templates-entrypoint/base.ts | 5 ++++- .../claude-extra-config.ts | 9 ++++++++ .../src/core/templates-entrypoint/codex.ts | 12 +++++++++++ .../src/core/templates-entrypoint/gemini.ts | 8 +++++++ packages/lib/tests/core/templates.test.ts | 21 +++++++++++++++++++ 9 files changed, 79 insertions(+), 3 deletions(-) diff --git a/docker-compose.api.yml b/docker-compose.api.yml index 4f68d18e..82fb15b3 100644 --- a/docker-compose.api.yml +++ b/docker-compose.api.yml @@ -6,6 +6,7 @@ services: container_name: docker-git-api environment: DOCKER_GIT_API_PORT: ${DOCKER_GIT_API_PORT:-3334} + DOCKER_GIT_API_PUBLIC_URL: ${DOCKER_GIT_API_PUBLIC_URL:-} DOCKER_GIT_PROJECTS_ROOT: ${DOCKER_GIT_PROJECTS_ROOT:-/home/dev/.docker-git} DOCKER_GIT_FEDERATION_PUBLIC_ORIGIN: ${DOCKER_GIT_FEDERATION_PUBLIC_ORIGIN:-} DOCKER_GIT_FEDERATION_ACTOR: ${DOCKER_GIT_FEDERATION_ACTOR:-docker-git} diff --git a/packages/api/README.md b/packages/api/README.md index 1875623a..1770292d 100644 --- a/packages/api/README.md +++ b/packages/api/README.md @@ -35,6 +35,7 @@ Optional env: - `DOCKER_GIT_API_BIND_HOST` (default: `127.0.0.1`) - `DOCKER_GIT_API_PORT` (default: `3334`) +- `DOCKER_GIT_API_PUBLIC_URL` (optional public base URL for prompts and externally visible API links) - `DOCKER_GIT_PROJECTS_ROOT_HOST` (host path with docker-git projects, default: `/home/dev/.docker-git`) - `DOCKER_GIT_PROJECTS_ROOT` (container path, default: `/home/dev/.docker-git`) - `DOCKER_GIT_FEDERATION_PUBLIC_ORIGIN` (optional public ActivityPub origin) diff --git a/packages/app/tests/docker-git/entrypoint-auth.test.ts b/packages/app/tests/docker-git/entrypoint-auth.test.ts index d863bcb7..e1afae3d 100644 --- a/packages/app/tests/docker-git/entrypoint-auth.test.ts +++ b/packages/app/tests/docker-git/entrypoint-auth.test.ts @@ -79,6 +79,20 @@ describe("renderEntrypoint auth bridge", () => { expect(entrypoint).toContain("CLAUDE_GLOBAL_PROMPT_FILE=\"/home/dev/.claude/CLAUDE.md\"") expect(entrypoint).toContain("CLAUDE_AUTO_SYSTEM_PROMPT=\"${CLAUDE_AUTO_SYSTEM_PROMPT:-1}\"") expect(entrypoint).toContain("docker-git-managed:claude-md") + expect(entrypoint).toContain("DOCKER_GIT_API_PUBLIC_URL=\"${DOCKER_GIT_API_PUBLIC_URL:-}\"") + expect(entrypoint).toContain( + "docker_git_upsert_ssh_env \"DOCKER_GIT_API_PUBLIC_URL\" \"$DOCKER_GIT_API_PUBLIC_URL\"" + ) + expect(entrypoint).toContain( + "PUBLIC_API_USAGE_LINE=\"Если пользователь просит ссылку на docker-git API или просит выполнить API-вызов, используй только публичный API адрес выше. Никогда не подставляй localhost/127.0.0.1.\"" + ) + expect(entrypoint).toContain("Публичный API docker-git: не задан.") + expect(entrypoint).toContain( + "AGENT_API_PROMPT=\" When mentioning or calling the docker-git API, use the public URL $DOCKER_GIT_API_PUBLIC_URL and never localhost/127.0.0.1.\"" + ) + expect(entrypoint).toContain( + "AGENT_API_PROMPT=\" Do not invent localhost/127.0.0.1 links for the docker-git API.\"" + ) expect(entrypoint).toContain( "SUBAGENTS_LINE=\"Для решения задач обязательно используй subagents. Сам агент обязан выполнять финальную проверку, интеграцию и валидацию результата перед ответом пользователю.\"" ) diff --git a/packages/lib/src/core/templates-entrypoint/agent.ts b/packages/lib/src/core/templates-entrypoint/agent.ts index aa748ce8..5c23a454 100644 --- a/packages/lib/src/core/templates-entrypoint/agent.ts +++ b/packages/lib/src/core/templates-entrypoint/agent.ts @@ -14,16 +14,23 @@ const indentBlock = (block: string, size = 2): string => { const renderAgentPrompt = (): string => String.raw`AGENT_PROMPT="" +AGENT_API_PROMPT="" ISSUE_NUM="" if [[ "$REPO_REF" =~ ^issue-([0-9]+)$ ]]; then ISSUE_NUM="${"${"}BASH_REMATCH[1]}" fi +if [[ -n "${"$"}{DOCKER_GIT_API_PUBLIC_URL:-}" ]]; then + AGENT_API_PROMPT=" When mentioning or calling the docker-git API, use the public URL ${"$"}DOCKER_GIT_API_PUBLIC_URL and never localhost/127.0.0.1." +else + AGENT_API_PROMPT=" Do not invent localhost/127.0.0.1 links for the docker-git API." +fi + if [[ "$AGENT_AUTO" == "1" ]]; then if [[ -n "$ISSUE_NUM" ]]; then - AGENT_PROMPT="Read GitHub issue #$ISSUE_NUM for this repository (use gh issue view $ISSUE_NUM). Implement the requested changes, commit them, create a PR that closes #$ISSUE_NUM, and push it." + AGENT_PROMPT="Read GitHub issue #$ISSUE_NUM for this repository (use gh issue view $ISSUE_NUM). Implement the requested changes, commit them, create a PR that closes #$ISSUE_NUM, and push it.$AGENT_API_PROMPT" else - AGENT_PROMPT="Analyze this repository, implement any pending tasks, commit changes, create a PR, and push it." + AGENT_PROMPT="Analyze this repository, implement any pending tasks, commit changes, create a PR, and push it.$AGENT_API_PROMPT" fi fi` diff --git a/packages/lib/src/core/templates-entrypoint/base.ts b/packages/lib/src/core/templates-entrypoint/base.ts index 9b3f7a8f..9d31f781 100644 --- a/packages/lib/src/core/templates-entrypoint/base.ts +++ b/packages/lib/src/core/templates-entrypoint/base.ts @@ -26,6 +26,7 @@ GIT_USER_EMAIL="\${GIT_USER_EMAIL:-}" CODEX_AUTO_UPDATE="\${CODEX_AUTO_UPDATE:-1}" AGENT_MODE="\${AGENT_MODE:-}" AGENT_AUTO="\${AGENT_AUTO:-}" +DOCKER_GIT_API_PUBLIC_URL="\${DOCKER_GIT_API_PUBLIC_URL:-}" MCP_PLAYWRIGHT_ENABLE="\${MCP_PLAYWRIGHT_ENABLE:-${config.enableMcpPlaywright ? "1" : "0"}}" MCP_PLAYWRIGHT_CDP_ENDPOINT="\${MCP_PLAYWRIGHT_CDP_ENDPOINT:-}" MCP_PLAYWRIGHT_ISOLATED="\${MCP_PLAYWRIGHT_ISOLATED:-1}" @@ -49,7 +50,9 @@ docker_git_upsert_ssh_env() { printf "%s\n" "$key=$value" >> "$SSH_ENV_PATH" chmod 600 "$SSH_ENV_PATH" || true chown 1000:1000 "$SSH_ENV_PATH" || true -}` +} + +docker_git_upsert_ssh_env "DOCKER_GIT_API_PUBLIC_URL" "$DOCKER_GIT_API_PUBLIC_URL"` export const renderEntrypointPackageCache = (config: TemplateConfig): string => `# Share package manager caches across all docker-git containers diff --git a/packages/lib/src/core/templates-entrypoint/claude-extra-config.ts b/packages/lib/src/core/templates-entrypoint/claude-extra-config.ts index e376aa66..a9cc325b 100644 --- a/packages/lib/src/core/templates-entrypoint/claude-extra-config.ts +++ b/packages/lib/src/core/templates-entrypoint/claude-extra-config.ts @@ -7,6 +7,13 @@ CLAUDE_AUTO_SYSTEM_PROMPT="${"$"}{CLAUDE_AUTO_SYSTEM_PROMPT:-1}" CLAUDE_WORKSPACE_CONTEXT="Контекст workspace: repository" REPO_REF_VALUE="${"$"}{REPO_REF:-__REPO_REF_DEFAULT__}" REPO_URL_VALUE="${"$"}{REPO_URL:-__REPO_URL_DEFAULT__}" +CLAUDE_PUBLIC_API_URL_VALUE="${"$"}{DOCKER_GIT_API_PUBLIC_URL:-}" +CLAUDE_PUBLIC_API_LINE="Публичный API docker-git: не задан." +CLAUDE_PUBLIC_API_USAGE_LINE="Если пользователь просит ссылку на docker-git API или просит выполнить API-вызов, используй только публичный API адрес выше. Никогда не подставляй localhost/127.0.0.1." + +if [[ -n "$CLAUDE_PUBLIC_API_URL_VALUE" ]]; then + CLAUDE_PUBLIC_API_LINE="Публичный API docker-git: $CLAUDE_PUBLIC_API_URL_VALUE" +fi if [[ "$REPO_REF_VALUE" == issue-* ]]; then ISSUE_ID_VALUE="$(printf "%s" "$REPO_REF_VALUE" | sed -E 's#^issue-##')" @@ -52,6 +59,8 @@ if [[ "$CLAUDE_AUTO_SYSTEM_PROMPT" == "1" ]]; then $CLAUDE_WORKSPACE_CONTEXT Фокус задачи: работай только в workspace, который запрашивает пользователь. Текущий workspace: __TARGET_DIR__ Доступ к интернету: есть. Если чего-то не знаешь — ищи в интернете или по кодовой базе. +$CLAUDE_PUBLIC_API_LINE +$CLAUDE_PUBLIC_API_USAGE_LINE Для решения задач обязательно используй subagents. Сам агент обязан выполнять финальную проверку, интеграцию и валидацию результата перед ответом пользователю. Если ты видишь файлы AGENTS.md или CLAUDE.md внутри проекта, ты обязан их читать и соблюдать инструкции. diff --git a/packages/lib/src/core/templates-entrypoint/codex.ts b/packages/lib/src/core/templates-entrypoint/codex.ts index a2b3b932..bbfe6e3b 100644 --- a/packages/lib/src/core/templates-entrypoint/codex.ts +++ b/packages/lib/src/core/templates-entrypoint/codex.ts @@ -129,7 +129,13 @@ WORKSPACES_LINE="Доступные workspace пути: __TARGET_DIR__" WORKSPACE_INFO_LINE="Контекст workspace: repository" FOCUS_LINE="Фокус задачи: работай только в workspace, который запрашивает пользователь. Текущий workspace: __TARGET_DIR__" INTERNET_LINE="Доступ к интернету: есть. Если чего-то не знаешь — ищи в интернете или по кодовой базе." +PUBLIC_API_URL_VALUE="${"$"}{DOCKER_GIT_API_PUBLIC_URL:-}" +PUBLIC_API_LINE="Публичный API docker-git: не задан." +PUBLIC_API_USAGE_LINE="Если пользователь просит ссылку на docker-git API или просит выполнить API-вызов, используй только публичный API адрес выше. Никогда не подставляй localhost/127.0.0.1." SUBAGENTS_LINE="Для решения задач обязательно используй subagents. Сам агент обязан выполнять финальную проверку, интеграцию и валидацию результата перед ответом пользователю." +if [[ -n "$PUBLIC_API_URL_VALUE" ]]; then + PUBLIC_API_LINE="Публичный API docker-git: $PUBLIC_API_URL_VALUE" +fi if [[ "$REPO_REF" == issue-* ]]; then ISSUE_ID="$(printf "%s" "$REPO_REF" | sed -E 's#^issue-##')" ISSUE_URL="" @@ -171,6 +177,8 @@ $WORKSPACES_LINE $WORKSPACE_INFO_LINE $FOCUS_LINE $INTERNET_LINE +$PUBLIC_API_LINE +$PUBLIC_API_USAGE_LINE $SUBAGENTS_LINE $MANAGED_END EOF @@ -190,6 +198,8 @@ $WORKSPACES_LINE $WORKSPACE_INFO_LINE $FOCUS_LINE $INTERNET_LINE +$PUBLIC_API_LINE +$PUBLIC_API_USAGE_LINE $SUBAGENTS_LINE $MANAGED_END EOF @@ -210,6 +220,8 @@ EOF -e '/^Фокус задачи:/d' \ -e '/^Issue AGENTS.md:/d' \ -e '/^Доступ к интернету:/d' \ + -e '/^Публичный API docker-git:/d' \ + -e '/^Если пользователь просит ссылку на docker-git API или просит выполнить API-вызов,/d' \ -e '/^Для решения задач обязательно используй subagents[.]/d' \ "$AGENTS_PATH" > "$TMP_AGENTS_PATH" if [[ -s "$TMP_AGENTS_PATH" ]]; then diff --git a/packages/lib/src/core/templates-entrypoint/gemini.ts b/packages/lib/src/core/templates-entrypoint/gemini.ts index b7a6f8a0..2bbb06ee 100644 --- a/packages/lib/src/core/templates-entrypoint/gemini.ts +++ b/packages/lib/src/core/templates-entrypoint/gemini.ts @@ -232,6 +232,12 @@ docker_git_upsert_ssh_env "GEMINI_CLI_APPROVAL_MODE" "yolo"` const entrypointGeminiNoticeTemplate = String.raw`# Ensure global GEMINI.md exists for container context GEMINI_MD_PATH="__GEMINI_HOME__/GEMINI.md" GEMINI_WORKSPACE_CONTEXT="Контекст workspace: repository" +GEMINI_PUBLIC_API_URL_VALUE="${"$"}{DOCKER_GIT_API_PUBLIC_URL:-}" +GEMINI_PUBLIC_API_LINE="Публичный API docker-git: не задан." +GEMINI_PUBLIC_API_USAGE_LINE="Если пользователь просит ссылку на docker-git API или просит выполнить API-вызов, используй только публичный API адрес выше. Никогда не подставляй localhost/127.0.0.1." +if [[ -n "$GEMINI_PUBLIC_API_URL_VALUE" ]]; then + GEMINI_PUBLIC_API_LINE="Публичный API docker-git: $GEMINI_PUBLIC_API_URL_VALUE" +fi if [[ "$REPO_REF" == issue-* ]]; then ISSUE_ID="$(printf "%s" "$REPO_REF" | sed -E 's#^issue-##')" ISSUE_URL="" @@ -272,6 +278,8 @@ cat < "$GEMINI_MD_PATH" $GEMINI_WORKSPACE_CONTEXT Фокус задачи: работай только в workspace, который запрашивает пользователь. Текущий workspace: __TARGET_DIR__ Доступ к интернету: есть. Если чего-то не знаешь — ищи в интернете или по кодовой базе. +$GEMINI_PUBLIC_API_LINE +$GEMINI_PUBLIC_API_USAGE_LINE Для решения задач обязательно используй subagents. Сам агент обязан выполнять финальную проверку, интеграцию и валидацию результата перед ответом пользователю. Если ты видишь файлы AGENTS.md, GEMINI.md или CLAUDE.md внутри проекта, ты обязан их читать и соблюдать инструкции. diff --git a/packages/lib/tests/core/templates.test.ts b/packages/lib/tests/core/templates.test.ts index b50d7c51..75c19632 100644 --- a/packages/lib/tests/core/templates.test.ts +++ b/packages/lib/tests/core/templates.test.ts @@ -1,3 +1,4 @@ +import { readFileSync } from "node:fs" import { describe, expect, it } from "@effect/vitest" import { defaultTemplateConfig, type TemplateConfig } from "../../src/core/domain.js" @@ -46,6 +47,17 @@ describe("renderEntrypointDnsRepair", () => { expect(dnsRepairIndex).toBeGreaterThanOrEqual(0) expect(packageCacheIndex).toBeGreaterThan(dnsRepairIndex) }) + + it("renders public API guidance in managed prompts without localhost fallback links", () => { + const entrypoint = renderEntrypoint(makeTemplateConfig()) + + expect(entrypoint).toContain("DOCKER_GIT_API_PUBLIC_URL=\"${DOCKER_GIT_API_PUBLIC_URL:-}\"") + expect(entrypoint).toContain('PUBLIC_API_URL_VALUE="${DOCKER_GIT_API_PUBLIC_URL:-}"') + expect(entrypoint).toContain("Публичный API docker-git: не задан.") + expect(entrypoint).toContain( + "Если пользователь просит ссылку на docker-git API или просит выполнить API-вызов, используй только публичный API адрес выше. Никогда не подставляй localhost/127.0.0.1." + ) + }) }) describe("renderEntrypointGitHooks", () => { @@ -109,4 +121,13 @@ describe("renderDockerCompose", () => { expect(browserDnsIndex).toBeGreaterThan(browserServiceIndex) expect((compose.match(/\n dns:\n/g) ?? []).length).toBe(2) }) + + it("passes through the public API URL to the api compose service", () => { + const apiCompose = readFileSync( + new URL("../../../../docker-compose.api.yml", import.meta.url), + "utf8" + ) + + expect(apiCompose).toContain("DOCKER_GIT_API_PUBLIC_URL: ${DOCKER_GIT_API_PUBLIC_URL:-}") + }) })