@nine-lab/nine-mu 0.1.347 → 0.1.349

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nine-lab/nine-mu",
3
- "version": "0.1.347",
3
+ "version": "0.1.349",
4
4
  "description": "AI-Driven Full-Stack Code Fabrication Engine",
5
5
  "type": "module",
6
6
  "main": "./dist/nine-mu.umd.js",
@@ -1,25 +1,91 @@
1
1
  import React from 'react';
2
2
 
3
+ // ==========================================
4
+ // 1. 터미널 프롬프트 테마 스타일 (블랙/화이트/그레이 기반)
5
+ // ==========================================
6
+ export const NineExceptionStyles = {
7
+ container: {
8
+ padding: '30px',
9
+ margin: '20px',
10
+ background: '#121314', // 터미널 다크 블랙 배경
11
+ border: '1px solid #343A40', // 소프트한 메탈릭 테두리
12
+ borderRadius: '6px',
13
+ fontFamily: 'Consolas, Monaco, "Courier New", monospace', // 터미널 고정폭 글꼴 우선
14
+ textAlign: 'left',
15
+ boxShadow: '0 4px 12px rgba(0,0,0,0.3)' // 터미널 윈도우 입체감
16
+ },
17
+ title: {
18
+ color: '#FFFFFF', // 화이트 타이틀
19
+ marginTop: 0,
20
+ fontSize: '16px',
21
+ fontWeight: '600',
22
+ display: 'flex',
23
+ alignItems: 'center',
24
+ gap: '8px',
25
+ borderBottom: '1px solid #2D3139', // 상단 바 구분선 느낌
26
+ paddingBottom: '12px'
27
+ },
28
+ label: {
29
+ margin: '15px 0 8px 0',
30
+ fontWeight: 'bold',
31
+ color: '#A0AEC0', // 프롬프트 서브 텍스트 (연한 그레이)
32
+ fontSize: '13px'
33
+ },
34
+ pre: {
35
+ background: '#1A1C1E', // 코드 블록 내부의 살짝 더 깊은 블랙
36
+ color: '#F8F9FA', // 에러 로그 화이트 출력
37
+ padding: '15px',
38
+ borderRadius: '4px',
39
+ border: '1px solid #2A2D30',
40
+ overflowX: 'auto',
41
+ whiteSpace: 'pre-wrap',
42
+ fontFamily: 'Consolas, Monaco, monospace',
43
+ fontSize: '13px',
44
+ lineHeight: '1.5'
45
+ },
46
+ footer: {
47
+ marginTop: '20px',
48
+ fontSize: '13px',
49
+ color: '#718096',
50
+ display: 'flex',
51
+ flexDirection: 'column',
52
+ gap: '10px'
53
+ },
54
+ button: {
55
+ padding: '10px 16px',
56
+ background: '#E53E3E', // 버튼의 고유 아이덴티티 유지 (레드)
57
+ color: '#FFFFFF',
58
+ border: 'none',
59
+ borderRadius: '4px',
60
+ cursor: 'pointer',
61
+ fontWeight: 'bold',
62
+ fontSize: '13px',
63
+ alignSelf: 'flex-start',
64
+ transition: 'background 0.2s',
65
+ fontFamily: 'sans-serif' // 버튼 텍스트는 일반 폰트로 가독성 확보
66
+ }
67
+ };
68
+
69
+ // ==========================================
70
+ // 2. 컴포넌트 본문 (기존 로직 유지)
71
+ // ==========================================
3
72
  export class NineExceptionHook extends React.Component {
4
73
 
5
74
  constructor(props) {
6
75
  super(props);
7
- this.state = { hasError: false, error: null };
76
+ this.state = { hasError: false, error: null, reportStatus: 'idle' };
8
77
  this.lastPath = window.location.pathname;
9
78
  this.handleLocationChange = this.handleLocationChange.bind(this);
79
+ this.handleReport = this.handleReport.bind(this);
10
80
  }
11
81
 
12
82
  static getDerivedStateFromError(error) {
13
- return { hasError: true, error };
83
+ return { hasError: true, error, reportStatus: 'idle' };
14
84
  }
15
85
 
16
86
  componentDidCatch(error, errorInfo) {
17
87
  console.error("🚨 [Nine-Library] 본문 렌더링 에러 포착:", error);
18
88
 
19
- if (window.triggerAutoRecovery) {
20
- window.triggerAutoRecovery(error.message || String(error));
21
- }
22
-
23
89
  if (this.props.onCatch) {
24
90
  this.props.onCatch(error, errorInfo);
25
91
  }
@@ -38,13 +104,29 @@ export class NineExceptionHook extends React.Component {
38
104
  handleLocationChange() {
39
105
  setTimeout(() => {
40
106
  if (this.state.hasError && this.lastPath !== window.location.pathname) {
41
- console.log("[Nine-Library] 페이지 주소 변경 감지 -> 리액트 에러 상태 초기화");
107
+ console.log("[Nine-Library] 페이지 주소 변경 감지 -> 리액트 에러 상태 초기화");
42
108
  this.lastPath = window.location.pathname;
43
- this.setState({ hasError: false, error: null });
109
+ this.setState({ hasError: false, error: null, reportStatus: 'idle' });
44
110
  }
45
111
  }, 10);
46
112
  }
47
113
 
114
+ handleReport() {
115
+ if (this.state.reportStatus !== 'idle') return;
116
+
117
+ this.setState({ reportStatus: 'sending' });
118
+ const errorMessage = this.state.error?.message || String(this.state.error);
119
+
120
+ setTimeout(() => {
121
+ if (window.triggerAutoRecovery) {
122
+ window.triggerAutoRecovery(errorMessage);
123
+ } else {
124
+ console.warn("[Nine-Library] window.triggerAutoRecovery 가 정의되지 않았습니다.");
125
+ }
126
+ this.setState({ reportStatus: 'success' });
127
+ }, 500);
128
+ }
129
+
48
130
  render() {
49
131
  if (this.state.hasError) {
50
132
  if (this.props.fallback) {
@@ -52,36 +134,44 @@ export class NineExceptionHook extends React.Component {
52
134
  }
53
135
 
54
136
  const errorMessage = this.state.error?.message || String(this.state.error);
137
+ const customStyles = this.props.styles || {};
138
+
139
+ let buttonText = '🚀 관제탑에 에러 피드백 전송하기';
140
+ if (this.state.reportStatus === 'sending') buttonText = '⏳ 관제탑 연락 중...';
141
+ if (this.state.reportStatus === 'success') buttonText = '✅ 전송 완료! AI 분석 시작';
55
142
 
56
- // ⭐ Vite 빌드 통과를 위해 순수 자바스크립트 함수(React.createElement)로 변경
57
143
  return React.createElement(
58
144
  'div',
59
145
  {
60
- style: {
61
- padding: '30px',
62
- margin: '20px',
63
- background: '#FFF5F5',
64
- border: '1px solid #FEB2B2',
65
- borderRadius: '8px',
66
- fontFamily: 'sans-serif',
67
- textAlign: 'left',
68
- ...this.props.containerStyle
69
- }
146
+ style: { ...NineExceptionStyles.container, ...customStyles.container, ...this.props.containerStyle }
70
147
  },
71
- React.createElement('h3', { style: { color: '#C53030', marginTop: 0, fontSize: '18px' } }, '⚠️ 컴포넌트 빌드/렌더링 에러 감지'),
72
- React.createElement('p', { style: { margin: '10px 0 5px 0', fontWeight: 'bold', color: '#4A5568' } }, '[에러 원인 로그]:'),
73
- React.createElement('pre', {
74
- style: {
75
- background: '#1A202C',
76
- color: '#EDF2F7',
77
- padding: '15px',
78
- borderRadius: '6px',
79
- overflowX: 'auto',
80
- whiteSpace: 'pre-wrap',
81
- fontFamily: 'monospace'
82
- }
83
- }, errorMessage),
84
- React.createElement('div', { style: { marginTop: '15px', fontSize: '14px', color: '#718096' } }, '🔄 에러 로그가 관제탑으로 자동 피드백되었습니다. AI가 소스 코드를 재수정하는 동안 잠시만 기다려주세요...')
148
+ React.createElement('h3', { style: { ...NineExceptionStyles.title, ...customStyles.title } }, '🤖 [SYSTEM] COMPONENT RENDER ERROR DETECTED'),
149
+ React.createElement('p', { style: { ...NineExceptionStyles.label, ...customStyles.label } }, '$ cat error.log'),
150
+ React.createElement('pre', { style: { ...NineExceptionStyles.pre, ...customStyles.pre } }, errorMessage),
151
+
152
+ React.createElement(
153
+ 'div',
154
+ { style: { ...NineExceptionStyles.footer, ...customStyles.footer } },
155
+ React.createElement(
156
+ 'button',
157
+ {
158
+ style: {
159
+ ...NineExceptionStyles.button,
160
+ ...customStyles.button,
161
+ backgroundColor: this.state.reportStatus === 'success' ? '#38A169' : (this.state.reportStatus === 'sending' ? '#A0AEC0' : '#E53E3E'),
162
+ cursor: this.state.reportStatus === 'idle' ? 'pointer' : 'not-allowed'
163
+ },
164
+ disabled: this.state.reportStatus !== 'idle',
165
+ onClick: this.handleReport
166
+ },
167
+ buttonText
168
+ ),
169
+ this.state.reportStatus === 'success' && React.createElement(
170
+ 'div',
171
+ { style: { color: '#CBD5E0', fontSize: '13px', marginTop: '5px', fontStyle: 'italic' } },
172
+ '>> AI가 소스 코드를 재수정하는 동안 잠시만 기다려주세요...'
173
+ )
174
+ )
85
175
  );
86
176
  }
87
177