@team-semicolon/semo-cli 3.13.1 → 3.14.1

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.
@@ -0,0 +1,727 @@
1
+ "use strict";
2
+ /**
3
+ * SEMO CLI - PostgreSQL 데이터베이스 클라이언트
4
+ *
5
+ * 팀 코어 PostgreSQL에서 스킬, 커맨드, 에이전트 정보를 조회합니다.
6
+ * DB 연결 실패 시 하드코딩된 폴백 데이터를 사용합니다.
7
+ *
8
+ * v3.14.0: Supabase → PostgreSQL 전환
9
+ * - semo-system 의존성 제거
10
+ * - 문서 내용을 DB에서 직접 조회
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.getActiveSkills = getActiveSkills;
14
+ exports.getActiveSkillNames = getActiveSkillNames;
15
+ exports.getCommands = getCommands;
16
+ exports.getAgents = getAgents;
17
+ exports.getPackages = getPackages;
18
+ exports.getSkillCountByCategory = getSkillCountByCategory;
19
+ exports.closeConnection = closeConnection;
20
+ exports.isDbConnected = isDbConnected;
21
+ const pg_1 = require("pg");
22
+ // PostgreSQL 연결 정보 (팀 코어)
23
+ const DB_CONFIG = {
24
+ host: process.env.SEMO_DB_HOST || "3.38.162.21",
25
+ port: parseInt(process.env.SEMO_DB_PORT || "5432"),
26
+ user: process.env.SEMO_DB_USER || "app",
27
+ password: process.env.SEMO_DB_PASSWORD || "ProductionPassword2024!@#",
28
+ database: process.env.SEMO_DB_NAME || "appdb",
29
+ ssl: false,
30
+ connectionTimeoutMillis: 5000,
31
+ idleTimeoutMillis: 30000,
32
+ };
33
+ // PostgreSQL Pool (싱글톤)
34
+ let pool = null;
35
+ function getPool() {
36
+ if (!pool) {
37
+ pool = new pg_1.Pool(DB_CONFIG);
38
+ }
39
+ return pool;
40
+ }
41
+ // DB 연결 가능 여부 확인
42
+ let dbAvailable = null;
43
+ async function checkDbConnection() {
44
+ if (dbAvailable !== null)
45
+ return dbAvailable;
46
+ try {
47
+ const client = await getPool().connect();
48
+ await client.query("SELECT 1");
49
+ client.release();
50
+ dbAvailable = true;
51
+ }
52
+ catch {
53
+ dbAvailable = false;
54
+ }
55
+ return dbAvailable;
56
+ }
57
+ // ============================================================
58
+ // 폴백 데이터 (DB 연결 실패 시 사용)
59
+ // ============================================================
60
+ const FALLBACK_SKILLS = [
61
+ // Workflow Management (3개)
62
+ {
63
+ id: "sk-1",
64
+ name: "workflow-start",
65
+ display_name: "워크플로우 시작",
66
+ description: "워크플로우 인스턴스 생성 및 시작",
67
+ content: `---
68
+ name: workflow-start
69
+ description: 워크플로우 인스턴스 생성 및 시작
70
+ ---
71
+
72
+ # workflow-start
73
+
74
+ 워크플로우 인스턴스를 생성하고 시작합니다.
75
+
76
+ ## Usage
77
+
78
+ \`\`\`
79
+ skill:workflow-start workflow_command="greenfield"
80
+ \`\`\`
81
+ `,
82
+ category: "workflow",
83
+ package: "core",
84
+ is_active: true,
85
+ is_required: true,
86
+ install_order: 1,
87
+ version: "1.0.0",
88
+ },
89
+ {
90
+ id: "sk-2",
91
+ name: "workflow-progress",
92
+ display_name: "워크플로우 진행",
93
+ description: "워크플로우 진행 상황 조회",
94
+ content: `---
95
+ name: workflow-progress
96
+ description: 워크플로우 진행 상황 조회
97
+ ---
98
+
99
+ # workflow-progress
100
+
101
+ 진행 중인 워크플로우의 현재 상태를 조회합니다.
102
+ `,
103
+ category: "workflow",
104
+ package: "core",
105
+ is_active: true,
106
+ is_required: true,
107
+ install_order: 2,
108
+ version: "1.0.0",
109
+ },
110
+ {
111
+ id: "sk-3",
112
+ name: "workflow-resume",
113
+ display_name: "워크플로우 재개",
114
+ description: "중단된 워크플로우 재개",
115
+ content: `---
116
+ name: workflow-resume
117
+ description: 중단된 워크플로우 재개
118
+ ---
119
+
120
+ # workflow-resume
121
+
122
+ 중단된 워크플로우를 재개합니다.
123
+ `,
124
+ category: "workflow",
125
+ package: "core",
126
+ is_active: true,
127
+ is_required: true,
128
+ install_order: 3,
129
+ version: "1.0.0",
130
+ },
131
+ // Discovery (1개)
132
+ {
133
+ id: "sk-10",
134
+ name: "ideate",
135
+ display_name: "아이디에이션",
136
+ description: "아이디어 발굴 및 분석",
137
+ content: `---
138
+ name: ideate
139
+ description: 아이디어 발굴 및 분석
140
+ ---
141
+
142
+ # ideate
143
+
144
+ 새로운 아이디어를 발굴하고 분석합니다.
145
+ `,
146
+ category: "discovery",
147
+ package: "core",
148
+ is_active: true,
149
+ is_required: true,
150
+ install_order: 10,
151
+ version: "1.0.0",
152
+ },
153
+ // Planning (3개)
154
+ {
155
+ id: "sk-20",
156
+ name: "create-epic",
157
+ display_name: "Epic 생성",
158
+ description: "Epic 이슈 생성",
159
+ content: `---
160
+ name: create-epic
161
+ description: Epic 이슈 생성
162
+ ---
163
+
164
+ # create-epic
165
+
166
+ Epic 이슈를 생성합니다.
167
+ `,
168
+ category: "planning",
169
+ package: "core",
170
+ is_active: true,
171
+ is_required: true,
172
+ install_order: 20,
173
+ version: "1.0.0",
174
+ },
175
+ {
176
+ id: "sk-21",
177
+ name: "design-user-flow",
178
+ display_name: "사용자 흐름 설계",
179
+ description: "UX 사용자 흐름 다이어그램 설계",
180
+ content: `---
181
+ name: design-user-flow
182
+ description: UX 사용자 흐름 다이어그램 설계
183
+ ---
184
+
185
+ # design-user-flow
186
+
187
+ 사용자 흐름을 설계합니다.
188
+ `,
189
+ category: "planning",
190
+ package: "core",
191
+ is_active: true,
192
+ is_required: true,
193
+ install_order: 21,
194
+ version: "1.0.0",
195
+ },
196
+ {
197
+ id: "sk-22",
198
+ name: "generate-mockup",
199
+ display_name: "목업 생성",
200
+ description: "UI 목업 생성",
201
+ content: `---
202
+ name: generate-mockup
203
+ description: UI 목업 생성
204
+ ---
205
+
206
+ # generate-mockup
207
+
208
+ UI 목업을 생성합니다.
209
+ `,
210
+ category: "planning",
211
+ package: "core",
212
+ is_active: true,
213
+ is_required: true,
214
+ install_order: 22,
215
+ version: "1.0.0",
216
+ },
217
+ // Solutioning (4개)
218
+ {
219
+ id: "sk-30",
220
+ name: "scaffold-domain",
221
+ display_name: "도메인 스캐폴딩",
222
+ description: "DDD 4-layer 도메인 구조 생성",
223
+ content: `---
224
+ name: scaffold-domain
225
+ description: DDD 4-layer 도메인 구조 생성
226
+ ---
227
+
228
+ # scaffold-domain
229
+
230
+ DDD 4-layer 도메인 구조를 생성합니다.
231
+ `,
232
+ category: "solutioning",
233
+ package: "core",
234
+ is_active: true,
235
+ is_required: true,
236
+ install_order: 30,
237
+ version: "1.0.0",
238
+ },
239
+ {
240
+ id: "sk-31",
241
+ name: "validate-architecture",
242
+ display_name: "아키텍처 검증",
243
+ description: "DDD 4-layer 아키텍처 준수 검증",
244
+ content: `---
245
+ name: validate-architecture
246
+ description: DDD 4-layer 아키텍처 준수 검증
247
+ ---
248
+
249
+ # validate-architecture
250
+
251
+ 아키텍처 준수 여부를 검증합니다.
252
+ `,
253
+ category: "solutioning",
254
+ package: "core",
255
+ is_active: true,
256
+ is_required: true,
257
+ install_order: 31,
258
+ version: "1.0.0",
259
+ },
260
+ {
261
+ id: "sk-32",
262
+ name: "generate-spec",
263
+ display_name: "명세 생성",
264
+ description: "Speckit 워크플로우 통합 실행",
265
+ content: `---
266
+ name: generate-spec
267
+ description: Speckit 워크플로우 통합 실행
268
+ ---
269
+
270
+ # generate-spec
271
+
272
+ 명세 문서를 생성합니다.
273
+ `,
274
+ category: "solutioning",
275
+ package: "core",
276
+ is_active: true,
277
+ is_required: true,
278
+ install_order: 32,
279
+ version: "1.0.0",
280
+ },
281
+ {
282
+ id: "sk-33",
283
+ name: "design-tests",
284
+ display_name: "테스트 설계",
285
+ description: "구현 전 테스트 케이스 설계 (TDD)",
286
+ content: `---
287
+ name: design-tests
288
+ description: 구현 전 테스트 케이스 설계 (TDD)
289
+ ---
290
+
291
+ # design-tests
292
+
293
+ 테스트 케이스를 설계합니다.
294
+ `,
295
+ category: "solutioning",
296
+ package: "core",
297
+ is_active: true,
298
+ is_required: true,
299
+ install_order: 33,
300
+ version: "1.0.0",
301
+ },
302
+ // Implementation (6개)
303
+ {
304
+ id: "sk-40",
305
+ name: "create-sprint",
306
+ display_name: "스프린트 생성",
307
+ description: "Sprint 목표 설정 및 시작",
308
+ content: `---
309
+ name: create-sprint
310
+ description: Sprint 목표 설정 및 시작
311
+ ---
312
+
313
+ # create-sprint
314
+
315
+ 스프린트를 생성하고 시작합니다.
316
+ `,
317
+ category: "implementation",
318
+ package: "core",
319
+ is_active: true,
320
+ is_required: true,
321
+ install_order: 40,
322
+ version: "1.0.0",
323
+ },
324
+ {
325
+ id: "sk-41",
326
+ name: "start-task",
327
+ display_name: "태스크 시작",
328
+ description: "작업 시작 (이슈 상태 변경, 브랜치 생성)",
329
+ content: `---
330
+ name: start-task
331
+ description: 작업 시작 (이슈 상태 변경, 브랜치 생성)
332
+ ---
333
+
334
+ # start-task
335
+
336
+ 태스크를 시작합니다.
337
+ `,
338
+ category: "implementation",
339
+ package: "core",
340
+ is_active: true,
341
+ is_required: true,
342
+ install_order: 41,
343
+ version: "1.0.0",
344
+ },
345
+ {
346
+ id: "sk-42",
347
+ name: "review-task",
348
+ display_name: "태스크 리뷰",
349
+ description: "태스크 이슈 기반 구현 완료 리뷰",
350
+ content: `---
351
+ name: review-task
352
+ description: 태스크 이슈 기반 구현 완료 리뷰
353
+ ---
354
+
355
+ # review-task
356
+
357
+ 태스크 구현을 리뷰합니다.
358
+ `,
359
+ category: "implementation",
360
+ package: "core",
361
+ is_active: true,
362
+ is_required: true,
363
+ install_order: 42,
364
+ version: "1.0.0",
365
+ },
366
+ {
367
+ id: "sk-43",
368
+ name: "write-code",
369
+ display_name: "코드 작성",
370
+ description: "코드 작성, 수정, 구현",
371
+ content: `---
372
+ name: write-code
373
+ description: 코드 작성, 수정, 구현
374
+ ---
375
+
376
+ # write-code
377
+
378
+ 코드를 작성합니다.
379
+ `,
380
+ category: "implementation",
381
+ package: "core",
382
+ is_active: true,
383
+ is_required: true,
384
+ install_order: 43,
385
+ version: "1.0.0",
386
+ },
387
+ {
388
+ id: "sk-44",
389
+ name: "run-code-review",
390
+ display_name: "코드 리뷰",
391
+ description: "프로젝트 통합 코드 리뷰",
392
+ content: `---
393
+ name: run-code-review
394
+ description: 프로젝트 통합 코드 리뷰
395
+ ---
396
+
397
+ # run-code-review
398
+
399
+ 코드 리뷰를 실행합니다.
400
+ `,
401
+ category: "implementation",
402
+ package: "core",
403
+ is_active: true,
404
+ is_required: true,
405
+ install_order: 44,
406
+ version: "1.0.0",
407
+ },
408
+ {
409
+ id: "sk-45",
410
+ name: "close-sprint",
411
+ display_name: "스프린트 종료",
412
+ description: "Sprint 종료 및 회고 정리",
413
+ content: `---
414
+ name: close-sprint
415
+ description: Sprint 종료 및 회고 정리
416
+ ---
417
+
418
+ # close-sprint
419
+
420
+ 스프린트를 종료합니다.
421
+ `,
422
+ category: "implementation",
423
+ package: "core",
424
+ is_active: true,
425
+ is_required: true,
426
+ install_order: 45,
427
+ version: "1.0.0",
428
+ },
429
+ // Supporting (2개)
430
+ {
431
+ id: "sk-50",
432
+ name: "git-workflow",
433
+ display_name: "Git 워크플로우",
434
+ description: "Git 커밋/푸시/PR 자동화",
435
+ content: `---
436
+ name: git-workflow
437
+ description: Git 커밋/푸시/PR 자동화
438
+ ---
439
+
440
+ # git-workflow
441
+
442
+ Git 워크플로우를 자동화합니다.
443
+ `,
444
+ category: "supporting",
445
+ package: "core",
446
+ is_active: true,
447
+ is_required: true,
448
+ install_order: 50,
449
+ version: "1.0.0",
450
+ },
451
+ {
452
+ id: "sk-51",
453
+ name: "notify-slack",
454
+ display_name: "Slack 알림",
455
+ description: "Slack 채널에 메시지 전송",
456
+ content: `---
457
+ name: notify-slack
458
+ description: Slack 채널에 메시지 전송
459
+ ---
460
+
461
+ # notify-slack
462
+
463
+ Slack에 알림을 전송합니다.
464
+ `,
465
+ category: "supporting",
466
+ package: "core",
467
+ is_active: true,
468
+ is_required: true,
469
+ install_order: 51,
470
+ version: "1.0.0",
471
+ },
472
+ ];
473
+ const FALLBACK_COMMANDS = [
474
+ {
475
+ id: "cmd-1",
476
+ name: "help",
477
+ folder: "SEMO",
478
+ content: `# /SEMO:help
479
+
480
+ SEMO 도움말을 표시합니다.
481
+
482
+ ## Usage
483
+
484
+ \`\`\`
485
+ /SEMO:help
486
+ \`\`\`
487
+ `,
488
+ description: "SEMO 도움말",
489
+ is_active: true,
490
+ },
491
+ {
492
+ id: "cmd-2",
493
+ name: "dry-run",
494
+ folder: "SEMO",
495
+ content: `# /SEMO:dry-run
496
+
497
+ 명령을 실행하지 않고 라우팅 결과만 확인합니다.
498
+
499
+ ## Usage
500
+
501
+ \`\`\`
502
+ /SEMO:dry-run {프롬프트}
503
+ \`\`\`
504
+ `,
505
+ description: "명령 검증 (라우팅 시뮬레이션)",
506
+ is_active: true,
507
+ },
508
+ {
509
+ id: "cmd-3",
510
+ name: "greenfield",
511
+ folder: "SEMO-workflow",
512
+ content: `# /SEMO-workflow:greenfield
513
+
514
+ BMad Method Greenfield Workflow를 시작합니다.
515
+
516
+ ## Purpose
517
+
518
+ 새로운 프로젝트를 처음부터 구축하는 4-Phase 워크플로우입니다.
519
+
520
+ \`\`\`
521
+ Phase 1: Discovery (Optional) - 아이디어 발굴 및 분석
522
+ Phase 2: Planning (Required) - PRD/Epic 생성 및 UX 설계
523
+ Phase 3: Solutioning (Required) - 아키텍처 및 명세 작성
524
+ Phase 4: Implementation (Required) - 스프린트 기반 개발
525
+ \`\`\`
526
+
527
+ ## Usage
528
+
529
+ \`\`\`
530
+ /SEMO-workflow:greenfield
531
+ \`\`\`
532
+ `,
533
+ description: "Greenfield 워크플로우 시작",
534
+ is_active: true,
535
+ },
536
+ ];
537
+ const FALLBACK_AGENTS = [
538
+ {
539
+ id: "agent-1",
540
+ name: "orchestrator",
541
+ display_name: "Orchestrator",
542
+ content: `---
543
+ name: orchestrator
544
+ description: SEMO 메인 오케스트레이터
545
+ ---
546
+
547
+ # Orchestrator Agent
548
+
549
+ 사용자 요청을 분석하고 적절한 Agent/Skill로 라우팅합니다.
550
+
551
+ ## Routing Table
552
+
553
+ | Intent | Agent/Skill |
554
+ |--------|-------------|
555
+ | 코드 작성 | write-code |
556
+ | Git 커밋 | git-workflow |
557
+ | 테스트 작성 | write-test |
558
+ `,
559
+ package: "core",
560
+ is_active: true,
561
+ install_order: 1,
562
+ },
563
+ ];
564
+ const FALLBACK_PACKAGES = [
565
+ {
566
+ id: "pkg-core",
567
+ name: "semo-core",
568
+ display_name: "SEMO Core",
569
+ description: "원칙, 오케스트레이터",
570
+ layer: "standard",
571
+ package_type: "standard",
572
+ version: "3.14.0",
573
+ is_active: true,
574
+ is_required: true,
575
+ install_order: 10,
576
+ },
577
+ {
578
+ id: "pkg-skills",
579
+ name: "semo-skills",
580
+ display_name: "SEMO Skills",
581
+ description: "19개 핵심 스킬",
582
+ layer: "standard",
583
+ package_type: "standard",
584
+ version: "3.14.0",
585
+ is_active: true,
586
+ is_required: true,
587
+ install_order: 20,
588
+ },
589
+ ];
590
+ // ============================================================
591
+ // DB 조회 함수
592
+ // ============================================================
593
+ /**
594
+ * 활성 스킬 목록 조회
595
+ */
596
+ async function getActiveSkills() {
597
+ const isConnected = await checkDbConnection();
598
+ if (!isConnected) {
599
+ console.warn("⚠️ DB 연결 실패, 폴백 스킬 목록 사용 (19개)");
600
+ return FALLBACK_SKILLS.filter((s) => s.is_active);
601
+ }
602
+ try {
603
+ const result = await getPool().query(`
604
+ SELECT id, name, display_name, description, content, category, package,
605
+ is_active, is_required, install_order, version
606
+ FROM semo.skills
607
+ WHERE is_active = true
608
+ ORDER BY install_order
609
+ `);
610
+ return result.rows;
611
+ }
612
+ catch (error) {
613
+ console.warn("⚠️ 스킬 조회 실패, 폴백 데이터 사용:", error);
614
+ return FALLBACK_SKILLS.filter((s) => s.is_active);
615
+ }
616
+ }
617
+ /**
618
+ * 스킬 이름 목록만 조회
619
+ */
620
+ async function getActiveSkillNames() {
621
+ const skills = await getActiveSkills();
622
+ return skills.map((s) => s.name);
623
+ }
624
+ /**
625
+ * 커맨드 목록 조회
626
+ */
627
+ async function getCommands() {
628
+ const isConnected = await checkDbConnection();
629
+ if (!isConnected) {
630
+ console.warn("⚠️ DB 연결 실패, 폴백 커맨드 목록 사용");
631
+ return FALLBACK_COMMANDS.filter((c) => c.is_active);
632
+ }
633
+ try {
634
+ const result = await getPool().query(`
635
+ SELECT id, name, folder, content, description, is_active
636
+ FROM semo.commands
637
+ WHERE is_active = true
638
+ `);
639
+ return result.rows;
640
+ }
641
+ catch (error) {
642
+ console.warn("⚠️ 커맨드 조회 실패, 폴백 데이터 사용:", error);
643
+ return FALLBACK_COMMANDS.filter((c) => c.is_active);
644
+ }
645
+ }
646
+ /**
647
+ * 에이전트 목록 조회
648
+ */
649
+ async function getAgents() {
650
+ const isConnected = await checkDbConnection();
651
+ if (!isConnected) {
652
+ console.warn("⚠️ DB 연결 실패, 폴백 에이전트 목록 사용");
653
+ return FALLBACK_AGENTS.filter((a) => a.is_active);
654
+ }
655
+ try {
656
+ const result = await getPool().query(`
657
+ SELECT id, name, display_name, content, package, is_active, install_order
658
+ FROM semo.agents
659
+ WHERE is_active = true
660
+ ORDER BY install_order
661
+ `);
662
+ return result.rows;
663
+ }
664
+ catch (error) {
665
+ console.warn("⚠️ 에이전트 조회 실패, 폴백 데이터 사용:", error);
666
+ return FALLBACK_AGENTS.filter((a) => a.is_active);
667
+ }
668
+ }
669
+ /**
670
+ * 패키지 목록 조회
671
+ */
672
+ async function getPackages(layer) {
673
+ const isConnected = await checkDbConnection();
674
+ if (!isConnected) {
675
+ console.warn("⚠️ DB 연결 실패, 폴백 패키지 목록 사용");
676
+ const fallback = FALLBACK_PACKAGES.filter((p) => p.is_active);
677
+ return layer ? fallback.filter((p) => p.layer === layer) : fallback;
678
+ }
679
+ try {
680
+ let query = `
681
+ SELECT id, name, display_name, description, layer, package_type,
682
+ version, is_active, is_required, install_order
683
+ FROM semo.packages
684
+ WHERE is_active = true
685
+ `;
686
+ const params = [];
687
+ if (layer) {
688
+ query += ` AND layer = $1`;
689
+ params.push(layer);
690
+ }
691
+ query += ` ORDER BY install_order`;
692
+ const result = await getPool().query(query, params);
693
+ return result.rows;
694
+ }
695
+ catch (error) {
696
+ console.warn("⚠️ 패키지 조회 실패, 폴백 데이터 사용:", error);
697
+ const fallback = FALLBACK_PACKAGES.filter((p) => p.is_active);
698
+ return layer ? fallback.filter((p) => p.layer === layer) : fallback;
699
+ }
700
+ }
701
+ /**
702
+ * 카테고리별 스킬 개수 조회
703
+ */
704
+ async function getSkillCountByCategory() {
705
+ const skills = await getActiveSkills();
706
+ const counts = {};
707
+ for (const skill of skills) {
708
+ counts[skill.category] = (counts[skill.category] || 0) + 1;
709
+ }
710
+ return counts;
711
+ }
712
+ /**
713
+ * DB 연결 종료
714
+ */
715
+ async function closeConnection() {
716
+ if (pool) {
717
+ await pool.end();
718
+ pool = null;
719
+ dbAvailable = null;
720
+ }
721
+ }
722
+ /**
723
+ * DB 연결 상태 확인
724
+ */
725
+ async function isDbConnected() {
726
+ return checkDbConnection();
727
+ }