343 lines
8.9 KiB
Bash
Executable file
343 lines
8.9 KiB
Bash
Executable file
#!/bin/bash
|
|
|
|
# agent-ops/bin/init-agent-ops.sh
|
|
# 프로젝트에 agent-ops 스캐폴드를 초기화하는 스크립트
|
|
|
|
set -e
|
|
|
|
SCRIPT_DIR=$(realpath "$(dirname "$0")")
|
|
SOURCE_DIR=$(realpath "$SCRIPT_DIR/..")
|
|
source "$SCRIPT_DIR/entry-files.sh"
|
|
source "$SCRIPT_DIR/ai-ignore.sh"
|
|
|
|
if [ -z "$1" ]; then
|
|
echo "Usage: $0 <target_directory>"
|
|
exit 1
|
|
fi
|
|
|
|
TARGET_DIR=$(realpath "$1")
|
|
|
|
create_project_agent_ops_dirs() {
|
|
local agent_ops_dir="$1"
|
|
|
|
mkdir -p "$agent_ops_dir/rules/project/domain"
|
|
mkdir -p "$agent_ops_dir/rules/private"
|
|
mkdir -p "$agent_ops_dir/skills/project"
|
|
}
|
|
|
|
copy_common_agent_ops() {
|
|
local source_dir="$1"
|
|
local target_agent_ops_dir="$2"
|
|
|
|
mkdir -p "$target_agent_ops_dir/rules"
|
|
mkdir -p "$target_agent_ops_dir/skills"
|
|
|
|
cp "$source_dir/.version" "$target_agent_ops_dir/"
|
|
rm -rf "$target_agent_ops_dir/bin"
|
|
rm -rf "$target_agent_ops_dir/rules/common"
|
|
rm -rf "$target_agent_ops_dir/skills/common"
|
|
cp -r "$source_dir/bin" "$target_agent_ops_dir/"
|
|
cp -r "$source_dir/rules/common" "$target_agent_ops_dir/rules/"
|
|
cp -r "$source_dir/skills/common" "$target_agent_ops_dir/skills/"
|
|
}
|
|
|
|
ensure_common_rules_file() {
|
|
local source_dir="$1"
|
|
local target_agent_ops_dir="$2"
|
|
local source_rules="$source_dir/rules/common/rules.md"
|
|
local target_rules="$target_agent_ops_dir/rules/common/rules.md"
|
|
|
|
if [ ! -f "$source_rules" ]; then
|
|
echo "Error: common rules file not found: $source_rules" >&2
|
|
exit 1
|
|
fi
|
|
|
|
mkdir -p "$(dirname "$target_rules")"
|
|
cp "$source_rules" "$target_rules"
|
|
}
|
|
|
|
ensure_gitignore_entry() {
|
|
local gitignore_file="$1"
|
|
local entry="$2"
|
|
|
|
if ! grep -qxF "$entry" "$gitignore_file"; then
|
|
printf '%s\n' "$entry" >> "$gitignore_file"
|
|
fi
|
|
}
|
|
|
|
discover_agent_test_domains() {
|
|
local target_dir="$1"
|
|
local domain_root="$target_dir/agent-ops/rules/project/domain"
|
|
local project_rules="$target_dir/agent-ops/rules/project/rules.md"
|
|
|
|
if [ -d "$domain_root" ]; then
|
|
find "$domain_root" -mindepth 2 -maxdepth 2 -name rules.md -print \
|
|
| while IFS= read -r rule_file; do
|
|
basename "$(dirname "$rule_file")"
|
|
done
|
|
fi
|
|
|
|
if [ -f "$project_rules" ]; then
|
|
grep -Eo 'agent-ops/rules/project/domain/[^/`[:space:]]+/rules\.md' "$project_rules" \
|
|
| awk -F/ '{ print $(NF-1) }'
|
|
fi
|
|
}
|
|
|
|
ensure_agent_test_route() {
|
|
local rules_file="$1"
|
|
local route_line="$2"
|
|
local placeholder="- 현재 등록된 도메인/검증 시나리오별 테스트 문서 없음."
|
|
local tmp
|
|
|
|
if grep -qxF -- "$route_line" "$rules_file"; then
|
|
return
|
|
fi
|
|
|
|
tmp="$(mktemp "$rules_file.tmp.XXXXXX")"
|
|
if grep -qxF -- "$placeholder" "$rules_file"; then
|
|
awk -v placeholder="$placeholder" -v route_line="$route_line" '
|
|
$0 == placeholder { print route_line; next }
|
|
{ print }
|
|
' "$rules_file" > "$tmp"
|
|
else
|
|
awk -v route_line="$route_line" '
|
|
BEGIN { added = 0 }
|
|
{ print }
|
|
!added && $0 == "## 라우팅" {
|
|
print ""
|
|
print route_line
|
|
added = 1
|
|
}
|
|
END {
|
|
if (!added) {
|
|
print ""
|
|
print "## 라우팅"
|
|
print ""
|
|
print route_line
|
|
}
|
|
}
|
|
' "$rules_file" > "$tmp"
|
|
fi
|
|
mv "$tmp" "$rules_file"
|
|
}
|
|
|
|
ensure_agent_test_profile() {
|
|
local target_dir="$1"
|
|
local env="$2"
|
|
local profile="$3"
|
|
local domain="$4"
|
|
local verification_type="$5"
|
|
local scope="$6"
|
|
local today="$7"
|
|
local profile_file="$target_dir/agent-test/$env/$profile.md"
|
|
local rules_file="$target_dir/agent-test/$env/rules.md"
|
|
local route_line
|
|
|
|
mkdir -p "$(dirname "$profile_file")"
|
|
|
|
if [ ! -f "$profile_file" ]; then
|
|
cat > "$profile_file" <<EOF
|
|
---
|
|
test_env: $env
|
|
test_profile: $profile
|
|
domain: $domain
|
|
verification_type: $verification_type
|
|
last_rule_updated_at: $today
|
|
---
|
|
|
|
# $profile $env 테스트
|
|
|
|
## 읽기 조건
|
|
|
|
- $domain 도메인 또는 $scope 검증 기준이 필요한 경우
|
|
|
|
## 적용 범위
|
|
|
|
- <확인 필요>
|
|
|
|
## 분류
|
|
|
|
- domain: $domain
|
|
- verification_type: $verification_type
|
|
- scope: $scope
|
|
|
|
## 환경
|
|
|
|
- host:
|
|
- port:
|
|
- runtime:
|
|
- package manager:
|
|
- docker:
|
|
- external service:
|
|
- model endpoint:
|
|
- credential:
|
|
|
|
## 명령
|
|
|
|
- setup:
|
|
- lint:
|
|
- unit:
|
|
- smoke:
|
|
- e2e:
|
|
- model:
|
|
- full-cycle:
|
|
|
|
## 필수 검증
|
|
|
|
- <확인 필요>
|
|
|
|
## 보조 검증
|
|
|
|
- <확인 필요>
|
|
|
|
## 판정 기준
|
|
|
|
- <확인 필요>
|
|
|
|
## 기준 출력 예시
|
|
|
|
\`\`\`text
|
|
<필요한 경우 기대 출력 예시>
|
|
\`\`\`
|
|
|
|
## 차단 기준
|
|
|
|
- <확인 필요>
|
|
|
|
## 보고 항목
|
|
|
|
- 실행한 명령:
|
|
- 성공한 검증:
|
|
- 실패/차단된 검증:
|
|
- 생략 사유:
|
|
- 남은 위험:
|
|
|
|
## 금지 사항
|
|
|
|
- 확인되지 않은 host, port, token, endpoint를 추측해 쓰지 않는다.
|
|
- secret, token, 개인 endpoint 원문은 tracked 파일에 기록하지 않는다.
|
|
EOF
|
|
fi
|
|
|
|
route_line="- $domain / $verification_type / $scope: \`agent-test/$env/$profile.md\`"
|
|
ensure_agent_test_route "$rules_file" "$route_line"
|
|
}
|
|
|
|
ensure_agent_test_local() {
|
|
local target_dir="$1"
|
|
local local_rules="$target_dir/agent-test/local/rules.md"
|
|
local today
|
|
local domain
|
|
local created_domain_profile="0"
|
|
|
|
today="$(date +%F)"
|
|
mkdir -p "$(dirname "$local_rules")"
|
|
mkdir -p "$target_dir/agent-test/runs"
|
|
|
|
if [ ! -f "$local_rules" ]; then
|
|
cat > "$local_rules" <<EOF
|
|
---
|
|
test_env: local
|
|
last_rule_updated_at: $today
|
|
---
|
|
|
|
# local 테스트 규칙
|
|
|
|
**현재 문서를 반드시 끝까지 정독하고 작업한다. 다 읽지 않고 즉각 작업은 금지한다.**
|
|
|
|
## 공통 규칙
|
|
|
|
- local 테스트/검증은 이 파일을 기준으로 판단한다.
|
|
- 작업 완료 검증은 변경 범위 기준으로 선택한다.
|
|
- 필수 검증을 실행하지 못하면 차단 사유로 보고한다.
|
|
- 최종 보고에는 실행 명령, 결과, 생략 사유, 남은 위험을 남긴다.
|
|
- 환경값, secret, 개인 endpoint는 tracked docs/roadmap에 쓰지 않는다.
|
|
|
|
## 기본 환경
|
|
|
|
- host:
|
|
- port:
|
|
- runtime:
|
|
- package manager:
|
|
- docker:
|
|
- external service:
|
|
- model endpoint:
|
|
- credential:
|
|
|
|
## 라우팅
|
|
|
|
- 현재 등록된 도메인/검증 시나리오별 테스트 문서 없음.
|
|
|
|
## 라우팅 규칙
|
|
|
|
- 여러 항목이 맞으면 모두 읽는다.
|
|
- 도메인 매핑이나 domain rule이 있으면 각 도메인의 <domain>-smoke 문서를 기본 baseline으로 둔다.
|
|
- 도메인이 아직 없을 때만 project-smoke를 fallback baseline으로 둔다.
|
|
- 도메인/검증 시나리오별 문서는 다른 테스트 문서로 라우팅하지 않는다.
|
|
EOF
|
|
fi
|
|
|
|
while IFS= read -r domain; do
|
|
[ -n "$domain" ] || continue
|
|
created_domain_profile="1"
|
|
ensure_agent_test_profile \
|
|
"$target_dir" \
|
|
"local" \
|
|
"$domain-smoke" \
|
|
"$domain" \
|
|
"smoke" \
|
|
"도메인 기본 smoke 검증" \
|
|
"$today"
|
|
done < <(discover_agent_test_domains "$target_dir" | sort -u)
|
|
|
|
if [ "$created_domain_profile" = "0" ]; then
|
|
ensure_agent_test_profile \
|
|
"$target_dir" \
|
|
"local" \
|
|
"project-smoke" \
|
|
"project-wide" \
|
|
"smoke" \
|
|
"프로젝트 기본 smoke 검증" \
|
|
"$today"
|
|
fi
|
|
}
|
|
|
|
echo "Initializing agent-ops in: $TARGET_DIR"
|
|
echo "Source agent-ops: $SOURCE_DIR"
|
|
|
|
# 1. 대상 폴더 생성 (프로젝트 전용 폴더는 내용 복사 없이 폴더만 생성)
|
|
create_project_agent_ops_dirs "$TARGET_DIR/agent-ops"
|
|
|
|
# 2. 공통 요소 복사 (프로젝트 전용 설정은 제외)
|
|
copy_common_agent_ops "$SOURCE_DIR" "$TARGET_DIR/agent-ops"
|
|
|
|
# 3. 에이전트 진입 파일 생성 (common/rules.md 복사)
|
|
COMMON_RULES="$SOURCE_DIR/rules/common/rules.md"
|
|
apply_agent_ops_entry_files "$COMMON_RULES" "$TARGET_DIR"
|
|
ensure_common_rules_file "$SOURCE_DIR" "$TARGET_DIR/agent-ops"
|
|
|
|
# 4. AI ignore / permission 설정
|
|
ensure_agent_ops_ai_ignore_config "$TARGET_DIR"
|
|
|
|
# 5. .gitignore 설정
|
|
TOUCH_GITIGNORE="$TARGET_DIR/.gitignore"
|
|
touch "$TOUCH_GITIGNORE"
|
|
agent_ops_ensure_gitignore_task_artifact_block "$TOUCH_GITIGNORE"
|
|
if ! grep -q "agent-ops/rules/private/" "$TOUCH_GITIGNORE"; then
|
|
echo "" >> "$TOUCH_GITIGNORE"
|
|
echo "# Agent-Ops Private Rules" >> "$TOUCH_GITIGNORE"
|
|
echo "agent-ops/rules/private/" >> "$TOUCH_GITIGNORE"
|
|
fi
|
|
if ! grep -qxF "# Agent-Test Local Environment" "$TOUCH_GITIGNORE"; then
|
|
echo "" >> "$TOUCH_GITIGNORE"
|
|
echo "# Agent-Test Local Environment" >> "$TOUCH_GITIGNORE"
|
|
fi
|
|
ensure_gitignore_entry "$TOUCH_GITIGNORE" "agent-test/local/"
|
|
ensure_gitignore_entry "$TOUCH_GITIGNORE" "agent-test/runs/"
|
|
|
|
# 6. local 테스트 환경 생성
|
|
ensure_agent_test_local "$TARGET_DIR"
|
|
|
|
echo "Successfully initialized agent-ops in $TARGET_DIR"
|
|
echo "Note: agent-ops/rules/project and agent-ops/skills/project are initialized as empty."
|
|
echo "Note: agent-test/local rules and baseline test profiles are initialized and ignored by git."
|