timsquad 3.5.0 → 3.6.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/README.ko.md +4 -0
- package/README.md +4 -0
- package/dist/commands/audit.d.ts +22 -0
- package/dist/commands/audit.d.ts.map +1 -0
- package/dist/commands/audit.js +233 -0
- package/dist/commands/audit.js.map +1 -0
- package/dist/commands/compile.d.ts.map +1 -1
- package/dist/commands/compile.js +84 -3
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/daemon.d.ts.map +1 -1
- package/dist/commands/daemon.js +48 -2
- package/dist/commands/daemon.js.map +1 -1
- package/dist/commands/init.js +42 -6
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/log.d.ts.map +1 -1
- package/dist/commands/log.js +32 -0
- package/dist/commands/log.js.map +1 -1
- package/dist/commands/meta-index.d.ts.map +1 -1
- package/dist/commands/meta-index.js +30 -0
- package/dist/commands/meta-index.js.map +1 -1
- package/dist/commands/retro.d.ts.map +1 -1
- package/dist/commands/retro.js +63 -6
- package/dist/commands/retro.js.map +1 -1
- package/dist/commands/workflow.d.ts +2 -0
- package/dist/commands/workflow.d.ts.map +1 -1
- package/dist/commands/workflow.js +180 -6
- package/dist/commands/workflow.js.map +1 -1
- package/dist/daemon/context-writer.d.ts +14 -0
- package/dist/daemon/context-writer.d.ts.map +1 -1
- package/dist/daemon/context-writer.js +29 -0
- package/dist/daemon/context-writer.js.map +1 -1
- package/dist/daemon/event-queue.d.ts +4 -0
- package/dist/daemon/event-queue.d.ts.map +1 -1
- package/dist/daemon/event-queue.js +107 -6
- package/dist/daemon/event-queue.js.map +1 -1
- package/dist/daemon/file-watcher.d.ts +14 -8
- package/dist/daemon/file-watcher.d.ts.map +1 -1
- package/dist/daemon/file-watcher.js +78 -41
- package/dist/daemon/file-watcher.js.map +1 -1
- package/dist/daemon/index.d.ts.map +1 -1
- package/dist/daemon/index.js +42 -36
- package/dist/daemon/index.js.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-generator.d.ts.map +1 -1
- package/dist/lib/agent-generator.js +11 -0
- package/dist/lib/agent-generator.js.map +1 -1
- package/dist/lib/compile-rules.d.ts +2 -0
- package/dist/lib/compile-rules.d.ts.map +1 -1
- package/dist/lib/compile-rules.js +2 -0
- package/dist/lib/compile-rules.js.map +1 -1
- package/dist/lib/compiler.d.ts +21 -1
- package/dist/lib/compiler.d.ts.map +1 -1
- package/dist/lib/compiler.js +113 -3
- package/dist/lib/compiler.js.map +1 -1
- package/dist/lib/config.d.ts +3 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +17 -2
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/skill-generator.d.ts +1 -1
- package/dist/lib/skill-generator.d.ts.map +1 -1
- package/dist/lib/skill-generator.js +17 -2
- package/dist/lib/skill-generator.js.map +1 -1
- package/dist/lib/ssot-map.d.ts +31 -0
- package/dist/lib/ssot-map.d.ts.map +1 -0
- package/dist/lib/ssot-map.js +76 -0
- package/dist/lib/ssot-map.js.map +1 -0
- package/dist/lib/template.js +1 -0
- package/dist/lib/template.js.map +1 -1
- package/dist/lib/workflow-state.d.ts +1 -1
- package/dist/lib/workflow-state.d.ts.map +1 -1
- package/dist/lib/workflow-state.js +1 -1
- package/dist/lib/workflow-state.js.map +1 -1
- package/dist/types/config.d.ts +10 -1
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js +22 -17
- package/dist/types/config.js.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/meta-index.d.ts +8 -0
- package/dist/types/meta-index.d.ts.map +1 -1
- package/dist/types/project.d.ts +1 -1
- package/dist/types/project.d.ts.map +1 -1
- package/dist/types/project.js.map +1 -1
- package/dist/types/ssot-map.d.ts +28 -0
- package/dist/types/ssot-map.d.ts.map +1 -0
- package/dist/types/ssot-map.js +6 -0
- package/dist/types/ssot-map.js.map +1 -0
- package/package.json +1 -1
- package/templates/base/agents/base/tsq-librarian.md +45 -0
- package/templates/base/skills/_shared/naming-conventions.md +49 -0
- package/templates/base/skills/_template/SKILL.md +33 -17
- package/templates/base/skills/audit/SKILL.md +66 -0
- package/templates/base/skills/coding/SKILL.md +49 -29
- package/templates/base/skills/coding/rules/async-patterns.md +81 -0
- package/templates/base/skills/coding/rules/code-organization.md +80 -0
- package/templates/base/skills/coding/rules/error-handling.md +76 -0
- package/templates/base/skills/coding/rules/type-safety.md +85 -0
- package/templates/base/skills/controller/SKILL.md +50 -84
- package/templates/base/skills/controller/delegation/developer.md +25 -0
- package/templates/base/skills/controller/delegation/librarian.md +33 -0
- package/templates/base/skills/controller/delegation/reviewer.md +19 -0
- package/templates/base/skills/controller/memory/.gitkeep +0 -0
- package/templates/base/skills/controller/triggers/phase-complete.md +25 -0
- package/templates/base/skills/controller/triggers/sequence-complete.md +15 -0
- package/templates/base/skills/controller/triggers/ssot-changed.md +14 -0
- package/templates/base/skills/controller/triggers/task-complete.md +14 -0
- package/templates/base/skills/database/SKILL.md +8 -25
- package/templates/base/skills/database/rules/query-optimization.md +32 -0
- package/templates/base/skills/database/rules/supabase-patterns.md +94 -0
- package/templates/base/skills/librarian/SKILL.md +53 -0
- package/templates/base/skills/main-session-constraints/SKILL.md +62 -0
- package/templates/base/skills/methodology/tdd/SKILL.md +6 -0
- package/templates/base/skills/product-audit/SKILL.md +115 -0
- package/templates/base/skills/product-audit/checklists/01-security.md +86 -0
- package/templates/base/skills/product-audit/checklists/02-performance.md +67 -0
- package/templates/base/skills/product-audit/checklists/03-seo.md +46 -0
- package/templates/base/skills/product-audit/checklists/04-accessibility.md +66 -0
- package/templates/base/skills/product-audit/checklists/05-ui-ux.md +50 -0
- package/templates/base/skills/product-audit/checklists/06-architecture.md +53 -0
- package/templates/base/skills/product-audit/checklists/07-functional-requirements.md +55 -0
- package/templates/base/skills/product-audit/rules/audit-protocol.md +136 -0
- package/templates/base/skills/product-audit/rules/false-positive-guard.md +81 -0
- package/templates/base/skills/product-audit/rules/scoring-criteria.md +113 -0
- package/templates/base/skills/product-audit/templates/improvement-plan-template.md +60 -0
- package/templates/base/skills/product-audit/templates/report-template.md +88 -0
- package/templates/base/skills/prompt-engineering/SKILL.md +54 -73
- package/templates/base/skills/retrospective/SKILL.md +70 -95
- package/templates/base/skills/retrospective/references/improvement-template.md +26 -0
- package/templates/base/skills/review/SKILL.md +72 -0
- package/templates/base/skills/security/SKILL.md +50 -37
- package/templates/base/skills/security/rules/auth-patterns.md +62 -0
- package/templates/base/skills/security/rules/dependency-security.md +69 -0
- package/templates/base/skills/security/rules/input-validation.md +68 -0
- package/templates/base/skills/security/rules/secrets-management.md +65 -0
- package/templates/base/skills/spec/SKILL.md +60 -0
- package/templates/base/skills/testing/SKILL.md +33 -25
- package/templates/base/skills/testing/references/e2e-stability.md +33 -0
- package/templates/base/skills/tsq-cli/SKILL.md +73 -0
- package/templates/base/skills/tsq-cli/references/cli-reference.md +92 -0
- package/templates/base/skills/tsq-protocol/SKILL.md +41 -25
- package/templates/base/skills/typescript/SKILL.md +3 -9
- package/templates/base/timsquad/ssot/test-spec.template.md +11 -1
- package/templates/base/timsquad/ssot-map.template.yaml +41 -0
- package/templates/platforms/claude-code/rules/api-conventions.md +12 -0
- package/templates/platforms/claude-code/rules/librarian-constraints.md +11 -0
- package/templates/platforms/claude-code/rules/test-conventions.md +13 -0
- package/templates/platforms/claude-code/scripts/change-scope-guard.sh +113 -0
- package/templates/platforms/claude-code/scripts/completion-guard.sh +75 -13
- package/templates/platforms/claude-code/scripts/context-restore.sh +68 -0
- package/templates/platforms/claude-code/scripts/e2e-commit-gate.sh +70 -0
- package/templates/platforms/claude-code/scripts/e2e-marker.sh +51 -0
- package/templates/platforms/claude-code/scripts/phase-guard.sh +1 -1
- package/templates/platforms/claude-code/scripts/pre-compact.sh +70 -0
- package/templates/platforms/claude-code/scripts/skill-inject.sh +216 -0
- package/templates/platforms/claude-code/scripts/skill-rules.json +11 -1
- package/templates/platforms/claude-code/scripts/subagent-inject.sh +53 -0
- package/templates/platforms/claude-code/settings.json +27 -1
|
@@ -1,47 +1,67 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: coding
|
|
3
|
-
description:
|
|
3
|
+
description: |
|
|
4
|
+
코드 작성 규칙 및 패턴 가이드라인.
|
|
5
|
+
네이밍 규칙, 함수 원칙, 에러 핸들링, 금지 패턴을 다룸.
|
|
6
|
+
Use when: "코드 작성, 구현, 리팩토링, 네이밍, 코딩 컨벤션"
|
|
4
7
|
version: "1.0.0"
|
|
5
8
|
tags: [coding, conventions, naming]
|
|
9
|
+
depends_on: []
|
|
10
|
+
conflicts_with: []
|
|
6
11
|
user-invocable: false
|
|
7
12
|
---
|
|
8
13
|
|
|
9
14
|
# Coding Guidelines
|
|
10
15
|
|
|
11
|
-
|
|
16
|
+
코드 작성 시 일관된 컨벤션과 패턴을 적용한다.
|
|
12
17
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
## Philosophy
|
|
19
|
+
|
|
20
|
+
- 단일 책임: 함수는 한 가지 일만 수행
|
|
21
|
+
- 명확한 이름: 코드만 읽고도 동작을 파악 가능
|
|
22
|
+
- 명시적 에러 처리: 에러를 삼키지 않는다
|
|
23
|
+
|
|
24
|
+
## Contract
|
|
25
|
+
|
|
26
|
+
- **Trigger**: 코드 작성/수정 태스크
|
|
27
|
+
- **Input**: 구현 요구사항 + 기존 코드 컨텍스트
|
|
28
|
+
- **Output**: 컨벤션 준수 코드
|
|
29
|
+
- **Error**: 컨벤션 위반 시 수정 안내
|
|
30
|
+
- **Dependencies**: 없음
|
|
31
|
+
|
|
32
|
+
## Protocol
|
|
33
|
+
|
|
34
|
+
1. **컨벤션 확인**: 네이밍, 파일 구조 규칙 확인
|
|
35
|
+
2. **구현**: 단일 책임 원칙 준수하며 코드 작성
|
|
36
|
+
3. **린트**: `tsc --noEmit` + 린트 검증
|
|
37
|
+
4. **리뷰**: 금지 패턴(any, 매직넘버, console.log) 제거 확인
|
|
20
38
|
|
|
21
|
-
##
|
|
22
|
-
- **단일 책임**: 함수는 한 가지 일만 수행
|
|
23
|
-
- **명확한 이름**: 함수 이름만으로 동작 파악 가능
|
|
24
|
-
- **적절한 크기**: 20줄 이내 권장
|
|
39
|
+
## Verification
|
|
25
40
|
|
|
26
|
-
|
|
41
|
+
| Check | Command | Pass Criteria |
|
|
42
|
+
|-------|---------|---------------|
|
|
43
|
+
| 타입 검사 | `tsc --noEmit` | exit code 0 |
|
|
44
|
+
| any 타입 | `grep -r "any" --include="*.ts"` | 0건 (신규 코드) |
|
|
45
|
+
| console.log | `grep -r "console.log" --include="*.ts"` | 0건 (신규 코드) |
|
|
46
|
+
| 함수 크기 | 수동 검증 | 20줄 이내 권장 |
|
|
27
47
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
48
|
+
## Resources
|
|
49
|
+
|
|
50
|
+
| Priority | Type | Resource | Description |
|
|
51
|
+
|----------|------|----------|-------------|
|
|
52
|
+
| HIGH | rule | [patterns](rules/patterns.md) | Error Handling, Repository, DTO, Anti-Patterns |
|
|
53
|
+
|
|
54
|
+
## Quick Rules
|
|
55
|
+
|
|
56
|
+
### 네이밍
|
|
57
|
+
| 대상 | 규칙 | 예시 |
|
|
58
|
+
|------|------|------|
|
|
59
|
+
| 클래스 | PascalCase | `UserService` |
|
|
60
|
+
| 함수/변수 | camelCase | `getUserById` |
|
|
61
|
+
| 상수 | UPPER_SNAKE | `MAX_RETRY_COUNT` |
|
|
62
|
+
| 파일 | kebab-case | `user-service.ts` |
|
|
32
63
|
|
|
33
64
|
### 금지
|
|
34
65
|
- `any` 타입 사용
|
|
35
66
|
- 매직 넘버/문자열 사용
|
|
36
67
|
- `console.log` 사용 (logger 사용)
|
|
37
|
-
|
|
38
|
-
## Checklist
|
|
39
|
-
- [ ] 함수가 단일 책임
|
|
40
|
-
- [ ] 네이밍이 명확하고 일관적
|
|
41
|
-
- [ ] 에러가 명시적으로 처리됨
|
|
42
|
-
- [ ] any 타입 없음
|
|
43
|
-
- [ ] 매직 넘버/문자열 없음
|
|
44
|
-
- [ ] console.log 없음
|
|
45
|
-
|
|
46
|
-
## 참조
|
|
47
|
-
- `rules/patterns.md` — Error Handling, Repository, DTO/Entity, 의존성 주입, Anti-Patterns
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Async/Await Best Practices
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: coding, async, performance
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Async/Await Best Practices
|
|
8
|
+
|
|
9
|
+
## Avoid Callback Hell
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
// Bad: 중첩 콜백
|
|
13
|
+
getUser(id, (user) => {
|
|
14
|
+
getOrders(user.id, (orders) => {
|
|
15
|
+
getItems(orders[0].id, (items) => { /* ... */ });
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// Good: async/await 플랫 구조
|
|
20
|
+
const user = await getUser(id);
|
|
21
|
+
const orders = await getOrders(user.id);
|
|
22
|
+
const items = await getItems(orders[0].id);
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Parallel Execution with Promise.all
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
// Bad: 순차 실행 — 불필요한 대기
|
|
29
|
+
const users = await getUsers();
|
|
30
|
+
const orders = await getOrders();
|
|
31
|
+
const stats = await getStats();
|
|
32
|
+
|
|
33
|
+
// Good: 독립 작업은 병렬 실행
|
|
34
|
+
const [users, orders, stats] = await Promise.all([
|
|
35
|
+
getUsers(),
|
|
36
|
+
getOrders(),
|
|
37
|
+
getStats(),
|
|
38
|
+
]);
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Error Propagation
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
// Bad: 에러 삼킴
|
|
45
|
+
async function fetchData() {
|
|
46
|
+
try { return await api.get('/data'); }
|
|
47
|
+
catch { return []; } // 실패 원인 불명
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Good: 의미 있는 에러 변환 후 전파
|
|
51
|
+
async function fetchData() {
|
|
52
|
+
try { return await api.get('/data'); }
|
|
53
|
+
catch (err) {
|
|
54
|
+
throw new AppError('FETCH_FAILED', 'Data fetch failed', 500, err as Error);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Promise.allSettled for Partial Failures
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
const results = await Promise.allSettled([
|
|
63
|
+
sendEmail(user1),
|
|
64
|
+
sendEmail(user2),
|
|
65
|
+
sendEmail(user3),
|
|
66
|
+
]);
|
|
67
|
+
|
|
68
|
+
const failures = results.filter(
|
|
69
|
+
(r): r is PromiseRejectedResult => r.status === 'rejected',
|
|
70
|
+
);
|
|
71
|
+
if (failures.length) logger.warn('Partial failures', { count: failures.length });
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Rules
|
|
75
|
+
|
|
76
|
+
| Rule | Description |
|
|
77
|
+
|------|-------------|
|
|
78
|
+
| 불필요한 await 금지 | return 직전 단일 Promise는 await 생략 가능 |
|
|
79
|
+
| for-of + await 주의 | 순차 필요 시만 사용, 아니면 Promise.all |
|
|
80
|
+
| void Promise 금지 | fire-and-forget 시 명시적 .catch 또는 void 연산자 |
|
|
81
|
+
| async 함수 반환 타입 | Promise<T>를 명시적으로 선언 |
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Code Organization
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: coding, architecture, modules
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Code Organization
|
|
8
|
+
|
|
9
|
+
## Single Responsibility
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
// Bad: 하나의 클래스가 여러 책임
|
|
13
|
+
class UserService {
|
|
14
|
+
async createUser(dto: CreateUserDto) { /* ... */ }
|
|
15
|
+
async sendWelcomeEmail(user: User) { /* ... */ }
|
|
16
|
+
async generateReport(userId: string) { /* ... */ }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Good: 책임 분리
|
|
20
|
+
class UserService { async createUser(dto: CreateUserDto) { /* ... */ } }
|
|
21
|
+
class NotificationService { async sendWelcomeEmail(user: User) { /* ... */ } }
|
|
22
|
+
class ReportService { async generateReport(userId: string) { /* ... */ } }
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Module Boundaries
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
src/
|
|
29
|
+
modules/
|
|
30
|
+
user/
|
|
31
|
+
user.service.ts
|
|
32
|
+
user.repository.ts
|
|
33
|
+
user.types.ts
|
|
34
|
+
index.ts # barrel export (public API)
|
|
35
|
+
order/
|
|
36
|
+
order.service.ts
|
|
37
|
+
order.repository.ts
|
|
38
|
+
order.types.ts
|
|
39
|
+
index.ts
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Barrel Exports
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
// modules/user/index.ts — 공개 인터페이스만 노출
|
|
46
|
+
export { UserService } from './user.service';
|
|
47
|
+
export type { User, CreateUserDto } from './user.types';
|
|
48
|
+
// user.repository.ts는 내부 구현이므로 export하지 않음
|
|
49
|
+
|
|
50
|
+
// 외부에서 사용
|
|
51
|
+
import { UserService, type User } from '@/modules/user';
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Circular Dependency Prevention
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
// Bad: A -> B -> A 순환 참조
|
|
58
|
+
// user.service.ts imports order.service.ts
|
|
59
|
+
// order.service.ts imports user.service.ts
|
|
60
|
+
|
|
61
|
+
// Good: 공통 인터페이스 추출
|
|
62
|
+
// shared/types.ts
|
|
63
|
+
export interface IUserLookup {
|
|
64
|
+
findById(id: string): Promise<User | null>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// order.service.ts — 인터페이스에 의존
|
|
68
|
+
class OrderService {
|
|
69
|
+
constructor(private userLookup: IUserLookup) {}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Rules
|
|
74
|
+
|
|
75
|
+
| Rule | Description |
|
|
76
|
+
|------|-------------|
|
|
77
|
+
| 파일 300줄 제한 | 초과 시 분리 검토 |
|
|
78
|
+
| 모듈 간 직접 import 금지 | barrel export(index.ts)를 통해서만 접근 |
|
|
79
|
+
| 상위 레이어 import 금지 | domain -> infra 방향 import 불가 |
|
|
80
|
+
| 공유 타입은 shared/ | 두 모듈 이상에서 사용되면 shared로 이동 |
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Error Handling Patterns
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: coding, error-handling, resilience
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Error Handling Patterns
|
|
8
|
+
|
|
9
|
+
## Custom Error Classes
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
class AppError extends Error {
|
|
13
|
+
constructor(
|
|
14
|
+
public readonly code: string,
|
|
15
|
+
message: string,
|
|
16
|
+
public readonly statusCode: number = 500,
|
|
17
|
+
public readonly cause?: Error,
|
|
18
|
+
) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.name = this.constructor.name;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
class NotFoundError extends AppError {
|
|
25
|
+
constructor(code: string, message: string) {
|
|
26
|
+
super(code, message, 404);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
class ValidationError extends AppError {
|
|
31
|
+
constructor(code: string, message: string, public readonly fields: string[]) {
|
|
32
|
+
super(code, message, 400);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Never Swallow Errors
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
// Bad: 에러 무시 — 디버깅 불가
|
|
41
|
+
try { await save(data); } catch {}
|
|
42
|
+
|
|
43
|
+
// Bad: 원인 손실
|
|
44
|
+
try { await save(data); } catch { throw new Error('save failed'); }
|
|
45
|
+
|
|
46
|
+
// Good: 원인 체이닝
|
|
47
|
+
try { await save(data); } catch (err) {
|
|
48
|
+
throw new AppError('SAVE_FAILED', 'Data save failed', 500, err as Error);
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Error Boundaries (React)
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
class ErrorBoundary extends React.Component<Props, { error?: Error }> {
|
|
56
|
+
static getDerivedStateFromError(error: Error) {
|
|
57
|
+
return { error };
|
|
58
|
+
}
|
|
59
|
+
componentDidCatch(error: Error, info: React.ErrorInfo) {
|
|
60
|
+
logger.error('UI Error', { error, componentStack: info.componentStack });
|
|
61
|
+
}
|
|
62
|
+
render() {
|
|
63
|
+
if (this.state.error) return this.props.fallback;
|
|
64
|
+
return this.props.children;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Rules
|
|
70
|
+
|
|
71
|
+
| Rule | Description |
|
|
72
|
+
|------|-------------|
|
|
73
|
+
| 에러 로깅 필수 | catch 블록에서 최소 로깅 또는 re-throw |
|
|
74
|
+
| 사용자 메시지 분리 | 내부 에러와 사용자 노출 메시지를 분리 |
|
|
75
|
+
| 에러 코드 사용 | 문자열 비교 대신 enum/const 에러 코드 |
|
|
76
|
+
| cause 체이닝 | 원본 에러를 cause로 보존 |
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: TypeScript Type Safety
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: coding, typescript, type-safety
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# TypeScript Type Safety
|
|
8
|
+
|
|
9
|
+
## Strict Mode
|
|
10
|
+
|
|
11
|
+
```jsonc
|
|
12
|
+
// tsconfig.json — 최소 필수 설정
|
|
13
|
+
{
|
|
14
|
+
"compilerOptions": {
|
|
15
|
+
"strict": true,
|
|
16
|
+
"noUncheckedIndexedAccess": true,
|
|
17
|
+
"exactOptionalPropertyTypes": true
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Avoid `any`
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// Bad: any는 타입 검사를 무력화
|
|
26
|
+
function process(data: any) { return data.name; }
|
|
27
|
+
|
|
28
|
+
// Good: 제네릭 또는 unknown 사용
|
|
29
|
+
function process<T extends { name: string }>(data: T) { return data.name; }
|
|
30
|
+
|
|
31
|
+
// Good: unknown + 타입 가드
|
|
32
|
+
function process(data: unknown): string {
|
|
33
|
+
if (typeof data === 'object' && data !== null && 'name' in data) {
|
|
34
|
+
return (data as { name: string }).name;
|
|
35
|
+
}
|
|
36
|
+
throw new Error('Invalid data');
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Discriminated Unions
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
// 상태별 안전한 분기 처리
|
|
44
|
+
type Result<T> =
|
|
45
|
+
| { status: 'success'; data: T }
|
|
46
|
+
| { status: 'error'; error: AppError }
|
|
47
|
+
| { status: 'loading' };
|
|
48
|
+
|
|
49
|
+
function handle(result: Result<User>) {
|
|
50
|
+
switch (result.status) {
|
|
51
|
+
case 'success': return render(result.data); // data 타입 보장
|
|
52
|
+
case 'error': return showError(result.error);
|
|
53
|
+
case 'loading': return showSpinner();
|
|
54
|
+
}
|
|
55
|
+
// exhaustiveness check: 누락된 case가 있으면 컴파일 에러
|
|
56
|
+
const _exhaustive: never = result;
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Branded Types
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// 같은 string이지만 혼용 방지
|
|
64
|
+
type UserId = string & { readonly __brand: 'UserId' };
|
|
65
|
+
type OrderId = string & { readonly __brand: 'OrderId' };
|
|
66
|
+
|
|
67
|
+
function createUserId(id: string): UserId { return id as UserId; }
|
|
68
|
+
function createOrderId(id: string): OrderId { return id as OrderId; }
|
|
69
|
+
|
|
70
|
+
function getUser(id: UserId) { /* ... */ }
|
|
71
|
+
|
|
72
|
+
const userId = createUserId('u-123');
|
|
73
|
+
const orderId = createOrderId('o-456');
|
|
74
|
+
getUser(userId); // OK
|
|
75
|
+
// getUser(orderId); // Compile error
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Rules
|
|
79
|
+
|
|
80
|
+
| Rule | Description |
|
|
81
|
+
|------|-------------|
|
|
82
|
+
| any 사용 금지 | eslint no-explicit-any 활성화 |
|
|
83
|
+
| as 캐스팅 최소화 | 타입 가드 또는 제네릭으로 대체 |
|
|
84
|
+
| union exhaustiveness | switch문에 never 체크 포함 |
|
|
85
|
+
| optional vs undefined | 선택 속성과 undefined 값을 구분 |
|
|
@@ -6,106 +6,72 @@ description: |
|
|
|
6
6
|
Use when: "구현해줘", "테스트해줘", "리뷰해줘", "설계해줘", 서브에이전트 위임
|
|
7
7
|
version: "1.0.0"
|
|
8
8
|
tags: [controller, di, context-injection]
|
|
9
|
+
depends_on: [tsq-protocol]
|
|
10
|
+
conflicts_with: []
|
|
9
11
|
user-invocable: false
|
|
10
12
|
---
|
|
11
13
|
|
|
12
14
|
# Controller (Context DI Container)
|
|
13
15
|
|
|
14
|
-
서브에이전트에게 작업을 위임할 때
|
|
15
|
-
에이전트가 "스스로 찾아 읽기"가 아닌 "주입받아 바로 시작"하도록 보장.
|
|
16
|
+
서브에이전트에게 작업을 위임할 때 컨텍스트를 자동 해석하고 주입하는 컨테이너.
|
|
16
17
|
|
|
17
|
-
##
|
|
18
|
+
## Philosophy
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
- "스스로 찾기"가 아닌 "주입받아 바로 시작"
|
|
21
|
+
- 태스크에 관련된 섹션만 선별 주입 (전체 주입 지양)
|
|
22
|
+
- spec 신선도는 controller가 판단
|
|
20
23
|
|
|
21
|
-
|
|
22
|
-
2. **Prerequisites 파싱**: `<prerequisites>` 태그에서 필요 SSOT 목록 추출
|
|
23
|
-
3. **Spec Resolve**: `controller/references/`에서 해당 compiled spec 로드
|
|
24
|
-
4. **Phase 제약 로드**: `controller/rules/`에서 현재 phase 제약 확인
|
|
25
|
-
5. **Stale 체크**: `.compile-manifest.json`의 hash와 현재 SSOT hash 비교
|
|
26
|
-
6. **프롬프트 조합**: tsq-protocol + resolved specs + phase 제약 + 태스크 지시
|
|
27
|
-
7. **Task() 호출**: 조합된 프롬프트로 서브에이전트 실행
|
|
24
|
+
## Contract
|
|
28
25
|
|
|
29
|
-
|
|
26
|
+
- **Trigger**: 서브에이전트 위임 시 (구현, 테스트, 리뷰 등)
|
|
27
|
+
- **Input**: 에이전트 파일 + prerequisites + compiled specs
|
|
28
|
+
- **Output**: 조합된 프롬프트로 Task() 실행
|
|
29
|
+
- **Error**: spec stale 시 `tsq compile` 재실행 안내
|
|
30
|
+
- **Dependencies**: tsq-protocol
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
에이전트 prerequisites → controller references/
|
|
33
|
-
─────────────────────────────────────────────────────────
|
|
34
|
-
service-spec.md → references/*.spec.md (endpoint별)
|
|
35
|
-
data-design.md → references/*.spec.md (entity별)
|
|
36
|
-
error-codes.md → references/error-codes.spec.md
|
|
37
|
-
```
|
|
32
|
+
## Protocol
|
|
38
33
|
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
1. **Memory 참조**: `memory/` 디렉토리의 모든 .md 파일을 Read (프로젝트 결정사항)
|
|
35
|
+
2. **SSOT Map 참조**: `.timsquad/ssot-map.yaml` 읽기 → 현재 작업 단위(phase/sequence/task) 판단 → 해당 티어 compiled spec 목록 확인
|
|
36
|
+
3. **에이전트 파일 확인**: `.claude/agents/{agent}.md` 읽기
|
|
37
|
+
4. **Prerequisites 파싱**: `<prerequisites>` 태그에서 SSOT 목록 추출
|
|
38
|
+
5. **Spec Resolve**: `references/`에서 해당 compiled spec + SSOT Map 티어 문서 로드
|
|
39
|
+
6. **Stale 체크**: `.compile-manifest.json` hash 비교
|
|
40
|
+
7. **방법론 참조**: `config.yaml`의 `methodology.development` 확인 → 해당 methodology 스킬 Protocol 로드
|
|
41
|
+
8. **프롬프트 조합**: tsq-protocol + memory + specs + methodology + phase 제약 + 지시
|
|
42
|
+
9. **Task() 호출**: 조합된 프롬프트로 서브에이전트 실행
|
|
43
|
+
10. **트리거 확인**: 완료 시 `triggers/` 해당 상황 규칙 참조 (task-complete, sequence-complete 등)
|
|
41
44
|
|
|
42
|
-
##
|
|
45
|
+
## Verification
|
|
43
46
|
|
|
44
|
-
|
|
47
|
+
| Check | Command | Pass Criteria |
|
|
48
|
+
|-------|---------|---------------|
|
|
49
|
+
| Stale 체크 | `.compile-manifest.json` hash | 일치 |
|
|
50
|
+
| Prerequisites | 에이전트 파일 파싱 | 모든 spec 존재 |
|
|
51
|
+
| Task 사용 | 위임 방식 확인 | Task() 사용 (TeamCreate 금지) |
|
|
52
|
+
| Phase 제약 | 프롬프트 포함 확인 | 현재 phase 제약 포함 |
|
|
45
53
|
|
|
46
|
-
|
|
47
|
-
- hash 불일치 → 사용자에게 `tsq compile` 재실행을 제안.
|
|
48
|
-
- manifest 없음 → 사용자에게 `tsq compile` 최초 실행을 안내.
|
|
54
|
+
## Quick Rules
|
|
49
55
|
|
|
50
|
-
|
|
56
|
+
### Spec Resolution
|
|
57
|
+
- 에이전트 prerequisites → `references/*.spec.md`로 매핑
|
|
58
|
+
- 태스크 관련 섹션만 주입 (예: "로그인 API" → 로그인 spec만)
|
|
51
59
|
|
|
52
|
-
|
|
53
|
-
|
|
60
|
+
### Delegation
|
|
61
|
+
- **지원**: Task() — 순차 호출, 도구 실행 가능
|
|
62
|
+
- **금지**: TeamCreate — SDK 제한으로 도구 실행 불가
|
|
63
|
+
- **역할별 규칙**: `delegation/` 디렉토리 참조 (developer, reviewer, librarian)
|
|
54
64
|
|
|
55
|
-
|
|
65
|
+
### Triggers
|
|
66
|
+
상황별 행동 규칙은 `triggers/` 디렉토리 참조:
|
|
67
|
+
- `task-complete.md` — 태스크 완료 시 테스트 게이트 + L1
|
|
68
|
+
- `sequence-complete.md` — 시퀀스 완료 시 통합테스트 + L2
|
|
69
|
+
- `phase-complete.md` — 페이즈 완료 시 e2e + L3 + Librarian
|
|
70
|
+
- `ssot-changed.md` — SSOT 변경 시 재컴파일 확인
|
|
56
71
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
- 금지: {forbidden_actions}
|
|
72
|
+
### Mode Declaration
|
|
73
|
+
서브에이전트 매 응답 첫 줄: `[MODE: {phase}] [TASK: {id}] [SPEC: {file}]`
|
|
60
74
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
[태스크 지시]
|
|
65
|
-
task_id: {task_id}
|
|
66
|
-
description: {description}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## Mode Declaration
|
|
70
|
-
|
|
71
|
-
서브에이전트는 **매 응답 첫 줄**에 모드 선언을 출력해야 한다:
|
|
72
|
-
|
|
73
|
-
```
|
|
74
|
-
[MODE: IMPLEMENTATION] [TASK: P3-S001-T001] [SPEC: 2-1-로그인.spec.md]
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
<mode-declaration>
|
|
78
|
-
<rules>
|
|
79
|
-
<must>응답 시작 시 [MODE: {phase}] [TASK: {task_id}] [SPEC: {spec}] 선언</must>
|
|
80
|
-
<must>phase는 current-phase.json 기준 (planning/design/implementation/review)</must>
|
|
81
|
-
<must>SPEC은 주입받은 primary spec 파일명</must>
|
|
82
|
-
</rules>
|
|
83
|
-
<rationale>
|
|
84
|
-
컨텍스트 압축(compaction) 후에도 에이전트가 자신의 역할·제약·참조 spec을
|
|
85
|
-
매 응답마다 재확인한다. Rationalization Prevention의 자연스러운 확장.
|
|
86
|
-
</rationale>
|
|
87
|
-
</mode-declaration>
|
|
88
|
-
|
|
89
|
-
## Rationalization Prevention
|
|
90
|
-
|
|
91
|
-
<rationalization-prevention>
|
|
92
|
-
|
|
93
|
-
| 에이전트의 변명 | 현실 |
|
|
94
|
-
|----------------|------|
|
|
95
|
-
| "이 태스크는 간단해서 spec 없이 가능" | 간단함은 주관적. spec이 있으면 반드시 참조 |
|
|
96
|
-
| "spec이 오래된 것 같아서 직접 판단" | spec 신선도는 controller가 판단. 주입받은 spec을 따를 것 |
|
|
97
|
-
| "이미 비슷한 코드가 있으니 참고만 하면 됨" | 기존 코드가 spec과 일치하는지 알 수 없음. spec 기준 |
|
|
98
|
-
| "테스트는 나중에 한번에 돌리는 게 효율적" | 각 태스크 완료 시 테스트 통과가 완료 조건 |
|
|
99
|
-
| "사용자가 빨리 해달라고 했으니 절차 생략" | 절차는 품질 보장. 절차를 따르는 것이 결과적으로 빠름 |
|
|
100
|
-
|
|
101
|
-
</rationalization-prevention>
|
|
102
|
-
|
|
103
|
-
## Checklist
|
|
104
|
-
|
|
105
|
-
| Priority | Item |
|
|
106
|
-
|----------|------|
|
|
107
|
-
| CRITICAL | 서브에이전트 위임 전 spec resolve 완료 |
|
|
108
|
-
| CRITICAL | compiled spec의 stale 여부 확인 |
|
|
109
|
-
| HIGH | phase 제약이 프롬프트에 포함됨 |
|
|
110
|
-
| HIGH | tsq-protocol이 프롬프트에 포함됨 |
|
|
111
|
-
| MEDIUM | 태스크에 관련된 섹션만 선별 주입 (전체 주입 지양) |
|
|
75
|
+
### P3 Workflow
|
|
76
|
+
Developer(구현+테스트) → vitest → QA(L1 피드백) → L2 자동 생성.
|
|
77
|
+
QA 진입: developer completed + tests pass + build success.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Developer 위임 규칙
|
|
2
|
+
|
|
3
|
+
## 역할
|
|
4
|
+
|
|
5
|
+
코드 구현 + 단위 테스트 작성 전담.
|
|
6
|
+
|
|
7
|
+
## 위임 시 포함 사항
|
|
8
|
+
|
|
9
|
+
1. **SSOT Map 티어 문서**: 현재 작업 단위에 맞는 compiled spec
|
|
10
|
+
2. **방법론 제약**: config.methodology.development에 따라:
|
|
11
|
+
- TDD: "테스트를 먼저 작성하고, 실패를 확인한 후 구현하라"
|
|
12
|
+
- BDD: "Gherkin 시나리오를 먼저 정의하고 구현하라"
|
|
13
|
+
- None: 방법론 제약 없음
|
|
14
|
+
3. **Phase 제약**: 현재 Phase에서 허용되는 작업 범위
|
|
15
|
+
4. **tsq-protocol**: TimSquad 프로세스 규칙
|
|
16
|
+
|
|
17
|
+
## 도구 권한
|
|
18
|
+
|
|
19
|
+
Read, Edit, Write, Bash (전체)
|
|
20
|
+
|
|
21
|
+
## 완료 조건
|
|
22
|
+
|
|
23
|
+
- 단위 테스트 작성 + 통과
|
|
24
|
+
- `tsc --noEmit` 클린
|
|
25
|
+
- 변경 파일 목록 핸드오프에 포함
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Librarian 위임 규칙
|
|
2
|
+
|
|
3
|
+
## 역할
|
|
4
|
+
|
|
5
|
+
Phase 종합 기록 전담. 문서 작성/갱신만 수행하고 소스 코드를 수정하지 않는다.
|
|
6
|
+
|
|
7
|
+
## 호출 조건
|
|
8
|
+
|
|
9
|
+
- Phase 내 모든 시퀀스 completed
|
|
10
|
+
- L3 로그 생성 완료
|
|
11
|
+
- Phase Gate PASS (또는 gate 미설정)
|
|
12
|
+
|
|
13
|
+
## 위임 시 포함 사항
|
|
14
|
+
|
|
15
|
+
1. **L1/L2/L3 로그**: `.timsquad/logs/` 하위 해당 Phase 로그 전체
|
|
16
|
+
2. **SSOT 현재 상태**: `.compile-manifest.json` stale 목록
|
|
17
|
+
3. **Phase 정보**: 완료된 Phase ID, 시퀀스 목록
|
|
18
|
+
|
|
19
|
+
## 도구 권한
|
|
20
|
+
|
|
21
|
+
Read, Write, Edit, Grep, Glob, Bash
|
|
22
|
+
|
|
23
|
+
## 제약
|
|
24
|
+
|
|
25
|
+
- **소스 코드(src/, lib/, app/) 수정 절대 금지**
|
|
26
|
+
- .timsquad/ 및 docs/ 내 문서 작성·갱신만 허용
|
|
27
|
+
- 기록, 분석, 리포트 작성만 수행
|
|
28
|
+
|
|
29
|
+
## 출력
|
|
30
|
+
|
|
31
|
+
1. Phase 종합 리포트 (`.timsquad/reports/{phase}-report.md`)
|
|
32
|
+
2. SSOT stale 목록 보고
|
|
33
|
+
3. 다음 Phase context note (`docs/sprint/` 하위)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Reviewer 위임 규칙
|
|
2
|
+
|
|
3
|
+
## 역할
|
|
4
|
+
|
|
5
|
+
코드 리뷰 + 교차 검증 전담. 읽기만 수행하고 코드를 수정하지 않는다.
|
|
6
|
+
|
|
7
|
+
## 위임 시 포함 사항
|
|
8
|
+
|
|
9
|
+
1. **변경 diff**: `git diff` 결과
|
|
10
|
+
2. **6가지 관점**: 보안, 타입 안전성, 에러 핸들링, API 호환성, 테스트 커버리지, 성능
|
|
11
|
+
3. **관련 spec**: 변경 파일과 관련된 SSOT compiled spec
|
|
12
|
+
|
|
13
|
+
## 도구 권한
|
|
14
|
+
|
|
15
|
+
Read, Grep, Glob, Bash (읽기 전용)
|
|
16
|
+
|
|
17
|
+
## 출력 형식
|
|
18
|
+
|
|
19
|
+
severity별 구조화된 리포트 (CRITICAL/HIGH/MEDIUM/LOW)
|
|
File without changes
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Phase Complete Trigger
|
|
2
|
+
|
|
3
|
+
Phase 내 모든 시퀀스 완료 시 controller가 수행하는 행동 규칙.
|
|
4
|
+
|
|
5
|
+
## 행동
|
|
6
|
+
|
|
7
|
+
1. **E2E 테스트**: `npm run test:e2e` 실행 확인
|
|
8
|
+
2. **L3 로그**: 데몬이 L3 페이즈 로그를 자동 생성했는지 확인
|
|
9
|
+
3. **Phase Gate**: `tsq log phase gate` 실행 → 전환 조건 확인
|
|
10
|
+
4. **Librarian 호출**: Phase 종합 리포트 작성을 위해 Librarian 에이전트 호출
|
|
11
|
+
5. **회고**: `tsq retro` 자동 실행 검토
|
|
12
|
+
|
|
13
|
+
## Librarian 호출 조건
|
|
14
|
+
|
|
15
|
+
- Phase 내 모든 시퀀스 completed
|
|
16
|
+
- L3 로그 생성 완료
|
|
17
|
+
- Phase Gate PASS
|
|
18
|
+
|
|
19
|
+
## 호출 방법
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
Librarian에게 위임 (delegation/librarian.md 참조):
|
|
23
|
+
- 입력: L1/L2/L3 로그, SSOT 현재 상태
|
|
24
|
+
- 출력: Phase 종합 리포트, SSOT stale 보고, 다음 Phase context note
|
|
25
|
+
```
|