pubuilder 0.5.0 → 0.7.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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/api.ts","../src/env.ts","../src/store.ts","../src/styles.ts","../src/layout.ts","../src/components/PageNode.tsx","../src/components/CanvasOverlay.tsx","../src/components/Fab.tsx","../src/inspector/heuristics.ts","../src/inspector/inspector.ts","../src/components/PublishPanel.tsx","../src/components/SelectionPanel.tsx","../src/components/PageViewer.tsx","../src/components/SkillDrawer.tsx","../src/components/PageMap.tsx"],"sourcesContent":["// 컴패니언 서버 HTTP 클라이언트 (브라우저 전용)\nimport { createContext } from 'react'\nimport type { BlockSelection } from './types'\n\nexport const DEFAULT_SERVER_URL = 'http://localhost:4816'\n\nexport interface SkillInfo {\n id: string\n name: string\n description: string\n source: 'project' | 'global' | 'uploaded'\n enabled: boolean\n}\nexport interface AgentEvent { type: 'log' | 'tool' | 'error' | 'done'; text: string }\nexport interface TokenStatus { configured: boolean; masked: string | null }\n\n/** 서버 에러 응답의 code(server/errors.ts 계약)를 UI 분기용으로 실어 나르는 에러 */\nexport class ApiError extends Error {\n constructor(message: string, readonly code?: string) {\n super(message)\n this.name = 'ApiError'\n }\n}\n\nexport class PubuilderApi {\n constructor(private readonly baseUrl: string = DEFAULT_SERVER_URL) {}\n\n private async request<T>(path: string, init?: RequestInit): Promise<T> {\n const res = await fetch(`${this.baseUrl}${path}`, {\n ...init,\n headers: { 'content-type': 'application/json', ...init?.headers },\n })\n if (!res.ok) {\n const body = (await res.json().catch(() => ({}))) as { code?: string; message?: string }\n throw new ApiError(body.message ?? `요청 실패 (${res.status})`, body.code)\n }\n return res.status === 204 ? (undefined as T) : ((await res.json()) as T)\n }\n\n async isAlive(): Promise<boolean> {\n try {\n await this.request('/api/health')\n return true\n } catch {\n return false\n }\n }\n listSkills() { return this.request<SkillInfo[]>('/api/skills') }\n toggleSkill(id: string, enabled: boolean) {\n return this.request<void>(`/api/skills/${encodeURIComponent(id)}`, { method: 'PATCH', body: JSON.stringify({ enabled }) })\n }\n uploadSkill(filename: string, content: string) {\n return this.request<SkillInfo>('/api/skills', { method: 'POST', body: JSON.stringify({ filename, content }) })\n }\n removeSkill(id: string) { return this.request<void>(`/api/skills/${encodeURIComponent(id)}`, { method: 'DELETE' }) }\n tokenStatus() { return this.request<TokenStatus>('/api/settings/figma-token') }\n saveToken(token: string) { return this.request<void>('/api/settings/figma-token', { method: 'PUT', body: JSON.stringify({ token }) }) }\n deleteToken() { return this.request<void>('/api/settings/figma-token', { method: 'DELETE' }) }\n startPublish(payload: { selection: BlockSelection; outerHTML: string; figmaUrl: string }) {\n return this.request<{ jobId: string }>('/api/publish', { method: 'POST', body: JSON.stringify(payload) })\n }\n cancelPublish(jobId: string) { return this.request<void>(`/api/publish/${jobId}`, { method: 'DELETE' }) }\n\n /** SSE 구독 — 반환값 호출로 해제 */\n subscribePublish(jobId: string, onEvent: (e: AgentEvent) => void): () => void {\n const source = new EventSource(`${this.baseUrl}/api/publish/${jobId}/events`)\n // terminal(done|error) 수신 전에 연결이 끊기면(서버 다운 등) 구독자가\n // running에 영구 고착되지 않도록 error 이벤트를 합성한다. terminal 후 끊김은 정상 종료.\n let terminal = false\n source.onmessage = (msg) => {\n const e = JSON.parse(msg.data) as AgentEvent\n if (e.type === 'done' || e.type === 'error') terminal = true\n onEvent(e)\n }\n source.onerror = () => {\n source.close() // 재연결 불필요\n if (!terminal) {\n terminal = true\n onEvent({ type: 'error', text: '서버 연결이 끊겼어요. pubuilder serve 상태를 확인해주세요' })\n }\n }\n return () => source.close()\n }\n}\n\n/** PageMap이 provider로 감싸고, SkillDrawer/PublishPanel이 useContext로 획득 */\nexport const PubuilderServerContext = createContext<PubuilderApi>(new PubuilderApi())\n","/**\n * production 번들 여부. 소비 측 번들러(Next/Vite 등)가 process.env.NODE_ENV를\n * 정적 치환하므로 앱 빌드 시 상수로 접힌다. 번들러 없는 환경(process 미정의)에서는\n * false — 렌더를 막는 쪽이 아니라 허용하는 쪽이 안전한 기본값.\n *\n * 주의: 라이브러리 빌드가 이 표현식을 미리 치환하면 안 된다 — vite.config.ts 참고.\n */\nexport function isProductionEnv(): boolean {\n return typeof process !== 'undefined' && process.env.NODE_ENV === 'production'\n}\n","import { create } from 'zustand'\nimport type { BlockSelection, Granularity } from './types'\n\ninterface PubuilderStore {\n isMapOpen: boolean\n /** 전체화면으로 확대 중인 페이지 path (null이면 캔버스만) */\n viewerPath: string | null\n granularity: Granularity\n inspectEnabled: boolean\n selection: BlockSelection | null\n /** 선택된 블록의 outerHTML 스냅샷 (Phase 3 퍼블리싱 프롬프트용, 20K 상한) */\n selectedOuterHTML: string | null\n skillDrawerOpen: boolean\n openMap: () => void\n closeMap: () => void\n openViewer: (path: string) => void\n closeViewer: () => void\n setGranularity: (g: Granularity) => void\n setInspectEnabled: (v: boolean) => void\n setSelectionWithHTML: (s: BlockSelection | null, html: string | null) => void\n toggleSkillDrawer: () => void\n}\n\nexport const usePubuilderStore = create<PubuilderStore>((set) => ({\n isMapOpen: false,\n viewerPath: null,\n granularity: 'section',\n inspectEnabled: true,\n selection: null,\n selectedOuterHTML: null,\n skillDrawerOpen: false,\n openMap: () => set({ isMapOpen: true }),\n closeMap: () => set({ isMapOpen: false, viewerPath: null, selection: null, selectedOuterHTML: null }),\n openViewer: (path) => set({ viewerPath: path, selection: null, selectedOuterHTML: null }),\n closeViewer: () => set({ viewerPath: null, selection: null, selectedOuterHTML: null }),\n setGranularity: (granularity) => set({ granularity }),\n setInspectEnabled: (inspectEnabled) => set({ inspectEnabled }),\n setSelectionWithHTML: (selection, selectedOuterHTML) => set({ selection, selectedOuterHTML }),\n toggleSkillDrawer: () => set((s) => ({ skillDrawerOpen: !s.skillDrawerOpen })),\n}))\n","// React Flow CSS를 빌드 시 텍스트로 인라인 — 소비 번들러(Next 등)가\n// node_modules 글로벌 CSS import를 금지해도 동작하도록 런타임 주입한다.\nimport xyflowCss from '@xyflow/react/dist/style.css?inline'\n\n/**\n * 툴 chrome 스타일. 호스트 CSS와의 충돌을 줄이기 위해\n * 전부 pbu- 접두 클래스 + 런타임 <style> 주입으로 격리한다.\n *\n * 디자인 컨셉: 개발자도구(DevTools/VSCode)식 시스템 UI.\n * 플랫, 최소 radius(≤2px), 무채색 팔레트 + 단일 액센트, 장식 없음.\n */\nconst STYLE_ID = 'pubuilder-styles'\nconst XYFLOW_STYLE_ID = 'pubuilder-xyflow-styles'\n\n// palette: bg #1e1e1e / surface #252526 / raised #2d2d2d / border #3c3c3c\n// text #cccccc / dim #8c8c8c / accent #0e639c\nconst CSS_TEXT = /* css */ `\n.pbu-fab {\n position: fixed;\n right: 16px;\n bottom: 16px;\n z-index: 2147483000;\n width: 40px;\n height: 40px;\n border-radius: 2px;\n border: 1px solid #3c3c3c;\n cursor: pointer;\n background: #252526;\n color: #cccccc;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.pbu-fab:hover { background: #2d2d2d; color: #ffffff; }\n\n.pbu-overlay,\n.pbu-viewer {\n position: fixed;\n inset: 0;\n display: flex;\n flex-direction: column;\n font-family: system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif;\n font-size: 12px;\n color: #cccccc;\n}\n.pbu-overlay { z-index: 2147483100; background: #1e1e1e; }\n.pbu-viewer { z-index: 2147483200; background: #1e1e1e; }\n\n.pbu-bar {\n display: flex;\n align-items: center;\n gap: 10px;\n height: 38px;\n padding: 0 12px;\n background: #252526;\n border-bottom: 1px solid #3c3c3c;\n flex-shrink: 0;\n}\n.pbu-logo {\n font-weight: 600;\n font-size: 11px;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: #cccccc;\n}\n.pbu-hint { font-size: 11px; color: #8c8c8c; }\n.pbu-spacer { flex: 1; }\n\n.pbu-btn {\n border: 1px solid #3c3c3c;\n background: #2d2d2d;\n color: #cccccc;\n font-size: 11px;\n padding: 4px 10px;\n border-radius: 2px;\n cursor: pointer;\n}\n.pbu-btn:hover { background: #37373d; }\n.pbu-btn:disabled { opacity: 0.4; cursor: not-allowed; }\n.pbu-btn-primary { background: #0e639c; border-color: #0e639c; color: #fff; }\n.pbu-btn-primary:hover:not(:disabled) { background: #1177bb; }\n\n.pbu-icon-btn {\n border: none;\n background: transparent;\n color: #8c8c8c;\n font-size: 14px;\n cursor: pointer;\n padding: 4px 8px;\n border-radius: 2px;\n}\n.pbu-icon-btn:hover { background: #2d2d2d; color: #ffffff; }\n\n.pbu-seg {\n display: flex;\n border: 1px solid #3c3c3c;\n border-radius: 2px;\n overflow: hidden;\n}\n.pbu-seg button {\n border: none;\n background: #2d2d2d;\n color: #8c8c8c;\n font-size: 11px;\n padding: 4px 12px;\n cursor: pointer;\n}\n.pbu-seg button + button { border-left: 1px solid #3c3c3c; }\n.pbu-seg button.pbu-on { background: #0e639c; color: #fff; }\n\n.pbu-toggle {\n display: flex;\n align-items: center;\n gap: 5px;\n font-size: 11px;\n color: #8c8c8c;\n cursor: pointer;\n user-select: none;\n}\n\n.pbu-canvas { flex: 1; min-height: 0; }\n.pbu-canvas .react-flow { background: #1e1e1e; }\n/* draggable/selectable 꺼도 노드 클릭은 받아야 함 (RF는 비인터랙티브 노드에 pointer-events:none을 줌) */\n.pbu-canvas .react-flow__node { pointer-events: all !important; cursor: pointer; }\n.pbu-canvas .react-flow__edge-path { stroke: #555555; stroke-width: 1; }\n.pbu-canvas .react-flow__controls button {\n background: #252526;\n border-bottom: 1px solid #3c3c3c;\n border-radius: 0;\n color: #cccccc;\n fill: #cccccc;\n}\n.pbu-canvas .react-flow__controls button:hover { background: #2d2d2d; }\n\n.pbu-node {\n background: #252526;\n border: 1px solid #3c3c3c;\n border-radius: 0;\n overflow: hidden;\n cursor: pointer;\n}\n.pbu-node:hover { border-color: #0e639c; }\n.pbu-node-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n height: 28px;\n padding: 0 8px;\n background: #2d2d2d;\n border-bottom: 1px solid #3c3c3c;\n}\n.pbu-node-title {\n font-size: 11px;\n font-weight: 600;\n color: #cccccc;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.pbu-node-path {\n font-size: 10px;\n color: #8c8c8c;\n font-family: ui-monospace, Menlo, monospace;\n white-space: nowrap;\n flex-shrink: 0;\n}\n.pbu-node-body { position: relative; background: #fff; overflow: hidden; }\n.pbu-node-iframe {\n border: 0;\n transform-origin: 0 0;\n pointer-events: none;\n display: block;\n}\n.pbu-node-shield { position: absolute; inset: 0; }\n.pbu-node-placeholder {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 11px;\n color: #8c8c8c;\n background: #1e1e1e;\n}\n.pbu-handle { opacity: 0; pointer-events: none; }\n\n.pbu-viewer-title { font-size: 12px; font-weight: 600; }\n.pbu-viewer-title code {\n margin-left: 8px;\n font-size: 11px;\n font-weight: 400;\n color: #8c8c8c;\n font-family: ui-monospace, Menlo, monospace;\n}\n.pbu-viewer-body { flex: 1; min-height: 0; display: flex; }\n.pbu-viewer-frame-wrap { flex: 1; min-width: 0; background: #fff; }\n.pbu-viewer-iframe { width: 100%; height: 100%; border: 0; display: block; }\n\n.pbu-panel {\n width: 300px;\n flex-shrink: 0;\n background: #252526;\n border-left: 1px solid #3c3c3c;\n padding: 12px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.pbu-panel-title {\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: #cccccc;\n padding-bottom: 8px;\n border-bottom: 1px solid #3c3c3c;\n}\n.pbu-panel-empty { font-size: 11px; color: #8c8c8c; line-height: 1.7; }\n.pbu-field { display: flex; flex-direction: column; gap: 4px; }\n.pbu-field > label {\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: #8c8c8c;\n}\n.pbu-field code {\n font-size: 11px;\n color: #cccccc;\n font-family: ui-monospace, Menlo, monospace;\n word-break: break-all;\n}\n.pbu-field span { font-size: 12px; color: #cccccc; }\n.pbu-selector {\n background: #1e1e1e;\n border: 1px solid #3c3c3c;\n border-radius: 2px;\n padding: 6px 8px;\n display: block;\n}\n.pbu-chip {\n display: inline-block;\n background: #37373d;\n color: #cccccc;\n font-size: 11px;\n font-weight: 600;\n font-family: ui-monospace, Menlo, monospace;\n padding: 1px 6px;\n border-radius: 2px;\n margin-right: 6px;\n}\n.pbu-publish {\n margin-top: 4px;\n padding: 10px;\n border: 1px solid #3c3c3c;\n border-radius: 2px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.pbu-publish > label { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: #8c8c8c; }\n.pbu-publish input {\n background: #1e1e1e;\n border: 1px solid #3c3c3c;\n border-radius: 2px;\n color: #cccccc;\n font-size: 11px;\n padding: 5px 8px;\n}\n.pbu-publish input:disabled { color: #8c8c8c; cursor: not-allowed; }\n.pbu-publish-log {\n max-height: 200px;\n overflow-y: auto;\n background: #1e1e1e;\n border: 1px solid #3c3c3c;\n border-radius: 2px;\n padding: 6px 8px;\n font-family: ui-monospace, Menlo, monospace;\n font-size: 11px;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.pbu-log-line { color: #cccccc; white-space: pre-wrap; word-break: break-all; }\n.pbu-log-tool { color: #8c8c8c; }\n.pbu-log-error { color: #f2b3b3; }\n.pbu-log-done { color: #89d185; font-weight: 600; }\n\n.pbu-drawer {\n position: fixed;\n top: 0;\n right: 0;\n height: 100vh;\n width: 360px;\n z-index: 2147483300;\n background: #252526;\n border-left: 1px solid #3c3c3c;\n padding: 12px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 10px;\n font-family: system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif;\n font-size: 12px;\n color: #cccccc;\n}\n.pbu-drawer-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding-bottom: 8px;\n border-bottom: 1px solid #3c3c3c;\n}\n.pbu-drawer-group {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: #8c8c8c;\n margin-top: 6px;\n}\n.pbu-skill-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 0;\n border-bottom: 1px solid #2d2d2d;\n}\n.pbu-skill-row .pbu-hint {\n flex: 1;\n min-width: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.pbu-token-masked {\n font-family: ui-monospace, Menlo, monospace;\n font-size: 11px;\n color: #cccccc;\n background: #1e1e1e;\n border: 1px solid #3c3c3c;\n border-radius: 2px;\n padding: 6px 8px;\n}\n.pbu-drawer-error {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n background: #5a1d1d;\n border: 1px solid #832525;\n color: #f2b3b3;\n font-size: 11px;\n padding: 6px 8px;\n border-radius: 2px;\n}\n.pbu-drawer-code {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 8px 0;\n background: #1e1e1e;\n border: 1px solid #3c3c3c;\n border-radius: 2px;\n padding: 6px 8px;\n}\n.pbu-drawer-code code {\n flex: 1;\n font-family: ui-monospace, Menlo, monospace;\n font-size: 11px;\n color: #cccccc;\n}\n`\n\nfunction injectOnce(id: string, css: string) {\n if (document.getElementById(id)) return\n const style = document.createElement('style')\n style.id = id\n style.textContent = css\n document.head.appendChild(style)\n}\n\n/** 스타일 태그를 1회 주입 (idempotent) */\nexport function ensureStyles() {\n if (typeof document === 'undefined') return\n injectOnce(XYFLOW_STYLE_ID, xyflowCss)\n injectOnce(STYLE_ID, CSS_TEXT)\n}\n","import type { IANode } from './types'\n\nexport interface LayoutedNode extends IANode {\n x: number\n y: number\n}\n\n/**\n * 좌→우(LR) tidy tree 레이아웃.\n * depth = 열, 리프는 세로로 쌓고 부모는 자식들의 세로 중앙에 배치.\n * 화면설계서 IA 다이어그램과 같은 모양을 만든다.\n */\nexport function layoutTree(\n nodes: IANode[],\n nodeWidth: number,\n nodeHeight: number,\n gapX = 140,\n gapY = 48,\n): LayoutedNode[] {\n const childrenOf = new Map<string | null, IANode[]>()\n for (const n of nodes) {\n const list = childrenOf.get(n.parentId) ?? []\n list.push(n)\n childrenOf.set(n.parentId, list)\n }\n\n const pos = new Map<string, { x: number; y: number }>()\n let cursorY = 0\n\n const place = (node: IANode): number => {\n const kids = childrenOf.get(node.id) ?? []\n const x = node.depth * (nodeWidth + gapX)\n let y: number\n if (kids.length === 0) {\n y = cursorY\n cursorY += nodeHeight + gapY\n } else {\n const ys = kids.map(place)\n y = (Math.min(...ys) + Math.max(...ys)) / 2\n }\n pos.set(node.id, { x, y })\n return y\n }\n\n for (const root of childrenOf.get(null) ?? []) place(root)\n\n return nodes.map((n) => ({ ...n, ...pos.get(n.id)! }))\n}\n","import { Handle, Position, type NodeProps } from '@xyflow/react'\nimport { memo, useEffect, useRef, useState } from 'react'\nimport { usePubuilderStore } from '../store'\nimport type { IANode } from '../types'\n\nexport interface PageNodeData {\n page: IANode\n viewport: { width: number; height: number }\n thumbWidth: number\n bodyHeight: number\n [key: string]: unknown\n}\n\nexport const PageNode = memo(function PageNode(props: NodeProps) {\n const { page, viewport, thumbWidth, bodyHeight } = props.data as PageNodeData\n const openViewer = usePubuilderStore((s) => s.openViewer)\n const ref = useRef<HTMLDivElement>(null)\n const [visible, setVisible] = useState(false)\n\n // 캔버스 뷰포트에 들어온 노드만 iframe 로드 (lazy)\n useEffect(() => {\n const el = ref.current\n if (!el || page.external) return\n const io = new IntersectionObserver(([entry]) => {\n if (entry.isIntersecting) {\n setVisible(true)\n io.disconnect()\n }\n })\n io.observe(el)\n return () => io.disconnect()\n }, [page.external])\n\n const scale = thumbWidth / viewport.width\n const open = () => {\n if (page.external) window.open(page.path, '_blank', 'noopener')\n else openViewer(page.path)\n }\n\n return (\n <div ref={ref} className=\"pbu-node\" style={{ width: thumbWidth }} onClick={open}>\n <Handle type=\"target\" position={Position.Left} className=\"pbu-handle\" isConnectable={false} />\n <div className=\"pbu-node-header\">\n <span className=\"pbu-node-title\">{page.title}</span>\n <span className=\"pbu-node-path\">{page.external ? '외부 ↗' : page.path}</span>\n </div>\n <div className=\"pbu-node-body\" style={{ height: bodyHeight }}>\n {page.external ? (\n <div className=\"pbu-node-placeholder\">↗ 외부 링크</div>\n ) : visible ? (\n <iframe\n className=\"pbu-node-iframe\"\n src={page.path}\n title={`${page.title} 미리보기`}\n loading=\"lazy\"\n tabIndex={-1}\n style={{\n width: viewport.width,\n height: viewport.height,\n transform: `scale(${scale})`,\n }}\n />\n ) : (\n <div className=\"pbu-node-placeholder\">…</div>\n )}\n {/* iframe 위 클릭 가드 + hover 커서 */}\n <div className=\"pbu-node-shield\" />\n </div>\n <Handle type=\"source\" position={Position.Right} className=\"pbu-handle\" isConnectable={false} />\n </div>\n )\n})\n","import {\n Position,\n ReactFlow,\n type Edge,\n type Node,\n type NodeTypes,\n} from '@xyflow/react'\nimport { useEffect, useMemo } from 'react'\nimport type { NormalizedIA } from '../config'\nimport { layoutTree } from '../layout'\nimport { usePubuilderStore } from '../store'\nimport { PageNode, type PageNodeData } from './PageNode'\n\nconst nodeTypes: NodeTypes = { page: PageNode }\n\nconst THUMB_WIDTH = 260\nconst HEADER_HEIGHT = 30\n\nexport function CanvasOverlay({ ia }: { ia: NormalizedIA }) {\n const closeMap = usePubuilderStore((s) => s.closeMap)\n const toggleSkillDrawer = usePubuilderStore((s) => s.toggleSkillDrawer)\n\n const { nodes, edges } = useMemo(() => {\n const scale = THUMB_WIDTH / ia.viewport.width\n const bodyHeight = Math.round(ia.viewport.height * scale)\n const nodeHeight = bodyHeight + HEADER_HEIGHT\n const laid = layoutTree(ia.nodes, THUMB_WIDTH, nodeHeight)\n\n const nodes: Node[] = laid.map((n) => ({\n id: n.id,\n type: 'page',\n position: { x: n.x, y: n.y },\n data: {\n page: n,\n viewport: ia.viewport,\n thumbWidth: THUMB_WIDTH,\n bodyHeight,\n } satisfies PageNodeData,\n sourcePosition: Position.Right,\n targetPosition: Position.Left,\n }))\n\n const edges: Edge[] = laid\n .filter((n) => n.parentId)\n .map((n) => ({\n id: `${n.parentId}->${n.id}`,\n source: n.parentId!,\n target: n.id,\n type: 'smoothstep',\n }))\n\n return { nodes, edges }\n }, [ia])\n\n // Esc → 맵 닫기 (뷰어/스킬함 드로어가 열려 있으면 그쪽이 처리)\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key !== 'Escape') return\n const state = usePubuilderStore.getState()\n if (state.viewerPath || state.skillDrawerOpen) return\n closeMap()\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [closeMap])\n\n return (\n <div className=\"pbu-overlay\">\n <div className=\"pbu-bar\">\n <span className=\"pbu-logo\">pubuilder</span>\n <span className=\"pbu-hint\">노드 클릭 → 페이지 확대 · 스크롤 줌 · 드래그 팬 · Esc 닫기</span>\n <span className=\"pbu-spacer\" />\n <button type=\"button\" className=\"pbu-btn\" onClick={toggleSkillDrawer}>🧰 스킬함</button>\n <button type=\"button\" className=\"pbu-icon-btn\" onClick={closeMap} aria-label=\"닫기\">✕</button>\n </div>\n <div className=\"pbu-canvas\">\n <ReactFlow\n nodes={nodes}\n edges={edges}\n nodeTypes={nodeTypes}\n fitView\n fitViewOptions={{ padding: 0.15, maxZoom: 1 }}\n minZoom={0.05}\n maxZoom={2}\n nodesDraggable={false}\n nodesConnectable={false}\n elementsSelectable={false}\n />\n </div>\n </div>\n )\n}\n","import { usePubuilderStore } from '../store'\n\nexport function Fab() {\n const isMapOpen = usePubuilderStore((s) => s.isMapOpen)\n const openMap = usePubuilderStore((s) => s.openMap)\n const closeMap = usePubuilderStore((s) => s.closeMap)\n\n return (\n <button\n type=\"button\"\n className=\"pbu-fab\"\n title=\"Page Map (pubuilder)\"\n aria-label=\"페이지 맵 열기\"\n onClick={() => (isMapOpen ? closeMap() : openMap())}\n >\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <polygon points=\"3 6 9 3 15 6 21 3 21 18 15 21 9 18 3 21\" />\n <line x1=\"9\" y1=\"3\" x2=\"9\" y2=\"18\" />\n <line x1=\"15\" y1=\"6\" x2=\"15\" y2=\"21\" />\n </svg>\n </button>\n )\n}\n","import type { Granularity } from '../types'\n\nconst SECTION_TAGS = new Set([\n 'section', 'header', 'footer', 'nav', 'main', 'article', 'aside', 'form',\n])\n\nconst UNIT_TAGS = new Set([\n 'a', 'button', 'input', 'select', 'textarea', 'img', 'video', 'table',\n 'ul', 'ol', 'li', 'figure', 'h1', 'h2', 'h3', 'h4', 'p', 'label',\n])\n\n/** target에서 body 직전까지의 조상 체인 (target 먼저) */\nfunction ancestorChain(el: Element, doc: Document): Element[] {\n const chain: Element[] = []\n let cur: Element | null = el\n while (cur && cur !== doc.body && cur !== doc.documentElement) {\n chain.push(cur)\n cur = cur.parentElement\n }\n return chain\n}\n\nfunction pickSection(target: Element, doc: Document): Element | null {\n const chain = ancestorChain(target, doc)\n if (chain.length === 0) return null\n\n // 1순위: 가장 가까운 시맨틱 섹션 태그 (단, main은 더 안쪽 섹션이 없을 때만)\n const semantic = chain.find((el) => {\n const tag = el.tagName.toLowerCase()\n return SECTION_TAGS.has(tag) && tag !== 'main'\n })\n if (semantic) return semantic\n\n const main = chain.find((el) => el.tagName.toLowerCase() === 'main')\n if (main) return main\n\n // 2순위: 페이지 전체 래퍼가 아닌 최상위 조상\n const bodyH = doc.body.scrollHeight || 1\n for (let i = chain.length - 1; i >= 0; i--) {\n const rect = chain[i].getBoundingClientRect()\n if (rect.height > 0 && rect.height < bodyH * 0.8) return chain[i]\n }\n return chain[chain.length - 1]\n}\n\nfunction pickUnit(target: Element, doc: Document): Element | null {\n const chain = ancestorChain(target, doc)\n for (const el of chain) {\n if (UNIT_TAGS.has(el.tagName.toLowerCase())) return el\n const rect = el.getBoundingClientRect()\n const hasContent =\n el.children.length > 0 || (el.textContent ?? '').trim().length > 0\n if (rect.width >= 40 && rect.height >= 24 && hasContent) return el\n }\n return chain[0] ?? null\n}\n\n/** hover/클릭 지점의 요소에서 granularity에 맞는 블록을 고른다 */\nexport function pickBlock(\n target: Element,\n doc: Document,\n granularity: Granularity,\n): Element | null {\n if (granularity === 'all') return doc.body\n if (granularity === 'section') return pickSection(target, doc)\n return pickUnit(target, doc)\n}\n\n/** 블록을 사람이 알아볼 라벨: 헤딩 > aria-label > alt > 텍스트 앞부분 */\nexport function blockLabel(el: Element): string {\n const heading = el.querySelector('h1, h2, h3, h4, h5, h6')\n const headingText = heading?.textContent?.trim()\n if (headingText) return truncate(headingText)\n\n const aria = el.getAttribute('aria-label')\n if (aria) return truncate(aria)\n\n const alt = el.getAttribute('alt')\n if (alt) return truncate(alt)\n\n const text = (el.textContent ?? '').trim().replace(/\\s+/g, ' ')\n return text ? truncate(text) : `<${el.tagName.toLowerCase()}>`\n}\n\nfunction truncate(s: string, max = 30): string {\n return s.length > max ? `${s.slice(0, max)}…` : s\n}\n\n/** document 기준 고유-ish CSS selector 생성 */\nexport function cssPath(el: Element, doc: Document): string {\n if (el.id) return `#${CSS.escape(el.id)}`\n const parts: string[] = []\n let cur: Element | null = el\n while (cur && cur !== doc.body && parts.length < 8) {\n if (cur.id) {\n parts.unshift(`#${CSS.escape(cur.id)}`)\n return parts.join(' > ')\n }\n const tag = cur.tagName.toLowerCase()\n const parent: Element | null = cur.parentElement\n let part = tag\n if (parent) {\n const sameTag = Array.from(parent.children).filter(\n (c) => c.tagName === cur!.tagName,\n )\n if (sameTag.length > 1) part += `:nth-of-type(${sameTag.indexOf(cur) + 1})`\n }\n parts.unshift(part)\n cur = parent\n }\n return parts.join(' > ')\n}\n","import type { BlockSelection, Granularity } from '../types'\nimport { blockLabel, cssPath, pickBlock } from './heuristics'\n\nexport interface InspectorOptions {\n pagePath: string\n granularity: Granularity\n enabled: boolean\n onSelect: (selection: BlockSelection, el: Element) => void\n}\n\nexport interface InspectorHandle {\n destroy: () => void\n setGranularity: (g: Granularity) => void\n setEnabled: (v: boolean) => void\n}\n\ninterface HighlightBox {\n root: HTMLDivElement\n label: HTMLDivElement\n}\n\nfunction createBox(doc: Document, color: string, bg: string): HighlightBox {\n const root = doc.createElement('div')\n root.setAttribute('data-pubuilder', 'highlight')\n Object.assign(root.style, {\n position: 'fixed',\n top: '0',\n left: '0',\n display: 'none',\n border: `1px solid ${color}`,\n background: bg,\n borderRadius: '0',\n pointerEvents: 'none',\n zIndex: '2147483647',\n boxSizing: 'border-box',\n } satisfies Partial<CSSStyleDeclaration>)\n\n const label = doc.createElement('div')\n Object.assign(label.style, {\n position: 'absolute',\n left: '-1px',\n top: '-22px',\n padding: '2px 7px',\n background: color,\n color: '#fff',\n font: '600 10px/16px system-ui, sans-serif',\n borderRadius: '0',\n whiteSpace: 'nowrap',\n pointerEvents: 'none',\n } satisfies Partial<CSSStyleDeclaration>)\n root.appendChild(label)\n return { root, label }\n}\n\nfunction placeBox(box: HighlightBox, el: Element, text: string, barBottom: number | null) {\n const rect = el.getBoundingClientRect()\n // 상단 고정 바(sticky/fixed 헤더) 아래로 클램프 — 헤더를 뚫고 그려지지 않게\n const minTop = barBottom ?? -Infinity\n const top = Math.max(rect.top, minTop)\n const height = rect.bottom - top\n if (height <= 2) {\n hideBox(box)\n return\n }\n box.root.style.display = 'block'\n box.root.style.transform = `translate(${rect.x}px, ${top}px)`\n box.root.style.width = `${rect.width}px`\n box.root.style.height = `${height}px`\n box.label.textContent = text\n // 라벨(높이 ~24px)이 올라갈 자리에 헤더가 있거나 뷰포트 최상단이면 박스 안쪽으로\n box.label.style.top = top < 30 || top - 24 < minTop ? '2px' : '-24px'\n}\n\nfunction hideBox(box: HighlightBox) {\n box.root.style.display = 'none'\n}\n\nfunction describe(el: Element): string {\n const rect = el.getBoundingClientRect()\n return `${el.tagName.toLowerCase()} · ${Math.round(rect.width)}×${Math.round(rect.height)}`\n}\n\n/**\n * 같은 오리진 iframe의 document에 개발자도구식 hover/클릭 인스펙터를 붙인다.\n * 크로스오리진이면 null을 반환한다.\n */\nexport function attachInspector(\n iframe: HTMLIFrameElement,\n opts: InspectorOptions,\n): InspectorHandle | null {\n let maybeDoc: Document | null = null\n try {\n maybeDoc = iframe.contentDocument\n } catch {\n return null\n }\n const win = iframe.contentWindow\n if (!maybeDoc || !maybeDoc.body || !win) return null\n const doc: Document = maybeDoc\n\n let granularity = opts.granularity\n let enabled = opts.enabled\n let hoverEl: Element | null = null\n let selectedEl: Element | null = null\n\n const hoverBox = createBox(doc, 'rgba(14,99,156,0.95)', 'rgba(14,99,156,0.10)')\n const selectBox = createBox(doc, 'rgba(35,134,54,0.95)', 'rgba(35,134,54,0.07)')\n doc.body.appendChild(hoverBox.root)\n doc.body.appendChild(selectBox.root)\n\n /** 화면 상단에 도킹된 fixed/sticky 바 목록 (헤더 등) */\n let topBars: { el: Element; rect: DOMRect }[] = []\n let lastBarScan = 0\n const refreshTopBars = () => {\n topBars = []\n for (const el of Array.from(doc.body.querySelectorAll<HTMLElement>('*'))) {\n if (el === hoverBox.root || el === selectBox.root) continue\n if (hoverBox.root.contains(el) || selectBox.root.contains(el)) continue\n const pos = win.getComputedStyle(el).position\n if (pos !== 'fixed' && pos !== 'sticky') continue\n const rect = el.getBoundingClientRect()\n if (rect.width === 0 || rect.height === 0) continue\n // 상단 도킹 + 화면 절반 미만 높이인 것만 헤더로 간주\n if (rect.top <= 1 && rect.height < win.innerHeight * 0.5) topBars.push({ el, rect })\n }\n }\n\n /**\n * 스로틀된 재스캔. iframe onLoad 시점엔 SPA가 아직 헤더를 렌더하기 전일 수\n * 있고, 라우팅으로 헤더가 바뀔 수도 있어 상호작용 시마다 갱신한다.\n */\n const ensureTopBars = () => {\n const now = Date.now()\n if (now - lastBarScan < 500) return\n lastBarScan = now\n refreshTopBars()\n }\n\n /** el과 가로로 겹치는 상단 바들의 최대 하단값 (없으면 null) — 클램프/라벨 배치 기준 */\n const topBarBottomFor = (el: Element): number | null => {\n const rect = el.getBoundingClientRect()\n let bottom: number | null = null\n for (const bar of topBars) {\n // 헤더 자신(또는 그 내부/조상)을 검사할 때는 제외\n if (bar.el === el || bar.el.contains(el) || el.contains(bar.el)) continue\n const overlapsX = rect.left < bar.rect.right && rect.right > bar.rect.left\n if (!overlapsX) continue\n if (bottom === null || bar.rect.bottom > bottom) bottom = bar.rect.bottom\n }\n return bottom\n }\n\n const syncBoxes = () => {\n if (hoverEl && enabled && hoverEl.isConnected)\n placeBox(hoverBox, hoverEl, describe(hoverEl), topBarBottomFor(hoverEl))\n else hideBox(hoverBox)\n if (selectedEl && selectedEl.isConnected)\n placeBox(selectBox, selectedEl, `선택됨 · ${describe(selectedEl)}`, topBarBottomFor(selectedEl))\n else hideBox(selectBox)\n }\n\n /**\n * 클릭/hover 지점의 블록 결정.\n * 이미 선택된 블록 안을 다시 가리키면 target 방향으로 한 단계 더 깊은\n * 자식을 반환한다 (Figma식 드릴다운 — 클릭할 때마다 더 깊은 뎁스 선택).\n * 전체 모드에서는 언제나 body를 유지한다.\n */\n const resolveBlock = (target: Element): Element | null => {\n if (granularity === 'all') return doc.body\n if (\n selectedEl &&\n selectedEl.isConnected &&\n selectedEl.contains(target)\n ) {\n if (selectedEl === target) return selectedEl // 최심부 도달 — 유지\n let cur: Element = target\n while (cur.parentElement && cur.parentElement !== selectedEl) {\n cur = cur.parentElement\n }\n return cur\n }\n return pickBlock(target, doc, granularity)\n }\n\n const onMove = (ev: MouseEvent) => {\n if (!enabled) return\n ensureTopBars()\n const target = ev.target as Element | null\n if (!target || !doc.body.contains(target)) return\n const block = resolveBlock(target)\n if (block !== hoverEl) {\n hoverEl = block\n syncBoxes()\n }\n }\n\n const onClick = (ev: MouseEvent) => {\n if (!enabled) return\n ev.preventDefault()\n ev.stopPropagation()\n refreshTopBars()\n lastBarScan = Date.now()\n const target = ev.target as Element | null\n if (!target) return\n const block = resolveBlock(target)\n if (!block) return\n selectedEl = block\n syncBoxes()\n const rect = block.getBoundingClientRect()\n opts.onSelect(\n {\n pagePath: opts.pagePath,\n selector: cssPath(block, doc),\n tag: block.tagName.toLowerCase(),\n label: blockLabel(block),\n rect: {\n x: rect.x + win.scrollX,\n y: rect.y + win.scrollY,\n width: rect.width,\n height: rect.height,\n },\n granularity,\n },\n block,\n )\n }\n\n const onLeave = () => {\n hoverEl = null\n syncBoxes()\n }\n\n const onScrollOrResize = () => syncBoxes()\n const onResize = () => {\n refreshTopBars()\n syncBoxes()\n }\n\n refreshTopBars()\n\n doc.addEventListener('mousemove', onMove, true)\n doc.addEventListener('click', onClick, true)\n doc.documentElement.addEventListener('mouseleave', onLeave)\n win.addEventListener('scroll', onScrollOrResize, true)\n win.addEventListener('resize', onResize)\n\n return {\n destroy() {\n try {\n doc.removeEventListener('mousemove', onMove, true)\n doc.removeEventListener('click', onClick, true)\n doc.documentElement.removeEventListener('mouseleave', onLeave)\n win.removeEventListener('scroll', onScrollOrResize, true)\n win.removeEventListener('resize', onResize)\n hoverBox.root.remove()\n selectBox.root.remove()\n } catch {\n // iframe이 이미 언로드된 경우\n }\n },\n setGranularity(g) {\n granularity = g\n hoverEl = null\n syncBoxes()\n },\n setEnabled(v) {\n enabled = v\n if (!v) hoverEl = null\n syncBoxes()\n },\n }\n}\n","import { useContext, useEffect, useRef, useState } from 'react'\nimport { ApiError, PubuilderServerContext, type AgentEvent } from '../api'\nimport { usePubuilderStore } from '../store'\n\ntype Status = 'idle' | 'running' | 'done' | 'error'\n\nconst EVENT_ICON: Record<AgentEvent['type'], string> = {\n log: '💬',\n tool: '🔧',\n error: '⛔',\n done: '✅',\n}\n\nexport function PublishPanel() {\n const api = useContext(PubuilderServerContext)\n const selection = usePubuilderStore((s) => s.selection)\n const selectedOuterHTML = usePubuilderStore((s) => s.selectedOuterHTML)\n const toggleSkillDrawer = usePubuilderStore((s) => s.toggleSkillDrawer)\n\n const [figmaUrl, setFigmaUrl] = useState('')\n const [status, setStatus] = useState<Status>('idle')\n const [jobId, setJobId] = useState<string | null>(null)\n const [events, setEvents] = useState<AgentEvent[]>([])\n const [serverDown, setServerDown] = useState(false)\n const [checking, setChecking] = useState(false)\n const [errorMessage, setErrorMessage] = useState<string | null>(null)\n const [errorCode, setErrorCode] = useState<string | null>(null)\n const [cancelling, setCancelling] = useState(false)\n const [copied, setCopied] = useState(false)\n\n const logRef = useRef<HTMLDivElement>(null)\n const unsubscribeRef = useRef<(() => void) | null>(null)\n // 진행 중인 onPublish 흐름의 세대 토큰. 선택 변경/unmount 시 증가시켜,\n // 비동기 갭(isAlive/startPublish await) 이후 도착한 stale 흐름의\n // setState/subscribe를 차단한다 (EventSource 누수 방지).\n const genRef = useRef(0)\n\n // 선택 블록이 바뀌면 이전 job 구독을 정리하고 패널 상태를 초기화한다.\n useEffect(() => {\n genRef.current++\n unsubscribeRef.current?.()\n unsubscribeRef.current = null\n setStatus('idle')\n setJobId(null)\n setEvents([])\n setServerDown(false)\n setChecking(false)\n setCancelling(false)\n setErrorMessage(null)\n setErrorCode(null)\n setFigmaUrl('')\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selection?.selector])\n\n // 새 이벤트 도착 시 로그 뷰 자동 스크롤\n useEffect(() => {\n const el = logRef.current\n if (el) el.scrollTop = el.scrollHeight\n }, [events])\n\n // 언마운트 시 구독 해제 (v1: 실행 중이던 job은 서버에서 계속 돌게 둔다)\n useEffect(() => {\n return () => {\n genRef.current++\n unsubscribeRef.current?.()\n unsubscribeRef.current = null\n }\n }, [])\n\n const subscribe = (id: string) => {\n unsubscribeRef.current = api.subscribePublish(id, (e) => {\n setEvents((prev) => [...prev, e])\n if (e.type === 'done') {\n setStatus('done')\n setJobId(null)\n setCancelling(false)\n unsubscribeRef.current?.()\n unsubscribeRef.current = null\n } else if (e.type === 'error') {\n setStatus('error')\n setErrorMessage(e.text)\n setJobId(null)\n setCancelling(false)\n unsubscribeRef.current?.()\n unsubscribeRef.current = null\n }\n })\n }\n\n const onPublish = async () => {\n if (!selection || status === 'running' || checking) return\n const myGen = genRef.current\n setServerDown(false)\n setErrorMessage(null)\n setErrorCode(null)\n setChecking(true)\n try {\n const alive = await api.isAlive()\n if (myGen !== genRef.current) return // 선택 변경/unmount로 stale — 상태 갱신 금지\n if (!alive) {\n setServerDown(true)\n return\n }\n const { jobId: id } = await api.startPublish({\n selection,\n outerHTML: selectedOuterHTML ?? '',\n figmaUrl,\n })\n if (myGen !== genRef.current) {\n // startPublish는 이미 성공 — 구독하지 않고 서버 job만 정리 시도 (실패해도 v1 수용)\n api.cancelPublish(id).catch(() => {})\n return\n }\n setJobId(id)\n setEvents([])\n setStatus('running')\n subscribe(id)\n } catch (e) {\n if (myGen !== genRef.current) return\n setStatus('error')\n setErrorMessage(e instanceof Error ? e.message : String(e))\n setErrorCode(e instanceof ApiError ? (e.code ?? null) : null)\n } finally {\n // stale 세대가 억제해야 하는 건 결과 해석이지 로딩 플래그가 아니다 —\n // 무조건 해제해 버튼이 영구 비활성되지 않게 한다.\n setChecking(false)\n }\n }\n\n const onCancel = async () => {\n if (!jobId || cancelling) return\n setCancelling(true)\n try {\n // 상태 전이는 서버가 보내는 error 이벤트로 처리한다 (위 subscribe 콜백)\n await api.cancelPublish(jobId)\n } catch (e) {\n setErrorMessage(e instanceof Error ? e.message : String(e))\n setCancelling(false)\n }\n // 성공 시 cancelling 해제는 terminal 이벤트(subscribe 콜백)에서 수행\n }\n\n const copyServeCommand = async () => {\n await navigator.clipboard.writeText('npx pubuilder serve')\n setCopied(true)\n setTimeout(() => setCopied(false), 1200)\n }\n\n const recheck = async () => {\n setChecking(true)\n try {\n const alive = await api.isAlive()\n setServerDown(!alive)\n } finally {\n setChecking(false)\n }\n }\n\n const isRunning = status === 'running'\n // 서버 에러 코드 계약(server/errors.ts) 기반 분기 — 토큰 설정으로 해결 가능한 에러만\n const showTokenHint = errorCode === 'NO_FIGMA_TOKEN' || errorCode === 'FIGMA_API_ERROR'\n\n return (\n <div className=\"pbu-publish\">\n <label>\n Figma 노드 링크\n </label>\n <input\n value={figmaUrl}\n onChange={(e) => setFigmaUrl(e.target.value)}\n disabled={isRunning}\n placeholder=\"https://www.figma.com/design/...\"\n />\n\n {serverDown && (\n <div className=\"pbu-panel-empty\">\n 컴패니언 서버가 꺼져 있어요\n <div className=\"pbu-drawer-code\">\n <code>npx pubuilder serve</code>\n <button type=\"button\" className=\"pbu-btn\" onClick={copyServeCommand}>\n {copied ? '복사됨 ✓' : '복사'}\n </button>\n </div>\n <div className=\"pbu-hint\">\n package.json의 dev 스크립트를 \"pubuilder dev -- &lt;기존 명령&gt;\"으로 감싸면 자동 실행돼요\n </div>\n <button type=\"button\" className=\"pbu-btn\" disabled={checking} onClick={recheck}>다시 확인</button>\n </div>\n )}\n\n {errorMessage && !serverDown && (\n <div className=\"pbu-drawer-error\">\n <span>{errorMessage}</span>\n {showTokenHint && (\n <button type=\"button\" className=\"pbu-btn\" onClick={toggleSkillDrawer}>스킬함 열기</button>\n )}\n </div>\n )}\n\n {isRunning ? (\n <button type=\"button\" className=\"pbu-btn pbu-btn-primary\" disabled={cancelling} onClick={onCancel}>\n {cancelling ? '중단 중...' : '중단'}\n </button>\n ) : (\n <button\n type=\"button\"\n className=\"pbu-btn pbu-btn-primary\"\n disabled={checking || !selection}\n onClick={onPublish}\n >\n 이 블록 퍼블리싱\n </button>\n )}\n\n {(events.length > 0 || isRunning) && (\n <div className=\"pbu-publish-log\" ref={logRef}>\n {isRunning && events.length === 0 && (\n <div className=\"pbu-log-line pbu-log-tool\">실행 중...</div>\n )}\n {events.map((e, i) => (\n <div\n key={i}\n className={\n e.type === 'error'\n ? 'pbu-log-line pbu-log-error'\n : e.type === 'done'\n ? 'pbu-log-line pbu-log-done'\n : e.type === 'tool'\n ? 'pbu-log-line pbu-log-tool'\n : 'pbu-log-line'\n }\n >\n <span>{EVENT_ICON[e.type]}</span> <span>{e.text}</span>\n </div>\n ))}\n </div>\n )}\n </div>\n )\n}\n","import { useState } from 'react'\nimport { usePubuilderStore } from '../store'\nimport { PublishPanel } from './PublishPanel'\n\nexport function SelectionPanel() {\n const selection = usePubuilderStore((s) => s.selection)\n const [copied, setCopied] = useState(false)\n\n const copySelector = async () => {\n if (!selection) return\n await navigator.clipboard.writeText(selection.selector)\n setCopied(true)\n setTimeout(() => setCopied(false), 1200)\n }\n\n return (\n <aside className=\"pbu-panel\">\n <div className=\"pbu-panel-title\">선택된 블록</div>\n {!selection ? (\n <div className=\"pbu-panel-empty\">\n 화면에서 블록에 마우스를 올리고 클릭해 선택하세요.\n <br />\n 상단 토글로 <b>전체 / 섹션 / 유닛</b> 단위를 바꿀 수 있어요.\n </div>\n ) : (\n <>\n <div className=\"pbu-field\">\n <label>페이지</label>\n <code>{selection.pagePath}</code>\n </div>\n <div className=\"pbu-field\">\n <label>블록</label>\n <div>\n <span className=\"pbu-chip\">{selection.tag}</span>\n <span>{selection.label}</span>\n </div>\n </div>\n <div className=\"pbu-field\">\n <label>Selector</label>\n <code className=\"pbu-selector\">{selection.selector}</code>\n <button type=\"button\" className=\"pbu-btn\" onClick={copySelector}>\n {copied ? '복사됨 ✓' : 'Selector 복사'}\n </button>\n </div>\n <div className=\"pbu-field\">\n <label>크기</label>\n <span>\n {Math.round(selection.rect.width)} × {Math.round(selection.rect.height)}px\n </span>\n </div>\n <div className=\"pbu-field\">\n <label>단위</label>\n <span>\n {selection.granularity === 'all'\n ? '전체'\n : selection.granularity === 'section'\n ? '섹션'\n : '유닛'}\n </span>\n </div>\n\n <PublishPanel />\n </>\n )}\n </aside>\n )\n}\n","import { useEffect, useRef, useState } from 'react'\nimport type { NormalizedIA } from '../config'\nimport { attachInspector, type InspectorHandle } from '../inspector/inspector'\nimport { usePubuilderStore } from '../store'\nimport { SelectionPanel } from './SelectionPanel'\n\nexport function PageViewer({ ia }: { ia: NormalizedIA }) {\n const viewerPath = usePubuilderStore((s) => s.viewerPath)\n const closeViewer = usePubuilderStore((s) => s.closeViewer)\n const granularity = usePubuilderStore((s) => s.granularity)\n const setGranularity = usePubuilderStore((s) => s.setGranularity)\n const inspectEnabled = usePubuilderStore((s) => s.inspectEnabled)\n const setInspectEnabled = usePubuilderStore((s) => s.setInspectEnabled)\n const toggleSkillDrawer = usePubuilderStore((s) => s.toggleSkillDrawer)\n\n const iframeRef = useRef<HTMLIFrameElement>(null)\n const handleRef = useRef<InspectorHandle | null>(null)\n const [inspectorFailed, setInspectorFailed] = useState(false)\n\n const node = ia.nodes.find((n) => n.path === viewerPath)\n\n const onFrameLoad = () => {\n handleRef.current?.destroy()\n handleRef.current = null\n const iframe = iframeRef.current\n if (!iframe || !viewerPath) return\n const state = usePubuilderStore.getState()\n const handle = attachInspector(iframe, {\n pagePath: viewerPath,\n granularity: state.granularity,\n enabled: state.inspectEnabled,\n onSelect: (sel, el) =>\n // 20K 상한 — 프롬프트 비대화 방지\n usePubuilderStore.getState().setSelectionWithHTML(sel, el.outerHTML.slice(0, 20_000)),\n })\n if (!handle) {\n setInspectorFailed(true)\n return\n }\n setInspectorFailed(false)\n handleRef.current = handle\n }\n\n // 언마운트 시 인스펙터 해제\n useEffect(() => () => handleRef.current?.destroy(), [])\n useEffect(() => { handleRef.current?.setGranularity(granularity) }, [granularity])\n useEffect(() => { handleRef.current?.setEnabled(inspectEnabled) }, [inspectEnabled])\n\n // Esc → 뷰어 닫기 (맵 캔버스로 복귀 · 스킬함 드로어가 열려 있으면 드로어가 처리)\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key !== 'Escape') return\n if (usePubuilderStore.getState().skillDrawerOpen) return\n closeViewer()\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [closeViewer])\n\n if (!node) return null\n\n return (\n <div className=\"pbu-viewer\">\n <div className=\"pbu-bar\">\n <button type=\"button\" className=\"pbu-btn\" onClick={closeViewer}>← 맵으로</button>\n <span className=\"pbu-viewer-title\">\n {node.title}\n <code>{node.path}</code>\n </span>\n <span className=\"pbu-spacer\" />\n {inspectorFailed && <span className=\"pbu-hint\">⚠ 이 페이지는 검사할 수 없어요</span>}\n <div className=\"pbu-seg\" role=\"group\" aria-label=\"블록 단위\">\n <button\n type=\"button\"\n className={granularity === 'all' ? 'pbu-on' : ''}\n onClick={() => setGranularity('all')}\n >\n 전체\n </button>\n <button\n type=\"button\"\n className={granularity === 'section' ? 'pbu-on' : ''}\n onClick={() => setGranularity('section')}\n >\n 섹션\n </button>\n <button\n type=\"button\"\n className={granularity === 'unit' ? 'pbu-on' : ''}\n onClick={() => setGranularity('unit')}\n >\n 유닛\n </button>\n </div>\n <label className=\"pbu-toggle\">\n <input\n type=\"checkbox\"\n checked={inspectEnabled}\n onChange={(e) => setInspectEnabled(e.target.checked)}\n />\n 검사 모드\n </label>\n <button type=\"button\" className=\"pbu-btn\" onClick={toggleSkillDrawer}>🧰 스킬함</button>\n <button type=\"button\" className=\"pbu-icon-btn\" onClick={closeViewer} aria-label=\"닫기\">✕</button>\n </div>\n <div className=\"pbu-viewer-body\">\n <div className=\"pbu-viewer-frame-wrap\">\n <iframe\n ref={iframeRef}\n className=\"pbu-viewer-iframe\"\n src={node.path}\n title={node.title}\n onLoad={onFrameLoad}\n />\n </div>\n <SelectionPanel />\n </div>\n </div>\n )\n}\n","import { useContext, useEffect, useRef, useState } from 'react'\nimport { PubuilderServerContext, type SkillInfo, type TokenStatus } from '../api'\nimport { usePubuilderStore } from '../store'\n\nconst GROUP_LABELS: Record<SkillInfo['source'], string> = {\n project: '프로젝트',\n global: '글로벌',\n uploaded: '업로드',\n}\nconst GROUP_ORDER: SkillInfo['source'][] = ['project', 'global', 'uploaded']\n\nexport function SkillDrawer() {\n const toggleSkillDrawer = usePubuilderStore((s) => s.toggleSkillDrawer)\n const api = useContext(PubuilderServerContext)\n\n const [loading, setLoading] = useState(true)\n const [alive, setAlive] = useState(false)\n const [skills, setSkills] = useState<SkillInfo[]>([])\n const [tokenStatus, setTokenStatus] = useState<TokenStatus | null>(null)\n const [tokenInput, setTokenInput] = useState('')\n const [showTokenInput, setShowTokenInput] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [copied, setCopied] = useState(false)\n\n const fileInputRef = useRef<HTMLInputElement>(null)\n // 늦게 도착한 응답이 최신 상태를 덮어쓰지 않도록 하는 증가 토큰\n const reqRef = useRef(0)\n // mutation 진행 중 컨트롤 비활성화용 (중복 요청 방지)\n const [busy, setBusy] = useState<string | null>(null)\n\n const load = async () => {\n const my = ++reqRef.current\n setLoading(true)\n setError(null)\n try {\n const isAlive = await api.isAlive()\n if (my !== reqRef.current) return\n setAlive(isAlive)\n if (!isAlive) return\n const [skillList, token] = await Promise.all([api.listSkills(), api.tokenStatus()])\n if (my !== reqRef.current) return\n setSkills(skillList)\n setTokenStatus(token)\n setShowTokenInput(!token.configured)\n } catch (e) {\n if (my !== reqRef.current) return\n setError(e instanceof Error ? e.message : String(e))\n } finally {\n if (my === reqRef.current) setLoading(false)\n }\n }\n\n useEffect(() => {\n load()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n // Esc → 드로어만 닫기 (viewer/canvas 핸들러는 드로어 열림 상태를 확인해 무시)\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') toggleSkillDrawer()\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [toggleSkillDrawer])\n\n const withErrorHandling = async (key: string, fn: () => Promise<void>) => {\n if (busy) return\n setBusy(key)\n try {\n await fn()\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e))\n } finally {\n setBusy(null)\n }\n }\n\n const onToggleSkill = (id: string, enabled: boolean) =>\n withErrorHandling(`toggle:${id}`, async () => {\n await api.toggleSkill(id, enabled)\n await load()\n })\n\n const onRemoveSkill = (id: string, name: string) => {\n if (!window.confirm(`\"${name}\" 스킬을 삭제할까요?`)) return\n withErrorHandling(`remove:${id}`, async () => {\n await api.removeSkill(id)\n await load()\n })\n }\n\n const onUploadClick = () => fileInputRef.current?.click()\n\n const onFileSelected = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0]\n e.target.value = ''\n if (!file) return\n withErrorHandling('upload', async () => {\n const reader = new FileReader()\n const text = await new Promise<string>((resolve, reject) => {\n reader.onload = () => resolve(String(reader.result ?? ''))\n reader.onerror = () => reject(reader.error ?? new Error('파일을 읽을 수 없어요'))\n reader.readAsText(file)\n })\n await api.uploadSkill(file.name, text)\n await load()\n })\n }\n\n const onSaveToken = () =>\n withErrorHandling('token:save', async () => {\n if (!tokenInput.trim()) return\n await api.saveToken(tokenInput.trim())\n setTokenInput('')\n await load()\n })\n\n const onDeleteToken = () =>\n withErrorHandling('token:delete', async () => {\n await api.deleteToken()\n setTokenInput('')\n await load()\n })\n\n const copyServeCommand = async () => {\n await navigator.clipboard.writeText('npx pubuilder serve')\n setCopied(true)\n setTimeout(() => setCopied(false), 1200)\n }\n\n const grouped = GROUP_ORDER.map((source) => ({\n source,\n label: GROUP_LABELS[source],\n items: skills.filter((s) => s.source === source),\n })).filter((g) => g.items.length > 0)\n\n return (\n <aside className=\"pbu-drawer\">\n <div className=\"pbu-drawer-header\">\n <span className=\"pbu-panel-title\">스킬함</span>\n <button type=\"button\" className=\"pbu-icon-btn\" onClick={toggleSkillDrawer} aria-label=\"닫기\">✕</button>\n </div>\n\n {error && (\n <div className=\"pbu-drawer-error\">\n <span>{error}</span>\n <button type=\"button\" className=\"pbu-icon-btn\" onClick={() => setError(null)} aria-label=\"닫기\">✕</button>\n </div>\n )}\n\n {loading ? (\n <div className=\"pbu-panel-empty\">불러오는 중...</div>\n ) : !alive ? (\n <div className=\"pbu-panel-empty\">\n 컴패니언 서버가 꺼져 있어요\n <div className=\"pbu-drawer-code\">\n <code>npx pubuilder serve</code>\n <button type=\"button\" className=\"pbu-btn\" onClick={copyServeCommand}>\n {copied ? '복사됨 ✓' : '복사'}\n </button>\n </div>\n <div className=\"pbu-hint\">\n package.json의 dev 스크립트를 \"pubuilder dev -- &lt;기존 명령&gt;\"으로 감싸면 자동 실행돼요\n </div>\n <button type=\"button\" className=\"pbu-btn\" onClick={load}>다시 확인</button>\n </div>\n ) : (\n <>\n <div className=\"pbu-drawer-group\">토큰</div>\n {tokenStatus?.configured && !showTokenInput ? (\n <div className=\"pbu-field\">\n <span className=\"pbu-token-masked\">{tokenStatus.masked}</span>\n <div>\n <button type=\"button\" className=\"pbu-btn\" disabled={busy !== null} onClick={() => setShowTokenInput(true)}>재입력</button>\n <button type=\"button\" className=\"pbu-btn\" disabled={busy !== null} onClick={onDeleteToken}>삭제</button>\n </div>\n </div>\n ) : (\n <div className=\"pbu-field\">\n <input\n type=\"password\"\n value={tokenInput}\n onChange={(e) => setTokenInput(e.target.value)}\n placeholder=\"Figma 토큰\"\n />\n <button type=\"button\" className=\"pbu-btn pbu-btn-primary\" disabled={busy !== null} onClick={onSaveToken}>저장</button>\n </div>\n )}\n\n <div className=\"pbu-drawer-group\">\n 스킬 목록\n <button type=\"button\" className=\"pbu-btn\" disabled={busy !== null} onClick={onUploadClick}>업로드</button>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\".md\"\n style={{ display: 'none' }}\n onChange={onFileSelected}\n />\n </div>\n\n {grouped.length === 0 ? (\n <div className=\"pbu-panel-empty\">등록된 스킬이 없어요.</div>\n ) : (\n grouped.map((g) => (\n <div key={g.source}>\n <div className=\"pbu-drawer-group\">{g.label}</div>\n {g.items.map((skill) => (\n <div key={skill.id} className=\"pbu-skill-row\">\n <label className=\"pbu-toggle\">\n <input\n type=\"checkbox\"\n checked={skill.enabled}\n disabled={busy !== null}\n onChange={(e) => onToggleSkill(skill.id, e.target.checked)}\n />\n {skill.name}\n </label>\n <span className=\"pbu-hint\" title={skill.description}>{skill.description}</span>\n {skill.source === 'uploaded' && (\n <button\n type=\"button\"\n className=\"pbu-icon-btn\"\n disabled={busy !== null}\n onClick={() => onRemoveSkill(skill.id, skill.name)}\n aria-label=\"삭제\"\n >\n 🗑\n </button>\n )}\n </div>\n ))}\n </div>\n ))\n )}\n </>\n )}\n </aside>\n )\n}\n","'use client'\n\nimport { useLayoutEffect, useMemo, useState } from 'react'\nimport { createPortal } from 'react-dom'\nimport { PubuilderApi, PubuilderServerContext } from '../api'\nimport { normalizeIA } from '../config'\nimport { isProductionEnv } from '../env'\nimport { usePubuilderStore } from '../store'\nimport { ensureStyles } from '../styles'\nimport type { IAConfig } from '../types.js'\nimport { CanvasOverlay } from './CanvasOverlay'\nimport { Fab } from './Fab'\nimport { PageViewer } from './PageViewer'\nimport { SkillDrawer } from './SkillDrawer'\n\nexport interface PageMapProps {\n config: IAConfig\n /**\n * 렌더 여부. 기본 true. production 빌드에서는 이 값과 무관하게\n * 자동으로 렌더하지 않는다 (dev 전용 안전장치).\n */\n enabled?: boolean\n /** 컴패니언 서버 URL. 기본 http://localhost:4816 */\n serverUrl?: string\n}\n\nexport function PageMap({ config, enabled = true, serverUrl }: PageMapProps) {\n // dev 전용 도구 — production 번들에 실수로 포함돼도 사용자에게 노출되지 않게 차단\n const active = enabled && !isProductionEnv()\n const [mounted, setMounted] = useState(false)\n const isMapOpen = usePubuilderStore((s) => s.isMapOpen)\n const viewerPath = usePubuilderStore((s) => s.viewerPath)\n const skillDrawerOpen = usePubuilderStore((s) => s.skillDrawerOpen)\n\n const ia = useMemo(() => normalizeIA(config), [config])\n const api = useMemo(() => new PubuilderApi(serverUrl), [serverUrl])\n\n useLayoutEffect(() => {\n if (!active) return\n // 썸네일 iframe 안에서 또 렌더되는 재귀 방지\n if (window.self !== window.top) return\n ensureStyles()\n setMounted(true)\n }, [active])\n\n // SSR / iframe 내부 / production / 비활성 → 아무것도 렌더하지 않음\n if (!mounted || !active) return null\n\n return createPortal(\n <PubuilderServerContext.Provider value={api}>\n <Fab />\n {isMapOpen && <CanvasOverlay ia={ia} />}\n {viewerPath && <PageViewer ia={ia} />}\n {skillDrawerOpen && <SkillDrawer />}\n </PubuilderServerContext.Provider>,\n document.body,\n )\n}\n"],"names":["DEFAULT_SERVER_URL","ApiError","message","code","PubuilderApi","baseUrl","path","init","res","body","id","enabled","filename","content","token","payload","jobId","onEvent","source","terminal","msg","e","PubuilderServerContext","createContext","isProductionEnv","usePubuilderStore","create","set","granularity","inspectEnabled","selection","selectedOuterHTML","s","STYLE_ID","XYFLOW_STYLE_ID","CSS_TEXT","injectOnce","css","style","ensureStyles","xyflowCss","layoutTree","nodes","nodeWidth","nodeHeight","gapX","gapY","childrenOf","n","list","pos","cursorY","place","node","kids","x","y","ys","root","PageNode","memo","props","page","viewport","thumbWidth","bodyHeight","openViewer","ref","useRef","visible","setVisible","useState","useEffect","el","io","entry","scale","jsxs","jsx","Handle","Position","nodeTypes","THUMB_WIDTH","HEADER_HEIGHT","CanvasOverlay","ia","closeMap","toggleSkillDrawer","edges","useMemo","laid","onKey","state","ReactFlow","Fab","isMapOpen","openMap","SECTION_TAGS","UNIT_TAGS","ancestorChain","doc","chain","cur","pickSection","target","semantic","tag","main","bodyH","rect","pickUnit","hasContent","pickBlock","blockLabel","headingText","truncate","aria","alt","text","max","cssPath","parts","parent","part","sameTag","c","createBox","color","bg","label","placeBox","box","barBottom","minTop","top","height","hideBox","describe","attachInspector","iframe","opts","maybeDoc","win","hoverEl","selectedEl","hoverBox","selectBox","topBars","lastBarScan","refreshTopBars","ensureTopBars","now","topBarBottomFor","bottom","bar","syncBoxes","resolveBlock","onMove","ev","block","onClick","onLeave","onScrollOrResize","onResize","g","v","EVENT_ICON","PublishPanel","api","useContext","figmaUrl","setFigmaUrl","status","setStatus","setJobId","events","setEvents","serverDown","setServerDown","checking","setChecking","errorMessage","setErrorMessage","errorCode","setErrorCode","cancelling","setCancelling","copied","setCopied","logRef","unsubscribeRef","genRef","subscribe","prev","onPublish","myGen","alive","onCancel","copyServeCommand","recheck","isRunning","i","SelectionPanel","copySelector","Fragment","PageViewer","viewerPath","closeViewer","setGranularity","setInspectEnabled","iframeRef","handleRef","inspectorFailed","setInspectorFailed","onFrameLoad","handle","sel","GROUP_LABELS","GROUP_ORDER","SkillDrawer","loading","setLoading","setAlive","skills","setSkills","tokenStatus","setTokenStatus","tokenInput","setTokenInput","showTokenInput","setShowTokenInput","error","setError","fileInputRef","reqRef","busy","setBusy","load","my","isAlive","skillList","withErrorHandling","key","fn","onToggleSkill","onRemoveSkill","name","onUploadClick","onFileSelected","file","reader","resolve","reject","onSaveToken","onDeleteToken","grouped","skill","PageMap","config","serverUrl","active","mounted","setMounted","skillDrawerOpen","normalizeIA","useLayoutEffect","createPortal"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/api.ts","../src/env.ts","../src/publish-jobs.ts","../src/store.ts","../src/styles.ts","../src/layout.ts","../src/components/PageNode.tsx","../src/components/SuspendButton.tsx","../src/components/CanvasOverlay.tsx","../src/components/Fab.tsx","../src/inspector/heuristics.ts","../src/inspector/inspector.ts","../src/components/PublishPanel.tsx","../src/components/SelectionPanel.tsx","../src/components/PageViewer.tsx","../src/components/SkillDrawer.tsx","../src/components/SuspendConflictPanel.tsx","../src/components/PageMap.tsx"],"sourcesContent":["// 컴패니언 서버 HTTP 클라이언트 (브라우저 전용)\nimport { createContext } from 'react'\nimport type { BlockSelection } from './types'\n\nexport const DEFAULT_SERVER_URL = 'http://localhost:4816'\n\nexport interface SkillInfo {\n id: string\n name: string\n description: string\n source: 'project' | 'global' | 'uploaded'\n enabled: boolean\n}\nexport interface AgentEvent { type: 'log' | 'tool' | 'error' | 'done'; text: string }\nexport interface TokenStatus { configured: boolean; masked: string | null }\n\n/** 일시 종료 시 롤백이 완료 job/사용자 편집과 겹치는 파일 */\nexport interface SuspendConflict { file: string; baseline: string; current: string }\nexport interface SuspendResult { autoReverted: string[]; conflicts: SuspendConflict[] }\nexport type SuspendResolution = { file: string; action: 'revert' | 'keep' | 'edit'; content?: string }\n\n/** 서버 에러 응답의 code(server/errors.ts 계약)를 UI 분기용으로 실어 나르는 에러 */\nexport class ApiError extends Error {\n constructor(message: string, readonly code?: string) {\n super(message)\n this.name = 'ApiError'\n }\n}\n\nexport class PubuilderApi {\n constructor(private readonly baseUrl: string = DEFAULT_SERVER_URL) {}\n\n private async request<T>(path: string, init?: RequestInit): Promise<T> {\n const res = await fetch(`${this.baseUrl}${path}`, {\n ...init,\n headers: { 'content-type': 'application/json', ...init?.headers },\n })\n if (!res.ok) {\n const body = (await res.json().catch(() => ({}))) as { code?: string; message?: string }\n throw new ApiError(body.message ?? `요청 실패 (${res.status})`, body.code)\n }\n return res.status === 204 ? (undefined as T) : ((await res.json()) as T)\n }\n\n async isAlive(): Promise<boolean> {\n try {\n await this.request('/api/health')\n return true\n } catch {\n return false\n }\n }\n listSkills() { return this.request<SkillInfo[]>('/api/skills') }\n toggleSkill(id: string, enabled: boolean) {\n return this.request<void>(`/api/skills/${encodeURIComponent(id)}`, { method: 'PATCH', body: JSON.stringify({ enabled }) })\n }\n uploadSkill(filename: string, content: string) {\n return this.request<SkillInfo>('/api/skills', { method: 'POST', body: JSON.stringify({ filename, content }) })\n }\n removeSkill(id: string) { return this.request<void>(`/api/skills/${encodeURIComponent(id)}`, { method: 'DELETE' }) }\n tokenStatus() { return this.request<TokenStatus>('/api/settings/figma-token') }\n saveToken(token: string) { return this.request<void>('/api/settings/figma-token', { method: 'PUT', body: JSON.stringify({ token }) }) }\n deleteToken() { return this.request<void>('/api/settings/figma-token', { method: 'DELETE' }) }\n startPublish(payload: { selection: BlockSelection; outerHTML: string; figmaUrl: string; instruction?: string }) {\n return this.request<{ jobId: string }>('/api/publish', { method: 'POST', body: JSON.stringify(payload) })\n }\n cancelPublish(jobId: string) { return this.request<void>(`/api/publish/${jobId}`, { method: 'DELETE' }) }\n /** 진행 중 job 전체 kill + 파일 자동롤백/충돌 분류 */\n suspendPublish() { return this.request<SuspendResult>('/api/publish/suspend', { method: 'POST', body: '{}' }) }\n /** 충돌 파일 결정(revert/keep/edit) 적용 */\n resolveSuspend(resolutions: SuspendResolution[]) {\n return this.request<void>('/api/publish/suspend/resolve', { method: 'POST', body: JSON.stringify({ resolutions }) })\n }\n\n /** SSE 구독 — 반환값 호출로 해제 */\n subscribePublish(jobId: string, onEvent: (e: AgentEvent) => void): () => void {\n const source = new EventSource(`${this.baseUrl}/api/publish/${jobId}/events`)\n // terminal(done|error) 수신 전에 연결이 끊기면(서버 다운 등) 구독자가\n // running에 영구 고착되지 않도록 error 이벤트를 합성한다. terminal 후 끊김은 정상 종료.\n let terminal = false\n source.onmessage = (msg) => {\n const e = JSON.parse(msg.data) as AgentEvent\n if (e.type === 'done' || e.type === 'error') terminal = true\n onEvent(e)\n }\n source.onerror = () => {\n source.close() // 재연결 불필요\n if (!terminal) {\n terminal = true\n onEvent({ type: 'error', text: '서버 연결이 끊겼어요. pubuilder serve 상태를 확인해주세요' })\n }\n }\n return () => source.close()\n }\n}\n\n/** PageMap이 provider로 감싸고, SkillDrawer/PublishPanel이 useContext로 획득 */\nexport const PubuilderServerContext = createContext<PubuilderApi>(new PubuilderApi())\n","/**\n * production 번들 여부. 소비 측 번들러(Next/Vite 등)가 process.env.NODE_ENV를\n * 정적 치환하므로 앱 빌드 시 상수로 접힌다. 번들러 없는 환경(process 미정의)에서는\n * false — 렌더를 막는 쪽이 아니라 허용하는 쪽이 안전한 기본값.\n *\n * 주의: 라이브러리 빌드가 이 표현식을 미리 치환하면 안 된다 — vite.config.ts 참고.\n */\nexport function isProductionEnv(): boolean {\n return typeof process !== 'undefined' && process.env.NODE_ENV === 'production'\n}\n","import type { AgentEvent } from './api'\nimport type { BlockSelection } from './types'\n\nexport type PublishStatus = 'idle' | 'running' | 'done' | 'error'\n\n/**\n * 한 블록의 퍼블리싱 job 상태. selection에 종속된 로컬 state가 아니라\n * store에 블록별로 보관되어, 다른 블록을 선택해도 실행 중인 job이 끊기지 않는다.\n */\nexport interface PublishJobState {\n jobId: string | null\n status: PublishStatus\n events: AgentEvent[]\n errorMessage: string | null\n errorCode: string | null\n serverDown: boolean\n /** isAlive/startPublish 왕복 중 로딩 플래그 */\n checking: boolean\n cancelling: boolean\n /** 입력값도 블록별로 유지 — 전환 후 돌아와도 그대로 */\n figmaUrl: string\n reply: string\n}\n\nexport const IDLE_PUBLISH_JOB: PublishJobState = {\n jobId: null,\n status: 'idle',\n events: [],\n errorMessage: null,\n errorCode: null,\n serverDown: false,\n checking: false,\n cancelling: false,\n figmaUrl: '',\n reply: '',\n}\n\n/**\n * 블록을 페이지 간에도 고유하게 식별하는 키.\n * 서로 다른 페이지가 같은 selector를 가질 수 있으므로 pagePath까지 합친다.\n * '\\n'은 selector/pagePath에 나타나지 않아 구분자로 안전하다.\n */\nexport function blockKey(sel: BlockSelection): string {\n return `${sel.pagePath}\\n${sel.selector}`\n}\n","import { create } from 'zustand'\nimport type { AgentEvent, SuspendConflict, SuspendResolution } from './api'\nimport { IDLE_PUBLISH_JOB, type PublishJobState } from './publish-jobs'\nimport type { BlockSelection, Granularity } from './types'\n\ninterface PubuilderStore {\n isMapOpen: boolean\n /** 전체화면으로 확대 중인 페이지 path (null이면 캔버스만) */\n viewerPath: string | null\n granularity: Granularity\n inspectEnabled: boolean\n selection: BlockSelection | null\n /** 선택된 블록의 outerHTML 스냅샷 (Phase 3 퍼블리싱 프롬프트용, 20K 상한) */\n selectedOuterHTML: string | null\n skillDrawerOpen: boolean\n /**\n * 블록별 퍼블리싱 job 상태 (key: blockKey). selection에서 분리되어 있어\n * 다른 블록을 선택하거나 맵을 닫아도 실행 중인 job이 끊기지 않는다.\n */\n publishJobs: Record<string, PublishJobState>\n openMap: () => void\n closeMap: () => void\n openViewer: (path: string) => void\n closeViewer: () => void\n setGranularity: (g: Granularity) => void\n setInspectEnabled: (v: boolean) => void\n setSelectionWithHTML: (s: BlockSelection | null, html: string | null) => void\n toggleSkillDrawer: () => void\n /** 블록 job의 일부 필드를 갱신 (없으면 IDLE에서 시작) */\n patchPublishJob: (key: string, partial: Partial<PublishJobState>) => void\n /** 블록 job의 이벤트 로그에 한 건 추가 */\n appendPublishEvent: (key: string, event: AgentEvent) => void\n /** 일시 종료 후 사용자가 해결해야 하는 충돌 파일들 (없으면 패널 미표시) */\n suspendConflicts: SuspendConflict[]\n /** 충돌 파일별 사용자 결정 (file → resolution) */\n suspendResolutions: Record<string, SuspendResolution>\n setSuspendConflicts: (conflicts: SuspendConflict[]) => void\n setConflictResolution: (file: string, action: SuspendResolution['action'], content?: string) => void\n clearSuspend: () => void\n}\n\nexport const usePubuilderStore = create<PubuilderStore>((set) => ({\n isMapOpen: false,\n viewerPath: null,\n granularity: 'section',\n inspectEnabled: true,\n selection: null,\n selectedOuterHTML: null,\n skillDrawerOpen: false,\n publishJobs: {},\n openMap: () => set({ isMapOpen: true }),\n // 오버레이만 닫는다 — publishJobs는 건드리지 않아 실행 중 job이 계속 살아있고,\n // 맵을 다시 열어 같은 블록을 선택하면 진행 상황/결과에 재연결된다.\n closeMap: () => set({ isMapOpen: false, viewerPath: null, selection: null, selectedOuterHTML: null }),\n openViewer: (path) => set({ viewerPath: path, selection: null, selectedOuterHTML: null }),\n closeViewer: () => set({ viewerPath: null, selection: null, selectedOuterHTML: null }),\n setGranularity: (granularity) => set({ granularity }),\n setInspectEnabled: (inspectEnabled) => set({ inspectEnabled }),\n setSelectionWithHTML: (selection, selectedOuterHTML) => set({ selection, selectedOuterHTML }),\n toggleSkillDrawer: () => set((s) => ({ skillDrawerOpen: !s.skillDrawerOpen })),\n patchPublishJob: (key, partial) =>\n set((s) => ({\n publishJobs: {\n ...s.publishJobs,\n [key]: { ...(s.publishJobs[key] ?? IDLE_PUBLISH_JOB), ...partial },\n },\n })),\n appendPublishEvent: (key, event) =>\n set((s) => {\n const prev = s.publishJobs[key] ?? IDLE_PUBLISH_JOB\n return {\n publishJobs: {\n ...s.publishJobs,\n [key]: { ...prev, events: [...prev.events, event] },\n },\n }\n }),\n suspendConflicts: [],\n suspendResolutions: {},\n setSuspendConflicts: (suspendConflicts) => set({ suspendConflicts, suspendResolutions: {} }),\n setConflictResolution: (file, action, content) =>\n set((s) => ({\n suspendResolutions: { ...s.suspendResolutions, [file]: { file, action, ...(content !== undefined ? { content } : {}) } },\n })),\n clearSuspend: () => set({ suspendConflicts: [], suspendResolutions: {} }),\n}))\n","// React Flow CSS를 빌드 시 텍스트로 인라인 — 소비 번들러(Next 등)가\n// node_modules 글로벌 CSS import를 금지해도 동작하도록 런타임 주입한다.\nimport xyflowCss from '@xyflow/react/dist/style.css?inline'\n\n/**\n * 툴 chrome 스타일. 호스트 CSS와의 충돌을 줄이기 위해\n * 전부 pbu- 접두 클래스 + 런타임 <style> 주입으로 격리한다.\n *\n * 디자인 컨셉: 개발자도구(DevTools/VSCode)식 시스템 UI.\n * 플랫, 최소 radius(≤2px), 무채색 팔레트 + 단일 액센트, 장식 없음.\n */\nconst STYLE_ID = 'pubuilder-styles'\nconst XYFLOW_STYLE_ID = 'pubuilder-xyflow-styles'\n\n// palette: bg #1e1e1e / surface #252526 / raised #2d2d2d / border #3c3c3c\n// text #cccccc / dim #8c8c8c / accent #0e639c\nconst CSS_TEXT = /* css */ `\n.pbu-fab {\n position: fixed;\n right: 16px;\n bottom: 16px;\n z-index: 2147483000;\n width: 40px;\n height: 40px;\n border-radius: 2px;\n border: 1px solid #3c3c3c;\n cursor: pointer;\n background: #252526;\n color: #cccccc;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.pbu-fab:hover { background: #2d2d2d; color: #ffffff; }\n\n.pbu-overlay,\n.pbu-viewer {\n position: fixed;\n inset: 0;\n display: flex;\n flex-direction: column;\n font-family: system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif;\n font-size: 12px;\n color: #cccccc;\n}\n.pbu-overlay { z-index: 2147483100; background: #1e1e1e; }\n.pbu-viewer { z-index: 2147483200; background: #1e1e1e; }\n\n.pbu-bar {\n display: flex;\n align-items: center;\n gap: 10px;\n height: 38px;\n padding: 0 12px;\n background: #252526;\n border-bottom: 1px solid #3c3c3c;\n flex-shrink: 0;\n}\n.pbu-logo {\n font-weight: 600;\n font-size: 11px;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: #cccccc;\n}\n.pbu-hint { font-size: 11px; color: #8c8c8c; }\n.pbu-spacer { flex: 1; }\n\n.pbu-btn {\n border: 1px solid #3c3c3c;\n background: #2d2d2d;\n color: #cccccc;\n font-size: 11px;\n padding: 4px 10px;\n border-radius: 2px;\n cursor: pointer;\n}\n.pbu-btn:hover { background: #37373d; }\n.pbu-btn:disabled { opacity: 0.4; cursor: not-allowed; }\n.pbu-btn-primary { background: #0e639c; border-color: #0e639c; color: #fff; }\n.pbu-btn-primary:hover:not(:disabled) { background: #1177bb; }\n\n.pbu-icon-btn {\n border: none;\n background: transparent;\n color: #8c8c8c;\n font-size: 14px;\n cursor: pointer;\n padding: 4px 8px;\n border-radius: 2px;\n}\n.pbu-icon-btn:hover { background: #2d2d2d; color: #ffffff; }\n\n.pbu-seg {\n display: flex;\n border: 1px solid #3c3c3c;\n border-radius: 2px;\n overflow: hidden;\n}\n.pbu-seg button {\n border: none;\n background: #2d2d2d;\n color: #8c8c8c;\n font-size: 11px;\n padding: 4px 12px;\n cursor: pointer;\n}\n.pbu-seg button + button { border-left: 1px solid #3c3c3c; }\n.pbu-seg button.pbu-on { background: #0e639c; color: #fff; }\n\n.pbu-toggle {\n display: flex;\n align-items: center;\n gap: 5px;\n font-size: 11px;\n color: #8c8c8c;\n cursor: pointer;\n user-select: none;\n}\n\n.pbu-canvas { flex: 1; min-height: 0; }\n.pbu-canvas .react-flow { background: #1e1e1e; }\n/* draggable/selectable 꺼도 노드 클릭은 받아야 함 (RF는 비인터랙티브 노드에 pointer-events:none을 줌) */\n.pbu-canvas .react-flow__node { pointer-events: all !important; cursor: pointer; }\n.pbu-canvas .react-flow__edge-path { stroke: #555555; stroke-width: 1; }\n.pbu-canvas .react-flow__controls button {\n background: #252526;\n border-bottom: 1px solid #3c3c3c;\n border-radius: 0;\n color: #cccccc;\n fill: #cccccc;\n}\n.pbu-canvas .react-flow__controls button:hover { background: #2d2d2d; }\n\n.pbu-node {\n background: #252526;\n border: 1px solid #3c3c3c;\n border-radius: 0;\n overflow: hidden;\n cursor: pointer;\n}\n.pbu-node:hover { border-color: #0e639c; }\n.pbu-node-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n height: 28px;\n padding: 0 8px;\n background: #2d2d2d;\n border-bottom: 1px solid #3c3c3c;\n}\n.pbu-node-title {\n font-size: 11px;\n font-weight: 600;\n color: #cccccc;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.pbu-node-path {\n font-size: 10px;\n color: #8c8c8c;\n font-family: ui-monospace, Menlo, monospace;\n white-space: nowrap;\n flex-shrink: 0;\n}\n.pbu-node-body { position: relative; background: #fff; overflow: hidden; }\n.pbu-node-iframe {\n border: 0;\n transform-origin: 0 0;\n pointer-events: none;\n display: block;\n}\n.pbu-node-shield { position: absolute; inset: 0; }\n.pbu-node-placeholder {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 11px;\n color: #8c8c8c;\n background: #1e1e1e;\n}\n.pbu-handle { opacity: 0; pointer-events: none; }\n\n.pbu-viewer-title { font-size: 12px; font-weight: 600; }\n.pbu-viewer-title code {\n margin-left: 8px;\n font-size: 11px;\n font-weight: 400;\n color: #8c8c8c;\n font-family: ui-monospace, Menlo, monospace;\n}\n.pbu-viewer-body { flex: 1; min-height: 0; display: flex; }\n.pbu-viewer-frame-wrap { flex: 1; min-width: 0; background: #fff; }\n.pbu-viewer-iframe { width: 100%; height: 100%; border: 0; display: block; }\n\n.pbu-panel {\n width: 300px;\n flex-shrink: 0;\n background: #252526;\n border-left: 1px solid #3c3c3c;\n padding: 12px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.pbu-panel-title {\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: #cccccc;\n padding-bottom: 8px;\n border-bottom: 1px solid #3c3c3c;\n}\n.pbu-panel-empty { font-size: 11px; color: #8c8c8c; line-height: 1.7; }\n.pbu-field { display: flex; flex-direction: column; gap: 4px; }\n.pbu-field > label {\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: #8c8c8c;\n}\n.pbu-field code {\n font-size: 11px;\n color: #cccccc;\n font-family: ui-monospace, Menlo, monospace;\n word-break: break-all;\n}\n.pbu-field span { font-size: 12px; color: #cccccc; }\n.pbu-selector {\n background: #1e1e1e;\n border: 1px solid #3c3c3c;\n border-radius: 2px;\n padding: 6px 8px;\n display: block;\n}\n.pbu-chip {\n display: inline-block;\n background: #37373d;\n color: #cccccc;\n font-size: 11px;\n font-weight: 600;\n font-family: ui-monospace, Menlo, monospace;\n padding: 1px 6px;\n border-radius: 2px;\n margin-right: 6px;\n}\n.pbu-publish {\n margin-top: 4px;\n padding: 10px;\n border: 1px solid #3c3c3c;\n border-radius: 2px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.pbu-publish-heading {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n.pbu-publish-heading > label { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: #8c8c8c; }\n.pbu-skill-entry { white-space: nowrap; }\n.pbu-publish input {\n background: #1e1e1e;\n border: 1px solid #3c3c3c;\n border-radius: 2px;\n color: #cccccc;\n font-size: 11px;\n padding: 5px 8px;\n}\n.pbu-publish input:disabled { color: #8c8c8c; cursor: not-allowed; }\n.pbu-publish-log {\n max-height: 200px;\n overflow-y: auto;\n background: #1e1e1e;\n border: 1px solid #3c3c3c;\n border-radius: 2px;\n padding: 6px 8px;\n font-family: ui-monospace, Menlo, monospace;\n font-size: 11px;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.pbu-log-line { color: #cccccc; white-space: pre-wrap; word-break: break-all; }\n.pbu-log-tool { color: #8c8c8c; }\n.pbu-log-error { color: #f2b3b3; }\n.pbu-log-done { color: #89d185; font-weight: 600; }\n.pbu-publish-reply {\n padding-top: 8px;\n border-top: 1px solid #3c3c3c;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.pbu-publish-reply > label {\n color: #cccccc;\n font-size: 11px;\n font-weight: 600;\n}\n.pbu-publish-reply textarea {\n width: 100%;\n min-height: 62px;\n resize: vertical;\n box-sizing: border-box;\n background: #1e1e1e;\n border: 1px solid #4b4b4b;\n border-radius: 2px;\n color: #e6e6e6;\n font: 11px/1.5 ui-monospace, Menlo, monospace;\n padding: 7px 8px;\n outline: none;\n}\n.pbu-publish-reply textarea:focus {\n border-color: #3794ff;\n box-shadow: 0 0 0 1px #3794ff;\n}\n.pbu-publish-reply textarea::placeholder { color: #6f6f6f; }\n.pbu-publish-reply-actions {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n.pbu-publish-reply-actions > span { color: #777; font-size: 9px; }\n\n.pbu-drawer {\n position: fixed;\n top: 0;\n right: 0;\n height: 100vh;\n width: 360px;\n z-index: 2147483300;\n background: #252526;\n border-left: 1px solid #3c3c3c;\n padding: 12px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 10px;\n font-family: system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif;\n font-size: 12px;\n color: #cccccc;\n}\n.pbu-drawer-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding-bottom: 8px;\n border-bottom: 1px solid #3c3c3c;\n}\n.pbu-drawer-header > div { display: flex; flex-direction: column; gap: 2px; }\n.pbu-drawer-kicker { color: #858585; font-size: 9px; letter-spacing: 0.04em; }\n.pbu-drawer-guide {\n background: #1e1e1e;\n border: 1px solid #3c3c3c;\n border-left: 2px solid #3794ff;\n padding: 10px;\n display: flex;\n flex-direction: column;\n gap: 5px;\n line-height: 1.45;\n}\n.pbu-drawer-guide strong { color: #e5e5e5; font-size: 11px; }\n.pbu-drawer-guide > span { color: #9d9d9d; font-size: 10px; }\n.pbu-guide-status { color: #cccccc; font-size: 10px; display: flex; align-items: center; gap: 5px; margin-top: 2px; }\n.pbu-status-dot { width: 6px; height: 6px; border-radius: 50%; background: #777; }\n.pbu-status-dot-on { background: #73c991; box-shadow: 0 0 0 2px rgba(115, 201, 145, 0.12); }\n.pbu-drawer-section-head {\n margin-top: 4px;\n padding-bottom: 7px;\n border-bottom: 1px solid #3c3c3c;\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 8px;\n}\n.pbu-drawer-section-head > div { display: flex; flex-direction: column; gap: 2px; }\n.pbu-drawer-section-head strong { color: #e5e5e5; font-size: 11px; }\n.pbu-drawer-section-head div > span { color: #858585; font-size: 9px; line-height: 1.4; }\n.pbu-drawer-section-head-skills { margin-top: 10px; }\n.pbu-status-badge, .pbu-skill-state {\n flex: none;\n border: 1px solid #4a4a4a;\n border-radius: 999px;\n padding: 1px 6px;\n color: #8c8c8c;\n font-size: 9px;\n line-height: 1.5;\n}\n.pbu-status-on, .pbu-skill-state-on { border-color: #3e7651; background: #23362a; color: #89d185; }\n.pbu-status-off { border-color: #765f3e; background: #382f22; color: #cca96a; }\n.pbu-skill-source { margin: 8px 0 4px; display: flex; flex-direction: column; gap: 1px; }\n.pbu-skill-source strong { color: #cccccc; font-size: 10px; }\n.pbu-skill-source span { color: #777; font-size: 9px; line-height: 1.35; }\n.pbu-drawer-group {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: #8c8c8c;\n margin-top: 6px;\n}\n.pbu-skill-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 0;\n border-bottom: 1px solid #2d2d2d;\n}\n.pbu-skill-row .pbu-hint {\n flex: 1;\n min-width: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.pbu-token-masked {\n font-family: ui-monospace, Menlo, monospace;\n font-size: 11px;\n color: #cccccc;\n background: #1e1e1e;\n border: 1px solid #3c3c3c;\n border-radius: 2px;\n padding: 6px 8px;\n}\n.pbu-drawer-error {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n background: #5a1d1d;\n border: 1px solid #832525;\n color: #f2b3b3;\n font-size: 11px;\n padding: 6px 8px;\n border-radius: 2px;\n}\n.pbu-drawer-code {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 8px 0;\n background: #1e1e1e;\n border: 1px solid #3c3c3c;\n border-radius: 2px;\n padding: 6px 8px;\n}\n.pbu-drawer-code code {\n flex: 1;\n font-family: ui-monospace, Menlo, monospace;\n font-size: 11px;\n color: #cccccc;\n}\n\n/* 일시 종료 버튼 — 위험 액션이라 붉은 계열 */\n.pbu-suspend-btn {\n border-color: #7a3b3b;\n background: #3a2626;\n color: #f2b3b3;\n white-space: nowrap;\n}\n.pbu-suspend-btn:hover:not(:disabled) { background: #4a2d2d; }\n\n/* 충돌 해결 모달 */\n.pbu-suspend-overlay {\n position: fixed;\n inset: 0;\n z-index: 2147483400;\n background: rgba(0, 0, 0, 0.55);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 24px;\n}\n.pbu-suspend-panel {\n width: min(560px, 100%);\n max-height: 82vh;\n overflow-y: auto;\n background: #252526;\n border: 1px solid #3c3c3c;\n border-radius: 4px;\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n color: #cccccc;\n}\n.pbu-suspend-head { display: flex; flex-direction: column; gap: 4px; }\n.pbu-suspend-head strong { color: #f2b3b3; font-size: 13px; }\n.pbu-suspend-head > span { color: #9d9d9d; font-size: 11px; line-height: 1.45; }\n.pbu-conflict-row {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 10px;\n border: 1px solid #3c3c3c;\n border-radius: 2px;\n background: #1e1e1e;\n}\n.pbu-conflict-file { font-family: ui-monospace, Menlo, monospace; font-size: 12px; color: #e6e6e6; }\n.pbu-conflict-actions { display: flex; gap: 6px; }\n.pbu-conflict-edit {\n width: 100%;\n box-sizing: border-box;\n resize: vertical;\n background: #1e1e1e;\n border: 1px solid #4b4b4b;\n border-radius: 2px;\n color: #e6e6e6;\n font: 11px/1.5 ui-monospace, Menlo, monospace;\n padding: 7px 8px;\n outline: none;\n}\n.pbu-conflict-edit:focus { border-color: #3794ff; box-shadow: 0 0 0 1px #3794ff; }\n.pbu-suspend-foot {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding-top: 4px;\n border-top: 1px solid #3c3c3c;\n}\n`\n\nfunction injectOnce(id: string, css: string) {\n if (document.getElementById(id)) return\n const style = document.createElement('style')\n style.id = id\n style.textContent = css\n document.head.appendChild(style)\n}\n\n/** 스타일 태그를 1회 주입 (idempotent) */\nexport function ensureStyles() {\n if (typeof document === 'undefined') return\n injectOnce(XYFLOW_STYLE_ID, xyflowCss)\n injectOnce(STYLE_ID, CSS_TEXT)\n}\n","import type { IANode } from './types'\n\nexport interface LayoutedNode extends IANode {\n x: number\n y: number\n}\n\n/**\n * 좌→우(LR) tidy tree 레이아웃.\n * depth = 열, 리프는 세로로 쌓고 부모는 자식들의 세로 중앙에 배치.\n * 화면설계서 IA 다이어그램과 같은 모양을 만든다.\n */\nexport function layoutTree(\n nodes: IANode[],\n nodeWidth: number,\n nodeHeight: number,\n gapX = 140,\n gapY = 48,\n): LayoutedNode[] {\n const childrenOf = new Map<string | null, IANode[]>()\n for (const n of nodes) {\n const list = childrenOf.get(n.parentId) ?? []\n list.push(n)\n childrenOf.set(n.parentId, list)\n }\n\n const pos = new Map<string, { x: number; y: number }>()\n let cursorY = 0\n\n const place = (node: IANode): number => {\n const kids = childrenOf.get(node.id) ?? []\n const x = node.depth * (nodeWidth + gapX)\n let y: number\n if (kids.length === 0) {\n y = cursorY\n cursorY += nodeHeight + gapY\n } else {\n const ys = kids.map(place)\n y = (Math.min(...ys) + Math.max(...ys)) / 2\n }\n pos.set(node.id, { x, y })\n return y\n }\n\n for (const root of childrenOf.get(null) ?? []) place(root)\n\n return nodes.map((n) => ({ ...n, ...pos.get(n.id)! }))\n}\n","import { Handle, Position, type NodeProps } from '@xyflow/react'\nimport { memo, useEffect, useRef, useState } from 'react'\nimport { usePubuilderStore } from '../store'\nimport type { IANode } from '../types'\n\nexport interface PageNodeData {\n page: IANode\n viewport: { width: number; height: number }\n thumbWidth: number\n bodyHeight: number\n [key: string]: unknown\n}\n\nexport const PageNode = memo(function PageNode(props: NodeProps) {\n const { page, viewport, thumbWidth, bodyHeight } = props.data as PageNodeData\n const openViewer = usePubuilderStore((s) => s.openViewer)\n const ref = useRef<HTMLDivElement>(null)\n const [visible, setVisible] = useState(false)\n\n // 캔버스 뷰포트에 들어온 노드만 iframe 로드 (lazy)\n useEffect(() => {\n const el = ref.current\n if (!el || page.external) return\n const io = new IntersectionObserver(([entry]) => {\n if (entry.isIntersecting) {\n setVisible(true)\n io.disconnect()\n }\n })\n io.observe(el)\n return () => io.disconnect()\n }, [page.external])\n\n const scale = thumbWidth / viewport.width\n const open = () => {\n if (page.external) window.open(page.path, '_blank', 'noopener')\n else openViewer(page.path)\n }\n\n return (\n <div ref={ref} className=\"pbu-node\" style={{ width: thumbWidth }} onClick={open}>\n <Handle type=\"target\" position={Position.Left} className=\"pbu-handle\" isConnectable={false} />\n <div className=\"pbu-node-header\">\n <span className=\"pbu-node-title\">{page.title}</span>\n <span className=\"pbu-node-path\">{page.external ? '외부 ↗' : page.path}</span>\n </div>\n <div className=\"pbu-node-body\" style={{ height: bodyHeight }}>\n {page.external ? (\n <div className=\"pbu-node-placeholder\">↗ 외부 링크</div>\n ) : visible ? (\n <iframe\n className=\"pbu-node-iframe\"\n src={page.path}\n title={`${page.title} 미리보기`}\n loading=\"lazy\"\n tabIndex={-1}\n style={{\n width: viewport.width,\n height: viewport.height,\n transform: `scale(${scale})`,\n }}\n />\n ) : (\n <div className=\"pbu-node-placeholder\">…</div>\n )}\n {/* iframe 위 클릭 가드 + hover 커서 */}\n <div className=\"pbu-node-shield\" />\n </div>\n <Handle type=\"source\" position={Position.Right} className=\"pbu-handle\" isConnectable={false} />\n </div>\n )\n})\n","import { useContext, useState } from 'react'\nimport { PubuilderServerContext } from '../api'\nimport { usePubuilderStore } from '../store'\n\n/**\n * \"일시 종료\" — 진행 중인 모든 퍼블리싱 job을 강제 종료하고 편집 파일을 롤백한다.\n * running job이 하나도 없으면 렌더하지 않는다. 충돌이 있으면 SuspendConflictPanel이\n * 뜨도록 store에 충돌을 싣는다.\n */\nexport function SuspendButton() {\n const api = useContext(PubuilderServerContext)\n const publishJobs = usePubuilderStore((s) => s.publishJobs)\n const setSuspendConflicts = usePubuilderStore((s) => s.setSuspendConflicts)\n const [busy, setBusy] = useState(false)\n\n const running = Object.values(publishJobs).some((j) => j.status === 'running')\n if (!running) return null\n\n const onSuspend = async () => {\n setBusy(true)\n try {\n const res = await api.suspendPublish()\n if (res.conflicts.length > 0) setSuspendConflicts(res.conflicts)\n // 충돌 없으면 자동 롤백 완료 — 죽은 job은 SSE error 이벤트로 상태가 정리된다.\n } catch {\n // 서버 다운 등 — 조용히 무시 (버튼은 running일 때만 보이므로 재시도 가능)\n } finally {\n setBusy(false)\n }\n }\n\n return (\n <button type=\"button\" className=\"pbu-btn pbu-suspend-btn\" onClick={onSuspend} disabled={busy}>\n {busy ? '종료 중...' : '⏹ 일시 종료'}\n </button>\n )\n}\n","import {\n Controls,\n Position,\n ReactFlow,\n type Edge,\n type Node,\n type NodeTypes,\n} from '@xyflow/react'\nimport { useEffect, useMemo } from 'react'\nimport type { NormalizedIA } from '../config'\nimport { layoutTree } from '../layout'\nimport { usePubuilderStore } from '../store'\nimport { PageNode, type PageNodeData } from './PageNode'\nimport { SuspendButton } from './SuspendButton'\n\nconst nodeTypes: NodeTypes = { page: PageNode }\n\nconst THUMB_WIDTH = 260\nconst HEADER_HEIGHT = 30\n\nexport function CanvasOverlay({ ia }: { ia: NormalizedIA }) {\n const closeMap = usePubuilderStore((s) => s.closeMap)\n\n const { nodes, edges } = useMemo(() => {\n const scale = THUMB_WIDTH / ia.viewport.width\n const bodyHeight = Math.round(ia.viewport.height * scale)\n const nodeHeight = bodyHeight + HEADER_HEIGHT\n const laid = layoutTree(ia.nodes, THUMB_WIDTH, nodeHeight)\n\n const nodes: Node[] = laid.map((n) => ({\n id: n.id,\n type: 'page',\n position: { x: n.x, y: n.y },\n data: {\n page: n,\n viewport: ia.viewport,\n thumbWidth: THUMB_WIDTH,\n bodyHeight,\n } satisfies PageNodeData,\n sourcePosition: Position.Right,\n targetPosition: Position.Left,\n }))\n\n const edges: Edge[] = laid\n .filter((n) => n.parentId)\n .map((n) => ({\n id: `${n.parentId}->${n.id}`,\n source: n.parentId!,\n target: n.id,\n type: 'smoothstep',\n }))\n\n return { nodes, edges }\n }, [ia])\n\n // Esc → 맵 닫기 (뷰어/스킬함 드로어가 열려 있으면 그쪽이 처리)\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key !== 'Escape') return\n const state = usePubuilderStore.getState()\n if (state.viewerPath || state.skillDrawerOpen) return\n closeMap()\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [closeMap])\n\n return (\n <div className=\"pbu-overlay\">\n <div className=\"pbu-bar\">\n <span className=\"pbu-logo\">pubuilder</span>\n <span className=\"pbu-hint\">노드 클릭 → 페이지 확대 · 스크롤 줌 · 드래그 팬 · Esc 닫기</span>\n <span className=\"pbu-spacer\" />\n <SuspendButton />\n <button type=\"button\" className=\"pbu-icon-btn\" onClick={closeMap} aria-label=\"닫기\">✕</button>\n </div>\n <div className=\"pbu-canvas\">\n <ReactFlow\n nodes={nodes}\n edges={edges}\n nodeTypes={nodeTypes}\n fitView\n fitViewOptions={{ padding: 0.15, maxZoom: 1 }}\n minZoom={0.05}\n maxZoom={2}\n nodesDraggable={false}\n nodesConnectable={false}\n elementsSelectable={false}\n proOptions={{ hideAttribution: true }}\n >\n <Controls showInteractive={false} />\n </ReactFlow>\n </div>\n </div>\n )\n}\n","import { usePubuilderStore } from '../store'\n\nexport function Fab() {\n const isMapOpen = usePubuilderStore((s) => s.isMapOpen)\n const openMap = usePubuilderStore((s) => s.openMap)\n const closeMap = usePubuilderStore((s) => s.closeMap)\n\n return (\n <button\n type=\"button\"\n className=\"pbu-fab\"\n title=\"Page Map (pubuilder)\"\n aria-label=\"페이지 맵 열기\"\n onClick={() => (isMapOpen ? closeMap() : openMap())}\n >\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <polygon points=\"3 6 9 3 15 6 21 3 21 18 15 21 9 18 3 21\" />\n <line x1=\"9\" y1=\"3\" x2=\"9\" y2=\"18\" />\n <line x1=\"15\" y1=\"6\" x2=\"15\" y2=\"21\" />\n </svg>\n </button>\n )\n}\n","import type { Granularity } from '../types'\n\nconst SECTION_TAGS = new Set([\n 'section', 'header', 'footer', 'nav', 'main', 'article', 'aside', 'form',\n])\n\nconst UNIT_TAGS = new Set([\n 'a', 'button', 'input', 'select', 'textarea', 'img', 'video', 'table',\n 'ul', 'ol', 'li', 'figure', 'h1', 'h2', 'h3', 'h4', 'p', 'label',\n])\n\n/** target에서 body 직전까지의 조상 체인 (target 먼저) */\nfunction ancestorChain(el: Element, doc: Document): Element[] {\n const chain: Element[] = []\n let cur: Element | null = el\n while (cur && cur !== doc.body && cur !== doc.documentElement) {\n chain.push(cur)\n cur = cur.parentElement\n }\n return chain\n}\n\nfunction pickSection(target: Element, doc: Document): Element | null {\n const chain = ancestorChain(target, doc)\n if (chain.length === 0) return null\n\n // 1순위: 가장 가까운 시맨틱 섹션 태그 (단, main은 더 안쪽 섹션이 없을 때만)\n const semantic = chain.find((el) => {\n const tag = el.tagName.toLowerCase()\n return SECTION_TAGS.has(tag) && tag !== 'main'\n })\n if (semantic) return semantic\n\n const main = chain.find((el) => el.tagName.toLowerCase() === 'main')\n if (main) return main\n\n // 2순위: 페이지 전체 래퍼가 아닌 최상위 조상\n const bodyH = doc.body.scrollHeight || 1\n for (let i = chain.length - 1; i >= 0; i--) {\n const rect = chain[i].getBoundingClientRect()\n if (rect.height > 0 && rect.height < bodyH * 0.8) return chain[i]\n }\n return chain[chain.length - 1]\n}\n\nfunction pickUnit(target: Element, doc: Document): Element | null {\n const chain = ancestorChain(target, doc)\n for (const el of chain) {\n if (UNIT_TAGS.has(el.tagName.toLowerCase())) return el\n const rect = el.getBoundingClientRect()\n const hasContent =\n el.children.length > 0 || (el.textContent ?? '').trim().length > 0\n if (rect.width >= 40 && rect.height >= 24 && hasContent) return el\n }\n return chain[0] ?? null\n}\n\n/** hover/클릭 지점의 요소에서 granularity에 맞는 블록을 고른다 */\nexport function pickBlock(\n target: Element,\n doc: Document,\n granularity: Granularity,\n): Element | null {\n if (granularity === 'all') return doc.body\n if (granularity === 'section') return pickSection(target, doc)\n return pickUnit(target, doc)\n}\n\n/** 블록을 사람이 알아볼 라벨: 헤딩 > aria-label > alt > 텍스트 앞부분 */\nexport function blockLabel(el: Element): string {\n const heading = el.querySelector('h1, h2, h3, h4, h5, h6')\n const headingText = heading?.textContent?.trim()\n if (headingText) return truncate(headingText)\n\n const aria = el.getAttribute('aria-label')\n if (aria) return truncate(aria)\n\n const alt = el.getAttribute('alt')\n if (alt) return truncate(alt)\n\n const text = (el.textContent ?? '').trim().replace(/\\s+/g, ' ')\n return text ? truncate(text) : `<${el.tagName.toLowerCase()}>`\n}\n\nfunction truncate(s: string, max = 30): string {\n return s.length > max ? `${s.slice(0, max)}…` : s\n}\n\n/** document 기준 고유-ish CSS selector 생성 */\nexport function cssPath(el: Element, doc: Document): string {\n if (el.id) return `#${CSS.escape(el.id)}`\n const parts: string[] = []\n let cur: Element | null = el\n while (cur && cur !== doc.body && parts.length < 8) {\n if (cur.id) {\n parts.unshift(`#${CSS.escape(cur.id)}`)\n return parts.join(' > ')\n }\n const tag = cur.tagName.toLowerCase()\n const parent: Element | null = cur.parentElement\n let part = tag\n if (parent) {\n const sameTag = Array.from(parent.children).filter(\n (c) => c.tagName === cur!.tagName,\n )\n if (sameTag.length > 1) part += `:nth-of-type(${sameTag.indexOf(cur) + 1})`\n }\n parts.unshift(part)\n cur = parent\n }\n return parts.join(' > ')\n}\n","import type { BlockSelection, Granularity } from '../types'\nimport { blockLabel, cssPath, pickBlock } from './heuristics'\n\nexport interface InspectorOptions {\n pagePath: string\n granularity: Granularity\n enabled: boolean\n onSelect: (selection: BlockSelection, el: Element) => void\n}\n\nexport interface InspectorHandle {\n destroy: () => void\n setGranularity: (g: Granularity) => void\n setEnabled: (v: boolean) => void\n}\n\ninterface HighlightBox {\n root: HTMLDivElement\n label: HTMLDivElement\n}\n\nfunction createBox(doc: Document, color: string, bg: string): HighlightBox {\n const root = doc.createElement('div')\n root.setAttribute('data-pubuilder', 'highlight')\n Object.assign(root.style, {\n position: 'fixed',\n top: '0',\n left: '0',\n display: 'none',\n border: `1px solid ${color}`,\n background: bg,\n borderRadius: '0',\n pointerEvents: 'none',\n zIndex: '2147483647',\n boxSizing: 'border-box',\n } satisfies Partial<CSSStyleDeclaration>)\n\n const label = doc.createElement('div')\n Object.assign(label.style, {\n position: 'absolute',\n left: '-1px',\n top: '-22px',\n padding: '2px 7px',\n background: color,\n color: '#fff',\n font: '600 10px/16px system-ui, sans-serif',\n borderRadius: '0',\n whiteSpace: 'nowrap',\n pointerEvents: 'none',\n } satisfies Partial<CSSStyleDeclaration>)\n root.appendChild(label)\n return { root, label }\n}\n\nfunction placeBox(box: HighlightBox, el: Element, text: string, barBottom: number | null) {\n const rect = el.getBoundingClientRect()\n // 상단 고정 바(sticky/fixed 헤더) 아래로 클램프 — 헤더를 뚫고 그려지지 않게\n const minTop = barBottom ?? -Infinity\n const top = Math.max(rect.top, minTop)\n const height = rect.bottom - top\n if (height <= 2) {\n hideBox(box)\n return\n }\n box.root.style.display = 'block'\n box.root.style.transform = `translate(${rect.x}px, ${top}px)`\n box.root.style.width = `${rect.width}px`\n box.root.style.height = `${height}px`\n box.label.textContent = text\n // 라벨(높이 ~24px)이 올라갈 자리에 헤더가 있거나 뷰포트 최상단이면 박스 안쪽으로\n box.label.style.top = top < 30 || top - 24 < minTop ? '2px' : '-24px'\n}\n\nfunction hideBox(box: HighlightBox) {\n box.root.style.display = 'none'\n}\n\nfunction describe(el: Element): string {\n const rect = el.getBoundingClientRect()\n return `${el.tagName.toLowerCase()} · ${Math.round(rect.width)}×${Math.round(rect.height)}`\n}\n\n/**\n * 같은 오리진 iframe의 document에 개발자도구식 hover/클릭 인스펙터를 붙인다.\n * 크로스오리진이면 null을 반환한다.\n */\nexport function attachInspector(\n iframe: HTMLIFrameElement,\n opts: InspectorOptions,\n): InspectorHandle | null {\n let maybeDoc: Document | null = null\n try {\n maybeDoc = iframe.contentDocument\n } catch {\n return null\n }\n const win = iframe.contentWindow\n if (!maybeDoc || !maybeDoc.body || !win) return null\n const doc: Document = maybeDoc\n\n let granularity = opts.granularity\n let enabled = opts.enabled\n let hoverEl: Element | null = null\n let selectedEl: Element | null = null\n\n const hoverBox = createBox(doc, 'rgba(14,99,156,0.95)', 'rgba(14,99,156,0.10)')\n const selectBox = createBox(doc, 'rgba(35,134,54,0.95)', 'rgba(35,134,54,0.07)')\n doc.body.appendChild(hoverBox.root)\n doc.body.appendChild(selectBox.root)\n\n /** 화면 상단에 도킹된 fixed/sticky 바 목록 (헤더 등) */\n let topBars: { el: Element; rect: DOMRect }[] = []\n let lastBarScan = 0\n const refreshTopBars = () => {\n topBars = []\n for (const el of Array.from(doc.body.querySelectorAll<HTMLElement>('*'))) {\n if (el === hoverBox.root || el === selectBox.root) continue\n if (hoverBox.root.contains(el) || selectBox.root.contains(el)) continue\n const pos = win.getComputedStyle(el).position\n if (pos !== 'fixed' && pos !== 'sticky') continue\n const rect = el.getBoundingClientRect()\n if (rect.width === 0 || rect.height === 0) continue\n // 상단 도킹 + 화면 절반 미만 높이인 것만 헤더로 간주\n if (rect.top <= 1 && rect.height < win.innerHeight * 0.5) topBars.push({ el, rect })\n }\n }\n\n /**\n * 스로틀된 재스캔. iframe onLoad 시점엔 SPA가 아직 헤더를 렌더하기 전일 수\n * 있고, 라우팅으로 헤더가 바뀔 수도 있어 상호작용 시마다 갱신한다.\n */\n const ensureTopBars = () => {\n const now = Date.now()\n if (now - lastBarScan < 500) return\n lastBarScan = now\n refreshTopBars()\n }\n\n /** el과 가로로 겹치는 상단 바들의 최대 하단값 (없으면 null) — 클램프/라벨 배치 기준 */\n const topBarBottomFor = (el: Element): number | null => {\n const rect = el.getBoundingClientRect()\n let bottom: number | null = null\n for (const bar of topBars) {\n // 헤더 자신(또는 그 내부/조상)을 검사할 때는 제외\n if (bar.el === el || bar.el.contains(el) || el.contains(bar.el)) continue\n const overlapsX = rect.left < bar.rect.right && rect.right > bar.rect.left\n if (!overlapsX) continue\n if (bottom === null || bar.rect.bottom > bottom) bottom = bar.rect.bottom\n }\n return bottom\n }\n\n const syncBoxes = () => {\n if (hoverEl && enabled && hoverEl.isConnected)\n placeBox(hoverBox, hoverEl, describe(hoverEl), topBarBottomFor(hoverEl))\n else hideBox(hoverBox)\n if (selectedEl && selectedEl.isConnected)\n placeBox(selectBox, selectedEl, `선택됨 · ${describe(selectedEl)}`, topBarBottomFor(selectedEl))\n else hideBox(selectBox)\n }\n\n /**\n * 클릭/hover 지점의 블록 결정.\n * 이미 선택된 블록 안을 다시 가리키면 target 방향으로 한 단계 더 깊은\n * 자식을 반환한다 (Figma식 드릴다운 — 클릭할 때마다 더 깊은 뎁스 선택).\n * 전체 모드에서는 언제나 body를 유지한다.\n */\n const resolveBlock = (target: Element): Element | null => {\n if (granularity === 'all') return doc.body\n if (\n selectedEl &&\n selectedEl.isConnected &&\n selectedEl.contains(target)\n ) {\n if (selectedEl === target) return selectedEl // 최심부 도달 — 유지\n let cur: Element = target\n while (cur.parentElement && cur.parentElement !== selectedEl) {\n cur = cur.parentElement\n }\n return cur\n }\n return pickBlock(target, doc, granularity)\n }\n\n const onMove = (ev: MouseEvent) => {\n if (!enabled) return\n ensureTopBars()\n const target = ev.target as Element | null\n if (!target || !doc.body.contains(target)) return\n const block = resolveBlock(target)\n if (block !== hoverEl) {\n hoverEl = block\n syncBoxes()\n }\n }\n\n const onClick = (ev: MouseEvent) => {\n if (!enabled) return\n ev.preventDefault()\n ev.stopPropagation()\n refreshTopBars()\n lastBarScan = Date.now()\n const target = ev.target as Element | null\n if (!target) return\n const block = resolveBlock(target)\n if (!block) return\n selectedEl = block\n syncBoxes()\n const rect = block.getBoundingClientRect()\n opts.onSelect(\n {\n pagePath: opts.pagePath,\n selector: cssPath(block, doc),\n tag: block.tagName.toLowerCase(),\n label: blockLabel(block),\n rect: {\n x: rect.x + win.scrollX,\n y: rect.y + win.scrollY,\n width: rect.width,\n height: rect.height,\n },\n granularity,\n },\n block,\n )\n }\n\n const onLeave = () => {\n hoverEl = null\n syncBoxes()\n }\n\n const onScrollOrResize = () => syncBoxes()\n const onResize = () => {\n refreshTopBars()\n syncBoxes()\n }\n\n refreshTopBars()\n\n doc.addEventListener('mousemove', onMove, true)\n doc.addEventListener('click', onClick, true)\n doc.documentElement.addEventListener('mouseleave', onLeave)\n win.addEventListener('scroll', onScrollOrResize, true)\n win.addEventListener('resize', onResize)\n\n return {\n destroy() {\n try {\n doc.removeEventListener('mousemove', onMove, true)\n doc.removeEventListener('click', onClick, true)\n doc.documentElement.removeEventListener('mouseleave', onLeave)\n win.removeEventListener('scroll', onScrollOrResize, true)\n win.removeEventListener('resize', onResize)\n hoverBox.root.remove()\n selectBox.root.remove()\n } catch {\n // iframe이 이미 언로드된 경우\n }\n },\n setGranularity(g) {\n granularity = g\n hoverEl = null\n syncBoxes()\n },\n setEnabled(v) {\n enabled = v\n if (!v) hoverEl = null\n syncBoxes()\n },\n }\n}\n","import { useContext, useEffect, useRef, useState } from 'react'\nimport { ApiError, PubuilderServerContext, type AgentEvent } from '../api'\nimport { blockKey, IDLE_PUBLISH_JOB } from '../publish-jobs'\nimport { usePubuilderStore } from '../store'\n\nconst EVENT_ICON: Record<AgentEvent['type'], string> = {\n log: '💬',\n tool: '🔧',\n error: '⛔',\n done: '✅',\n}\n\n/**\n * 블록별 SSE 구독 핸들 (key: blockKey). 렌더 데이터가 아니라 사이드이펙트\n * 핸들이므로 컴포넌트 밖 모듈 스코프에 둔다. 이렇게 하면 선택 변경/패널\n * 언마운트에도 구독이 살아남아, 여러 블록의 퍼블리싱이 동시에 진행된다.\n * 각 구독은 terminal(done|error) 이벤트에서 스스로 정리된다.\n */\nconst activeSubs = new Map<string, () => void>()\n\nexport function PublishPanel() {\n const api = useContext(PubuilderServerContext)\n const selection = usePubuilderStore((s) => s.selection)\n const selectedOuterHTML = usePubuilderStore((s) => s.selectedOuterHTML)\n const toggleSkillDrawer = usePubuilderStore((s) => s.toggleSkillDrawer)\n const patchPublishJob = usePubuilderStore((s) => s.patchPublishJob)\n const appendPublishEvent = usePubuilderStore((s) => s.appendPublishEvent)\n\n const key = selection ? blockKey(selection) : null\n const job = usePubuilderStore((s) => (key ? s.publishJobs[key] : undefined)) ?? IDLE_PUBLISH_JOB\n\n // 클립보드 복사 피드백만 순간적/전역이라 로컬 state로 둔다.\n const [copied, setCopied] = useState(false)\n const logRef = useRef<HTMLDivElement>(null)\n\n // 새 이벤트 도착 시 로그 뷰 자동 스크롤\n useEffect(() => {\n const el = logRef.current\n if (el) el.scrollTop = el.scrollHeight\n }, [job.events])\n\n // 블록별 SSE 구독. terminal 이벤트에서 store 상태를 확정하고 스스로 정리한다.\n const subscribe = (k: string, id: string) => {\n activeSubs.get(k)?.()\n const unsub = api.subscribePublish(id, (e) => {\n appendPublishEvent(k, e)\n if (e.type === 'done') {\n patchPublishJob(k, { status: 'done', jobId: null, cancelling: false })\n activeSubs.get(k)?.()\n activeSubs.delete(k)\n } else if (e.type === 'error') {\n patchPublishJob(k, { status: 'error', errorMessage: e.text, jobId: null, cancelling: false })\n activeSubs.get(k)?.()\n activeSubs.delete(k)\n }\n })\n activeSubs.set(k, unsub)\n }\n\n const onPublish = async () => {\n if (!key || !selection || job.status === 'running' || job.checking) return\n patchPublishJob(key, { serverDown: false, errorMessage: null, errorCode: null, checking: true })\n try {\n const alive = await api.isAlive()\n if (!alive) {\n patchPublishJob(key, { serverDown: true })\n return\n }\n const { jobId: id } = await api.startPublish({\n selection,\n outerHTML: selectedOuterHTML ?? '',\n figmaUrl: job.figmaUrl,\n })\n patchPublishJob(key, { jobId: id, status: 'running', events: [] })\n subscribe(key, id)\n } catch (e) {\n patchPublishJob(key, {\n status: 'error',\n errorMessage: e instanceof Error ? e.message : String(e),\n errorCode: e instanceof ApiError ? (e.code ?? null) : null,\n })\n } finally {\n // 블록별 상태라 다른 블록에 영향 없음 — 무조건 해제해 버튼이 영구 비활성되지 않게 한다.\n patchPublishJob(key, { checking: false })\n }\n }\n\n const onCancel = async () => {\n if (!key || !job.jobId || job.cancelling) return\n patchPublishJob(key, { cancelling: true })\n try {\n // 상태 전이는 서버가 보내는 error 이벤트로 처리한다 (subscribe 콜백)\n await api.cancelPublish(job.jobId)\n } catch (e) {\n patchPublishJob(key, {\n errorMessage: e instanceof Error ? e.message : String(e),\n cancelling: false,\n })\n }\n }\n\n const onReply = async () => {\n const instruction = job.reply.trim()\n if (!key || !selection || !instruction || job.checking || job.status === 'running') return\n patchPublishJob(key, { checking: true, errorMessage: null })\n try {\n const { jobId: id } = await api.startPublish({\n selection,\n outerHTML: selectedOuterHTML ?? '',\n figmaUrl: job.figmaUrl,\n instruction,\n })\n appendPublishEvent(key, { type: 'log', text: `내 답변: ${instruction}` })\n patchPublishJob(key, { reply: '', jobId: id, status: 'running' })\n subscribe(key, id)\n } catch (e) {\n patchPublishJob(key, {\n status: 'error',\n errorMessage: e instanceof Error ? e.message : String(e),\n errorCode: e instanceof ApiError ? (e.code ?? null) : null,\n })\n } finally {\n patchPublishJob(key, { checking: false })\n }\n }\n\n const copyServeCommand = async () => {\n await navigator.clipboard.writeText('npx pubuilder serve')\n setCopied(true)\n setTimeout(() => setCopied(false), 1200)\n }\n\n const recheck = async () => {\n if (!key) return\n patchPublishJob(key, { checking: true })\n try {\n const alive = await api.isAlive()\n patchPublishJob(key, { serverDown: !alive })\n } finally {\n patchPublishJob(key, { checking: false })\n }\n }\n\n const isRunning = job.status === 'running'\n // 서버 에러 코드 계약(server/errors.ts) 기반 분기 — 토큰 설정으로 해결 가능한 에러만\n const showTokenHint = job.errorCode === 'NO_FIGMA_TOKEN' || job.errorCode === 'FIGMA_API_ERROR'\n\n return (\n <div className=\"pbu-publish\">\n <div className=\"pbu-publish-heading\">\n <label htmlFor=\"pbu-figma-url\">Figma 노드 링크</label>\n <button type=\"button\" className=\"pbu-btn pbu-skill-entry\" onClick={toggleSkillDrawer}>\n 🧰 스킬함 · 설정\n </button>\n </div>\n <input\n id=\"pbu-figma-url\"\n value={job.figmaUrl}\n onChange={(e) => key && patchPublishJob(key, { figmaUrl: e.target.value })}\n disabled={isRunning}\n placeholder=\"https://www.figma.com/design/...\"\n />\n\n {job.serverDown && (\n <div className=\"pbu-panel-empty\">\n 컴패니언 서버가 꺼져 있어요\n <div className=\"pbu-drawer-code\">\n <code>npx pubuilder serve</code>\n <button type=\"button\" className=\"pbu-btn\" onClick={copyServeCommand}>\n {copied ? '복사됨 ✓' : '복사'}\n </button>\n </div>\n <div className=\"pbu-hint\">\n package.json의 dev 스크립트를 \"pubuilder dev -- &lt;기존 명령&gt;\"으로 감싸면 자동 실행돼요\n </div>\n <button type=\"button\" className=\"pbu-btn\" disabled={job.checking} onClick={recheck}>다시 확인</button>\n </div>\n )}\n\n {job.errorMessage && !job.serverDown && (\n <div className=\"pbu-drawer-error\">\n <span>{job.errorMessage}</span>\n {showTokenHint && (\n <button type=\"button\" className=\"pbu-btn\" onClick={toggleSkillDrawer}>스킬함 열기</button>\n )}\n </div>\n )}\n\n {isRunning ? (\n <button type=\"button\" className=\"pbu-btn pbu-btn-primary\" disabled={job.cancelling} onClick={onCancel}>\n {job.cancelling ? '중단 중...' : '중단'}\n </button>\n ) : (\n <button\n type=\"button\"\n className=\"pbu-btn pbu-btn-primary\"\n disabled={job.checking || !selection}\n onClick={onPublish}\n >\n 이 블록 퍼블리싱\n </button>\n )}\n\n {(job.events.length > 0 || isRunning) && (\n <div className=\"pbu-publish-log\" ref={logRef}>\n {isRunning && job.events.length === 0 && (\n <div className=\"pbu-log-line pbu-log-tool\">실행 중...</div>\n )}\n {job.events.map((e, i) => (\n <div\n key={i}\n className={\n e.type === 'error'\n ? 'pbu-log-line pbu-log-error'\n : e.type === 'done'\n ? 'pbu-log-line pbu-log-done'\n : e.type === 'tool'\n ? 'pbu-log-line pbu-log-tool'\n : 'pbu-log-line'\n }\n >\n <span>{EVENT_ICON[e.type]}</span> <span>{e.text}</span>\n </div>\n ))}\n </div>\n )}\n\n {job.status === 'done' && (\n <div className=\"pbu-publish-reply\">\n <label htmlFor=\"pbu-publish-reply\">AI에게 이어서 답하기</label>\n <textarea\n id=\"pbu-publish-reply\"\n value={job.reply}\n onChange={(e) => key && patchPublishJob(key, { reply: e.target.value })}\n onKeyDown={(e) => {\n if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') void onReply()\n }}\n placeholder=\"예: B 방향으로 진행해줘. 공지와 알림은 유지해.\"\n rows={3}\n />\n <div className=\"pbu-publish-reply-actions\">\n <span>⌘/Ctrl + Enter</span>\n <button\n type=\"button\"\n className=\"pbu-btn pbu-btn-primary\"\n disabled={job.checking || !job.reply.trim()}\n onClick={onReply}\n >\n {job.checking ? '전송 중...' : '답변 전송'}\n </button>\n </div>\n </div>\n )}\n </div>\n )\n}\n","import { useState } from 'react'\nimport { usePubuilderStore } from '../store'\nimport { PublishPanel } from './PublishPanel'\n\nexport function SelectionPanel() {\n const selection = usePubuilderStore((s) => s.selection)\n const [copied, setCopied] = useState(false)\n\n const copySelector = async () => {\n if (!selection) return\n await navigator.clipboard.writeText(selection.selector)\n setCopied(true)\n setTimeout(() => setCopied(false), 1200)\n }\n\n return (\n <aside className=\"pbu-panel\">\n <div className=\"pbu-panel-title\">선택된 블록</div>\n {!selection ? (\n <div className=\"pbu-panel-empty\">\n 화면에서 블록에 마우스를 올리고 클릭해 선택하세요.\n <br />\n 상단 토글로 <b>전체 / 섹션 / 유닛</b> 단위를 바꿀 수 있어요.\n </div>\n ) : (\n <>\n <div className=\"pbu-field\">\n <label>페이지</label>\n <code>{selection.pagePath}</code>\n </div>\n <div className=\"pbu-field\">\n <label>블록</label>\n <div>\n <span className=\"pbu-chip\">{selection.tag}</span>\n <span>{selection.label}</span>\n </div>\n </div>\n <div className=\"pbu-field\">\n <label>Selector</label>\n <code className=\"pbu-selector\">{selection.selector}</code>\n <button type=\"button\" className=\"pbu-btn\" onClick={copySelector}>\n {copied ? '복사됨 ✓' : 'Selector 복사'}\n </button>\n </div>\n <div className=\"pbu-field\">\n <label>크기</label>\n <span>\n {Math.round(selection.rect.width)} × {Math.round(selection.rect.height)}px\n </span>\n </div>\n <div className=\"pbu-field\">\n <label>단위</label>\n <span>\n {selection.granularity === 'all'\n ? '전체'\n : selection.granularity === 'section'\n ? '섹션'\n : '유닛'}\n </span>\n </div>\n\n <PublishPanel />\n </>\n )}\n </aside>\n )\n}\n","import { useEffect, useRef, useState } from 'react'\nimport type { NormalizedIA } from '../config'\nimport { attachInspector, type InspectorHandle } from '../inspector/inspector'\nimport { usePubuilderStore } from '../store'\nimport { SelectionPanel } from './SelectionPanel'\nimport { SuspendButton } from './SuspendButton'\n\nexport function PageViewer({ ia }: { ia: NormalizedIA }) {\n const viewerPath = usePubuilderStore((s) => s.viewerPath)\n const closeViewer = usePubuilderStore((s) => s.closeViewer)\n const granularity = usePubuilderStore((s) => s.granularity)\n const setGranularity = usePubuilderStore((s) => s.setGranularity)\n const inspectEnabled = usePubuilderStore((s) => s.inspectEnabled)\n const setInspectEnabled = usePubuilderStore((s) => s.setInspectEnabled)\n\n const iframeRef = useRef<HTMLIFrameElement>(null)\n const handleRef = useRef<InspectorHandle | null>(null)\n const [inspectorFailed, setInspectorFailed] = useState(false)\n\n const node = ia.nodes.find((n) => n.path === viewerPath)\n\n const onFrameLoad = () => {\n handleRef.current?.destroy()\n handleRef.current = null\n const iframe = iframeRef.current\n if (!iframe || !viewerPath) return\n const state = usePubuilderStore.getState()\n const handle = attachInspector(iframe, {\n pagePath: viewerPath,\n granularity: state.granularity,\n enabled: state.inspectEnabled,\n onSelect: (sel, el) =>\n // 20K 상한 — 프롬프트 비대화 방지\n usePubuilderStore.getState().setSelectionWithHTML(sel, el.outerHTML.slice(0, 20_000)),\n })\n if (!handle) {\n setInspectorFailed(true)\n return\n }\n setInspectorFailed(false)\n handleRef.current = handle\n }\n\n // 언마운트 시 인스펙터 해제\n useEffect(() => () => handleRef.current?.destroy(), [])\n useEffect(() => { handleRef.current?.setGranularity(granularity) }, [granularity])\n useEffect(() => { handleRef.current?.setEnabled(inspectEnabled) }, [inspectEnabled])\n\n // Esc → 뷰어 닫기 (맵 캔버스로 복귀 · 스킬함 드로어가 열려 있으면 드로어가 처리)\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key !== 'Escape') return\n if (usePubuilderStore.getState().skillDrawerOpen) return\n closeViewer()\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [closeViewer])\n\n if (!node) return null\n\n return (\n <div className=\"pbu-viewer\">\n <div className=\"pbu-bar\">\n <button type=\"button\" className=\"pbu-btn\" onClick={closeViewer}>← 맵으로</button>\n <span className=\"pbu-viewer-title\">\n {node.title}\n <code>{node.path}</code>\n </span>\n <span className=\"pbu-spacer\" />\n {inspectorFailed && <span className=\"pbu-hint\">⚠ 이 페이지는 검사할 수 없어요</span>}\n <div className=\"pbu-seg\" role=\"group\" aria-label=\"블록 단위\">\n <button\n type=\"button\"\n className={granularity === 'all' ? 'pbu-on' : ''}\n onClick={() => setGranularity('all')}\n >\n 전체\n </button>\n <button\n type=\"button\"\n className={granularity === 'section' ? 'pbu-on' : ''}\n onClick={() => setGranularity('section')}\n >\n 섹션\n </button>\n <button\n type=\"button\"\n className={granularity === 'unit' ? 'pbu-on' : ''}\n onClick={() => setGranularity('unit')}\n >\n 유닛\n </button>\n </div>\n <label className=\"pbu-toggle\">\n <input\n type=\"checkbox\"\n checked={inspectEnabled}\n onChange={(e) => setInspectEnabled(e.target.checked)}\n />\n 검사 모드\n </label>\n <SuspendButton />\n <button type=\"button\" className=\"pbu-icon-btn\" onClick={closeViewer} aria-label=\"닫기\">✕</button>\n </div>\n <div className=\"pbu-viewer-body\">\n <div className=\"pbu-viewer-frame-wrap\">\n <iframe\n ref={iframeRef}\n className=\"pbu-viewer-iframe\"\n src={node.path}\n title={node.title}\n onLoad={onFrameLoad}\n />\n </div>\n <SelectionPanel />\n </div>\n </div>\n )\n}\n","import { useContext, useEffect, useRef, useState } from 'react'\nimport { PubuilderServerContext, type SkillInfo, type TokenStatus } from '../api'\nimport { usePubuilderStore } from '../store'\n\nconst GROUP_LABELS: Record<SkillInfo['source'], string> = {\n project: '프로젝트',\n global: '글로벌',\n uploaded: '업로드',\n}\nconst GROUP_DESCRIPTIONS: Record<SkillInfo['source'], string> = {\n project: '현재 프로젝트에서 발견한 스킬 · 여기서는 삭제할 수 없어요',\n global: '내 전역 환경에 설치된 공용 스킬 · 여기서는 삭제할 수 없어요',\n uploaded: '이 스킬함에 직접 올린 Markdown 스킬 · 삭제할 수 있어요',\n}\nconst GROUP_ORDER: SkillInfo['source'][] = ['project', 'global', 'uploaded']\n\nexport function SkillDrawer() {\n const toggleSkillDrawer = usePubuilderStore((s) => s.toggleSkillDrawer)\n const api = useContext(PubuilderServerContext)\n\n const [loading, setLoading] = useState(true)\n const [alive, setAlive] = useState(false)\n const [skills, setSkills] = useState<SkillInfo[]>([])\n const [tokenStatus, setTokenStatus] = useState<TokenStatus | null>(null)\n const [tokenInput, setTokenInput] = useState('')\n const [showTokenInput, setShowTokenInput] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [copied, setCopied] = useState(false)\n\n const fileInputRef = useRef<HTMLInputElement>(null)\n // 늦게 도착한 응답이 최신 상태를 덮어쓰지 않도록 하는 증가 토큰\n const reqRef = useRef(0)\n // mutation 진행 중 컨트롤 비활성화용 (중복 요청 방지)\n const [busy, setBusy] = useState<string | null>(null)\n\n const load = async () => {\n const my = ++reqRef.current\n setLoading(true)\n setError(null)\n try {\n const isAlive = await api.isAlive()\n if (my !== reqRef.current) return\n setAlive(isAlive)\n if (!isAlive) return\n const [skillList, token] = await Promise.all([api.listSkills(), api.tokenStatus()])\n if (my !== reqRef.current) return\n setSkills(skillList)\n setTokenStatus(token)\n setShowTokenInput(!token.configured)\n } catch (e) {\n if (my !== reqRef.current) return\n setError(e instanceof Error ? e.message : String(e))\n } finally {\n if (my === reqRef.current) setLoading(false)\n }\n }\n\n useEffect(() => {\n load()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n // Esc → 드로어만 닫기 (viewer/canvas 핸들러는 드로어 열림 상태를 확인해 무시)\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') toggleSkillDrawer()\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [toggleSkillDrawer])\n\n const withErrorHandling = async (key: string, fn: () => Promise<void>) => {\n if (busy) return\n setBusy(key)\n try {\n await fn()\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e))\n } finally {\n setBusy(null)\n }\n }\n\n const onToggleSkill = (id: string, enabled: boolean) =>\n withErrorHandling(`toggle:${id}`, async () => {\n await api.toggleSkill(id, enabled)\n await load()\n })\n\n const onRemoveSkill = (id: string, name: string) => {\n if (!window.confirm(`\"${name}\" 스킬을 삭제할까요?`)) return\n withErrorHandling(`remove:${id}`, async () => {\n await api.removeSkill(id)\n await load()\n })\n }\n\n const onUploadClick = () => fileInputRef.current?.click()\n\n const onFileSelected = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0]\n e.target.value = ''\n if (!file) return\n withErrorHandling('upload', async () => {\n const reader = new FileReader()\n const text = await new Promise<string>((resolve, reject) => {\n reader.onload = () => resolve(String(reader.result ?? ''))\n reader.onerror = () => reject(reader.error ?? new Error('파일을 읽을 수 없어요'))\n reader.readAsText(file)\n })\n await api.uploadSkill(file.name, text)\n await load()\n })\n }\n\n const onSaveToken = () =>\n withErrorHandling('token:save', async () => {\n if (!tokenInput.trim()) return\n await api.saveToken(tokenInput.trim())\n setTokenInput('')\n await load()\n })\n\n const onDeleteToken = () =>\n withErrorHandling('token:delete', async () => {\n await api.deleteToken()\n setTokenInput('')\n await load()\n })\n\n const copyServeCommand = async () => {\n await navigator.clipboard.writeText('npx pubuilder serve')\n setCopied(true)\n setTimeout(() => setCopied(false), 1200)\n }\n\n const grouped = GROUP_ORDER.map((source) => ({\n source,\n label: GROUP_LABELS[source],\n items: skills.filter((s) => s.source === source),\n })).filter((g) => g.items.length > 0)\n const enabledCount = skills.filter((skill) => skill.enabled).length\n\n return (\n <aside className=\"pbu-drawer\">\n <div className=\"pbu-drawer-header\">\n <div>\n <span className=\"pbu-panel-title\">스킬함</span>\n <span className=\"pbu-drawer-kicker\">퍼블리싱 실행 설정</span>\n </div>\n <button type=\"button\" className=\"pbu-icon-btn\" onClick={toggleSkillDrawer} aria-label=\"닫기\">✕</button>\n </div>\n\n <div className=\"pbu-drawer-guide\">\n <strong>다음 퍼블리싱에 적용할 규칙을 고르세요.</strong>\n <span>체크된 스킬의 지침만 AI에게 전달됩니다. 변경 사항은 다음 실행부터 적용돼요.</span>\n {!loading && alive && (\n <div className=\"pbu-guide-status\">\n <span className=\"pbu-status-dot pbu-status-dot-on\" />\n {skills.length > 0 ? `${enabledCount}/${skills.length}개 스킬 사용 중` : '사용 가능한 스킬 없음'}\n </div>\n )}\n </div>\n\n {error && (\n <div className=\"pbu-drawer-error\">\n <span>{error}</span>\n <button type=\"button\" className=\"pbu-icon-btn\" onClick={() => setError(null)} aria-label=\"닫기\">✕</button>\n </div>\n )}\n\n {loading ? (\n <div className=\"pbu-panel-empty\">불러오는 중...</div>\n ) : !alive ? (\n <div className=\"pbu-panel-empty\">\n 컴패니언 서버가 꺼져 있어요\n <div className=\"pbu-drawer-code\">\n <code>npx pubuilder serve</code>\n <button type=\"button\" className=\"pbu-btn\" onClick={copyServeCommand}>\n {copied ? '복사됨 ✓' : '복사'}\n </button>\n </div>\n <div className=\"pbu-hint\">\n package.json의 dev 스크립트를 \"pubuilder dev -- &lt;기존 명령&gt;\"으로 감싸면 자동 실행돼요\n </div>\n <button type=\"button\" className=\"pbu-btn\" onClick={load}>다시 확인</button>\n </div>\n ) : (\n <>\n <div className=\"pbu-drawer-section-head\">\n <div>\n <strong>Figma 연결</strong>\n <span>노드 링크에서 시안 이미지와 구조 정보를 읽을 때 사용해요.</span>\n </div>\n <span className={`pbu-status-badge ${tokenStatus?.configured ? 'pbu-status-on' : 'pbu-status-off'}`}>\n {tokenStatus?.configured ? '연결됨' : '연결 필요'}\n </span>\n </div>\n {tokenStatus?.configured && !showTokenInput ? (\n <div className=\"pbu-field\">\n <span className=\"pbu-token-masked\">{tokenStatus.masked}</span>\n <div>\n <button type=\"button\" className=\"pbu-btn\" disabled={busy !== null} onClick={() => setShowTokenInput(true)}>재입력</button>\n <button type=\"button\" className=\"pbu-btn\" disabled={busy !== null} onClick={onDeleteToken}>삭제</button>\n </div>\n </div>\n ) : (\n <div className=\"pbu-field\">\n <input\n type=\"password\"\n value={tokenInput}\n onChange={(e) => setTokenInput(e.target.value)}\n placeholder=\"Figma 토큰\"\n />\n <button type=\"button\" className=\"pbu-btn pbu-btn-primary\" disabled={busy !== null} onClick={onSaveToken}>저장</button>\n </div>\n )}\n\n <div className=\"pbu-drawer-section-head pbu-drawer-section-head-skills\">\n <div>\n <strong>AI 작업 스킬</strong>\n <span>스킬은 AI에게 전달되는 작업 규칙이 담긴 Markdown 파일이에요.</span>\n </div>\n <button type=\"button\" className=\"pbu-btn\" disabled={busy !== null} onClick={onUploadClick}>업로드</button>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\".md\"\n style={{ display: 'none' }}\n onChange={onFileSelected}\n />\n </div>\n\n {grouped.length === 0 ? (\n <div className=\"pbu-panel-empty\">등록된 스킬이 없어요.</div>\n ) : (\n grouped.map((g) => (\n <div key={g.source}>\n <div className=\"pbu-skill-source\">\n <strong>{g.label}</strong>\n <span>{GROUP_DESCRIPTIONS[g.source]}</span>\n </div>\n {g.items.map((skill) => (\n <div key={skill.id} className=\"pbu-skill-row\">\n <label className=\"pbu-toggle\">\n <input\n type=\"checkbox\"\n checked={skill.enabled}\n disabled={busy !== null}\n onChange={(e) => onToggleSkill(skill.id, e.target.checked)}\n />\n {skill.name}\n </label>\n <span className=\"pbu-hint\" title={skill.description}>{skill.description}</span>\n <span className={`pbu-skill-state ${skill.enabled ? 'pbu-skill-state-on' : ''}`}>\n {busy === `toggle:${skill.id}` ? '변경 중' : skill.enabled ? '사용 중' : '제외됨'}\n </span>\n {skill.source === 'uploaded' && (\n <button\n type=\"button\"\n className=\"pbu-icon-btn\"\n disabled={busy !== null}\n onClick={() => onRemoveSkill(skill.id, skill.name)}\n aria-label=\"삭제\"\n >\n 🗑\n </button>\n )}\n </div>\n ))}\n </div>\n ))\n )}\n </>\n )}\n </aside>\n )\n}\n","import { useContext, useState } from 'react'\nimport { PubuilderServerContext } from '../api'\nimport { usePubuilderStore } from '../store'\n\n/**\n * 일시 종료 시 자동 롤백이 완료 job/사용자 편집과 겹치는 파일을 파일 단위로 해결한다.\n * suspendConflicts가 비어 있으면 렌더하지 않는다.\n */\nexport function SuspendConflictPanel() {\n const api = useContext(PubuilderServerContext)\n const conflicts = usePubuilderStore((s) => s.suspendConflicts)\n const resolutions = usePubuilderStore((s) => s.suspendResolutions)\n const setConflictResolution = usePubuilderStore((s) => s.setConflictResolution)\n const clearSuspend = usePubuilderStore((s) => s.clearSuspend)\n const [applying, setApplying] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n if (conflicts.length === 0) return null\n\n const allResolved = conflicts.every((c) => resolutions[c.file])\n\n const apply = async () => {\n setApplying(true)\n setError(null)\n try {\n await api.resolveSuspend(conflicts.map((c) => resolutions[c.file]))\n clearSuspend()\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e))\n } finally {\n setApplying(false)\n }\n }\n\n return (\n <div className=\"pbu-suspend-overlay\">\n <div className=\"pbu-suspend-panel\">\n <div className=\"pbu-suspend-head\">\n <strong>일시 종료 — 충돌 {conflicts.length}건</strong>\n <span>롤백이 다른 변경과 겹쳐요. 파일마다 처리를 골라주세요. 충돌 없는 파일은 이미 되돌렸어요.</span>\n </div>\n\n {conflicts.map((c) => {\n const r = resolutions[c.file]\n return (\n <div key={c.file} className=\"pbu-conflict-row\">\n <div className=\"pbu-conflict-file\">{c.file}</div>\n <div className=\"pbu-conflict-actions\">\n <button\n type=\"button\"\n className={`pbu-btn ${r?.action === 'revert' ? 'pbu-btn-primary' : ''}`}\n onClick={() => setConflictResolution(c.file, 'revert')}\n >\n 이전으로\n </button>\n <button\n type=\"button\"\n className={`pbu-btn ${r?.action === 'keep' ? 'pbu-btn-primary' : ''}`}\n onClick={() => setConflictResolution(c.file, 'keep')}\n >\n 현재 유지\n </button>\n <button\n type=\"button\"\n className={`pbu-btn ${r?.action === 'edit' ? 'pbu-btn-primary' : ''}`}\n onClick={() => setConflictResolution(c.file, 'edit', c.current)}\n >\n 편집\n </button>\n </div>\n {r?.action === 'edit' && (\n <textarea\n className=\"pbu-conflict-edit\"\n value={r.content ?? ''}\n onChange={(e) => setConflictResolution(c.file, 'edit', e.target.value)}\n rows={6}\n />\n )}\n </div>\n )\n })}\n\n {error && (\n <div className=\"pbu-drawer-error\">\n <span>{error}</span>\n </div>\n )}\n\n <div className=\"pbu-suspend-foot\">\n <button type=\"button\" className=\"pbu-btn\" onClick={clearSuspend} disabled={applying}>\n 닫기\n </button>\n <button\n type=\"button\"\n className=\"pbu-btn pbu-btn-primary\"\n onClick={apply}\n disabled={!allResolved || applying}\n >\n {applying ? '적용 중...' : '모두 해결 후 적용'}\n </button>\n </div>\n </div>\n </div>\n )\n}\n","'use client'\n\nimport { useLayoutEffect, useMemo, useState } from 'react'\nimport { createPortal } from 'react-dom'\nimport { PubuilderApi, PubuilderServerContext } from '../api'\nimport { normalizeIA } from '../config'\nimport { isProductionEnv } from '../env'\nimport { usePubuilderStore } from '../store'\nimport { ensureStyles } from '../styles'\nimport type { IAConfig } from '../types.js'\nimport { CanvasOverlay } from './CanvasOverlay'\nimport { Fab } from './Fab'\nimport { PageViewer } from './PageViewer'\nimport { SkillDrawer } from './SkillDrawer'\nimport { SuspendConflictPanel } from './SuspendConflictPanel'\n\nexport interface PageMapProps {\n config: IAConfig\n /**\n * 렌더 여부. 기본 true. production 빌드에서는 이 값과 무관하게\n * 자동으로 렌더하지 않는다 (dev 전용 안전장치).\n */\n enabled?: boolean\n /** 컴패니언 서버 URL. 기본 http://localhost:4816 */\n serverUrl?: string\n}\n\nexport function PageMap({ config, enabled = true, serverUrl }: PageMapProps) {\n // dev 전용 도구 — production 번들에 실수로 포함돼도 사용자에게 노출되지 않게 차단\n const active = enabled && !isProductionEnv()\n const [mounted, setMounted] = useState(false)\n const isMapOpen = usePubuilderStore((s) => s.isMapOpen)\n const viewerPath = usePubuilderStore((s) => s.viewerPath)\n const skillDrawerOpen = usePubuilderStore((s) => s.skillDrawerOpen)\n\n const ia = useMemo(() => normalizeIA(config), [config])\n const api = useMemo(() => new PubuilderApi(serverUrl), [serverUrl])\n\n useLayoutEffect(() => {\n if (!active) return\n // 썸네일 iframe 안에서 또 렌더되는 재귀 방지\n if (window.self !== window.top) return\n ensureStyles()\n setMounted(true)\n }, [active])\n\n // SSR / iframe 내부 / production / 비활성 → 아무것도 렌더하지 않음\n if (!mounted || !active) return null\n\n return createPortal(\n <PubuilderServerContext.Provider value={api}>\n <Fab />\n {isMapOpen && <CanvasOverlay ia={ia} />}\n {viewerPath && <PageViewer ia={ia} />}\n {skillDrawerOpen && <SkillDrawer />}\n <SuspendConflictPanel />\n </PubuilderServerContext.Provider>,\n document.body,\n )\n}\n"],"names":["DEFAULT_SERVER_URL","ApiError","message","code","PubuilderApi","baseUrl","path","init","res","body","id","enabled","filename","content","token","payload","jobId","resolutions","onEvent","source","terminal","msg","e","PubuilderServerContext","createContext","isProductionEnv","IDLE_PUBLISH_JOB","blockKey","sel","usePubuilderStore","create","set","granularity","inspectEnabled","selection","selectedOuterHTML","s","key","partial","event","prev","suspendConflicts","file","action","STYLE_ID","XYFLOW_STYLE_ID","CSS_TEXT","injectOnce","css","style","ensureStyles","xyflowCss","layoutTree","nodes","nodeWidth","nodeHeight","gapX","gapY","childrenOf","n","list","pos","cursorY","place","node","kids","x","y","ys","root","PageNode","memo","props","page","viewport","thumbWidth","bodyHeight","openViewer","ref","useRef","visible","setVisible","useState","useEffect","el","io","entry","scale","jsxs","jsx","Handle","Position","SuspendButton","api","useContext","publishJobs","setSuspendConflicts","busy","setBusy","j","nodeTypes","THUMB_WIDTH","HEADER_HEIGHT","CanvasOverlay","ia","closeMap","edges","useMemo","laid","onKey","state","ReactFlow","Controls","Fab","isMapOpen","openMap","SECTION_TAGS","UNIT_TAGS","ancestorChain","doc","chain","cur","pickSection","target","semantic","tag","main","bodyH","i","rect","pickUnit","hasContent","pickBlock","blockLabel","headingText","truncate","aria","alt","text","max","cssPath","parts","parent","part","sameTag","c","createBox","color","bg","label","placeBox","box","barBottom","minTop","top","height","hideBox","describe","attachInspector","iframe","opts","maybeDoc","win","hoverEl","selectedEl","hoverBox","selectBox","topBars","lastBarScan","refreshTopBars","ensureTopBars","now","topBarBottomFor","bottom","bar","syncBoxes","resolveBlock","onMove","ev","block","onClick","onLeave","onScrollOrResize","onResize","g","v","EVENT_ICON","activeSubs","PublishPanel","toggleSkillDrawer","patchPublishJob","appendPublishEvent","job","copied","setCopied","logRef","subscribe","k","unsub","onPublish","onCancel","onReply","instruction","copyServeCommand","recheck","alive","isRunning","showTokenHint","SelectionPanel","copySelector","Fragment","PageViewer","viewerPath","closeViewer","setGranularity","setInspectEnabled","iframeRef","handleRef","inspectorFailed","setInspectorFailed","onFrameLoad","handle","GROUP_LABELS","GROUP_DESCRIPTIONS","GROUP_ORDER","SkillDrawer","loading","setLoading","setAlive","skills","setSkills","tokenStatus","setTokenStatus","tokenInput","setTokenInput","showTokenInput","setShowTokenInput","error","setError","fileInputRef","reqRef","load","my","isAlive","skillList","withErrorHandling","fn","onToggleSkill","onRemoveSkill","name","onUploadClick","onFileSelected","reader","resolve","reject","onSaveToken","onDeleteToken","grouped","enabledCount","skill","SuspendConflictPanel","conflicts","setConflictResolution","clearSuspend","applying","setApplying","allResolved","apply","r","PageMap","config","serverUrl","active","mounted","setMounted","skillDrawerOpen","normalizeIA","useLayoutEffect","createPortal"],"mappings":"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AA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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"}