@ccdd/core 2.0.1
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 +301 -0
- package/dist/src/definitions.d.ts +53 -0
- package/dist/src/definitions.js +2 -0
- package/dist/src/definitions.js.map +1 -0
- package/dist/src/sdk.d.ts +9 -0
- package/dist/src/sdk.js +3 -0
- package/dist/src/sdk.js.map +1 -0
- package/dist/src/tools/contracts.d.ts +108 -0
- package/dist/src/tools/contracts.js +2 -0
- package/dist/src/tools/contracts.js.map +1 -0
- package/examples/artifact-groups/README.md +67 -0
- package/examples/artifact-groups/ccdd.config.ts +37 -0
- package/examples/artifact-groups/effect.md +12 -0
- package/examples/artifact-groups/preview.png +0 -0
- package/examples/custom-text-reader/README.md +25 -0
- package/examples/custom-text-reader/ccdd.config.ts +64 -0
- package/examples/custom-text-reader/spec.md +4 -0
- package/examples/custom-text-reader/why.md +3 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
# CCDD
|
|
2
|
+
|
|
3
|
+
**CCDD는 Artifact·Critic·관계와 도구를 정의합니다. 프로젝트 검증과 실행 이력은 별도 Project 패키지가 담당합니다.**
|
|
4
|
+
|
|
5
|
+
| 패키지 | 책임 |
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| `@ccdd/core` | `defineConfig`, `defineTool`, Artifact·Critic·stale 전략 타입. 실행 의존성과 DB가 없습니다. |
|
|
8
|
+
| `@ccdd/project` | 현재 검증 조회, 필요한 검증 의뢰, 실제 판정 이력, Broker·실행기·모니터. |
|
|
9
|
+
| `@ccdd/default-tools` | 프로젝트가 선택하여 명시적으로 등록하는 관측 도구. |
|
|
10
|
+
|
|
11
|
+
## 시작하기
|
|
12
|
+
|
|
13
|
+
Node.js 24 이상이 필요합니다. 공개 npm 배포를 지원하며, 첫 게시가 완료된 버전부터 리뷰 대상 프로젝트에 다음과 같이 설치할 수 있습니다. npm 게시 절차와 버전 확인은 [배포 안내](docs/releases.md#npm-공개-배포)를 참고하세요.
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npm init -y
|
|
17
|
+
npm pkg set type=module
|
|
18
|
+
npm install --ignore-scripts @ccdd/core @ccdd/project @ccdd/default-tools
|
|
19
|
+
npx ccdd-project help
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
GitHub에 같은 버전의 Release가 게시된 경우 tarball로도 설치할 수 있습니다. 다음은 v2.0.1 게시 후의 설치 명령입니다. 다운로드에는 저장소 접근 권한이 있는 GitHub CLI 로그인이 필요합니다.
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
npm init -y
|
|
26
|
+
npm pkg set type=module
|
|
27
|
+
mkdir -p vendor/ccdd
|
|
28
|
+
gh release download v2.0.1 --repo lhj6102/ccdd --dir vendor/ccdd \
|
|
29
|
+
--pattern '*.tgz' --pattern SHA256SUMS --pattern verification.json
|
|
30
|
+
(cd vendor/ccdd && shasum -a 256 -c SHA256SUMS)
|
|
31
|
+
npm install --ignore-scripts \
|
|
32
|
+
./vendor/ccdd/ccdd-core-2.0.1.tgz \
|
|
33
|
+
./vendor/ccdd/ccdd-project-2.0.1.tgz \
|
|
34
|
+
./vendor/ccdd/ccdd-default-tools-2.0.1.tgz
|
|
35
|
+
npx ccdd-project help
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Linux에서는 `sha256sum -c SHA256SUMS`도 사용할 수 있습니다. v2.0.0까지의 `@lhj6102/ccdd*` 패키지에서는 import 이름도 변경해야 합니다. [v2.0.1 이전 안내](docs/releases/v2.0.1.md)를 참고하세요. 소스 저장소에서 개발할 때는 다음 명령을 사용합니다.
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
nvm use # nvm 사용 시 .nvmrc의 Node 24 선택
|
|
42
|
+
npm ci
|
|
43
|
+
npm run build
|
|
44
|
+
node dist/src/project/cli.js help
|
|
45
|
+
node dist/src/project/cli.js config check --repo /path/to/project
|
|
46
|
+
node dist/src/project/cli.js plan spec --recursive --repo /path/to/project
|
|
47
|
+
node dist/src/project/cli.js verify spec --recursive --wait --repo /path/to/project
|
|
48
|
+
node dist/src/project/cli.js status spec --repo /path/to/project
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
리뷰할 프로젝트에는 아래 예제처럼 `ccdd.config.ts`와 그 설정이 가리키는 파일을 둡니다. 설정이 import하는 core와 선택한 도구 라이브러리는 그 프로젝트에도 설치해야 합니다. 세 패키지를 설치하면 `npx ccdd-project`를 사용할 수 있습니다. 기본 도구 없이 custom 도구를 사용한다면 core와 Project를 설치합니다. 정의만 사용하는 프로젝트는 core만 설치할 수 있습니다.
|
|
52
|
+
|
|
53
|
+
`status`·`plan`은 현재 입력에 적용 가능한 실제 판정을 조회합니다. `verify`는 필요한 검증을 의뢰하며 기본 입력 정책은 copy입니다. `--recursive`가 없으면 선택한 Critic 중 실행 가능한 것부터 진행하고, 선행 검증이 필요한 항목은 미완료로 보고합니다. 검증 조회는 Provider나 리뷰 도구를 실행하지 않습니다. TS 설정의 평가는 명시적인 현재 입력 조회 시 일어납니다.
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
artifacts: {
|
|
57
|
+
why: { type: 'markdown', path: 'why.md', basis: true },
|
|
58
|
+
spec: { type: 'markdown', path: 'spec.md',
|
|
59
|
+
stale: { kind: 'file-hash', paths: ['spec.md', 'references'] } },
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
기본 동일성 기준은 Artifact 경로의 파일 내용 hash입니다. `paths`로 별도 입력 경로들을 선언하거나 `{ kind: 'always' }`로 요청마다 검증하게 할 수 있습니다. 설정한 경로들은 Artifact의 의미에 영향을 주는 입력을 빠짐없이 포함해야 합니다.
|
|
64
|
+
|
|
65
|
+
Why → Spec → Tests → Implementation에서 Why가 바뀌면 Spec의 검증 입력이 바뀝니다. Spec이 내용 수정 없이 다시 PASS하면 Tests의 target·직접 deps hash는 그대로이므로 이전 실제 PASS를 재사용합니다. 하위 노드에 stale 상태를 전파하거나 저장하지 않고 조회마다 DAG를 재귀적으로 평가합니다.
|
|
66
|
+
|
|
67
|
+
상태 저장 위치는 repo 밖의 `~/.local/state/ccdd/<repo 경로 식별자>/broker.sqlite`입니다. 실제 판정과 검증 당시 입력 hash, 실행·티켓 이력을 저장합니다. `--state-dir` 또는 `CCDD_STATE_HOME`으로 변경할 수 있습니다. [프로젝트 검증 명령과 저장 계약](docs/project-validation.md)에 전체 UX와 종료 코드를 설명합니다.
|
|
68
|
+
|
|
69
|
+
`ccdd-project monitor`의 **현재 입력**에서 명시적으로 입력을 확인하고, Kanban·Graph에서 실행과 실제 판정을 볼 수 있습니다. 자동 GET 갱신은 설정을 평가하거나 리뷰 상태를 변경하지 않습니다. Graph의 재사용 항목은 원래 리뷰 요청으로 연결됩니다.
|
|
70
|
+
|
|
71
|
+
기존 `ccdd` 명령도 Project 패키지에 호환용으로 포함합니다. 아래의 `ccdd run`, `status RUN_ID`, Human·진단 명령은 기존 실행 계약을 유지합니다. 새 pull 검증은 `ccdd-project verify`를 사용합니다. 소스 개발에서 기존 CLI는 `node dist/src/cli.js`입니다.
|
|
72
|
+
|
|
73
|
+
## Artifact 의존 관계
|
|
74
|
+
|
|
75
|
+
Critic 설정은 `target`(평가 대상 하나)과 `deps`(참조 Artifact 배열)를 사용합니다. 같은 Artifact의 필수 Critic이 모두 통과하면 다음 검토가 시작됩니다. `basis: true`로 명시한 기준 Artifact를 제외하고 검토 없는 입력을 자동 통과시키지 않습니다. 기존 `dependsOn`·Critic의 `artifacts` 설정은 [설정 변경 안내](docs/artifact-graph.md)를 따라 변경하세요.
|
|
76
|
+
|
|
77
|
+
모니터에서 **Kanban / Graph**를 선택할 수 있습니다. Graph는 선택한 검증 실행의 Artifact 관계와 Critic별 판정을 보여주며, 노드에서 기존 Human 요청 상세로 이어집니다. 과거에 역할 정보 없이 저장한 실행은 Kanban에서 계속 확인할 수 있습니다.
|
|
78
|
+
|
|
79
|
+
개별 Artifact를 ID로 참조하여 그룹으로 묶을 수도 있습니다.
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
artifacts: {
|
|
83
|
+
effect: { type: 'markdown', path: 'effect.md' },
|
|
84
|
+
preview: { type: 'image', path: 'preview.png' },
|
|
85
|
+
explosion: { kind: 'group', members: ['effect', 'preview'] },
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
그룹에는 타입·경로가 없으며 다른 그룹도 구성원으로 참조할 수 있습니다. `target`·`deps`·`basis`는 그룹에도 적용됩니다. 그룹 판정은 그 그룹을 평가하는 Critic만 집계하며 멤버 판정과 서로 전파하지 않습니다. 구성 관계는 실행 의존성이 아니므로, 이미지 평가 후 그룹을 검토하려면 그룹 Critic에 `deps: ['preview']`를 명시합니다. 관측 도구는 중복을 제거한 모든 leaf에 제공하고 기존 ID를 유지합니다. Agent는 각 leaf를 관측해야 합니다. 자세한 규칙은 [Artifact 그룹](docs/artifact-graph.md#artifact-그룹)을 참고하세요.
|
|
90
|
+
|
|
91
|
+
## Agent Provider와 인증
|
|
92
|
+
|
|
93
|
+
Agent profile은 Pi의 정확한 Provider·모델 ID와 reasoning을 명시합니다. 예:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{"kind":"agent","provider":"openai-codex","model":"gpt-6-astra","reasoning":"medium"}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`@earendil-works/pi-agent-core`와 `@earendil-works/pi-ai` 0.85.1을 라이브러리로 사용합니다. Provider 호출과 Agent 도구 루프는 Agent 실행기 내부의 Pi가 맡으며, CCDD가 판정 스키마·필수 Artifact 관측·workspace 무결성을 검증합니다. 기본 이미지 도구도 내부 CLI에서 Pi의 read를 재사용하지만 세션이나 Provider 호출은 만들지 않습니다. Broker·Human·Runtime은 Pi 세션을 사용하지 않습니다.
|
|
100
|
+
|
|
101
|
+
Provider API key 환경변수는 Pi의 Provider별 규칙을 따릅니다. 파일 인증은 명시적으로 연결합니다.
|
|
102
|
+
|
|
103
|
+
```sh
|
|
104
|
+
ccdd doctor --repo /path/to/project --pi-auth-file /outside/repo/pi-auth.json --json
|
|
105
|
+
ccdd run --repo /path/to/project --copy --pi-auth-file /outside/repo/pi-auth.json --wait
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Pi 파일 형식은 Provider ID별 credential 객체입니다. 예를 들어 API key는 `{"anthropic":{"type":"api_key","key":"..."}}`, OAuth는 `{"openai-codex":{"type":"oauth","access":"...","refresh":"...","expires":1234567890000}}` 형태입니다. 토큰은 해당 로그인 도구에서 발급받으며, repo와 리뷰 상태에 저장하지 않습니다.
|
|
109
|
+
|
|
110
|
+
기존 Codex 인증을 사용할 때도 경로를 직접 지정합니다.
|
|
111
|
+
|
|
112
|
+
```sh
|
|
113
|
+
ccdd doctor --repo /path/to/project --codex-auth-file "$HOME/.codex/auth.json" --json
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
이 연결은 유효한 access token만 읽으며 공유 refresh token을 Pi에 전달하거나 파일을 변경하지 않습니다. Pi 인증 파일도 현재는 읽기 전용으로 연결합니다. 만료됐거나 5분 안에 만료될 OAuth는 거부하며, 발급 도구에서 인증을 갱신한 뒤 다시 실행해야 합니다. 인증을 자동 승계하거나 로그인·갱신을 대신하지 않습니다.
|
|
117
|
+
|
|
118
|
+
환경변수 `CCDD_PI_AUTH_FILE`·`CCDD_CODEX_AUTH_FILE`로 경로를 지정할 수도 있습니다. worker에는 경로만 저장하고, Human 결과 제출이나 `resume`은 원래 실행 설정을 다시 사용합니다. Provider API key 환경변수는 실행·재개 프로세스에서 사용할 수 있어야 합니다.
|
|
119
|
+
|
|
120
|
+
미지원 Provider·모델·reasoning을 다른 설정으로 대체하지 않습니다. 기존 `provider: "codex"`는 Pi의 `openai-codex`로 명시적으로 바꿔야 합니다. Pi 0.85.1은 `openai`와 `openai-codex`의 `gpt-6-astra`를 지원합니다. Astra reasoning은 `low`·`medium`·`high`·`xhigh`·`max`를 그대로 적용하며, `off`·`minimal`·`ultra`는 거부합니다. 새 데모는 `openai-codex / gpt-6-astra / medium`을 명시합니다. 현재 지원 범위는 [Pi 공식 문서](https://github.com/earendil-works/pi/tree/main/packages/ai)를 참고하고, 실제 접근은 `doctor`로 확인하세요.
|
|
121
|
+
|
|
122
|
+
## 리뷰 입력 선택
|
|
123
|
+
|
|
124
|
+
`run`은 `--copy` 또는 `--lock` 중 하나를 명시해야 합니다. 두 옵션을 동시에 사용할 수 없습니다.
|
|
125
|
+
|
|
126
|
+
| 옵션 | 입력 | 수정 정책 |
|
|
127
|
+
| --- | --- | --- |
|
|
128
|
+
| `--copy` · 권장 | 현재 repo 전체의 복사본 | 복사가 끝나면 원본을 수정할 수 있습니다. |
|
|
129
|
+
| `--lock` | 현재 workspace 전체 | 리뷰 중 변경이 검출되면 `ERROR`로 실패합니다. |
|
|
130
|
+
|
|
131
|
+
커밋 여부와 ignore 규칙에 관계없이 모든 파일이 대상입니다. `.git`, 의존성 디렉터리, 새 파일도 포함합니다. 상대경로·내용·파일 유형·실행 권한으로 계산한 SHA-256이 같은 복사본은 동시에 여러 리뷰에서 재사용합니다. 판정은 매번 실행하며, 입력 공유가 판정 재사용을 의미하지 않습니다.
|
|
132
|
+
|
|
133
|
+
공유 복사본은 읽기 전용입니다. 테스트 출력은 `CCDD_OUTPUT_DIR`, 임시 파일은 `CCDD_TMP_DIR` 또는 `TMPDIR`에 작성합니다. CCDD의 상태·로그·복사본·리뷰 출력은 repo 밖에 저장합니다. 기본 경로는 `~/.local/state/ccdd/<repo 식별자>`이며, `--state-dir` 또는 `CCDD_STATE_HOME`으로 변경합니다.
|
|
134
|
+
|
|
135
|
+
`--lock`은 쓰기를 강제로 막는 기능이 아닙니다. 파일 이벤트와 메타데이터, 내용 검증으로 변경을 감시합니다. 감시할 수 없는 환경에서는 실행을 거부합니다. 원본을 수정한 후 내용을 되돌려도 변경으로 검출되면 실패합니다. 자세한 범위와 제한은 [workspace 계약](docs/contracts.md)을 참고하세요.
|
|
136
|
+
|
|
137
|
+
## Artifact 도구 설정
|
|
138
|
+
|
|
139
|
+
설정은 `ccdd.config.ts`입니다. 프로젝트 `package.json`의 `type`은 `module`로 지정합니다(`npm pkg set type=module`). 설정 객체 또는 객체를 반환하는 동기·비동기 함수를 default export합니다. `@ccdd/core`는 가벼운 `defineConfig`, `defineTool`과 도구 타입을 제공하고, `@ccdd/default-tools`는 선택적으로 설치하는 구현 라이브러리입니다. import하거나 factory를 호출하는 것만으로 파일을 읽거나 프로그램을 실행하지 않습니다.
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
import { defineConfig } from '@ccdd/core';
|
|
143
|
+
import { agent, human } from '@ccdd/default-tools';
|
|
144
|
+
|
|
145
|
+
export default defineConfig(() => ({
|
|
146
|
+
artifactTypes: {
|
|
147
|
+
markdown: {
|
|
148
|
+
agentTools: { read: agent.text.read() },
|
|
149
|
+
humanTools: { open: human.desktop.open() },
|
|
150
|
+
},
|
|
151
|
+
code: {
|
|
152
|
+
agentTools: { list: agent.files.list(), read: agent.files.read() },
|
|
153
|
+
humanTools: { open: human.desktop.open() },
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
artifacts: {
|
|
157
|
+
why: { type: 'markdown', path: 'why.md', basis: true },
|
|
158
|
+
spec: { type: 'markdown', path: 'spec.md' },
|
|
159
|
+
},
|
|
160
|
+
critics: [{
|
|
161
|
+
id: 'spec-why', title: 'Spec이 Why에 부합하는가', target: 'spec', deps: ['why'],
|
|
162
|
+
profile: { kind: 'agent', provider: 'openai-codex', model: 'gpt-6-astra', reasoning: 'medium' },
|
|
163
|
+
payload: { instruction: '{spec}이 {why}의 요구사항을 충족하는지 검토하세요.' },
|
|
164
|
+
}],
|
|
165
|
+
}));
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
기본 도구도 `agent.text.read()`처럼 명시적으로 등록합니다. 자동 등록, 빈 객체의 기본값, 필수 `viewer: text|files`는 TS 설정에 없습니다. `agentTools`와 `humanTools`를 비우거나 생략하면 해당 종류의 Critic은 그 Artifact를 사용할 수 없습니다. 평가 대상과 참조 모두 적용하며 Runtime은 별도 실행 계약입니다.
|
|
169
|
+
|
|
170
|
+
기본 Agent 도구는 패키지에 포함된 Node CLI를 호출합니다. `text.read()`는 단일 파일, `files.list()`·`files.read()`는 디렉터리용입니다. 이름은 `read_spec`, `list_tests`처럼 `<toolName>_<artifactName>`이며 설명의 `{artifactName}`도 실제 Artifact ID로 치환합니다. 읽기는 1번 줄부터 기본 80줄, 최대 500줄을 요청하고 `nextStartLine`으로 이어 읽습니다. 원래 UTF-8·LF/CRLF와 완전한 줄을 보존하며 응답은 64KiB로 제한합니다.
|
|
171
|
+
|
|
172
|
+
이미지 타입에는 `agentTools: { view_image: agent.image.view() }`를 등록합니다. `preview`에 연결하면 `view_image_preview`가 제공됩니다. 파일 Artifact에는 `{}`, 디렉터리에는 `{"path":"frames/preview.png"}`를 전달합니다. Pi read의 실제 이미지 결과만 사용하며 지원 범위는 PNG/JPEG/WebP, 최대 4MiB입니다. 텍스트·GIF·BMP·APNG는 실패하고 자동 축소·변환은 하지 않습니다. 이미지 읽기 자체는 모델을 호출하지 않으며, 그 결과를 리뷰하는 Agent 모델은 이미지 입력을 지원해야 합니다.
|
|
173
|
+
|
|
174
|
+
기본 Human 도구는 텍스트를 반환하지 않고 snapshot의 파일·폴더를 데스크톱 프로그램으로 엽니다. `human.desktop.open({ app: 'TextEdit' })`처럼 앱을 지정할 수 있습니다. 기본 OS 연결은 macOS이며 다른 OS에서는 `command`와 고정 `args`를 명시합니다. 프로그램 열기 성공은 사람의 검토나 판정 완료가 아닙니다.
|
|
175
|
+
|
|
176
|
+
사용자 도구는 `{ metadata, execute(context, args), preflight? }`를 직접 작성합니다. `metadata`에 설명·입력 JSON Schema·결과 종류·관측 방식을 선언하고, CCDD가 실제 snapshot Artifact와 출력·임시 경로·취소 신호를 연결합니다. 함수·SDK·CLI를 선택할 수 있으며 텍스트·JSON·이미지·프로그램 열기 결과를 지원합니다. 기본 도구 라이브러리 없이 작성하는 [사용자 Reader 예제](examples/custom-text-reader/README.md)와 정확한 [도구 계약](docs/contracts.md)을 참고하세요.
|
|
177
|
+
|
|
178
|
+
설정과 import한 구현은 repo 안에서 해석합니다. 필요한 패키지를 **리뷰 대상 프로젝트의 `node_modules`에 실제 설치**해야 하며 상위 repo·전역 설치로 fallback하지 않습니다. 함수는 기록에 저장하지 않고 도구 명세와 구현 식별 정보를 저장합니다. 실행·Human 재개 시 동일 snapshot의 구현과 대조합니다. TS 설정은 신뢰하는 repo 코드이며 OS sandbox는 아닙니다.
|
|
179
|
+
|
|
180
|
+
기존 `ccdd.config.json`의 `viewer`·`read/list`·Human 명령 설정은 이전을 위한 호환 경로로 계속 지원합니다. 과거 기록을 새 도구로 바꾸지 않으며, JSON과 TS 설정이 함께 있으면 충돌 오류입니다. 신규 예제는 TS와 명시적 등록을 사용합니다.
|
|
181
|
+
|
|
182
|
+
### 지시사항의 Artifact 참조
|
|
183
|
+
|
|
184
|
+
`payload.instruction`에서 `{spec}`처럼 요청 범위의 Artifact ID를 참조할 수 있습니다. 위 예제는 Agent 프롬프트에서 다음과 같이 펼쳐집니다.
|
|
185
|
+
|
|
186
|
+
```text
|
|
187
|
+
{"artifact":"spec","tools":["read_spec"]}이 {"artifact":"why","tools":["read_why"]}의 요구사항을 충족하는지 검토하세요.
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
`tools`에는 해당 Artifact에 실제로 제공된 Agent 도구 이름이 들어갑니다. custom 도구를 등록했다면 그 이름을 사용합니다. Human 요청에서는 참조를 버튼으로 표시하고 연결된 Human 도구의 선택 영역으로 이동합니다. 참조 버튼만 눌러서는 도구가 실행되지 않으며, claim 후 실행할 도구를 명시적으로 선택합니다.
|
|
191
|
+
|
|
192
|
+
그룹 참조 `{explosion}`은 `{"artifactGroup":"explosion","members":[{"artifact":"effect","tools":["read_effect"]},{"artifact":"preview","tools":["view_image_preview"]}]}`처럼 구성원의 실제 도구 목록으로 펼칩니다. Human 화면에서는 해당 멤버의 도구를 고르는 버튼으로 표시합니다.
|
|
193
|
+
|
|
194
|
+
설정·저장된 요청·HTTP 응답의 `instruction` 문자열은 원문을 유지합니다. 다른 payload 필드도 바꾸지 않습니다. JSON 객체처럼 중괄호로 묶인 구간, 중첩·이중 중괄호, `\{spec}`처럼 escape한 참조, 알 수 없거나 요청 범위 밖인 ID, `{spec.path}` 같은 표현식은 그대로 둡니다. instruction을 일반 JSON 문서로 해석하지 않으므로 그 구간 밖의 따옴표나 배열 안에서도 `{spec}`은 참조입니다. 문자 그대로 쓰려면 escape합니다. 참조는 파일 본문을 삽입하거나 접근 범위를 늘리지 않습니다. 도구 설명의 `{artifactName}`은 그 도구에 연결된 ID를 치환하는 별도 규칙이며, instruction에 같은 이름의 예약변수를 추가하지 않습니다.
|
|
195
|
+
|
|
196
|
+
## 실행과 기록
|
|
197
|
+
|
|
198
|
+
```sh
|
|
199
|
+
ccdd run --copy --critic tests-spec --wait --json
|
|
200
|
+
ccdd status RUN_ID --wait --json
|
|
201
|
+
ccdd list
|
|
202
|
+
ccdd request REQUEST_ID
|
|
203
|
+
ccdd cancel RUN_ID
|
|
204
|
+
ccdd status RUN_ID --state-dir /outside/repo/state
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
TS 요청의 Human Artifact 도구는 모니터에서 claim한 뒤 호출합니다. `tools check --execute`는 현재 프로젝트에서 새 진단 입력을 만들어 검사하며 기존 요청의 snapshot을 여는 명령이 아닙니다. `ccdd artifact REQUEST_ID spec`은 legacy JSON 요청의 수동 텍스트 조회에만 사용합니다.
|
|
208
|
+
|
|
209
|
+
원본 폴더가 삭제된 복사본 리뷰도 `--state-dir`만 지정하면 기록 조회와 Human 응답을 이어갈 수 있습니다.
|
|
210
|
+
|
|
211
|
+
각 Run은 독립된 실행 프로세스를 가집니다. 요청 CLI가 종료되거나 대기 시간이 초과돼도 실행 프로세스는 계속 작업합니다. `--wait`의 종료 코드는 `0=GREEN`, `1=RED`, `2=ERROR`, `3=대기 시간 초과`입니다. `--wait`를 생략한 종료 코드 0은 접수 성공입니다.
|
|
212
|
+
|
|
213
|
+
`--critic`은 선택한 Critic 하나만 독립적으로 평가합니다. 생략하면 Artifact 의존 그래프 전체를 실행합니다. 단독 GREEN은 선택한 기준의 통과이며 다른 필수 Critic의 통과를 뜻하지 않습니다. RED의 근거를 반영해 파일을 수정하고 새 요청을 보내면 됩니다. 새 commit은 필요하지 않습니다.
|
|
214
|
+
|
|
215
|
+
[Builder 사용법](docs/builder-workflow.md) · [요청 계약](docs/requester-contract.md)
|
|
216
|
+
|
|
217
|
+
## Human 리뷰
|
|
218
|
+
|
|
219
|
+
`--human-inbox`는 repo 밖의 `human-inbox.jsonl`을 명시적인 알림 수단으로 등록합니다. Human 실행에는 최소 하나의 알림 수단이 필요하며, 알림 전달 실패는 `ERROR`입니다.
|
|
220
|
+
|
|
221
|
+
```sh
|
|
222
|
+
ccdd run --copy --critic human-review --human-inbox
|
|
223
|
+
ccdd request REQUEST_ID
|
|
224
|
+
ccdd human-claim REQUEST_ID --reviewer reviewer-a
|
|
225
|
+
ccdd human-result REQUEST_ID --reviewer reviewer-a --result-file /outside/repo/result.json
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
결과 파일은 `{"verdict":"GREEN","summary":"검토 결과","evidence":["spec.md의 확인 근거"]}` 형식입니다. `--copy`는 알림이 전달되면 대기 상태를 저장하고 실행 프로세스를 종료할 수 있습니다. 이후 별도 명령으로 결과를 제출하면 필요한 후속 리뷰가 실행됩니다. `--lock`은 Human 대기 중에도 변경 감시 프로세스를 유지합니다.
|
|
229
|
+
|
|
230
|
+
모니터에서도 Human 카드를 열어 **리뷰 맡기 → 도구 실행 → 성공·실패 판정 제출**을 진행할 수 있습니다. Claim한 브라우저만 해당 도구와 제출 버튼을 사용할 수 있습니다. 판정에는 요약과 최소 하나의 근거가 필요합니다. 서버를 재시작해도 같은 브라우저에서 이어갈 수 있으며, 브라우저 쿠키를 삭제하면 해당 브라우저의 담당 식별자가 사라집니다.
|
|
231
|
+
|
|
232
|
+
## Artifact 도구 검사
|
|
233
|
+
|
|
234
|
+
```sh
|
|
235
|
+
ccdd tools check --repo /path/to/project
|
|
236
|
+
ccdd tools check --artifact spec --for human
|
|
237
|
+
ccdd tools check --artifact spec --for human --tool open --execute
|
|
238
|
+
ccdd tools check --artifact tests --for agent --tool read --execute --args '{"path":"rank.test.mjs","startLine":1,"lineCount":30}'
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
기본 검사는 도구 정의·Artifact 경로와 등록된 `preflight`를 확인합니다. custom preflight가 없으면 등록 확인과 실제 실행 미검증을 구분하여 표시합니다. `--execute`는 지정한 도구를 실제로 호출하며, Human `open` 도구라면 프로그램이 열립니다. 실제 실행에는 Artifact·리뷰어 종류·도구를 모두 지정합니다. `--copy`가 기본이며, `--lock`도 지원합니다.
|
|
242
|
+
|
|
243
|
+
`ccdd tools check --artifact explosion --for agent`처럼 그룹을 선택하면 모든 leaf 도구를 중복 없이 검사합니다. `--execute`는 `--artifact preview --for agent --tool view_image --execute`처럼 leaf를 명시해야 합니다.
|
|
244
|
+
|
|
245
|
+
검사 결과에는 성공 여부와 실패 원인이 표시됩니다. 리뷰 기록이나 판정은 생성하지 않으며 Provider도 호출하지 않습니다. 데스크톱 프로그램을 연 복사본은 앱이 계속 읽을 수 있도록 보관합니다. 프로젝트 전체의 Provider·실행기 준비 상태는 `ccdd doctor`로 검사합니다. Provider 진단은 내부 nonce 도구로 연결을 확인하며 프로젝트 custom 도구를 대신 실행하지 않습니다.
|
|
246
|
+
|
|
247
|
+
## CLI 데모
|
|
248
|
+
|
|
249
|
+
설치한 CLI와 Release의 두 tarball로 네 가지 시나리오를 만들 수 있습니다. tarball 환경변수는 절대경로로 지정하고, 업그레이드할 때는 새 데모 폴더를 선택하세요.
|
|
250
|
+
|
|
251
|
+
```sh
|
|
252
|
+
export CCDD_DEMO_CORE_TARBALL="$PWD/vendor/ccdd/ccdd-core-2.0.1.tgz"
|
|
253
|
+
export CCDD_DEMO_TOOLS_TARBALL="$PWD/vendor/ccdd/ccdd-default-tools-2.0.1.tgz"
|
|
254
|
+
export CCDD_DEMO_DIR="$HOME/.local/share/ccdd/demo-2.0.1"
|
|
255
|
+
npx ccdd prepare-demo --demo-dir "$CCDD_DEMO_DIR"
|
|
256
|
+
npx ccdd run --demo --demo-dir "$CCDD_DEMO_DIR" --scenario why-change --copy --critic spec-why --wait
|
|
257
|
+
npx ccdd run --demo --demo-dir "$CCDD_DEMO_DIR" --scenario runtime-failure --copy --critic implementation-tests --wait
|
|
258
|
+
npx ccdd run --demo --demo-dir "$CCDD_DEMO_DIR" --scenario fixed --copy --wait
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
새 데모는 Git 없는 네 개의 수정 가능한 프로젝트를 만듭니다. tarball에서 의존성을 한 번 설치한 뒤 각 프로젝트에 물리적으로 복사하므로, 각 snapshot이 자신의 구현·의존성을 가집니다. 공개된 전이 의존성 설치에는 npm 접근 또는 로컬 캐시가 필요합니다. lifecycle script는 실행하지 않습니다. 각 프로젝트에 tarball·package lock도 보관합니다.
|
|
262
|
+
|
|
263
|
+
`--demo-dir`를 생략한 기본 경로는 기존과 같은 `~/.local/share/ccdd/demo-v9`입니다. 이 이름은 데모 형식 버전이며 패키지 버전과 별개입니다. 기존 데모는 편집한 파일과 설치된 패키지를 보존하며 재설치하지 않습니다. Release 업그레이드는 위처럼 새 폴더에서 준비합니다. 소스로 tarball을 만드는 절차와 전체 시연은 [데모 안내](docs/demo.md)를 참고하세요.
|
|
264
|
+
|
|
265
|
+
```text
|
|
266
|
+
why.md → spec.md → tests/ → implementation/
|
|
267
|
+
Agent Agent Runtime
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
시연 주제는 중요한 미완료 작업을 우선 제안하는 함수입니다. 목적 변경, 구현 불일치, 수정 완료를 실제 Agent 판정과 Node 테스트로 확인합니다. 기본 도구는 TS config에 명시적으로 등록되며 Human 도구는 데스크톱 열기로 구성됩니다. 기본 시나리오의 Critic은 Agent 2개·Runtime 1개입니다.
|
|
271
|
+
|
|
272
|
+
## 로컬 모니터
|
|
273
|
+
|
|
274
|
+
```sh
|
|
275
|
+
ccdd monitor
|
|
276
|
+
# 소스에서 실행: node dist/src/cli.js monitor
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
표시되는 로컬 주소를 브라우저에서 열면 됩니다. 기본 주소는 `http://127.0.0.1:4318`입니다. `--port`로 변경할 수 있습니다.
|
|
280
|
+
|
|
281
|
+
프로젝트를 선택하면 **요청·진행 중·성공·실패** 네 영역에 리뷰 카드가 나타납니다. 각 영역에서 이전 요청을 추가로 불러올 수 있어 최근 완료 기록이 많아도 대기 중인 리뷰가 가려지지 않습니다. 카드를 열면 판정·근거·진행 기록과 요청에 제공된 Artifact를 확인할 수 있습니다.
|
|
282
|
+
|
|
283
|
+
```sh
|
|
284
|
+
ccdd monitor --repo /path/to/project
|
|
285
|
+
ccdd monitor --state-dir /outside/repo/state
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
별도 저장 위치는 `--state-dir`로 연결합니다. Human 카드는 담당 전에는 요청 영역에, claim 후에는 진행 중 영역에 표시합니다. 상세에서 등록된 Human 도구를 실행하고 GREEN·RED를 제출합니다. 후속 리뷰는 독립된 작업자로 재개되므로 모니터를 종료해도 계속 진행됩니다. 화면 조회만으로 저장된 상태나 판정을 변경하지 않습니다.
|
|
289
|
+
|
|
290
|
+
Graph의 그룹 노드는 자신의 판정과 구성원 수를 표시하며, 선택하면 멤버별 판정을 확인하고 해당 노드로 이동할 수 있습니다. 구성 관계는 Critic 의존 간선과 구분합니다. 모니터는 저장된 그룹 정보를 검증해 표시하고 설정 코드를 실행하지 않습니다.
|
|
291
|
+
|
|
292
|
+
목록의 경과 시간은 접수 이후입니다. 기존 기록에는 입력 복사·검증 이전의 시간이 없으므로 해당 준비 시간은 포함하지 않습니다. Human의 담당 이후 시간은 실제 작업 시간이 아닌 담당 후 경과입니다.
|
|
293
|
+
|
|
294
|
+
## 검증
|
|
295
|
+
|
|
296
|
+
```sh
|
|
297
|
+
npm run typecheck
|
|
298
|
+
npm test
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
동시 복사본 공유, 복사 중 변경 거부, lock 변경·복원, 프로세스 간 소유권, Human 담당·도구·판정 제출, 도구 검사, 실제 테스트 실행, Provider 진단을 검증합니다. 모니터는 Node 내장 HTTP 서버와 Vue 3 화면을 사용하며, 빌드된 화면 파일이 npm 패키지에 포함됩니다. 이전 릴리스 문서와 영상은 당시 구현을 기록한 자료이며 현재 사용법은 이 문서를 따릅니다.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** The definition package has no dependency on persistence or review execution. */
|
|
2
|
+
export interface AgentProfile {
|
|
3
|
+
kind: 'agent';
|
|
4
|
+
provider: string;
|
|
5
|
+
model: string;
|
|
6
|
+
reasoning: string;
|
|
7
|
+
timeoutMs?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface HumanProfile {
|
|
10
|
+
kind: 'human';
|
|
11
|
+
}
|
|
12
|
+
export interface RuntimeProfile {
|
|
13
|
+
kind: 'runtime';
|
|
14
|
+
command: string;
|
|
15
|
+
args: string[];
|
|
16
|
+
timeoutMs?: number;
|
|
17
|
+
}
|
|
18
|
+
export type CriticProfile = AgentProfile | HumanProfile | RuntimeProfile;
|
|
19
|
+
export interface ReviewPayload {
|
|
20
|
+
instruction: string;
|
|
21
|
+
[key: string]: unknown;
|
|
22
|
+
}
|
|
23
|
+
export interface CriticDefinition {
|
|
24
|
+
id: string;
|
|
25
|
+
title: string;
|
|
26
|
+
target: string;
|
|
27
|
+
deps: string[];
|
|
28
|
+
profile: CriticProfile;
|
|
29
|
+
payload: ReviewPayload;
|
|
30
|
+
}
|
|
31
|
+
export type StaleStrategy = {
|
|
32
|
+
kind: 'file-hash';
|
|
33
|
+
paths?: string[];
|
|
34
|
+
} | {
|
|
35
|
+
kind: 'always';
|
|
36
|
+
};
|
|
37
|
+
export interface ArtifactDefinition {
|
|
38
|
+
type: string;
|
|
39
|
+
path: string;
|
|
40
|
+
basis?: boolean;
|
|
41
|
+
stale?: StaleStrategy;
|
|
42
|
+
}
|
|
43
|
+
export interface ArtifactGroupDefinition {
|
|
44
|
+
kind: 'group';
|
|
45
|
+
members: string[];
|
|
46
|
+
basis?: boolean;
|
|
47
|
+
stale?: StaleStrategy;
|
|
48
|
+
}
|
|
49
|
+
export type ArtifactEntryDefinition = ArtifactDefinition | ArtifactGroupDefinition;
|
|
50
|
+
export interface ArtifactGroupReference {
|
|
51
|
+
id: string;
|
|
52
|
+
members: string[];
|
|
53
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Config, ConfigFactory, InferSchema, JsonSchema, ToolDefinition, ToolMetadata } from './tools/contracts.js';
|
|
2
|
+
export type * from './tools/contracts.js';
|
|
3
|
+
export type * from './definitions.js';
|
|
4
|
+
export declare function defineConfig<T extends Config | ConfigFactory>(config: T): T;
|
|
5
|
+
export declare function defineTool<const S extends JsonSchema>(tool: Omit<ToolDefinition<InferSchema<S>>, 'metadata'> & {
|
|
6
|
+
metadata: Omit<ToolMetadata, 'inputSchema'> & {
|
|
7
|
+
inputSchema: S;
|
|
8
|
+
};
|
|
9
|
+
}): ToolDefinition<InferSchema<S>>;
|
package/dist/src/sdk.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdk.js","sourceRoot":"","sources":["../../src/sdk.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,YAAY,CAAmC,MAAS,IAAO,OAAO,MAAM,CAAC,CAAC,CAAC;AAC/F,MAAM,UAAU,UAAU,CAA6B,IAA6H,IAAoC,OAAO,IAAI,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { ArtifactEntryDefinition, CriticDefinition } from '../definitions.js';
|
|
2
|
+
export type JsonValue = null | boolean | number | string | JsonValue[] | {
|
|
3
|
+
[key: string]: JsonValue;
|
|
4
|
+
};
|
|
5
|
+
export type JsonSchema = Record<string, unknown>;
|
|
6
|
+
export type ToolResultKind = 'text' | 'json' | 'image' | 'launch';
|
|
7
|
+
export interface ToolMetadata {
|
|
8
|
+
description: string;
|
|
9
|
+
inputSchema: JsonSchema;
|
|
10
|
+
resultKinds: ToolResultKind[];
|
|
11
|
+
observation: 'content' | 'none';
|
|
12
|
+
artifactKind?: 'file' | 'directory' | 'any';
|
|
13
|
+
timeoutMs?: number;
|
|
14
|
+
}
|
|
15
|
+
export interface ToolContext {
|
|
16
|
+
artifactId: string;
|
|
17
|
+
artifactPath: string;
|
|
18
|
+
artifactDirectory: boolean;
|
|
19
|
+
outputDir: string;
|
|
20
|
+
tmpDir: string;
|
|
21
|
+
signal: AbortSignal;
|
|
22
|
+
resolvePath(path?: string): Promise<string>;
|
|
23
|
+
}
|
|
24
|
+
export type ToolContent = {
|
|
25
|
+
type: 'text';
|
|
26
|
+
text: string;
|
|
27
|
+
} | {
|
|
28
|
+
type: 'json';
|
|
29
|
+
data: JsonValue;
|
|
30
|
+
} | {
|
|
31
|
+
type: 'image';
|
|
32
|
+
path: string;
|
|
33
|
+
mimeType: 'image/png' | 'image/jpeg' | 'image/webp';
|
|
34
|
+
} | {
|
|
35
|
+
type: 'image';
|
|
36
|
+
data: string;
|
|
37
|
+
mimeType: 'image/png' | 'image/jpeg' | 'image/webp';
|
|
38
|
+
} | {
|
|
39
|
+
type: 'launch';
|
|
40
|
+
launched: true;
|
|
41
|
+
};
|
|
42
|
+
export interface ToolResult {
|
|
43
|
+
content: ToolContent[];
|
|
44
|
+
observation?: {
|
|
45
|
+
kind: 'content' | 'empty';
|
|
46
|
+
detail?: string;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export interface ToolDefinition<Args = Record<string, unknown>> {
|
|
50
|
+
metadata: ToolMetadata;
|
|
51
|
+
execute(context: ToolContext, args: Args): ToolResult | Promise<ToolResult>;
|
|
52
|
+
preflight?(context: ToolContext): {
|
|
53
|
+
ok: boolean;
|
|
54
|
+
message: string;
|
|
55
|
+
} | Promise<{
|
|
56
|
+
ok: boolean;
|
|
57
|
+
message: string;
|
|
58
|
+
}>;
|
|
59
|
+
}
|
|
60
|
+
export interface ArtifactToolsConfig {
|
|
61
|
+
agentTools?: Record<string, ToolDefinition<any>>;
|
|
62
|
+
humanTools?: Record<string, ToolDefinition<any>>;
|
|
63
|
+
}
|
|
64
|
+
export interface Config {
|
|
65
|
+
artifacts: Record<string, ArtifactEntryDefinition>;
|
|
66
|
+
artifactTypes: Record<string, ArtifactToolsConfig>;
|
|
67
|
+
critics: CriticDefinition[];
|
|
68
|
+
}
|
|
69
|
+
export type ConfigFactory = () => Config | Promise<Config>;
|
|
70
|
+
export interface ConfigManifest {
|
|
71
|
+
version: 1;
|
|
72
|
+
configHash: string;
|
|
73
|
+
modules: {
|
|
74
|
+
path: string;
|
|
75
|
+
hash: string;
|
|
76
|
+
}[];
|
|
77
|
+
types: Record<string, {
|
|
78
|
+
agentTools: Record<string, ToolMetadata>;
|
|
79
|
+
humanTools: Record<string, ToolMetadata>;
|
|
80
|
+
}>;
|
|
81
|
+
}
|
|
82
|
+
type Properties<S> = S extends {
|
|
83
|
+
properties: infer P;
|
|
84
|
+
} ? P : {};
|
|
85
|
+
type RequiredKeys<S> = S extends {
|
|
86
|
+
required: readonly (infer K)[];
|
|
87
|
+
} ? K : never;
|
|
88
|
+
export type InferSchema<S> = S extends {
|
|
89
|
+
enum: readonly (infer E)[];
|
|
90
|
+
} ? E : S extends {
|
|
91
|
+
type: 'string';
|
|
92
|
+
} ? string : S extends {
|
|
93
|
+
type: 'number' | 'integer';
|
|
94
|
+
} ? number : S extends {
|
|
95
|
+
type: 'boolean';
|
|
96
|
+
} ? boolean : S extends {
|
|
97
|
+
type: 'null';
|
|
98
|
+
} ? null : S extends {
|
|
99
|
+
type: 'array';
|
|
100
|
+
items: infer I;
|
|
101
|
+
} ? InferSchema<I>[] : S extends {
|
|
102
|
+
type: 'object';
|
|
103
|
+
} ? {
|
|
104
|
+
[K in keyof Properties<S> as K extends RequiredKeys<S> ? K : never]: InferSchema<Properties<S>[K]>;
|
|
105
|
+
} & {
|
|
106
|
+
[K in keyof Properties<S> as K extends RequiredKeys<S> ? never : K]?: InferSchema<Properties<S>[K]>;
|
|
107
|
+
} : unknown;
|
|
108
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contracts.js","sourceRoot":"","sources":["../../../src/tools/contracts.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# 이미지 기본 도구와 Artifact 그룹
|
|
2
|
+
|
|
3
|
+
`effect` 문서와 `preview` 이미지는 독립 Artifact입니다. `explosion`은 두 ID를 참조하는 그룹이며 경로와 타입이 없습니다. 문서·이미지의 개별 도구를 명시적으로 등록합니다. 이 예제는 실제 VFX 파일이 아닌 정적 샘플입니다.
|
|
4
|
+
|
|
5
|
+
- `preview-review`: 이미지 하나를 평가합니다. `view_image_preview`만 제공됩니다.
|
|
6
|
+
- `explosion-review`: 그룹을 평가합니다. `read_effect`와 `view_image_preview`가 제공됩니다. `preview`가 그룹 멤버이면서 `deps`여도 도구는 중복되지 않습니다.
|
|
7
|
+
- `explosion-human`: 그룹의 문서·이미지를 각각 데스크톱 앱에서 연 뒤 판정을 제출합니다.
|
|
8
|
+
|
|
9
|
+
전체 Run에서 두 그룹 Critic은 명시적인 `deps: ['preview']` 때문에 이미지 평가가 통과해야 시작합니다. 그룹에 속해 있다는 것만으로 선행 평가가 필요해지지는 않습니다. 그룹의 두 Critic이 모두 GREEN이면 `explosion`이 GREEN이며 `effect`는 미평가로 남습니다.
|
|
10
|
+
|
|
11
|
+
## 실행
|
|
12
|
+
|
|
13
|
+
Node 24 이상에서 v2.0.1의 세 패키지를 설치합니다. 다음 다운로드 명령은 GitHub Release 게시 후 사용할 수 있으며, 게시 전에는 아래 로컬 소스 빌드 절차를 사용합니다. 아래 명령은 CCDD 소스 저장소에서 시작하며, 예제를 저장소 밖의 새 프로젝트로 복사합니다. 다운로드에는 이 비공개 저장소에 접근할 수 있는 GitHub CLI 로그인이 필요합니다.
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
CCDD_EXAMPLE_ROOT=$(mktemp -d /tmp/ccdd-groups.XXXXXX)
|
|
17
|
+
cp -R examples/artifact-groups "$CCDD_EXAMPLE_ROOT/project"
|
|
18
|
+
cd "$CCDD_EXAMPLE_ROOT/project"
|
|
19
|
+
npm init -y
|
|
20
|
+
npm pkg set type=module
|
|
21
|
+
mkdir -p vendor/ccdd
|
|
22
|
+
gh release download v2.0.1 --repo lhj6102/ccdd --dir vendor/ccdd \
|
|
23
|
+
--pattern '*.tgz' --pattern SHA256SUMS --pattern verification.json
|
|
24
|
+
(cd vendor/ccdd && shasum -a 256 -c SHA256SUMS)
|
|
25
|
+
npm install --ignore-scripts \
|
|
26
|
+
./vendor/ccdd/ccdd-core-2.0.1.tgz \
|
|
27
|
+
./vendor/ccdd/ccdd-project-2.0.1.tgz \
|
|
28
|
+
./vendor/ccdd/ccdd-default-tools-2.0.1.tgz
|
|
29
|
+
|
|
30
|
+
# Provider 호출 없이 그룹 구성원의 도구 준비 상태를 확인합니다.
|
|
31
|
+
npx ccdd tools check --artifact explosion --for agent
|
|
32
|
+
# 실제 이미지 읽기는 개별 Artifact를 지정합니다.
|
|
33
|
+
npx ccdd tools check --artifact preview --for agent --tool view_image --execute
|
|
34
|
+
|
|
35
|
+
# 한 Critic만 검토: 이 경우 선행 판정 대기는 생략됩니다.
|
|
36
|
+
npx ccdd run --copy --critic explosion-review --codex-auth-file "$HOME/.codex/auth.json" --wait
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
실제 Agent 리뷰에는 이미지 입력을 지원하는 모델의 인증·접근 권한이 필요합니다. 다른 인증 방식은 본체 README를 참고하세요. 도구 검사는 모델을 호출하지 않습니다. 위 명령의 `--execute` 결과에는 실제 이미지의 base64 블록이 포함됩니다.
|
|
40
|
+
|
|
41
|
+
이미 본체를 설치했다면 첫 `cp`의 원본을 `node_modules/@ccdd/core/examples/artifact-groups`로 바꿉니다. Linux에서는 `shasum` 대신 `sha256sum -c SHA256SUMS`를 사용할 수 있습니다.
|
|
42
|
+
|
|
43
|
+
전체 Run과 Human 검토는 로컬 알림을 등록하여 시작합니다.
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
npx ccdd run --copy --human-inbox --codex-auth-file "$HOME/.codex/auth.json"
|
|
47
|
+
npx ccdd monitor
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
모니터에서 프로젝트·Run을 선택하고 Graph의 그룹 노드를 누르면 구성원을 확인할 수 있습니다. Human 요청을 맡은 다음 `{explosion}` 버튼을 눌러 각 멤버의 `open` 도구를 실행하고 판정과 근거를 제출합니다. 기본 데스크톱 열기는 macOS용이며 다른 운영체제에서는 명시적인 실행 프로그램을 등록합니다.
|
|
51
|
+
|
|
52
|
+
`view_image`는 Pi `read`의 이미지 결과를 재사용합니다. PNG/JPEG/WebP를 파일 내용으로 판별하며 최대 4MiB입니다. GIF/BMP/animated PNG, 텍스트 결과는 실패하며 자동 변환이나 축소는 하지 않습니다. 디렉터리 Artifact에 등록한 경우에는 `{"path":"frames/preview.png"}`처럼 내부 경로를 전달합니다.
|
|
53
|
+
|
|
54
|
+
## 로컬 소스 빌드 사용
|
|
55
|
+
|
|
56
|
+
수정한 소스를 시험할 때는 CCDD 저장소에서 세 tarball을 준비합니다.
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
npm ci
|
|
60
|
+
npm run build
|
|
61
|
+
CCDD_LOCAL_PACKAGES=$(mktemp -d /tmp/ccdd-group-packages.XXXXXX)
|
|
62
|
+
npm pack --ignore-scripts --pack-destination "$CCDD_LOCAL_PACKAGES"
|
|
63
|
+
npm pack --ignore-scripts --workspace @ccdd/project --pack-destination "$CCDD_LOCAL_PACKAGES"
|
|
64
|
+
npm pack --ignore-scripts --workspace @ccdd/default-tools --pack-destination "$CCDD_LOCAL_PACKAGES"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
같은 셸에서 위 실행 절차의 새 예제 프로젝트를 만들고, Release 다운로드·설치 대신 `npm install --ignore-scripts "$CCDD_LOCAL_PACKAGES"/*.tgz`를 실행합니다. 이후 도구 검사·리뷰 명령은 같습니다. 커밋에 고정된 소스의 전체 테스트와 별도 설치 검증도 하려면 [로컬 Release 명령](../../docs/releases.md#커밋을-지정하여-로컬에서-배포)의 `--dry-run`을 사용합니다.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { defineConfig } from '@ccdd/core';
|
|
2
|
+
import { agent, human } from '@ccdd/default-tools';
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
artifacts: {
|
|
6
|
+
effect: { type: 'markdown', path: 'effect.md' },
|
|
7
|
+
preview: { type: 'image', path: 'preview.png' },
|
|
8
|
+
explosion: { kind: 'group', members: ['effect', 'preview'] },
|
|
9
|
+
},
|
|
10
|
+
artifactTypes: {
|
|
11
|
+
markdown: {
|
|
12
|
+
agentTools: { read: agent.text.read() },
|
|
13
|
+
humanTools: { open: human.desktop.open() },
|
|
14
|
+
},
|
|
15
|
+
image: {
|
|
16
|
+
agentTools: { view_image: agent.image.view() },
|
|
17
|
+
humanTools: { open: human.desktop.open() },
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
critics: [
|
|
21
|
+
{
|
|
22
|
+
id: 'preview-review', title: '이미지 자체의 시인성', target: 'preview', deps: [],
|
|
23
|
+
profile: { kind: 'agent', provider: 'openai-codex', model: 'gpt-6-astra', reasoning: 'medium' },
|
|
24
|
+
payload: { instruction: '{preview}에 어두운 배경과 구분되는 밝은 중심과 주황색 고리가 보이는지 확인하세요. 이 검토는 이미지 자체에 관한 것이며 효과 명세와의 일치는 평가하지 않습니다.' },
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: 'explosion-review', title: '효과 설명과 프리뷰의 일치', target: 'explosion', deps: ['preview'],
|
|
28
|
+
profile: { kind: 'agent', provider: 'openai-codex', model: 'gpt-6-astra', reasoning: 'medium' },
|
|
29
|
+
payload: { instruction: '{explosion}의 모든 구성원을 관측하여 {effect}에 명시된 정적 외형과 {preview}가 일치하는지 평가하세요. 애니메이션 타이밍이나 실제 VFX 런타임 동작은 이 정적 예제의 평가 대상이 아닙니다.' },
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: 'explosion-human', title: '데스크톱에서 그룹 검토', target: 'explosion', deps: ['preview'],
|
|
33
|
+
profile: { kind: 'human' },
|
|
34
|
+
payload: { instruction: '{explosion}의 문서와 이미지를 각각 데스크톱 프로그램으로 열어 비교한 뒤 판정을 제출하세요.' },
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
});
|
|
Binary file
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# 사용자 정의 Reader
|
|
2
|
+
|
|
3
|
+
기본 도구 라이브러리 없이 `{ metadata, execute }`를 직접 등록하는 예제입니다. `customTextReader()`는 정의를 만들고, 실제 파일 읽기는 Agent가 `read_spec`·`read_why`를 호출할 때 수행합니다.
|
|
4
|
+
|
|
5
|
+
각 프로젝트가 자신의 의존성을 포함해야 하므로 이 폴더를 저장소 밖의 새 프로젝트로 복사한 뒤 core와 Project를 설치합니다. 아래 명령은 npm v2.0.1 게시 후 사용할 수 있으며, 게시 전에는 아래에 설명한 로컬 tarball을 사용합니다. 예제는 소스 저장소와 core 패키지의 `examples/custom-text-reader`에 포함됩니다. 상위 저장소에 설치된 CCDD를 그대로 참조하지 않습니다.
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
# CCDD 소스 저장소에서 예제를 복사합니다.
|
|
9
|
+
cp -R examples/custom-text-reader /tmp/ccdd-custom-reader
|
|
10
|
+
cd /tmp/ccdd-custom-reader
|
|
11
|
+
npm init -y
|
|
12
|
+
npm pkg set type=module
|
|
13
|
+
npm install --ignore-scripts @ccdd/core@2.0.1 @ccdd/project@2.0.1
|
|
14
|
+
npx ccdd tools check --artifact spec --for agent --tool read
|
|
15
|
+
npx ccdd tools check --artifact spec --for agent --tool read --execute --args '{"startLine":1,"lineCount":20}'
|
|
16
|
+
npx ccdd run --copy --critic spec-why --codex-auth-file "$HOME/.codex/auth.json" --wait
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
이 예제는 core와 Project를 설치하며 기본 도구 라이브러리는 사용하지 않습니다. 소스 저장소에서 `npm run release:npm -- --commit <40자리 SHA> --dry-run`으로 검증·생성한 같은 버전의 `ccdd-core-2.0.1.tgz`와 `ccdd-project-2.0.1.tgz`를 `npm install --ignore-scripts <core.tgz> <project.tgz>`로 설치할 수도 있습니다. 이 로컬 검증에는 GitHub 인증이 필요하지 않습니다. 이미 CCDD를 설치했다면 첫 `cp`의 원본을 `node_modules/@ccdd/core/examples/custom-text-reader`로 바꿉니다.
|
|
20
|
+
|
|
21
|
+
도구의 `preflight`는 생략했습니다. 기본 검사는 등록 확인과 실제 실행 미검증을 구분하며, `--execute`는 파일을 실제로 읽습니다. Agent 리뷰에는 유효한 Provider 인증이 필요합니다.
|
|
22
|
+
|
|
23
|
+
이 Reader는 구조를 보여주기 위한 작은 구현입니다. 파일을 메모리로 읽은 뒤 1MiB 이하인지 확인하며, 반환 텍스트는 64KiB로 제한합니다. 큰 파일은 스트리밍 리더가 적합합니다. UTF-8·CRLF와 마지막 줄바꿈을 보존하고, 빈 파일과 EOF 이후 읽기를 구분합니다. 실제 내용이나 빈 파일을 관측했을 때만 관측 receipt를 반환합니다.
|
|
24
|
+
|
|
25
|
+
Human 도구를 Agent Reader로 복제하지 않았습니다. 이 타입에는 Human 도구가 없으므로 Human Critic에 사용할 수 없습니다. 사람의 열람을 추가하려면 데스크톱 프로그램을 여는 사용자 도구를 작성하거나 `@ccdd/default-tools`의 `human.desktop.open()`을 명시적으로 등록합니다.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { defineConfig, defineTool } from '@ccdd/core';
|
|
3
|
+
|
|
4
|
+
// This factory defines a tool. It does not read the Artifact or execute an app.
|
|
5
|
+
function customTextReader() {
|
|
6
|
+
return defineTool({
|
|
7
|
+
metadata: {
|
|
8
|
+
description: '{artifactName}의 지정한 줄 범위를 읽습니다.',
|
|
9
|
+
inputSchema: {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
startLine: { type: 'integer', minimum: 1 },
|
|
13
|
+
lineCount: { type: 'integer', minimum: 1, maximum: 80 },
|
|
14
|
+
},
|
|
15
|
+
required: ['startLine', 'lineCount'],
|
|
16
|
+
additionalProperties: false,
|
|
17
|
+
} as const,
|
|
18
|
+
resultKinds: ['json'],
|
|
19
|
+
observation: 'content',
|
|
20
|
+
artifactKind: 'file',
|
|
21
|
+
},
|
|
22
|
+
async execute(context, args) {
|
|
23
|
+
// Deliberately small teaching example: it accepts files up to 1 MiB.
|
|
24
|
+
const file = await context.resolvePath();
|
|
25
|
+
const bytes = await readFile(file, { signal: context.signal });
|
|
26
|
+
if (bytes.length > 1024 * 1024) throw new Error('This example reader supports files up to 1 MiB.');
|
|
27
|
+
const text = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(bytes);
|
|
28
|
+
if (text.includes('\0')) throw new Error('This example reader accepts text, not binary data.');
|
|
29
|
+
const lines = text.match(/[^\n]*\n|[^\n]+$/g) ?? [];
|
|
30
|
+
const offset = args.startLine - 1;
|
|
31
|
+
const selected = lines.slice(offset, offset + args.lineCount);
|
|
32
|
+
const content = selected.join('');
|
|
33
|
+
if (Buffer.byteLength(content) > 64 * 1024) throw new Error('Select a smaller line range.');
|
|
34
|
+
const nextOffset = offset + selected.length;
|
|
35
|
+
return {
|
|
36
|
+
content: [{ type: 'json', data: {
|
|
37
|
+
content,
|
|
38
|
+
startLine: args.startLine,
|
|
39
|
+
endLine: selected.length ? nextOffset : null,
|
|
40
|
+
lineCount: selected.length,
|
|
41
|
+
totalLines: lines.length,
|
|
42
|
+
nextStartLine: nextOffset < lines.length ? nextOffset + 1 : null,
|
|
43
|
+
} }],
|
|
44
|
+
...(selected.length ? { observation: { kind: 'content' as const } }
|
|
45
|
+
: lines.length === 0 ? { observation: { kind: 'empty' as const } } : {}),
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export default defineConfig(() => ({
|
|
52
|
+
artifactTypes: {
|
|
53
|
+
document: { agentTools: { read: customTextReader() } },
|
|
54
|
+
},
|
|
55
|
+
artifacts: {
|
|
56
|
+
why: { type: 'document', path: 'why.md', basis: true },
|
|
57
|
+
spec: { type: 'document', path: 'spec.md' },
|
|
58
|
+
},
|
|
59
|
+
critics: [{
|
|
60
|
+
id: 'spec-why', title: 'Spec이 Why에 부합하는가', target: 'spec', deps: ['why'],
|
|
61
|
+
profile: { kind: 'agent', provider: 'openai-codex', model: 'gpt-6-astra', reasoning: 'medium' },
|
|
62
|
+
payload: { instruction: '두 문서를 읽고 Spec이 Why의 최대 개수 조건을 충족하는지 평가하세요.' },
|
|
63
|
+
}],
|
|
64
|
+
}));
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ccdd/core",
|
|
3
|
+
"version": "2.0.1",
|
|
4
|
+
"publishConfig": { "access": "public", "registry": "https://registry.npmjs.org/" },
|
|
5
|
+
"repository": { "type": "git", "url": "git+https://github.com/lhj6102/ccdd.git" },
|
|
6
|
+
"description": "Artifact, Critic, relationship and tool definitions for CCDD",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"types": "./dist/src/sdk.d.ts",
|
|
9
|
+
"exports": { ".": { "types": "./dist/src/sdk.d.ts", "import": "./dist/src/sdk.js" } },
|
|
10
|
+
"workspaces": ["packages/default-tools", "packages/project"],
|
|
11
|
+
"engines": {
|
|
12
|
+
"node": ">=24"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "node scripts/clean-build.mjs && npm run build:core && npm run build:tools && node node_modules/typescript/bin/tsc -p tsconfig.json && npm run build:ui && npm run build:project",
|
|
16
|
+
"build:core": "node node_modules/typescript/bin/tsc -p tsconfig.runtime.json",
|
|
17
|
+
"build:tools": "npm run build --workspace @ccdd/default-tools",
|
|
18
|
+
"build:project": "node scripts/build-project.mjs",
|
|
19
|
+
"build:ui": "npm run typecheck:ui && vite build --config vite.config.ts",
|
|
20
|
+
"typecheck:ui": "node src/monitor/ui/typecheck.cjs -p tsconfig.ui.json --noEmit",
|
|
21
|
+
"typecheck": "node node_modules/typescript/bin/tsc -p tsconfig.json --noEmit && npm run typecheck:ui",
|
|
22
|
+
"test": "npm run build && node --test dist/test/*.test.js",
|
|
23
|
+
"test:packages": "npm run build && node scripts/smoke-project.mjs",
|
|
24
|
+
"prepack": "npm run build",
|
|
25
|
+
"release": "node scripts/local-release.mjs",
|
|
26
|
+
"release:npm": "node scripts/local-release.mjs --npm",
|
|
27
|
+
"release:npm:check": "node scripts/check-npm.mjs",
|
|
28
|
+
"demo:prepare": "npm run build && node dist/src/cli.js prepare-demo",
|
|
29
|
+
"demo": "npm run build && node dist/src/cli.js run --demo --copy --wait"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist/src/sdk.*",
|
|
33
|
+
"dist/src/definitions.*",
|
|
34
|
+
"dist/src/tools/contracts.*",
|
|
35
|
+
"README.md",
|
|
36
|
+
"examples/"
|
|
37
|
+
],
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@earendil-works/pi-agent-core": "0.85.1",
|
|
40
|
+
"@earendil-works/pi-ai": "0.85.1",
|
|
41
|
+
"@lucide/vue": "1.41.0",
|
|
42
|
+
"@vue-flow/background": "1.3.2",
|
|
43
|
+
"@vue-flow/core": "1.48.2",
|
|
44
|
+
"elkjs": "0.12.0",
|
|
45
|
+
"typebox": "1.3.7",
|
|
46
|
+
"vue": "3.5.42",
|
|
47
|
+
"@types/node": "24.13.3",
|
|
48
|
+
"@vitejs/plugin-vue": "6.0.8",
|
|
49
|
+
"typescript": "7.0.2",
|
|
50
|
+
"typescript-ui": "npm:typescript@6.0.3",
|
|
51
|
+
"vite": "8.2.2",
|
|
52
|
+
"vue-tsc": "3.3.11"
|
|
53
|
+
}
|
|
54
|
+
}
|