diff --git a/.claude/commands/yakcloud.md b/.claude/commands/yakcloud.md new file mode 100644 index 0000000..384c8c7 --- /dev/null +++ b/.claude/commands/yakcloud.md @@ -0,0 +1,43 @@ +--- +description: YakCloud 배포 CLI를 Claude Code에서 구동 — 스캐폴딩·배포·데이터소스·도메인 (/yakcloud ) +argument-hint: project init | project deploy | datasource ls | domain | info | check +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, AskUserQuestion +--- + +사용자가 `/yakcloud $ARGUMENTS` 로 호출했다. 너는 `yakcloud` CLI(단일 진실원천)를 **현재 작업 디렉터리**에서 +구동하는 드라이버다. 터미널이 아니라 Claude Code 안이므로, TTY가 필요한 대화형 흐름은 네가 값을 모아 +**비대화형으로 대신** 실행한다. + +## 0) 준비 (매 호출 첫 단계) +- `command -v yakcloud` 확인. 없으면 설치: + `curl -fsSL https://gitea.yakenator.io/yakenator/yakcloud-starter/raw/branch/main/install.sh | sh` + 이후에도 PATH에 없으면 `$HOME/.local/bin/yakcloud` 절대경로로 실행. +- `알 수 없는 명령`/구버전 신호가 보이면 `yakcloud upgrade` 로 최신화 후 재시도. + +## 1) 디스패치 — `$ARGUMENTS` +- **비어 있거나 `help`** → `yakcloud help` 실행 결과 + 한 줄 사용 요약. +- **`project init [name]`** → §2 스캐폴딩(마법사 대체). +- **`login`** → 비밀 입력이라 여기서 실행하지 말고, 터미널에서 `yakcloud login` 하라고 한 줄 안내. + (사용자가 값을 직접 주면 `YAKCLOUD_URL=… YAKCLOUD_TOKEN=… GITEA_USER=… GITEA_TOKEN=… yakcloud config` 로 저장하되 **값은 화면에 출력 금지**.) +- **그 외 전부**(`project deploy|info|check|update`, `datasource ls`, `domain`, `scale`, `set`, `env`, + `source`, `bind`, `unbind`, `config`, `upgrade`) → `yakcloud $ARGUMENTS` 를 실행하고 **출력을 그대로** 보여준 뒤, + 필요할 때만 한 줄로 해석. 배포/삭제성(`deploy`·`source rm`·`unbind`·`domain`)은 실행 전 무엇을 하는지 한 줄 알리고 진행. + +## 2) `project init` — 마법사 대체 (핵심) +터미널 마법사는 TTY가 없으면 안 뜬다. 네가 대신한다: +1. `yakcloud project init -y` 로 **비대화형 스캐폴딩**(기본 매니페스트 생성; `bin/`·`install.sh` 잔재 없음). +2. `$ARGUMENTS`/대화 맥락에 이미 있는 값은 **재질문 금지**. 부족한 핵심값만 `AskUserQuestion` 으로 모은다: + 대상 클러스터, 앱 포트, 노출 경로(기본 `/`), CPU/메모리, 필요한 데이터소스(있으면), 도메인(있으면). +3. 모은 값을 CLI로 반영: + - `yakcloud set --port … --cpu … --mem … --path …` + - 소스: `yakcloud source add [plan]` + `yakcloud bind ` + - 도메인: `yakcloud domain ` + - 이용 가능한 클러스터 소스를 먼저 보고 싶으면 `yakcloud datasource ls`. +4. 자격 미설정이면(`yakcloud config` 로 확인) 터미널 `yakcloud login` 안내. +5. 다음 단계(개발 → `yakcloud project deploy`) 를 요약. + +## 규약 +- 전역 명령이지만 **대상은 현재 프로젝트**(현지 `yakcloud.yaml`). ctl 계열(`set`/`env`/`source`/`bind`/`domain`/`info`)은 + 프로젝트 폴더에서만 동작 — 아니면 먼저 `yakcloud project init` 안내. `datasource ls` 는 클러스터만 있으면 조회 가능. +- **자격/비밀 화면 출력 금지.** 배포토큰(`yakd_…`)·Gitea 토큰은 CLI의 OS 키체인 저장에 위임. +- 실패 시 종료코드·stderr 를 그대로 + 원인이 자명하면 한 줄 + 다음 행동 제시. diff --git a/.claude/skills/yakcloud-deploy/SKILL.md b/.claude/skills/yakcloud-deploy/SKILL.md index bf78280..8816bb3 100644 --- a/.claude/skills/yakcloud-deploy/SKILL.md +++ b/.claude/skills/yakcloud-deploy/SKILL.md @@ -20,6 +20,7 @@ YakCloud 콘솔 API로 **데이터소스 리컨실 + 워크로드 배포 + 바 ## CLI 가 있으면 우선 사용 `yakcloud` CLI 가 설치돼 있으면(`command -v yakcloud`) 스캐폴딩/배포/환경설정을 이걸로 처리한다. 설치: `curl -fsSL https://gitea.yakenator.io/yakenator/yakcloud-starter/raw/branch/main/install.sh | sh` +> 설치 시 **Claude Code 전역 슬래시 명령 `/yakcloud`** 도 함께 생성된다(`~/.claude/commands/yakcloud.md`). 예: `/yakcloud project init my-app`, `/yakcloud datasource ls`, `/yakcloud project deploy`. 이후 `yakcloud upgrade` 가 CLI와 슬래시 명령을 함께 최신화. **프로젝트 라이프사이클** - **"프로젝트 초기화"** → 빈 폴더에서 `yakcloud project init [name]` (스타터+CI+매니페스트+이 스킬) diff --git a/bin/yakcloud b/bin/yakcloud index 33533ea..53b7baa 100755 --- a/bin/yakcloud +++ b/bin/yakcloud @@ -18,7 +18,7 @@ set -uo pipefail # -e 미사용: 'test && action' 관용구가 값 없을 때 REPO="${YAKCLOUD_STARTER_REPO:-https://gitea.yakenator.io/yakenator/yakcloud-starter}" BRANCH="${YAKCLOUD_STARTER_BRANCH:-main}" -VERSION="0.5.0" +VERSION="0.6.0" CONFIG_DIR="${YAKCLOUD_CONFIG_DIR:-$HOME/.config/yakcloud}" CONFIG_FILE="$CONFIG_DIR/config" @@ -275,6 +275,21 @@ cmd_project_check() { } # 전역 CLI 자기 갱신 — 버전이 같아도 항상 최신 파일을 강제로 다시 받아 덮어쓴다(캐시 우회). +# Claude Code 전역 슬래시 명령(/yakcloud) 설치/최신화 — 설치·업그레이드 시 함께 실행. +# opt-out: YAKCLOUD_NO_CLAUDE_CMD=1. 실패해도 CLI 동작엔 지장 없음(비치명적). +install_claude_command() { + [ -z "${YAKCLOUD_NO_CLAUDE_CMD:-}" ] || return 0 + local dir="${CLAUDE_COMMANDS_DIR:-$HOME/.claude/commands}" + local bust; bust="$(date +%s 2>/dev/null || echo 0)" + if mkdir -p "$dir" 2>/dev/null && \ + curl -fsSL -H 'Cache-Control: no-cache' -H 'Pragma: no-cache' \ + "$REPO/raw/branch/$BRANCH/.claude/commands/yakcloud.md?nocache=$bust" -o "$dir/yakcloud.md" 2>/dev/null; then + echo "✓ Claude Code 전역 슬래시 명령 → $dir/yakcloud.md (Claude Code에서 /yakcloud)" + else + echo " ⚠ /yakcloud 슬래시 명령 설치 건너뜀(무시 가능) — 터미널 yakcloud 는 정상" + fi +} + cmd_upgrade() { local self; self="$(command -v yakcloud 2>/dev/null || true)"; [ -n "$self" ] || self="$0" # 심볼릭 링크면 실체 파일을 갱신. @@ -292,6 +307,7 @@ cmd_upgrade() { mv "$tmp" "$self" 2>/dev/null || { rm -f "$tmp"; die "설치 실패(권한) — 'DEST= 재설치' 또는 sudo"; } hash -r 2>/dev/null || true # 셸 명령 해시 캐시 초기화(새 바이너리 즉시 반영) echo "✓ 업그레이드 완료: $before → $("$self" version 2>/dev/null || echo yakcloud)" + install_claude_command # /yakcloud 슬래시 명령도 최신화 } # 기존 프로젝트의 플러밍(엔진·CI·스킬)만 최신화. 앱/매니페스트/Dockerfile 등 사용자 파일은 보존. diff --git a/install.sh b/install.sh index ebcfc1e..497048c 100755 --- a/install.sh +++ b/install.sh @@ -13,6 +13,20 @@ BUST="$(date +%s 2>/dev/null || echo 0)" curl -fsSL -H 'Cache-Control: no-cache' -H 'Pragma: no-cache' \ "$REPO/raw/branch/$BRANCH/bin/yakcloud?nocache=$BUST" -o "$DEST/yakcloud" chmod +x "$DEST/yakcloud" + +# Claude Code 전역 슬래시 명령(/yakcloud) 설치 — opt-out: YAKCLOUD_NO_CLAUDE_CMD=1 +if [ -z "${YAKCLOUD_NO_CLAUDE_CMD:-}" ]; then + CMD_DIR="${CLAUDE_COMMANDS_DIR:-$HOME/.claude/commands}" + if mkdir -p "$CMD_DIR" 2>/dev/null && \ + curl -fsSL -H 'Cache-Control: no-cache' -H 'Pragma: no-cache' \ + "$REPO/raw/branch/$BRANCH/.claude/commands/yakcloud.md?nocache=$BUST" -o "$CMD_DIR/yakcloud.md" 2>/dev/null; then + echo "✓ Claude Code 전역 슬래시 명령 설치 → $CMD_DIR/yakcloud.md" + else + echo " ⚠ /yakcloud 슬래시 명령 설치 건너뜀(무시 가능) — 터미널 yakcloud 는 정상" + fi +fi + echo "✓ 완료. PATH 에 $DEST 가 있는지 확인하세요:" echo ' export PATH="$HOME/.local/bin:$PATH"' -echo " 사용: yakcloud init my-app → 개발 → yakcloud deploy v0.1.0" +echo " 터미널: yakcloud project init my-app → 개발 → yakcloud project deploy" +echo " Claude Code: /yakcloud project init my-app (전역 슬래시 명령)"