Skip to content

Nâng gói: tra Context7 trước khi đổi phiên bản ​

Luật UI của repo bắt "luôn dùng bản mới nhất". Trang này nói cách nâng mà không làm vỡ CI một cách lặng lẽ: tra tài liệu của bản đích trước, kiểm bằng thứ CI không kiểm sau.

Trạng thái 14.10.2026

  • .mcp.json (server context7) đã có trong repo. Mỗi máy phải duyệt một lần ở phiên đầu tiên; chưa duyệt thì không có tool mcp__context7__*.
  • Môi trường cloud chưa có mcp.context7.com trong allowlist mạng (việc của chủ repo, xem cuối trang). Tới khi thêm, phiên cloud không có Context7: hook chặn một lần rồi cho qua kèm cảnh báo nêu gói chưa tra.
  • Chưa có khoá API: Context7 chạy ẩn danh, hạn mức thấp hơn, vẫn dùng được.
  • npm run check:lockfiles và npm run check:hooks chỉ chạy ở CI sau khi khai vào job changes của ci-checks.yml (gói thay đổi 14.10.2026 trả đoạn khai cho người tích hợp).

Vì sao: TypeScript 7, xanh ở máy, đỏ ở CI ​

Ngày 03.10.2026 đợt nâng major đưa TypeScript lên 7. Ở www và mam, typegen, tsc và build đều xanh ở máy; rồi npm ci ERESOLVE ở CI vì @react-router/dev 7.18 khai peer typescript ^5 || ^6. typescript-eslint sập ở ba site khác vì gói TS 7 không còn JS API. Cả hai điều đó nằm sẵn trong changelog và bảng peer. Thứ thiếu là thói quen đọc trước khi nâng (known-risks).

Kiểm lại 14.10.2026 thấy chuyện còn khó thấy hơn: mọi job build và bước deploy cài bằng npm ci --legacy-peer-deps || { warning; npm install; }. --legacy-peer-deps bỏ qua peer, nên một xung đột y hệt TS 7 không làm đỏ job build nào. Thử trên mẫu typescript-eslint 8.71 + TypeScript 7.0: bản nghiêm exit 1 ERESOLVE, bản --legacy-peer-deps exit 0.

Quy trình ​

BướcLàm gìBắt cái gì
1Context7: resolve-library-id rồi query-docs cho changelog / migration guide của bản đíchbreaking change, API bị bỏ
2Đọc bảng peer: npm view <gói>@<bản> peerDependencies, và của các gói khai peer lên gói mình nângkiểu lỗi TS 7
3Đối chiếu .claude/memory/deps-upgrade-holdbacks.mdnâng nhầm gói đang giữ có lý do
4Nâng packages/* cùng lượt với site dùng nó; họ gói nâng cùng một sốhai bản @types/react
5npm ci --dry-run --legacy-peer-deps=false ở mọi thư mục đổi, hoặc npm run check:lockfilesxung đột peer, lockfile lệch
6typecheck + build ở mọi thư mục đổivite build không kiểm type

Giữ một gói ở bản cũ thì ghi lý do bằng khoá "//<tên gói>" ngay trong package.json (npm bỏ qua khoá bắt đầu bằng //), và thêm một dòng vào file memory. Ví dụ đang có: //typescript ở www, mam, play/frontend, video2; //mermaid ở docs.

Hai luật đi kèm: wrangler ở lại package.json của sáu Worker (CI deploy bằng npx --no-install wrangler), và vòng QC đêm không bao giờ nâng gói (skill nightly-qc).

Gói đang giữ bản cũ (14.10.2026) ​

GóiỞ đâuVì saoGỡ khi
TypeScript 5www, mam@react-router/dev 7.x chỉ nhận TS 5/6nâng cả họ React Router lên 8 (8.4 đã nhận TS 7), một việc major
TypeScript 6play/frontend, video2typescript-eslint 8.71 khai <6.1.0, cần JS APItypescript-eslint nhận TS 7
mermaid 11docsvitepress-plugin-mermaid 2.0.17 chỉ nhận 10/11plugin nhận 12

Bản đầy đủ, kèm những mục đã hết hạn và vì sao: .claude/memory/deps-upgrade-holdbacks.md. Trước 14.10.2026 danh sách này chỉ nằm trên máy chủ repo, nên phiên cloud và vòng đêm chưa từng thấy nó, trong khi skill nightly-qc vẫn trỏ tới nó như thể nó có trong repo.

Hook deps-docs-guard ​

scripts/hooks/deps-docs-guard.mjs, hook PreToolUse của Claude Code (Edit|Write|MultiEdit|Bash). Khi lượt sắp chạy đổi phiên bản một gói mà tác nhân đang chạy lệnh chưa tra Context7 cho chính gói đó, nó chặn một lần và nói ba việc phải làm.

Bị coi là đổi phiên bảnKhông bị coi
sửa package.json thêm hay đổi bản ở dependencies, devDependencies, peerDependencies, optionalDependencies, overrides; gỡ một overrideđổi scripts, khoá //, version của chính gói, chuyển section giữ nguyên bản, gỡ một gói
npm/pnpm/yarn install|i|add|update|up|upgrade <gói>, cả trong for … do, if … then, bash -c, xargsnpm ci, npm install trần, -g, --no-save, xargs -I{} npm install --prefix {}
ncu -u (qua npx, npm exec, dlx), npm audit fix, pnpm up --latest, npm pkg set devDependencies.<gói>=chữ "npm i" trong commit message hay heredoc; npm update trần; npm pkg set scripts.*
ghi package.json bằng shell: sed -i/perl -i có dáng phiên bản, >, tee, sponge, mv/cp đè, node -e … writeFileSyncsed -n, cat, jq chỉ đọc; sed -i sửa scripts

"Đã tra" nghĩa là gì. Trong transcript của chính tác nhân đó có một lượt gọi resolve-library-id / query-docs thoả cả ba điều:

  1. Là khối tool_use thật, không phải tên tool nằm trong danh sách tool hoãn.
  2. Nhắc tới gói trong libraryName, libraryId hay query. Gói có scope tính theo scope (@react-router/dev khớp /remix-run/react-router, @sentry/cloudflare khớp Sentry), @types/x tính theo x, gói cùng họ tính theo thư viện đã tra (tra React phủ react-dom). Trường languagekhông được đọc.
  3. Có kết quả thật: không is_error, không mở đầu bằng Invalid API key hay câu lỗi tương tự, và dài từ 200 ký tự (kết quả thật ngắn nhất trong 50 lượt tra của repo là 665 ký tự).

Subagent chỉ được tính lượt tra trong transcript của nó. Lệnh không nêu được tên gói (ncu -u, audit fix, --latest, ghi package.json bằng shell mà không có cặp "tên": "bản") chỉ đòi một lượt tra thành công bất kỳ, và luôn in ghi chú rằng hook không kiểm được tra đúng gói.

Chống kẹt: chặn tối đa một lần cho mỗi tác nhân trong phiên (file đánh dấu theo session_id + agent_id); không đọc được transcript hay không ghi được file đánh dấu thì cho qua. File đánh dấu chỉ được xét sau transcript: đã tra đủ thì cho qua im lặng, chưa tra thì lần sau cho qua kèm một dòng systemMessage nêu đúng gói còn thiếu. Nhờ vậy "đã tuân thủ" và "đang lách" không bao giờ ra cùng một câu.

Bẫy khi viết hook này, hai thế hệ, cùng một loại "gác xanh mà chưa kiểm gì":

  • Tìm chuỗi thô. Transcript chứa sẵn danh sách tool hoãn và schema tool. Trong 74 transcript của repo, 64 có chuỗi __query-docs, chỉ 1 có lượt gọi thật.
  • Đếm lượt gọi bất kỳ (bản đầu của chính hook này, rà soát 14.10.2026 bắt được). Trong một phiên workflow, phiên cha tra tài liệu Sentry; subagent không tra gì; npm i -D typescript@7 của subagent qua im lặng, đúng sự cố TS 7. Tệ hơn, query-docs gửi kèm "language":"TypeScript", nên một phép "input có nhắc tên gói không" ngây thơ cũng cho lượt tra Sentry phủ gói typescript. Và một lượt tra trả Invalid API key vẫn được tính như đã đọc.

Quét transcript 79 MB (không lượt tra nào, phải đọc hết): khoảng 200 ms cả tiến trình hook; lệnh không đổi phiên bản dừng trước khi đọc transcript, khoảng 60 ms.

npm run check:hooks (scripts/check-hooks.mjs) kiểm chính các hook: lệnh trỏ tới file có thật, mọi file hook đều được khai, node --check sạch, --self-test xanh (deps-docs-guard: 80 mẫu). Trước 14.10.2026 không gì kiểm hook, và một hook hỏng chỉ là "lỗi không chặn" mà Claude Code in ở chế độ verbose. Lệnh hook dùng đường dẫn tương đối thì gác in ghi chú; cả ba cách viết "$CLAUDE_PROJECT_DIR/…", "${CLAUDE_PROJECT_DIR}/…" và "$CLAUDE_PROJECT_DIR"/… đều được nhận.

Context7: dựng ở máy và ở cloud ​

.mcp.json ở gốc repo:

json
{ "mcpServers": { "context7": { "type": "http", "url": "https://mcp.context7.com/mcp",
  "headers": { "CONTEXT7_API_KEY": "${CONTEXT7_API_KEY:-}" } } } }

Không có bí mật nào trong file. ${CONTEXT7_API_KEY:-} thay bằng chuỗi rỗng khi biến không đặt, và máy chủ Context7 nhận header rỗng như ẩn danh (thử trực tiếp 14.10.2026).

Phải có :-. Viết ${CONTEXT7_API_KEY} không mặc định thì khi biến không đặt, Claude Code chỉ in cảnh báo trong phần chẩn đoán của claude mcp list rồi gửi nguyên chữ ${CONTEXT7_API_KEY} làm khoá. claude mcp list vẫn báo Connected, và mọi lượt gọi trả về một kết quả bình thường có nội dung Invalid API key, không cờ lỗi nào. Khoá sai cũng ra đúng câu đó.

Ở đâuLàm gì
MáyPhiên đầu tiên trong repo hỏi duyệt server context7 từ .mcp.json: đồng ý. Chủ repo đã có Context7 qua connector tài khoản (mcp__<uuid>__*); hai nguồn cùng có cũng không sao, hook tính cả hai.
Máy, có khoáĐặt CONTEXT7_API_KEY trong shell profile; hoặc ghi đè riêng máy mình: claude mcp add --scope local --transport http context7 https://mcp.context7.com/mcp --header "CONTEXT7_API_KEY: <khoá>" (scope local thắng scope project, không vào git).
Cloud.mcp.json theo clone. Thêm mcp.context7.com vào allowlist mạng (mức Custom). Khoá, nếu có: biến môi trường CONTEXT7_API_KEY trong hộp thoại môi trường.

Kiểm nhanh: claude mcp list phải ra context7 ... ✔ Connected, rồi gọi thử resolve-library-id một lần: nội dung trả về phải là danh sách thư viện, không phải Invalid API key.

Việc chỉ chủ repo làm được ​

  1. Cloud: thêm mcp.context7.com vào allowlist mạng của môi trường ở claude.ai/code (Network access: Custom, giữ "also include default list"). Xem cloud-dev.
  2. Máy: duyệt server context7 ở lần đầu được hỏi (hoặc từ chối nếu chỉ muốn dùng connector).
  3. Tuỳ chọn, khoá API: tạo khoá ở bảng điều khiển Context7, đặt vào biến CONTEXT7_API_KEY (shell profile ở máy, hộp thoại môi trường ở cloud). Không bao giờ ghi khoá vào .mcp.json.
  4. Tuỳ chọn, tự duyệt: thêm "enabledMcpjsonServers": ["context7"] vào .claude/settings.json để mọi máy khỏi bị hỏi. Đây là đổi cấu hình tin cậy cho mọi người clone repo, nên không làm thay chủ repo.
  5. Tích hợp CI: khai check:hooks và check:lockfiles vào job changes và check:guards.

Xem thêm: skill deps-upgrade, design-system, guardrails & vòng đêm.

Tài liệu nội bộ nền tảng Conan School.