Skip to content

Commit 73a0b07

Browse files
tae2089claude
andauthored
Remove the file-upload workspace feature; keep namespace discovery (#14)
The namespace file-workspace was a generic base64 blob store (upload/list/ delete files under a server root) — a redundant ingestion path next to local `ccg build` and webhook clone/pull, and off the project's purpose (annotation + graph + search for code context). Drop it, but keep namespace *discovery*. - delete internal/namespacefs (~500 LOC: upload/list/delete/write machinery) - remove 5 MCP tools: upload_file, upload_files, list_files, delete_file, delete_namespace (24 -> ... net 21 with the reworked tool below) - rework list_namespaces to be graph-backed: distinct namespaces with per-namespace node counts, paginated, cross-namespace; registered under the query tool group so callers can scope searches to other namespaces - relocate the namespace path-safety helpers into internal/mcp/namespace_paths.go (used by RAG doc reads), rewired onto pathutil.ValidateNamespacePath + safepath.EnsureNoSymlinkInPath; validation logic is unchanged - move the namespace-name/path validator to internal/pathutil; wikiserver uses it - sweep docs, skills, AGENTS.md, and the integration script (drop the file-upload phases; the MCP build phase relied on upload and is covered by the webhook clone->build pipeline) Path-traversal and symlink-escape checks are preserved verbatim (independently reviewed). Net -2235 lines. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 30b57de commit 73a0b07

23 files changed

Lines changed: 252 additions & 2487 deletions

.claude/skills/ccg-docs/SKILL.md

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,6 @@ User: "RAG 인덱스 만들어줘"
5656
→ Creates searchable document tree from docs + communities
5757
```
5858

59-
### Build RAG index from namespace docs
60-
```
61-
User: "my-service namespace 문서로 RAG 인덱스 만들어줘"
62-
→ upload_file(namespace: "my-service", file_path: "docs/handler.go.md", content: "<base64>")
63-
→ build_rag_index(namespace: "my-service")
64-
→ search_docs(query: "handler")
65-
→ get_doc_content(namespace: "my-service", file_path: "docs/handler.go.md")
66-
```
67-
6859
### Check documentation quality
6960
```
7061
User: "문서 상태 체크해줘"

.claude/skills/ccg-workspace/SKILL.md

Lines changed: 0 additions & 104 deletions
This file was deleted.

.claude/skills/ccg/SKILL.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ Related skills:
6060
/ccg-analyze — Code analysis & architecture
6161
/ccg-annotate — Annotation system & AI workflow
6262
/ccg-docs — Documentation & RAG indexing
63-
/ccg-workspace — Namespace file management
6463
```
6564

6665
## MCP Tools (7)

AGENTS.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@ The ccg MCP server registered in `.mcp.json` provides 33 tools:
88

99
- `parse_project`, `build_or_update_graph`, `run_postprocess`
1010
- `get_postprocess_policy`, `reset_postprocess_policy`
11-
- `get_node`, `search`, `query_graph`, `list_graph_stats`, `get_minimal_context`
11+
- `get_node`, `search`, `query_graph`, `list_graph_stats`, `list_namespaces`, `get_minimal_context`
1212
- `get_impact_radius`, `trace_flow`
1313
- `find_large_functions`, `find_dead_code`
1414
- `detect_changes`, `get_affected_flows`, `list_flows`
1515
- `list_communities`, `get_community`, `get_architecture_overview`
1616
- `get_annotation`
1717
- `build_rag_index`, `get_rag_tree`, `get_doc_content`, `search_docs`, `retrieve_docs`
18-
- `upload_file`, `upload_files`, `list_namespaces`, `list_files`, `delete_file`, `delete_namespace`
1918

2019
`ccg serve` is the local stdio MCP entry point. Self-hosted HTTP mode is provided by
2120
the separate `ccg-server` binary, which serves `/mcp`, `/health`, `/ready`, `/status`,

CLAUDE.md

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,15 @@ Follow the global prompt rules first. This file adds project-specific skill rout
66

77
## MCP 서버
88

9-
`.mcp.json`에 등록된 ccg MCP 서버가 26개 도구를 제공합니다:
9+
`.mcp.json`에 등록된 ccg MCP 서버가 21개 도구를 제공합니다:
1010

1111
- `parse_project`, `build_or_update_graph`, `run_postprocess`
1212
- `get_postprocess_policy`, `reset_postprocess_policy`
13-
- `get_node`, `search`, `query_graph`, `list_graph_stats`, `get_minimal_context`
13+
- `get_node`, `search`, `query_graph`, `list_graph_stats`, `list_namespaces`, `get_minimal_context`
1414
- `get_impact_radius`, `trace_flow`, `find_suspect_fallback_edges`
1515
- `detect_changes`, `get_affected_flows`, `list_flows`
1616
- `get_annotation`
1717
- `get_doc_content`, `search_docs`, `retrieve_docs`
18-
- `upload_file`, `upload_files`, `list_files`, `delete_file`, `list_namespaces`, `delete_namespace`
1918

2019
HTTP 모드 (`--transport streamable-http`)에서는 `/health``/webhook` 엔드포인트도 제공합니다.
2120
Webhook은 `--allow-repo` 플래그로 허용 리포지토리를 설정하면 활성화됩니다.
@@ -24,15 +23,14 @@ GitHub (`X-Hub-Signature-256`) 및 Gitea (`X-Gitea-Signature`, `X-Gitea-Event`)
2423
Push 이벤트 수신 → 자동 clone/pull → 그래프 빌드 → DB 저장 파이프라인.
2524
Graceful shutdown: SIGINT/SIGTERM 시 진행 중인 clone/build에 context cancel 전파.
2625

27-
## CLI Skills (5개)
26+
## CLI Skills (4개)
2827

29-
| Skill | 설명 |
30-
| ---------------- | ----------------------------------------------------------- |
31-
| `/ccg` | 코어 빌드 & 검색 — 파싱, 그래프 빌드, 쿼리, 검색 |
32-
| `/ccg-analyze` | 코드 분석 — 영향 반경, 플로우 추적, 데드코드, 아키텍처 |
33-
| `/ccg-annotate` | 어노테이션 시스템 — AI 어노테이션 워크플로우, 태그 레퍼런스 |
34-
| `/ccg-docs` | 문서 — 문서 생성, RAG 인덱싱, lint |
35-
| `/ccg-workspace` | 파일 워크스페이스 — 파일/워크스페이스 업로드, 목록, 삭제 |
28+
| Skill | 설명 |
29+
| --------------- | ----------------------------------------------------------- |
30+
| `/ccg` | 코어 빌드 & 검색 — 파싱, 그래프 빌드, 쿼리, 검색 |
31+
| `/ccg-analyze` | 코드 분석 — 영향 반경, 플로우 추적, 데드코드, 아키텍처 |
32+
| `/ccg-annotate` | 어노테이션 시스템 — AI 어노테이션 워크플로우, 태그 레퍼런스 |
33+
| `/ccg-docs` | 문서 — 문서 생성, RAG 인덱싱, lint |
3634

3735
주요 커맨드:
3836

guide/ko/mcp-tools.md

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -139,37 +139,28 @@ RAG 인덱스 품질은 생성 문서와 비어 있지 않은 community postproc
139139
`run_postprocess``communities=true`, `flows=false`, `fts=false`
140140
호출하십시오.
141141

142-
### 네임스페이스 파일 관리 (Namespace File Management)
142+
### 네임스페이스 탐색 (Namespace Discovery)
143143

144-
업로드 파일, 서비스별 그래프 데이터, 네임스페이스별 RAG 인덱스의 격리 단위는
145-
`namespace`입니다.
144+
서비스별 그래프 데이터와 네임스페이스별 RAG 인덱스의 격리 단위는 `namespace`입니다.
146145

147146
| 도구 | 설명 |
148147
|------|-------------|
149-
| `upload_file` | 네임스페이스에 파일 업로드 (base64) |
150-
| `upload_files` | 단일 호출로 여러 네임스페이스에 다수 파일 업로드 |
151-
| `list_namespaces` | 모든 네임스페이스 목록 출력 |
152-
| `list_files` | 네임스페이스 내 파일 목록 출력 |
153-
| `delete_file` | 네임스페이스에서 파일 삭제 |
154-
| `delete_namespace` | 네임스페이스 전체 및 관련 파일 모두 삭제 |
148+
| `list_namespaces` | 그래프 데이터를 가진 네임스페이스를 네임스페이스별 노드 수와 함께 출력 |
155149

156150
정식 예시:
157151

158152
```
159-
upload_file(namespace: "payment-svc", file_path: "handler.go", content: "<base64>")
160-
list_files(namespace: "payment-svc")
161-
delete_namespace(namespace: "payment-svc")
153+
list_namespaces() // -> [{namespace: "payment-svc", node_count: 128}, ...]
162154
```
163155

164-
## Agent Skills (5개)
156+
## Agent Skills (4개)
165157

166158
| 스킬 | 설명 |
167159
|-------|-------------|
168160
| `/ccg` | 핵심 빌드 및 검색 — 파싱, 그래프 빌드, 쿼리, 검색 |
169161
| `/ccg-analyze` | 코드 분석 — 영향 범위, 흐름 추적, 데드 코드, 아키텍처 |
170162
| `/ccg-annotate` | 어노테이션 시스템 — AI 기반 어노테이션 워크플로우, 태그 레퍼런스 |
171163
| `/ccg-docs` | 문서화 — 문서 생성, RAG 인덱싱, 린트 |
172-
| `/ccg-namespace` | 네임스페이스 파일 관리 — 네임스페이스 파일 업로드, 목록 출력, 삭제 |
173164

174165
이 스킬 파일들은 `skills/`에 있으며 slash-command 스타일의 에이전트
175166
워크플로우를 위해 작성되었습니다. 일반적인 코딩 에이전트 작업을 적절한

guide/mcp-tools.md

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -144,37 +144,29 @@ when it is configured. In MCP-only workflows, run `run_postprocess` with
144144
`communities=true`, `flows=false`, and `fts=false` before `build_rag_index` when
145145
communities may be missing.
146146

147-
### Namespace File Management
147+
### Namespace Discovery
148148

149-
Use `namespace` as the isolation term for uploaded files, per-service graph data,
150-
and namespace-specific RAG indexes.
149+
`namespace` is the isolation term for per-service graph data and namespace-specific
150+
RAG indexes.
151151

152152
| Tool | Description |
153153
|------|-------------|
154-
| `upload_file` | Upload file to namespace (base64) |
155-
| `upload_files` | Upload multiple files to namespaces in a single call |
156-
| `list_namespaces` | List all namespaces |
157-
| `list_files` | List files in a namespace |
158-
| `delete_file` | Delete file from namespace |
159-
| `delete_namespace` | Delete an entire namespace and all its files |
154+
| `list_namespaces` | List namespaces that hold graph data, with per-namespace node counts |
160155

161-
Canonical examples:
156+
Canonical example:
162157

163158
```
164-
upload_file(namespace: "payment-svc", file_path: "handler.go", content: "<base64>")
165-
list_files(namespace: "payment-svc")
166-
delete_namespace(namespace: "payment-svc")
159+
list_namespaces() // -> [{namespace: "payment-svc", node_count: 128}, ...]
167160
```
168161

169-
## Agent Skills (5)
162+
## Agent Skills (4)
170163

171164
| Skill | Description |
172165
|-------|-------------|
173166
| `/ccg` | Core build & search — parse, build graph, query, search |
174167
| `/ccg-analyze` | Code analysis — impact radius, flow tracing, dead code, architecture |
175168
| `/ccg-annotate` | Annotation system — AI-driven annotation workflow, tag reference |
176169
| `/ccg-docs` | Documentation — generate docs, RAG indexing, lint |
177-
| `/ccg-namespace` | Namespace file management — upload, list, and delete namespace files |
178170

179171
These skill files live in `skills/` and are written for slash-command style
180172
agent workflows. They route common coding-agent tasks to the right CLI and MCP

internal/mcp/e2e_test.go

Lines changed: 0 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package mcp
22

33
import (
44
"context"
5-
"encoding/base64"
65
"encoding/json"
76
"errors"
87
"fmt"
@@ -524,101 +523,3 @@ func Gamma() {}
524523
t.Errorf("expected at least 3 nodes, got %v", resp["total_nodes"])
525524
}
526525
}
527-
528-
func TestE2E_UploadBuildSearch(t *testing.T) {
529-
deps := setupE2EDeps(t)
530-
531-
wsRoot := t.TempDir()
532-
deps.NamespaceRoot = wsRoot
533-
534-
// Step 1: Upload Go source into the namespace with upload_file.
535-
goSrc := `package payment
536-
537-
func ProcessPayment(amount int) error {
538-
return nil
539-
}
540-
541-
func RefundPayment(txID string) error {
542-
return nil
543-
}
544-
`
545-
encoded := base64.StdEncoding.EncodeToString([]byte(goSrc))
546-
547-
uploadResult := callTool(t, deps, "upload_file", map[string]any{
548-
"namespace": "payment-svc",
549-
"file_path": "payment.go",
550-
"content": encoded,
551-
})
552-
if uploadResult.IsError {
553-
t.Fatalf("upload_file error: %s", getTextContent(uploadResult))
554-
}
555-
556-
// Step 2: Build the namespace path with build_or_update_graph.
557-
wsPath := filepath.Join(wsRoot, "payment-svc")
558-
buildResult := callTool(t, deps, "build_or_update_graph", map[string]any{
559-
"path": wsPath,
560-
"full_rebuild": true,
561-
"postprocess": "none",
562-
})
563-
if buildResult.IsError {
564-
t.Fatalf("build_or_update_graph error: %s", getTextContent(buildResult))
565-
}
566-
567-
// Step 3: Build the search index.
568-
ctx := context.Background()
569-
nodesInFile, err := deps.Store.GetNodesByFile(ctx, "payment.go")
570-
if err != nil {
571-
t.Fatal(err)
572-
}
573-
if len(nodesInFile) == 0 {
574-
t.Fatal("expected at least 1 node after build")
575-
}
576-
for _, n := range nodesInFile {
577-
if n.Kind == model.NodeKindFunction {
578-
deps.DB.Create(&model.SearchDocument{
579-
NodeID: n.ID,
580-
Content: n.Name + " " + n.QualifiedName,
581-
Language: n.Language,
582-
})
583-
}
584-
}
585-
deps.SearchBackend.Rebuild(ctx, deps.DB)
586-
587-
// Step 4: Verify with search.
588-
searchResult := callTool(t, deps, "search", map[string]any{"query": "ProcessPayment", "limit": 10})
589-
if searchResult.IsError {
590-
t.Fatalf("search error: %s", getTextContent(searchResult))
591-
}
592-
searchText := getTextContent(searchResult)
593-
var results []map[string]any
594-
if err := json.Unmarshal([]byte(searchText), &results); err != nil {
595-
t.Fatalf("search result not JSON array: %s", searchText)
596-
}
597-
if len(results) == 0 {
598-
t.Fatal("expected at least 1 search result for 'ProcessPayment'")
599-
}
600-
601-
found := false
602-
for _, r := range results {
603-
if name, ok := r["name"].(string); ok && name == "ProcessPayment" {
604-
found = true
605-
}
606-
}
607-
if !found {
608-
t.Error("expected ProcessPayment in search results")
609-
}
610-
611-
// Step 5: Confirm Refund is searchable too.
612-
refundResult := callTool(t, deps, "search", map[string]any{"query": "RefundPayment", "limit": 10})
613-
if refundResult.IsError {
614-
t.Fatalf("search error: %s", getTextContent(refundResult))
615-
}
616-
refundText := getTextContent(refundResult)
617-
var refundResults []map[string]any
618-
if err := json.Unmarshal([]byte(refundText), &refundResults); err != nil {
619-
t.Fatalf("search result not JSON array: %s", refundText)
620-
}
621-
if len(refundResults) == 0 {
622-
t.Fatal("expected at least 1 search result for 'RefundPayment'")
623-
}
624-
}

0 commit comments

Comments
 (0)