@devport-kr/portki 0.2.0 → 0.2.2
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/AGENTS.md +14 -14
- package/CLAUDE.md +14 -14
- package/README.md +70 -162
- package/dist/cli.js +22 -22
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -11,7 +11,7 @@ Do not call external LLM APIs. Do not add OpenAI or Anthropic API usage.
|
|
|
11
11
|
- This branch is the public version.
|
|
12
12
|
- There is no DB, no embeddings, no PostgreSQL, and no OpenAI API dependency.
|
|
13
13
|
- It should work without `.env` setup.
|
|
14
|
-
- Final output lives under `
|
|
14
|
+
- Final output lives under `portki-output/wiki/{owner}/{repo}/` as Markdown files.
|
|
15
15
|
- `persist-section` means local validation plus session registration only.
|
|
16
16
|
- `finalize` assembles the full Markdown wiki bundle.
|
|
17
17
|
- `package` is the monolithic path that exports Markdown directly from a full accepted output.
|
|
@@ -56,20 +56,20 @@ Monolithic alternative for small repos:
|
|
|
56
56
|
|
|
57
57
|
## Workspace Naming Rule
|
|
58
58
|
|
|
59
|
-
If multiple repos are processed in parallel, all agent-authored intermediate files must be stored in `
|
|
59
|
+
If multiple repos are processed in parallel, all agent-authored intermediate files must be stored in `portki-output/workspace/` and prefixed with the repo slug.
|
|
60
60
|
|
|
61
61
|
Examples:
|
|
62
62
|
|
|
63
|
-
- `
|
|
64
|
-
- `
|
|
65
|
-
- `
|
|
63
|
+
- `portki-output/workspace/ollama-artifact.json`
|
|
64
|
+
- `portki-output/workspace/ollama-section-plan.json`
|
|
65
|
+
- `portki-output/workspace/ollama-section-1-output.json`
|
|
66
66
|
|
|
67
67
|
## Commands
|
|
68
68
|
|
|
69
69
|
### `ingest`
|
|
70
70
|
|
|
71
71
|
```bash
|
|
72
|
-
npx tsx src/agent.ts ingest --repo owner/repo --out
|
|
72
|
+
npx tsx src/agent.ts ingest --repo owner/repo --out portki-output/workspace/{repo-slug}-artifact.json
|
|
73
73
|
```
|
|
74
74
|
|
|
75
75
|
The agent must read these fields:
|
|
@@ -97,7 +97,7 @@ Interpret the status as:
|
|
|
97
97
|
### `plan-sections`
|
|
98
98
|
|
|
99
99
|
```bash
|
|
100
|
-
npx tsx src/agent.ts plan-sections --artifact
|
|
100
|
+
npx tsx src/agent.ts plan-sections --artifact portki-output/workspace/{repo-slug}-artifact.json --out portki-output/workspace/{repo-slug}-plan-context.json
|
|
101
101
|
```
|
|
102
102
|
|
|
103
103
|
The output includes:
|
|
@@ -111,13 +111,13 @@ The output includes:
|
|
|
111
111
|
### `validate-plan`
|
|
112
112
|
|
|
113
113
|
```bash
|
|
114
|
-
npx tsx src/agent.ts validate-plan --input
|
|
114
|
+
npx tsx src/agent.ts validate-plan --input portki-output/workspace/{repo-slug}-section-plan.json --context portki-output/workspace/{repo-slug}-plan-context.json --out portki-output/workspace/{repo-slug}-section-plan.json
|
|
115
115
|
```
|
|
116
116
|
|
|
117
117
|
### `persist-section`
|
|
118
118
|
|
|
119
119
|
```bash
|
|
120
|
-
npx tsx src/agent.ts persist-section --plan
|
|
120
|
+
npx tsx src/agent.ts persist-section --plan portki-output/workspace/{repo-slug}-section-plan.json --section sec-1 --input portki-output/workspace/{repo-slug}-section-1-output.json
|
|
121
121
|
```
|
|
122
122
|
|
|
123
123
|
This command only does the following:
|
|
@@ -131,21 +131,21 @@ It does not write to a database, generate embeddings, or call external APIs.
|
|
|
131
131
|
### `finalize`
|
|
132
132
|
|
|
133
133
|
```bash
|
|
134
|
-
npx tsx src/agent.ts finalize --plan
|
|
134
|
+
npx tsx src/agent.ts finalize --plan portki-output/workspace/{repo-slug}-section-plan.json --advance_baseline
|
|
135
135
|
```
|
|
136
136
|
|
|
137
137
|
This command:
|
|
138
138
|
|
|
139
139
|
- validates cross-section repetition
|
|
140
140
|
- assembles persisted sections from the local session
|
|
141
|
-
- writes `
|
|
142
|
-
- writes section Markdown files such as `
|
|
141
|
+
- writes `portki-output/wiki/{owner}/{repo}/README.md`
|
|
142
|
+
- writes section Markdown files such as `portki-output/wiki/{owner}/{repo}/01-sec-1.md`
|
|
143
143
|
- optionally advances the freshness baseline
|
|
144
144
|
|
|
145
145
|
### `package`
|
|
146
146
|
|
|
147
147
|
```bash
|
|
148
|
-
npx tsx src/agent.ts package --input
|
|
148
|
+
npx tsx src/agent.ts package --input portki-output/workspace/{repo-slug}-accepted-output.json --advance_baseline
|
|
149
149
|
```
|
|
150
150
|
|
|
151
151
|
This validates a monolithic accepted output and writes the same Markdown wiki bundle.
|
|
@@ -196,7 +196,7 @@ The final result is Markdown, not a delivery JSON artifact.
|
|
|
196
196
|
## Output Paths
|
|
197
197
|
|
|
198
198
|
```text
|
|
199
|
-
|
|
199
|
+
portki-output/
|
|
200
200
|
workspace/
|
|
201
201
|
snapshots/{owner}/{repo}/
|
|
202
202
|
chunked/{owner}/{repo}/session.json
|
package/CLAUDE.md
CHANGED
|
@@ -11,7 +11,7 @@ Do not call external LLM APIs. Do not add OpenAI or Anthropic API usage.
|
|
|
11
11
|
- This branch is the public version.
|
|
12
12
|
- There is no DB, no embeddings, no PostgreSQL, and no OpenAI API dependency.
|
|
13
13
|
- It should work without `.env` setup.
|
|
14
|
-
- Final output lives under `
|
|
14
|
+
- Final output lives under `portki-output/wiki/{owner}/{repo}/` as Markdown files.
|
|
15
15
|
- `persist-section` means local validation plus session registration only.
|
|
16
16
|
- `finalize` assembles the full Markdown wiki bundle.
|
|
17
17
|
- `package` is the monolithic path that exports Markdown directly from a full accepted output.
|
|
@@ -54,20 +54,20 @@ Monolithic alternative for small repos:
|
|
|
54
54
|
|
|
55
55
|
## Workspace Naming Rule
|
|
56
56
|
|
|
57
|
-
All agent-authored intermediate files must be written to `
|
|
57
|
+
All agent-authored intermediate files must be written to `portki-output/workspace/` and prefixed with the repo slug.
|
|
58
58
|
|
|
59
59
|
Examples:
|
|
60
60
|
|
|
61
|
-
- `
|
|
62
|
-
- `
|
|
63
|
-
- `
|
|
61
|
+
- `portki-output/workspace/redis-artifact.json`
|
|
62
|
+
- `portki-output/workspace/redis-section-plan.json`
|
|
63
|
+
- `portki-output/workspace/redis-section-2-output.json`
|
|
64
64
|
|
|
65
65
|
## Commands
|
|
66
66
|
|
|
67
67
|
### `ingest`
|
|
68
68
|
|
|
69
69
|
```bash
|
|
70
|
-
npx tsx src/agent.ts ingest --repo owner/repo --out
|
|
70
|
+
npx tsx src/agent.ts ingest --repo owner/repo --out portki-output/workspace/{repo-slug}-artifact.json
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
Read these fields from the artifact:
|
|
@@ -93,19 +93,19 @@ npx tsx src/agent.ts detect --repo owner/repo
|
|
|
93
93
|
### `plan-sections`
|
|
94
94
|
|
|
95
95
|
```bash
|
|
96
|
-
npx tsx src/agent.ts plan-sections --artifact
|
|
96
|
+
npx tsx src/agent.ts plan-sections --artifact portki-output/workspace/{repo-slug}-artifact.json --out portki-output/workspace/{repo-slug}-plan-context.json
|
|
97
97
|
```
|
|
98
98
|
|
|
99
99
|
### `validate-plan`
|
|
100
100
|
|
|
101
101
|
```bash
|
|
102
|
-
npx tsx src/agent.ts validate-plan --input
|
|
102
|
+
npx tsx src/agent.ts validate-plan --input portki-output/workspace/{repo-slug}-section-plan.json --context portki-output/workspace/{repo-slug}-plan-context.json --out portki-output/workspace/{repo-slug}-section-plan.json
|
|
103
103
|
```
|
|
104
104
|
|
|
105
105
|
### `persist-section`
|
|
106
106
|
|
|
107
107
|
```bash
|
|
108
|
-
npx tsx src/agent.ts persist-section --plan
|
|
108
|
+
npx tsx src/agent.ts persist-section --plan portki-output/workspace/{repo-slug}-section-plan.json --section sec-1 --input portki-output/workspace/{repo-slug}-section-1-output.json
|
|
109
109
|
```
|
|
110
110
|
|
|
111
111
|
What it does:
|
|
@@ -123,19 +123,19 @@ What it does not do:
|
|
|
123
123
|
### `finalize`
|
|
124
124
|
|
|
125
125
|
```bash
|
|
126
|
-
npx tsx src/agent.ts finalize --plan
|
|
126
|
+
npx tsx src/agent.ts finalize --plan portki-output/workspace/{repo-slug}-section-plan.json --advance_baseline
|
|
127
127
|
```
|
|
128
128
|
|
|
129
129
|
Outputs:
|
|
130
130
|
|
|
131
|
-
- `
|
|
132
|
-
- `
|
|
131
|
+
- `portki-output/wiki/{owner}/{repo}/README.md`
|
|
132
|
+
- `portki-output/wiki/{owner}/{repo}/01-sec-1.md`
|
|
133
133
|
- additional section Markdown files
|
|
134
134
|
|
|
135
135
|
### `package`
|
|
136
136
|
|
|
137
137
|
```bash
|
|
138
|
-
npx tsx src/agent.ts package --input
|
|
138
|
+
npx tsx src/agent.ts package --input portki-output/workspace/{repo-slug}-accepted-output.json --advance_baseline
|
|
139
139
|
```
|
|
140
140
|
|
|
141
141
|
This validates a monolithic accepted output and writes the same Markdown result.
|
|
@@ -165,7 +165,7 @@ Code call-flow analysis should begin in `sub-1-2` or later.
|
|
|
165
165
|
## Output Paths
|
|
166
166
|
|
|
167
167
|
```text
|
|
168
|
-
|
|
168
|
+
portki-output/
|
|
169
169
|
workspace/
|
|
170
170
|
snapshots/{owner}/{repo}/
|
|
171
171
|
chunked/{owner}/{repo}/session.json
|
package/README.md
CHANGED
|
@@ -12,215 +12,123 @@
|
|
|
12
12
|
- **증분 업데이트 (Incremental Update)**: 전체 코드를 매번 다시 분석하지 않고, 마지막 위키 생성 커밋 이후 변경된 파일과 영향을 받는 섹션만 추적하여 위키를 효율적으로 갱신합니다.
|
|
13
13
|
- **AI 에이전트 원클릭 통합**: Claude Code, Codex, Gemini CLI에서 한 줄의 명령으로 위키를 생성할 수 있습니다.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
---
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
npx @devport-kr/portki facebook/react
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
이 한 줄이면 저장소를 분석하고 `handoff.md`를 생성합니다. AI 에이전트가 이 파일을 읽고 위키를 완성합니다.
|
|
22
|
-
|
|
23
|
-
## 설치
|
|
24
|
-
|
|
25
|
-
Node.js 20 이상이 필요합니다. `.env` 설정은 필요 없습니다.
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
npx @devport-kr/portki help
|
|
29
|
-
```
|
|
17
|
+
## 📦 설치 (Installation)
|
|
30
18
|
|
|
31
|
-
|
|
19
|
+
**Node.js 20 이상**이 필요합니다.
|
|
32
20
|
|
|
33
21
|
```bash
|
|
34
22
|
npm install -g @devport-kr/portki
|
|
35
23
|
portki help
|
|
36
24
|
```
|
|
37
25
|
|
|
38
|
-
|
|
39
|
-
|
|
26
|
+
**환경 점검:** 현재 시스템 환경이 portki를 실행하기에 적합한지 확인하려면 아래 명령어를 사용하세요.
|
|
40
27
|
```bash
|
|
41
28
|
portki doctor
|
|
42
29
|
```
|
|
43
30
|
|
|
44
|
-
|
|
31
|
+
---
|
|
45
32
|
|
|
46
|
-
|
|
33
|
+
## 🚀 빠른 시작 (Quick Start)
|
|
47
34
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
# 1. 어댑터 설치 (프로젝트 루트에서 한 번만)
|
|
52
|
-
portki install --agent claude
|
|
53
|
-
|
|
54
|
-
# 2. Claude Code에서 슬래시 명령으로 실행
|
|
55
|
-
/portki facebook/react
|
|
56
|
-
```
|
|
35
|
+
portki는 주요 3사의 Coding CLI들과 완벽하게 연동됩니다. 한 번의 어댑터 설치로 에이전트 내에서 직접 명령어를 실행할 수 있습니다.
|
|
57
36
|
|
|
58
|
-
|
|
37
|
+
> 💡 **안내:** 아래 명령어들에 사용된 `devport-kr/portki`는 예시 저장소입니다. 실제로 위키를 생성하고자 하는 대상 GitHub 저장소(예: `facebook/react`, `owner/repo`)로 변경하여 실행해 주세요.
|
|
59
38
|
|
|
60
|
-
|
|
39
|
+
### 1. Claude Code
|
|
40
|
+
프로젝트 루트에서 어댑터를 설치한 후, Claude Code 내에서 슬래시 명령어로 실행합니다.
|
|
61
41
|
|
|
62
42
|
```bash
|
|
63
|
-
#
|
|
64
|
-
portki
|
|
65
|
-
|
|
43
|
+
# 어댑터 설치 (최초 1회)
|
|
44
|
+
portki install --agent claude
|
|
45
|
+
|
|
46
|
+
# Claude Code에서 실행
|
|
47
|
+
/portki devport-kr/portki
|
|
66
48
|
```
|
|
49
|
+
*참고: 어댑터를 설치하지 않은 경우 터미널에서 `portki devport-kr/portki`를 실행한 뒤, 출력되는 `handoff.md`의 경로를 Claude에게 직접 전달해도 됩니다.*
|
|
67
50
|
|
|
68
|
-
### Codex (OpenAI)
|
|
51
|
+
### 2. Codex (OpenAI)
|
|
52
|
+
Codex 환경에 맞게 `AGENTS.md` 파일에 portki 사용법을 자동으로 추가합니다.
|
|
69
53
|
|
|
70
54
|
```bash
|
|
71
|
-
#
|
|
55
|
+
# 어댑터 설치 (최초 1회)
|
|
72
56
|
portki install --agent codex
|
|
73
57
|
```
|
|
58
|
+
*Codex 사용 예시:* "portki devport-kr/portki 실행하고, handoff.md 지침을 따라서 위키를 만들어줘."
|
|
74
59
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
Codex에서 사용 예시:
|
|
78
|
-
|
|
79
|
-
```
|
|
80
|
-
portki facebook/react 실행하고 handoff.md 따라서 위키 만들어줘
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### Gemini CLI
|
|
60
|
+
### 3. Gemini CLI
|
|
61
|
+
Gemini CLI 환경을 위한 전용 슬래시 명령어를 설정합니다.
|
|
84
62
|
|
|
85
63
|
```bash
|
|
86
|
-
#
|
|
64
|
+
# 어댑터 설치 (최초 1회)
|
|
87
65
|
portki install --agent gemini
|
|
88
66
|
|
|
89
|
-
#
|
|
90
|
-
/portki
|
|
67
|
+
# Gemini CLI에서 실행
|
|
68
|
+
/portki devport-kr/portki
|
|
91
69
|
```
|
|
92
70
|
|
|
93
|
-
|
|
71
|
+
---
|
|
94
72
|
|
|
95
|
-
|
|
73
|
+
## ⚙️ 주요 명령어 (Commands)
|
|
96
74
|
|
|
97
|
-
|
|
75
|
+
portki는 AI 에이전트의 원활한 작업을 위한 상위 명령어와, 디테일한 제어를 위한 하위 명령어를 제공합니다.
|
|
98
76
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
77
|
+
| 분류 | 명령어 | 설명 |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| **기본 실행** | `portki owner/repo` | 저장소를 분석하고 AI 에이전트용 작업 지침서(`handoff.md`)를 생성합니다. |
|
|
80
|
+
| **상태 관리** | `portki status owner/repo` | 현재 진행 중인 파이프라인의 작업 상태를 확인합니다. |
|
|
81
|
+
| | `portki resume owner/repo` | 중단된 작업을 마지막으로 완료된 단계부터 이어서 진행합니다. |
|
|
82
|
+
| **환경 설정** | `portki doctor` | 시스템 실행 환경 및 의존성 상태를 점검합니다. |
|
|
83
|
+
| | `portki install --agent <name>` | 특정 AI 에이전트(`claude`, `codex`, `gemini`)용 어댑터를 설치합니다. |
|
|
104
84
|
|
|
105
|
-
|
|
85
|
+
*(수동 작업 및 세밀한 파이프라인 제어가 필요한 경우 `ingest`, `plan-sections`, `validate-plan`, `persist-section`, `finalize`, `detect` 등의 하위 명령어를 지원합니다.)*
|
|
106
86
|
|
|
107
|
-
|
|
108
|
-
portki status owner/repo
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
중단된 작업을 이어서 하려면:
|
|
112
|
-
|
|
113
|
-
```bash
|
|
114
|
-
portki resume owner/repo
|
|
115
|
-
```
|
|
87
|
+
---
|
|
116
88
|
|
|
117
|
-
##
|
|
118
|
-
**(2026년 3월 7일 기준)**
|
|
119
|
-
| 환경 | 권장 모델 | Effort (Thinking) Level | 설정 지침 |
|
|
120
|
-
|------|-----------|--------------------------|------------------|
|
|
121
|
-
| **Claude Code** | `Opus 4.6` | High | [`CLAUDE.md`](./CLAUDE.md)|
|
|
122
|
-
| **Codex** | `GPT-5.4` | xHigh | [`AGENTS.md`](./AGENTS.md)|
|
|
123
|
-
| **Gemini CLI** | `gemini 3.1-pro-preview` | High | [`AGENTS.md`](./AGENTS.md)|
|
|
89
|
+
## 🔄 워크플로우 (Workflows)
|
|
124
90
|
|
|
125
|
-
|
|
91
|
+
portki는 코드베이스 규모에 구애받지 않고 고품질의 위키를 생성하기 위해 **청크 단위 작업(Chunked Generation)**을 수행합니다.
|
|
126
92
|
|
|
127
|
-
###
|
|
93
|
+
### 1. AI 에이전트 자동 워크플로우 (권장)
|
|
94
|
+
가장 쉽고 권장하는 방식입니다. portki가 분석 파이프라인을 구축하면, 에이전트가 이를 따라 문서를 완성합니다.
|
|
128
95
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
| `portki resume owner/repo` | 마지막 유효 단계에서 handoff를 재생성합니다. |
|
|
134
|
-
| `portki doctor` | 실행 환경 상태를 점검합니다. |
|
|
135
|
-
| `portki install --agent <name>` | AI 에이전트 어댑터를 설치합니다. (`claude`, `codex`, `gemini`) |
|
|
96
|
+
1. `portki owner/repo` 실행하여 저장소 스냅샷 수집 및 `handoff.md` 생성.
|
|
97
|
+
2. AI 에이전트가 `handoff.md` 지침에 따라 섹션별 계획 수립 및 검증(`validate-plan`).
|
|
98
|
+
3. 섹션 단위로 문서를 작성하고 로컬 세션에 반영(`persist-section`).
|
|
99
|
+
4. 모든 섹션 작성이 끝나면 최종 Markdown 파일로 조립(`finalize`).
|
|
136
100
|
|
|
137
|
-
###
|
|
101
|
+
### 2. 증분 업데이트 (Incremental Update)
|
|
102
|
+
기존에 생성된 위키가 있다면, 변경된 코드만 추적하여 효율적으로 문서를 갱신할 수 있습니다.
|
|
138
103
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
| `persist-section` | 생성된 단일 섹션의 품질을 검증하고, 허용되면 로컬 세션 상태에 반영합니다. |
|
|
145
|
-
| `finalize` | 작성 완료된 모든 섹션 간의 교차 검증을 수행하고, 최종 Markdown 위키와 기준점을 업데이트합니다. |
|
|
146
|
-
| `package` | 위키 결과물 규격을 검증하고 순수 Markdown 위키 번들로 출력합니다. |
|
|
147
|
-
| `detect` | 마지막 배포 시점과 현재 저장소의 변경 사항을 비교하여 증분 업데이트 필요 여부와 대상 섹션을 파악합니다. |
|
|
104
|
+
1. **변경 사항 감지**: `portki detect --repo owner/repo`
|
|
105
|
+
- 변경이 없으면 건너뜀 (`noop`)
|
|
106
|
+
- 일부 변경 시 연관된 섹션만 업데이트 (`incremental`)
|
|
107
|
+
- 대규모 구조 변경 시 전체 재작성 (`full-rebuild`)
|
|
108
|
+
2. 변경된 스냅샷 수집 후 필요한 섹션만 재생성 및 병합 진행.
|
|
148
109
|
|
|
149
|
-
|
|
110
|
+
---
|
|
150
111
|
|
|
151
|
-
|
|
112
|
+
## 📂 출력 디렉토리 구조 (Output Directory)
|
|
152
113
|
|
|
153
|
-
|
|
114
|
+
모든 작업 내역과 최종 결과물은 프로젝트 루트를 오염시키지 않도록 `portki-output/` 폴더에 안전하게 저장됩니다. (기본적으로 `.gitignore`에 포함됩니다.)
|
|
154
115
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
#
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
#
|
|
162
|
-
# (에이전트가 validate-plan, persist-section, finalize를 자동으로 실행)
|
|
163
|
-
|
|
164
|
-
# 3. 진행 상황 확인 (선택)
|
|
165
|
-
portki status owner/repo
|
|
166
|
-
|
|
167
|
-
# 4. 중단 시 복구 (선택)
|
|
168
|
-
portki resume owner/repo
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
### 2. 수동 청크 단위 위키 생성
|
|
172
|
-
|
|
173
|
-
저장소를 분석하여 여러 섹션으로 분리한 후 각 섹션별로 코드를 깊이 있게 확인하고 작성하는 방식입니다.
|
|
174
|
-
|
|
175
|
-
```bash
|
|
176
|
-
# 1. 저장소 스냅샷 수집
|
|
177
|
-
portki ingest --repo owner/repo --out devport-output/workspace/{repo-slug}-artifact.json
|
|
178
|
-
|
|
179
|
-
# 2. 분석 및 섹션 계획 수립 준비 (컨텍스트 생성)
|
|
180
|
-
portki plan-sections --artifact devport-output/workspace/{repo-slug}-artifact.json --out devport-output/workspace/{repo-slug}-plan-context.json
|
|
181
|
-
|
|
182
|
-
# (AI 작업: plan-context.json과 주요 코드를 바탕으로 {repo-slug}-section-plan.json 생성)
|
|
183
|
-
|
|
184
|
-
# 3. 플랜 검증
|
|
185
|
-
portki validate-plan --input devport-output/workspace/{repo-slug}-section-plan.json --context devport-output/workspace/{repo-slug}-plan-context.json --out devport-output/workspace/{repo-slug}-section-plan.json
|
|
186
|
-
|
|
187
|
-
# 4. 각 섹션별 작성 및 세션 반영 (전체 섹션 완료 시까지 반복)
|
|
188
|
-
# (AI 작업: 해당 섹션의 코드를 분석하고 {repo-slug}-section-1-output.json 생성)
|
|
189
|
-
portki persist-section --plan devport-output/workspace/{repo-slug}-section-plan.json --section sec-1 --input devport-output/workspace/{repo-slug}-section-1-output.json
|
|
190
|
-
|
|
191
|
-
# 5. 최종 완성 및 증분 베이스라인 갱신
|
|
192
|
-
portki finalize --plan devport-output/workspace/{repo-slug}-section-plan.json --advance_baseline
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
`finalize`가 완료되면 `devport-output/wiki/{owner}/{repo}/README.md`와 섹션별 Markdown 파일이 생성됩니다.
|
|
196
|
-
|
|
197
|
-
### 3. 증분 업데이트 (Incremental Update)
|
|
198
|
-
|
|
199
|
-
이전에 작성 완료된 위키를 바탕으로 변경된 파일들만 식별하여 최신화합니다.
|
|
200
|
-
|
|
201
|
-
```bash
|
|
202
|
-
# 1. 변경사항 감지
|
|
203
|
-
portki detect --repo owner/repo
|
|
204
|
-
# 반환된 JSON의 status에 따라 분기:
|
|
205
|
-
# - noop: 변경점 없음 (수정 불필요)
|
|
206
|
-
# - incremental: 변경된 코드와 영향을 받는 섹션(impacted_section_ids)만 재생성
|
|
207
|
-
# - full-rebuild: 너무 많은 변화로 인해 전체 위키 재작성 필요
|
|
208
|
-
|
|
209
|
-
# 2. 재생성 필요 시 최신 코드로 스냅샷 다시 수집
|
|
210
|
-
portki ingest --repo owner/repo --out devport-output/workspace/{repo-slug}-artifact.json
|
|
211
|
-
|
|
212
|
-
# (이후 영향을 받는 섹션만 다시 작성하여 persist-section 후 finalize 수행)
|
|
116
|
+
```text
|
|
117
|
+
portki-output/
|
|
118
|
+
├── workspace/ # AI 에이전트용 중간 작업 파일 (*.json)
|
|
119
|
+
├── snapshots/owner/repo/ # 원본 코드 스냅샷 (직접 수정 금지)
|
|
120
|
+
├── chunked/owner/repo/ # 섹션별 작업 내역 및 세션 상태
|
|
121
|
+
├── freshness/state.json # 증분 업데이트를 위한 베이스라인 상태값
|
|
122
|
+
└── wiki/owner/repo/ # ✨ 완성된 최종 Markdown 위키
|
|
213
123
|
```
|
|
214
124
|
|
|
215
|
-
|
|
125
|
+
---
|
|
216
126
|
|
|
217
|
-
|
|
127
|
+
## 💻 권장 실행 환경
|
|
128
|
+
안정적인 위키 생성을 위해 높은 수준의 추론 능력을 가진 모델 사용을 권장합니다. *(2026년 3월 7일 기준)*
|
|
218
129
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
chunked/{owner}/{repo}/ # 진행 중인 섹션별 작업 및 세션 상태 보관 파일
|
|
225
|
-
freshness/state.json # 증분 업데이트 감지 시 사용하는 마지막 베이스라인 상태 파일
|
|
226
|
-
```
|
|
130
|
+
| 환경 | 권장 모델 | 추론(Thinking) 레벨 | 설정 파일 |
|
|
131
|
+
|---|---|---|---|
|
|
132
|
+
| **Claude Code** | `Opus 4.6` | High | [`CLAUDE.md`](./CLAUDE.md) |
|
|
133
|
+
| **Codex** | `GPT-5.4` | xHigh | [`AGENTS.md`](./AGENTS.md) |
|
|
134
|
+
| **Gemini CLI** | `gemini 3.1-pro-preview` | High | [`AGENTS.md`](./AGENTS.md) |
|
package/dist/cli.js
CHANGED
|
@@ -90,7 +90,7 @@ var resolvedIngestRefSchema = z.object({
|
|
|
90
90
|
var ingestRunInputSchema = z.object({
|
|
91
91
|
repo_ref: repoRefInputSchema,
|
|
92
92
|
force_rebuild: z.boolean().default(false),
|
|
93
|
-
snapshot_root: z.string().trim().min(1).default("
|
|
93
|
+
snapshot_root: z.string().trim().min(1).default("portki-output/snapshots"),
|
|
94
94
|
now: z.function().args().returns(z.string()).optional(),
|
|
95
95
|
fixture_commit: z.string().trim().min(4).optional()
|
|
96
96
|
}).strict();
|
|
@@ -363,7 +363,7 @@ var RepoSnapshotManager = class {
|
|
|
363
363
|
this.config = config;
|
|
364
364
|
this.now = config.now || (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
365
365
|
this.forceRebuild = Boolean(config.forceRebuild);
|
|
366
|
-
this.rootPath = path2.resolve(config.snapshotRoot || "
|
|
366
|
+
this.rootPath = path2.resolve(config.snapshotRoot || "portki-output/snapshots");
|
|
367
367
|
this.gitShell = config.gitShell || (config.sourcePath ? new LocalSourceShell(config.sourcePath) : defaultGitShell);
|
|
368
368
|
}
|
|
369
369
|
now;
|
|
@@ -3575,7 +3575,7 @@ function validateSection(section, options) {
|
|
|
3575
3575
|
import { promises as fs7 } from "node:fs";
|
|
3576
3576
|
import path10 from "node:path";
|
|
3577
3577
|
import crypto from "node:crypto";
|
|
3578
|
-
function sessionPathForRepo(repoFullName, rootDir = "
|
|
3578
|
+
function sessionPathForRepo(repoFullName, rootDir = "portki-output/chunked") {
|
|
3579
3579
|
const [owner, repo] = repoFullName.split("/");
|
|
3580
3580
|
if (!owner || !repo) {
|
|
3581
3581
|
throw new Error(`Invalid repoFullName: ${repoFullName}`);
|
|
@@ -3742,7 +3742,7 @@ function renderSectionMarkdown(section, sectionIndex, sourcePaths) {
|
|
|
3742
3742
|
return lines.join("\n").trimEnd();
|
|
3743
3743
|
}
|
|
3744
3744
|
async function writeMarkdownBundle(acceptedOutput, options = {}) {
|
|
3745
|
-
const outputDir = buildOutputDir(options.outDir ?? "
|
|
3745
|
+
const outputDir = buildOutputDir(options.outDir ?? "portki-output/wiki", acceptedOutput.repo_ref);
|
|
3746
3746
|
await mkdir(outputDir, { recursive: true });
|
|
3747
3747
|
const files = [];
|
|
3748
3748
|
const sectionFiles = acceptedOutput.draft.sections.map((section, index) => ({
|
|
@@ -3951,7 +3951,7 @@ function renderHandoff(opts) {
|
|
|
3951
3951
|
} = opts;
|
|
3952
3952
|
const step = (name, fallback) => stepOverrides?.[name] ?? fallback;
|
|
3953
3953
|
const persistedSet = new Set(persistedSections ?? []);
|
|
3954
|
-
const sectionPlanPath = `
|
|
3954
|
+
const sectionPlanPath = `portki-output/workspace/${slug}-section-plan.json`;
|
|
3955
3955
|
const profileLines = [
|
|
3956
3956
|
`- **Repo**: ${ownerRepo}`,
|
|
3957
3957
|
`- **Commit**: ${artifact.commit_sha.slice(0, 7)}`,
|
|
@@ -4046,7 +4046,7 @@ function renderHandoff(opts) {
|
|
|
4046
4046
|
"3. Persist it:",
|
|
4047
4047
|
"",
|
|
4048
4048
|
"```bash",
|
|
4049
|
-
`portki persist-section --plan ${sectionPlanPath} --section sec-N --input
|
|
4049
|
+
`portki persist-section --plan ${sectionPlanPath} --section sec-N --input portki-output/workspace/${slug}-section-N-output.json`,
|
|
4050
4050
|
"```",
|
|
4051
4051
|
""
|
|
4052
4052
|
];
|
|
@@ -4064,7 +4064,7 @@ function renderHandoff(opts) {
|
|
|
4064
4064
|
`portki finalize --plan ${sectionPlanPath} --advance_baseline`,
|
|
4065
4065
|
"```",
|
|
4066
4066
|
"",
|
|
4067
|
-
`Output will be written to \`
|
|
4067
|
+
`Output will be written to \`portki-output/wiki/${ownerRepo}/\`.`,
|
|
4068
4068
|
"",
|
|
4069
4069
|
"## Writing Rules",
|
|
4070
4070
|
"",
|
|
@@ -4087,7 +4087,7 @@ function repoSlug(ownerRepo) {
|
|
|
4087
4087
|
}
|
|
4088
4088
|
function workspacePath(ownerRepo, suffix) {
|
|
4089
4089
|
const slug = repoSlug(ownerRepo);
|
|
4090
|
-
return `
|
|
4090
|
+
return `portki-output/workspace/${slug}-${suffix}`;
|
|
4091
4091
|
}
|
|
4092
4092
|
async function wikiCommand(ownerRepo, flags) {
|
|
4093
4093
|
const parts = ownerRepo.toLowerCase().split("/");
|
|
@@ -4096,7 +4096,7 @@ async function wikiCommand(ownerRepo, flags) {
|
|
|
4096
4096
|
}
|
|
4097
4097
|
const repo = `${parts[0]}/${parts[1]}`;
|
|
4098
4098
|
const slug = repoSlug(repo);
|
|
4099
|
-
const snapshotRoot = flags["snapshot_root"] ?? "
|
|
4099
|
+
const snapshotRoot = flags["snapshot_root"] ?? "portki-output/snapshots";
|
|
4100
4100
|
process.stderr.write(`[portki] ${repo} \u2014 ingesting...
|
|
4101
4101
|
`);
|
|
4102
4102
|
const ref = flags["ref"];
|
|
@@ -4201,7 +4201,7 @@ async function statusCommand(argv) {
|
|
|
4201
4201
|
No session found yet.
|
|
4202
4202
|
`);
|
|
4203
4203
|
}
|
|
4204
|
-
const wikiReadme = `
|
|
4204
|
+
const wikiReadme = `portki-output/wiki/${repo}/README.md`;
|
|
4205
4205
|
const finalized = existsSync4(path14.resolve(wikiReadme));
|
|
4206
4206
|
const fIcon = finalized ? "+" : "-";
|
|
4207
4207
|
process.stderr.write(` [${fIcon}] finalized (wiki output)
|
|
@@ -4319,7 +4319,7 @@ async function doctorCommand() {
|
|
|
4319
4319
|
`
|
|
4320
4320
|
);
|
|
4321
4321
|
if (!nodeOk) allOk = false;
|
|
4322
|
-
const outputDir = path16.resolve("
|
|
4322
|
+
const outputDir = path16.resolve("portki-output");
|
|
4323
4323
|
let writable = false;
|
|
4324
4324
|
if (existsSync6(outputDir)) {
|
|
4325
4325
|
try {
|
|
@@ -4331,11 +4331,11 @@ async function doctorCommand() {
|
|
|
4331
4331
|
writable = true;
|
|
4332
4332
|
}
|
|
4333
4333
|
process.stderr.write(
|
|
4334
|
-
` ${writable ? "ok" : "FAIL"}
|
|
4334
|
+
` ${writable ? "ok" : "FAIL"} portki-output/ ${existsSync6(outputDir) ? "writable" : "will be created on first run"}
|
|
4335
4335
|
`
|
|
4336
4336
|
);
|
|
4337
4337
|
if (!writable) allOk = false;
|
|
4338
|
-
const chunkedDir = path16.resolve("
|
|
4338
|
+
const chunkedDir = path16.resolve("portki-output/chunked");
|
|
4339
4339
|
let sessionCount = 0;
|
|
4340
4340
|
if (existsSync6(chunkedDir)) {
|
|
4341
4341
|
try {
|
|
@@ -4580,7 +4580,7 @@ function resolveQualityGateLevel(flags, defaultLevel) {
|
|
|
4580
4580
|
}
|
|
4581
4581
|
async function ingestCommand(flags) {
|
|
4582
4582
|
const { repo, ref } = parseRepo(requireFlag(flags, "repo"), flags["ref"]);
|
|
4583
|
-
const snapshotRoot = flags["snapshot_root"] ?? "
|
|
4583
|
+
const snapshotRoot = flags["snapshot_root"] ?? "portki-output/snapshots";
|
|
4584
4584
|
const outFile = flags["out"];
|
|
4585
4585
|
process.stderr.write(`[devport-agent] ingest: ${repo}${ref ? `@${ref}` : ""}
|
|
4586
4586
|
`);
|
|
@@ -4615,7 +4615,7 @@ async function detectCommand(flags) {
|
|
|
4615
4615
|
throw new Error(`--repo must be owner/repo, got: ${repoFlag}`);
|
|
4616
4616
|
}
|
|
4617
4617
|
const repoRef = `${parts[0]}/${parts[1]}`;
|
|
4618
|
-
const statePath = flags["state_path"] ?? "
|
|
4618
|
+
const statePath = flags["state_path"] ?? "portki-output/freshness/state.json";
|
|
4619
4619
|
process.stderr.write(`[devport-agent] detect: ${repoRef}
|
|
4620
4620
|
`);
|
|
4621
4621
|
const state = await loadFreshnessState(statePath);
|
|
@@ -4686,10 +4686,10 @@ async function detectCommand(flags) {
|
|
|
4686
4686
|
);
|
|
4687
4687
|
}
|
|
4688
4688
|
async function packageCommand(flags) {
|
|
4689
|
-
const outDir = flags["out_dir"] ?? "
|
|
4689
|
+
const outDir = flags["out_dir"] ?? "portki-output/wiki";
|
|
4690
4690
|
const inputFile = flags["input"];
|
|
4691
4691
|
const advanceBaseline = flags["advance_baseline"] === "true";
|
|
4692
|
-
const statePath = flags["state_path"] ?? "
|
|
4692
|
+
const statePath = flags["state_path"] ?? "portki-output/freshness/state.json";
|
|
4693
4693
|
const qualityGateLevel = resolveQualityGateLevel(flags, getQualityGateLevel(process.env));
|
|
4694
4694
|
let raw;
|
|
4695
4695
|
if (inputFile) {
|
|
@@ -4875,9 +4875,9 @@ async function finalizeCommand(flags) {
|
|
|
4875
4875
|
const planFile = requireFlag(flags, "plan");
|
|
4876
4876
|
const sessionFile = flags["session"];
|
|
4877
4877
|
const advanceBaseline = flags["advance_baseline"] === "true";
|
|
4878
|
-
const statePath = flags["state_path"] ?? "
|
|
4878
|
+
const statePath = flags["state_path"] ?? "portki-output/freshness/state.json";
|
|
4879
4879
|
const deleteSnapshot = flags["delete_snapshot"] === "true";
|
|
4880
|
-
const outDir = flags["out_dir"] ?? "
|
|
4880
|
+
const outDir = flags["out_dir"] ?? "portki-output/wiki";
|
|
4881
4881
|
const planRaw = await readFile4(path18.resolve(planFile), "utf8");
|
|
4882
4882
|
const plan = SectionPlanOutputSchema.parse(JSON.parse(planRaw));
|
|
4883
4883
|
const sessionPath = sessionFile ? path18.resolve(sessionFile) : sessionPathForRepo(plan.repoFullName);
|
|
@@ -4938,16 +4938,16 @@ function printHelp() {
|
|
|
4938
4938
|
" --repo owner/repo (required)",
|
|
4939
4939
|
" --ref branch|sha (optional, uses default branch if omitted)",
|
|
4940
4940
|
" --out artifact.json (optional, prints to stdout if omitted)",
|
|
4941
|
-
" --snapshot_root (default:
|
|
4941
|
+
" --snapshot_root (default: portki-output/snapshots)",
|
|
4942
4942
|
" --force_rebuild (re-download even if cache is valid)",
|
|
4943
4943
|
"",
|
|
4944
4944
|
" detect Detect what changed since the last delivery",
|
|
4945
4945
|
" --repo owner/repo (required)",
|
|
4946
|
-
" --state_path (default:
|
|
4946
|
+
" --state_path (default: portki-output/freshness/state.json)",
|
|
4947
4947
|
"",
|
|
4948
4948
|
" package Validate AI-generated output, write markdown wiki files",
|
|
4949
4949
|
" --input accepted-output.json (optional, reads stdin if omitted)",
|
|
4950
|
-
" --out_dir (default:
|
|
4950
|
+
" --out_dir (default: portki-output/wiki)",
|
|
4951
4951
|
" --quality_gate_level standard|strict",
|
|
4952
4952
|
" --advance_baseline save freshness state for future detect",
|
|
4953
4953
|
"",
|