metadatafy 1.5.0 → 1.5.3
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/README.md +243 -304
- package/dist/cli.cjs +68 -51
- package/dist/cli.js +68 -51
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,7 +12,8 @@ A build plugin for extracting project metadata from your codebase. Supports Vite
|
|
|
12
12
|
- **Import/Export extraction** - Tracks file dependencies and call graphs
|
|
13
13
|
- **Component props detection** - Extracts React component props
|
|
14
14
|
- **Korean keyword mapping** - Automatic English-Korean keyword translation
|
|
15
|
-
- **Multiple output formats** - JSON file,
|
|
15
|
+
- **Multiple output formats** - JSON file, Supabase, or custom API server
|
|
16
|
+
- **Global CLI** - Install once, use everywhere
|
|
16
17
|
|
|
17
18
|
---
|
|
18
19
|
|
|
@@ -22,102 +23,196 @@ A build plugin for extracting project metadata from your codebase. Supports Vite
|
|
|
22
23
|
- **Import/Export 추출** - 파일 의존성 및 호출 그래프 추적
|
|
23
24
|
- **컴포넌트 Props 감지** - React 컴포넌트 props 추출
|
|
24
25
|
- **한글 키워드 매핑** - 영어-한글 키워드 자동 변환
|
|
25
|
-
- **다양한 출력 형식** - JSON 파일,
|
|
26
|
+
- **다양한 출력 형식** - JSON 파일, Supabase, 또는 커스텀 API 서버
|
|
27
|
+
- **글로벌 CLI** - 한 번 설치로 어디서나 사용
|
|
26
28
|
|
|
27
29
|
## Installation / 설치
|
|
28
30
|
|
|
31
|
+
### Global CLI (Recommended) / 글로벌 CLI (권장)
|
|
32
|
+
|
|
29
33
|
```bash
|
|
30
|
-
npm install metadatafy
|
|
34
|
+
npm install -g metadatafy
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Now you can use `metadatafy` command anywhere:
|
|
38
|
+
|
|
39
|
+
이제 어디서나 `metadatafy` 명령어를 사용할 수 있습니다:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
metadatafy --help
|
|
43
|
+
metadatafy config setup
|
|
44
|
+
metadatafy analyze
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Per-project / 프로젝트별 설치
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm install -D metadatafy
|
|
31
51
|
# or
|
|
32
|
-
yarn add metadatafy
|
|
52
|
+
yarn add -D metadatafy
|
|
33
53
|
# or
|
|
34
|
-
pnpm add metadatafy
|
|
54
|
+
pnpm add -D metadatafy
|
|
35
55
|
```
|
|
36
56
|
|
|
37
57
|
## Quick Start / 빠른 시작
|
|
38
58
|
|
|
39
|
-
|
|
59
|
+
### 1. Global Setup (One-time) / 글로벌 설정 (1회)
|
|
40
60
|
|
|
41
|
-
|
|
61
|
+
```bash
|
|
62
|
+
# Install globally
|
|
63
|
+
npm install -g metadatafy
|
|
64
|
+
|
|
65
|
+
# Configure upload destination (Supabase or API server)
|
|
66
|
+
metadatafy config setup
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 2. Project Setup / 프로젝트 설정
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# In your project directory
|
|
73
|
+
metadatafy init
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 3. Analyze & Upload / 분석 및 업로드
|
|
42
77
|
|
|
43
78
|
```bash
|
|
44
|
-
|
|
79
|
+
# Analyze only (generates local JSON file)
|
|
80
|
+
metadatafy analyze
|
|
81
|
+
|
|
82
|
+
# Analyze + upload to configured destination
|
|
83
|
+
metadatafy analyze --upload
|
|
45
84
|
```
|
|
46
85
|
|
|
47
|
-
|
|
48
|
-
- Auto-detect your project type (Next.js, Vite, CRA, etc.)
|
|
49
|
-
- Detect your package manager (npm, yarn, pnpm)
|
|
50
|
-
- Create a `metadata.config.json` with optimized settings
|
|
51
|
-
- Optionally add the plugin to your build config (vite.config.ts or next.config.js)
|
|
52
|
-
- Optionally configure Supabase integration for automatic uploads
|
|
86
|
+
## CLI Commands / CLI 명령어
|
|
53
87
|
|
|
54
|
-
|
|
55
|
-
- 프로젝트 타입 자동 감지 (Next.js, Vite, CRA 등)
|
|
56
|
-
- 패키지 매니저 감지 (npm, yarn, pnpm)
|
|
57
|
-
- 최적화된 설정으로 `metadata.config.json` 생성
|
|
58
|
-
- 선택적으로 빌드 설정에 플러그인 추가 (vite.config.ts 또는 next.config.js)
|
|
59
|
-
- 선택적으로 Supabase 연동 설정 (자동 업로드)
|
|
88
|
+
### Global Config / 글로벌 설정
|
|
60
89
|
|
|
61
|
-
|
|
90
|
+
Settings are stored in `~/.metadatafy/` and shared across all projects.
|
|
62
91
|
|
|
63
|
-
|
|
92
|
+
설정은 `~/.metadatafy/`에 저장되며 모든 프로젝트에서 공유됩니다.
|
|
64
93
|
|
|
65
94
|
```bash
|
|
66
|
-
# Interactive setup
|
|
67
|
-
|
|
68
|
-
npx metadatafy init
|
|
95
|
+
# Interactive setup wizard
|
|
96
|
+
metadatafy config setup
|
|
69
97
|
|
|
70
|
-
#
|
|
71
|
-
|
|
72
|
-
npx metadatafy analyze
|
|
98
|
+
# Show current config
|
|
99
|
+
metadatafy config show
|
|
73
100
|
|
|
74
|
-
#
|
|
75
|
-
|
|
76
|
-
|
|
101
|
+
# Set individual values
|
|
102
|
+
metadatafy config set database.provider supabase
|
|
103
|
+
metadatafy config set api.serverUrl https://my-server.com
|
|
77
104
|
|
|
78
|
-
#
|
|
79
|
-
|
|
80
|
-
|
|
105
|
+
# Reset all config
|
|
106
|
+
metadatafy config reset
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Authentication (for API server mode) / 인증 (API 서버 모드용)
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Login via browser (OAuth)
|
|
113
|
+
metadatafy login
|
|
81
114
|
|
|
82
|
-
#
|
|
83
|
-
|
|
84
|
-
npx metadatafy upload
|
|
115
|
+
# Check login status
|
|
116
|
+
metadatafy whoami
|
|
85
117
|
|
|
86
|
-
#
|
|
87
|
-
|
|
118
|
+
# Logout
|
|
119
|
+
metadatafy logout
|
|
88
120
|
```
|
|
89
121
|
|
|
90
|
-
|
|
122
|
+
### Project Commands / 프로젝트 명령어
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Initialize project config
|
|
126
|
+
metadatafy init
|
|
127
|
+
|
|
128
|
+
# Analyze project
|
|
129
|
+
metadatafy analyze
|
|
130
|
+
|
|
131
|
+
# Analyze with upload
|
|
132
|
+
metadatafy analyze --upload
|
|
133
|
+
|
|
134
|
+
# Upload existing metadata file
|
|
135
|
+
metadatafy upload
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Command Reference / 명령어 레퍼런스
|
|
91
139
|
|
|
92
140
|
| Command | Description |
|
|
93
141
|
|---------|-------------|
|
|
94
|
-
| `
|
|
95
|
-
| `
|
|
96
|
-
| `
|
|
97
|
-
| `
|
|
98
|
-
|
|
99
|
-
|
|
142
|
+
| `config setup` | Interactive global config wizard / 대화형 글로벌 설정 |
|
|
143
|
+
| `config show` | Display current config / 현재 설정 표시 |
|
|
144
|
+
| `config set <key> <value>` | Set config value / 설정값 변경 |
|
|
145
|
+
| `config reset` | Reset all config / 모든 설정 초기화 |
|
|
146
|
+
| `login` | OAuth login to API server / API 서버 로그인 |
|
|
147
|
+
| `logout` | Clear login session / 로그아웃 |
|
|
148
|
+
| `whoami` | Show login status / 로그인 상태 확인 |
|
|
149
|
+
| `init` | Initialize project config / 프로젝트 설정 초기화 |
|
|
150
|
+
| `analyze` | Analyze project and generate metadata / 분석 및 메타데이터 생성 |
|
|
151
|
+
| `upload` | Upload existing metadata file / 기존 메타데이터 업로드 |
|
|
152
|
+
|
|
153
|
+
### Analyze Options / Analyze 옵션
|
|
100
154
|
|
|
101
155
|
| Option | Short | Description |
|
|
102
156
|
|--------|-------|-------------|
|
|
103
|
-
| `--project-id` | `-p` | Project ID (default: folder name) |
|
|
104
157
|
| `--output` | `-o` | Output file path (default: project-metadata.json) |
|
|
105
158
|
| `--config` | `-c` | Config file path |
|
|
106
|
-
| `--upload` | |
|
|
107
|
-
| `--no-upload` | | Skip DB upload / DB 업로드 스킵 |
|
|
159
|
+
| `--upload` | | Upload to configured destination |
|
|
108
160
|
| `--verbose` | | Enable detailed logging |
|
|
109
161
|
| `--help` | `-h` | Show help |
|
|
110
162
|
|
|
111
|
-
|
|
163
|
+
## Upload Modes / 업로드 모드
|
|
164
|
+
|
|
165
|
+
metadatafy supports 3 upload modes:
|
|
166
|
+
|
|
167
|
+
metadatafy는 3가지 업로드 모드를 지원합니다:
|
|
168
|
+
|
|
169
|
+
### 1. Local File Only / 로컬 파일만
|
|
170
|
+
|
|
171
|
+
No upload, just generate `project-metadata.json`:
|
|
172
|
+
|
|
173
|
+
업로드 없이 `project-metadata.json`만 생성:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
metadatafy analyze
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### 2. Supabase Direct / Supabase 직접 연결
|
|
180
|
+
|
|
181
|
+
Connect to your own Supabase instance:
|
|
182
|
+
|
|
183
|
+
자신의 Supabase 인스턴스에 직접 연결:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
metadatafy config setup
|
|
187
|
+
# Select: 1) Supabase 직접 연결
|
|
188
|
+
# Enter: Supabase URL, Service Role Key, Table name
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### 3. API Server / API 서버
|
|
192
|
+
|
|
193
|
+
Upload via API server (requires login):
|
|
194
|
+
|
|
195
|
+
API 서버를 통해 업로드 (로그인 필요):
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
metadatafy config setup
|
|
199
|
+
# Select: 2) API 서버
|
|
200
|
+
|
|
201
|
+
metadatafy login
|
|
202
|
+
metadatafy init # Select project from server
|
|
203
|
+
metadatafy analyze --upload
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Vite Plugin
|
|
112
207
|
|
|
113
208
|
```typescript
|
|
114
209
|
// vite.config.ts
|
|
115
210
|
import { defineConfig } from 'vite';
|
|
116
|
-
import
|
|
211
|
+
import metadatafy from 'metadatafy/vite';
|
|
117
212
|
|
|
118
213
|
export default defineConfig({
|
|
119
214
|
plugins: [
|
|
120
|
-
|
|
215
|
+
metadatafy({
|
|
121
216
|
projectId: 'my-project',
|
|
122
217
|
output: {
|
|
123
218
|
file: {
|
|
@@ -130,158 +225,102 @@ export default defineConfig({
|
|
|
130
225
|
});
|
|
131
226
|
```
|
|
132
227
|
|
|
133
|
-
|
|
228
|
+
## Next.js Plugin
|
|
134
229
|
|
|
135
|
-
|
|
230
|
+
### Next.js 15+ with Turbopack
|
|
136
231
|
|
|
137
|
-
|
|
138
|
-
// metadata-adapter.js
|
|
139
|
-
const { createMetadataAdapter } = require('metadatafy/next');
|
|
232
|
+
For Next.js 15+ with Turbopack, use CLI instead of webpack plugin:
|
|
140
233
|
|
|
141
|
-
|
|
142
|
-
projectId: 'my-project',
|
|
143
|
-
verbose: true,
|
|
144
|
-
output: {
|
|
145
|
-
file: { enabled: true, path: 'project-metadata.json' },
|
|
146
|
-
},
|
|
147
|
-
});
|
|
148
|
-
```
|
|
234
|
+
Next.js 15+ Turbopack 환경에서는 webpack 플러그인 대신 CLI를 사용하세요:
|
|
149
235
|
|
|
150
|
-
```
|
|
151
|
-
//
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
},
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
export default nextConfig;
|
|
236
|
+
```json
|
|
237
|
+
// package.json
|
|
238
|
+
{
|
|
239
|
+
"scripts": {
|
|
240
|
+
"build": "next build && metadatafy analyze --upload"
|
|
241
|
+
}
|
|
242
|
+
}
|
|
161
243
|
```
|
|
162
244
|
|
|
163
|
-
|
|
245
|
+
### Next.js 14 or Earlier (Webpack)
|
|
164
246
|
|
|
165
247
|
```javascript
|
|
166
248
|
// next.config.js
|
|
167
|
-
const {
|
|
249
|
+
const { withMetadatafy } = require('metadatafy/next');
|
|
168
250
|
|
|
169
251
|
/** @type {import('next').NextConfig} */
|
|
170
252
|
const nextConfig = {};
|
|
171
253
|
|
|
172
|
-
module.exports =
|
|
173
|
-
projectId: 'my-project',
|
|
174
|
-
})(nextConfig);
|
|
254
|
+
module.exports = withMetadatafy()(nextConfig);
|
|
175
255
|
```
|
|
176
256
|
|
|
177
|
-
## File
|
|
178
|
-
|
|
179
|
-
metadatafy uses a **hybrid detection system** that combines multiple approaches:
|
|
180
|
-
|
|
181
|
-
metadatafy는 여러 접근 방식을 결합한 **하이브리드 감지 시스템**을 사용합니다:
|
|
257
|
+
## Configuration File / 설정 파일
|
|
182
258
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
1. **Next.js special files** - `page.tsx`, `layout.tsx`, `route.ts` → route/api
|
|
186
|
-
2. **Path segments** - `/api/` in path → api
|
|
187
|
-
3. **Folder names** - `components/`, `hooks/`, `utils/`, `lib/` → corresponding type
|
|
188
|
-
4. **Code pattern analysis** - AST-based detection of actual code patterns
|
|
189
|
-
5. **Glob patterns** - User-defined patterns in config
|
|
259
|
+
Project-level config is stored in `metadata.config.json`:
|
|
190
260
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
When folder/path detection fails, metadatafy analyzes the actual code:
|
|
194
|
-
|
|
195
|
-
폴더/경로 감지가 실패하면 실제 코드를 분석합니다:
|
|
196
|
-
|
|
197
|
-
| Type | Detection Pattern |
|
|
198
|
-
|------|-------------------|
|
|
199
|
-
| **hook** | Uses `useState`, `useEffect`, etc. / Function starts with `use` |
|
|
200
|
-
| **component** | Returns JSX / Has `props` parameter |
|
|
201
|
-
| **api** | Exports `GET`, `POST`, etc. / Uses `NextRequest`/`NextResponse` |
|
|
202
|
-
| **service** | Uses `fetch`, `axios` / Multiple async functions / `*Service` class |
|
|
203
|
-
| **utility** | Multiple exported functions / No React dependencies |
|
|
204
|
-
|
|
205
|
-
### Supported Naming Conventions / 지원하는 네이밍 컨벤션
|
|
206
|
-
|
|
207
|
-
All naming conventions are supported:
|
|
208
|
-
|
|
209
|
-
모든 네이밍 컨벤션을 지원합니다:
|
|
210
|
-
|
|
211
|
-
| Type | Examples |
|
|
212
|
-
|------|----------|
|
|
213
|
-
| **hook** | `useAuth.ts`, `use-auth.ts`, `use_auth.ts` |
|
|
214
|
-
| **service** | `AuthService.ts`, `auth-service.ts`, `auth.service.ts` |
|
|
215
|
-
| **utility** | `string-utils.ts`, `date_helper.ts`, `formatUtil.ts` |
|
|
216
|
-
| **component** | `Button.tsx`, `auth-modal.tsx`, `user_profile.tsx` |
|
|
217
|
-
|
|
218
|
-
### Auto Pattern Expansion / 자동 패턴 확장
|
|
219
|
-
|
|
220
|
-
Include patterns are automatically expanded to match nested structures:
|
|
221
|
-
|
|
222
|
-
include 패턴은 중첩 구조에 맞게 자동 확장됩니다:
|
|
223
|
-
|
|
224
|
-
```json
|
|
225
|
-
{
|
|
226
|
-
"include": ["hooks/**/*.ts"]
|
|
227
|
-
}
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
This will match both:
|
|
231
|
-
- `hooks/useAuth.ts`
|
|
232
|
-
- `src/hooks/useAuth.ts`
|
|
233
|
-
- `src/features/auth/hooks/useAuth.ts`
|
|
234
|
-
|
|
235
|
-
## Configuration / 설정
|
|
236
|
-
|
|
237
|
-
Create `metadata.config.json` in your project root:
|
|
238
|
-
|
|
239
|
-
프로젝트 루트에 `metadata.config.json` 파일을 생성하세요:
|
|
261
|
+
프로젝트 레벨 설정은 `metadata.config.json`에 저장됩니다:
|
|
240
262
|
|
|
241
263
|
```json
|
|
242
264
|
{
|
|
243
265
|
"projectId": "my-project",
|
|
266
|
+
"projectUuid": "uuid-from-server",
|
|
244
267
|
"include": [
|
|
245
268
|
"app/**/*.{ts,tsx}",
|
|
246
269
|
"components/**/*.{ts,tsx}",
|
|
247
|
-
"hooks/**/*.{ts,tsx}"
|
|
248
|
-
"services/**/*.ts",
|
|
249
|
-
"lib/**/*.ts"
|
|
270
|
+
"hooks/**/*.{ts,tsx}"
|
|
250
271
|
],
|
|
251
272
|
"exclude": [
|
|
252
273
|
"**/node_modules/**",
|
|
253
|
-
"**/*.test.{ts,tsx}"
|
|
254
|
-
"**/*.spec.{ts,tsx}"
|
|
274
|
+
"**/*.test.{ts,tsx}"
|
|
255
275
|
],
|
|
256
276
|
"output": {
|
|
257
277
|
"file": {
|
|
258
278
|
"enabled": true,
|
|
259
279
|
"path": "project-metadata.json"
|
|
260
|
-
},
|
|
261
|
-
"database": {
|
|
262
|
-
"enabled": true,
|
|
263
|
-
"provider": "supabase",
|
|
264
|
-
"supabase": {
|
|
265
|
-
"url": "${SUPABASE_URL}",
|
|
266
|
-
"serviceRoleKey": "${SUPABASE_SERVICE_ROLE_KEY}",
|
|
267
|
-
"tableName": "code_index"
|
|
268
|
-
}
|
|
269
280
|
}
|
|
270
281
|
},
|
|
271
282
|
"koreanKeywords": {
|
|
272
|
-
"attendance": ["출석", "출결"]
|
|
273
|
-
"student": ["학생", "수강생"]
|
|
283
|
+
"attendance": ["출석", "출결"]
|
|
274
284
|
},
|
|
275
285
|
"verbose": false
|
|
276
286
|
}
|
|
277
287
|
```
|
|
278
288
|
|
|
289
|
+
## Database Schema / 데이터베이스 스키마
|
|
290
|
+
|
|
291
|
+
If using Supabase direct mode, create this table:
|
|
292
|
+
|
|
293
|
+
Supabase 직접 연결 모드 사용 시 이 테이블을 생성하세요:
|
|
294
|
+
|
|
295
|
+
```sql
|
|
296
|
+
CREATE TABLE code_index (
|
|
297
|
+
id TEXT PRIMARY KEY,
|
|
298
|
+
project_id TEXT NOT NULL,
|
|
299
|
+
file_type TEXT NOT NULL,
|
|
300
|
+
name TEXT NOT NULL,
|
|
301
|
+
path TEXT NOT NULL,
|
|
302
|
+
keywords TEXT[] DEFAULT '{}',
|
|
303
|
+
search_text TEXT,
|
|
304
|
+
calls TEXT[] DEFAULT '{}',
|
|
305
|
+
called_by TEXT[] DEFAULT '{}',
|
|
306
|
+
metadata JSONB DEFAULT '{}',
|
|
307
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
308
|
+
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
|
309
|
+
UNIQUE(project_id, path)
|
|
310
|
+
);
|
|
311
|
+
|
|
312
|
+
-- Indexes
|
|
313
|
+
CREATE INDEX idx_code_index_project_id ON code_index(project_id);
|
|
314
|
+
CREATE INDEX idx_code_index_file_type ON code_index(file_type);
|
|
315
|
+
CREATE INDEX idx_code_index_keywords ON code_index USING GIN(keywords);
|
|
316
|
+
```
|
|
317
|
+
|
|
279
318
|
## Output Format / 출력 형식
|
|
280
319
|
|
|
281
320
|
```json
|
|
282
321
|
{
|
|
283
322
|
"projectId": "my-project",
|
|
284
|
-
"timestamp": "2025-01-
|
|
323
|
+
"timestamp": "2025-01-11T12:00:00Z",
|
|
285
324
|
"stats": {
|
|
286
325
|
"totalFiles": 150,
|
|
287
326
|
"byType": {
|
|
@@ -302,7 +341,7 @@ Create `metadata.config.json` in your project root:
|
|
|
302
341
|
"path": "components/attendance/AttendanceModal.tsx",
|
|
303
342
|
"keywords": ["attendance", "modal", "출석", "모달"],
|
|
304
343
|
"searchText": "attendancemodal components attendance ...",
|
|
305
|
-
"calls": ["hooks/useAttendance.ts"
|
|
344
|
+
"calls": ["hooks/useAttendance.ts"],
|
|
306
345
|
"calledBy": ["app/attendance/page.tsx"],
|
|
307
346
|
"metadata": {
|
|
308
347
|
"exports": ["AttendanceModal"],
|
|
@@ -313,147 +352,36 @@ Create `metadata.config.json` in your project root:
|
|
|
313
352
|
}
|
|
314
353
|
```
|
|
315
354
|
|
|
316
|
-
##
|
|
317
|
-
|
|
318
|
-
### Supabase Table Schema / Supabase 테이블 스키마
|
|
319
|
-
|
|
320
|
-
metadatafy stores each file as an individual row for better queryability:
|
|
321
|
-
|
|
322
|
-
metadatafy는 더 나은 쿼리를 위해 각 파일을 개별 row로 저장합니다:
|
|
323
|
-
|
|
324
|
-
```sql
|
|
325
|
-
-- File type enum
|
|
326
|
-
CREATE TYPE file_type AS ENUM (
|
|
327
|
-
'route', 'component', 'hook', 'service', 'api', 'table', 'utility'
|
|
328
|
-
);
|
|
329
|
-
|
|
330
|
-
-- Main table: individual code file metadata
|
|
331
|
-
CREATE TABLE code_index (
|
|
332
|
-
id TEXT PRIMARY KEY,
|
|
333
|
-
project_id TEXT NOT NULL,
|
|
334
|
-
file_type file_type NOT NULL,
|
|
335
|
-
name TEXT NOT NULL,
|
|
336
|
-
path TEXT NOT NULL,
|
|
337
|
-
keywords TEXT[] DEFAULT '{}',
|
|
338
|
-
search_text TEXT,
|
|
339
|
-
calls TEXT[] DEFAULT '{}',
|
|
340
|
-
called_by TEXT[] DEFAULT '{}',
|
|
341
|
-
metadata JSONB DEFAULT '{}',
|
|
342
|
-
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
343
|
-
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
|
344
|
-
UNIQUE(project_id, path)
|
|
345
|
-
);
|
|
346
|
-
|
|
347
|
-
-- Analysis log table
|
|
348
|
-
CREATE TABLE code_analysis_log (
|
|
349
|
-
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
|
|
350
|
-
project_id TEXT NOT NULL,
|
|
351
|
-
total_files INTEGER NOT NULL,
|
|
352
|
-
stats JSONB NOT NULL,
|
|
353
|
-
parse_errors TEXT[] DEFAULT '{}',
|
|
354
|
-
analyzed_at TIMESTAMPTZ NOT NULL,
|
|
355
|
-
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
356
|
-
);
|
|
357
|
-
|
|
358
|
-
-- Indexes for search optimization
|
|
359
|
-
CREATE INDEX idx_code_index_project_id ON code_index(project_id);
|
|
360
|
-
CREATE INDEX idx_code_index_file_type ON code_index(file_type);
|
|
361
|
-
CREATE INDEX idx_code_index_keywords ON code_index USING GIN(keywords);
|
|
362
|
-
CREATE INDEX idx_code_index_search_text ON code_index USING GIN(to_tsvector('simple', search_text));
|
|
363
|
-
|
|
364
|
-
-- RLS Policies
|
|
365
|
-
ALTER TABLE code_index ENABLE ROW LEVEL SECURITY;
|
|
366
|
-
ALTER TABLE code_analysis_log ENABLE ROW LEVEL SECURITY;
|
|
367
|
-
|
|
368
|
-
-- Read access for authenticated users
|
|
369
|
-
CREATE POLICY "Authenticated users can read code_index"
|
|
370
|
-
ON code_index FOR SELECT TO authenticated USING (true);
|
|
371
|
-
|
|
372
|
-
-- Write access for service role only
|
|
373
|
-
CREATE POLICY "Service role can manage code_index"
|
|
374
|
-
ON code_index FOR ALL TO service_role USING (true) WITH CHECK (true);
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
### Configuration / 설정
|
|
378
|
-
|
|
379
|
-
```json
|
|
380
|
-
{
|
|
381
|
-
"output": {
|
|
382
|
-
"database": {
|
|
383
|
-
"enabled": true,
|
|
384
|
-
"provider": "supabase",
|
|
385
|
-
"supabase": {
|
|
386
|
-
"url": "${SUPABASE_URL}",
|
|
387
|
-
"serviceRoleKey": "${SUPABASE_SERVICE_ROLE_KEY}",
|
|
388
|
-
"tableName": "code_index"
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
```
|
|
394
|
-
|
|
395
|
-
### Environment Variables / 환경변수
|
|
355
|
+
## CI/CD Integration / CI/CD 연동
|
|
396
356
|
|
|
397
|
-
|
|
398
|
-
SUPABASE_URL=https://your-project.supabase.co
|
|
399
|
-
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
|
|
400
|
-
```
|
|
401
|
-
|
|
402
|
-
### How It Works / 작동 방식
|
|
403
|
-
|
|
404
|
-
1. **Delete existing project data** - Removes all rows with matching `project_id`
|
|
405
|
-
2. **Bulk insert new data** - Inserts all files in chunks of 500
|
|
406
|
-
3. **Log analysis run** - Records stats in `code_analysis_log` table
|
|
407
|
-
|
|
408
|
-
---
|
|
409
|
-
|
|
410
|
-
1. **기존 프로젝트 데이터 삭제** - 동일한 `project_id`의 모든 row 삭제
|
|
411
|
-
2. **새 데이터 일괄 삽입** - 500개 단위로 모든 파일 삽입
|
|
412
|
-
3. **분석 로그 기록** - `code_analysis_log` 테이블에 통계 기록
|
|
413
|
-
|
|
414
|
-
### Querying Code / 코드 쿼리 예시
|
|
415
|
-
|
|
416
|
-
```sql
|
|
417
|
-
-- Find all hooks in a project
|
|
418
|
-
SELECT * FROM code_index
|
|
419
|
-
WHERE project_id = 'my-project' AND file_type = 'hook';
|
|
420
|
-
|
|
421
|
-
-- Full-text search
|
|
422
|
-
SELECT * FROM code_index
|
|
423
|
-
WHERE project_id = 'my-project'
|
|
424
|
-
AND search_text ILIKE '%authentication%';
|
|
425
|
-
|
|
426
|
-
-- Find files that call a specific file
|
|
427
|
-
SELECT * FROM code_index
|
|
428
|
-
WHERE 'hooks/useAuth.ts' = ANY(calls);
|
|
429
|
-
|
|
430
|
-
-- Get analysis history
|
|
431
|
-
SELECT * FROM code_analysis_log
|
|
432
|
-
WHERE project_id = 'my-project'
|
|
433
|
-
ORDER BY analyzed_at DESC;
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
### Recommended Workflow / 권장 워크플로우
|
|
437
|
-
|
|
438
|
-
```bash
|
|
439
|
-
# Generate metadata + upload
|
|
440
|
-
npx metadatafy analyze --upload
|
|
441
|
-
|
|
442
|
-
# Or in CI/CD
|
|
443
|
-
npx metadatafy analyze --upload
|
|
444
|
-
```
|
|
445
|
-
|
|
446
|
-
**GitHub Actions:**
|
|
357
|
+
### GitHub Actions
|
|
447
358
|
|
|
448
359
|
```yaml
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
360
|
+
name: Analyze Code
|
|
361
|
+
on:
|
|
362
|
+
push:
|
|
363
|
+
branches: [main]
|
|
364
|
+
|
|
365
|
+
jobs:
|
|
366
|
+
analyze:
|
|
367
|
+
runs-on: ubuntu-latest
|
|
368
|
+
steps:
|
|
369
|
+
- uses: actions/checkout@v4
|
|
370
|
+
- uses: actions/setup-node@v4
|
|
371
|
+
with:
|
|
372
|
+
node-version: '20'
|
|
373
|
+
|
|
374
|
+
- run: npm ci
|
|
375
|
+
- run: npm run build
|
|
376
|
+
|
|
377
|
+
# Using Supabase direct
|
|
378
|
+
- run: npx metadatafy analyze --upload
|
|
379
|
+
env:
|
|
380
|
+
METADATAFY_DB_URL: ${{ secrets.SUPABASE_URL }}
|
|
381
|
+
METADATAFY_DB_KEY: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }}
|
|
454
382
|
```
|
|
455
383
|
|
|
456
|
-
## API / 프로그래밍 방식 사용
|
|
384
|
+
## API Usage / 프로그래밍 방식 사용
|
|
457
385
|
|
|
458
386
|
```typescript
|
|
459
387
|
import { ProjectAnalyzer, createDefaultConfig } from 'metadatafy';
|
|
@@ -470,11 +398,26 @@ console.log(result.stats);
|
|
|
470
398
|
console.log(result.items);
|
|
471
399
|
```
|
|
472
400
|
|
|
473
|
-
##
|
|
401
|
+
## File Type Detection / 파일 타입 감지
|
|
402
|
+
|
|
403
|
+
metadatafy uses a hybrid detection system:
|
|
404
|
+
|
|
405
|
+
1. **Next.js special files** - `page.tsx`, `layout.tsx`, `route.ts` → route/api
|
|
406
|
+
2. **Path segments** - `/api/` in path → api
|
|
407
|
+
3. **Folder names** - `components/`, `hooks/`, `utils/` → corresponding type
|
|
408
|
+
4. **Code pattern analysis** - AST-based detection
|
|
409
|
+
|
|
410
|
+
| Type | Detection Pattern |
|
|
411
|
+
|------|-------------------|
|
|
412
|
+
| **hook** | Uses `useState`, `useEffect` / Function starts with `use` |
|
|
413
|
+
| **component** | Returns JSX / Has `props` parameter |
|
|
414
|
+
| **api** | Exports `GET`, `POST` / Uses `NextRequest` |
|
|
415
|
+
| **service** | Uses `fetch`, `axios` / `*Service` class |
|
|
416
|
+
| **utility** | Multiple exported functions / No React |
|
|
474
417
|
|
|
475
|
-
|
|
418
|
+
## Korean Keyword Mapping / 한글 키워드 매핑
|
|
476
419
|
|
|
477
|
-
|
|
420
|
+
Built-in mappings:
|
|
478
421
|
|
|
479
422
|
| English | Korean |
|
|
480
423
|
|---------|--------|
|
|
@@ -485,9 +428,7 @@ Built-in mappings include common development terms:
|
|
|
485
428
|
| login | 로그인 |
|
|
486
429
|
| user | 사용자, 유저, 회원 |
|
|
487
430
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
설정에서 커스텀 매핑을 추가할 수 있습니다.
|
|
431
|
+
Extend with custom mappings in `metadata.config.json`.
|
|
491
432
|
|
|
492
433
|
## License / 라이선스
|
|
493
434
|
|
|
@@ -497,6 +438,4 @@ MIT
|
|
|
497
438
|
|
|
498
439
|
Issues and pull requests are welcome!
|
|
499
440
|
|
|
500
|
-
이슈와 풀 리퀘스트를 환영합니다!
|
|
501
|
-
|
|
502
441
|
GitHub: https://github.com/rungchan2/metadatafy
|
package/dist/cli.cjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
'use strict';var chunkCY7QWWFH_cjs=require('./chunk-CY7QWWFH.cjs'),util=require('util'),m=require('path'),
|
|
3
|
-
\u{1F4E6} \uD504\uB85C\uC81D\uD2B8 \uD0C0\uC785\uC744 \uC120\uD0DD\uD558\uC138\uC694:`),
|
|
4
|
-
\uC120\uD0DD [${s}]: `)).trim()||s;return
|
|
5
|
-
\u{1F4E6} \uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800\uB97C \uC120\uD0DD\uD558\uC138\uC694:`),
|
|
6
|
-
\uC120\uD0DD [${s}]: `)).trim()||s;return
|
|
2
|
+
'use strict';var chunkCY7QWWFH_cjs=require('./chunk-CY7QWWFH.cjs'),util=require('util'),m=require('path'),h=require('fs/promises'),K=require('readline'),d=require('fs'),Z=require('os');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var m__namespace=/*#__PURE__*/_interopNamespace(m);var h__namespace=/*#__PURE__*/_interopNamespace(h);var K__namespace=/*#__PURE__*/_interopNamespace(K);var d__namespace=/*#__PURE__*/_interopNamespace(d);var Z__namespace=/*#__PURE__*/_interopNamespace(Z);async function le(e){let o=[{file:"pnpm-lock.yaml",manager:"pnpm"},{file:"yarn.lock",manager:"yarn"},{file:"package-lock.json",manager:"npm"}];for(let{file:t,manager:s}of o)try{return await h__namespace.access(m__namespace.join(e,t)),s}catch{}return "npm"}async function pe(e){let o={};try{let s=await h__namespace.readFile(m__namespace.join(e,"package.json"),"utf-8");o=JSON.parse(s);}catch{return "unknown"}let t={...o.dependencies||{},...o.devDependencies||{}};return t.next?await $(m__namespace.join(e,"app"))||await $(m__namespace.join(e,"src","app"))?"nextjs-app":"nextjs-pages":t.vite?"vite":t["react-scripts"]?"cra":t.express||t.fastify||t.koa?"node":"unknown"}async function G(e){let[o,t]=await Promise.all([pe(e),le(e)]),s=await fe(m__namespace.join(e,"tsconfig.json")),n=await $(m__namespace.join(e,"src")),a=["app","pages","components","hooks","services","lib","utils","api","src/app","src/pages","src/components","src/hooks","src/services","src/lib","src/utils"],r=[];for(let l of a)await $(m__namespace.join(e,l))&&r.push(l);let i=await $(m__namespace.join(e,"prisma")),c=await $(m__namespace.join(e,"supabase"));return {type:o,packageManager:t,hasTypescript:s,hasSrc:n,existingFolders:r,hasPrisma:i,hasSupabase:c}}async function fe(e){try{return (await h__namespace.stat(e)).isFile()}catch{return false}}async function $(e){try{return (await h__namespace.stat(e)).isDirectory()}catch{return false}}function H(e){return {"nextjs-app":"Next.js (App Router)","nextjs-pages":"Next.js (Pages Router)",vite:"Vite + React",cra:"Create React App",node:"Node.js Backend",unknown:"Unknown"}[e]}var P=null;function ge(){return P||(P=K__namespace.createInterface({input:process.stdin,output:process.stdout,terminal:false})),P}function y(e){return new Promise(o=>{process.stdout.write(e),ge().once("line",t=>{o(t);});})}function u(){P&&(P.close(),P=null);}async function V(e){let o=[{key:"1",type:"nextjs-app",label:"Next.js (App Router)"},{key:"2",type:"nextjs-pages",label:"Next.js (Pages Router)"},{key:"3",type:"vite",label:"Vite + React"},{key:"4",type:"cra",label:"Create React App"},{key:"5",type:"node",label:"Node.js Backend"}],t=o.findIndex(i=>i.type===e),s=t>=0?o[t].key:"1";console.log(`
|
|
3
|
+
\u{1F4E6} \uD504\uB85C\uC81D\uD2B8 \uD0C0\uC785\uC744 \uC120\uD0DD\uD558\uC138\uC694:`),o.forEach(i=>{let l=i.type===e?" (\uAC10\uC9C0\uB428)":"";console.log(` ${i.key}) ${i.label}${l}`);});let a=(await y(`
|
|
4
|
+
\uC120\uD0DD [${s}]: `)).trim()||s;return o.find(i=>i.key===a)?.type||e}async function W(e){let o=[{key:"1",manager:"npm"},{key:"2",manager:"yarn"},{key:"3",manager:"pnpm"}],t=o.findIndex(i=>i.manager===e),s=t>=0?o[t].key:"1";console.log(`
|
|
5
|
+
\u{1F4E6} \uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800\uB97C \uC120\uD0DD\uD558\uC138\uC694:`),o.forEach(i=>{let l=i.manager===e?" (\uAC10\uC9C0\uB428)":"";console.log(` ${i.key}) ${i.manager}${l}`);});let a=(await y(`
|
|
6
|
+
\uC120\uD0DD [${s}]: `)).trim()||s;return o.find(i=>i.key===a)?.manager||e}async function q(e){return e==="node"||e==="unknown"||e.startsWith("nextjs")?false:(console.log(`
|
|
7
7
|
\u{1F527} vite.config \uD30C\uC77C\uC5D0 metadatafy \uD50C\uB7EC\uADF8\uC778\uC744 \uC790\uB3D9\uC73C\uB85C \uCD94\uAC00\uD560\uAE4C\uC694?`),console.log(" \uBE4C\uB4DC \uC2DC \uC790\uB3D9\uC73C\uB85C \uBA54\uD0C0\uB370\uC774\uD130\uAC00 \uC0DD\uC131\uB429\uB2C8\uB2E4."),(await y(`
|
|
8
|
-
\uCD94\uAC00\uD560\uAE4C\uC694? [Y/n]: `)).trim().toLowerCase()!=="n")}async function
|
|
9
|
-
`;return n.includes("from 'vite'")?n=n.replace(/^(import .+ from ['"]vite['"];?\n)/m,`$1${
|
|
8
|
+
\uCD94\uAC00\uD560\uAE4C\uC694? [Y/n]: `)).trim().toLowerCase()!=="n")}async function A(e,o=true){let n=(await y(`${e} ${o?"[Y/n]":"[y/N]"}: `)).trim().toLowerCase();return n===""?o:n==="y"||n==="yes"}function ue(e){let{projectType:o,projectInfo:t}=e,s=[],n=t.hasTypescript?"{ts,tsx}":"{js,jsx}";switch(o){case "nextjs-app":t.hasSrc?s.push(`src/app/**/*.${n}`):s.push(`app/**/*.${n}`),s.push(`components/**/*.${n}`),s.push(`hooks/**/*.${n}`),s.push(`lib/**/*.${n}`);break;case "nextjs-pages":t.hasSrc?s.push(`src/pages/**/*.${n}`):s.push(`pages/**/*.${n}`),s.push(`components/**/*.${n}`),s.push(`hooks/**/*.${n}`),s.push(`lib/**/*.${n}`);break;case "vite":case "cra":s.push(`src/**/*.${n}`);break;case "node":s.push(`src/**/*.${t.hasTypescript?"ts":"js"}`),s.push(`routes/**/*.${t.hasTypescript?"ts":"js"}`),s.push(`controllers/**/*.${t.hasTypescript?"ts":"js"}`);break;default:s.push(`src/**/*.${n}`);}return t.hasPrisma&&s.push("prisma/migrations/**/*.sql"),t.hasSupabase&&s.push("supabase/migrations/*.sql"),s}async function Y(e,o,t){let s=m__namespace.join(e,"metadata.config.json"),n={projectId:o,projectUuid:t.projectUuid,projectName:t.projectName,include:ue(t),exclude:["**/node_modules/**","**/.next/**","**/dist/**","**/build/**","**/*.test.{ts,tsx,js,jsx}","**/*.spec.{ts,tsx,js,jsx}","**/__tests__/**"],output:{file:{enabled:true,path:"project-metadata.json"}},koreanKeywords:{},verbose:false};return await h__namespace.writeFile(s,JSON.stringify(n,null,2)),s}async function X(e){let o=["vite.config.ts","vite.config.js","vite.config.mts","vite.config.mjs"];for(let t of o){let s=m__namespace.join(e,t);try{let n=await h__namespace.readFile(s,"utf-8");if(n.includes("metadatafy"))return !0;let a=`import metadatafy from 'metadatafy/vite';
|
|
9
|
+
`;return n.includes("from 'vite'")?n=n.replace(/^(import .+ from ['"]vite['"];?\n)/m,`$1${a}`):n=a+n,n.includes("plugins:")?n=n.replace(/plugins:\s*\[/,`plugins: [
|
|
10
10
|
metadatafy(),`):n.includes("defineConfig(")&&(n=n.replace(/defineConfig\(\{/,`defineConfig({
|
|
11
|
-
plugins: [metadatafy()],`)),await
|
|
11
|
+
plugins: [metadatafy()],`)),await h__namespace.writeFile(s,n),!0}catch{}}return false}var U=m__namespace.join(Z__namespace.homedir(),".metadatafy"),E=m__namespace.join(U,"config.json"),R=m__namespace.join(U,"auth.json");function Q(){d__namespace.existsSync(U)||d__namespace.mkdirSync(U,{mode:448});}function x(){try{if(!d__namespace.existsSync(E))return {};let e=d__namespace.readFileSync(E,"utf-8");return JSON.parse(e)}catch{return {}}}function v(e){Q(),d__namespace.writeFileSync(E,JSON.stringify(e,null,2),{mode:384});}function I(){try{if(!d__namespace.existsSync(R))return null;let e=d__namespace.readFileSync(R,"utf-8"),o=JSON.parse(e);return o.expiresAt&&new Date(o.expiresAt)<new Date?(console.log("\u26A0\uFE0F \uC778\uC99D\uC774 \uB9CC\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uB85C\uADF8\uC778\uD558\uC138\uC694."),null):o}catch{return null}}function ee(e){Q(),d__namespace.writeFileSync(R,JSON.stringify(e,null,2),{mode:384});}function M(){d__namespace.existsSync(R)&&d__namespace.unlinkSync(R);}function T(){let e=I();return e!==null&&!!e.accessToken}function O(){return I()?.accessToken||null}function L(){return U}function oe(){let e=x();return e.database?.provider?e.database:null}function N(){return x().api?.serverUrl||"https://management.impakers.club"}var de="1.5.1",te=`
|
|
12
12
|
metadatafy - \uD504\uB85C\uC81D\uD2B8 \uBA54\uD0C0\uB370\uC774\uD130 \uCD94\uCD9C \uB3C4\uAD6C
|
|
13
13
|
|
|
14
14
|
Usage:
|
|
@@ -16,6 +16,7 @@ Usage:
|
|
|
16
16
|
|
|
17
17
|
Commands:
|
|
18
18
|
init \uD504\uB85C\uC81D\uD2B8 \uC124\uC815 \uCD08\uAE30\uD654
|
|
19
|
+
link API \uC11C\uBC84\uC758 \uD504\uB85C\uC81D\uD2B8\uC640 \uC5F0\uACB0
|
|
19
20
|
analyze \uD504\uB85C\uC81D\uD2B8\uB97C \uBD84\uC11D\uD558\uACE0 \uBA54\uD0C0\uB370\uC774\uD130 \uC0DD\uC131
|
|
20
21
|
upload \uAE30\uC874 \uBA54\uD0C0\uB370\uC774\uD130 \uD30C\uC77C\uC744 \uC5C5\uB85C\uB4DC
|
|
21
22
|
|
|
@@ -35,10 +36,11 @@ Options:
|
|
|
35
36
|
|
|
36
37
|
Examples:
|
|
37
38
|
metadatafy init # \uD504\uB85C\uC81D\uD2B8 \uC124\uC815
|
|
39
|
+
metadatafy link # \uC11C\uBC84 \uD504\uB85C\uC81D\uD2B8 \uC5F0\uACB0
|
|
38
40
|
metadatafy analyze # \uBD84\uC11D (\uB85C\uCEEC \uD30C\uC77C \uC0DD\uC131)
|
|
39
41
|
metadatafy analyze --upload # \uBD84\uC11D + \uC5C5\uB85C\uB4DC
|
|
40
42
|
metadatafy config setup # DB \uC5F0\uACB0 \uC124\uC815
|
|
41
|
-
`,
|
|
43
|
+
`,ne=`
|
|
42
44
|
Usage: metadatafy config <subcommand>
|
|
43
45
|
|
|
44
46
|
Subcommands:
|
|
@@ -52,7 +54,7 @@ Examples:
|
|
|
52
54
|
metadatafy config setup
|
|
53
55
|
metadatafy config set database.provider supabase
|
|
54
56
|
metadatafy config set api.serverUrl https://my-server.com
|
|
55
|
-
`,
|
|
57
|
+
`,me=`
|
|
56
58
|
Usage: metadatafy analyze [options]
|
|
57
59
|
|
|
58
60
|
Options:
|
|
@@ -61,7 +63,7 @@ Options:
|
|
|
61
63
|
--upload \uC5C5\uB85C\uB4DC \uC2E4\uD589 (\uAE00\uB85C\uBC8C config \uB610\uB294 API \uC11C\uBC84)
|
|
62
64
|
--verbose \uC0C1\uC138 \uB85C\uADF8 \uCD9C\uB825
|
|
63
65
|
-h, --help \uB3C4\uC6C0\uB9D0 \uD45C\uC2DC
|
|
64
|
-
`,
|
|
66
|
+
`,ye=`
|
|
65
67
|
Usage: metadatafy upload [options]
|
|
66
68
|
|
|
67
69
|
\uAE30\uC874 \uBA54\uD0C0\uB370\uC774\uD130 JSON \uD30C\uC77C\uC744 \uC5C5\uB85C\uB4DC\uD569\uB2C8\uB2E4.
|
|
@@ -72,55 +74,70 @@ Options:
|
|
|
72
74
|
-c, --config <path> \uC124\uC815 \uD30C\uC77C \uACBD\uB85C
|
|
73
75
|
--verbose \uC0C1\uC138 \uB85C\uADF8 \uCD9C\uB825
|
|
74
76
|
-h, --help \uB3C4\uC6C0\uB9D0 \uD45C\uC2DC
|
|
75
|
-
`;async function
|
|
76
|
-
\u{1F4C1} \uC124\uC815 \uC704\uCE58: ${
|
|
77
|
-
`),Object.keys(e).length===0){console.log("\uC124\uC815\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. metadatafy config setup \uC73C\uB85C \uC124\uC815\uD558\uC138\uC694.");return}console.log("\uD604\uC7AC \uC124\uC815:"),console.log(JSON.stringify(e,null,2));let
|
|
78
|
-
\u{1F510} \uC778\uC99D \uC0C1\uD0DC: \uB85C\uADF8\uC778\uB428`),
|
|
77
|
+
`;async function he(){let e=process.argv.slice(2);(e.length===0||e[0]==="-h"||e[0]==="--help")&&(console.log(te),process.exit(0)),(e[0]==="-v"||e[0]==="--version")&&(console.log(de),process.exit(0));let o=e[0];switch(o){case "config":await we(e.slice(1));break;case "login":await ae();break;case "logout":await Se();break;case "whoami":await Ae();break;case "analyze":await Ue(e.slice(1));break;case "upload":await Re(e.slice(1));break;case "init":await ie();break;case "link":await Ce();break;default:console.error(`Unknown command: ${o}`),console.log(te),process.exit(1);}}async function we(e){let o=e[0];if(!o||o==="-h"||o==="--help"){console.log(ne);return}switch(o){case "show":await be();break;case "setup":await ke();break;case "set":await Pe(e.slice(1));break;case "reset":await ve();break;default:console.error(`Unknown config subcommand: ${o}`),console.log(ne),process.exit(1);}}async function be(){let e=x(),o=L();if(console.log(`
|
|
78
|
+
\u{1F4C1} \uC124\uC815 \uC704\uCE58: ${o}
|
|
79
|
+
`),Object.keys(e).length===0){console.log("\uC124\uC815\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. metadatafy config setup \uC73C\uB85C \uC124\uC815\uD558\uC138\uC694.");return}console.log("\uD604\uC7AC \uC124\uC815:"),console.log(JSON.stringify(e,null,2));let t=I();t&&(console.log(`
|
|
80
|
+
\u{1F510} \uC778\uC99D \uC0C1\uD0DC: \uB85C\uADF8\uC778\uB428`),t.serverUrl&&console.log(` \uC11C\uBC84: ${t.serverUrl}`));}async function ke(){console.log(`
|
|
79
81
|
\u2699\uFE0F metadatafy \uAE00\uB85C\uBC8C \uC124\uC815
|
|
80
82
|
`),console.log("\uC774 \uC124\uC815\uC740 ~/.metadatafy/\uC5D0 \uC800\uC7A5\uB429\uB2C8\uB2E4."),console.log(`\uBAA8\uB4E0 \uD504\uB85C\uC81D\uD2B8\uC5D0\uC11C \uACF5\uD1B5\uC73C\uB85C \uC0AC\uC6A9\uB429\uB2C8\uB2E4.
|
|
81
|
-
`);let e=
|
|
82
|
-
`),console.log(" 1) Supabase \uC9C1\uC811 \uC5F0\uACB0"),console.log(" 2) API \uC11C\uBC84 (ticket-ms \uB4F1)"),console.log(" 3) \uB85C\uCEEC \uD30C\uC77C\uB9CC (\uC5C5\uB85C\uB4DC \uC548 \uD568)");let
|
|
83
|
-
\uC120\uD0DD [1-3]: `);
|
|
84
|
-
\u2705 \uB85C\uCEEC \uD30C\uC77C \uBAA8\uB4DC\uB85C \uC124\uC815\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`)),
|
|
85
|
-
\u{1F389} \uC124\uC815\uC774 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4!`),console.log(` \uC800\uC7A5 \uC704\uCE58: ${
|
|
86
|
-
`);}async function
|
|
83
|
+
`);let e=x();console.log(`\u{1F4E4} \uBA54\uD0C0\uB370\uC774\uD130 \uC5C5\uB85C\uB4DC \uBC29\uC2DD\uC744 \uC120\uD0DD\uD558\uC138\uC694:
|
|
84
|
+
`),console.log(" 1) Supabase \uC9C1\uC811 \uC5F0\uACB0"),console.log(" 2) API \uC11C\uBC84 (ticket-ms \uB4F1)"),console.log(" 3) \uB85C\uCEEC \uD30C\uC77C\uB9CC (\uC5C5\uB85C\uB4DC \uC548 \uD568)");let o=await y(`
|
|
85
|
+
\uC120\uD0DD [1-3]: `);o==="1"?await xe(e):o==="2"?await je(e):(e.database=void 0,e.api=void 0,v(e),console.log(`
|
|
86
|
+
\u2705 \uB85C\uCEEC \uD30C\uC77C \uBAA8\uB4DC\uB85C \uC124\uC815\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`)),u(),console.log(`
|
|
87
|
+
\u{1F389} \uC124\uC815\uC774 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4!`),console.log(` \uC800\uC7A5 \uC704\uCE58: ${L()}/config.json
|
|
88
|
+
`);}async function xe(e){console.log(`
|
|
87
89
|
\u{1F5C4}\uFE0F Supabase \uC124\uC815
|
|
88
90
|
`),console.log("Supabase \uB300\uC2DC\uBCF4\uB4DC\uC5D0\uC11C \uB2E4\uC74C \uC815\uBCF4\uB97C \uD655\uC778\uD558\uC138\uC694:"),console.log(`Settings > API > Project URL, service_role key
|
|
89
|
-
`);let
|
|
90
|
-
\u2705 Supabase \uC124\uC815\uC774 \uC800\uC7A5\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`)
|
|
91
|
+
`);let o=await y("Supabase URL: "),t=await $e("Service Role Key: "),s=await y("\uD14C\uC774\uBE14 \uC774\uB984 [code_index]: ");e.database={provider:"supabase",supabaseUrl:o.trim(),supabaseServiceRoleKey:t,supabaseTable:s.trim()||"code_index"},v(e),console.log(`
|
|
92
|
+
\u2705 Supabase \uC124\uC815\uC774 \uC800\uC7A5\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`),console.log(`
|
|
93
|
+
\u{1F4A1} \uAC01 \uD504\uB85C\uC81D\uD2B8\uC5D0\uC11C metadatafy init \uC73C\uB85C \uD504\uB85C\uC81D\uD2B8 ID\uB97C \uC124\uC815\uD558\uC138\uC694.`);}async function je(e){console.log(`
|
|
91
94
|
\u{1F310} API \uC11C\uBC84 \uC124\uC815
|
|
92
|
-
`);let
|
|
95
|
+
`);let o=e.api?.serverUrl||"https://management.impakers.club",t=await y(`\uC11C\uBC84 URL [${o}]: `);e.api={serverUrl:t.trim()||o},console.log(`
|
|
93
96
|
\u{1F4A1} API \uC11C\uBC84 \uC0AC\uC6A9 \uC2DC \uB85C\uADF8\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.`),console.log(" metadatafy login \uC73C\uB85C \uB85C\uADF8\uC778\uD558\uC138\uC694."),v(e),console.log(`
|
|
94
|
-
\u2705 API \uC11C\uBC84 \uC124\uC815\uC774 \uC800\uC7A5\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`);}function
|
|
95
|
-
`:case "\r":case "":
|
|
96
|
-
`),
|
|
97
|
-
Examples:`),console.log(" metadatafy config set database.provider supabase"),console.log(" metadatafy config set api.serverUrl https://my-server.com"),process.exit(1));let[t
|
|
97
|
+
\u2705 API \uC11C\uBC84 \uC124\uC815\uC774 \uC800\uC7A5\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`);}function $e(e){return new Promise(o=>{process.stdout.write(e);let t=process.stdin,s=t.isRaw;t.isTTY&&t.setRawMode(true);let n="",a=r=>{let i=r.toString("utf8");switch(i){case `
|
|
98
|
+
`:case "\r":case "":t.isTTY&&t.setRawMode(s),t.removeListener("data",a),process.stdout.write(`
|
|
99
|
+
`),o(n);break;case "":process.exit();break;case "\x7F":n.length>0&&(n=n.slice(0,-1),process.stdout.clearLine(0),process.stdout.cursorTo(0),process.stdout.write(e+"*".repeat(n.length)));break;default:n+=i,process.stdout.write("*");break}};t.on("data",a),t.resume();})}async function Pe(e){e.length<2&&(console.error("Usage: metadatafy config set <key> <value>"),console.log(`
|
|
100
|
+
Examples:`),console.log(" metadatafy config set database.provider supabase"),console.log(" metadatafy config set api.serverUrl https://my-server.com"),process.exit(1));let[o,...t]=e,s=t.join(" "),n=x(),a=o.split("."),r=n;for(let i=0;i<a.length-1;i++){let c=a[i];(!r[c]||typeof r[c]!="object")&&(r[c]={}),r=r[c];}r[a[a.length-1]]=s,v(n),console.log(`\u2705 ${o} = ${s}`);}async function ve(){let e=await A("\uBAA8\uB4E0 \uC124\uC815\uC744 \uCD08\uAE30\uD654\uD560\uAE4C\uC694?",false);if(u(),!e){console.log("\uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");return}v({}),M(),console.log("\u2705 \uBAA8\uB4E0 \uC124\uC815\uC774 \uCD08\uAE30\uD654\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");}async function ae(){let e=N();if(T()){let n=I();if(console.log(`\uC774\uBBF8 \uB85C\uADF8\uC778\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4. (${n?.serverUrl||e})`),!await A("\uB2E4\uC2DC \uB85C\uADF8\uC778\uD560\uAE4C\uC694?",false)){u();return}}console.log(`
|
|
98
101
|
\u{1F510} \uB85C\uADF8\uC778 (${e})
|
|
99
|
-
`);let
|
|
100
|
-
\u{1F310} \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uC778\uC99D\uC744 \uC644\uB8CC\uD558\uC138\uC694.`),console.log(` ${
|
|
101
|
-
`),await
|
|
102
|
-
\u274C \uC778\uC99D \uC2DC\uAC04\uC774 \uCD08\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694.`),
|
|
103
|
-
\u2705 \uB85C\uADF8\uC778 \uC131\uACF5!`),
|
|
104
|
-
\u{
|
|
105
|
-
`)
|
|
106
|
-
|
|
107
|
-
\
|
|
108
|
-
\
|
|
109
|
-
|
|
102
|
+
`);let o=crypto.randomUUID();console.log("\u{1F504} \uC778\uC99D \uC900\uBE44 \uC911...");try{let n=await fetch(`${e}/api/auth/device`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({deviceCode:o})});if(!n.ok)throw new Error(`HTTP ${n.status}`)}catch{console.error("\u274C \uC11C\uBC84 \uC5F0\uACB0\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4."),console.log(` ${e}/api/auth/device`),u(),process.exit(1);}let t=`${e}/auth/device?code=${o}`;console.log(`
|
|
103
|
+
\u{1F310} \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uC778\uC99D\uC744 \uC644\uB8CC\uD558\uC138\uC694.`),console.log(` ${t}
|
|
104
|
+
`),await Ie(t),console.log("\u23F3 \uC778\uC99D \uB300\uAE30 \uC911... (\uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uB85C\uADF8\uC778\uD558\uC138\uC694)");let s=await Te(e,o);s||(console.error(`
|
|
105
|
+
\u274C \uC778\uC99D \uC2DC\uAC04\uC774 \uCD08\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694.`),u(),process.exit(1)),ee({accessToken:s.accessToken,expiresAt:s.expiresAt,userId:s.userId,serverUrl:e}),console.log(`
|
|
106
|
+
\u2705 \uB85C\uADF8\uC778 \uC131\uACF5!`),u();}async function Ie(e){let{exec:o}=await import('child_process'),t=process.platform,s=t==="darwin"?`open "${e}"`:t==="win32"?`start "${e}"`:`xdg-open "${e}"`;o(s);}async function Te(e,o){let n=Date.now();for(;Date.now()-n<3e5;)try{let a=await fetch(`${e}/api/auth/device/status?code=${o}`);if(!a.ok){await _(2e3);continue}let r=await a.json();if(r.status==="authorized"&&r.accessToken)return {accessToken:r.accessToken,expiresAt:r.expiresAt||new Date(Date.now()+720*60*60*1e3).toISOString(),userId:r.userId};if(r.status==="expired")return null;await _(2e3);}catch{await _(2e3);}return null}function _(e){return new Promise(o=>setTimeout(o,e))}async function Se(){if(!T()){console.log("\uB85C\uADF8\uC778\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");return}M(),console.log("\u2705 \uB85C\uADF8\uC544\uC6C3\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");}async function Ae(){let e=I();if(!e){console.log("\uB85C\uADF8\uC778\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4."),console.log("metadatafy login \uC73C\uB85C \uB85C\uADF8\uC778\uD558\uC138\uC694.");return}console.log("\u2705 \uB85C\uADF8\uC778\uB428"),e.serverUrl&&console.log(` \uC11C\uBC84: ${e.serverUrl}`),e.userId&&console.log(` User ID: ${e.userId}`),e.expiresAt&&console.log(` \uB9CC\uB8CC: ${new Date(e.expiresAt).toLocaleString()}`);}async function Ce(){let e=process.cwd();m__namespace.basename(e);console.log(`
|
|
107
|
+
\u{1F517} \uD504\uB85C\uC81D\uD2B8 \uC5F0\uACB0
|
|
108
|
+
`),T()||(console.log("\u274C \uB85C\uADF8\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4."),console.log(" metadatafy login \uC73C\uB85C \uBA3C\uC800 \uB85C\uADF8\uC778\uD558\uC138\uC694."),u(),process.exit(1));let t=N(),s=O();s||(console.log("\u274C \uC778\uC99D \uD1A0\uD070\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."),console.log(" metadatafy login \uC73C\uB85C \uB85C\uADF8\uC778\uD558\uC138\uC694."),u(),process.exit(1)),console.log("\u{1F4CB} \uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D \uC870\uD68C \uC911...");try{let n=await fetch(`${t}/api/projects`,{headers:{Authorization:`Bearer ${s}`}});if(!n.ok)throw n.status===401&&(console.log(`
|
|
109
|
+
\u274C \uC778\uC99D\uC774 \uB9CC\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`),console.log(" metadatafy login \uC73C\uB85C \uB2E4\uC2DC \uB85C\uADF8\uC778\uD558\uC138\uC694."),u(),process.exit(1)),new Error(`HTTP ${n.status}`);let r=(await n.json()).projects||[];if(r.length===0){console.log(`
|
|
110
|
+
\u26A0\uFE0F \uC5F0\uACB0\uD560 \uC218 \uC788\uB294 \uD504\uB85C\uC81D\uD2B8\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.`),console.log(" \uC11C\uBC84\uC5D0\uC11C \uBA3C\uC800 \uD504\uB85C\uC81D\uD2B8\uB97C \uC0DD\uC131\uD558\uC138\uC694."),u();return}console.log(`
|
|
111
|
+
\u{1F4E6} \uC5F0\uACB0\uD560 \uD504\uB85C\uC81D\uD2B8\uB97C \uC120\uD0DD\uD558\uC138\uC694:
|
|
112
|
+
`),r.forEach((f,k)=>{console.log(` ${k+1}) ${f.name}`);});let i=await y(`
|
|
113
|
+
\uC120\uD0DD [1-${r.length}]: `),c=parseInt(i.trim(),10)-1;(isNaN(c)||c<0||c>=r.length)&&(console.log(`
|
|
114
|
+
\u274C \uC798\uBABB\uB41C \uC120\uD0DD\uC785\uB2C8\uB2E4.`),u(),process.exit(1));let l=r[c],g=m__namespace.join(e,"metadata.config.json"),p={};try{let f=await h__namespace.readFile(g,"utf-8");p=JSON.parse(f);}catch{}p.projectId=l.name,p.projectUuid=l.id,await h__namespace.writeFile(g,JSON.stringify(p,null,2)),console.log(`
|
|
115
|
+
\u2705 \uD504\uB85C\uC81D\uD2B8 \uC5F0\uACB0 \uC644\uB8CC!`),console.log(` \uD504\uB85C\uC81D\uD2B8: ${l.name}`),console.log(` \uC124\uC815 \uD30C\uC77C: ${m__namespace.relative(e,g)}`),console.log(`
|
|
116
|
+
\u{1F4A1} \uC774\uC81C metadatafy analyze --upload \uB85C \uC5C5\uB85C\uB4DC\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.
|
|
117
|
+
`);}catch(n){console.error(`
|
|
118
|
+
\u274C \uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D \uC870\uD68C \uC2E4\uD328: ${n instanceof Error?n.message:n}`),process.exit(1);}finally{u();}}async function Ue(e){let{values:o}=util.parseArgs({args:e,options:{output:{type:"string",short:"o"},config:{type:"string",short:"c"},upload:{type:"boolean"},verbose:{type:"boolean"},help:{type:"boolean",short:"h"}}});o.help&&(console.log(me),process.exit(0));let t=process.cwd(),s=o.output||"project-metadata.json",n=o.verbose||false,a={};if(o.config)try{let g=await h__namespace.readFile(o.config,"utf-8");a=JSON.parse(g);}catch{console.error(`Failed to load config file: ${o.config}`),process.exit(1);}else {let g=m__namespace.join(t,"metadata.config.json");try{let p=await h__namespace.readFile(g,"utf-8");a=JSON.parse(p),n&&console.log(`Loaded config from ${g}`);}catch{}}let r=a.projectId||m__namespace.basename(t),i=chunkCY7QWWFH_cjs.d({...a,projectId:r,verbose:n,output:{file:{enabled:true,path:s}}});console.log(`
|
|
119
|
+
\u{1F4E6} Analyzing project: ${r}`),console.log(`\u{1F4C1} Root directory: ${t}
|
|
120
|
+
`);let c=new chunkCY7QWWFH_cjs.y(i),l=new chunkCY7QWWFH_cjs.z(i);try{let g=Date.now(),p=await c.analyze(t),f=Date.now()-g,k=m__namespace.resolve(t,s);await l.write(p,k),console.log(`\u2705 Analysis completed in ${f}ms
|
|
121
|
+
`),console.log("\u{1F4CA} Results:"),console.log(` Total files: ${p.stats.totalFiles}`),console.log(` - Routes: ${p.stats.byType.route}`),console.log(` - Components: ${p.stats.byType.component}`),console.log(` - Hooks: ${p.stats.byType.hook}`),console.log(` - Services: ${p.stats.byType.service}`),console.log(` - APIs: ${p.stats.byType.api}`),console.log(` - Tables: ${p.stats.byType.table}`),console.log(` - Utilities: ${p.stats.byType.utility}`),console.log(`
|
|
122
|
+
\u{1F4C4} Output: ${k}`),p.stats.parseErrors.length>0&&(console.log(`
|
|
123
|
+
\u26A0\uFE0F Parse errors (${p.stats.parseErrors.length}):`),p.stats.parseErrors.slice(0,5).forEach(w=>{console.log(` - ${w}`);}),p.stats.parseErrors.length>5&&console.log(` ... and ${p.stats.parseErrors.length-5} more`)),o.upload&&(console.log(""),await re(a.projectUuid,p,n)),console.log("");}catch(g){console.error("\u274C Analysis failed:",g),process.exit(1);}}async function Re(e){let{values:o}=util.parseArgs({args:e,options:{input:{type:"string",short:"i"},config:{type:"string",short:"c"},verbose:{type:"boolean"},help:{type:"boolean",short:"h"}}});o.help&&(console.log(ye),process.exit(0));let t=process.cwd(),s=o.input||"project-metadata.json",n=o.verbose||false,a={};if(o.config)try{let c=await h__namespace.readFile(o.config,"utf-8");a=JSON.parse(c);}catch{console.error(`Failed to load config file: ${o.config}`),process.exit(1);}else {let c=m__namespace.join(t,"metadata.config.json");try{let l=await h__namespace.readFile(c,"utf-8");a=JSON.parse(l),n&&console.log(`Loaded config from ${c}`);}catch{}}let r=m__namespace.resolve(t,s),i;try{let c=await h__namespace.readFile(r,"utf-8");i=JSON.parse(c);}catch{console.error(`\u274C \uBA54\uD0C0\uB370\uC774\uD130 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${r}`),console.log(" metadatafy analyze \uB85C \uBA3C\uC800 \uBD84\uC11D\uC744 \uC2E4\uD589\uD558\uC138\uC694."),process.exit(1);}console.log(`
|
|
124
|
+
\u{1F4E4} Uploading metadata from: ${r}`),await re(a.projectUuid,i);}async function re(e,o,t){let s=x(),n=oe();if(n?.provider==="supabase"&&n.supabaseUrl){console.log("\u{1F504} Supabase\uC5D0 \uC5C5\uB85C\uB4DC \uC911..."),await Ne(n,e,o);return}if(s.api?.serverUrl||!n){T()||(console.error("\u274C \uB85C\uADF8\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4."),console.log(" metadatafy login \uC73C\uB85C \uBA3C\uC800 \uB85C\uADF8\uC778\uD558\uC138\uC694."),process.exit(1)),e||(console.error("\u274C \uD504\uB85C\uC81D\uD2B8\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4."),console.log(" metadatafy init \uC73C\uB85C \uD504\uB85C\uC81D\uD2B8\uB97C \uC120\uD0DD\uD558\uC138\uC694."),process.exit(1)),console.log("\u{1F504} \uC11C\uBC84\uC5D0 \uC5C5\uB85C\uB4DC \uC911..."),await Fe(e,o);return}console.error("\u274C \uC5C5\uB85C\uB4DC \uC124\uC815\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."),console.log(" metadatafy config setup \uC73C\uB85C \uC124\uC815\uD558\uC138\uC694."),process.exit(1);}async function Ne(e,o,t,s){let{supabaseUrl:n,supabaseServiceRoleKey:a,supabaseTable:r}=e;(!n||!a)&&(console.error("\u274C Supabase \uC124\uC815\uC774 \uBD88\uC644\uC804\uD569\uB2C8\uB2E4."),console.log(" metadatafy config setup \uC73C\uB85C \uB2E4\uC2DC \uC124\uC815\uD558\uC138\uC694."),process.exit(1));let i=o||t.projectId,c=r||"code_index";try{let l=await fetch(`${n}/rest/v1/${c}?project_id=eq.${i}`,{method:"DELETE",headers:{apikey:a,Authorization:`Bearer ${a}`}});if(!l.ok&&l.status!==404){let f=await l.text();throw new Error(`Delete failed: ${l.status} - ${f}`)}let g=t.items.map(f=>({project_id:i,file_type:f.type,name:f.name,path:f.path,keywords:f.keywords,search_text:f.searchText,calls:f.calls,called_by:f.calledBy,metadata:f.metadata})),p=await fetch(`${n}/rest/v1/${c}`,{method:"POST",headers:{apikey:a,Authorization:`Bearer ${a}`,"Content-Type":"application/json",Prefer:"return=minimal"},body:JSON.stringify(g)});if(!p.ok){let f=await p.text();throw new Error(`Insert failed: ${f}`)}console.log(`\u2705 \uC5C5\uB85C\uB4DC \uC644\uB8CC! (${t.items.length}\uAC1C \uD30C\uC77C)`);}catch(l){console.error(`\u274C \uC5C5\uB85C\uB4DC \uC2E4\uD328: ${l instanceof Error?l.message:l}`),process.exit(1);}}async function Fe(e,o,t){let s=N(),n=O();n||(console.error("\u274C \uC778\uC99D \uD1A0\uD070\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."),console.log(" metadatafy login \uC73C\uB85C \uB85C\uADF8\uC778\uD558\uC138\uC694."),process.exit(1));try{let a=await fetch(`${s}/api/code-index`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify({projectId:e,items:o.items,stats:o.stats})});if(!a.ok){let i=await a.json().catch(()=>({}));throw new Error(i.error||`HTTP ${a.status}`)}let r=await a.json();console.log(`\u2705 \uC5C5\uB85C\uB4DC \uC644\uB8CC! (${r.count||o.items.length}\uAC1C \uD30C\uC77C)`);}catch(a){console.error(`\u274C \uC5C5\uB85C\uB4DC \uC2E4\uD328: ${a instanceof Error?a.message:a}`),process.exit(1);}}async function ie(){let e=process.cwd(),o=m__namespace.basename(e);console.log(`
|
|
110
125
|
\u{1F680} metadatafy \uC124\uC815 \uB9C8\uBC95\uC0AC
|
|
111
|
-
`),console.log(`\uD3F4\uB354: ${
|
|
112
|
-
\u{1F50D} \uD504\uB85C\uC81D\uD2B8 \uBD84\uC11D \uC911...`);let
|
|
113
|
-
\u2705 \uAC10\uC9C0\uB41C \uC815\uBCF4:`),console.log(` \uD504\uB85C\uC81D\uD2B8 \uD0C0\uC785: ${
|
|
114
|
-
\u{
|
|
126
|
+
`),console.log(`\uD3F4\uB354: ${o}`),console.log(`\uACBD\uB85C: ${e}`),console.log(`
|
|
127
|
+
\u{1F50D} \uD504\uB85C\uC81D\uD2B8 \uBD84\uC11D \uC911...`);let t=await G(e);console.log(`
|
|
128
|
+
\u2705 \uAC10\uC9C0\uB41C \uC815\uBCF4:`),console.log(` \uD504\uB85C\uC81D\uD2B8 \uD0C0\uC785: ${H(t.type)}`),console.log(` \uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800: ${t.packageManager}`),console.log(` TypeScript: ${t.hasTypescript?"\uC608":"\uC544\uB2C8\uC624"}`);let s=x(),n=!!s.api?.serverUrl,a=s.database?.provider==="supabase",r=o,i="";if(a&&!n)console.log(`
|
|
129
|
+
\u{1F4CC} \uD504\uB85C\uC81D\uD2B8 ID \uC124\uC815`),console.log(" Supabase code_index \uD14C\uC774\uBE14\uC758 project_id \uCEEC\uB7FC\uC5D0 \uC800\uC7A5\uB420 \uAC12\uC785\uB2C8\uB2E4."),console.log(` \uC5EC\uB7EC \uD504\uB85C\uC81D\uD2B8\uB97C \uAD6C\uBD84\uD558\uB294 \uB370 \uC0AC\uC6A9\uB429\uB2C8\uB2E4.
|
|
130
|
+
`),r=(await y(`\uD504\uB85C\uC81D\uD2B8 ID [${o}]: `)).trim()||o;else if(n||T()){console.log(`
|
|
131
|
+
\u{1F4CB} \uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D \uC870\uD68C \uC911...`);let c=N(),l=O();if(l)try{let g=await fetch(`${c}/api/projects`,{headers:{Authorization:`Bearer ${l}`}});if(g.ok){let f=(await g.json()).projects;if(f.length>0){console.log(`
|
|
115
132
|
\u{1F4E6} \uC5F0\uACB0\uD560 \uD504\uB85C\uC81D\uD2B8\uB97C \uC120\uD0DD\uD558\uC138\uC694:
|
|
116
|
-
`),
|
|
117
|
-
\uC120\uD0DD [1-${
|
|
118
|
-
\u2705 \uC120\uD0DD\uB428: ${
|
|
119
|
-
\u26A0\uFE0F \uB85C\uADF8\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.`),await
|
|
120
|
-
\u26A0\uFE0F metadata.config.json \uD30C\uC77C\uC774 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4.`),
|
|
133
|
+
`),f.forEach((S,ce)=>{console.log(` ${ce+1}) ${S.name}`);});let k=await y(`
|
|
134
|
+
\uC120\uD0DD [1-${f.length}]: `),w=parseInt(k.trim(),10)-1;if(!isNaN(w)&&w>=0&&w<f.length){let S=f[w];r=S.name,i=S.id,console.log(`
|
|
135
|
+
\u2705 \uC120\uD0DD\uB428: ${S.name}`);}}}}catch{console.log("\u26A0\uFE0F \uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D\uC744 \uAC00\uC838\uC62C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");}else if(console.log(`
|
|
136
|
+
\u26A0\uFE0F \uB85C\uADF8\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.`),await A("\uC9C0\uAE08 \uB85C\uADF8\uC778\uD560\uAE4C\uC694?",true)){u(),await ae(),await ie();return}}try{let c=await V(t.type),l=await W(t.packageManager),g=!1;(c==="vite"||c==="cra")&&(g=await q(c));let p={projectType:c,packageManager:l,projectInfo:t,addBuildIntegration:g,projectUuid:i,projectName:r},f=m__namespace.join(e,"metadata.config.json"),k=!0;try{await h__namespace.access(f),console.log(`
|
|
137
|
+
\u26A0\uFE0F metadata.config.json \uD30C\uC77C\uC774 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4.`),k=await A("\uB36E\uC5B4\uC4F8\uAE4C\uC694?",!1);}catch{}if(console.log(`
|
|
121
138
|
\u{1F4DD} \uC124\uC815 \uC801\uC6A9 \uC911...
|
|
122
|
-
`),
|
|
139
|
+
`),k){let w=await Y(e,r,p);console.log(`\u2705 \uC124\uC815 \uD30C\uC77C \uC0DD\uC131: ${m__namespace.relative(e,w)}`);}if(g){let w=await X(e);console.log(w?"\u2705 vite.config \uD30C\uC77C\uC5D0 \uD50C\uB7EC\uADF8\uC778 \uCD94\uAC00\uB428":"\u26A0\uFE0F \uBE4C\uB4DC \uC124\uC815 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC218\uB3D9\uC73C\uB85C \uCD94\uAC00\uD574\uC8FC\uC138\uC694.");}console.log(`
|
|
123
140
|
\u{1F389} \uC124\uC815\uC774 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4!
|
|
124
|
-
`),!n&&!
|
|
141
|
+
`),!n&&!a&&(console.log("\u{1F4A1} \uC5C5\uB85C\uB4DC\uB97C \uC0AC\uC6A9\uD558\uB824\uBA74 \uAE00\uB85C\uBC8C \uC124\uC815\uC744 \uC644\uB8CC\uD558\uC138\uC694:"),console.log(` metadatafy config setup
|
|
125
142
|
`)),console.log(`\u{1F4A1} \uC0AC\uC6A9\uBC95:
|
|
126
|
-
`),console.log(" metadatafy analyze # \uBD84\uC11D (\uB85C\uCEEC \uD30C\uC77C \uC0DD\uC131)"),console.log(" metadatafy analyze --upload # \uBD84\uC11D + \uC5C5\uB85C\uB4DC"),console.log("");}finally{
|
|
143
|
+
`),console.log(" metadatafy analyze # \uBD84\uC11D (\uB85C\uCEEC \uD30C\uC77C \uC0DD\uC131)"),console.log(" metadatafy analyze --upload # \uBD84\uC11D + \uC5C5\uB85C\uB4DC"),console.log("");}finally{u();}}he().catch(e=>{console.error("Fatal error:",e),process.exit(1);});
|
package/dist/cli.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {d,y as y$1,z}from'./chunk-ZKXUE22E.js';import {parseArgs}from'util';import*as m from'path';import*as
|
|
3
|
-
\u{1F4E6} \uD504\uB85C\uC81D\uD2B8 \uD0C0\uC785\uC744 \uC120\uD0DD\uD558\uC138\uC694:`),
|
|
4
|
-
\uC120\uD0DD [${s}]: `)).trim()||s;return
|
|
5
|
-
\u{1F4E6} \uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800\uB97C \uC120\uD0DD\uD558\uC138\uC694:`),
|
|
6
|
-
\uC120\uD0DD [${s}]: `)).trim()||s;return
|
|
2
|
+
import {d as d$1,y as y$1,z}from'./chunk-ZKXUE22E.js';import {parseArgs}from'util';import*as m from'path';import*as h from'fs/promises';import*as K from'readline';import*as d from'fs';import*as Z from'os';async function le(e){let o=[{file:"pnpm-lock.yaml",manager:"pnpm"},{file:"yarn.lock",manager:"yarn"},{file:"package-lock.json",manager:"npm"}];for(let{file:t,manager:s}of o)try{return await h.access(m.join(e,t)),s}catch{}return "npm"}async function pe(e){let o={};try{let s=await h.readFile(m.join(e,"package.json"),"utf-8");o=JSON.parse(s);}catch{return "unknown"}let t={...o.dependencies||{},...o.devDependencies||{}};return t.next?await $(m.join(e,"app"))||await $(m.join(e,"src","app"))?"nextjs-app":"nextjs-pages":t.vite?"vite":t["react-scripts"]?"cra":t.express||t.fastify||t.koa?"node":"unknown"}async function G(e){let[o,t]=await Promise.all([pe(e),le(e)]),s=await fe(m.join(e,"tsconfig.json")),n=await $(m.join(e,"src")),a=["app","pages","components","hooks","services","lib","utils","api","src/app","src/pages","src/components","src/hooks","src/services","src/lib","src/utils"],r=[];for(let l of a)await $(m.join(e,l))&&r.push(l);let i=await $(m.join(e,"prisma")),c=await $(m.join(e,"supabase"));return {type:o,packageManager:t,hasTypescript:s,hasSrc:n,existingFolders:r,hasPrisma:i,hasSupabase:c}}async function fe(e){try{return (await h.stat(e)).isFile()}catch{return false}}async function $(e){try{return (await h.stat(e)).isDirectory()}catch{return false}}function H(e){return {"nextjs-app":"Next.js (App Router)","nextjs-pages":"Next.js (Pages Router)",vite:"Vite + React",cra:"Create React App",node:"Node.js Backend",unknown:"Unknown"}[e]}var P=null;function ge(){return P||(P=K.createInterface({input:process.stdin,output:process.stdout,terminal:false})),P}function y(e){return new Promise(o=>{process.stdout.write(e),ge().once("line",t=>{o(t);});})}function u(){P&&(P.close(),P=null);}async function V(e){let o=[{key:"1",type:"nextjs-app",label:"Next.js (App Router)"},{key:"2",type:"nextjs-pages",label:"Next.js (Pages Router)"},{key:"3",type:"vite",label:"Vite + React"},{key:"4",type:"cra",label:"Create React App"},{key:"5",type:"node",label:"Node.js Backend"}],t=o.findIndex(i=>i.type===e),s=t>=0?o[t].key:"1";console.log(`
|
|
3
|
+
\u{1F4E6} \uD504\uB85C\uC81D\uD2B8 \uD0C0\uC785\uC744 \uC120\uD0DD\uD558\uC138\uC694:`),o.forEach(i=>{let l=i.type===e?" (\uAC10\uC9C0\uB428)":"";console.log(` ${i.key}) ${i.label}${l}`);});let a=(await y(`
|
|
4
|
+
\uC120\uD0DD [${s}]: `)).trim()||s;return o.find(i=>i.key===a)?.type||e}async function W(e){let o=[{key:"1",manager:"npm"},{key:"2",manager:"yarn"},{key:"3",manager:"pnpm"}],t=o.findIndex(i=>i.manager===e),s=t>=0?o[t].key:"1";console.log(`
|
|
5
|
+
\u{1F4E6} \uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800\uB97C \uC120\uD0DD\uD558\uC138\uC694:`),o.forEach(i=>{let l=i.manager===e?" (\uAC10\uC9C0\uB428)":"";console.log(` ${i.key}) ${i.manager}${l}`);});let a=(await y(`
|
|
6
|
+
\uC120\uD0DD [${s}]: `)).trim()||s;return o.find(i=>i.key===a)?.manager||e}async function q(e){return e==="node"||e==="unknown"||e.startsWith("nextjs")?false:(console.log(`
|
|
7
7
|
\u{1F527} vite.config \uD30C\uC77C\uC5D0 metadatafy \uD50C\uB7EC\uADF8\uC778\uC744 \uC790\uB3D9\uC73C\uB85C \uCD94\uAC00\uD560\uAE4C\uC694?`),console.log(" \uBE4C\uB4DC \uC2DC \uC790\uB3D9\uC73C\uB85C \uBA54\uD0C0\uB370\uC774\uD130\uAC00 \uC0DD\uC131\uB429\uB2C8\uB2E4."),(await y(`
|
|
8
|
-
\uCD94\uAC00\uD560\uAE4C\uC694? [Y/n]: `)).trim().toLowerCase()!=="n")}async function
|
|
9
|
-
`;return n.includes("from 'vite'")?n=n.replace(/^(import .+ from ['"]vite['"];?\n)/m,`$1${
|
|
8
|
+
\uCD94\uAC00\uD560\uAE4C\uC694? [Y/n]: `)).trim().toLowerCase()!=="n")}async function A(e,o=true){let n=(await y(`${e} ${o?"[Y/n]":"[y/N]"}: `)).trim().toLowerCase();return n===""?o:n==="y"||n==="yes"}function ue(e){let{projectType:o,projectInfo:t}=e,s=[],n=t.hasTypescript?"{ts,tsx}":"{js,jsx}";switch(o){case "nextjs-app":t.hasSrc?s.push(`src/app/**/*.${n}`):s.push(`app/**/*.${n}`),s.push(`components/**/*.${n}`),s.push(`hooks/**/*.${n}`),s.push(`lib/**/*.${n}`);break;case "nextjs-pages":t.hasSrc?s.push(`src/pages/**/*.${n}`):s.push(`pages/**/*.${n}`),s.push(`components/**/*.${n}`),s.push(`hooks/**/*.${n}`),s.push(`lib/**/*.${n}`);break;case "vite":case "cra":s.push(`src/**/*.${n}`);break;case "node":s.push(`src/**/*.${t.hasTypescript?"ts":"js"}`),s.push(`routes/**/*.${t.hasTypescript?"ts":"js"}`),s.push(`controllers/**/*.${t.hasTypescript?"ts":"js"}`);break;default:s.push(`src/**/*.${n}`);}return t.hasPrisma&&s.push("prisma/migrations/**/*.sql"),t.hasSupabase&&s.push("supabase/migrations/*.sql"),s}async function Y(e,o,t){let s=m.join(e,"metadata.config.json"),n={projectId:o,projectUuid:t.projectUuid,projectName:t.projectName,include:ue(t),exclude:["**/node_modules/**","**/.next/**","**/dist/**","**/build/**","**/*.test.{ts,tsx,js,jsx}","**/*.spec.{ts,tsx,js,jsx}","**/__tests__/**"],output:{file:{enabled:true,path:"project-metadata.json"}},koreanKeywords:{},verbose:false};return await h.writeFile(s,JSON.stringify(n,null,2)),s}async function X(e){let o=["vite.config.ts","vite.config.js","vite.config.mts","vite.config.mjs"];for(let t of o){let s=m.join(e,t);try{let n=await h.readFile(s,"utf-8");if(n.includes("metadatafy"))return !0;let a=`import metadatafy from 'metadatafy/vite';
|
|
9
|
+
`;return n.includes("from 'vite'")?n=n.replace(/^(import .+ from ['"]vite['"];?\n)/m,`$1${a}`):n=a+n,n.includes("plugins:")?n=n.replace(/plugins:\s*\[/,`plugins: [
|
|
10
10
|
metadatafy(),`):n.includes("defineConfig(")&&(n=n.replace(/defineConfig\(\{/,`defineConfig({
|
|
11
|
-
plugins: [metadatafy()],`)),await
|
|
11
|
+
plugins: [metadatafy()],`)),await h.writeFile(s,n),!0}catch{}}return false}var U=m.join(Z.homedir(),".metadatafy"),E=m.join(U,"config.json"),R=m.join(U,"auth.json");function Q(){d.existsSync(U)||d.mkdirSync(U,{mode:448});}function x(){try{if(!d.existsSync(E))return {};let e=d.readFileSync(E,"utf-8");return JSON.parse(e)}catch{return {}}}function v(e){Q(),d.writeFileSync(E,JSON.stringify(e,null,2),{mode:384});}function I(){try{if(!d.existsSync(R))return null;let e=d.readFileSync(R,"utf-8"),o=JSON.parse(e);return o.expiresAt&&new Date(o.expiresAt)<new Date?(console.log("\u26A0\uFE0F \uC778\uC99D\uC774 \uB9CC\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uB85C\uADF8\uC778\uD558\uC138\uC694."),null):o}catch{return null}}function ee(e){Q(),d.writeFileSync(R,JSON.stringify(e,null,2),{mode:384});}function M(){d.existsSync(R)&&d.unlinkSync(R);}function T(){let e=I();return e!==null&&!!e.accessToken}function O(){return I()?.accessToken||null}function L(){return U}function oe(){let e=x();return e.database?.provider?e.database:null}function N(){return x().api?.serverUrl||"https://management.impakers.club"}var de="1.5.1",te=`
|
|
12
12
|
metadatafy - \uD504\uB85C\uC81D\uD2B8 \uBA54\uD0C0\uB370\uC774\uD130 \uCD94\uCD9C \uB3C4\uAD6C
|
|
13
13
|
|
|
14
14
|
Usage:
|
|
@@ -16,6 +16,7 @@ Usage:
|
|
|
16
16
|
|
|
17
17
|
Commands:
|
|
18
18
|
init \uD504\uB85C\uC81D\uD2B8 \uC124\uC815 \uCD08\uAE30\uD654
|
|
19
|
+
link API \uC11C\uBC84\uC758 \uD504\uB85C\uC81D\uD2B8\uC640 \uC5F0\uACB0
|
|
19
20
|
analyze \uD504\uB85C\uC81D\uD2B8\uB97C \uBD84\uC11D\uD558\uACE0 \uBA54\uD0C0\uB370\uC774\uD130 \uC0DD\uC131
|
|
20
21
|
upload \uAE30\uC874 \uBA54\uD0C0\uB370\uC774\uD130 \uD30C\uC77C\uC744 \uC5C5\uB85C\uB4DC
|
|
21
22
|
|
|
@@ -35,10 +36,11 @@ Options:
|
|
|
35
36
|
|
|
36
37
|
Examples:
|
|
37
38
|
metadatafy init # \uD504\uB85C\uC81D\uD2B8 \uC124\uC815
|
|
39
|
+
metadatafy link # \uC11C\uBC84 \uD504\uB85C\uC81D\uD2B8 \uC5F0\uACB0
|
|
38
40
|
metadatafy analyze # \uBD84\uC11D (\uB85C\uCEEC \uD30C\uC77C \uC0DD\uC131)
|
|
39
41
|
metadatafy analyze --upload # \uBD84\uC11D + \uC5C5\uB85C\uB4DC
|
|
40
42
|
metadatafy config setup # DB \uC5F0\uACB0 \uC124\uC815
|
|
41
|
-
`,
|
|
43
|
+
`,ne=`
|
|
42
44
|
Usage: metadatafy config <subcommand>
|
|
43
45
|
|
|
44
46
|
Subcommands:
|
|
@@ -52,7 +54,7 @@ Examples:
|
|
|
52
54
|
metadatafy config setup
|
|
53
55
|
metadatafy config set database.provider supabase
|
|
54
56
|
metadatafy config set api.serverUrl https://my-server.com
|
|
55
|
-
`,
|
|
57
|
+
`,me=`
|
|
56
58
|
Usage: metadatafy analyze [options]
|
|
57
59
|
|
|
58
60
|
Options:
|
|
@@ -61,7 +63,7 @@ Options:
|
|
|
61
63
|
--upload \uC5C5\uB85C\uB4DC \uC2E4\uD589 (\uAE00\uB85C\uBC8C config \uB610\uB294 API \uC11C\uBC84)
|
|
62
64
|
--verbose \uC0C1\uC138 \uB85C\uADF8 \uCD9C\uB825
|
|
63
65
|
-h, --help \uB3C4\uC6C0\uB9D0 \uD45C\uC2DC
|
|
64
|
-
`,
|
|
66
|
+
`,ye=`
|
|
65
67
|
Usage: metadatafy upload [options]
|
|
66
68
|
|
|
67
69
|
\uAE30\uC874 \uBA54\uD0C0\uB370\uC774\uD130 JSON \uD30C\uC77C\uC744 \uC5C5\uB85C\uB4DC\uD569\uB2C8\uB2E4.
|
|
@@ -72,55 +74,70 @@ Options:
|
|
|
72
74
|
-c, --config <path> \uC124\uC815 \uD30C\uC77C \uACBD\uB85C
|
|
73
75
|
--verbose \uC0C1\uC138 \uB85C\uADF8 \uCD9C\uB825
|
|
74
76
|
-h, --help \uB3C4\uC6C0\uB9D0 \uD45C\uC2DC
|
|
75
|
-
`;async function
|
|
76
|
-
\u{1F4C1} \uC124\uC815 \uC704\uCE58: ${
|
|
77
|
-
`),Object.keys(e).length===0){console.log("\uC124\uC815\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. metadatafy config setup \uC73C\uB85C \uC124\uC815\uD558\uC138\uC694.");return}console.log("\uD604\uC7AC \uC124\uC815:"),console.log(JSON.stringify(e,null,2));let
|
|
78
|
-
\u{1F510} \uC778\uC99D \uC0C1\uD0DC: \uB85C\uADF8\uC778\uB428`),
|
|
77
|
+
`;async function he(){let e=process.argv.slice(2);(e.length===0||e[0]==="-h"||e[0]==="--help")&&(console.log(te),process.exit(0)),(e[0]==="-v"||e[0]==="--version")&&(console.log(de),process.exit(0));let o=e[0];switch(o){case "config":await we(e.slice(1));break;case "login":await ae();break;case "logout":await Se();break;case "whoami":await Ae();break;case "analyze":await Ue(e.slice(1));break;case "upload":await Re(e.slice(1));break;case "init":await ie();break;case "link":await Ce();break;default:console.error(`Unknown command: ${o}`),console.log(te),process.exit(1);}}async function we(e){let o=e[0];if(!o||o==="-h"||o==="--help"){console.log(ne);return}switch(o){case "show":await be();break;case "setup":await ke();break;case "set":await Pe(e.slice(1));break;case "reset":await ve();break;default:console.error(`Unknown config subcommand: ${o}`),console.log(ne),process.exit(1);}}async function be(){let e=x(),o=L();if(console.log(`
|
|
78
|
+
\u{1F4C1} \uC124\uC815 \uC704\uCE58: ${o}
|
|
79
|
+
`),Object.keys(e).length===0){console.log("\uC124\uC815\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. metadatafy config setup \uC73C\uB85C \uC124\uC815\uD558\uC138\uC694.");return}console.log("\uD604\uC7AC \uC124\uC815:"),console.log(JSON.stringify(e,null,2));let t=I();t&&(console.log(`
|
|
80
|
+
\u{1F510} \uC778\uC99D \uC0C1\uD0DC: \uB85C\uADF8\uC778\uB428`),t.serverUrl&&console.log(` \uC11C\uBC84: ${t.serverUrl}`));}async function ke(){console.log(`
|
|
79
81
|
\u2699\uFE0F metadatafy \uAE00\uB85C\uBC8C \uC124\uC815
|
|
80
82
|
`),console.log("\uC774 \uC124\uC815\uC740 ~/.metadatafy/\uC5D0 \uC800\uC7A5\uB429\uB2C8\uB2E4."),console.log(`\uBAA8\uB4E0 \uD504\uB85C\uC81D\uD2B8\uC5D0\uC11C \uACF5\uD1B5\uC73C\uB85C \uC0AC\uC6A9\uB429\uB2C8\uB2E4.
|
|
81
|
-
`);let e=
|
|
82
|
-
`),console.log(" 1) Supabase \uC9C1\uC811 \uC5F0\uACB0"),console.log(" 2) API \uC11C\uBC84 (ticket-ms \uB4F1)"),console.log(" 3) \uB85C\uCEEC \uD30C\uC77C\uB9CC (\uC5C5\uB85C\uB4DC \uC548 \uD568)");let
|
|
83
|
-
\uC120\uD0DD [1-3]: `);
|
|
84
|
-
\u2705 \uB85C\uCEEC \uD30C\uC77C \uBAA8\uB4DC\uB85C \uC124\uC815\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`)),
|
|
85
|
-
\u{1F389} \uC124\uC815\uC774 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4!`),console.log(` \uC800\uC7A5 \uC704\uCE58: ${
|
|
86
|
-
`);}async function
|
|
83
|
+
`);let e=x();console.log(`\u{1F4E4} \uBA54\uD0C0\uB370\uC774\uD130 \uC5C5\uB85C\uB4DC \uBC29\uC2DD\uC744 \uC120\uD0DD\uD558\uC138\uC694:
|
|
84
|
+
`),console.log(" 1) Supabase \uC9C1\uC811 \uC5F0\uACB0"),console.log(" 2) API \uC11C\uBC84 (ticket-ms \uB4F1)"),console.log(" 3) \uB85C\uCEEC \uD30C\uC77C\uB9CC (\uC5C5\uB85C\uB4DC \uC548 \uD568)");let o=await y(`
|
|
85
|
+
\uC120\uD0DD [1-3]: `);o==="1"?await xe(e):o==="2"?await je(e):(e.database=void 0,e.api=void 0,v(e),console.log(`
|
|
86
|
+
\u2705 \uB85C\uCEEC \uD30C\uC77C \uBAA8\uB4DC\uB85C \uC124\uC815\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`)),u(),console.log(`
|
|
87
|
+
\u{1F389} \uC124\uC815\uC774 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4!`),console.log(` \uC800\uC7A5 \uC704\uCE58: ${L()}/config.json
|
|
88
|
+
`);}async function xe(e){console.log(`
|
|
87
89
|
\u{1F5C4}\uFE0F Supabase \uC124\uC815
|
|
88
90
|
`),console.log("Supabase \uB300\uC2DC\uBCF4\uB4DC\uC5D0\uC11C \uB2E4\uC74C \uC815\uBCF4\uB97C \uD655\uC778\uD558\uC138\uC694:"),console.log(`Settings > API > Project URL, service_role key
|
|
89
|
-
`);let
|
|
90
|
-
\u2705 Supabase \uC124\uC815\uC774 \uC800\uC7A5\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`)
|
|
91
|
+
`);let o=await y("Supabase URL: "),t=await $e("Service Role Key: "),s=await y("\uD14C\uC774\uBE14 \uC774\uB984 [code_index]: ");e.database={provider:"supabase",supabaseUrl:o.trim(),supabaseServiceRoleKey:t,supabaseTable:s.trim()||"code_index"},v(e),console.log(`
|
|
92
|
+
\u2705 Supabase \uC124\uC815\uC774 \uC800\uC7A5\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`),console.log(`
|
|
93
|
+
\u{1F4A1} \uAC01 \uD504\uB85C\uC81D\uD2B8\uC5D0\uC11C metadatafy init \uC73C\uB85C \uD504\uB85C\uC81D\uD2B8 ID\uB97C \uC124\uC815\uD558\uC138\uC694.`);}async function je(e){console.log(`
|
|
91
94
|
\u{1F310} API \uC11C\uBC84 \uC124\uC815
|
|
92
|
-
`);let
|
|
95
|
+
`);let o=e.api?.serverUrl||"https://management.impakers.club",t=await y(`\uC11C\uBC84 URL [${o}]: `);e.api={serverUrl:t.trim()||o},console.log(`
|
|
93
96
|
\u{1F4A1} API \uC11C\uBC84 \uC0AC\uC6A9 \uC2DC \uB85C\uADF8\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.`),console.log(" metadatafy login \uC73C\uB85C \uB85C\uADF8\uC778\uD558\uC138\uC694."),v(e),console.log(`
|
|
94
|
-
\u2705 API \uC11C\uBC84 \uC124\uC815\uC774 \uC800\uC7A5\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`);}function
|
|
95
|
-
`:case "\r":case "":
|
|
96
|
-
`),
|
|
97
|
-
Examples:`),console.log(" metadatafy config set database.provider supabase"),console.log(" metadatafy config set api.serverUrl https://my-server.com"),process.exit(1));let[t
|
|
97
|
+
\u2705 API \uC11C\uBC84 \uC124\uC815\uC774 \uC800\uC7A5\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`);}function $e(e){return new Promise(o=>{process.stdout.write(e);let t=process.stdin,s=t.isRaw;t.isTTY&&t.setRawMode(true);let n="",a=r=>{let i=r.toString("utf8");switch(i){case `
|
|
98
|
+
`:case "\r":case "":t.isTTY&&t.setRawMode(s),t.removeListener("data",a),process.stdout.write(`
|
|
99
|
+
`),o(n);break;case "":process.exit();break;case "\x7F":n.length>0&&(n=n.slice(0,-1),process.stdout.clearLine(0),process.stdout.cursorTo(0),process.stdout.write(e+"*".repeat(n.length)));break;default:n+=i,process.stdout.write("*");break}};t.on("data",a),t.resume();})}async function Pe(e){e.length<2&&(console.error("Usage: metadatafy config set <key> <value>"),console.log(`
|
|
100
|
+
Examples:`),console.log(" metadatafy config set database.provider supabase"),console.log(" metadatafy config set api.serverUrl https://my-server.com"),process.exit(1));let[o,...t]=e,s=t.join(" "),n=x(),a=o.split("."),r=n;for(let i=0;i<a.length-1;i++){let c=a[i];(!r[c]||typeof r[c]!="object")&&(r[c]={}),r=r[c];}r[a[a.length-1]]=s,v(n),console.log(`\u2705 ${o} = ${s}`);}async function ve(){let e=await A("\uBAA8\uB4E0 \uC124\uC815\uC744 \uCD08\uAE30\uD654\uD560\uAE4C\uC694?",false);if(u(),!e){console.log("\uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");return}v({}),M(),console.log("\u2705 \uBAA8\uB4E0 \uC124\uC815\uC774 \uCD08\uAE30\uD654\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");}async function ae(){let e=N();if(T()){let n=I();if(console.log(`\uC774\uBBF8 \uB85C\uADF8\uC778\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4. (${n?.serverUrl||e})`),!await A("\uB2E4\uC2DC \uB85C\uADF8\uC778\uD560\uAE4C\uC694?",false)){u();return}}console.log(`
|
|
98
101
|
\u{1F510} \uB85C\uADF8\uC778 (${e})
|
|
99
|
-
`);let
|
|
100
|
-
\u{1F310} \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uC778\uC99D\uC744 \uC644\uB8CC\uD558\uC138\uC694.`),console.log(` ${
|
|
101
|
-
`),await
|
|
102
|
-
\u274C \uC778\uC99D \uC2DC\uAC04\uC774 \uCD08\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694.`),
|
|
103
|
-
\u2705 \uB85C\uADF8\uC778 \uC131\uACF5!`),
|
|
104
|
-
\u{
|
|
105
|
-
`)
|
|
106
|
-
|
|
107
|
-
\
|
|
108
|
-
\
|
|
109
|
-
|
|
102
|
+
`);let o=crypto.randomUUID();console.log("\u{1F504} \uC778\uC99D \uC900\uBE44 \uC911...");try{let n=await fetch(`${e}/api/auth/device`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({deviceCode:o})});if(!n.ok)throw new Error(`HTTP ${n.status}`)}catch{console.error("\u274C \uC11C\uBC84 \uC5F0\uACB0\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4."),console.log(` ${e}/api/auth/device`),u(),process.exit(1);}let t=`${e}/auth/device?code=${o}`;console.log(`
|
|
103
|
+
\u{1F310} \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uC778\uC99D\uC744 \uC644\uB8CC\uD558\uC138\uC694.`),console.log(` ${t}
|
|
104
|
+
`),await Ie(t),console.log("\u23F3 \uC778\uC99D \uB300\uAE30 \uC911... (\uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uB85C\uADF8\uC778\uD558\uC138\uC694)");let s=await Te(e,o);s||(console.error(`
|
|
105
|
+
\u274C \uC778\uC99D \uC2DC\uAC04\uC774 \uCD08\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694.`),u(),process.exit(1)),ee({accessToken:s.accessToken,expiresAt:s.expiresAt,userId:s.userId,serverUrl:e}),console.log(`
|
|
106
|
+
\u2705 \uB85C\uADF8\uC778 \uC131\uACF5!`),u();}async function Ie(e){let{exec:o}=await import('child_process'),t=process.platform,s=t==="darwin"?`open "${e}"`:t==="win32"?`start "${e}"`:`xdg-open "${e}"`;o(s);}async function Te(e,o){let n=Date.now();for(;Date.now()-n<3e5;)try{let a=await fetch(`${e}/api/auth/device/status?code=${o}`);if(!a.ok){await _(2e3);continue}let r=await a.json();if(r.status==="authorized"&&r.accessToken)return {accessToken:r.accessToken,expiresAt:r.expiresAt||new Date(Date.now()+720*60*60*1e3).toISOString(),userId:r.userId};if(r.status==="expired")return null;await _(2e3);}catch{await _(2e3);}return null}function _(e){return new Promise(o=>setTimeout(o,e))}async function Se(){if(!T()){console.log("\uB85C\uADF8\uC778\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");return}M(),console.log("\u2705 \uB85C\uADF8\uC544\uC6C3\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");}async function Ae(){let e=I();if(!e){console.log("\uB85C\uADF8\uC778\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4."),console.log("metadatafy login \uC73C\uB85C \uB85C\uADF8\uC778\uD558\uC138\uC694.");return}console.log("\u2705 \uB85C\uADF8\uC778\uB428"),e.serverUrl&&console.log(` \uC11C\uBC84: ${e.serverUrl}`),e.userId&&console.log(` User ID: ${e.userId}`),e.expiresAt&&console.log(` \uB9CC\uB8CC: ${new Date(e.expiresAt).toLocaleString()}`);}async function Ce(){let e=process.cwd();m.basename(e);console.log(`
|
|
107
|
+
\u{1F517} \uD504\uB85C\uC81D\uD2B8 \uC5F0\uACB0
|
|
108
|
+
`),T()||(console.log("\u274C \uB85C\uADF8\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4."),console.log(" metadatafy login \uC73C\uB85C \uBA3C\uC800 \uB85C\uADF8\uC778\uD558\uC138\uC694."),u(),process.exit(1));let t=N(),s=O();s||(console.log("\u274C \uC778\uC99D \uD1A0\uD070\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."),console.log(" metadatafy login \uC73C\uB85C \uB85C\uADF8\uC778\uD558\uC138\uC694."),u(),process.exit(1)),console.log("\u{1F4CB} \uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D \uC870\uD68C \uC911...");try{let n=await fetch(`${t}/api/projects`,{headers:{Authorization:`Bearer ${s}`}});if(!n.ok)throw n.status===401&&(console.log(`
|
|
109
|
+
\u274C \uC778\uC99D\uC774 \uB9CC\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`),console.log(" metadatafy login \uC73C\uB85C \uB2E4\uC2DC \uB85C\uADF8\uC778\uD558\uC138\uC694."),u(),process.exit(1)),new Error(`HTTP ${n.status}`);let r=(await n.json()).projects||[];if(r.length===0){console.log(`
|
|
110
|
+
\u26A0\uFE0F \uC5F0\uACB0\uD560 \uC218 \uC788\uB294 \uD504\uB85C\uC81D\uD2B8\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.`),console.log(" \uC11C\uBC84\uC5D0\uC11C \uBA3C\uC800 \uD504\uB85C\uC81D\uD2B8\uB97C \uC0DD\uC131\uD558\uC138\uC694."),u();return}console.log(`
|
|
111
|
+
\u{1F4E6} \uC5F0\uACB0\uD560 \uD504\uB85C\uC81D\uD2B8\uB97C \uC120\uD0DD\uD558\uC138\uC694:
|
|
112
|
+
`),r.forEach((f,k)=>{console.log(` ${k+1}) ${f.name}`);});let i=await y(`
|
|
113
|
+
\uC120\uD0DD [1-${r.length}]: `),c=parseInt(i.trim(),10)-1;(isNaN(c)||c<0||c>=r.length)&&(console.log(`
|
|
114
|
+
\u274C \uC798\uBABB\uB41C \uC120\uD0DD\uC785\uB2C8\uB2E4.`),u(),process.exit(1));let l=r[c],g=m.join(e,"metadata.config.json"),p={};try{let f=await h.readFile(g,"utf-8");p=JSON.parse(f);}catch{}p.projectId=l.name,p.projectUuid=l.id,await h.writeFile(g,JSON.stringify(p,null,2)),console.log(`
|
|
115
|
+
\u2705 \uD504\uB85C\uC81D\uD2B8 \uC5F0\uACB0 \uC644\uB8CC!`),console.log(` \uD504\uB85C\uC81D\uD2B8: ${l.name}`),console.log(` \uC124\uC815 \uD30C\uC77C: ${m.relative(e,g)}`),console.log(`
|
|
116
|
+
\u{1F4A1} \uC774\uC81C metadatafy analyze --upload \uB85C \uC5C5\uB85C\uB4DC\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.
|
|
117
|
+
`);}catch(n){console.error(`
|
|
118
|
+
\u274C \uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D \uC870\uD68C \uC2E4\uD328: ${n instanceof Error?n.message:n}`),process.exit(1);}finally{u();}}async function Ue(e){let{values:o}=parseArgs({args:e,options:{output:{type:"string",short:"o"},config:{type:"string",short:"c"},upload:{type:"boolean"},verbose:{type:"boolean"},help:{type:"boolean",short:"h"}}});o.help&&(console.log(me),process.exit(0));let t=process.cwd(),s=o.output||"project-metadata.json",n=o.verbose||false,a={};if(o.config)try{let g=await h.readFile(o.config,"utf-8");a=JSON.parse(g);}catch{console.error(`Failed to load config file: ${o.config}`),process.exit(1);}else {let g=m.join(t,"metadata.config.json");try{let p=await h.readFile(g,"utf-8");a=JSON.parse(p),n&&console.log(`Loaded config from ${g}`);}catch{}}let r=a.projectId||m.basename(t),i=d$1({...a,projectId:r,verbose:n,output:{file:{enabled:true,path:s}}});console.log(`
|
|
119
|
+
\u{1F4E6} Analyzing project: ${r}`),console.log(`\u{1F4C1} Root directory: ${t}
|
|
120
|
+
`);let c=new y$1(i),l=new z(i);try{let g=Date.now(),p=await c.analyze(t),f=Date.now()-g,k=m.resolve(t,s);await l.write(p,k),console.log(`\u2705 Analysis completed in ${f}ms
|
|
121
|
+
`),console.log("\u{1F4CA} Results:"),console.log(` Total files: ${p.stats.totalFiles}`),console.log(` - Routes: ${p.stats.byType.route}`),console.log(` - Components: ${p.stats.byType.component}`),console.log(` - Hooks: ${p.stats.byType.hook}`),console.log(` - Services: ${p.stats.byType.service}`),console.log(` - APIs: ${p.stats.byType.api}`),console.log(` - Tables: ${p.stats.byType.table}`),console.log(` - Utilities: ${p.stats.byType.utility}`),console.log(`
|
|
122
|
+
\u{1F4C4} Output: ${k}`),p.stats.parseErrors.length>0&&(console.log(`
|
|
123
|
+
\u26A0\uFE0F Parse errors (${p.stats.parseErrors.length}):`),p.stats.parseErrors.slice(0,5).forEach(w=>{console.log(` - ${w}`);}),p.stats.parseErrors.length>5&&console.log(` ... and ${p.stats.parseErrors.length-5} more`)),o.upload&&(console.log(""),await re(a.projectUuid,p,n)),console.log("");}catch(g){console.error("\u274C Analysis failed:",g),process.exit(1);}}async function Re(e){let{values:o}=parseArgs({args:e,options:{input:{type:"string",short:"i"},config:{type:"string",short:"c"},verbose:{type:"boolean"},help:{type:"boolean",short:"h"}}});o.help&&(console.log(ye),process.exit(0));let t=process.cwd(),s=o.input||"project-metadata.json",n=o.verbose||false,a={};if(o.config)try{let c=await h.readFile(o.config,"utf-8");a=JSON.parse(c);}catch{console.error(`Failed to load config file: ${o.config}`),process.exit(1);}else {let c=m.join(t,"metadata.config.json");try{let l=await h.readFile(c,"utf-8");a=JSON.parse(l),n&&console.log(`Loaded config from ${c}`);}catch{}}let r=m.resolve(t,s),i;try{let c=await h.readFile(r,"utf-8");i=JSON.parse(c);}catch{console.error(`\u274C \uBA54\uD0C0\uB370\uC774\uD130 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${r}`),console.log(" metadatafy analyze \uB85C \uBA3C\uC800 \uBD84\uC11D\uC744 \uC2E4\uD589\uD558\uC138\uC694."),process.exit(1);}console.log(`
|
|
124
|
+
\u{1F4E4} Uploading metadata from: ${r}`),await re(a.projectUuid,i);}async function re(e,o,t){let s=x(),n=oe();if(n?.provider==="supabase"&&n.supabaseUrl){console.log("\u{1F504} Supabase\uC5D0 \uC5C5\uB85C\uB4DC \uC911..."),await Ne(n,e,o);return}if(s.api?.serverUrl||!n){T()||(console.error("\u274C \uB85C\uADF8\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4."),console.log(" metadatafy login \uC73C\uB85C \uBA3C\uC800 \uB85C\uADF8\uC778\uD558\uC138\uC694."),process.exit(1)),e||(console.error("\u274C \uD504\uB85C\uC81D\uD2B8\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4."),console.log(" metadatafy init \uC73C\uB85C \uD504\uB85C\uC81D\uD2B8\uB97C \uC120\uD0DD\uD558\uC138\uC694."),process.exit(1)),console.log("\u{1F504} \uC11C\uBC84\uC5D0 \uC5C5\uB85C\uB4DC \uC911..."),await Fe(e,o);return}console.error("\u274C \uC5C5\uB85C\uB4DC \uC124\uC815\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."),console.log(" metadatafy config setup \uC73C\uB85C \uC124\uC815\uD558\uC138\uC694."),process.exit(1);}async function Ne(e,o,t,s){let{supabaseUrl:n,supabaseServiceRoleKey:a,supabaseTable:r}=e;(!n||!a)&&(console.error("\u274C Supabase \uC124\uC815\uC774 \uBD88\uC644\uC804\uD569\uB2C8\uB2E4."),console.log(" metadatafy config setup \uC73C\uB85C \uB2E4\uC2DC \uC124\uC815\uD558\uC138\uC694."),process.exit(1));let i=o||t.projectId,c=r||"code_index";try{let l=await fetch(`${n}/rest/v1/${c}?project_id=eq.${i}`,{method:"DELETE",headers:{apikey:a,Authorization:`Bearer ${a}`}});if(!l.ok&&l.status!==404){let f=await l.text();throw new Error(`Delete failed: ${l.status} - ${f}`)}let g=t.items.map(f=>({project_id:i,file_type:f.type,name:f.name,path:f.path,keywords:f.keywords,search_text:f.searchText,calls:f.calls,called_by:f.calledBy,metadata:f.metadata})),p=await fetch(`${n}/rest/v1/${c}`,{method:"POST",headers:{apikey:a,Authorization:`Bearer ${a}`,"Content-Type":"application/json",Prefer:"return=minimal"},body:JSON.stringify(g)});if(!p.ok){let f=await p.text();throw new Error(`Insert failed: ${f}`)}console.log(`\u2705 \uC5C5\uB85C\uB4DC \uC644\uB8CC! (${t.items.length}\uAC1C \uD30C\uC77C)`);}catch(l){console.error(`\u274C \uC5C5\uB85C\uB4DC \uC2E4\uD328: ${l instanceof Error?l.message:l}`),process.exit(1);}}async function Fe(e,o,t){let s=N(),n=O();n||(console.error("\u274C \uC778\uC99D \uD1A0\uD070\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."),console.log(" metadatafy login \uC73C\uB85C \uB85C\uADF8\uC778\uD558\uC138\uC694."),process.exit(1));try{let a=await fetch(`${s}/api/code-index`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify({projectId:e,items:o.items,stats:o.stats})});if(!a.ok){let i=await a.json().catch(()=>({}));throw new Error(i.error||`HTTP ${a.status}`)}let r=await a.json();console.log(`\u2705 \uC5C5\uB85C\uB4DC \uC644\uB8CC! (${r.count||o.items.length}\uAC1C \uD30C\uC77C)`);}catch(a){console.error(`\u274C \uC5C5\uB85C\uB4DC \uC2E4\uD328: ${a instanceof Error?a.message:a}`),process.exit(1);}}async function ie(){let e=process.cwd(),o=m.basename(e);console.log(`
|
|
110
125
|
\u{1F680} metadatafy \uC124\uC815 \uB9C8\uBC95\uC0AC
|
|
111
|
-
`),console.log(`\uD3F4\uB354: ${
|
|
112
|
-
\u{1F50D} \uD504\uB85C\uC81D\uD2B8 \uBD84\uC11D \uC911...`);let
|
|
113
|
-
\u2705 \uAC10\uC9C0\uB41C \uC815\uBCF4:`),console.log(` \uD504\uB85C\uC81D\uD2B8 \uD0C0\uC785: ${
|
|
114
|
-
\u{
|
|
126
|
+
`),console.log(`\uD3F4\uB354: ${o}`),console.log(`\uACBD\uB85C: ${e}`),console.log(`
|
|
127
|
+
\u{1F50D} \uD504\uB85C\uC81D\uD2B8 \uBD84\uC11D \uC911...`);let t=await G(e);console.log(`
|
|
128
|
+
\u2705 \uAC10\uC9C0\uB41C \uC815\uBCF4:`),console.log(` \uD504\uB85C\uC81D\uD2B8 \uD0C0\uC785: ${H(t.type)}`),console.log(` \uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800: ${t.packageManager}`),console.log(` TypeScript: ${t.hasTypescript?"\uC608":"\uC544\uB2C8\uC624"}`);let s=x(),n=!!s.api?.serverUrl,a=s.database?.provider==="supabase",r=o,i="";if(a&&!n)console.log(`
|
|
129
|
+
\u{1F4CC} \uD504\uB85C\uC81D\uD2B8 ID \uC124\uC815`),console.log(" Supabase code_index \uD14C\uC774\uBE14\uC758 project_id \uCEEC\uB7FC\uC5D0 \uC800\uC7A5\uB420 \uAC12\uC785\uB2C8\uB2E4."),console.log(` \uC5EC\uB7EC \uD504\uB85C\uC81D\uD2B8\uB97C \uAD6C\uBD84\uD558\uB294 \uB370 \uC0AC\uC6A9\uB429\uB2C8\uB2E4.
|
|
130
|
+
`),r=(await y(`\uD504\uB85C\uC81D\uD2B8 ID [${o}]: `)).trim()||o;else if(n||T()){console.log(`
|
|
131
|
+
\u{1F4CB} \uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D \uC870\uD68C \uC911...`);let c=N(),l=O();if(l)try{let g=await fetch(`${c}/api/projects`,{headers:{Authorization:`Bearer ${l}`}});if(g.ok){let f=(await g.json()).projects;if(f.length>0){console.log(`
|
|
115
132
|
\u{1F4E6} \uC5F0\uACB0\uD560 \uD504\uB85C\uC81D\uD2B8\uB97C \uC120\uD0DD\uD558\uC138\uC694:
|
|
116
|
-
`),
|
|
117
|
-
\uC120\uD0DD [1-${
|
|
118
|
-
\u2705 \uC120\uD0DD\uB428: ${
|
|
119
|
-
\u26A0\uFE0F \uB85C\uADF8\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.`),await
|
|
120
|
-
\u26A0\uFE0F metadata.config.json \uD30C\uC77C\uC774 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4.`),
|
|
133
|
+
`),f.forEach((S,ce)=>{console.log(` ${ce+1}) ${S.name}`);});let k=await y(`
|
|
134
|
+
\uC120\uD0DD [1-${f.length}]: `),w=parseInt(k.trim(),10)-1;if(!isNaN(w)&&w>=0&&w<f.length){let S=f[w];r=S.name,i=S.id,console.log(`
|
|
135
|
+
\u2705 \uC120\uD0DD\uB428: ${S.name}`);}}}}catch{console.log("\u26A0\uFE0F \uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D\uC744 \uAC00\uC838\uC62C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");}else if(console.log(`
|
|
136
|
+
\u26A0\uFE0F \uB85C\uADF8\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.`),await A("\uC9C0\uAE08 \uB85C\uADF8\uC778\uD560\uAE4C\uC694?",true)){u(),await ae(),await ie();return}}try{let c=await V(t.type),l=await W(t.packageManager),g=!1;(c==="vite"||c==="cra")&&(g=await q(c));let p={projectType:c,packageManager:l,projectInfo:t,addBuildIntegration:g,projectUuid:i,projectName:r},f=m.join(e,"metadata.config.json"),k=!0;try{await h.access(f),console.log(`
|
|
137
|
+
\u26A0\uFE0F metadata.config.json \uD30C\uC77C\uC774 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4.`),k=await A("\uB36E\uC5B4\uC4F8\uAE4C\uC694?",!1);}catch{}if(console.log(`
|
|
121
138
|
\u{1F4DD} \uC124\uC815 \uC801\uC6A9 \uC911...
|
|
122
|
-
`),
|
|
139
|
+
`),k){let w=await Y(e,r,p);console.log(`\u2705 \uC124\uC815 \uD30C\uC77C \uC0DD\uC131: ${m.relative(e,w)}`);}if(g){let w=await X(e);console.log(w?"\u2705 vite.config \uD30C\uC77C\uC5D0 \uD50C\uB7EC\uADF8\uC778 \uCD94\uAC00\uB428":"\u26A0\uFE0F \uBE4C\uB4DC \uC124\uC815 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC218\uB3D9\uC73C\uB85C \uCD94\uAC00\uD574\uC8FC\uC138\uC694.");}console.log(`
|
|
123
140
|
\u{1F389} \uC124\uC815\uC774 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4!
|
|
124
|
-
`),!n&&!
|
|
141
|
+
`),!n&&!a&&(console.log("\u{1F4A1} \uC5C5\uB85C\uB4DC\uB97C \uC0AC\uC6A9\uD558\uB824\uBA74 \uAE00\uB85C\uBC8C \uC124\uC815\uC744 \uC644\uB8CC\uD558\uC138\uC694:"),console.log(` metadatafy config setup
|
|
125
142
|
`)),console.log(`\u{1F4A1} \uC0AC\uC6A9\uBC95:
|
|
126
|
-
`),console.log(" metadatafy analyze # \uBD84\uC11D (\uB85C\uCEEC \uD30C\uC77C \uC0DD\uC131)"),console.log(" metadatafy analyze --upload # \uBD84\uC11D + \uC5C5\uB85C\uB4DC"),console.log("");}finally{
|
|
143
|
+
`),console.log(" metadatafy analyze # \uBD84\uC11D (\uB85C\uCEEC \uD30C\uC77C \uC0DD\uC131)"),console.log(" metadatafy analyze --upload # \uBD84\uC11D + \uC5C5\uB85C\uB4DC"),console.log("");}finally{u();}}he().catch(e=>{console.error("Fatal error:",e),process.exit(1);});
|