@haema/cli 0.8.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 +258 -0
- package/dist/auth.js +30 -0
- package/dist/auth.js.map +1 -0
- package/dist/discoverClaudeFiles.js +132 -0
- package/dist/discoverClaudeFiles.js.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/install.js +353 -0
- package/dist/mcp/install.js.map +1 -0
- package/dist/mcp/mcpClient.js +55 -0
- package/dist/mcp/mcpClient.js.map +1 -0
- package/dist/mcp/resolveProjectId.js +27 -0
- package/dist/mcp/resolveProjectId.js.map +1 -0
- package/dist/mcp/server.js +344 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/addTask.js +15 -0
- package/dist/mcp/tools/addTask.js.map +1 -0
- package/dist/mcp/tools/applyHooks.js +110 -0
- package/dist/mcp/tools/applyHooks.js.map +1 -0
- package/dist/mcp/tools/brief.js +166 -0
- package/dist/mcp/tools/brief.js.map +1 -0
- package/dist/mcp/tools/createFolder.js +11 -0
- package/dist/mcp/tools/createFolder.js.map +1 -0
- package/dist/mcp/tools/finishTask.js +16 -0
- package/dist/mcp/tools/finishTask.js.map +1 -0
- package/dist/mcp/tools/getTask.js +31 -0
- package/dist/mcp/tools/getTask.js.map +1 -0
- package/dist/mcp/tools/listTasks.js +27 -0
- package/dist/mcp/tools/listTasks.js.map +1 -0
- package/dist/mcp/tools/loadSkill.js +8 -0
- package/dist/mcp/tools/loadSkill.js.map +1 -0
- package/dist/mcp/tools/logSession.js +13 -0
- package/dist/mcp/tools/logSession.js.map +1 -0
- package/dist/mcp/tools/recall.js +23 -0
- package/dist/mcp/tools/recall.js.map +1 -0
- package/dist/mcp/tools/signin.js +111 -0
- package/dist/mcp/tools/signin.js.map +1 -0
- package/dist/mcp/tools/signout.js +11 -0
- package/dist/mcp/tools/signout.js.map +1 -0
- package/dist/mcp/tools/startTask.js +21 -0
- package/dist/mcp/tools/startTask.js.map +1 -0
- package/dist/mcp/tools/updateTask.js +9 -0
- package/dist/mcp/tools/updateTask.js.map +1 -0
- package/dist/mcp/tools/uploadPrompt.js +32 -0
- package/dist/mcp/tools/uploadPrompt.js.map +1 -0
- package/dist/mcp/tools/whoami.js +13 -0
- package/dist/mcp/tools/whoami.js.map +1 -0
- package/dist/openBrowser.js +15 -0
- package/dist/openBrowser.js.map +1 -0
- package/dist/readClaudeFile.js +16 -0
- package/dist/readClaudeFile.js.map +1 -0
- package/dist/scanLimits.js +15 -0
- package/dist/scanLimits.js.map +1 -0
- package/package.json +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# @votra/cli
|
|
2
|
+
|
|
3
|
+
세션 간 메모리를 AI 에이전트에 제공하는 MCP 서버예요.
|
|
4
|
+
태스크 관리, 과거 결정 검색, 프롬프트 파일 업로드, 계정 관리 기능을 포함해요.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 시작하기
|
|
9
|
+
|
|
10
|
+
### 1. 설치 & MCP 등록
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm i -g @votra/cli
|
|
14
|
+
votra install
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`votra install`이 하는 것:
|
|
18
|
+
- Claude Desktop `claude_desktop_config.json`에 MCP 서버 등록
|
|
19
|
+
- `~/.claude/CLAUDE.md`에 툴 사용 가이드 추가
|
|
20
|
+
|
|
21
|
+
→ **Claude Desktop 재시작**
|
|
22
|
+
|
|
23
|
+
### 2. 로그인
|
|
24
|
+
|
|
25
|
+
Claude Desktop에서:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
signin 툴 실행해줘
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
→ 브라우저 자동 열림 → votra 계정 로그인 → `~/.votra/auth.json` 저장
|
|
32
|
+
|
|
33
|
+
### 3. 프로젝트 작업 시작
|
|
34
|
+
|
|
35
|
+
AI 에이전트가 새 세션을 열면 `brief`를 자동 호출해요.
|
|
36
|
+
**프로젝트가 없으면 cwd 기준으로 자동 등록**되므로 별도 설정 불필요.
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
brief → 컨텍스트 로드 + 현황 정리
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 유저 플로우
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
설치 → votra install → Claude Desktop 재시작
|
|
48
|
+
↓
|
|
49
|
+
signin 툴로 로그인
|
|
50
|
+
↓
|
|
51
|
+
새 세션 열 때마다 brief 자동 호출
|
|
52
|
+
(첫 진입 시 프로젝트 자동 등록)
|
|
53
|
+
↓
|
|
54
|
+
start_task → 구현 → finish_task
|
|
55
|
+
↓
|
|
56
|
+
필요 시 upload_prompt로
|
|
57
|
+
CLAUDE.md 업로드
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## MCP 툴 레퍼런스
|
|
63
|
+
|
|
64
|
+
모든 툴은 선택적으로 `cwd` 파라미터를 받아요. 여러 프로젝트를 넘나들 때 명시하면 돼요.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
### 계정 관리
|
|
69
|
+
|
|
70
|
+
#### `signin`
|
|
71
|
+
|
|
72
|
+
votra 계정에 로그인해요. 브라우저가 자동으로 열리고 로그인 후 `~/.votra/auth.json`에 저장돼요.
|
|
73
|
+
|
|
74
|
+
| 파라미터 | 타입 | 설명 |
|
|
75
|
+
|---------|------|------|
|
|
76
|
+
| `appUrl` | string (선택) | votra 서버 URL (기본값 자동 사용) |
|
|
77
|
+
|
|
78
|
+
#### `whoami`
|
|
79
|
+
|
|
80
|
+
현재 로그인 상태와 계정 정보를 반환해요.
|
|
81
|
+
|
|
82
|
+
#### `signout`
|
|
83
|
+
|
|
84
|
+
`~/.votra/auth.json`을 삭제해 로그아웃해요.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
### 프로젝트 컨텍스트
|
|
89
|
+
|
|
90
|
+
#### `brief`
|
|
91
|
+
|
|
92
|
+
세션 시작 브리핑. 프로젝트 태스크 현황, AI 추천 태스크, 행동 지침을 한번에 반환해요.
|
|
93
|
+
**첫 실행 시 cwd 기준으로 프로젝트를 자동 등록해요.**
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
새 대화창을 열면 반드시 brief를 먼저 호출하세요.
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
| 파라미터 | 타입 | 설명 |
|
|
100
|
+
|---------|------|------|
|
|
101
|
+
| `cwd` | string (선택) | 프로젝트 절대경로 |
|
|
102
|
+
|
|
103
|
+
#### `recall`
|
|
104
|
+
|
|
105
|
+
의미 유사도로 과거 결정 사항과 인사이트를 검색해요.
|
|
106
|
+
|
|
107
|
+
| 파라미터 | 타입 | 설명 |
|
|
108
|
+
|---------|------|------|
|
|
109
|
+
| `query` | string (필수) | 검색 쿼리 |
|
|
110
|
+
| `limit` | number (선택) | 최대 결과 수 (기본 10) |
|
|
111
|
+
| `cwd` | string (선택) | 프로젝트 절대경로 |
|
|
112
|
+
|
|
113
|
+
#### `upload_prompt`
|
|
114
|
+
|
|
115
|
+
현재 프로젝트의 `CLAUDE.md` / `AGENTS.md` / `SKILL.md`를 스캔해 votra 서버로 업로드해요.
|
|
116
|
+
Claude Files 탭에서 AI 정책 평가 결과를 확인할 수 있어요.
|
|
117
|
+
|
|
118
|
+
| 파라미터 | 타입 | 설명 |
|
|
119
|
+
|---------|------|------|
|
|
120
|
+
| `cwd` | string (필수) | 프로젝트 절대경로 |
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
### 태스크 관리
|
|
125
|
+
|
|
126
|
+
#### `start_task`
|
|
127
|
+
|
|
128
|
+
태스크를 생성하고 즉시 IN_PROGRESS로 시작해요.
|
|
129
|
+
|
|
130
|
+
| 파라미터 | 타입 | 설명 |
|
|
131
|
+
|---------|------|------|
|
|
132
|
+
| `title` | string (필수) | 태스크 제목 |
|
|
133
|
+
| `description` | string (선택) | 상세 설명 |
|
|
134
|
+
| `module` | string (선택) | 모듈명 (예: auth, api, ui) |
|
|
135
|
+
| `priority` | number (선택) | 우선순위 0-10 |
|
|
136
|
+
| `cwd` | string (선택) | 프로젝트 절대경로 |
|
|
137
|
+
|
|
138
|
+
#### `add_task`
|
|
139
|
+
|
|
140
|
+
태스크를 PENDING 상태로 등록해요.
|
|
141
|
+
|
|
142
|
+
| 파라미터 | 타입 | 설명 |
|
|
143
|
+
|---------|------|------|
|
|
144
|
+
| `title` | string (필수) | 태스크 제목 |
|
|
145
|
+
| `description` | string (선택) | 상세 설명 |
|
|
146
|
+
| `module` | string (선택) | 모듈명 |
|
|
147
|
+
| `priority` | number (선택) | 우선순위 0-10 |
|
|
148
|
+
| `cwd` | string (선택) | 프로젝트 절대경로 |
|
|
149
|
+
|
|
150
|
+
#### `update_task`
|
|
151
|
+
|
|
152
|
+
태스크 상태나 내용을 변경해요.
|
|
153
|
+
|
|
154
|
+
| 파라미터 | 타입 | 설명 |
|
|
155
|
+
|---------|------|------|
|
|
156
|
+
| `taskSeq` | number (필수) | 태스크 번호 (`#42` 형태) |
|
|
157
|
+
| `status` | string (선택) | `PENDING` \| `IN_PROGRESS` \| `DONE` \| `CANCELLED` |
|
|
158
|
+
| `title` | string (선택) | 새 제목 |
|
|
159
|
+
| `description` | string (선택) | 새 설명 |
|
|
160
|
+
| `module` | string (선택) | 새 모듈명 |
|
|
161
|
+
| `priority` | number (선택) | 새 우선순위 |
|
|
162
|
+
|
|
163
|
+
#### `finish_task`
|
|
164
|
+
|
|
165
|
+
태스크를 DONE으로 완료하고 세션 요약을 저장해요.
|
|
166
|
+
|
|
167
|
+
| 파라미터 | 타입 | 설명 |
|
|
168
|
+
|---------|------|------|
|
|
169
|
+
| `taskSeq` | number (필수) | 완료할 태스크 번호 |
|
|
170
|
+
| `summary` | string (필수) | 이번 세션 작업 요약 (2-5문장) |
|
|
171
|
+
| `keyDecisions` | string[] (선택) | 핵심 결정/인사이트 — recall 검색 대상 |
|
|
172
|
+
| `outcome` | string (선택) | 구현/변경 내용 서술 (수정 파일 경로 포함 권장) |
|
|
173
|
+
| `aiTool` | string (선택) | `claude` \| `cursor` \| `gemini` \| `codex` |
|
|
174
|
+
| `cwd` | string (선택) | 프로젝트 절대경로 |
|
|
175
|
+
|
|
176
|
+
#### `list_tasks`
|
|
177
|
+
|
|
178
|
+
태스크 목록을 조회해요.
|
|
179
|
+
|
|
180
|
+
| 파라미터 | 타입 | 설명 |
|
|
181
|
+
|---------|------|------|
|
|
182
|
+
| `status` | string (선택) | `PENDING` \| `IN_PROGRESS` \| `DONE` \| `CANCELLED` |
|
|
183
|
+
| `module` | string (선택) | 모듈 필터 |
|
|
184
|
+
| `cwd` | string (선택) | 프로젝트 절대경로 |
|
|
185
|
+
|
|
186
|
+
#### `log_session`
|
|
187
|
+
|
|
188
|
+
세션 종료 전 작업 요약을 저장해요.
|
|
189
|
+
|
|
190
|
+
| 파라미터 | 타입 | 설명 |
|
|
191
|
+
|---------|------|------|
|
|
192
|
+
| `summary` | string (필수) | 이번 세션 작업 요약 (2-5문장) |
|
|
193
|
+
| `aiTool` | string (선택) | `claude` \| `cursor` \| `gemini` \| `codex` |
|
|
194
|
+
| `cwd` | string (선택) | 프로젝트 절대경로 |
|
|
195
|
+
|
|
196
|
+
#### `load_skill`
|
|
197
|
+
|
|
198
|
+
스킬의 전체 지침을 로드해요. `brief` 응답에 나열된 스킬을 맥락에 맞게 호출하세요.
|
|
199
|
+
|
|
200
|
+
| 파라미터 | 타입 | 설명 |
|
|
201
|
+
|---------|------|------|
|
|
202
|
+
| `slug` | string (필수) | 스킬 슬러그 (예: `planner`, `reviewer`) |
|
|
203
|
+
| `cwd` | string (선택) | 프로젝트 절대경로 |
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## 권장 워크플로우
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
세션 시작 → brief
|
|
211
|
+
작업 시작 → start_task
|
|
212
|
+
탐색 → recall "관련 결정 검색"
|
|
213
|
+
구현
|
|
214
|
+
완료 → finish_task (outcome에 수정 파일 경로 포함)
|
|
215
|
+
세션 종료 → log_session
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## 구조
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
src/
|
|
224
|
+
├─ index.ts 진입점 (install | MCP 서버 시작)
|
|
225
|
+
├─ auth.ts ~/.votra/auth.json 읽기/쓰기
|
|
226
|
+
├─ mcp/
|
|
227
|
+
│ ├─ server.ts MCP 서버 (stdio / HTTP transport)
|
|
228
|
+
│ ├─ mcpClient.ts votra API 클라이언트
|
|
229
|
+
│ ├─ resolveProjectId.ts cwd → projectId (없으면 자동 등록)
|
|
230
|
+
│ ├─ install.ts Claude Desktop MCP 등록 + CLAUDE.md 주입
|
|
231
|
+
│ └─ tools/
|
|
232
|
+
│ ├─ brief.ts 세션 시작 브리핑
|
|
233
|
+
│ ├─ recall.ts 의미 검색
|
|
234
|
+
│ ├─ addTask.ts 태스크 등록
|
|
235
|
+
│ ├─ startTask.ts 태스크 생성 + IN_PROGRESS
|
|
236
|
+
│ ├─ updateTask.ts 태스크 상태/내용 변경
|
|
237
|
+
│ ├─ finishTask.ts 태스크 완료 + 세션 요약
|
|
238
|
+
│ ├─ listTasks.ts 태스크 목록 조회
|
|
239
|
+
│ ├─ logSession.ts 세션 요약 저장
|
|
240
|
+
│ ├─ loadSkill.ts 스킬 지침 로드
|
|
241
|
+
│ ├─ signin.ts 브라우저 OAuth 로그인
|
|
242
|
+
│ ├─ whoami.ts 로그인 계정 확인
|
|
243
|
+
│ ├─ signout.ts 로그아웃
|
|
244
|
+
│ └─ uploadPrompt.ts CLAUDE.md 등 업로드
|
|
245
|
+
├─ discoverClaudeFiles.ts 프로젝트 내 claude files 탐색
|
|
246
|
+
├─ readClaudeFile.ts 파일 읽기 + mtime
|
|
247
|
+
└─ openBrowser.ts OS별 브라우저 열기
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## 개발
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
npm install
|
|
256
|
+
npm run typecheck # tsc --noEmit
|
|
257
|
+
npm run build # dist/ 생성 (prebuild에서 자동 정리)
|
|
258
|
+
```
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
const AUTH_DIR = path.join(homedir(), ".haema");
|
|
5
|
+
const AUTH_FILE = path.join(AUTH_DIR, "auth.json");
|
|
6
|
+
export function authFilePath() {
|
|
7
|
+
return AUTH_FILE;
|
|
8
|
+
}
|
|
9
|
+
export async function readAuth() {
|
|
10
|
+
try {
|
|
11
|
+
const raw = await fs.readFile(AUTH_FILE, "utf8");
|
|
12
|
+
const data = JSON.parse(raw);
|
|
13
|
+
if (typeof data.appUrl !== "string" || typeof data.apiKey !== "string")
|
|
14
|
+
return null;
|
|
15
|
+
return {
|
|
16
|
+
appUrl: data.appUrl,
|
|
17
|
+
apiKey: data.apiKey,
|
|
18
|
+
email: typeof data.email === "string" ? data.email : undefined,
|
|
19
|
+
signedInAt: typeof data.signedInAt === "string" ? data.signedInAt : "",
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export async function writeAuth(auth) {
|
|
27
|
+
await fs.mkdir(AUTH_DIR, { recursive: true, mode: 0o700 });
|
|
28
|
+
await fs.writeFile(AUTH_FILE, JSON.stringify(auth, null, 2), { mode: 0o600 });
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;AAChD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;AASnD,MAAM,UAAU,YAAY;IAC1B,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ;IAC5B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACjD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAkB,CAAC;QAC9C,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QACpF,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,KAAK,EAAE,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;YAC9D,UAAU,EAAE,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE;SACvE,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAU;IACxC,MAAM,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3D,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAChF,CAAC"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { readdir } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join, relative, sep } from "node:path";
|
|
4
|
+
import { MAX_DEPTH, MAX_ENTRIES, SKIP_DIRS } from "./scanLimits.js";
|
|
5
|
+
const ROOT_FILE_KIND = {
|
|
6
|
+
"CLAUDE.md": "CLAUDE",
|
|
7
|
+
"CLAUDE.local.md": "CLAUDE",
|
|
8
|
+
"AGENTS.md": "AGENTS",
|
|
9
|
+
};
|
|
10
|
+
const NESTED_FILE_KIND = {
|
|
11
|
+
"CLAUDE.md": "CLAUDE",
|
|
12
|
+
"CLAUDE.local.md": "CLAUDE",
|
|
13
|
+
"AGENTS.md": "AGENTS",
|
|
14
|
+
"SKILL.md": "SKILL",
|
|
15
|
+
};
|
|
16
|
+
export async function discoverClaudeFiles(cwd) {
|
|
17
|
+
const results = [];
|
|
18
|
+
await collectGlobal(results);
|
|
19
|
+
await collectProjectRoot(results, cwd);
|
|
20
|
+
await collectSubdir(results, cwd);
|
|
21
|
+
return results;
|
|
22
|
+
}
|
|
23
|
+
async function collectGlobal(out) {
|
|
24
|
+
const home = homedir();
|
|
25
|
+
await collectRootFiles(home, "~", out);
|
|
26
|
+
const dotClaude = join(home, ".claude");
|
|
27
|
+
await collectRootFiles(dotClaude, "~/.claude", out);
|
|
28
|
+
const skillsRoot = join(dotClaude, "skills");
|
|
29
|
+
await walkSkills(skillsRoot, "~/.claude/skills", out);
|
|
30
|
+
}
|
|
31
|
+
async function collectRootFiles(dir, displayPrefix, out) {
|
|
32
|
+
let entries;
|
|
33
|
+
try {
|
|
34
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
for (const e of entries) {
|
|
40
|
+
if ((e.isFile() || e.isSymbolicLink()) && e.name in ROOT_FILE_KIND) {
|
|
41
|
+
out.push({
|
|
42
|
+
absPath: join(dir, e.name),
|
|
43
|
+
displayPath: `${displayPrefix}/${e.name}`,
|
|
44
|
+
kind: ROOT_FILE_KIND[e.name],
|
|
45
|
+
scope: "global",
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function walkSkills(absDir, displayPrefix, out) {
|
|
51
|
+
let entries;
|
|
52
|
+
try {
|
|
53
|
+
entries = await readdir(absDir, { withFileTypes: true });
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
for (const e of entries) {
|
|
59
|
+
if (e.isFile() && e.name === "SKILL.md") {
|
|
60
|
+
out.push({
|
|
61
|
+
absPath: join(absDir, e.name),
|
|
62
|
+
displayPath: `${displayPrefix}/${e.name}`,
|
|
63
|
+
kind: "SKILL",
|
|
64
|
+
scope: "global",
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
else if (e.isDirectory() && !e.isSymbolicLink() && !SKIP_DIRS.has(e.name)) {
|
|
68
|
+
await walkSkills(join(absDir, e.name), `${displayPrefix}/${e.name}`, out);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async function collectProjectRoot(out, cwd) {
|
|
73
|
+
let entries;
|
|
74
|
+
try {
|
|
75
|
+
entries = await readdir(cwd, { withFileTypes: true });
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
for (const e of entries) {
|
|
81
|
+
if ((e.isFile() || e.isSymbolicLink()) && e.name in ROOT_FILE_KIND) {
|
|
82
|
+
out.push({
|
|
83
|
+
absPath: join(cwd, e.name),
|
|
84
|
+
displayPath: e.name,
|
|
85
|
+
kind: ROOT_FILE_KIND[e.name],
|
|
86
|
+
scope: "project-root",
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async function collectSubdir(out, cwd) {
|
|
92
|
+
const counter = { count: 0 };
|
|
93
|
+
await walkSubdir(cwd, cwd, 0, counter, out);
|
|
94
|
+
}
|
|
95
|
+
async function walkSubdir(absDir, cwd, depth, counter, out) {
|
|
96
|
+
if (depth > MAX_DEPTH || counter.count > MAX_ENTRIES)
|
|
97
|
+
return;
|
|
98
|
+
let entries;
|
|
99
|
+
try {
|
|
100
|
+
entries = await readdir(absDir, { withFileTypes: true });
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
for (const e of entries) {
|
|
106
|
+
counter.count += 1;
|
|
107
|
+
if (counter.count > MAX_ENTRIES)
|
|
108
|
+
break;
|
|
109
|
+
if (e.isSymbolicLink())
|
|
110
|
+
continue;
|
|
111
|
+
if (e.isFile()) {
|
|
112
|
+
if (depth === 0)
|
|
113
|
+
continue;
|
|
114
|
+
const kind = NESTED_FILE_KIND[e.name];
|
|
115
|
+
if (!kind)
|
|
116
|
+
continue;
|
|
117
|
+
const abs = join(absDir, e.name);
|
|
118
|
+
out.push({
|
|
119
|
+
absPath: abs,
|
|
120
|
+
displayPath: relative(cwd, abs).split(sep).join("/"),
|
|
121
|
+
kind,
|
|
122
|
+
scope: "subdir",
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
else if (e.isDirectory()) {
|
|
126
|
+
if (SKIP_DIRS.has(e.name))
|
|
127
|
+
continue;
|
|
128
|
+
await walkSubdir(join(absDir, e.name), cwd, depth + 1, counter, out);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=discoverClaudeFiles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discoverClaudeFiles.js","sourceRoot":"","sources":["../src/discoverClaudeFiles.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { installCommand } from "./mcp/install.js";
|
|
3
|
+
import { readMcpConfig } from "./mcp/mcpClient.js";
|
|
4
|
+
import { startHttp, startStdio } from "./mcp/server.js";
|
|
5
|
+
const args = process.argv.slice(2);
|
|
6
|
+
if (args[0] === "install") {
|
|
7
|
+
installCommand(args[1]).catch((e) => {
|
|
8
|
+
console.error(e instanceof Error ? e.message : e);
|
|
9
|
+
process.exit(1);
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
const portArg = args.indexOf("--port");
|
|
14
|
+
const port = portArg !== -1 ? Number(args[portArg + 1]) : undefined;
|
|
15
|
+
const cwdArg = args.indexOf("--cwd");
|
|
16
|
+
const cwd = cwdArg !== -1 ? args[cwdArg + 1] : process.cwd();
|
|
17
|
+
readMcpConfig()
|
|
18
|
+
.catch(() => null)
|
|
19
|
+
.then((config) => {
|
|
20
|
+
if (port !== undefined)
|
|
21
|
+
return startHttp(port, config, cwd);
|
|
22
|
+
return startStdio(config, cwd);
|
|
23
|
+
})
|
|
24
|
+
.catch((e) => {
|
|
25
|
+
console.error(e instanceof Error ? e.message : e);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAExD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;IAC1B,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;QAClC,OAAO,CAAC,KAAK,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;KAAM,CAAC;IACN,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACpE,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACrC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;IAE7D,aAAa,EAAE;SACZ,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;SACjB,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;QACf,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;QAC5D,OAAO,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,CAAC,CAAC;SACD,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;QACX,OAAO,CAAC,KAAK,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACP,CAAC"}
|