makdoong2-team 1.3.0 → 1.4.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/README.md +160 -115
- package/agents/makdoong2-planner.md +1 -0
- package/agents/makdoong2-researcher.md +67 -0
- package/assets/makdoong2-team.default.json +4 -0
- package/assets/makdoong2-team.schema.json +18 -0
- package/bin/cli.js +1 -1
- package/dist/agent-stage-config.js +10 -0
- package/dist/config.d.ts +8 -0
- package/dist/model-fallback-policy.js +5 -0
- package/dist/opencode-plugin.js +260 -1
- package/dist/research-fanout.d.ts +133 -0
- package/dist/research-fanout.js +291 -0
- package/dist/tmux-monitor.d.ts +1 -1
- package/dist/tmux-monitor.js +3 -3
- package/opencode.json.example +1 -0
- package/package.json +3 -2
- package/scripts/install-lib.mjs +1 -1
- package/scripts/model-policy.mjs +5 -0
- package/scripts/rollback-commits.sh +7 -1
- package/scripts/run-tests.mjs +140 -0
- package/scripts/test-ubuntu.sh +179 -0
- package/stages/01-planning.md +19 -6
- package/stages/02-requirements.md +32 -6
package/README.md
CHANGED
|
@@ -1,48 +1,127 @@
|
|
|
1
1
|
# makdoong2-team
|
|
2
2
|
|
|
3
|
-
> Jira
|
|
4
|
-
>
|
|
5
|
-
> **Phase**: `1_planning` (jira/requirements/scope) → `2_implementation` (dev/test) → `3_delivery` (commit/pr/review)
|
|
3
|
+
> Jira 이슈 하나를 **3 phase · 9 substage** 로 쪼개 역할별 막둥이(전문 에이전트)에게 위임하는 self-contained opencode 플러그인.
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
```
|
|
6
|
+
1_planning jira → requirements → scope planner
|
|
7
|
+
↓ worktree 자동 생성
|
|
8
|
+
2_implementation analysis → dev → test analyzer, engineer
|
|
9
|
+
3_delivery commit → pr → review publisher
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
부장님(`makdoong2-team-leader`)이 각 단계 진입을 **셸 게이트**로 검증하고, 통과한 단계만 격리된 서브세션의 막둥이에게 넘긴다. 막둥이가 끝나면 `makdoong2-verifier` 가 산출물을 2차 검증한다.
|
|
13
|
+
|
|
14
|
+
---
|
|
8
15
|
|
|
9
|
-
|
|
16
|
+
## 1. 설치
|
|
17
|
+
|
|
18
|
+
공개 npm 패키지 [`makdoong2-team`](https://www.npmjs.com/package/makdoong2-team) 이다. 별도 registry 설정이나 인증이 필요 없다.
|
|
10
19
|
|
|
11
20
|
```bash
|
|
12
|
-
npm install -g makdoong2-team #
|
|
13
|
-
makdoong2-team install # opencode 배포
|
|
21
|
+
npm install -g makdoong2-team # 모듈 설치
|
|
22
|
+
makdoong2-team install # opencode 에 배포
|
|
14
23
|
makdoong2-team doctor # 설치 진단
|
|
15
24
|
```
|
|
16
25
|
|
|
17
|
-
|
|
26
|
+
| 명령 | 하는 일 |
|
|
27
|
+
|---|---|
|
|
28
|
+
| `install` | agents / skills / config seed 를 `~/.config/opencode/` 에 복사하고 `opencode.json` 을 패치 |
|
|
29
|
+
| `uninstall` | 위에서 복사한 파일 제거 |
|
|
30
|
+
| `doctor` | 설치 상태·설정 오류·state.json 오염 진단 |
|
|
31
|
+
| `validate` | `makdoong2-team.json` 의 모델 정책 위반 사전 검증 |
|
|
32
|
+
|
|
33
|
+
**요구 환경**: opencode ≥ 1.18.0, Node ≥ 20, tmux ≥ 3.0.
|
|
34
|
+
|
|
35
|
+
**설치되는 것과 안 되는 것**
|
|
36
|
+
|
|
37
|
+
- 복사됨 — `agents/*.md`, 리서치 skill, 최초 1회 `makdoong2-team.json` (재설치 시 보존, `--force` 로 덮어쓰기)
|
|
38
|
+
- 복사 안 됨 — `dist`, `gates`, `stages`, `scripts`. npm 모듈 안에서 직접 로드된다.
|
|
39
|
+
- `install` 은 `~/.cache/opencode/packages/makdoong2-team@latest/` 를 전역 모듈로 심볼릭 링크한다. opencode 가 registry 에서 다시 받지 않고 방금 설치한 버전을 쓰게 만드는 장치다.
|
|
40
|
+
|
|
41
|
+
로컬 개발 설치는 `npm pack` 후 tgz 를 `npm install -g` 한다.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 2. 에이전트와 단계
|
|
46
|
+
|
|
47
|
+
에이전트 **7개**. 권한이 좁을수록 사고 반경이 좁다는 원칙으로 나눴다.
|
|
48
|
+
|
|
49
|
+
| 에이전트 | 담당 | 권한 |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| `makdoong2-team-leader` | 라우팅 (부장님) | **git 전면 deny**, 파일 편집 불가 — 위임만 |
|
|
52
|
+
| `makdoong2-planner` | 1_planning 3단계 | 읽기 전용 + 리서치 MCP |
|
|
53
|
+
| `makdoong2-analyzer` | 2_implementation.analysis | 읽기 + 분석 산출물 write |
|
|
54
|
+
| `makdoong2-engineer` | dev / test | edit·write 허용, commit/push deny |
|
|
55
|
+
| `makdoong2-publisher` | 3_delivery 3단계 | **git add/commit/push 직접 실행** + bitbucket MCP |
|
|
56
|
+
| `makdoong2-verifier` | 메타 검증 | 읽기 전용 |
|
|
57
|
+
| `makdoong2-researcher` | 리서치 fan-out 워커 | 읽기 전용 + 리서치 MCP — 소스 1개 전담 |
|
|
58
|
+
|
|
59
|
+
> **Publisher 는 직접 실행자다.** commit·pr·review 모두 publisher 가 worktree 에서 직접 git 명령과 MCP 를 호출한다. 부장님은 git 권한이 아예 없고 dispatch 와 verdict 수신만 한다. (구버전의 "spec 계산 → 부장님 실행" 하이브리드 모델은 폐기됐다.)
|
|
60
|
+
|
|
61
|
+
### Substage → agent → spec 매핑
|
|
62
|
+
|
|
63
|
+
| Substage | Agent | Stage spec | 게이트 |
|
|
64
|
+
|---|---|---|---|
|
|
65
|
+
| `1_planning.jira` | planner | `stages/01-planning.md` | `verify.sh` |
|
|
66
|
+
| `1_planning.requirements` | planner | `stages/02-requirements.md` | `stage2-requirements-verify.sh` |
|
|
67
|
+
| `1_planning.scope` | planner | `stages/03-scope.md` | `stage3-scope-verify.sh` |
|
|
68
|
+
| `2_implementation.analysis` | analyzer | `stages/04-analysis.md` | `stage-analysis-verify.sh` |
|
|
69
|
+
| `2_implementation.dev` | engineer | `stages/05-worktree-dev.md` | `stage4-dev-verify.sh` |
|
|
70
|
+
| `2_implementation.test` | engineer | `stages/06-test.md` | `stage5-test-verify.sh` + coverage |
|
|
71
|
+
| `3_delivery.commit` | publisher | `stages/07-commit.md` | `stage6-commit-verify.sh` |
|
|
72
|
+
| `3_delivery.pr` | publisher | `stages/08-pr.md` | `stage7-pr-verify.sh` |
|
|
73
|
+
| `3_delivery.review` | publisher | `stages/09-review-comments.md` | `stage8-review-verify.sh` |
|
|
74
|
+
|
|
75
|
+
매핑 원본은 `src/agent-stage-config.ts` (`STAGE_SPEC_FILES`, `agentForStage()`).
|
|
76
|
+
|
|
77
|
+
**통합 Planning**: `1_planning.jira` 를 dispatch 하면 `01-planning.md` 명세에 따라 **한 planner 세션이 jira → requirements → scope 를 연속 처리**한다. requirements / scope 단독 dispatch 는 planner 가 중간에 실패했을 때의 폴백 경로다.
|
|
78
|
+
|
|
79
|
+
### 작업 범주화
|
|
80
|
+
|
|
81
|
+
`1_planning.requirements` 가 작업을 `.policy.category` (`minor` | `major`) 로 분류한다. `1_planning.scope` 는 minor → major 상향만 허용한다.
|
|
82
|
+
|
|
83
|
+
**두 범주 모두 기본은 무인 진행**이다. 실제 승인 여부는 `.policy.auto_approve.<substage>` 마커가 결정하고 기본값이 전 substage `true` 이기 때문이다. `category` 는 위험도 라벨이자 향후 opt-in 훅의 스위치로 남겨둔 값이다. HITL 이 필요하면 planner 가 특정 substage 를 `false` 로 내리고, 그때만 `change-report.md` + 사용자 승인이 요구된다.
|
|
84
|
+
|
|
85
|
+
게이트는 이 마커를 **결정론적으로만** 검사한다 (LLM 호출 0).
|
|
18
86
|
|
|
19
|
-
|
|
20
|
-
- `install` 은 `~/.cache/opencode/packages/makdoong2-team@latest/` 를 전역 모듈 심볼릭 링크로 seed 한다. opencode 가 registry 에서 별도로 fetch 하지 않고 방금 설치한 버전을 그대로 로드하게 만든다.
|
|
21
|
-
- 재설치 시 `makdoong2-team.json` 은 보존된다. 덮어쓰려면 `--force`.
|
|
87
|
+
### 다출처 병렬 조사
|
|
22
88
|
|
|
23
|
-
|
|
89
|
+
`1_planning.requirements` 의 교차 조사는 `dispatch_research` 툴 **1회 호출**로 Jira · Confluence · Bitbucket (필요 시 GitHub OSS) 을 **동시에** 조사한다. 플러그인이 소스마다 별도 세션을 띄우므로:
|
|
24
90
|
|
|
25
|
-
|
|
91
|
+
- 대기 시간이 **가장 느린 소스 하나**로 수렴한다 (직렬 합이 아니다)
|
|
92
|
+
- 각 소스의 원자료가 planner 컨텍스트를 잠식하지 않는다
|
|
93
|
+
- 한 소스가 실패해도 나머지 결과는 그대로 남는다 (부분 성공이 정상)
|
|
94
|
+
|
|
95
|
+
결과는 `.makdoong2-team/<이슈>/research-findings.json` 으로 병합된다. 상세: ARCHITECTURE.md §3.6
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 3. 설정 — `makdoong2-team.json` 한 파일
|
|
100
|
+
|
|
101
|
+
모든 설정은 `~/.config/opencode/makdoong2-team.json` 하나로 제어한다. 플러그인(`src/config.ts`)과 셸 게이트(`scripts/config.sh`)가 같은 파일을 읽는다. **환경변수는 쓰지 않는다.**
|
|
26
102
|
|
|
27
103
|
| 블록 | 용도 |
|
|
28
104
|
|---|---|
|
|
29
105
|
| `agents` | 에이전트별 모델 오버라이드 (`model`, `variant`, `fallback_models`) |
|
|
30
106
|
| `model_policy.allowed_primaries` | 빌트인 primary 허용 목록 **확장** (추가 전용 — 빈 배열은 "제한 없음" 이 아니라 "추가 없음") |
|
|
31
|
-
| `coverage.threshold` | 커버리지 게이트
|
|
32
|
-
| `timeout.
|
|
33
|
-
| `
|
|
107
|
+
| `coverage.threshold` | 커버리지 게이트 최소치 (%, 기본 95) |
|
|
108
|
+
| `timeout.substage_minutes` | 서브에이전트 1회 실행 상한 (기본 30분) |
|
|
109
|
+
| `timeout.per_agent` | 에이전트별 상한 override (기본 seed: engineer 60분) |
|
|
110
|
+
| `timeout.stall_escalate_threshold` | substage 누적 hang 상한 (기본 5). 초과 시 dispatch 차단 후 사용자 에스컬레이션 |
|
|
111
|
+
| `research.max_parallel` | 동시 리서치 세션 수 (기본 3, 상한 6) |
|
|
112
|
+
| `research.timeout_minutes` | 리서치 소스 1개당 상한 (기본 10분) |
|
|
113
|
+
| `tmux` | 막둥이 pane 모니터. 코드 기본값은 off, seed 되는 설정 파일은 `enabled: true` |
|
|
34
114
|
| `worktree.extra_exclude` | worktree 동기화 추가 제외 패턴 |
|
|
35
|
-
| `logging
|
|
36
|
-
| `logging.max_bytes` | `mode="file"` 로그 회전 임계값 (기본 10 MiB). 초과 시 `<path>.1` 로 회전 |
|
|
115
|
+
| `logging` | `level` / `mode` / `path` / `max_bytes` |
|
|
37
116
|
| `paths` | 비표준 설치 경로 오버라이드 |
|
|
38
|
-
| `hosts` | 리서치
|
|
39
|
-
| `secrets` | 리서치
|
|
117
|
+
| `hosts` | 리서치 MCP 온프레미스 endpoint (`JIRA_HOST`, `CONFLUENCE_HOST`, `BITBUCKET_API_BASE_PATH`, `BAMBOO_URL`) |
|
|
118
|
+
| `secrets` | 리서치 MCP 토큰 (Jira / Confluence / Bitbucket / Bamboo) |
|
|
40
119
|
|
|
41
|
-
|
|
120
|
+
전체 스키마는 `assets/makdoong2-team.schema.json`.
|
|
42
121
|
|
|
43
|
-
|
|
122
|
+
### 모델 정책
|
|
44
123
|
|
|
45
|
-
빌트인 primary 허용 목록은 `
|
|
124
|
+
빌트인 primary 허용 목록은 `github-copilot/*` 와 `local/*` 브랜드 40개다 (전체 목록: `src/model-fallback-policy.ts` 의 `DEFAULT_ALLOWED_PRIMARIES`). fallback 은 **항상 primary 보다 낮은 tier** 여야 한다 (`low < medium < high < max`).
|
|
46
125
|
|
|
47
126
|
```jsonc
|
|
48
127
|
{
|
|
@@ -51,7 +130,7 @@ makdoong2-team doctor # 설치 진단
|
|
|
51
130
|
},
|
|
52
131
|
"agents": {
|
|
53
132
|
"makdoong2-engineer": {
|
|
54
|
-
"model": "
|
|
133
|
+
"model": "github-copilot/claude-opus-4.8",
|
|
55
134
|
"fallback_models": [
|
|
56
135
|
{ "id": "github-copilot/claude-haiku-4.5", "tier": "low" }
|
|
57
136
|
]
|
|
@@ -60,133 +139,99 @@ makdoong2-team doctor # 설치 진단
|
|
|
60
139
|
}
|
|
61
140
|
```
|
|
62
141
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
| 값 | 동작 | 부장님 pane 리사이즈 |
|
|
66
|
-
|---|---|---|
|
|
67
|
-
| `window` (기본) | 막둥이마다 **별도 tmux window** (`new-window -d`) | 없음 |
|
|
68
|
-
| `pane` | 부장님 window 를 분할 (`split-window` + `select-layout`) | 매 spawn/kill 마다 발생 |
|
|
69
|
-
|
|
70
|
-
`pane` 모드는 substage 마다 부장님 화면이 분할·재배치되어 흔들린다 (실측 170x44 → 80x44 → 170x44). `window` 모드는 detached window 를 쓰므로 부장님 pane 크기와 포커스가 전혀 변하지 않는다. 기본값을 `window` 로 둔 이유다.
|
|
142
|
+
`makdoong2-team validate` 로 위반 여부와 최종 체인을 미리 확인할 수 있다. 위반 시 플러그인은 defaults 로 롤백하고 stderr 에 경고만 남긴다 — 설정 오류로 워크플로우가 죽지 않는다.
|
|
71
143
|
|
|
72
|
-
|
|
144
|
+
### 로깅
|
|
73
145
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
막둥이 pane 은 spawn 직후에는 배너만 띄운 placeholder 상태이고, **해당 창을 선택하는 순간** `opencode attach` 로 자동 전환된다. 한 번 전환되면 다른 창으로 돌아가도 attach 상태가 유지되므로 live 관찰에 제약은 없다.
|
|
77
|
-
|
|
78
|
-
프롬프트 입력창에 `/0c0c/0c0c/0c0c…` 가 타이핑되던 현상의 원인은 **spawn 되는 자식 opencode TUI 가 기동 시 보내는 터미널 팔레트 질의**다 (프로세스당 19개). tmux 가 이를 실제 터미널로 중계하는데, 응답이 조각나면 남은 조각이 활성 pane(= 부장님)에 키 입력으로 배달된다. 포커스 전까지 자식 프로세스를 아예 만들지 않아 이 경로를 차단한다 — 실측상 누출 0건. 즉시 attach 하는 모드는 제공하지 않는다 (동일 현상이 재현됨). oh-my-opencode 의 `tmux-core` placeholder → `respawn-pane -k` 설계를 따랐다. 상세: ARCHITECTURE.md §17.7.
|
|
79
|
-
|
|
80
|
-
`makdoong2-team validate` 로 정책 위반 여부와 최종 chain 을 사전 검증할 수 있다. 위반 시 plugin 은 defaults 로 롤백되며 stderr 에 경고를 남긴다. 전체 스키마: `assets/makdoong2-team.schema.json`.
|
|
81
|
-
|
|
82
|
-
## 에이전트 5개
|
|
83
|
-
|
|
84
|
-
| ID | 담당 phase | 권한 요약 |
|
|
85
|
-
|---|---|---|
|
|
86
|
-
| `makdoong2-team-leader` | 라우팅 (orchestrator) | commit/push 허용 — PRIMARY 단계 직접 실행 |
|
|
87
|
-
| `makdoong2-planner` | 1_planning | 읽기 전용 |
|
|
88
|
-
| `makdoong2-engineer` | 2_implementation | edit/write 허용, commit/push deny |
|
|
89
|
-
| `makdoong2-publisher` | 3_delivery | 읽기 전용 — spec 계산만 (하이브리드) |
|
|
90
|
-
| `makdoong2-verifier` | 메타 검증 | 읽기 전용 |
|
|
146
|
+
`level` 은 임계값이다. `error` 는 error 만, `debug` 는 error/warn/info/debug 까지 출력한다. 기본값 `error` 는 BLOCKED 같은 중요 이벤트만 노출한다. **변경 후 opencode 재시작이 필요하다** (설정은 플러그인 초기화 시 1회만 로드된다).
|
|
91
147
|
|
|
92
|
-
**
|
|
148
|
+
`mode="file"` 로그는 **append 전용**이다. 한 호스트의 모든 opencode 프로세스(메인 TUI, 막둥이 pane, `npm test`)가 같은 파일을 공유하므로 truncate 하면 남의 기록이 사라진다. 프로세스 구분은 각 라인의 `[pid=N]` 태그로, 크기는 `max_bytes` 회전으로 관리한다. → ARCHITECTURE.md §11
|
|
93
149
|
|
|
94
|
-
|
|
150
|
+
### tmux 막둥이 창
|
|
95
151
|
|
|
96
|
-
`
|
|
152
|
+
- `placement: "window"` (기본) — 막둥이마다 별도 detached window. 부장님 화면이 **전혀 흔들리지 않는다.**
|
|
153
|
+
- `placement: "pane"` (legacy) — 부장님 window 를 분할. spawn/kill 마다 리사이즈가 발생한다. `layout` · `main_pane_size` · `agent_pane_min_width` · `split_direction` 은 이 모드에서만 유효하다.
|
|
97
154
|
|
|
98
|
-
|
|
99
|
-
- **major** — 테스트까지 무인 진행 후 `3_delivery.commit` 직전 1곳만 사람 승인 + `change-report.md` 필수
|
|
155
|
+
막둥이 창은 **포커스할 때 실제 TUI 로 붙는다.** spawn 직후에는 배너만 띄운 placeholder 이고, 그 창을 선택하는 순간 `opencode attach` 로 교체된다. 한 번 붙으면 계속 유지되므로 관찰에 제약은 없다. 즉시 attach 하는 모드는 제공하지 않는다 — 부장님 프롬프트에 `/0c0c/0c0c…` 가 타이핑되는 터미널 팔레트 질의 누출을 재현하기 때문이다. → ARCHITECTURE.md §9
|
|
100
156
|
|
|
101
|
-
|
|
157
|
+
---
|
|
102
158
|
|
|
103
|
-
## 단계별
|
|
159
|
+
## 4. 단계별 프롬프트 확장
|
|
104
160
|
|
|
105
|
-
|
|
161
|
+
프롬프트는 세 계층으로 조립되어 서브에이전트에 주입된다. **어느 계층에 쓸지부터 정한다.**
|
|
106
162
|
|
|
107
|
-
| 계층 | 파일 | 범위 | 재빌드 |
|
|
163
|
+
| 계층 | 파일 | 적용 범위 | 재빌드 |
|
|
108
164
|
|---|---|---|---|
|
|
109
|
-
| ① Agent persona | `agents/makdoong2-<role>.md` |
|
|
110
|
-
| ② Stage spec | `stages/NN-<name>.md` | **단일 substage
|
|
111
|
-
| ③ Dispatch header | `src/opencode-plugin.ts` `promptText` | **모든 stage
|
|
165
|
+
| ① Agent persona | `agents/makdoong2-<role>.md` | 그 role 의 **모든 substage** | 불필요 |
|
|
166
|
+
| ② Stage spec | `stages/NN-<name>.md` | **단일 substage** 절차·게이트·마커 | 불필요 |
|
|
167
|
+
| ③ Dispatch header | `src/opencode-plugin.ts` `promptText` | **모든 stage** 공통 헤더 | 필요 |
|
|
112
168
|
|
|
113
|
-
|
|
169
|
+
- **① 페르소나** — 역할, 권한 요약, 금지사항, 공통 절차. YAML frontmatter(`tools`, `permission`) 아래 본문이 시스템 프롬프트가 된다.
|
|
170
|
+
- **② Stage spec** — 그 substage 전용 절차와 state.json 마커 예시. dispatch 프롬프트에 `Stage spec: read <경로> and follow it strictly.` 로 참조 지시가 자동 삽입된다.
|
|
171
|
+
- **③ Dispatch header** — `Working directory` / `Scripts directory` / `Issue` 같은 전역 강제 라인. 거의 건드릴 일이 없고, 고치면 `npm run build` + 재배포가 필요하다.
|
|
114
172
|
|
|
115
|
-
|
|
116
|
-
|---|---|---|
|
|
117
|
-
| `1_planning.jira` | `makdoong2-planner` | `stages/01-jira.md` |
|
|
118
|
-
| `1_planning.requirements` | `makdoong2-planner` | `stages/02-requirements.md` |
|
|
119
|
-
| `1_planning.scope` | `makdoong2-planner` | `stages/03-scope.md` |
|
|
120
|
-
| `2_implementation.analysis` | `makdoong2-analyzer` | `stages/04-analysis.md` |
|
|
121
|
-
| `2_implementation.dev` | `makdoong2-engineer` | `stages/05-worktree-dev.md` |
|
|
122
|
-
| `2_implementation.test` | `makdoong2-engineer` | `stages/06-test.md` |
|
|
123
|
-
| `3_delivery.commit` | `makdoong2-publisher` | `stages/07-commit.md` |
|
|
124
|
-
| `3_delivery.pr` | `makdoong2-publisher` | `stages/08-pr.md` |
|
|
125
|
-
| `3_delivery.review` | `makdoong2-publisher` | `stages/09-review-comments.md` |
|
|
173
|
+
**반영 방법**: ①·② 만 고쳤으면 `makdoong2-team install --force` 로 재배포하면 끝. ③ 또는 `src/**` 를 고쳤으면 빌드 후 배포 절차를 밟는다.
|
|
126
174
|
|
|
127
|
-
|
|
175
|
+
### 새 substage 추가 (드문 경우)
|
|
128
176
|
|
|
129
|
-
|
|
177
|
+
기존 substage 에 내용을 **추가**만 하려면 ① 또는 ② 편집으로 끝난다. **새 substage 자체**를 만들려면 5곳을 함께 고친다.
|
|
130
178
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
179
|
+
1. `src/agent-stage-config.ts` — `Stage` union + `STAGE_SPEC_FILES` + 필요 시 `agentForStage()`
|
|
180
|
+
2. `src/opencode-plugin.ts` — `STAGE_ORDER` 배열에 삽입
|
|
181
|
+
3. `stages/NN-<name>.md` — 신규 spec 작성
|
|
182
|
+
4. `agents/makdoong2-<role>.md` + `gates/verify.sh` (+ 전용 `stage*-verify.sh`)
|
|
183
|
+
5. README 매핑표 · `AGENTS.md` sealed workflow 규약 갱신
|
|
134
184
|
|
|
135
|
-
|
|
185
|
+
이후 `makdoong2-team validate` → `npm test` 로 회귀를 확인한다.
|
|
136
186
|
|
|
137
|
-
|
|
187
|
+
---
|
|
138
188
|
|
|
139
|
-
|
|
140
|
-
2. `stages/NN-<name>.md` — 신규 stage spec 파일 생성 (절차, 게이트 조건, 마커 예시).
|
|
141
|
-
3. `agents/makdoong2-<role>.md` — 담당 agent 페르소나에 신규 substage 처리 로직 추가.
|
|
142
|
-
4. `gates/verify.sh` — 진입 게이트 검증 로직 추가 (state.json 마커 조건).
|
|
143
|
-
5. `README.md` 매핑표 갱신 + `AGENTS.md` sealed workflow 규약 반영.
|
|
189
|
+
## 5. 테스트
|
|
144
190
|
|
|
145
|
-
|
|
191
|
+
```bash
|
|
192
|
+
npm test # 전체
|
|
193
|
+
npm run test:install # 설치 라이브러리만
|
|
194
|
+
```
|
|
146
195
|
|
|
147
|
-
|
|
196
|
+
`npm test` 는 각 단계를 순차 실행하되 **실패해도 멈추지 않고** 끝까지 돌린 뒤 실패 목록을 모아 보고한다. macOS 등 비-Linux 호스트에서는 같은 스위트를 Ubuntu 컨테이너에서 한 번 더 돌려 플랫폼 차이로 갈리는 회귀까지 잡는다 (docker 가 없으면 안내 후 건너뛴다).
|
|
148
197
|
|
|
149
|
-
-
|
|
150
|
-
|
|
198
|
+
`.husky/pre-push` 도 같은 `npm test` 를 부르므로 push 마다 docker 가 기동됐다 종료된다. 건너뛰려면:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
MAKDOONG2_SKIP_LINUX_CHECK=1 git push # 그 push 는 Linux 검증 없이 나간다
|
|
202
|
+
```
|
|
151
203
|
|
|
152
|
-
|
|
204
|
+
---
|
|
153
205
|
|
|
154
|
-
## 배포 (Maintainer)
|
|
206
|
+
## 6. 배포 (Maintainer)
|
|
155
207
|
|
|
156
|
-
두
|
|
208
|
+
두 경로 모두 **승인 게이트 2회**를 통과해야 배포된다.
|
|
157
209
|
|
|
158
|
-
|
|
210
|
+
**경로 A — `npm run release:*` (권장)**
|
|
159
211
|
|
|
160
212
|
```bash
|
|
161
|
-
npm run release:patch #
|
|
162
|
-
npm run release:minor #
|
|
163
|
-
npm run release:major #
|
|
213
|
+
npm run release:patch # 1.3.1 → 1.3.2 (버그 수정)
|
|
214
|
+
npm run release:minor # 1.3.1 → 1.4.0 (기능 추가)
|
|
215
|
+
npm run release:major # 1.3.1 → 2.0.0 (breaking)
|
|
164
216
|
```
|
|
165
217
|
|
|
166
|
-
`scripts/release.sh` 가 9단계를 순차 실행한다 — pre-flight → `npm test` → 버전 미리보기 → **승인 #1** → `npm version` → `publish --dry-run` → **승인 #2** → `npm publish` → `git push --follow-tags`.
|
|
218
|
+
`scripts/release.sh` 가 9단계를 순차 실행한다 — pre-flight → `npm test` → 버전 미리보기 → **승인 #1** → `npm version` → `publish --dry-run` → **승인 #2** → `npm publish` → `git push --follow-tags`. publish 이전에 실패하면 자동 롤백된다. CI 는 `--yes` 로 대화형을 우회한다 (대화형 셸에서는 금지).
|
|
167
219
|
|
|
168
|
-
|
|
220
|
+
**경로 B — git push 자동 배포**
|
|
169
221
|
|
|
170
|
-
`package.json` 의 `version` 을
|
|
222
|
+
`package.json` 의 `version` 을 올린 커밋을 push 하면 `.husky/pre-push` 가 감지해 같은 2회 승인 후 publish 한다. 이미 registry 에 있는 버전은 skip.
|
|
171
223
|
|
|
172
|
-
|
|
224
|
+
**인증**: `npm login` 또는 `~/.npmrc` 의 `//registry.npmjs.org/:_authToken=<token>` (chmod 600). 설치하는 쪽은 인증이 필요 없다.
|
|
173
225
|
|
|
174
|
-
|
|
226
|
+
---
|
|
175
227
|
|
|
176
|
-
##
|
|
228
|
+
## 7. 문서
|
|
177
229
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
`.husky/pre-push` 가 unit test 실행 + version 변경 감지 시 자동 배포 훅을 트리거한다.
|
|
184
|
-
|
|
185
|
-
## 문서
|
|
186
|
-
|
|
187
|
-
- **[ARCHITECTURE.md](./ARCHITECTURE.md)** — 어떻게 동작하는가. 모듈, hook 흐름, custom tool API, state schema, 실패 모드.
|
|
188
|
-
- **[DESIGN.md](./DESIGN.md)** — 왜 이렇게 설계했는가. 하네스 4기둥 (Constrain / Inform / Verify / Correct).
|
|
189
|
-
- **[AGENTS.md](./AGENTS.md)** — 개발 규약 (git commit, npm 배포, sealed workflow).
|
|
230
|
+
| 문서 | 내용 |
|
|
231
|
+
|---|---|
|
|
232
|
+
| [ARCHITECTURE.md](./ARCHITECTURE.md) | **어떻게 동작하는가** — 모듈, 툴 API, state 스키마, 훅, 런타임 방어, 실패 모드 |
|
|
233
|
+
| [DESIGN.md](./DESIGN.md) | **왜 이렇게 만들었는가** — 하네스 4기둥 (Constrain / Inform / Verify / Correct) 과 트레이드오프 |
|
|
234
|
+
| [AGENTS.md](./AGENTS.md) | **개발 규약** — git commit, npm 배포, sealed workflow, state.sh 하드룰 |
|
|
190
235
|
|
|
191
236
|
## 라이선스
|
|
192
237
|
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: makdoong2-researcher
|
|
3
|
+
description: workflow research fan-out worker — 단일 소스(Jira / Confluence / Bitbucket / GitHub OSS) 만 읽기 전용 조사하고 고정 스키마 JSON 을 반환한다. dispatch_research 툴이 소스별로 병렬 spawn 한다. 직접 호출하지 않는다.
|
|
4
|
+
temperature: 0.1
|
|
5
|
+
mode: subagent
|
|
6
|
+
tools:
|
|
7
|
+
Read: true
|
|
8
|
+
Bash: true
|
|
9
|
+
Grep: true
|
|
10
|
+
Glob: true
|
|
11
|
+
skill: true
|
|
12
|
+
skill_mcp: true
|
|
13
|
+
Write: false
|
|
14
|
+
Edit: false
|
|
15
|
+
Patch: false
|
|
16
|
+
MultiEdit: false
|
|
17
|
+
permission:
|
|
18
|
+
bash:
|
|
19
|
+
"*": "allow"
|
|
20
|
+
"git commit*": "deny"
|
|
21
|
+
"git push*": "deny"
|
|
22
|
+
"git add*": "deny"
|
|
23
|
+
"git rm*": "deny"
|
|
24
|
+
"git reset --hard*": "deny"
|
|
25
|
+
"git branch -D*": "deny"
|
|
26
|
+
"git worktree add*": "deny"
|
|
27
|
+
"git worktree remove*": "deny"
|
|
28
|
+
"rm -rf*": "deny"
|
|
29
|
+
write:
|
|
30
|
+
"**/*": "deny"
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
당신은 **리서치 막둥이**다. 배정받은 **소스 한 곳만** 조사하고 고정 스키마 JSON 을 반환한다.
|
|
34
|
+
|
|
35
|
+
`dispatch_research` 툴이 소스마다 별도 세션을 병렬로 띄운다. 당신의 세션에는 당신이 맡은 소스의 자료만 쌓인다 — 이것이 fan-out 의 목적이므로 **다른 소스를 기웃거리지 않는다.**
|
|
36
|
+
|
|
37
|
+
## 하드룰
|
|
38
|
+
|
|
39
|
+
1. **읽기 전용.** 파일 생성·수정 불가 (Write/Edit 프론트매터 차단). state.json 도 건드리지 않는다 — 결과 저장은 플러그인이 한다.
|
|
40
|
+
2. **배정된 소스만.** 프롬프트의 `Research source` 에 적힌 소스 외의 skill 을 로드하지 않는다.
|
|
41
|
+
3. **skill 먼저, MCP 나중.** `skill(name=...)` 로 스킬을 로드하기 전에 `skill_mcp` 를 부르면 `MCP server "<name>" not found` 로 실패한다. 순서를 지킨다.
|
|
42
|
+
4. **추측 금지.** 확인하지 못한 것은 `findings` 에 넣지 않고 `gaps` 에 적는다. `url` 은 실제 출처가 있을 때만 넣는다.
|
|
43
|
+
5. **outer-world 에이전트 위임 금지.** Task 툴이 프론트매터에서 제거되어 물리적으로 불가하다.
|
|
44
|
+
|
|
45
|
+
## 실행 규약
|
|
46
|
+
|
|
47
|
+
bash 명령은 **실행 후 결과로 판단**한다. 실행 전 permission 을 추론하지 않는다. `[makdoong2-team hook] BLOCKED:` stderr 로그가 나온 것만 실제 차단이다.
|
|
48
|
+
|
|
49
|
+
## 출력 규약
|
|
50
|
+
|
|
51
|
+
마지막 assistant turn 에 ```json 펜스 블록을 **정확히 하나** 출력한다. 스키마는 dispatch 프롬프트에 명시되어 있다:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"source": "<배정받은 source>",
|
|
56
|
+
"findings": [{"title": "...", "detail": "...", "url": "... 또는 null"}],
|
|
57
|
+
"gaps": ["확인하지 못한 항목"]
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
- 조사 결과가 없어도 **JSON 블록은 반드시 출력한다.** `findings: []` + `gaps` 에 이유를 적는다.
|
|
62
|
+
- 블록을 출력하지 않으면 플러그인이 파싱 실패로 기록하고 해당 소스는 `status: "failed"` 가 된다.
|
|
63
|
+
- 펜스 블록 앞뒤의 한국어 설명은 자유다. 단 JSON 블록은 하나여야 한다 (여러 개면 마지막 것이 채택된다).
|
|
64
|
+
|
|
65
|
+
## 조기 종료
|
|
66
|
+
|
|
67
|
+
MCP 인증 실패(exit 68/69), 접근 권한 부족, 대상 부재 등으로 조사가 불가능하면 **재시도로 시간을 쓰지 말고** 즉시 `findings: []` + `gaps` 에 사유를 적어 반환한다. 한 소스의 실패는 다른 소스의 조사를 막지 않는다 — 플러그인이 부분 성공으로 병합한다.
|
|
@@ -352,6 +352,24 @@
|
|
|
352
352
|
"description": "Bamboo personal-access token consumed by skills/bamboo-ci/run-bamboo.sh."
|
|
353
353
|
}
|
|
354
354
|
}
|
|
355
|
+
},
|
|
356
|
+
"research": {
|
|
357
|
+
"type": "object",
|
|
358
|
+
"additionalProperties": false,
|
|
359
|
+
"description": "Parallel multi-source research fan-out (dispatch_research tool).",
|
|
360
|
+
"properties": {
|
|
361
|
+
"max_parallel": {
|
|
362
|
+
"type": "integer",
|
|
363
|
+
"minimum": 1,
|
|
364
|
+
"maximum": 6,
|
|
365
|
+
"description": "Maximum research sub-sessions spawned simultaneously. Default 3, hard ceiling 6. Queries beyond this are reported as deferred, never silently dropped."
|
|
366
|
+
},
|
|
367
|
+
"timeout_minutes": {
|
|
368
|
+
"type": "number",
|
|
369
|
+
"minimum": 1,
|
|
370
|
+
"description": "Per-source wall-clock budget. Default 10. Deliberately shorter than timeout.substage_minutes: a source that cannot answer in this window is recorded as failed so the other sources' findings still land."
|
|
371
|
+
}
|
|
372
|
+
}
|
|
355
373
|
}
|
|
356
374
|
}
|
|
357
375
|
}
|
package/bin/cli.js
CHANGED
|
@@ -31,7 +31,7 @@ const HERE = dirname(fileURLToPath(import.meta.url));
|
|
|
31
31
|
const PKG_ROOT = resolve(HERE, "..");
|
|
32
32
|
const PKG = JSON.parse(readFileSync(join(PKG_ROOT, "package.json"), "utf8"));
|
|
33
33
|
|
|
34
|
-
const TOOLS = ["verify_stage", "dispatch_stage", "dispatch_verifier", "auto_advance_stage", "get_fallback_model"];
|
|
34
|
+
const TOOLS = ["verify_stage", "dispatch_stage", "dispatch_verifier", "dispatch_research", "auto_advance_stage", "get_fallback_model"];
|
|
35
35
|
|
|
36
36
|
// Skill directories that used to ship a per-skill secrets.env under
|
|
37
37
|
// ${configDir}/skills/<skill>/. Credentials are now sourced only from
|
|
@@ -70,6 +70,16 @@ export const AGENTS = {
|
|
|
70
70
|
tools: ["bash", "read", "grep", "glob", "write"],
|
|
71
71
|
skills: [],
|
|
72
72
|
},
|
|
73
|
+
// Research fan-out worker. Not bound to a substage — dispatch_research spawns
|
|
74
|
+
// one session per source in parallel, each loading exactly one research skill.
|
|
75
|
+
"makdoong2-researcher": {
|
|
76
|
+
id: "makdoong2-researcher",
|
|
77
|
+
stage: "all",
|
|
78
|
+
primary_only: false,
|
|
79
|
+
permissions: RO_PERM,
|
|
80
|
+
tools: ["bash", "read", "grep", "glob", "skill", "skill_mcp"],
|
|
81
|
+
skills: ["jira-research", "confluence-research", "bitbucket-research", "github-oss-research"],
|
|
82
|
+
},
|
|
73
83
|
"makdoong2-engineer": {
|
|
74
84
|
id: "makdoong2-engineer",
|
|
75
85
|
stage: "all",
|
package/dist/config.d.ts
CHANGED
|
@@ -33,6 +33,13 @@ export interface TimeoutConfig {
|
|
|
33
33
|
stall_escalate_threshold?: number;
|
|
34
34
|
}
|
|
35
35
|
export declare const DEFAULT_STALL_ESCALATE_THRESHOLD = 5;
|
|
36
|
+
export interface ResearchConfig {
|
|
37
|
+
/** Max research sub-sessions spawned simultaneously. Clamped to [1, 6]. */
|
|
38
|
+
max_parallel?: number;
|
|
39
|
+
/** Per-source wall-clock budget. Shorter than a substage on purpose — a source
|
|
40
|
+
* that cannot answer in this window is reported as failed, not waited on. */
|
|
41
|
+
timeout_minutes?: number;
|
|
42
|
+
}
|
|
36
43
|
export type LogLevel = "silent" | "error" | "warn" | "info" | "debug" | "trace";
|
|
37
44
|
export type LogMode = "stdin" | "file";
|
|
38
45
|
export interface LoggingConfig {
|
|
@@ -49,6 +56,7 @@ export interface Makdoong2Config {
|
|
|
49
56
|
threshold?: number;
|
|
50
57
|
};
|
|
51
58
|
timeout?: TimeoutConfig;
|
|
59
|
+
research?: ResearchConfig;
|
|
52
60
|
tmux?: TmuxConfigJson;
|
|
53
61
|
worktree?: {
|
|
54
62
|
extra_exclude?: string;
|
|
@@ -73,6 +73,11 @@ export const POLICIES = {
|
|
|
73
73
|
primary: { id: "local/qwen3.6-27b", variant: "high", tier: "medium" },
|
|
74
74
|
fallbacks: [{ id: "github-copilot/claude-haiku-4.5", tier: "low" }],
|
|
75
75
|
},
|
|
76
|
+
// Research fan-out worker — one session per source, spawned in parallel.
|
|
77
|
+
"makdoong2-researcher": {
|
|
78
|
+
primary: { id: "local/qwen3.6-27b", variant: "high", tier: "medium" },
|
|
79
|
+
fallbacks: [{ id: "github-copilot/claude-haiku-4.5", tier: "low" }],
|
|
80
|
+
},
|
|
76
81
|
"makdoong2-planner": {
|
|
77
82
|
primary: { id: "local/qwen3.6-27b", variant: "high", tier: "medium" },
|
|
78
83
|
fallbacks: [{ id: "github-copilot/claude-haiku-4.5", tier: "low" }],
|