Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,14 @@ EntityConfig (설정 객체) 공통 UI Primitives 도메

```text
src/
features/ ← 도메인별 feature 디렉토리 (타입, 서비스, 서버, 쿼리, 컴포넌트 co-locate)
hook/ ← Hook 도메인 (types, constants, utils, service, server, queries, config, components/)
components/
ui/ ← shadcn primitives (Button, Sheet, ListItem, Inspector 등)
skill/ ← SkillInspector, SkillListItem
memory/ ← MemoryInspector
agent/ ← AgentInspector
mcp/ ← McpInspector
hook/ ← HookInspector
plugin/ ← PluginInspector
file/ ← FileInspector
board/ ← BoardLayout, EntityListPanel, EntityInspector, Add*Dialog
Expand All @@ -82,18 +83,17 @@ src/
icons/ ← entity-icons, agent-logos, editor-icons
config/
entity-registry.ts ← EntityConfig<T> 타입 + 레지스트리
entities/ ← 엔티티별 config (skill, command, agent, hook, mcp, plugin, memory, file)
hooks/ ← React Query 커스텀 훅 (use-hooks, use-mcp, use-plugins 등)
entities/ ← 엔티티별 config (skill, command, agent, mcp, plugin, memory, file)
hooks/ ← React Query 커스텀 훅 (use-mcp, use-plugins 등)
server/ ← Server Functions (createServerFn 기반)
skills.ts, marketplace.ts, items.ts, hooks.ts, agents.ts
skills.ts, marketplace.ts, items.ts, agents.ts
mcp-fns.ts, plugins-fns.ts, files.ts, overview.ts
claude-md.ts, config-settings.ts, memory.ts, editor.ts
config.ts, validation.ts, projects.ts, middleware/auth.ts
services/ ← 서버 사이드 서비스
config-service.ts ← 설정 파일 파싱 (스킬, 커맨드, 에이전트)
agent-file-service.ts ← AgentFile CRUD
skills-service.ts ← 스킬 설치/삭제 (skills.sh CLI)
hooks-service.ts ← Hook CRUD
mcp-service.ts ← MCP 서버 관리 (Claude CLI 위임)
plugin-service.ts ← 플러그인 관리
memory-service.ts ← 메모리 파일 조회
Expand Down
5 changes: 5 additions & 0 deletions docs/DESIGN-SYSTEM.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,12 +228,17 @@ export function XxxInspector({ itemKey }: { itemKey: string }) {
- `InspectorSkeleton` — 아이템 로딩 중 표시. 아이템을 찾을 수 없는 경우에도 사용
- `entity-inspector.tsx` — `type`에 따라 올바른 Inspector 컴포넌트로 라우팅

**리스트 vs Inspector 역할 분리:**
- 리스트(`EntityListPanel`)는 **선택만** 담당 — 더보기 버튼, 컨텍스트 메뉴 없음
- 모든 조작(편집, 삭제, 에디터에서 열기)은 **Inspector에서** 처리

## 참조 구현

새 패널이나 디테일 뷰를 추가할 때는 기존 구현을 참조:
- 엔티티 config: `src/config/entities/command-config.tsx` (groupBy 포함 최신 패턴)
- 범용 패널: `src/components/board/EntityListPanel.tsx` (flat + grouped 지원)
- Inspector: `src/components/skill/skill-inspector.tsx`
- Feature directory 패턴: `src/features/hook/` (타입, 서비스, 서버, 쿼리, 컴포넌트 co-locate)
- 레이아웃: `src/components/board/BoardLayout.tsx`

## 금지 사항
Expand Down
2 changes: 2 additions & 0 deletions docs/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,13 @@ Claude Code가 자체 설정 관리 GUI를 추가하면, 그걸 쓰면 된다. a
- [ ] 플러그인 `scope: "managed"` 개선 — `scanPluginComponents`에서 `scope: "managed"` 주입
- [ ] Add 다이얼로그 재설계 — `AddSkillDialog`, `AddAgentDialog`는 파일 직접 생성 방식이라 뷰어/모니터링 철학과 불일치. CLI 위임 원칙에 맞게 재설계 필요 (CLI 명령 안내 or 마켓플레이스 연결). `AddHookDialog`, `AddMcpDialog`도 에이전트별 분기 필요 (현재 Claude Code 전용 하드코딩)
- [ ] `edit` 액션 → 다이얼로그 연결 — MCP/Hook의 edit 액션이 현재 no-op. Add 다이얼로그를 edit 모드로 재활용하거나 별도 edit 다이얼로그 필요
- [ ] Inspector 헤더 드롭다운 공통화 — 각 Inspector(Hook, Skill, MCP 등)에서 Open in Editor / Edit / Delete 드롭다운이 중복 구현. `InspectorActionMenu` 공통 컴포넌트로 추출하고 entity config 기반으로 액션 자동 생성

---

## Shipped

- **Hook feature directory 이관 + 리스트 액션 제거** (2026-03-19) — Hook 도메인 파일을 `src/features/hook/`로 통합. 서버 Zod 스키마 중복 제거, Inspector에 EntityActionDropdown 적용. EntityListPanel에서 더보기 버튼/컨텍스트 메뉴 제거 (조작은 Inspector에서만).
- **Inspector 아키텍처 단순화** (2026-03-18) — `DashboardDetailTarget` union / `toDetailTarget` 제거. Inspector가 `itemKey`만 받아 자체 fetch 및 액션 처리. `use-entity-action-handler.ts` 제거.
- **Inspector 리디자인** (2026-03-18) — DetailPanel/EntityDetailPanel/DetailContent 시스템을 Inspector primitives + 도메인별 full Inspector로 전환. entity/ 해소, 도메인 디렉토리 이동.
- **Commands in Skills 패널** (2026-03-18) — `.claude/commands/` 파일을 Skills 열에 통합 표시. `commandConfig` + `ENTITY_ICONS.command`(TerminalSquareIcon) 추가, namespace 트리 그룹핑(`GroupedList`), 디테일 패널 slash command 필드 + 복사 버튼, `getSlashCommand` 유틸.
Expand Down
77 changes: 0 additions & 77 deletions src/components/board/AgentsPanel.tsx

This file was deleted.

74 changes: 63 additions & 11 deletions src/components/board/BoardLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
PlusIcon,
} from "lucide-react"
import type { ElementType } from "react"
import { useMemo, useRef, useState } from "react"
import { useEffect, useMemo, useRef, useState } from "react"
import { toast } from "sonner"
import { ENTITY_ICONS } from "@/components/icons/entity-icons"
import { useProjectContext } from "@/components/ProjectContext"
Expand All @@ -50,19 +50,17 @@ import {
memoryConfig,
skillConfig,
} from "@/config/entities"
import { getEntityConfig } from "@/config/entity-registry"
import { AddHookDialog } from "@/features/hook/components/add-hook-dialog"
import { useHooksQuery } from "@/features/hook/queries"
import type { HookScope, HooksSettings } from "@/features/hook/types"
import { getHookIcon } from "@/features/hook/utils"
import { useAgentFiles, useMemoryFiles } from "@/hooks/use-config"
import { useHooksQuery } from "@/hooks/use-hooks"
import { useMcpMutations, useMcpQuery } from "@/hooks/use-mcp"

import { usePluginsQuery } from "@/hooks/use-plugins"
import { m } from "@/paraglide/messages"
import type {
BoardColumnId,
HookScope,
HooksSettings,
Scope,
} from "@/shared/types"
import type { BoardColumnId, Scope } from "@/shared/types"
import { AddAgentDialog } from "./AddAgentDialog"
import { AddHookDialog } from "./AddHookDialog"
import { AddMcpDialog } from "./AddMcpDialog"
import { AddSkillDialog } from "./AddSkillDialog"
import { BoardColumnSettings } from "./BoardColumnSettings"
Expand Down Expand Up @@ -256,6 +254,9 @@ export function BoardLayout() {
const { data: mcpServers = [], isLoading: mcpLoading } = useMcpQuery()
const { toggleMutation } = useMcpMutations()
const { data: memoryFiles = [], isLoading: memoryLoading } = useMemoryFiles()
const { data: plugins = [], isLoading: pluginsLoading } = usePluginsQuery(
activeProjectPath ?? undefined,
)

const hookItems = useMemo<HookItem[]>(() => {
return [
Expand All @@ -270,6 +271,56 @@ export function BoardLayout() {
[mcpServers],
)

// ── Auto-close inspector when selected item no longer exists ──
const entityDataMap: Record<string, { items: unknown[]; loading: boolean }> =
useMemo(
() => ({
skill: {
items: skills.filter((s) => s.type === "skill"),
loading: skillsLoading,
},
command: {
items: skills.filter((s) => s.type === "command"),
loading: skillsLoading,
},
agent: { items: agents, loading: agentsLoading },
hook: {
items: hookItems,
loading: globalHooksLoading || projectHooksLoading,
},
mcp: { items: directMcpServers, loading: mcpLoading },
plugin: { items: plugins, loading: pluginsLoading },
memory: { items: memoryFiles, loading: memoryLoading },
}),
[
skills,
agents,
hookItems,
directMcpServers,
plugins,
memoryFiles,
skillsLoading,
agentsLoading,
globalHooksLoading,
projectHooksLoading,
mcpLoading,
pluginsLoading,
memoryLoading,
],
)

useEffect(() => {
if (!selected) return
const data = entityDataMap[selected.type]
if (!data || data.loading) return
const config = getEntityConfig(selected.type)
if (!config) return
const exists = data.items.some(
(item) => config.getKey(item) === selected.key,
)
if (!exists) setSelected(null)
}, [selected, entityDataMap])

function toggleScope(scope: string) {
setCollapsedScopes((prev) => {
const next = new Set(prev)
Expand Down Expand Up @@ -462,7 +513,8 @@ export function BoardLayout() {
items={hookItems}
{...common}
emptyDescription={m.board_no_hooks()}
isLoading={globalHooksLoading && projectHooksLoading}
isLoading={globalHooksLoading || projectHooksLoading}
getItemIcon={(item) => getHookIcon(item.entry)}
/>
)
case "memory":
Expand Down
Loading
Loading