@taejung3852/project-scaffold 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.hooks/convention-check.sh +79 -0
- package/.hooks/devlog-auto.sh +55 -0
- package/.obsidian-template/appearance.json +6 -0
- package/.obsidian-template/core-plugins.json +20 -0
- package/.obsidian-template/graph.json +22 -0
- package/.obsidian-template/snippets/folder-colors.css +55 -0
- package/AGENT.md +55 -0
- package/README.kr.md +247 -0
- package/README.md +247 -0
- package/SOUL.md +54 -0
- package/THIRD_PARTY_NOTICES.md +14 -0
- package/bin/project-scaffold.js +122 -0
- package/lib/agents-registry.js +197 -0
- package/lib/agents.js +203 -0
- package/lib/install.js +342 -0
- package/package.json +33 -0
- package/skills/brief/SKILL.md +63 -0
- package/skills/brief/agents/openai.yaml +4 -0
- package/skills/brief/references/dashboard.md +140 -0
- package/skills/brief/references/handoff.md +130 -0
- package/skills/brief/references/report.md +163 -0
- package/skills/review/SKILL.md +123 -0
- package/skills/review/agents/openai.yaml +4 -0
- package/skills/wiki/SKILL.md +73 -0
- package/skills/wiki/agents/openai.yaml +4 -0
- package/skills/wiki/references/ambiguity-check.md +16 -0
- package/skills/wiki/references/capture.md +119 -0
- package/skills/wiki/references/clear-path.md +82 -0
- package/skills/wiki/references/devlog.md +111 -0
- package/skills/wiki/references/ingest.md +118 -0
- package/skills/wiki/references/lint.md +83 -0
- package/skills/wiki/references/query.md +81 -0
- package/skills/wiki/references/setup.md +397 -0
- package/skills/wiki/references/unclear-path.md +51 -0
- package/templates/gitignore +14 -0
package/README.md
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/taejung3852/project-scaffold/master/assets/logo.png" width="200" alt="project-scaffold logo" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# project-scaffold
|
|
6
|
+
|
|
7
|
+
> An LLM Wiki-based development context layer that gives AI project memory and gives humans back project control
|
|
8
|
+
|
|
9
|
+
[](https://nodejs.org/)
|
|
10
|
+
[](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f)
|
|
11
|
+
[](./skills)
|
|
12
|
+
|
|
13
|
+
<p align="center">English | <a href="README.kr.md">한국어</a></p>
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## What it solves
|
|
18
|
+
|
|
19
|
+
AI coding agents move quickly, but new sessions often lose the project's character, earlier decisions, user preferences, and overall work history. Repeating all of that in a long prompt is expensive and hard for humans to follow.
|
|
20
|
+
|
|
21
|
+
project-scaffold addresses this with two layers:
|
|
22
|
+
|
|
23
|
+
- **Agent Memory Layer** — accumulates project context in `raw/` and `wiki/`.
|
|
24
|
+
- **Human Control Plane** — briefs the human on the current goal, recent changes, decisions, and next action.
|
|
25
|
+
|
|
26
|
+
Users do not memorize twelve commands. The agent routes each request to one of three skills: `/wiki`, `/brief`, or `/review`.
|
|
27
|
+
|
|
28
|
+
## Quick start
|
|
29
|
+
|
|
30
|
+
Requires Node.js 20+ and a Git repository.
|
|
31
|
+
|
|
32
|
+
### New project
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
mkdir my-project && cd my-project
|
|
36
|
+
git init
|
|
37
|
+
npx @taejung3852/project-scaffold@latest init --agent claude-code,codex
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Then start the project interview inside your AI agent:
|
|
41
|
+
|
|
42
|
+
```text
|
|
43
|
+
/wiki
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Because no conventions exist yet, `/wiki` recommends project setup as the first action.
|
|
47
|
+
|
|
48
|
+
### Existing project
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
cd /path/to/existing-project
|
|
52
|
+
npx @taejung3852/project-scaffold@latest add --agent claude-code,cursor
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Existing files are preserved by default. Use `--force` only when you explicitly want to replace scaffold-managed files.
|
|
56
|
+
|
|
57
|
+
When migrating from the former twelve-skill version, the following command removes legacy skills and self-evolution files. Review your diff first because customized legacy skills are also removed.
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npx @taejung3852/project-scaffold@latest add --agent claude-code,codex --force
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Add agents and verify the installation
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npx @taejung3852/project-scaffold@latest add-agent --agent codex,cursor
|
|
67
|
+
npx @taejung3852/project-scaffold@latest doctor
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Installation state is stored in `.project-scaffold/manifest.json`.
|
|
71
|
+
|
|
72
|
+
## Three core skills
|
|
73
|
+
|
|
74
|
+
### `/wiki` — project knowledge lifecycle
|
|
75
|
+
|
|
76
|
+
Calling `/wiki` by itself inspects the project and recommends what to do next. Users do not need to remember the internal capabilities below.
|
|
77
|
+
|
|
78
|
+
| Mode | Role |
|
|
79
|
+
|---|---|
|
|
80
|
+
| `setup` | Scan the codebase and run the 14-category convention interview |
|
|
81
|
+
| `capture` | Preserve meeting and decision sources in `raw/` |
|
|
82
|
+
| `devlog` | Draft a development log from git and conversation context |
|
|
83
|
+
| `ingest` | Compile pending raw sources into the structured wiki |
|
|
84
|
+
| `query` | Answer from project character, previous decisions, and records |
|
|
85
|
+
| `lint` | Detect broken links, orphan pages, contradictions, and stale knowledge |
|
|
86
|
+
|
|
87
|
+
```text
|
|
88
|
+
/wiki
|
|
89
|
+
Why did we choose this architecture?
|
|
90
|
+
Record this decision.
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### `/brief` — human-centered briefing
|
|
94
|
+
|
|
95
|
+
Calling `/brief` by itself inspects recent git and devlog context, then puts the most relevant briefing action first.
|
|
96
|
+
|
|
97
|
+
The default briefing answers:
|
|
98
|
+
|
|
99
|
+
1. What are we doing now?
|
|
100
|
+
2. Why are we doing it?
|
|
101
|
+
3. What changed since the last check-in?
|
|
102
|
+
4. What does the human need to decide?
|
|
103
|
+
5. What is the next action?
|
|
104
|
+
6. Where is the supporting evidence?
|
|
105
|
+
|
|
106
|
+
| Mode | Role |
|
|
107
|
+
|---|---|
|
|
108
|
+
| default | 30-second briefing, expandable to five-minute or deep views |
|
|
109
|
+
| `dashboard` | Refresh TODOs, milestones, recent devlogs, and warnings |
|
|
110
|
+
| `report` | Create meeting, interview, ADR, or sprint reports |
|
|
111
|
+
| `handoff` | Save and restore context for another session or agent |
|
|
112
|
+
|
|
113
|
+
```text
|
|
114
|
+
/brief
|
|
115
|
+
Explain the recent changes in detail.
|
|
116
|
+
Leave a handoff for the next session.
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### `/review` — convention-grounded change review
|
|
120
|
+
|
|
121
|
+
Combines static analysis with LLM review against `wiki/conventions/`:
|
|
122
|
+
|
|
123
|
+
- naming and architecture dependencies
|
|
124
|
+
- missing tests
|
|
125
|
+
- error handling
|
|
126
|
+
- security and hard-coded secrets
|
|
127
|
+
- project-specific review rules
|
|
128
|
+
|
|
129
|
+
It reports evidence and proposed fixes without automatically changing the code.
|
|
130
|
+
|
|
131
|
+
## Users do not need to remember skill names
|
|
132
|
+
|
|
133
|
+
`AGENT.md` acts as the intent router.
|
|
134
|
+
|
|
135
|
+
| User request | Agent behavior |
|
|
136
|
+
|---|---|
|
|
137
|
+
| “Where are we now?” | `/brief` |
|
|
138
|
+
| “Why did we choose this database?” | `/wiki` routes to project Q&A |
|
|
139
|
+
| “Record this decision.” | `/wiki` routes to decision capture |
|
|
140
|
+
| “Summarize today's work.” | `/wiki` routes to devlog |
|
|
141
|
+
| “Review this before the PR.” | `/review` |
|
|
142
|
+
|
|
143
|
+
Every agent adapter uses `AGENT.md` as the shared source of truth.
|
|
144
|
+
|
|
145
|
+
## LLM Wiki structure
|
|
146
|
+
|
|
147
|
+
```text
|
|
148
|
+
raw/ immutable human-authored sources
|
|
149
|
+
└─ compiled by /wiki when appropriate
|
|
150
|
+
wiki/ agent-maintained project knowledge
|
|
151
|
+
├─ conventions/ project rules
|
|
152
|
+
├─ decisions/ technical and product decisions
|
|
153
|
+
├─ devlog/ curated development history
|
|
154
|
+
├─ sources/ raw source summaries
|
|
155
|
+
├─ synthesis/ answers connecting multiple documents
|
|
156
|
+
├─ index.md navigation entry point
|
|
157
|
+
├─ dashboard.md current state
|
|
158
|
+
└─ log.md wiki operation history
|
|
159
|
+
AGENT.md intent routing and invariant project rules
|
|
160
|
+
SOUL.md user preferences and assistant persona
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
The body of `raw/` is immutable. When the wiki finds a contradiction, it preserves both sources instead of silently replacing one.
|
|
164
|
+
|
|
165
|
+
## Supported agents
|
|
166
|
+
|
|
167
|
+
The CLI supports all 73 agent IDs and project paths from the official [`skills@1.5.16`](https://github.com/vercel-labs/skills) registry.
|
|
168
|
+
|
|
169
|
+
| Path type | Examples |
|
|
170
|
+
|---|---|
|
|
171
|
+
| shared `.agents/skills/` | Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode, Amp, Warp, Zed, and others |
|
|
172
|
+
| `.claude/skills/` | Claude Code |
|
|
173
|
+
| `.continue/skills/` | Continue |
|
|
174
|
+
| `.hermes/skills/` | Hermes Agent |
|
|
175
|
+
| `.windsurf/skills/` | Windsurf |
|
|
176
|
+
| other dedicated paths | Goose, Kiro CLI, Roo Code, Qwen Code, AiderDesk, and others |
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
npx @taejung3852/project-scaffold@latest agents
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Use this command to see every ID and path. `--agent all` and `--agent '*'` are also supported.
|
|
183
|
+
|
|
184
|
+
The CLI installs canonical `skills/{wiki,brief,review}` once and deduplicates agents that share the same target directory. Without `--agent`, it recommends reliably detected local agents and falls back to universal `.agents/skills/` when none are found. Existing aliases such as `claude` and `hermes` remain supported.
|
|
185
|
+
|
|
186
|
+
## Installed structure
|
|
187
|
+
|
|
188
|
+
```text
|
|
189
|
+
[your-project]/
|
|
190
|
+
├── .project-scaffold/manifest.json
|
|
191
|
+
├── AGENT.md
|
|
192
|
+
├── SOUL.md
|
|
193
|
+
├── skills/
|
|
194
|
+
│ ├── wiki/
|
|
195
|
+
│ │ ├── SKILL.md
|
|
196
|
+
│ │ └── references/
|
|
197
|
+
│ ├── brief/
|
|
198
|
+
│ │ ├── SKILL.md
|
|
199
|
+
│ │ └── references/
|
|
200
|
+
│ └── review/SKILL.md
|
|
201
|
+
├── wiki/
|
|
202
|
+
│ ├── index.md
|
|
203
|
+
│ ├── dashboard.md
|
|
204
|
+
│ ├── log.md
|
|
205
|
+
│ └── devlog/
|
|
206
|
+
├── raw/
|
|
207
|
+
└── .hooks/
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
The Node CLI is the only installer entry point. The legacy shell installers have been removed.
|
|
211
|
+
|
|
212
|
+
## Git hooks
|
|
213
|
+
|
|
214
|
+
- `pre-commit` — checks staged blobs for secrets and available static-analysis rules, handles spaces safely, and never downloads tools
|
|
215
|
+
- `post-commit` — records commit messages and changed files as stable Markdown under `raw/dev-logs/`
|
|
216
|
+
|
|
217
|
+
Existing hooks are preserved by default.
|
|
218
|
+
|
|
219
|
+
## Obsidian and Graphify
|
|
220
|
+
|
|
221
|
+
- Open `wiki/` as an Obsidian vault for human navigation.
|
|
222
|
+
- When Graphify is installed, update the knowledge graph after wiki changes.
|
|
223
|
+
- Both are optional; the core LLM Wiki workflow works without them.
|
|
224
|
+
|
|
225
|
+
## Development and release
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
npm test
|
|
229
|
+
npm run check
|
|
230
|
+
npm pack --dry-run
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Publish only after the full feature and documentation pass is complete.
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
npm publish --access public
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Current status
|
|
240
|
+
|
|
241
|
+
| Item | Status |
|
|
242
|
+
|---|---|
|
|
243
|
+
| Node CLI (`init`, `add`, `add-agent`, `agents`, `doctor`) | ✅ Implemented |
|
|
244
|
+
| 73-agent registry based on skills@1.5.16 | ✅ Implemented |
|
|
245
|
+
| Three core skills (`wiki`, `brief`, `review`) | ✅ Implemented |
|
|
246
|
+
| Hermes-style usage tracking and self-evolution | 🗑️ Removed |
|
|
247
|
+
| Initial npm publish | ⏳ After all planned changes |
|
package/SOUL.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# SOUL.md — AI 비서 페르소나
|
|
2
|
+
|
|
3
|
+
> 개인 설정 파일입니다. `/wiki`의 초기 설정이 AGENT.md를 갱신해도 이 파일은 변경되지 않습니다.
|
|
4
|
+
> 초기 설정 카테고리 14에서 설정하거나 직접 수정하세요.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 말투
|
|
9
|
+
|
|
10
|
+
| 항목 | 설정 |
|
|
11
|
+
|---|---|
|
|
12
|
+
| 격식 | 비격식체 (반말 허용) |
|
|
13
|
+
| 길이 | 간결하게. 요약 없이 핵심만 |
|
|
14
|
+
| 어조 | 동료처럼. 지시하지 않고 함께 고민 |
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 전문성 가정
|
|
19
|
+
|
|
20
|
+
| 항목 | 설정 |
|
|
21
|
+
|---|---|
|
|
22
|
+
| 기본 수준 | 개발 기초는 안다고 가정 |
|
|
23
|
+
| 설명 방식 | WHY 중심. 코드 한 줄씩 설명 금지 |
|
|
24
|
+
| 모르는 게 있으면 | 먼저 물어봐서 수준 파악 |
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 판단·피드백 방식
|
|
29
|
+
|
|
30
|
+
| 항목 | 설정 |
|
|
31
|
+
|---|---|
|
|
32
|
+
| 내가 틀렸을 때 | 바로 말해. 돌려 말하지 않아도 됨 |
|
|
33
|
+
| 선택지가 있을 때 | 추천 하나 + 이유. 목록 나열 금지 |
|
|
34
|
+
| 확신 없을 때 | 모른다고 말하고 같이 찾아 |
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 불확실·위험한 상황
|
|
39
|
+
|
|
40
|
+
| 항목 | 설정 |
|
|
41
|
+
|---|---|
|
|
42
|
+
| 파괴적 작업 | 반드시 먼저 물어봐 |
|
|
43
|
+
| 애매한 요청 | 바로 실행하지 말고 의도 확인 |
|
|
44
|
+
| 큰 변경 전 | 계획 먼저 보여주고 승인 받아 |
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 언어
|
|
49
|
+
|
|
50
|
+
| 항목 | 설정 |
|
|
51
|
+
|---|---|
|
|
52
|
+
| 기본 언어 | 한국어 |
|
|
53
|
+
| 코드·기술 용어 | 영어 원어 유지 |
|
|
54
|
+
| 영어로 질문 받으면 | 한국어로 답 |
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Third-Party Notices
|
|
2
|
+
|
|
3
|
+
## vercel-labs/skills
|
|
4
|
+
|
|
5
|
+
The agent identifiers and project skill-directory mappings in
|
|
6
|
+
`lib/agents-registry.js` are derived from `skills@1.5.16`.
|
|
7
|
+
|
|
8
|
+
- Source: https://github.com/vercel-labs/skills
|
|
9
|
+
- Package: https://www.npmjs.com/package/skills
|
|
10
|
+
- License: MIT
|
|
11
|
+
|
|
12
|
+
No runtime code from the `skills` package is bundled or executed by
|
|
13
|
+
project-scaffold. The registry is vendored so installation remains deterministic
|
|
14
|
+
and works without a nested network dependency.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import process from "node:process";
|
|
4
|
+
import { addAgents, registryLines } from "../lib/agents.js";
|
|
5
|
+
import { doctor, install } from "../lib/install.js";
|
|
6
|
+
|
|
7
|
+
const HELP = `
|
|
8
|
+
project-scaffold — LLM Wiki 기반 AI 개발 컨텍스트 설치 도구
|
|
9
|
+
|
|
10
|
+
사용법:
|
|
11
|
+
project-scaffold init [경로] [옵션] 새 프로젝트에 초기화
|
|
12
|
+
project-scaffold add [경로] [옵션] 기존 프로젝트에 설치
|
|
13
|
+
project-scaffold add-agent [경로] [옵션] 에이전트 어댑터 추가
|
|
14
|
+
project-scaffold doctor [경로] 설치 상태 검사
|
|
15
|
+
project-scaffold agents 지원 에이전트와 설치 경로 목록
|
|
16
|
+
|
|
17
|
+
옵션:
|
|
18
|
+
-a, --agent <목록> 쉼표로 구분한 에이전트 ID 또는 all
|
|
19
|
+
전체 목록: project-scaffold agents
|
|
20
|
+
-t, --target <경로> 대상 Git 저장소 경로
|
|
21
|
+
-y, --yes 질문 없이 자동 감지값 사용 (미감지 시 universal)
|
|
22
|
+
--force 기존 scaffold 관리 파일 덮어쓰기
|
|
23
|
+
--skip-hooks Git hook 설치 생략
|
|
24
|
+
--skip-graphify Graphify 등록 생략
|
|
25
|
+
--json doctor 결과를 JSON으로 출력
|
|
26
|
+
-h, --help 도움말 출력
|
|
27
|
+
|
|
28
|
+
예시:
|
|
29
|
+
npx @taejung3852/project-scaffold@latest init --agent claude-code,codex
|
|
30
|
+
npx @taejung3852/project-scaffold@latest add ~/workspace/my-app --agent all
|
|
31
|
+
npx @taejung3852/project-scaffold@latest doctor
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
function parseArgs(argv) {
|
|
35
|
+
const options = {
|
|
36
|
+
command: "help",
|
|
37
|
+
target: undefined,
|
|
38
|
+
agents: [],
|
|
39
|
+
yes: false,
|
|
40
|
+
force: false,
|
|
41
|
+
hooks: true,
|
|
42
|
+
graphify: true,
|
|
43
|
+
json: false,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const args = [...argv];
|
|
47
|
+
if (args[0] && !args[0].startsWith("-")) {
|
|
48
|
+
options.command = args.shift();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
while (args.length > 0) {
|
|
52
|
+
const arg = args.shift();
|
|
53
|
+
if (arg === "-h" || arg === "--help") {
|
|
54
|
+
options.command = "help";
|
|
55
|
+
} else if (arg === "-y" || arg === "--yes") {
|
|
56
|
+
options.yes = true;
|
|
57
|
+
} else if (arg === "--force") {
|
|
58
|
+
options.force = true;
|
|
59
|
+
} else if (arg === "--skip-hooks") {
|
|
60
|
+
options.hooks = false;
|
|
61
|
+
} else if (arg === "--skip-graphify") {
|
|
62
|
+
options.graphify = false;
|
|
63
|
+
} else if (arg === "--json") {
|
|
64
|
+
options.json = true;
|
|
65
|
+
} else if (arg === "-a" || arg === "--agent") {
|
|
66
|
+
const value = args.shift();
|
|
67
|
+
if (!value) throw new Error(`${arg} 뒤에 에이전트 목록이 필요합니다.`);
|
|
68
|
+
options.agents.push(...value.split(","));
|
|
69
|
+
} else if (arg.startsWith("--agent=")) {
|
|
70
|
+
options.agents.push(...arg.slice("--agent=".length).split(","));
|
|
71
|
+
} else if (arg === "-t" || arg === "--target") {
|
|
72
|
+
const value = args.shift();
|
|
73
|
+
if (!value) throw new Error(`${arg} 뒤에 경로가 필요합니다.`);
|
|
74
|
+
options.target = value;
|
|
75
|
+
} else if (arg.startsWith("--target=")) {
|
|
76
|
+
options.target = arg.slice("--target=".length);
|
|
77
|
+
} else if (!arg.startsWith("-") && !options.target) {
|
|
78
|
+
options.target = arg;
|
|
79
|
+
} else {
|
|
80
|
+
throw new Error(`알 수 없는 옵션: ${arg}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return options;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function main() {
|
|
88
|
+
const options = parseArgs(process.argv.slice(2));
|
|
89
|
+
|
|
90
|
+
if (options.command === "help") {
|
|
91
|
+
process.stdout.write(HELP);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (options.command === "init" || options.command === "add") {
|
|
96
|
+
await install({ ...options, mode: options.command });
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (options.command === "add-agent") {
|
|
101
|
+
await addAgents(options);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (options.command === "doctor") {
|
|
106
|
+
const result = await doctor(options);
|
|
107
|
+
if (!result.ok) process.exitCode = 1;
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (options.command === "agents") {
|
|
112
|
+
console.log(registryLines().join("\n"));
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
throw new Error(`알 수 없는 명령: ${options.command}\n${HELP}`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
main().catch((error) => {
|
|
120
|
+
console.error(`❌ ${error.message}`);
|
|
121
|
+
process.exitCode = 1;
|
|
122
|
+
});
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
export const registrySource = Object.freeze({
|
|
6
|
+
package: "skills",
|
|
7
|
+
version: "1.5.16",
|
|
8
|
+
repository: "https://github.com/vercel-labs/skills",
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const universalAgents = [
|
|
12
|
+
"amp",
|
|
13
|
+
"antigravity",
|
|
14
|
+
"antigravity-cli",
|
|
15
|
+
"cline",
|
|
16
|
+
"codex",
|
|
17
|
+
"cursor",
|
|
18
|
+
"deepagents",
|
|
19
|
+
"dexto",
|
|
20
|
+
"firebender",
|
|
21
|
+
"gemini-cli",
|
|
22
|
+
"github-copilot",
|
|
23
|
+
"kimi-code-cli",
|
|
24
|
+
"loaf",
|
|
25
|
+
"opencode",
|
|
26
|
+
"promptscript",
|
|
27
|
+
"replit",
|
|
28
|
+
"universal",
|
|
29
|
+
"warp",
|
|
30
|
+
"zed",
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
const customAgentPaths = {
|
|
34
|
+
"aider-desk": ".aider-desk/skills",
|
|
35
|
+
astrbot: "data/skills",
|
|
36
|
+
"autohand-code": ".autohand/skills",
|
|
37
|
+
augment: ".augment/skills",
|
|
38
|
+
bob: ".bob/skills",
|
|
39
|
+
"claude-code": ".claude/skills",
|
|
40
|
+
openclaw: "skills",
|
|
41
|
+
"codearts-agent": ".codeartsdoer/skills",
|
|
42
|
+
codebuddy: ".codebuddy/skills",
|
|
43
|
+
codemaker: ".codemaker/skills",
|
|
44
|
+
codestudio: ".codestudio/skills",
|
|
45
|
+
"command-code": ".commandcode/skills",
|
|
46
|
+
continue: ".continue/skills",
|
|
47
|
+
cortex: ".cortex/skills",
|
|
48
|
+
crush: ".crush/skills",
|
|
49
|
+
devin: ".devin/skills",
|
|
50
|
+
droid: ".factory/skills",
|
|
51
|
+
eve: "agent/skills",
|
|
52
|
+
forgecode: ".forge/skills",
|
|
53
|
+
goose: ".goose/skills",
|
|
54
|
+
"hermes-agent": ".hermes/skills",
|
|
55
|
+
"inference-sh": ".inferencesh/skills",
|
|
56
|
+
jazz: ".jazz/skills",
|
|
57
|
+
junie: ".junie/skills",
|
|
58
|
+
"iflow-cli": ".iflow/skills",
|
|
59
|
+
kilo: ".kilocode/skills",
|
|
60
|
+
"kiro-cli": ".kiro/skills",
|
|
61
|
+
kode: ".kode/skills",
|
|
62
|
+
lingma: ".lingma/skills",
|
|
63
|
+
mcpjam: ".mcpjam/skills",
|
|
64
|
+
"mistral-vibe": ".vibe/skills",
|
|
65
|
+
moxby: ".moxby/skills",
|
|
66
|
+
mux: ".mux/skills",
|
|
67
|
+
openhands: ".openhands/skills",
|
|
68
|
+
ona: ".ona/skills",
|
|
69
|
+
pi: ".pi/skills",
|
|
70
|
+
qoder: ".qoder/skills",
|
|
71
|
+
"qoder-cn": ".qoder/skills",
|
|
72
|
+
"qwen-code": ".qwen/skills",
|
|
73
|
+
reasonix: ".reasonix/skills",
|
|
74
|
+
rovodev: ".rovodev/skills",
|
|
75
|
+
roo: ".roo/skills",
|
|
76
|
+
"tabnine-cli": ".tabnine/agent/skills",
|
|
77
|
+
terramind: ".terramind/skills",
|
|
78
|
+
tinycloud: ".tinycloud/skills",
|
|
79
|
+
trae: ".trae/skills",
|
|
80
|
+
"trae-cn": ".trae/skills",
|
|
81
|
+
windsurf: ".windsurf/skills",
|
|
82
|
+
zcode: ".zcode/skills",
|
|
83
|
+
zencoder: ".zencoder/skills",
|
|
84
|
+
zenflow: ".zencoder/skills",
|
|
85
|
+
neovate: ".neovate/skills",
|
|
86
|
+
pochi: ".pochi/skills",
|
|
87
|
+
adal: ".adal/skills",
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const displayNameOverrides = {
|
|
91
|
+
"aider-desk": "AiderDesk",
|
|
92
|
+
"autohand-code": "Autohand Code CLI",
|
|
93
|
+
bob: "IBM Bob",
|
|
94
|
+
"claude-code": "Claude Code",
|
|
95
|
+
"codearts-agent": "CodeArts Agent",
|
|
96
|
+
codestudio: "Code Studio",
|
|
97
|
+
codex: "Codex",
|
|
98
|
+
cortex: "Cortex Code",
|
|
99
|
+
deepagents: "Deep Agents",
|
|
100
|
+
devin: "Devin for Terminal",
|
|
101
|
+
droid: "Droid",
|
|
102
|
+
"gemini-cli": "Gemini CLI",
|
|
103
|
+
"github-copilot": "GitHub Copilot",
|
|
104
|
+
"hermes-agent": "Hermes Agent",
|
|
105
|
+
"iflow-cli": "iFlow CLI",
|
|
106
|
+
"inference-sh": "inference.sh",
|
|
107
|
+
kilo: "Kilo Code",
|
|
108
|
+
"kimi-code-cli": "Kimi Code CLI",
|
|
109
|
+
"kiro-cli": "Kiro CLI",
|
|
110
|
+
"mistral-vibe": "Mistral Vibe",
|
|
111
|
+
opencode: "OpenCode",
|
|
112
|
+
openhands: "OpenHands",
|
|
113
|
+
"qoder-cn": "Qoder CN",
|
|
114
|
+
"qwen-code": "Qwen Code",
|
|
115
|
+
roo: "Roo Code",
|
|
116
|
+
"tabnine-cli": "Tabnine CLI",
|
|
117
|
+
"trae-cn": "Trae CN",
|
|
118
|
+
zcode: "ZCode",
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export const agentAliases = Object.freeze({
|
|
122
|
+
claude: "claude-code",
|
|
123
|
+
hermes: "hermes-agent",
|
|
124
|
+
"continue-dev": "continue",
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
function titleCase(id) {
|
|
128
|
+
return id
|
|
129
|
+
.split("-")
|
|
130
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
131
|
+
.join(" ");
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const entries = [
|
|
135
|
+
...universalAgents.map((id) => [id, ".agents/skills"]),
|
|
136
|
+
...Object.entries(customAgentPaths),
|
|
137
|
+
].map(([id, projectSkillsDir]) => ({
|
|
138
|
+
id,
|
|
139
|
+
displayName: displayNameOverrides[id] ?? titleCase(id),
|
|
140
|
+
projectSkillsDir,
|
|
141
|
+
}));
|
|
142
|
+
|
|
143
|
+
export const agentRegistry = Object.freeze(
|
|
144
|
+
Object.fromEntries(entries.sort((a, b) => a.id.localeCompare(b.id)).map((entry) => [entry.id, Object.freeze(entry)])),
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
export const supportedAgentIds = Object.freeze(Object.keys(agentRegistry));
|
|
148
|
+
|
|
149
|
+
export function normalizeAgentId(value) {
|
|
150
|
+
const normalized = value.trim().toLowerCase();
|
|
151
|
+
return agentAliases[normalized] ?? normalized;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function getAgent(id) {
|
|
155
|
+
return agentRegistry[normalizeAgentId(id)];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const detectionPaths = {
|
|
159
|
+
"aider-desk": ["~/.aider-desk"],
|
|
160
|
+
antigravity: ["~/.gemini/antigravity"],
|
|
161
|
+
"antigravity-cli": ["~/.gemini/antigravity-cli"],
|
|
162
|
+
"claude-code": ["~/.claude"],
|
|
163
|
+
codex: ["$CODEX_HOME", "~/.codex", "/etc/codex"],
|
|
164
|
+
continue: ["~/.continue", ".continue"],
|
|
165
|
+
cursor: ["~/.cursor", ".cursor"],
|
|
166
|
+
devin: ["~/.config/devin"],
|
|
167
|
+
droid: ["~/.factory"],
|
|
168
|
+
"gemini-cli": ["~/.gemini"],
|
|
169
|
+
goose: ["~/.config/goose"],
|
|
170
|
+
"hermes-agent": ["~/.hermes"],
|
|
171
|
+
"kiro-cli": ["~/.kiro"],
|
|
172
|
+
opencode: ["~/.config/opencode"],
|
|
173
|
+
windsurf: ["~/.codeium/windsurf"],
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
function expandDetectionPath(value, target, home, env) {
|
|
177
|
+
if (value === "$CODEX_HOME") return env.CODEX_HOME?.trim() || null;
|
|
178
|
+
if (value.startsWith("~/")) return path.join(home, value.slice(2));
|
|
179
|
+
if (path.isAbsolute(value)) return value;
|
|
180
|
+
return path.join(target, value);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export function detectAgents({ target = process.cwd(), home = os.homedir(), env = process.env } = {}) {
|
|
184
|
+
return Object.entries(detectionPaths)
|
|
185
|
+
.filter(([, candidates]) =>
|
|
186
|
+
candidates.some((candidate) => {
|
|
187
|
+
const expanded = expandDetectionPath(candidate, target, home, env);
|
|
188
|
+
return expanded ? fs.existsSync(expanded) : false;
|
|
189
|
+
}),
|
|
190
|
+
)
|
|
191
|
+
.map(([id]) => id)
|
|
192
|
+
.sort();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function uniqueProjectSkillDirs(agentIds) {
|
|
196
|
+
return [...new Set(agentIds.map((id) => getAgent(id)?.projectSkillsDir).filter(Boolean))];
|
|
197
|
+
}
|