npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@fcg-labs/cx-agent-hook

v0.6.0

Published

FCG CX Agent 후킹 SDK — 서빙 답변 수신 + CS팀 교정(점수·수정·발송) 후킹. 의존성 0, CMS에 install만으로 이식

Readme

@fcg-labs/cx-agent-hook

FCG CX Agent 후킹 SDK — 상담 화면에 AI 답변 제안을 띄우고, 상담사의 판단(채택· 수정·발송)을 학습 광물로 돌려받는다.

전송 계층은 의존성 0 (내장 fetch, 브라우저·Node 18+). React 는 ./react 서브패스에서만 쓰는 optional peer 다.

설계 원칙 — 고객사 저장소에 제품 로직을 두지 않는다

고객사(관리자 화면) 코드에 들어가도 되는 것은 주소·토큰·도메인 세 값을 자기 빌드 방식으로 읽어 넘기는 일컴포넌트를 어디에 놓을지뿐이다.

| 고객사 코드 | 이 라이브러리 | |---|---| | env 세 값 읽기 | 미설정 판정·널 가드·실패 시 돌려줄 모양 | | 패널 배치 위치 | 패널 UI·상태 전이·기본 스타일 | | 발송 시 훅 호출 | 사유 코드 목록과 상담사 안내 문구 | | — | 채택한 제안 ↔ 발송 최종본을 잇는 answer_id 기록 |

이 선을 넘어가면 서버가 사유를 하나 늘릴 때마다 고객사 저장소를 고쳐 재배포해야 하고, 2호 고객이 올 때 같은 것을 또 짜게 된다.

설치

npm install @fcg-labs/cx-agent-hook

React·Vue 어댑터를 쓸 때만 그 프레임워크가 필요하다 (optional peer). 전송 계층만 쓰면 의존성은 0 이다.

AI 코딩 에이전트에게 맡기기 (권장)

패키지 안에 에이전트 스킬이 들어 있다 — 설치→환경변수→훅(adminApi 포함)→답변 슬롯→처리 카드→확인까지, 프로젝트를 먼저 실측하고(프레임워크·번들러·기존 관리자 API 헬퍼·엔드포인트 맵·세션 만료 처리·문의 화면) 그 성격에 맞춰 배선하는 절차와, 인용해도 되는 API 이름 표(reference.md, 시험이 실제 export 와 대조)다.

npx cx-agent-hook skills install          # Claude Code: .claude/skills/cx-agent-hook-setup/
npx cx-agent-hook skills install --all    # + Cursor 규칙(.cursor/rules) + AGENTS.md 한 줄
npx cx-agent-hook skills path             # 그냥 "이 파일 읽고 따라줘" 라고 줄 때

그 뒤 에이전트에게 "cx-agent-hook 셋업 도와줘" — 답변 패널만이 아니라 처리 카드 (adminApi)까지가 셋업이라고 스킬이 못박는다. 사람이 읽을 때는 아래 절과 skills/cx-agent-hook-setup/SKILL.md 가 같은 내용이다.

0.3.0 — 문의별 세션 (권장 표면)

createCxHook 은 그대로 동작한다(호환층). 문의별 초안 상태·영속이 필요한 관리자 화면은 세션 표면으로 올라온다 — 초안의 정본이 세션 버퍼라 메뉴 이탈·문의 전환에도 AI 초안이 살아남고, 스트림은 화면과 무관하게 완주한다:

import { createCxAgent } from "@fcg-labs/cx-agent-hook/agent";

const agent = createCxAgent({ baseUrl, token, domain });
const session = agent.session(inquiryId);           // 같은 id = 같은 세션
session.attachUi({ getDraft, setDraft, setStatus });
session.restore();                                  // 복귀 시 초안 복원 한 줄
session.compose({ inquiry, context });              // 이탈해도 버퍼로 완주
session.remember(editorText);                       // 상담사 편집 반영
session.answerSent(finalText, agentId);             // 발송 후킹 + 세션 소멸

테넌트 특수분은 파라미터다: source(인그레스 채널명, 기본 "cms"), draftDecorators(초안 후처리 — 기본 한국어 호칭 개인화, 비한국어는 []), storage(sessionStorage TTL·LRU 정책). 상세와 훅→세션 대응표는 MIGRATION.md.

CSS 는 사용처 var(--fcx-*, 폴백) 직참조라 소비처 :root 한 줄로 팔레트를 바꾼다. 다크는 조상에 data-fcx-theme="dark". headless 2단계(스타일 0 / UI 0 — aiSuggestTree)도 공식 표면이다.

0.5.0 — 처리 액션 (브라우저 실행기: 실행기는 CMS 자신)

답변 제안 옆에 처리 선택지가 실릴 수 있다 (payload.suggested_actions). 이 SDK 는 그 선택지를 보관·표시하고, 상담사 확인 뒤 CMS 의 기존 관리자 API 를 CMS 세션으로 불러 처리하고, 결과를 허브 원장에 보고한다. 허브는 어떤 고객사 서버도 부르지 않는다. 고객사 개발자가 새로 짜는 코드는 없다 — 이미 있는 요청 헬퍼와 엔드포인트 맵의 참조 두 개를 옵션으로 넘길 뿐이다.

import TempAdminApi, { EndPoint } from "@/constant/TempAdminApi";   // CMS 에 이미 있는 것
import TempAdminApiMap from "@/constant/TempAdminApiMap";
const agent = createCxAgent({
  baseUrl, token, domain,
  adminApi: { request: TempAdminApi.request, endpoints: EndPoint, map: TempAdminApiMap,
              onAuthExpired: handleAuthExpiredResponse },   // 없으면 액션 표면은 닫힌다
});
const session = agent.session(inquiryId);
session.attachActionUi({ setOffers: (offers, pending) => render(offers, pending) });
// 사람 확인(확인 문구·고위험은 2단) 뒤에만:
const r = await session.executeAction(offer, { actorClaimed: agentDisplayName });
// r.state: succeeded | failed | unknown — unknown 은 재실행 없음("확인 필요"로 남는다)
// 보고가 안 됐으면(r.reported=false) session.resendResult(r.requestId) — 재실행 아님

3단: ① 허브 선점(request_id ULID, 전송 전 영속, 재시도 0 — 네트워크 오류면 상태를 묻고 기록이 없을 때만 같은 request_id 로 1회 재전송) → ② adminApi.request 1회 — 카탈로그의 실행 사양(offer.execution)이 $nameparams_bound 로 치환하고 response_rule 이 성공/실패를 읽는다 → ③ 결과 보고(허브가 상태 단조·멱등 보장).

초기화 시 SDK 가 엔드포인트 맵의 키·메서드·경로 템플릿(호스트 없음) 을 허브에 1회 발행한다 — 공장 시스템 탭의 "이 CMS 가 이미 하는 처리" 목록이 여기서 온다. 같은 지문이면 네트워크 0(agent.candidatesReady, publishActionCandidates({force})).

처리 카드 슬롯은 어댑터 한 줄이다 — React ActionOffersPanel(/react), Vue ActionOffersPanel (/vue), 그 밖은 <cx-action-offers>(/element, defineCxActionOffers()), 스타일은 같은 styles.css(.fcx-act-*). 확인 2단·고위험 체크·재실행 금지·미보고 재보고 규약을 컴포넌트가 갖는다:

import { ActionOffersPanel } from "@fcg-labs/cx-agent-hook/react";
<ActionOffersPanel session={agent.session(csId)} agent={agent} actorClaimed={answerWriter}
                   onResult={(r) => r.state === "succeeded" && refresh()} />

카드 상태: locked(같은 대상·같은 입력의 최근 성공 — "이미 처리됨 · 시각 · 행위자") · unavailable(이 CMS 가 그 API 를 모름 — fail-closed) · 실행 중 · 완료 · 실패(재시도 가능) · 확인 필요(unknown) · 미보고(결과 다시 보고). 눌렀던 처리는 session.pendingActions() 로 새로고침 뒤에도 안다(정본은 허브 원장). 헤드리스 뷰: actionOffersView / actionOffersTree(view.js), 클래스 fcx-act-*, 문구는 ui_action_* 로케일 키. 순수 함수 buildCandidateSnapshot · resolveExecution · judgeResponse · executeViaAdminApi (actions.js) 는 시험·커스텀 경로용으로 공개.

지원 프레임워크

| 진입점 | 대상 | 필요한 peer | |---|---|---| | /react | React 16.8+ | react | | /next | Next.js App Router ("use client" 선언 포함) | react | | /vue | Vue 3 | vue | | /astro | Astro — 표준 커스텀 엘리먼트 | 없음 | | /angular | Angular — 표준 커스텀 엘리먼트 | 없음 | | /element | 순수 HTML·그 밖 | 없음 |

표시 판단은 하나다. 다섯 어댑터가 같은 aiSuggestView() 와 같은 클래스 이름을 쓰므로 styles.css 한 벌이 전부를 덮고, 규약이 바뀌어도 한 곳만 고친다.

Astro·Angular 에 프레임워크 컴포넌트를 따로 내주지 않는 이유: 메이저 버전마다 규약이 흔들려 우리가 고객 버전을 따라다니게 되고, "빌드 단계 없음" 성질도 깨진다. 브라우저 표준 하나로 덮는 편이 오래 간다.

화면 언어

setup 에서 한 번 정하면 이후 문구는 전부 훅이 낸다 — 고객사가 사유별 문구를 알 필요가 없다. 지원: ko · en · ja · zh-TW. 모르는 값이면 조용히 en 으로 떨어진다(화면이 깨지지 않는다).

createCxHook({ ..., locale: "ja" });
createCxHook({ ..., locale: "ko", messages: { ui_request: "답변 초안 받기" } });

간체 중국어(zh-CN)를 zh-TW 로 붙이지 않는다 — 잘못 안내하느니 영어가 낫다.

통합 (전부)

주소는 하나다. 허브의 ingress·feedback·answer 세 라우트는 같은 호스트에 같은 권한 등급이라 갈릴 수 없다.

// cxAgentHook.js — 고객사 저장소에 두는 배선 파일. 이게 전부다.
import { createCxHook } from "@fcg-labs/cx-agent-hook";

export const cxHook = createCxHook({
  baseUrl: import.meta.env.VITE_CX_HUB_URL,
  token: import.meta.env.VITE_CX_HUB_BROWSER_TOKEN,   // browser 등급 (적재 전용)
  domain: import.meta.env.VITE_CX_DOMAIN,
  api: "hub",
});
// 상담 화면 (Vue·Astro·Angular 는 위 표의 진입점으로 바꾸면 된다)
import { AiSuggestPanel } from "@fcg-labs/cx-agent-hook/react";
import "@fcg-labs/cx-agent-hook/styles.css";
import { cxHook } from "./cxAgentHook";

<AiSuggestPanel hook={cxHook} inquiry={selected?.content} onAdopt={setAnswerText} />

// 발송 버튼에서 두 줄
cxHook.answerSent(editor.value, session.userId);   // ① 채택본이었을 때만 동작
cxHook.inquirySent({                               // ② 문의·답변 쌍 적재
  externalId: inquiry.id, inquiry: inquiry.text,
  reply: editor.value, agent: session.userId,
  meta: { category: inquiry.category },
});

②가 인입의 유일한 통로다. AI 제안을 안 쓰더라도 ②만 붙이면 문의·답변 쌍이 쌓이고, 그게 교재·평가 데이터가 된다. ①은 AI 제안을 쓸 때만 의미가 있다.

켜고 끄기는 서버가 정한다

"적재만 받고 AI 제안은 안 함"은 서버 설정이다(허브의 answer 업스트림 미설정). 고객사 빌드에 스위치를 두지 않는다 — 두면 진실의 주인이 둘이 되고, 켜는 데 관리자 화면 재배포가 필요해진다. 꺼져 있으면 패널이 눌렀을 때 그 사실을 평문으로 안내한다.

상담사 판단 후킹 — 학습의 재료

채택한 제안에 대해서만 동작한다. answer_id고객사가 들지 않는다 — 패널이 채택 시점에 기록하고, 아래 호출이 그 기록을 쓴다.

cxHook.scored(4, agent);              // 제안 품질 1~5
cxHook.edited(editor.value, agent);   // 고쳐 씀 (초안↔최종본 델타)
cxHook.discarded(agent, "톤이 어색함"); // 안 씀 + 이유
cxHook.answerSent(editor.value, agent); // 발송

answerSent·discarded 는 그 제안에 대한 마지막 판단이라 보낸 뒤 채택 기록을 비운다(재발송해도 중복되지 않는다). scored·edited 는 발송 전에 여러 번 올 수 있어 비우지 않는다.

전송 계층은 공개하지 않는다

CxAgentClient(HTTP 왕복·재시도·경로 규약)는 client.js 에 있고 exports 맵에 없다. 소비처가 @fcg-labs/cx-agent-hook/client.js 로 닿을 수 없다.

의도된 제약이다. 저수준을 열어 두면 새 능력을 붙일 때 자연히 그리로 내려가고, 그 순간 answer_id 수명 관리 같은 제품 지식이 다시 고객사 코드로 흩어진다. 능력이 모자라면 저수준을 노출하는 게 아니라 createCxHook 표면을 채운다.

능력별로 주소가 정말 갈려야 하면(예: 답변만 공장 직결) createCxHook 설정에 answer·ingress·feedback 대상을 넘긴다 — 전송 계층에 그대로 전달된다.

계약 보증

  • 어떤 메서드도 throw 하지 않는다 — 발송 UX 를 막지 않고 { ok:false } 로 보고. getAnswer 도 대상 미설정·네트워크 오류를 throw 없이 돌려준다(상담사는 수동 작성으로 계속 간다). 설정 실수는 onError 로 개발자에게만 알린다.
  • 서버가 준 거절 사유를 뭉개지 않는다answer_disabled(아직 안 켬)와 answer_unavailable(장애)이 같은 503 이지만 다른 안내로 갈린다.
  • sendFeedback·logInquiry 는 네트워크 오류를 재시도(기본 2회, 백오프) 후 보고
  • 4xx(계약 위반)는 재시도하지 않고 즉시 보고 — onError 콜백으로 관측
  • logInquiryexternalId 기준 멱등 — 같은 문의를 두 번 보내도 중복되지 않는다
  • answerSent 는 한 번 보내면 채택 기록을 비운다 — 재발송해도 교정이 중복되지 않는다

라이선스와 접속 자격

공개 배포이고, 받아서 쓰셔도 됩니다 — 여러분의 애플리케이션에 넣어 함께 배포하는 것도 됩니다. SDK 자체의 재배포·개작, 경쟁 서비스 구축은 제외입니다 (LICENSE 전문 참조).

여는 데 부담이 없는 이유는 이 패키지에 자산이 없기 때문입니다. 지식베이스도 코퍼스도 학습 데이터도 가중치도 들어 있지 않고, 접속 자격이 없으면 아무 동작도 하지 않습니다 — 요청을 보내지 않고 조용히 꺼져 있습니다(시험으로 고정).

접속 토큰

token도메인에 묶인 값이다 (cx1_<domain>_<mac>). 게이트웨이가 요청 경로의 도메인과 대조하므로, 한 고객의 토큰으로 다른 고객의 수집함에 쓸 수 없다. 적재·교정·답변만 되고 학습 산출물에는 닿지 못하는 등급이라 번들에 실려도 안전하다. 값은 플랫폼의 도메인 화면에서 받는다.

테스트

npm test          # 65건 — 전송 계약·훅 표면·다국어·5종 어댑터

패널의 표시 판단은 aiSuggestView() 순수 함수로 떼어 두었다 — 이 패키지는 react-dom 을 의존하지 않으므로 렌더러 없이 검증한다. Vue 는 SSR 렌더로, 커스텀 엘리먼트는 실제 DOM 으로 확인한다 (둘 다 devDependency — 배포물에는 없다).

배포 전에는 npm publishscripts/prepublish-guard.mjs 를 먼저 돌린다: 화이트리스트 밖 파일·진입점 누락·비밀/실주소/고객 식별자·시험 실패를 막는다.