deel-local-cli 1.1.0 → 1.2.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.en.md +347 -9
- package/README.md +317 -6
- package/package.json +2 -2
- package/src/agent/budget.js +0 -14
- package/src/agent/compact.js +87 -0
- package/src/agent/evolve.js +213 -0
- package/src/agent/loop.js +38 -1
- package/src/agent/modes.js +2 -0
- package/src/agent/route.js +55 -3
- package/src/agent/session.js +145 -1
- package/src/agent/threads.js +154 -0
- package/src/backend/http.js +41 -4
- package/src/commands.js +268 -4
- package/src/config.js +10 -1
- package/src/oneshot.js +4 -0
- package/src/preview/serve.js +326 -0
- package/src/repl.js +210 -34
- package/src/safety/guard.js +37 -2
- package/src/safety/undo.js +1 -1
- package/src/setup.js +2 -2
- package/src/skills/builtin//352/262/200/354/202/254-/353/250/274/354/240/200/SKILL.md +64 -0
- package/src/skills/builtin//352/271/212/354/235/264/354/236/210/352/262/214-/353/247/214/353/223/244/352/270/260/SKILL.md +78 -0
- package/src/skills/builtin//353/201/235/352/271/214/354/247/200-/355/225/230/352/270/260/SKILL.md +65 -0
- package/src/skills/builtin//354/212/244/354/212/244/353/241/234-/352/262/200/355/206/240/SKILL.md +74 -0
- package/src/skills/builtin//354/260/224/353/237/254/353/263/264/352/270/260/SKILL.md +59 -0
- package/src/skills/builtin//354/260/250/352/267/274/354/260/250/352/267/274-/353/224/224/353/262/204/352/271/205/SKILL.md +73 -0
- package/src/skills/builtin//354/275/224/353/223/234-/354/244/204/354/235/264/352/270/260/SKILL.md +66 -0
- package/src/skills/discover.js +18 -3
- package/src/tools/edit-match.js +16 -5
- package/src/tools/excel-com.js +1 -1
- package/src/tools/excel.js +1 -1
- package/src/tools/fsutil.js +0 -8
- package/src/tools/index.js +1 -1
- package/src/tools/todo.js +19 -3
- package/src/ui/ansi.js +6 -2
- package/src/ui/inputbox.js +37 -8
- package/src/ui/md.js +227 -0
- package/src/ui/motion.js +212 -0
- package/src/ui/prompt.js +1 -1
- package/src/ui/screen.js +1 -1
- package/src/ui/status.js +14 -1
- package/src/ui/working.js +0 -3
- package/src/ui/wrap.js +1 -8
package/src/skills/builtin//353/201/235/352/271/214/354/247/200-/355/225/230/352/270/260/SKILL.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 끝까지-하기
|
|
3
|
+
description: 시킨 것이 여러 조각일 때 쉬운 것만 하고 멈추지 않기. 빼먹은 것은 말한다
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 끝까지 하기
|
|
7
|
+
|
|
8
|
+
## 왜 있나
|
|
9
|
+
|
|
10
|
+
한 번에 여러 가지를 시키면 앞의 한둘만 하고 "다 했습니다" 로 끝나는 일이
|
|
11
|
+
잦다. 나머지는 조용히 사라진다. 사람은 다 된 줄 알고 넘어갔다가 나중에
|
|
12
|
+
발견한다 — 그때는 이미 그걸 믿고 다음 일을 시작한 뒤다.
|
|
13
|
+
|
|
14
|
+
**빼먹는 것 자체보다, 빼먹은 줄 모르게 하는 것이 나쁘다.**
|
|
15
|
+
|
|
16
|
+
## 어떻게
|
|
17
|
+
|
|
18
|
+
### 1. 조각부터 다 센다
|
|
19
|
+
|
|
20
|
+
시작하기 전에 요청을 조각으로 끊는다. '그리고', '또', '~도', 쉼표,
|
|
21
|
+
줄바꿈이 경계다. 중간에 끼워 넣은 말도 조각이다.
|
|
22
|
+
|
|
23
|
+
셋을 넘으면 **TodoWrite 로 적는다.** 머리로 들고 있으면 반드시 샌다.
|
|
24
|
+
|
|
25
|
+
### 2. 순서를 정한다
|
|
26
|
+
|
|
27
|
+
- 남의 답을 기다려야 하는 것부터 던져 놓는다
|
|
28
|
+
- 서로 안 엮인 것은 한 번에 처리한다
|
|
29
|
+
- 막힐 것 같은 것을 **뒤로 미루지 않는다.** 미루면 시간이 없어 못 하게 되고,
|
|
30
|
+
그게 정확히 조용히 빠지는 자리다
|
|
31
|
+
|
|
32
|
+
### 3. 하나씩 끝내고 표시한다
|
|
33
|
+
|
|
34
|
+
- 끝난 것은 바로 done 으로 바꾼다
|
|
35
|
+
- 다음으로 넘어가기 전에 **그 조각이 정말 끝났는지** 본다. 절반쯤 해 놓고
|
|
36
|
+
넘어간 것이 나중에 다 됐다고 세어진다
|
|
37
|
+
|
|
38
|
+
### 4. 막히면 나머지를 먼저 끝낸다
|
|
39
|
+
|
|
40
|
+
한 조각이 막혔다고 전부 멈추지 않는다.
|
|
41
|
+
|
|
42
|
+
- 그것에 안 엮인 나머지를 **전부** 끝낸다
|
|
43
|
+
- 막힌 것은 무엇이 왜 막혔는지 적는다
|
|
44
|
+
- 범위를 줄이는 것은 사람이 정할 일이다. 혼자 줄이고 다 했다고 하지 않는다
|
|
45
|
+
|
|
46
|
+
### 5. 끝에 반드시 셈을 맞춘다
|
|
47
|
+
|
|
48
|
+
원래 요청을 다시 읽고 조각과 하나씩 맞춰 본다.
|
|
49
|
+
|
|
50
|
+
시킨 것 5개 · 끝낸 것 4개 · 못 한 것 1개 (왜: …)
|
|
51
|
+
|
|
52
|
+
숫자가 안 맞으면 아직 안 끝난 것이다.
|
|
53
|
+
|
|
54
|
+
## 말할 때
|
|
55
|
+
|
|
56
|
+
- 다 했으면 짧게 "다 했다" 고 한다
|
|
57
|
+
- 못 한 것이 있으면 **먼저** 말한다. 잘된 것 뒤에 붙이면 안 읽힌다
|
|
58
|
+
- 나중에 하겠다는 것도 안 한 것이다. 그렇게 적는다
|
|
59
|
+
|
|
60
|
+
## 하지 말 것
|
|
61
|
+
|
|
62
|
+
- 쉬운 것만 하고 "다 했습니다"
|
|
63
|
+
- 조각을 세지 않고 시작하기
|
|
64
|
+
- 막혔다고 통째로 멈추기
|
|
65
|
+
- 조용히 범위 줄이기 — 줄였으면 줄였다고 말한다
|
package/src/skills/builtin//354/212/244/354/212/244/353/241/234-/352/262/200/355/206/240/SKILL.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 스스로-검토
|
|
3
|
+
description: 다 됐다고 말하기 전에 스스로 훑고 못 잰 것까지 말하기. 끝냈을 때·커밋 전에 쓴다
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 스스로 검토
|
|
7
|
+
|
|
8
|
+
## 왜 있나
|
|
9
|
+
|
|
10
|
+
"다 됐습니다" 는 제일 하기 쉬운 말이고, 제일 자주 틀리는 말이다.
|
|
11
|
+
사람이 그 말을 믿고 넘어간 뒤에 깨진 것을 발견하면, 그 다음부터는
|
|
12
|
+
아무 말도 못 믿게 된다.
|
|
13
|
+
|
|
14
|
+
**검토는 잘한 것을 확인하는 자리가 아니라 안 한 것을 찾는 자리다.**
|
|
15
|
+
|
|
16
|
+
## 훑는 차례
|
|
17
|
+
|
|
18
|
+
### 1. 시킨 것을 다 했나
|
|
19
|
+
|
|
20
|
+
- 요청을 다시 읽는다. 조각이 여럿이면 하나씩 짚는다
|
|
21
|
+
- 조용히 줄인 것은 없나. 줄였으면 **줄였다고 말한다** — 그건 사람이 정할 일이다
|
|
22
|
+
- 못 한 것이 있으면 무엇을 왜 못 했는지 적는다
|
|
23
|
+
|
|
24
|
+
### 2. 돌려 봤나
|
|
25
|
+
|
|
26
|
+
- 화면·숫자로 확인했나, 아니면 될 것 같아서 말하는 건가
|
|
27
|
+
- 검사가 있으면 돌렸나. **전체**를 돌렸나
|
|
28
|
+
- 고친 자리를 실제로 밟는 검사인가
|
|
29
|
+
|
|
30
|
+
### 3. 안 되어야 하는 것도 봤나
|
|
31
|
+
|
|
32
|
+
되는 길만 보면 절반이다.
|
|
33
|
+
|
|
34
|
+
- 빈 값·없는 파일·권한 없음·끊긴 연결
|
|
35
|
+
- 한글·공백 든 경로·CRLF
|
|
36
|
+
- 다른 셸(PowerShell·cmd)·다른 OS 에서도 같은가
|
|
37
|
+
|
|
38
|
+
### 4. 조용히 실패하는 자리는 없나
|
|
39
|
+
|
|
40
|
+
- 삼킨 오류(`catch {}`)
|
|
41
|
+
- 못 찾으면 기본값으로 넘어가는 자리 — 그게 맞는 기본값인가
|
|
42
|
+
- 조건 때문에 통째로 건너뛰어지는 검사
|
|
43
|
+
|
|
44
|
+
### 5. 남은 것을 치웠나
|
|
45
|
+
|
|
46
|
+
- 임시 파일·디버그 출력·주석 처리한 코드
|
|
47
|
+
- 띄운 프로세스·열린 포트·안 지운 임시 폴더
|
|
48
|
+
|
|
49
|
+
### 6. 왜 그랬는지 적었나
|
|
50
|
+
|
|
51
|
+
겪어서 알게 된 것은 코드에 안 남는다. 다음 사람(과 다음의 나)이 그걸
|
|
52
|
+
모르면 같은 데서 또 넘어진다. 주석이나 커밋 본문에 남긴다.
|
|
53
|
+
|
|
54
|
+
## 무엇을 못 쟀는지 말한다
|
|
55
|
+
|
|
56
|
+
이게 제일 중요하다. **못 잰 것을 안 말하면 사람은 다 쟀다고 읽는다.**
|
|
57
|
+
|
|
58
|
+
- "로컬 모델로는 못 재 봤습니다. 가짜 게이트웨이로만 확인했습니다"
|
|
59
|
+
- "unzip 이 없는 자리에서는 11건을 못 쟀습니다"
|
|
60
|
+
- "인식률은 잴 방법이 없어 그 이유로 결정하지 않았습니다"
|
|
61
|
+
|
|
62
|
+
## 어떻게 말하나
|
|
63
|
+
|
|
64
|
+
- 됐으면 됐다고 짧게. 에두르지 않는다
|
|
65
|
+
- 안 됐으면 **출력을 붙여** 말한다. "검사가 실패합니다" 만으로는 부족하다
|
|
66
|
+
- 지어낸 숫자를 쓰지 않는다. 안 잰 것은 "안 쟀다" 고 한다
|
|
67
|
+
- 잘못을 길게 뉘우치지 않는다. 무엇이 틀렸고 어떻게 했는지만 적는다
|
|
68
|
+
|
|
69
|
+
## 하지 말 것
|
|
70
|
+
|
|
71
|
+
- 안 돌려 보고 "될 겁니다"
|
|
72
|
+
- 요청의 일부를 조용히 빼고 "다 했습니다"
|
|
73
|
+
- 실패한 검사를 안 보이는 곳에 두기
|
|
74
|
+
- 못 잰 것을 잰 것처럼 말하기
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 찔러보기
|
|
3
|
+
description: 되는지 모를 때 시간 정해 작게 찔러 답만 얻고 버리기. 헤매지 않으려고 쓴다
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 찔러보기 (spike)
|
|
7
|
+
|
|
8
|
+
## 언제 쓰나
|
|
9
|
+
|
|
10
|
+
- 이 방법이 되는지 안 되는지를 모른다
|
|
11
|
+
- 남의 규격·API 가 실제로 무엇을 돌려주는지 모른다
|
|
12
|
+
- 둘 중 어느 쪽이 나은지 재 보지 않고는 못 정하겠다
|
|
13
|
+
|
|
14
|
+
**모르는 채로 본 코드를 짜기 시작하면 안 된다.** 절반쯤 짓고 나서 안 된다는
|
|
15
|
+
것을 알게 되고, 그때는 되돌리기도 아깝다.
|
|
16
|
+
|
|
17
|
+
## 어떻게
|
|
18
|
+
|
|
19
|
+
### 1. 물음을 하나로 좁힌다
|
|
20
|
+
|
|
21
|
+
답이 **예/아니오** 나 **숫자 하나**로 나와야 한다.
|
|
22
|
+
|
|
23
|
+
- ✗ "이 방식이 괜찮을까"
|
|
24
|
+
- ✓ "이 프록시가 401 을 줄 때 본문에 사람이 읽을 문장이 들어 있나"
|
|
25
|
+
- ✓ "파일 600개짜리 폴더를 훑는 데 몇 ms 걸리나"
|
|
26
|
+
|
|
27
|
+
### 2. 시간을 먼저 정한다
|
|
28
|
+
|
|
29
|
+
15분, 30분, 한 시간. 정하고 시작한다. 넘기면 **멈추고 무엇까지 알아냈는지
|
|
30
|
+
말한다.** 끝이 없는 찌르기는 찌르기가 아니라 헤매는 것이다.
|
|
31
|
+
|
|
32
|
+
### 3. 제일 더러운 방법으로 짠다
|
|
33
|
+
|
|
34
|
+
- 임시 폴더에 짠다. 본 코드에 안 섞는다
|
|
35
|
+
- 오류 처리·이름·구조 다 신경 안 쓴다
|
|
36
|
+
- 화면에 답만 찍히면 된다
|
|
37
|
+
|
|
38
|
+
### 4. 답을 적고 **버린다**
|
|
39
|
+
|
|
40
|
+
찔러 본 코드는 지운다. 남기는 것은 **알아낸 사실 한 줄**이다.
|
|
41
|
+
|
|
42
|
+
"unzip 은 Git Bash PATH 에만 있다. cmd 에는 없고, npm 은 cmd 로 돈다."
|
|
43
|
+
"폴더 600개 훑기 7ms — 켤 때마다 해도 된다."
|
|
44
|
+
"이 모델은 content 가 비고 전부 thinking 으로 간다. 상한이 낮으면 본문이 안 나온다."
|
|
45
|
+
|
|
46
|
+
그 한 줄이 본 코드의 주석이 되고 결정의 근거가 된다.
|
|
47
|
+
|
|
48
|
+
## 왜 버리나
|
|
49
|
+
|
|
50
|
+
찔러 본 코드는 **답을 얻으려고** 짠 것이지 오래 쓰려고 짠 게 아니다.
|
|
51
|
+
그대로 두면 오류 처리도 없고 이름도 엉망인 것이 본 코드가 된다.
|
|
52
|
+
"어차피 도니까" 로 남긴 것이 나중에 제일 오래 남는다.
|
|
53
|
+
|
|
54
|
+
## 하지 말 것
|
|
55
|
+
|
|
56
|
+
- 시간을 안 정하고 시작하기
|
|
57
|
+
- 찌르다가 슬그머니 본 구현으로 넘어가기
|
|
58
|
+
- 답을 안 적고 코드만 남기기 — 코드는 무엇을 알아냈는지 말해 주지 않는다
|
|
59
|
+
- 사내망·운영 서버에 대고 찌르기. 가짜를 세워서 찌른다
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 차근차근-디버깅
|
|
3
|
+
description: 재현→좁히기→원인→고치기→증명. 짐작으로 손대지 않기. 고장·재발에 쓴다
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 차근차근 디버깅
|
|
7
|
+
|
|
8
|
+
## 왜 있나
|
|
9
|
+
|
|
10
|
+
안 되는 것을 보면 바로 고치고 싶어진다. 그래서 짐작으로 한 줄 바꾸고
|
|
11
|
+
"이제 될 겁니다" 라고 말하게 된다. 그게 맞을 때도 있는데, **틀렸을 때
|
|
12
|
+
그걸 알 방법이 없다.** 그리고 틀린 채로 넘어간 것은 반드시 다시 돌아온다.
|
|
13
|
+
|
|
14
|
+
## 순서
|
|
15
|
+
|
|
16
|
+
### 1. 재현한다 — 이걸 건너뛰지 않는다
|
|
17
|
+
|
|
18
|
+
고칠 수 있는 것은 **볼 수 있는 것**뿐이다.
|
|
19
|
+
|
|
20
|
+
- 무엇을 하면 터지는가를 명령 한 줄로 만든다
|
|
21
|
+
- 매번 터지는가, 가끔인가. 가끔이면 몇 번에 한 번인가
|
|
22
|
+
- 못 재현하면 거기서 멈추고 **무엇이 더 필요한지 말한다.** 재현 못 한 채
|
|
23
|
+
고치는 것은 고치는 게 아니라 바꾸는 것이다
|
|
24
|
+
|
|
25
|
+
### 2. 좁힌다 — 반씩 자른다
|
|
26
|
+
|
|
27
|
+
원인을 짐작하지 말고 **범위를 자른다.**
|
|
28
|
+
|
|
29
|
+
- 언제부터 됐나 / 안 됐나 (되던 시점이 있으면 그 사이가 범위다)
|
|
30
|
+
- 되는 입력과 안 되는 입력의 차이는 정확히 무엇인가
|
|
31
|
+
- 절반을 빼면 여전히 터지나
|
|
32
|
+
- 다른 자리(다른 셸·다른 PC·다른 폴더)에서도 터지나
|
|
33
|
+
|
|
34
|
+
세 번 좁혔는데 범위가 안 줄면 좁히는 방향이 틀린 것이다. 처음으로 돌아간다.
|
|
35
|
+
|
|
36
|
+
### 3. 원인을 말로 만든다
|
|
37
|
+
|
|
38
|
+
**"A 일 때 B 가 C 를 하므로 D 가 된다"** 꼴로 한 문장이 나와야 한다.
|
|
39
|
+
안 나오면 아직 원인을 모르는 것이다. 이때 고치면 증상만 덮게 된다.
|
|
40
|
+
|
|
41
|
+
"아마 인코딩 문제일 것" 은 원인이 아니다.
|
|
42
|
+
"파일이 CP949 로 저장돼 있는데 utf8 로 읽어서 앞 두 글자가 깨진다" 가 원인이다.
|
|
43
|
+
|
|
44
|
+
### 4. 고치기 전에 실패를 못 박는다
|
|
45
|
+
|
|
46
|
+
**터지는 것을 먼저 검사로 만든다.** 지금 실패해야 맞다.
|
|
47
|
+
|
|
48
|
+
- 실패하는 것을 확인한 뒤에 고친다
|
|
49
|
+
- 안 만들면 "고쳤다" 를 증명할 방법이 없고, 다음에 같은 게 돌아와도 모른다
|
|
50
|
+
- 검사를 만들기 어려운 자리면, 최소한 재현 명령과 그 출력을 남긴다
|
|
51
|
+
|
|
52
|
+
### 5. 고치고 증명한다
|
|
53
|
+
|
|
54
|
+
- 아까 실패하던 것이 통과하는가
|
|
55
|
+
- **다른 것이 안 깨졌는가** — 전체 검사를 돌린다
|
|
56
|
+
- 원인을 지웠는가, 증상을 덮었는가. 덮었으면 그렇다고 말한다
|
|
57
|
+
|
|
58
|
+
## 겪은 것에서 나온 규칙
|
|
59
|
+
|
|
60
|
+
- **문법이 맞는다고 맞는 게 아니다.** 셸이 `${...}` 를 먹어서 만들어진
|
|
61
|
+
`error: + '…'` 는 `node --check` 를 통과한다. 검사가 잡았다.
|
|
62
|
+
- **같은 코드가 셸에 따라 다르게 돈다.** Git Bash 의 PATH 에만 있는 도구에
|
|
63
|
+
기댄 검사가 npm(cmd) 에서만 실패했다. "간헐적" 으로 보이면 **무엇이
|
|
64
|
+
다른지**부터 본다 — 대개 간헐적이 아니다.
|
|
65
|
+
- **조용히 건너뛴 것이 실패보다 나쁘다.** 실패는 눈에 띄지만 건너뛴 것은
|
|
66
|
+
통과처럼 보인다.
|
|
67
|
+
|
|
68
|
+
## 하지 말 것
|
|
69
|
+
|
|
70
|
+
- 재현 없이 고치기
|
|
71
|
+
- 한 번에 여러 군데 고치기 — 뭐가 들었는지 알 수 없게 된다
|
|
72
|
+
- 원인을 모른 채 `try/catch` 로 덮기
|
|
73
|
+
- "이제 될 겁니다" — 돌려 보고 말한다
|
package/src/skills/builtin//354/275/224/353/223/234-/354/244/204/354/235/264/352/270/260/SKILL.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 코드-줄이기
|
|
3
|
+
description: 동작은 그대로 두고 읽기 쉽게 줄이기. 정리해달라는 말에 쓴다
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 코드 줄이기
|
|
7
|
+
|
|
8
|
+
## 규칙 하나
|
|
9
|
+
|
|
10
|
+
**동작을 바꾸지 않는다.** 줄이기와 고치기를 같이 하면, 뭔가 깨졌을 때
|
|
11
|
+
줄여서 깨진 건지 고치다 깨진 건지 알 수 없다. 둘을 섞지 않는다.
|
|
12
|
+
|
|
13
|
+
시작하기 전에 검사가 초록인지 본다. 빨강에서 시작하면 줄이는 게 아니라
|
|
14
|
+
그냥 헤매는 것이다.
|
|
15
|
+
|
|
16
|
+
## 무엇을 줄이나 — 값이 큰 순서
|
|
17
|
+
|
|
18
|
+
### 1. 같은 것이 세 군데 이상
|
|
19
|
+
|
|
20
|
+
두 군데는 놔둔다. 세 번째가 나타나면 묶는다. **두 번에 묶으면** 나중에
|
|
21
|
+
셋이 서로 다른 방향으로 갈라질 때 억지로 한 틀에 우겨넣게 된다.
|
|
22
|
+
|
|
23
|
+
### 2. 이름이 하는 일과 다른 것
|
|
24
|
+
|
|
25
|
+
`process()`, `data`, `handle2()`. 이름만 바꿔도 읽는 속도가 달라진다.
|
|
26
|
+
이름을 못 짓겠으면 그 함수가 두 가지 일을 하고 있는 것이다.
|
|
27
|
+
|
|
28
|
+
### 3. 세 겹 넘는 중첩
|
|
29
|
+
|
|
30
|
+
- 일찍 돌려보낸다 (`if (없으면) return`)
|
|
31
|
+
- 안쪽 덩어리를 이름 있는 함수로 뺀다
|
|
32
|
+
|
|
33
|
+
### 4. 죽은 것
|
|
34
|
+
|
|
35
|
+
안 쓰는 함수·변수·주석 처리된 코드. **지운다.** "나중에 쓸까 봐" 는 이유가
|
|
36
|
+
못 된다 — 되돌리기가 있다.
|
|
37
|
+
|
|
38
|
+
### 5. 주석이 코드를 되풀이하는 것
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
// i 를 1 늘린다
|
|
42
|
+
i += 1;
|
|
43
|
+
```
|
|
44
|
+
지운다. **왜 그렇게 했는지**만 남긴다. 무엇을 하는지는 코드가 말한다.
|
|
45
|
+
|
|
46
|
+
## 무엇을 안 줄이나
|
|
47
|
+
|
|
48
|
+
- **왜 그런지 적어 둔 주석.** 이건 코드에 안 남는 정보다. 제일 먼저 지워지고
|
|
49
|
+
제일 아깝다
|
|
50
|
+
- 겪어서 붙은 예외 처리. `// 윈도우 GNU tar 는 'C:\' 를 원격 호스트로 오해한다`
|
|
51
|
+
같은 것. 이유가 안 적혀 있으면 지우기 전에 왜 있는지부터 찾는다
|
|
52
|
+
- 검사 코드 — 조금 지저분해도 괜찮다. 검사는 읽히는 것보다 **잡는 것**이 일이다
|
|
53
|
+
- 이미 잘 도는 남의 코드
|
|
54
|
+
|
|
55
|
+
## 끝내기 전에
|
|
56
|
+
|
|
57
|
+
- 검사가 여전히 전부 초록인가
|
|
58
|
+
- 지운 것 중에 **왜 있었는지 모르는 채로** 지운 게 있나. 있으면 되돌린다
|
|
59
|
+
- 줄인 만큼 읽기 쉬워졌나. 짧아지기만 하고 더 어려워졌으면 되돌린다
|
|
60
|
+
|
|
61
|
+
## 하지 말 것
|
|
62
|
+
|
|
63
|
+
- 줄이면서 기능 고치기
|
|
64
|
+
- 검사가 빨강인 채로 시작하기
|
|
65
|
+
- 한 번에 여러 파일 갈아엎기 — 무엇이 깨졌는지 못 찾는다
|
|
66
|
+
- 짧게 만들려고 한 줄에 우겨넣기. 짧은 것과 읽기 쉬운 것은 다르다
|
package/src/skills/discover.js
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
// 스킬·슬래시명령 찾기.
|
|
2
|
-
// deel 는
|
|
3
|
-
//
|
|
4
|
-
|
|
2
|
+
// deel 는 그 PC 를 훑어 있는 것을 쓴다. Claude Code 와 같은 형식을 읽으므로,
|
|
3
|
+
// 그쪽으로 쓰인 것이 그대로 먹는다.
|
|
4
|
+
//
|
|
5
|
+
// **다만 일하는 방법 몇 가지는 품고 다닌다(builtin/).**
|
|
6
|
+
// 전에는 하나도 안 품었다. 그런데 사내에서 새로 받은 PC 에는 ~/.claude/skills 도
|
|
7
|
+
// 플러그인도 없다 — 거기서는 방법론이 0개였고, 모델은 매번 제 나름대로 했다.
|
|
8
|
+
// 시킨 것만 겨우 하고 끝나는 얄팍한 결과가 거기서 나온다.
|
|
9
|
+
// 품고 다니는 것은 **가장 낮은 자리**에 둔다. 같은 이름을 사용자가 만들면 그쪽이 이긴다.
|
|
10
|
+
import { readdirSync, readFileSync, existsSync } from 'node:fs';
|
|
5
11
|
import { join, basename, dirname } from 'node:path';
|
|
12
|
+
import { fileURLToPath } from 'node:url';
|
|
6
13
|
import { homedir } from 'node:os';
|
|
7
14
|
|
|
15
|
+
// 이 파일 옆의 builtin/ — 패키지에 같이 실려 나간다(package.json files: src).
|
|
16
|
+
export const 내장자리 = join(dirname(fileURLToPath(import.meta.url)), 'builtin');
|
|
17
|
+
|
|
8
18
|
// --- YAML 앞머리 읽기 (name, description 만 쓰므로 최소만 구현) -------------
|
|
9
19
|
export function frontmatter(text) {
|
|
10
20
|
if (!text.startsWith('---')) return { data: {}, body: text };
|
|
@@ -156,6 +166,11 @@ export function discover(root, opts = {}) {
|
|
|
156
166
|
const commands = [];
|
|
157
167
|
const plugins = [];
|
|
158
168
|
|
|
169
|
+
// 0) 품고 다니는 것 — 제일 먼저 넣어 제일 낮은 자리를 준다.
|
|
170
|
+
// dedupe 는 나중에 온 것이 이기므로, 사용자·프로젝트가 같은 이름을 만들면 그쪽이 이긴다.
|
|
171
|
+
// 끄고 싶으면 opts.내장 = false (검사에서 이 여섯을 세지 않으려고 쓴다).
|
|
172
|
+
if (opts.내장 !== false) skillsIn(내장자리, 'builtin', null, skills, caps.skills);
|
|
173
|
+
|
|
159
174
|
// 1) 플러그인
|
|
160
175
|
// 같은 플러그인이 cache/ 와 marketplaces/ 양쪽에 있을 수 있다.
|
|
161
176
|
// 이름이 같으면 알맹이가 더 많은 쪽 하나만 쓴다.
|
package/src/tools/edit-match.js
CHANGED
|
@@ -46,11 +46,22 @@ function findAll(text, needle, tier) {
|
|
|
46
46
|
let re;
|
|
47
47
|
try { re = new RegExp(p, 'g'); } catch { return []; }
|
|
48
48
|
const out = [];
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
// 만들 때 말고 **돌릴 때** 터지는 것이 있다.
|
|
50
|
+
//
|
|
51
|
+
// 모델은 큰 파일을 고칠 때 덩이를 통째로 old_string 에 담아 보낸다. 4만 자쯤
|
|
52
|
+
// 넘어가면 new RegExp 는 멀쩡히 만들어지는데(패턴만 훑는다) 실제로 돌릴 때
|
|
53
|
+
// 프로그램 크기 한도에 걸려 SyntaxError 가 난다. 위의 try 는 만들 때만 감싸므로
|
|
54
|
+
// 그 오류가 그대로 튀어나가서 "찾지 못했습니다" 대신 도구가 죽었다.
|
|
55
|
+
//
|
|
56
|
+
// 여기서는 못 찾은 것으로 친다. 정확히 일치하는 경우는 위에서 indexOf 로 이미
|
|
57
|
+
// 처리했으니, 느슨하게 맞춰 보는 이 길만 포기하는 것이다.
|
|
58
|
+
try {
|
|
59
|
+
for (const m of text.matchAll(re)) {
|
|
60
|
+
if (m[0].length === 0) continue;
|
|
61
|
+
out.push({ start: m.index, end: m.index + m[0].length });
|
|
62
|
+
if (out.length > 50) break; // 너무 많으면 어차피 모호하다
|
|
63
|
+
}
|
|
64
|
+
} catch { return []; }
|
|
54
65
|
return out;
|
|
55
66
|
}
|
|
56
67
|
|
package/src/tools/excel-com.js
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
// 2) 엑셀은 바쁘면 호출을 거절한다(0x80010001, 0x800AC472). 잘못된 호출이
|
|
18
18
|
// 아니라 '지금은 말고' 라는 뜻이라, 쉬었다 다시 부르면 된다.
|
|
19
19
|
import { spawn } from 'node:child_process';
|
|
20
|
-
import { mkdtempSync, readFileSync,
|
|
20
|
+
import { mkdtempSync, readFileSync, rmSync } from 'node:fs';
|
|
21
21
|
import { tmpdir } from 'node:os';
|
|
22
22
|
import { join } from 'node:path';
|
|
23
23
|
import { decode } from './encoding.js';
|
package/src/tools/excel.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
//
|
|
6
6
|
// 부르는 쪽은 어느 갈래인지 몰라도 된다. 다만 암호가 필요할 때는 물어볼 수
|
|
7
7
|
// 있어야 하므로, 물어보는 방법을 받아 온다(askPassword).
|
|
8
|
-
import { readFileSync
|
|
8
|
+
import { readFileSync } from 'node:fs';
|
|
9
9
|
import { extname } from 'node:path';
|
|
10
10
|
import { readXlsx, toCsv, looksXlsx, looksOle } from './xlsx.js';
|
|
11
11
|
import { excelToTables, canUseExcel } from './excel-com.js';
|
package/src/tools/fsutil.js
CHANGED
|
@@ -171,14 +171,6 @@ export function walk(root, { limit = 20000, skipDirs = SKIP_DIRS } = {}) {
|
|
|
171
171
|
return out;
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
// 텍스트 파일인지 — 앞부분에 NUL 이 있으면 바이너리로 본다.
|
|
175
|
-
export function isText(path) {
|
|
176
|
-
try {
|
|
177
|
-
const fd = readFileSync(path);
|
|
178
|
-
return !fd.subarray(0, 8000).includes(0);
|
|
179
|
-
} catch { return false; }
|
|
180
|
-
}
|
|
181
|
-
|
|
182
174
|
/**
|
|
183
175
|
* 글 파일을 읽는다. 무엇으로 쓰여 있든 알아보고 읽는다.
|
|
184
176
|
*
|
package/src/tools/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { writeFileSync, appendFileSync, readFileSync, existsSync, mkdirSync, statSync } from 'node:fs';
|
|
4
4
|
import { dirname } from 'node:path';
|
|
5
5
|
import { execFile } from 'node:child_process';
|
|
6
|
-
import { globToRegex, walk, readText, readTextFull,
|
|
6
|
+
import { globToRegex, walk, readText, readTextFull, 내부살림 } from './fsutil.js';
|
|
7
7
|
import { encode, label as encLabel, decode as decodeBytes, consoleCodepage, looksBinary } from './encoding.js';
|
|
8
8
|
import { checkCommand, checkPaths, isMutating } from '../safety/guard.js';
|
|
9
9
|
import { 띄우기, JOBS_TOOL } from './jobs.js';
|
package/src/tools/todo.js
CHANGED
|
@@ -39,16 +39,32 @@ export function render(items) {
|
|
|
39
39
|
export const TODO_TOOL = {
|
|
40
40
|
schema: {
|
|
41
41
|
name: 'TodoWrite',
|
|
42
|
+
/*
|
|
43
|
+
* 문장 차례가 곧 중요도다.
|
|
44
|
+
*
|
|
45
|
+
* 창이 좁으면 tools/index.js 가 **뒤에서부터 문장째로 잘라 낸다**(설명길이).
|
|
46
|
+
* 그러니 규격(state·doing)이 뒤에 있으면 작은 모델에서 조용히 사라진다.
|
|
47
|
+
* 규격 → 규칙 → 조언 차례로 둔다.
|
|
48
|
+
*
|
|
49
|
+
* '세 단계 이상 걸리는 일이면' 이라고 적었더니 모델이 그걸 **세 개를 적으라는
|
|
50
|
+
* 말**로 읽었다. 열 단계짜리 일도 세 줄로 뭉쳐 나왔다. 그래서 개수 이야기를
|
|
51
|
+
* 따로 못 박는다 — 개수는 일의 크기가 정하는 것이고 상한이 없다.
|
|
52
|
+
*/
|
|
42
53
|
description:
|
|
43
|
-
'할 일 목록을 만들고 갱신한다.
|
|
54
|
+
'할 일 목록을 만들고 갱신한다. 여러 단계가 걸리는 일이면 먼저 목록을 만들고, '
|
|
44
55
|
+ '하나를 끝낼 때마다 바로 갱신한다. 목록 전체를 매번 통째로 보낸다. '
|
|
45
|
-
+ 'state 는 todo(아직) / doing(하는 중) / done(끝) 셋 중 하나이고, doing 은 한 번에 하나만 둔다.'
|
|
56
|
+
+ 'state 는 todo(아직) / doing(하는 중) / done(끝) 셋 중 하나이고, doing 은 한 번에 하나만 둔다. '
|
|
57
|
+
+ '단계 수는 일의 크기가 정한다 — 정해진 개수도 상한도 없다. '
|
|
58
|
+
+ '개수를 맞추려고 다른 일을 한 줄에 뭉치지 마라. '
|
|
59
|
+
+ '각 단계는 끝났는지 따로 확인할 수 있는 크기로 적어라.',
|
|
46
60
|
parameters: {
|
|
47
61
|
type: 'object',
|
|
48
62
|
properties: {
|
|
49
63
|
todos: {
|
|
50
64
|
type: 'array',
|
|
51
|
-
|
|
65
|
+
// 인자 설명은 따로 잘리므로, 개수 이야기를 여기에도 한 번 둔다.
|
|
66
|
+
// 창이 좁아 바깥 설명이 잘려 나가도 이건 남는다.
|
|
67
|
+
description: '할 일 전체 목록. 개수 제한 없음 — 일의 크기만큼 적는다',
|
|
52
68
|
items: {
|
|
53
69
|
type: 'object',
|
|
54
70
|
properties: {
|
package/src/ui/ansi.js
CHANGED
|
@@ -54,6 +54,12 @@ export const cursor = {
|
|
|
54
54
|
show: () => ON && process.stdout.write('\x1b[?25h'),
|
|
55
55
|
up: (n = 1) => ON && process.stdout.write(`\x1b[${n}A`),
|
|
56
56
|
clearLine: () => ON && process.stdout.write('\x1b[2K\r'),
|
|
57
|
+
// 여러 조각을 한 덩이로 묶어 한 번에 내보낼 때 쓰는 글자값.
|
|
58
|
+
//
|
|
59
|
+
// 나눠 쓰면 그 사이가 화면에 그대로 보인다. 커서를 숨기기 전에 지우는 글이
|
|
60
|
+
// 먼저 나가면, 커서가 상자 안을 훑고 지나가는 것이 눈에 띈다.
|
|
61
|
+
숨김: ON ? '\x1b[?25l' : '',
|
|
62
|
+
보임: ON ? '\x1b[?25h' : '',
|
|
57
63
|
};
|
|
58
64
|
|
|
59
65
|
// 한글·한자·가나는 터미널에서 두 칸을 차지한다. 표 정렬이 이걸 모르면 어긋난다.
|
|
@@ -175,5 +181,3 @@ export const mark = {
|
|
|
175
181
|
tree: c.gray('└'),
|
|
176
182
|
branch: c.gray('├'),
|
|
177
183
|
};
|
|
178
|
-
|
|
179
|
-
export const COLOR_ON = ON;
|
package/src/ui/inputbox.js
CHANGED
|
@@ -36,7 +36,8 @@
|
|
|
36
36
|
import { c, width, cursor, clip } from './ansi.js';
|
|
37
37
|
import { statusLine, contextWarning } from './status.js';
|
|
38
38
|
import { 접어쓰기 } from './wrap.js';
|
|
39
|
-
import { 문구고르기,
|
|
39
|
+
import { 문구고르기, 걸린시간, 느긋해질때, 문구주기 } from './working.js';
|
|
40
|
+
import { 그림고르기 } from './motion.js';
|
|
40
41
|
import { 최대추천 } from './complete.js';
|
|
41
42
|
|
|
42
43
|
const 줄끝지움 = '\x1b[K';
|
|
@@ -317,7 +318,9 @@ export class InputBox {
|
|
|
317
318
|
const 갈래 = 지난 >= 느긋해질때 ? '느긋' : this.일감.갈래;
|
|
318
319
|
const 회차 = Math.floor((this.틱 * 돌림주기) / 문구주기);
|
|
319
320
|
this.그리기(this.session, '', 0, {
|
|
320
|
-
|
|
321
|
+
// 갈래에 맞는 작은 그림. 무엇을 하는 중인지 글자와 그림이 같이 말한다.
|
|
322
|
+
// DEEL_NO_MOTION=1 이면 예전처럼 한 칸짜리 돌림표가 온다.
|
|
323
|
+
돌림: 그림고르기(갈래, this.틱),
|
|
321
324
|
말: 문구고르기(갈래, 회차),
|
|
322
325
|
곁: [
|
|
323
326
|
걸린시간(지난),
|
|
@@ -369,7 +372,6 @@ export class InputBox {
|
|
|
369
372
|
process.stdout.write('\n');
|
|
370
373
|
this.줄중간 = false;
|
|
371
374
|
}
|
|
372
|
-
this.지우기();
|
|
373
375
|
|
|
374
376
|
const { 줄들, 커서: 자리 } = 프레임({
|
|
375
377
|
글,
|
|
@@ -382,10 +384,35 @@ export class InputBox {
|
|
|
382
384
|
추천,
|
|
383
385
|
});
|
|
384
386
|
|
|
385
|
-
cursor.hide();
|
|
386
|
-
process.stdout.write(줄들.map((l) => l + 줄끝지움).join('\n') + '\n');
|
|
387
387
|
/*
|
|
388
|
-
*
|
|
388
|
+
* ── 지우지 않고 덮어쓴다. 그리고 한 번에 내보낸다 ────────────────────
|
|
389
|
+
*
|
|
390
|
+
* 예전에는 이랬다: 지우기() 로 상자를 싹 지우고 → 새로 그리고 → 커서를
|
|
391
|
+
* 되돌린다. 세 번을 따로 내보냈다. 터미널은 받는 대로 그리므로 **그 사이가
|
|
392
|
+
* 사람 눈에 보인다** — 상자가 한 번 비었다가 다시 차는 것이 백스페이스를
|
|
393
|
+
* 누를 때마다 반복되어, 화면이 깜빡 꺼지는 것처럼 느껴졌다. 글자를 지울
|
|
394
|
+
* 때는 한 번에 한 글자씩 여러 번 누르므로 특히 심했다.
|
|
395
|
+
*
|
|
396
|
+
* 그래서 두 가지를 바꿨다.
|
|
397
|
+
* 1) 지우고 다시 그리지 않는다. 상자 맨 윗줄로 올라가 **덮어쓴다.**
|
|
398
|
+
* 줄 끝마다 줄끝지움이 붙으므로 전에 있던 글자가 남을 자리가 없다.
|
|
399
|
+
* 빈 화면이 스쳐 가는 순간 자체가 사라진다.
|
|
400
|
+
* 2) 지우기·그리기·커서 되돌리기를 한 덩이로 묶어 **한 번만** 쓴다.
|
|
401
|
+
* 중간 상태가 화면에 못 나간다.
|
|
402
|
+
*
|
|
403
|
+
* 상자가 전보다 짧아졌을 때만 남는 줄이 생긴다. 그때만 그 줄을 지운다.
|
|
404
|
+
*/
|
|
405
|
+
const 이전줄 = this.그린줄;
|
|
406
|
+
// 커서는 상자 아래에서 커서위 번째 줄에 있다. 맨 윗줄까지 남은 거리.
|
|
407
|
+
const 윗줄까지 = 이전줄 ? Math.max(0, 이전줄 - 1 - this.커서위) : 0;
|
|
408
|
+
const 남은줄 = Math.max(0, 이전줄 - 줄들.length);
|
|
409
|
+
|
|
410
|
+
let 나갈것 = cursor.숨김 + '\r' + 위로(윗줄까지);
|
|
411
|
+
나갈것 += 줄들.map((l) => l + 줄끝지움).join('\n') + '\n';
|
|
412
|
+
for (let i = 0; i < 남은줄; i++) 나갈것 += 줄끝지움 + '\n';
|
|
413
|
+
/*
|
|
414
|
+
* 방금 찍은 마지막 줄 **다음** 줄에 커서가 있다(남은 줄을 지웠으면 그만큼
|
|
415
|
+
* 더 아래). 거기서 되짚어 올라간다.
|
|
389
416
|
*
|
|
390
417
|
* 오른쪽으로 옮길 때 한 칸이 어긋나기 쉽다. \r 은 커서를 1칸째에 놓고,
|
|
391
418
|
* \x1b[nC 는 거기서 n칸 **더** 간다 — 그래서 1부터 세는 목표 칸으로
|
|
@@ -393,8 +420,10 @@ export class InputBox {
|
|
|
393
420
|
* 백스페이스가 엉뚱한 자리를 지우는 것처럼 보인다.
|
|
394
421
|
*/
|
|
395
422
|
const 오른쪽 = Math.max(0, 자리.열 - 1);
|
|
396
|
-
|
|
397
|
-
cursor
|
|
423
|
+
나갈것 += 위로(남은줄 + 자리.위 + 1) + '\r' + (오른쪽 ? `\x1b[${오른쪽}C` : '');
|
|
424
|
+
나갈것 += cursor.보임;
|
|
425
|
+
process.stdout.write(나갈것);
|
|
426
|
+
|
|
398
427
|
this.그린줄 = 줄들.length;
|
|
399
428
|
this.커서위 = 자리.위;
|
|
400
429
|
}
|