Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions docker-compose.api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
1 change: 1 addition & 0 deletions packages/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
14 changes: 14 additions & 0 deletions packages/app/tests/docker-git/entrypoint-auth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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. Сам агент обязан выполнять финальную проверку, интеграцию и валидацию результата перед ответом пользователю.\""
)
Expand Down
11 changes: 9 additions & 2 deletions packages/lib/src/core/templates-entrypoint/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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`

Expand Down
5 changes: 4 additions & 1 deletion packages/lib/src/core/templates-entrypoint/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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-##')"
Expand Down Expand Up @@ -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 внутри проекта, ты обязан их читать и соблюдать инструкции.
<!-- /docker-git-managed:claude-md -->
Expand Down
12 changes: 12 additions & 0 deletions packages/lib/src/core/templates-entrypoint/codex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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=""
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
8 changes: 8 additions & 0 deletions packages/lib/src/core/templates-entrypoint/gemini.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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=""
Expand Down Expand Up @@ -272,6 +278,8 @@ cat <<EOF > "$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 внутри проекта, ты обязан их читать и соблюдать инструкции.
<!-- /docker-git-managed:gemini-md -->
Expand Down
21 changes: 21 additions & 0 deletions packages/lib/tests/core/templates.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { readFileSync } from "node:fs"

Check failure on line 1 in packages/lib/tests/core/templates.test.ts

View workflow job for this annotation

GitHub Actions / Lint Effect-TS

'node:fs' import is restricted from being used by a pattern. Do not import from node:* directly. Use @effect/platform-node or @effect/platform services

Check failure on line 1 in packages/lib/tests/core/templates.test.ts

View workflow job for this annotation

GitHub Actions / Lint Effect-TS

'node:fs' import is restricted from being used. Use @effect/platform FileSystem instead of node:fs
import { describe, expect, it } from "@effect/vitest"

import { defaultTemplateConfig, type TemplateConfig } from "../../src/core/domain.js"
Expand Down Expand Up @@ -46,6 +47,17 @@
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", () => {
Expand Down Expand Up @@ -109,4 +121,13 @@
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:-}")
})
})
Loading