sleepcode 1.3.0 → 1.4.0
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/.claude/settings.local.json +2 -1
- package/README.md +27 -3
- package/bin/index.js +131 -3
- package/package.json +1 -1
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"Bash(npm publish)",
|
|
12
12
|
"Bash(npm version:*)",
|
|
13
13
|
"Bash(NPM_TOKEN=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 npm publish:*)",
|
|
14
|
-
"Bash(NPM_TOKEN=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 npm publish)"
|
|
14
|
+
"Bash(NPM_TOKEN=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 npm publish)",
|
|
15
|
+
"Bash(git push:*)"
|
|
15
16
|
]
|
|
16
17
|
}
|
|
17
18
|
}
|
package/README.md
CHANGED
|
@@ -31,7 +31,22 @@ npx sleepcode
|
|
|
31
31
|
|
|
32
32
|
인터랙티브 모드로 프로젝트 타입, 이름, AI 역할 등을 설정합니다.
|
|
33
33
|
|
|
34
|
-
### 2.
|
|
34
|
+
### 2. 참고 자료 추가
|
|
35
|
+
|
|
36
|
+
`.sleepcode/docs/`에 기획서, 피그마 스크린샷 등 참고 자료를 넣습니다.
|
|
37
|
+
|
|
38
|
+
### 3. 태스크 작성
|
|
39
|
+
|
|
40
|
+
**방법 A: 자동 생성 (추천)**
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npx sleepcode generate
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
참고 자료(docs/, Figma, Notion)와 프로젝트 구조를 분석해서 `tasks.md`를 자동 생성합니다.
|
|
47
|
+
이미 구현된 기능은 제외됩니다.
|
|
48
|
+
|
|
49
|
+
**방법 B: 직접 작성**
|
|
35
50
|
|
|
36
51
|
`.sleepcode/tasks.md` 에 AI가 수행할 작업을 작성합니다:
|
|
37
52
|
|
|
@@ -43,7 +58,7 @@ npx sleepcode
|
|
|
43
58
|
- [ ] 홈 화면 UI 개선
|
|
44
59
|
```
|
|
45
60
|
|
|
46
|
-
###
|
|
61
|
+
### 4. 실행
|
|
47
62
|
|
|
48
63
|
```bash
|
|
49
64
|
# 1회 실행
|
|
@@ -55,7 +70,7 @@ npx sleepcode run --loop
|
|
|
55
70
|
|
|
56
71
|
OS에 맞는 스크립트를 자동으로 선택합니다 (macOS/Linux: `.sh`, Windows: `.ps1`).
|
|
57
72
|
|
|
58
|
-
###
|
|
73
|
+
### 5. 아침에 확인
|
|
59
74
|
|
|
60
75
|
```bash
|
|
61
76
|
git log --oneline --since="12 hours ago"
|
|
@@ -74,6 +89,15 @@ git log --oneline --since="12 hours ago"
|
|
|
74
89
|
|
|
75
90
|
---
|
|
76
91
|
|
|
92
|
+
## CLI 명령어
|
|
93
|
+
|
|
94
|
+
| 명령어 | 설명 |
|
|
95
|
+
|--------|------|
|
|
96
|
+
| `npx sleepcode` | 인터랙티브 초기화 |
|
|
97
|
+
| `npx sleepcode run` | 1회 실행 |
|
|
98
|
+
| `npx sleepcode run --loop` | 무한 루프 실행 |
|
|
99
|
+
| `npx sleepcode generate` | 참고자료 기반 tasks.md 자동 생성 |
|
|
100
|
+
|
|
77
101
|
## CLI 옵션
|
|
78
102
|
|
|
79
103
|
인터랙티브 모드 외에 CLI 인자로도 사용 가능합니다:
|
package/bin/index.js
CHANGED
|
@@ -199,12 +199,14 @@ function parseArgs() {
|
|
|
199
199
|
console.log(`
|
|
200
200
|
사용법: sleepcode [옵션]
|
|
201
201
|
sleepcode run [--loop]
|
|
202
|
+
sleepcode generate
|
|
202
203
|
|
|
203
204
|
옵션 없이 실행하면 인터랙티브 모드로 동작합니다.
|
|
204
205
|
|
|
205
206
|
명령어:
|
|
206
207
|
run 1회 실행 (ai_worker 스크립트)
|
|
207
208
|
run --loop 무한 루프 실행 (run_forever 스크립트)
|
|
209
|
+
generate 참고자료 기반으로 tasks.md 자동 생성
|
|
208
210
|
|
|
209
211
|
옵션:
|
|
210
212
|
--type <type> 프로젝트 타입 (spring-boot, react-native, nextjs, custom)
|
|
@@ -388,8 +390,11 @@ function printResult() {
|
|
|
388
390
|
${C.bold}${C.green}완료!${C.reset} 다음 단계:
|
|
389
391
|
|
|
390
392
|
${C.bold}1.${C.reset} .sleepcode/rules.md 를 프로젝트에 맞게 수정
|
|
391
|
-
${C.bold}2.${C.reset} .sleepcode/
|
|
392
|
-
${C.bold}3.${C.reset}
|
|
393
|
+
${C.bold}2.${C.reset} .sleepcode/docs/ 에 참고 자료 추가 (기획서, 스크린샷 등)
|
|
394
|
+
${C.bold}3.${C.reset} 태스크 생성:
|
|
395
|
+
${C.cyan}npx sleepcode generate${C.reset} ${C.dim}# 참고자료 기반 tasks.md 자동 생성${C.reset}
|
|
396
|
+
${C.dim}또는 .sleepcode/tasks.md 를 직접 작성${C.reset}
|
|
397
|
+
${C.bold}4.${C.reset} 실행:
|
|
393
398
|
${C.cyan}npx sleepcode run${C.reset} ${C.dim}# 1회 실행${C.reset}
|
|
394
399
|
${C.cyan}npx sleepcode run --loop${C.reset} ${C.dim}# 무한 루프${C.reset}
|
|
395
400
|
`);
|
|
@@ -428,17 +433,140 @@ function runWorker(loop) {
|
|
|
428
433
|
}
|
|
429
434
|
}
|
|
430
435
|
|
|
436
|
+
// ─── 태스크 자동 생성 ───
|
|
437
|
+
function generateTasks() {
|
|
438
|
+
const targetDir = process.cwd();
|
|
439
|
+
const scDir = path.join(targetDir, '.sleepcode');
|
|
440
|
+
|
|
441
|
+
if (!fs.existsSync(scDir)) {
|
|
442
|
+
console.error(`${C.red}.sleepcode/ 폴더가 없습니다. 먼저 'npx sleepcode'로 초기화하세요.${C.reset}`);
|
|
443
|
+
process.exit(1);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// claude CLI 확인
|
|
447
|
+
if (!checkCommand('claude --version')) {
|
|
448
|
+
console.error(`${C.red}claude CLI가 설치되어 있지 않습니다.${C.reset}`);
|
|
449
|
+
process.exit(1);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
console.log(`${C.cyan}태스크 자동 생성 중...${C.reset}\n`);
|
|
453
|
+
|
|
454
|
+
// 참고 자료 수집
|
|
455
|
+
const parts = [];
|
|
456
|
+
|
|
457
|
+
// 1. base_rules.md (프로젝트 공통 규칙 — 역할 파악용)
|
|
458
|
+
const baseRulesPath = path.join(scDir, 'scripts', 'base_rules.md');
|
|
459
|
+
if (fs.existsSync(baseRulesPath)) {
|
|
460
|
+
parts.push(fs.readFileSync(baseRulesPath, 'utf-8'));
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// 2. rules.md (프로젝트별 역할/작업방식)
|
|
464
|
+
const rulesPath = path.join(scDir, 'rules.md');
|
|
465
|
+
if (fs.existsSync(rulesPath)) {
|
|
466
|
+
parts.push(fs.readFileSync(rulesPath, 'utf-8'));
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// 3. docs/ 디렉토리 파일 목록 + 내용
|
|
470
|
+
const docsDir = path.join(scDir, 'docs');
|
|
471
|
+
if (fs.existsSync(docsDir)) {
|
|
472
|
+
const files = fs.readdirSync(docsDir).filter(f => f !== '.gitkeep');
|
|
473
|
+
for (const file of files) {
|
|
474
|
+
const filePath = path.join(docsDir, file);
|
|
475
|
+
const stat = fs.statSync(filePath);
|
|
476
|
+
if (stat.isFile() && stat.size < 100000) {
|
|
477
|
+
// 텍스트 파일만 읽기 (이미지 등은 파일명만)
|
|
478
|
+
const ext = path.extname(file).toLowerCase();
|
|
479
|
+
if (['.md', '.txt', '.json', '.yaml', '.yml', '.csv', '.html'].includes(ext)) {
|
|
480
|
+
parts.push(`--- docs/${file} ---\n${fs.readFileSync(filePath, 'utf-8')}`);
|
|
481
|
+
} else {
|
|
482
|
+
parts.push(`--- docs/${file} --- (파일 존재, 내용은 직접 참고)`);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// 4. 현재 프로젝트 구조 (이미 구현된 것 파악용)
|
|
489
|
+
try {
|
|
490
|
+
const tree = execSync('git ls-files', { cwd: targetDir, stdio: ['pipe', 'pipe', 'pipe'], timeout: 10000 })
|
|
491
|
+
.toString().trim();
|
|
492
|
+
if (tree) {
|
|
493
|
+
parts.push(`--- 현재 프로젝트 파일 목록 (이미 구현됨) ---\n${tree}`);
|
|
494
|
+
}
|
|
495
|
+
} catch {
|
|
496
|
+
// git이 없거나 실패하면 무시
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// 5. 기존 tasks.md (있으면 참고)
|
|
500
|
+
const tasksPath = path.join(scDir, 'tasks.md');
|
|
501
|
+
if (fs.existsSync(tasksPath)) {
|
|
502
|
+
const existing = fs.readFileSync(tasksPath, 'utf-8');
|
|
503
|
+
if (existing.includes('[ ]') || existing.includes('[x]')) {
|
|
504
|
+
parts.push(`--- 기존 tasks.md ---\n${existing}`);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// 프롬프트 구성
|
|
509
|
+
const context = parts.join('\n\n---\n\n');
|
|
510
|
+
const prompt = `${context}
|
|
511
|
+
|
|
512
|
+
---
|
|
513
|
+
|
|
514
|
+
위 프로젝트 정보와 참고 자료를 바탕으로 .sleepcode/tasks.md 파일을 생성해주세요.
|
|
515
|
+
|
|
516
|
+
규칙:
|
|
517
|
+
- 마크다운 체크리스트 형식으로 작성: \`- [ ] 태스크 내용\`
|
|
518
|
+
- 구체적이고 실행 가능한 단위로 태스크를 나눌 것
|
|
519
|
+
- 태스크 순서는 의존성을 고려하여 배치
|
|
520
|
+
- Figma 디자인이 있으면 UI 구현 태스크도 포함
|
|
521
|
+
- Notion 문서가 있으면 기획 내용을 반영
|
|
522
|
+
- docs/ 폴더의 참고 자료를 반영
|
|
523
|
+
- **이미 프로젝트에 구현되어 있는 기능은 태스크에 포함하지 않는다**
|
|
524
|
+
- 현재 프로젝트 파일 목록을 분석하여 아직 구현되지 않은 것만 태스크로 작성
|
|
525
|
+
- 첫 줄은 \`# 작업 목록\` 으로 시작
|
|
526
|
+
- 태스크 목록 앞에 간단한 안내 문구 포함
|
|
527
|
+
|
|
528
|
+
tasks.md 내용만 출력하세요. 다른 설명은 하지 마세요.`;
|
|
529
|
+
|
|
530
|
+
try {
|
|
531
|
+
const result = execSync(
|
|
532
|
+
'claude -p --output-format text',
|
|
533
|
+
{
|
|
534
|
+
input: prompt,
|
|
535
|
+
cwd: targetDir,
|
|
536
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
537
|
+
timeout: 300000,
|
|
538
|
+
maxBuffer: 1024 * 1024,
|
|
539
|
+
}
|
|
540
|
+
).toString().trim();
|
|
541
|
+
|
|
542
|
+
// tasks.md에 저장
|
|
543
|
+
fs.writeFileSync(tasksPath, result + '\n');
|
|
544
|
+
console.log(`${C.green}✓${C.reset} .sleepcode/tasks.md 생성 완료\n`);
|
|
545
|
+
console.log(`${C.dim}${result}${C.reset}\n`);
|
|
546
|
+
console.log(`필요하면 tasks.md를 직접 수정한 뒤 실행하세요:`);
|
|
547
|
+
console.log(` ${C.cyan}npx sleepcode run${C.reset} ${C.dim}# 1회 실행${C.reset}`);
|
|
548
|
+
console.log(` ${C.cyan}npx sleepcode run --loop${C.reset} ${C.dim}# 무한 루프${C.reset}`);
|
|
549
|
+
} catch (e) {
|
|
550
|
+
console.error(`${C.red}태스크 생성 실패: ${e.message}${C.reset}`);
|
|
551
|
+
process.exit(1);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
431
555
|
// ─── 메인 ───
|
|
432
556
|
async function main() {
|
|
433
557
|
const targetDir = process.cwd();
|
|
434
558
|
|
|
435
|
-
//
|
|
559
|
+
// 서브커맨드 처리
|
|
436
560
|
const firstArg = process.argv[2];
|
|
437
561
|
if (firstArg === 'run') {
|
|
438
562
|
const loop = process.argv.includes('--loop');
|
|
439
563
|
runWorker(loop);
|
|
440
564
|
return;
|
|
441
565
|
}
|
|
566
|
+
if (firstArg === 'generate') {
|
|
567
|
+
generateTasks();
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
442
570
|
|
|
443
571
|
const cliArgs = parseArgs();
|
|
444
572
|
|