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.
Files changed (4) hide show
  1. package/README.md +243 -304
  2. package/dist/cli.cjs +68 -51
  3. package/dist/cli.js +68 -51
  4. 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, API endpoint, or Supabase database
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 파일, API 엔드포인트, 또는 Supabase 데이터베이스
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
- The easiest way to get started is with the interactive setup wizard:
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
- npx metadatafy init
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
- This will:
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
- ## Usage / 사용법
90
+ Settings are stored in `~/.metadatafy/` and shared across all projects.
62
91
 
63
- ### CLI
92
+ 설정은 `~/.metadatafy/`에 저장되며 모든 프로젝트에서 공유됩니다.
64
93
 
65
94
  ```bash
66
- # Interactive setup (recommended for new projects)
67
- # 인터랙티브 설정 (새 프로젝트에 권장)
68
- npx metadatafy init
95
+ # Interactive setup wizard
96
+ metadatafy config setup
69
97
 
70
- # Analyze project and generate metadata (file only)
71
- # 프로젝트 분석 및 메타데이터 생성 (파일만)
72
- npx metadatafy analyze
98
+ # Show current config
99
+ metadatafy config show
73
100
 
74
- # Analyze + upload to database
75
- # 분석 + 데이터베이스 업로드
76
- npx metadatafy analyze --upload
101
+ # Set individual values
102
+ metadatafy config set database.provider supabase
103
+ metadatafy config set api.serverUrl https://my-server.com
77
104
 
78
- # Analyze without DB upload (even if configured)
79
- # 분석만 (DB 업로드 스킵)
80
- npx metadatafy analyze --no-upload
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
- # Upload existing metadata file to database
83
- # 기존 메타데이터 파일을 DB에 업로드
84
- npx metadatafy upload
115
+ # Check login status
116
+ metadatafy whoami
85
117
 
86
- # With options / 옵션과 함께
87
- npx metadatafy analyze --project-id my-project --output ./metadata.json --verbose
118
+ # Logout
119
+ metadatafy logout
88
120
  ```
89
121
 
90
- #### CLI Commands / CLI 명령어
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
- | `init` | Interactive setup wizard / 인터랙티브 설정 마법사 |
95
- | `analyze` | Analyze project and generate metadata / 프로젝트 분석 메타데이터 생성 |
96
- | `upload` | Upload existing metadata file to database / 기존 메타데이터 파일을 DB에 업로드 |
97
- | `database-init` | Database connection setup (Supabase, etc.) / 데이터베이스 연동 설정 |
98
-
99
- #### Analyze Options / Analyze 옵션
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` | | Force DB upload / DB 업로드 강제 실행 |
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
- ### Vite Plugin
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 { metadataPlugin } from 'metadatafy/vite';
211
+ import metadatafy from 'metadatafy/vite';
117
212
 
118
213
  export default defineConfig({
119
214
  plugins: [
120
- metadataPlugin({
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
- ### Next.js Plugin
228
+ ## Next.js Plugin
134
229
 
135
- #### Next.js 16+ (Turbopack) - Recommended
230
+ ### Next.js 15+ with Turbopack
136
231
 
137
- ```javascript
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
- module.exports = createMetadataAdapter({
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
- ```typescript
151
- // next.config.ts
152
- import type { NextConfig } from 'next';
153
-
154
- const nextConfig: NextConfig = {
155
- experimental: {
156
- adapterPath: require.resolve('./metadata-adapter.js'),
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
- #### Next.js 15 or Earlier (Webpack)
245
+ ### Next.js 14 or Earlier (Webpack)
164
246
 
165
247
  ```javascript
166
248
  // next.config.js
167
- const { withMetadata } = require('metadatafy/next');
249
+ const { withMetadatafy } = require('metadatafy/next');
168
250
 
169
251
  /** @type {import('next').NextConfig} */
170
252
  const nextConfig = {};
171
253
 
172
- module.exports = withMetadata({
173
- projectId: 'my-project',
174
- })(nextConfig);
254
+ module.exports = withMetadatafy()(nextConfig);
175
255
  ```
176
256
 
177
- ## File Type Detection / 파일 타입 감지
178
-
179
- metadatafy uses a **hybrid detection system** that combines multiple approaches:
180
-
181
- metadatafy는 여러 접근 방식을 결합한 **하이브리드 감지 시스템**을 사용합니다:
257
+ ## Configuration File / 설정 파일
182
258
 
183
- ### Detection Priority / 감지 우선순위
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
- ### Code Pattern Detection / 코드 패턴 감지
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-04T12:00:00Z",
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", "services/attendanceService.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
- ## Database Integration / 데이터베이스 연동
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
- ```bash
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
- - run: npm run build
450
- - run: npx metadatafy analyze --upload
451
- env:
452
- SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
453
- SUPABASE_SERVICE_ROLE_KEY: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }}
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
- ## Korean Keyword Mapping / 한글 키워드 매핑
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
- Built-in mappings include common development terms:
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
- You can extend with custom mappings in config.
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'),b=require('fs/promises'),H=require('readline'),g=require('fs'),X=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 b__namespace=/*#__PURE__*/_interopNamespace(b);var H__namespace=/*#__PURE__*/_interopNamespace(H);var g__namespace=/*#__PURE__*/_interopNamespace(g);var X__namespace=/*#__PURE__*/_interopNamespace(X);async function ce(e){let t=[{file:"pnpm-lock.yaml",manager:"pnpm"},{file:"yarn.lock",manager:"yarn"},{file:"package-lock.json",manager:"npm"}];for(let{file:o,manager:s}of t)try{return await b__namespace.access(m__namespace.join(e,o)),s}catch{}return "npm"}async function le(e){let t={};try{let s=await b__namespace.readFile(m__namespace.join(e,"package.json"),"utf-8");t=JSON.parse(s);}catch{return "unknown"}let o={...t.dependencies||{},...t.devDependencies||{}};return o.next?await j(m__namespace.join(e,"app"))||await j(m__namespace.join(e,"src","app"))?"nextjs-app":"nextjs-pages":o.vite?"vite":o["react-scripts"]?"cra":o.express||o.fastify||o.koa?"node":"unknown"}async function G(e){let[t,o]=await Promise.all([le(e),ce(e)]),s=await pe(m__namespace.join(e,"tsconfig.json")),n=await j(m__namespace.join(e,"src")),r=["app","pages","components","hooks","services","lib","utils","api","src/app","src/pages","src/components","src/hooks","src/services","src/lib","src/utils"],i=[];for(let f of r)await j(m__namespace.join(e,f))&&i.push(f);let a=await j(m__namespace.join(e,"prisma")),l=await j(m__namespace.join(e,"supabase"));return {type:t,packageManager:o,hasTypescript:s,hasSrc:n,existingFolders:i,hasPrisma:a,hasSupabase:l}}async function pe(e){try{return (await b__namespace.stat(e)).isFile()}catch{return false}}async function j(e){try{return (await b__namespace.stat(e)).isDirectory()}catch{return false}}function B(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 fe(){return P||(P=H__namespace.createInterface({input:process.stdin,output:process.stdout,terminal:false})),P}function y(e){return new Promise(t=>{process.stdout.write(e),fe().once("line",o=>{t(o);});})}function h(){P&&(P.close(),P=null);}async function K(e){let t=[{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"}],o=t.findIndex(a=>a.type===e),s=o>=0?t[o].key:"1";console.log(`
3
- \u{1F4E6} \uD504\uB85C\uC81D\uD2B8 \uD0C0\uC785\uC744 \uC120\uD0DD\uD558\uC138\uC694:`),t.forEach(a=>{let f=a.type===e?" (\uAC10\uC9C0\uB428)":"";console.log(` ${a.key}) ${a.label}${f}`);});let r=(await y(`
4
- \uC120\uD0DD [${s}]: `)).trim()||s;return t.find(a=>a.key===r)?.type||e}async function V(e){let t=[{key:"1",manager:"npm"},{key:"2",manager:"yarn"},{key:"3",manager:"pnpm"}],o=t.findIndex(a=>a.manager===e),s=o>=0?t[o].key:"1";console.log(`
5
- \u{1F4E6} \uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800\uB97C \uC120\uD0DD\uD558\uC138\uC694:`),t.forEach(a=>{let f=a.manager===e?" (\uAC10\uC9C0\uB428)":"";console.log(` ${a.key}) ${a.manager}${f}`);});let r=(await y(`
6
- \uC120\uD0DD [${s}]: `)).trim()||s;return t.find(a=>a.key===r)?.manager||e}async function W(e){return e==="node"||e==="unknown"||e.startsWith("nextjs")?false:(console.log(`
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 T(e,t=true){let n=(await y(`${e} ${t?"[Y/n]":"[y/N]"}: `)).trim().toLowerCase();return n===""?t:n==="y"||n==="yes"}function ge(e){let{projectType:t,projectInfo:o}=e,s=[],n=o.hasTypescript?"{ts,tsx}":"{js,jsx}";switch(t){case "nextjs-app":o.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":o.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/**/*.${o.hasTypescript?"ts":"js"}`),s.push(`routes/**/*.${o.hasTypescript?"ts":"js"}`),s.push(`controllers/**/*.${o.hasTypescript?"ts":"js"}`);break;default:s.push(`src/**/*.${n}`);}return o.hasPrisma&&s.push("prisma/migrations/**/*.sql"),o.hasSupabase&&s.push("supabase/migrations/*.sql"),s}async function q(e,t,o){let s=m__namespace.join(e,"metadata.config.json"),n={projectId:t,projectUuid:o.projectUuid,projectName:o.projectName,include:ge(o),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 b__namespace.writeFile(s,JSON.stringify(n,null,2)),s}async function Y(e){let t=["vite.config.ts","vite.config.js","vite.config.mts","vite.config.mjs"];for(let o of t){let s=m__namespace.join(e,o);try{let n=await b__namespace.readFile(s,"utf-8");if(n.includes("metadatafy"))return !0;let r=`import metadatafy from 'metadatafy/vite';
9
- `;return n.includes("from 'vite'")?n=n.replace(/^(import .+ from ['"]vite['"];?\n)/m,`$1${r}`):n=r+n,n.includes("plugins:")?n=n.replace(/plugins:\s*\[/,`plugins: [
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 b__namespace.writeFile(s,n),!0}catch{}}return false}var I=m__namespace.join(X__namespace.homedir(),".metadatafy"),O=m__namespace.join(I,"config.json"),A=m__namespace.join(I,"auth.json");function Z(){g__namespace.existsSync(I)||g__namespace.mkdirSync(I,{mode:448});}function w(){try{if(!g__namespace.existsSync(O))return {};let e=g__namespace.readFileSync(O,"utf-8");return JSON.parse(e)}catch{return {}}}function v(e){Z(),g__namespace.writeFileSync(O,JSON.stringify(e,null,2),{mode:384});}function $(){try{if(!g__namespace.existsSync(A))return null;let e=g__namespace.readFileSync(A,"utf-8"),t=JSON.parse(e);return t.expiresAt&&new Date(t.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):t}catch{return null}}function Q(e){Z(),g__namespace.writeFileSync(A,JSON.stringify(e,null,2),{mode:384});}function D(){g__namespace.existsSync(A)&&g__namespace.unlinkSync(A);}function C(){let e=$();return e!==null&&!!e.accessToken}function M(){return $()?.accessToken||null}function E(){return I}function ee(){let e=w();return e.database?.provider?e.database:null}function R(){return w().api?.serverUrl||"https://management.impakers.club"}var ue="2.0.0",te=`
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
- `,oe=`
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
- `,de=`
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
- `,me=`
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 ye(){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(ue),process.exit(0));let t=e[0];switch(t){case "config":await he(e.slice(1));break;case "login":await se();break;case "logout":await Se();break;case "whoami":await Ie();break;case "analyze":await Ae(e.slice(1));break;case "upload":await Ce(e.slice(1));break;case "init":await re();break;default:console.error(`Unknown command: ${t}`),console.log(te),process.exit(1);}}async function he(e){let t=e[0];if(!t||t==="-h"||t==="--help"){console.log(oe);return}switch(t){case "show":await we();break;case "setup":await be();break;case "set":await Pe(e.slice(1));break;case "reset":await ve();break;default:console.error(`Unknown config subcommand: ${t}`),console.log(oe),process.exit(1);}}async function we(){let e=w(),t=E();if(console.log(`
76
- \u{1F4C1} \uC124\uC815 \uC704\uCE58: ${t}
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 o=$();o&&(console.log(`
78
- \u{1F510} \uC778\uC99D \uC0C1\uD0DC: \uB85C\uADF8\uC778\uB428`),o.serverUrl&&console.log(` \uC11C\uBC84: ${o.serverUrl}`));}async function be(){console.log(`
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=w();console.log(`\u{1F4E4} \uBA54\uD0C0\uB370\uC774\uD130 \uC5C5\uB85C\uB4DC \uBC29\uC2DD\uC744 \uC120\uD0DD\uD558\uC138\uC694:
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 t=await y(`
83
- \uC120\uD0DD [1-3]: `);t==="1"?await ke(e):t==="2"?await xe(e):(e.database=void 0,e.api=void 0,v(e),console.log(`
84
- \u2705 \uB85C\uCEEC \uD30C\uC77C \uBAA8\uB4DC\uB85C \uC124\uC815\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`)),h(),console.log(`
85
- \u{1F389} \uC124\uC815\uC774 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4!`),console.log(` \uC800\uC7A5 \uC704\uCE58: ${E()}/config.json
86
- `);}async function ke(e){console.log(`
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 t=await y("Supabase URL: "),o=await je("Service Role Key: "),s=await y("\uD14C\uC774\uBE14 \uC774\uB984 [code_index]: ");e.database={provider:"supabase",supabaseUrl:t.trim(),supabaseServiceRoleKey:o,supabaseTable:s.trim()||"code_index"},v(e),console.log(`
90
- \u2705 Supabase \uC124\uC815\uC774 \uC800\uC7A5\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`);}async function xe(e){console.log(`
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 t=e.api?.serverUrl||"https://management.impakers.club",o=await y(`\uC11C\uBC84 URL [${t}]: `);e.api={serverUrl:o.trim()||t},console.log(`
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 je(e){return new Promise(t=>{process.stdout.write(e);let o=process.stdin,s=o.isRaw;o.isTTY&&o.setRawMode(true);let n="",r=i=>{let a=i.toString("utf8");switch(a){case `
95
- `:case "\r":case "":o.isTTY&&o.setRawMode(s),o.removeListener("data",r),process.stdout.write(`
96
- `),t(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+=a,process.stdout.write("*");break}};o.on("data",r),o.resume();})}async function Pe(e){e.length<2&&(console.error("Usage: metadatafy config set <key> <value>"),console.log(`
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,...o]=e,s=o.join(" "),n=w(),r=t.split("."),i=n;for(let a=0;a<r.length-1;a++){let l=r[a];(!i[l]||typeof i[l]!="object")&&(i[l]={}),i=i[l];}i[r[r.length-1]]=s,v(n),console.log(`\u2705 ${t} = ${s}`);}async function ve(){let e=await T("\uBAA8\uB4E0 \uC124\uC815\uC744 \uCD08\uAE30\uD654\uD560\uAE4C\uC694?",false);if(h(),!e){console.log("\uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");return}v({}),D(),console.log("\u2705 \uBAA8\uB4E0 \uC124\uC815\uC774 \uCD08\uAE30\uD654\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");}async function se(){let e=R();if(C()){let n=$();if(console.log(`\uC774\uBBF8 \uB85C\uADF8\uC778\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4. (${n?.serverUrl||e})`),!await T("\uB2E4\uC2DC \uB85C\uADF8\uC778\uD560\uAE4C\uC694?",false)){h();return}}console.log(`
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 t=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:t})});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`),h(),process.exit(1);}let o=`${e}/auth/device?code=${t}`;console.log(`
100
- \u{1F310} \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uC778\uC99D\uC744 \uC644\uB8CC\uD558\uC138\uC694.`),console.log(` ${o}
101
- `),await $e(o),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,t);s||(console.error(`
102
- \u274C \uC778\uC99D \uC2DC\uAC04\uC774 \uCD08\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694.`),h(),process.exit(1)),Q({accessToken:s.accessToken,expiresAt:s.expiresAt,userId:s.userId,serverUrl:e}),console.log(`
103
- \u2705 \uB85C\uADF8\uC778 \uC131\uACF5!`),h();}async function $e(e){let{exec:t}=await import('child_process'),o=process.platform,s=o==="darwin"?`open "${e}"`:o==="win32"?`start "${e}"`:`xdg-open "${e}"`;t(s);}async function Te(e,t){let n=Date.now();for(;Date.now()-n<3e5;)try{let r=await fetch(`${e}/api/auth/device/status?code=${t}`);if(!r.ok){await L(2e3);continue}let i=await r.json();if(i.status==="authorized"&&i.accessToken)return {accessToken:i.accessToken,expiresAt:i.expiresAt||new Date(Date.now()+720*60*60*1e3).toISOString(),userId:i.userId};if(i.status==="expired")return null;await L(2e3);}catch{await L(2e3);}return null}function L(e){return new Promise(t=>setTimeout(t,e))}async function Se(){if(!C()){console.log("\uB85C\uADF8\uC778\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");return}D(),console.log("\u2705 \uB85C\uADF8\uC544\uC6C3\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");}async function Ie(){let e=$();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 Ae(e){let{values:t}=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"}}});t.help&&(console.log(de),process.exit(0));let o=process.cwd(),s=t.output||"project-metadata.json",n=t.verbose||false,r={};if(t.config)try{let p=await b__namespace.readFile(t.config,"utf-8");r=JSON.parse(p);}catch{console.error(`Failed to load config file: ${t.config}`),process.exit(1);}else {let p=m__namespace.join(o,"metadata.config.json");try{let c=await b__namespace.readFile(p,"utf-8");r=JSON.parse(c),n&&console.log(`Loaded config from ${p}`);}catch{}}let i=r.projectId||m__namespace.basename(o),a=chunkCY7QWWFH_cjs.d({...r,projectId:i,verbose:n,output:{file:{enabled:true,path:s}}});console.log(`
104
- \u{1F4E6} Analyzing project: ${i}`),console.log(`\u{1F4C1} Root directory: ${o}
105
- `);let l=new chunkCY7QWWFH_cjs.y(a),f=new chunkCY7QWWFH_cjs.z(a);try{let p=Date.now(),c=await l.analyze(o),x=Date.now()-p,d=m__namespace.resolve(o,s);await f.write(c,d),console.log(`\u2705 Analysis completed in ${x}ms
106
- `),console.log("\u{1F4CA} Results:"),console.log(` Total files: ${c.stats.totalFiles}`),console.log(` - Routes: ${c.stats.byType.route}`),console.log(` - Components: ${c.stats.byType.component}`),console.log(` - Hooks: ${c.stats.byType.hook}`),console.log(` - Services: ${c.stats.byType.service}`),console.log(` - APIs: ${c.stats.byType.api}`),console.log(` - Tables: ${c.stats.byType.table}`),console.log(` - Utilities: ${c.stats.byType.utility}`),console.log(`
107
- \u{1F4C4} Output: ${d}`),c.stats.parseErrors.length>0&&(console.log(`
108
- \u26A0\uFE0F Parse errors (${c.stats.parseErrors.length}):`),c.stats.parseErrors.slice(0,5).forEach(N=>{console.log(` - ${N}`);}),c.stats.parseErrors.length>5&&console.log(` ... and ${c.stats.parseErrors.length-5} more`)),t.upload&&(console.log(""),await ae(r.projectUuid,c,n)),console.log("");}catch(p){console.error("\u274C Analysis failed:",p),process.exit(1);}}async function Ce(e){let{values:t}=util.parseArgs({args:e,options:{input:{type:"string",short:"i"},config:{type:"string",short:"c"},verbose:{type:"boolean"},help:{type:"boolean",short:"h"}}});t.help&&(console.log(me),process.exit(0));let o=process.cwd(),s=t.input||"project-metadata.json",n=t.verbose||false,r={};if(t.config)try{let l=await b__namespace.readFile(t.config,"utf-8");r=JSON.parse(l);}catch{console.error(`Failed to load config file: ${t.config}`),process.exit(1);}else {let l=m__namespace.join(o,"metadata.config.json");try{let f=await b__namespace.readFile(l,"utf-8");r=JSON.parse(f),n&&console.log(`Loaded config from ${l}`);}catch{}}let i=m__namespace.resolve(o,s),a;try{let l=await b__namespace.readFile(i,"utf-8");a=JSON.parse(l);}catch{console.error(`\u274C \uBA54\uD0C0\uB370\uC774\uD130 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${i}`),console.log(" metadatafy analyze \uB85C \uBA3C\uC800 \uBD84\uC11D\uC744 \uC2E4\uD589\uD558\uC138\uC694."),process.exit(1);}console.log(`
109
- \u{1F4E4} Uploading metadata from: ${i}`),await ae(r.projectUuid,a);}async function ae(e,t,o){let s=w(),n=ee();if(n?.provider==="supabase"&&n.supabaseUrl){console.log("\u{1F504} Supabase\uC5D0 \uC5C5\uB85C\uB4DC \uC911..."),await Ue(n,t);return}if(s.api?.serverUrl||!n){C()||(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 Re(e,t);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 Ue(e,t,o){let{supabaseUrl:s,supabaseServiceRoleKey:n,supabaseTable:r}=e;(!s||!n)&&(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=r||"code_index";try{let a=await fetch(`${s}/rest/v1/${i}?project_id=eq.${t.projectId}`,{method:"DELETE",headers:{apikey:n,Authorization:`Bearer ${n}`}});if(!a.ok&&a.status!==404)throw new Error(`Delete failed: ${a.status}`);let l=t.items.map(p=>({project_id:t.projectId,file_path:p.path,file_type:p.type,file_name:p.name,keywords:p.keywords,search_text:p.searchText,calls:p.calls,called_by:p.calledBy,metadata:p.metadata})),f=await fetch(`${s}/rest/v1/${i}`,{method:"POST",headers:{apikey:n,Authorization:`Bearer ${n}`,"Content-Type":"application/json",Prefer:"return=minimal"},body:JSON.stringify(l)});if(!f.ok){let p=await f.text();throw new Error(`Insert failed: ${p}`)}console.log(`\u2705 \uC5C5\uB85C\uB4DC \uC644\uB8CC! (${t.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 Re(e,t,o){let s=R(),n=M();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 r=await fetch(`${s}/api/code-index`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify({projectId:e,items:t.items,stats:t.stats})});if(!r.ok){let a=await r.json().catch(()=>({}));throw new Error(a.error||`HTTP ${r.status}`)}let i=await r.json();console.log(`\u2705 \uC5C5\uB85C\uB4DC \uC644\uB8CC! (${i.count||t.items.length}\uAC1C \uD30C\uC77C)`);}catch(r){console.error(`\u274C \uC5C5\uB85C\uB4DC \uC2E4\uD328: ${r instanceof Error?r.message:r}`),process.exit(1);}}async function re(){let e=process.cwd(),t=m__namespace.basename(e);console.log(`
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: ${t}`),console.log(`\uACBD\uB85C: ${e}`),console.log(`
112
- \u{1F50D} \uD504\uB85C\uC81D\uD2B8 \uBD84\uC11D \uC911...`);let o=await G(e);console.log(`
113
- \u2705 \uAC10\uC9C0\uB41C \uC815\uBCF4:`),console.log(` \uD504\uB85C\uC81D\uD2B8 \uD0C0\uC785: ${B(o.type)}`),console.log(` \uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800: ${o.packageManager}`),console.log(` TypeScript: ${o.hasTypescript?"\uC608":"\uC544\uB2C8\uC624"}`);let s=w(),n=!!s.api?.serverUrl,r=!!s.database?.provider,i=null;if(n||!r&&C()){console.log(`
114
- \u{1F4CB} \uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D \uC870\uD68C \uC911...`);let a=R(),l=M();if(l)try{let f=await fetch(`${a}/api/projects`,{headers:{Authorization:`Bearer ${l}`}});if(f.ok){let c=(await f.json()).projects;if(c.length>0){console.log(`
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
- `),c.forEach((N,ie)=>{console.log(` ${ie+1}) ${N.name}`);});let x=await y(`
117
- \uC120\uD0DD [1-${c.length}]: `),d=parseInt(x.trim(),10)-1;!isNaN(d)&&d>=0&&d<c.length&&(i=c[d],console.log(`
118
- \u2705 \uC120\uD0DD\uB428: ${i.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(`
119
- \u26A0\uFE0F \uB85C\uADF8\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.`),await T("\uC9C0\uAE08 \uB85C\uADF8\uC778\uD560\uAE4C\uC694?",true)){h(),await se(),await re();return}}try{let a=await K(o.type),l=await V(o.packageManager),f=!1;(a==="vite"||a==="cra")&&(f=await W(a));let p={projectType:a,packageManager:l,projectInfo:o,addBuildIntegration:f,projectUuid:i?.id||"",projectName:i?.name||t},c=m__namespace.join(e,"metadata.config.json"),x=!0;try{await b__namespace.access(c),console.log(`
120
- \u26A0\uFE0F metadata.config.json \uD30C\uC77C\uC774 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4.`),x=await T("\uB36E\uC5B4\uC4F8\uAE4C\uC694?",!1);}catch{}if(console.log(`
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
- `),x){let d=await q(e,p.projectName,p);console.log(`\u2705 \uC124\uC815 \uD30C\uC77C \uC0DD\uC131: ${m__namespace.relative(e,d)}`);}if(f){let d=await Y(e);console.log(d?"\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(`
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&&!r&&(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
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{h();}}ye().catch(e=>{console.error("Fatal error:",e),process.exit(1);});
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 b from'fs/promises';import*as H from'readline';import*as g from'fs';import*as X from'os';async function ce(e){let t=[{file:"pnpm-lock.yaml",manager:"pnpm"},{file:"yarn.lock",manager:"yarn"},{file:"package-lock.json",manager:"npm"}];for(let{file:o,manager:s}of t)try{return await b.access(m.join(e,o)),s}catch{}return "npm"}async function le(e){let t={};try{let s=await b.readFile(m.join(e,"package.json"),"utf-8");t=JSON.parse(s);}catch{return "unknown"}let o={...t.dependencies||{},...t.devDependencies||{}};return o.next?await j(m.join(e,"app"))||await j(m.join(e,"src","app"))?"nextjs-app":"nextjs-pages":o.vite?"vite":o["react-scripts"]?"cra":o.express||o.fastify||o.koa?"node":"unknown"}async function G(e){let[t,o]=await Promise.all([le(e),ce(e)]),s=await pe(m.join(e,"tsconfig.json")),n=await j(m.join(e,"src")),r=["app","pages","components","hooks","services","lib","utils","api","src/app","src/pages","src/components","src/hooks","src/services","src/lib","src/utils"],i=[];for(let f of r)await j(m.join(e,f))&&i.push(f);let a=await j(m.join(e,"prisma")),l=await j(m.join(e,"supabase"));return {type:t,packageManager:o,hasTypescript:s,hasSrc:n,existingFolders:i,hasPrisma:a,hasSupabase:l}}async function pe(e){try{return (await b.stat(e)).isFile()}catch{return false}}async function j(e){try{return (await b.stat(e)).isDirectory()}catch{return false}}function B(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 fe(){return P||(P=H.createInterface({input:process.stdin,output:process.stdout,terminal:false})),P}function y(e){return new Promise(t=>{process.stdout.write(e),fe().once("line",o=>{t(o);});})}function h(){P&&(P.close(),P=null);}async function K(e){let t=[{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"}],o=t.findIndex(a=>a.type===e),s=o>=0?t[o].key:"1";console.log(`
3
- \u{1F4E6} \uD504\uB85C\uC81D\uD2B8 \uD0C0\uC785\uC744 \uC120\uD0DD\uD558\uC138\uC694:`),t.forEach(a=>{let f=a.type===e?" (\uAC10\uC9C0\uB428)":"";console.log(` ${a.key}) ${a.label}${f}`);});let r=(await y(`
4
- \uC120\uD0DD [${s}]: `)).trim()||s;return t.find(a=>a.key===r)?.type||e}async function V(e){let t=[{key:"1",manager:"npm"},{key:"2",manager:"yarn"},{key:"3",manager:"pnpm"}],o=t.findIndex(a=>a.manager===e),s=o>=0?t[o].key:"1";console.log(`
5
- \u{1F4E6} \uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800\uB97C \uC120\uD0DD\uD558\uC138\uC694:`),t.forEach(a=>{let f=a.manager===e?" (\uAC10\uC9C0\uB428)":"";console.log(` ${a.key}) ${a.manager}${f}`);});let r=(await y(`
6
- \uC120\uD0DD [${s}]: `)).trim()||s;return t.find(a=>a.key===r)?.manager||e}async function W(e){return e==="node"||e==="unknown"||e.startsWith("nextjs")?false:(console.log(`
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 T(e,t=true){let n=(await y(`${e} ${t?"[Y/n]":"[y/N]"}: `)).trim().toLowerCase();return n===""?t:n==="y"||n==="yes"}function ge(e){let{projectType:t,projectInfo:o}=e,s=[],n=o.hasTypescript?"{ts,tsx}":"{js,jsx}";switch(t){case "nextjs-app":o.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":o.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/**/*.${o.hasTypescript?"ts":"js"}`),s.push(`routes/**/*.${o.hasTypescript?"ts":"js"}`),s.push(`controllers/**/*.${o.hasTypescript?"ts":"js"}`);break;default:s.push(`src/**/*.${n}`);}return o.hasPrisma&&s.push("prisma/migrations/**/*.sql"),o.hasSupabase&&s.push("supabase/migrations/*.sql"),s}async function q(e,t,o){let s=m.join(e,"metadata.config.json"),n={projectId:t,projectUuid:o.projectUuid,projectName:o.projectName,include:ge(o),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 b.writeFile(s,JSON.stringify(n,null,2)),s}async function Y(e){let t=["vite.config.ts","vite.config.js","vite.config.mts","vite.config.mjs"];for(let o of t){let s=m.join(e,o);try{let n=await b.readFile(s,"utf-8");if(n.includes("metadatafy"))return !0;let r=`import metadatafy from 'metadatafy/vite';
9
- `;return n.includes("from 'vite'")?n=n.replace(/^(import .+ from ['"]vite['"];?\n)/m,`$1${r}`):n=r+n,n.includes("plugins:")?n=n.replace(/plugins:\s*\[/,`plugins: [
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 b.writeFile(s,n),!0}catch{}}return false}var I=m.join(X.homedir(),".metadatafy"),O=m.join(I,"config.json"),A=m.join(I,"auth.json");function Z(){g.existsSync(I)||g.mkdirSync(I,{mode:448});}function w(){try{if(!g.existsSync(O))return {};let e=g.readFileSync(O,"utf-8");return JSON.parse(e)}catch{return {}}}function v(e){Z(),g.writeFileSync(O,JSON.stringify(e,null,2),{mode:384});}function $(){try{if(!g.existsSync(A))return null;let e=g.readFileSync(A,"utf-8"),t=JSON.parse(e);return t.expiresAt&&new Date(t.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):t}catch{return null}}function Q(e){Z(),g.writeFileSync(A,JSON.stringify(e,null,2),{mode:384});}function D(){g.existsSync(A)&&g.unlinkSync(A);}function C(){let e=$();return e!==null&&!!e.accessToken}function M(){return $()?.accessToken||null}function E(){return I}function ee(){let e=w();return e.database?.provider?e.database:null}function R(){return w().api?.serverUrl||"https://management.impakers.club"}var ue="2.0.0",te=`
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
- `,oe=`
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
- `,de=`
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
- `,me=`
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 ye(){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(ue),process.exit(0));let t=e[0];switch(t){case "config":await he(e.slice(1));break;case "login":await se();break;case "logout":await Se();break;case "whoami":await Ie();break;case "analyze":await Ae(e.slice(1));break;case "upload":await Ce(e.slice(1));break;case "init":await re();break;default:console.error(`Unknown command: ${t}`),console.log(te),process.exit(1);}}async function he(e){let t=e[0];if(!t||t==="-h"||t==="--help"){console.log(oe);return}switch(t){case "show":await we();break;case "setup":await be();break;case "set":await Pe(e.slice(1));break;case "reset":await ve();break;default:console.error(`Unknown config subcommand: ${t}`),console.log(oe),process.exit(1);}}async function we(){let e=w(),t=E();if(console.log(`
76
- \u{1F4C1} \uC124\uC815 \uC704\uCE58: ${t}
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 o=$();o&&(console.log(`
78
- \u{1F510} \uC778\uC99D \uC0C1\uD0DC: \uB85C\uADF8\uC778\uB428`),o.serverUrl&&console.log(` \uC11C\uBC84: ${o.serverUrl}`));}async function be(){console.log(`
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=w();console.log(`\u{1F4E4} \uBA54\uD0C0\uB370\uC774\uD130 \uC5C5\uB85C\uB4DC \uBC29\uC2DD\uC744 \uC120\uD0DD\uD558\uC138\uC694:
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 t=await y(`
83
- \uC120\uD0DD [1-3]: `);t==="1"?await ke(e):t==="2"?await xe(e):(e.database=void 0,e.api=void 0,v(e),console.log(`
84
- \u2705 \uB85C\uCEEC \uD30C\uC77C \uBAA8\uB4DC\uB85C \uC124\uC815\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`)),h(),console.log(`
85
- \u{1F389} \uC124\uC815\uC774 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4!`),console.log(` \uC800\uC7A5 \uC704\uCE58: ${E()}/config.json
86
- `);}async function ke(e){console.log(`
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 t=await y("Supabase URL: "),o=await je("Service Role Key: "),s=await y("\uD14C\uC774\uBE14 \uC774\uB984 [code_index]: ");e.database={provider:"supabase",supabaseUrl:t.trim(),supabaseServiceRoleKey:o,supabaseTable:s.trim()||"code_index"},v(e),console.log(`
90
- \u2705 Supabase \uC124\uC815\uC774 \uC800\uC7A5\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`);}async function xe(e){console.log(`
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 t=e.api?.serverUrl||"https://management.impakers.club",o=await y(`\uC11C\uBC84 URL [${t}]: `);e.api={serverUrl:o.trim()||t},console.log(`
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 je(e){return new Promise(t=>{process.stdout.write(e);let o=process.stdin,s=o.isRaw;o.isTTY&&o.setRawMode(true);let n="",r=i=>{let a=i.toString("utf8");switch(a){case `
95
- `:case "\r":case "":o.isTTY&&o.setRawMode(s),o.removeListener("data",r),process.stdout.write(`
96
- `),t(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+=a,process.stdout.write("*");break}};o.on("data",r),o.resume();})}async function Pe(e){e.length<2&&(console.error("Usage: metadatafy config set <key> <value>"),console.log(`
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,...o]=e,s=o.join(" "),n=w(),r=t.split("."),i=n;for(let a=0;a<r.length-1;a++){let l=r[a];(!i[l]||typeof i[l]!="object")&&(i[l]={}),i=i[l];}i[r[r.length-1]]=s,v(n),console.log(`\u2705 ${t} = ${s}`);}async function ve(){let e=await T("\uBAA8\uB4E0 \uC124\uC815\uC744 \uCD08\uAE30\uD654\uD560\uAE4C\uC694?",false);if(h(),!e){console.log("\uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");return}v({}),D(),console.log("\u2705 \uBAA8\uB4E0 \uC124\uC815\uC774 \uCD08\uAE30\uD654\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");}async function se(){let e=R();if(C()){let n=$();if(console.log(`\uC774\uBBF8 \uB85C\uADF8\uC778\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4. (${n?.serverUrl||e})`),!await T("\uB2E4\uC2DC \uB85C\uADF8\uC778\uD560\uAE4C\uC694?",false)){h();return}}console.log(`
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 t=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:t})});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`),h(),process.exit(1);}let o=`${e}/auth/device?code=${t}`;console.log(`
100
- \u{1F310} \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uC778\uC99D\uC744 \uC644\uB8CC\uD558\uC138\uC694.`),console.log(` ${o}
101
- `),await $e(o),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,t);s||(console.error(`
102
- \u274C \uC778\uC99D \uC2DC\uAC04\uC774 \uCD08\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694.`),h(),process.exit(1)),Q({accessToken:s.accessToken,expiresAt:s.expiresAt,userId:s.userId,serverUrl:e}),console.log(`
103
- \u2705 \uB85C\uADF8\uC778 \uC131\uACF5!`),h();}async function $e(e){let{exec:t}=await import('child_process'),o=process.platform,s=o==="darwin"?`open "${e}"`:o==="win32"?`start "${e}"`:`xdg-open "${e}"`;t(s);}async function Te(e,t){let n=Date.now();for(;Date.now()-n<3e5;)try{let r=await fetch(`${e}/api/auth/device/status?code=${t}`);if(!r.ok){await L(2e3);continue}let i=await r.json();if(i.status==="authorized"&&i.accessToken)return {accessToken:i.accessToken,expiresAt:i.expiresAt||new Date(Date.now()+720*60*60*1e3).toISOString(),userId:i.userId};if(i.status==="expired")return null;await L(2e3);}catch{await L(2e3);}return null}function L(e){return new Promise(t=>setTimeout(t,e))}async function Se(){if(!C()){console.log("\uB85C\uADF8\uC778\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");return}D(),console.log("\u2705 \uB85C\uADF8\uC544\uC6C3\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");}async function Ie(){let e=$();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 Ae(e){let{values:t}=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"}}});t.help&&(console.log(de),process.exit(0));let o=process.cwd(),s=t.output||"project-metadata.json",n=t.verbose||false,r={};if(t.config)try{let p=await b.readFile(t.config,"utf-8");r=JSON.parse(p);}catch{console.error(`Failed to load config file: ${t.config}`),process.exit(1);}else {let p=m.join(o,"metadata.config.json");try{let c=await b.readFile(p,"utf-8");r=JSON.parse(c),n&&console.log(`Loaded config from ${p}`);}catch{}}let i=r.projectId||m.basename(o),a=d({...r,projectId:i,verbose:n,output:{file:{enabled:true,path:s}}});console.log(`
104
- \u{1F4E6} Analyzing project: ${i}`),console.log(`\u{1F4C1} Root directory: ${o}
105
- `);let l=new y$1(a),f=new z(a);try{let p=Date.now(),c=await l.analyze(o),x=Date.now()-p,d=m.resolve(o,s);await f.write(c,d),console.log(`\u2705 Analysis completed in ${x}ms
106
- `),console.log("\u{1F4CA} Results:"),console.log(` Total files: ${c.stats.totalFiles}`),console.log(` - Routes: ${c.stats.byType.route}`),console.log(` - Components: ${c.stats.byType.component}`),console.log(` - Hooks: ${c.stats.byType.hook}`),console.log(` - Services: ${c.stats.byType.service}`),console.log(` - APIs: ${c.stats.byType.api}`),console.log(` - Tables: ${c.stats.byType.table}`),console.log(` - Utilities: ${c.stats.byType.utility}`),console.log(`
107
- \u{1F4C4} Output: ${d}`),c.stats.parseErrors.length>0&&(console.log(`
108
- \u26A0\uFE0F Parse errors (${c.stats.parseErrors.length}):`),c.stats.parseErrors.slice(0,5).forEach(N=>{console.log(` - ${N}`);}),c.stats.parseErrors.length>5&&console.log(` ... and ${c.stats.parseErrors.length-5} more`)),t.upload&&(console.log(""),await ae(r.projectUuid,c,n)),console.log("");}catch(p){console.error("\u274C Analysis failed:",p),process.exit(1);}}async function Ce(e){let{values:t}=parseArgs({args:e,options:{input:{type:"string",short:"i"},config:{type:"string",short:"c"},verbose:{type:"boolean"},help:{type:"boolean",short:"h"}}});t.help&&(console.log(me),process.exit(0));let o=process.cwd(),s=t.input||"project-metadata.json",n=t.verbose||false,r={};if(t.config)try{let l=await b.readFile(t.config,"utf-8");r=JSON.parse(l);}catch{console.error(`Failed to load config file: ${t.config}`),process.exit(1);}else {let l=m.join(o,"metadata.config.json");try{let f=await b.readFile(l,"utf-8");r=JSON.parse(f),n&&console.log(`Loaded config from ${l}`);}catch{}}let i=m.resolve(o,s),a;try{let l=await b.readFile(i,"utf-8");a=JSON.parse(l);}catch{console.error(`\u274C \uBA54\uD0C0\uB370\uC774\uD130 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${i}`),console.log(" metadatafy analyze \uB85C \uBA3C\uC800 \uBD84\uC11D\uC744 \uC2E4\uD589\uD558\uC138\uC694."),process.exit(1);}console.log(`
109
- \u{1F4E4} Uploading metadata from: ${i}`),await ae(r.projectUuid,a);}async function ae(e,t,o){let s=w(),n=ee();if(n?.provider==="supabase"&&n.supabaseUrl){console.log("\u{1F504} Supabase\uC5D0 \uC5C5\uB85C\uB4DC \uC911..."),await Ue(n,t);return}if(s.api?.serverUrl||!n){C()||(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 Re(e,t);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 Ue(e,t,o){let{supabaseUrl:s,supabaseServiceRoleKey:n,supabaseTable:r}=e;(!s||!n)&&(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=r||"code_index";try{let a=await fetch(`${s}/rest/v1/${i}?project_id=eq.${t.projectId}`,{method:"DELETE",headers:{apikey:n,Authorization:`Bearer ${n}`}});if(!a.ok&&a.status!==404)throw new Error(`Delete failed: ${a.status}`);let l=t.items.map(p=>({project_id:t.projectId,file_path:p.path,file_type:p.type,file_name:p.name,keywords:p.keywords,search_text:p.searchText,calls:p.calls,called_by:p.calledBy,metadata:p.metadata})),f=await fetch(`${s}/rest/v1/${i}`,{method:"POST",headers:{apikey:n,Authorization:`Bearer ${n}`,"Content-Type":"application/json",Prefer:"return=minimal"},body:JSON.stringify(l)});if(!f.ok){let p=await f.text();throw new Error(`Insert failed: ${p}`)}console.log(`\u2705 \uC5C5\uB85C\uB4DC \uC644\uB8CC! (${t.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 Re(e,t,o){let s=R(),n=M();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 r=await fetch(`${s}/api/code-index`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify({projectId:e,items:t.items,stats:t.stats})});if(!r.ok){let a=await r.json().catch(()=>({}));throw new Error(a.error||`HTTP ${r.status}`)}let i=await r.json();console.log(`\u2705 \uC5C5\uB85C\uB4DC \uC644\uB8CC! (${i.count||t.items.length}\uAC1C \uD30C\uC77C)`);}catch(r){console.error(`\u274C \uC5C5\uB85C\uB4DC \uC2E4\uD328: ${r instanceof Error?r.message:r}`),process.exit(1);}}async function re(){let e=process.cwd(),t=m.basename(e);console.log(`
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: ${t}`),console.log(`\uACBD\uB85C: ${e}`),console.log(`
112
- \u{1F50D} \uD504\uB85C\uC81D\uD2B8 \uBD84\uC11D \uC911...`);let o=await G(e);console.log(`
113
- \u2705 \uAC10\uC9C0\uB41C \uC815\uBCF4:`),console.log(` \uD504\uB85C\uC81D\uD2B8 \uD0C0\uC785: ${B(o.type)}`),console.log(` \uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800: ${o.packageManager}`),console.log(` TypeScript: ${o.hasTypescript?"\uC608":"\uC544\uB2C8\uC624"}`);let s=w(),n=!!s.api?.serverUrl,r=!!s.database?.provider,i=null;if(n||!r&&C()){console.log(`
114
- \u{1F4CB} \uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D \uC870\uD68C \uC911...`);let a=R(),l=M();if(l)try{let f=await fetch(`${a}/api/projects`,{headers:{Authorization:`Bearer ${l}`}});if(f.ok){let c=(await f.json()).projects;if(c.length>0){console.log(`
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
- `),c.forEach((N,ie)=>{console.log(` ${ie+1}) ${N.name}`);});let x=await y(`
117
- \uC120\uD0DD [1-${c.length}]: `),d=parseInt(x.trim(),10)-1;!isNaN(d)&&d>=0&&d<c.length&&(i=c[d],console.log(`
118
- \u2705 \uC120\uD0DD\uB428: ${i.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(`
119
- \u26A0\uFE0F \uB85C\uADF8\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.`),await T("\uC9C0\uAE08 \uB85C\uADF8\uC778\uD560\uAE4C\uC694?",true)){h(),await se(),await re();return}}try{let a=await K(o.type),l=await V(o.packageManager),f=!1;(a==="vite"||a==="cra")&&(f=await W(a));let p={projectType:a,packageManager:l,projectInfo:o,addBuildIntegration:f,projectUuid:i?.id||"",projectName:i?.name||t},c=m.join(e,"metadata.config.json"),x=!0;try{await b.access(c),console.log(`
120
- \u26A0\uFE0F metadata.config.json \uD30C\uC77C\uC774 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4.`),x=await T("\uB36E\uC5B4\uC4F8\uAE4C\uC694?",!1);}catch{}if(console.log(`
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
- `),x){let d=await q(e,p.projectName,p);console.log(`\u2705 \uC124\uC815 \uD30C\uC77C \uC0DD\uC131: ${m.relative(e,d)}`);}if(f){let d=await Y(e);console.log(d?"\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(`
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&&!r&&(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
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{h();}}ye().catch(e=>{console.error("Fatal error:",e),process.exit(1);});
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metadatafy",
3
- "version": "1.5.0",
3
+ "version": "1.5.3",
4
4
  "description": "Build plugin for extracting project metadata for ticket analysis system",
5
5
  "type": "module",
6
6
  "exports": {