makdoong2-team 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +193 -0
- package/agents/makdoong2-analyzer.md +135 -0
- package/agents/makdoong2-engineer.md +165 -0
- package/agents/makdoong2-planner.md +267 -0
- package/agents/makdoong2-publisher.md +481 -0
- package/agents/makdoong2-team-leader.md +249 -0
- package/agents/makdoong2-verifier.md +353 -0
- package/assets/makdoong2-team.default.json +46 -0
- package/assets/makdoong2-team.schema.json +357 -0
- package/bin/cli.js +404 -0
- package/dist/agent-stage-config.d.ts +15 -0
- package/dist/agent-stage-config.js +119 -0
- package/dist/config.d.ts +79 -0
- package/dist/config.js +96 -0
- package/dist/logger.d.ts +14 -0
- package/dist/logger.js +131 -0
- package/dist/mcp-secret-injector.d.ts +56 -0
- package/dist/mcp-secret-injector.js +89 -0
- package/dist/model-chain-cli.d.ts +1 -0
- package/dist/model-chain-cli.js +21 -0
- package/dist/model-fallback-policy.d.ts +69 -0
- package/dist/model-fallback-policy.js +211 -0
- package/dist/opencode-plugin.d.ts +8 -0
- package/dist/opencode-plugin.js +2457 -0
- package/dist/poll-sub-session.d.ts +139 -0
- package/dist/poll-sub-session.js +494 -0
- package/dist/redact-secrets.d.ts +3 -0
- package/dist/redact-secrets.js +68 -0
- package/dist/session-index.d.ts +11 -0
- package/dist/session-index.js +71 -0
- package/dist/skill-mcp-registry.d.ts +59 -0
- package/dist/skill-mcp-registry.js +178 -0
- package/dist/stall-escalation.d.ts +1 -0
- package/dist/stall-escalation.js +22 -0
- package/dist/tmux-monitor.d.ts +193 -0
- package/dist/tmux-monitor.js +694 -0
- package/dist/verdict-hash.d.ts +1 -0
- package/dist/verdict-hash.js +62 -0
- package/gates/stage-analysis-verify.sh +84 -0
- package/gates/stage2-requirements-verify.sh +13 -0
- package/gates/stage3-scope-verify.sh +45 -0
- package/gates/stage4-dev-post-verify.sh +64 -0
- package/gates/stage4-dev-verify.sh +36 -0
- package/gates/stage5-coverage-verify.sh +36 -0
- package/gates/stage5-test-verify.sh +24 -0
- package/gates/stage6-commit-verify.sh +41 -0
- package/gates/stage6-post-commit-verify.sh +131 -0
- package/gates/stage7-post-pr-verify.sh +53 -0
- package/gates/stage7-pr-verify.sh +48 -0
- package/gates/stage8-post-review-verify.sh +84 -0
- package/gates/stage8-review-verify.sh +45 -0
- package/gates/verify.sh +44 -0
- package/opencode.json.example +40 -0
- package/package.json +84 -0
- package/postinstall.mjs +56 -0
- package/references/commit-convention.md +130 -0
- package/references/jira-issue-templates.md +203 -0
- package/references/pr-template.md +381 -0
- package/scripts/config.sh +46 -0
- package/scripts/coverage-record.sh +67 -0
- package/scripts/gate-policy-test.sh +152 -0
- package/scripts/install-lib.mjs +1029 -0
- package/scripts/lint-agent-prompts.sh +74 -0
- package/scripts/log-event.sh +44 -0
- package/scripts/model-policy.mjs +183 -0
- package/scripts/publish-if-changed.sh +207 -0
- package/scripts/release.sh +276 -0
- package/scripts/rollback-commits.sh +35 -0
- package/scripts/smoke-test.mjs +194 -0
- package/scripts/state.sh +192 -0
- package/scripts/test-postinstall.mjs +141 -0
- package/scripts/with-fallback.sh +56 -0
- package/scripts/wt-sync-ignored.sh +193 -0
- package/skills/_lib/load-secret.sh +149 -0
- package/skills/bamboo-ci/SKILL.md +81 -0
- package/skills/bamboo-ci/run-bamboo.sh +23 -0
- package/skills/bitbucket-research/SKILL.md +87 -0
- package/skills/bitbucket-research/run-repos.sh +23 -0
- package/skills/confluence-research/SKILL.md +75 -0
- package/skills/confluence-research/run-docs.sh +23 -0
- package/skills/github-oss-research/SKILL.md +59 -0
- package/skills/jira-research/SKILL.md +75 -0
- package/skills/jira-research/run-works.sh +23 -0
- package/src/hooks/guard-bash.sh +67 -0
- package/src/hooks/session-start.sh +96 -0
- package/src/hooks/sync-state.sh +47 -0
- package/stages/01-jira.md +43 -0
- package/stages/01-planning.md +229 -0
- package/stages/02-requirements.md +298 -0
- package/stages/03-scope.md +81 -0
- package/stages/04-analysis.md +281 -0
- package/stages/05-worktree-dev.md +124 -0
- package/stages/06-test.md +161 -0
- package/stages/07-commit.md +229 -0
- package/stages/08-pr.md +177 -0
- package/stages/09-review-comments.md +277 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# guard-bash.sh — PreToolUse(bash) hook 핸들러.
|
|
3
|
+
# stdin으로 hook payload(JSON)를 받아 실행될 bash 명령을 검사한다.
|
|
4
|
+
# - 파괴적 명령: 승인 마커가 없으면 exit 2(차단)
|
|
5
|
+
# - git push: commit substage(3_delivery.commit) 완료 여부만 확인 후 허용
|
|
6
|
+
# 워크플로우 브랜치가 아니면 게이트를 적용하지 않는다.
|
|
7
|
+
#
|
|
8
|
+
# 의존: jq, git
|
|
9
|
+
set -euo pipefail
|
|
10
|
+
HERE="$(cd "$(dirname "$0")" && pwd)"
|
|
11
|
+
PKG_ROOT="$(dirname "$(dirname "$HERE")")"
|
|
12
|
+
# 입력: 인자(opencode 플러그인) 우선, 없으면 stdin JSON(Claude Code) — dual-mode
|
|
13
|
+
if [ -n "${1:-}" ]; then
|
|
14
|
+
CMD="$1"
|
|
15
|
+
ISSUE="${2:-}"
|
|
16
|
+
# plugin 모드: ISSUE=""이면 이 세션에 makdoong2-team 워크플로우 없음 → 게이트 미적용.
|
|
17
|
+
# standalone 모드와 달리 폴백 스캔 없이 즉시 종료한다.
|
|
18
|
+
[ -n "$ISSUE" ] || exit 0
|
|
19
|
+
else
|
|
20
|
+
IN="$(cat 2>/dev/null || true)"
|
|
21
|
+
CMD="$(printf '%s' "$IN" | jq -r '.tool_input.command // .tool_input.cmd // .command // empty' 2>/dev/null || true)"
|
|
22
|
+
ISSUE=""
|
|
23
|
+
fi
|
|
24
|
+
[ -n "$CMD" ] || exit 0
|
|
25
|
+
|
|
26
|
+
_STATE="$PKG_ROOT/scripts/state.sh"
|
|
27
|
+
ROOT="$("$_STATE" root 2>/dev/null || pwd)"
|
|
28
|
+
|
|
29
|
+
# standalone 모드(plugin 외부 직접 실행) 폴백:
|
|
30
|
+
# state.json × 활성 git 워크트리 교집합으로 ISSUE를 추론한다.
|
|
31
|
+
# plugin 모드에서는 이 블록을 건너뛴다(ISSUE가 이미 설정됨).
|
|
32
|
+
if [ -z "$ISSUE" ] && [ -d "$ROOT/.makdoong2-team" ]; then
|
|
33
|
+
_active="$(git -C "$ROOT" worktree list --porcelain 2>/dev/null \
|
|
34
|
+
| grep '^branch refs/heads/' | sed 's|^branch refs/heads/||' || true)"
|
|
35
|
+
for _sdir in "$ROOT"/.makdoong2-team/*/; do
|
|
36
|
+
[ -f "${_sdir}state.json" ] || continue
|
|
37
|
+
_key="$(basename "$_sdir")"
|
|
38
|
+
if printf '%s' "$_active" | grep -qE "(^|/)feature/$_key$"; then
|
|
39
|
+
ISSUE="$_key"
|
|
40
|
+
break
|
|
41
|
+
fi
|
|
42
|
+
done
|
|
43
|
+
fi
|
|
44
|
+
[ -n "$ISSUE" ] || exit 0
|
|
45
|
+
APPROVE="$ROOT/.makdoong2-team/$ISSUE/APPROVED_DESTRUCTIVE"
|
|
46
|
+
|
|
47
|
+
if printf '%s' "$CMD" | grep -qE 'git(\s+\S+)*\s+(push\s+--force(-with-lease)?|reset\s+--hard|branch\s+-D|worktree\s+(add|remove)\s+--force)|rm\s+-rf'; then
|
|
48
|
+
if [ ! -f "$APPROVE" ]; then
|
|
49
|
+
echo "MAKDOONG2-GATE BLOCKED: 파괴적 명령은 사용자 명시 승인 필요." >&2
|
|
50
|
+
echo " 대상: $CMD" >&2
|
|
51
|
+
echo " 승인하려면: touch \"$APPROVE\" 후 재시도" >&2
|
|
52
|
+
exit 2
|
|
53
|
+
fi
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
if printf '%s' "$CMD" | grep -qE 'git(\s+\S+)*\s+push(\s|$)'; then
|
|
57
|
+
# stage7-pr-verify.sh 전체를 재사용하면 "remote branch 없음 → push 불가" circular dependency가 발생한다.
|
|
58
|
+
# (stage7은 remote branch 존재를 검증하지만, remote branch는 push해야 생긴다.)
|
|
59
|
+
# guard에서는 commit substage 완료 여부만 확인한다.
|
|
60
|
+
# remote branch 존재 확인은 auto_advance_stage → 3_delivery.pr 진입 게이트에서 수행한다.
|
|
61
|
+
_commit_done="$("$_STATE" get "$ISSUE" '.stages."3_delivery".substages."commit".done' 2>/dev/null || echo '__MISSING__')"
|
|
62
|
+
if [ "$_commit_done" != "true" ]; then
|
|
63
|
+
echo "MAKDOONG2-GATE BLOCKED [git push]: 3_delivery.commit 미완료 — commit substage를 먼저 완료하라" >&2
|
|
64
|
+
exit 2
|
|
65
|
+
fi
|
|
66
|
+
fi
|
|
67
|
+
exit 0
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# session-start.sh — emit a context reminder when a session starts.
|
|
3
|
+
#
|
|
4
|
+
# 목적:
|
|
5
|
+
# 부장님 세션 재시작 시 state.json + events.ndjson에서 가장 중요한 신호를
|
|
6
|
+
# stdout으로 다시 주입한다 — 부장님이 컨텍스트를 잃지 않도록.
|
|
7
|
+
#
|
|
8
|
+
# 보고 내용:
|
|
9
|
+
# - 현재 issue (브랜치명에서 추출)
|
|
10
|
+
# - 단계별 done / pending 요약
|
|
11
|
+
# - verification_pending=true 인 단계 (사용자 승인 차단 중)
|
|
12
|
+
# - 마지막 3개 이벤트
|
|
13
|
+
#
|
|
14
|
+
# 사용:
|
|
15
|
+
# - Claude Code SessionStart hook 등록: settings.json `hooks.SessionStart`에
|
|
16
|
+
# 이 파일 경로 추가.
|
|
17
|
+
# - 또는 부장님이 세션 시작 시 직접 호출: `bash $HOME/.config/opencode/plugins/makdoong2-team/src/hooks/session-start.sh`
|
|
18
|
+
#
|
|
19
|
+
# 의존: jq, git
|
|
20
|
+
set -euo pipefail
|
|
21
|
+
|
|
22
|
+
HOOK_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
23
|
+
PKG_ROOT="$(dirname "$(dirname "$HOOK_DIR")")"
|
|
24
|
+
_STATE="$PKG_ROOT/scripts/state.sh"
|
|
25
|
+
ISSUE="$("$_STATE" issue 2>/dev/null || true)"
|
|
26
|
+
|
|
27
|
+
# 브랜치에 이슈키가 없으면 조용히 종료 (워크플로우 외부 작업)
|
|
28
|
+
[ -n "$ISSUE" ] || exit 0
|
|
29
|
+
|
|
30
|
+
ROOT="$("$_STATE" root)"
|
|
31
|
+
DIR="$ROOT/.makdoong2-team/$ISSUE"
|
|
32
|
+
STATE_FILE="$DIR/state.json"
|
|
33
|
+
EVENTS_FILE="$DIR/events.ndjson"
|
|
34
|
+
|
|
35
|
+
# state.json이 없으면 (아직 stage 1 초기화 전) 종료
|
|
36
|
+
[ -f "$STATE_FILE" ] || exit 0
|
|
37
|
+
|
|
38
|
+
echo "=== makdoong2-team SessionStart: $ISSUE ==="
|
|
39
|
+
|
|
40
|
+
CATEGORY="$(jq -r '.policy.category // "uncategorized"' "$STATE_FILE" 2>/dev/null || true)"
|
|
41
|
+
COMMIT_AUTO="$(jq -r '.policy.auto_approve."3_delivery.commit" // "unset"' "$STATE_FILE" 2>/dev/null || true)"
|
|
42
|
+
echo ""
|
|
43
|
+
echo "## 작업 범주: $CATEGORY"
|
|
44
|
+
if [ "$COMMIT_AUTO" = "false" ]; then
|
|
45
|
+
echo " → HITL opt-in: 6단계 커밋 직전 사람 승인 필요 (변경 보고서 + 승인 마커)"
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
echo ""
|
|
49
|
+
echo "## 단계 진행 현황"
|
|
50
|
+
jq -r '
|
|
51
|
+
.stages."1_planning" as $p1 |
|
|
52
|
+
.stages."2_implementation" as $p2 |
|
|
53
|
+
.stages."3_delivery" as $p3 |
|
|
54
|
+
|
|
55
|
+
# Planning substages
|
|
56
|
+
($p1.substages.jira // {} | " 1_planning.jira: done=" + ((.done // false) | tostring) + (if .approved_by_user then " (approved)" else "" end)),
|
|
57
|
+
($p1.substages.requirements // {} | " 1_planning.requirements: done=" + ((.done // false) | tostring) + (if .approved_by_user then " (approved)" else "" end)),
|
|
58
|
+
($p1.substages.scope // {} | " 1_planning.scope: done=" + ((.done // false) | tostring) + (if .approved_by_user then " (approved)" else "" end)),
|
|
59
|
+
|
|
60
|
+
# Implementation substages
|
|
61
|
+
($p2.substages.analysis // {} | " 2_implementation.analysis: done=" + ((.done // false) | tostring) + (if .skipped then " (skipped)" else "" end)),
|
|
62
|
+
($p2.substages.dev // {} | " 2_implementation.dev: done=" + ((.done // false) | tostring) + (if .approved_by_user then " (approved)" else "" end)),
|
|
63
|
+
($p2.substages.test // {} | " 2_implementation.test: unit=" + (.unit // "none") + " / integration=" + (.integration // "none") + " / coverage=" + (.coverage // "none")),
|
|
64
|
+
|
|
65
|
+
# Delivery substages
|
|
66
|
+
($p3.substages.commit // {} | " 3_delivery.commit: done=" + ((.done // false) | tostring) + (if .approved_by_user then " (approved)" else "" end)),
|
|
67
|
+
($p3.substages.pr // {} | " 3_delivery.pr: done=" + ((.done // false) | tostring) + " / draft_url=" + (if .draft_url then "set" else "null" end)),
|
|
68
|
+
($p3.substages.review // {} | " 3_delivery.review: comments=" + ((.comments // 0) | tostring))
|
|
69
|
+
' "$STATE_FILE"
|
|
70
|
+
|
|
71
|
+
echo ""
|
|
72
|
+
echo "## verification_pending=true (사용자 승인 대기 중)"
|
|
73
|
+
PENDING=$(jq -r '
|
|
74
|
+
[
|
|
75
|
+
(.stages."1_planning".substages // {} | to_entries[] | select(.value.verification_pending == true) | "1_planning." + .key),
|
|
76
|
+
(.stages."2_implementation".substages // {} | to_entries[] | select(.value.verification_pending == true) | "2_implementation." + .key),
|
|
77
|
+
(.stages."3_delivery".substages // {} | to_entries[] | select(.value.verification_pending == true) | "3_delivery." + .key)
|
|
78
|
+
] | .[]
|
|
79
|
+
' "$STATE_FILE" 2>/dev/null || true)
|
|
80
|
+
if [ -n "$PENDING" ]; then
|
|
81
|
+
echo "$PENDING" | sed 's/^/ ⚠️ /'
|
|
82
|
+
echo " → 해소: state.sh set $ISSUE '.stages.\"<phase>\".substages.\"<substage>\".approved_by_user' 'true' + verification_pending=false"
|
|
83
|
+
else
|
|
84
|
+
echo " (없음)"
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
echo ""
|
|
88
|
+
echo "## 최근 이벤트 (마지막 3개)"
|
|
89
|
+
if [ -f "$EVENTS_FILE" ]; then
|
|
90
|
+
tail -3 "$EVENTS_FILE" 2>/dev/null | sed 's/^/ /' || echo " (이벤트 로그 비어있음)"
|
|
91
|
+
else
|
|
92
|
+
echo " (events.ndjson 없음 — 첫 dispatch 후 자동 생성)"
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
echo ""
|
|
96
|
+
echo "=== end SessionStart ==="
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# sync-state.sh — PostToolUse(bash) hook 핸들러.
|
|
3
|
+
# bash 실행 후, 기계적으로 감지 가능한 완료 사실만 state.json에 반영한다(best-effort 보조).
|
|
4
|
+
# 의미적(semantic) 마커(요구사항 승인, PR URL 등)는
|
|
5
|
+
# 각 단계에서 에이전트가 state.sh set 으로 명시적으로 기록한다.
|
|
6
|
+
# 의존: jq, git
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
HERE="$(cd "$(dirname "$0")" && pwd)"
|
|
9
|
+
PKG_ROOT="$(dirname "$(dirname "$HERE")")"
|
|
10
|
+
# 입력: 인자(opencode 플러그인) 우선, 없으면 stdin JSON(Claude Code) — dual-mode
|
|
11
|
+
if [ -n "${1:-}" ]; then
|
|
12
|
+
CMD="$1"; OUT="${2:-}"; ISSUE="${3:-}"
|
|
13
|
+
[ -n "$ISSUE" ] || exit 0 # plugin 모드, 워크플로우 없음 → sync 불필요
|
|
14
|
+
else
|
|
15
|
+
IN="$(cat 2>/dev/null || true)"
|
|
16
|
+
CMD="$(printf '%s' "$IN" | jq -r '.tool_input.command // .tool_input.cmd // .command // empty' 2>/dev/null || true)"
|
|
17
|
+
OUT="$(printf '%s' "$IN" | jq -r '.tool_response.output // .tool_response // .tool_output // .output // empty' 2>/dev/null || true)"
|
|
18
|
+
ISSUE=""
|
|
19
|
+
fi
|
|
20
|
+
_STATE="$PKG_ROOT/scripts/state.sh"
|
|
21
|
+
ROOT="$("$_STATE" root 2>/dev/null || pwd)"
|
|
22
|
+
|
|
23
|
+
# standalone 모드(plugin 외부 직접 실행) 폴백:
|
|
24
|
+
# state.json × 활성 git 워크트리 교집합으로 ISSUE를 추론한다.
|
|
25
|
+
# plugin 모드에서는 이 블록을 건너뛴다(ISSUE가 이미 설정됨).
|
|
26
|
+
if [ -z "$ISSUE" ] && [ -d "$ROOT/.makdoong2-team" ]; then
|
|
27
|
+
_active="$(git -C "$ROOT" worktree list --porcelain 2>/dev/null \
|
|
28
|
+
| grep '^branch refs/heads/' | sed 's|^branch refs/heads/||' || true)"
|
|
29
|
+
for _sdir in "$ROOT"/.makdoong2-team/*/; do
|
|
30
|
+
[ -f "${_sdir}state.json" ] || continue
|
|
31
|
+
_key="$(basename "$_sdir")"
|
|
32
|
+
if printf '%s' "$_active" | grep -qE "(^|/)feature/$_key$"; then
|
|
33
|
+
ISSUE="$_key"
|
|
34
|
+
break
|
|
35
|
+
fi
|
|
36
|
+
done
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
[ -n "$ISSUE" ] && [ -n "$CMD" ] || exit 0
|
|
40
|
+
S(){ "$_STATE" set "$ISSUE" "$1" "$2" >/dev/null 2>&1 || true; }
|
|
41
|
+
|
|
42
|
+
# (test 결과 자동감지는 제거됨 — 단위/통합 구분이 명령으로만 식별 불가하고,
|
|
43
|
+
# SBT는 BUILD SUCCESSFUL 출력 패턴이 다름. 테스트 결과는 5단계에서
|
|
44
|
+
# state.sh set으로 unit/integration 각각 명시적으로 기록한다.)
|
|
45
|
+
# 커밋 감지
|
|
46
|
+
if printf '%s' "$CMD" | grep -qE 'git(\s+\S+)*\s+commit(\s|$)'; then S '.stages."3_delivery".substages."commit".done' 'true'; fi
|
|
47
|
+
exit 0
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# 1단계: Jira 이슈 조회 — `1_planning.jira` substage
|
|
2
|
+
|
|
3
|
+
**목적**: 이슈 내용을 확보한다.
|
|
4
|
+
**진입 게이트**: 없음 (시작 단계).
|
|
5
|
+
|
|
6
|
+
> `<SCRIPTS_DIR>`는 부장님이 dispatch_stage 프롬프트로 주입한 절대경로다. 이 값을 그대로 대입하여 실행한다.
|
|
7
|
+
|
|
8
|
+
## 작업
|
|
9
|
+
|
|
10
|
+
`jira-research` 스킬을 사용해 이슈키로 조회한다(`works` MCP는 해당 스킬 frontmatter에 embedded — `skill_mcp` 경유). 다음을 수집한다.
|
|
11
|
+
- summary, description, status, 담당자
|
|
12
|
+
- 코멘트 전체 이력
|
|
13
|
+
- 링크된 이슈와 서브태스크 (2단계 깊이까지)
|
|
14
|
+
|
|
15
|
+
## 출력
|
|
16
|
+
|
|
17
|
+
이슈 핵심 내용을 3~5줄로 요약하여 사용자에게 제시한다. 출처 URL을 함께 포함한다.
|
|
18
|
+
|
|
19
|
+
## 최종 자가 검증 (Pre-Completion Checklist)
|
|
20
|
+
|
|
21
|
+
`done=true` 기록 직전, 다음 5항목을 자체 확인하고 결과를 state.json에 기록한다.
|
|
22
|
+
하나라도 false면 완료 기록 금지 — 미충족 항목으로 되돌아간다.
|
|
23
|
+
|
|
24
|
+
| 항목 | 확인 |
|
|
25
|
+
|---|---|
|
|
26
|
+
| 1 | `.stages."1_planning".substages."jira".template_validation` 6항목(content_template_match / content_quality_adequate / priority_set / assignee_set / reporter_set / fix_version_handled) 결과가 모두 기록되었다 |
|
|
27
|
+
| 2 | 실패 항목이 있었다면 인터뷰가 완료되었거나(`interview_completed=true`) 사용자 명시 수용을 받았다 |
|
|
28
|
+
| 3 | `validation_passed=true`는 6항목 통과 또는 사용자 명시 수용 직후에만 기록했다 (임의 우회 X) |
|
|
29
|
+
| 4 | Jira 메타데이터(priority/assignee/reporter 등)를 일체 수정하지 않았다 (RO 원칙) |
|
|
30
|
+
| 5 | 이슈 요약·출처 URL을 사용자에게 보고했다 |
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."1_planning".substages."jira".self_check' \
|
|
34
|
+
'{"validations_recorded": true, "interview_handled": true, "validation_passed_legit": true, "ro_preserved": true, "summary_reported": true}'
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## 완료 기록
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
ROOT="$(bash <SCRIPTS_DIR>/state.sh root)"
|
|
41
|
+
bash <SCRIPTS_DIR>/state.sh init <이슈키> "$ROOT" # state.json 생성(워크트리 전이면 4단계 후 갱신)
|
|
42
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."1_planning".substages."jira".done' 'true'
|
|
43
|
+
```
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# 1–3단계 통합 Planning — `1_planning.{jira,requirements,scope}` 연속 처리
|
|
2
|
+
|
|
3
|
+
**목적**: Jira 조회 → 요구사항 확정 → 개발 범위 파악을 **단일 세션**에서 완료한다.
|
|
4
|
+
**속도**: 3개 substage dispatch(모델 호출 3회)를 1회로 단축.
|
|
5
|
+
**진입 게이트**: 없음 (첫 단계).
|
|
6
|
+
|
|
7
|
+
> `<SCRIPTS_DIR>` / `<STAGES_DIR>` 는 부장님이 주입한 절대경로다. 그대로 대입한다.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 0. 재개 감지 (필수 — 첫 번째 행동)
|
|
12
|
+
|
|
13
|
+
세션 시작 즉시 state.json을 확인해 어디까지 완료됐는지 파악한다.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bash <SCRIPTS_DIR>/state.sh get <이슈키> '.stages."1_planning".substages."jira".done'
|
|
17
|
+
bash <SCRIPTS_DIR>/state.sh get <이슈키> '.stages."1_planning".substages."requirements".done'
|
|
18
|
+
bash <SCRIPTS_DIR>/state.sh get <이슈키> '.stages."1_planning".substages."scope".done'
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
- `jira.done=true` → Phase 1 건너뛰고 Phase 2로 직행
|
|
22
|
+
- `jira.done=true` + `requirements.done=true` → Phase 3으로 직행
|
|
23
|
+
- 셋 다 `true` → 모두 완료. 완료 메시지 출력 후 종료
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Phase 1: Jira 조회 및 검증 (`1_planning.jira`)
|
|
28
|
+
|
|
29
|
+
### 1-1. Jira 이슈 조회
|
|
30
|
+
|
|
31
|
+
`jira-research` 스킬의 MCP(`works`)를 사용해 조회한다. 수집 항목:
|
|
32
|
+
- summary, description, status, 담당자
|
|
33
|
+
- 코멘트 전체 이력
|
|
34
|
+
- 링크된 이슈와 서브태스크 (2단계 깊이)
|
|
35
|
+
|
|
36
|
+
이슈 핵심 내용을 3~5줄로 요약해 출력한다. 출처 URL 포함.
|
|
37
|
+
|
|
38
|
+
### 1-2. 템플릿 검증 (6항목)
|
|
39
|
+
|
|
40
|
+
| 항목 | 확인 방법 |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `content_template_match` | 내용이 템플릿 구조를 따르는가 |
|
|
43
|
+
| `content_quality_adequate` | 내용이 구현 가능 수준으로 충분한가 |
|
|
44
|
+
| `priority_set` | Priority 필드가 설정되어 있는가 |
|
|
45
|
+
| `assignee_set` | Assignee가 지정되어 있는가 |
|
|
46
|
+
| `reporter_set` | Reporter가 설정되어 있는가 |
|
|
47
|
+
| `fix_version_handled` | Fix Version 처리 여부(없음도 의도면 OK) |
|
|
48
|
+
|
|
49
|
+
실패 항목이 있으면 해당 항목과 이유를 출력한다. Jira 메타데이터 수정 금지(RO 원칙).
|
|
50
|
+
|
|
51
|
+
### 1-3. Jira 마커 기록
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."1_planning".substages."jira".template_validation' \
|
|
55
|
+
'{"content_template_match":true,"content_quality_adequate":true,"priority_set":true,"assignee_set":true,"reporter_set":true,"fix_version_handled":true}'
|
|
56
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."1_planning".substages."jira".validation_passed' 'true'
|
|
57
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."1_planning".substages."jira".self_check' \
|
|
58
|
+
'{"validations_recorded":true,"interview_handled":true,"validation_passed_legit":true,"ro_preserved":true,"summary_reported":true}'
|
|
59
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."1_planning".substages."jira".done' 'true'
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Phase 2: 요구사항 구체화 (`1_planning.requirements`)
|
|
65
|
+
|
|
66
|
+
### 2-1. 복잡도 분류
|
|
67
|
+
|
|
68
|
+
Jira 조회 결과로 작업 의도를 분류한다:
|
|
69
|
+
|
|
70
|
+
| 유형 | 기준 |
|
|
71
|
+
|---|---|
|
|
72
|
+
| **Simple** | 단순 수정, 명확한 단일 변경, ≤1일 |
|
|
73
|
+
| **Standard** | 일반 Task/Improvement, 명확한 기능 단위 |
|
|
74
|
+
| **Complex** | 시스템 전반 영향, 아키텍처 변경, 성능 임계점 |
|
|
75
|
+
| **Ambiguous** | description이 추상적 ("개선"·"정리"만 있음) |
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."1_planning".substages."requirements".intent_type' '"Standard"'
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 2-2. 요구사항 초안 파일 생성
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# 상대경로 (repo/worktree root 기준) — cwd 독립적 접근 보장.
|
|
85
|
+
# planner 는 main repo cwd 에서 실행되므로 실제 물리 파일은 main repo 하위에 생성되고,
|
|
86
|
+
# 이후 dev 진입 시 wt-sync-ignored.sh 가 worktree 로 동일 상대경로에 복사한다.
|
|
87
|
+
mkdir -p .makdoong2-team/<이슈키>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
파일 (repo/worktree root 기준 상대경로): `.makdoong2-team/<이슈키>/requirements-draft.md`
|
|
91
|
+
|
|
92
|
+
초안 구조:
|
|
93
|
+
```markdown
|
|
94
|
+
# 요구사항 초안 — <이슈키>
|
|
95
|
+
## 복잡도 분류: <Simple|Standard|Complex|Ambiguous>
|
|
96
|
+
## 수집된 정보
|
|
97
|
+
## 수정 파일 후보
|
|
98
|
+
## 검증 기준 (Acceptance Criteria)
|
|
99
|
+
## 스코프 아웃
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# state.json 에는 반드시 상대경로만 저장한다 (절대경로 저장 시 다른 cwd 에서 접근 불가 → Read hang 유발).
|
|
104
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> \
|
|
105
|
+
'.stages."1_planning".substages."requirements".draft_path' '".makdoong2-team/<이슈키>/requirements-draft.md"'
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### 2-3. 다출처 교차 조사
|
|
109
|
+
|
|
110
|
+
`skill_mcp`으로 필요한 스킬을 순차 호출한다. **outer-world 에이전트 위임 금지.**
|
|
111
|
+
|
|
112
|
+
- **조사 A (`jira-research`)**: 에픽/상위 이슈, 링크 이슈, 관련 코멘트에서 구체화된 요구
|
|
113
|
+
- **조사 B (`confluence-research`)**: 관련 설계 문서, ADR, API 스펙, 운영 가이드
|
|
114
|
+
- **조사 C (`bitbucket-research`)**: 수정 대상 파일/클래스 현재 구현, 관련 PR 이력, 테스트 패턴
|
|
115
|
+
|
|
116
|
+
Simple 이슈는 조사 A + C만으로 축소 가능.
|
|
117
|
+
|
|
118
|
+
### 2-4. 요구사항 체크리스트 확인
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
[ ] 기능적 요구사항 — 입력/출력 형식, 경계 케이스
|
|
122
|
+
[ ] 비기능적 요구사항 — 성능, 동시성, 보안
|
|
123
|
+
[ ] 호환성·마이그레이션 — 기존 API 호환, 데이터 마이그레이션
|
|
124
|
+
[ ] 검증 기준(Acceptance Criteria) — 완료 선언 가능한 객관적 조건
|
|
125
|
+
[ ] 범위 경계 — 이번 이슈에서 다루지 않는 것
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
조사 간 충돌이 있으면 state.json에 기록하고 출력에 명시한다.
|
|
129
|
+
**인터뷰가 필요하다고 판단되면**: 미결 항목을 명시하고 `interview_required=true`를 기록 후 Phase 완료 마커는 설정하지 않고 즉시 출력한다. 부장님이 사용자 인터뷰를 수행한 뒤 재dispatch한다.
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."1_planning".substages."requirements".interview_required' 'true'
|
|
133
|
+
# ↑ 인터뷰 필요 시에만 기록. 이후 종료 — 부장님이 인터뷰 후 재dispatch
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
인터뷰가 불필요한 경우:
|
|
137
|
+
```bash
|
|
138
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."1_planning".substages."requirements".interview_required' 'false'
|
|
139
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."1_planning".substages."requirements".interview_completed' 'true'
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 2-5. 작업 범주화 (minor / major)
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
base = (intent_type ∈ {Simple, Standard}) ? "minor" : "major"
|
|
146
|
+
category = (criticality == "critical" OR scope_size == "large") ? "major" : base
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
| 차원 | 값 |
|
|
150
|
+
|---|---|
|
|
151
|
+
| `change_type` | `feature` / `bugfix` / `refactor` / `other` |
|
|
152
|
+
| `scope_size` | `small` (단일~소수 파일) / `large` (다수 파일·모듈) |
|
|
153
|
+
| `criticality` | `normal` / `critical` (인증·결제·보안·마이그레이션) |
|
|
154
|
+
|
|
155
|
+
**auto_approve 맵** (minor/major 공통 — 전 단계 무인 진행이 기본):
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.policy' \
|
|
159
|
+
'{"intent_type":"Standard","change_type":"bugfix","scope_size":"small","criticality":"normal","category":"minor","auto_approve":{"1_planning.requirements":true,"1_planning.scope":true,"3_delivery.commit":true,"3_delivery.pr":true},"rationale":"<한 줄 근거>","categorized_by":"1_planning.requirements"}'
|
|
160
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.policy.categorized_at' "\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\""
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
major 로 판정된 경우에도 `auto_approve` 맵은 **모두 true** 로 두고 `"category":"major"` 만 다르게 기록한다. HITL 을 강제해야 하는 이슈 유형별 opt-in 이 필요한 경우에만 특정 substage 를 명시적으로 `false` 로 설정한다.
|
|
164
|
+
|
|
165
|
+
### 2-6. Requirements 완료 기록
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."1_planning".substages."requirements".self_check' \
|
|
169
|
+
'{"checklist_complete":true,"conflicts_resolved":true,"user_confirmed":true,"scope_clean":true,"draft_synced":true,"categorized":true}'
|
|
170
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."1_planning".substages."requirements".verification_pending' 'false'
|
|
171
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."1_planning".substages."requirements".done' 'true'
|
|
172
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."1_planning".substages."requirements".done_at' "\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\""
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Phase 3: 개발 범위 파악 (`1_planning.scope`)
|
|
178
|
+
|
|
179
|
+
2단계 조사 결과로 코드 수정 계획을 수립한다. 2단계 `bitbucket-research` 탐색을 이어서 사용한다.
|
|
180
|
+
|
|
181
|
+
### 3-1. 범위 출력
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
### 개발 범위
|
|
185
|
+
**수정 파일**: <path>: <변경 요지>
|
|
186
|
+
**추가 파일**: <path>: <목적>
|
|
187
|
+
**테스트 범위**: 단위(<대상 클래스/메서드>), 통합(<빌드 플랜명/시나리오>)
|
|
188
|
+
**영향 범위**: <모듈>: <영향 요지>
|
|
189
|
+
**예상 작업 단위(커밋 후보)**: 1. <단위1> 2. <단위2>
|
|
190
|
+
**스코프 아웃**: <이번 이슈에서 다루지 않는 것>
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### 3-2. 범주 재평가 (escalation — 하향 금지)
|
|
194
|
+
|
|
195
|
+
실제 수정/추가 파일과 작업 단위가 확정된 뒤, `scope_size`·`criticality`를 재평가한다.
|
|
196
|
+
|
|
197
|
+
minor → major로 상향될 경우에만 아래 항목들을 갱신한다. `auto_approve` 맵은 건드리지 않고 **모두 true 로 유지**한다 — 상향은 위험도 라벨 정정에 그치며 흐름 자체는 무인 진행으로 유지된다:
|
|
198
|
+
```bash
|
|
199
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.policy.category' '"major"'
|
|
200
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.policy.scope_size' '"large"'
|
|
201
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.policy.categorized_by' '"1_planning.scope"'
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### 3-3. Scope 완료 기록
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."1_planning".substages."scope".self_check' \
|
|
208
|
+
'{"paths_explicit":true,"test_scope_defined":true,"atomic_units":true,"scope_out_listed":true,"user_approved":true}'
|
|
209
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."1_planning".substages."scope".verification_pending' 'false'
|
|
210
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."1_planning".substages."scope".done' 'true'
|
|
211
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."1_planning".substages."scope".done_at' "\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\""
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## 최종 출력
|
|
217
|
+
|
|
218
|
+
모든 Phase 완료 후:
|
|
219
|
+
|
|
220
|
+
```
|
|
221
|
+
[Planning 완료]
|
|
222
|
+
- 이슈: <요약>
|
|
223
|
+
- 범주: <minor|major> (<intent_type>, <change_type>)
|
|
224
|
+
- 수정 예정 파일: <목록>
|
|
225
|
+
- 커밋 단위: <목록>
|
|
226
|
+
- 스코프 아웃: <목록>
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
> **인터뷰 중단 경우**: `interview_required=true`를 기록하고 미결 항목을 출력한 뒤 즉시 종료. requirements.done은 기록하지 않는다. 부장님이 사용자 인터뷰 후 context에 답변을 포함해 재dispatch한다.
|