{"id":603,"date":"2026-02-02T00:29:06","date_gmt":"2026-02-01T16:29:06","guid":{"rendered":"https:\/\/blog.itsmygo.uk\/2026\/02\/02\/claude-code-action-%e5%8e%9f%e5%a7%8b%e7%a2%bc%e8%a7%a3%e8%ae%80%ef%bc%9agithub-action-%e4%b8%ad%e7%9a%84%e9%9b%99%e6%a8%a1%e5%bc%8f%e6%9e%b6%e6%a7%8b%e8%88%87-mcp-%e6%95%b4%e5%90%88%e8%a8%ad%e8%a8%88\/"},"modified":"2026-02-02T00:51:08","modified_gmt":"2026-02-01T16:51:08","slug":"claude-code-action-%e5%8e%9f%e5%a7%8b%e7%a2%bc%e8%a7%a3%e8%ae%80%ef%bc%9agithub-action-%e4%b8%ad%e7%9a%84%e9%9b%99%e6%a8%a1%e5%bc%8f%e6%9e%b6%e6%a7%8b%e8%88%87-mcp-%e6%95%b4%e5%90%88%e8%a8%ad%e8%a8%88","status":"publish","type":"post","link":"https:\/\/blog.itsmygo.uk\/wordpress\/2026\/02\/02\/claude-code-action-%e5%8e%9f%e5%a7%8b%e7%a2%bc%e8%a7%a3%e8%ae%80%ef%bc%9agithub-action-%e4%b8%ad%e7%9a%84%e9%9b%99%e6%a8%a1%e5%bc%8f%e6%9e%b6%e6%a7%8b%e8%88%87-mcp-%e6%95%b4%e5%90%88%e8%a8%ad%e8%a8%88\/","title":{"rendered":"Claude Code Action \u539f\u59cb\u78bc\u89e3\u8b80\uff1aGitHub Action \u4e2d\u7684\u96d9\u6a21\u5f0f\u67b6\u69cb\u8207 MCP \u6574\u5408\u8a2d\u8a08"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Claude Code Action \u662f Anthropic \u5b98\u65b9\u63a8\u51fa\u7684 GitHub Action\uff0c\u8b93 Claude \u80fd\u76f4\u63a5\u5728 PR \u548c Issue \u4e2d\u56de\u7b54\u554f\u984c\u3001\u5be9\u67e5\u7a0b\u5f0f\u78bc\u3001\u5be6\u4f5c\u4fee\u6539\u3002\u9019\u500b\u5c08\u6848\u503c\u5f97\u6df1\u5165\u95b1\u8b80\u7684\u539f\u56e0\u4e0d\u5728\u65bc\u300c\u5982\u4f55\u4f7f\u7528\u300d\uff0c\u800c\u5728\u65bc\u5b83\u5c55\u793a\u4e86\u4e00\u5957\u7cbe\u5de7\u7684\u8a2d\u8a08\uff1a\u5982\u4f55\u5728 GitHub Actions \u7684 composite action \u6846\u67b6\u4e0b\uff0c\u5efa\u69cb\u51fa\u4e00\u500b\u5177\u5099\u667a\u6167\u6a21\u5f0f\u5075\u6e2c\u3001\u591a\u5c64\u5b89\u5168\u9632\u8b77\u3001MCP \u5de5\u5177\u6574\u5408\u7684 AI \u81ea\u52d5\u5316\u7cfb\u7d71\u3002\u8b80\u5b8c\u4f60\u80fd\u5b78\u5230\uff1a\u96d9\u968e\u6bb5\u57f7\u884c\u67b6\u69cb\u7684\u5206\u96e2\u7b56\u7565\u3001Mode \u7cfb\u7d71\u7684 Registry Pattern \u8a2d\u8a08\u3001\u4ee5 MCP Server \u4f5c\u70ba\u5de5\u5177\u908a\u754c\u7684\u6574\u5408\u6a21\u5f0f\u3001\u4ee5\u53ca\u91dd\u5c0d prompt injection \u7684\u591a\u5c64\u9632\u79a6\u6a5f\u5236\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/anthropics\/claude-code-action\">Claude Code Action GitHub Repository<\/a> \u2014 \u5c08\u6848\u539f\u59cb\u78bc\uff0c\u5305\u542b\u672c\u6587\u89e3\u8b80\u7684\u6240\u6709\u8a2d\u8a08\u5be6\u4f5c<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u5c08\u6848\u6982\u89bd<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Claude Code Action \u662f\u4e00\u500b GitHub composite action\uff0c\u4ee5 TypeScript \u64b0\u5beb\uff0c\u4f7f\u7528 Bun \u4f5c\u70ba runtime\u3002\u5c08\u6848\u652f\u63f4\u591a\u7a2e\u8a8d\u8b49\u65b9\u5f0f\uff08Anthropic API\u3001Amazon Bedrock\u3001Google Vertex AI\u3001Microsoft Foundry\uff09\uff0c\u80fd\u56de\u61c9 <code>@claude<\/code> \u63d0\u53ca\u3001Issue \u6307\u6d3e\u3001Label \u89f8\u767c\uff0c\u6216\u900f\u904e prompt \u76f4\u63a5\u9a45\u52d5\u81ea\u52d5\u5316\u5de5\u4f5c\u6d41\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u6280\u8853\u68e7\uff1aTypeScript + Bun\u3001GitHub Actions composite action\u3001MCP\uff08Model Context Protocol\uff09\u3001Claude Agent SDK\u3001Octokit\uff08GitHub REST\/GraphQL\uff09\u3001Zod schema validation\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u67b6\u69cb\u7e3d\u89bd<\/h2>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">claude-code-action\/\n\u251c\u2500\u2500 action.yml                    <span class=\"hljs-comment\"># Composite action \u5b9a\u7fa9\uff0c\u4e32\u63a5\u6240\u6709\u6b65\u9a5f<\/span>\n\u251c\u2500\u2500 src\/\n\u2502   \u251c\u2500\u2500 entrypoints\/              <span class=\"hljs-comment\"># Action \u9032\u5165\u9ede\uff08Phase 1\uff09<\/span>\n\u2502   \u2502   \u251c\u2500\u2500 prepare.ts            <span class=\"hljs-comment\"># \u4e3b\u8981\u6e96\u5099\u908f\u8f2f\uff1a\u8a8d\u8b49\u3001\u9a57\u8b49\u3001\u89f8\u767c\u5075\u6e2c<\/span>\n\u2502   \u2502   \u251c\u2500\u2500 update-comment-link.ts <span class=\"hljs-comment\"># \u57f7\u884c\u5f8c\u66f4\u65b0 comment<\/span>\n\u2502   \u2502   \u251c\u2500\u2500 format-turns.ts       <span class=\"hljs-comment\"># \u5c0d\u8a71\u683c\u5f0f\u5316<\/span>\n\u2502   \u2502   \u251c\u2500\u2500 cleanup-ssh-signing.ts <span class=\"hljs-comment\"># SSH \u91d1\u9470\u6e05\u7406<\/span>\n\u2502   \u2502   \u2514\u2500\u2500 collect-inputs.ts     <span class=\"hljs-comment\"># \u6536\u96c6 action inputs<\/span>\n\u2502   \u251c\u2500\u2500 modes\/                    <span class=\"hljs-comment\"># \u6a21\u5f0f\u7cfb\u7d71<\/span>\n\u2502   \u2502   \u251c\u2500\u2500 detector.ts           <span class=\"hljs-comment\"># \u81ea\u52d5\u6a21\u5f0f\u5075\u6e2c<\/span>\n\u2502   \u2502   \u251c\u2500\u2500 registry.ts           <span class=\"hljs-comment\"># \u6a21\u5f0f\u8a3b\u518a\u8868<\/span>\n\u2502   \u2502   \u251c\u2500\u2500 types.ts              <span class=\"hljs-comment\"># Mode interface \u5b9a\u7fa9<\/span>\n\u2502   \u2502   \u251c\u2500\u2500 tag\/index.ts          <span class=\"hljs-comment\"># Tag \u6a21\u5f0f\u5be6\u4f5c<\/span>\n\u2502   \u2502   \u2514\u2500\u2500 agent\/index.ts        <span class=\"hljs-comment\"># Agent \u6a21\u5f0f\u5be6\u4f5c<\/span>\n\u2502   \u251c\u2500\u2500 github\/                   <span class=\"hljs-comment\"># GitHub \u6574\u5408\u5c64<\/span>\n\u2502   \u2502   \u251c\u2500\u2500 context.ts            <span class=\"hljs-comment\"># \u7d71\u4e00\u7684\u4e8b\u4ef6\u4e0a\u4e0b\u6587\u89e3\u6790<\/span>\n\u2502   \u2502   \u251c\u2500\u2500 token.ts              <span class=\"hljs-comment\"># OIDC token \u4ea4\u63db\u8207\u8a8d\u8b49<\/span>\n\u2502   \u2502   \u251c\u2500\u2500 api\/                  <span class=\"hljs-comment\"># REST\/GraphQL client<\/span>\n\u2502   \u2502   \u251c\u2500\u2500 data\/                 <span class=\"hljs-comment\"># \u8cc7\u6599\u64f7\u53d6\u8207\u683c\u5f0f\u5316<\/span>\n\u2502   \u2502   \u251c\u2500\u2500 validation\/           <span class=\"hljs-comment\"># \u6b0a\u9650\u8207\u89f8\u767c\u9a57\u8b49<\/span>\n\u2502   \u2502   \u251c\u2500\u2500 operations\/           <span class=\"hljs-comment\"># \u5206\u652f\u3001\u7559\u8a00\u3001Git \u64cd\u4f5c<\/span>\n\u2502   \u2502   \u2514\u2500\u2500 utils\/                <span class=\"hljs-comment\"># \u6e05\u6f54\u3001\u5716\u7247\u4e0b\u8f09<\/span>\n\u2502   \u251c\u2500\u2500 mcp\/                      <span class=\"hljs-comment\"># MCP Server \u5be6\u4f5c<\/span>\n\u2502   \u2502   \u251c\u2500\u2500 install-mcp-server.ts <span class=\"hljs-comment\"># MCP \u914d\u7f6e\u7d44\u88dd<\/span>\n\u2502   \u2502   \u251c\u2500\u2500 github-comment-server.ts    <span class=\"hljs-comment\"># \u7559\u8a00\u64cd\u4f5c<\/span>\n\u2502   \u2502   \u251c\u2500\u2500 github-file-ops-server.ts   <span class=\"hljs-comment\"># \u6a94\u6848\u64cd\u4f5c\uff08commit signing\uff09<\/span>\n\u2502   \u2502   \u251c\u2500\u2500 github-actions-server.ts    <span class=\"hljs-comment\"># CI\/CD \u5b58\u53d6<\/span>\n\u2502   \u2502   \u2514\u2500\u2500 github-inline-comment-server.ts <span class=\"hljs-comment\"># PR inline comment<\/span>\n\u2502   \u251c\u2500\u2500 create-prompt\/            <span class=\"hljs-comment\"># Prompt \u751f\u6210<\/span>\n\u2502   \u2514\u2500\u2500 prepare\/                  <span class=\"hljs-comment\"># \u6e96\u5099\u968e\u6bb5\u7de8\u6392<\/span>\n\u251c\u2500\u2500 base-action\/                  <span class=\"hljs-comment\"># Phase 2\uff1aClaude Code \u57f7\u884c\u6838\u5fc3<\/span>\n\u2502   \u2514\u2500\u2500 src\/\n\u2502       \u251c\u2500\u2500 index.ts              <span class=\"hljs-comment\"># base-action \u9032\u5165\u9ede<\/span>\n\u2502       \u251c\u2500\u2500 run-claude-sdk.ts     <span class=\"hljs-comment\"># Claude Agent SDK \u547c\u53eb<\/span>\n\u2502       \u251c\u2500\u2500 run-claude.ts         <span class=\"hljs-comment\"># CLI \u57f7\u884c\u908f\u8f2f<\/span>\n\u2502       \u251c\u2500\u2500 prepare-prompt.ts     <span class=\"hljs-comment\"># Prompt \u6a94\u6848\u8655\u7406<\/span>\n\u2502       \u2514\u2500\u2500 setup-claude-code-settings.ts <span class=\"hljs-comment\"># \u8a2d\u5b9a\u7ba1\u7406<\/span>\n\u2514\u2500\u2500 test\/                         <span class=\"hljs-comment\"># \u6e2c\u8a66<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u6574\u9ad4\u67b6\u69cb\u5206\u70ba\u5169\u500b\u660e\u78ba\u7684\u968e\u6bb5\uff1a<strong>Phase 1\uff08Preparation\uff09<\/strong> \u7531 <code>src\/<\/code> \u8ca0\u8cac\uff0c\u8655\u7406\u8a8d\u8b49\u3001\u9a57\u8b49\u3001\u6a21\u5f0f\u5075\u6e2c\u3001\u4e0a\u4e0b\u6587\u6e96\u5099\u3001MCP \u914d\u7f6e\uff1b<strong>Phase 2\uff08Execution\uff09<\/strong> \u7531 <code>base-action\/<\/code> \u8ca0\u8cac\uff0c\u5be6\u969b\u57f7\u884c Claude Code SDK \u547c\u53eb\u3002\u9019\u7a2e\u5206\u96e2\u8b93 <code>base-action<\/code> \u53ef\u4ee5\u7368\u7acb\u4f5c\u70ba <code>@anthropic-ai\/claude-code-base-action<\/code> \u767c\u5e03\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u6838\u5fc3\u8a2d\u8a08\u89e3\u6790<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\u8a2d\u8a08\u4e00\uff1a\u96d9\u968e\u6bb5\u57f7\u884c\u67b6\u69cb\u2014\u2014Preparation \u8207 Execution \u7684\u89e3\u8026<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u6574\u500b Action \u7684\u57f7\u884c\u900f\u904e <code>action.yml<\/code> \u4e32\u63a5\uff0c\u4f46\u6838\u5fc3\u908f\u8f2f\u88ab\u5207\u5206\u70ba\u5169\u500b\u5b8c\u5168\u7368\u7acb\u7684\u968e\u6bb5\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/anthropics\/claude-code-action\/blob\/main\/action.yml\"><code>action.yml<\/code><\/a> \u2014 Composite action \u5b9a\u7fa9\uff0c\u5b9a\u7fa9\u4e86\u6240\u6709\u6b65\u9a5f\u7684\u4e32\u63a5\u9806\u5e8f\u8207\u74b0\u5883\u8b8a\u6578\u50b3\u905e<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u5728 <code>action.yml<\/code> \u4e2d\u53ef\u4ee5\u770b\u5230\u95dc\u9375\u6b65\u9a5f\uff1a<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">steps:\n  - name: Prepare action\n    <span class=\"hljs-attr\">id<\/span>: prepare\n    <span class=\"hljs-attr\">shell<\/span>: bash\n    <span class=\"hljs-attr\">run<\/span>: bun run ${GITHUB_ACTION_PATH}\/src\/entrypoints\/prepare.ts\n\n  - name: Run Claude Code\n    <span class=\"hljs-attr\">id<\/span>: claude-code\n    <span class=\"hljs-attr\">if<\/span>: steps.prepare.outputs.contains_trigger == <span class=\"hljs-string\">'true'<\/span>\n    <span class=\"hljs-attr\">shell<\/span>: bash\n    <span class=\"hljs-attr\">run<\/span>: bun run ${GITHUB_ACTION_PATH}\/base-action\/src\/index.ts\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Phase 1 \u7684 <code>prepare.ts<\/code> \u8ca0\u8cac\u6240\u6709\u524d\u7f6e\u5de5\u4f5c\u2014\u2014\u5982\u679c\u89f8\u767c\u689d\u4ef6\u4e0d\u6210\u7acb\uff0cPhase 2 \u6839\u672c\u4e0d\u6703\u57f7\u884c\u3002\u5169\u500b\u968e\u6bb5\u4e4b\u9593\u7684\u6e9d\u901a\u5b8c\u5168\u900f\u904e GitHub Actions \u7684 <code>outputs<\/code> \u6a5f\u5236\u548c\u74b0\u5883\u8b8a\u6578\uff0c\u6c92\u6709\u4efb\u4f55 in-process \u7684\u72c0\u614b\u5171\u4eab\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/anthropics\/claude-code-action\/blob\/main\/src\/entrypoints\/prepare.ts\"><code>src\/entrypoints\/prepare.ts<\/code><\/a> \u2014 Phase 1 \u9032\u5165\u9ede\uff0c\u7de8\u6392\u8a8d\u8b49\u3001\u9a57\u8b49\u3001\u6a21\u5f0f\u5075\u6e2c\u7684\u5b8c\u6574\u6d41\u7a0b<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">run<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  collectActionInputsPresence();\n  <span class=\"hljs-keyword\">const<\/span> context = parseGitHubContext();\n  <span class=\"hljs-keyword\">const<\/span> mode = getMode(context);\n  <span class=\"hljs-keyword\">const<\/span> githubToken = <span class=\"hljs-keyword\">await<\/span> setupGitHubToken();\n  <span class=\"hljs-keyword\">const<\/span> octokit = createOctokit(githubToken);\n\n  <span class=\"hljs-keyword\">if<\/span> (isEntityContext(context)) {\n    <span class=\"hljs-keyword\">const<\/span> hasWritePermissions = <span class=\"hljs-keyword\">await<\/span> checkWritePermissions(\n      octokit.rest, context, context.inputs.allowedNonWriteUsers, githubTokenProvided,\n    );\n    <span class=\"hljs-keyword\">if<\/span> (!hasWritePermissions) {\n      <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Error<\/span>(<span class=\"hljs-string\">\"Actor does not have write permissions to the repository\"<\/span>);\n    }\n  }\n\n  <span class=\"hljs-keyword\">const<\/span> containsTrigger = mode.shouldTrigger(context);\n  core.setOutput(<span class=\"hljs-string\">\"contains_trigger\"<\/span>, containsTrigger.toString());\n\n  <span class=\"hljs-keyword\">if<\/span> (!containsTrigger) {\n    <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">\"No trigger found, skipping remaining steps\"<\/span>);\n    <span class=\"hljs-keyword\">return<\/span>;\n  }\n\n  <span class=\"hljs-keyword\">const<\/span> result = <span class=\"hljs-keyword\">await<\/span> prepare({ context, octokit, mode, githubToken });\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u9019\u500b\u8a2d\u8a08\u7684\u597d\u8655\u662f\uff1aPhase 1 \u53ef\u4ee5\u5feb\u901f fail-fast\uff08\u4e0d\u7b26\u5408\u89f8\u767c\u689d\u4ef6\u5c31\u7d50\u675f\uff09\uff0cPhase 2 \u7684 <code>base-action<\/code> \u53ef\u4ee5\u88ab\u5176\u4ed6 action \u7368\u7acb\u4f7f\u7528\uff0c\u800c\u4e14\u5169\u500b\u968e\u6bb5\u7684\u6e2c\u8a66\u53ef\u4ee5\u5b8c\u5168\u7368\u7acb\u9032\u884c\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u8a2d\u8a08\u4e8c\uff1aMode \u7cfb\u7d71\u2014\u2014Registry Pattern \u8207\u7b56\u7565\u6a21\u5f0f<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u5c08\u6848\u5b9a\u7fa9\u4e86\u4e00\u500b\u6e05\u6670\u7684 <code>Mode<\/code> interface\uff0c\u6bcf\u500b\u6a21\u5f0f\u81ea\u884c\u6c7a\u5b9a\u89f8\u767c\u689d\u4ef6\u3001prompt \u751f\u6210\u3001\u5de5\u5177\u914d\u7f6e\u7b49\u884c\u70ba\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/anthropics\/claude-code-action\/blob\/main\/src\/modes\/types.ts\"><code>src\/modes\/types.ts<\/code><\/a> \u2014 Mode interface \u5b9a\u7fa9\uff0c\u898f\u7bc4\u4e86\u6bcf\u500b\u6a21\u5f0f\u5fc5\u9808\u5be6\u4f5c\u7684\u65b9\u6cd5\u5951\u7d04<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">export<\/span> type Mode = {\n  <span class=\"hljs-attr\">name<\/span>: ModeName;\n  description: string;\n  shouldTrigger(context: GitHubContext): boolean;\n  prepareContext(context: GitHubContext, data?: ModeData): ModeContext;\n  getAllowedTools(): string&#91;];\n  getDisallowedTools(): string&#91;];\n  shouldCreateTrackingComment(): boolean;\n  generatePrompt(context: PreparedContext, <span class=\"hljs-attr\">githubData<\/span>: FetchDataResult, <span class=\"hljs-attr\">useCommitSigning<\/span>: boolean): string;\n  prepare(options: ModeOptions): <span class=\"hljs-built_in\">Promise<\/span>&lt;ModeResult&gt;;\n  getSystemPrompt?(context: ModeContext): string | <span class=\"hljs-literal\">undefined<\/span>;\n};\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u9019\u500b interface \u7684\u8a2d\u8a08\u628a\u300c\u662f\u5426\u89f8\u767c\u300d\u3001\u300c\u5982\u4f55\u6e96\u5099\u74b0\u5883\u300d\u3001\u300c\u751f\u6210\u4ec0\u9ebc prompt\u300d\u3001\u300c\u5141\u8a31\u4ec0\u9ebc\u5de5\u5177\u300d\u5168\u90e8\u5c01\u88dd\u5728\u6a21\u5f0f\u5167\u90e8\uff0c\u5916\u90e8\u4ee3\u78bc\u53ea\u9700\u8981\u62ff\u5230 mode \u7269\u4ef6\u5c31\u80fd\u57f7\u884c\u5b8c\u6574\u6d41\u7a0b\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/anthropics\/claude-code-action\/blob\/main\/src\/modes\/registry.ts\"><code>src\/modes\/registry.ts<\/code><\/a> \u2014 \u6a21\u5f0f\u8a3b\u518a\u8868\uff0c\u8ca0\u8cac\u6839\u64da context \u81ea\u52d5\u9078\u64c7\u6b63\u78ba\u7684\u6a21\u5f0f<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">const<\/span> modes = {\n  <span class=\"hljs-attr\">tag<\/span>: tagMode,\n  <span class=\"hljs-attr\">agent<\/span>: agentMode,\n} <span class=\"hljs-keyword\">as<\/span> <span class=\"hljs-keyword\">const<\/span> satisfies Record&lt;AutoDetectedMode, Mode&gt;;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getMode<\/span>(<span class=\"hljs-params\">context: GitHubContext<\/span>): <span class=\"hljs-title\">Mode<\/span> <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> modeName = detectMode(context);\n  <span class=\"hljs-keyword\">const<\/span> mode = modes&#91;modeName];\n  <span class=\"hljs-keyword\">if<\/span> (!mode) {\n    <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Error<\/span>(<span class=\"hljs-string\">`Mode '<span class=\"hljs-subst\">${modeName}<\/span>' not found.`<\/span>);\n  }\n  <span class=\"hljs-keyword\">return<\/span> mode;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Registry \u4f7f\u7528 <code>as const satisfies Record&lt;AutoDetectedMode, Mode&gt;<\/code> \u78ba\u4fdd\u578b\u5225\u5b89\u5168\u2014\u2014\u6bcf\u500b <code>AutoDetectedMode<\/code> \u90fd\u5fc5\u9808\u6709\u5c0d\u61c9\u7684 Mode \u5be6\u4f5c\uff0c\u7de8\u8b6f\u5668\u6703\u5f37\u5236\u6aa2\u67e5\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u8a2d\u8a08\u4e09\uff1a\u667a\u6167\u6a21\u5f0f\u5075\u6e2c\u2014\u2014\u5f9e GitHub \u4e8b\u4ef6\u63a8\u5c0e\u57f7\u884c\u7b56\u7565<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><code>detector.ts<\/code> \u5be6\u4f5c\u4e86\u4e00\u5957\u57fa\u65bc GitHub \u4e8b\u4ef6\u985e\u578b\u548c\u4f7f\u7528\u8005\u914d\u7f6e\u7684\u81ea\u52d5\u5075\u6e2c\u908f\u8f2f\uff0c\u4f7f\u7528\u8005\u4e0d\u9700\u8981\u624b\u52d5\u6307\u5b9a\u6a21\u5f0f\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/anthropics\/claude-code-action\/blob\/main\/src\/modes\/detector.ts\"><code>src\/modes\/detector.ts<\/code><\/a> \u2014 \u6a21\u5f0f\u5075\u6e2c\u5668\uff0c\u6839\u64da\u4e8b\u4ef6\u985e\u578b\u548c\u914d\u7f6e\u81ea\u52d5\u9078\u64c7 tag \u6216 agent \u6a21\u5f0f<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">detectMode<\/span>(<span class=\"hljs-params\">context: GitHubContext<\/span>): <span class=\"hljs-title\">AutoDetectedMode<\/span> <\/span>{\n  <span class=\"hljs-keyword\">if<\/span> (context.inputs.trackProgress) {\n    validateTrackProgressEvent(context);\n  }\n\n  <span class=\"hljs-comment\">\/\/ \u5982\u679c\u8a2d\u5b9a\u4e86 track_progress\uff0c\u5f37\u5236\u4f7f\u7528 tag \u6a21\u5f0f<\/span>\n  <span class=\"hljs-keyword\">if<\/span> (context.inputs.trackProgress &amp;&amp; isEntityContext(context)) {\n    <span class=\"hljs-keyword\">if<\/span> (isPullRequestEvent(context) || isIssuesEvent(context) || ...) {\n      <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-string\">\"tag\"<\/span>;\n    }\n  }\n\n  <span class=\"hljs-comment\">\/\/ Comment \u4e8b\u4ef6\uff1a\u6709 prompt \u5c31\u7528 agent\uff0c\u6709 @claude \u5c31\u7528 tag<\/span>\n  <span class=\"hljs-keyword\">if<\/span> (isEntityContext(context)) {\n    <span class=\"hljs-keyword\">if<\/span> (isIssueCommentEvent(context) || isPullRequestReviewCommentEvent(context) || ...) {\n      <span class=\"hljs-keyword\">if<\/span> (context.inputs.prompt) <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-string\">\"agent\"<\/span>;\n      <span class=\"hljs-keyword\">if<\/span> (checkContainsTrigger(context)) <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-string\">\"tag\"<\/span>;\n    }\n  }\n\n  <span class=\"hljs-comment\">\/\/ \u9810\u8a2d\u56de\u5230 agent \u6a21\u5f0f<\/span>\n  <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-string\">\"agent\"<\/span>;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u5075\u6e2c\u908f\u8f2f\u7684\u6838\u5fc3\u601d\u8def\u662f\uff1a<strong>\u6709\u660e\u78ba prompt \u5c31\u7528 agent\uff08\u81ea\u52d5\u5316\uff09\uff0c\u6709 @claude \u63d0\u53ca\u5c31\u7528 tag\uff08\u4e92\u52d5\u5f0f\uff09<\/strong>\u3002\u9019\u7a2e\u300cconvention over configuration\u300d\u7684\u8a2d\u8a08\u8b93\u4f7f\u7528\u8005\u5e7e\u4e4e\u4e0d\u9700\u8981\u7406\u89e3\u6a21\u5f0f\u7cfb\u7d71\u5c31\u80fd\u6b63\u78ba\u4f7f\u7528\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u8a2d\u8a08\u56db\uff1aDiscriminated Union \u578b\u5225\u7cfb\u7d71\u2014\u2014\u7d71\u4e00\u7684 GitHub \u4e8b\u4ef6\u8655\u7406<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><code>context.ts<\/code> \u4f7f\u7528 TypeScript \u7684 discriminated union \u628a\u6240\u6709 GitHub \u4e8b\u4ef6\u985e\u578b\u7d71\u4e00\u70ba\u4e00\u500b <code>GitHubContext<\/code> \u578b\u5225\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/anthropics\/claude-code-action\/blob\/main\/src\/github\/context.ts\"><code>src\/github\/context.ts<\/code><\/a> \u2014 GitHub \u4e0a\u4e0b\u6587\u89e3\u6790\uff0c\u5c07\u4e0d\u540c\u4e8b\u4ef6\u985e\u578b\u7d71\u4e00\u70ba\u578b\u5225\u5b89\u5168\u7684\u8cc7\u6599\u7d50\u69cb<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">type EntityEventName = <span class=\"hljs-string\">\"issues\"<\/span> | <span class=\"hljs-string\">\"issue_comment\"<\/span> | <span class=\"hljs-string\">\"pull_request\"<\/span>\n  | <span class=\"hljs-string\">\"pull_request_review\"<\/span> | <span class=\"hljs-string\">\"pull_request_review_comment\"<\/span>;\ntype AutomationEventName = <span class=\"hljs-string\">\"workflow_dispatch\"<\/span> | <span class=\"hljs-string\">\"repository_dispatch\"<\/span>\n  | <span class=\"hljs-string\">\"schedule\"<\/span> | <span class=\"hljs-string\">\"workflow_run\"<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> type ParsedGitHubContext = BaseContext &amp; {\n  <span class=\"hljs-attr\">eventName<\/span>: EntityEventName;\n  payload: IssuesEvent | IssueCommentEvent | PullRequestEvent | ...;\n  entityNumber: number;\n  isPR: boolean;\n};\n\n<span class=\"hljs-keyword\">export<\/span> type AutomationContext = BaseContext &amp; {\n  <span class=\"hljs-attr\">eventName<\/span>: AutomationEventName;\n  payload: WorkflowDispatchEvent | RepositoryDispatchEvent | ...;\n};\n\n<span class=\"hljs-keyword\">export<\/span> type GitHubContext = ParsedGitHubContext | AutomationContext;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u642d\u914d\u4e00\u7cfb\u5217 type guard \u51fd\u5f0f\uff1a<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">isEntityContext<\/span>(<span class=\"hljs-params\">context: GitHubContext<\/span>): <span class=\"hljs-title\">context<\/span> <span class=\"hljs-title\">is<\/span> <span class=\"hljs-title\">ParsedGitHubContext<\/span> <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> ENTITY_EVENT_NAMES.includes(context.eventName <span class=\"hljs-keyword\">as<\/span> EntityEventName);\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">isIssueCommentEvent<\/span>(<span class=\"hljs-params\">context: GitHubContext<\/span>):\n  <span class=\"hljs-title\">context<\/span> <span class=\"hljs-title\">is<\/span> <span class=\"hljs-title\">ParsedGitHubContext<\/span> &amp; <\/span>{ payload: IssueCommentEvent } {\n  <span class=\"hljs-keyword\">return<\/span> context.eventName === <span class=\"hljs-string\">\"issue_comment\"<\/span>;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u9019\u500b\u8a2d\u8a08\u8b93 TypeScript \u7de8\u8b6f\u5668\u80fd\u5728 type guard \u5f8c\u81ea\u52d5\u6536\u7a84\u578b\u5225\uff0c\u6240\u6709\u5c0d <code>payload<\/code> \u7684\u5b58\u53d6\u90fd\u662f\u578b\u5225\u5b89\u5168\u7684\u3002\u4e0d\u9700\u8981 <code>as<\/code> \u5f37\u5236\u8f49\u578b\uff0c\u6d88\u9664\u4e86 runtime \u578b\u5225\u932f\u8aa4\u7684\u53ef\u80fd\u6027\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u8a2d\u8a08\u4e94\uff1aMCP Server \u4f5c\u70ba\u5de5\u5177\u908a\u754c\u2014\u2014\u6309\u9700\u7d44\u88dd\u7684\u80fd\u529b\u914d\u7f6e<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u5c08\u6848\u6c92\u6709\u7d66 Claude \u7121\u9650\u5236\u7684\u5de5\u5177\u5b58\u53d6\u6b0a\uff0c\u800c\u662f\u900f\u904e\u591a\u500b MCP Server \u7cbe\u78ba\u63a7\u5236\u6bcf\u500b\u80fd\u529b\u908a\u754c\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/anthropics\/claude-code-action\/blob\/main\/src\/mcp\/install-mcp-server.ts\"><code>src\/mcp\/install-mcp-server.ts<\/code><\/a> \u2014 MCP \u914d\u7f6e\u7d44\u88dd\u5668\uff0c\u6839\u64da\u6a21\u5f0f\u548c\u6b0a\u9650\u52d5\u614b\u6c7a\u5b9a\u555f\u7528\u54ea\u4e9b MCP Server<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">prepareMcpConfig<\/span>(<span class=\"hljs-params\">params: PrepareConfigParams<\/span>): <span class=\"hljs-title\">Promise<\/span>&lt;<span class=\"hljs-title\">string<\/span>&gt; <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> baseMcpConfig: { <span class=\"hljs-attr\">mcpServers<\/span>: Record&lt;string, unknown&gt; } = { <span class=\"hljs-attr\">mcpServers<\/span>: {} };\n\n  <span class=\"hljs-comment\">\/\/ Comment server\uff1atag \u6a21\u5f0f\u5fc5\u5099\uff0cagent \u6a21\u5f0f\u53ea\u5728\u660e\u78ba\u8981\u6c42\u6642\u555f\u7528<\/span>\n  <span class=\"hljs-keyword\">const<\/span> shouldIncludeCommentServer = !isAgentMode || hasGitHubCommentTools;\n  <span class=\"hljs-keyword\">if<\/span> (shouldIncludeCommentServer) {\n    baseMcpConfig.mcpServers.github_comment = { <span class=\"hljs-comment\">\/* ... *\/<\/span> };\n  }\n\n  <span class=\"hljs-comment\">\/\/ File ops server\uff1a\u53ea\u6709\u555f\u7528 commit signing \u6642\u624d\u555f\u7528<\/span>\n  <span class=\"hljs-keyword\">if<\/span> (context.inputs.useCommitSigning) {\n    baseMcpConfig.mcpServers.github_file_ops = { <span class=\"hljs-comment\">\/* ... *\/<\/span> };\n  }\n\n  <span class=\"hljs-comment\">\/\/ Inline comment server\uff1a\u53ea\u5c0d PR \u4e14\u660e\u78ba\u8981\u6c42\u6642\u555f\u7528<\/span>\n  <span class=\"hljs-keyword\">if<\/span> (isEntityContext(context) &amp;&amp; context.isPR &amp;&amp; (hasGitHubMcpTools || hasInlineCommentTools)) {\n    baseMcpConfig.mcpServers.github_inline_comment = { <span class=\"hljs-comment\">\/* ... *\/<\/span> };\n  }\n\n  <span class=\"hljs-comment\">\/\/ CI server\uff1a\u9700\u8981\u984d\u5916\u6b0a\u9650\u6aa2\u67e5<\/span>\n  <span class=\"hljs-keyword\">if<\/span> (shouldIncludeCIServer) {\n    <span class=\"hljs-keyword\">const<\/span> actuallyHasPermission = <span class=\"hljs-keyword\">await<\/span> checkActionsReadPermission(\n      process.env.DEFAULT_WORKFLOW_TOKEN || <span class=\"hljs-string\">\"\"<\/span>, owner, repo\n    );\n    <span class=\"hljs-keyword\">if<\/span> (actuallyHasPermission) {\n      baseMcpConfig.mcpServers.github_ci = { <span class=\"hljs-comment\">\/* ... *\/<\/span> };\n    }\n  }\n\n  <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-built_in\">JSON<\/span>.stringify(baseMcpConfig, <span class=\"hljs-literal\">null<\/span>, <span class=\"hljs-number\">2<\/span>);\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u6bcf\u500b MCP Server \u90fd\u662f\u7368\u7acb\u7684 process\uff08\u900f\u904e <code>command: \"bun\"<\/code> \u555f\u52d5\uff09\uff0c\u6709\u81ea\u5df1\u7684\u74b0\u5883\u8b8a\u6578\u548c\u6b0a\u9650\u7bc4\u570d\u3002\u9019\u7a2e\u8a2d\u8a08\u8b93\u5b89\u5168\u908a\u754c\u975e\u5e38\u6e05\u6670\uff1aClaude \u53ea\u80fd\u900f\u904e MCP \u5de5\u5177\u5b58\u53d6\u88ab\u6388\u6b0a\u7684 GitHub \u64cd\u4f5c\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u8a2d\u8a08\u516d\uff1a\u591a\u5c64\u5b89\u5168\u9632\u8b77\u2014\u2014\u5f9e Actor \u5230 Content \u7684\u5168\u65b9\u4f4d\u9632\u79a6<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u5b89\u5168\u8a2d\u8a08\u8cab\u7a7f\u6574\u500b codebase\uff0c\u5f9e\u89f8\u767c\u8005\u8eab\u4efd\u5230\u5167\u5bb9\u6e05\u6f54\uff0c\u5f62\u6210\u591a\u5c64\u9632\u79a6\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u7b2c\u4e00\u5c64\uff1aActor \u9a57\u8b49<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/anthropics\/claude-code-action\/blob\/main\/src\/github\/validation\/actor.ts\"><code>src\/github\/validation\/actor.ts<\/code><\/a> \u2014 \u78ba\u4fdd\u89f8\u767c\u8005\u662f\u4eba\u985e\uff0c\u9632\u6b62 bot \u89f8\u767c\u7121\u9650\u8ff4\u5708<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">checkHumanActor<\/span>(<span class=\"hljs-params\">octokit: Octokit, githubContext: GitHubContext<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> { <span class=\"hljs-attr\">data<\/span>: userData } = <span class=\"hljs-keyword\">await<\/span> octokit.users.getByUsername({\n    <span class=\"hljs-attr\">username<\/span>: githubContext.actor,\n  });\n\n  <span class=\"hljs-keyword\">if<\/span> (actorType !== <span class=\"hljs-string\">\"User\"<\/span>) {\n    <span class=\"hljs-keyword\">const<\/span> allowedBots = githubContext.inputs.allowedBots;\n    <span class=\"hljs-keyword\">if<\/span> (allowedBots.trim() === <span class=\"hljs-string\">\"*\"<\/span>) <span class=\"hljs-keyword\">return<\/span>;  <span class=\"hljs-comment\">\/\/ \u5141\u8a31\u6240\u6709 bot<\/span>\n    <span class=\"hljs-comment\">\/\/ \u6aa2\u67e5\u7279\u5b9a bot \u767d\u540d\u55ae...<\/span>\n    <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Error<\/span>(<span class=\"hljs-string\">`Workflow initiated by non-human actor: <span class=\"hljs-subst\">${botName}<\/span>`<\/span>);\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u7b2c\u4e8c\u5c64\uff1a\u6b0a\u9650\u9a57\u8b49<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/anthropics\/claude-code-action\/blob\/main\/src\/github\/validation\/permissions.ts\"><code>src\/github\/validation\/permissions.ts<\/code><\/a> \u2014 \u78ba\u4fdd\u89f8\u767c\u8005\u6709\u5009\u5eab\u5beb\u5165\u6b0a\u9650<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">checkWritePermissions<\/span>(<span class=\"hljs-params\">\n  octokit: Octokit, context: ParsedGitHubContext,\n  allowedNonWriteUsers?: string, githubTokenProvided?: boolean\n<\/span>): <span class=\"hljs-title\">Promise<\/span>&lt;<span class=\"hljs-title\">boolean<\/span>&gt; <\/span>{\n  <span class=\"hljs-comment\">\/\/ \u5982\u679c\u8a2d\u5b9a\u4e86 allowedNonWriteUsers \u4e14\u63d0\u4f9b\u4e86\u81ea\u8a02 token\uff0c\u53ef\u4ee5\u7e5e\u904e<\/span>\n  <span class=\"hljs-keyword\">if<\/span> (allowedNonWriteUsers &amp;&amp; githubTokenProvided) {\n    core.warning(<span class=\"hljs-string\">`SECURITY WARNING: Bypassing write permission check...`<\/span>);\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-literal\">true<\/span>;\n  }\n\n  <span class=\"hljs-keyword\">const<\/span> response = <span class=\"hljs-keyword\">await<\/span> octokit.repos.getCollaboratorPermissionLevel({\n    <span class=\"hljs-attr\">owner<\/span>: repository.owner, <span class=\"hljs-attr\">repo<\/span>: repository.repo, <span class=\"hljs-attr\">username<\/span>: actor\n  });\n  <span class=\"hljs-keyword\">return<\/span> permissionLevel === <span class=\"hljs-string\">\"admin\"<\/span> || permissionLevel === <span class=\"hljs-string\">\"write\"<\/span>;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u7b2c\u4e09\u5c64\uff1a\u6642\u9593\u7a97\u53e3\u9632\u8b77<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/anthropics\/claude-code-action\/blob\/main\/src\/github\/data\/fetcher.ts\"><code>src\/github\/data\/fetcher.ts<\/code><\/a> \u2014 TOCTOU \u653b\u64ca\u9632\u79a6\uff0c\u904e\u6ffe\u89f8\u767c\u6642\u9593\u9ede\u4e4b\u5f8c\u88ab\u4fee\u6539\u7684\u5167\u5bb9<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">filterCommentsToTriggerTime<\/span>&lt;\n  <span class=\"hljs-title\">T<\/span> <span class=\"hljs-title\">extends<\/span> <\/span>{ createdAt: string; updatedAt?: string; lastEditedAt?: string }\n&gt;(comments: T&#91;], <span class=\"hljs-attr\">triggerTime<\/span>: string | <span class=\"hljs-literal\">undefined<\/span>): T&#91;] {\n  <span class=\"hljs-keyword\">if<\/span> (!triggerTime) <span class=\"hljs-keyword\">return<\/span> comments;\n  <span class=\"hljs-keyword\">const<\/span> triggerTimestamp = <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Date<\/span>(triggerTime).getTime();\n\n  <span class=\"hljs-keyword\">return<\/span> comments.filter(<span class=\"hljs-function\">(<span class=\"hljs-params\">comment<\/span>) =&gt;<\/span> {\n    <span class=\"hljs-keyword\">const<\/span> createdTimestamp = <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Date<\/span>(comment.createdAt).getTime();\n    <span class=\"hljs-keyword\">if<\/span> (createdTimestamp &gt;= triggerTimestamp) <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-literal\">false<\/span>;\n\n    <span class=\"hljs-keyword\">const<\/span> lastEditTime = comment.lastEditedAt || comment.updatedAt;\n    <span class=\"hljs-keyword\">if<\/span> (lastEditTime) {\n      <span class=\"hljs-keyword\">const<\/span> lastEditTimestamp = <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Date<\/span>(lastEditTime).getTime();\n      <span class=\"hljs-keyword\">if<\/span> (lastEditTimestamp &gt;= triggerTimestamp) <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-literal\">false<\/span>;\n    }\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-literal\">true<\/span>;\n  });\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u9019\u662f\u4e00\u500b\u7cbe\u5de7\u7684 TOCTOU\uff08Time-of-Check-Time-of-Use\uff09\u9632\u79a6\uff1a\u5982\u679c\u653b\u64ca\u8005\u5728\u89f8\u767c Claude \u4e4b\u5f8c\u4fee\u6539\u4e86\u7559\u8a00\u6216 Issue body\uff0c\u9019\u4e9b\u4fee\u6539\u904e\u7684\u5167\u5bb9\u6703\u88ab\u6392\u9664\uff0c\u9632\u6b62\u6ce8\u5165\u60e1\u610f\u6307\u4ee4\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u7b2c\u56db\u5c64\uff1a\u5167\u5bb9\u6e05\u6f54<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/anthropics\/claude-code-action\/blob\/main\/src\/github\/utils\/sanitizer.ts\"><code>src\/github\/utils\/sanitizer.ts<\/code><\/a> \u2014 \u591a\u5c64\u5167\u5bb9\u6e05\u6f54\uff0c\u9632\u6b62\u96b1\u5f62\u5b57\u5143\u548c prompt injection<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">sanitizeContent<\/span>(<span class=\"hljs-params\">content: string<\/span>): <span class=\"hljs-title\">string<\/span> <\/span>{\n  content = stripHtmlComments(content);          <span class=\"hljs-comment\">\/\/ \u79fb\u9664 HTML \u8a3b\u89e3\uff08\u5e38\u898b\u6ce8\u5165\u5411\u91cf\uff09<\/span>\n  content = stripInvisibleCharacters(content);    <span class=\"hljs-comment\">\/\/ \u79fb\u9664\u96f6\u5bec\u5b57\u5143<\/span>\n  content = stripMarkdownImageAltText(content);   <span class=\"hljs-comment\">\/\/ \u6e05\u9664\u5716\u7247 alt text<\/span>\n  content = stripMarkdownLinkTitles(content);     <span class=\"hljs-comment\">\/\/ \u6e05\u9664\u9023\u7d50 title<\/span>\n  content = stripHiddenAttributes(content);       <span class=\"hljs-comment\">\/\/ \u6e05\u9664 data-* \u7b49\u96b1\u85cf\u5c6c\u6027<\/span>\n  content = normalizeHtmlEntities(content);       <span class=\"hljs-comment\">\/\/ \u6b63\u898f\u5316 HTML entities<\/span>\n  content = redactGitHubTokens(content);          <span class=\"hljs-comment\">\/\/ \u906e\u853d GitHub tokens<\/span>\n  <span class=\"hljs-keyword\">return<\/span> content;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u7b2c\u4e94\u5c64\uff1a\u5206\u652f\u540d\u7a31\u9a57\u8b49<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/anthropics\/claude-code-action\/blob\/main\/src\/github\/operations\/branch.ts\"><code>src\/github\/operations\/branch.ts<\/code><\/a> \u2014 \u56b4\u683c\u7684\u5206\u652f\u540d\u7a31\u767d\u540d\u55ae\u9a57\u8b49\uff0c\u9632\u6b62 command injection<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">validateBranchName<\/span>(<span class=\"hljs-params\">branchName: string<\/span>): <span class=\"hljs-title\">void<\/span> <\/span>{\n  <span class=\"hljs-keyword\">if<\/span> (branchName.startsWith(<span class=\"hljs-string\">\"-\"<\/span>)) {\n    <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Error<\/span>(<span class=\"hljs-string\">`Branch names cannot start with a dash.`<\/span>);  <span class=\"hljs-comment\">\/\/ \u9632\u6b62 option injection<\/span>\n  }\n  <span class=\"hljs-keyword\">if<\/span> (<span class=\"hljs-regexp\">\/&#91;\\x00-\\x1F\\x7F ~^:?*&#91;\\]\\\\]\/<\/span>.test(branchName)) {\n    <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Error<\/span>(<span class=\"hljs-string\">`Branch names cannot contain control characters...`<\/span>);\n  }\n  <span class=\"hljs-keyword\">const<\/span> validPattern = <span class=\"hljs-regexp\">\/^&#91;a-zA-Z0-9]&#91;a-zA-Z0-9\/_.-]*$\/<\/span>;\n  <span class=\"hljs-keyword\">if<\/span> (!validPattern.test(branchName)) {\n    <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Error<\/span>(<span class=\"hljs-string\">`Branch names must start with alphanumeric...`<\/span>);\n  }\n  <span class=\"hljs-comment\">\/\/ \u9084\u6709\u66f4\u591a\u6aa2\u67e5\uff1a..\u3001.lock\u3001@{\u3001\u9023\u7e8c \/\/...<\/span>\n}\n\n<span class=\"hljs-comment\">\/\/ \u4f7f\u7528 execFileSync \u800c\u975e shell \u57f7\u884c git \u547d\u4ee4<\/span>\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">execGit<\/span>(<span class=\"hljs-params\">args: string&#91;]<\/span>): <span class=\"hljs-title\">void<\/span> <\/span>{\n  execFileSync(<span class=\"hljs-string\">\"git\"<\/span>, args, { <span class=\"hljs-attr\">stdio<\/span>: <span class=\"hljs-string\">\"inherit\"<\/span> });\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u6ce8\u610f <code>execFileSync<\/code> \u7684\u4f7f\u7528\u2014\u2014\u5b83\u76f4\u63a5\u5c07\u53c3\u6578\u50b3\u7d66 git binary\uff0c\u4e0d\u7d93\u904e shell \u89e3\u6790\uff0c\u5f9e\u6839\u672c\u4e0a\u9632\u6b62\u4e86 command injection\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u8a2d\u8a08\u4e03\uff1aTag \u6a21\u5f0f vs Agent \u6a21\u5f0f\u2014\u2014\u5169\u7a2e\u622a\u7136\u4e0d\u540c\u7684\u57f7\u884c\u7b56\u7565<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u5169\u7a2e\u6a21\u5f0f\u5728\u884c\u70ba\u4e0a\u6709\u6839\u672c\u5dee\u7570\uff0c\u9ad4\u73fe\u5728\u5de5\u5177\u914d\u7f6e\u3001prompt \u751f\u6210\u3001\u5206\u652f\u7ba1\u7406\u7b49\u591a\u500b\u9762\u5411\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/anthropics\/claude-code-action\/blob\/main\/src\/modes\/tag\/index.ts\"><code>src\/modes\/tag\/index.ts<\/code><\/a> \u2014 Tag \u6a21\u5f0f\u5be6\u4f5c\uff0c\u5b8c\u6574\u7684\u4e92\u52d5\u5f0f\u5de5\u4f5c\u6d41\uff0c\u5305\u542b tracking comment\u3001\u5206\u652f\u7ba1\u7406\u3001\u7cbe\u78ba\u7684\u5de5\u5177\u767d\u540d\u55ae<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Tag \u6a21\u5f0f\u7684\u5de5\u5177\u914d\u7f6e\u662f\u767d\u540d\u55ae\u5236\uff1a<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">const<\/span> tagModeTools = &#91;\n  <span class=\"hljs-string\">\"Edit\"<\/span>, <span class=\"hljs-string\">\"MultiEdit\"<\/span>, <span class=\"hljs-string\">\"Glob\"<\/span>, <span class=\"hljs-string\">\"Grep\"<\/span>, <span class=\"hljs-string\">\"LS\"<\/span>, <span class=\"hljs-string\">\"Read\"<\/span>, <span class=\"hljs-string\">\"Write\"<\/span>,\n  <span class=\"hljs-string\">\"mcp__github_comment__update_claude_comment\"<\/span>,\n  <span class=\"hljs-string\">\"mcp__github_ci__get_ci_status\"<\/span>,\n  <span class=\"hljs-string\">\"mcp__github_ci__get_workflow_run_details\"<\/span>,\n  <span class=\"hljs-string\">\"mcp__github_ci__download_job_log\"<\/span>,\n  ...userAllowedMCPTools,\n];\n\n<span class=\"hljs-comment\">\/\/ \u6839\u64da commit signing \u7b56\u7565\u52a0\u5165\u4e0d\u540c\u5de5\u5177<\/span>\n<span class=\"hljs-keyword\">if<\/span> (!useApiCommitSigning) {\n  tagModeTools.push(\n    <span class=\"hljs-string\">\"Bash(git add:*)\"<\/span>, <span class=\"hljs-string\">\"Bash(git commit:*)\"<\/span>, <span class=\"hljs-string\">\"Bash(git push:*)\"<\/span>,\n    <span class=\"hljs-string\">\"Bash(git status:*)\"<\/span>, <span class=\"hljs-string\">\"Bash(git diff:*)\"<\/span>, <span class=\"hljs-string\">\"Bash(git log:*)\"<\/span>, <span class=\"hljs-string\">\"Bash(git rm:*)\"<\/span>,\n  );\n} <span class=\"hljs-keyword\">else<\/span> {\n  tagModeTools.push(\n    <span class=\"hljs-string\">\"mcp__github_file_ops__commit_files\"<\/span>,\n    <span class=\"hljs-string\">\"mcp__github_file_ops__delete_files\"<\/span>,\n  );\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u503c\u5f97\u6ce8\u610f\u7684\u662f <code>Bash(git add:*)<\/code> \u9019\u7a2e\u8a9e\u6cd5\u2014\u2014\u5b83\u53ea\u5141\u8a31 Claude \u57f7\u884c\u7279\u5b9a\u7684 git \u5b50\u547d\u4ee4\uff0c\u800c\u975e\u4efb\u610f Bash \u547d\u4ee4\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/anthropics\/claude-code-action\/blob\/main\/src\/modes\/agent\/index.ts\"><code>src\/modes\/agent\/index.ts<\/code><\/a> \u2014 Agent \u6a21\u5f0f\u5be6\u4f5c\uff0c\u7c21\u6f54\u7684\u81ea\u52d5\u5316\u6a21\u5f0f\uff0c\u76f4\u63a5\u4f7f\u7528\u4f7f\u7528\u8005\u7684 prompt<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Agent \u6a21\u5f0f\u5247\u66f4\u70ba\u7c21\u6f54\uff1a<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> agentMode: Mode = {\n  <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">\"agent\"<\/span>,\n  shouldTrigger(context) {\n    <span class=\"hljs-keyword\">return<\/span> !!context.inputs?.prompt;  <span class=\"hljs-comment\">\/\/ \u53ea\u5728\u6709\u660e\u78ba prompt \u6642\u89f8\u767c<\/span>\n  },\n  shouldCreateTrackingComment() {\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-literal\">false<\/span>;  <span class=\"hljs-comment\">\/\/ \u4e0d\u5efa\u7acb tracking comment<\/span>\n  },\n  <span class=\"hljs-keyword\">async<\/span> prepare({ context, octokit, githubToken }) {\n    <span class=\"hljs-comment\">\/\/ \u76f4\u63a5\u5beb\u5165\u4f7f\u7528\u8005\u7684 prompt \u5230\u6a94\u6848<\/span>\n    <span class=\"hljs-keyword\">const<\/span> promptContent = context.inputs.prompt ||\n      <span class=\"hljs-string\">`Repository: <span class=\"hljs-subst\">${context.repository.owner}<\/span>\/<span class=\"hljs-subst\">${context.repository.repo}<\/span>`<\/span>;\n    <span class=\"hljs-keyword\">await<\/span> writeFile(<span class=\"hljs-string\">`<span class=\"hljs-subst\">${RUNNER_TEMP}<\/span>\/claude-prompts\/claude-prompt.txt`<\/span>, promptContent);\n    <span class=\"hljs-comment\">\/\/ \u4e0d\u9700\u8981 fetchGitHubData\u3001\u4e0d\u9700\u8981\u5efa\u7acb\u5206\u652f...<\/span>\n  },\n};\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u5169\u7a2e\u6a21\u5f0f\u7684\u5c0d\u6bd4\uff1aTag \u6a21\u5f0f\u662f\u300c\u5168\u529f\u80fd\u4e92\u52d5\u300d\uff08fetching PR data\u3001creating tracking comments\u3001branch management\uff09\uff0cAgent \u6a21\u5f0f\u662f\u300c\u6700\u5c0f\u5316\u81ea\u52d5\u5316\u300d\uff08\u76f4\u63a5\u4f7f\u7528 prompt\uff0c\u4e0d\u505a\u591a\u9918\u52d5\u4f5c\uff09\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u8a2d\u8a08\u516b\uff1aOIDC Token Exchange\u2014\u2014\u96f6 Secret \u7684\u8a8d\u8b49\u65b9\u6848<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/anthropics\/claude-code-action\/blob\/main\/src\/github\/token.ts\"><code>src\/github\/token.ts<\/code><\/a> \u2014 Token \u7ba1\u7406\uff0c\u652f\u63f4 OIDC token exchange \u548c\u81ea\u8a02 GitHub App \u8a8d\u8b49<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">setupGitHubToken<\/span>(<span class=\"hljs-params\"><\/span>): <span class=\"hljs-title\">Promise<\/span>&lt;<span class=\"hljs-title\">string<\/span>&gt; <\/span>{\n  <span class=\"hljs-comment\">\/\/ \u5982\u679c\u63d0\u4f9b\u4e86\u81ea\u8a02 token\uff0c\u76f4\u63a5\u4f7f\u7528<\/span>\n  <span class=\"hljs-keyword\">const<\/span> providedToken = process.env.OVERRIDE_GITHUB_TOKEN;\n  <span class=\"hljs-keyword\">if<\/span> (providedToken) {\n    core.setOutput(<span class=\"hljs-string\">\"GITHUB_TOKEN\"<\/span>, providedToken);\n    <span class=\"hljs-keyword\">return<\/span> providedToken;\n  }\n\n  <span class=\"hljs-comment\">\/\/ \u5426\u5247\u8d70 OIDC \u6d41\u7a0b<\/span>\n  <span class=\"hljs-keyword\">const<\/span> oidcToken = <span class=\"hljs-keyword\">await<\/span> retryWithBackoff(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> getOidcToken());\n  <span class=\"hljs-keyword\">const<\/span> permissions = parseAdditionalPermissions();\n  <span class=\"hljs-keyword\">const<\/span> appToken = <span class=\"hljs-keyword\">await<\/span> retryWithBackoff(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> exchangeForAppToken(oidcToken, permissions));\n  <span class=\"hljs-keyword\">return<\/span> appToken;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">OIDC \u6d41\u7a0b\u907f\u514d\u4e86\u5728 repository secrets \u4e2d\u5132\u5b58\u9577\u671f\u6709\u6548\u7684 token\u3002GitHub Actions \u63d0\u4f9b\u7684 OIDC token \u662f\u77ed\u671f\u7684\uff0c\u900f\u904e Anthropic \u7684 API \u4ea4\u63db\u70ba GitHub App token\uff0c\u9019\u500b token \u5728 action \u7d50\u675f\u5f8c\u6703\u88ab\u64a4\u92b7\uff08\u898b <code>action.yml<\/code> \u6700\u5f8c\u7684 <code>Revoke app token<\/code> \u6b65\u9a5f\uff09\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u7279\u5225\u6ce8\u610f <code>parseAdditionalPermissions()<\/code> \u7684\u8a2d\u8a08\uff1a<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">const<\/span> DEFAULT_PERMISSIONS: Record&lt;string, string&gt; = {\n  <span class=\"hljs-attr\">contents<\/span>: <span class=\"hljs-string\">\"write\"<\/span>,\n  <span class=\"hljs-attr\">pull_requests<\/span>: <span class=\"hljs-string\">\"write\"<\/span>,\n  <span class=\"hljs-attr\">issues<\/span>: <span class=\"hljs-string\">\"write\"<\/span>,\n};\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u9810\u8a2d\u53ea\u8981\u6c42\u6700\u5c0f\u5fc5\u8981\u6b0a\u9650\uff0c\u4f7f\u7528\u8005\u53ef\u4ee5\u900f\u904e <code>additional_permissions<\/code> input \u64f4\u5c55\uff0c\u4f46\u7121\u6cd5\u7e2e\u5c0f\u57fa\u790e\u6b0a\u9650\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u8a2d\u8a08\u4e5d\uff1aPrompt \u751f\u6210\u2014\u2014\u7d50\u69cb\u5316\u4e0a\u4e0b\u6587\u6ce8\u5165<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/anthropics\/claude-code-action\/blob\/main\/src\/create-prompt\/index.ts\"><code>src\/create-prompt\/index.ts<\/code><\/a> \u2014 Prompt \u751f\u6210\u5668\uff0c\u5c07 GitHub \u8cc7\u6599\u8f49\u63db\u70ba\u7d50\u69cb\u5316\u7684 Claude \u6307\u4ee4<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Prompt \u751f\u6210\u4f7f\u7528 XML-like tags \u5c07\u4e0d\u540c\u985e\u578b\u7684\u4e0a\u4e0b\u6587\u5206\u9694\uff1a<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-19\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\">let promptContent = `You are Claude, an AI assistant...\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">formatted_context<\/span>&gt;<\/span>\n${formattedContext}\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">formatted_context<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">pr_or_issue_body<\/span>&gt;<\/span>\n${formattedBody}\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">pr_or_issue_body<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">comments<\/span>&gt;<\/span>\n${formattedComments || \"No comments\"}\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">comments<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">event_type<\/span>&gt;<\/span>${eventType}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">event_type<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">trigger_comment<\/span>&gt;<\/span>\n${sanitizeContent(eventData.commentBody)}\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">trigger_comment<\/span>&gt;<\/span>\n`;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-19\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u9019\u7a2e\u7d50\u69cb\u5316\u8a2d\u8a08\u8b93 Claude \u80fd\u660e\u78ba\u5340\u5206\u300c\u7cfb\u7d71\u6307\u4ee4\u300d\u548c\u300c\u4f7f\u7528\u8005\u63d0\u4f9b\u7684\u5167\u5bb9\u300d\uff0c\u964d\u4f4e prompt injection \u98a8\u96aa\u3002\u540c\u6642\uff0c\u6240\u6709\u4f7f\u7528\u8005\u63d0\u4f9b\u7684\u5167\u5bb9\uff08comment body\u3001PR body\uff09\u90fd\u7d93\u904e <code>sanitizeContent()<\/code> \u6e05\u6f54\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u53e6\u4e00\u500b\u7cbe\u5de7\u7684\u8a2d\u8a08\u662f\u300c\u81ea\u8a02 prompt \u6ce8\u5165\u300d\uff1a<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-20\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">generatePrompt(context, githubData, useCommitSigning): string {\n  <span class=\"hljs-keyword\">const<\/span> defaultPrompt = generateDefaultPrompt(context, githubData, useCommitSigning);\n  <span class=\"hljs-keyword\">if<\/span> (context.githubContext?.inputs?.prompt) {\n    <span class=\"hljs-keyword\">return<\/span> defaultPrompt + <span class=\"hljs-string\">`\\n\\n&lt;custom_instructions&gt;\\n<span class=\"hljs-subst\">${context.githubContext.inputs.prompt}<\/span>\\n&lt;\/custom_instructions&gt;`<\/span>;\n  }\n  <span class=\"hljs-keyword\">return<\/span> defaultPrompt;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-20\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u4f7f\u7528\u8005\u7684\u81ea\u8a02 prompt \u88ab\u5305\u88f9\u5728 <code>&lt;custom_instructions&gt;<\/code> tag \u4e2d\uff0c\u9644\u52a0\u5728\u7cfb\u7d71 prompt \u4e4b\u5f8c\uff0c\u800c\u975e\u53d6\u4ee3\u5b83\u3002\u9019\u78ba\u4fdd\u4e86\u6838\u5fc3\u884c\u70ba\u6307\u4ee4\u4e0d\u6703\u88ab\u8986\u84cb\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u8a2d\u8a08\u5341\uff1aCommit Signing \u96d9\u8ecc\u6a5f\u5236\u2014\u2014Git CLI vs GitHub API<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u5c08\u6848\u652f\u63f4\u5169\u7a2e\u5b8c\u5168\u4e0d\u540c\u7684 commit \u65b9\u5f0f\uff0c\u5404\u6709\u512a\u7f3a\u9ede\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Git CLI \u6a21\u5f0f<\/strong>\uff08\u9810\u8a2d\uff09\uff1a\u76f4\u63a5\u5728 runner \u4e0a\u4f7f\u7528 git \u547d\u4ee4\uff1a<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-21\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ Tag \u6a21\u5f0f\u4e2d\u7684\u5de5\u5177\u914d\u7f6e<\/span>\n<span class=\"hljs-keyword\">if<\/span> (!useApiCommitSigning) {\n  tagModeTools.push(\n    <span class=\"hljs-string\">\"Bash(git add:*)\"<\/span>, <span class=\"hljs-string\">\"Bash(git commit:*)\"<\/span>, <span class=\"hljs-string\">\"Bash(git push:*)\"<\/span>, ...\n  );\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-21\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\"><strong>GitHub API \u6a21\u5f0f<\/strong>\uff08commit signing\uff09\uff1a\u900f\u904e MCP Server \u4f7f\u7528 GitHub API \u5efa\u7acb commit\uff1a<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/anthropics\/claude-code-action\/blob\/main\/src\/mcp\/github-file-ops-server.ts\"><code>src\/mcp\/github-file-ops-server.ts<\/code><\/a> \u2014 File Operations MCP Server\uff0c\u900f\u904e GitHub Git Data API \u5be6\u73fe verified commit<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-22\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">server.tool(<span class=\"hljs-string\">\"commit_files\"<\/span>, <span class=\"hljs-string\">\"Commit one or more files...\"<\/span>, {\n  <span class=\"hljs-attr\">files<\/span>: z.array(z.string()),\n  <span class=\"hljs-attr\">message<\/span>: z.string(),\n}, <span class=\"hljs-keyword\">async<\/span> ({ files, message }) =&gt; {\n  <span class=\"hljs-comment\">\/\/ 1. \u53d6\u5f97\u6216\u5efa\u7acb\u5206\u652f reference<\/span>\n  <span class=\"hljs-keyword\">const<\/span> baseSha = <span class=\"hljs-keyword\">await<\/span> getOrCreateBranchRef(owner, repo, branch, githubToken);\n  <span class=\"hljs-comment\">\/\/ 2. \u53d6\u5f97 base commit<\/span>\n  <span class=\"hljs-comment\">\/\/ 3. \u5efa\u7acb tree entries\uff08\u652f\u63f4 binary \u548c text \u6a94\u6848\uff09<\/span>\n  <span class=\"hljs-comment\">\/\/ 4. \u5efa\u7acb\u65b0 tree<\/span>\n  <span class=\"hljs-comment\">\/\/ 5. \u5efa\u7acb\u65b0 commit<\/span>\n  <span class=\"hljs-comment\">\/\/ 6. \u66f4\u65b0 reference\uff08\u542b retry \u6a5f\u5236\uff09<\/span>\n  <span class=\"hljs-keyword\">await<\/span> retryWithBackoff(<span class=\"hljs-keyword\">async<\/span> () =&gt; {\n    <span class=\"hljs-keyword\">const<\/span> updateRefResponse = <span class=\"hljs-keyword\">await<\/span> fetch(updateRefUrl, { <span class=\"hljs-comment\">\/* ... *\/<\/span> });\n    <span class=\"hljs-keyword\">if<\/span> (updateRefResponse.status === <span class=\"hljs-number\">403<\/span>) {\n      <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Error<\/span>(<span class=\"hljs-string\">`Permission denied: Unable to push commits to branch...`<\/span>);\n    }\n  }, { <span class=\"hljs-attr\">maxAttempts<\/span>: <span class=\"hljs-number\">3<\/span>, <span class=\"hljs-attr\">initialDelayMs<\/span>: <span class=\"hljs-number\">1000<\/span>, <span class=\"hljs-attr\">backoffFactor<\/span>: <span class=\"hljs-number\">2<\/span> });\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-22\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">GitHub API \u6a21\u5f0f\u7684\u597d\u8655\u662f commit \u6703\u5e36\u6709 GitHub \u7684 verified \u6a19\u8a18\uff08\u56e0\u70ba\u662f\u900f\u904e GitHub App \u8eab\u4efd\u5efa\u7acb\u7684\uff09\uff0c\u4f46\u9700\u8981\u66f4\u591a API \u547c\u53eb\u3002\u503c\u5f97\u6ce8\u610f\u7684\u662f <code>retryWithBackoff<\/code> \u7684\u4f7f\u7528\u2014\u2014GitHub API \u6709\u6642\u6703\u51fa\u73fe\u66ab\u6642\u6027\u7684 403 \u932f\u8aa4\uff0cretry \u6a5f\u5236\u78ba\u4fdd\u4e86\u53ef\u9760\u6027\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u8a2d\u8a08\u7406\u5ff5\u8403\u53d6<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li><strong>\u96d9\u968e\u6bb5\u89e3\u8026\u52dd\u904e\u55ae\u4e00\u6d41\u7a0b<\/strong> \u2014 Preparation \u548c Execution \u7684\u5206\u96e2\u8b93\u6bcf\u500b\u968e\u6bb5\u53ef\u4ee5\u7368\u7acb\u6e2c\u8a66\u3001\u7368\u7acb\u90e8\u7f72\uff08base-action \u53ef\u4ee5\u55ae\u7368\u4f7f\u7528\uff09\uff0c\u4e5f\u8b93 fail-fast \u6210\u70ba\u53ef\u80fd\u3002\u9019\u7a2e\u8a2d\u8a08\u7279\u5225\u9069\u5408\u9700\u8981\u524d\u7f6e\u9a57\u8b49\u7684\u7cfb\u7d71\u3002<\/li>\n\n\n<li><strong>\u578b\u5225\u7cfb\u7d71\u662f\u6700\u597d\u7684\u6587\u4ef6<\/strong> \u2014 Discriminated union + type guard \u7684\u7d44\u5408\uff0c\u8b93 TypeScript \u7de8\u8b6f\u5668\u53d6\u4ee3\u4e86\u5927\u91cf runtime \u6aa2\u67e5\u548c\u6587\u4ef6\u8aaa\u660e\u3002\u7576\u4f60\u770b\u5230 <code>isEntityContext(context)<\/code> \u5f8c\u9762\u7684\u4ee3\u78bc\uff0c\u4e0d\u9700\u8981\u984d\u5916\u6587\u4ef6\u5c31\u77e5\u9053 <code>context.entityNumber<\/code> \u4e00\u5b9a\u5b58\u5728\u3002<\/li>\n\n\n<li><strong>\u5b89\u5168\u9632\u8b77\u8981\u591a\u5c64\u4e14\u5404\u81ea\u7368\u7acb<\/strong> \u2014 \u4e0d\u4f9d\u8cf4\u4efb\u4f55\u55ae\u4e00\u9632\u7dda\uff1aActor \u9a57\u8b49\u9632 bot \u89f8\u767c\u3001\u6b0a\u9650\u9a57\u8b49\u9632\u7121\u6b0a\u9650\u64cd\u4f5c\u3001\u6642\u9593\u7a97\u53e3\u9632 TOCTOU \u653b\u64ca\u3001\u5167\u5bb9\u6e05\u6f54\u9632 prompt injection\u3001\u5206\u652f\u540d\u7a31\u9a57\u8b49\u9632 command injection\u3001<code>execFileSync<\/code> \u9632 shell injection\u3002\u6bcf\u4e00\u5c64\u90fd\u5047\u8a2d\u5176\u4ed6\u5c64\u53ef\u80fd\u5931\u6548\u3002<\/li>\n\n\n<li><strong>MCP Server \u662f\u5929\u7136\u7684\u80fd\u529b\u908a\u754c<\/strong> \u2014 \u628a GitHub \u64cd\u4f5c\u5c01\u88dd\u70ba\u7368\u7acb MCP Server\uff0c\u800c\u975e\u76f4\u63a5\u7d66 Claude \u5de5\u5177\u5b58\u53d6\uff0c\u5275\u9020\u4e86\u660e\u78ba\u7684\u5b89\u5168\u908a\u754c\u3002\u6bcf\u500b Server \u53ea\u66b4\u9732\u7279\u5b9a\u64cd\u4f5c\uff0c\u6709\u81ea\u5df1\u7684 token \u548c\u74b0\u5883\u8b8a\u6578\uff0c\u6309\u9700\u555f\u52d5\u3002<\/li>\n\n\n<li><strong>Convention over Configuration \u964d\u4f4e\u4f7f\u7528\u9580\u6abb<\/strong> \u2014 Mode detector \u6839\u64da GitHub \u4e8b\u4ef6\u985e\u578b\u81ea\u52d5\u9078\u64c7\u6a21\u5f0f\uff0c\u4f7f\u7528\u8005\u4e0d\u9700\u8981\u7406\u89e3 tag\/agent \u7684\u5340\u5225\u3002\u6709 prompt \u5c31\u8d70\u81ea\u52d5\u5316\uff0c\u6709 @claude \u5c31\u8d70\u4e92\u52d5\u5f0f\uff0c\u8a2d\u8a08\u610f\u5716\u96b1\u542b\u5728\u4f7f\u7528\u65b9\u5f0f\u4e2d\u3002<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">\u5ef6\u4f38\u601d\u8003<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">\u9019\u500b\u5c08\u6848\u5c55\u793a\u4e86\u5982\u4f55\u5728\u300c\u7d66 AI \u8db3\u5920\u80fd\u529b\u300d\u548c\u300c\u7dad\u6301\u5b89\u5168\u63a7\u5236\u300d\u4e4b\u9593\u53d6\u5f97\u5e73\u8861\u3002\u5982\u679c\u4f60\u6b63\u5728\u5efa\u69cb\u81ea\u5df1\u7684 AI \u81ea\u52d5\u5316\u7cfb\u7d71\uff0c\u53ef\u4ee5\u8003\u616e\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n\n<li><strong>\u5de5\u5177\u5b58\u53d6\u7684\u767d\u540d\u55ae\u8a2d\u8a08<\/strong>\uff1a\u4e0d\u8981\u7d66 AI \u300c\u6240\u6709 Bash \u547d\u4ee4\u300d\u7684\u5b58\u53d6\u6b0a\uff0c\u800c\u662f\u50cf <code>Bash(git add:*)<\/code> \u9019\u6a23\u7cbe\u78ba\u63a7\u5236\u5141\u8a31\u7684\u5b50\u547d\u4ee4\u3002<\/li>\n\n\n<li><strong>MCP \u4f5c\u70ba\u80fd\u529b\u5c01\u88dd<\/strong>\uff1a\u5982\u679c\u4f60\u7684 AI agent \u9700\u8981\u5b58\u53d6\u5916\u90e8\u670d\u52d9\uff0c\u8003\u616e\u5c07\u6bcf\u500b\u670d\u52d9\u5c01\u88dd\u70ba\u7368\u7acb\u7684 MCP Server\uff0c\u800c\u975e\u76f4\u63a5\u5728 agent \u4e2d\u547c\u53eb API\u3002\u9019\u8b93\u6b0a\u9650\u63a7\u5236\u548c\u6e2c\u8a66\u90fd\u66f4\u5bb9\u6613\u3002<\/li>\n\n\n<li><strong>\u591a\u5c64 sanitization<\/strong>\uff1a\u8655\u7406\u4f7f\u7528\u8005\u8f38\u5165\u6642\uff0c\u4e0d\u8981\u53ea\u505a\u4e00\u7a2e\u6e05\u6f54\u3002HTML \u8a3b\u89e3\u3001\u96b1\u5f62\u5b57\u5143\u3001image alt text\u3001link title \u90fd\u53ef\u80fd\u6210\u70ba prompt injection \u7684\u5411\u91cf\u3002<\/li>\n\n\n<li><strong>TOCTOU \u9632\u8b77<\/strong>\uff1a\u5982\u679c\u4f60\u7684\u7cfb\u7d71\u5728\u300c\u89f8\u767c\u6642\u300d\u548c\u300c\u8655\u7406\u6642\u300d\u4e4b\u9593\u6709\u6642\u9593\u5dee\uff0c\u8981\u8003\u616e\u9019\u6bb5\u6642\u9593\u5167\u8cc7\u6599\u53ef\u80fd\u88ab\u4fee\u6539\u3002\u8a18\u9304\u89f8\u767c\u6642\u9593\u6233\uff0c\u904e\u6ffe\u6389\u4e4b\u5f8c\u4fee\u6539\u7684\u5167\u5bb9\u3002<\/li>\n\n\n<li><strong>Discriminated union \u7d71\u4e00\u4e8b\u4ef6\u8655\u7406<\/strong>\uff1a\u7576\u4f60\u7684\u7cfb\u7d71\u9700\u8981\u8655\u7406\u591a\u7a2e\u4e8b\u4ef6\u985e\u578b\u6642\uff0c\u7528 TypeScript \u7684 discriminated union \u642d\u914d type guard\uff0c\u6bd4\u8d77 <code>switch-case<\/code> + <code>as<\/code> \u8f49\u578b\u66f4\u5b89\u5168\u3001\u66f4\u5177\u53ef\u7dad\u8b77\u6027\u3002<\/li>\n\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Vibe Coding\uff1a\u628a\u89c0\u5ff5\u8b8a\u6210\u7a0b\u5f0f\u78bc<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">\u4ee5\u4e0b\u662f\u4f60\u53ef\u4ee5\u76f4\u63a5\u7d66 AI \u7684 prompt \u6307\u4ee4\uff0c\u5c07\u672c\u6587\u4ecb\u7d39\u7684\u8a2d\u8a08\u89c0\u5ff5\u61c9\u7528\u5230\u4f60\u7684\u5c08\u6848\u4e2d\uff1a<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u96d9\u968e\u6bb5\u57f7\u884c\u67b6\u69cb\uff08Preparation \/ Execution \u89e3\u8026\uff09<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u5834\u666f<\/strong>\uff1a\u4f60\u6b63\u5728\u5efa\u69cb\u4e00\u500b\u9700\u8981\u300c\u524d\u7f6e\u9a57\u8b49\u300d\u518d\u300c\u57f7\u884c\u6838\u5fc3\u908f\u8f2f\u300d\u7684\u7cfb\u7d71\uff0c\u4f8b\u5982 CI\/CD pipeline\u3001API Gateway\u3001\u6216\u4efb\u4f55\u6709 pre-check \u6d41\u7a0b\u7684\u81ea\u52d5\u5316\u5de5\u5177\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u7d66 AI \u7684\u6307\u4ee4<\/strong>\uff1a<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u6211\u60f3\u91cd\u69cb\u76ee\u524d\u7684 [\u7cfb\u7d71\u540d\u7a31] \u6d41\u7a0b\uff0c\u63a1\u7528\u96d9\u968e\u6bb5\u57f7\u884c\u67b6\u69cb\uff08Preparation \/ Execution \u89e3\u8026\uff09\u3002\u76ee\u524d\u6240\u6709\u908f\u8f2f\u90fd\u5728\u540c\u4e00\u500b\u51fd\u5f0f\u4e2d\uff0c\u6211\u5e0c\u671b\u62c6\u6210\u5169\u500b\u7368\u7acb\u968e\u6bb5\uff1aPhase 1 \u8ca0\u8cac\u8a8d\u8b49\u3001\u9a57\u8b49\u3001\u689d\u4ef6\u6aa2\u67e5\uff0c\u5982\u679c\u4e0d\u7b26\u5408\u689d\u4ef6\u5c31 fail-fast \u76f4\u63a5\u7d50\u675f\uff1bPhase 2 \u8ca0\u8cac\u6838\u5fc3\u908f\u8f2f\u57f7\u884c\u3002\u5169\u500b\u968e\u6bb5\u4e4b\u9593\u53ea\u900f\u904e\u660e\u78ba\u5b9a\u7fa9\u7684\u8cc7\u6599\u7d50\u69cb\u50b3\u905e\u72c0\u614b\uff0c\u4e0d\u5171\u4eab\u4efb\u4f55 in-process \u72c0\u614b\u3002\u8acb\u5e6b\u6211\uff1a(1) \u5b9a\u7fa9 Phase 1 \u7684\u8f38\u51fa\u8cc7\u6599\u7d50\u69cb\uff08\u5305\u542b Phase 2 \u6240\u9700\u7684\u6240\u6709\u8cc7\u8a0a\uff09\uff1b(2) \u5c07\u76ee\u524d\u7684 [\u51fd\u5f0f\u540d\u7a31] \u62c6\u5206\u70ba prepare() \u548c execute() \u5169\u500b\u51fd\u5f0f\uff1b(3) \u78ba\u4fdd Phase 2 \u53ef\u4ee5\u7368\u7acb\u88ab\u5176\u4ed6\u6a21\u7d44\u547c\u53eb\u3002<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u6548\u679c<\/strong>\uff1aAI \u6703\u5206\u6790\u4f60\u73fe\u6709\u7684\u7a0b\u5f0f\u78bc\uff0c\u63d0\u53d6\u524d\u7f6e\u6aa2\u67e5\u908f\u8f2f\u5230 prepare \u968e\u6bb5\uff0c\u5b9a\u7fa9\u5169\u968e\u6bb5\u4e4b\u9593\u7684\u4ecb\u9762\u578b\u5225\uff0c\u4e26\u5c07\u6838\u5fc3\u908f\u8f2f\u5c01\u88dd\u70ba\u53ef\u7368\u7acb\u4f7f\u7528\u7684 execute \u51fd\u5f0f\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Registry Pattern \u8207\u7b56\u7565\u6a21\u5f0f\uff08Mode \u7cfb\u7d71\uff09<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u5834\u666f<\/strong>\uff1a\u4f60\u7684\u7cfb\u7d71\u9700\u8981\u6839\u64da\u4e0d\u540c\u689d\u4ef6\u57f7\u884c\u4e0d\u540c\u7684\u7b56\u7565\uff0c\u4f8b\u5982\u4e0d\u540c\u7684\u4e8b\u4ef6\u985e\u578b\u9700\u8981\u4e0d\u540c\u8655\u7406\u6d41\u7a0b\u3001\u4e0d\u540c\u4f7f\u7528\u8005\u7b49\u7d1a\u5c0d\u61c9\u4e0d\u540c\u529f\u80fd\u96c6\u3001\u6216\u4e0d\u540c\u74b0\u5883\uff08dev\/staging\/prod\uff09\u6709\u4e0d\u540c\u7684\u57f7\u884c\u884c\u70ba\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u7d66 AI \u7684\u6307\u4ee4<\/strong>\uff1a<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u6211\u7684 [\u7cfb\u7d71\u540d\u7a31] \u76ee\u524d\u4f7f\u7528 if-else \u6216 switch-case \u4f86\u8655\u7406\u4e0d\u540c\u7684 [\u4e8b\u4ef6\/\u7b56\u7565\/\u6a21\u5f0f]\uff0c\u6211\u60f3\u91cd\u69cb\u70ba Registry Pattern \u642d\u914d\u7b56\u7565\u6a21\u5f0f\u3002\u8acb\u53c3\u8003\u4ee5\u4e0b\u8a2d\u8a08\uff1a(1) \u5b9a\u7fa9\u4e00\u500b Mode interface\uff0c\u5305\u542b shouldTrigger()\u3001prepare()\u3001execute() \u7b49\u65b9\u6cd5\uff0c\u6bcf\u500b\u6a21\u5f0f\u81ea\u884c\u6c7a\u5b9a\u89f8\u767c\u689d\u4ef6\u548c\u57f7\u884c\u908f\u8f2f\uff1b(2) \u5efa\u7acb\u4e00\u500b registry\uff08\u4f7f\u7528 <code>as const satisfies Record&lt;ModeName, Mode&gt;<\/code> \u78ba\u4fdd\u578b\u5225\u5b89\u5168\uff09\uff0c\u8b93\u6bcf\u500b\u6a21\u5f0f\u540d\u7a31\u90fd\u6709\u5c0d\u61c9\u7684\u5be6\u4f5c\uff1b(3) \u5be6\u4f5c\u4e00\u500b detectMode() \u51fd\u5f0f\uff0c\u6839\u64da [\u4f60\u7684\u5224\u65b7\u689d\u4ef6] \u81ea\u52d5\u9078\u64c7\u6b63\u78ba\u7684\u6a21\u5f0f\u3002\u76ee\u524d\u6211\u6709\u4ee5\u4e0b\u5e7e\u7a2e\u6a21\u5f0f\uff1a[\u5217\u51fa\u4f60\u7684\u6a21\u5f0f]\u3002\u8acb\u5e6b\u6211\u5efa\u7acb\u5b8c\u6574\u7684\u578b\u5225\u5b9a\u7fa9\u3001registry\u3001\u548c\u5075\u6e2c\u908f\u8f2f\u3002<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u6548\u679c<\/strong>\uff1aAI \u6703\u5efa\u7acb\u5b8c\u6574\u7684 Mode interface\u3001\u5404\u6a21\u5f0f\u7684\u5be6\u4f5c\u985e\u5225\u3001\u578b\u5225\u5b89\u5168\u7684 registry \u7269\u4ef6\uff0c\u4ee5\u53ca\u81ea\u52d5\u5075\u6e2c\u908f\u8f2f\u3002\u65b0\u589e\u6a21\u5f0f\u6642\u53ea\u9700\u5be6\u4f5c interface \u4e26\u52a0\u5165 registry\uff0c\u4e0d\u9700\u8981\u4fee\u6539\u4efb\u4f55 if-else\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Discriminated Union \u7d71\u4e00\u4e8b\u4ef6\u8655\u7406<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u5834\u666f<\/strong>\uff1a\u4f60\u7684\u7cfb\u7d71\u9700\u8981\u8655\u7406\u591a\u7a2e\u4e0d\u540c\u7d50\u69cb\u7684\u4e8b\u4ef6\u6216\u8cc7\u6599\u985e\u578b\uff08\u4f8b\u5982 webhook \u4e8b\u4ef6\u3001API \u56de\u61c9\u3001\u4f7f\u7528\u8005\u64cd\u4f5c\uff09\uff0c\u76ee\u524d\u4f7f\u7528 <code>any<\/code> \u6216\u5927\u91cf <code>as<\/code> \u578b\u5225\u65b7\u8a00\u4f86\u8655\u7406\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u7d66 AI \u7684\u6307\u4ee4<\/strong>\uff1a<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u6211\u6b63\u5728\u7528 TypeScript \u8655\u7406\u591a\u7a2e [\u4e8b\u4ef6\/\u8cc7\u6599] \u985e\u578b\uff0c\u76ee\u524d\u4f7f\u7528 any \u548c as \u8f49\u578b\uff0c\u5bb9\u6613\u51fa\u73fe runtime \u932f\u8aa4\u3002\u8acb\u5e6b\u6211\u91cd\u69cb\u70ba discriminated union \u642d\u914d type guard \u7684\u6a21\u5f0f\u3002\u6211\u7684\u4e8b\u4ef6\u985e\u578b\u5305\u62ec\uff1a[\u5217\u51fa\u4f60\u7684\u4e8b\u4ef6\u985e\u578b\u548c\u5404\u81ea\u7684 payload \u7d50\u69cb]\u3002\u8acb\u5e6b\u6211\uff1a(1) \u5b9a\u7fa9\u4e00\u500b discriminated union type\uff0c\u7528 eventName \u4f5c\u70ba discriminant\uff1b(2) \u70ba\u6bcf\u7a2e\u4e8b\u4ef6\u5beb type guard \u51fd\u5f0f\uff08\u4f8b\u5982 isXxxEvent()\uff09\uff0c\u8b93 TypeScript \u5728 type guard \u5f8c\u81ea\u52d5\u6536\u7a84\u578b\u5225\uff1b(3) \u793a\u7bc4\u5982\u4f55\u5728\u4e0d\u4f7f\u7528 as \u5f37\u5236\u8f49\u578b\u7684\u60c5\u6cc1\u4e0b\u5b89\u5168\u5b58\u53d6\u5404\u4e8b\u4ef6\u7684\u7279\u6709\u6b04\u4f4d\u3002<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u6548\u679c<\/strong>\uff1aAI \u6703\u7522\u51fa\u5b8c\u6574\u7684 discriminated union \u578b\u5225\u5b9a\u7fa9\u3001\u4e00\u7d44 type guard \u51fd\u5f0f\uff0c\u4ee5\u53ca\u4f7f\u7528\u7bc4\u4f8b\u3002\u91cd\u69cb\u5f8c\u6240\u6709 payload \u5b58\u53d6\u90fd\u662f\u578b\u5225\u5b89\u5168\u7684\uff0c\u7de8\u8b6f\u5668\u6703\u5728\u4f60\u6f0f\u6389\u67d0\u7a2e\u4e8b\u4ef6\u8655\u7406\u6642\u767c\u51fa\u8b66\u544a\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">MCP Server \u4f5c\u70ba\u5de5\u5177\u908a\u754c<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u5834\u666f<\/strong>\uff1a\u4f60\u6b63\u5728\u5efa\u69cb AI agent \u7cfb\u7d71\uff0c\u9700\u8981\u8b93 AI \u5b58\u53d6\u5916\u90e8\u670d\u52d9\uff08\u8cc7\u6599\u5eab\u3001API\u3001\u6a94\u6848\u7cfb\u7d71\u7b49\uff09\uff0c\u4f46\u60f3\u8981\u7cbe\u78ba\u63a7\u5236 AI \u80fd\u4f7f\u7528\u7684\u64cd\u4f5c\u7bc4\u570d\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u7d66 AI \u7684\u6307\u4ee4<\/strong>\uff1a<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u6211\u6b63\u5728\u5efa\u69cb\u4e00\u500b AI agent\uff0c\u9700\u8981\u5b58\u53d6 [\u5916\u90e8\u670d\u52d9\u540d\u7a31]\u3002\u6211\u4e0d\u60f3\u76f4\u63a5\u7d66 agent \u5b8c\u6574\u7684 API \u5b58\u53d6\u6b0a\uff0c\u800c\u662f\u60f3\u7528 MCP Server \u4f5c\u70ba\u5de5\u5177\u908a\u754c\uff0c\u7cbe\u78ba\u63a7\u5236\u5141\u8a31\u7684\u64cd\u4f5c\u3002\u8acb\u5e6b\u6211\u8a2d\u8a08\u4e00\u500b MCP Server\uff0c\u53c3\u8003 Claude Code Action \u7684\u8a2d\u8a08\u6a21\u5f0f\uff1a(1) \u53ea\u66b4\u9732\u7279\u5b9a\u7684\u64cd\u4f5c\uff08\u4f8b\u5982 [\u5217\u51fa\u5141\u8a31\u7684\u64cd\u4f5c]\uff09\uff0c\u4e0d\u66b4\u9732\u5371\u96aa\u64cd\u4f5c\uff08\u4f8b\u5982 [\u5217\u51fa\u7981\u6b62\u7684\u64cd\u4f5c]\uff09\uff1b(2) \u6bcf\u500b\u5de5\u5177\u90fd\u7528 Zod schema \u9a57\u8b49\u8f38\u5165\u53c3\u6578\uff1b(3) \u6839\u64da\u4e0d\u540c\u7684\u6a21\u5f0f\uff08\u4f8b\u5982\u552f\u8b80 vs \u8b80\u5beb\uff09\u52d5\u614b\u6c7a\u5b9a\u555f\u7528\u54ea\u4e9b MCP Server\uff1b(4) \u52a0\u5165\u6b0a\u9650\u6aa2\u67e5\uff0c\u78ba\u8a8d\u547c\u53eb\u8005\u6709\u8db3\u5920\u6b0a\u9650\u624d\u555f\u7528\u5c0d\u61c9\u7684 Server\u3002<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u6548\u679c<\/strong>\uff1aAI \u6703\u8a2d\u8a08\u51fa\u4ee5\u5b89\u5168\u908a\u754c\u70ba\u6838\u5fc3\u7684 MCP Server \u67b6\u69cb\uff0c\u5305\u542b\u5de5\u5177\u5b9a\u7fa9\u3001\u8f38\u5165\u9a57\u8b49\u3001\u6b0a\u9650\u6aa2\u67e5\u908f\u8f2f\u3001\u4ee5\u53ca\u52d5\u614b\u914d\u7f6e\u7d44\u88dd\u51fd\u5f0f\u3002\u6bcf\u500b Server \u90fd\u662f\u7368\u7acb process\uff0c\u4e92\u4e0d\u5f71\u97ff\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u591a\u5c64\u5b89\u5168\u9632\u8b77\uff08Defense in Depth\uff09<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u5834\u666f<\/strong>\uff1a\u4f60\u7684\u7cfb\u7d71\u63a5\u53d7\u5916\u90e8\u8f38\u5165\uff08\u4f7f\u7528\u8005\u7559\u8a00\u3001webhook payload\u3001API \u8acb\u6c42\u7b49\uff09\uff0c\u9700\u8981\u9632\u6b62\u60e1\u610f\u8f38\u5165\u9020\u6210\u5b89\u5168\u554f\u984c\uff0c\u7279\u5225\u662f\u5728 AI agent \u5834\u666f\u4e2d\u8981\u9632\u6b62 prompt injection\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u7d66 AI \u7684\u6307\u4ee4<\/strong>\uff1a<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u6211\u7684 [\u7cfb\u7d71\u540d\u7a31] \u63a5\u53d7\u4f86\u81ea [\u8f38\u5165\u4f86\u6e90] \u7684\u5167\u5bb9\uff0c\u9019\u4e9b\u5167\u5bb9\u6703\u88ab\u9001\u7d66 AI \u8655\u7406\u3002\u8acb\u5e6b\u6211\u5be6\u4f5c\u591a\u5c64\u5b89\u5168\u9632\u8b77\uff08Defense in Depth\uff09\uff0c\u53c3\u8003 Claude Code Action \u7684\u4e94\u5c64\u9632\u79a6\u8a2d\u8a08\uff1a(1) Actor \u9a57\u8b49\u5c64\uff1a\u78ba\u8a8d\u89f8\u767c\u8005\u8eab\u4efd\uff0c\u9632\u6b62 bot \u89f8\u767c\u7121\u9650\u8ff4\u5708\uff1b(2) \u6b0a\u9650\u9a57\u8b49\u5c64\uff1a\u78ba\u8a8d\u64cd\u4f5c\u8005\u6709\u8db3\u5920\u6b0a\u9650\uff1b(3) \u6642\u9593\u7a97\u53e3\u9632\u8b77\uff08TOCTOU \u9632\u79a6\uff09\uff1a\u8a18\u9304\u89f8\u767c\u6642\u9593\u6233\uff0c\u904e\u6ffe\u6389\u89f8\u767c\u5f8c\u88ab\u4fee\u6539\u7684\u5167\u5bb9\uff1b(4) \u5167\u5bb9\u6e05\u6f54\u5c64\uff1a\u5be6\u4f5c sanitizeContent() \u51fd\u5f0f\uff0c\u4f9d\u5e8f\u79fb\u9664 HTML \u8a3b\u89e3\u3001\u96f6\u5bec\u96b1\u5f62\u5b57\u5143\u3001\u96b1\u85cf\u5c6c\u6027\u3001\u6b63\u898f\u5316 HTML entities\uff1b(5) \u547d\u4ee4\u6ce8\u5165\u9632\u8b77\uff1a\u4f7f\u7528 execFileSync \u53d6\u4ee3 shell \u57f7\u884c\uff0c\u5c0d\u6240\u6709\u52d5\u614b\u53c3\u6578\u505a\u767d\u540d\u55ae\u9a57\u8b49\u3002\u8acb\u91dd\u5c0d\u6211\u7684 [\u8f38\u5165\u4f86\u6e90] \u8a2d\u8a08\u5b8c\u6574\u7684\u9632\u8b77 pipeline\u3002<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u6548\u679c<\/strong>\uff1aAI \u6703\u7522\u51fa\u4e00\u500b\u5b8c\u6574\u7684\u5b89\u5168\u9632\u8b77 pipeline\uff0c\u6bcf\u4e00\u5c64\u90fd\u662f\u7368\u7acb\u7684\u51fd\u5f0f\uff0c\u53ef\u4ee5\u55ae\u7368\u6e2c\u8a66\u3002\u6bcf\u4e00\u5c64\u90fd\u5047\u8a2d\u5176\u4ed6\u5c64\u53ef\u80fd\u5931\u6548\uff0c\u5be6\u73fe\u771f\u6b63\u7684\u7e31\u6df1\u9632\u79a6\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u767d\u540d\u55ae\u5de5\u5177\u63a7\u5236\u8207\u7d50\u69cb\u5316 Prompt<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u5834\u666f<\/strong>\uff1a\u4f60\u6b63\u5728\u914d\u7f6e AI agent \u7684\u5de5\u5177\u6b0a\u9650\u548c prompt\uff0c\u60f3\u8981\u65e2\u7d66 AI \u8db3\u5920\u7684\u80fd\u529b\u5b8c\u6210\u4efb\u52d9\uff0c\u53c8\u9632\u6b62 AI \u57f7\u884c\u5371\u96aa\u64cd\u4f5c\u6216\u88ab prompt injection \u5f71\u97ff\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u7d66 AI \u7684\u6307\u4ee4<\/strong>\uff1a<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u6211\u6b63\u5728\u914d\u7f6e\u4e00\u500b AI agent \u7684\u5de5\u5177\u6b0a\u9650\u548c\u7cfb\u7d71 prompt\u3002\u8acb\u5e6b\u6211\u8a2d\u8a08\u767d\u540d\u55ae\u5de5\u5177\u63a7\u5236\u548c\u7d50\u69cb\u5316 prompt\uff0c\u53c3\u8003 Claude Code Action \u7684\u505a\u6cd5\uff1a(1) \u5de5\u5177\u767d\u540d\u55ae\uff1a\u53ea\u5141\u8a31\u7279\u5b9a\u5de5\u5177\u548c\u5b50\u547d\u4ee4\uff08\u4f8b\u5982 <code>Bash(git add:*)<\/code> \u53ea\u5141\u8a31 git add\uff0c\u4e0d\u5141\u8a31\u4efb\u610f Bash\uff09\uff0c\u5217\u51fa\u6211\u7684 agent \u9700\u8981\u7684\u64cd\u4f5c\uff1a[\u4f60\u7684\u64cd\u4f5c\u6e05\u55ae]\uff1b(2) \u7d50\u69cb\u5316 prompt\uff1a\u4f7f\u7528 XML-like tags \u5c07\u4e0d\u540c\u985e\u578b\u7684\u4e0a\u4e0b\u6587\u5206\u9694\uff08system instructions\u3001user content\u3001custom instructions\uff09\uff0c\u8b93 AI \u80fd\u660e\u78ba\u5340\u5206\u7cfb\u7d71\u6307\u4ee4\u548c\u4f7f\u7528\u8005\u63d0\u4f9b\u7684\u5167\u5bb9\uff1b(3) \u4f7f\u7528\u8005\u81ea\u8a02\u6307\u4ee4\u8981\u5305\u88f9\u5728\u5c08\u7528 tag \u4e2d\uff08\u5982 <code>&lt;custom_instructions&gt;<\/code>\uff09\uff0c\u9644\u52a0\u5728\u7cfb\u7d71 prompt \u4e4b\u5f8c\u800c\u975e\u53d6\u4ee3\u5b83\u3002\u8acb\u7522\u51fa\u5b8c\u6574\u7684\u5de5\u5177\u914d\u7f6e\u548c prompt template\u3002<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u6548\u679c<\/strong>\uff1aAI \u6703\u7522\u51fa\u7cbe\u78ba\u7684\u5de5\u5177\u767d\u540d\u55ae\u914d\u7f6e\u3001\u7d50\u69cb\u5316\u7684 prompt template\uff08\u542b XML tags \u5206\u9694\uff09\uff0c\u4ee5\u53ca\u81ea\u8a02\u6307\u4ee4\u7684\u5b89\u5168\u6ce8\u5165\u6a5f\u5236\u3002\u9019\u78ba\u4fdd\u4e86 AI \u53ea\u80fd\u4f7f\u7528\u88ab\u6388\u6b0a\u7684\u5de5\u5177\uff0c\u4e14\u7cfb\u7d71\u6307\u4ee4\u4e0d\u6703\u88ab\u4f7f\u7528\u8005\u8f38\u5165\u8986\u84cb\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u5ef6\u4f38\u95b1\u8b80<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li><a href=\"https:\/\/github.com\/anthropics\/claude-code-action\">Claude Code Action GitHub Repository<\/a> \u2014 \u5c08\u6848\u5b8c\u6574\u539f\u59cb\u78bc\uff0c\u5305\u542b\u672c\u6587\u89e3\u8b80\u7684\u6240\u6709\u8a2d\u8a08\u5be6\u4f5c\uff0c\u662f\u6700\u76f4\u63a5\u7684\u53c3\u8003\u8cc7\u6e90<\/li>\n\n\n<li><a href=\"https:\/\/code.claude.com\/docs\/en\/github-actions\">Claude Code GitHub Actions \u5b98\u65b9\u6587\u4ef6<\/a> \u2014 Anthropic \u5b98\u65b9\u7684 GitHub Actions \u6574\u5408\u6307\u5357\uff0c\u6db5\u84cb\u8a2d\u5b9a\u3001\u8a8d\u8b49\u3001\u9032\u968e\u7528\u6cd5<\/li>\n\n\n<li><a href=\"https:\/\/www.anthropic.com\/engineering\/claude-code-best-practices\">Claude Code: Best practices for agentic coding<\/a> \u2014 Anthropic \u5de5\u7a0b\u5718\u968a\u5206\u4eab\u7684 agentic coding \u6700\u4f73\u5be6\u8e10\uff0c\u7406\u89e3 Claude Code \u7684\u8a2d\u8a08\u54f2\u5b78<\/li>\n\n\n<li><a href=\"https:\/\/deepwiki.com\/anthropics\/claude-code-action\/4.1-github-action-structure\">GitHub Action Structure | DeepWiki<\/a> \u2014 DeepWiki \u5c0d Claude Code Action \u67b6\u69cb\u7684\u8996\u89ba\u5316\u89e3\u6790\uff0c\u5305\u542b\u96d9\u5c64 composite action \u7d50\u69cb\u5716\u548c\u57f7\u884c\u6d41\u7a0b\u5716<\/li>\n\n\n<li><a href=\"https:\/\/modelcontextprotocol.io\/specification\/draft\/basic\/security<em>best<\/em>practices&#8221;>Security Best Practices &#8211; Model Context Protocol<\/a> \u2014 MCP \u5b98\u65b9\u5b89\u5168\u6700\u4f73\u5be6\u8e10\u898f\u7bc4\uff0c\u6df1\u5165\u7406\u89e3\u672c\u6587\u63d0\u5230\u7684 MCP Server \u5b89\u5168\u908a\u754c\u8a2d\u8a08\u80cc\u5f8c\u7684\u898f\u7bc4\u57fa\u790e<\/li>\n\n\n<li><a href=\"https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/LLM<em>Prompt<\/em>Injection<em>Prevention<\/em>Cheat_Sheet.html&#8221;>LLM Prompt Injection Prevention &#8211; OWASP Cheat Sheet<\/a> \u2014 OWASP \u7684 LLM Prompt Injection \u9632\u79a6\u6307\u5357\uff0c\u7cfb\u7d71\u6027\u6574\u7406\u4e86\u672c\u6587\u63d0\u5230\u7684\u591a\u5c64\u9632\u79a6\u7b56\u7565<\/li>\n\n<\/ul>\n\n\n<div class=\"wp-like-post__wrapper\" style=\"\"><button type=\"button\" class=\"wp-like-post__button \" style=\"height: 30px; color: #000000;\" data-post-id=\"603\" data-total-likes=\"0\" data-likes-from-user=\"0\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" width=\"30\" height=\"30\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6.633 10.5c.806 0 1.533-.446 2.031-1.08a9.041 9.041 0 012.861-2.4c.723-.384 1.35-.956 1.653-1.715a4.498 4.498 0 00.322-1.672V3a.75.75 0 01.75-.75A2.25 2.25 0 0116.5 4.5c0 1.152-.26 2.243-.723 3.218-.266.558.107 1.282.725 1.282h3.126c1.026 0 1.945.694 2.054 1.715.045.422.068.85.068 1.285a11.95 11.95 0 01-2.649 7.521c-.388.482-.987.729-1.605.729H13.48c-.483 0-.964-.078-1.423-.23l-3.114-1.04a4.501 4.501 0 00-1.423-.23H5.904M14.25 9h2.25M5.904 18.75c.083.205.173.405.27.602.197.4-.078.898-.523.898h-.908c-.889 0-1.713-.518-1.972-1.368a12 12 0 01-.521-3.507c0-1.553.295-3.036.831-4.398C3.387 10.203 4.167 9.75 5 9.75h1.053c.472 0 .745.556.5.96a8.958 8.958 0 00-1.302 4.665c0 1.194.232 2.333.654 3.375z\" \/><\/svg><\/button><div class=\"wp-like-post__count\"\">0<\/div><\/div>","protected":false},"excerpt":{"rendered":"<p>Claude Code Action \u662f Anthropic \u5b98\u65b9\u63a8\u51fa\u7684 GitHub Action\uff0c\u8b93 Cl [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"rolpb_likes":0,"footnotes":""},"categories":[555],"tags":[576,324,440,575,26],"class_list":["post-603","post","type-post","status-publish","format-standard","hentry","category-ai-agent-github","tag-design-pattern","tag-github-actions","tag-mcp","tag-security","tag-typescript"],"blocksy_meta":{"styles_descriptor":{"styles":{"desktop":"","tablet":"","mobile":""},"google_fonts":[],"version":7}},"_links":{"self":[{"href":"https:\/\/blog.itsmygo.uk\/wordpress\/wp-json\/wp\/v2\/posts\/603","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.itsmygo.uk\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.itsmygo.uk\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.itsmygo.uk\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.itsmygo.uk\/wordpress\/wp-json\/wp\/v2\/comments?post=603"}],"version-history":[{"count":1,"href":"https:\/\/blog.itsmygo.uk\/wordpress\/wp-json\/wp\/v2\/posts\/603\/revisions"}],"predecessor-version":[{"id":615,"href":"https:\/\/blog.itsmygo.uk\/wordpress\/wp-json\/wp\/v2\/posts\/603\/revisions\/615"}],"wp:attachment":[{"href":"https:\/\/blog.itsmygo.uk\/wordpress\/wp-json\/wp\/v2\/media?parent=603"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.itsmygo.uk\/wordpress\/wp-json\/wp\/v2\/categories?post=603"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.itsmygo.uk\/wordpress\/wp-json\/wp\/v2\/tags?post=603"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}