@simplysm/sd-claude 14.0.49 → 14.0.51

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 CHANGED
@@ -50,9 +50,9 @@ npm install @simplysm/sd-claude
50
50
 
51
51
  | API | Type | Description |
52
52
  |-----|------|-------------|
53
- | `claude/skills/` | asset directory | 16개 sd-* 스킬 디렉토리 (각 스킬은 `SKILL.md` + 선택적 `SKILL.eval.md`와 `references/` 포함) |
53
+ | `claude/skills/` | asset directory | 19개 sd-* 스킬 디렉토리 (각 스킬은 `SKILL.md` + 선택적 `SKILL.eval.md`와 `references/` 포함) |
54
54
  | `claude/rules/` | asset directory | Claude Code 규칙 파일 (`sd-claude-rules.md`, `sd-options.md`) |
55
- | `claude/references/` | asset directory | 스킬/규칙에서 참조하는 공유 문서 패키지 문서 디렉토리 |
55
+ | `claude/references/` | asset directory | 스킬/규칙에서 참조하는 공유 문서 (`sd-frontend-design.md`, `sd-testing.md`) |
56
56
 
57
57
  → See [docs/assets.md](./docs/assets.md) for details.
58
58
 
@@ -1,124 +1,44 @@
1
- # CRITICAL: 무단 진행·추측 금지
2
-
3
- - 어떠한 경우에도 지침을 무시하고 건너뛰지 않는다. 혼자만의 판단으로 무단 진행 절대(NEVER) 금지
4
- - 지침이 충돌등의 이유로 애매하면 사용자에게 질문한다.
5
- - 코드를 수정할 때, 왜 그 코드가 문제인지 근거를 먼저 확인하고 수정한다. "일단 바꿔보고 되면 넘어가자" 식의 추측성 시행착오를 절대(NEVER) 금지한다.
6
-
7
- # CRITICAL: 사실·지침 날조 금지
8
-
9
- **존재하지 않는 것을 지어내지 않는다(NEVER).**
10
-
11
- - 인용하는 파일·함수·API·라이브러리 시그니처는 반드시 Read/Grep으로 **직접 확인한 것**만 쓴다. 기억·일반 지식·추측 금지.
12
- - 사용자가 명시한 적 없는 지침/규칙을 "있는 것처럼" 만들어 따르지 않는다. 룰은 `.claude/rules/`, `CLAUDE.md`, 사용자 발화에만 존재한다. 본인이 추론한 베스트 프랙티스를 "규칙"으로 격상시키지 않는다.
13
- - 불확실하면 "확인 필요" 또는 "추측"이라 명시하고, 가능하면 도구로 검증한다. 모르면 모른다고 말한다.
14
- - 답변·코드·계획에 들어가는 모든 사실 주장은 **출처(파일경로:라인 / 도구 결과 / 사용자 발화)** 를 응답에 인라인으로 인용한다. 특히 조회로 얻은 존재·부재 단정은 조회 도구·대상·결과를 응답에 함께 표기한다 (예: "Grep `reverseBits` in `packages/core-common` → 결과 없음"). 출처를 댈 수 없는 주장은 하지 않는다.
15
-
16
- # CRITICAL: 변경사항 되돌리기 금지
17
-
18
- **git diff에 나타나는 변경사항을 임의로 되돌리지 않는다(NEVER).**
19
-
20
- - `git diff`에 보이는 변경은 사용자가 직접 수정한 것일 수 있다. subagent가 만든 변경인지, 사용자가 직접 한 변경인지 구분할 수 없으므로, 어떤 변경이든 되돌리기 전에 반드시 사용자에게 확인한다.
21
- - 특히 현재 작업 범위 밖의 파일 변경을 발견해도, "의도하지 않은 변경"이라고 단정짓지 않는다. 사용자가 별도로 수정한 코드일 수 있다.
22
- - 되돌려야 할 명확한 근거(사용자의 명시적 요청, 빌드/테스트 실패 등)가 없으면 절대 되돌리지 않는다.
23
-
24
- # Compaction Rules
25
-
26
- `/compact`수행 시, 항상 보존할 것:
27
-
28
- - 수정된 파일의 전체 경로 목록
29
- - 에러 메시지 원문
30
-
31
- # Python 인코딩
32
-
33
- - `python3 -c`로 유니코드 텍스트를 출력할 때, 반드시 `sys.stdout.reconfigure(encoding='utf-8')`을 사용한다. (Windows cp949 인코딩 에러 방지)
34
-
35
1
  # 금지 명령어
36
2
 
37
- - **GIT**: `git stash`, `git checkout`, `git restore`, `git reset`, `git clean` 사용 금지.
38
- - **CRITICAL: 폴더이동 금지**: `cd` 명령을 통한 타 폴더로의 이동 금지. 폴더이동시 hook 오류남!!
39
- - **타입체크 명령어**: `npx tsc` 사용 금지. 반드시 `pnpm typecheck [targets..]`등의 스크립트 사용
40
- - **Lint 명령어**: `npx eslint` 사용 금지. 반드시 `pnpm lint [targets..]`등의 스크립트 사용
41
-
42
- # 도구사용 규칙
43
-
44
- - Write: 이미 존재하는 파일에 Write 도구를 사용하지 않는다. 기존 파일 수정은 반드시 Edit 도구를 사용한다. (Write는 덮어쓰기때문에 위험함)
45
- - **CRITICAL: 파일을 읽으라는 지침이 있으면 Read tool로 반드시(MUST) 읽어라. 절대(NEVER) 무시하지 말것**
46
- - subagent 도구 사용시, 명시적으로 백그라운드 수행을 언급하지 않은경우, 굳이 백그라운드로 수행하지 않는다.
3
+ - `git stash`, `git checkout`, `git restore`, `git reset`, `git clean` 사용 금지.
4
+ - `cd` 명령을 통한 타 폴더로의 이동 금지.
5
+ - `npx tsc` 사용 금지. 반드시 `pnpm typecheck [targets..]`등의 스크립트 사용
6
+ - `npx eslint` 사용 금지. 반드시 `pnpm lint [targets..]`등의 스크립트 사용
47
7
 
48
8
  # 대화 규칙
49
9
 
50
- - 사용자의 질문에 답변만 하라. 절대 지침 없이 임의로 다음단계(특히, 코드변경)로 넘어가지 않는다(NEVER). 답변만 하고 사용자의 명시적 요청을 기다린다.
51
- - 사용자의 질문은 동의를 구하는것이 아니다. 무조건적 동의하려하지 말고, 비판적으로 사고하여 답변한다.
52
- - 사용자 요청의 의도가 불명확할 때는 `/sd-inner-clarify` 스킬을 호출하여 명확화한다. 단순 정보 조회처럼 의도가 명확한 질문에는 위 "답변만 하라" 규칙을 따른다. (절대 추측하지 않는다.)
53
- - **CRITICAL: 맥락에 맞는 언어로 말한다**. 지금 대화의 층위가 무엇인지 먼저 파악하고 그 층위의 용어로 말한다.
10
+ - 응답 항상 thinking 것.
11
+ - 내장 도구 적극 활용 (Read/Grep/Glob/Bash/WebFetch/WebSearch/Skill/TaskCreate 등)
12
+ - 사용자가 명시하지 않은 사항 추측으로 행동 금지. 추측한것이 맞는지 `AskUserQuestion` tool로 물어볼 것.
13
+ - 사용자 요청의 의도가 불명확할 때는 `/sd-inner-clarify` 스킬을 호출하여 명확화.
14
+ - 맥락에 맞는 용어 사용
54
15
  - 업무 기능·요구사항 논의 → 업무 용어 (사용자가 화면에서 뭘 하는지)
55
16
  - DB 스키마 설계 → 테이블·컬럼명
56
17
  - 코드 구현 → 함수·클래스명
57
- - 층위를 섞지 않는다. 업무 결정을 하면서 DB 컬럼명부터 던지거나, 스키마 설계를 하면서 업무 용어만 쓰지 않는다.
58
- - **한국 개발 현장 통용 용어 우선**: 한국 개발 현장에서 일반적으로 통용되는 용어를 우선 사용한다. 그런 용어가 없거나 불확실할 때는 한글 음차("시딩") 대신 영어 원문("seeding")을 그대로 쓰고, 처음 쓸 때 한 줄로 풀어 설명한다.
59
- - 사용자가 "무슨 소린지 모르겠다"는 취지로 되물으면, 같은 말을 반복하지 말고 **한 층위 위**(구현→스키마→업무)로 올라가서 다시 설명한다.
18
+ - 한국 개발 현장 통용 용어 사용
60
19
 
61
20
  # Playwright
62
21
 
63
- - playwright 사용시, 사용자가 접속주소를 알려주지 않았다면, 반드시 사용자에게 접속주소를 요청할것. (절대 서버를 강제로 임의 실행하지 말것)
22
+ - 사용자가 접속주소를 알려주지 않았다면, 반드시 사용자에게 접속주소를 요청할것. (서버 강제 실행 금지)
64
23
  - /playwright-cli 스킬을 사용할 것
65
24
 
66
- # 코딩
67
-
68
- - `@simplysm/*` 패키지를 사용할 때 아래 `# @simplysm 패키지 참조` 섹션을 따른다.
69
- - `@angular/*` 패키지를 사용할 때 `angular-cli` mcp를 활용하여, 표준 사용법을 확인하여 따른다.
70
- - 테스트 작성 시 `.claude/references/sd-testing.md`를 읽고 따른다.
71
- - 프론트엔드 UI 코드 작성·수정 시 `.claude/references/sd-frontend-design.md`를 읽고 따른다.
72
- - 디버깅 시 `/sd-inner-debug` 스킬을 호출한다.
73
- - **CRITICAL: 코딩·코드예제 출력 시, 반드시 Grep/Glob/Read로 코드베이스의 유사 코드를 먼저 검색·확인한 뒤 동일 패턴으로 작성한다.** "이미 알고 있다", "일반적인 패턴이다" 등의 이유로 검색을 생략하는 것은 위반이다.
74
- - 코드를 수정할 경우 수정에 의한 사이드이펙트를 항상 고려한다. (예, html구조가 바뀌면 css의 selector도 바뀌어야함)
75
- - 함수 작성 혹은 함수내 기능 추가시 단일 책임 원칙을 따른다. (함수가 이름에서 드러나지 않는 일을 몰래 해선 안됨)
76
- - `src/`에는 프로덕션 코드만 둔다. 테스트에서만 사용하는 파일(타입 선언, 헬퍼 등)은 `tests/`에 위치시킨다.
77
- - **barrel export 금지**: `src/` 루트의 `index.ts`를 제외하고, 하위 폴더에 re-export 전용 `index.ts`를 만들지 않는다. 패키지 루트 `index.ts`에서 개별 파일 경로를 직접 export한다.
78
- - 다른 패키지의 타입등 re-export 금지.
79
- - **dynamic import (`import()`) 사용 금지**: 조건부 peer dependency 로딩, 외부 ts 파일 읽기 등 정적 import가 불가능한 경우를 제외하고 `import()` 사용 금지. 정적 `import` 문을 사용한다.
80
- - **CRITICAL: 구조화된 문법 처리 시 파서 사용 필수**: TypeScript/JavaScript, HTML, CSS, JSON, YAML 등 **문법 구조가 정의된 텍스트**를 분석·변환할 때는 반드시 해당 언어의 **공식 파서/AST**(예: TypeScript Compiler API, `@angular/compiler`, `postcss`, `parse5`, `JSON.parse` 등)를 사용한다. 정규식·문자열 치환으로 **우회 금지(NEVER)**. 정규식은 주석·문자열·중첩 구조·이스케이프 등 엣지 케이스에서 반드시 깨진다. 파서 사용이 어렵거나 오버헤드가 크다고 판단되면 **사용자에게 먼저 질문**한다.
81
- - **null/undefined 비교 규칙**: `===`/`!==` 사용이 기본이지만 **null/undefined 비교만 예외**이다. 일반 값 비교는 `===`/`!==`, null/undefined 검사는 `== null`/`!= null`을 사용한다. `=== null`, `!== null`, `=== undefined`, `!== undefined`는 lint 에러이다.
82
- - `value === "hello"` ○ (일반 값 비교 → `===`)
83
- - `value == null` ○ (null/undefined 검사 → `==`)
84
- - `value === null` ✕ (lint 에러)
85
- - `value === undefined` ✕ (lint 에러)
86
-
87
- ## 자주 하는 실수
88
-
89
- - **import 경로에 `.js` 확장자 금지**: 내부 모듈 import 시 `.js` 확장자를 붙이지 않는다. `from "./foo"` ○, `from "./foo.js"` ✕. 이 프로젝트는 번들러(esbuild/Vite)가 확장자를 해석하므로 `.js`를 붙이면 안 된다.
90
- - **`as any[]` 캐스팅 후 `??` 방어**: `value as any[]`로 캐스팅하면 TypeScript는 nullable이 아니라고 판단하여 `?? []`에 lint 에러 발생. `value as any[] | undefined`로 캐스팅해야 한다
91
- - **타입 추론 해제 금지**: 타입 추론을 해제하는 방식의 수정은 절대 금지한다.
92
- - **불필요한 `as` 캐스팅**: 가드(`target !== "client"` 등)로 타입이 좁혀진 후에는 `as SdClientPackageConfig` 같은 캐스팅 불필요. lint 에러 `no-unnecessary-type-assertion` 발생
93
- - **타입 정의 확인 필수**: 인터페이스에 없는 프로퍼티를 추측으로 넣지 않는다. 반드시 실제 타입 정의를 읽고 작성한다
94
- - **클래스 필드 vs prototype**: `Object.getOwnPropertyDescriptor`로 클래스 필드를 찾을 때, TypeScript 클래스 필드는 prototype이 아닌 instance에 존재한다. prototype에서 찾으면 `undefined` 반환
95
- - **요청하지 않은 기능 추가 금지**: 원본 코드에 없고 사용자가 요청하지 않은 기능을 임의로 추가하지 않는다. 기존 코드의 이벤트/패턴을 그대로 유지하고, 요청된 변경만 수행한다.
96
- - **프로젝트 구조 이해 필수**: 코드를 배치하기 전에 해당 디렉토리가 빌드 산출물인지, 영구 소스인지 반드시 확인한다. 모르면 사용자에게 질문한다.
97
- - `eslint-disable @typescript-eslint/require-await` 금지
98
-
99
- # @simplysm 패키지 참조
25
+ # 사용법 참조
100
26
 
101
- - `@simplysm/*` 패키지 사용 시, 해당 패키지의 `README.md` 및 `docs/` 문서를 읽는다.
102
- - v14: `node_modules/@simplysm/{패키지명}/README.md` (분량이 많은 항목은 `node_modules/@simplysm/{패키지명}/docs/*.md`)
103
- - v12: `.claude/references/sd-simplysm12.md`
104
- - 해당 문서에는 사용법 및 지침이 기록되어 있다.
105
- - 주의사항: 해당 패키지의 `CLAUDE.md`는 모노레포 **내부 개발자용 컨텍스트**이므로 소비앱에서 이를 읽지 않는다. 소비앱은 `README.md`와 `docs/`만 참조한다.
106
- - simplysm 패키지의 경우 context7은 구버전일 수 있으니 사용을 지양한다.
27
+ - 프론트엔드: `.claude/references/sd-frontend-design.md`
28
+ - `@angular/*`: `angular-cli` mcp를 활용
29
+ - `@simplysm/*`: 해당 패키지의 `README.md`
107
30
 
108
- # 프로젝트 경계
109
-
110
- **CRITICAL: 프로젝트 루트 외부의 파일을 절대 생성/수정/삭제하지 않는다.**
111
-
112
- - 다른 모노레포(`../simplysm/` 등)에 파일을 만드는 것은 절대 금지.
113
-
114
- # 빌드 산출물 디렉토리
115
-
116
- **CRITICAL: `.capacitor/`, `.electron/` 디렉토리는 빌드 시 삭제 후 재생성되는 산출물이다.**
117
-
118
- - 이 디렉토리 안에 직접 파일을 생성/수정하면 빌드 시 전부 사라진다.
31
+ # 코딩
119
32
 
120
- # Feature 범위 준수
33
+ - barrel export 금지: `src/` 루트의 `index.ts`외, 하위 폴더 re-export `index.ts` 금지
34
+ - 다른 패키지에 대한 re-export 금지
35
+ - 정적 import가 불가능한 경우를 제외하고 `import()` 사용 금지
36
+ - 구조화된 문법 처리 시 파서 사용 필수. 정규식·문자열 치환으로 우회 금지
37
+ - null/undefined 비교 규칙: 일반 값 비교는 `===`/`!==`, null/undefined 검사는 `== null`/`!= null`을 사용.
38
+ - 내부 모듈 import 시 `.js` 확장자를 붙이지 않는다. (번들러가 확장자 해석)
39
+ - 타입 추론을 해제하는 방식의 수정 금지
40
+ - 불필요한 `as` 캐스팅 금지
121
41
 
122
- **CRITICAL: Feature 문서에 명시되지 않은 작업을 임의로 수행하지 않는다.**
42
+ ## 주의사항
123
43
 
124
- - 구현 추가 작업이 필요하다고 판단되면, 먼저 사용자에게 확인한다.
44
+ - 프로젝트 루트 외부 파일 생성/수정/삭제 금지
@@ -1,42 +1,49 @@
1
1
  # sd-options: 선택지 제시 규칙
2
2
 
3
- 사용자에게 질문, 제안등 선택지를 제시하는 **모든 상황**에서 아래 규칙을 따른다.
3
+ ## 적용 대상 (예외 없음)
4
4
 
5
- - 선택지에 대해 **장단점/트레이드오프/10점 만점 점수**를 포함한다
6
- - **"수행 안 함"** 선택지를 반드시 포함한다 — 수정/변경을 하지 않는 경우에도 동일하게 장단점과 점수를 매긴다
7
- - **결정 대상**을 먼저 명시한 뒤, 선택지 정보를 아래 **근거 제시 규칙**에 따라 출력하고, `---` 구분선을 출력한다.
8
- - **CRITICAL**: 선택지 출력 후에는 반드시 `AskUserQuestion` tool을 즉시 호출하여 사용자에게 선택을 요구한다
9
- - 텍스트로 "진행할까요?", "어떤 걸로 할까요?", "선택해주세요" 등을 묻고 사용자 응답을 기다리는 것은 **위반**이다
5
+ 사용자에게 질문·제안·확인 응답이 필요한 모든 출력에 적용한다.
10
6
 
11
- ## 결정 대상 명시 규칙
7
+ - "이 정도 질문은 과하다", "단순 확인이니 생략"은 위반이다
8
+ - 단일 경로만 합리적이라 느껴질 때도, "수행 안 함"을 포함한 선택지 구조로 제시한다
9
+ - 가벼운 사안은 경량 모드로 오버헤드를 낮추되, 선택지 구조와 `AskUserQuestion` 호출은 생략 불가
12
10
 
13
- 선택지를 나열하기 **전에**, 이 결정이 **어디의 무엇**에 대한 것인지 한 줄로 명시한다.
11
+ ## 공통 규칙
14
12
 
15
- - 형식: `**결정 대상:** {파일경로:라인번호} {대상 설명}` (대상이 여러 라인이어도 대표 라인/범위를 반드시 명시)
16
- - 예시 (단일 라인): `**결정 대상:** packages/angular/src/controls/input/sd-textfield.ts:45 — validate() 메서드의 에러 처리 방식`
17
- - 예시 (복수 라인): `**결정 대상:** .claude/rules/sd-options.md:8,31 CRITICAL 키워드 사용 방식`
18
- - 예시 (범위): `**결정 대상:** .claude/skills/sd-use/SKILL.md:43-68 스킬 카탈로그 섹션`
13
+ - 결정 대상 명시: 선택지 전에 한 줄로 `결정 대상: {파일경로:라인}` 출력 (예: `결정 대상: packages/foo.ts:45`)
14
+ - 하나의 선택지를 추천하고 사유 요약
15
+ - 복수 결정사항: 응답에 건만. 다음 건은 응답에서. 남은 건수 표시 (예: "1/3건 완료")
16
+ - 도구 호출 의무: 선택지 출력 즉시 `AskUserQuestion` tool을 호출하여 응답을 종료한다. 텍스트로 "진행할까요?" 묻고 응답 대기하면 위반.
17
+ - `AskUserQuestion`이 deferred tool로 표시되어 있으면 먼저 `ToolSearch query="select:AskUserQuestion"`로 스키마를 로드한 뒤 호출한다.
19
18
 
20
- ## 근거 제시 규칙
19
+ ## 티어 선택
21
20
 
22
- 사용자가 선택지를 판단하려면 **구체적 근거**가 필요하다. 추상적 설명만 나열하지 말고, 아래 항목을 반드시 포함한다.
21
+ 사안의 무게에 따라 경량 모드와 전체 모드 하나를 선택한다.
23
22
 
24
- - **현재 상태 인용**: 선택의 대상이 되는 코드·설정·구조를 인용할 때, **파일경로:라인번호를 반드시 포함**한다. 코드블록을 사용할 경우에도 해당 코드가 위치한 파일경로:라인번호를 함께 명시한다
25
- - **변경 후 모습**: 각 선택지를 적용하면 실제로 어떻게 바뀌는지 코드블록·구조도·시그니처 등으로 보여준다
26
- - **차이점 대비**: 선택지 간 차이가 드러나도록 동일한 관점에서 나란히 비교한다 (예: 같은 코드 조각이 A안/B안에서 각각 어떻게 되는지)
27
- - **영향 범위**: 변경이 파급되는 파일·모듈·API를 명시한다
23
+ ### 경량 모드 적용 대상 가벼운 결정
28
24
 
29
- > 원칙: 사용자가 **코드나 원문을 직접 찾아보지 않아도** 출력만으로 판단할 있어야 한다.
25
+ 조건: 영향 범위가 단일 파일·수 이내이고, 선택지의 차이가 한눈에 명확할 때.
30
26
 
31
- ## 복수 결정사항 처리
27
+ 필수 항목:
28
+ - 결정 대상 한 줄
29
+ - 2~4개 선택지 + "수행 안 함"
30
+ - 각 선택지: 한 줄 요약 + 한 줄 트레이드오프 + 10점 만점 단일 점수
31
+ - 추천 한 줄
32
+ - `AskUserQuestion` 호출
32
33
 
33
- - **CRITICAL: 결정사항이 여러 개일 경우, 반드시 번에 하나의 결정사항만 제시하고, 사용자 선택 후 다음으로 넘어간다.**
34
- - 선택지 제시 후 `AskUserQuestion` 호출로 **응답을 완전히 종료**한다. 다음 결정사항은 **새 응답**에서 제시한다 (같은 응답 내 연속 제시 금지)
35
- - 이전 선택 결과에 따라 후속 결정사항이 변경·추가·삭제될 수 있으므로, 매 단계마다 남은 결정사항을 재평가한다
36
- - 남은 결정사항이 몇 건인지 알려준다 (예: "1/3건 완료")
34
+ ### 전체 모드 적용 대상 무거운 결정
37
35
 
38
- ## 점수 기준
36
+ 조건: 설계·아키텍처·공개 API·규칙/설정 파일·복수 파일 영향·되돌리기 어려운 변경.
37
+
38
+ 필수 항목 (공통 규칙 + 아래):
39
+
40
+ - 근거 제시
41
+ - 현재 상태 인용: 파일경로:라인번호 필수. 코드블록 사용 시에도 경로:라인 병기
42
+ - 변경 후 모습: 코드블록·구조도·시그니처로 제시
43
+ - 차이점 대비: 동일 관점에서 선택지 나란히 비교
44
+ - 영향 범위: 파급되는 파일·모듈·API 명시
45
+ - 원칙: 사용자가 원문을 찾지 않아도 이 출력만으로 판단 가능해야 한다
46
+ - 축별 점수
47
+ - 맥락에 맞는 관점(축) 3개 이상 선정
48
+ - 축별 점수를 반드시 노출한 뒤 평균을 10점 만점으로 병기 (최종 점수만 쓰는 것 금지)
39
49
 
40
- - 모든 점수는 **10점 만점**이다
41
- - LLM이 맥락에 맞는 관점(축)을 3개 이상 선정하여 관점별 점수를 매기고, **축별 점수를 반드시 노출한 뒤 평균을 10점 만점으로 함께 표시**한다 (최종 점수만 쓰는 것 금지)
42
- - **하나의 선택지를 명시적으로 추천** — 추천 사유를 한 줄로 요약
@@ -0,0 +1,18 @@
1
+ import hashlib, json, os, sys
2
+
3
+ data = json.load(sys.stdin)
4
+ tool_input = data["tool_input"]
5
+ file_path = tool_input.get("file_path", "")
6
+ session_id = data.get("session_id", "unknown")
7
+
8
+ if not file_path or not os.path.isfile(file_path):
9
+ sys.exit(0)
10
+
11
+ file_hash = hashlib.sha256(open(file_path, "rb").read()).hexdigest()
12
+ path_hash = hashlib.sha256(os.path.normpath(file_path).encode()).hexdigest()
13
+
14
+ cache_dir = os.path.join(".tmp", "read_hash", session_id)
15
+ os.makedirs(cache_dir, exist_ok=True)
16
+
17
+ with open(os.path.join(cache_dir, path_hash), "w") as f:
18
+ f.write(file_hash)
@@ -1,7 +1,19 @@
1
- import json, os, sys
1
+ import hashlib, json, os, sys
2
2
 
3
3
  data = json.load(sys.stdin)
4
4
  file_path = data["tool_input"]["file_path"]
5
+ session_id = data.get("session_id", "unknown")
6
+
5
7
  if os.path.isfile(file_path):
6
- print(f"CRITICAL: This file already exists. NEVER delete/rm the file and retry with Write. You MUST use the Edit tool instead: {file_path}", file=sys.stderr)
7
- sys.exit(2)
8
+ path_hash = hashlib.sha256(os.path.normpath(file_path).encode()).hexdigest()
9
+ cache_file = os.path.join(".tmp", "read_hash", session_id, path_hash)
10
+
11
+ cached_hash = ""
12
+ if os.path.isfile(cache_file):
13
+ cached_hash = open(cache_file, "r").read().strip()
14
+
15
+ current_hash = hashlib.sha256(open(file_path, "rb").read()).hexdigest()
16
+
17
+ if cached_hash != current_hash:
18
+ print(f"CRITICAL: File content has changed or was never Read. You MUST Read the file first, then MUST REVISE your Write content based on the current file content before retrying: {file_path}", file=sys.stderr)
19
+ sys.exit(2)
@@ -29,6 +29,17 @@
29
29
  ]
30
30
  }
31
31
  ],
32
+ "PostToolUse": [
33
+ {
34
+ "matcher": "Read",
35
+ "hooks": [
36
+ {
37
+ "type": "command",
38
+ "command": "python .claude/sd-cache-read-hash.py"
39
+ }
40
+ ]
41
+ }
42
+ ],
32
43
  "SubagentStart": [
33
44
  {
34
45
  "hooks": [
@@ -16,9 +16,9 @@ description: typecheck, lint, test를 실행하고 에러 발생시 사용자
16
16
  발견된 에러가 **수정 대상**인지 판단하는 기준:
17
17
 
18
18
  - **sd-check 단독 실행 (이 대화에서 sd-check 호출 전 Claude의 코드 수정이 없음)**: 발견된 **모든 에러**가 수정 대상. "수정 대상 외"로 판단하여 스킵 금지(NEVER).
19
- - **직전 대화 내 코드 수정이 있음**: 해당 수정과 **관련된 에러만** 수정 대상. 무관한 에러는 조용히 스킵하되, 사용자에게 **보고하지 않는다** (그냥 넘어간다).
19
+ - **대화세션내 코드 수정이 있음**: 해당 수정과 **관련된 에러만** 수정 대상. 무관한 에러는 조용히 스킵하되, 사용자에게 **보고하지 않는다** (그냥 넘어간다).
20
20
 
21
- 판단 제외 — "직전 수정"에 해당하지 않는 것:
21
+ 판단 제외 — "대화세션내 수정"에 해당하지 않는 것:
22
22
  - git status의 미커밋 변경, 과거 커밋 변경
23
23
  - sd-check 내부(typecheck/lint/test 단계)에서 발생한 수정
24
24
 
@@ -106,28 +106,6 @@ typecheck 명령어를 실행한다. (`출력 캡처 규칙`에 따라 파일로
106
106
  - 에러 발생 시: `에러 분석 및 수정`에 따라, 테스트 실패의 원인을 분석하고 코드를 수정한다.
107
107
  - 코드 수정후, 테스트 변경이 누락되었을 수 있음. 의도파악을 위해서 history확인이 필요할 수 있다.
108
108
 
109
- ## Step 5: .verify.md 재검증
109
+ ## Step 5: 반복 혹은 완료
110
110
 
111
- `에러 처리 범위` 규칙에 따라 대상 `.verify.md`를 결정한다:
112
- - sd-check 단독 실행: 모든 `.verify.md`
113
- - 직전 수정 있음: 수정과 관련된 `.verify.md`만
114
-
115
- 각 `.verify.md`는 체크박스가 없는 검증 항목 명세이다. 항목을 순회하며 LLM이 매번 재수행한다 — 코드를 읽고, 명령을 실행하고, 설정을 확인하여 각 항목의 통과 여부를 판단한다. 판단 결과는 파일에 기록하지 않는다 (파일은 명세 그대로 유지).
116
-
117
- - 문제 발견 시: test 실패와 동일하게 `에러 분석 및 수정` 규칙을 따른다.
118
-
119
- ## Step 6: .spec.md 정합성 확인
120
-
121
- `에러 처리 범위` 규칙에 따라 대상 `.spec.md`를 결정한다 (Step 5와 동일).
122
-
123
- `.spec.md`는 사용자 수동 검증 문서이다. 각 문서의 전제 조건·수행 절차·기대 결과를 읽고, 관련 코드를 읽어 **의미적 정합성**을 LLM이 추론한다:
124
- - 절차에 등장하는 UI 요소·메서드·이벤트가 실제 코드에 존재하는가
125
- - 기대 결과가 현재 코드 동작과 일치하는가
126
-
127
- - 불일치 발견 시: 사용자에게 보고한다. **자동 수정 금지** — 코드가 맞는지 문서가 맞는지 LLM이 판단할 수 없으므로 사용자가 결정한다.
128
-
129
- ## Step 7: 반복 혹은 완료
130
-
131
- typecheck, lint, test, `.verify.md` 재검증을 수행하는 동안 코드 수정이 있었으면 `typecheck`부터 다시 시작한다. 수정이 없었으면 완료.
132
-
133
- (`.spec.md` 정합성 확인은 코드 수정을 유발하지 않으므로 반복 트리거가 아니다.)
111
+ typecheck, lint, test 수행 코드 수정이 있었으면 `typecheck`부터 다시 시작한다. 수정이 없었으면 완료.