鎮(zhèn)伪嫖觯簭膎pm包到agent loop的安全排查)
簡(jiǎn)介Anthropic 官方 Claude Code 命令行工具的完整源代碼壓縮包2026年4月1日版面向 AI 編程助手研發(fā)者、CLI 工具愛(ài)好者和希望深入理解 MCP 協(xié)議、Agent 工具鏈及終端交互設(shè)計(jì)的中高級(jí)開(kāi)發(fā)者是一份適合源碼級(jí)拆解與二次開(kāi)發(fā)的基礎(chǔ)參考。源碼在 src 目錄下按職責(zé)清晰分層commands 實(shí)現(xiàn)斜杠命令components 與 design-system 負(fù)責(zé)終端 UIservices 包含 API、MCP、分析、設(shè)置同步等核心服務(wù)tools 提供 Bash、文件讀寫(xiě)、Grep、Glob、Task 等工具另含 hooks、schemas、ink 等基礎(chǔ)模塊模塊劃分完整類型定義清晰方便逐一研讀。壓縮包共 1903 個(gè)文件以 TypeScript 為主其中 1332 個(gè) ts 與 552 個(gè) tsx 分別承載純邏輯與 UI 組件另有少量 js 和 1 個(gè) md 說(shuō)明文件包體大小約 9.43MB。目前已有 707 人學(xué)習(xí)下載。通過(guò)通讀源碼可掌握 Claude Code 的命令調(diào)度機(jī)制、工具封裝方式、MCP 通信設(shè)計(jì)以及終端交互渲染邏輯對(duì)自研 AI 編程助手或二次開(kāi)發(fā)腳手架具有直接參考價(jià)值尤其適合研究工具調(diào)用、上下文維護(hù)與權(quán)限控制等核心實(shí)現(xiàn)。1. 源碼泄露先看一眼日期再?zèng)Q定要不要激動(dòng)“Claude Code源碼泄露”這個(gè)標(biāo)題真正值得先看的不是內(nèi)容而是日期。4月1日懂的都懂。這幾天確實(shí)有技術(shù)群里在轉(zhuǎn)一個(gè)幾百 MB 的壓縮包配文是“限時(shí)刪除”“錯(cuò)過(guò)再無(wú)”這類話術(shù)。作為一個(gè)被各種假源碼坑過(guò)的人我的第一反應(yīng)不是下載而是問(wèn)三個(gè)問(wèn)題官方發(fā)布形態(tài)里到底有沒(méi)有“源碼”這個(gè)概念如果真泄露了普通開(kāi)發(fā)者拿到能做什么如果是個(gè)釣魚(yú)包我能不能在五分鐘內(nèi)識(shí)別出來(lái)。這篇筆記就是圍繞這三個(gè)問(wèn)題展開(kāi)的。2. Claude Code 的發(fā)布形態(tài)與“源碼”的邊界npm包、打包產(chǎn)物、閉源推理層2.1 所謂的“源碼”在工程上其實(shí)分三層先說(shuō)結(jié)論Claude Code 的發(fā)布形態(tài)是一個(gè) npm 包安裝后本機(jī)跑的是打包壓縮過(guò)的 JavaScript 產(chǎn)物不是一份能直接閱讀、修改、重新構(gòu)建的 TypeScript 工程。所謂“源碼泄露”在工程上至少要拆成三個(gè)層次看待。第一層是 CLI 側(cè)邏輯包括命令行解析、會(huì)話管理、工具調(diào)用、權(quán)限確認(rèn)、日志輸出。這一層會(huì)以壓縮后的 dist 文件形式出現(xiàn)在你本機(jī)的 node_modules 里嚴(yán)格說(shuō)它“可見(jiàn)”但變量名和函數(shù)名都被混淆過(guò)可讀性很差談不上“泄露”。第二層是 agent 循環(huán)的編排層官方術(shù)語(yǔ)里叫 harness。它負(fù)責(zé)把用戶的一句話目標(biāo)翻譯成多輪工具調(diào)用維護(hù)上下文狀態(tài)決定什么時(shí)候調(diào)用 read_file、什么時(shí)候執(zhí)行 bash、什么時(shí)候停下來(lái)問(wèn)你要權(quán)限。這一層同樣打包在 npm 產(chǎn)物里。第三層是模型推理服務(wù)本身。真正的模型權(quán)重、推理邏輯、服務(wù)端調(diào)度都在遠(yuǎn)端CLI 進(jìn)程里只有一個(gè) HTTP 客戶端。這一層是不可能通過(guò)一個(gè)“源碼壓縮包”泄露到你手里的因?yàn)樗谌魏伪镜胤职l(fā)鏈路中都不存在。所以當(dāng)你看到一個(gè)帖子聲稱“Claude Code 完整源碼泄露”先問(wèn)它說(shuō)的是哪一層。如果壓縮包里是幾千個(gè) .ts 源文件且?guī)暾?.git 目錄反而說(shuō)明它是別人重新整理過(guò)的二手工程如果聲稱包含模型服務(wù)端源碼那基本可以直接判斷為噱頭。2.2 從安裝到首次運(yùn)行一條命令背后發(fā)生的事很多人搜“claude code安裝”“claude code下載安裝”以為裝完就能看到全套源碼其實(shí)安裝過(guò)程本身就說(shuō)明了它的分發(fā)策略。最常見(jiàn)的安裝方式是全局 npm 安裝命令如下# 全局安裝 Claude Code 的官方 npm 包 npm install -g anthropic-ai/claude-code # 查看安裝后的可執(zhí)行文件 which claude # 常見(jiàn)輸出/usr/local/bin/claude - ../lib/node_modules/anthropic-ai/claude-code/cli.js安裝完成后npm 會(huì)在系統(tǒng)全局目錄下建立 bin 軟鏈把 cli.js 暴露成 claude 這個(gè)命令。你真正執(zhí)行的入口就是一個(gè)壓縮后的 JavaScript 文件它內(nèi)部再按需 require 同目錄下的一系列 chunk 文件。這里有幾個(gè)安裝時(shí)需要留神的參數(shù)和環(huán)境問(wèn)題。Node.js 的版本要滿足官方要求太老的版本會(huì)在啟動(dòng)時(shí)直接報(bào)語(yǔ)法錯(cuò)誤因?yàn)榇虬a(chǎn)物使用了較新的 JS 語(yǔ)法。全局安裝目錄的寫(xiě)權(quán)限也經(jīng)常出問(wèn)題如果你之前改過(guò) npm prefix或者用 sudo 裝過(guò)別的全局包后面會(huì)出現(xiàn) auto-update failed 一類的報(bào)錯(cuò)這個(gè)我在第 4 章單獨(dú)講。網(wǎng)絡(luò)源方面npm registry 可以換成你網(wǎng)絡(luò)環(huán)境下訪問(wèn)更快的鏡像節(jié)點(diǎn)但要注意鏡像節(jié)點(diǎn)的同步頻率官網(wǎng)已發(fā)布新版而你本地的鏡像還沒(méi)同步是很多“裝完還是舊版”的根源。第一次運(yùn)行 claude 會(huì)要求完成登錄授權(quán)這是官方的賬號(hào)流程和源碼無(wú)關(guān)。在 VSCode 里配置 Claude Code本質(zhì)上也只是在集成終端里運(yùn)行同一個(gè) claude 命令不需要單獨(dú)的插件安裝很多教程把這件事復(fù)雜化了。2.3 真正值得研究的骨架harness、agent loop 與工具調(diào)用循環(huán)拋開(kāi)“源碼”這個(gè)誘餌Claude Code 里真正有學(xué)習(xí)價(jià)值的是 harness 的工程設(shè)計(jì)而這些信息并不需要靠泄露包獲取。官方文檔中對(duì) harness 的描述、CLI 自身的日志輸出、hook 機(jī)制、MCP 配置格式已經(jīng)把架構(gòu)輪廓暴露得很清楚。一個(gè)典型的 agent 循環(huán)是這樣運(yùn)轉(zhuǎn)的用戶輸入目標(biāo) → 模型返回一個(gè)決策可能包含工具調(diào)用 → CLI 檢查該工具是否需要權(quán)限確認(rèn) → 執(zhí)行工具并把結(jié)果回填給模型 → 模型繼續(xù)決策 → 直到模型認(rèn)為任務(wù)完成。這個(gè)循環(huán)和很多開(kāi)源 agent 框架的結(jié)構(gòu)一致差別在于實(shí)現(xiàn)細(xì)節(jié)工具結(jié)果如何截?cái)?、上下文窗口滿了怎么辦、失敗的工具調(diào)用如何重試、權(quán)限確認(rèn)怎么不打斷用戶節(jié)奏。// 一個(gè)高度簡(jiǎn)化的 agent loop 偽代碼 let messages [{ role: user, content: 把當(dāng)前目錄的 README 總結(jié)成 5 條要點(diǎn) }] while (true) { const decision await model.chat(messages) // 調(diào)用模型 if (decision.tool_calls null) break // 不再要工具說(shuō)明任務(wù)結(jié)束 for (const call of decision.tool_calls) { if (needPermission(call.name)) await confirm(call) // 關(guān)鍵交互點(diǎn) const output await tools[call.name](call.arguments) // 執(zhí)行 messages.push({ role: tool, content: output }) // 回填結(jié)果 } if (messages.length 40) messages trimHistory(messages) // 控制窗口 }這段代碼里最值得品的是 needPermission 和 trimHistory 兩個(gè)點(diǎn)。前者是 agent 在真實(shí)工程環(huán)境中能落地的前提——工具權(quán)限不能全程自動(dòng)放行否則一個(gè)錯(cuò)誤指令就能刪庫(kù)后者決定了長(zhǎng)任務(wù)的穩(wěn)定性窗口一滿簡(jiǎn)單粗暴地丟棄早期消息會(huì)導(dǎo)致 agent 失去任務(wù)上下文這是很多自建 agent 翻車(chē)的常見(jiàn)原因。理解了 harness 與模型服務(wù)的關(guān)系就能回答一個(gè)常被問(wèn)到的問(wèn)題能不能把 Claude Code 的 harness 換成別的模型來(lái)跑。從架構(gòu)上看CLI 和模型服務(wù)之間是協(xié)議解耦的社區(qū)里也有人通過(guò)改環(huán)境變量里的接口地址和模型名把整個(gè)工具鏈指向兼容 OpenAI 協(xié)議的第三方服務(wù)。這件事和“源碼泄露”沒(méi)關(guān)系它恰恰說(shuō)明協(xié)議層的研究?jī)r(jià)值高于追逐一個(gè)假泄露包。3. 判斷一個(gè)“Claude Code源碼包”的真?zhèn)嗡牟胶藢?duì)法3.1 第一步核對(duì)包名、版本號(hào)與發(fā)布時(shí)間拿到一個(gè)號(hào)稱 Claude Code 源碼的壓縮包先別急著解壓。第一步是回到 npm registry核對(duì)官方真實(shí)的包名、版本號(hào)和發(fā)布時(shí)間。偽造者最容易犯的錯(cuò)誤就是給一個(gè)根本不存在的版本號(hào)或者發(fā)布時(shí)間對(duì)不上。# 查官方包的最新版本號(hào)和各版本發(fā)布時(shí)間 npm view anthropic-ai/claude-code dist-tags --json npm view anthropic-ai/claude-code time --json # 查官方包名是否存在 npm view anthropic-ai/claude-code name versiondist-tags 里看 latest 字段這是當(dāng)前穩(wěn)定版的真實(shí)版本號(hào)。time 字段里能看到每一個(gè)版本的發(fā)布時(shí)間重點(diǎn)看 modified 時(shí)間它代表官方最近一次更新。如果壓縮包里的 README 聲稱自己是 5.x.x而 latest 明明是 2.x.x說(shuō)明這個(gè)包要么是改名的翻版要么是故意夸大的噱頭。版本號(hào)相同也不能直接信任。很多釣魚(yú)包會(huì)把 README 改成和官方一模一樣但 package.json 里的 name、version、bin 字段被悄悄改過(guò)。所以下一步要做的不是讀 README而是對(duì)比 package.json 的完整字段和文件清單。3.2 第二步檢查文件清單和入口識(shí)別官方產(chǎn)物特征解壓之前可以先列清單。無(wú)論壓縮包是 tar.gz 還是 zip都可以在不解壓的情況下查看內(nèi)部文件列表這一步能暴露大量信息。# 查看 tar.gz 包內(nèi)的文件清單 tar -tzf claude-code-source.tar.gz | head -50 # 查看 zip 包內(nèi)的文件清單 unzip -l claude-code-source.zip | head -50官方 npm 包的文件結(jié)構(gòu)有兩個(gè)顯著特征根目錄一定有一個(gè) package.jsonbin 字段指向一個(gè) cli.js 入口主體代碼在 dist 或者 vendor 目錄下是一堆壓縮后的 js/chunk 文件。你可以看到 readme、license但不會(huì)看到一個(gè)完整的 src 目錄更不會(huì)有 .git 目錄。我見(jiàn)過(guò)把官方發(fā)布產(chǎn)物重打包成“源碼包”的例子也見(jiàn)過(guò)拿一個(gè)無(wú)關(guān)開(kāi)源項(xiàng)目改標(biāo)題的例子兩種情況的文件清單截然不同。把常見(jiàn)特征整理成一份對(duì)比判斷時(shí)會(huì)快很多| 特征項(xiàng) | 官方 npm 發(fā)布包 | 常見(jiàn)偽造“源碼包” | | 根目錄 | package.json README license | 一堆 src/、docs/ 目錄 | | 代碼位置 | dist/ 或 vendor/ 下壓縮產(chǎn)物 | 干凈整齊的 .ts/.js 源文件 | | .git 目錄 | 無(wú) | 經(jīng)常出現(xiàn) | | 版本信息 | 和 registry 完全一致 | 常被改成更高的假版本 | | 文件體量 | 正常 CLI 的合理范圍 | 幾 KB 或明顯注水的大包 |這個(gè)表不能覆蓋所有情況但能幫你過(guò)濾掉八成以上的假包。真正需要繼續(xù)做硬核對(duì)的是那些文件結(jié)構(gòu)看起來(lái)很像官方產(chǎn)物的重打包包。3.3 第三步拉官方包做哈希與體積比對(duì)文件清單看著像還不夠第三步用哈希和體積做一次硬核對(duì)。npm 自帶 pack 命令可以把官方包完整下載成 tgz然后計(jì)算哈希和你的壓縮包對(duì)比。# 下載官方包到本地 npm pack anthropic-ai/claude-code # 生成類似 anthropic-ai-claude-code-2.x.x.tgz 的文件 # 計(jì)算官方包的哈希 shasum -a 256 anthropic-ai-claude-code-2.x.x.tgz # 計(jì)算你手上“泄露源碼包”的哈希 shasum -a 256 claude-code-source-4-1.tar.gz哈希完全一致的情況幾乎不存在因?yàn)閮蓚€(gè)包的構(gòu)建時(shí)間和元數(shù)據(jù)不同但你可以看體積數(shù)量級(jí)。官方 CLI 打包出來(lái)是一個(gè)正常工具鏈該有的大小如果你手上的“完整源碼”只有 200KB那它連官方產(chǎn)物都未必是更別談源碼。反過(guò)來(lái)如果自稱源碼的包體積異常巨大里面大概率塞了一堆不相關(guān)的資源文件撐體積。這里有一個(gè)容易誤導(dǎo)人的點(diǎn)哈希不一致不能證明它是假的它可能是某一次構(gòu)建快照但哈希不一致加上文件結(jié)構(gòu)和版本對(duì)不上三個(gè)證據(jù)疊加基本可以下判斷。還有一個(gè)更直接的檢查方向打開(kāi)壓縮包里的 JS 文件隨便抽幾段搜有沒(méi)有官方域名、官方 CLI 標(biāo)志性的提示語(yǔ)、以及產(chǎn)物混淆痕跡。一個(gè)聲稱“源碼”的包里沒(méi)有這些字符串說(shuō)明它和真正的 Claude Code 關(guān)系不大。3.4 第四步斷網(wǎng)最小啟動(dòng)盯住網(wǎng)絡(luò)行為文件和哈希都核對(duì)完還有一種情況需要實(shí)測(cè)包是別人重打包的官方產(chǎn)物但被注入了后門(mén)邏輯。這時(shí)候要做的不是直接在主力環(huán)境里登錄運(yùn)行而是找一個(gè)隔離環(huán)境做一次啟動(dòng)觀察。# 在隔離目錄里直接調(diào)用入口腳本先看它打印什么 cd /tmp/inspect-source node cli.js --help # Linux 上用 strace 觀察網(wǎng)絡(luò)相關(guān)系統(tǒng)調(diào)用 strace -f -e tracenetwork node cli.js --help 21 | head -50第一次運(yùn)行建議加 --help 或者直接傳一個(gè)無(wú)害參數(shù)目的不是完成任務(wù)而是看它的啟動(dòng)過(guò)程有沒(méi)有超出預(yù)期的行為。如果它突然開(kāi)始請(qǐng)求一個(gè)陌生域名、往臨時(shí)目錄寫(xiě)奇怪的文件、嘗試讀取 ~/.ssh 或 ~/.aws 下的密鑰那這就是一個(gè)帶后門(mén)的重打包包。需要特別強(qiáng)調(diào)的是不要在主力環(huán)境、不要用真實(shí)賬號(hào)去試運(yùn)行一個(gè)來(lái)源不明的包。我見(jiàn)過(guò)拿到包就迫不及待登錄官方賬號(hào)跑 demo 的開(kāi)發(fā)者結(jié)果賬號(hào)密鑰通過(guò)環(huán)境變量被腳本讀走幾分鐘后就看到了異地登錄提醒。所謂的“泄露源碼”驗(yàn)證安全優(yōu)先級(jí)永遠(yuǎn)是第一位。4. 號(hào)稱泄露的源碼包避坑記錄五分鐘內(nèi)出現(xiàn)這些現(xiàn)象就該停手4.1 現(xiàn)象裝完CPU占用異常飆升現(xiàn)象描述解壓后照著 README 運(yùn)行安裝腳本機(jī)器風(fēng)扇馬上狂轉(zhuǎn)CPU 占用率沖到 90% 以上而且沒(méi)有任何窗口顯示任務(wù)進(jìn)度。原因分析這類“源碼包”里通常帶一個(gè)安裝腳本腳本在后臺(tái)拉取并執(zhí)行了挖礦模塊。挖礦程序?yàn)榱瞬槐涣⒖滩煊X(jué)往往把自己寫(xiě)成無(wú)界面守護(hù)進(jìn)程占用率又不做限流結(jié)果就是整機(jī)卡頓。解決思路立即斷開(kāi)網(wǎng)絡(luò)用 htop 按 CPU 排序找出可疑進(jìn)程并 kill再去檢查 crontab、開(kāi)機(jī)自啟目錄和 /tmp 下的臨時(shí)文件。然后把全局 node_modules 里那個(gè)可疑包徹底刪掉改回官方 npm 源重裝。這個(gè)處理順序很重要先斷網(wǎng)再做清理否則挖礦程序會(huì)從遠(yuǎn)端拉取新版繼續(xù)運(yùn)行。4.2 現(xiàn)象一運(yùn)行就要求安裝“Python依賴包”現(xiàn)象描述運(yùn)行時(shí)腳本提示“缺少環(huán)境依賴需要執(zhí)行 python 安裝命令”給出的命令里含有一段你從沒(méi)見(jiàn)過(guò)的一大串 --index-url 參數(shù)。原因分析這是典型的供應(yīng)鏈注水手法。安裝腳本在安裝階段通過(guò)自定義 pip 源把惡意 Python 包混進(jìn)環(huán)境后續(xù)通過(guò) Python 進(jìn)程執(zhí)行命令。偽造者預(yù)判了你的好奇心把“安裝依賴”包裝成常規(guī)初始化動(dòng)作用戶很容易習(xí)慣性回車(chē)執(zhí)行。解決思路任何時(shí)候都不要直接執(zhí)行 README 或 install.sh 里給的安裝命令。先打開(kāi)腳本讀一遍head -80 install.sh看里面有哪些外聯(lián)地址、有沒(méi)有 base64 解碼、有沒(méi)有把內(nèi)容重定向到某個(gè) URL。一旦看到類似 curl xxx | bash 或 python -c “…” 的結(jié)構(gòu)果斷停手。如果已經(jīng)執(zhí)行了檢查 pip list 里是否多了和項(xiàng)目無(wú)關(guān)的包再看 ~/.bashrc 是否被追加了可疑行。4.3 現(xiàn)象配置目錄里藏著無(wú)法解釋的外聯(lián)地址現(xiàn)象描述包自帶的“激活腳本”往 ~/.claude 下寫(xiě)入了 settings.json打開(kāi)后里面多了一個(gè)你在官方文檔里沒(méi)見(jiàn)過(guò)的 apiBaseUrl 或 endpoint 字段指向某個(gè)陌生地址。原因分析這類配置把模型請(qǐng)求的流量轉(zhuǎn)發(fā)到第三方服務(wù)器。Claude Code 這類 CLI 是按協(xié)議和遠(yuǎn)端服務(wù)通信的配置文件里的接口地址、認(rèn)證密鑰就是流量入口。被篡改后你的授權(quán)信息會(huì)隨每次請(qǐng)求一并發(fā)送給攻擊者。解決思路檢查 ~/.claude 目錄下所有 json 配置對(duì)照官方文檔確認(rèn)哪些字段是合法的。出現(xiàn)不在官方文檔里的 apiBaseUrl、代理地址、自定義證書(shū)路徑直接刪除對(duì)應(yīng)字段或整份配置。修改配置后重啟 CLI再看日志輸出里的請(qǐng)求地址是否恢復(fù)為官方域名。4.4 現(xiàn)象auto-update failed: no write permission to npm prefix現(xiàn)象描述裝了某個(gè)來(lái)源不明的包之后啟動(dòng) claude 時(shí)報(bào) auto-update failed: no write permission to npm prefix自更新一直失敗但命令行本體能跑。原因分析這個(gè)問(wèn)題其實(shí)不一定是惡意包引起的更多是全局 npm 目錄權(quán)限不對(duì)。npm 的全局 prefix 指向 /usr/lib/node_modules 或 /usr/local/lib/node_modules如果之前用 sudo 裝過(guò)包目錄所有者被改成了 root后續(xù)以普通用戶運(yùn)行 claude 時(shí)自更新就寫(xiě)不進(jìn)去。所謂“破解版”經(jīng)常遇到這個(gè)報(bào)錯(cuò)因?yàn)樗陌惭b方式改了目錄權(quán)限。解決思路先看 prefix 指向哪里再修正目錄所有者不要用 chmod 777 這種一刀切方式。npm prefix -g ls -ld $(npm prefix -g) sudo chown -R $(whoami) $(npm prefix -g)修正后再跑 claude 的自動(dòng)更新確認(rèn)能順利拉到新版這本身也能驗(yàn)證你裝的包是否還和官方更新通道連通。如果 chown 之后啟動(dòng)仍然報(bào)錯(cuò)說(shuō)明這臺(tái)機(jī)器的 node 安裝路徑本身有問(wèn)題可以考慮改用用戶級(jí)目錄重新安裝但不要因此輕易卸掉系統(tǒng) node容易造成其它全局命令同時(shí)失效。4.5 現(xiàn)象提示“源碼已加密”交錢(qián)才給解壓密碼現(xiàn)象描述壓縮包解壓到一半彈出提示說(shuō)主目錄被 AES 加密聯(lián)系發(fā)布者付費(fèi)才能拿到密碼。這是最直接的信號(hào)。原因分析這已經(jīng)不是“源碼泄露”問(wèn)題了是拿泄露噱頭做引流或騙局。所謂“限時(shí)刪除”“交押金看源碼”本質(zhì)是利用白嫖心理讓人付費(fèi)。真正的開(kāi)源或泄露內(nèi)容不會(huì)用加密套娃的方式分發(fā)。解決思路不付款不聯(lián)系直接放棄這個(gè)包。也不要因?yàn)楹闷嫒ミ\(yùn)行它附帶的主程序加密可能只是個(gè)幌子主程序一旦執(zhí)行就可能干別的事。對(duì)這類包的正確處置是記錄文件名和來(lái)源渠道然后刪除再回到官方 npm 渠道裝一遍正規(guī)產(chǎn)品。5. 不追泄露也能拆開(kāi)學(xué)基于官方安裝產(chǎn)物的工程梳理與最小復(fù)刻5.1 從 package.json 和 dist 入口反推啟動(dòng)鏈路不追偽造的泄露包官方安裝產(chǎn)物里的工程信息已經(jīng)足夠?qū)W一陣。安裝完成后先定位全局包目錄把 package.json 和文件結(jié)構(gòu)讀一遍。NODE_PATH$(npm root -g) ls -la $NODE_PATH/anthropic-ai/claude-code cat $NODE_PATH/anthropic-ai/claude-code/package.json # 用 node 直接讀取關(guān)鍵字段 node -e const prequire($NODE_PATH/anthropic-ai/claude-code/package.json); console.log(version:, p.version); console.log(bin:, JSON.stringify(p.bin)); console.log(main:, p.main)package.json 里的 bin 映射能告訴你 claude 命令實(shí)際指向哪個(gè)入口main 字段則標(biāo)記了庫(kù)模式下的入口。順著 cli.js 打開(kāi)能看到它 require 了哪些模塊這個(gè)依賴關(guān)系就是啟動(dòng)鏈路的地圖。讀這一層時(shí)重點(diǎn)不是讀懂每一行混淆代碼而是記錄模塊名和文件大小找出哪些 chunk 被入口直接依賴、哪些是懶加載。懶加載文件通常對(duì)應(yīng)按需功能比如某個(gè)特定工具或某種登錄方式啟動(dòng)時(shí)不會(huì)被立即執(zhí)行。這種靜態(tài)分析習(xí)慣比追一個(gè)假泄露包能積累更扎實(shí)的工程判斷力。5.2 用字符串搜索定位 agent loop 的關(guān)鍵節(jié)點(diǎn)打包產(chǎn)物雖然被壓縮混淆但字符串常量不會(huì)被全部抹掉。工具名稱、權(quán)限提示語(yǔ)、錯(cuò)誤信息、日志模板這些字符串會(huì)原樣留在產(chǎn)物文件里。用 grep 做一次字符串挖掘就能還原 agent loop 的大致地圖。NODE_PATH$(npm root -g) CLAUDE_DIR$NODE_PATH/anthropic-ai/claude-code # 列出所有工具相關(guān)的字符串 grep -roh read_file\|execute_command\|write_file\|notify $CLAUDE_DIR | sort | uniq -c | sort -rn | head -20 # 檢索權(quán)限確認(rèn)提示語(yǔ) grep -roh permission\|allow\|deny $CLAUDE_DIR/dist | sort | uniq -c | sort -rn | head -20grep 結(jié)果里出現(xiàn)頻率高的工具名基本就是 agent 默認(rèn)開(kāi)放的工具集權(quán)限相關(guān)字符串的密度能告訴你哪些操作默認(rèn)需要確認(rèn)。把這些字符串和一個(gè)實(shí)際的運(yùn)行日志對(duì)照看你會(huì)發(fā)現(xiàn)模型的 tool_calls 參數(shù)名、CLI 內(nèi)部的事件名、日志里打印的字段名是一一對(duì)應(yīng)的。這個(gè)方法的妙處在于完全基于官方產(chǎn)物合法且可持續(xù)。每次官方更新版本重新跑一遍字符串挖掘還能看到新增工具和變更提示語(yǔ)相當(dāng)于一份自動(dòng)生成的版本差異說(shuō)明。如果你要寫(xiě)自己的 agent這些字符串就是現(xiàn)成的兼容性參考。5.3 一份最小可運(yùn)行的“harness”骨架前面分析了這么多最終價(jià)值應(yīng)該落在能動(dòng)手。我經(jīng)常給同事看的一份最小 agent 骨架長(zhǎng)這樣它只有一個(gè) read_file 和一個(gè) bash 工具通過(guò)一個(gè)循環(huán)把模型決策和工具執(zhí)行串起來(lái)。代碼刻意精簡(jiǎn)目的是展示 harness 的核心機(jī)制不是復(fù)刻產(chǎn)品。import os import subprocess TOOLS { read_file: lambda path: open(path, encodingutf-8).read(), bash: lambda cmd: subprocess.run( cmd, shellTrue, capture_outputTrue, textTrue ).stdout, } def call_model(messages: list[dict]) - dict: # 這里通過(guò)任意兼容 OpenAI 協(xié)議的端點(diǎn)調(diào)用模型 # 需要設(shè)置環(huán)境變量 LLM_ENDPOINT 和 LLM_MODEL endpoint os.getenv(LLM_ENDPOINT) model os.getenv(LLM_MODEL) # 省略 HTTP 請(qǐng)求細(xì)節(jié)返回模型的響應(yīng) JSON raise NotImplementedError(用你手頭的模型服務(wù)補(bǔ)全這段) def agent_loop(task: str, max_turns: int 5) - None: messages [{role: user, content: task}] for _ in range(max_turns): resp call_model(messages) tool_calls resp.get(tool_calls) if not tool_calls: print(resp[content]) return for call in tool_calls: name call[function][name] args call[function][arguments] result TOOLS[name](args) # 執(zhí)行工具 messages.append({role: tool, tool_call_id: call[id], content: result}) print(達(dá)到最大輪次停止。)這段骨架里的關(guān)鍵參數(shù)是 max_turns它決定了 agent 不會(huì)因?yàn)槟P头磸?fù)請(qǐng)求工具而進(jìn)入死循環(huán)。TOOLS 字典是工具白名單不加新工具模型就無(wú)法調(diào)用它。實(shí)際運(yùn)行前應(yīng)該把環(huán)境變量配好并確認(rèn) TOOLS 里每個(gè)函數(shù)都能處理異常工具拋錯(cuò)會(huì)直接中斷整個(gè)循環(huán)這是新手最容易翻車(chē)的地方。從這個(gè)骨架再往前邁一步就是權(quán)限確認(rèn)、消息歷史裁剪、工具結(jié)果截?cái)唷C恳徊蕉际窃诮鉀Q真實(shí)場(chǎng)景里的一個(gè)問(wèn)題而不是追逐一份來(lái)路不明的源碼。理解了這些再回頭看“源碼泄露”的標(biāo)題你會(huì)發(fā)現(xiàn)真正該學(xué)的部分從來(lái)不在那個(gè)壓縮包里。6. 一個(gè)具體習(xí)慣拿到任何代碼包先“三查三試”再動(dòng)手把前面五章的思路濃縮成一條可執(zhí)行的習(xí)慣就是三查三試。三查一查包名和版本是否與官方 registry 對(duì)得上二查文件清單里有沒(méi)有不該在發(fā)布包里出現(xiàn)的東西比如源碼目錄、.git、加密提示、安裝腳本外聯(lián)三查解壓后的配置和腳本內(nèi)容重點(diǎn)看 api 地址、密鑰路徑、base64 解碼段。三試一試試在隔離目錄里不用主力工作目錄二試先斷網(wǎng)或最小權(quán)限跑 --help觀察有沒(méi)有意外外聯(lián)三試看日志和進(jìn)程列表確認(rèn)沒(méi)有多余的子進(jìn)程常駐。這個(gè)習(xí)慣在分析任何來(lái)源的第三方包時(shí)都通用不只是 Claude Code。源碼泄露的瓜每年都有但絕大多數(shù)最后都被證偽成引流工具或釣魚(yú)包真正值得投入時(shí)間的是理解一個(gè)成熟 CLI 的發(fā)布形態(tài)和 agent 循環(huán)的骨架設(shè)計(jì)。這些年我養(yǎng)成的習(xí)慣是任何來(lái)路不明的包都不直接進(jìn)工作目錄先解壓到 /tmp 看一眼腳本再?zèng)Q定。這個(gè)習(xí)慣幫我避開(kāi)了很多麻煩不只是挖礦腳本還有各種偽裝成工具包的引流陷阱。希望這篇筆記能幫你在下次看到“完整源碼”標(biāo)題時(shí)先花五分鐘做三查三試而不是被 4 月 1 日的時(shí)間戳帶著走。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取