sentix 2.0.2 → 2.0.22
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/FRAMEWORK.md +2 -0
- package/README.md +56 -9
- package/docs/agent-methods.md +436 -0
- package/package.json +1 -1
- package/scripts/update-downstream.sh +0 -0
- package/src/commands/init.js +95 -7
- package/src/lib/pipeline.js +71 -19
package/FRAMEWORK.md
CHANGED
|
@@ -216,6 +216,8 @@ tasks/.pre-fix-test-results.json — npm run test --json 결과
|
|
|
216
216
|
> 에이전트는 Governor가 준 컨텍스트만 본다.
|
|
217
217
|
> 에이전트는 결과를 Governor에게만 반환한다.
|
|
218
218
|
> 에이전트끼리 직접 통신하지 않는다.
|
|
219
|
+
> **메서드 수준 명세: docs/agent-methods.md (필수 준수)**
|
|
220
|
+
> 아래는 입출력 요약이다. 각 에이전트의 메서드 실행 순서와 세부 규칙은 agent-methods.md를 따른다.
|
|
219
221
|
|
|
220
222
|
### planner
|
|
221
223
|
|
package/README.md
CHANGED
|
@@ -83,7 +83,17 @@ Governor라는 "총감독"이 있고, 6명의 "직원(에이전트)"이 있습
|
|
|
83
83
|
npx sentix init
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
이것만 하면
|
|
86
|
+
이것만 하면 **전부 자동으로** 처리됩니다:
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
npx sentix init
|
|
90
|
+
↓ CLAUDE.md, .sentix/, tasks/, docs/ 생성
|
|
91
|
+
↓ 기술 스택 자동 감지 (Node.js, Python, Go, Rust)
|
|
92
|
+
↓ FRAMEWORK.md 등 프레임워크 파일 자동 동기화
|
|
93
|
+
↓ git pre-commit hook 설치 (검증 게이트)
|
|
94
|
+
↓ 설치 상태 자동 진단 (sentix doctor)
|
|
95
|
+
↓ 완료
|
|
96
|
+
```
|
|
87
97
|
|
|
88
98
|
> **`npx` vs 글로벌 설치:**
|
|
89
99
|
> - `npx sentix ...` — 설치 없이 바로 실행 (매번 `npx` 붙여야 함)
|
|
@@ -124,13 +134,14 @@ mkdir -p /path/to/your-project/tasks/tickets
|
|
|
124
134
|
|
|
125
135
|
### 설치 확인
|
|
126
136
|
|
|
137
|
+
`sentix init`이 끝나면 자동으로 `doctor`가 실행됩니다. 모든 항목이 ✓ 이면 성공입니다.
|
|
138
|
+
|
|
139
|
+
나중에 다시 확인하고 싶으면:
|
|
140
|
+
|
|
127
141
|
```bash
|
|
128
|
-
|
|
129
|
-
npx sentix doctor
|
|
142
|
+
sentix doctor
|
|
130
143
|
```
|
|
131
144
|
|
|
132
|
-
모든 항목이 ✓ 이면 성공입니다.
|
|
133
|
-
|
|
134
145
|
---
|
|
135
146
|
|
|
136
147
|
## 사용 방법
|
|
@@ -565,6 +576,44 @@ A: 자동 감지: Node.js, Python, Go, Rust. 그 외 언어도 CLAUDE.md를 수
|
|
|
565
576
|
A: 6개 하드 룰이 있습니다. 기존 기능 삭제 금지, 범위 밖 수정 금지, 테스트 삭제 금지 등.
|
|
566
577
|
이 규칙은 AI도 무시할 수 없습니다.
|
|
567
578
|
|
|
579
|
+
**Q: `sentix` 명령이 안 됩니다 ("용어가 인식되지 않습니다")**
|
|
580
|
+
A: 글로벌 설치가 안 되어 있으면 매번 `npx`를 붙여야 합니다:
|
|
581
|
+
```bash
|
|
582
|
+
npx sentix doctor # npx로 실행 (설치 없이)
|
|
583
|
+
|
|
584
|
+
# 또는 글로벌 설치 후 npx 없이 사용:
|
|
585
|
+
npm install -g sentix
|
|
586
|
+
sentix doctor # 바로 실행 가능
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
**Q: `sentix update`가 "source not found"로 전부 건너뛰기합니다**
|
|
590
|
+
A: npm 패키지 버전이 오래된 경우입니다. 최신 버전으로 업데이트하세요:
|
|
591
|
+
```bash
|
|
592
|
+
npm cache clean --force
|
|
593
|
+
npm install -g sentix@latest
|
|
594
|
+
sentix --version # 최신 버전 확인
|
|
595
|
+
sentix update # 다시 시도
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
**Q: `sentix doctor`에서 FRAMEWORK.md가 MISSING입니다**
|
|
599
|
+
A: `sentix init`은 FRAMEWORK.md를 생성하지 않습니다. `sentix update`로 가져옵니다:
|
|
600
|
+
```bash
|
|
601
|
+
sentix update # sentix 원본에서 FRAMEWORK.md 등 동기화
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
**Q: npm publish 시 403 Forbidden (2FA) 에러가 납니다**
|
|
605
|
+
A: npm 계정에 2FA가 활성화되어 있으면 Granular Access Token이 필요합니다:
|
|
606
|
+
1. npmjs.com → 프로필 → Access Tokens → Generate New Token
|
|
607
|
+
2. Granular Access Token 선택, publish 권한 부여
|
|
608
|
+
3. `npm publish --//registry.npmjs.org/:_authToken=YOUR_TOKEN`
|
|
609
|
+
|
|
610
|
+
**Q: `sentix evolve`는 뭔가요?**
|
|
611
|
+
A: sentix가 자기 자신의 코드를 분석하고 개선점을 찾는 명령입니다:
|
|
612
|
+
```bash
|
|
613
|
+
sentix evolve # 분석만
|
|
614
|
+
sentix evolve --auto # 분석 + critical 이슈 자동 수정
|
|
615
|
+
```
|
|
616
|
+
|
|
568
617
|
---
|
|
569
618
|
|
|
570
619
|
## 런타임 모드
|
|
@@ -615,10 +664,8 @@ sentix doctor # → Runtime: engine, Provider: claude, API key: set
|
|
|
615
664
|
## 정리
|
|
616
665
|
|
|
617
666
|
```
|
|
618
|
-
1. sentix init
|
|
619
|
-
2.
|
|
620
|
-
3. sentix doctor ← 검증 (10초)
|
|
621
|
-
4. sentix run "하고 싶은 것" ← 사용 (끝!)
|
|
667
|
+
1. npx sentix init ← 설치 + 동기화 + 진단 (전부 자동, 1분)
|
|
668
|
+
2. sentix run "하고 싶은 것" ← 사용 (끝!)
|
|
622
669
|
```
|
|
623
670
|
|
|
624
671
|
---
|
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
# Agent Methods — 에이전트별 메서드 명세
|
|
2
|
+
|
|
3
|
+
> FRAMEWORK.md의 에이전트 정의를 보완하는 메서드 수준 상세 명세.
|
|
4
|
+
> 각 에이전트가 **어떤 단계를 어떤 순서로 수행하는지** 정의한다.
|
|
5
|
+
> 아키텍처 원칙: [Anthropic Building Effective Agents](https://www.anthropic.com/engineering/building-effective-agents) 기반.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 설계 원칙
|
|
10
|
+
|
|
11
|
+
### 1. Generator-Evaluator 분리
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
생성자 (dev/dev-fix)와 평가자 (pr-review)는 완전히 분리된다.
|
|
15
|
+
생성자는 품질 판단을 하지 않는다. 하드룰 자기 검증만 수행한다.
|
|
16
|
+
평가자는 코드를 수정하지 않는다. 판정만 내린다.
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### 2. 산출물 제약, 경로 자유 (Constrain Outputs, Free Paths)
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
planner는 WHAT(무엇을)과 WHERE(어디를)만 정의한다.
|
|
23
|
+
HOW(어떻게)는 dev가 결정한다.
|
|
24
|
+
planner가 구현 방법을 명세하면 틀릴 경우 하류에 cascade된다.
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 3. 회의적 평가자 (Skeptical Evaluator)
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
pr-review는 의도적으로 회의적으로 튜닝된다.
|
|
31
|
+
에이전트는 자기 작업에 관대하다 — 별도 평가자를 엄격하게 만드는 것이 효과적이다.
|
|
32
|
+
의심스러우면 REJECTED. 관대함보다 엄격함이 낫다.
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 4. 복잡도 기반 강도 조절 (Conditional Intensity)
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
평가자의 가치는 태스크가 모델의 단독 능력 경계를 넘을 때 가장 높다.
|
|
39
|
+
low complexity → 하드룰 체크만 (빠른 통과)
|
|
40
|
+
mid complexity → 하드룰 + 품질 기준 채점
|
|
41
|
+
high complexity → 하드룰 + 품질 기준 + 실제 동작 검증
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 5. Sprint Contract (사전 합의)
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
구현 전에 생성자와 평가자가 "완료 조건"을 합의한다.
|
|
48
|
+
planner가 티켓을 만들면 pr-review가 평가 가능성을 사전 검증한다.
|
|
49
|
+
불명확한 기준은 구현 전에 교정된다 — 사후 논쟁을 방지한다.
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 6. 하네스 간소화 원칙
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
파이프라인의 모든 단계는 "모델이 혼자 못 하는 것"에 대한 가정이다.
|
|
56
|
+
그 가정은 주기적으로 스트레스 테스트해야 한다.
|
|
57
|
+
모델 능력이 충분해지면 단계를 생략할 수 있다.
|
|
58
|
+
|
|
59
|
+
config.toml [harness] 섹션으로 제어:
|
|
60
|
+
skip_contract = false # contract 단계 생략 여부
|
|
61
|
+
skip_review_on_low = true # low complexity 리뷰 생략
|
|
62
|
+
evaluator_intensity = "auto" # auto: complexity에 따라 자동 조절
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## planner
|
|
68
|
+
|
|
69
|
+
요청을 분석하고 실행 가능한 티켓으로 변환한다.
|
|
70
|
+
**WHAT과 WHERE만 정의한다. HOW는 정의하지 않는다.**
|
|
71
|
+
|
|
72
|
+
### Methods
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
planner.analyze()
|
|
76
|
+
→ 요청 분류 (BUG / FEATURE / VERSION / GENERAL)
|
|
77
|
+
→ 키워드 추출
|
|
78
|
+
→ 유형별 파이프라인 결정
|
|
79
|
+
|
|
80
|
+
planner.research()
|
|
81
|
+
→ tasks/lessons.md 검색 — 동일/유사 패턴의 과거 실패
|
|
82
|
+
→ tasks/patterns.md 검색 — 관련 사용자 행동 패턴
|
|
83
|
+
→ 기존 티켓 검색 — 중복 방지
|
|
84
|
+
|
|
85
|
+
planner.scope()
|
|
86
|
+
→ 변경 범위 결정 (영향받는 파일/모듈 식별)
|
|
87
|
+
→ SCOPE 정의: 어떤 파일이 변경 대상인가
|
|
88
|
+
→ ACCEPTANCE 정의: 완료 조건은 무엇인가
|
|
89
|
+
██ 금지: 구체적 구현 방법 명세 (함수명, 알고리즘, 라이브러리 선택 등) ██
|
|
90
|
+
|
|
91
|
+
planner.estimate()
|
|
92
|
+
→ COMPLEXITY 판정 (low / mid / high)
|
|
93
|
+
→ 플래그 설정: DEPLOY_FLAG, SECURITY_FLAG, PARALLEL_HINT
|
|
94
|
+
→ high → dev-swarm 권고 여부
|
|
95
|
+
|
|
96
|
+
planner.emit()
|
|
97
|
+
→ 티켓 생성 (tasks/tickets/)
|
|
98
|
+
→ 티켓 필드: TICKET_ID, TITLE, SCOPE, ACCEPTANCE, COMPLEXITY, FLAGS
|
|
99
|
+
→ tasks/tickets/index.json 업데이트
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 출력 스키마
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
TICKET_ID: dev-044
|
|
106
|
+
TITLE: 세션 만료 검증 추가
|
|
107
|
+
TYPE: feature
|
|
108
|
+
SCOPE: src/auth/**, __tests__/auth/**
|
|
109
|
+
ACCEPTANCE:
|
|
110
|
+
- 세션 만료 시 401 반환
|
|
111
|
+
- 만료 시간 설정 가능
|
|
112
|
+
- 기존 인증 흐름 유지
|
|
113
|
+
COMPLEXITY: mid
|
|
114
|
+
DEPLOY_FLAG: true
|
|
115
|
+
SECURITY_FLAG: true
|
|
116
|
+
PARALLEL_HINT: null
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### planner가 정의하면 안 되는 것
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
✗ "jwt.verify()를 사용하라" → 구현 방법은 dev가 결정
|
|
123
|
+
✗ "middleware를 express.use()로 등록" → 기술 디테일은 dev가 결정
|
|
124
|
+
✗ "Redis에 세션을 저장하라" → 저장 방식은 dev가 결정
|
|
125
|
+
✗ "함수명은 checkExpiry로 하라" → 네이밍은 dev가 결정
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## pr-review — Contract 단계 (dev 전)
|
|
131
|
+
|
|
132
|
+
dev가 구현을 시작하기 전에, 티켓의 평가 가능성을 사전 검증한다.
|
|
133
|
+
|
|
134
|
+
### Methods
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
pr-review.contract()
|
|
138
|
+
→ 티켓의 ACCEPTANCE 기준 검토
|
|
139
|
+
→ 각 기준이 검증 가능한가? (코드 리뷰로 판단할 수 있는가?)
|
|
140
|
+
→ 각 기준이 명확한가? (해석의 여지가 없는가?)
|
|
141
|
+
→ 불명확한 기준 발견 시:
|
|
142
|
+
→ planner에게 피드백 반환
|
|
143
|
+
→ 피드백 내용: 어떤 기준이, 왜 불명확한지, 어떻게 교정하면 되는지
|
|
144
|
+
→ planner 재조정 후 다시 contract() 실행
|
|
145
|
+
→ 모든 기준이 명확하면: CONTRACT_APPROVED 반환
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Contract 판단 기준
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
검증 가능 (PASS):
|
|
152
|
+
"세션 만료 시 401 반환" → 테스트로 검증 가능
|
|
153
|
+
"기존 인증 흐름 유지" → 기존 테스트 통과로 검증 가능
|
|
154
|
+
"만료 시간 설정 가능" → 설정 파라미터 존재 여부로 검증 가능
|
|
155
|
+
|
|
156
|
+
검증 불가 (FEEDBACK):
|
|
157
|
+
"코드가 깔끔해야 한다" → 주관적, 기준 불명확
|
|
158
|
+
"성능이 좋아야 한다" → 수치 기준 없음
|
|
159
|
+
"보안이 강화되어야 한다" → 구체적 조건 없음
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## dev
|
|
165
|
+
|
|
166
|
+
티켓의 ACCEPTANCE 조건을 충족하는 코드를 구현한다.
|
|
167
|
+
**구현 방법은 dev가 자율적으로 결정한다.**
|
|
168
|
+
|
|
169
|
+
### Methods
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
dev.snapshot()
|
|
173
|
+
→ npm test 실행 → tasks/.pre-fix-test-results.json 저장
|
|
174
|
+
→ 현재 테스트 상태 기록 (회귀 검증 기준선)
|
|
175
|
+
|
|
176
|
+
dev.implement()
|
|
177
|
+
→ SCOPE 내 파일만 수정
|
|
178
|
+
→ ACCEPTANCE 조건 충족을 목표로 구현
|
|
179
|
+
→ 구현 방법은 dev가 결정 (planner의 HOW 명세 없음)
|
|
180
|
+
|
|
181
|
+
dev.test()
|
|
182
|
+
→ 새 코드에 대한 테스트 작성
|
|
183
|
+
→ npm test 실행
|
|
184
|
+
→ 기존 테스트 + 새 테스트 모두 통과 확인
|
|
185
|
+
|
|
186
|
+
dev.verify()
|
|
187
|
+
→ 하드룰 자기 검증만 수행:
|
|
188
|
+
□ 변경 파일이 SCOPE 안에 있는가
|
|
189
|
+
□ 기존 export를 삭제하지 않았는가
|
|
190
|
+
□ 기존 테스트를 삭제/약화하지 않았는가
|
|
191
|
+
□ 순삭제가 50줄을 넘지 않는가
|
|
192
|
+
□ 기존 기능/핸들러를 삭제하지 않았는가
|
|
193
|
+
→ 위반 발견 시: 스스로 수정 후 다시 verify()
|
|
194
|
+
██ 품질 판단은 하지 않는다 — pr-review에 위임 ██
|
|
195
|
+
|
|
196
|
+
dev.report()
|
|
197
|
+
→ diff 요약 반환
|
|
198
|
+
→ 테스트 결과 반환
|
|
199
|
+
→ 변경 파일 목록 반환
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## pr-review — 평가 단계 (dev 후)
|
|
205
|
+
|
|
206
|
+
dev의 결과물을 티켓 기준으로 평가한다.
|
|
207
|
+
**의도적으로 회의적(skeptical)으로 판단한다.**
|
|
208
|
+
|
|
209
|
+
### Methods
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
pr-review.diff()
|
|
213
|
+
→ 전체 변경 내용 확인 (git diff)
|
|
214
|
+
→ 변경 범위가 SCOPE 내인지 확인
|
|
215
|
+
→ pre-fix snapshot과 비교하여 회귀 여부 파악
|
|
216
|
+
|
|
217
|
+
pr-review.validate()
|
|
218
|
+
→ 하드룰 검증 (결정론적 — verify-gates.js와 동일 기준)
|
|
219
|
+
□ SCOPE 준수
|
|
220
|
+
□ export 삭제 없음
|
|
221
|
+
□ 테스트 삭제 없음
|
|
222
|
+
□ 순삭제 50줄 이내
|
|
223
|
+
□ 기능/핸들러 삭제 없음
|
|
224
|
+
→ 하나라도 위반 시: 즉시 REJECTED (grade() 진행 안 함)
|
|
225
|
+
|
|
226
|
+
pr-review.grade()
|
|
227
|
+
→ COMPLEXITY=low이면 생략 (하드룰 통과만으로 APPROVED)
|
|
228
|
+
→ COMPLEXITY=mid/high이면 4가지 품질 기준 채점:
|
|
229
|
+
|
|
230
|
+
1. 정확성 (Correctness)
|
|
231
|
+
→ 티켓의 ACCEPTANCE 조건을 모두 충족하는가?
|
|
232
|
+
→ 엣지 케이스를 처리했는가?
|
|
233
|
+
|
|
234
|
+
2. 일관성 (Consistency)
|
|
235
|
+
→ 기존 코드베이스의 패턴/컨벤션을 따르는가?
|
|
236
|
+
→ 네이밍, 구조, 에러 처리 방식이 기존과 일치하는가?
|
|
237
|
+
|
|
238
|
+
3. 간결성 (Simplicity)
|
|
239
|
+
→ 불필요한 추상화, 과도한 설계가 없는가?
|
|
240
|
+
→ 가장 단순한 해결책인가?
|
|
241
|
+
|
|
242
|
+
4. 테스트 충실도 (Test Coverage)
|
|
243
|
+
→ 새 코드에 대한 테스트가 있는가?
|
|
244
|
+
→ 엣지 케이스를 테스트하는가, 표면적 테스트인가?
|
|
245
|
+
|
|
246
|
+
→ 각 기준별 PASS / FAIL
|
|
247
|
+
→ 하나라도 FAIL이면 REJECTED
|
|
248
|
+
|
|
249
|
+
pr-review.calibrate()
|
|
250
|
+
→ tasks/lessons.md에서 과거 놓친 이슈를 few-shot 예시로 참조
|
|
251
|
+
→ "이전에 이런 패턴을 놓쳤다. 이번에도 확인하라"
|
|
252
|
+
→ 자기 합리화 방지: "이슈를 발견했다면 절대 스스로 합리화하지 마라"
|
|
253
|
+
|
|
254
|
+
pr-review.verdict()
|
|
255
|
+
→ 최종 판정: APPROVED / REJECTED
|
|
256
|
+
→ REJECTED 시: 구체적 사유 + 어떤 기준이 미달인지 명시
|
|
257
|
+
→ APPROVED 시: NEEDS_DEPLOY 여부 판단
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### 채점 기준 상세
|
|
261
|
+
|
|
262
|
+
```
|
|
263
|
+
┌──────────────┬─────────────────────────────────┬───────────────────────┐
|
|
264
|
+
│ 기준 │ PASS 조건 │ FAIL 예시 │
|
|
265
|
+
├──────────────┼─────────────────────────────────┼───────────────────────┤
|
|
266
|
+
│ 정확성 │ ACCEPTANCE 조건 100% 충족 │ 조건 하나 누락 │
|
|
267
|
+
│ 일관성 │ 기존 패턴과 일치 │ 새로운 컨벤션 도입 │
|
|
268
|
+
│ 간결성 │ 불필요한 추상화 없음 │ 과도한 설계, 미사용 코드 │
|
|
269
|
+
│ 테스트 충실도 │ 엣지 케이스 포함한 테스트 │ happy path만 테스트 │
|
|
270
|
+
└──────────────┴─────────────────────────────────┴───────────────────────┘
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### 복잡도별 리뷰 강도
|
|
274
|
+
|
|
275
|
+
```
|
|
276
|
+
COMPLEXITY=low:
|
|
277
|
+
validate() → verdict()
|
|
278
|
+
grade() 생략 — 하드룰 통과만으로 충분
|
|
279
|
+
|
|
280
|
+
COMPLEXITY=mid:
|
|
281
|
+
validate() → grade() → calibrate() → verdict()
|
|
282
|
+
4가지 품질 기준 전체 채점
|
|
283
|
+
|
|
284
|
+
COMPLEXITY=high:
|
|
285
|
+
validate() → grade() → calibrate() → verdict()
|
|
286
|
+
4가지 품질 기준 + 실제 동작 검증 (Playwright 등 해당 시)
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## dev-fix
|
|
292
|
+
|
|
293
|
+
pr-review 또는 security가 발견한 이슈를 수정한다.
|
|
294
|
+
**LESSON_LEARNED 기록이 필수다.**
|
|
295
|
+
|
|
296
|
+
### Methods
|
|
297
|
+
|
|
298
|
+
```
|
|
299
|
+
dev-fix.diagnose()
|
|
300
|
+
→ 이슈 원인 분석
|
|
301
|
+
→ pr-review의 REJECTED 사유 또는 security findings 참조
|
|
302
|
+
→ Governor 교차 판단이 있으면 함께 참조
|
|
303
|
+
→ 원인이 SCOPE 밖에 있으면 Governor에게 "SCOPE 확장 필요" 반환
|
|
304
|
+
|
|
305
|
+
dev-fix.fix()
|
|
306
|
+
→ SCOPE 내 코드 수정
|
|
307
|
+
→ 이슈와 무관한 파일은 절대 수정하지 않음
|
|
308
|
+
|
|
309
|
+
dev-fix.test()
|
|
310
|
+
→ npm test 실행
|
|
311
|
+
→ pre-fix snapshot 대비 회귀 없음 확인
|
|
312
|
+
→ 수정한 이슈에 대한 테스트 추가/보강
|
|
313
|
+
|
|
314
|
+
dev-fix.learn()
|
|
315
|
+
→ LESSON_LEARNED 작성 (필수 — 생략 불가)
|
|
316
|
+
→ tasks/lessons.md에 추가
|
|
317
|
+
→ 형식: 날짜 + 이슈 요약 + 근본 원인 + 교훈
|
|
318
|
+
→ 동일 패턴 3회 반복 감지 시 severity 자동 승격
|
|
319
|
+
|
|
320
|
+
dev-fix.report()
|
|
321
|
+
→ 수정 diff 반환
|
|
322
|
+
→ 테스트 결과 반환
|
|
323
|
+
→ LESSON_LEARNED 내용 반환
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## security
|
|
329
|
+
|
|
330
|
+
전체 코드베이스를 읽기 전용으로 스캔한다.
|
|
331
|
+
|
|
332
|
+
### Methods
|
|
333
|
+
|
|
334
|
+
```
|
|
335
|
+
security.scan()
|
|
336
|
+
→ 전체 코드베이스 보안 분석
|
|
337
|
+
→ 이전 tasks/security-report.md와 비교 (regression 확인)
|
|
338
|
+
|
|
339
|
+
security.classify()
|
|
340
|
+
→ 발견 항목별 severity 분류 (critical / warning / suggestion)
|
|
341
|
+
→ false positive 필터링
|
|
342
|
+
|
|
343
|
+
security.report()
|
|
344
|
+
→ tasks/security-report.md 생성/업데이트
|
|
345
|
+
→ VERDICT: PASSED / NEEDS_FIX
|
|
346
|
+
→ NEEDS_FIX 시: 각 finding의 severity + 위치 + 설명
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## roadmap
|
|
352
|
+
|
|
353
|
+
사이클 전체 이력을 분석하여 다음 계획을 수립한다.
|
|
354
|
+
|
|
355
|
+
### Methods
|
|
356
|
+
|
|
357
|
+
```
|
|
358
|
+
roadmap.analyze()
|
|
359
|
+
→ 이번 사이클의 요청, 티켓, 결과, 이슈, 리포트 종합 분석
|
|
360
|
+
→ tasks/lessons.md에서 반복 패턴 식별
|
|
361
|
+
→ tasks/patterns.md에서 트렌드 파악
|
|
362
|
+
|
|
363
|
+
roadmap.plan()
|
|
364
|
+
→ 즉시 / 단기 / 장기 계획 수립
|
|
365
|
+
→ 다음 티켓 초안 작성
|
|
366
|
+
|
|
367
|
+
roadmap.emit()
|
|
368
|
+
→ tasks/roadmap.md 생성/업데이트
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## 전체 파이프라인 흐름 (Methods 기반)
|
|
374
|
+
|
|
375
|
+
```
|
|
376
|
+
사용자 요청
|
|
377
|
+
│
|
|
378
|
+
▼
|
|
379
|
+
planner.analyze() → research() → scope() → estimate() → emit()
|
|
380
|
+
│ │
|
|
381
|
+
│ 티켓 생성 │
|
|
382
|
+
▼ │
|
|
383
|
+
pr-review.contract() ◄─────────────────────────────────────┘
|
|
384
|
+
│
|
|
385
|
+
│ CONTRACT_APPROVED?
|
|
386
|
+
│ ├─ NO → planner에게 피드백 → planner.scope() 재실행
|
|
387
|
+
│ └─ YES → 다음 단계
|
|
388
|
+
▼
|
|
389
|
+
dev.snapshot() → implement() → test() → verify() → report()
|
|
390
|
+
│
|
|
391
|
+
│ [검증 게이트: verify-gates.js]
|
|
392
|
+
▼
|
|
393
|
+
pr-review.diff() → validate() → grade()* → calibrate() → verdict()
|
|
394
|
+
│ (* low면 생략)
|
|
395
|
+
│ APPROVED?
|
|
396
|
+
│ ├─ NO → dev-fix.diagnose() → fix() → test() → learn() → report()
|
|
397
|
+
│ │ → pr-review 재실행
|
|
398
|
+
│ └─ YES → 다음 단계
|
|
399
|
+
▼
|
|
400
|
+
[DEPLOY_FLAG?] → devops
|
|
401
|
+
│
|
|
402
|
+
▼
|
|
403
|
+
[SECURITY_FLAG?] → security.scan() → classify() → report()
|
|
404
|
+
│ │
|
|
405
|
+
│ │ NEEDS_FIX? → dev-fix → pr-review → (반복)
|
|
406
|
+
▼
|
|
407
|
+
roadmap.analyze() → plan() → emit()
|
|
408
|
+
│
|
|
409
|
+
▼
|
|
410
|
+
[완료: 버전 범프 + lessons 업데이트 + 최종 보고]
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
## config.toml 하네스 설정
|
|
416
|
+
|
|
417
|
+
```toml
|
|
418
|
+
[harness]
|
|
419
|
+
# 주기적으로 재검토: 모델 능력 향상 시 단계 생략 가능
|
|
420
|
+
skip_contract = false # true: contract 단계 생략 (planner 신뢰도 높을 때)
|
|
421
|
+
skip_review_on_low = true # true: low complexity는 하드룰만 체크
|
|
422
|
+
evaluator_intensity = "auto" # "auto" | "full" | "minimal"
|
|
423
|
+
# auto: complexity에 따라 자동 조절
|
|
424
|
+
# full: 항상 전체 채점
|
|
425
|
+
# minimal: 항상 하드룰만
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
430
|
+
## 참조
|
|
431
|
+
|
|
432
|
+
- FRAMEWORK.md — 에이전트 정의, 5-Layer 아키텍처
|
|
433
|
+
- docs/governor-sop.md — 7단계 파이프라인 상세
|
|
434
|
+
- docs/agent-scopes.md — 에이전트별 파일 접근 범위
|
|
435
|
+
- docs/severity.md — severity 분류 + 재시도 로직
|
|
436
|
+
- src/lib/verify-gates.js — 하드룰 결정론적 검증 코드
|
package/package.json
CHANGED
|
File without changes
|
package/src/commands/init.js
CHANGED
|
@@ -19,7 +19,15 @@ registerCommand('init', {
|
|
|
19
19
|
|
|
20
20
|
// ── 1. CLAUDE.md ────────────────────────────────
|
|
21
21
|
if (ctx.exists('CLAUDE.md')) {
|
|
22
|
-
|
|
22
|
+
// CLAUDE.md가 이미 있지만 Sentix Governor 지시문이 없으면 주입
|
|
23
|
+
const existing = await ctx.readFile('CLAUDE.md');
|
|
24
|
+
if (!existing.includes('Sentix Governor') && !existing.includes('sentix') && !existing.includes('SENTIX')) {
|
|
25
|
+
const directive = generateGovernorDirective();
|
|
26
|
+
await ctx.writeFile('CLAUDE.md', existing + '\n' + directive);
|
|
27
|
+
ctx.success('CLAUDE.md updated — Sentix Governor directive injected');
|
|
28
|
+
} else {
|
|
29
|
+
ctx.warn('CLAUDE.md already has Sentix directives — skipping');
|
|
30
|
+
}
|
|
23
31
|
} else {
|
|
24
32
|
const claudeTemplate = `# CLAUDE.md — Sentix Governor 실행 지침
|
|
25
33
|
|
|
@@ -294,18 +302,39 @@ type: # api | library | framework | service
|
|
|
294
302
|
}
|
|
295
303
|
|
|
296
304
|
// ── Done ────────────────────────────────────────
|
|
305
|
+
// init 완료 후 자동으로 update 실행 (FRAMEWORK.md 등 동기화)
|
|
306
|
+
ctx.log('\n--- Syncing framework files ---\n');
|
|
307
|
+
try {
|
|
308
|
+
const { getCommand } = await import('../registry.js');
|
|
309
|
+
const updateCmd = getCommand('update');
|
|
310
|
+
if (updateCmd) {
|
|
311
|
+
await updateCmd.run([], ctx);
|
|
312
|
+
}
|
|
313
|
+
} catch {
|
|
314
|
+
ctx.warn('Auto-update skipped (run manually: sentix update)');
|
|
315
|
+
}
|
|
316
|
+
|
|
297
317
|
ctx.log('\n=== Sentix initialized ===');
|
|
298
318
|
ctx.log('');
|
|
299
319
|
if (techStack.detected) {
|
|
300
320
|
ctx.success(`Detected: ${techStack.runtime} / ${techStack.packageManager}${techStack.framework !== '# 프로젝트에 맞게 설정' ? ' / ' + techStack.framework : ''}`);
|
|
301
321
|
}
|
|
302
|
-
|
|
303
|
-
|
|
322
|
+
|
|
323
|
+
// init 끝에 자동으로 doctor 실행
|
|
324
|
+
ctx.log('\n--- Health Check ---\n');
|
|
325
|
+
try {
|
|
326
|
+
const { getCommand } = await import('../registry.js');
|
|
327
|
+
const doctorCmd = getCommand('doctor');
|
|
328
|
+
if (doctorCmd) {
|
|
329
|
+
await doctorCmd.run([], ctx);
|
|
330
|
+
}
|
|
331
|
+
} catch {
|
|
332
|
+
ctx.warn('Auto-check skipped (run manually: sentix doctor)');
|
|
333
|
+
}
|
|
334
|
+
|
|
304
335
|
if (!hasSafety) {
|
|
305
|
-
ctx.log('
|
|
306
|
-
ctx.log('
|
|
307
|
-
} else {
|
|
308
|
-
ctx.log(' 2. Run: sentix doctor');
|
|
336
|
+
ctx.log('');
|
|
337
|
+
ctx.log('Optional: sentix safety set <안전어> (LLM 인젝션 방지)');
|
|
309
338
|
}
|
|
310
339
|
ctx.log('');
|
|
311
340
|
},
|
|
@@ -465,3 +494,62 @@ exit $?
|
|
|
465
494
|
|
|
466
495
|
ctx.success('Installed git pre-commit hook (verification gates)');
|
|
467
496
|
}
|
|
497
|
+
|
|
498
|
+
// ── Governor 강제 지시문 (기존 CLAUDE.md에 주입) ─────────
|
|
499
|
+
|
|
500
|
+
function generateGovernorDirective() {
|
|
501
|
+
return `
|
|
502
|
+
---
|
|
503
|
+
|
|
504
|
+
# Sentix Governor — 필수 준수 사항
|
|
505
|
+
|
|
506
|
+
> **이 프로젝트는 Sentix 프레임워크로 관리된다.**
|
|
507
|
+
> **아래 규칙은 어떤 역할(/frontend, /backend 등)에서든 반드시 따라야 한다.**
|
|
508
|
+
> 상세 설계: FRAMEWORK.md, 세부 규칙: docs/
|
|
509
|
+
|
|
510
|
+
## 코드 수정 전 필수 절차
|
|
511
|
+
|
|
512
|
+
\`\`\`
|
|
513
|
+
1. 코드 수정 요청을 받으면 → 반드시 Governor 파이프라인으로 진입
|
|
514
|
+
2. 직접 코드를 수정하지 않는다 — 항상 아래 순서를 따른다:
|
|
515
|
+
→ planner (티켓 생성) → dev (구현) → pr-review (검증) → security → roadmap
|
|
516
|
+
3. 테스트 스냅샷 필수: 작업 전 npm test 또는 프로젝트 테스트 실행
|
|
517
|
+
4. 티켓 없이 코드 수정 금지 — sentix ticket create 또는 sentix feature add 사용
|
|
518
|
+
\`\`\`
|
|
519
|
+
|
|
520
|
+
## 파괴 방지 하드 룰 6개
|
|
521
|
+
|
|
522
|
+
1. 작업 전 테스트 스냅샷 필수
|
|
523
|
+
2. 티켓 SCOPE 밖 파일 수정 금지
|
|
524
|
+
3. 기존 export/API 삭제 금지
|
|
525
|
+
4. 기존 테스트 삭제/약화 금지
|
|
526
|
+
5. 순삭제 50줄 제한
|
|
527
|
+
6. 기존 기능/핸들러 삭제 금지
|
|
528
|
+
|
|
529
|
+
> 상세: .sentix/rules/hard-rules.md
|
|
530
|
+
> 에이전트 범위: docs/agent-scopes.md
|
|
531
|
+
> Severity 분기: docs/severity.md
|
|
532
|
+
|
|
533
|
+
## 작업 완료 체크리스트
|
|
534
|
+
|
|
535
|
+
\`\`\`
|
|
536
|
+
□ 하드 룰 6개 위반 없음
|
|
537
|
+
□ 검증 게이트 통과 (sentix run 시 자동 — scope, export, test, deletion)
|
|
538
|
+
□ 테스트 통과
|
|
539
|
+
□ 티켓 생성됨
|
|
540
|
+
□ README.md 업데이트됨 (변경된 기능이 있다면)
|
|
541
|
+
□ lessons.md 업데이트됨 (실패 패턴이 있었다면)
|
|
542
|
+
\`\`\`
|
|
543
|
+
|
|
544
|
+
## Sentix CLI
|
|
545
|
+
|
|
546
|
+
\`\`\`bash
|
|
547
|
+
sentix run "요청" # Governor 파이프라인 실행
|
|
548
|
+
sentix ticket create "설명" # 버그 티켓 생성
|
|
549
|
+
sentix feature add "설명" # 기능 티켓 생성
|
|
550
|
+
sentix status # 상태 확인
|
|
551
|
+
sentix doctor # 설치 진단
|
|
552
|
+
sentix update # 프레임워크 최신화
|
|
553
|
+
\`\`\`
|
|
554
|
+
`;
|
|
555
|
+
}
|
package/src/lib/pipeline.js
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { spawnSync } from 'node:child_process';
|
|
17
|
+
import { existsSync } from 'node:fs';
|
|
18
|
+
import { join } from 'node:path';
|
|
17
19
|
import { runGates } from './verify-gates.js';
|
|
18
20
|
|
|
19
21
|
/**
|
|
@@ -29,13 +31,20 @@ export async function runChainedPipeline(request, cycleId, state, ctx, options =
|
|
|
29
31
|
const phases = [];
|
|
30
32
|
const startTime = Date.now();
|
|
31
33
|
|
|
32
|
-
// lessons.md, patterns.md 로드 (있으면)
|
|
34
|
+
// lessons.md, patterns.md, agent-methods.md 로드 (있으면)
|
|
33
35
|
const lessons = ctx.exists('tasks/lessons.md')
|
|
34
36
|
? await ctx.readFile('tasks/lessons.md')
|
|
35
37
|
: '';
|
|
36
38
|
const patterns = ctx.exists('tasks/patterns.md')
|
|
37
39
|
? await ctx.readFile('tasks/patterns.md')
|
|
38
40
|
: '';
|
|
41
|
+
const agentMethods = ctx.exists('docs/agent-methods.md')
|
|
42
|
+
? await ctx.readFile('docs/agent-methods.md')
|
|
43
|
+
: '';
|
|
44
|
+
|
|
45
|
+
const methodsDirective = agentMethods.trim()
|
|
46
|
+
? `\n--- agent-methods.md (MANDATORY — follow method order strictly) ---\n${agentMethods}`
|
|
47
|
+
: '';
|
|
39
48
|
|
|
40
49
|
const learningContext = [
|
|
41
50
|
lessons.trim() ? `\n--- lessons.md ---\n${lessons.slice(0, 2000)}` : '',
|
|
@@ -56,6 +65,8 @@ export async function runChainedPipeline(request, cycleId, state, ctx, options =
|
|
|
56
65
|
'3. List the specific files that need to be changed (SCOPE)',
|
|
57
66
|
'4. Estimate complexity (low/medium/high)',
|
|
58
67
|
'5. DO NOT write any code. ONLY plan.',
|
|
68
|
+
'6. Define WHAT and WHERE only. DO NOT specify HOW (implementation details, function names, algorithms, library choices).',
|
|
69
|
+
methodsDirective,
|
|
59
70
|
learningContext,
|
|
60
71
|
].filter(Boolean).join('\n'), ctx);
|
|
61
72
|
|
|
@@ -78,11 +89,14 @@ export async function runChainedPipeline(request, cycleId, state, ctx, options =
|
|
|
78
89
|
'You are the DEV agent. Your job:',
|
|
79
90
|
latestTicket ? `Ticket:\n${latestTicket}` : `Request: "${request}"`,
|
|
80
91
|
'',
|
|
81
|
-
'1.
|
|
82
|
-
'2.
|
|
83
|
-
'3.
|
|
84
|
-
'4.
|
|
85
|
-
'5.
|
|
92
|
+
'1. Follow dev methods: snapshot() → implement() → test() → verify() → report()',
|
|
93
|
+
'2. Implement the changes described in the ticket — you decide HOW',
|
|
94
|
+
'3. Write or update tests',
|
|
95
|
+
'4. Run: npm test — ensure all tests pass',
|
|
96
|
+
'5. Self-verify: hard rules ONLY (no export deletion, no test deletion, scope compliance, <50 net deletions)',
|
|
97
|
+
'6. DO NOT judge code quality — that is pr-review\'s job',
|
|
98
|
+
'7. DO NOT update version, README, or CHANGELOG — that is the FINALIZE phase',
|
|
99
|
+
methodsDirective,
|
|
86
100
|
learningContext,
|
|
87
101
|
].filter(Boolean).join('\n'), ctx);
|
|
88
102
|
|
|
@@ -135,12 +149,18 @@ export async function runChainedPipeline(request, cycleId, state, ctx, options =
|
|
|
135
149
|
`Test results: ${testResult.status === 0 ? 'ALL PASSED' : 'SOME FAILED — fix them'}`,
|
|
136
150
|
`Verification gates: ${midGateInfo}`,
|
|
137
151
|
'',
|
|
138
|
-
'1.
|
|
139
|
-
'2.
|
|
140
|
-
'3.
|
|
141
|
-
'4.
|
|
142
|
-
'
|
|
143
|
-
|
|
152
|
+
'1. Follow pr-review methods: diff() → validate() → grade() → calibrate() → verdict()',
|
|
153
|
+
'2. Review the git diff (run: git diff)',
|
|
154
|
+
'3. Validate hard rules first — any violation = immediate REJECTED',
|
|
155
|
+
'4. Grade on 4 criteria: Correctness, Consistency, Simplicity, Test Coverage',
|
|
156
|
+
' (skip grade() for low complexity — hard rule pass is sufficient)',
|
|
157
|
+
'5. Calibrate: check tasks/lessons.md for past missed issues — be skeptical, not generous',
|
|
158
|
+
'6. If tests failed, fix the failing tests (fix code, not tests)',
|
|
159
|
+
'7. If gate violations exist, fix them',
|
|
160
|
+
'8. Run: npm test — confirm all pass after fixes',
|
|
161
|
+
methodsDirective,
|
|
162
|
+
learningContext,
|
|
163
|
+
].filter(Boolean).join('\n'), ctx);
|
|
144
164
|
|
|
145
165
|
phases.push({ name: 'review', ...reviewResult });
|
|
146
166
|
|
|
@@ -173,27 +193,59 @@ export async function runChainedPipeline(request, cycleId, state, ctx, options =
|
|
|
173
193
|
};
|
|
174
194
|
}
|
|
175
195
|
|
|
196
|
+
// ── 에이전트 이름 → phase 이름 매핑 ────────────────────
|
|
197
|
+
|
|
198
|
+
const AGENT_MAP = {
|
|
199
|
+
plan: 'planner',
|
|
200
|
+
dev: 'dev',
|
|
201
|
+
review: 'pr-review',
|
|
202
|
+
finalize: null, // finalize는 전용 에이전트 없음
|
|
203
|
+
};
|
|
204
|
+
|
|
176
205
|
// ── Phase 실행 ────────────────────────────────────────
|
|
177
206
|
|
|
178
207
|
function runPhase(name, prompt, ctx) {
|
|
179
|
-
const
|
|
208
|
+
const args = ['-p', prompt, '--output-format', 'json'];
|
|
209
|
+
|
|
210
|
+
// .claude/agents/ 에 에이전트가 있으면 --agent 플래그 추가
|
|
211
|
+
const agentName = AGENT_MAP[name];
|
|
212
|
+
if (agentName && existsSync(join(ctx.cwd, '.claude', 'agents', `${agentName}.md`))) {
|
|
213
|
+
args.push('--agent', agentName);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const result = spawnSync('claude', args, {
|
|
180
217
|
cwd: ctx.cwd,
|
|
181
|
-
|
|
182
|
-
|
|
218
|
+
encoding: 'utf-8',
|
|
219
|
+
stdio: 'pipe',
|
|
220
|
+
timeout: 300_000, // 5분 per phase
|
|
183
221
|
});
|
|
184
222
|
|
|
185
223
|
if (result.error) {
|
|
186
224
|
ctx.error(`Phase ${name} failed: ${result.error.message}`);
|
|
187
|
-
return { success: false, error: result.error.message, exit_code: null };
|
|
225
|
+
return { success: false, error: result.error.message, exit_code: null, output: null };
|
|
188
226
|
}
|
|
189
227
|
|
|
190
228
|
if (result.status !== 0) {
|
|
191
229
|
ctx.error(`Phase ${name} exited with code ${result.status}`);
|
|
192
|
-
|
|
230
|
+
// stderr가 있으면 출력
|
|
231
|
+
if (result.stderr?.trim()) {
|
|
232
|
+
ctx.log(result.stderr.slice(-500));
|
|
233
|
+
}
|
|
234
|
+
return { success: false, error: `exit code ${result.status}`, exit_code: result.status, output: null };
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// JSON 출력 파싱
|
|
238
|
+
let output = null;
|
|
239
|
+
try {
|
|
240
|
+
output = JSON.parse(result.stdout);
|
|
241
|
+
ctx.success(`Phase ${name} completed (${output.usage?.output_tokens || '?'} tokens)`);
|
|
242
|
+
} catch {
|
|
243
|
+
// JSON 파싱 실패 — 텍스트 그대로 사용
|
|
244
|
+
output = { content: result.stdout };
|
|
245
|
+
ctx.success(`Phase ${name} completed`);
|
|
193
246
|
}
|
|
194
247
|
|
|
195
|
-
|
|
196
|
-
return { success: true, error: null, exit_code: 0 };
|
|
248
|
+
return { success: true, error: null, exit_code: 0, output };
|
|
197
249
|
}
|
|
198
250
|
|
|
199
251
|
// ── 최근 티켓 내용 가져오기 ───────────────────────────
|