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.
- package/package.json +3 -2
- package/src/cli/index.js +39 -336
- package/src/lib/installer.js +310 -90
- package/src/utils/messages.js +24 -0
- package/src/DEPENDENCY_MAP.md +0 -90
- package/src/cli/cache-cli.js +0 -459
- package/src/cli/checkpoint-cli.js +0 -417
- package/src/cli/language-cli.js +0 -286
- package/src/cli/sprint-cli.js +0 -287
- package/src/commands/ai-tool.js +0 -383
- package/src/commands/compress.js +0 -60
- package/src/commands/create-project.js +0 -160
- package/src/commands/evaluate.js +0 -459
- package/src/commands/persona.js +0 -309
- package/src/commands/sprint-task.js +0 -262
- package/src/commands/token.js +0 -312
- package/src/lib/ai-persona-manager.js +0 -711
- package/src/lib/cache-system.js +0 -332
- package/src/lib/context-engine.js +0 -568
- package/src/lib/github-integration.js +0 -402
- package/src/lib/memory-profiler.js +0 -471
- package/src/lib/metrics-collector.js +0 -885
- package/src/lib/offline-detector.js +0 -386
- package/src/lib/resource-loader-enhanced.js +0 -399
- package/src/lib/resource-loader.js +0 -250
- package/src/lib/resources/commands/ai-persona.js +0 -602
- package/src/lib/resources/commands/compress-context.js +0 -389
- package/src/lib/resources/commands/evaluate.js +0 -246
- package/src/lib/resources/commands/persona-context-apply.js +0 -562
- package/src/lib/resources/commands/token-tracking.js +0 -443
- package/src/lib/resources/config/commit-patterns.js +0 -103
- package/src/lib/resources/config/language.json +0 -6
- package/src/lib/resources/personas/PERSONA_INDEX.md +0 -57
- package/src/lib/resources/personas/analyst.json +0 -44
- package/src/lib/resources/personas/architect/best_practices.md +0 -136
- package/src/lib/resources/personas/architect/knowledge_base.md +0 -377
- package/src/lib/resources/personas/architect.json +0 -44
- package/src/lib/resources/personas/backend/best_practices.md +0 -766
- package/src/lib/resources/personas/backend/knowledge_base.md +0 -1070
- package/src/lib/resources/personas/data_analyst/best_practices.md +0 -594
- package/src/lib/resources/personas/data_analyst/knowledge_base.md +0 -1057
- package/src/lib/resources/personas/developer.json +0 -44
- package/src/lib/resources/personas/developer.md +0 -37
- package/src/lib/resources/personas/evaluation_criteria.json +0 -137
- package/src/lib/resources/personas/frontend/best_practices.md +0 -445
- package/src/lib/resources/personas/frontend/knowledge_base.md +0 -729
- package/src/lib/resources/personas/persona-index.json +0 -31
- package/src/lib/resources/personas/reviewer.json +0 -44
- package/src/lib/resources/personas/security/best_practices.md +0 -307
- package/src/lib/resources/personas/security/knowledge_base.md +0 -498
- package/src/lib/resources/personas/tester.json +0 -44
- package/src/lib/resources/templates/README.md +0 -78
- package/src/lib/resources/templates/api-server/config.json +0 -64
- package/src/lib/resources/templates/api-server/template/.aiwf/config.json +0 -56
- package/src/lib/resources/templates/api-server/template/.aiwf/feature-ledger.json +0 -42
- package/src/lib/resources/templates/api-server/template/.aiwf/personas/backend-engineer.json +0 -40
- package/src/lib/resources/templates/api-server/template/.aiwf/scripts/cli.js +0 -111
- package/src/lib/resources/templates/api-server/template/.env.example +0 -29
- package/src/lib/resources/templates/api-server/template/.eslintrc.json +0 -23
- package/src/lib/resources/templates/api-server/template/README.md +0 -171
- package/src/lib/resources/templates/api-server/template/jest.config.js +0 -26
- package/src/lib/resources/templates/api-server/template/nodemon.json +0 -9
- package/src/lib/resources/templates/api-server/template/package.json +0 -61
- package/src/lib/resources/templates/api-server/template/src/app.ts +0 -60
- package/src/lib/resources/templates/api-server/template/src/config/swagger.ts +0 -38
- package/src/lib/resources/templates/api-server/template/src/controllers/aiwfController.ts +0 -54
- package/src/lib/resources/templates/api-server/template/src/controllers/authController.ts +0 -128
- package/src/lib/resources/templates/api-server/template/src/controllers/statusController.ts +0 -28
- package/src/lib/resources/templates/api-server/template/src/index.ts +0 -28
- package/src/lib/resources/templates/api-server/template/src/middleware/aiwfMiddleware.ts +0 -50
- package/src/lib/resources/templates/api-server/template/src/middleware/authMiddleware.ts +0 -41
- package/src/lib/resources/templates/api-server/template/src/middleware/errorHandler.ts +0 -42
- package/src/lib/resources/templates/api-server/template/src/middleware/notFoundHandler.ts +0 -14
- package/src/lib/resources/templates/api-server/template/src/middleware/requestLogger.ts +0 -20
- package/src/lib/resources/templates/api-server/template/src/routes/aiwf.ts +0 -31
- package/src/lib/resources/templates/api-server/template/src/routes/index.ts +0 -13
- package/src/lib/resources/templates/api-server/template/src/routes/v1/index.ts +0 -67
- package/src/lib/resources/templates/api-server/template/src/utils/logger.ts +0 -37
- package/src/lib/resources/templates/api-server/template/tests/app.test.ts +0 -40
- package/src/lib/resources/templates/api-server/template/tsconfig.json +0 -43
- package/src/lib/resources/templates/npm-library/config.json +0 -61
- package/src/lib/resources/templates/npm-library/template/LICENSE +0 -21
- package/src/lib/resources/templates/npm-library/template/README.md +0 -201
- package/src/lib/resources/templates/npm-library/template/package.json +0 -78
- package/src/lib/resources/templates/web-app/config.json +0 -53
- package/src/lib/resources/templates/web-app/template/.aiwf/config.json +0 -54
- package/src/lib/resources/templates/web-app/template/.aiwf/feature-ledger.json +0 -37
- package/src/lib/resources/templates/web-app/template/.aiwf/personas/fullstack-developer.json +0 -40
- package/src/lib/resources/templates/web-app/template/.aiwf/scripts/cli.js +0 -110
- package/src/lib/resources/templates/web-app/template/.eslintrc.cjs +0 -20
- package/src/lib/resources/templates/web-app/template/README.md +0 -151
- package/src/lib/resources/templates/web-app/template/index.html +0 -14
- package/src/lib/resources/templates/web-app/template/package.json +0 -44
- package/src/lib/resources/templates/web-app/template/postcss.config.js +0 -6
- package/src/lib/resources/templates/web-app/template/public/vite.svg +0 -1
- package/src/lib/resources/templates/web-app/template/src/App.tsx +0 -21
- package/src/lib/resources/templates/web-app/template/src/components/Layout.tsx +0 -57
- package/src/lib/resources/templates/web-app/template/src/components/aiwf/ContextStatus.tsx +0 -107
- package/src/lib/resources/templates/web-app/template/src/components/aiwf/TokenUsage.tsx +0 -71
- package/src/lib/resources/templates/web-app/template/src/index.css +0 -60
- package/src/lib/resources/templates/web-app/template/src/main.tsx +0 -10
- package/src/lib/resources/templates/web-app/template/src/pages/AiwfDashboard.tsx +0 -57
- package/src/lib/resources/templates/web-app/template/src/pages/HomePage.tsx +0 -89
- package/src/lib/resources/templates/web-app/template/src/pages/NotFound.tsx +0 -25
- package/src/lib/resources/templates/web-app/template/src/stores/aiwfStore.ts +0 -126
- package/src/lib/resources/templates/web-app/template/src/types/global.d.ts +0 -9
- package/src/lib/resources/templates/web-app/template/src/vite-env.d.ts +0 -1
- package/src/lib/resources/templates/web-app/template/tailwind.config.js +0 -30
- package/src/lib/resources/templates/web-app/template/tsconfig.json +0 -37
- package/src/lib/resources/templates/web-app/template/tsconfig.node.json +0 -10
- package/src/lib/resources/templates/web-app/template/vite.config.ts +0 -23
- package/src/lib/resources/utils/background-monitor.js +0 -223
- package/src/lib/resources/utils/compression-metrics.js +0 -1031
- package/src/lib/resources/utils/compression-strategies.js +0 -557
- package/src/lib/resources/utils/content-normalizer.js +0 -455
- package/src/lib/resources/utils/context-compressor.js +0 -583
- package/src/lib/resources/utils/context-rule-parser.js +0 -180
- package/src/lib/resources/utils/context-token-monitor.js +0 -463
- package/src/lib/resources/utils/context-update-manager.js +0 -502
- package/src/lib/resources/utils/git-utils.js +0 -220
- package/src/lib/resources/utils/importance-classifier.js +0 -645
- package/src/lib/resources/utils/information-filter.js +0 -710
- package/src/lib/resources/utils/persona-aware-compressor.js +0 -598
- package/src/lib/resources/utils/prompt-injector.js +0 -242
- package/src/lib/resources/utils/simplified-evaluator.js +0 -119
- package/src/lib/resources/utils/text-summarizer.js +0 -492
- package/src/lib/resources/utils/token-counter.js +0 -177
- package/src/lib/resources/utils/token-monitor.js +0 -484
- package/src/lib/resources/utils/token-reporter.js +0 -452
- package/src/lib/resources/utils/token-storage.js +0 -433
- package/src/lib/resources/utils/token-tracker.js +0 -283
- package/src/lib/state/priority-calculator.js +0 -217
- package/src/lib/state/state-index.js +0 -155
- package/src/lib/state/task-scanner.js +0 -328
- package/src/lib/task-analyzer.js +0 -599
- package/src/lib/template-cache-system.js +0 -559
- package/src/lib/template-downloader.js +0 -467
- package/src/lib/template-version-manager.js +0 -491
- package/src/lib/token-optimizer.js +0 -517
- package/src/utils/engineering-guard.js +0 -399
|
@@ -1,467 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import fs from 'fs/promises';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import { EventEmitter } from 'events';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* 템플릿 다운로드 시스템
|
|
9
|
-
* - AI 도구 및 프로젝트 템플릿 다운로드
|
|
10
|
-
* - 선택적 다운로드 및 배치 처리
|
|
11
|
-
* - 진행률 추적 및 재시도 메커니즘
|
|
12
|
-
* - 버전 관리 및 증분 업데이트
|
|
13
|
-
*/
|
|
14
|
-
class TemplateDownloader extends EventEmitter {
|
|
15
|
-
constructor(options = {}) {
|
|
16
|
-
super();
|
|
17
|
-
|
|
18
|
-
this.options = {
|
|
19
|
-
// 다운로드 설정
|
|
20
|
-
batchSize: options.batchSize || 3,
|
|
21
|
-
retryCount: options.retryCount || 3,
|
|
22
|
-
retryDelay: options.retryDelay || 1000,
|
|
23
|
-
timeout: options.timeout || 30000,
|
|
24
|
-
|
|
25
|
-
// 소스 경로
|
|
26
|
-
aiToolsPath: options.aiToolsPath || '.aiwf/ai-tools',
|
|
27
|
-
projectsPath: options.projectsPath || '.aiwf/templates',
|
|
28
|
-
|
|
29
|
-
// 진행률 콜백
|
|
30
|
-
onProgress: options.onProgress || null,
|
|
31
|
-
onComplete: options.onComplete || null,
|
|
32
|
-
onError: options.onError || null
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
this.state = {
|
|
36
|
-
downloading: false,
|
|
37
|
-
progress: {
|
|
38
|
-
total: 0,
|
|
39
|
-
completed: 0,
|
|
40
|
-
failed: 0,
|
|
41
|
-
current: null
|
|
42
|
-
},
|
|
43
|
-
results: []
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
this.cache = null; // TemplateCache 인스턴스
|
|
47
|
-
this.offlineDetector = null; // OfflineDetector 인스턴스
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* 캐시 및 오프라인 감지기 연결
|
|
52
|
-
*/
|
|
53
|
-
setCache(cache) {
|
|
54
|
-
this.cache = cache;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
setOfflineDetector(detector) {
|
|
58
|
-
this.offlineDetector = detector;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* 사용 가능한 템플릿 스캔
|
|
63
|
-
*/
|
|
64
|
-
async scanAvailableTemplates() {
|
|
65
|
-
const templates = {
|
|
66
|
-
'ai-tools': {},
|
|
67
|
-
'projects': {}
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
try {
|
|
71
|
-
// AI 도구 템플릿 스캔
|
|
72
|
-
const aiToolsDir = this.options.aiToolsPath;
|
|
73
|
-
const aiTools = await fs.readdir(aiToolsDir);
|
|
74
|
-
|
|
75
|
-
for (const tool of aiTools) {
|
|
76
|
-
const toolPath = path.join(aiToolsDir, tool);
|
|
77
|
-
const stat = await fs.stat(toolPath);
|
|
78
|
-
|
|
79
|
-
if (stat.isDirectory()) {
|
|
80
|
-
const configPath = path.join(toolPath, 'config.json');
|
|
81
|
-
try {
|
|
82
|
-
const config = JSON.parse(await fs.readFile(configPath, 'utf8'));
|
|
83
|
-
templates['ai-tools'][tool] = {
|
|
84
|
-
name: config.name || tool,
|
|
85
|
-
version: config.version || '1.0.0',
|
|
86
|
-
description: config.description || '',
|
|
87
|
-
size: await this.getDirectorySize(toolPath),
|
|
88
|
-
path: toolPath,
|
|
89
|
-
config
|
|
90
|
-
};
|
|
91
|
-
} catch (error) {
|
|
92
|
-
console.warn(`Invalid config for AI tool ${tool}:`, error.message);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// 프로젝트 템플릿 스캔
|
|
98
|
-
const projectsDir = this.options.projectsPath;
|
|
99
|
-
const projects = await fs.readdir(projectsDir);
|
|
100
|
-
|
|
101
|
-
for (const project of projects) {
|
|
102
|
-
const projectPath = path.join(projectsDir, project);
|
|
103
|
-
const stat = await fs.stat(projectPath);
|
|
104
|
-
|
|
105
|
-
if (stat.isDirectory() && project !== 'README.md') {
|
|
106
|
-
const configPath = path.join(projectPath, 'config.json');
|
|
107
|
-
try {
|
|
108
|
-
const config = JSON.parse(await fs.readFile(configPath, 'utf8'));
|
|
109
|
-
templates['projects'][project] = {
|
|
110
|
-
name: config.name || project,
|
|
111
|
-
version: config.version || '1.0.0',
|
|
112
|
-
description: config.description || '',
|
|
113
|
-
size: await this.getDirectorySize(projectPath),
|
|
114
|
-
path: projectPath,
|
|
115
|
-
config
|
|
116
|
-
};
|
|
117
|
-
} catch (error) {
|
|
118
|
-
console.warn(`Invalid config for project ${project}:`, error.message);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
} catch (error) {
|
|
124
|
-
console.error('Failed to scan templates:', error.message);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return templates;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* 디렉토리 크기 계산
|
|
132
|
-
*/
|
|
133
|
-
async getDirectorySize(dirPath) {
|
|
134
|
-
let totalSize = 0;
|
|
135
|
-
|
|
136
|
-
try {
|
|
137
|
-
const files = await fs.readdir(dirPath);
|
|
138
|
-
|
|
139
|
-
for (const file of files) {
|
|
140
|
-
const filePath = path.join(dirPath, file);
|
|
141
|
-
const stat = await fs.stat(filePath);
|
|
142
|
-
|
|
143
|
-
if (stat.isDirectory()) {
|
|
144
|
-
totalSize += await this.getDirectorySize(filePath);
|
|
145
|
-
} else {
|
|
146
|
-
totalSize += stat.size;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
} catch (error) {
|
|
150
|
-
console.warn(`Failed to calculate size for ${dirPath}:`, error.message);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return totalSize;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* 선택적 템플릿 다운로드
|
|
158
|
-
*/
|
|
159
|
-
async downloadSelectedTemplates(selections) {
|
|
160
|
-
if (this.state.downloading) {
|
|
161
|
-
throw new Error('Download already in progress');
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
this.state.downloading = true;
|
|
165
|
-
this.state.progress = {
|
|
166
|
-
total: selections.length,
|
|
167
|
-
completed: 0,
|
|
168
|
-
failed: 0,
|
|
169
|
-
current: null
|
|
170
|
-
};
|
|
171
|
-
this.state.results = [];
|
|
172
|
-
|
|
173
|
-
try {
|
|
174
|
-
// 병렬 다운로드 처리
|
|
175
|
-
const batches = this.createBatches(selections);
|
|
176
|
-
|
|
177
|
-
for (const batch of batches) {
|
|
178
|
-
const batchPromises = batch.map(selection =>
|
|
179
|
-
this.downloadSingleTemplate(selection.type, selection.name, selection.version)
|
|
180
|
-
);
|
|
181
|
-
|
|
182
|
-
const batchResults = await Promise.allSettled(batchPromises);
|
|
183
|
-
|
|
184
|
-
for (let i = 0; i < batchResults.length; i++) {
|
|
185
|
-
const result = batchResults[i];
|
|
186
|
-
const selection = batch[i];
|
|
187
|
-
|
|
188
|
-
if (result.status === 'fulfilled') {
|
|
189
|
-
this.state.progress.completed++;
|
|
190
|
-
this.state.results.push({
|
|
191
|
-
...selection,
|
|
192
|
-
success: true,
|
|
193
|
-
result: result.value
|
|
194
|
-
});
|
|
195
|
-
} else {
|
|
196
|
-
this.state.progress.failed++;
|
|
197
|
-
this.state.results.push({
|
|
198
|
-
...selection,
|
|
199
|
-
success: false,
|
|
200
|
-
error: result.reason.message
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// 진행률 이벤트 발생
|
|
205
|
-
this.emit('progress', {
|
|
206
|
-
...this.state.progress,
|
|
207
|
-
percentage: (this.state.progress.completed / this.state.progress.total) * 100
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
const summary = {
|
|
213
|
-
total: this.state.progress.total,
|
|
214
|
-
completed: this.state.progress.completed,
|
|
215
|
-
failed: this.state.progress.failed,
|
|
216
|
-
results: this.state.results
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
this.emit('complete', summary);
|
|
220
|
-
|
|
221
|
-
if (this.options.onComplete) {
|
|
222
|
-
this.options.onComplete(summary);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
return summary;
|
|
226
|
-
|
|
227
|
-
} finally {
|
|
228
|
-
this.state.downloading = false;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* 배치 생성
|
|
234
|
-
*/
|
|
235
|
-
createBatches(items) {
|
|
236
|
-
const batches = [];
|
|
237
|
-
|
|
238
|
-
for (let i = 0; i < items.length; i += this.options.batchSize) {
|
|
239
|
-
batches.push(items.slice(i, i + this.options.batchSize));
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
return batches;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* 단일 템플릿 다운로드
|
|
247
|
-
*/
|
|
248
|
-
async downloadSingleTemplate(type, name, version = '1.0.0') {
|
|
249
|
-
this.state.progress.current = { type, name, version };
|
|
250
|
-
|
|
251
|
-
this.emit('templateStart', { type, name, version });
|
|
252
|
-
|
|
253
|
-
try {
|
|
254
|
-
// 소스 경로 확인
|
|
255
|
-
const sourcePath = this.getTemplatePath(type, name);
|
|
256
|
-
const exists = await this.directoryExists(sourcePath);
|
|
257
|
-
|
|
258
|
-
if (!exists) {
|
|
259
|
-
throw new Error(`Template source not found: ${sourcePath}`);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// 캐시에 저장
|
|
263
|
-
const result = await this.cache.cacheTemplate(type, name, sourcePath, version);
|
|
264
|
-
|
|
265
|
-
this.emit('templateComplete', { type, name, version, result });
|
|
266
|
-
|
|
267
|
-
return result;
|
|
268
|
-
|
|
269
|
-
} catch (error) {
|
|
270
|
-
this.emit('templateError', { type, name, version, error: error.message });
|
|
271
|
-
throw error;
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* 템플릿 소스 경로 반환
|
|
277
|
-
*/
|
|
278
|
-
getTemplatePath(type, name) {
|
|
279
|
-
if (type === 'ai-tools') {
|
|
280
|
-
return path.join(this.options.aiToolsPath, name);
|
|
281
|
-
} else {
|
|
282
|
-
return path.join(this.options.projectsPath, name);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* 디렉토리 존재 확인
|
|
288
|
-
*/
|
|
289
|
-
async directoryExists(dirPath) {
|
|
290
|
-
try {
|
|
291
|
-
const stat = await fs.stat(dirPath);
|
|
292
|
-
return stat.isDirectory();
|
|
293
|
-
} catch {
|
|
294
|
-
return false;
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* 모든 템플릿 다운로드
|
|
300
|
-
*/
|
|
301
|
-
async downloadAllTemplates() {
|
|
302
|
-
const templates = await this.scanAvailableTemplates();
|
|
303
|
-
const selections = [];
|
|
304
|
-
|
|
305
|
-
// AI 도구 추가
|
|
306
|
-
for (const [name, info] of Object.entries(templates['ai-tools'])) {
|
|
307
|
-
selections.push({
|
|
308
|
-
type: 'ai-tools',
|
|
309
|
-
name,
|
|
310
|
-
version: info.version
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// 프로젝트 템플릿 추가
|
|
315
|
-
for (const [name, info] of Object.entries(templates['projects'])) {
|
|
316
|
-
selections.push({
|
|
317
|
-
type: 'projects',
|
|
318
|
-
name,
|
|
319
|
-
version: info.version
|
|
320
|
-
});
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
return await this.downloadSelectedTemplates(selections);
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/**
|
|
327
|
-
* 특정 타입의 템플릿만 다운로드
|
|
328
|
-
*/
|
|
329
|
-
async downloadTemplatesByType(type) {
|
|
330
|
-
const templates = await this.scanAvailableTemplates();
|
|
331
|
-
const selections = [];
|
|
332
|
-
|
|
333
|
-
if (templates[type]) {
|
|
334
|
-
for (const [name, info] of Object.entries(templates[type])) {
|
|
335
|
-
selections.push({
|
|
336
|
-
type,
|
|
337
|
-
name,
|
|
338
|
-
version: info.version
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
return await this.downloadSelectedTemplates(selections);
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
/**
|
|
347
|
-
* 업데이트 필요한 템플릿 확인
|
|
348
|
-
*/
|
|
349
|
-
async checkForUpdates() {
|
|
350
|
-
const availableTemplates = await this.scanAvailableTemplates();
|
|
351
|
-
const cachedTemplates = await this.cache.listTemplates();
|
|
352
|
-
const updates = [];
|
|
353
|
-
|
|
354
|
-
for (const type of ['ai-tools', 'projects']) {
|
|
355
|
-
const available = availableTemplates[type];
|
|
356
|
-
const cached = cachedTemplates[type];
|
|
357
|
-
|
|
358
|
-
for (const [name, info] of Object.entries(available)) {
|
|
359
|
-
const cachedInfo = cached[name];
|
|
360
|
-
|
|
361
|
-
if (!cachedInfo) {
|
|
362
|
-
updates.push({
|
|
363
|
-
type,
|
|
364
|
-
name,
|
|
365
|
-
status: 'new',
|
|
366
|
-
currentVersion: null,
|
|
367
|
-
availableVersion: info.version
|
|
368
|
-
});
|
|
369
|
-
} else if (this.isVersionNewer(info.version, cachedInfo.version)) {
|
|
370
|
-
updates.push({
|
|
371
|
-
type,
|
|
372
|
-
name,
|
|
373
|
-
status: 'update',
|
|
374
|
-
currentVersion: cachedInfo.version,
|
|
375
|
-
availableVersion: info.version
|
|
376
|
-
});
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
return updates;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
/**
|
|
385
|
-
* 버전 비교 (간단한 semantic versioning)
|
|
386
|
-
*/
|
|
387
|
-
isVersionNewer(newVersion, currentVersion) {
|
|
388
|
-
const parseVersion = (version) => {
|
|
389
|
-
return version.split('.').map(num => parseInt(num, 10));
|
|
390
|
-
};
|
|
391
|
-
|
|
392
|
-
const newParts = parseVersion(newVersion);
|
|
393
|
-
const currentParts = parseVersion(currentVersion);
|
|
394
|
-
|
|
395
|
-
for (let i = 0; i < Math.max(newParts.length, currentParts.length); i++) {
|
|
396
|
-
const newPart = newParts[i] || 0;
|
|
397
|
-
const currentPart = currentParts[i] || 0;
|
|
398
|
-
|
|
399
|
-
if (newPart > currentPart) return true;
|
|
400
|
-
if (newPart < currentPart) return false;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
return false;
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
/**
|
|
407
|
-
* 다운로드 진행률 정보
|
|
408
|
-
*/
|
|
409
|
-
getProgress() {
|
|
410
|
-
return {
|
|
411
|
-
...this.state.progress,
|
|
412
|
-
percentage: this.state.progress.total > 0
|
|
413
|
-
? (this.state.progress.completed / this.state.progress.total) * 100
|
|
414
|
-
: 0,
|
|
415
|
-
downloading: this.state.downloading
|
|
416
|
-
};
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
/**
|
|
420
|
-
* 다운로드 중단
|
|
421
|
-
*/
|
|
422
|
-
cancel() {
|
|
423
|
-
if (this.state.downloading) {
|
|
424
|
-
this.state.downloading = false;
|
|
425
|
-
this.emit('cancelled');
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
/**
|
|
430
|
-
* 재시도 다운로드
|
|
431
|
-
*/
|
|
432
|
-
async retryFailedDownloads() {
|
|
433
|
-
const failedResults = this.state.results.filter(result => !result.success);
|
|
434
|
-
|
|
435
|
-
if (failedResults.length === 0) {
|
|
436
|
-
return { message: 'No failed downloads to retry' };
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
const retrySelections = failedResults.map(result => ({
|
|
440
|
-
type: result.type,
|
|
441
|
-
name: result.name,
|
|
442
|
-
version: result.version
|
|
443
|
-
}));
|
|
444
|
-
|
|
445
|
-
return await this.downloadSelectedTemplates(retrySelections);
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
/**
|
|
449
|
-
* 다운로드 통계
|
|
450
|
-
*/
|
|
451
|
-
getStats() {
|
|
452
|
-
const totalResults = this.state.results.length;
|
|
453
|
-
const successCount = this.state.results.filter(r => r.success).length;
|
|
454
|
-
const failureCount = this.state.results.filter(r => !r.success).length;
|
|
455
|
-
|
|
456
|
-
return {
|
|
457
|
-
totalAttempts: totalResults,
|
|
458
|
-
successCount,
|
|
459
|
-
failureCount,
|
|
460
|
-
successRate: totalResults > 0 ? (successCount / totalResults * 100).toFixed(2) + '%' : '0%',
|
|
461
|
-
downloading: this.state.downloading,
|
|
462
|
-
progress: this.getProgress()
|
|
463
|
-
};
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
export { TemplateDownloader };
|