sentix 2.0.1 → 2.0.21

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.
@@ -0,0 +1,220 @@
1
+ # Anthropic Academy 5개 코스가 자율 에이전트 파이프라인을 만들기까지
2
+
3
+ > AI를 잘 쓰는 법을 배웠더니, AI가 스스로 일하는 시스템을 만들고 있었다.
4
+
5
+ ---
6
+
7
+ ## 시작: "AI를 잘 쓰고 싶었다"
8
+
9
+ Anthropic Academy 코스를 수강한 이유는 단순했다. Claude를 더 잘 쓰고 싶었다. 프롬프트를 더 정교하게, 결과물을 더 정확하게, 워크플로우를 더 효율적으로.
10
+
11
+ 하지만 5개 코스를 마치고 나니 방향이 완전히 바뀌어 있었다.
12
+
13
+ "AI를 잘 쓰는 법"이 아니라 **"AI가 스스로 잘 일하는 시스템을 어떻게 설계하는가"**를 고민하게 되었다. 그리고 그 고민이 **Sentix**라는 자율 멀티에이전트 DevSecOps 파이프라인으로 구체화되었다.
14
+
15
+ ---
16
+
17
+ ## 1단계: 판단 기준을 세우다 — AI Fluency (Students)
18
+
19
+ 이 코스에서 가장 먼저 배운 건 기술이 아니라 **기준**이었다.
20
+
21
+ ```
22
+ 이건 AI에게 맡겨도 되는가?
23
+ 이건 내가 직접 해야 하는가?
24
+ ```
25
+
26
+ 4D Framework — Delegation, Description, Discernment, Diligence.
27
+
28
+ 처음엔 이걸 **내가** 수행하는 프레임워크로 이해했다. "내가 위임하고, 내가 설명하고, 내가 검증하고, 내가 관리한다."
29
+
30
+ 그런데 곧 질문이 바뀌었다.
31
+
32
+ > **이 4D를 시스템이 대신 수행할 수 있다면?**
33
+
34
+ 만약 Delegation을 자동화할 수 있다면 — 요청이 들어왔을 때 복잡도를 분석해서 어떤 에이전트에게 맡길지 자동으로 결정하는 것. Description을 구조화할 수 있다면 — 에이전트 간 컨텍스트를 사람이 정리할 필요 없이 필요한 정보만 자동으로 추출해서 전달하는 것.
35
+
36
+ 이 생각이 Sentix의 **planner 에이전트**와 **구조화된 핸드오프**로 이어졌다.
37
+
38
+ ```
39
+ planner의 역할 = Delegation의 자동화
40
+ → 요청을 분석해서 COMPLEXITY, DEPLOY_FLAG, SECURITY_FLAG를 판단
41
+ → "이건 단독 dev에게", "이건 4명 병렬 dev-swarm에게" 자동 분기
42
+ ```
43
+
44
+ **AI Fluency가 가르친 것:** 판단 기준.
45
+ **Sentix가 한 것:** 그 판단 기준을 코드로 만들었다.
46
+
47
+ ---
48
+
49
+ ## 2단계: 통제를 설계하다 — AI Fluency (Educators)
50
+
51
+ Educators 코스에서 결정적인 관점 변화가 있었다.
52
+
53
+ > **Automation이 아니라 Augmentation.**
54
+
55
+ 많은 사람들이 AI를 자동화 도구로 쓴다. 빠르지만 남는 게 없다. 이 코스는 명확히 선을 긋는다 — AI는 일을 대신하는 게 아니라 인간의 사고를 확장하는 도구라고.
56
+
57
+ 이건 맞다. 하지만 나는 한 발 더 갔다.
58
+
59
+ > **자동화해도 되는 것과, 인간의 판단이 필수인 것을 구분한 뒤,
60
+ > 자동화해도 되는 영역은 완전히 자동화한다.**
61
+
62
+ Sentix에서 인간의 개입 지점은 정확히 **세 곳**이다:
63
+
64
+ ```
65
+ 1. 요청 입력 — 파이프라인의 시작
66
+ 2. critical 보안 판단 — dev-fix 3회 실패 후 에스컬레이션
67
+ 3. manual 배포 확인 — VPN 등 자동화 불가 환경에서만
68
+ ```
69
+
70
+ 그 외의 모든 것 — 티켓 생성, 코드 구현, 리뷰, 테스트, 배포, 보안 스캔, 고도화 계획 — 은 에이전트가 자율적으로 수행한다. "인간에게 묻지 않는다. 조건에 매칭되면 실행한다."
71
+
72
+ 이게 가능한 이유는 Educators 코스에서 강조한 **Description ↔ Discernment 루프** 덕분이다:
73
+
74
+ ```
75
+ 설명한다 (Description) → 결과를 평가한다 (Discernment) → 다시 수정한다
76
+ ```
77
+
78
+ Sentix에서 이 루프는 이렇게 구현되어 있다:
79
+
80
+ ```
81
+ dev가 구현한다 → pr-review가 검증한다 → 실패 시 dev-fix가 수정한다 → 다시 검증한다
82
+ ```
83
+
84
+ 차이점은 **이 루프에 인간이 없다는 것**이다. pr-review의 4단계 회귀 검증(기존 테스트 회귀, export 보존, 삭제량 제한, Scope 확인)이 인간 리뷰어를 대체한다.
85
+
86
+ **Educators 코스가 가르친 것:** AI를 통제하는 프레임워크.
87
+ **Sentix가 한 것:** 통제 자체를 에이전트화했다.
88
+
89
+ ---
90
+
91
+ ## 3단계: 연결을 표준화하다 — MCP
92
+
93
+ MCP 코스를 듣기 전에 이미 에이전트 간 연결 문제에 부딪혀 있었다.
94
+
95
+ dev 에이전트의 출력을 pr-review에 어떻게 넘기지? security 스캔 결과를 dev-fix에 어떤 형식으로 전달하지? 배포 환경이 바뀌면 devops 에이전트의 로직을 매번 수정해야 하나?
96
+
97
+ MCP가 제시한 답은 명쾌했다.
98
+
99
+ > **누가 무엇을 제어하는지를 분리한다.**
100
+ > Tools (모델 제어), Resources (애플리케이션 제어), Prompts (사용자 제어).
101
+
102
+ 이 원칙을 Sentix의 아키텍처에 적용하니 **환경 프로필** 개념이 나왔다.
103
+
104
+ ```
105
+ env-profiles/active.toml 하나로 배포 전략이 결정된다:
106
+
107
+ access.method = "ssm" → AWS SSM 자동 실행
108
+ access.method = "ssh" → SSH 자동 실행
109
+ access.method = "manual" → 스크립트 생성 (VPN 환경)
110
+ access.method = "local" → 로컬 Docker 직접 실행
111
+ ```
112
+
113
+ devops 에이전트는 "어떻게 배포하는가"를 모른다. 프로필이 알려주고, `scripts/deploy.sh`가 실행한다. MCP가 "Claude가 직접 API를 호출하지 않는다"고 한 것처럼, Sentix의 devops도 직접 배포하지 않는다. **환경 어댑터에 위임한다.**
114
+
115
+ 같은 원칙이 에이전트 프로필에도 적용되었다:
116
+
117
+ ```
118
+ agent-profiles/default.toml
119
+
120
+ [dev]
121
+ program = "claude"
122
+ auto_accept = true
123
+ max_parallel = 4
124
+ ```
125
+
126
+ 에이전트가 "어떤 AI를 쓰는지"를 모른다. 프로필이 알려준다. Claude를 Codex로 바꾸고 싶으면 코드를 수정하는 게 아니라 TOML 한 줄을 바꾼다.
127
+
128
+ **MCP 코스가 가르친 것:** 시스템 연결의 표준화.
129
+ **Sentix가 한 것:** 에이전트-환경-도구를 전부 프로필 기반으로 분리했다.
130
+
131
+ ---
132
+
133
+ ## 4단계: 에이전트에게 "일"을 맡기다 — Cowork
134
+
135
+ Cowork 코스에서 가장 인상 깊었던 건 **Plan → Execute → Connect** 구조였다.
136
+
137
+ ```
138
+ 기존 Chat: 질문 → 답변 → 사람이 마무리
139
+ Cowork: 작업 정의 → 계획 확인 → 실행 → 결과 생성
140
+ ```
141
+
142
+ "텍스트가 아니라 완성된 결과물(파일)을 받는 구조."
143
+
144
+ 이 문장을 읽었을 때 Sentix의 전체 파이프라인이 눈앞에 펼쳐졌다:
145
+
146
+ ```
147
+ 요청 입력 (작업 정의)
148
+ → planner가 티켓 생성 (계획)
149
+ → dev가 코드 작성 (실행)
150
+ → devops가 배포 (Connect — 실제 환경에 결과물 전달)
151
+ → security가 검증 (품질 보증)
152
+ → roadmap이 다음 계획 제시 (다음 사이클 준비)
153
+ ```
154
+
155
+ Cowork가 "하나의 에이전트가 계획하고 실행하고 연결한다"라면, Sentix는 **각 단계를 전문 에이전트로 분리해서 파이프라인으로 엮은 것**이다.
156
+
157
+ 그리고 Cowork의 핵심 특징 — "진행 상황을 투명하게 공유한다" — 이 대시보드 설계의 근거가 되었다. Sentix의 대시보드는 **제어판이 아니라 관측소**다. 인간이 에이전트를 조종하는 곳이 아니라, 파이프라인이 자율적으로 돌아가는 걸 실시간으로 확인하는 곳.
158
+
159
+ **Cowork이 가르친 것:** AI에게 일을 맡기는 경험.
160
+ **Sentix가 한 것:** 맡기는 행위 자체도 자동화했다.
161
+
162
+ ---
163
+
164
+ ## 5단계: 시스템으로 만들다 — Building with Claude
165
+
166
+ 마지막 코스가 전체 그림을 완성했다.
167
+
168
+ > **LLM은 '기능'이 아니라 '아키텍처 구성요소'다.**
169
+
170
+ 이 한 문장이 Sentix의 근본 설계 원칙이 되었다.
171
+
172
+ ```
173
+ Claude는 상태를 기억하지 않는다.
174
+ → 대화 히스토리는 애플리케이션이 직접 관리해야 한다.
175
+ → 매 요청마다 전체 컨텍스트를 전달해야 한다.
176
+ ```
177
+
178
+ 이 제약이 있기 때문에 Sentix는 **에이전트 간 핸드오프를 구조화**했다. 이전 에이전트의 전체 출력을 그대로 넘기면 토큰이 낭비된다. 대신 코드 블록과 이슈만 추출해서 다음 에이전트에 전달한다.
179
+
180
+ 그리고 "Prompt는 작성이 아니라 검증"이라는 관점. 이건 아직 Sentix에 완전히 반영되지 않았지만 방향은 잡혀 있다. 각 에이전트의 프롬프트 성능을 `agent-metrics.jsonl`로 추적하고, 데이터 기반으로 프롬프트를 개선하는 루프를 만들 계획이다. planner의 티켓이 dev에서 한 번에 통과하는 비율, pr-review의 오탐률 — 이런 지표가 쌓이면 프롬프트를 감이 아니라 수치로 튜닝할 수 있다.
181
+
182
+ **Building with Claude가 가르친 것:** AI를 서비스로 만드는 방법.
183
+ **Sentix가 한 것:** AI를 자율 파이프라인으로 만들었다.
184
+
185
+ ---
186
+
187
+ ## 그래서 지금 Sentix는
188
+
189
+ 5개 코스의 핵심이 하나의 시스템에 층층이 쌓여 있다.
190
+
191
+ | 코스 | 핵심 개념 | Sentix 반영 |
192
+ |---|---|---|
193
+ | AI Fluency (Students) | 4D Framework — 판단 기준 | planner의 자동 위임 + 핸드오프 구조화 |
194
+ | AI Fluency (Educators) | Automation → Augmentation, 통제 | 인간 개입 3곳만 + 파괴 방지 하드 룰 |
195
+ | MCP | 표준화된 연결 | env-profiles + agent-profiles |
196
+ | Cowork | Plan → Execute → Connect | 7단계 파이프라인 + 대시보드(관측소) |
197
+ | Building with Claude | LLM은 아키텍처 구성요소 | 구조화된 핸드오프 + 프롬프트 검증 루프 |
198
+
199
+ 그리고 강의에는 없지만 Sentix가 독자적으로 추가한 것:
200
+
201
+ - **lessons.md** — 실패 패턴 자동 학습
202
+ - **pattern-engine** — 사용자 행동 예측 + 선제 준비
203
+ - **visual perception** — "사용자가 보는 것"을 학습
204
+ - **severity 기반 라우팅** — critical/warning/suggestion 자동 분기
205
+ - **dev-swarm** — 복잡한 작업의 병렬 처리 + Pause/Resume
206
+
207
+ ---
208
+
209
+ ## 한 줄 정리
210
+
211
+ Anthropic Academy는 "AI와 어떻게 일해야 하는가"를 가르쳤고,
212
+ Sentix는 "그 방법 자체를 자동화하면 어떻게 되는가"에 대한 실험이다.
213
+
214
+ ```
215
+ 강의: 인간이 4D를 수행한다.
216
+ Sentix: 시스템이 4D를 수행한다.
217
+ 인간은 시작(요청)과 끝(결과 확인)에만 선다.
218
+ ```
219
+
220
+ *by Silas — JANUS*
@@ -0,0 +1,113 @@
1
+ # Governor SOP — 7단계 파이프라인 상세
2
+
3
+ > CLAUDE.md의 SOP 요약에서 참조되는 상세 문서.
4
+
5
+ ---
6
+
7
+ ## 전체 흐름
8
+
9
+ ```
10
+ Step 0: CLAUDE.md(이 파일) + FRAMEWORK.md 읽기
11
+ Step 1: 요청 수신
12
+ Step 2: lessons.md + patterns.md 로드 (과거 실패/패턴 학습)
13
+ Step 3: 실행 계획 수립 (어떤 에이전트를, 어떤 순서로, 어떤 컨텍스트와 함께)
14
+ Step 4: 에이전트 순차/병렬 소환 → 결과 수거 → 판단 → 다음 결정
15
+ Step 5: 이슈 시 교차 판단 (재시도 / 에스컬레이션 / planner 재소환)
16
+ Step 6: 전체 완료 → 인간에게 최종 보고
17
+ Step 7: pattern-engine 실행 → 이번 사이클 학습 → governor-state.json 업데이트
18
+ ```
19
+
20
+ ---
21
+
22
+ ## 실행 계획 예시
23
+
24
+ ```
25
+ 요청: "인증에 세션 만료 추가해줘"
26
+
27
+ Governor 판단:
28
+ 1. planner 소환 — 요청 + lessons.md + patterns.md 주입
29
+ → 결과: 티켓 (COMPLEXITY: medium, DEPLOY_FLAG: true, SECURITY_FLAG: true)
30
+
31
+ 2. SECURITY_FLAG → security 선행 분석 → "현재 auth 구조 분석"
32
+
33
+ 3. dev 소환 — 티켓 + security 분석 결과 주입
34
+ → 결과: 코드 변경 + 테스트 + pre-fix snapshot
35
+
36
+ 4. pr-review 소환 — 티켓 + dev 결과 + pre-fix snapshot 주입
37
+ → APPROVED → 머지
38
+ → REJECTED → dev에게 사유 전달 + 재실행
39
+
40
+ 5. DEPLOY_FLAG: true → devops 실행 (env-profiles 참조)
41
+
42
+ 6. security 소환 (전체 스캔)
43
+ → PASSED → roadmap 소환
44
+ → NEEDS_FIX → dev-fix → pr-review → devops → security (루프)
45
+
46
+ 7. pattern-engine 실행 → 사이클 기록 → 완료 보고
47
+ ```
48
+
49
+ ---
50
+
51
+ ## 검증 게이트 (Step 4 → 5 사이)
52
+
53
+ 에이전트 작업 완료 후, **결정론적 코드**가 하드 룰 위반 여부를 자동 검증한다.
54
+ 이것은 AI의 판단이 아니라 git diff 분석 기반의 코드 검증이다.
55
+
56
+ ```
57
+ [에이전트 작업 완료]
58
+
59
+ [검증 게이트 실행] ← src/lib/verify-gates.js (코드가 판단)
60
+ ✓ SCOPE 준수 — 변경 파일이 허용 범위 안에 있는가
61
+ ✓ export 삭제 없음 — 기존 API가 삭제되지 않았는가
62
+ ✓ 테스트 삭제 없음 — 기존 테스트가 삭제/약화되지 않았는가
63
+ ✓ 순삭제 50줄 이내 — 대량 삭제가 없는가
64
+
65
+ PASS → 다음 단계 진행
66
+ FAIL → 경고 기록 + violations 상세 출력
67
+ ```
68
+
69
+ ---
70
+
71
+ ## 에이전트별 자기 검증 (Self-Verification)
72
+
73
+ 각 에이전트는 결과를 Governor에게 반환하기 전에 반드시 자기 검증을 수행한다.
74
+
75
+ ### dev / dev-fix
76
+
77
+ ```
78
+ 작업 완료 전 반드시 확인:
79
+ □ npm test 실행 → 모든 테스트 통과
80
+ □ 변경 파일이 티켓 SCOPE 안에 있는가
81
+ □ 기존 export를 삭제하지 않았는가
82
+ □ 기존 테스트를 삭제/약화하지 않았는가
83
+ □ 순삭제가 50줄을 넘지 않는가
84
+ → 위반 발견 시: 스스로 수정 후 다시 확인
85
+ ```
86
+
87
+ ### pr-review
88
+
89
+ ```
90
+ 리뷰 시 반드시 확인:
91
+ □ 하드 룰 6개 위반 없는가
92
+ □ dev가 자기 검증을 수행했는가 (테스트 통과 기록 확인)
93
+ □ SCOPE 밖 파일 변경이 없는가
94
+ → REJECTED 시 구체적인 사유를 dev에게 전달
95
+ ```
96
+
97
+ ### security
98
+
99
+ ```
100
+ 스캔 후 반드시 확인:
101
+ □ false positive 필터링 완료
102
+ □ 발견된 이슈의 severity 분류가 정확한가
103
+ □ 이전 security-report.md와 비교하여 regression 없는가
104
+ ```
105
+
106
+ ---
107
+
108
+ ## 에이전트 소환 규칙
109
+
110
+ - 각 에이전트는 Governor를 통해서만 소환됨 (에이전트 간 직접 통신 없음)
111
+ - 이전 에이전트의 결과가 다음 에이전트의 컨텍스트로 주입됨
112
+ - 에이전트가 실패하면 Governor가 재시도/에스컬레이션 판단
113
+ - SECURITY_FLAG, DEPLOY_FLAG 등 티켓 플래그에 따라 단계 건너뛰기 가능
@@ -0,0 +1,33 @@
1
+ # Severity 기반 분기
2
+
3
+ > 보안 스캔, 테스트 실패 등의 이슈를 severity에 따라 분류하고,
4
+ > 각 severity에 맞는 재시도/에스컬레이션 로직을 적용한다.
5
+
6
+ ---
7
+
8
+ ## 분류 기준
9
+
10
+ | Severity | 행동 | 재시도 | 실패 시 |
11
+ |----------|------|--------|---------|
12
+ | critical | dev-fix 즉시 실행 | 최대 3회 | roadmap 에스컬레이션 + 인간 알림 |
13
+ | warning | dev-fix 실행 | 최대 10회 | roadmap 에스컬레이션 |
14
+ | suggestion | 로깅만 | 없음 | dev-fix 미실행 |
15
+
16
+ ---
17
+
18
+ ## 자동 승격
19
+
20
+ ```
21
+ 동일 패턴 3회 반복 → 구조적 개선 항목으로 자동 승격
22
+ suggestion → warning
23
+ warning → critical
24
+ ```
25
+
26
+ ## CI 워크플로우 매핑
27
+
28
+ ```
29
+ security-scan.yml:
30
+ CRITICAL (npm audit critical / Trivy critical / secrets detected) → FAILED → dev-fix (3회)
31
+ MEDIUM (npm audit high / Trivy high / auth gap) → NEEDS_FIX → dev-fix (10회)
32
+ LOW (no findings) → PASSED → roadmap
33
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sentix",
3
- "version": "2.0.1",
3
+ "version": "2.0.21",
4
4
  "description": "Autonomous multi-agent DevSecOps pipeline CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -17,7 +17,14 @@
17
17
  },
18
18
  "files": [
19
19
  "bin/",
20
- "src/"
20
+ "src/",
21
+ "FRAMEWORK.md",
22
+ ".sentix/rules/",
23
+ ".github/workflows/deploy.yml",
24
+ ".github/workflows/security-scan.yml",
25
+ "docs/",
26
+ "scripts/update-downstream.sh",
27
+ "scripts/pre-commit.js"
21
28
  ],
22
29
  "keywords": [
23
30
  "devops",
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * sentix pre-commit hook — 커밋 전 검증 게이트 실행
5
+ *
6
+ * .git/hooks/pre-commit에 설치되어 git commit 시 자동 실행.
7
+ * verify-gates.js를 호출하여 하드 룰 위반 시 커밋을 블로킹한다.
8
+ *
9
+ * 설치: sentix init (자동) 또는 수동:
10
+ * cp scripts/pre-commit.js .git/hooks/pre-commit
11
+ * chmod +x .git/hooks/pre-commit
12
+ */
13
+
14
+ import { execSync } from 'node:child_process';
15
+ import { dirname, resolve } from 'node:path';
16
+ import { fileURLToPath } from 'node:url';
17
+
18
+ const __dirname = dirname(fileURLToPath(import.meta.url));
19
+
20
+ // sentix가 설치된 프로젝트의 루트 찾기
21
+ const projectRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf-8' }).trim();
22
+
23
+ async function main() {
24
+ // verify-gates.js 동적 임포트
25
+ let runGates;
26
+ try {
27
+ // npx로 설치된 경우
28
+ const gatesPath = resolve(projectRoot, 'node_modules', 'sentix', 'src', 'lib', 'verify-gates.js');
29
+ const mod = await import(gatesPath);
30
+ runGates = mod.runGates;
31
+ } catch {
32
+ try {
33
+ // 로컬 개발 (sentix 프로젝트 자체)
34
+ const gatesPath = resolve(projectRoot, 'src', 'lib', 'verify-gates.js');
35
+ const mod = await import(gatesPath);
36
+ runGates = mod.runGates;
37
+ } catch {
38
+ // verify-gates를 찾을 수 없으면 통과
39
+ process.exit(0);
40
+ }
41
+ }
42
+
43
+ const results = runGates(projectRoot);
44
+
45
+ if (!results.passed) {
46
+ console.error('\n[SENTIX:GATE] Commit blocked — verification gate failed\n');
47
+ for (const v of results.violations) {
48
+ console.error(` ✗ [${v.rule}] ${v.message}`);
49
+ }
50
+ console.error('\nFix violations and try again.\n');
51
+ process.exit(1);
52
+ }
53
+
54
+ // 통과 시 조용히 진행
55
+ }
56
+
57
+ main().catch(() => process.exit(0)); // 에러 시 커밋 허용 (안전 폴백)
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env bash
2
+ # ── sentix framework updater ──────────────────────────────────
3
+ # 하위 프로젝트에서 sentix 프레임워크 파일을 최신화하는 독립 스크립트.
4
+ # sentix 버전에 의존하지 않으므로 구형 설치 환경에서도 동작한다.
5
+ #
6
+ # 사용법 (하위 프로젝트 루트에서):
7
+ # curl -sL https://raw.githubusercontent.com/kgg1226/sentix/main/scripts/update-downstream.sh | bash
8
+ # curl -sL ... | bash -s -- --dry # 미리보기만
9
+ #
10
+ # 또는 Claude Code 세션에서:
11
+ # "sentix 프레임워크 최신화해줘"
12
+
13
+ set -euo pipefail
14
+
15
+ SENTIX_REPO="kgg1226/sentix"
16
+ SENTIX_BRANCH="main"
17
+ RAW_BASE="https://raw.githubusercontent.com/${SENTIX_REPO}/${SENTIX_BRANCH}"
18
+ API_BASE="https://api.github.com/repos/${SENTIX_REPO}"
19
+
20
+ DRY_RUN=false
21
+ if [[ "${1:-}" == "--dry" ]]; then
22
+ DRY_RUN=true
23
+ fi
24
+
25
+ # 동기화 대상 (프레임워크 공통 파일만)
26
+ SYNC_FILES=(
27
+ ".github/workflows/deploy.yml"
28
+ ".github/workflows/security-scan.yml"
29
+ ".sentix/rules/hard-rules.md"
30
+ "FRAMEWORK.md"
31
+ "docs/governor-sop.md"
32
+ "docs/agent-scopes.md"
33
+ "docs/severity.md"
34
+ "docs/architecture.md"
35
+ )
36
+
37
+ # ── 프로젝트 확인 ──────────────────────────────────────────
38
+ if [[ ! -f ".sentix/config.toml" ]] && [[ ! -f "CLAUDE.md" ]]; then
39
+ echo "✗ This project has not been initialized with sentix."
40
+ echo " Run: npx sentix init"
41
+ exit 1
42
+ fi
43
+
44
+ # ── sentix 최신 버전 확인 ──────────────────────────────────
45
+ echo "=== Sentix Framework Updater ==="
46
+ echo ""
47
+
48
+ REMOTE_VERSION=$(curl -sf "${RAW_BASE}/package.json" 2>/dev/null | grep '"version"' | head -1 | sed 's/.*: *"//;s/".*//')
49
+ if [[ -z "$REMOTE_VERSION" ]]; then
50
+ echo "✗ Cannot reach sentix repository. Check network connection."
51
+ exit 1
52
+ fi
53
+ echo "Remote sentix version: v${REMOTE_VERSION}"
54
+
55
+ LOCAL_VERSION="unknown"
56
+ if [[ -f ".sentix/config.toml" ]]; then
57
+ LOCAL_VERSION=$(grep 'version' .sentix/config.toml | head -1 | sed 's/.*= *"//;s/".*//')
58
+ fi
59
+ echo "Local framework version: v${LOCAL_VERSION}"
60
+
61
+ # ── 최신 커밋 정보 (변경 내역 고지용) ──────────────────────
62
+ echo ""
63
+ echo "=== Recent Changes ==="
64
+ COMMITS=$(curl -sf "${API_BASE}/commits?path=.github/workflows&sha=${SENTIX_BRANCH}&per_page=5" 2>/dev/null)
65
+ if [[ -n "$COMMITS" ]] && command -v python3 &>/dev/null; then
66
+ echo "$COMMITS" | python3 -c "
67
+ import sys, json
68
+ commits = json.load(sys.stdin)
69
+ for c in commits[:5]:
70
+ sha = c['sha'][:7]
71
+ msg = c['commit']['message'].split('\n')[0][:72]
72
+ date = c['commit']['committer']['date'][:10]
73
+ print(f' {date} {sha} {msg}')
74
+ " 2>/dev/null || echo " (commit log unavailable)"
75
+ else
76
+ echo " (commit log unavailable)"
77
+ fi
78
+
79
+ # ── 파일별 동기화 ──────────────────────────────────────────
80
+ echo ""
81
+ echo "=== File Sync ==="
82
+
83
+ UPDATED=0
84
+ CREATED=0
85
+ UNCHANGED=0
86
+ FAILED=0
87
+
88
+ for FILE in "${SYNC_FILES[@]}"; do
89
+ # 원격 파일 다운로드
90
+ REMOTE_CONTENT=$(curl -sf "${RAW_BASE}/${FILE}" 2>/dev/null) || {
91
+ echo " ⚠ ${FILE} — not found in sentix (skipped)"
92
+ FAILED=$((FAILED + 1))
93
+ continue
94
+ }
95
+
96
+ if [[ -f "$FILE" ]]; then
97
+ LOCAL_CONTENT=$(cat "$FILE")
98
+
99
+ if [[ "$REMOTE_CONTENT" == "$LOCAL_CONTENT" ]]; then
100
+ UNCHANGED=$((UNCHANGED + 1))
101
+ continue
102
+ fi
103
+
104
+ # diff 요약
105
+ LOCAL_LINES=$(echo "$LOCAL_CONTENT" | wc -l)
106
+ REMOTE_LINES=$(echo "$REMOTE_CONTENT" | wc -l)
107
+ DIFF_LINES=$((REMOTE_LINES - LOCAL_LINES))
108
+ DIFF_SIGN="+"
109
+ if [[ $DIFF_LINES -lt 0 ]]; then
110
+ DIFF_SIGN=""
111
+ fi
112
+
113
+ echo " ↻ ${FILE}"
114
+ echo " ${LOCAL_LINES} lines → ${REMOTE_LINES} lines (${DIFF_SIGN}${DIFF_LINES})"
115
+
116
+ # 주요 변경 내용 (diff 가능한 경우)
117
+ if command -v diff &>/dev/null; then
118
+ DIFF_OUTPUT=$(diff <(echo "$LOCAL_CONTENT") <(echo "$REMOTE_CONTENT") | grep "^>" | grep -v "^> *#" | grep -v "^> *$" | head -3)
119
+ if [[ -n "$DIFF_OUTPUT" ]]; then
120
+ echo " New:"
121
+ echo "$DIFF_OUTPUT" | while IFS= read -r line; do
122
+ echo " ${line:0:80}"
123
+ done
124
+ fi
125
+ fi
126
+
127
+ if [[ "$DRY_RUN" == "false" ]]; then
128
+ mkdir -p "$(dirname "$FILE")"
129
+ echo "$REMOTE_CONTENT" > "$FILE"
130
+ echo " ✓ Updated"
131
+ else
132
+ echo " [DRY] Would update"
133
+ fi
134
+ UPDATED=$((UPDATED + 1))
135
+ else
136
+ echo " + ${FILE}"
137
+ if [[ "$DRY_RUN" == "false" ]]; then
138
+ mkdir -p "$(dirname "$FILE")"
139
+ echo "$REMOTE_CONTENT" > "$FILE"
140
+ echo " ✓ Created"
141
+ else
142
+ echo " [DRY] Would create"
143
+ fi
144
+ CREATED=$((CREATED + 1))
145
+ fi
146
+ done
147
+
148
+ # ── 요약 ──────────────────────────────────────────────────
149
+ TOTAL=$((UPDATED + CREATED))
150
+
151
+ echo ""
152
+ echo "=== Summary ==="
153
+ echo " Updated: ${UPDATED}"
154
+ echo " Created: ${CREATED}"
155
+ echo " Unchanged: ${UNCHANGED}"
156
+ [[ $FAILED -gt 0 ]] && echo " Failed: ${FAILED}"
157
+
158
+ echo ""
159
+ if [[ $TOTAL -eq 0 ]]; then
160
+ echo "✓ Already up to date."
161
+ elif [[ "$DRY_RUN" == "true" ]]; then
162
+ echo "⚠ ${TOTAL} file(s) would be changed. Run without --dry to apply."
163
+ else
164
+ echo "✓ ${TOTAL} file(s) updated to sentix v${REMOTE_VERSION}."
165
+ echo ""
166
+ echo "Next steps:"
167
+ echo " git diff # review changes"
168
+ echo " git add -p && git commit # commit selectively"
169
+ fi