Skip to content

Latest commit

ย 

History

History
124 lines (88 loc) ยท 9.78 KB

AGENTS.md

File metadata and controls

124 lines (88 loc) ยท 9.78 KB

AGENTS.md

DaleStudy ์กฐ์ง์˜ GitHub App์ด ๋ฐ›๋Š” ์›นํ›…๊ณผ ์ž๋™ํ™” ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” Cloudflare Worker. ์ฃผ ๋Œ€์ƒ์€ leetcode-study ์ €์žฅ์†Œ๋‹ค.

๋ช…๋ น์–ด

bun install
bun run test                # ์ „์ฒด ํ…Œ์ŠคํŠธ (CI ์™€ ๋ฐฐํฌ ์ „์— ๊ฐ™์€ ๋ช…๋ น์„ ๋ˆ๋‹ค)
bun run test -- handlers/webhooks.test.js
wrangler dev                # http://localhost:8787
wrangler tail               # ์šด์˜ ๋กœ๊ทธ

๊ตฌ์กฐ

index.js        ์—”๋“œํฌ์ธํŠธ ๋ผ์šฐํŒ…๋งŒ ํ•œ๋‹ค (POST ๋งŒ ๋ฐ›๋Š”๋‹ค)
handlers/       ๊ธฐ๋Šฅ๋ณ„ ํ•ธ๋“ค๋Ÿฌ์™€ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ(*.test.js)
utils/          ๊ณตํ†ต ์œ ํ‹ธ๋ฆฌํ‹ฐ์™€ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ (github.js: App ์ธ์ฆ, prActions.js: ์Šน์ธยท๋ณ‘ํ•ฉ ๊ณตํ†ต ๋กœ์ง)
tests/          Worker runtime smoke test, subrequest ์˜ˆ์‚ฐ, ๊ต์ฐจ ๋ชจ๋“ˆ ํ…Œ์ŠคํŠธ
wrangler.jsonc  Worker ์„ค์ •๊ณผ ๊ณต๊ฐœ ๊ฐ’(vars)

์ƒˆ ๊ธฐ๋Šฅ์€ handlers/ ์— ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋งŒ๋“ค๊ณ  index.js ์— ๊ฒฝ๋กœ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค. ํ•„์š”ํ•œ GitHub App ๊ถŒํ•œ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ํ•ธ๋“ค๋Ÿฌ ์˜†์— ํ…Œ์ŠคํŠธ๋ฅผ ๋‘”๋‹ค.

์—”๋“œํฌ์ธํŠธ

repo_owner ๋ฅผ ๋ฐ›๋Š” ์—”๋“œํฌ์ธํŠธ๋Š” DaleStudy ๊ฐ€ ์•„๋‹ˆ๋ฉด 403 ์ด๋‹ค (์ƒ๋žตํ•˜๋ฉด DaleStudy). /check-weeks ๋Š” ์ €์žฅ์†Œ๋„ leetcode-study ๋งŒ ๋ฐ›๋Š”๋‹ค.

๊ฒฝ๋กœ ํ•˜๋Š” ์ผ
POST /webhooks GitHub App ์›นํ›… ์ˆ˜์‹  (์•„๋ž˜ "์›นํ›…")
POST /check-weeks ์—ด๋ฆฐ PR ์ „์ฒด์˜ Week ์„ค์ •์„ ๊ฒ€์‚ฌํ•ด ๊ฒฝ๊ณ  ๋Œ“๊ธ€์„ ๋‹ฌ๊ฑฐ๋‚˜ ์ง€์šด๋‹ค. { "repo_name" }
POST /approve-prs ํ•ด๋‹น ์ฃผ์ฐจ ํ’€์ด PR ์„ ์ผ๊ด„ ์Šน์ธํ•œ๋‹ค. { "repo_name", "week": "Week 8", "excludes"? }
POST /merge-prs ํ•ด๋‹น ์ฃผ์ฐจ์˜ ์Šน์ธ๋œ PR ์„ ์ผ๊ด„ ๋ณ‘ํ•ฉํ•œ๋‹ค. { "repo_name", "week", "excludes"?, "merge_method"? } (๊ธฐ๋ณธ squash)
POST /resolve-iteration ๋‚ ์งœ๊ฐ€ ๋ช‡ ๊ธฐ ๋ช‡ ์ฃผ์ฐจ์ธ์ง€ ํ”„๋กœ์ ํŠธ ๋ณด๋“œ์—์„œ ์ฝ๋Š”๋‹ค. { "date": "2026-08-08" }
POST /internal/* ์›นํ›… ํ•ธ๋“ค๋Ÿฌ๊ฐ€ AI ์ž‘์—…์„ ๋ณ„๋„ invocation ์œผ๋กœ ๋„˜๊ธธ ๋•Œ ์“ด๋‹ค (X-Internal-Secret ์ธ์ฆ)

์Šน์ธยท๋ณ‘ํ•ฉ์˜ ๊ณตํ†ต ๊ทœ์น™์€ utils/prActions.js ์— ์žˆ๋‹ค. ์š”์•ฝํ•˜๋ฉด Week ๊ฐ€ ๋‹ค๋ฅด๊ฑฐ๋‚˜ Status ๊ฐ€ Solving ์ธ PR, Draft PR ์€ ๊ฑด๋„ˆ๋›ฐ๊ณ , ์Šน์ธ์€ CI ๊ฐ€ ํ†ต๊ณผํ•œ PR ์—๋งŒ, ๋ณ‘ํ•ฉ์€ ์Šน์ธ ๋ฆฌ๋ทฐ๊ฐ€ ์žˆ๊ณ  mergeable_state ๊ฐ€ clean ์ธ PR ์—๋งŒ ํ•œ๋‹ค.

/resolve-iteration ์ด ์žˆ๋Š” ์ด์œ : Actions ์˜ ๊ธฐ๋ณธ GITHUB_TOKEN ์€ org ํ”„๋กœ์ ํŠธ ๋ณด๋“œ๋ฅผ ์ฝ์ง€ ๋ชปํ•ด์„œ(read:project ์—†์Œ) App ํ† ํฐ์„ ๊ฐ€์ง„ ์ด Worker ๊ฐ€ ๋Œ€์‹  ์ฝ๋Š”๋‹ค. ์ฃผ์ฐจ๋Š” ๋ณด๋“œ์˜ Week(Iteration) ํ•„๋“œ์—์„œ ์˜ค๋ฏ€๋กœ ํ•˜๋“œ์ฝ”๋”ฉํ•˜์ง€ ์•Š๋Š”๋‹ค.

์›นํ›…

handlers/webhooks.js ๊ฐ€ leetcode-study ์ €์žฅ์†Œ์˜ ์ด๋ฒคํŠธ๋งŒ ์ฒ˜๋ฆฌํ•œ๋‹ค.

์ด๋ฒคํŠธ ํ•˜๋Š” ์ผ
projects_v2_item Week ์„ค์ •์ด ๋ฐ”๋€Œ๋ฉด ๊ฒฝ๊ณ  ๋Œ“๊ธ€์„ ๋‹ฌ๊ฑฐ๋‚˜ ์ง€์šด๋‹ค
pull_request (opened, reopened, synchronize) Week ๊ฒ€์‚ฌ, AI ๋ฆฌ๋ทฐ check run(aiReview)
issue_comment, pull_request_review_comment (created) @dalestudy ๋ฉ˜์…˜์— ์‘๋‹ตํ•œ๋‹ค. approveยท์Šน์ธ ์ด๋ฉด PR ์„ ์Šน์ธํ•˜๊ณ , ๊ทธ ๋ฐ–์—๋Š” AI ๋ฆฌ๋ทฐ๋ฅผ ๋‹จ๋‹ค

Week ๊ฒ€์‚ฌ๋Š” ์ œ๋ชฉ์— Week ์ˆซ์ž ๋˜๋Š” Onboarding์ด ํฌํ•จ๋œ ํ’€์ด PR์„ ๋Œ€์ƒ์œผ๋กœ ํ•˜๊ณ , ๊ฒฝ๊ณ  ๋Œ“๊ธ€์€ ๋ด‡์ด ๋‹จ ๊ฒƒ๋งŒ ์ง€์šด๋‹ค. AI ๋ฆฌ๋ทฐ๋Š” ์ œ๋ชฉ๊ณผ ์ƒ๊ด€์—†์ด ๋Œ๋ฆฌ๊ณ ([user] Onboarding ๊ฐ™์€ PR ๋„ ํฌํ•จ), ํ’€์ด ํŒŒ์ผ์ด ์—†์œผ๋ฉด AI ๋ฅผ ๋ถ€๋ฅด์ง€ ์•Š๊ณ  ๊ฑด๋„ˆ๋›ด๋‹ค.

AI ๋ฆฌ๋ทฐ๋Š” ํ’€์ด ํŒŒ์ผ๋ณ„ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ํŒจํ„ด, ์˜๋„ํ•œ ์ ‘๊ทผ๋ฒ• ์ผ์น˜ ์—ฌ๋ถ€(problem-categories.json ๊ธฐ์ค€), ์‹œ๊ฐ„/๊ณต๊ฐ„ ๋ณต์žก๋„์™€ ์ž‘์„ฑ์ž์˜ ์ด๋ฒˆ ๊ธฐ์ˆ˜ ํ•™์Šต ํ˜„ํ™ฉ์„ PR head ์ปค๋ฐ‹์˜ check run ํ•˜๋‚˜(AI ๋ฆฌ๋ทฐ)์— ๋‹ด๋Š”๋‹ค. ๋Œ€ํ™” ํƒญ์—๋Š” ๊ทธ check run ์œผ๋กœ ๊ฐ€๋Š” ๋งํฌ ๋Œ“๊ธ€ ํ•˜๋‚˜๋งŒ ์œ ์ง€ํ•œ๋‹ค.

AI ๋ฆฌ๋ทฐ๋ฅผ ๋ณ„๋„ invocation ์œผ๋กœ ๋‚˜๋ˆ„๊ธฐ

Worker ํ•œ ๋ฒˆ์˜ ์‹คํ–‰(invocation)์€ subrequest ๋ฅผ 50 ๊ฐœ๊นŒ์ง€ ์“ธ ์ˆ˜ ์žˆ๋‹ค. ํŒŒ์ผ์ด ๋งŽ์€ PR ์—์„œ ๋„˜์น˜์ง€ ์•Š๋„๋ก, ์›นํ›… ํ•ธ๋“ค๋Ÿฌ๋Š” AI ๋ฆฌ๋ทฐ๋ฅผ ์ž๊ธฐ ์ž์‹ ์—๊ฒŒ ๋‹ค์‹œ ์š”์ฒญํ•ด ๋”ฐ๋กœ ์‹คํ–‰ํ•œ๋‹ค.

GitHub webhook
   โ–ผ
[#1] webhook ํ•ธ๋“ค๋Ÿฌ                       โ† 50 ์˜ˆ์‚ฐ
   โ””โ”€ ctx.waitUntil(fetch("/internal/ai-review"))  โ†’ [#2] aiReview   โ† ๋…๋ฆฝ 50 ์˜ˆ์‚ฐ

INTERNAL_SECRET ๊ณผ WORKER_URL ์ด ๋‘˜ ๋‹ค ์žˆ์–ด์•ผ ์ผœ์ง„๋‹ค. ํ•˜๋‚˜๋ผ๋„ ์—†์œผ๋ฉด ๊ฐ™์€ invocation ์—์„œ ์‹คํ–‰๋œ๋‹ค. tests/subrequest-budget.test.js ๊ฐ€ fetch ํšŸ์ˆ˜(aiReview ํŒŒ์ผ 15 ๊ฐœ์— 40, AI ํ˜ธ์ถœ ํฌํ•จ)๋ฅผ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ๋กœ ๊ณ ์ •ํ•œ๋‹ค.

๋ฐฐํฌ์™€ ์‹œํฌ๋ฆฟ

main ์— ๋จธ์ง€๋˜๋ฉด GitHub Actions(.github/workflows/deploy.yml)๊ฐ€ ํ…Œ์ŠคํŠธ ํ›„ GitHub secret ์„ Worker secret ์œผ๋กœ ๋„ฃ์œผ๋ฉฐ ๋ฐฐํฌํ•œ๋‹ค. PR ์—์„œ๋Š” integration.yaml ์ด ํ…Œ์ŠคํŠธ๋งŒ ๋ˆ๋‹ค. ์›นํ›…์„ ๋ฐ›๋Š” ์„œ๋ฒ„๋ผ PR ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋Š” ๋‘์ง€ ์•Š๋Š”๋‹ค.

Worker ์—์„œ ์ฝ๋Š” ์ด๋ฆ„ ์–ด๋””์„œ ์˜ค๋‚˜
APP_ID, WORKER_URL wrangler.jsonc ์˜ vars (๊ณต๊ฐœ ๊ฐ’)
PRIVATE_KEY GitHub org secret APP_PRIVATE_KEY
AI wrangler.jsonc ์˜ AI ๋ฐ”์ธ๋”ฉ. ๊ฐ™์€ ๊ณ„์ •์˜ AI Gateway dalestudy ๋ฅผ ํ† ํฐ ์—†์ด ๋ถ€๋ฅธ๋‹ค
INTERNAL_SECRET GitHub ์ €์žฅ์†Œ secret INTERNAL_SECRET
WEBHOOK_SECRET GitHub ์ €์žฅ์†Œ secret WEBHOOK_SECRET. GitHub App ์›นํ›… ์„ค์ •์˜ secret ๊ณผ ๊ฐ™์€ ๊ฐ’์ด๋‹ค

GitHub secret ์€ ๋ฐฐํฌํ•  ๋•Œ๋งˆ๋‹ค Worker secret ์œผ๋กœ ๋“ค์–ด๊ฐ€๋ฏ€๋กœ wrangler secret put ์œผ๋กœ ๋”ฐ๋กœ ๋ฐ”๊พธ์ง€ ์•Š๋Š”๋‹ค. ๋‹ค์Œ ๋ฐฐํฌ ๋•Œ GitHub ๊ฐ’์œผ๋กœ ๋ฎ์ธ๋‹ค. ๋กœ์ปฌ์—์„œ๋Š” .dev.vars ์— ๊ฐ™์€ ์ด๋ฆ„์œผ๋กœ ๋„ฃ๋Š”๋‹ค. .dev.vars, *.pem ์€ ์ปค๋ฐ‹ํ•˜์ง€ ์•Š๋Š”๋‹ค.

OpenAI ํ‚ค๋Š” Worker ์— ๋‘์ง€ ์•Š๋Š”๋‹ค. AI Gateway dalestudy ์˜ Provider Keys(BYOK)์— ์ €์žฅ๋ผ ์žˆ๊ณ , ๊ฒŒ์ดํŠธ์›จ์ด๋Š” BYOK only ๋ผ ํ‚ค๊ฐ€ ์—†์œผ๋ฉด Unified Billing ์œผ๋กœ ๋„˜์–ด๊ฐ€์ง€ ์•Š๊ณ  ์‹คํŒจํ•œ๋‹ค. AI ๋ฐ”์ธ๋”ฉ์€ wrangler dev ์—์„œ๋„ ์›๊ฒฉ ๊ฒŒ์ดํŠธ์›จ์ด๋ฅผ ๋ถ€๋ฅด๋ฏ€๋กœ wrangler login ์ด dalestudy ๊ณ„์ •์— ๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค.

GitHub App ์„ค์ •

https://github.com/organizations/DaleStudy/settings/apps/dalestudy

  • Webhook URL: https://github.dalestudy.com/webhooks, Webhook secret ์€ ์ €์žฅ์†Œ secret WEBHOOK_SECRET ๊ณผ ๊ฐ™์€ ๊ฐ’. /webhooks ๋Š” ์„œ๋ช…(X-Hub-Signature-256)์ด ๋งž์ง€ ์•Š๊ฑฐ๋‚˜ WEBHOOK_SECRET ์ด ์—†์œผ๋ฉด ๋ฐ›์ง€ ์•Š๋Š”๋‹ค
  • Repository permissions: Checks(Read & write), Contents(Read), Issues(Read & write), Metadata(Read), Pull requests(Read & write), Projects(Read & write)
  • ์ด๋ฒคํŠธ: Issue comments, Pull request review comments, Projects v2 item, Pull requests
  • DaleStudy ์กฐ์ง์— ์„ค์น˜๋ผ ์žˆ๊ณ  leetcode-study ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค

ํ…Œ์ŠคํŠธ

ํ…Œ์ŠคํŠธ๋Š” ๋Œ€์ƒ ํŒŒ์ผ ์˜†์— *.test.js ๋กœ ๋‘”๋‹ค. vitest ์˜ describeยทitยทexpectยทvi ๋ฅผ ์“ฐ๊ณ , ์™ธ๋ถ€ ๋ชจ๋“ˆ์€ vi.mock(), fetch ๋Š” globalThis.fetch = vi.fn() ์œผ๋กœ ๋ฐ”๊พผ๋‹ค. Worker runtime ๊ณผ ๋ฐ”์ธ๋”ฉ์ด ํ•„์š”ํ•œ ํ…Œ์ŠคํŠธ๋Š” cloudflare:test, cloudflare:workers ๋ฅผ ์“ด๋‹ค (@cloudflare/vitest-pool-workers ๊ฐ€ wrangler.jsonc ๋ฅผ ์ฝ๋Š”๋‹ค).

vi.mock("../utils/github.js", () => ({
  generateGitHubAppToken: vi.fn().mockResolvedValue("fake-token"),
}));

์ฃผ์˜์‚ฌํ•ญ

  • Workers ๋Ÿฐํƒ€์ž„์ด๋‹ค. Node.js ๋ชจ๋“ˆ๊ณผ Octokit ๊ฐ™์€ npm ํŒจํ‚ค์ง€๋Š” ๋Œ€๋ถ€๋ถ„ ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค. fetch ์™€ Web Crypto API ๋กœ ์ง์ ‘ ๊ตฌํ˜„ํ•œ๋‹ค. Private Key ๋Š” PKCS8, PKCS1 ๋ชจ๋‘ ๋ฐ›๋Š”๋‹ค (utils/github.js).
  • GraphQL ์ฟผ๋ฆฌ์— ๊ฐ’์„ ๋ฌธ์ž์—ด๋กœ ์ง์ ‘ ๋ผ์›Œ ๋„ฃ๋Š”๋‹ค. GraphQL ๋ณ€์ˆ˜ ๋ฌธ๋ฒ•์„ ์“ฐ์ง€ ์•Š์œผ๋ฏ€๋กœ ์ž…๋ ฅ๊ฐ’ ๊ฒ€์ฆ์„ ๋น ๋œจ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.
  • ์‘๋‹ต์—๋Š” CORS ํ—ค๋”(Access-Control-Allow-Origin: *)๊ฐ€ ๋ถ™๊ณ , ์—๋Ÿฌ๋Š” 500 ์œผ๋กœ ๋Œ๋ ค์ค€๋‹ค. ์›์ธ์€ wrangler tail ๋กœ ๋ณธ๋‹ค.
  • 401 ์ด ๋‚˜๋ฉด APP_ID ์™€ PRIVATE_KEY ๊ฐ€ ๊ฐ™์€ App ์˜ ๊ฒƒ์ธ์ง€ ํ™•์ธํ•œ๋‹ค.

Code Review Rules

  • Node.js ๋‚ด์žฅ ๋ชจ๋“ˆ์ด๋‚˜ Octokit ๊ฐ™์€ Workers ๋Ÿฐํƒ€์ž„์—์„œ ๋™์ž‘ํ•˜์ง€ ์•Š๋Š” ํŒจํ‚ค์ง€๋ฅผ ์“ฐ๋ฉด ์ง€์ ํ•œ๋‹ค.
  • GraphQL ์ฟผ๋ฆฌ์— ๋ฌธ์ž์—ด๋กœ ๋ผ์›Œ ๋„ฃ๋Š” ๊ฐ’์€ ๋ฐ˜๋“œ์‹œ ๊ฒ€์ฆ๋˜์–ด์•ผ ํ•œ๋‹ค. ์‚ฌ์šฉ์ž ์ž…๋ ฅ(PR ์ œ๋ชฉ, ๋Œ“๊ธ€ ๋“ฑ)์ด ๊ฒ€์ฆ ์—†์ด ๋“ค์–ด๊ฐ€๋ฉด ์‹ฌ๊ฐํ•œ ๋ฌธ์ œ๋กœ ์ง€์ ํ•œ๋‹ค.
  • ์ƒˆ ์—”๋“œํฌ์ธํŠธ๋Š” ๊ธฐ์กด์ฒ˜๋Ÿผ repo_owner๊ฐ€ DaleStudy๊ฐ€ ์•„๋‹ˆ๋ฉด 403์„ ๋Œ๋ ค์•ผ ํ•˜๊ณ , /internal/*๋Š” X-Internal-Secret์„ ๊ฒ€์‚ฌํ•ด์•ผ ํ•œ๋‹ค.
  • aiReview์— fetch๊ฐ€ ๋Š˜์–ด๋‚˜๋ฉด tests/subrequest-budget.test.js์˜ ๊ณ ์ •๊ฐ’๋„ ํ•จ๊ป˜ ๊ฐฑ์‹ ๋˜์–ด์•ผ ํ•œ๋‹ค.
  • ์ƒˆ ์‹œํฌ๋ฆฟ์„ wrangler secret put ์ „์ œ๋กœ ์ถ”๊ฐ€ํ•˜๋ฉด ์ง€์ ํ•œ๋‹ค. ์‹œํฌ๋ฆฟ์€ GitHub secret์œผ๋กœ ๋‘๊ณ  ๋ฐฐํฌ ์›Œํฌํ”Œ๋กœ๊ฐ€ ๋„ฃ๋Š”๋‹ค.