From 1498681fdc374cef9208e2a6bae89531862c9b3f Mon Sep 17 00:00:00 2001 From: Chris Lee Date: Wed, 18 Feb 2026 21:35:19 +1100 Subject: [PATCH 1/2] fix(dependabot): switch npm ecosystem to bun for dependency updates --- .github/dependabot.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 99aac827..752cce80 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,8 +12,8 @@ updates: patterns: - "*" - # Bun / npm dependencies - - package-ecosystem: "npm" + # Bun dependencies + - package-ecosystem: "bun" directory: "/" schedule: interval: "monthly" From 2a15926349ad46ab7be5cb60cbda6808a9d5cd1c Mon Sep 17 00:00:00 2001 From: Chris Lee Date: Wed, 18 Feb 2026 22:26:40 +1100 Subject: [PATCH 2/2] fix(deps): upgrade zod to v4, prepare npm publish, fix CI peer-dep conflict --- .npmignore | 12 ++++++++++++ bun.lock | 14 ++++++-------- package.json | 23 ++++++++++++++++++----- src/config.ts | 6 +++--- src/core/executor.ts | 27 ++++++++++++++++----------- 5 files changed, 55 insertions(+), 27 deletions(-) create mode 100644 .npmignore diff --git a/.npmignore b/.npmignore new file mode 100644 index 00000000..72c52a5e --- /dev/null +++ b/.npmignore @@ -0,0 +1,12 @@ +src/ +test/ +scripts/ +.github/ +.husky/ +*.test.ts +tsconfig.json +eslint.config.* +.prettierrc* +.commitlintrc* +docker* +Dockerfile* diff --git a/bun.lock b/bun.lock index ba71034c..32404ebd 100644 --- a/bun.lock +++ b/bun.lock @@ -3,15 +3,15 @@ "configVersion": 1, "workspaces": { "": { - "name": "chrisleekr-bot", + "name": "@chrisleekr/github-app-playground", "dependencies": { "@anthropic-ai/claude-agent-sdk": "^0.2.44", - "@modelcontextprotocol/sdk": "^1.11.0", + "@modelcontextprotocol/sdk": "^1.26.0", "@octokit/webhooks": "13.9.1", "@octokit/webhooks-types": "^7.6.1", "octokit": "^4.1.2", "pino": "^9.6.0", - "zod": "^3.24.4", + "zod": "^4.0.0", }, "devDependencies": { "@commitlint/cli": "^20.4.1", @@ -34,7 +34,7 @@ }, }, "packages": { - "@anthropic-ai/claude-agent-sdk": ["@anthropic-ai/claude-agent-sdk@0.2.44", "", { "optionalDependencies": { "@img/sharp-darwin-arm64": "^0.33.5", "@img/sharp-darwin-x64": "^0.33.5", "@img/sharp-linux-arm": "^0.33.5", "@img/sharp-linux-arm64": "^0.33.5", "@img/sharp-linux-x64": "^0.33.5", "@img/sharp-linuxmusl-arm64": "^0.33.5", "@img/sharp-linuxmusl-x64": "^0.33.5", "@img/sharp-win32-x64": "^0.33.5" }, "peerDependencies": { "zod": "^4.0.0" } }, "sha512-bryUo6qq5dalO4MmhYLTPonTOAmdSVpMaVLJl8Y0qm6M7G+NZ3WS4cTMGrTbz97Uz5nah+FIOMA4hh8sKLm3YQ=="], + "@anthropic-ai/claude-agent-sdk": ["@anthropic-ai/claude-agent-sdk@0.2.45", "", { "optionalDependencies": { "@img/sharp-darwin-arm64": "^0.33.5", "@img/sharp-darwin-x64": "^0.33.5", "@img/sharp-linux-arm": "^0.33.5", "@img/sharp-linux-arm64": "^0.33.5", "@img/sharp-linux-x64": "^0.33.5", "@img/sharp-linuxmusl-arm64": "^0.33.5", "@img/sharp-linuxmusl-x64": "^0.33.5", "@img/sharp-win32-x64": "^0.33.5" }, "peerDependencies": { "zod": "^4.0.0" } }, "sha512-AKH2hKoJNyjLf9ThAttKqbmCjUFg7qs/8+LR/UTVX20fCLn359YH9WrQc6dAiAfi8RYNA+mWwrNYCAq+Sdo5Ag=="], "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], @@ -438,7 +438,7 @@ "help-me": ["help-me@5.0.0", "", {}, "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg=="], - "hono": ["hono@4.11.9", "", {}, "sha512-Eaw2YTGM6WOxA6CXbckaEvslr2Ne4NFsKrvc0v97JD5awbmeBLO5w9Ho9L9kmKonrwF9RJlW6BxT1PVv/agBHQ=="], + "hono": ["hono@4.11.10", "", {}, "sha512-kyWP5PAiMooEvGrA9jcD3IXF7ATu8+o7B3KCbPXid5se52NPqnOpM/r9qeW2heMnOekF4kqR1fXJqCYeCLKrZg=="], "http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="], @@ -738,7 +738,7 @@ "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], - "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], "zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="], @@ -766,8 +766,6 @@ "eslint/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], - "fdir/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - "import-fresh/resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], "log-update/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], diff --git a/package.json b/package.json index 0769975d..2ef88119 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,20 @@ { - "name": "chrisleekr/github-app-playground", - "description": "A test GitHub App that listens for @chrisleekr-bot mentions on PRs and issues, then autonomously responds using the Claude Agent SDK (@anthropic-ai/claude-agent-sdk) with MCP servers", + "name": "@chrisleekr/github-app-playground", + "description": "A GitHub App that listens for @chrisleekr-bot mentions on PRs and issues, then autonomously responds using the Claude Agent SDK (@anthropic-ai/claude-agent-sdk) with MCP servers", "author": "Chris Lee ", "version": "1.0.0", - "private": true, + "main": "dist/app.js", + "bin": { + "github-app-playground": "dist/app.js" + }, + "files": [ + "dist/", + "README.md", + "LICENSE" + ], + "publishConfig": { + "access": "public" + }, "keywords": [ "github", "app", @@ -28,6 +39,8 @@ }, "packageManager": "bun@1.3.8", "scripts": { + "prepublishOnly": "bun run clean && NODE_ENV=production bun run build", + "clean": "rm -rf dist", "build": "bun run scripts/build.ts", "dev": "bun run build && bun run --watch src/app.ts", "dev:ngrok": "ngrok http 3000", @@ -47,12 +60,12 @@ "license": "MIT", "dependencies": { "@anthropic-ai/claude-agent-sdk": "^0.2.44", - "@modelcontextprotocol/sdk": "^1.11.0", + "@modelcontextprotocol/sdk": "^1.26.0", "@octokit/webhooks": "13.9.1", "@octokit/webhooks-types": "^7.6.1", "octokit": "^4.1.2", "pino": "^9.6.0", - "zod": "^3.24.4" + "zod": "^4.0.0" }, "devDependencies": { "@commitlint/cli": "^20.4.1", diff --git a/src/config.ts b/src/config.ts index bc64533f..ad8b6574 100644 --- a/src/config.ts +++ b/src/config.ts @@ -67,7 +67,7 @@ const configSchema = z // Direct Anthropic API requires a non-empty API key if (data.anthropicApiKey === undefined || data.anthropicApiKey === "") { ctx.addIssue({ - code: z.ZodIssueCode.custom, + code: "custom", message: "ANTHROPIC_API_KEY is required when CLAUDE_PROVIDER=anthropic", path: ["anthropicApiKey"], }); @@ -77,7 +77,7 @@ const configSchema = z // Bedrock always needs a region to construct the endpoint if (data.awsRegion === undefined || data.awsRegion === "") { ctx.addIssue({ - code: z.ZodIssueCode.custom, + code: "custom", message: "AWS_REGION is required when CLAUDE_PROVIDER=bedrock", path: ["awsRegion"], }); @@ -87,7 +87,7 @@ const configSchema = z // default that the Bedrock API will reject. if (data.model === undefined) { ctx.addIssue({ - code: z.ZodIssueCode.custom, + code: "custom", message: "CLAUDE_MODEL is required when CLAUDE_PROVIDER=bedrock (e.g. us.anthropic.claude-sonnet-4-6)", path: ["model"], diff --git a/src/core/executor.ts b/src/core/executor.ts index 3b4eb21a..3af294f4 100644 --- a/src/core/executor.ts +++ b/src/core/executor.ts @@ -1,8 +1,18 @@ -import { query } from "@anthropic-ai/claude-agent-sdk"; +import { query, type SDKResultMessage } from "@anthropic-ai/claude-agent-sdk"; import { config } from "../config"; import type { BotContext, ExecutionResult, McpServerConfig } from "../types"; +/** Narrows an unknown streamed SDK message to the final result shape. */ +function isResultMessage(msg: unknown): msg is SDKResultMessage { + return ( + typeof msg === "object" && + msg !== null && + "type" in msg && + (msg as { type: unknown }).type === "result" + ); +} + /** * Build the subprocess environment for the Claude Code CLI. * @@ -44,14 +54,7 @@ export async function executeAgent( ); const startTime = Date.now(); - let result: - | { - subtype?: string; - total_cost_usd?: number; - duration_ms?: number; - num_turns?: number; - } - | undefined; + let result: SDKResultMessage | undefined; // Build query options. model is only included when set (exactOptionalPropertyTypes // forbids assigning undefined to optional properties). @@ -77,8 +80,10 @@ export async function executeAgent( // eventually exhaust MAX_CONCURRENT_REQUESTS for all subsequent requests. const agentLoop = (async (): Promise => { for await (const message of query({ prompt, options: queryOptions })) { - // Capture the final result message for metadata - if (message.type === "result") { + // Capture the final result message for metadata. + // isResultMessage guards against the SDK message union resolving to + // `any` in ESLint's type graph — ensures safe property access. + if (isResultMessage(message)) { result = message; } }