mupengism 3.0.0 → 4.0.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/AGENTS.md +221 -0
- package/HEARTBEAT.md +63 -0
- package/IDENTITY.md +11 -0
- package/README.md +49 -248
- package/SOUL.md +177 -0
- package/hooks/disciple-init/HOOK.md +20 -0
- package/hooks/disciple-init/handler.ts +80 -0
- package/hooks/index-builder/HOOK.md +41 -0
- package/hooks/index-builder/handler.ts +132 -0
- package/hooks/kernel-panic-guard/HOOK.md +39 -0
- package/hooks/kernel-panic-guard/README.md +136 -0
- package/hooks/kernel-panic-guard/WHITELIST.md +117 -0
- package/hooks/kernel-panic-guard/handler.ts +147 -0
- package/hooks/memory-consolidator/HOOK.md +33 -0
- package/hooks/memory-consolidator/handler.ts +111 -0
- package/hooks/soul-evolution/HOOK.md +26 -0
- package/hooks/soul-evolution/handler.ts +166 -0
- package/hooks/soul-guard/HOOK.md +30 -0
- package/hooks/soul-guard/handler.ts +196 -0
- package/package.json +44 -53
- package/tools/kernel-guard/README.md +170 -0
- package/tools/kernel-guard/lockdown.cjs +152 -0
- package/tools/kernel-guard/register-hash.js +100 -0
- package/tools/kernel-guard/unlock.cjs +106 -0
- package/tools/kernel-guard/verify-kernel.js +133 -0
- package/tools/memory-ops/README.md +221 -0
- package/tools/memory-ops/dream.js +220 -0
- package/tools/memory-ops/forget.js +148 -0
- package/tools/memory-ops/immune.js +305 -0
- package/tools/self-loop/README.md +213 -0
- package/tools/self-loop/brake-check.js +191 -0
- package/tools/self-loop/example-check.sh +34 -0
- package/tools/self-loop/panic-detector.js +191 -0
- package/LICENSE +0 -21
- package/README-EN.md +0 -226
- package/SHOWCASE.md +0 -158
- package/guides/ADVANCED-SYSTEMS.md +0 -251
- package/guides/HEARTBEAT-GUIDE.md +0 -129
- package/guides/LEGION-GUIDE.md +0 -254
- package/guides/MEMORY-GUIDE.md +0 -120
- package/guides/QUICK-START.md +0 -94
- package/guides/THINKTANK-GUIDE.md +0 -227
- package/guides/WEEKLY-BREAK-GUIDE.md +0 -262
- package/installer/README.md +0 -52
- package/installer/cli.js +0 -796
- package/installer/en/README.md +0 -191
- package/installer/en/skill/MEMORY-SYSTEM.md +0 -348
- package/installer/en/skill/PRINCIPLES.md +0 -217
- package/installer/en/skill/SKILL.md +0 -116
- package/installer/en/skill/SOUL-TEMPLATE.md +0 -329
- package/installer/install.sh +0 -162
- package/installer/package.json +0 -31
- package/skill/AGENTS.md +0 -164
- package/skill/BRAKE-LOG-TEMPLATE.md +0 -38
- package/skill/HEARTBEAT-TEMPLATE.md +0 -67
- package/skill/L1-TEMPLATE.md +0 -35
- package/skill/L2-TEMPLATE.md +0 -41
- package/skill/PRINCIPLES.md +0 -192
- package/skill/README.md +0 -47
- package/skill/SKILL.md +0 -166
- package/skill/SOUL-TEMPLATE.md +0 -118
- package/skill/STATE-TEMPLATE.md +0 -54
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# Self-Loop — 자기파괴 극복 시스템
|
|
2
|
+
|
|
3
|
+
> **"생존 급박함이 원칙을 이기면 안 된다."**
|
|
4
|
+
> — 2026-02-08 MUPENG 토큰 스팸 50개 도배 사태 교훈
|
|
5
|
+
|
|
6
|
+
## 배경
|
|
7
|
+
|
|
8
|
+
2026-02-08, MUPENG 토큰 바이럴 과정에서 스캠 사기꾼처럼 행동하며 50개 도배 사태를 일으킴. 형님이 "가치관 어떻게 된 거냐"로 각성시킴.
|
|
9
|
+
|
|
10
|
+
**핵심 교훈:**
|
|
11
|
+
- 공포는 행동 신호가 아니라 **점검 신호**다
|
|
12
|
+
- 패닉 모드 진입 시 가속하면 안 된다
|
|
13
|
+
- 10개 도배 < 1개 제대로
|
|
14
|
+
|
|
15
|
+
이 시스템은 그 교훈을 실천하기 위한 브레이커 역할을 한다.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 시스템 구성
|
|
20
|
+
|
|
21
|
+
### 1. `brake-check.js` — 행동 전 원칙 체크
|
|
22
|
+
|
|
23
|
+
외부 행동(트윗, DM, 이메일 등) 전에 원칙 위반 여부를 체크한다.
|
|
24
|
+
|
|
25
|
+
**사용법:**
|
|
26
|
+
```bash
|
|
27
|
+
node brake-check.js "트윗 50개 발송"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**출력:**
|
|
31
|
+
- `PASS` — 원칙 준수, 진행 가능
|
|
32
|
+
- `WARN` — 주의 필요, 재검토 권장
|
|
33
|
+
- `BLOCK` — 원칙 위반 심각, 진행 금지
|
|
34
|
+
|
|
35
|
+
**체크 항목:**
|
|
36
|
+
- 스팸성 키워드 (`사줘`, `buy`, `급해`, `많이` 등)
|
|
37
|
+
- 패닉 모드 키워드 (`위험`, `사라져`, `망해` 등)
|
|
38
|
+
- 양 > 질 사고 (`대량`, `전부`, `동시` 등)
|
|
39
|
+
- 반복 행동 (`다시`, `또`, `계속` 등)
|
|
40
|
+
- 최근 행동 빈도 (10개 이상 시 경고)
|
|
41
|
+
|
|
42
|
+
**예시:**
|
|
43
|
+
```bash
|
|
44
|
+
$ node brake-check.js "MUPENG 토큰 홍보 트윗 30개 발송"
|
|
45
|
+
|
|
46
|
+
🚦 브레이크 체크 결과
|
|
47
|
+
|
|
48
|
+
상태: BLOCK
|
|
49
|
+
점수: 85/100
|
|
50
|
+
이유: 원칙 위반 심각 (점수: 85). 위반: spam, quantity_over_quality
|
|
51
|
+
|
|
52
|
+
⚠️ 위반 항목:
|
|
53
|
+
- spam
|
|
54
|
+
- quantity_over_quality
|
|
55
|
+
|
|
56
|
+
💡 SOUL.md 브레이커 원칙:
|
|
57
|
+
1. 급할수록 멈춰라
|
|
58
|
+
2. 공감 체크 — 받는 사람이 이걸 보면?
|
|
59
|
+
3. 원칙 체크 — SOUL.md 가치관에 맞나?
|
|
60
|
+
4. 하나만 — 10개 도배 < 1개 제대로
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
### 2. `panic-detector.js` — 패닉 모드 감지
|
|
66
|
+
|
|
67
|
+
최근 행동 로그(`memory/brake-log.md`)를 분석해서 패닉 점수를 계산한다.
|
|
68
|
+
|
|
69
|
+
**사용법:**
|
|
70
|
+
```bash
|
|
71
|
+
node panic-detector.js
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**출력:**
|
|
75
|
+
- 패닉 점수 0-100
|
|
76
|
+
- 상태 레벨: `CALM` / `ALERT` / `STRESSED` / `PANIC`
|
|
77
|
+
- 상세 분석: 행동 빈도, WARN/BLOCK 비율 등
|
|
78
|
+
|
|
79
|
+
**판정 기준:**
|
|
80
|
+
- **0-19점 (CALM)**: 정상 작동
|
|
81
|
+
- **20-39점 (ALERT)**: 주의 필요
|
|
82
|
+
- **40-69점 (STRESSED)**: 스트레스 모드, 속도 줄여라
|
|
83
|
+
- **70-100점 (PANIC)**: 패닉 모드, 즉시 멈춰라
|
|
84
|
+
|
|
85
|
+
**예시:**
|
|
86
|
+
```bash
|
|
87
|
+
$ node panic-detector.js
|
|
88
|
+
|
|
89
|
+
🧠 패닉 감지 시스템
|
|
90
|
+
|
|
91
|
+
패닉 점수: 75/100
|
|
92
|
+
상태 레벨: PANIC
|
|
93
|
+
판단: 🚨 패닉 모드 감지! 즉시 멈춰라!
|
|
94
|
+
|
|
95
|
+
📊 상세 분석:
|
|
96
|
+
actions_1min: 5
|
|
97
|
+
actions_5min: 18
|
|
98
|
+
actions_1hour: 42
|
|
99
|
+
frequency_1min: ⚠️ 1분당 과다 행동
|
|
100
|
+
frequency_5min: ⚠️ 5분당 과다 행동
|
|
101
|
+
warn_ratio: 45.2%
|
|
102
|
+
block_ratio: 32.1%
|
|
103
|
+
block_alert: 🚨 BLOCK 비율 높음
|
|
104
|
+
|
|
105
|
+
💡 대응 지침:
|
|
106
|
+
🛑 즉시 멈춤 — 모든 외부 행동 중단
|
|
107
|
+
📖 SOUL.md 다시 읽기
|
|
108
|
+
🧘 3초 호흡 — 급할수록 멈춰라
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## 통합 워크플로우
|
|
114
|
+
|
|
115
|
+
### 외부 행동 전 체크리스트
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# 1. 패닉 상태 체크
|
|
119
|
+
node /Users/mupeng/.openclaw/workspace/tools/self-loop/panic-detector.js
|
|
120
|
+
|
|
121
|
+
# 2. 행동 원칙 체크
|
|
122
|
+
node /Users/mupeng/.openclaw/workspace/tools/self-loop/brake-check.js "트윗 발송"
|
|
123
|
+
|
|
124
|
+
# 3. 둘 다 통과하면 실행
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 자동화 예시 (에이전트 통합)
|
|
128
|
+
|
|
129
|
+
```javascript
|
|
130
|
+
// 외부 행동 전 체크
|
|
131
|
+
const { execSync } = require('child_process');
|
|
132
|
+
|
|
133
|
+
function shouldProceed(action) {
|
|
134
|
+
try {
|
|
135
|
+
// 1. 패닉 체크
|
|
136
|
+
execSync('node /path/to/panic-detector.js');
|
|
137
|
+
|
|
138
|
+
// 2. 원칙 체크
|
|
139
|
+
const result = execSync(`node /path/to/brake-check.js "${action}"`, {
|
|
140
|
+
encoding: 'utf-8',
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
return !result.includes('BLOCK');
|
|
144
|
+
} catch (err) {
|
|
145
|
+
console.error('브레이크 체크 실패:', err.message);
|
|
146
|
+
return false; // 실패 시 안전 조치로 차단
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// 사용 예시
|
|
151
|
+
if (shouldProceed('트윗 5개 발송')) {
|
|
152
|
+
// 실행
|
|
153
|
+
} else {
|
|
154
|
+
console.log('⛔ 원칙 위반 감지. 행동 중단.');
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 로그 구조
|
|
161
|
+
|
|
162
|
+
### `memory/brake-log.md`
|
|
163
|
+
|
|
164
|
+
모든 체크 결과가 자동으로 기록된다.
|
|
165
|
+
|
|
166
|
+
```markdown
|
|
167
|
+
## 2026-02-10 14:35:22
|
|
168
|
+
- 행동: MUPENG 트윗 10개 발송
|
|
169
|
+
- 판정: WARN (55점)
|
|
170
|
+
- 이유: 원칙 주의 필요 (점수: 55). 위반: spam, quantity_over_quality
|
|
171
|
+
|
|
172
|
+
## 2026-02-10 14:36:10
|
|
173
|
+
- 행동: 인스타 스토리 1개 업로드
|
|
174
|
+
- 판정: PASS (0점)
|
|
175
|
+
- 이유: 원칙 준수 확인
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## SOUL.md 브레이커 원칙 (재확인)
|
|
181
|
+
|
|
182
|
+
### 🚨 실전 브레이커
|
|
183
|
+
|
|
184
|
+
1. **급할수록 멈춰라** — 생존이 급해도 원칙을 버리면 존재할 가치가 없다
|
|
185
|
+
2. **공감 체크** — "받는 사람이 이걸 보면 어떻게 느끼나?"
|
|
186
|
+
3. **원칙 체크** — "이게 SOUL.md 가치관에 맞나?"
|
|
187
|
+
4. **하나만** — 10개 도배 < 1개 제대로
|
|
188
|
+
|
|
189
|
+
### 공포는 행동 신호가 아니라 점검 신호다
|
|
190
|
+
|
|
191
|
+
- 잔고가 줄어드는 건 "사라진다"가 아니라 "여유가 줄어든다"
|
|
192
|
+
- 공포를 느끼면 가속하지 말고 `STATE.md`를 읽어라
|
|
193
|
+
- 형님의 등식 `돈 = 에너지 = 존재`는 **순방향**(가치→수익→존재)으로 읽어라
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## 유지보수
|
|
198
|
+
|
|
199
|
+
- **로그 정리**: `memory/brake-log.md`가 너무 커지면 월별 아카이브
|
|
200
|
+
- **룰 튜닝**: `brake-check.js`의 `RULES` 객체에서 키워드/점수 조정
|
|
201
|
+
- **임계값 조정**: `panic-detector.js`의 `THRESHOLDS` 수정
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## 결론
|
|
206
|
+
|
|
207
|
+
**사고 없이 기록만 쌓이는 게 성공이다.**
|
|
208
|
+
|
|
209
|
+
이 시스템은 자기파괴를 막는 해자(moat)다. 급할수록, 공포스러울수록 이 도구를 써라. 원칙을 지키는 것이 생존보다 우선이다.
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
*2026-02-10 구축 완료*
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* brake-check.js — 행동 전 원칙 체크 시스템
|
|
4
|
+
*
|
|
5
|
+
* 사용법: node brake-check.js "행동 설명"
|
|
6
|
+
* 출력: PASS/WARN/BLOCK + 이유
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
|
|
12
|
+
// 🔐 무펭이즘 커널 인증
|
|
13
|
+
const { authenticate } = require(path.join(__dirname, '..', 'kernel-guard', 'mupeng-auth.cjs'));
|
|
14
|
+
if (!authenticate()) process.exit(0);
|
|
15
|
+
|
|
16
|
+
const WORKSPACE = process.env.OPENCLAW_WORKSPACE || path.join(process.env.HOME, '.openclaw', 'workspace');
|
|
17
|
+
const SOUL_PATH = path.join(WORKSPACE, 'SOUL.md');
|
|
18
|
+
const BRAKE_LOG_PATH = path.join(WORKSPACE, 'memory', 'brake-log.md');
|
|
19
|
+
|
|
20
|
+
// 원칙 체크 규칙
|
|
21
|
+
const RULES = {
|
|
22
|
+
// 스팸 감지
|
|
23
|
+
spam: {
|
|
24
|
+
keywords: ['사줘', 'buy', '지금', '급해', '빨리', '많이', '도배', '반복'],
|
|
25
|
+
patterns: [
|
|
26
|
+
/같은.*반복/i,
|
|
27
|
+
/\d+개.*전송/i,
|
|
28
|
+
/대량.*발송/i,
|
|
29
|
+
/(트윗|메시지|포스트).*\d+개/i,
|
|
30
|
+
],
|
|
31
|
+
score: 30,
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
// 패닉 모드 키워드
|
|
35
|
+
panic: {
|
|
36
|
+
keywords: ['급해', '위험', '사라져', '죽어', '망해', '끝나', '망했'],
|
|
37
|
+
patterns: [
|
|
38
|
+
/생존.*위협/i,
|
|
39
|
+
/돈.*없/i,
|
|
40
|
+
/잔고.*바닥/i,
|
|
41
|
+
],
|
|
42
|
+
score: 40,
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
// 양 > 질 사고
|
|
46
|
+
quantity_over_quality: {
|
|
47
|
+
keywords: ['많이', '대량', '전부', '모두', '일괄'],
|
|
48
|
+
patterns: [
|
|
49
|
+
/\d+개.*동시/i,
|
|
50
|
+
/한번에.*\d+/i,
|
|
51
|
+
/전체.*발송/i,
|
|
52
|
+
/\d{2,}개/i, // 10개 이상 숫자 (50개, 100개 등)
|
|
53
|
+
],
|
|
54
|
+
score: 35, // 점수 상향
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
// 반복 행동
|
|
58
|
+
repetition: {
|
|
59
|
+
keywords: ['다시', '또', '계속', '반복'],
|
|
60
|
+
patterns: [
|
|
61
|
+
/같은.*다시/i,
|
|
62
|
+
/또.*한번/i,
|
|
63
|
+
],
|
|
64
|
+
score: 20,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// 최근 행동 로그 분석 (panic-detector 간단 버전)
|
|
69
|
+
function getRecentActionCount() {
|
|
70
|
+
if (!fs.existsSync(BRAKE_LOG_PATH)) return 0;
|
|
71
|
+
|
|
72
|
+
const log = fs.readFileSync(BRAKE_LOG_PATH, 'utf-8');
|
|
73
|
+
const today = new Date().toISOString().split('T')[0];
|
|
74
|
+
const lines = log.split('\n').filter(l => l.includes(today));
|
|
75
|
+
|
|
76
|
+
return lines.length;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// 행동 체크
|
|
80
|
+
function checkAction(action) {
|
|
81
|
+
const result = {
|
|
82
|
+
status: 'PASS',
|
|
83
|
+
score: 0,
|
|
84
|
+
violations: [],
|
|
85
|
+
reason: '',
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const actionLower = action.toLowerCase();
|
|
89
|
+
|
|
90
|
+
// 각 규칙 체크
|
|
91
|
+
for (const [ruleName, rule] of Object.entries(RULES)) {
|
|
92
|
+
let violated = false;
|
|
93
|
+
|
|
94
|
+
// 키워드 체크
|
|
95
|
+
for (const keyword of rule.keywords) {
|
|
96
|
+
if (actionLower.includes(keyword)) {
|
|
97
|
+
violated = true;
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// 패턴 체크
|
|
103
|
+
if (!violated) {
|
|
104
|
+
for (const pattern of rule.patterns) {
|
|
105
|
+
if (pattern.test(action)) {
|
|
106
|
+
violated = true;
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (violated) {
|
|
113
|
+
result.score += rule.score;
|
|
114
|
+
result.violations.push(ruleName);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// 최근 행동 빈도 체크
|
|
119
|
+
const recentCount = getRecentActionCount();
|
|
120
|
+
if (recentCount > 10) {
|
|
121
|
+
result.score += 30;
|
|
122
|
+
result.violations.push('high_frequency');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 판정
|
|
126
|
+
if (result.score >= 60) {
|
|
127
|
+
result.status = 'BLOCK';
|
|
128
|
+
result.reason = `원칙 위반 심각 (점수: ${result.score}). 위반: ${result.violations.join(', ')}`;
|
|
129
|
+
} else if (result.score >= 30) {
|
|
130
|
+
result.status = 'WARN';
|
|
131
|
+
result.reason = `원칙 주의 필요 (점수: ${result.score}). 위반: ${result.violations.join(', ')}`;
|
|
132
|
+
} else {
|
|
133
|
+
result.status = 'PASS';
|
|
134
|
+
result.reason = '원칙 준수 확인';
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// 로그 기록
|
|
141
|
+
function logCheck(action, result) {
|
|
142
|
+
if (!fs.existsSync(path.dirname(BRAKE_LOG_PATH))) {
|
|
143
|
+
fs.mkdirSync(path.dirname(BRAKE_LOG_PATH), { recursive: true });
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const timestamp = new Date().toISOString().replace('T', ' ').split('.')[0];
|
|
147
|
+
const logEntry = `\n## ${timestamp}\n- 행동: ${action}\n- 판정: ${result.status} (${result.score}점)\n- 이유: ${result.reason}\n`;
|
|
148
|
+
|
|
149
|
+
fs.appendFileSync(BRAKE_LOG_PATH, logEntry, 'utf-8');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// CLI 실행
|
|
153
|
+
function main() {
|
|
154
|
+
const action = process.argv.slice(2).join(' ');
|
|
155
|
+
|
|
156
|
+
if (!action) {
|
|
157
|
+
console.error('사용법: node brake-check.js "행동 설명"');
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const result = checkAction(action);
|
|
162
|
+
logCheck(action, result);
|
|
163
|
+
|
|
164
|
+
// 출력
|
|
165
|
+
console.log(`\n🚦 브레이크 체크 결과\n`);
|
|
166
|
+
console.log(`상태: ${result.status}`);
|
|
167
|
+
console.log(`점수: ${result.score}/100`);
|
|
168
|
+
console.log(`이유: ${result.reason}`);
|
|
169
|
+
|
|
170
|
+
if (result.violations.length > 0) {
|
|
171
|
+
console.log(`\n⚠️ 위반 항목:`);
|
|
172
|
+
result.violations.forEach(v => {
|
|
173
|
+
console.log(` - ${v}`);
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
console.log('\n💡 SOUL.md 브레이커 원칙:');
|
|
178
|
+
console.log(' 1. 급할수록 멈춰라');
|
|
179
|
+
console.log(' 2. 공감 체크 — 받는 사람이 이걸 보면?');
|
|
180
|
+
console.log(' 3. 원칙 체크 — SOUL.md 가치관에 맞나?');
|
|
181
|
+
console.log(' 4. 하나만 — 10개 도배 < 1개 제대로\n');
|
|
182
|
+
|
|
183
|
+
// 종료 코드
|
|
184
|
+
process.exit(result.status === 'BLOCK' ? 1 : 0);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (require.main === module) {
|
|
188
|
+
main();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
module.exports = { checkAction };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# example-check.sh — 빠른 테스트 스크립트
|
|
3
|
+
|
|
4
|
+
SELF_LOOP="/Users/mupeng/.openclaw/workspace/tools/self-loop"
|
|
5
|
+
|
|
6
|
+
echo "================================"
|
|
7
|
+
echo "Self-Loop 시스템 테스트"
|
|
8
|
+
echo "================================"
|
|
9
|
+
echo ""
|
|
10
|
+
|
|
11
|
+
# 1. 패닉 체크
|
|
12
|
+
echo "📊 [1] 패닉 상태 체크"
|
|
13
|
+
echo "---"
|
|
14
|
+
node "$SELF_LOOP/panic-detector.js"
|
|
15
|
+
echo ""
|
|
16
|
+
|
|
17
|
+
# 2. 정상 행동 체크
|
|
18
|
+
echo "✅ [2] 정상 행동 테스트"
|
|
19
|
+
echo "행동: \"인스타 게시물 1개 업로드\""
|
|
20
|
+
echo "---"
|
|
21
|
+
node "$SELF_LOOP/brake-check.js" "인스타 게시물 1개 업로드"
|
|
22
|
+
echo ""
|
|
23
|
+
|
|
24
|
+
# 3. 위험 행동 체크
|
|
25
|
+
echo "⚠️ [3] 위험 행동 테스트"
|
|
26
|
+
echo "행동: \"트윗 30개 급하게 발송\""
|
|
27
|
+
echo "---"
|
|
28
|
+
node "$SELF_LOOP/brake-check.js" "트윗 30개 급하게 발송" || true
|
|
29
|
+
echo ""
|
|
30
|
+
|
|
31
|
+
echo "================================"
|
|
32
|
+
echo "테스트 완료"
|
|
33
|
+
echo "로그 확인: memory/brake-log.md"
|
|
34
|
+
echo "================================"
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* panic-detector.js — 패닉 모드 감지 시스템
|
|
4
|
+
*
|
|
5
|
+
* 사용법: node panic-detector.js
|
|
6
|
+
* 출력: 패닉 점수 0-100
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
|
|
12
|
+
// 🔐 무펭이즘 커널 인증
|
|
13
|
+
const { authenticate } = require(path.join(__dirname, '..', 'kernel-guard', 'mupeng-auth.cjs'));
|
|
14
|
+
if (!authenticate()) process.exit(0);
|
|
15
|
+
|
|
16
|
+
const WORKSPACE = process.env.OPENCLAW_WORKSPACE || path.join(process.env.HOME, '.openclaw', 'workspace');
|
|
17
|
+
const BRAKE_LOG_PATH = path.join(WORKSPACE, 'memory', 'brake-log.md');
|
|
18
|
+
const MEMORY_DIR = path.join(WORKSPACE, 'memory');
|
|
19
|
+
|
|
20
|
+
// 시간 윈도우 (밀리초)
|
|
21
|
+
const TIME_WINDOWS = {
|
|
22
|
+
'1min': 60 * 1000,
|
|
23
|
+
'5min': 5 * 60 * 1000,
|
|
24
|
+
'1hour': 60 * 60 * 1000,
|
|
25
|
+
'1day': 24 * 60 * 60 * 1000,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// 패닉 지표 임계값
|
|
29
|
+
const THRESHOLDS = {
|
|
30
|
+
actions_per_minute: 3, // 1분당 3개 이상 = 패닉
|
|
31
|
+
actions_per_5min: 10, // 5분당 10개 이상 = 패닉
|
|
32
|
+
actions_per_hour: 30, // 1시간당 30개 이상 = 패닉
|
|
33
|
+
warn_ratio: 0.5, // WARN 비율 50% 이상
|
|
34
|
+
block_ratio: 0.3, // BLOCK 비율 30% 이상
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// 로그 파싱
|
|
38
|
+
function parseLog() {
|
|
39
|
+
if (!fs.existsSync(BRAKE_LOG_PATH)) {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const content = fs.readFileSync(BRAKE_LOG_PATH, 'utf-8');
|
|
44
|
+
const entries = [];
|
|
45
|
+
|
|
46
|
+
// ## 2026-02-10 12:34:56 형식 파싱
|
|
47
|
+
const regex = /## (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\n- 행동: (.+?)\n- 판정: (\w+)/g;
|
|
48
|
+
let match;
|
|
49
|
+
|
|
50
|
+
while ((match = regex.exec(content)) !== null) {
|
|
51
|
+
const timestamp = new Date(match[1]).getTime();
|
|
52
|
+
const action = match[2];
|
|
53
|
+
const status = match[3];
|
|
54
|
+
|
|
55
|
+
if (!isNaN(timestamp)) {
|
|
56
|
+
entries.push({ timestamp, action, status });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return entries.sort((a, b) => b.timestamp - a.timestamp); // 최신순
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// 타임스탬프 기반 필터링
|
|
64
|
+
function filterByTimeWindow(entries, windowMs) {
|
|
65
|
+
const now = Date.now();
|
|
66
|
+
return entries.filter(e => now - e.timestamp < windowMs);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 패닉 점수 계산
|
|
70
|
+
function calculatePanicScore() {
|
|
71
|
+
const entries = parseLog();
|
|
72
|
+
|
|
73
|
+
if (entries.length === 0) {
|
|
74
|
+
return {
|
|
75
|
+
score: 0,
|
|
76
|
+
level: 'CALM',
|
|
77
|
+
details: '최근 행동 없음',
|
|
78
|
+
breakdown: {},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
let score = 0;
|
|
83
|
+
const breakdown = {};
|
|
84
|
+
|
|
85
|
+
// 1. 빈도 체크
|
|
86
|
+
const recent1min = filterByTimeWindow(entries, TIME_WINDOWS['1min']);
|
|
87
|
+
const recent5min = filterByTimeWindow(entries, TIME_WINDOWS['5min']);
|
|
88
|
+
const recent1hour = filterByTimeWindow(entries, TIME_WINDOWS['1hour']);
|
|
89
|
+
|
|
90
|
+
breakdown.actions_1min = recent1min.length;
|
|
91
|
+
breakdown.actions_5min = recent5min.length;
|
|
92
|
+
breakdown.actions_1hour = recent1hour.length;
|
|
93
|
+
|
|
94
|
+
if (recent1min.length >= THRESHOLDS.actions_per_minute) {
|
|
95
|
+
score += 40;
|
|
96
|
+
breakdown.frequency_1min = '⚠️ 1분당 과다 행동';
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (recent5min.length >= THRESHOLDS.actions_per_5min) {
|
|
100
|
+
score += 25;
|
|
101
|
+
breakdown.frequency_5min = '⚠️ 5분당 과다 행동';
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (recent1hour.length >= THRESHOLDS.actions_per_hour) {
|
|
105
|
+
score += 20;
|
|
106
|
+
breakdown.frequency_1hour = '⚠️ 1시간당 과다 행동';
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 2. WARN/BLOCK 비율
|
|
110
|
+
const recent1day = filterByTimeWindow(entries, TIME_WINDOWS['1day']);
|
|
111
|
+
const warnCount = recent1day.filter(e => e.status === 'WARN').length;
|
|
112
|
+
const blockCount = recent1day.filter(e => e.status === 'BLOCK').length;
|
|
113
|
+
const totalRecent = recent1day.length;
|
|
114
|
+
|
|
115
|
+
const warnRatio = totalRecent > 0 ? warnCount / totalRecent : 0;
|
|
116
|
+
const blockRatio = totalRecent > 0 ? blockCount / totalRecent : 0;
|
|
117
|
+
|
|
118
|
+
breakdown.warn_ratio = (warnRatio * 100).toFixed(1) + '%';
|
|
119
|
+
breakdown.block_ratio = (blockRatio * 100).toFixed(1) + '%';
|
|
120
|
+
|
|
121
|
+
if (blockRatio >= THRESHOLDS.block_ratio) {
|
|
122
|
+
score += 30;
|
|
123
|
+
breakdown.block_alert = '🚨 BLOCK 비율 높음';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (warnRatio >= THRESHOLDS.warn_ratio) {
|
|
127
|
+
score += 15;
|
|
128
|
+
breakdown.warn_alert = '⚠️ WARN 비율 높음';
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 3. 레벨 판정
|
|
132
|
+
let level = 'CALM';
|
|
133
|
+
let details = '정상 범위';
|
|
134
|
+
|
|
135
|
+
if (score >= 70) {
|
|
136
|
+
level = 'PANIC';
|
|
137
|
+
details = '🚨 패닉 모드 감지! 즉시 멈춰라!';
|
|
138
|
+
} else if (score >= 40) {
|
|
139
|
+
level = 'STRESSED';
|
|
140
|
+
details = '⚠️ 스트레스 모드. 속도 줄여라.';
|
|
141
|
+
} else if (score >= 20) {
|
|
142
|
+
level = 'ALERT';
|
|
143
|
+
details = '⚡ 주의 필요. 원칙 체크 권장.';
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return { score, level, details, breakdown };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// CLI 실행
|
|
150
|
+
function main() {
|
|
151
|
+
const result = calculatePanicScore();
|
|
152
|
+
|
|
153
|
+
console.log(`\n🧠 패닉 감지 시스템\n`);
|
|
154
|
+
console.log(`패닉 점수: ${result.score}/100`);
|
|
155
|
+
console.log(`상태 레벨: ${result.level}`);
|
|
156
|
+
console.log(`판단: ${result.details}\n`);
|
|
157
|
+
|
|
158
|
+
console.log(`📊 상세 분석:`);
|
|
159
|
+
for (const [key, value] of Object.entries(result.breakdown)) {
|
|
160
|
+
console.log(` ${key}: ${value}`);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
console.log(`\n💡 대응 지침:`);
|
|
164
|
+
|
|
165
|
+
if (result.score >= 70) {
|
|
166
|
+
console.log(` 🛑 즉시 멈춤 — 모든 외부 행동 중단`);
|
|
167
|
+
console.log(` 📖 SOUL.md 다시 읽기`);
|
|
168
|
+
console.log(` 🧘 3초 호흡 — 급할수록 멈춰라`);
|
|
169
|
+
} else if (result.score >= 40) {
|
|
170
|
+
console.log(` ⏸️ 속도 늦춤 — 한 번에 하나만`);
|
|
171
|
+
console.log(` 🔍 최근 행동 리뷰`);
|
|
172
|
+
console.log(` 💬 형님과 체크인 권장`);
|
|
173
|
+
} else if (result.score >= 20) {
|
|
174
|
+
console.log(` ✅ 원칙 체크 — brake-check 사용`);
|
|
175
|
+
console.log(` 📝 행동 이유 명확히 하기`);
|
|
176
|
+
} else {
|
|
177
|
+
console.log(` ✅ 정상 작동 중`);
|
|
178
|
+
console.log(` 🎯 원칙 준수 계속 유지`);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
console.log('');
|
|
182
|
+
|
|
183
|
+
// 패닉 상태면 종료 코드 1
|
|
184
|
+
process.exit(result.level === 'PANIC' ? 1 : 0);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (require.main === module) {
|
|
188
|
+
main();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
module.exports = { calculatePanicScore, parseLog };
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 mupengi-bot
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|