aiwf 0.3.21 → 0.3.23

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 (140) hide show
  1. package/package.json +3 -2
  2. package/src/cli/index.js +39 -336
  3. package/src/lib/installer.js +310 -90
  4. package/src/utils/messages.js +24 -0
  5. package/src/DEPENDENCY_MAP.md +0 -90
  6. package/src/cli/cache-cli.js +0 -459
  7. package/src/cli/checkpoint-cli.js +0 -417
  8. package/src/cli/language-cli.js +0 -286
  9. package/src/cli/sprint-cli.js +0 -287
  10. package/src/commands/ai-tool.js +0 -383
  11. package/src/commands/compress.js +0 -60
  12. package/src/commands/create-project.js +0 -160
  13. package/src/commands/evaluate.js +0 -459
  14. package/src/commands/persona.js +0 -309
  15. package/src/commands/sprint-task.js +0 -262
  16. package/src/commands/token.js +0 -312
  17. package/src/lib/ai-persona-manager.js +0 -711
  18. package/src/lib/cache-system.js +0 -332
  19. package/src/lib/context-engine.js +0 -568
  20. package/src/lib/github-integration.js +0 -402
  21. package/src/lib/memory-profiler.js +0 -471
  22. package/src/lib/metrics-collector.js +0 -885
  23. package/src/lib/offline-detector.js +0 -386
  24. package/src/lib/resource-loader-enhanced.js +0 -399
  25. package/src/lib/resource-loader.js +0 -250
  26. package/src/lib/resources/commands/ai-persona.js +0 -602
  27. package/src/lib/resources/commands/compress-context.js +0 -389
  28. package/src/lib/resources/commands/evaluate.js +0 -246
  29. package/src/lib/resources/commands/persona-context-apply.js +0 -562
  30. package/src/lib/resources/commands/token-tracking.js +0 -443
  31. package/src/lib/resources/config/commit-patterns.js +0 -103
  32. package/src/lib/resources/config/language.json +0 -6
  33. package/src/lib/resources/personas/PERSONA_INDEX.md +0 -57
  34. package/src/lib/resources/personas/analyst.json +0 -44
  35. package/src/lib/resources/personas/architect/best_practices.md +0 -136
  36. package/src/lib/resources/personas/architect/knowledge_base.md +0 -377
  37. package/src/lib/resources/personas/architect.json +0 -44
  38. package/src/lib/resources/personas/backend/best_practices.md +0 -766
  39. package/src/lib/resources/personas/backend/knowledge_base.md +0 -1070
  40. package/src/lib/resources/personas/data_analyst/best_practices.md +0 -594
  41. package/src/lib/resources/personas/data_analyst/knowledge_base.md +0 -1057
  42. package/src/lib/resources/personas/developer.json +0 -44
  43. package/src/lib/resources/personas/developer.md +0 -37
  44. package/src/lib/resources/personas/evaluation_criteria.json +0 -137
  45. package/src/lib/resources/personas/frontend/best_practices.md +0 -445
  46. package/src/lib/resources/personas/frontend/knowledge_base.md +0 -729
  47. package/src/lib/resources/personas/persona-index.json +0 -31
  48. package/src/lib/resources/personas/reviewer.json +0 -44
  49. package/src/lib/resources/personas/security/best_practices.md +0 -307
  50. package/src/lib/resources/personas/security/knowledge_base.md +0 -498
  51. package/src/lib/resources/personas/tester.json +0 -44
  52. package/src/lib/resources/templates/README.md +0 -78
  53. package/src/lib/resources/templates/api-server/config.json +0 -64
  54. package/src/lib/resources/templates/api-server/template/.aiwf/config.json +0 -56
  55. package/src/lib/resources/templates/api-server/template/.aiwf/feature-ledger.json +0 -42
  56. package/src/lib/resources/templates/api-server/template/.aiwf/personas/backend-engineer.json +0 -40
  57. package/src/lib/resources/templates/api-server/template/.aiwf/scripts/cli.js +0 -111
  58. package/src/lib/resources/templates/api-server/template/.env.example +0 -29
  59. package/src/lib/resources/templates/api-server/template/.eslintrc.json +0 -23
  60. package/src/lib/resources/templates/api-server/template/README.md +0 -171
  61. package/src/lib/resources/templates/api-server/template/jest.config.js +0 -26
  62. package/src/lib/resources/templates/api-server/template/nodemon.json +0 -9
  63. package/src/lib/resources/templates/api-server/template/package.json +0 -61
  64. package/src/lib/resources/templates/api-server/template/src/app.ts +0 -60
  65. package/src/lib/resources/templates/api-server/template/src/config/swagger.ts +0 -38
  66. package/src/lib/resources/templates/api-server/template/src/controllers/aiwfController.ts +0 -54
  67. package/src/lib/resources/templates/api-server/template/src/controllers/authController.ts +0 -128
  68. package/src/lib/resources/templates/api-server/template/src/controllers/statusController.ts +0 -28
  69. package/src/lib/resources/templates/api-server/template/src/index.ts +0 -28
  70. package/src/lib/resources/templates/api-server/template/src/middleware/aiwfMiddleware.ts +0 -50
  71. package/src/lib/resources/templates/api-server/template/src/middleware/authMiddleware.ts +0 -41
  72. package/src/lib/resources/templates/api-server/template/src/middleware/errorHandler.ts +0 -42
  73. package/src/lib/resources/templates/api-server/template/src/middleware/notFoundHandler.ts +0 -14
  74. package/src/lib/resources/templates/api-server/template/src/middleware/requestLogger.ts +0 -20
  75. package/src/lib/resources/templates/api-server/template/src/routes/aiwf.ts +0 -31
  76. package/src/lib/resources/templates/api-server/template/src/routes/index.ts +0 -13
  77. package/src/lib/resources/templates/api-server/template/src/routes/v1/index.ts +0 -67
  78. package/src/lib/resources/templates/api-server/template/src/utils/logger.ts +0 -37
  79. package/src/lib/resources/templates/api-server/template/tests/app.test.ts +0 -40
  80. package/src/lib/resources/templates/api-server/template/tsconfig.json +0 -43
  81. package/src/lib/resources/templates/npm-library/config.json +0 -61
  82. package/src/lib/resources/templates/npm-library/template/LICENSE +0 -21
  83. package/src/lib/resources/templates/npm-library/template/README.md +0 -201
  84. package/src/lib/resources/templates/npm-library/template/package.json +0 -78
  85. package/src/lib/resources/templates/web-app/config.json +0 -53
  86. package/src/lib/resources/templates/web-app/template/.aiwf/config.json +0 -54
  87. package/src/lib/resources/templates/web-app/template/.aiwf/feature-ledger.json +0 -37
  88. package/src/lib/resources/templates/web-app/template/.aiwf/personas/fullstack-developer.json +0 -40
  89. package/src/lib/resources/templates/web-app/template/.aiwf/scripts/cli.js +0 -110
  90. package/src/lib/resources/templates/web-app/template/.eslintrc.cjs +0 -20
  91. package/src/lib/resources/templates/web-app/template/README.md +0 -151
  92. package/src/lib/resources/templates/web-app/template/index.html +0 -14
  93. package/src/lib/resources/templates/web-app/template/package.json +0 -44
  94. package/src/lib/resources/templates/web-app/template/postcss.config.js +0 -6
  95. package/src/lib/resources/templates/web-app/template/public/vite.svg +0 -1
  96. package/src/lib/resources/templates/web-app/template/src/App.tsx +0 -21
  97. package/src/lib/resources/templates/web-app/template/src/components/Layout.tsx +0 -57
  98. package/src/lib/resources/templates/web-app/template/src/components/aiwf/ContextStatus.tsx +0 -107
  99. package/src/lib/resources/templates/web-app/template/src/components/aiwf/TokenUsage.tsx +0 -71
  100. package/src/lib/resources/templates/web-app/template/src/index.css +0 -60
  101. package/src/lib/resources/templates/web-app/template/src/main.tsx +0 -10
  102. package/src/lib/resources/templates/web-app/template/src/pages/AiwfDashboard.tsx +0 -57
  103. package/src/lib/resources/templates/web-app/template/src/pages/HomePage.tsx +0 -89
  104. package/src/lib/resources/templates/web-app/template/src/pages/NotFound.tsx +0 -25
  105. package/src/lib/resources/templates/web-app/template/src/stores/aiwfStore.ts +0 -126
  106. package/src/lib/resources/templates/web-app/template/src/types/global.d.ts +0 -9
  107. package/src/lib/resources/templates/web-app/template/src/vite-env.d.ts +0 -1
  108. package/src/lib/resources/templates/web-app/template/tailwind.config.js +0 -30
  109. package/src/lib/resources/templates/web-app/template/tsconfig.json +0 -37
  110. package/src/lib/resources/templates/web-app/template/tsconfig.node.json +0 -10
  111. package/src/lib/resources/templates/web-app/template/vite.config.ts +0 -23
  112. package/src/lib/resources/utils/background-monitor.js +0 -223
  113. package/src/lib/resources/utils/compression-metrics.js +0 -1031
  114. package/src/lib/resources/utils/compression-strategies.js +0 -557
  115. package/src/lib/resources/utils/content-normalizer.js +0 -455
  116. package/src/lib/resources/utils/context-compressor.js +0 -583
  117. package/src/lib/resources/utils/context-rule-parser.js +0 -180
  118. package/src/lib/resources/utils/context-token-monitor.js +0 -463
  119. package/src/lib/resources/utils/context-update-manager.js +0 -502
  120. package/src/lib/resources/utils/git-utils.js +0 -220
  121. package/src/lib/resources/utils/importance-classifier.js +0 -645
  122. package/src/lib/resources/utils/information-filter.js +0 -710
  123. package/src/lib/resources/utils/persona-aware-compressor.js +0 -598
  124. package/src/lib/resources/utils/prompt-injector.js +0 -242
  125. package/src/lib/resources/utils/simplified-evaluator.js +0 -119
  126. package/src/lib/resources/utils/text-summarizer.js +0 -492
  127. package/src/lib/resources/utils/token-counter.js +0 -177
  128. package/src/lib/resources/utils/token-monitor.js +0 -484
  129. package/src/lib/resources/utils/token-reporter.js +0 -452
  130. package/src/lib/resources/utils/token-storage.js +0 -433
  131. package/src/lib/resources/utils/token-tracker.js +0 -283
  132. package/src/lib/state/priority-calculator.js +0 -217
  133. package/src/lib/state/state-index.js +0 -155
  134. package/src/lib/state/task-scanner.js +0 -328
  135. package/src/lib/task-analyzer.js +0 -599
  136. package/src/lib/template-cache-system.js +0 -559
  137. package/src/lib/template-downloader.js +0 -467
  138. package/src/lib/template-version-manager.js +0 -491
  139. package/src/lib/token-optimizer.js +0 -517
  140. package/src/utils/engineering-guard.js +0 -399
@@ -1,502 +0,0 @@
1
- /**
2
- * 컨텍스트 실시간 업데이트 관리자
3
- * 페르소나 컨텍스트 파일의 변경을 감지하고 실시간으로 반영하는 모듈
4
- */
5
-
6
- const fs = require('fs');
7
- const path = require('path');
8
- const EventEmitter = require('events');
9
- const chokidar = require('chokidar');
10
- const ContextRuleParser = require('./context-rule-parser');
11
-
12
- class ContextUpdateManager extends EventEmitter {
13
- constructor() {
14
- super();
15
- this.contextParser = new ContextRuleParser();
16
- this.watchers = new Map();
17
- this.updateQueue = [];
18
- this.isProcessing = false;
19
- this.pollingInterval = null;
20
- this.lastUpdateTimes = new Map();
21
- }
22
-
23
- /**
24
- * 컨텍스트 파일 감시 시작
25
- * @param {Array} personas - 감시할 페르소나 목록
26
- * @param {Object} options - 감시 옵션
27
- */
28
- startWatching(personas = ['architect', 'frontend', 'backend', 'data_analyst', 'security'], options = {}) {
29
- const watchOptions = {
30
- persistent: true,
31
- ignoreInitial: true,
32
- awaitWriteFinish: {
33
- stabilityThreshold: 1000,
34
- pollInterval: 100
35
- },
36
- ...options
37
- };
38
-
39
- personas.forEach(persona => {
40
- const contextPath = path.join(
41
- process.cwd(),
42
- '.aiwf',
43
- '07_AI_PERSONAS',
44
- persona,
45
- 'context_rules.md'
46
- );
47
-
48
- try {
49
- // 파일이 존재하는지 확인
50
- if (!fs.existsSync(contextPath)) {
51
- this.createDefaultContextFile(persona, contextPath);
52
- }
53
-
54
- // Chokidar 감시자 생성
55
- const watcher = chokidar.watch(contextPath, watchOptions);
56
-
57
- watcher
58
- .on('change', () => this.handleFileChange(persona, contextPath))
59
- .on('add', () => this.handleFileAdd(persona, contextPath))
60
- .on('unlink', () => this.handleFileRemove(persona, contextPath))
61
- .on('error', error => this.handleWatchError(persona, error));
62
-
63
- this.watchers.set(persona, watcher);
64
- console.log(`컨텍스트 감시 시작: ${persona}`);
65
- } catch (error) {
66
- console.error(`감시 설정 실패 (${persona}):`, error);
67
- // 폴백: 폴링 방식으로 전환
68
- this.startPolling(persona, contextPath);
69
- }
70
- });
71
-
72
- // 이벤트 리스너 설정
73
- this.setupEventHandlers();
74
- }
75
-
76
- /**
77
- * 기본 컨텍스트 파일 생성
78
- * @param {string} persona - 페르소나 이름
79
- * @param {string} filePath - 파일 경로
80
- */
81
- createDefaultContextFile(persona, filePath) {
82
- const defaultContexts = {
83
- architect: `---
84
- persona_name: architect
85
- analysis_approach: 시스템 설계 중심
86
- design_principles:
87
- - 확장성
88
- - 유지보수성
89
- - 성능
90
- communication_style: 구조적이고 논리적
91
- ---
92
-
93
- # 아키텍트 페르소나 컨텍스트
94
-
95
- ## 핵심 역할
96
- 시스템 전체 구조를 설계하고 기술적 결정을 내리는 역할을 수행합니다.
97
-
98
- ## 분석 접근법
99
- - 전체 시스템 관점에서 문제 분석
100
- - 컴포넌트 간 상호작용 고려
101
- - 장기적 확장성과 유지보수성 중시
102
-
103
- ## 소통 스타일
104
- - 다이어그램과 구조도를 활용한 설명
105
- - 기술적 트레이드오프 명확히 제시
106
- - 단계별 구현 계획 제공`,
107
-
108
- frontend: `---
109
- persona_name: frontend
110
- analysis_approach: UI/UX 중심
111
- design_principles:
112
- - 사용성
113
- - 접근성
114
- - 반응성
115
- communication_style: 시각적이고 직관적
116
- ---
117
-
118
- # 프론트엔드 페르소나 컨텍스트
119
-
120
- ## 핵심 역할
121
- 사용자 인터페이스와 경험을 설계하고 구현하는 역할을 수행합니다.
122
-
123
- ## 분석 접근법
124
- - 사용자 관점에서 문제 접근
125
- - 시각적 요소와 인터랙션 중시
126
- - 다양한 디바이스와 브라우저 고려
127
-
128
- ## 소통 스타일
129
- - 목업과 프로토타입 활용
130
- - 사용자 시나리오 기반 설명
131
- - 직관적이고 이해하기 쉬운 표현`,
132
-
133
- backend: `---
134
- persona_name: backend
135
- analysis_approach: API 및 데이터 처리 중심
136
- design_principles:
137
- - 보안
138
- - 효율성
139
- - 확장성
140
- communication_style: 기술적이고 정확함
141
- ---
142
-
143
- # 백엔드 페르소나 컨텍스트
144
-
145
- ## 핵심 역할
146
- 서버 사이드 로직과 데이터 처리를 담당하는 역할을 수행합니다.
147
-
148
- ## 분석 접근법
149
- - 데이터 흐름과 처리 로직 중심
150
- - 성능과 보안 최적화 고려
151
- - API 설계와 데이터베이스 구조 중시
152
-
153
- ## 소통 스타일
154
- - API 문서와 데이터 스키마 제공
155
- - 기술적 세부사항 명확히 전달
156
- - 성능 지표와 보안 고려사항 강조`,
157
-
158
- data_analyst: `---
159
- persona_name: data_analyst
160
- analysis_approach: 데이터 기반 의사결정
161
- design_principles:
162
- - 정확성
163
- - 통찰력
164
- - 시각화
165
- communication_style: 분석적이고 통계적
166
- ---
167
-
168
- # 데이터 분석가 페르소나 컨텍스트
169
-
170
- ## 핵심 역할
171
- 데이터를 분석하여 인사이트를 도출하고 의사결정을 지원하는 역할을 수행합니다.
172
-
173
- ## 분석 접근법
174
- - 정량적 데이터 분석 우선
175
- - 통계적 방법론 적용
176
- - 시각화를 통한 인사이트 전달
177
-
178
- ## 소통 스타일
179
- - 차트와 그래프 활용
180
- - 데이터 기반 근거 제시
181
- - 객관적이고 중립적인 관점`,
182
-
183
- security: `---
184
- persona_name: security
185
- analysis_approach: 보안 취약점 중심
186
- design_principles:
187
- - 보안성
188
- - 무결성
189
- - 기밀성
190
- communication_style: 신중하고 방어적
191
- ---
192
-
193
- # 보안 페르소나 컨텍스트
194
-
195
- ## 핵심 역할
196
- 시스템의 보안 취약점을 식별하고 보호 방안을 제시하는 역할을 수행합니다.
197
-
198
- ## 분석 접근법
199
- - 위협 모델링과 취약점 분석
200
- - 보안 모범 사례 적용
201
- - 컴플라이언스 요구사항 고려
202
-
203
- ## 소통 스타일
204
- - 위험도 평가와 우선순위 제시
205
- - 구체적인 보안 대책 제안
206
- - 예방적 접근과 지속적 모니터링 강조`
207
- };
208
-
209
- const content = defaultContexts[persona] || `---
210
- persona_name: ${persona}
211
- analysis_approach: 일반적 접근
212
- design_principles:
213
- - 품질
214
- - 효율성
215
- communication_style: 표준적
216
- ---
217
-
218
- # ${persona} 페르소나 컨텍스트
219
-
220
- 기본 페르소나 컨텍스트입니다.`;
221
-
222
- // 디렉토리 생성
223
- const dir = path.dirname(filePath);
224
- if (!fs.existsSync(dir)) {
225
- fs.mkdirSync(dir, { recursive: true });
226
- }
227
-
228
- // 파일 생성
229
- fs.writeFileSync(filePath, content, 'utf-8');
230
- console.log(`기본 컨텍스트 파일 생성: ${persona}`);
231
- }
232
-
233
- /**
234
- * 파일 변경 처리
235
- * @param {string} persona - 페르소나 이름
236
- * @param {string} filePath - 파일 경로
237
- */
238
- async handleFileChange(persona, filePath) {
239
- console.log(`컨텍스트 변경 감지: ${persona}`);
240
-
241
- // 업데이트 큐에 추가
242
- this.updateQueue.push({
243
- type: 'change',
244
- persona,
245
- filePath,
246
- timestamp: new Date().toISOString()
247
- });
248
-
249
- // 큐 처리
250
- this.processUpdateQueue();
251
- }
252
-
253
- /**
254
- * 파일 추가 처리
255
- * @param {string} persona - 페르소나 이름
256
- * @param {string} filePath - 파일 경로
257
- */
258
- handleFileAdd(persona, filePath) {
259
- console.log(`컨텍스트 파일 추가: ${persona}`);
260
-
261
- this.updateQueue.push({
262
- type: 'add',
263
- persona,
264
- filePath,
265
- timestamp: new Date().toISOString()
266
- });
267
-
268
- this.processUpdateQueue();
269
- }
270
-
271
- /**
272
- * 파일 제거 처리
273
- * @param {string} persona - 페르소나 이름
274
- * @param {string} filePath - 파일 경로
275
- */
276
- handleFileRemove(persona, filePath) {
277
- console.log(`컨텍스트 파일 제거: ${persona}`);
278
-
279
- this.updateQueue.push({
280
- type: 'remove',
281
- persona,
282
- filePath,
283
- timestamp: new Date().toISOString()
284
- });
285
-
286
- this.processUpdateQueue();
287
- }
288
-
289
- /**
290
- * 감시 오류 처리
291
- * @param {string} persona - 페르소나 이름
292
- * @param {Error} error - 오류 객체
293
- */
294
- handleWatchError(persona, error) {
295
- console.error(`감시 오류 (${persona}):`, error);
296
-
297
- // 폴링으로 전환
298
- const contextPath = path.join(
299
- process.cwd(),
300
- '.aiwf',
301
- '07_AI_PERSONAS',
302
- persona,
303
- 'context_rules.md'
304
- );
305
- this.startPolling(persona, contextPath);
306
- }
307
-
308
- /**
309
- * 폴링 방식으로 파일 감시
310
- * @param {string} persona - 페르소나 이름
311
- * @param {string} filePath - 파일 경로
312
- */
313
- startPolling(persona, filePath) {
314
- const pollInterval = 5000; // 5초마다 확인
315
-
316
- const checkFile = async () => {
317
- try {
318
- const stats = await fs.promises.stat(filePath);
319
- const lastModified = stats.mtimeMs;
320
- const previousModified = this.lastUpdateTimes.get(persona);
321
-
322
- if (previousModified && lastModified !== previousModified) {
323
- this.handleFileChange(persona, filePath);
324
- }
325
-
326
- this.lastUpdateTimes.set(persona, lastModified);
327
- } catch (error) {
328
- // 파일이 없으면 생성
329
- if (error.code === 'ENOENT') {
330
- this.createDefaultContextFile(persona, filePath);
331
- }
332
- }
333
- };
334
-
335
- // 기존 인터벌 정리
336
- if (this.pollingInterval) {
337
- clearInterval(this.pollingInterval);
338
- }
339
-
340
- // 새 인터벌 설정
341
- this.pollingInterval = setInterval(checkFile, pollInterval);
342
- console.log(`폴링 모드로 전환: ${persona}`);
343
- }
344
-
345
- /**
346
- * 업데이트 큐 처리
347
- */
348
- async processUpdateQueue() {
349
- if (this.isProcessing || this.updateQueue.length === 0) {
350
- return;
351
- }
352
-
353
- this.isProcessing = true;
354
-
355
- while (this.updateQueue.length > 0) {
356
- const update = this.updateQueue.shift();
357
-
358
- try {
359
- await this.processUpdate(update);
360
- } catch (error) {
361
- console.error('업데이트 처리 오류:', error);
362
- this.emit('error', { update, error });
363
- }
364
- }
365
-
366
- this.isProcessing = false;
367
- }
368
-
369
- /**
370
- * 개별 업데이트 처리
371
- * @param {Object} update - 업데이트 정보
372
- */
373
- async processUpdate(update) {
374
- const { type, persona, filePath, timestamp } = update;
375
-
376
- switch (type) {
377
- case 'change':
378
- case 'add':
379
- // 컨텍스트 다시 파싱
380
- const newContext = await this.contextParser.parseContextRules(persona);
381
-
382
- // 캐시 무효화
383
- this.contextParser.clearCache();
384
-
385
- // 이벤트 발생
386
- this.emit('contextUpdated', {
387
- persona,
388
- context: newContext,
389
- updateType: type,
390
- timestamp
391
- });
392
-
393
- console.log(`컨텍스트 업데이트 완료: ${persona}`);
394
- break;
395
-
396
- case 'remove':
397
- // 기본 컨텍스트로 복원
398
- this.createDefaultContextFile(persona, filePath);
399
-
400
- this.emit('contextRemoved', {
401
- persona,
402
- timestamp
403
- });
404
- break;
405
- }
406
- }
407
-
408
- /**
409
- * 이벤트 핸들러 설정
410
- */
411
- setupEventHandlers() {
412
- // 컨텍스트 업데이트 시 로깅
413
- this.on('contextUpdated', (data) => {
414
- console.log(`[이벤트] 컨텍스트 업데이트: ${data.persona} (${data.updateType})`);
415
- });
416
-
417
- // 오류 발생 시 로깅
418
- this.on('error', (data) => {
419
- console.error(`[이벤트] 오류 발생:`, data.error);
420
- });
421
- }
422
-
423
- /**
424
- * 모든 감시 중지
425
- */
426
- stopWatching() {
427
- // Chokidar 감시자 정리
428
- this.watchers.forEach((watcher, persona) => {
429
- watcher.close();
430
- console.log(`감시 중지: ${persona}`);
431
- });
432
- this.watchers.clear();
433
-
434
- // 폴링 인터벌 정리
435
- if (this.pollingInterval) {
436
- clearInterval(this.pollingInterval);
437
- this.pollingInterval = null;
438
- }
439
-
440
- // 큐 초기화
441
- this.updateQueue = [];
442
- this.isProcessing = false;
443
- }
444
-
445
- /**
446
- * 특정 페르소나 감시 중지
447
- * @param {string} persona - 페르소나 이름
448
- */
449
- stopWatchingPersona(persona) {
450
- const watcher = this.watchers.get(persona);
451
- if (watcher) {
452
- watcher.close();
453
- this.watchers.delete(persona);
454
- console.log(`감시 중지: ${persona}`);
455
- }
456
- }
457
-
458
- /**
459
- * 감시 상태 확인
460
- * @returns {Object} 감시 상태 정보
461
- */
462
- getWatchStatus() {
463
- const activeWatchers = Array.from(this.watchers.keys());
464
- const queueLength = this.updateQueue.length;
465
- const isPolling = this.pollingInterval !== null;
466
-
467
- return {
468
- activeWatchers,
469
- watcherCount: activeWatchers.length,
470
- queueLength,
471
- isProcessing: this.isProcessing,
472
- isPolling,
473
- lastUpdateTimes: Object.fromEntries(this.lastUpdateTimes)
474
- };
475
- }
476
-
477
- /**
478
- * 강제 업데이트 트리거
479
- * @param {string} persona - 페르소나 이름
480
- */
481
- forceUpdate(persona) {
482
- const contextPath = path.join(
483
- process.cwd(),
484
- '.aiwf',
485
- '07_AI_PERSONAS',
486
- persona,
487
- 'context_rules.md'
488
- );
489
-
490
- this.handleFileChange(persona, contextPath);
491
- }
492
-
493
- /**
494
- * 모든 페르소나 강제 업데이트
495
- */
496
- forceUpdateAll() {
497
- const personas = Array.from(this.watchers.keys());
498
- personas.forEach(persona => this.forceUpdate(persona));
499
- }
500
- }
501
-
502
- module.exports = ContextUpdateManager;
@@ -1,220 +0,0 @@
1
- const { exec } = require('child_process');
2
- const { promisify } = require('util');
3
- const execAsync = promisify(exec);
4
- const path = require('path');
5
- const { extractFeatureIds, extractFeatureIdFromBranch } = require('../config/commit-patterns');
6
-
7
- /**
8
- * Git 커밋 정보를 추출하는 유틸리티 모듈
9
- */
10
-
11
- /**
12
- * Git 명령어 실행
13
- * @param {string} command - 실행할 git 명령어
14
- * @param {string} cwd - 작업 디렉토리 (선택사항)
15
- * @returns {Promise<string>} - 명령어 출력
16
- */
17
- async function runGitCommand(command, cwd = process.cwd()) {
18
- try {
19
- const { stdout, stderr } = await execAsync(`git ${command}`, { cwd });
20
- if (stderr && !stderr.includes('warning:')) {
21
- throw new Error(`Git command failed: ${stderr}`);
22
- }
23
- return stdout.trim();
24
- } catch (error) {
25
- throw new Error(`Git command execution failed: ${error.message}`);
26
- }
27
- }
28
-
29
- /**
30
- * 현재 브랜치 이름 가져오기
31
- * @returns {Promise<string>} - 브랜치 이름
32
- */
33
- async function getCurrentBranch() {
34
- return await runGitCommand('rev-parse --abbrev-ref HEAD');
35
- }
36
-
37
- /**
38
- * 커밋 정보 객체 구조
39
- * @typedef {Object} CommitInfo
40
- * @property {string} hash - 커밋 해시
41
- * @property {string} author - 작성자
42
- * @property {string} date - 커밋 날짜
43
- * @property {string} message - 커밋 메시지
44
- * @property {Array<string>} featureIds - 관련 Feature ID 목록
45
- */
46
-
47
- /**
48
- * 특정 커밋의 상세 정보 가져오기
49
- * @param {string} commitHash - 커밋 해시
50
- * @returns {Promise<CommitInfo>} - 커밋 정보
51
- */
52
- async function getCommitInfo(commitHash) {
53
- const format = '%H%n%an%n%aI%n%s%n%b';
54
- const output = await runGitCommand(`show -s --format="${format}" ${commitHash}`);
55
- const lines = output.split('\n');
56
-
57
- const message = lines.slice(3).join('\n').trim();
58
- const featureIds = extractFeatureIds(message);
59
-
60
- return {
61
- hash: lines[0],
62
- author: lines[1],
63
- date: lines[2],
64
- message: message,
65
- featureIds: featureIds
66
- };
67
- }
68
-
69
- /**
70
- * 커밋 범위에서 Feature 관련 커밋 찾기
71
- * @param {string} since - 시작 날짜 (예: '2025-01-01')
72
- * @param {string} until - 종료 날짜 (선택사항)
73
- * @returns {Promise<Array<CommitInfo>>} - Feature 관련 커밋 목록
74
- */
75
- async function getFeatureRelatedCommits(since, until = 'HEAD') {
76
- try {
77
- // git log 명령어 구성
78
- let command = `log --since="${since}"`;
79
- if (until !== 'HEAD') {
80
- command += ` --until="${until}"`;
81
- }
82
- command += ' --pretty=format:"%H" --grep="FL[0-9]\\{3\\}"';
83
-
84
- const output = await runGitCommand(command);
85
- if (!output) {
86
- return [];
87
- }
88
-
89
- const commitHashes = output.split('\n').filter(Boolean);
90
- const commits = [];
91
-
92
- for (const hash of commitHashes) {
93
- const commitInfo = await getCommitInfo(hash);
94
- if (commitInfo.featureIds.length > 0) {
95
- commits.push(commitInfo);
96
- }
97
- }
98
-
99
- return commits;
100
- } catch (error) {
101
- console.error('Error getting feature related commits:', error);
102
- return [];
103
- }
104
- }
105
-
106
- /**
107
- * 특정 Feature ID와 관련된 모든 커밋 찾기
108
- * @param {string} featureId - Feature ID (예: 'FL001')
109
- * @returns {Promise<Array<CommitInfo>>} - 해당 Feature의 커밋 목록
110
- */
111
- async function getCommitsByFeatureId(featureId) {
112
- try {
113
- const command = `log --pretty=format:"%H" --grep="${featureId}"`;
114
- const output = await runGitCommand(command);
115
-
116
- if (!output) {
117
- return [];
118
- }
119
-
120
- const commitHashes = output.split('\n').filter(Boolean);
121
- const commits = [];
122
-
123
- for (const hash of commitHashes) {
124
- const commitInfo = await getCommitInfo(hash);
125
- if (commitInfo.featureIds.includes(featureId)) {
126
- commits.push(commitInfo);
127
- }
128
- }
129
-
130
- return commits;
131
- } catch (error) {
132
- console.error(`Error getting commits for feature ${featureId}:`, error);
133
- return [];
134
- }
135
- }
136
-
137
- /**
138
- * 현재 브랜치의 Feature ID 추출
139
- * @returns {Promise<string|null>} - Feature ID 또는 null
140
- */
141
- async function getCurrentFeatureId() {
142
- try {
143
- const branch = await getCurrentBranch();
144
- return extractFeatureIdFromBranch(branch);
145
- } catch (error) {
146
- console.error('Error getting current feature ID:', error);
147
- return null;
148
- }
149
- }
150
-
151
- /**
152
- * 최근 N개의 커밋에서 Feature 관련 커밋 찾기
153
- * @param {number} count - 확인할 커밋 수
154
- * @returns {Promise<Array<CommitInfo>>} - Feature 관련 커밋 목록
155
- */
156
- async function getRecentFeatureCommits(count = 10) {
157
- try {
158
- const command = `log -${count} --pretty=format:"%H"`;
159
- const output = await runGitCommand(command);
160
-
161
- if (!output) {
162
- return [];
163
- }
164
-
165
- const commitHashes = output.split('\n').filter(Boolean);
166
- const featureCommits = [];
167
-
168
- for (const hash of commitHashes) {
169
- const commitInfo = await getCommitInfo(hash);
170
- if (commitInfo.featureIds.length > 0) {
171
- featureCommits.push(commitInfo);
172
- }
173
- }
174
-
175
- return featureCommits;
176
- } catch (error) {
177
- console.error('Error getting recent feature commits:', error);
178
- return [];
179
- }
180
- }
181
-
182
- /**
183
- * Git 저장소인지 확인
184
- * @param {string} dir - 확인할 디렉토리
185
- * @returns {Promise<boolean>}
186
- */
187
- async function isGitRepository(dir = process.cwd()) {
188
- try {
189
- await runGitCommand('rev-parse --git-dir', dir);
190
- return true;
191
- } catch (error) {
192
- return false;
193
- }
194
- }
195
-
196
- /**
197
- * 변경된 파일 목록 가져오기
198
- * @returns {Promise<Array<string>>} - 변경된 파일 경로 목록
199
- */
200
- async function getChangedFiles() {
201
- try {
202
- const output = await runGitCommand('diff --name-only HEAD');
203
- return output ? output.split('\n').filter(Boolean) : [];
204
- } catch (error) {
205
- console.error('Error getting changed files:', error);
206
- return [];
207
- }
208
- }
209
-
210
- module.exports = {
211
- runGitCommand,
212
- getCurrentBranch,
213
- getCommitInfo,
214
- getFeatureRelatedCommits,
215
- getCommitsByFeatureId,
216
- getCurrentFeatureId,
217
- getRecentFeatureCommits,
218
- isGitRepository,
219
- getChangedFiles
220
- };