@silbaram/artifact-driven-agent 0.1.6 β 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +709 -516
- package/ai-dev-team/.ada-status.json +10 -0
- package/ai-dev-team/.ada-version +6 -0
- package/ai-dev-team/.current-template +1 -0
- package/ai-dev-team/.sessions/logs/20260124-014551-00f04724.log +5 -0
- package/ai-dev-team/.sessions/logs/20260124-014623-cb2b1d44.log +5 -0
- package/ai-dev-team/ada.config.json +15 -0
- package/ai-dev-team/artifacts/api.md +212 -0
- package/ai-dev-team/artifacts/decision.md +72 -0
- package/ai-dev-team/artifacts/improvement-reports/IMP-0000-template.md +57 -0
- package/ai-dev-team/artifacts/plan.md +187 -0
- package/ai-dev-team/artifacts/project.md +193 -0
- package/ai-dev-team/artifacts/sprints/_template/docs/release-notes.md +37 -0
- package/ai-dev-team/artifacts/sprints/_template/meta.md +54 -0
- package/ai-dev-team/artifacts/sprints/_template/retrospective.md +50 -0
- package/ai-dev-team/artifacts/sprints/_template/review-reports/review-template.md +49 -0
- package/ai-dev-team/artifacts/sprints/_template/tasks/task-template.md +43 -0
- package/ai-dev-team/artifacts/ui.md +104 -0
- package/ai-dev-team/roles/analyzer.md +265 -0
- package/ai-dev-team/roles/developer.md +222 -0
- package/ai-dev-team/roles/documenter.md +715 -0
- package/ai-dev-team/roles/improver.md +461 -0
- package/ai-dev-team/roles/manager.md +544 -0
- package/ai-dev-team/roles/planner.md +398 -0
- package/ai-dev-team/roles/reviewer.md +294 -0
- package/ai-dev-team/rules/api-change.md +198 -0
- package/ai-dev-team/rules/document-priority.md +199 -0
- package/ai-dev-team/rules/escalation.md +172 -0
- package/ai-dev-team/rules/iteration.md +236 -0
- package/ai-dev-team/rules/rfc.md +31 -0
- package/ai-dev-team/rules/rollback.md +218 -0
- package/bin/cli.js +49 -5
- package/core/artifacts/sprints/_template/meta.md +4 -4
- package/core/docs-templates/mkdocs/docs/architecture/overview.md +29 -0
- package/core/docs-templates/mkdocs/docs/changelog.md +36 -0
- package/core/docs-templates/mkdocs/docs/contributing/contributing.md +60 -0
- package/core/docs-templates/mkdocs/docs/getting-started/configuration.md +51 -0
- package/core/docs-templates/mkdocs/docs/getting-started/installation.md +41 -0
- package/core/docs-templates/mkdocs/docs/getting-started/quick-start.md +56 -0
- package/core/docs-templates/mkdocs/docs/guides/api-reference.md +83 -0
- package/core/docs-templates/mkdocs/docs/index.md +32 -0
- package/core/docs-templates/mkdocs/mkdocs.yml +86 -0
- package/core/roles/analyzer.md +32 -10
- package/core/roles/developer.md +222 -223
- package/core/roles/documenter.md +592 -170
- package/core/roles/improver.md +461 -0
- package/core/roles/manager.md +4 -1
- package/core/roles/planner.md +160 -10
- package/core/roles/reviewer.md +31 -3
- package/core/rules/document-priority.md +2 -1
- package/core/rules/rollback.md +3 -3
- package/package.json +1 -1
- package/src/commands/config.js +371 -0
- package/src/commands/docs.js +502 -0
- package/src/commands/interactive.js +324 -33
- package/src/commands/monitor.js +236 -0
- package/src/commands/run.js +360 -122
- package/src/commands/sessions.js +270 -70
- package/src/commands/setup.js +22 -1
- package/src/commands/sprint.js +295 -54
- package/src/commands/status.js +34 -1
- package/src/commands/upgrade.js +416 -0
- package/src/commands/validate.js +4 -3
- package/src/index.js +1 -0
- package/src/ui/dashboard.js +518 -0
- package/src/ui/keyHandler.js +147 -0
- package/src/ui/quickActions.js +111 -0
- package/src/utils/config.js +74 -0
- package/src/utils/files.js +70 -3
- package/src/utils/sessionState.js +472 -328
- package/src/utils/sessionState.process.test.js +101 -0
- package/src/utils/sessionState.test.js +183 -0
- package/src/utils/sprintUtils.js +134 -0
- package/src/utils/taskParser.js +134 -0
- package/src/utils/taskParser.test.js +76 -0
- package/ai-dev-team/artifacts/features/_template/qa.md +0 -16
- package/examples/todo-app/README.md +0 -23
- package/examples/todo-app/artifacts/backlog.md +0 -23
- package/examples/todo-app/artifacts/plan.md +0 -23
- package/examples/todo-app/artifacts/project.md +0 -23
package/src/commands/sessions.js
CHANGED
|
@@ -3,11 +3,18 @@ import path from 'path';
|
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import readline from 'readline';
|
|
5
5
|
import { getSessionsDir, isWorkspaceSetup, getWorkspaceDir } from '../utils/files.js';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
getActiveSessions,
|
|
8
|
+
getPendingQuestions,
|
|
9
|
+
readStatus,
|
|
10
|
+
getStatusFilePath,
|
|
11
|
+
cleanupZombieSessions,
|
|
12
|
+
answerQuestion
|
|
13
|
+
} from '../utils/sessionState.js';
|
|
7
14
|
|
|
8
15
|
export async function sessions(options = {}) {
|
|
9
16
|
if (!isWorkspaceSetup()) {
|
|
10
|
-
console.log(chalk.red('
|
|
17
|
+
console.log(chalk.red('? λ¨Όμ setupμ μ€ννμΈμ.'));
|
|
11
18
|
process.exit(1);
|
|
12
19
|
}
|
|
13
20
|
|
|
@@ -16,26 +23,31 @@ export async function sessions(options = {}) {
|
|
|
16
23
|
return watchSessions();
|
|
17
24
|
}
|
|
18
25
|
|
|
26
|
+
// Clean λͺ¨λ
|
|
27
|
+
if (options.clean) {
|
|
28
|
+
return cleanupCompletedSessions();
|
|
29
|
+
}
|
|
30
|
+
|
|
19
31
|
const sessionsDir = getSessionsDir();
|
|
20
32
|
|
|
21
|
-
// μ’λΉ μΈμ
μ 리 (
|
|
33
|
+
// μ’λΉ μΈμ
μ 리 (λΉνμ±/μ€λλ μΈμ
)
|
|
22
34
|
const removedCount = cleanupZombieSessions(60);
|
|
23
35
|
|
|
24
36
|
console.log('');
|
|
25
37
|
console.log(chalk.cyan('β'.repeat(60)));
|
|
26
|
-
console.log(chalk.cyan.bold('
|
|
38
|
+
console.log(chalk.cyan.bold('μΈμ
μν'));
|
|
27
39
|
console.log(chalk.cyan('β'.repeat(60)));
|
|
28
40
|
console.log('');
|
|
29
41
|
|
|
30
42
|
if (removedCount > 0) {
|
|
31
|
-
console.log(chalk.yellow(
|
|
43
|
+
console.log(chalk.yellow(`μ’λΉ μΈμ
${removedCount}κ° μ λ¦¬λ¨ (λΉνμ±/μ€λλ¨)`));
|
|
32
44
|
console.log('');
|
|
33
45
|
}
|
|
34
46
|
|
|
35
47
|
// 1. μ€μκ° νμ± μΈμ
νμ
|
|
36
48
|
const activeSessions = getActiveSessions();
|
|
37
49
|
if (activeSessions.length > 0) {
|
|
38
|
-
console.log(chalk.yellow.bold('
|
|
50
|
+
console.log(chalk.yellow.bold('νμ± μΈμ
(μ€μκ°)'));
|
|
39
51
|
console.log('');
|
|
40
52
|
console.log(chalk.gray(' μν λꡬ μμ μκ° μν'));
|
|
41
53
|
console.log(chalk.gray(' ' + 'β'.repeat(56)));
|
|
@@ -45,7 +57,7 @@ export async function sessions(options = {}) {
|
|
|
45
57
|
const tool = (session.tool || '-').padEnd(8);
|
|
46
58
|
const startTime = new Date(session.startedAt).toLocaleString('ko-KR');
|
|
47
59
|
const status = session.status || 'active';
|
|
48
|
-
const statusIcon = status === 'active' ? '
|
|
60
|
+
const statusIcon = status === 'active' ? '+' : '-';
|
|
49
61
|
|
|
50
62
|
console.log(` ${role} ${tool} ${startTime} ${statusIcon} ${status}`);
|
|
51
63
|
});
|
|
@@ -58,7 +70,7 @@ export async function sessions(options = {}) {
|
|
|
58
70
|
// 2. λκΈ° μ€μΈ μ§λ¬Έ νμ
|
|
59
71
|
const pendingQuestions = getPendingQuestions();
|
|
60
72
|
if (pendingQuestions.length > 0) {
|
|
61
|
-
console.log(chalk.yellow.bold('
|
|
73
|
+
console.log(chalk.yellow.bold('λκΈ° μ§λ¬Έ'));
|
|
62
74
|
console.log('');
|
|
63
75
|
|
|
64
76
|
pendingQuestions.forEach(q => {
|
|
@@ -74,18 +86,23 @@ export async function sessions(options = {}) {
|
|
|
74
86
|
// 3. Task μ§ν μν© νμ
|
|
75
87
|
const status = readStatus();
|
|
76
88
|
const taskProgress = status.taskProgress || {};
|
|
77
|
-
const activeTasks = Object.entries(taskProgress).filter(([_, info]) =>
|
|
78
|
-
|
|
79
|
-
|
|
89
|
+
const activeTasks = Object.entries(taskProgress).filter(([_, info]) => {
|
|
90
|
+
const s = (info.status || '').toUpperCase();
|
|
91
|
+
return s && s !== 'DONE' && s !== 'REJECTED';
|
|
92
|
+
});
|
|
80
93
|
|
|
81
94
|
if (activeTasks.length > 0) {
|
|
82
|
-
console.log(chalk.cyan.bold('
|
|
95
|
+
console.log(chalk.cyan.bold('μ§ν μ€μΈ Task'));
|
|
83
96
|
console.log('');
|
|
84
97
|
|
|
85
98
|
activeTasks.forEach(([taskId, info]) => {
|
|
86
|
-
const
|
|
87
|
-
const
|
|
88
|
-
|
|
99
|
+
const normalizedStatus = info.status === 'IN_QA' ? 'IN_REVIEW' : info.status;
|
|
100
|
+
const statusColor = normalizedStatus === 'DONE' ? chalk.green :
|
|
101
|
+
normalizedStatus === 'IN_DEV' ? chalk.yellow :
|
|
102
|
+
normalizedStatus === 'IN_REVIEW' ? chalk.blue :
|
|
103
|
+
chalk.white;
|
|
104
|
+
|
|
105
|
+
console.log(` ${taskId}: [${statusColor(normalizedStatus)}]`);
|
|
89
106
|
if (info.assignee) {
|
|
90
107
|
console.log(chalk.gray(` λ΄λΉ: ${info.assignee}`));
|
|
91
108
|
}
|
|
@@ -117,7 +134,7 @@ export async function sessions(options = {}) {
|
|
|
117
134
|
return;
|
|
118
135
|
}
|
|
119
136
|
|
|
120
|
-
console.log(chalk.cyan.bold('
|
|
137
|
+
console.log(chalk.cyan.bold('μ΅κ·Ό μΈμ
κΈ°λ‘'));
|
|
121
138
|
console.log('');
|
|
122
139
|
console.log(chalk.gray(' μΈμ
ID μν λꡬ μν'));
|
|
123
140
|
console.log(chalk.gray(' ' + 'β'.repeat(56)));
|
|
@@ -159,11 +176,124 @@ async function watchSessions() {
|
|
|
159
176
|
const statusFile = getStatusFilePath();
|
|
160
177
|
let lastUpdate = '';
|
|
161
178
|
let isWatching = true;
|
|
179
|
+
let isPrompting = false;
|
|
180
|
+
const promptQueue = [];
|
|
181
|
+
const promptedQuestions = new Set();
|
|
182
|
+
|
|
183
|
+
function pauseWatch() {
|
|
184
|
+
isWatching = false;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function resumeWatch() {
|
|
188
|
+
isWatching = true;
|
|
189
|
+
drawScreen();
|
|
190
|
+
lastUpdate = new Date().toLocaleTimeString('ko-KR');
|
|
191
|
+
}
|
|
162
192
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
193
|
+
function disableKeypressHandling() {
|
|
194
|
+
if (process.stdin.isTTY) {
|
|
195
|
+
process.stdin.setRawMode(false);
|
|
196
|
+
}
|
|
197
|
+
process.stdin.removeListener('keypress', keyHandler);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function enableKeypressHandling() {
|
|
201
|
+
if (process.stdin.isTTY) {
|
|
202
|
+
readline.emitKeypressEvents(process.stdin);
|
|
203
|
+
process.stdin.setRawMode(true);
|
|
204
|
+
}
|
|
205
|
+
process.stdin.on('keypress', keyHandler);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function enqueueQuestions(questions) {
|
|
209
|
+
questions.forEach(question => {
|
|
210
|
+
if (!promptedQuestions.has(question.id)) {
|
|
211
|
+
promptQueue.push(question);
|
|
212
|
+
promptedQuestions.add(question.id);
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async function processPromptQueue() {
|
|
218
|
+
if (isPrompting || promptQueue.length === 0) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
isPrompting = true;
|
|
223
|
+
pauseWatch();
|
|
224
|
+
disableKeypressHandling();
|
|
225
|
+
|
|
226
|
+
while (promptQueue.length > 0) {
|
|
227
|
+
const nextQuestion = promptQueue.shift();
|
|
228
|
+
await promptQuestion(nextQuestion);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
enableKeypressHandling();
|
|
232
|
+
isPrompting = false;
|
|
233
|
+
resumeWatch();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async function promptQuestion(question) {
|
|
237
|
+
const status = readStatus();
|
|
238
|
+
const currentQuestion = status.pendingQuestions?.find(q => q.id === question.id);
|
|
239
|
+
|
|
240
|
+
if (!currentQuestion || currentQuestion.status !== 'waiting') {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
console.log('');
|
|
245
|
+
console.log(chalk.yellow('β'.repeat(60)));
|
|
246
|
+
console.log(chalk.yellow.bold('μ§λ¬Έ μλ΅ νμ'));
|
|
247
|
+
console.log(chalk.yellow('β'.repeat(60)));
|
|
248
|
+
console.log(chalk.white(` ID: ${currentQuestion.id}`));
|
|
249
|
+
console.log(chalk.white(` μμ²: ${currentQuestion.from} β ${currentQuestion.to}`));
|
|
250
|
+
console.log(chalk.white(` μ§λ¬Έ: ${currentQuestion.question}`));
|
|
251
|
+
|
|
252
|
+
if (currentQuestion.options && currentQuestion.options.length > 0) {
|
|
253
|
+
console.log(chalk.gray(' μ΅μ
:'));
|
|
254
|
+
currentQuestion.options.forEach((option, index) => {
|
|
255
|
+
console.log(chalk.gray(` ${index + 1}) ${option}`));
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const promptText = currentQuestion.options && currentQuestion.options.length > 0
|
|
260
|
+
? ' λ΅λ³(λ²νΈ λλ μ§μ μ
λ ₯): '
|
|
261
|
+
: ' λ΅λ³: ';
|
|
262
|
+
|
|
263
|
+
const answerInput = await askInput(chalk.cyan(promptText));
|
|
264
|
+
let answer = (answerInput || '').trim();
|
|
265
|
+
|
|
266
|
+
if (currentQuestion.options && currentQuestion.options.length > 0) {
|
|
267
|
+
const optionIndex = Number.parseInt(answer, 10);
|
|
268
|
+
if (!Number.isNaN(optionIndex) && optionIndex >= 1 && optionIndex <= currentQuestion.options.length) {
|
|
269
|
+
answer = currentQuestion.options[optionIndex - 1];
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (!answer) {
|
|
274
|
+
answer = '(μλ΅ μμ)';
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
answerQuestion(currentQuestion.id, answer);
|
|
278
|
+
|
|
279
|
+
// μ²λ¦¬ μλ£ λ©μμ§
|
|
280
|
+
console.log(chalk.green(` β μ μ₯ μλ£: ${currentQuestion.id}`));
|
|
281
|
+
console.log(chalk.gray(` β κ΄λ ¨ μλ¦Ό μ½μ μ²λ¦¬λ¨`));
|
|
282
|
+
console.log('');
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function askInput(prompt) {
|
|
286
|
+
return new Promise(resolve => {
|
|
287
|
+
const rl = readline.createInterface({
|
|
288
|
+
input: process.stdin,
|
|
289
|
+
output: process.stdout
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
rl.question(prompt, answer => {
|
|
293
|
+
rl.close();
|
|
294
|
+
resolve(answer);
|
|
295
|
+
});
|
|
296
|
+
});
|
|
167
297
|
}
|
|
168
298
|
|
|
169
299
|
// νλ©΄ 그리기 ν¨μ
|
|
@@ -172,24 +302,25 @@ async function watchSessions() {
|
|
|
172
302
|
|
|
173
303
|
const now = new Date();
|
|
174
304
|
const timeString = now.toLocaleTimeString('ko-KR');
|
|
305
|
+
let pendingQuestions = [];
|
|
175
306
|
|
|
176
307
|
// ν€λ
|
|
177
308
|
console.log('');
|
|
178
309
|
console.log(chalk.cyan('β' + 'β'.repeat(78) + 'β'));
|
|
179
|
-
console.log(chalk.cyan('β') + chalk.bold.white('
|
|
180
|
-
console.log(chalk.cyan('β') + chalk.gray(`
|
|
310
|
+
console.log(chalk.cyan('β') + chalk.bold.white(' Manager Watch Mode'.padEnd(78)) + chalk.cyan('β'));
|
|
311
|
+
console.log(chalk.cyan('β') + chalk.gray(` μκ°: ${timeString}`.padEnd(78)) + chalk.cyan('β'));
|
|
181
312
|
console.log(chalk.cyan('β' + 'β'.repeat(78) + 'β'));
|
|
182
313
|
console.log('');
|
|
183
314
|
|
|
184
315
|
try {
|
|
185
316
|
const status = readStatus();
|
|
186
317
|
const activeSessions = status.activeSessions || [];
|
|
187
|
-
|
|
318
|
+
pendingQuestions = status.pendingQuestions?.filter(q => q.status === 'waiting') || [];
|
|
188
319
|
const taskProgress = status.taskProgress || {};
|
|
189
320
|
const notifications = status.notifications || [];
|
|
190
321
|
|
|
191
322
|
// ν΅κ³ ν¨λ
|
|
192
|
-
console.log(chalk.bgBlue.white.bold('
|
|
323
|
+
console.log(chalk.bgBlue.white.bold(' ν΅κ³ '));
|
|
193
324
|
console.log('');
|
|
194
325
|
console.log(chalk.white(` νμ± μΈμ
: ${chalk.yellow(activeSessions.length)}κ°`));
|
|
195
326
|
console.log(chalk.white(` λκΈ° μ§λ¬Έ: ${pendingQuestions.length > 0 ? chalk.red(pendingQuestions.length) : chalk.green('0')}κ°`));
|
|
@@ -203,13 +334,13 @@ async function watchSessions() {
|
|
|
203
334
|
|
|
204
335
|
// νμ± μΈμ
|
|
205
336
|
if (activeSessions.length > 0) {
|
|
206
|
-
console.log(chalk.bgGreen.black.bold('
|
|
337
|
+
console.log(chalk.bgGreen.black.bold(' νμ± μΈμ
'));
|
|
207
338
|
console.log('');
|
|
208
339
|
|
|
209
340
|
activeSessions.forEach((session, index) => {
|
|
210
341
|
const startTime = new Date(session.startedAt);
|
|
211
342
|
const duration = Math.floor((now - startTime) / 1000 / 60); // λΆ
|
|
212
|
-
const statusIcon = session.status === 'active' ? '
|
|
343
|
+
const statusIcon = session.status === 'active' ? '+' : '-';
|
|
213
344
|
|
|
214
345
|
console.log(chalk.white(` ${index + 1}. ${statusIcon} ${chalk.bold(session.role)}`));
|
|
215
346
|
console.log(chalk.gray(` λꡬ: ${session.tool}`));
|
|
@@ -227,7 +358,7 @@ async function watchSessions() {
|
|
|
227
358
|
|
|
228
359
|
// λκΈ° μ§λ¬Έ (κ°μ‘°)
|
|
229
360
|
if (pendingQuestions.length > 0) {
|
|
230
|
-
console.log(chalk.bgYellow.black.bold('
|
|
361
|
+
console.log(chalk.bgYellow.black.bold(' λκΈ° μ§λ¬Έ '));
|
|
231
362
|
console.log('');
|
|
232
363
|
|
|
233
364
|
pendingQuestions.slice(0, 3).forEach((q, index) => {
|
|
@@ -255,30 +386,29 @@ async function watchSessions() {
|
|
|
255
386
|
|
|
256
387
|
// μ§ν μ€μΈ Task
|
|
257
388
|
if (activeTasks.length > 0) {
|
|
258
|
-
console.log(chalk.bgCyan.black.bold('
|
|
389
|
+
console.log(chalk.bgCyan.black.bold(' μ§ν μ€μΈ Task '));
|
|
259
390
|
console.log('');
|
|
260
391
|
|
|
261
392
|
activeTasks.slice(0, 5).forEach((taskId, index) => {
|
|
262
393
|
const task = taskProgress[taskId];
|
|
263
|
-
|
|
264
|
-
const bars = Math.floor(progress / 5);
|
|
265
|
-
const progressBar = 'β'.repeat(bars) + 'β'.repeat(20 - bars);
|
|
266
|
-
|
|
394
|
+
|
|
267
395
|
const statusColors = {
|
|
268
396
|
'IN_DEV': chalk.blue,
|
|
269
397
|
'IN_REVIEW': chalk.yellow,
|
|
270
|
-
'IN_QA': chalk.magenta,
|
|
271
398
|
'READY': chalk.gray,
|
|
272
399
|
'IN_SPRINT': chalk.cyan
|
|
273
400
|
};
|
|
274
401
|
|
|
275
|
-
const
|
|
402
|
+
const normalizedStatus = task.status === 'IN_QA' ? 'IN_REVIEW' : task.status;
|
|
403
|
+
const statusColor = statusColors[normalizedStatus] || chalk.white;
|
|
276
404
|
|
|
277
|
-
console.log(chalk.white(` ${taskId}: ${
|
|
278
|
-
|
|
405
|
+
console.log(chalk.white(` ${taskId}: [${statusColor(normalizedStatus)}]`));
|
|
406
|
+
if (task.assignee) {
|
|
407
|
+
console.log(chalk.gray(` λ΄λΉ: ${task.assignee}`));
|
|
408
|
+
}
|
|
279
409
|
|
|
280
410
|
if (task.note) {
|
|
281
|
-
console.log(chalk.gray(`
|
|
411
|
+
console.log(chalk.gray(` λ©λͺ¨: ${task.note}`));
|
|
282
412
|
}
|
|
283
413
|
|
|
284
414
|
if (index < Math.min(activeTasks.length, 5) - 1) {
|
|
@@ -296,19 +426,19 @@ async function watchSessions() {
|
|
|
296
426
|
// μ΅κ·Ό μλ¦Ό
|
|
297
427
|
const recentNotifications = notifications.slice(-3).reverse();
|
|
298
428
|
if (recentNotifications.length > 0) {
|
|
299
|
-
console.log(chalk.bgMagenta.white.bold('
|
|
429
|
+
console.log(chalk.bgMagenta.white.bold(' μ΅κ·Ό μλ¦Ό '));
|
|
300
430
|
console.log('');
|
|
301
431
|
|
|
302
432
|
recentNotifications.forEach((notif, index) => {
|
|
303
433
|
const typeIcons = {
|
|
304
|
-
'info': '
|
|
305
|
-
'warning': '
|
|
306
|
-
'error': '
|
|
307
|
-
'question': '
|
|
308
|
-
'complete': '
|
|
434
|
+
'info': 'i',
|
|
435
|
+
'warning': '!',
|
|
436
|
+
'error': 'x',
|
|
437
|
+
'question': '?',
|
|
438
|
+
'complete': 'v'
|
|
309
439
|
};
|
|
310
440
|
|
|
311
|
-
const icon = typeIcons[notif.type] || '
|
|
441
|
+
const icon = typeIcons[notif.type] || '?';
|
|
312
442
|
const readStatus = notif.read ? chalk.gray('[μ½μ]') : chalk.yellow('[μμ½μ]');
|
|
313
443
|
|
|
314
444
|
console.log(chalk.white(` ${icon} ${readStatus} ${notif.message}`));
|
|
@@ -335,8 +465,30 @@ async function watchSessions() {
|
|
|
335
465
|
if (lastUpdate) {
|
|
336
466
|
console.log(chalk.gray(` λ§μ§λ§ μ
λ°μ΄νΈ: ${lastUpdate}`));
|
|
337
467
|
}
|
|
468
|
+
|
|
469
|
+
enqueueQuestions(pendingQuestions);
|
|
470
|
+
processPromptQueue();
|
|
338
471
|
}
|
|
339
472
|
|
|
473
|
+
// ν€λ³΄λ μ
λ ₯ μ²λ¦¬
|
|
474
|
+
const keyHandler = (str, key) => {
|
|
475
|
+
if (key.ctrl && key.name === 'c') {
|
|
476
|
+
cleanup();
|
|
477
|
+
} else if (key.name === 'q') {
|
|
478
|
+
cleanup();
|
|
479
|
+
} else if (key.name === 'r') {
|
|
480
|
+
drawScreen();
|
|
481
|
+
lastUpdate = new Date().toLocaleTimeString('ko-KR');
|
|
482
|
+
} else if (key.name === 'c') {
|
|
483
|
+
console.clear();
|
|
484
|
+
drawScreen();
|
|
485
|
+
} else if (key.name === 'h') {
|
|
486
|
+
showHelp();
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
enableKeypressHandling();
|
|
491
|
+
|
|
340
492
|
// μ΄κΈ° νλ©΄ 그리기
|
|
341
493
|
drawScreen();
|
|
342
494
|
lastUpdate = new Date().toLocaleTimeString('ko-KR');
|
|
@@ -361,7 +513,7 @@ async function watchSessions() {
|
|
|
361
513
|
|
|
362
514
|
// 30μ΄λ§λ€ μ’λΉ μΈμ
μ 리 (2μ΄ Γ 15 = 30μ΄)
|
|
363
515
|
if (tickCount % 15 === 0) {
|
|
364
|
-
const removedCount = cleanupZombieSessions(60); //
|
|
516
|
+
const removedCount = cleanupZombieSessions(60); // λΉνμ±/μ€λλ μΈμ
μ κ±°
|
|
365
517
|
if (removedCount > 0) {
|
|
366
518
|
lastUpdate = `${new Date().toLocaleTimeString('ko-KR')} (μ’λΉ μΈμ
${removedCount}κ° μ 리λ¨)`;
|
|
367
519
|
}
|
|
@@ -371,38 +523,16 @@ async function watchSessions() {
|
|
|
371
523
|
}
|
|
372
524
|
}, 2000);
|
|
373
525
|
|
|
374
|
-
// ν€λ³΄λ μ
λ ₯ μ²λ¦¬
|
|
375
|
-
const keyHandler = (str, key) => {
|
|
376
|
-
if (key.ctrl && key.name === 'c') {
|
|
377
|
-
cleanup();
|
|
378
|
-
} else if (key.name === 'q') {
|
|
379
|
-
cleanup();
|
|
380
|
-
} else if (key.name === 'r') {
|
|
381
|
-
drawScreen();
|
|
382
|
-
lastUpdate = new Date().toLocaleTimeString('ko-KR');
|
|
383
|
-
} else if (key.name === 'c') {
|
|
384
|
-
console.clear();
|
|
385
|
-
drawScreen();
|
|
386
|
-
} else if (key.name === 'h') {
|
|
387
|
-
showHelp();
|
|
388
|
-
}
|
|
389
|
-
};
|
|
390
|
-
|
|
391
|
-
process.stdin.on('keypress', keyHandler);
|
|
392
|
-
|
|
393
526
|
// μ 리 ν¨μ
|
|
394
527
|
function cleanup() {
|
|
395
528
|
isWatching = false;
|
|
396
529
|
clearInterval(intervalId);
|
|
397
530
|
if (watcher) watcher.close();
|
|
398
531
|
|
|
399
|
-
|
|
400
|
-
process.stdin.setRawMode(false);
|
|
401
|
-
}
|
|
402
|
-
process.stdin.removeListener('keypress', keyHandler);
|
|
532
|
+
disableKeypressHandling();
|
|
403
533
|
|
|
404
534
|
console.log('');
|
|
405
|
-
console.log(chalk.cyan('
|
|
535
|
+
console.log(chalk.cyan('Watch λͺ¨λλ₯Ό μ’
λ£ν©λλ€.'));
|
|
406
536
|
console.log('');
|
|
407
537
|
process.exit(0);
|
|
408
538
|
}
|
|
@@ -412,7 +542,7 @@ async function watchSessions() {
|
|
|
412
542
|
console.clear();
|
|
413
543
|
console.log('');
|
|
414
544
|
console.log(chalk.cyan('β' + 'β'.repeat(78) + 'β'));
|
|
415
|
-
console.log(chalk.cyan('β') + chalk.bold.white('
|
|
545
|
+
console.log(chalk.cyan('β') + chalk.bold.white(' Watch λͺ¨λ λμλ§'.padEnd(78)) + chalk.cyan('β'));
|
|
416
546
|
console.log(chalk.cyan('β' + 'β'.repeat(78) + 'β'));
|
|
417
547
|
console.log('');
|
|
418
548
|
console.log(chalk.white(' Watch λͺ¨λλ μ€μκ°μΌλ‘ μΈμ
μνλ₯Ό λͺ¨λν°λ§ν©λλ€.'));
|
|
@@ -430,6 +560,7 @@ async function watchSessions() {
|
|
|
430
560
|
console.log('');
|
|
431
561
|
console.log(chalk.yellow(' Manager μν :'));
|
|
432
562
|
console.log(chalk.white(' - λκΈ° μ§λ¬Έ νμΈ λ° μλ΅'));
|
|
563
|
+
console.log(chalk.white(' - μ§λ¬Έ λ°μ μ μλ μλ΅ ν둬ννΈ νμ'));
|
|
433
564
|
console.log(chalk.white(' - Task μ§ν μν© λͺ¨λν°λ§'));
|
|
434
565
|
console.log(chalk.white(' - μΈμ
μν μ€μκ° μΆμ '));
|
|
435
566
|
console.log('');
|
|
@@ -444,3 +575,72 @@ async function watchSessions() {
|
|
|
444
575
|
process.on('SIGINT', cleanup);
|
|
445
576
|
process.on('SIGTERM', cleanup);
|
|
446
577
|
}
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* μλ£λ μΈμ
μ 리
|
|
581
|
+
*/
|
|
582
|
+
async function cleanupCompletedSessions() {
|
|
583
|
+
const sessionsDir = getSessionsDir();
|
|
584
|
+
|
|
585
|
+
if (!fs.existsSync(sessionsDir)) {
|
|
586
|
+
console.log(chalk.yellow('β οΈ μΈμ
λλ ν λ¦¬κ° μμ΅λλ€.'));
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
console.log('');
|
|
591
|
+
console.log(chalk.cyan('β'.repeat(60)));
|
|
592
|
+
console.log(chalk.cyan.bold('μλ£λ μΈμ
μ 리 (status: completed)'));
|
|
593
|
+
console.log(chalk.cyan('β'.repeat(60)));
|
|
594
|
+
console.log('');
|
|
595
|
+
|
|
596
|
+
const sessionDirs = fs.readdirSync(sessionsDir)
|
|
597
|
+
.filter(f => fs.statSync(path.join(sessionsDir, f)).isDirectory())
|
|
598
|
+
.sort();
|
|
599
|
+
|
|
600
|
+
let completedCount = 0;
|
|
601
|
+
let skippedCount = 0;
|
|
602
|
+
let errorCount = 0;
|
|
603
|
+
|
|
604
|
+
for (const sessionId of sessionDirs) {
|
|
605
|
+
const sessionPath = path.join(sessionsDir, sessionId);
|
|
606
|
+
const sessionFile = path.join(sessionPath, 'session.json');
|
|
607
|
+
|
|
608
|
+
try {
|
|
609
|
+
// session.json νμΈ
|
|
610
|
+
if (!fs.existsSync(sessionFile)) {
|
|
611
|
+
console.log(chalk.gray(` ${sessionId}: session.json μμ (건λλ)`));
|
|
612
|
+
skippedCount++;
|
|
613
|
+
continue;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// μΈμ
μ 보 μ½κΈ°
|
|
617
|
+
const session = JSON.parse(fs.readFileSync(sessionFile, 'utf-8'));
|
|
618
|
+
|
|
619
|
+
// μλ£ μνκ° μλλ©΄ 건λλ
|
|
620
|
+
if (session.status !== 'completed') {
|
|
621
|
+
console.log(chalk.yellow(` ${sessionId}: μλ£ μλ (${session.status || 'unknown'}) - μ μ§`));
|
|
622
|
+
skippedCount++;
|
|
623
|
+
continue;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// μΈμ
λλ ν 리 μμ
|
|
627
|
+
fs.removeSync(sessionPath);
|
|
628
|
+
console.log(chalk.green(` β ${sessionId}: μμ λ¨ (${session.status})`));
|
|
629
|
+
completedCount++;
|
|
630
|
+
|
|
631
|
+
} catch (error) {
|
|
632
|
+
console.log(chalk.red(` β ${sessionId}: μ€λ₯ - ${error.message}`));
|
|
633
|
+
errorCount++;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
console.log('');
|
|
638
|
+
console.log(chalk.cyan('β'.repeat(60)));
|
|
639
|
+
console.log(chalk.white(` μμ λ¨: ${chalk.green(completedCount)}κ°`));
|
|
640
|
+
console.log(chalk.white(` μ μ§λ¨: ${chalk.gray(skippedCount)}κ°`));
|
|
641
|
+
if (errorCount > 0) {
|
|
642
|
+
console.log(chalk.white(` μ€λ₯: ${chalk.red(errorCount)}κ°`));
|
|
643
|
+
}
|
|
644
|
+
console.log(chalk.cyan('β'.repeat(60)));
|
|
645
|
+
console.log('');
|
|
646
|
+
}
|
package/src/commands/setup.js
CHANGED
|
@@ -7,7 +7,9 @@ import {
|
|
|
7
7
|
getWorkspaceDir,
|
|
8
8
|
getCurrentTemplateFile,
|
|
9
9
|
getAvailableTemplates,
|
|
10
|
-
copyDirMerge
|
|
10
|
+
copyDirMerge,
|
|
11
|
+
getPackageVersion,
|
|
12
|
+
writeVersion
|
|
11
13
|
} from '../utils/files.js';
|
|
12
14
|
|
|
13
15
|
export async function setup(template) {
|
|
@@ -66,8 +68,11 @@ export async function setup(template) {
|
|
|
66
68
|
fs.ensureDirSync(path.join(workspace, 'roles'));
|
|
67
69
|
fs.ensureDirSync(path.join(workspace, 'artifacts'));
|
|
68
70
|
fs.ensureDirSync(path.join(workspace, 'rules'));
|
|
71
|
+
fs.ensureDirSync(path.join(workspace, 'artifacts', 'backlog'));
|
|
72
|
+
fs.ensureDirSync(path.join(workspace, 'artifacts', 'sprints'));
|
|
69
73
|
fs.ensureDirSync(path.join(workspace, 'artifacts', 'features', '_template'));
|
|
70
74
|
fs.ensureDirSync(path.join(workspace, 'artifacts', 'rfc'));
|
|
75
|
+
fs.ensureDirSync(path.join(workspace, 'artifacts', 'improvement-reports'));
|
|
71
76
|
|
|
72
77
|
// Core 볡μ¬
|
|
73
78
|
console.log(chalk.gray('π Core νμΌ λ³΅μ¬ μ€...'));
|
|
@@ -93,9 +98,25 @@ export async function setup(template) {
|
|
|
93
98
|
fs.copyFileSync(rfcTemplateFile, path.join(workspace, 'artifacts', 'rfc', 'RFC-0000-template.md'));
|
|
94
99
|
}
|
|
95
100
|
|
|
101
|
+
// Improvement Reports ν
νλ¦Ώ 볡μ¬
|
|
102
|
+
const improvementTemplateFile = path.join(packageRoot, 'ai-dev-team', 'artifacts', 'improvement-reports', 'IMP-0000-template.md');
|
|
103
|
+
if (fs.existsSync(improvementTemplateFile)) {
|
|
104
|
+
fs.copyFileSync(improvementTemplateFile, path.join(workspace, 'artifacts', 'improvement-reports', 'IMP-0000-template.md'));
|
|
105
|
+
}
|
|
106
|
+
|
|
96
107
|
// νμ¬ ν
νλ¦Ώ μ μ₯
|
|
97
108
|
fs.writeFileSync(getCurrentTemplateFile(), template);
|
|
98
109
|
|
|
110
|
+
// λ²μ μ 보 μ μ₯
|
|
111
|
+
const packageVersion = getPackageVersion();
|
|
112
|
+
const versionInfo = {
|
|
113
|
+
packageVersion: packageVersion,
|
|
114
|
+
workspaceVersion: packageVersion,
|
|
115
|
+
template: template,
|
|
116
|
+
lastUpgrade: new Date().toISOString()
|
|
117
|
+
};
|
|
118
|
+
writeVersion(versionInfo);
|
|
119
|
+
|
|
99
120
|
// κ²°κ³Ό μΆλ ₯
|
|
100
121
|
console.log('');
|
|
101
122
|
console.log(chalk.green('β
μΈν
μλ£!'));
|