@nine-lab/nine-mu 0.1.14
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/dist/css/nine-mu.css +796 -0
- package/dist/nine-mu.js +170 -0
- package/dist/nine-mu.js.map +1 -0
- package/dist/nine-mu.umd.js +2 -0
- package/dist/nine-mu.umd.js.map +1 -0
- package/package.json +45 -0
- package/public/css/nine-mu.css +796 -0
- package/src/components/NineChat.js +124 -0
- package/src/index.js +17 -0
- package/src/services/NineMuService.js +55 -0
- package/vite.config.js +30 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { nine, trace } from '@nine-lab/nine-util';
|
|
2
|
+
import { NineMuService } from '../services/NineMuService.js';
|
|
3
|
+
|
|
4
|
+
export class NineChat extends HTMLElement {
|
|
5
|
+
#service = null;
|
|
6
|
+
#routes = [];
|
|
7
|
+
|
|
8
|
+
constructor() {
|
|
9
|
+
super();
|
|
10
|
+
this.attachShadow({ mode: 'open' });
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async connectedCallback() {
|
|
14
|
+
// 서비스 초기화
|
|
15
|
+
const connectorUrl = this.getAttribute('connector-url') || 'http://localhost:3002';
|
|
16
|
+
this.#service = new NineMuService(connectorUrl);
|
|
17
|
+
|
|
18
|
+
this.#render();
|
|
19
|
+
this.#initInteractions(); // UI 토글 로직
|
|
20
|
+
this.#initActions(); // 엔터 시 실행 로직
|
|
21
|
+
|
|
22
|
+
// 경로 데이터 로드
|
|
23
|
+
this.#routes = await this.#service.fetchRoutes(this.getAttribute('route-url'));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// --- [그룹 1: Interaction] 화면 토글 및 메뉴 클릭 ---
|
|
27
|
+
#initInteractions() {
|
|
28
|
+
const $settings = this.shadowRoot.querySelector('nine-ai-settings');
|
|
29
|
+
const $menuIcons = this.shadowRoot.querySelectorAll(".menu-icon");
|
|
30
|
+
|
|
31
|
+
const toggleUI = () => this.classList.toggle("collapse");
|
|
32
|
+
this.shadowRoot.querySelector(".expand-icon").addEventListener("click", toggleUI);
|
|
33
|
+
this.shadowRoot.querySelector(".collapse-icon").addEventListener("click", toggleUI);
|
|
34
|
+
|
|
35
|
+
$menuIcons.forEach(el => {
|
|
36
|
+
el.addEventListener("click", (e) => {
|
|
37
|
+
$menuIcons.forEach(icon => icon.classList.remove("active"));
|
|
38
|
+
const clicked = e.target.closest(".menu-icon");
|
|
39
|
+
clicked.classList.add("active");
|
|
40
|
+
$settings.classList.toggle("expand", clicked.classList.contains('menu-setting'));
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// --- [그룹 2: Action] 엔터키 입력 시 서비스 호출 ---
|
|
46
|
+
#initActions() {
|
|
47
|
+
const $textarea = this.shadowRoot.querySelector('#q');
|
|
48
|
+
const $status = this.shadowRoot.querySelector('#status-tag');
|
|
49
|
+
|
|
50
|
+
$textarea.addEventListener('keypress', async (e) => {
|
|
51
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
52
|
+
e.preventDefault();
|
|
53
|
+
const command = e.target.value.trim();
|
|
54
|
+
if (!command) return;
|
|
55
|
+
|
|
56
|
+
// 1. UI 피드백
|
|
57
|
+
$status.textContent = "⚙️ 공정 분석 중...";
|
|
58
|
+
e.target.value = '';
|
|
59
|
+
|
|
60
|
+
// 2. 체크된 타겟 수집
|
|
61
|
+
const targets = Array.from(this.shadowRoot.querySelectorAll('input[name="gen_target"]:checked'))
|
|
62
|
+
.map(el => el.value);
|
|
63
|
+
|
|
64
|
+
// 3. 분리된 서비스 호출
|
|
65
|
+
try {
|
|
66
|
+
const result = await this.#service.generate(command, targets, this.#routes);
|
|
67
|
+
|
|
68
|
+
// 4. 성공 처리
|
|
69
|
+
$status.textContent = "✅ 완료";
|
|
70
|
+
nine.alert("소스 생성 성공").rgb();
|
|
71
|
+
this.dispatchEvent(new CustomEvent('nine-fab-completed', { detail: result, bubbles: true }));
|
|
72
|
+
} catch (err) {
|
|
73
|
+
// 5. 실패 처리
|
|
74
|
+
$status.textContent = "❌ 실패";
|
|
75
|
+
nine.alert(err.message).rgb().shake();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
#render() {
|
|
82
|
+
const placeholder = this.getAttribute("placeholder") || "나에게 무엇이든 물어봐...";
|
|
83
|
+
const customImport = this.getAttribute("css-path") ? `@import "${this.getAttribute("css-path")}";` : "";
|
|
84
|
+
|
|
85
|
+
this.shadowRoot.innerHTML = `
|
|
86
|
+
<style>
|
|
87
|
+
@import "https://cdn.jsdelivr.net/npm/@nine-lab/nine-fab@${__APP_VERSION__}/dist/css/nine-fab.css";
|
|
88
|
+
${customImport}
|
|
89
|
+
</style>
|
|
90
|
+
<div class="wrapper">
|
|
91
|
+
<nine-ai-settings></nine-ai-settings>
|
|
92
|
+
<div class="container">
|
|
93
|
+
<div class="head">
|
|
94
|
+
<div class="logo"><span></span></div>
|
|
95
|
+
<div id="status-tag" style="font-size:10px; color:#ff5722; padding:5px;">Fab Engine Ready</div>
|
|
96
|
+
</div>
|
|
97
|
+
<nx-ai-chat></nx-ai-chat>
|
|
98
|
+
<div class="foot">
|
|
99
|
+
<div class="apply-src">
|
|
100
|
+
${['MyBatis', 'Service', 'Controller', 'JavaScript'].map(t => `
|
|
101
|
+
<div>
|
|
102
|
+
<input type="checkbox" id="${t.toLowerCase()}" name="gen_target" value="${t}" checked />
|
|
103
|
+
<label for="${t.toLowerCase()}">${t}</label>
|
|
104
|
+
</div>
|
|
105
|
+
`).join('')}
|
|
106
|
+
</div>
|
|
107
|
+
<textarea id="q" rows="4" placeholder="${placeholder}"></textarea>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
<div class="menu">
|
|
111
|
+
<div class="collapse-icon"></div>
|
|
112
|
+
<div class="menu-icon menu-filter active"></div>
|
|
113
|
+
<div class="menu-icon menu-general"></div>
|
|
114
|
+
<div class="menu-icon menu-setting"></div>
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
<div class="expand-icon"></div>
|
|
118
|
+
`;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (!customElements.get('nine-chat')) {
|
|
123
|
+
customElements.define('nine-chat', NineChat);
|
|
124
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { trace } from '@nine-lab/nine-util';
|
|
2
|
+
import { NineChat } from './components/NineChat.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Nine-Fab 엔진 메인 클래스
|
|
6
|
+
*/
|
|
7
|
+
export const NineFab = {
|
|
8
|
+
version: typeof __APP_VERSION__ !== 'undefined' ? __APP_VERSION__ : '0.1.0',
|
|
9
|
+
init: (config) => {
|
|
10
|
+
trace.log("🛠️ Nine-Fab Engine initialized", config);
|
|
11
|
+
// 향후 커넥터 URL 전역 설정이나 인증 토큰 처리 로직 추가 가능
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// 기본 export 및 컴포넌트 export
|
|
16
|
+
export default NineFab;
|
|
17
|
+
export { NineChat };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { nine, trace } from '@nine-lab/nine-util';
|
|
2
|
+
|
|
3
|
+
export class NineMuService {
|
|
4
|
+
constructor(connectorUrl) {
|
|
5
|
+
this.connectorUrl = connectorUrl;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* AI 소스 생성 실행
|
|
10
|
+
* @param {string} command - 사용자 입력 명령
|
|
11
|
+
* @param {Array} targets - 체크된 생성 대상 (MyBatis, Service 등)
|
|
12
|
+
* @param {Array} currentRoutes - 현재 프로젝트 경로 정보
|
|
13
|
+
*/
|
|
14
|
+
async generate(command, targets, currentRoutes) {
|
|
15
|
+
try {
|
|
16
|
+
trace.log(`🚀 Fab 공정 시작: "${command}" [대상: ${targets.join(', ')}]`);
|
|
17
|
+
|
|
18
|
+
const response = await fetch(`${this.connectorUrl}/api/fab/generate`, {
|
|
19
|
+
method: 'POST',
|
|
20
|
+
headers: { 'Content-Type': 'application/json' },
|
|
21
|
+
body: JSON.stringify({
|
|
22
|
+
command,
|
|
23
|
+
targets,
|
|
24
|
+
projectType: 'spring-react',
|
|
25
|
+
currentRoutes
|
|
26
|
+
})
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const result = await response.json();
|
|
30
|
+
|
|
31
|
+
if (!result.success) {
|
|
32
|
+
throw new Error(result.error || "소스 생성 중 서버 오류가 발생했습니다.");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return result;
|
|
36
|
+
} catch (error) {
|
|
37
|
+
trace.error("❌ Fab Service Error:", error);
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 초기 경로 정보 로드
|
|
44
|
+
*/
|
|
45
|
+
async fetchRoutes(routeUrl) {
|
|
46
|
+
if (!routeUrl) return [];
|
|
47
|
+
try {
|
|
48
|
+
const res = await fetch(routeUrl);
|
|
49
|
+
return await res.json();
|
|
50
|
+
} catch (err) {
|
|
51
|
+
trace.error("Route load fail", err);
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
package/vite.config.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import { resolve } from 'path';
|
|
3
|
+
import pkg from './package.json';
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
define: {
|
|
7
|
+
'__APP_VERSION__': JSON.stringify(pkg.version)
|
|
8
|
+
},
|
|
9
|
+
build: {
|
|
10
|
+
lib: {
|
|
11
|
+
entry: resolve(__dirname, 'src/index.js'),
|
|
12
|
+
name: 'NineFab',
|
|
13
|
+
fileName: (format) => `nine-mu.${format === 'es' ? 'js' : 'umd.js'}`,
|
|
14
|
+
formats: ['es', 'umd']
|
|
15
|
+
},
|
|
16
|
+
rollupOptions: {
|
|
17
|
+
external: ['@nine-lab/nine-ai', '@nine-lab/nine-util', '@nine-lab/nine-ux'],
|
|
18
|
+
output: {
|
|
19
|
+
globals: {
|
|
20
|
+
'@nine-lab/nine-ai': 'NineAi',
|
|
21
|
+
'@nine-lab/nine-util': 'NineUtil',
|
|
22
|
+
'@nine-lab/nine-ux': 'NineUx'
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
minify: 'terser',
|
|
27
|
+
sourcemap: true,
|
|
28
|
+
emptyOutDir: true
|
|
29
|
+
}
|
|
30
|
+
});
|