Skip to content

Commit 328b9a7

Browse files
committed
Respect agent-specific project rules
1 parent 8e5d328 commit 328b9a7

7 files changed

Lines changed: 84 additions & 7 deletions

File tree

packages/app/tests/docker-git/entrypoint-auth.test.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,22 @@ describe("renderEntrypoint auth bridge", () => {
8181
expect(entrypoint).toContain("docker-git-managed:claude-md")
8282
expect(entrypoint).toContain("docker_git_sync_project_codex_skills()")
8383
expect(entrypoint).toContain('project_skills_root="$codex_home/skills/.docker-git-project"')
84+
expect(entrypoint).toContain("docker_git_prepare_active_agent_project_rules()")
85+
expect(entrypoint).toContain('docker_git_detect_claude_project_rules()')
86+
expect(entrypoint).toContain('docker_git_detect_gemini_project_rules()')
87+
expect(entrypoint).toContain('"codex")')
88+
expect(entrypoint).toContain('"claude")')
89+
expect(entrypoint).toContain('"gemini")')
8490
expect(entrypoint).toContain('"20-agents-skills::.agents/skills"')
8591
expect(entrypoint).toContain('"30-agents-dot-skills::.agents/.skills"')
8692
expect(entrypoint).toContain('"80-codex-skills::.codex/skills"')
8793
expect(entrypoint).toContain('"90-codex-dot-skills::.codex/.skills"')
88-
expect(entrypoint).toContain('docker_git_sync_project_codex_skills')
94+
expect(entrypoint).not.toContain('"40-claude-skills::.claude/skills"')
95+
expect(entrypoint).toContain('$project_dir/.claude/settings.json')
96+
expect(entrypoint).toContain('$project_dir/.claude/agents')
97+
expect(entrypoint).toContain('$project_dir/.gemini/settings.json')
98+
expect(entrypoint).toContain('$project_dir/.gemini/commands')
99+
expect(entrypoint).toContain('$project_dir/.gemini/skills')
89100
expect(entrypoint).toContain(
90101
"SUBAGENTS_LINE=\"Для решения задач обязательно используй subagents. Сам агент обязан выполнять финальную проверку, интеграцию и валидацию результата перед ответом пользователю.\""
91102
)

packages/lib/src/core/templates-entrypoint.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { renderEntrypointGeminiConfig } from "./templates-entrypoint/gemini.js"
2525
import { renderEntrypointGitConfig, renderEntrypointGitHooks } from "./templates-entrypoint/git.js"
2626
import { renderEntrypointDockerGitBootstrap } from "./templates-entrypoint/nested-docker-git.js"
2727
import { renderEntrypointOpenCodeConfig } from "./templates-entrypoint/opencode.js"
28+
import { renderEntrypointProjectAgentRules } from "./templates-entrypoint/project-rules.js"
2829
import { renderEntrypointBackgroundTasks } from "./templates-entrypoint/tasks.js"
2930
import {
3031
renderEntrypointBashCompletion,
@@ -53,6 +54,7 @@ export const renderEntrypoint = (config: TemplateConfig): string =>
5354
renderEntrypointZshConfig(),
5455
renderEntrypointCodexResumeHint(config),
5556
renderEntrypointProjectCodexSkillsSync(config),
57+
renderEntrypointProjectAgentRules(),
5658
renderEntrypointAgentsNotice(config),
5759
renderEntrypointDockerSocket(config),
5860
renderEntrypointGitConfig(config),

packages/lib/src/core/templates-entrypoint/codex.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,13 +139,11 @@ docker_git_sync_project_codex_skills() {
139139
rm -rf "$project_skills_root"
140140
mkdir -p "$project_skills_root"
141141
142-
# Priority goes from generic -> shared agent dirs -> agent-specific Codex dirs.
142+
# Priority goes from generic/shared skill trees -> Codex-specific trees.
143143
for spec in \
144144
"10-root-skills::.skills" \
145145
"20-agents-skills::.agents/skills" \
146146
"30-agents-dot-skills::.agents/.skills" \
147-
"40-claude-skills::.claude/skills" \
148-
"50-claude-dot-skills::.claude/.skills" \
149147
"80-codex-skills::.codex/skills" \
150148
"90-codex-dot-skills::.codex/.skills"; do
151149
mount_name="${"$"}{spec%%::*}"
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// CHANGE: separate project rule preparation by active agent mode
2+
// WHY: Codex, Claude Code, and Gemini CLI each have different native project-level config models
3+
// REF: issue-207
4+
// PURITY: CORE
5+
// INVARIANT: Codex gets a bridge for skills that live outside CODEX_HOME; Claude/Gemini stay on native project-local discovery
6+
// COMPLEXITY: O(1)
7+
const entrypointProjectAgentRulesTemplate = String.raw`# Prepare project-local rules using each agent's native conventions.
8+
docker_git_detect_claude_project_rules() {
9+
local project_dir="${"$"}{TARGET_DIR:-}"
10+
11+
if [[ -z "$project_dir" || ! -d "$project_dir" ]]; then
12+
return 0
13+
fi
14+
15+
if [[ -f "$project_dir/CLAUDE.md" \
16+
|| -f "$project_dir/.claude/CLAUDE.md" \
17+
|| -f "$project_dir/.claude/settings.json" \
18+
|| -d "$project_dir/.claude/agents" \
19+
|| -f "$project_dir/.mcp.json" ]]; then
20+
echo "[claude] project-local Claude rules available in $project_dir"
21+
fi
22+
}
23+
24+
docker_git_detect_gemini_project_rules() {
25+
local project_dir="${"$"}{TARGET_DIR:-}"
26+
27+
if [[ -z "$project_dir" || ! -d "$project_dir" ]]; then
28+
return 0
29+
fi
30+
31+
if [[ -f "$project_dir/GEMINI.md" \
32+
|| -f "$project_dir/.gemini/settings.json" \
33+
|| -d "$project_dir/.gemini/commands" \
34+
|| -d "$project_dir/.gemini/skills" \
35+
|| -d "$project_dir/.agents/skills" ]]; then
36+
echo "[gemini] project-local Gemini rules available in $project_dir"
37+
fi
38+
}
39+
40+
docker_git_prepare_active_agent_project_rules() {
41+
case "$AGENT_MODE" in
42+
"codex")
43+
docker_git_sync_project_codex_skills
44+
;;
45+
"claude")
46+
docker_git_detect_claude_project_rules
47+
;;
48+
"gemini")
49+
docker_git_detect_gemini_project_rules
50+
;;
51+
*)
52+
docker_git_sync_project_codex_skills
53+
docker_git_detect_claude_project_rules
54+
docker_git_detect_gemini_project_rules
55+
;;
56+
esac
57+
}`
58+
59+
export const renderEntrypointProjectAgentRules = (): string => entrypointProjectAgentRulesTemplate

packages/lib/src/core/templates-entrypoint/tasks.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ ${renderEntrypointAutoUpdate()}
222222
${renderEntrypointClone(config)}
223223
224224
if [[ "$CLONE_OK" -eq 1 ]]; then
225-
docker_git_sync_project_codex_skills
225+
docker_git_prepare_active_agent_project_rules
226226
fi
227227
228228
${renderAgentLaunch(config)}

packages/lib/tests/usecases/apply.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,9 @@ describe("applyProjectFiles", () => {
154154
expect(composeAfter).toContain('mem_limit: "')
155155

156156
const entrypointAfter = yield* _(fs.readFileString(path.join(outDir, "entrypoint.sh")))
157-
expect(entrypointAfter).toContain("docker_git_sync_project_codex_skills()")
157+
expect(entrypointAfter).toContain("docker_git_prepare_active_agent_project_rules()")
158158
expect(entrypointAfter).toContain('"20-agents-skills::.agents/skills"')
159+
expect(entrypointAfter).toContain('$project_dir/.claude/settings.json')
159160

160161
const configAfter = yield* _(fs.readFileString(configPath))
161162
expect(configAfter).toContain('"cpuLimit": "30%"')

packages/lib/tests/usecases/prepare-files.test.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,9 +177,13 @@ describe("prepareProjectFiles", () => {
177177
expect(entrypoint).not.toContain("codex --approval-mode full-auto")
178178
expect(entrypoint).toContain("docker_git_sync_project_codex_skills()")
179179
expect(entrypoint).toContain('project_skills_root="$codex_home/skills/.docker-git-project"')
180+
expect(entrypoint).toContain("docker_git_prepare_active_agent_project_rules()")
180181
expect(entrypoint).toContain('"10-root-skills::.skills"')
181182
expect(entrypoint).toContain('"20-agents-skills::.agents/skills"')
182183
expect(entrypoint).toContain('"90-codex-dot-skills::.codex/.skills"')
184+
expect(entrypoint).not.toContain('"40-claude-skills::.claude/skills"')
185+
expect(entrypoint).toContain('$project_dir/.claude/settings.json')
186+
expect(entrypoint).toContain('$project_dir/.gemini/settings.json')
183187
expect(entrypoint).toContain("docker_git_repair_dns() {")
184188
expect(entrypoint).toContain('local test_domain="github.com"')
185189
expect(entrypoint).toContain('local fallback_dns="8.8.8.8 8.8.4.4 1.1.1.1"')
@@ -191,7 +195,9 @@ describe("prepareProjectFiles", () => {
191195
expect(entrypoint).toContain("cat > \"$MOVE_SCRIPT\" << 'EOFMOVE'")
192196
expect(entrypoint).toMatch(/\nEOFMOVE\n\s*chmod \+x "\$MOVE_SCRIPT"/)
193197
expect(entrypoint).not.toContain("\n EOFMOVE\n")
194-
expect(entrypoint).toContain("if [[ \"$CLONE_OK\" -eq 1 ]]; then\n docker_git_sync_project_codex_skills\nfi")
198+
expect(entrypoint).toContain(
199+
"if [[ \"$CLONE_OK\" -eq 1 ]]; then\n docker_git_prepare_active_agent_project_rules\nfi"
200+
)
195201
expect(composeBefore).toContain("container_name: dg-test")
196202
expect(composeBefore).toContain("restart: unless-stopped")
197203
expect(composeBefore).toContain(":/home/dev/.docker-git")

0 commit comments

Comments
 (0)