agent-work-loop 0.6.46 → 0.6.48
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 +77 -57
- package/dist/{brief-SGMFXOY2.js → brief-ODMUS5B3.js} +4 -4
- package/dist/{changelog-VNJ4EQ74.js → changelog-P35RSRT3.js} +4 -4
- package/dist/{chunk-FK3Q7UY2.js → chunk-2NETKDCV.js} +2 -2
- package/dist/{chunk-XWMS6Z5E.js → chunk-AVIUMBJZ.js} +3 -3
- package/dist/{chunk-MLTY3EE6.js → chunk-FLVRMRHX.js} +1 -1
- package/dist/{chunk-PUINOFOR.js → chunk-FPNV5L3Y.js} +3 -3
- package/dist/{chunk-ZEX5ZF6C.js → chunk-HW2OSIB3.js} +1 -1
- package/dist/{chunk-SJG22DAK.js → chunk-IPNBHVGX.js} +30 -1
- package/dist/{chunk-ZRKOZQKP.js → chunk-ITZ52UYF.js} +4 -4
- package/dist/{chunk-WWZIKKHP.js → chunk-IUXE7EG3.js} +4 -4
- package/dist/{chunk-AGFQC2UO.js → chunk-JY3DXRXV.js} +8 -8
- package/dist/{chunk-DA27NBCS.js → chunk-KKFXZ3NV.js} +6 -6
- package/dist/{chunk-EHJYX57P.js → chunk-OQJIRLKN.js} +1 -1
- package/dist/{chunk-VVZOIFL4.js → chunk-RTALSPLK.js} +1 -1
- package/dist/{chunk-VE2GVNNS.js → chunk-RTZLAXTZ.js} +16 -5
- package/dist/{chunk-IVEV5L7P.js → chunk-TCIRO4GU.js} +1 -1
- package/dist/{chunk-SSSOO2GH.js → chunk-UFVGXPJB.js} +4 -4
- package/dist/cli.js +44 -42
- package/dist/{commit-GPQATPEA.js → commit-7ONX22OG.js} +25 -7
- package/dist/{config-QTEKLFZP.js → config-KNSNSKU7.js} +2 -2
- package/dist/{doctor-JNUZJC6Z.js → doctor-UYO4Z6VC.js} +7 -7
- package/dist/{evolve-N3S32P5I.js → evolve-KSA5W6F3.js} +6 -6
- package/dist/{feedback-log-UCNJ2GVT.js → feedback-log-BIIFYX6D.js} +4 -4
- package/dist/{gotchas-PDG2ZZFQ.js → gotchas-US2HUCK2.js} +6 -6
- package/dist/{hold-recheck-UNAILFN5.js → hold-recheck-NYW2AGYK.js} +5 -5
- package/dist/{init-3B4ZRGWY.js → init-PEKMQY7D.js} +1 -1
- package/dist/{lane-ETMPPVXP.js → lane-647Q33RO.js} +14 -14
- package/dist/{loop-summary-CODZMRUY.js → loop-summary-BRRJ6V2U.js} +5 -5
- package/dist/{metrics-ZR7BPATB.js → metrics-C3UUN5U5.js} +3 -3
- package/dist/{record-TSB22DIO.js → record-MBGID3SX.js} +4 -4
- package/dist/{remove-VJ7VBKTZ.js → remove-46IZDWJ7.js} +14 -14
- package/dist/{review-CGALGS5X.js → review-XBOUKZTN.js} +12 -12
- package/dist/{rules-QLUXNSCN.js → rules-JKR4DO6F.js} +7 -7
- package/dist/{state-6IIH7SW2.js → state-QVDADIXS.js} +3 -3
- package/dist/{status-2LPWVCHT.js → status-BJ4B6NKL.js} +5 -5
- package/dist/{update-CKGPHO5B.js → update-UXULNKWR.js} +1 -1
- package/dist/{verify-7NQ3DOFY.js → verify-7KWUZCN7.js} +9 -9
- package/dist/{version-check-5BX3SO7G.js → version-check-Y3KBDUQ2.js} +4 -4
- package/dist/{work-3YHL3P6U.js → work-T5S4FNFZ.js} +13 -13
- package/engine/skills/claude/awl-pipeline/SKILL.md +1 -0
- package/engine/skills/claude/awl-pipeline-exec/SKILL.md +7 -4
- package/engine/skills/claude/awl-pipeline-review/SKILL.md +6 -3
- package/engine/version.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,13 +1,32 @@
|
|
|
1
1
|
# agent-work-loop
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/agent-work-loop)
|
|
4
|
+
[](https://github.com/kh1012/agent-work-loop/actions/workflows/ci.yml)
|
|
5
|
+
[](https://github.com/kh1012/agent-work-loop/tags)
|
|
6
|
+
[](LICENSE)
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
`agent-work-loop`(명령어: `awl`)은 AI 에이전트가 같은 실패를 두 번 반복하지 않도록 돕는 도구입니다. 에이전트가 작업하며 남긴 기록, 검증 결과, 완료 조건, 규칙, 교훈, 막힘을 파일로 관리합니다.
|
|
6
9
|
|
|
7
10
|
**awl 자체는 판단하지 않습니다.** LLM을 호출하지 않고, 파일과 상태만 결정적으로 다룹니다. 무엇을 배우고 어떤 규칙을 세울지는 이미 설치된 에이전트(Claude Code, Codex)가 스킬로 판단합니다.
|
|
8
11
|
|
|
12
|
+
이 README는 **실용 문서**입니다. 설치부터 첫 루프까지, 손으로 따라 할 수 있는 순서만 다룹니다. "왜 이렇게 만들었는가"(하네스 개념, 게이트 위치, narrative 실증 사례)는 [`docs/presentation/storyline.md`](docs/presentation/storyline.md)에, 명령어 하나하나의 자세한 사용법은 [`docs/presentation/commands.md`](docs/presentation/commands.md)에 정리했습니다.
|
|
13
|
+
|
|
9
14
|
크로스 환경을 처음부터 전제로 합니다. macOS와 Windows, Claude Code와 Codex를 모두 지원하는 것을 목표로 합니다(Windows는 아직 macOS만큼 검증되지 않았습니다. [알려진 위험](docs/decisions.md)을 참고하세요).
|
|
10
15
|
|
|
16
|
+
## 목차
|
|
17
|
+
|
|
18
|
+
- [언제 쓰나](#언제-쓰나)
|
|
19
|
+
- [설치](#설치)
|
|
20
|
+
- [5분 시작](#5분-시작)
|
|
21
|
+
- [LLM과 함께 실제로 쓰는 시나리오](#llm과-함께-실제로-쓰는-시나리오)
|
|
22
|
+
- [명령어 요약](#명령어-요약)
|
|
23
|
+
- [설정(config): 검증 명령과 모노레포](#설정config-검증-명령과-모노레포)
|
|
24
|
+
- [무엇이 어디에 쌓이나](#무엇이-어디에-쌓이나)
|
|
25
|
+
- [워크아이템 병행](#워크아이템-병행)
|
|
26
|
+
- [오케스트레이션 파이프라인: 여러 레인을 나란히](#오케스트레이션-파이프라인-여러-레인을-나란히)
|
|
27
|
+
- [문제 해결](#문제-해결)
|
|
28
|
+
- [기여하기](#기여하기)
|
|
29
|
+
|
|
11
30
|
---
|
|
12
31
|
|
|
13
32
|
## 언제 쓰나
|
|
@@ -35,32 +54,26 @@ yarn global add agent-work-loop
|
|
|
35
54
|
|
|
36
55
|
> **pnpm 함정**: pnpm으로 전역 설치하면 `awl` 명령을 찾을 수 없다는 에러가 날 수 있습니다. pnpm의 전역 bin 디렉토리가 PATH에 없어서입니다. `pnpm setup`을 한 번 실행하고 터미널을 새로 열면 해결됩니다.
|
|
37
56
|
|
|
38
|
-
|
|
39
|
-
> ```bash
|
|
40
|
-
> git clone <이 저장소> && cd agent-work-loop
|
|
41
|
-
> pnpm install && pnpm run build
|
|
42
|
-
> pnpm link --global # 또는: npm link
|
|
43
|
-
> ```
|
|
44
|
-
> `dist/cli.js`가 `awl` bin으로 등록됩니다. 정식 npm 배포가 되면 이 문단은 지웁니다.
|
|
57
|
+
저장소를 직접 빌드해서 쓰고 싶다면(기여하거나 배포 전 최신 상태를 바로 써보고 싶을 때):
|
|
45
58
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
1. npm i -g agent-work-loop@latest npm에 배포된 최신 버전을 받습니다
|
|
51
|
-
2. awl update 설치된 패키지로 전역 엔진(~/.awl/engine)을 갱신합니다
|
|
59
|
+
```bash
|
|
60
|
+
git clone https://github.com/kh1012/agent-work-loop.git && cd agent-work-loop
|
|
61
|
+
pnpm install && pnpm run build
|
|
62
|
+
pnpm link --global # 또는: npm link
|
|
52
63
|
```
|
|
53
64
|
|
|
54
|
-
|
|
65
|
+
`dist/cli.js`가 `awl` bin으로 등록됩니다.
|
|
55
66
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
67
|
+
### 업데이트 하기
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
1. npm i -g agent-work-loop@latest npm에 배포된 최신 버전을 받습니다
|
|
71
|
+
2. awl update 설치된 패키지로 전역 엔진(~/.awl/engine)을 갱신합니다
|
|
59
72
|
```
|
|
60
73
|
|
|
61
|
-
`awl update`(옵션 없음)는 `awl update --global`과 같습니다. 전역 엔진만 갱신하고 어떤 프로젝트도 건드리지 않습니다. 대부분은 이 두 줄이면 끝입니다.
|
|
74
|
+
pnpm이나 yarn을 쓴다면 1번만 그 도구로 바꿉니다. `awl update`(옵션 없음)는 `awl update --global`과 같습니다. 전역 엔진만 갱신하고 어떤 프로젝트도 건드리지 않습니다. 대부분은 이 두 줄이면 끝입니다.
|
|
62
75
|
|
|
63
|
-
**여러 프로젝트를 관리하는 입장이라면** 등록된 프로젝트들의 로컬 스킬(`.claude/skills`, `AGENTS.md`, `.awl/config.json`)까지 한 번에 맞추고 싶을 수
|
|
76
|
+
**여러 프로젝트를 관리하는 입장이라면** 등록된 프로젝트들의 로컬 스킬(`.claude/skills`, `AGENTS.md`, `.awl/config.json`)까지 한 번에 맞추고 싶을 수 있습니다.
|
|
64
77
|
|
|
65
78
|
```bash
|
|
66
79
|
npm i -g agent-work-loop@latest
|
|
@@ -71,12 +84,12 @@ awl update --all
|
|
|
71
84
|
|
|
72
85
|
이렇게 갱신한 프로젝트를 커밋해서 push하면, 그 저장소를 쓰는 다른 사람들은 다음에 pull할 때 최신 스킬을 받습니다. **다만 자동으로 알림이 가는 구조는 아닙니다.** 각자 컴퓨터의 `~/.awl/engine`이 낡았는지는 그 사람이 `awl doctor`/`awl version-check`를 실행하거나 `/awl-loop`·`/awl-pipeline`을 실행할 때(버전 확인이 맨 처음 단계로 들어있습니다) 노란 경고로 보게 됩니다.
|
|
73
86
|
|
|
74
|
-
설치가 됐는지
|
|
87
|
+
설치가 됐는지 확인합니다.
|
|
75
88
|
|
|
76
89
|
```bash
|
|
77
90
|
$ awl doctor
|
|
78
91
|
|
|
79
|
-
|
|
92
|
+
+ Agent Work Loop · 진단
|
|
80
93
|
| 환경
|
|
81
94
|
| |-- Node: v22.22.2 [ok]
|
|
82
95
|
| |-- 플랫폼: darwin arm64 [ok]
|
|
@@ -92,10 +105,10 @@ $ awl doctor
|
|
|
92
105
|
|
|
|
93
106
|
| 에이전트
|
|
94
107
|
| |-- Claude Code: 없음
|
|
95
|
-
|
|
|
108
|
+
| `-- Codex: 없음
|
|
96
109
|
|
|
|
97
110
|
| [x] 문제 2개. awl init 을 실행하세요.
|
|
98
|
-
|
|
111
|
+
+
|
|
99
112
|
```
|
|
100
113
|
|
|
101
114
|
터미널이 유니코드/색을 지원하면(Windows Terminal, VS Code 터미널 등) 자동으로 감지해 상자 그림과 색을 씁니다. 지원 안 되면 위처럼 ASCII로 자동 전환됩니다. `doctor`는 아무것도 고치지 않습니다. 점검만 합니다.
|
|
@@ -111,22 +124,26 @@ $ cd my-project
|
|
|
111
124
|
$ awl init
|
|
112
125
|
```
|
|
113
126
|
|
|
114
|
-
질문 없이 감지된 값으로 바로 진행하려면 `awl init --yes`를 씁니다. 실제
|
|
127
|
+
질문 없이 감지된 값으로 바로 진행하려면 `awl init --yes`를 씁니다. 실제 출력:
|
|
115
128
|
|
|
116
129
|
```
|
|
117
|
-
|
|
118
|
-
|
|
|
119
|
-
| ~/.awl
|
|
120
|
-
|
|
|
121
|
-
| .awl/
|
|
122
|
-
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
|
128
|
-
|
|
|
129
|
-
|
|
130
|
+
+ 설정 완료
|
|
131
|
+
| [v0.6.46]
|
|
132
|
+
| ~/.awl 생성됨
|
|
133
|
+
| ~/.awl/engine 0.6.46
|
|
134
|
+
| .awl/config.json 생성됨 <- 커밋하세요. 팀원은 이 파일을 씁니다
|
|
135
|
+
| .awl/state.json gitignore 에 추가함 [ok] git push 차단 훅 설치
|
|
136
|
+
| 규칙 0개 · 교훈 0개 · 등록된 프로젝트 1개 · 1세대
|
|
137
|
+
+
|
|
138
|
+
|
|
139
|
+
+ 다음 단계
|
|
140
|
+
| Claude Code 를 열고 이렇게 말하세요.
|
|
141
|
+
|
|
|
142
|
+
| /awl-loop 페이지 편집기에 여백 시스템을 넣고 싶어
|
|
143
|
+
|
|
|
144
|
+
| /awl-pipeline <레인명> --gl 을 실행해보세요.
|
|
145
|
+
| (격리된 작업 세션이 생성되며, 자율 모드로 실행됩니다.)
|
|
146
|
+
+
|
|
130
147
|
```
|
|
131
148
|
|
|
132
149
|
대화형 모드(`--yes` 없이)는 3단계 화면(1/3 주 언어 → 2/3 검증 명령어 → 3/3 규칙과 이 프로젝트의 성격)을 방향키(또는 번호)로 물은 뒤, 설치할 에이전트를 고르는 스킬 화면을 보여줍니다.
|
|
@@ -150,6 +167,13 @@ $ awl init
|
|
|
150
167
|
awl status # 지금 어디까지 왔는지 한눈에
|
|
151
168
|
```
|
|
152
169
|
|
|
170
|
+
명령어 전체와 스킬(`/awl-loop`·`/awl-pipeline`) 부연설명은 CLI 안에서도 바로 볼 수 있습니다.
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
awl --examples # 자주 쓰는 명령 예시
|
|
174
|
+
awl --skills # /awl-loop·/awl-pipeline·레인·게이트 밀도(<mode>) 설명
|
|
175
|
+
```
|
|
176
|
+
|
|
153
177
|
---
|
|
154
178
|
|
|
155
179
|
## LLM과 함께 실제로 쓰는 시나리오
|
|
@@ -198,10 +222,10 @@ awl status # 지금 어디까지 왔는지 한눈에
|
|
|
198
222
|
```bash
|
|
199
223
|
awl records --json # 있었던 일 전수(타입·워크아이템으로 필터 가능)
|
|
200
224
|
awl gotchas # 아직 규칙 안 된 교훈
|
|
201
|
-
awl rules
|
|
202
|
-
awl metrics --compare
|
|
203
|
-
awl brief
|
|
204
|
-
awl defer-summary
|
|
225
|
+
awl rules # 이 프로젝트에 적용되는 규칙
|
|
226
|
+
awl metrics --compare # 워크아이템 세대별 지표 추세
|
|
227
|
+
awl brief # 오늘(KST) 진행분만 모아 보기
|
|
228
|
+
awl defer-summary # gate-medium/gate-low에서 보류된 중요 항목 최종 확인
|
|
205
229
|
```
|
|
206
230
|
|
|
207
231
|
`~/.awl`을 직접 열어보면 이렇게 생겼습니다.
|
|
@@ -223,7 +247,7 @@ awl defer-summary # gate-medium/gate-low에서 보류된 중요 항목 최
|
|
|
223
247
|
|
|
224
248
|
## 명령어 요약
|
|
225
249
|
|
|
226
|
-
자주 쓰는 것만 적습니다.
|
|
250
|
+
자주 쓰는 것만 적습니다. 전체 명령과 실제 실행 예시는 [`commands.md`](docs/presentation/commands.md)에, `awl --examples`로도 바로 볼 수 있습니다.
|
|
227
251
|
|
|
228
252
|
```bash
|
|
229
253
|
awl status # 지금 어디까지 왔는지
|
|
@@ -245,7 +269,7 @@ awl feedback-log # awl 도구 자체에 남겨진 피드백 기록 검토
|
|
|
245
269
|
```json
|
|
246
270
|
{
|
|
247
271
|
"project": "my-project",
|
|
248
|
-
"mainLanguage": "typescript",
|
|
272
|
+
"mainLanguage": ["typescript"],
|
|
249
273
|
"character": "디자인 토큰 강제, 여백은 자유 px 금지",
|
|
250
274
|
"verify": {
|
|
251
275
|
"typecheck": { "cmd": "tsc --noEmit" },
|
|
@@ -286,11 +310,11 @@ $ awl config set verify.typecheck.cwd packages/app
|
|
|
286
310
|
|---|---|---|
|
|
287
311
|
| 담는 것 | 엔진(스킬 템플릿), 규칙, 교훈(gotcha), 기록(records), 등록된 프로젝트 목록 | 이 프로젝트의 설정(config.json), 지금 루프 위치(state.json) |
|
|
288
312
|
| 누구 것인가 | **당신**. 프로젝트를 옮겨 다녀도 따라옵니다 | **이 프로젝트**. 리포지토리를 나가면 안 따라옵니다 |
|
|
289
|
-
| git 커밋 | 대상 아님(홈 디렉토리) | `
|
|
313
|
+
| git 커밋 | 대상 아님(홈 디렉토리) | 프로젝트마다 다름 — `state.json`은 항상 gitignore, `config.json`은 팀 컨벤션에 따라 커밋하거나 로컬 전용으로 gitignore할 수 있습니다 |
|
|
290
314
|
|
|
291
315
|
두 층으로 나눈 이유(다음 프로젝트에서 빈손으로 시작하지 않기 위해)와 규칙/교훈이 어떻게 승격되는지는 [`storyline.md` 4절·5절](docs/presentation/storyline.md)에서 다룹니다. `AWL_HOME` 환경변수로 전역 위치를 바꿀 수 있습니다(테스트·CI에서 유용합니다).
|
|
292
316
|
|
|
293
|
-
규칙 승격은 사람이 직접 합니다(자동 승격 없음)
|
|
317
|
+
규칙 승격은 사람이 직접 합니다(자동 승격 없음).
|
|
294
318
|
|
|
295
319
|
```bash
|
|
296
320
|
awl rules promote G-003 \
|
|
@@ -298,7 +322,7 @@ awl rules promote G-003 \
|
|
|
298
322
|
--counter "이미 디자인 토큰 시스템이 없는 프로젝트"
|
|
299
323
|
```
|
|
300
324
|
|
|
301
|
-
교훈(gotcha, `~/.awl/gotchas`)과 awl 도구 자체 피드백(`~/.awl/records`, `awl record awl-feedback`)은 다른 종류입니다. 전자는 작업 대상 코드에 대한 것이고, 후자는 "awl commit이 이래서 아팠다" 같은 도구 자체의 문제입니다.
|
|
325
|
+
교훈(gotcha, `~/.awl/gotchas`)과 awl 도구 자체 피드백(`~/.awl/records`, `awl record awl-feedback`)은 다른 종류입니다. 전자는 작업 대상 코드에 대한 것이고, 후자는 "awl commit이 이래서 아팠다" 같은 도구 자체의 문제입니다. `awl feedback-log`로 모아 봅니다.
|
|
302
326
|
|
|
303
327
|
---
|
|
304
328
|
|
|
@@ -335,9 +359,6 @@ awl work switch <ID> # 보관된 워크아이템으로 전환
|
|
|
335
359
|
**`awl: command not found` (pnpm 설치 후)**
|
|
336
360
|
`pnpm setup`을 실행하고 터미널을 새로 엽니다. pnpm 전역 bin이 PATH에 없어서입니다.
|
|
337
361
|
|
|
338
|
-
**`npm install -g agent-work-loop`를 했는데 `awl`이 아무것도 못 한다**
|
|
339
|
-
위 설치 섹션을 참고하세요. 아직 npm에 `0.0.0` placeholder만 배포돼 있습니다. 저장소를 클론해 `pnpm install && pnpm run build && pnpm link --global`로 설치하세요.
|
|
340
|
-
|
|
341
362
|
**`awl --version`이 엔진 버전 불일치를 경고한다**
|
|
342
363
|
`awl`을 업그레이드했는데 `~/.awl/engine`은 예전 버전 그대로일 때 나옵니다. `awl update`로 엔진을 갱신하면 맞춰집니다(프로젝트 설정은 안 건드립니다). `awl version-check`로 어긋난 버전 쌍(package.json, 설치된 엔진, 프로젝트 config, 설치된 스킬)을 직접 봅니다. 프로젝트 config가 엔진보다 낡았다면 `awl init --yes`를 다시 실행합니다.
|
|
343
364
|
|
|
@@ -357,10 +378,7 @@ awl work switch <ID> # 보관된 워크아이템으로 전환
|
|
|
357
378
|
`awl init`이 심는 pre-push 훅 때문입니다(위 5분 시작 참고). 실제 터미널에서 사람이 직접 치는 push는 막히지 않습니다 — 막혔다면 비대화형(에이전트, CI, 스크립트)으로 실행된 경우이고, 그때는 `AWL_ALLOW_PUSH=1 git push`를 씁니다.
|
|
358
379
|
|
|
359
380
|
**대형 저장소에서 `awl lane new`/`awl work new --worktree`가 `Could not write new index file`로 실패한다**
|
|
360
|
-
`git worktree add`가 기본 180초 안에 못 끝나 강제 종료됐다는 뜻입니다(대형 모노레포는
|
|
361
|
-
체크아웃이 오래 걸립니다) — 디스크 문제가 아닙니다. `AWL_GIT_WORKTREE_TIMEOUT_MS=<ms>`
|
|
362
|
-
환경변수로 값을 늘려 다시 시도하세요(예: `AWL_GIT_WORKTREE_TIMEOUT_MS=300000 awl lane new
|
|
363
|
-
<이름>`).
|
|
381
|
+
`git worktree add`가 기본 180초 안에 못 끝나 강제 종료됐다는 뜻입니다(대형 모노레포는 체크아웃이 오래 걸립니다) — 디스크 문제가 아닙니다. `AWL_GIT_WORKTREE_TIMEOUT_MS=<ms>` 환경변수로 값을 늘려 다시 시도하세요(예: `AWL_GIT_WORKTREE_TIMEOUT_MS=300000 awl lane new <이름>`).
|
|
364
382
|
|
|
365
383
|
**게이트에서 스킬이 안 멈추고 그냥 진행한다**
|
|
366
384
|
스킬 문서가 게이트에서 반드시 도구를 호출하도록 지시돼 있습니다. 계속 안 멈추면 스킬이 최신인지 확인하세요. `awl doctor`가 `claude-skill-vs-engine` 불일치를 경고하면 `awl init --yes`로 재설치합니다.
|
|
@@ -370,7 +388,7 @@ awl work switch <ID> # 보관된 워크아이템으로 전환
|
|
|
370
388
|
|
|
371
389
|
---
|
|
372
390
|
|
|
373
|
-
##
|
|
391
|
+
## 기여하기
|
|
374
392
|
|
|
375
393
|
이 저장소는 pnpm을 사용합니다.
|
|
376
394
|
|
|
@@ -382,8 +400,10 @@ pnpm run lint # biome 검사
|
|
|
382
400
|
pnpm run typecheck
|
|
383
401
|
```
|
|
384
402
|
|
|
403
|
+
PR을 올리면 [GitHub Actions](.github/workflows/ci.yml)가 Node 18/22 두 버전에서 typecheck·lint·test·build를 자동으로 돌립니다.
|
|
404
|
+
|
|
385
405
|
릴리스는 `pnpm release:patch` / `pnpm release:minor` / `pnpm release:major`로 합니다. 검증·빌드·tarball·`npm publish --dry-run`을 통과한 뒤 버전, CHANGELOG, 커밋, 태그, 원격 push를 한 번에 처리합니다. **`npm publish`만 사람이 실행합니다.**
|
|
386
406
|
|
|
387
407
|
npm에 `awl` 패키지가 이미 있어, 패키지 이름은 `agent-work-loop`로 배포하고 명령어 이름만 `awl`로 씁니다.
|
|
388
408
|
|
|
389
|
-
라이선스는 MIT입니다.
|
|
409
|
+
라이선스는 [MIT](LICENSE)입니다.
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadProjectName,
|
|
3
3
|
readRecords
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-2NETKDCV.js";
|
|
5
5
|
import {
|
|
6
6
|
loadState
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-RTZLAXTZ.js";
|
|
8
8
|
import {
|
|
9
9
|
resolveProjectRoot,
|
|
10
10
|
run
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import "./chunk-
|
|
11
|
+
} from "./chunk-FLVRMRHX.js";
|
|
12
|
+
import "./chunk-IPNBHVGX.js";
|
|
13
13
|
import "./chunk-FGHILN3D.js";
|
|
14
14
|
|
|
15
15
|
// src/commands/brief.ts
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
readRecords
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2NETKDCV.js";
|
|
4
4
|
import {
|
|
5
5
|
loadState
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-RTZLAXTZ.js";
|
|
7
7
|
import {
|
|
8
8
|
resolveProjectRoot
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-FLVRMRHX.js";
|
|
10
|
+
import "./chunk-IPNBHVGX.js";
|
|
11
11
|
import {
|
|
12
12
|
caps,
|
|
13
13
|
signal
|
|
@@ -2,11 +2,11 @@ import {
|
|
|
2
2
|
getCriterion,
|
|
3
3
|
loadState,
|
|
4
4
|
writeState
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-RTZLAXTZ.js";
|
|
6
6
|
import {
|
|
7
7
|
resolveProjectRoot,
|
|
8
8
|
run
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-FLVRMRHX.js";
|
|
10
10
|
import {
|
|
11
11
|
caps,
|
|
12
12
|
makeColors,
|
|
@@ -3,14 +3,14 @@ import {
|
|
|
3
3
|
getLatestVersionCached,
|
|
4
4
|
name,
|
|
5
5
|
version
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-HW2OSIB3.js";
|
|
7
7
|
import {
|
|
8
8
|
resolveProjectRoot
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-FLVRMRHX.js";
|
|
10
10
|
import {
|
|
11
11
|
packageEngineDir,
|
|
12
12
|
skillsVersionPath
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-IPNBHVGX.js";
|
|
14
14
|
import {
|
|
15
15
|
caps,
|
|
16
16
|
installedEngineVersion,
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
readRecords
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2NETKDCV.js";
|
|
4
4
|
import {
|
|
5
5
|
loadState
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-RTZLAXTZ.js";
|
|
7
7
|
import {
|
|
8
8
|
multiProjectFooter,
|
|
9
9
|
resolveProjectScope,
|
|
10
10
|
run
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-FLVRMRHX.js";
|
|
12
12
|
import {
|
|
13
13
|
WORKTREES_DIR,
|
|
14
14
|
caps,
|
|
@@ -531,9 +531,38 @@ function ensureGitignore(projectRoot) {
|
|
|
531
531
|
fs.writeFileSync(gi, content);
|
|
532
532
|
return "added";
|
|
533
533
|
}
|
|
534
|
+
function safetyHookPath(projectRoot) {
|
|
535
|
+
const dotGit = path.join(projectRoot, ".git");
|
|
536
|
+
const dotGitStat = fs.statSync(dotGit);
|
|
537
|
+
if (dotGitStat.isDirectory()) {
|
|
538
|
+
return path.join(dotGit, "hooks", "pre-push");
|
|
539
|
+
}
|
|
540
|
+
if (!dotGitStat.isFile()) {
|
|
541
|
+
throw new Error(`${dotGit} is neither a directory nor a gitdir file`);
|
|
542
|
+
}
|
|
543
|
+
const gitdirMatch = fs.readFileSync(dotGit, "utf8").match(/^gitdir:\s*(.+?)\s*$/m);
|
|
544
|
+
if (!gitdirMatch) {
|
|
545
|
+
throw new Error(`${dotGit} does not contain a gitdir: line`);
|
|
546
|
+
}
|
|
547
|
+
const gitdir = gitdirMatch[1];
|
|
548
|
+
if (!gitdir) {
|
|
549
|
+
throw new Error(`${dotGit} has an empty gitdir: line`);
|
|
550
|
+
}
|
|
551
|
+
const worktreeGitDir = path.resolve(path.dirname(dotGit), gitdir);
|
|
552
|
+
const commonDirFile = path.join(worktreeGitDir, "commondir");
|
|
553
|
+
let commonGitDir = worktreeGitDir;
|
|
554
|
+
if (exists(commonDirFile)) {
|
|
555
|
+
const commonDir = fs.readFileSync(commonDirFile, "utf8").trim();
|
|
556
|
+
if (commonDir === "") {
|
|
557
|
+
throw new Error(`${commonDirFile} is empty`);
|
|
558
|
+
}
|
|
559
|
+
commonGitDir = path.resolve(worktreeGitDir, commonDir);
|
|
560
|
+
}
|
|
561
|
+
return path.join(commonGitDir, "hooks", "pre-push");
|
|
562
|
+
}
|
|
534
563
|
function installSafetyHook(projectRoot) {
|
|
535
564
|
try {
|
|
536
|
-
const hook =
|
|
565
|
+
const hook = safetyHookPath(projectRoot);
|
|
537
566
|
if (exists(hook))
|
|
538
567
|
return { installed: false, warning: "\uAE30\uC874 pre-push \uD6C5\uC774 \uC788\uC5B4 awl \uD6C5\uC744 \uB36E\uC5B4\uC4F0\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4." };
|
|
539
568
|
const template = path.join(packageEngineDir(), "templates", "pre-push.sample");
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
computeDurationMs
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-TCIRO4GU.js";
|
|
4
4
|
import {
|
|
5
5
|
computeCoverage,
|
|
6
6
|
readRecords
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-2NETKDCV.js";
|
|
8
8
|
import {
|
|
9
9
|
loadState
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-RTZLAXTZ.js";
|
|
11
11
|
import {
|
|
12
12
|
requireConfig
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-FLVRMRHX.js";
|
|
14
14
|
import {
|
|
15
15
|
caps,
|
|
16
16
|
generationsDir,
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import {
|
|
2
2
|
protectedFilesMessage
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-RTALSPLK.js";
|
|
4
4
|
import {
|
|
5
5
|
gitDirtyFiles
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-KKFXZ3NV.js";
|
|
7
7
|
import {
|
|
8
8
|
applyVerificationAttempts,
|
|
9
9
|
loadState,
|
|
10
10
|
writeState
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-RTZLAXTZ.js";
|
|
12
12
|
import {
|
|
13
13
|
CommandNotFoundError,
|
|
14
14
|
VERIFY_ORDER,
|
|
15
15
|
requireConfig,
|
|
16
16
|
run
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-FLVRMRHX.js";
|
|
18
18
|
import {
|
|
19
19
|
caps,
|
|
20
20
|
makeColors,
|
|
@@ -4,37 +4,37 @@ import {
|
|
|
4
4
|
} from "./chunk-D5OINC3G.js";
|
|
5
5
|
import {
|
|
6
6
|
parseRuleFile
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-OQJIRLKN.js";
|
|
8
8
|
import {
|
|
9
9
|
nextGotchaId
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-ITZ52UYF.js";
|
|
11
11
|
import {
|
|
12
12
|
buildVerifyBaseline,
|
|
13
13
|
isCheckPassed,
|
|
14
14
|
runVerifyChecks,
|
|
15
15
|
writeVerifyBaseline
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-IUXE7EG3.js";
|
|
17
17
|
import {
|
|
18
18
|
gitBranch
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-KKFXZ3NV.js";
|
|
20
20
|
import {
|
|
21
21
|
loadProjectName
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-2NETKDCV.js";
|
|
23
23
|
import {
|
|
24
24
|
loadState,
|
|
25
25
|
migrateState,
|
|
26
26
|
writeState
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-RTZLAXTZ.js";
|
|
28
28
|
import {
|
|
29
29
|
loadConfig,
|
|
30
30
|
multiProjectFooter,
|
|
31
31
|
resolveProjectRoot,
|
|
32
32
|
resolveProjectScope,
|
|
33
33
|
run
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-FLVRMRHX.js";
|
|
35
35
|
import {
|
|
36
36
|
installClaudeSkill
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-IPNBHVGX.js";
|
|
38
38
|
import {
|
|
39
39
|
caps,
|
|
40
40
|
feedback,
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadProjectName,
|
|
3
3
|
readRecords
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-2NETKDCV.js";
|
|
5
5
|
import {
|
|
6
6
|
loadState,
|
|
7
7
|
readStateLock
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-RTZLAXTZ.js";
|
|
9
9
|
import {
|
|
10
10
|
gatherVersionInputs
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-AVIUMBJZ.js";
|
|
12
12
|
import {
|
|
13
13
|
checkVersions
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-HW2OSIB3.js";
|
|
15
15
|
import {
|
|
16
16
|
CommandNotFoundError,
|
|
17
17
|
run,
|
|
18
18
|
tokenize
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-FLVRMRHX.js";
|
|
20
20
|
import {
|
|
21
21
|
listRegisteredProjects
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-IPNBHVGX.js";
|
|
23
23
|
import {
|
|
24
24
|
caps,
|
|
25
25
|
clipToWidth,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
resolveProjectRoot
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-FLVRMRHX.js";
|
|
4
4
|
import {
|
|
5
5
|
caps,
|
|
6
6
|
makeColors,
|
|
@@ -232,13 +232,16 @@ function runStateSet(jsonPatch, opts = {}) {
|
|
|
232
232
|
process.exit(1);
|
|
233
233
|
}
|
|
234
234
|
let gateRejected = false;
|
|
235
|
+
let workitemRejected = false;
|
|
236
|
+
let activeWorkitem;
|
|
235
237
|
try {
|
|
236
238
|
const current = loadState(root);
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
239
|
+
activeWorkitem = typeof current.workitem === "string" ? current.workitem : void 0;
|
|
240
|
+
workitemRejected = opts.workitem !== void 0 && activeWorkitem !== opts.workitem;
|
|
241
|
+
if (!workitemRejected && p.phase === "loop" && opts.requireGateForLoop) {
|
|
242
|
+
gateRejected = !opts.requireGateForLoop(activeWorkitem);
|
|
240
243
|
}
|
|
241
|
-
if (!gateRejected) {
|
|
244
|
+
if (!workitemRejected && !gateRejected) {
|
|
242
245
|
const merged = mergeState(current, p);
|
|
243
246
|
writeState(root, merged);
|
|
244
247
|
process.stdout.write(`${JSON.stringify(merged, null, 2)}
|
|
@@ -247,6 +250,14 @@ function runStateSet(jsonPatch, opts = {}) {
|
|
|
247
250
|
} finally {
|
|
248
251
|
releaseStateLock(root, token);
|
|
249
252
|
}
|
|
253
|
+
if (workitemRejected) {
|
|
254
|
+
process.stderr.write(
|
|
255
|
+
`
|
|
256
|
+
\uD65C\uC131 \uC6CC\uD06C\uC544\uC774\uD15C\uC774 ${activeWorkitem ?? "(\uC5C6\uC74C)"}\uC73C\uB85C \uBC14\uB00C\uC5B4 \uC788\uC5B4 ${opts.workitem} \uB300\uC0C1 \uAC31\uC2E0\uC744 \uAC70\uBD80\uD588\uC2B5\uB2C8\uB2E4.
|
|
257
|
+
`
|
|
258
|
+
);
|
|
259
|
+
process.exit(1);
|
|
260
|
+
}
|
|
250
261
|
if (gateRejected) {
|
|
251
262
|
process.stderr.write(
|
|
252
263
|
"\n \uAC8C\uC774\uD2B8 1 \uC2B9\uC778 \uAE30\uB85D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. awl record gate \uB85C \uACC4\uD68D\uC744 \uC2B9\uC778(approved)\uD55C \uB4A4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694.\n"
|
|
@@ -5,18 +5,18 @@ import {
|
|
|
5
5
|
runWorkNew,
|
|
6
6
|
sanitizeForGit,
|
|
7
7
|
worktreeDirtyTracked
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-JY3DXRXV.js";
|
|
9
9
|
import {
|
|
10
10
|
loadProjectName
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-2NETKDCV.js";
|
|
12
12
|
import {
|
|
13
13
|
loadState,
|
|
14
14
|
writeState
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-RTZLAXTZ.js";
|
|
16
16
|
import {
|
|
17
17
|
resolveProjectRoot,
|
|
18
18
|
run
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-FLVRMRHX.js";
|
|
20
20
|
import {
|
|
21
21
|
WORKTREES_DIR,
|
|
22
22
|
caps,
|