Compare commits

...

10 commits

10 changed files with 450 additions and 8 deletions

View file

@ -1 +1 @@
1.1.1
1.1.7

28
agent-ops/bin/bump-version.sh Executable file
View file

@ -0,0 +1,28 @@
#!/usr/bin/env bash
# bump-version.sh <version>
# patch +1, 999 초과 시 minor 올림. major는 수동 관리.
# 결과 버전을 stdout으로 출력.
set -euo pipefail
YELLOW='\033[1;33m'; RESET='\033[0m'
VERSION="${1:-}"
if [[ -z "$VERSION" ]]; then
echo "사용법: $0 <major.minor.patch>" >&2
exit 1
fi
IFS='.' read -r major minor patch <<< "$VERSION"
patch=$((patch + 1))
if [[ $patch -gt 999 ]]; then
patch=0
minor=$((minor + 1))
fi
if [[ $minor -gt 999 ]]; then
minor=0
echo -e "${YELLOW}⚠ minor 버전이 999를 초과했습니다. major 버전을 수동으로 올려주세요.${RESET}" >&2
fi
echo "$major.$minor.$patch"

47
agent-ops/bin/init-agent-ops.sh Executable file
View file

@ -0,0 +1,47 @@
#!/bin/bash
# agent-ops/bin/init-agent-ops.sh
# 프로젝트에 agent-ops 스캐폴드를 초기화하는 스크립트
set -e
if [ -z "$1" ]; then
echo "Usage: $0 <target_directory>"
exit 1
fi
TARGET_DIR=$(realpath "$1")
SOURCE_DIR=$(realpath "$(dirname "$0")/..")
echo "Initializing agent-ops in: $TARGET_DIR"
echo "Source agent-ops: $SOURCE_DIR"
# 1. 대상 폴더 생성
mkdir -p "$TARGET_DIR/agent-ops/rules/project/domain"
mkdir -p "$TARGET_DIR/agent-ops/rules/private"
mkdir -p "$TARGET_DIR/agent-ops/skills/project"
# 2. 공통 요소 복사 (프로젝트 전용 설정은 제외)
cp "$SOURCE_DIR/.version" "$TARGET_DIR/agent-ops/"
cp -r "$SOURCE_DIR/rules/common" "$TARGET_DIR/agent-ops/rules/"
cp -r "$SOURCE_DIR/skills/common" "$TARGET_DIR/agent-ops/skills/"
# 3. 에이전트 진입 파일 생성 (common/rules.md 복사)
COMMON_RULES="$SOURCE_DIR/rules/common/rules.md"
cp "$COMMON_RULES" "$TARGET_DIR/GEMINI.md"
cp "$COMMON_RULES" "$TARGET_DIR/CLAUDE.md"
cp "$COMMON_RULES" "$TARGET_DIR/AGENTS.md"
cp "$COMMON_RULES" "$TARGET_DIR/.cursorrules"
cp "$COMMON_RULES" "$TARGET_DIR/.clinerules"
# 4. .gitignore 설정
TOUCH_GITIGNORE="$TARGET_DIR/.gitignore"
touch "$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
echo "Successfully initialized agent-ops in $TARGET_DIR"
echo "Note: agent-ops/rules/project and agent-ops/skills/project are initialized as empty."

206
agent-ops/bin/sync.sh Executable file
View file

@ -0,0 +1,206 @@
#!/usr/bin/env bash
set -euo pipefail
# ── 경로 설정 ────────────────────────────────────────────────────────────────
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
AGENT_OPS_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
PROJECT_ROOT="$(cd "$AGENT_OPS_DIR/.." && pwd)"
# ── 색상 ─────────────────────────────────────────────────────────────────────
RED='\033[0;31m'; YELLOW='\033[1;33m'; GREEN='\033[0;32m'; RESET='\033[0m'
# ── 대상 경로 해석 (폴더명 / 상대경로 / 절대경로) ────────────────────────────
resolve_target() {
local input="$1"
if [[ "$input" == /* ]]; then
[[ -d "$input" ]] && echo "$input" || echo ""
return
fi
if [[ "$input" == */* ]]; then
local resolved
resolved="$(cd "$input" 2>/dev/null && pwd)" || { echo ""; return; }
echo "$resolved"
return
fi
local sibling="$(dirname "$PROJECT_ROOT")/$input"
[[ -d "$sibling" ]] && echo "$sibling" || echo ""
}
# ── 버전 비교: v1 > v2 이면 0 반환 ───────────────────────────────────────────
version_gt() {
local v1="$1" v2="$2"
[[ "$v1" == "$v2" ]] && return 1
[[ "$(printf '%s\n%s' "$v1" "$v2" | sort -V | head -1)" == "$v2" ]]
}
# ── 버전 +1 ──────────────────────────────────────────────────────────────────
bump_version() {
bash "$SCRIPT_DIR/bump-version.sh" "$1"
}
# ── 폴더 동기화 (rules.md 제외, 삭제된 파일도 반영) ─────────────────────────
sync_folder() {
local src="$1" dst="$2" exclude="${3:-}"
mkdir -p "$dst"
# dst에서 src에 없는 항목 제거 (exclude 파일 보존)
find "$dst" -mindepth 1 -maxdepth 1 | while IFS= read -r item; do
local name
name="$(basename "$item")"
[[ -n "$exclude" && "$name" == "$exclude" ]] && continue
if [[ ! -e "$src/$name" ]]; then
rm -rf "$item"
fi
done
# src에서 dst로 복사 (exclude 파일 제외)
find "$src" -mindepth 1 -maxdepth 1 | while IFS= read -r item; do
local name
name="$(basename "$item")"
[[ -n "$exclude" && "$name" == "$exclude" ]] && continue
rm -rf "$dst/$name"
cp -r "$item" "$dst/"
done
}
sync_common() {
local src="$1" dst="$2"
sync_folder "$src/rules/common" "$dst/rules/common" "rules.md"
sync_folder "$src/skills/common" "$dst/skills/common"
sync_folder "$src/bin" "$dst/bin"
}
# ── rules.md 내용을 진입 파일들에 반영 ───────────────────────────────────────
apply_entry_files() {
local rules_md="$1"
local target_root="$2"
if [[ ! -f "$rules_md" ]]; then
echo -e "${YELLOW} rules.md 없음, 진입 파일 재적용 건너뜀${RESET}"
return
fi
# 기본 자동 생성/갱신 대상
local default_files=("CLAUDE.md" "GEMINI.md" ".cursorrules" "AGENTS.md")
# 존재할 때만 갱신
local optional_files=(".clinerules")
for f in "${default_files[@]}"; do
cp "$rules_md" "$target_root/$f"
echo " 진입 파일 적용: $f"
done
for f in "${optional_files[@]}"; do
if [[ -f "$target_root/$f" ]]; then
cp "$rules_md" "$target_root/$f"
echo " 진입 파일 적용: $f"
fi
done
}
# ── 사용법 ────────────────────────────────────────────────────────────────────
usage() {
echo "사용법: $0 [--pull] <target>"
echo ""
echo " (기본) 현재 프로젝트 → target(agentic-framework) 으로 push"
echo " --pull target(agentic-framework) → 현재 프로젝트 로 pull"
echo ""
echo " target: 폴더명 (동일 레벨 탐색) | 상대경로 | 절대경로"
}
# ─────────────────────────────────────────────────────────────────────────────
PULL_MODE="0"
if [[ "${1:-}" == "--pull" ]]; then
PULL_MODE="1"
shift
fi
TARGET_INPUT="${1:-}"
if [[ -z "$TARGET_INPUT" ]]; then
usage; exit 1
fi
TARGET="$(resolve_target "$TARGET_INPUT")"
if [[ -z "$TARGET" ]]; then
echo -e "${RED}Error: 대상을 찾을 수 없습니다: $TARGET_INPUT${RESET}"
exit 1
fi
SRC_AO="$AGENT_OPS_DIR"
DST_AO="$TARGET/agent-ops"
IS_FRAMEWORK="$([[ -f "$PROJECT_ROOT/.agent-ops-source" ]] && echo "1" || echo "0")"
# ── pull 모드: agentic-framework → 현재 프로젝트 ─────────────────────────────
if [[ "$PULL_MODE" == "1" ]]; then
if [[ "$IS_FRAMEWORK" == "1" ]]; then
echo -e "${RED}Error: agentic-framework에서는 --pull을 사용할 수 없습니다.${RESET}"
exit 1
fi
if [[ ! -f "$TARGET/.agent-ops-source" ]]; then
echo -e "${RED}Error: target이 agentic-framework가 아닙니다 (.agent-ops-source 없음)${RESET}"
exit 1
fi
SRC_VER="$(cat "$SRC_AO/.version" 2>/dev/null || echo "0.0.0")"
DST_VER="$(cat "$DST_AO/.version" 2>/dev/null || echo "0.0.0")"
echo "$(basename "$TARGET")$(basename "$PROJECT_ROOT") (pull)"
echo " 현재 버전: $SRC_VER | framework 버전: $DST_VER"
sync_common "$DST_AO" "$SRC_AO"
cp "$DST_AO/.version" "$SRC_AO/.version"
apply_entry_files "$DST_AO/rules/common/rules.md" "$PROJECT_ROOT"
cd "$PROJECT_ROOT"
git add agent-ops/rules/common agent-ops/skills/common agent-ops/bin agent-ops/.version \
CLAUDE.md GEMINI.md .cursorrules AGENTS.md
git commit -m "sync: pull from agentic-framework v$DST_VER"
git push
echo -e "${GREEN}✓ 완료 (pull v$DST_VER)${RESET}"
exit 0
fi
echo "$(basename "$PROJECT_ROOT")$(basename "$TARGET")"
# ── agentic-framework에서 다른 프로젝트로 ────────────────────────────────────
if [[ "$IS_FRAMEWORK" == "1" ]]; then
if [[ ! -d "$DST_AO" ]]; then
echo " 최초 진행: agent-ops 전체 복사"
cp -r "$SRC_AO" "$TARGET/"
echo -e "${YELLOW} init-agent-ops 스킬로 초기화를 진행하세요.${RESET}"
else
echo " 이후 진행: common/ 동기화"
sync_common "$SRC_AO" "$DST_AO"
cp "$SRC_AO/.version" "$DST_AO/.version"
apply_entry_files "$SRC_AO/rules/common/rules.md" "$TARGET"
fi
echo -e "${GREEN}✓ 완료 → $(basename "$TARGET")${RESET}"
exit 0
fi
# ── 일반 프로젝트에서 agentic-framework로 (push) ─────────────────────────────
if [[ ! -f "$TARGET/.agent-ops-source" ]]; then
echo -e "${RED}Error: target이 agentic-framework가 아닙니다 (.agent-ops-source 없음)${RESET}"
exit 1
fi
SRC_VER="$(cat "$SRC_AO/.version" 2>/dev/null || echo "0.0.0")"
DST_VER="$(cat "$DST_AO/.version" 2>/dev/null || echo "0.0.0")"
echo " 현재 버전: $SRC_VER | framework 버전: $DST_VER"
if version_gt "$DST_VER" "$SRC_VER"; then
echo -e "${RED}⚠ 버전 충돌: framework($DST_VER) > current($SRC_VER)${RESET}"
echo -e "${YELLOW} 먼저 sync-pull로 내려받은 뒤 재시도하세요.${RESET}"
exit 1
fi
NEW_VER="$(bump_version "$SRC_VER")"
sync_common "$SRC_AO" "$DST_AO"
echo "$NEW_VER" > "$SRC_AO/.version"
echo "$NEW_VER" > "$DST_AO/.version"
cd "$TARGET"
git add agent-ops/rules/common agent-ops/skills/common agent-ops/bin agent-ops/.version
git commit -m "sync: from $(basename "$PROJECT_ROOT") v$NEW_VER"
git push
cd "$PROJECT_ROOT"
git add agent-ops/rules/common agent-ops/skills/common agent-ops/bin agent-ops/.version
git commit -m "sync: to agentic-framework v$NEW_VER"
git push
echo -e "${GREEN}✓ 완료 (v$SRC_VER → v$NEW_VER)${RESET}"

View file

@ -0,0 +1,16 @@
# 공통 규칙
- 기존 구조를 우선한다. 새 파일 생성보다 기존 파일 수정을 우선한다.
- 코드 변경 전 관련 domain rule을 먼저 확인한다.
- 요청 범위를 넘는 변경을 하지 않는다.
- 불확실하면 단정하지 말고 후보를 제시한다.
아래 요청은 `agent-ops/skills/common/router.md`를 읽고 수행한다.
- agent-ops 초기화
- domain rule 생성
- skill 생성
- git commit / git push
- agent-ops 업데이트 / 진입 파일 재적용
`agent-ops/rules/project/rules.md`
`agent-ops/rules/private/rules.md`를 읽고 작업을 시작한다. 파일이 없을경우 무시한다.

View file

@ -149,6 +149,14 @@ common/rules.md와 내용이 중복되지 않도록 한다.
도메인은 실제 폴더, 모듈, 패키지, 책임 경계와 연결되어야 한다.
## 실행 (Execution)
지정한 대상 디렉토리에 agent-ops 스캐폴드를 생성한다.
```bash
./agent-ops/bin/init-agent-ops.sh <target_directory>
```
## 실행 절차
1. **상태 판별**

View file

@ -8,4 +8,6 @@
| 계획 세워줘, 구현 계획, PLAN.md, plan | `agent-ops/skills/common/plan/SKILL.md` |
| 코드 리뷰해줘, code review, CODE_REVIEW.md, 리뷰 루프 | `agent-ops/skills/common/code-review/SKILL.md` |
| 커밋해줘, 푸시해줘, commit, push, 반영해줘 | `agent-ops/skills/common/commit-push/SKILL.md` |
| agent-ops 싱크해, agent-ops 동기화해, agentic-framework에 올려줘, agent-ops를 [프로젝트]로 싱크해 | `agent-ops/skills/common/sync-agent-ops/SKILL.md` |
| agent-ops 싱크해, agent-ops 동기화해, agentic-framework에 올려줘, agent-ops를 [프로젝트]로 싱크해 | `agent-ops/skills/common/sync-push/SKILL.md` |
| agent-ops pull해, agent-ops 가져와, agentic-framework에서 가져와, agent-ops 내려받아 | `agent-ops/skills/common/sync-pull/SKILL.md` |
| 도메인 업데이트, domain rule 갱신, 도메인 검토, domain 스캔 | `agent-ops/skills/common/update-domain-rule/SKILL.md` |

View file

@ -0,0 +1,36 @@
---
name: sync-pull
description: agentic-framework에서 현재 프로젝트로 agent-ops를 내려받는다. "agent-ops pull해", "agentic-framework에서 가져와" 요청 시 사용한다.
---
# sync-pull
## 목적
`agent-ops/bin/sync.sh --pull`을 호출해 agentic-framework → 현재 프로젝트 방향으로 agent-ops를 내려받는다.
## 언제 호출할지
- "agent-ops pull해", "agent-ops 가져와" 요청 시
- "agentic-framework에서 가져와" 요청 시
- "agent-ops 내려받아" 요청 시
## 실행 절차
1. 현재 프로젝트의 **상위 폴더(`../`)**`agentic-framework` 폴더가 있는지 확인한다 (현재 폴더 내부가 아님)
2. **있으면**: `agent-ops/bin/sync.sh --pull agentic-framework` 실행
3. **없으면**: 사용자에게 agentic-framework 경로 입력을 안내하고, 입력받은 경로로 실행
```bash
agent-ops/bin/sync.sh --pull <target>
```
## 실행 결과 검증
- [ ] sync.sh 가 오류 없이 완료됐는가
- [ ] 현재 프로젝트 버전이 framework 버전과 일치하는가
- [ ] 진입 파일(CLAUDE.md 등)이 갱신됐는가
## 금지 사항
- sync.sh 를 거치지 않고 직접 파일을 복사하지 않는다

View file

@ -1,14 +1,13 @@
---
name: sync-agent-ops
description: agent-ops를 agentic-framework와 동기화한다. "agent-ops 싱크해", "agent-ops 동기화해" 요청 시 사용한다.
name: sync-push
description: 현재 프로젝트의 agent-ops를 agentic-framework로 올린다. "agent-ops 싱크해", "agent-ops 동기화해", "agentic-framework에 올려줘" 요청 시 사용한다.
---
# sync-agent-ops
# sync-push
## 목적
`agent-ops/bin/sync.sh`를 호출해 agent-ops를 동기화한다.
현재 프로젝트가 agentic-framework인지 여부에 따라 동작이 달라진다.
`agent-ops/bin/sync.sh`를 호출해 현재 프로젝트 → agentic-framework 방향으로 agent-ops를 올린다.
## 언제 호출할지
@ -20,7 +19,7 @@ description: agent-ops를 agentic-framework와 동기화한다. "agent-ops 싱
### 현 프로젝트가 일반 프로젝트인 경우 (`.agent-ops-source` 없음)
1. 동일 레벨`agentic-framework` 폴더가 있는지 확인한다
1. 현재 프로젝트의 **상위 폴더(`../`)** `agentic-framework` 폴더가 있는지 확인한다 (현재 폴더 내부가 아님)
2. **있으면**: `agent-ops/bin/sync.sh agentic-framework` 실행
3. **없으면**: 사용자에게 agentic-framework 경로 입력을 안내하고, 입력받은 경로로 실행

View file

@ -0,0 +1,100 @@
---
name: update-domain-rule
version: 1.0.0
description: 기존 도메인 rules.md를 코드 현황에 맞게 갱신. 전체 스캔(full) 또는 지정 도메인(targeted) 두 모드 지원
---
# update-domain-rule
## 목적
프로젝트 코드가 변경되면서 기존 domain rule이 실제 구조와 어긋날 수 있다.
이 스킬은 실제 파일 구조를 탐색하여 기존 `rules.md`와 비교하고, 누락·오류·구식 항목을 수정한다.
## 언제 호출할지
- 대규모 리팩터링 또는 외부 패키지 내재화 후 domain rule 동기화가 필요할 때
- 특정 도메인 파일 구조가 바뀌어 기존 rule이 맞지 않을 때
- 사용자가 "도메인 업데이트", "domain rule 갱신", "domain 검토" 등을 요청할 때
- agent-ops 초기 scaffold 이후 코드가 많이 달라진 경우
## 입력
- `mode`: `full`(전체 도메인 스캔) | `targeted`(지정 도메인만) (필수)
- `domain-name`: 업데이트할 도메인 이름 — `targeted` 모드에서만 필수
## 먼저 확인할 것
- [ ] `agent-ops/rules/project/domain/` 하위 기존 도메인 목록 확인
- [ ] `agent-ops/rules/common/_templates/domain-rule-template.md` 읽어 최신 템플릿 형식 파악
- [ ] `targeted` 모드이면 `agent-ops/rules/project/domain/<domain-name>/rules.md` 존재 여부 확인
- 존재하지 않으면 `create-domain-rule` 스킬을 사용하도록 안내하고 중단
## 실행 절차
1. **대상 목록 결정**
- `full`: `agent-ops/rules/project/domain/` 하위 모든 도메인 디렉터리를 대상으로 한다
- `targeted`: 지정된 `domain-name` 하나만 대상으로 한다
2. **도메인별 코드 탐색**
- 기존 `rules.md`**포함 경로** 목록을 기준으로 실제 파일 구조 탐색
- 포함 경로에 없지만 도메인 이름과 연관된 경로도 함께 탐색
- 탐색 시 실제로 존재하는 경로만 수집한다
3. **비교 및 변경 항목 식별**
다음 항목 각각을 현재 `rules.md`와 비교한다:
- **포함 경로**: 실제로 존재하지 않는 경로 제거, 새로 생긴 경로 추가
- **주요 구성 요소**: 파일/클래스 삭제·이름 변경·신규 추가 반영
- **유지할 패턴**: 코드에서 더 이상 사용되지 않는 패턴 제거, 새 패턴 추가
- **다른 도메인과의 경계**: 도메인 간 import 관계가 바뀐 경우 반영
- **목적/책임**: 도메인 책임이 실질적으로 변경된 경우에만 수정
4. **rules.md 업데이트**
- 변경이 필요한 항목만 수정한다 — 변경 불필요한 섹션은 그대로 둔다
- 확인된 사실만 기재한다; 불확실하면 `<!-- TODO: 확인 필요 -->` 주석 처리
- `domain-rule-template.md`의 섹션 구조를 유지한다
5. **도메인 매핑 테이블 검토** (`full` 모드 시)
- `agent-ops/rules/project/rules.md`의 도메인 매핑 테이블과 실제 포함 경로 비교
- 누락된 경로 패턴은 추가, 존재하지 않는 경로 패턴은 제거
- 기존 항목 순서는 변경하지 않는다
6. **결과 보고**
- 도메인별로 수정한 항목 목록
- `TODO`로 남긴 항목 (해당 시)
- 도메인 매핑 테이블 변경 내용 (full 모드 시)
## 실행 결과 검증
- [ ] 수정된 `rules.md`의 포함 경로가 모두 실제 프로젝트에 존재하는가
- [ ] 섹션 구조가 `domain-rule-template.md` 형식을 유지하는가
- [ ] 변경하지 않아도 되는 섹션이 의도치 않게 바뀌지 않았는가
- [ ] `full` 모드에서 도메인 매핑 테이블이 실제 포함 경로와 일치하는가
- 검증 실패 시: 실제 존재하지 않는 경로나 누락된 섹션을 사용자에게 알리고 해당 항목만 보완한다
## 출력 형식
```
## 업데이트 완료
### <domain-name>
- 변경: <수정된 항목 요약>
- 추가: <새로 추가된 경로/구성 요소>
- 제거: <삭제된 경로/구성 요소>
- 유지: 변경 없음 (해당 섹션)
### 도메인 매핑 테이블 (full 모드 시)
- 추가: < 경로 패턴>
- 제거: <삭제된 경로 패턴>
## TODO 항목 (확인 필요)
- <불확실하여 직접 확인이 필요한 항목> (해당 시)
```
## 금지 사항
- 실제 존재하지 않는 경로를 포함 경로에 기재하지 않는다
- 추측으로 패턴·금지 사항을 추가하지 않는다 — 코드에서 확인된 내용만 기재한다
- 신규 도메인 생성이 필요한 경우 직접 생성하지 않고 `create-domain-rule` 스킬 사용을 안내한다
- `rules/project/rules.md`의 기존 항목을 삭제하거나 재정렬하지 않는다
- 코드 파일을 수정하지 않는다 — 이 스킬은 rule 파일 갱신만 담당한다