Compare commits
75 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef50f123a3 | ||
|
|
b3c0320e7e | ||
|
|
c93e8fe879 | ||
|
|
11a9dadd19 | ||
|
|
567fe954a4 | ||
|
|
2da6cfae68 | ||
|
|
e58dfa5555 | ||
|
|
6ee201f023 | ||
|
|
b4d6741327 | ||
|
|
4e5d8b13ca | ||
|
|
5d5c10a4f3 | ||
|
|
632a368e81 | ||
|
|
4c682d8b65 | ||
|
|
38ec876110 | ||
|
|
0d2971c794 | ||
|
|
c68f82cb11 | ||
|
|
78758edf84 | ||
|
|
c3d45e8e94 | ||
|
|
931e620273 | ||
|
|
905d4eb99a | ||
|
|
5fb899572b | ||
|
|
c3bf66dbc2 | ||
|
|
3943183052 | ||
|
|
65f29cf68e | ||
|
|
1c8b699d43 | ||
|
|
ff49ec5fd6 | ||
|
|
25474bfe8b | ||
|
|
b47fd721da | ||
|
|
c26cb6427d | ||
|
|
657fb7c9c9 | ||
|
|
2ff1acb3ee | ||
|
|
b2fdd80112 | ||
|
|
26ddc358fe | ||
|
|
398370690e | ||
|
|
6cad158a17 | ||
|
|
0f1fe5ef85 | ||
|
|
6e2bd52842 | ||
|
|
3534c326a5 | ||
|
|
6685b26dfb | ||
|
|
5150ea9643 | ||
|
|
eb8baa46af | ||
|
|
f328a5c889 | ||
|
|
b15d4751a6 | ||
|
|
d5db8208f9 | ||
|
|
d8af4e9f01 | ||
|
|
f37c786ad3 | ||
|
|
21b0f0f9aa | ||
|
|
27f549ae64 | ||
|
|
263993d836 | ||
|
|
85133eeab2 | ||
|
|
1eddb334cf | ||
|
|
0432df8bfe | ||
|
|
ba026a3e56 | ||
|
|
c95e735eb1 | ||
|
|
58dbe8ed68 | ||
|
|
c281e17d7f | ||
|
|
408a40e7c2 | ||
|
|
bee87b3258 | ||
|
|
32156b120b | ||
|
|
7225f045c6 | ||
|
|
88c168b39e | ||
|
|
e7b588b6ea | ||
|
|
094bd24d57 | ||
|
|
3ac52d0da9 | ||
|
|
0ee1beea58 | ||
|
|
ff9acae588 | ||
|
|
6062f37096 | ||
|
|
df37d2f076 | ||
|
|
1ba15be4f0 | ||
|
|
9ddce40de8 | ||
|
|
1b422b3517 | ||
|
|
4c044bb2f5 | ||
|
|
cd77b50d2b | ||
|
|
0e80d3c5b8 | ||
|
|
f956510b1a |
@ -45,7 +45,7 @@ TASK OVERVIEW:
|
|||||||
- If you find similar issues using ./scripts/gh.sh search, consider using a "duplicate" label if appropriate. Only do so if the issue is a duplicate of another OPEN issue.
|
- If you find similar issues using ./scripts/gh.sh search, consider using a "duplicate" label if appropriate. Only do so if the issue is a duplicate of another OPEN issue.
|
||||||
|
|
||||||
5. Apply the selected labels:
|
5. Apply the selected labels:
|
||||||
- Use `./scripts/edit-issue-labels.sh --issue NUMBER --add-label LABEL1 --add-label LABEL2` to apply your selected labels
|
- Use `./scripts/edit-issue-labels.sh --add-label LABEL1 --add-label LABEL2` to apply your selected labels (issue number is read from the workflow event)
|
||||||
- DO NOT post any comments explaining your decision
|
- DO NOT post any comments explaining your decision
|
||||||
- DO NOT communicate directly with users
|
- DO NOT communicate directly with users
|
||||||
- If no labels are clearly applicable, do not apply any labels
|
- If no labels are clearly applicable, do not apply any labels
|
||||||
|
|||||||
2
.github/workflows/claude-review.yml
vendored
2
.github/workflows/claude-review.yml
vendored
@ -25,4 +25,4 @@ jobs:
|
|||||||
prompt: "/review-pr REPO: ${{ github.repository }} PR_NUMBER: ${{ github.event.pull_request.number }}"
|
prompt: "/review-pr REPO: ${{ github.repository }} PR_NUMBER: ${{ github.event.pull_request.number }}"
|
||||||
claude_args: |
|
claude_args: |
|
||||||
--allowedTools "mcp__github_inline_comment__create_inline_comment"
|
--allowedTools "mcp__github_inline_comment__create_inline_comment"
|
||||||
--model "claude-opus-4-6"
|
--model "claude-opus-4-7"
|
||||||
|
|||||||
2
.github/workflows/claude.yml
vendored
2
.github/workflows/claude.yml
vendored
@ -36,4 +36,4 @@ jobs:
|
|||||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||||
claude_args: |
|
claude_args: |
|
||||||
--allowedTools "Bash(bun install),Bash(bun test:*),Bash(bun run format),Bash(bun typecheck)"
|
--allowedTools "Bash(bun install),Bash(bun test:*),Bash(bun run format),Bash(bun typecheck)"
|
||||||
--model "claude-opus-4-6"
|
--model "claude-opus-4-7"
|
||||||
|
|||||||
2
.github/workflows/issue-triage.yml
vendored
2
.github/workflows/issue-triage.yml
vendored
@ -20,6 +20,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Run Claude Code for Issue Triage
|
- name: Run Claude Code for Issue Triage
|
||||||
uses: anthropics/claude-code-action@main
|
uses: anthropics/claude-code-action@main
|
||||||
|
env:
|
||||||
|
CLAUDE_CODE_SCRIPT_CAPS: '{"edit-issue-labels.sh":2}'
|
||||||
with:
|
with:
|
||||||
prompt: "/label-issue REPO: ${{ github.repository }} ISSUE_NUMBER: ${{ github.event.issue.number }}"
|
prompt: "/label-issue REPO: ${{ github.repository }} ISSUE_NUMBER: ${{ github.event.issue.number }}"
|
||||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||||
|
|||||||
113
action.yml
113
action.yml
@ -32,7 +32,16 @@ inputs:
|
|||||||
required: false
|
required: false
|
||||||
default: ""
|
default: ""
|
||||||
allowed_non_write_users:
|
allowed_non_write_users:
|
||||||
description: "Comma-separated list of usernames to allow without write permissions, or '*' to allow all users. Only works when github_token input is provided. WARNING: Use with extreme caution - this bypasses security checks and should only be used for workflows with very limited permissions (e.g., issue labeling)."
|
description: |
|
||||||
|
Comma-separated list of usernames to allow without write permissions, or '*' to allow all users.
|
||||||
|
Only works when github_token input is provided. WARNING: Use with extreme caution - this
|
||||||
|
bypasses security checks and should only be used for workflows with very limited permissions
|
||||||
|
(e.g., issue labeling).
|
||||||
|
|
||||||
|
SECURITY: Processing untrusted content exposes the workflow to prompt injection. When this
|
||||||
|
input is set, Claude does a best-effort scrub of Anthropic, cloud, and GitHub Actions secrets
|
||||||
|
from subprocess environments. This reduces but does not eliminate prompt injection risk -
|
||||||
|
only use for workflows with very limited permissions and validate all outputs.
|
||||||
required: false
|
required: false
|
||||||
default: ""
|
default: ""
|
||||||
include_comments_by_actor:
|
include_comments_by_actor:
|
||||||
@ -164,7 +173,7 @@ runs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Install Bun
|
- name: Install Bun
|
||||||
if: inputs.path_to_bun_executable == ''
|
if: inputs.path_to_bun_executable == ''
|
||||||
uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # https://github.com/oven-sh/setup-bun/releases/tag/v2.1.2
|
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # https://github.com/oven-sh/setup-bun/releases/tag/v2.2.0
|
||||||
with:
|
with:
|
||||||
bun-version: 1.3.6
|
bun-version: 1.3.6
|
||||||
token: ${{ inputs.github_token || github.token }}
|
token: ${{ inputs.github_token || github.token }}
|
||||||
@ -186,11 +195,56 @@ runs:
|
|||||||
cd ${GITHUB_ACTION_PATH}
|
cd ${GITHUB_ACTION_PATH}
|
||||||
bun install --production
|
bun install --production
|
||||||
|
|
||||||
|
- name: Install subprocess isolation dependencies
|
||||||
|
# Install subprocess isolation dependencies when processing content from non-write users.
|
||||||
|
# Best-effort: skips on non-Linux or when sudo/apt unavailable (self-hosted runners).
|
||||||
|
if: ${{ inputs.allowed_non_write_users != '' && runner.os == 'Linux' }}
|
||||||
|
continue-on-error: true
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
if [ "${CLAUDE_CODE_SUBPROCESS_ENV_SCRUB:-}" = "0" ]; then
|
||||||
|
echo "Subprocess isolation opted out via CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=0"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
if command -v apt-get >/dev/null && command -v sudo >/dev/null; then
|
||||||
|
for i in 1 2 3; do
|
||||||
|
sudo apt-get update -qq && sudo apt-get install -y --no-install-recommends bubblewrap socat && break
|
||||||
|
echo "apt-get attempt $i failed, retrying..."
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
# Ubuntu 24.04+ restricts unprivileged user namespaces via AppArmor.
|
||||||
|
# The sysctl doesn't exist on older kernels — that's fine.
|
||||||
|
if [ -f /proc/sys/kernel/apparmor_restrict_unprivileged_userns ] && command -v sudo >/dev/null; then
|
||||||
|
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Pin bun binary for post-steps
|
||||||
|
if: ${{ inputs.allowed_non_write_users != '' }}
|
||||||
|
continue-on-error: true
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
# Keep a copy of the bun binary alongside the action's own files so
|
||||||
|
# post-steps use the same version that was on PATH at action start.
|
||||||
|
mkdir -p "$GITHUB_ACTION_PATH/bin"
|
||||||
|
cp "$(command -v bun)" "$GITHUB_ACTION_PATH/bin/bun"
|
||||||
|
|
||||||
|
- name: Prepend system bin dirs to PATH
|
||||||
|
if: ${{ inputs.allowed_non_write_users != '' && runner.os != 'Windows' }}
|
||||||
|
continue-on-error: true
|
||||||
|
shell: /bin/bash --noprofile --norc -e -o pipefail {0}
|
||||||
|
run: |
|
||||||
|
echo "/usr/bin" >> "$GITHUB_PATH"
|
||||||
|
echo "/bin" >> "$GITHUB_PATH"
|
||||||
|
|
||||||
- name: Run Claude Code Action
|
- name: Run Claude Code Action
|
||||||
id: run
|
id: run
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
bun run ${GITHUB_ACTION_PATH}/src/entrypoints/run.ts
|
bun --no-env-file \
|
||||||
|
--config="${GITHUB_ACTION_PATH}/bunfig.toml" \
|
||||||
|
--tsconfig-override="${GITHUB_ACTION_PATH}/tsconfig.json" \
|
||||||
|
run ${GITHUB_ACTION_PATH}/src/entrypoints/run.ts
|
||||||
env:
|
env:
|
||||||
# Prepare inputs
|
# Prepare inputs
|
||||||
MODE: ${{ inputs.mode }}
|
MODE: ${{ inputs.mode }}
|
||||||
@ -204,6 +258,8 @@ runs:
|
|||||||
OVERRIDE_GITHUB_TOKEN: ${{ inputs.github_token }}
|
OVERRIDE_GITHUB_TOKEN: ${{ inputs.github_token }}
|
||||||
ALLOWED_BOTS: ${{ inputs.allowed_bots }}
|
ALLOWED_BOTS: ${{ inputs.allowed_bots }}
|
||||||
ALLOWED_NON_WRITE_USERS: ${{ inputs.allowed_non_write_users }}
|
ALLOWED_NON_WRITE_USERS: ${{ inputs.allowed_non_write_users }}
|
||||||
|
CLAUDE_CODE_SUBPROCESS_ENV_SCRUB: ${{ env.CLAUDE_CODE_SUBPROCESS_ENV_SCRUB || (inputs.allowed_non_write_users != '' && '1') || '' }}
|
||||||
|
CLAUDE_CODE_SCRIPT_CAPS: ${{ env.CLAUDE_CODE_SCRIPT_CAPS || '' }}
|
||||||
INCLUDE_COMMENTS_BY_ACTOR: ${{ inputs.include_comments_by_actor }}
|
INCLUDE_COMMENTS_BY_ACTOR: ${{ inputs.include_comments_by_actor }}
|
||||||
EXCLUDE_COMMENTS_BY_ACTOR: ${{ inputs.exclude_comments_by_actor }}
|
EXCLUDE_COMMENTS_BY_ACTOR: ${{ inputs.exclude_comments_by_actor }}
|
||||||
GITHUB_RUN_ID: ${{ github.run_id }}
|
GITHUB_RUN_ID: ${{ github.run_id }}
|
||||||
@ -270,6 +326,15 @@ runs:
|
|||||||
ANTHROPIC_DEFAULT_HAIKU_MODEL: ${{ env.ANTHROPIC_DEFAULT_HAIKU_MODEL }}
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: ${{ env.ANTHROPIC_DEFAULT_HAIKU_MODEL }}
|
||||||
ANTHROPIC_DEFAULT_OPUS_MODEL: ${{ env.ANTHROPIC_DEFAULT_OPUS_MODEL }}
|
ANTHROPIC_DEFAULT_OPUS_MODEL: ${{ env.ANTHROPIC_DEFAULT_OPUS_MODEL }}
|
||||||
|
|
||||||
|
# MCP configuration — these env vars are read directly from process.env by the
|
||||||
|
# Claude CLI subprocess. They must be listed explicitly here because this step's
|
||||||
|
# env: block shadows the calling workflow's job-level env vars (GitHub Actions
|
||||||
|
# composite action behavior). Set these in your workflow's job-level env: or via
|
||||||
|
# a prior step that writes to $GITHUB_ENV.
|
||||||
|
MCP_TIMEOUT: ${{ env.MCP_TIMEOUT }}
|
||||||
|
MCP_TOOL_TIMEOUT: ${{ env.MCP_TOOL_TIMEOUT }}
|
||||||
|
MAX_MCP_OUTPUT_TOKENS: ${{ env.MAX_MCP_OUTPUT_TOKENS }}
|
||||||
|
|
||||||
# Telemetry configuration
|
# Telemetry configuration
|
||||||
CLAUDE_CODE_ENABLE_TELEMETRY: ${{ env.CLAUDE_CODE_ENABLE_TELEMETRY }}
|
CLAUDE_CODE_ENABLE_TELEMETRY: ${{ env.CLAUDE_CODE_ENABLE_TELEMETRY }}
|
||||||
OTEL_METRICS_EXPORTER: ${{ env.OTEL_METRICS_EXPORTER }}
|
OTEL_METRICS_EXPORTER: ${{ env.OTEL_METRICS_EXPORTER }}
|
||||||
@ -281,11 +346,42 @@ runs:
|
|||||||
OTEL_LOGS_EXPORT_INTERVAL: ${{ env.OTEL_LOGS_EXPORT_INTERVAL }}
|
OTEL_LOGS_EXPORT_INTERVAL: ${{ env.OTEL_LOGS_EXPORT_INTERVAL }}
|
||||||
OTEL_RESOURCE_ATTRIBUTES: ${{ env.OTEL_RESOURCE_ATTRIBUTES }}
|
OTEL_RESOURCE_ATTRIBUTES: ${{ env.OTEL_RESOURCE_ATTRIBUTES }}
|
||||||
|
|
||||||
|
- name: Re-prepend system bin dirs to PATH
|
||||||
|
if: ${{ always() && inputs.allowed_non_write_users != '' && runner.os != 'Windows' }}
|
||||||
|
continue-on-error: true
|
||||||
|
shell: /bin/bash --noprofile --norc -e -o pipefail {0}
|
||||||
|
env:
|
||||||
|
BASH_ENV: ""
|
||||||
|
LD_PRELOAD: ""
|
||||||
|
LD_LIBRARY_PATH: ""
|
||||||
|
NODE_OPTIONS: ""
|
||||||
|
DYLD_INSERT_LIBRARIES: ""
|
||||||
|
DYLD_PRELOAD: ""
|
||||||
|
DYLD_LIBRARY_PATH: ""
|
||||||
|
DYLD_FRAMEWORK_PATH: ""
|
||||||
|
run: |
|
||||||
|
echo "/usr/bin" >> "$GITHUB_PATH"
|
||||||
|
echo "/bin" >> "$GITHUB_PATH"
|
||||||
|
{
|
||||||
|
echo "BASH_ENV="
|
||||||
|
echo "LD_PRELOAD="
|
||||||
|
echo "LD_LIBRARY_PATH="
|
||||||
|
echo "DYLD_INSERT_LIBRARIES="
|
||||||
|
echo "DYLD_PRELOAD="
|
||||||
|
echo "DYLD_LIBRARY_PATH="
|
||||||
|
echo "DYLD_FRAMEWORK_PATH="
|
||||||
|
} >> "$GITHUB_ENV"
|
||||||
|
|
||||||
- name: Cleanup SSH signing key
|
- name: Cleanup SSH signing key
|
||||||
if: always() && inputs.ssh_signing_key != ''
|
if: always() && inputs.ssh_signing_key != ''
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
bun run ${GITHUB_ACTION_PATH}/src/entrypoints/cleanup-ssh-signing.ts
|
BUN_BIN="${GITHUB_ACTION_PATH}/bin/bun"
|
||||||
|
[ -x "$BUN_BIN" ] || BUN_BIN="bun"
|
||||||
|
"$BUN_BIN" --no-env-file \
|
||||||
|
--config="${GITHUB_ACTION_PATH}/bunfig.toml" \
|
||||||
|
--tsconfig-override="${GITHUB_ACTION_PATH}/tsconfig.json" \
|
||||||
|
run ${GITHUB_ACTION_PATH}/src/entrypoints/cleanup-ssh-signing.ts
|
||||||
|
|
||||||
- name: Post buffered inline comments
|
- name: Post buffered inline comments
|
||||||
if: always() && inputs.classify_inline_comments != 'false'
|
if: always() && inputs.classify_inline_comments != 'false'
|
||||||
@ -297,10 +393,15 @@ runs:
|
|||||||
PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }}
|
PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }}
|
||||||
ANTHROPIC_API_KEY: ${{ inputs.anthropic_api_key }}
|
ANTHROPIC_API_KEY: ${{ inputs.anthropic_api_key }}
|
||||||
run: |
|
run: |
|
||||||
bun run ${GITHUB_ACTION_PATH}/src/entrypoints/post-buffered-inline-comments.ts
|
BUN_BIN="${GITHUB_ACTION_PATH}/bin/bun"
|
||||||
|
[ -x "$BUN_BIN" ] || BUN_BIN="bun"
|
||||||
|
"$BUN_BIN" --no-env-file \
|
||||||
|
--config="${GITHUB_ACTION_PATH}/bunfig.toml" \
|
||||||
|
--tsconfig-override="${GITHUB_ACTION_PATH}/tsconfig.json" \
|
||||||
|
run ${GITHUB_ACTION_PATH}/src/entrypoints/post-buffered-inline-comments.ts
|
||||||
|
|
||||||
- name: Revoke app token
|
- name: Revoke app token
|
||||||
if: always() && inputs.github_token == '' && steps.run.outputs.skipped_due_to_workflow_validation_mismatch != 'true'
|
if: always() && inputs.github_token == '' && steps.run.outputs.github_token != '' && steps.run.outputs.skipped_due_to_workflow_validation_mismatch != 'true'
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
curl -L \
|
curl -L \
|
||||||
|
|||||||
@ -4,6 +4,14 @@ This GitHub Action allows you to run [Claude Code](https://www.anthropic.com/cla
|
|||||||
|
|
||||||
For simply tagging @claude in issues and PRs out of the box, [check out the Claude Code action and GitHub app](https://github.com/anthropics/claude-code-action).
|
For simply tagging @claude in issues and PRs out of the box, [check out the Claude Code action and GitHub app](https://github.com/anthropics/claude-code-action).
|
||||||
|
|
||||||
|
## Trust model
|
||||||
|
|
||||||
|
This action is a thin wrapper that installs and runs Claude Code with the inputs you provide. It does **not** enforce any trust boundaries on its own. Running this action in a directory is equivalent to running Claude Code in that directory — Claude reads project-level configuration (`.claude/`, `CLAUDE.md`, `.mcp.json`, etc.) from the working directory, and the action's own setup steps run from there as well.
|
||||||
|
|
||||||
|
**The caller is responsible for ensuring the working directory and prompt are trusted.** If your workflow processes untrusted input (issues, fork pull requests, external comments), use [`anthropics/claude-code-action`](https://github.com/anthropics/claude-code-action) instead — it provides actor permission checks, restores project configuration from the base ref in PR contexts, and is the supported path for those scenarios.
|
||||||
|
|
||||||
|
See [Claude Code's security documentation](https://docs.anthropic.com/en/docs/claude-code/security) and the [GitHub Actions guidance on `pull_request_target`](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/) for background.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Add the following to your workflow file:
|
Add the following to your workflow file:
|
||||||
|
|||||||
@ -97,7 +97,7 @@ runs:
|
|||||||
|
|
||||||
- name: Install Bun
|
- name: Install Bun
|
||||||
if: inputs.path_to_bun_executable == ''
|
if: inputs.path_to_bun_executable == ''
|
||||||
uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # https://github.com/oven-sh/setup-bun/releases/tag/v2.1.2
|
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # https://github.com/oven-sh/setup-bun/releases/tag/v2.2.0
|
||||||
with:
|
with:
|
||||||
bun-version: 1.3.6
|
bun-version: 1.3.6
|
||||||
|
|
||||||
@ -124,7 +124,7 @@ runs:
|
|||||||
PATH_TO_CLAUDE_CODE_EXECUTABLE: ${{ inputs.path_to_claude_code_executable }}
|
PATH_TO_CLAUDE_CODE_EXECUTABLE: ${{ inputs.path_to_claude_code_executable }}
|
||||||
run: |
|
run: |
|
||||||
if [ -z "$PATH_TO_CLAUDE_CODE_EXECUTABLE" ]; then
|
if [ -z "$PATH_TO_CLAUDE_CODE_EXECUTABLE" ]; then
|
||||||
CLAUDE_CODE_VERSION="2.1.73"
|
CLAUDE_CODE_VERSION="2.1.123"
|
||||||
echo "Installing Claude Code v${CLAUDE_CODE_VERSION}..."
|
echo "Installing Claude Code v${CLAUDE_CODE_VERSION}..."
|
||||||
for attempt in 1 2 3; do
|
for attempt in 1 2 3; do
|
||||||
echo "Installation attempt $attempt..."
|
echo "Installation attempt $attempt..."
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
"name": "@anthropic-ai/claude-code-base-action",
|
"name": "@anthropic-ai/claude-code-base-action",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.10.1",
|
"@actions/core": "^1.10.1",
|
||||||
"@anthropic-ai/claude-agent-sdk": "^0.2.73",
|
"@anthropic-ai/claude-agent-sdk": "^0.2.123",
|
||||||
"shell-quote": "^1.8.3",
|
"shell-quote": "^1.8.3",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -27,41 +27,33 @@
|
|||||||
|
|
||||||
"@actions/io": ["@actions/io@1.1.3", "", {}, "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="],
|
"@actions/io": ["@actions/io@1.1.3", "", {}, "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="],
|
||||||
|
|
||||||
"@anthropic-ai/claude-agent-sdk": ["@anthropic-ai/claude-agent-sdk@0.2.73", "", { "optionalDependencies": { "@img/sharp-darwin-arm64": "^0.34.2", "@img/sharp-darwin-x64": "^0.34.2", "@img/sharp-linux-arm": "^0.34.2", "@img/sharp-linux-arm64": "^0.34.2", "@img/sharp-linux-x64": "^0.34.2", "@img/sharp-linuxmusl-arm64": "^0.34.2", "@img/sharp-linuxmusl-x64": "^0.34.2", "@img/sharp-win32-arm64": "^0.34.2", "@img/sharp-win32-x64": "^0.34.2" }, "peerDependencies": { "zod": "^4.0.0" } }, "sha512-JrHeMl93Q5ai9GMPAffQkSisbbDvD1skU2x6sf6WRzEZw0sK6aTG+XSiZHY2F5aSrfd4G2qUogLHEm6Y8obyOQ=="],
|
"@anthropic-ai/claude-agent-sdk": ["@anthropic-ai/claude-agent-sdk@0.2.123", "", { "dependencies": { "@anthropic-ai/sdk": "^0.81.0", "@modelcontextprotocol/sdk": "^1.29.0" }, "optionalDependencies": { "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.2.123", "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.2.123", "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.2.123", "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.2.123", "@anthropic-ai/claude-agent-sdk-linux-x64": "0.2.123", "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.2.123", "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.2.123", "@anthropic-ai/claude-agent-sdk-win32-x64": "0.2.123" }, "peerDependencies": { "zod": "^4.0.0" } }, "sha512-a4TysYoR9DBdkM9Uwh4J5ub7TwKmRPe5hFiWh4En+IKC+qkk5UFkxFM22c//cZjYZKynHX0ah2t6LUqb+najYA=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk-darwin-arm64": ["@anthropic-ai/claude-agent-sdk-darwin-arm64@0.2.123", "", { "os": "darwin", "cpu": "arm64" }, "sha512-tYAXCjlXZQklsUs0J//gip3fZQRzhlH5OCgvNXV70qe7A1iiwHqO2KPGvEHV1L+deEKQoMZmTaCOrQpN6zju3w=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk-darwin-x64": ["@anthropic-ai/claude-agent-sdk-darwin-x64@0.2.123", "", { "os": "darwin", "cpu": "x64" }, "sha512-AcUC6sTon6z6HculP87KsAOeTMRLBwpovdhcXUTjXUpo/8nplJ7lBEzWjZCHt8FF1KuN/WBy1Z4bDg/59TQDmA=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk-linux-arm64": ["@anthropic-ai/claude-agent-sdk-linux-arm64@0.2.123", "", { "os": "linux", "cpu": "arm64" }, "sha512-7+GnbcF3/aZ8RJ1WmU/ogtPsOpknBAoUPer90MvZuFYBLPT9iI/U7f24gjrOHuYdcbDA5n7jFlhcfIO26F5DJQ=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk-linux-arm64-musl": ["@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.2.123", "", { "os": "linux", "cpu": "arm64" }, "sha512-bYgRiaf2q+yVbGAoUluuhqrEW1zexL34+3HDmK9DneKXa2K2EJpw4M6Sq4XoBD/JezGaemoAP78Xv/M/QUS1OQ=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk-linux-x64": ["@anthropic-ai/claude-agent-sdk-linux-x64@0.2.123", "", { "os": "linux", "cpu": "x64" }, "sha512-Xi+Rwk8uP5vWEnawJOlsk179fr0ATLl5J90MlbLj+puKaX5svEq8ljS+P3zq6zHTJeKh9GKLzPf7bc5YJKwcew=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk-linux-x64-musl": ["@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.2.123", "", { "os": "linux", "cpu": "x64" }, "sha512-IX95lFKhmmndY/YPfWPsVV+C3rLYJmuuq5wCS53p6jYIkCMxH1iGfhBGF1EUWcXO4Uc8yqXFmQ3aaxMzOOPrwA=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk-win32-arm64": ["@anthropic-ai/claude-agent-sdk-win32-arm64@0.2.123", "", { "os": "win32", "cpu": "arm64" }, "sha512-WDZmAQG1rOiqNLZlSXaCjSWmqJvLk2io+vFQWWqSy2b5HCk9pa3PadLiaLztiihyk81wPhH9Q/44kOxdyfEGMw=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk-win32-x64": ["@anthropic-ai/claude-agent-sdk-win32-x64@0.2.123", "", { "os": "win32", "cpu": "x64" }, "sha512-588xrd1i6d4kXQ6FqwL+cgBiN4evRQSi5DCtPa02CZ3VEbuVQBeFlyPlD8tfWtNNeGZ4NM8kjPNNzZz5omezPA=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.81.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-D4K5PvEV6wPiRtVlVsJHIUhHAmOZ6IT/I9rKlTf84gR7GyyAurPJK7z9BOf/AZqC5d1DhYQGJNKRmV+q8dGhgw=="],
|
||||||
|
|
||||||
|
"@babel/runtime": ["@babel/runtime@7.29.2", "", {}, "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g=="],
|
||||||
|
|
||||||
"@fastify/busboy": ["@fastify/busboy@2.1.1", "", {}, "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="],
|
"@fastify/busboy": ["@fastify/busboy@2.1.1", "", {}, "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="],
|
||||||
|
|
||||||
"@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w=="],
|
"@hono/node-server": ["@hono/node-server@1.19.11", "", { "peerDependencies": { "hono": "^4" } }, "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g=="],
|
||||||
|
|
||||||
"@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.4" }, "os": "darwin", "cpu": "x64" }, "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw=="],
|
"@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.29.0", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ=="],
|
||||||
|
|
||||||
"@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g=="],
|
|
||||||
|
|
||||||
"@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg=="],
|
|
||||||
|
|
||||||
"@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.4", "", { "os": "linux", "cpu": "arm" }, "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A=="],
|
|
||||||
|
|
||||||
"@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw=="],
|
|
||||||
|
|
||||||
"@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw=="],
|
|
||||||
|
|
||||||
"@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw=="],
|
|
||||||
|
|
||||||
"@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg=="],
|
|
||||||
|
|
||||||
"@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.4" }, "os": "linux", "cpu": "arm" }, "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw=="],
|
|
||||||
|
|
||||||
"@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg=="],
|
|
||||||
|
|
||||||
"@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ=="],
|
|
||||||
|
|
||||||
"@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg=="],
|
|
||||||
|
|
||||||
"@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q=="],
|
|
||||||
|
|
||||||
"@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g=="],
|
|
||||||
|
|
||||||
"@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="],
|
|
||||||
|
|
||||||
"@types/bun": ["@types/bun@1.2.19", "", { "dependencies": { "bun-types": "1.2.19" } }, "sha512-d9ZCmrH3CJ2uYKXQIUuZ/pUnTqIvLDS0SK7pFmbx8ma+ziH/FRMoAq5bYpRG7y+w1gl+HgyNZbtqgMq4W4e2Lg=="],
|
"@types/bun": ["@types/bun@1.2.19", "", { "dependencies": { "bun-types": "1.2.19" } }, "sha512-d9ZCmrH3CJ2uYKXQIUuZ/pUnTqIvLDS0SK7pFmbx8ma+ziH/FRMoAq5bYpRG7y+w1gl+HgyNZbtqgMq4W4e2Lg=="],
|
||||||
|
|
||||||
@ -71,22 +63,202 @@
|
|||||||
|
|
||||||
"@types/shell-quote": ["@types/shell-quote@1.7.5", "", {}, "sha512-+UE8GAGRPbJVQDdxi16dgadcBfQ+KG2vgZhV1+3A1XmHbmwcdwhCUwIdy+d3pAGrbvgRoVSjeI9vOWyq376Yzw=="],
|
"@types/shell-quote": ["@types/shell-quote@1.7.5", "", {}, "sha512-+UE8GAGRPbJVQDdxi16dgadcBfQ+KG2vgZhV1+3A1XmHbmwcdwhCUwIdy+d3pAGrbvgRoVSjeI9vOWyq376Yzw=="],
|
||||||
|
|
||||||
|
"accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
|
||||||
|
|
||||||
|
"ajv": ["ajv@8.18.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A=="],
|
||||||
|
|
||||||
|
"ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="],
|
||||||
|
|
||||||
|
"body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="],
|
||||||
|
|
||||||
"bun-types": ["bun-types@1.2.19", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-uAOTaZSPuYsWIXRpj7o56Let0g/wjihKCkeRqUBhlLVM/Bt+Fj9xTo+LhC1OV1XDaGkz4hNC80et5xgy+9KTHQ=="],
|
"bun-types": ["bun-types@1.2.19", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-uAOTaZSPuYsWIXRpj7o56Let0g/wjihKCkeRqUBhlLVM/Bt+Fj9xTo+LhC1OV1XDaGkz4hNC80et5xgy+9KTHQ=="],
|
||||||
|
|
||||||
|
"bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
|
||||||
|
|
||||||
|
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
|
||||||
|
|
||||||
|
"call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="],
|
||||||
|
|
||||||
|
"content-disposition": ["content-disposition@1.0.1", "", {}, "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q=="],
|
||||||
|
|
||||||
|
"content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="],
|
||||||
|
|
||||||
|
"cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
|
||||||
|
|
||||||
|
"cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
|
||||||
|
|
||||||
|
"cors": ["cors@2.8.6", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw=="],
|
||||||
|
|
||||||
|
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
||||||
|
|
||||||
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
||||||
|
|
||||||
|
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
||||||
|
|
||||||
|
"depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="],
|
||||||
|
|
||||||
|
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
||||||
|
|
||||||
|
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
|
||||||
|
|
||||||
|
"encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
|
||||||
|
|
||||||
|
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
|
||||||
|
|
||||||
|
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
|
||||||
|
|
||||||
|
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
|
||||||
|
|
||||||
|
"escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="],
|
||||||
|
|
||||||
|
"etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="],
|
||||||
|
|
||||||
|
"eventsource": ["eventsource@3.0.7", "", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA=="],
|
||||||
|
|
||||||
|
"eventsource-parser": ["eventsource-parser@3.0.6", "", {}, "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg=="],
|
||||||
|
|
||||||
|
"express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="],
|
||||||
|
|
||||||
|
"express-rate-limit": ["express-rate-limit@8.3.1", "", { "dependencies": { "ip-address": "10.1.0" }, "peerDependencies": { "express": ">= 4.11" } }, "sha512-D1dKN+cmyPWuvB+G2SREQDzPY1agpBIcTa9sJxOPMCNeH3gwzhqJRDWCXW3gg0y//+LQ/8j52JbMROWyrKdMdw=="],
|
||||||
|
|
||||||
|
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||||
|
|
||||||
|
"fast-uri": ["fast-uri@3.1.0", "", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="],
|
||||||
|
|
||||||
|
"finalhandler": ["finalhandler@2.1.1", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA=="],
|
||||||
|
|
||||||
|
"forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
|
||||||
|
|
||||||
|
"fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
|
||||||
|
|
||||||
|
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
|
||||||
|
|
||||||
|
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
|
||||||
|
|
||||||
|
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
|
||||||
|
|
||||||
|
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
|
||||||
|
|
||||||
|
"has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
|
||||||
|
|
||||||
|
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
|
||||||
|
|
||||||
|
"hono": ["hono@4.12.9", "", {}, "sha512-wy3T8Zm2bsEvxKZM5w21VdHDDcwVS1yUFFY6i8UobSsKfFceT7TOwhbhfKsDyx7tYQlmRM5FLpIuYvNFyjctiA=="],
|
||||||
|
|
||||||
|
"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=="],
|
||||||
|
|
||||||
|
"iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="],
|
||||||
|
|
||||||
|
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
||||||
|
|
||||||
|
"ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="],
|
||||||
|
|
||||||
|
"ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
|
||||||
|
|
||||||
|
"is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="],
|
||||||
|
|
||||||
|
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||||
|
|
||||||
|
"jose": ["jose@6.2.2", "", {}, "sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ=="],
|
||||||
|
|
||||||
|
"json-schema-to-ts": ["json-schema-to-ts@3.1.1", "", { "dependencies": { "@babel/runtime": "^7.18.3", "ts-algebra": "^2.0.0" } }, "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g=="],
|
||||||
|
|
||||||
|
"json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
|
||||||
|
|
||||||
|
"json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="],
|
||||||
|
|
||||||
|
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
||||||
|
|
||||||
|
"media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
|
||||||
|
|
||||||
|
"merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="],
|
||||||
|
|
||||||
|
"mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
||||||
|
|
||||||
|
"mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="],
|
||||||
|
|
||||||
|
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||||
|
|
||||||
|
"negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
|
||||||
|
|
||||||
|
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
|
||||||
|
|
||||||
|
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
|
||||||
|
|
||||||
|
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
|
||||||
|
|
||||||
|
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
|
||||||
|
|
||||||
|
"parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="],
|
||||||
|
|
||||||
|
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
||||||
|
|
||||||
|
"path-to-regexp": ["path-to-regexp@8.4.0", "", {}, "sha512-PuseHIvAnz3bjrM2rGJtSgo1zjgxapTLZ7x2pjhzWwlp4SJQgK3f3iZIQwkpEnBaKz6seKBADpM4B4ySkuYypg=="],
|
||||||
|
|
||||||
|
"pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="],
|
||||||
|
|
||||||
"prettier": ["prettier@3.5.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw=="],
|
"prettier": ["prettier@3.5.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw=="],
|
||||||
|
|
||||||
|
"proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
|
||||||
|
|
||||||
|
"qs": ["qs@6.15.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ=="],
|
||||||
|
|
||||||
|
"range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="],
|
||||||
|
|
||||||
|
"raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="],
|
||||||
|
|
||||||
|
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
|
||||||
|
|
||||||
|
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
|
||||||
|
|
||||||
|
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
|
||||||
|
|
||||||
|
"send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="],
|
||||||
|
|
||||||
|
"serve-static": ["serve-static@2.2.1", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw=="],
|
||||||
|
|
||||||
|
"setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
|
||||||
|
|
||||||
|
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||||
|
|
||||||
|
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
||||||
|
|
||||||
"shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="],
|
"shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="],
|
||||||
|
|
||||||
|
"side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="],
|
||||||
|
|
||||||
|
"side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="],
|
||||||
|
|
||||||
|
"side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="],
|
||||||
|
|
||||||
|
"side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="],
|
||||||
|
|
||||||
|
"statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="],
|
||||||
|
|
||||||
|
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
|
||||||
|
|
||||||
|
"ts-algebra": ["ts-algebra@2.0.0", "", {}, "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw=="],
|
||||||
|
|
||||||
"tunnel": ["tunnel@0.0.6", "", {}, "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="],
|
"tunnel": ["tunnel@0.0.6", "", {}, "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="],
|
||||||
|
|
||||||
|
"type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
|
||||||
|
|
||||||
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
|
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
|
||||||
|
|
||||||
"undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="],
|
"undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="],
|
||||||
|
|
||||||
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
||||||
|
|
||||||
|
"unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="],
|
||||||
|
|
||||||
|
"vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
|
||||||
|
|
||||||
|
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||||
|
|
||||||
|
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
|
||||||
|
|
||||||
"zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
"zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
||||||
|
|
||||||
|
"zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.10.1",
|
"@actions/core": "^1.10.1",
|
||||||
"@anthropic-ai/claude-agent-sdk": "^0.2.73",
|
"@anthropic-ai/claude-agent-sdk": "^0.2.123",
|
||||||
"shell-quote": "^1.8.3"
|
"shell-quote": "^1.8.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@ -11,6 +11,14 @@ async function run() {
|
|||||||
try {
|
try {
|
||||||
validateEnvironmentVariables();
|
validateEnvironmentVariables();
|
||||||
|
|
||||||
|
// The composite action's "Install Claude Code" step writes the binary to
|
||||||
|
// ~/.local/bin/claude. Pass that path explicitly so the Agent SDK doesn't
|
||||||
|
// fall back to its bundled platform package, which bun may resolve to the
|
||||||
|
// wrong libc variant on Linux.
|
||||||
|
const claudeExecutable =
|
||||||
|
process.env.INPUT_PATH_TO_CLAUDE_CODE_EXECUTABLE ||
|
||||||
|
`${process.env.HOME}/.local/bin/claude`;
|
||||||
|
|
||||||
await setupClaudeCodeSettings(
|
await setupClaudeCodeSettings(
|
||||||
process.env.INPUT_SETTINGS,
|
process.env.INPUT_SETTINGS,
|
||||||
undefined, // homeDir
|
undefined, // homeDir
|
||||||
@ -20,7 +28,7 @@ async function run() {
|
|||||||
await installPlugins(
|
await installPlugins(
|
||||||
process.env.INPUT_PLUGIN_MARKETPLACES,
|
process.env.INPUT_PLUGIN_MARKETPLACES,
|
||||||
process.env.INPUT_PLUGINS,
|
process.env.INPUT_PLUGINS,
|
||||||
process.env.INPUT_PATH_TO_CLAUDE_CODE_EXECUTABLE,
|
claudeExecutable,
|
||||||
);
|
);
|
||||||
|
|
||||||
const promptConfig = await preparePrompt({
|
const promptConfig = await preparePrompt({
|
||||||
@ -38,8 +46,7 @@ async function run() {
|
|||||||
appendSystemPrompt: process.env.INPUT_APPEND_SYSTEM_PROMPT,
|
appendSystemPrompt: process.env.INPUT_APPEND_SYSTEM_PROMPT,
|
||||||
fallbackModel: process.env.INPUT_FALLBACK_MODEL,
|
fallbackModel: process.env.INPUT_FALLBACK_MODEL,
|
||||||
model: process.env.ANTHROPIC_MODEL,
|
model: process.env.ANTHROPIC_MODEL,
|
||||||
pathToClaudeCodeExecutable:
|
pathToClaudeCodeExecutable: claudeExecutable,
|
||||||
process.env.INPUT_PATH_TO_CLAUDE_CODE_EXECUTABLE,
|
|
||||||
showFullOutput: process.env.INPUT_SHOW_FULL_OUTPUT,
|
showFullOutput: process.env.INPUT_SHOW_FULL_OUTPUT,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -79,6 +79,20 @@ function mergeMcpConfigs(configValues: string[]): string {
|
|||||||
return JSON.stringify(merged);
|
return JSON.stringify(merged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strip comment lines from a shell argument string.
|
||||||
|
* Lines whose first non-whitespace character is `#` are removed entirely.
|
||||||
|
* Inline `#` within a line (e.g. inside a quoted value) is left untouched
|
||||||
|
* because shell-quote handles quoting — we only need to remove full comment lines
|
||||||
|
* before shell-quote sees them.
|
||||||
|
*/
|
||||||
|
function stripShellComments(input: string): string {
|
||||||
|
return input
|
||||||
|
.split("\n")
|
||||||
|
.filter((line) => !line.trim().startsWith("#"))
|
||||||
|
.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse claudeArgs string into extraArgs record for SDK pass-through
|
* Parse claudeArgs string into extraArgs record for SDK pass-through
|
||||||
* The SDK/CLI will handle --mcp-config, --json-schema, etc.
|
* The SDK/CLI will handle --mcp-config, --json-schema, etc.
|
||||||
@ -92,7 +106,7 @@ function parseClaudeArgsToExtraArgs(
|
|||||||
if (!claudeArgs?.trim()) return {};
|
if (!claudeArgs?.trim()) return {};
|
||||||
|
|
||||||
const result: Record<string, string | null> = {};
|
const result: Record<string, string | null> = {};
|
||||||
const args = parseShellArgs(claudeArgs).filter(
|
const args = parseShellArgs(stripShellComments(claudeArgs)).filter(
|
||||||
(arg): arg is string => typeof arg === "string",
|
(arg): arg is string => typeof arg === "string",
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -215,6 +229,12 @@ export function parseSdkOptions(options: ClaudeOptions): ParsedSdkOptions {
|
|||||||
// Set the entrypoint for Claude Code to identify this as the GitHub Action
|
// Set the entrypoint for Claude Code to identify this as the GitHub Action
|
||||||
env.CLAUDE_CODE_ENTRYPOINT = "claude-code-github-action";
|
env.CLAUDE_CODE_ENTRYPOINT = "claude-code-github-action";
|
||||||
|
|
||||||
|
// Remove OIDC token request variables so Claude cannot mint new tokens.
|
||||||
|
// These are only needed by the action itself (via @actions/core.getIDToken()),
|
||||||
|
// not by the Claude session.
|
||||||
|
delete env.ACTIONS_ID_TOKEN_REQUEST_URL;
|
||||||
|
delete env.ACTIONS_ID_TOKEN_REQUEST_TOKEN;
|
||||||
|
|
||||||
// Build system prompt option - default to claude_code preset
|
// Build system prompt option - default to claude_code preset
|
||||||
let systemPrompt: SdkOptions["systemPrompt"];
|
let systemPrompt: SdkOptions["systemPrompt"];
|
||||||
if (options.systemPrompt) {
|
if (options.systemPrompt) {
|
||||||
|
|||||||
@ -151,7 +151,7 @@ export async function runClaudeWithSdk(
|
|||||||
|
|
||||||
console.log(`Running Claude with prompt from file: ${promptPath}`);
|
console.log(`Running Claude with prompt from file: ${promptPath}`);
|
||||||
// Log SDK options without env (which could contain sensitive data)
|
// Log SDK options without env (which could contain sensitive data)
|
||||||
const { env, ...optionsToLog } = sdkOptions;
|
const { env, extraArgs, ...optionsToLog } = sdkOptions;
|
||||||
console.log("SDK options:", JSON.stringify(optionsToLog, null, 2));
|
console.log("SDK options:", JSON.stringify(optionsToLog, null, 2));
|
||||||
|
|
||||||
const messages: SDKMessage[] = [];
|
const messages: SDKMessage[] = [];
|
||||||
|
|||||||
@ -313,6 +313,40 @@ describe("parseSdkOptions", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("shell comment stripping", () => {
|
||||||
|
test("should parse flags before and after a comment line", () => {
|
||||||
|
const options: ClaudeOptions = {
|
||||||
|
claudeArgs: "--model 'claude-haiku'\n# comment\n--allowed-tools 'Edit'",
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = parseSdkOptions(options);
|
||||||
|
|
||||||
|
expect(result.sdkOptions.extraArgs?.["model"]).toBe("claude-haiku");
|
||||||
|
expect(result.sdkOptions.allowedTools).toEqual(["Edit"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should parse flags correctly when no comments are present", () => {
|
||||||
|
const options: ClaudeOptions = {
|
||||||
|
claudeArgs: "--model 'claude-haiku'",
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = parseSdkOptions(options);
|
||||||
|
|
||||||
|
expect(result.sdkOptions.extraArgs?.["model"]).toBe("claude-haiku");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should not strip inline # that appears inside a quoted value", () => {
|
||||||
|
const options: ClaudeOptions = {
|
||||||
|
claudeArgs: "--model 'claude-haiku' --prompt 'use color #ff0000'",
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = parseSdkOptions(options);
|
||||||
|
|
||||||
|
expect(result.sdkOptions.extraArgs?.["model"]).toBe("claude-haiku");
|
||||||
|
expect(result.sdkOptions.extraArgs?.["prompt"]).toBe("use color #ff0000");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("environment variables passthrough", () => {
|
describe("environment variables passthrough", () => {
|
||||||
test("should include OTEL environment variables in sdkOptions.env", () => {
|
test("should include OTEL environment variables in sdkOptions.env", () => {
|
||||||
// Set up test environment variables
|
// Set up test environment variables
|
||||||
@ -366,5 +400,26 @@ describe("parseSdkOptions", () => {
|
|||||||
"claude-code-github-action",
|
"claude-code-github-action",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("should strip ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN from env", () => {
|
||||||
|
const originalEnv = { ...process.env };
|
||||||
|
process.env.ACTIONS_ID_TOKEN_REQUEST_URL =
|
||||||
|
"https://token.actions.githubusercontent.com";
|
||||||
|
process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = "secret-token-value";
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options: ClaudeOptions = {};
|
||||||
|
const result = parseSdkOptions(options);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
result.sdkOptions.env?.ACTIONS_ID_TOKEN_REQUEST_URL,
|
||||||
|
).toBeUndefined();
|
||||||
|
expect(
|
||||||
|
result.sdkOptions.env?.ACTIONS_ID_TOKEN_REQUEST_TOKEN,
|
||||||
|
).toBeUndefined();
|
||||||
|
} finally {
|
||||||
|
process.env = originalEnv;
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
110
bun.lock
110
bun.lock
@ -7,7 +7,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.10.1",
|
"@actions/core": "^1.10.1",
|
||||||
"@actions/github": "^6.0.1",
|
"@actions/github": "^6.0.1",
|
||||||
"@anthropic-ai/claude-agent-sdk": "^0.2.73",
|
"@anthropic-ai/claude-agent-sdk": "^0.2.123",
|
||||||
"@modelcontextprotocol/sdk": "^1.11.0",
|
"@modelcontextprotocol/sdk": "^1.11.0",
|
||||||
"@octokit/graphql": "^8.2.2",
|
"@octokit/graphql": "^8.2.2",
|
||||||
"@octokit/rest": "^21.1.1",
|
"@octokit/rest": "^21.1.1",
|
||||||
@ -37,41 +37,31 @@
|
|||||||
|
|
||||||
"@actions/io": ["@actions/io@1.1.3", "", {}, "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="],
|
"@actions/io": ["@actions/io@1.1.3", "", {}, "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="],
|
||||||
|
|
||||||
"@anthropic-ai/claude-agent-sdk": ["@anthropic-ai/claude-agent-sdk@0.2.73", "", { "optionalDependencies": { "@img/sharp-darwin-arm64": "^0.34.2", "@img/sharp-darwin-x64": "^0.34.2", "@img/sharp-linux-arm": "^0.34.2", "@img/sharp-linux-arm64": "^0.34.2", "@img/sharp-linux-x64": "^0.34.2", "@img/sharp-linuxmusl-arm64": "^0.34.2", "@img/sharp-linuxmusl-x64": "^0.34.2", "@img/sharp-win32-arm64": "^0.34.2", "@img/sharp-win32-x64": "^0.34.2" }, "peerDependencies": { "zod": "^4.0.0" } }, "sha512-JrHeMl93Q5ai9GMPAffQkSisbbDvD1skU2x6sf6WRzEZw0sK6aTG+XSiZHY2F5aSrfd4G2qUogLHEm6Y8obyOQ=="],
|
"@anthropic-ai/claude-agent-sdk": ["@anthropic-ai/claude-agent-sdk@0.2.123", "", { "dependencies": { "@anthropic-ai/sdk": "^0.81.0", "@modelcontextprotocol/sdk": "^1.29.0" }, "optionalDependencies": { "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.2.123", "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.2.123", "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.2.123", "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.2.123", "@anthropic-ai/claude-agent-sdk-linux-x64": "0.2.123", "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.2.123", "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.2.123", "@anthropic-ai/claude-agent-sdk-win32-x64": "0.2.123" }, "peerDependencies": { "zod": "^4.0.0" } }, "sha512-a4TysYoR9DBdkM9Uwh4J5ub7TwKmRPe5hFiWh4En+IKC+qkk5UFkxFM22c//cZjYZKynHX0ah2t6LUqb+najYA=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk-darwin-arm64": ["@anthropic-ai/claude-agent-sdk-darwin-arm64@0.2.123", "", { "os": "darwin", "cpu": "arm64" }, "sha512-tYAXCjlXZQklsUs0J//gip3fZQRzhlH5OCgvNXV70qe7A1iiwHqO2KPGvEHV1L+deEKQoMZmTaCOrQpN6zju3w=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk-darwin-x64": ["@anthropic-ai/claude-agent-sdk-darwin-x64@0.2.123", "", { "os": "darwin", "cpu": "x64" }, "sha512-AcUC6sTon6z6HculP87KsAOeTMRLBwpovdhcXUTjXUpo/8nplJ7lBEzWjZCHt8FF1KuN/WBy1Z4bDg/59TQDmA=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk-linux-arm64": ["@anthropic-ai/claude-agent-sdk-linux-arm64@0.2.123", "", { "os": "linux", "cpu": "arm64" }, "sha512-7+GnbcF3/aZ8RJ1WmU/ogtPsOpknBAoUPer90MvZuFYBLPT9iI/U7f24gjrOHuYdcbDA5n7jFlhcfIO26F5DJQ=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk-linux-arm64-musl": ["@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.2.123", "", { "os": "linux", "cpu": "arm64" }, "sha512-bYgRiaf2q+yVbGAoUluuhqrEW1zexL34+3HDmK9DneKXa2K2EJpw4M6Sq4XoBD/JezGaemoAP78Xv/M/QUS1OQ=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk-linux-x64": ["@anthropic-ai/claude-agent-sdk-linux-x64@0.2.123", "", { "os": "linux", "cpu": "x64" }, "sha512-Xi+Rwk8uP5vWEnawJOlsk179fr0ATLl5J90MlbLj+puKaX5svEq8ljS+P3zq6zHTJeKh9GKLzPf7bc5YJKwcew=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk-linux-x64-musl": ["@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.2.123", "", { "os": "linux", "cpu": "x64" }, "sha512-IX95lFKhmmndY/YPfWPsVV+C3rLYJmuuq5wCS53p6jYIkCMxH1iGfhBGF1EUWcXO4Uc8yqXFmQ3aaxMzOOPrwA=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk-win32-arm64": ["@anthropic-ai/claude-agent-sdk-win32-arm64@0.2.123", "", { "os": "win32", "cpu": "arm64" }, "sha512-WDZmAQG1rOiqNLZlSXaCjSWmqJvLk2io+vFQWWqSy2b5HCk9pa3PadLiaLztiihyk81wPhH9Q/44kOxdyfEGMw=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk-win32-x64": ["@anthropic-ai/claude-agent-sdk-win32-x64@0.2.123", "", { "os": "win32", "cpu": "x64" }, "sha512-588xrd1i6d4kXQ6FqwL+cgBiN4evRQSi5DCtPa02CZ3VEbuVQBeFlyPlD8tfWtNNeGZ4NM8kjPNNzZz5omezPA=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.81.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-D4K5PvEV6wPiRtVlVsJHIUhHAmOZ6IT/I9rKlTf84gR7GyyAurPJK7z9BOf/AZqC5d1DhYQGJNKRmV+q8dGhgw=="],
|
||||||
|
|
||||||
|
"@babel/runtime": ["@babel/runtime@7.29.2", "", {}, "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g=="],
|
||||||
|
|
||||||
"@fastify/busboy": ["@fastify/busboy@2.1.1", "", {}, "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="],
|
"@fastify/busboy": ["@fastify/busboy@2.1.1", "", {}, "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="],
|
||||||
|
|
||||||
"@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w=="],
|
"@hono/node-server": ["@hono/node-server@1.19.11", "", { "peerDependencies": { "hono": "^4" } }, "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g=="],
|
||||||
|
|
||||||
"@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.4" }, "os": "darwin", "cpu": "x64" }, "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw=="],
|
|
||||||
|
|
||||||
"@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g=="],
|
|
||||||
|
|
||||||
"@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg=="],
|
|
||||||
|
|
||||||
"@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.4", "", { "os": "linux", "cpu": "arm" }, "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A=="],
|
|
||||||
|
|
||||||
"@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw=="],
|
|
||||||
|
|
||||||
"@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw=="],
|
|
||||||
|
|
||||||
"@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw=="],
|
|
||||||
|
|
||||||
"@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg=="],
|
|
||||||
|
|
||||||
"@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.4" }, "os": "linux", "cpu": "arm" }, "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw=="],
|
|
||||||
|
|
||||||
"@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg=="],
|
|
||||||
|
|
||||||
"@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ=="],
|
|
||||||
|
|
||||||
"@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg=="],
|
|
||||||
|
|
||||||
"@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q=="],
|
|
||||||
|
|
||||||
"@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g=="],
|
|
||||||
|
|
||||||
"@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="],
|
|
||||||
|
|
||||||
"@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.16.0", "", { "dependencies": { "ajv": "^6.12.6", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-8ofX7gkZcLj9H9rSd50mCgm3SSF8C7XoclxJuLoV0Cz3rEQ1tv9MZRYYvJtm9n1BiEQQMzSmE/w2AEkNacLYfg=="],
|
"@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.16.0", "", { "dependencies": { "ajv": "^6.12.6", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-8ofX7gkZcLj9H9rSd50mCgm3SSF8C7XoclxJuLoV0Cz3rEQ1tv9MZRYYvJtm9n1BiEQQMzSmE/w2AEkNacLYfg=="],
|
||||||
|
|
||||||
@ -113,6 +103,8 @@
|
|||||||
|
|
||||||
"ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
|
"ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
|
||||||
|
|
||||||
|
"ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="],
|
||||||
|
|
||||||
"asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
|
"asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
|
||||||
|
|
||||||
"before-after-hook": ["before-after-hook@2.2.3", "", {}, "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="],
|
"before-after-hook": ["before-after-hook@2.2.3", "", {}, "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="],
|
||||||
@ -183,6 +175,8 @@
|
|||||||
|
|
||||||
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
|
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
|
||||||
|
|
||||||
|
"fast-uri": ["fast-uri@3.1.0", "", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="],
|
||||||
|
|
||||||
"fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="],
|
"fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="],
|
||||||
|
|
||||||
"finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="],
|
"finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="],
|
||||||
@ -209,20 +203,30 @@
|
|||||||
|
|
||||||
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
|
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
|
||||||
|
|
||||||
|
"hono": ["hono@4.12.9", "", {}, "sha512-wy3T8Zm2bsEvxKZM5w21VdHDDcwVS1yUFFY6i8UobSsKfFceT7TOwhbhfKsDyx7tYQlmRM5FLpIuYvNFyjctiA=="],
|
||||||
|
|
||||||
"http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="],
|
"http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="],
|
||||||
|
|
||||||
"iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
|
"iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
|
||||||
|
|
||||||
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
||||||
|
|
||||||
|
"ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="],
|
||||||
|
|
||||||
"ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
|
"ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
|
||||||
|
|
||||||
"is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="],
|
"is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="],
|
||||||
|
|
||||||
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||||
|
|
||||||
|
"jose": ["jose@6.2.2", "", {}, "sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ=="],
|
||||||
|
|
||||||
|
"json-schema-to-ts": ["json-schema-to-ts@3.1.1", "", { "dependencies": { "@babel/runtime": "^7.18.3", "ts-algebra": "^2.0.0" } }, "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g=="],
|
||||||
|
|
||||||
"json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
|
"json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
|
||||||
|
|
||||||
|
"json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="],
|
||||||
|
|
||||||
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
||||||
|
|
||||||
"media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
|
"media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
|
||||||
@ -269,6 +273,8 @@
|
|||||||
|
|
||||||
"raw-body": ["raw-body@3.0.0", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.6.3", "unpipe": "1.0.0" } }, "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g=="],
|
"raw-body": ["raw-body@3.0.0", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.6.3", "unpipe": "1.0.0" } }, "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g=="],
|
||||||
|
|
||||||
|
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
|
||||||
|
|
||||||
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
|
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
|
||||||
|
|
||||||
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
||||||
@ -299,6 +305,8 @@
|
|||||||
|
|
||||||
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
|
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
|
||||||
|
|
||||||
|
"ts-algebra": ["ts-algebra@2.0.0", "", {}, "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw=="],
|
||||||
|
|
||||||
"tunnel": ["tunnel@0.0.6", "", {}, "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="],
|
"tunnel": ["tunnel@0.0.6", "", {}, "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="],
|
||||||
|
|
||||||
"type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
|
"type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
|
||||||
@ -327,6 +335,8 @@
|
|||||||
|
|
||||||
"zod-to-json-schema": ["zod-to-json-schema@3.24.6", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg=="],
|
"zod-to-json-schema": ["zod-to-json-schema@3.24.6", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk/@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.29.0", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ=="],
|
||||||
|
|
||||||
"@octokit/core/@octokit/graphql": ["@octokit/graphql@7.1.1", "", { "dependencies": { "@octokit/request": "^8.4.1", "@octokit/types": "^13.0.0", "universal-user-agent": "^6.0.0" } }, "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g=="],
|
"@octokit/core/@octokit/graphql": ["@octokit/graphql@7.1.1", "", { "dependencies": { "@octokit/request": "^8.4.1", "@octokit/types": "^13.0.0", "universal-user-agent": "^6.0.0" } }, "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g=="],
|
||||||
|
|
||||||
"@octokit/core/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="],
|
"@octokit/core/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="],
|
||||||
@ -359,12 +369,24 @@
|
|||||||
|
|
||||||
"accepts/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
|
"accepts/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
|
||||||
|
|
||||||
|
"ajv-formats/ajv": ["ajv@8.18.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A=="],
|
||||||
|
|
||||||
"express/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
|
"express/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
|
||||||
|
|
||||||
"send/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
|
"send/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
|
||||||
|
|
||||||
"type-is/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
|
"type-is/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk/@modelcontextprotocol/sdk/ajv": ["ajv@8.18.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk/@modelcontextprotocol/sdk/express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk/@modelcontextprotocol/sdk/express-rate-limit": ["express-rate-limit@8.3.1", "", { "dependencies": { "ip-address": "10.1.0" }, "peerDependencies": { "express": ">= 4.11" } }, "sha512-D1dKN+cmyPWuvB+G2SREQDzPY1agpBIcTa9sJxOPMCNeH3gwzhqJRDWCXW3gg0y//+LQ/8j52JbMROWyrKdMdw=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk/@modelcontextprotocol/sdk/raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk/@modelcontextprotocol/sdk/zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="],
|
||||||
|
|
||||||
"@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
|
"@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
|
||||||
|
|
||||||
"@octokit/endpoint/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
|
"@octokit/endpoint/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
|
||||||
@ -403,12 +425,24 @@
|
|||||||
|
|
||||||
"accepts/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
"accepts/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
||||||
|
|
||||||
|
"ajv-formats/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
|
||||||
|
|
||||||
"express/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
"express/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
||||||
|
|
||||||
"send/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
"send/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
||||||
|
|
||||||
"type-is/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
"type-is/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk/@modelcontextprotocol/sdk/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk/@modelcontextprotocol/sdk/express/body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk/@modelcontextprotocol/sdk/express/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk/@modelcontextprotocol/sdk/raw-body/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=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk/@modelcontextprotocol/sdk/raw-body/iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="],
|
||||||
|
|
||||||
"@octokit/plugin-request-log/@octokit/core/@octokit/request/@octokit/endpoint": ["@octokit/endpoint@10.1.4", "", { "dependencies": { "@octokit/types": "^14.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-OlYOlZIsfEVZm5HCSR8aSg02T2lbUWOsCQoPKfTXJwDzcHQBrVBGdGXb89dv2Kw2ToZaRtudp8O3ZIYoaOjKlA=="],
|
"@octokit/plugin-request-log/@octokit/core/@octokit/request/@octokit/endpoint": ["@octokit/endpoint@10.1.4", "", { "dependencies": { "@octokit/types": "^14.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-OlYOlZIsfEVZm5HCSR8aSg02T2lbUWOsCQoPKfTXJwDzcHQBrVBGdGXb89dv2Kw2ToZaRtudp8O3ZIYoaOjKlA=="],
|
||||||
|
|
||||||
"@octokit/rest/@octokit/core/@octokit/request/@octokit/endpoint": ["@octokit/endpoint@10.1.4", "", { "dependencies": { "@octokit/types": "^14.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-OlYOlZIsfEVZm5HCSR8aSg02T2lbUWOsCQoPKfTXJwDzcHQBrVBGdGXb89dv2Kw2ToZaRtudp8O3ZIYoaOjKlA=="],
|
"@octokit/rest/@octokit/core/@octokit/request/@octokit/endpoint": ["@octokit/endpoint@10.1.4", "", { "dependencies": { "@octokit/types": "^14.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-OlYOlZIsfEVZm5HCSR8aSg02T2lbUWOsCQoPKfTXJwDzcHQBrVBGdGXb89dv2Kw2ToZaRtudp8O3ZIYoaOjKlA=="],
|
||||||
@ -416,5 +450,15 @@
|
|||||||
"@octokit/rest/@octokit/plugin-paginate-rest/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
|
"@octokit/rest/@octokit/plugin-paginate-rest/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
|
||||||
|
|
||||||
"@octokit/rest/@octokit/plugin-rest-endpoint-methods/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
|
"@octokit/rest/@octokit/plugin-rest-endpoint-methods/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk/@modelcontextprotocol/sdk/express/body-parser/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk/@modelcontextprotocol/sdk/express/body-parser/iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk/@modelcontextprotocol/sdk/express/body-parser/qs": ["qs@6.15.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk/@modelcontextprotocol/sdk/express/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
||||||
|
|
||||||
|
"@anthropic-ai/claude-agent-sdk/@modelcontextprotocol/sdk/raw-body/http-errors/statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
bunfig.toml
Normal file
2
bunfig.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Intentionally minimal. action.yml pins --config to this file so bun resolves
|
||||||
|
# its runtime config from the action directory rather than the workspace.
|
||||||
@ -13,10 +13,46 @@
|
|||||||
- Accepts either a comma-separated list of specific usernames or `*` to allow all users
|
- Accepts either a comma-separated list of specific usernames or `*` to allow all users
|
||||||
- **Should be used with extreme caution** as it bypasses the primary security mechanism of this action
|
- **Should be used with extreme caution** as it bypasses the primary security mechanism of this action
|
||||||
- Is designed for automation workflows where user permissions are already restricted by the workflow's permission scope
|
- Is designed for automation workflows where user permissions are already restricted by the workflow's permission scope
|
||||||
|
- When set, Claude does a best-effort scrub of Anthropic, cloud, and GitHub Actions secrets from subprocess environments. On Linux runners with bubblewrap available, subprocesses additionally run with PID-namespace isolation. This reduces but does not eliminate prompt injection risk — keep workflow permissions minimal and validate all outputs. Set `CLAUDE_CODE_SUBPROCESS_ENV_SCRUB: 0` in your workflow or job `env:` block to opt out.
|
||||||
|
- Optionally set `CLAUDE_CODE_SCRIPT_CAPS` in your workflow `env:` block to limit how many times Claude can call specific scripts per run. Value is JSON: `{"script-name.sh": maxCalls}`. Example: `CLAUDE_CODE_SCRIPT_CAPS: '{"edit-issue-labels.sh":2}'` allows at most 2 calls to `edit-issue-labels.sh`. Useful for write-capable helper scripts.
|
||||||
|
- When using `allowed_non_write_users`, always pass `github_token: ${{ secrets.GITHUB_TOKEN }}`. The auto-generated workflow token is scoped to the job's declared permissions and expires when the job completes. **Do not use a personal access token** — a static token does not rotate between runs and could be partially or fully recovered over time via prompt injection. Restricting allowed tools via `claude_args` reduces the rate of recovery but may not eliminate the risk. We recommend restricting allowed tools (e.g. `claude_args: '--allowedTools "Bash(gh issue view:*)"'`) to the minimum required when using `allowed_non_write_users`.
|
||||||
- **Token Permissions**: The GitHub app receives only a short-lived token scoped specifically to the repository it's operating in
|
- **Token Permissions**: The GitHub app receives only a short-lived token scoped specifically to the repository it's operating in
|
||||||
- **No Cross-Repository Access**: Each action invocation is limited to the repository where it was triggered
|
- **No Cross-Repository Access**: Each action invocation is limited to the repository where it was triggered
|
||||||
- **Limited Scope**: The token cannot access other repositories or perform actions beyond the configured permissions
|
- **Limited Scope**: The token cannot access other repositories or perform actions beyond the configured permissions
|
||||||
|
|
||||||
|
## Using this action with `pull_request_target` or `workflow_run`
|
||||||
|
|
||||||
|
`pull_request_target` and `workflow_run` execute with the **base repository's secrets**. If your workflow checks out the PR head (`ref: ${{ github.event.pull_request.head.sha }}` for `pull_request_target`, `ref: ${{ github.event.workflow_run.head_sha }}` for `workflow_run`) into `$GITHUB_WORKSPACE` before this action, the action and Claude run with that checkout as the working directory.
|
||||||
|
|
||||||
|
**Do not check out an untrusted ref into the workspace root before this action.** Use one of these patterns instead:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Preferred — check out the base ref (default).
|
||||||
|
- uses: actions/checkout@v6 # no `ref:` → base branch
|
||||||
|
- uses: anthropics/claude-code-action@v1
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# If you need the PR's files locally — check out the base ref at the workspace
|
||||||
|
# root (this action expects a git repo there), then check out the head ref into
|
||||||
|
# a subdirectory and pass it via --add-dir.
|
||||||
|
- uses: actions/checkout@v6 # no `ref:` → base branch at workspace root
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
# For workflow_run use: ${{ github.event.workflow_run.head_sha }}
|
||||||
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
|
path: pr-head
|
||||||
|
- uses: anthropics/claude-code-action@v1
|
||||||
|
with:
|
||||||
|
claude_args: "--add-dir pr-head"
|
||||||
|
```
|
||||||
|
|
||||||
|
This is general guidance for these event types — see [GitHub's documentation](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/).
|
||||||
|
|
||||||
|
### `claude-code-action` vs `claude-code-base-action`
|
||||||
|
|
||||||
|
`claude-code-base-action` is a lower-level building block that installs and runs Claude Code with the inputs you provide. It does not perform actor permission checks or restore project configuration from the base ref. If you need those behaviors, use this action (`claude-code-action`). See the [base-action README](../base-action/README.md#trust-model) for details.
|
||||||
|
|
||||||
## Pull Request Creation
|
## Pull Request Creation
|
||||||
|
|
||||||
In its default configuration, **Claude does not create pull requests automatically** when responding to `@claude` mentions. Instead:
|
In its default configuration, **Claude does not create pull requests automatically** when responding to `@claude` mentions. Instead:
|
||||||
@ -31,6 +67,8 @@ This design ensures that users retain full control over what pull requests are c
|
|||||||
|
|
||||||
**Beware of potential hidden markdown when tagging Claude on untrusted content.** External contributors may include hidden instructions through HTML comments, invisible characters, hidden attributes, or other techniques. The action sanitizes content by stripping HTML comments, invisible characters, markdown image alt text, hidden HTML attributes, and HTML entities, but new bypass techniques may emerge. We recommend reviewing the raw content of all input coming from external contributors before allowing Claude to process it.
|
**Beware of potential hidden markdown when tagging Claude on untrusted content.** External contributors may include hidden instructions through HTML comments, invisible characters, hidden attributes, or other techniques. The action sanitizes content by stripping HTML comments, invisible characters, markdown image alt text, hidden HTML attributes, and HTML entities, but new bypass techniques may emerge. We recommend reviewing the raw content of all input coming from external contributors before allowing Claude to process it.
|
||||||
|
|
||||||
|
On public repos, you can also use `include_comments_by_actor` to allowlist which users' comments are passed to Claude, reducing exposure to untrusted input. Use `exclude_comments_by_actor` to filter out noisy bot comments (e.g., `dependabot[bot]`, `renovate[bot]`). If an actor matches both lists, exclusion takes priority. See [Usage](./usage.md) for details.
|
||||||
|
|
||||||
## GitHub App Permissions
|
## GitHub App Permissions
|
||||||
|
|
||||||
The [Claude Code GitHub app](https://github.com/apps/claude) requests the following permissions:
|
The [Claude Code GitHub app](https://github.com/apps/claude) requests the following permissions:
|
||||||
|
|||||||
@ -421,7 +421,8 @@ jobs:
|
|||||||
- `./scripts/gh.sh label list` to see available labels
|
- `./scripts/gh.sh label list` to see available labels
|
||||||
|
|
||||||
Based on your analysis, add the appropriate labels using:
|
Based on your analysis, add the appropriate labels using:
|
||||||
`./scripts/edit-issue-labels.sh --issue [number] --add-label "label1" --add-label "label2"`
|
`./scripts/edit-issue-labels.sh --add-label "label1" --add-label "label2"`
|
||||||
|
(the issue number is read automatically from the workflow event)
|
||||||
|
|
||||||
If it appears to be a duplicate, post a comment mentioning the original issue.
|
If it appears to be a duplicate, post a comment mentioning the original issue.
|
||||||
|
|
||||||
|
|||||||
@ -76,6 +76,8 @@ jobs:
|
|||||||
| `ssh_signing_key` | SSH private key for signing commits. Enables signed commits with full git CLI support (rebasing, etc.). See [Security](./security.md#commit-signing) | No | "" |
|
| `ssh_signing_key` | SSH private key for signing commits. Enables signed commits with full git CLI support (rebasing, etc.). See [Security](./security.md#commit-signing) | No | "" |
|
||||||
| `bot_id` | GitHub user ID to use for git operations (defaults to Claude's bot ID). Required with `ssh_signing_key` for verified commits | No | `41898282` |
|
| `bot_id` | GitHub user ID to use for git operations (defaults to Claude's bot ID). Required with `ssh_signing_key` for verified commits | No | `41898282` |
|
||||||
| `bot_name` | GitHub username to use for git operations (defaults to Claude's bot name). Required with `ssh_signing_key` for verified commits | No | `claude[bot]` |
|
| `bot_name` | GitHub username to use for git operations (defaults to Claude's bot name). Required with `ssh_signing_key` for verified commits | No | `claude[bot]` |
|
||||||
|
| `include_comments_by_actor` | Comma-separated list of actor usernames to INCLUDE in comments. Supports the `*[bot]` wildcard to match all bot accounts. Empty (default) includes all actors | No | "" |
|
||||||
|
| `exclude_comments_by_actor` | Comma-separated list of actor usernames to EXCLUDE from comments. Supports the `*[bot]` wildcard to match all bot accounts. If an actor matches both lists, exclusion takes priority | No | "" |
|
||||||
| `allowed_bots` | Comma-separated list of allowed bot usernames, or '\*' to allow all bots. Empty string (default) allows no bots. **⚠️ On public repos with `'*'`, external Apps may be able to invoke this action.** See [Security](./security.md) | No | "" |
|
| `allowed_bots` | Comma-separated list of allowed bot usernames, or '\*' to allow all bots. Empty string (default) allows no bots. **⚠️ On public repos with `'*'`, external Apps may be able to invoke this action.** See [Security](./security.md) | No | "" |
|
||||||
| `allowed_non_write_users` | **⚠️ RISKY**: Comma-separated list of usernames to allow without write permissions, or '\*' for all users. Only works with `github_token` input. See [Security](./security.md) | No | "" |
|
| `allowed_non_write_users` | **⚠️ RISKY**: Comma-separated list of usernames to allow without write permissions, or '\*' for all users. Only works with `github_token` input. See [Security](./security.md) | No | "" |
|
||||||
| `path_to_claude_code_executable` | Optional path to a custom Claude Code executable. Skips automatic installation. Useful for Nix, custom containers, or specialized environments | No | "" |
|
| `path_to_claude_code_executable` | Optional path to a custom Claude Code executable. Skips automatic installation. Useful for Nix, custom containers, or specialized environments | No | "" |
|
||||||
|
|||||||
@ -1,5 +1,21 @@
|
|||||||
name: Auto Fix CI Failures
|
name: Auto Fix CI Failures
|
||||||
|
|
||||||
|
# ⚠️ SECURITY NOTE
|
||||||
|
#
|
||||||
|
# This workflow checks out the PR branch and runs build/test commands
|
||||||
|
# (npm, bun, etc.) against it with elevated permissions (contents:write,
|
||||||
|
# id-token:write). This means code from the PR branch executes in a
|
||||||
|
# trusted context with access to secrets and the ability to push to the
|
||||||
|
# repository.
|
||||||
|
#
|
||||||
|
# Only use this workflow in repositories where everyone with write access
|
||||||
|
# is fully trusted with these permissions. Do not use this in repositories
|
||||||
|
# that accept contributions from untrusted or semi-trusted collaborators.
|
||||||
|
#
|
||||||
|
# The pull_requests[0] check below limits this to same-repo PRs (fork PRs
|
||||||
|
# are excluded), but anyone who can push a branch to this repository can
|
||||||
|
# control what code runs here.
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_run:
|
workflow_run:
|
||||||
workflows: ["CI"]
|
workflows: ["CI"]
|
||||||
@ -35,10 +51,14 @@ jobs:
|
|||||||
|
|
||||||
- name: Create fix branch
|
- name: Create fix branch
|
||||||
id: branch
|
id: branch
|
||||||
|
env:
|
||||||
|
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
|
||||||
|
RUN_ID: ${{ github.run_id }}
|
||||||
run: |
|
run: |
|
||||||
BRANCH_NAME="claude-auto-fix-ci-${{ github.event.workflow_run.head_branch }}-${{ github.run_id }}"
|
SAFE_BRANCH=$(printf '%s' "$HEAD_BRANCH" | tr -cd 'a-zA-Z0-9/_.-')
|
||||||
|
BRANCH_NAME="claude-auto-fix-ci-${SAFE_BRANCH}-${RUN_ID}"
|
||||||
git checkout -b "$BRANCH_NAME"
|
git checkout -b "$BRANCH_NAME"
|
||||||
echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT
|
echo "branch_name=$BRANCH_NAME" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Get CI failure details
|
- name: Get CI failure details
|
||||||
id: failure_details
|
id: failure_details
|
||||||
|
|||||||
@ -53,6 +53,8 @@ jobs:
|
|||||||
fromJSON(steps.detect.outputs.structured_output).confidence >= 0.7
|
fromJSON(steps.detect.outputs.structured_output).confidence >= 0.7
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
WORKFLOW_NAME: ${{ github.event.workflow_run.name }}
|
||||||
|
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
|
||||||
run: |
|
run: |
|
||||||
OUTPUT='${{ steps.detect.outputs.structured_output }}'
|
OUTPUT='${{ steps.detect.outputs.structured_output }}'
|
||||||
CONFIDENCE=$(echo "$OUTPUT" | jq -r '.confidence')
|
CONFIDENCE=$(echo "$OUTPUT" | jq -r '.confidence')
|
||||||
@ -63,8 +65,7 @@ jobs:
|
|||||||
echo ""
|
echo ""
|
||||||
echo "Triggering automatic retry..."
|
echo "Triggering automatic retry..."
|
||||||
|
|
||||||
gh workflow run "${{ github.event.workflow_run.name }}" \
|
gh workflow run "$WORKFLOW_NAME" --ref "$HEAD_BRANCH"
|
||||||
--ref "${{ github.event.workflow_run.head_branch }}"
|
|
||||||
|
|
||||||
# Low confidence flaky detection - skip retry
|
# Low confidence flaky detection - skip retry
|
||||||
- name: Low confidence detection
|
- name: Low confidence detection
|
||||||
@ -83,13 +84,14 @@ jobs:
|
|||||||
if: github.event.workflow_run.event == 'pull_request'
|
if: github.event.workflow_run.event == 'pull_request'
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
|
||||||
run: |
|
run: |
|
||||||
OUTPUT='${{ steps.detect.outputs.structured_output }}'
|
OUTPUT='${{ steps.detect.outputs.structured_output }}'
|
||||||
IS_FLAKY=$(echo "$OUTPUT" | jq -r '.is_flaky')
|
IS_FLAKY=$(echo "$OUTPUT" | jq -r '.is_flaky')
|
||||||
CONFIDENCE=$(echo "$OUTPUT" | jq -r '.confidence')
|
CONFIDENCE=$(echo "$OUTPUT" | jq -r '.confidence')
|
||||||
SUMMARY=$(echo "$OUTPUT" | jq -r '.summary')
|
SUMMARY=$(echo "$OUTPUT" | jq -r '.summary')
|
||||||
|
|
||||||
pr_number=$(gh pr list --head "${{ github.event.workflow_run.head_branch }}" --json number --jq '.[0].number')
|
pr_number=$(gh pr list --head "$HEAD_BRANCH" --json number --jq '.[0].number')
|
||||||
|
|
||||||
if [ -n "$pr_number" ]; then
|
if [ -n "$pr_number" ]; then
|
||||||
if [ "$IS_FLAKY" = "true" ]; then
|
if [ "$IS_FLAKY" = "true" ]; then
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.10.1",
|
"@actions/core": "^1.10.1",
|
||||||
"@actions/github": "^6.0.1",
|
"@actions/github": "^6.0.1",
|
||||||
"@anthropic-ai/claude-agent-sdk": "^0.2.73",
|
"@anthropic-ai/claude-agent-sdk": "^0.2.123",
|
||||||
"@modelcontextprotocol/sdk": "^1.11.0",
|
"@modelcontextprotocol/sdk": "^1.11.0",
|
||||||
"@octokit/graphql": "^8.2.2",
|
"@octokit/graphql": "^8.2.2",
|
||||||
"@octokit/rest": "^21.1.1",
|
"@octokit/rest": "^21.1.1",
|
||||||
|
|||||||
@ -1,22 +1,26 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
#
|
#
|
||||||
# Edits labels on a GitHub issue.
|
# Edits labels on a GitHub issue.
|
||||||
# Usage: ./scripts/edit-issue-labels.sh --issue 123 --add-label bug --add-label needs-triage --remove-label untriaged
|
# Usage: ./scripts/edit-issue-labels.sh --add-label bug --add-label needs-triage --remove-label untriaged
|
||||||
|
#
|
||||||
|
# The issue number is read from the workflow event payload.
|
||||||
#
|
#
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ISSUE=""
|
# Read from event payload so the issue number is bound to the triggering event
|
||||||
|
ISSUE=$(jq -r '.issue.number // empty' "${GITHUB_EVENT_PATH:?GITHUB_EVENT_PATH not set}")
|
||||||
|
if ! [[ "$ISSUE" =~ ^[0-9]+$ ]]; then
|
||||||
|
echo "Error: no issue number in event payload" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
ADD_LABELS=()
|
ADD_LABELS=()
|
||||||
REMOVE_LABELS=()
|
REMOVE_LABELS=()
|
||||||
|
|
||||||
# Parse arguments
|
# Parse arguments
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
case $1 in
|
case $1 in
|
||||||
--issue)
|
|
||||||
ISSUE="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
--add-label)
|
--add-label)
|
||||||
ADD_LABELS+=("$2")
|
ADD_LABELS+=("$2")
|
||||||
shift 2
|
shift 2
|
||||||
@ -26,20 +30,12 @@ while [[ $# -gt 0 ]]; do
|
|||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
|
echo "Error: unknown argument (only --add-label and --remove-label are accepted)" >&2
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
# Validate issue number
|
|
||||||
if [[ -z "$ISSUE" ]]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! [[ "$ISSUE" =~ ^[0-9]+$ ]]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${#ADD_LABELS[@]} -eq 0 && ${#REMOVE_LABELS[@]} -eq 0 ]]; then
|
if [[ ${#ADD_LABELS[@]} -eq 0 && ${#REMOVE_LABELS[@]} -eq 0 ]]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
36
scripts/git-push.sh
Executable file
36
scripts/git-push.sh
Executable file
@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Wrapper around `git push` that only allows `origin <ref>` with no flags.
|
||||||
|
# Defends against --receive-pack / --exec RCE and arbitrary-remote exfiltration
|
||||||
|
# (H1 #3556799). `git push:*` in allowedTools permits `git push --receive-pack='sh -c ...' ext::sh`
|
||||||
|
# which runs arbitrary shell on the Actions runner. This wrapper closes that.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# git-push.sh origin HEAD
|
||||||
|
# git-push.sh origin claude/issue-123-20260304
|
||||||
|
|
||||||
|
if [[ $# -ne 2 ]]; then
|
||||||
|
echo "Error: exactly two arguments required: origin <ref>" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
for arg in "$@"; do
|
||||||
|
if [[ "$arg" == -* ]]; then
|
||||||
|
echo "Error: flags are not allowed (got: $arg)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ "$1" != "origin" ]]; then
|
||||||
|
echo "Error: remote must be 'origin' (got: $1)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
REF="$2"
|
||||||
|
if [[ "$REF" != "HEAD" ]] && ! git check-ref-format --branch "$REF" >/dev/null 2>&1; then
|
||||||
|
echo "Error: invalid ref: $REF" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec git push origin "$REF"
|
||||||
@ -23,19 +23,15 @@ import { GITHUB_SERVER_URL } from "../github/api/config";
|
|||||||
import { extractUserRequest } from "../utils/extract-user-request";
|
import { extractUserRequest } from "../utils/extract-user-request";
|
||||||
export type { CommonFields, PreparedContext } from "./types";
|
export type { CommonFields, PreparedContext } from "./types";
|
||||||
|
|
||||||
|
const GIT_PUSH_WRAPPER = `${process.env.GITHUB_ACTION_PATH}/scripts/git-push.sh`;
|
||||||
|
|
||||||
/** Filename for the user request file, read by the SDK runner */
|
/** Filename for the user request file, read by the SDK runner */
|
||||||
const USER_REQUEST_FILENAME = "claude-user-request.txt";
|
const USER_REQUEST_FILENAME = "claude-user-request.txt";
|
||||||
|
|
||||||
// Tag mode defaults - these tools are needed for tag mode to function
|
// Tag mode defaults - these tools are needed for tag mode to function.
|
||||||
const BASE_ALLOWED_TOOLS = [
|
// Edit/MultiEdit/Write are intentionally omitted: acceptEdits permission mode
|
||||||
"Edit",
|
// auto-allows file edits inside $GITHUB_WORKSPACE and denies writes outside it.
|
||||||
"MultiEdit",
|
const BASE_ALLOWED_TOOLS = ["Glob", "Grep", "LS", "Read"];
|
||||||
"Glob",
|
|
||||||
"Grep",
|
|
||||||
"LS",
|
|
||||||
"Read",
|
|
||||||
"Write",
|
|
||||||
];
|
|
||||||
|
|
||||||
export function buildAllowedToolsString(
|
export function buildAllowedToolsString(
|
||||||
customAllowedTools?: string[],
|
customAllowedTools?: string[],
|
||||||
@ -59,10 +55,7 @@ export function buildAllowedToolsString(
|
|||||||
baseTools.push(
|
baseTools.push(
|
||||||
"Bash(git add:*)",
|
"Bash(git add:*)",
|
||||||
"Bash(git commit:*)",
|
"Bash(git commit:*)",
|
||||||
"Bash(git push:*)",
|
`Bash(${GIT_PUSH_WRAPPER}:*)`,
|
||||||
"Bash(git status:*)",
|
|
||||||
"Bash(git diff:*)",
|
|
||||||
"Bash(git log:*)",
|
|
||||||
"Bash(git rm:*)",
|
"Bash(git rm:*)",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -434,7 +427,7 @@ function getCommitInstructions(
|
|||||||
Bash(git commit -m "<message>\\n\\n${coAuthorLine}")`
|
Bash(git commit -m "<message>\\n\\n${coAuthorLine}")`
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
- Push to the remote: Bash(git push origin HEAD)`;
|
- Push to the remote: Bash(${GIT_PUSH_WRAPPER} origin HEAD)`;
|
||||||
} else {
|
} else {
|
||||||
const branchName = eventData.claudeBranch || eventData.baseBranch;
|
const branchName = eventData.claudeBranch || eventData.baseBranch;
|
||||||
return `
|
return `
|
||||||
@ -448,7 +441,7 @@ function getCommitInstructions(
|
|||||||
Bash(git commit -m "<message>\\n\\n${coAuthorLine}")`
|
Bash(git commit -m "<message>\\n\\n${coAuthorLine}")`
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
- Push to the remote: Bash(git push origin ${branchName})`;
|
- Push to the remote: Bash(${GIT_PUSH_WRAPPER} origin ${branchName})`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -823,7 +816,7 @@ ${
|
|||||||
: `- Use git commands via the Bash tool for version control (remember that you have access to these git commands):
|
: `- Use git commands via the Bash tool for version control (remember that you have access to these git commands):
|
||||||
- Stage files: Bash(git add <files>)
|
- Stage files: Bash(git add <files>)
|
||||||
- Commit changes: Bash(git commit -m "<message>")
|
- Commit changes: Bash(git commit -m "<message>")
|
||||||
- Push to remote: Bash(git push origin <branch>) (NEVER force push)
|
- Push to remote: Bash(${GIT_PUSH_WRAPPER} origin <branch>)
|
||||||
- Delete files: Bash(git rm <files>) followed by commit and push
|
- Delete files: Bash(git rm <files>) followed by commit and push
|
||||||
- Check status: Bash(git status)
|
- Check status: Bash(git status)
|
||||||
- View diff: Bash(git diff)${eventData.isPR && eventData.baseBranch ? `\n - IMPORTANT: For PR diffs, use: Bash(git diff origin/${eventData.baseBranch}...HEAD)` : ""}`
|
- View diff: Bash(git diff)${eventData.isPR && eventData.baseBranch ? `\n - IMPORTANT: For PR diffs, use: Bash(git diff origin/${eventData.baseBranch}...HEAD)` : ""}`
|
||||||
@ -977,7 +970,9 @@ export async function createPrompt(
|
|||||||
console.log("========================");
|
console.log("========================");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set allowed tools
|
// NOTE: these env var exports are dead — nothing reads ALLOWED_TOOLS / DISALLOWED_TOOLS.
|
||||||
|
// The live path is modes/tag/index.ts which builds --allowedTools into claudeArgs directly.
|
||||||
|
// Kept only so the H1 report's pointed-to file stays in sync with the live fix.
|
||||||
const hasActionsReadPermission = false;
|
const hasActionsReadPermission = false;
|
||||||
|
|
||||||
const allAllowedTools = buildAllowedToolsString(
|
const allAllowedTools = buildAllowedToolsString(
|
||||||
|
|||||||
@ -15,12 +15,20 @@ import { setupGitHubToken, WorkflowValidationSkipError } from "../github/token";
|
|||||||
import { checkWritePermissions } from "../github/validation/permissions";
|
import { checkWritePermissions } from "../github/validation/permissions";
|
||||||
import { createOctokit } from "../github/api/client";
|
import { createOctokit } from "../github/api/client";
|
||||||
import type { Octokits } from "../github/api/client";
|
import type { Octokits } from "../github/api/client";
|
||||||
import { parseGitHubContext, isEntityContext } from "../github/context";
|
import {
|
||||||
|
parseGitHubContext,
|
||||||
|
isEntityContext,
|
||||||
|
isPullRequestEvent,
|
||||||
|
isPullRequestReviewEvent,
|
||||||
|
isPullRequestReviewCommentEvent,
|
||||||
|
} from "../github/context";
|
||||||
import type { GitHubContext } from "../github/context";
|
import type { GitHubContext } from "../github/context";
|
||||||
import { detectMode } from "../modes/detector";
|
import { detectMode } from "../modes/detector";
|
||||||
import { prepareTagMode } from "../modes/tag";
|
import { prepareTagMode } from "../modes/tag";
|
||||||
import { prepareAgentMode } from "../modes/agent";
|
import { prepareAgentMode } from "../modes/agent";
|
||||||
import { checkContainsTrigger } from "../github/validation/trigger";
|
import { checkContainsTrigger } from "../github/validation/trigger";
|
||||||
|
import { restoreConfigFromBase } from "../github/operations/restore-config";
|
||||||
|
import { validateBranchName } from "../github/operations/branch";
|
||||||
import { collectActionInputsPresence } from "./collect-inputs";
|
import { collectActionInputsPresence } from "./collect-inputs";
|
||||||
import { updateCommentLink } from "./update-comment-link";
|
import { updateCommentLink } from "./update-comment-link";
|
||||||
import { formatTurnsFromData } from "./format-turns";
|
import { formatTurnsFromData } from "./format-turns";
|
||||||
@ -35,10 +43,16 @@ import type { ClaudeRunResult } from "../../base-action/src/run-claude-sdk";
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Install Claude Code CLI, handling retry logic and custom executable paths.
|
* Install Claude Code CLI, handling retry logic and custom executable paths.
|
||||||
|
* Returns the absolute path to the claude executable.
|
||||||
*/
|
*/
|
||||||
async function installClaudeCode(): Promise<void> {
|
async function installClaudeCode(): Promise<string> {
|
||||||
const customExecutable = process.env.PATH_TO_CLAUDE_CODE_EXECUTABLE;
|
const customExecutable = process.env.PATH_TO_CLAUDE_CODE_EXECUTABLE;
|
||||||
if (customExecutable) {
|
if (customExecutable) {
|
||||||
|
if (/[\x00-\x1f\x7f]/.test(customExecutable)) {
|
||||||
|
throw new Error(
|
||||||
|
"PATH_TO_CLAUDE_CODE_EXECUTABLE contains control characters (e.g. newlines), which is not allowed",
|
||||||
|
);
|
||||||
|
}
|
||||||
console.log(`Using custom Claude Code executable: ${customExecutable}`);
|
console.log(`Using custom Claude Code executable: ${customExecutable}`);
|
||||||
const claudeDir = dirname(customExecutable);
|
const claudeDir = dirname(customExecutable);
|
||||||
// Add to PATH by appending to GITHUB_PATH
|
// Add to PATH by appending to GITHUB_PATH
|
||||||
@ -48,10 +62,10 @@ async function installClaudeCode(): Promise<void> {
|
|||||||
}
|
}
|
||||||
// Also add to current process PATH
|
// Also add to current process PATH
|
||||||
process.env.PATH = `${claudeDir}:${process.env.PATH}`;
|
process.env.PATH = `${claudeDir}:${process.env.PATH}`;
|
||||||
return;
|
return customExecutable;
|
||||||
}
|
}
|
||||||
|
|
||||||
const claudeCodeVersion = "2.1.73";
|
const claudeCodeVersion = "2.1.123";
|
||||||
console.log(`Installing Claude Code v${claudeCodeVersion}...`);
|
console.log(`Installing Claude Code v${claudeCodeVersion}...`);
|
||||||
|
|
||||||
for (let attempt = 1; attempt <= 3; attempt++) {
|
for (let attempt = 1; attempt <= 3; attempt++) {
|
||||||
@ -80,7 +94,7 @@ async function installClaudeCode(): Promise<void> {
|
|||||||
await appendFile(githubPath, `${homeBin}\n`);
|
await appendFile(githubPath, `${homeBin}\n`);
|
||||||
}
|
}
|
||||||
process.env.PATH = `${homeBin}:${process.env.PATH}`;
|
process.env.PATH = `${homeBin}:${process.env.PATH}`;
|
||||||
return;
|
return `${homeBin}/claude`;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (attempt === 3) {
|
if (attempt === 3) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -91,6 +105,7 @@ async function installClaudeCode(): Promise<void> {
|
|||||||
await new Promise((resolve) => setTimeout(resolve, 5000));
|
await new Promise((resolve) => setTimeout(resolve, 5000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
throw new Error("unreachable");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -207,7 +222,7 @@ async function run() {
|
|||||||
prepareCompleted = true;
|
prepareCompleted = true;
|
||||||
|
|
||||||
// Phase 2: Install Claude Code CLI
|
// Phase 2: Install Claude Code CLI
|
||||||
await installClaudeCode();
|
const claudeExecutable = await installClaudeCode();
|
||||||
|
|
||||||
// Phase 3: Run Claude (import base-action directly)
|
// Phase 3: Run Claude (import base-action directly)
|
||||||
// Set env vars needed by the base-action code
|
// Set env vars needed by the base-action code
|
||||||
@ -217,12 +232,36 @@ async function run() {
|
|||||||
|
|
||||||
validateEnvironmentVariables();
|
validateEnvironmentVariables();
|
||||||
|
|
||||||
|
// On PRs, .claude/ and .mcp.json in the checkout are attacker-controlled.
|
||||||
|
// Restore them from the base branch before the CLI reads them.
|
||||||
|
//
|
||||||
|
// We read pull_request.base.ref from the payload directly because agent
|
||||||
|
// mode's branchInfo.baseBranch defaults to the repo's default branch rather
|
||||||
|
// than the PR's actual target (agent/index.ts). For issue_comment on a PR the payload
|
||||||
|
// lacks base.ref, so we fall back to the mode-provided value — tag mode
|
||||||
|
// fetches it from GraphQL; agent mode on issue_comment is an edge case
|
||||||
|
// that at worst restores from the wrong trusted branch (still secure).
|
||||||
|
if (isEntityContext(context) && context.isPR) {
|
||||||
|
let restoreBase = baseBranch;
|
||||||
|
if (
|
||||||
|
isPullRequestEvent(context) ||
|
||||||
|
isPullRequestReviewEvent(context) ||
|
||||||
|
isPullRequestReviewCommentEvent(context)
|
||||||
|
) {
|
||||||
|
restoreBase = context.payload.pull_request.base.ref;
|
||||||
|
validateBranchName(restoreBase);
|
||||||
|
}
|
||||||
|
if (restoreBase) {
|
||||||
|
restoreConfigFromBase(restoreBase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await setupClaudeCodeSettings(process.env.INPUT_SETTINGS);
|
await setupClaudeCodeSettings(process.env.INPUT_SETTINGS);
|
||||||
|
|
||||||
await installPlugins(
|
await installPlugins(
|
||||||
process.env.INPUT_PLUGIN_MARKETPLACES,
|
process.env.INPUT_PLUGIN_MARKETPLACES,
|
||||||
process.env.INPUT_PLUGINS,
|
process.env.INPUT_PLUGINS,
|
||||||
process.env.INPUT_PATH_TO_CLAUDE_CODE_EXECUTABLE,
|
claudeExecutable,
|
||||||
);
|
);
|
||||||
|
|
||||||
const promptFile =
|
const promptFile =
|
||||||
@ -237,8 +276,7 @@ async function run() {
|
|||||||
claudeArgs: prepareResult.claudeArgs,
|
claudeArgs: prepareResult.claudeArgs,
|
||||||
appendSystemPrompt: process.env.APPEND_SYSTEM_PROMPT,
|
appendSystemPrompt: process.env.APPEND_SYSTEM_PROMPT,
|
||||||
model: process.env.ANTHROPIC_MODEL,
|
model: process.env.ANTHROPIC_MODEL,
|
||||||
pathToClaudeCodeExecutable:
|
pathToClaudeCodeExecutable: claudeExecutable,
|
||||||
process.env.INPUT_PATH_TO_CLAUDE_CODE_EXECUTABLE,
|
|
||||||
showFullOutput: process.env.INPUT_SHOW_FULL_OUTPUT,
|
showFullOutput: process.env.INPUT_SHOW_FULL_OUTPUT,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -280,7 +318,7 @@ async function run() {
|
|||||||
commentId,
|
commentId,
|
||||||
githubToken,
|
githubToken,
|
||||||
claudeBranch,
|
claudeBranch,
|
||||||
baseBranch: baseBranch || "main",
|
baseBranch: baseBranch || context.repository.default_branch || "main",
|
||||||
triggerUsername: context.actor,
|
triggerUsername: context.actor,
|
||||||
context,
|
context,
|
||||||
octokit,
|
octokit,
|
||||||
|
|||||||
@ -253,7 +253,8 @@ async function run() {
|
|||||||
commentId: parseInt(process.env.CLAUDE_COMMENT_ID!),
|
commentId: parseInt(process.env.CLAUDE_COMMENT_ID!),
|
||||||
githubToken,
|
githubToken,
|
||||||
claudeBranch: process.env.CLAUDE_BRANCH,
|
claudeBranch: process.env.CLAUDE_BRANCH,
|
||||||
baseBranch: process.env.BASE_BRANCH || "main",
|
baseBranch:
|
||||||
|
process.env.BASE_BRANCH || context.repository.default_branch || "main",
|
||||||
triggerUsername: process.env.TRIGGER_USERNAME,
|
triggerUsername: process.env.TRIGGER_USERNAME,
|
||||||
context,
|
context,
|
||||||
octokit,
|
octokit,
|
||||||
|
|||||||
@ -12,6 +12,13 @@ export const PR_QUERY = `
|
|||||||
baseRefName
|
baseRefName
|
||||||
headRefName
|
headRefName
|
||||||
headRefOid
|
headRefOid
|
||||||
|
isCrossRepository
|
||||||
|
headRepository {
|
||||||
|
owner {
|
||||||
|
login
|
||||||
|
}
|
||||||
|
name
|
||||||
|
}
|
||||||
createdAt
|
createdAt
|
||||||
updatedAt
|
updatedAt
|
||||||
lastEditedAt
|
lastEditedAt
|
||||||
|
|||||||
@ -79,6 +79,7 @@ type BaseContext = {
|
|||||||
owner: string;
|
owner: string;
|
||||||
repo: string;
|
repo: string;
|
||||||
full_name: string;
|
full_name: string;
|
||||||
|
default_branch?: string;
|
||||||
};
|
};
|
||||||
actor: string;
|
actor: string;
|
||||||
inputs: {
|
inputs: {
|
||||||
@ -140,6 +141,7 @@ export function parseGitHubContext(): GitHubContext {
|
|||||||
owner: context.repo.owner,
|
owner: context.repo.owner,
|
||||||
repo: context.repo.repo,
|
repo: context.repo.repo,
|
||||||
full_name: `${context.repo.owner}/${context.repo.repo}`,
|
full_name: `${context.repo.owner}/${context.repo.repo}`,
|
||||||
|
default_branch: context.payload.repository?.default_branch,
|
||||||
},
|
},
|
||||||
actor: context.actor,
|
actor: context.actor,
|
||||||
inputs: {
|
inputs: {
|
||||||
|
|||||||
@ -299,7 +299,7 @@ export async function fetchGitHubData({
|
|||||||
includeCommentsByActor,
|
includeCommentsByActor,
|
||||||
excludeCommentsByActor,
|
excludeCommentsByActor,
|
||||||
);
|
);
|
||||||
reviewData = pullRequest.reviews || [];
|
reviewData = pullRequest.reviews || { nodes: [] };
|
||||||
|
|
||||||
console.log(`Successfully fetched PR #${prNumber} data`);
|
console.log(`Successfully fetched PR #${prNumber} data`);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -28,7 +28,7 @@ function extractFirstLabel(githubData: FetchDataResult): string | undefined {
|
|||||||
*
|
*
|
||||||
* Valid branch names:
|
* Valid branch names:
|
||||||
* - Start with alphanumeric character (not dash, to prevent option injection)
|
* - Start with alphanumeric character (not dash, to prevent option injection)
|
||||||
* - Contain only alphanumeric, forward slash, hyphen, underscore, or period
|
* - Contain only alphanumeric, forward slash, hyphen, underscore, period, or hash (#)
|
||||||
* - Do not start or end with a period
|
* - Do not start or end with a period
|
||||||
* - Do not end with a slash
|
* - Do not end with a slash
|
||||||
* - Do not contain '..' (path traversal)
|
* - Do not contain '..' (path traversal)
|
||||||
@ -58,12 +58,16 @@ export function validateBranchName(branchName: string): void {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strict whitelist pattern: alphanumeric start, then alphanumeric/slash/hyphen/underscore/period
|
// Strict whitelist pattern: alphanumeric start, then alphanumeric/slash/hyphen/underscore/period/hash/plus.
|
||||||
const validPattern = /^[a-zA-Z0-9][a-zA-Z0-9/_.-]*$/;
|
// # is valid per git-check-ref-format and commonly used in branch names like "fix/#123-description".
|
||||||
|
// + is valid per git-check-ref-format and generated by Claude Code's EnterWorktree tool when
|
||||||
|
// converting worktree names containing "/" (e.g. "feat/foo" becomes "worktree-feat+foo").
|
||||||
|
// All git calls use execFileSync (not shell interpolation), so neither # nor + carries injection risk.
|
||||||
|
const validPattern = /^[a-zA-Z0-9][a-zA-Z0-9/_.#+-]*$/;
|
||||||
|
|
||||||
if (!validPattern.test(branchName)) {
|
if (!validPattern.test(branchName)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Invalid branch name: "${branchName}". Branch names must start with an alphanumeric character and contain only alphanumeric characters, forward slashes, hyphens, underscores, or periods.`,
|
`Invalid branch name: "${branchName}". Branch names must start with an alphanumeric character and contain only alphanumeric characters, forward slashes, hyphens, underscores, periods, hashes (#), or plus signs (+).`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,7 +122,7 @@ export function validateBranchName(branchName: string): void {
|
|||||||
* @param args - Git command arguments (e.g., ["checkout", "branch-name"])
|
* @param args - Git command arguments (e.g., ["checkout", "branch-name"])
|
||||||
*/
|
*/
|
||||||
function execGit(args: string[]): void {
|
function execGit(args: string[]): void {
|
||||||
execFileSync("git", args, { stdio: "inherit" });
|
execFileSync("git", args, { stdio: "inherit", env: process.env });
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BranchInfo = {
|
export type BranchInfo = {
|
||||||
@ -164,9 +168,23 @@ export async function setupBranch(
|
|||||||
// Validate branch names before use to prevent command injection
|
// Validate branch names before use to prevent command injection
|
||||||
validateBranchName(branchName);
|
validateBranchName(branchName);
|
||||||
|
|
||||||
// Execute git commands to checkout PR branch (dynamic depth based on PR size)
|
// For cross-repository (fork) PRs, fetch via the pull ref since the
|
||||||
// Using execFileSync instead of shell template literals for security
|
// branch only exists on the fork's remote, not on origin.
|
||||||
execGit(["fetch", "origin", `--depth=${fetchDepth}`, branchName]);
|
if (prData.isCrossRepository) {
|
||||||
|
console.log(
|
||||||
|
`PR #${entityNumber} is from a fork, fetching via refs/pull/${entityNumber}/head...`,
|
||||||
|
);
|
||||||
|
execGit([
|
||||||
|
"fetch",
|
||||||
|
"origin",
|
||||||
|
`--depth=${fetchDepth}`,
|
||||||
|
`pull/${entityNumber}/head:${branchName}`,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
// Execute git commands to checkout PR branch (dynamic depth based on PR size)
|
||||||
|
// Using execFileSync instead of shell template literals for security
|
||||||
|
execGit(["fetch", "origin", `--depth=${fetchDepth}`, branchName]);
|
||||||
|
}
|
||||||
execGit(["checkout", branchName, "--"]);
|
execGit(["checkout", branchName, "--"]);
|
||||||
|
|
||||||
console.log(`Successfully checked out PR branch for PR #${entityNumber}`);
|
console.log(`Successfully checked out PR branch for PR #${entityNumber}`);
|
||||||
|
|||||||
@ -51,11 +51,34 @@ export async function configureGitAuth(
|
|||||||
console.log("No existing authentication headers to remove");
|
console.log("No existing authentication headers to remove");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the remote URL to include the token for authentication
|
if (process.env.ALLOWED_NON_WRITE_USERS) {
|
||||||
console.log("Updating remote URL with authentication...");
|
// When processing content from non-write users, use a credential helper
|
||||||
const remoteUrl = `https://x-access-token:${githubToken}@${serverUrl.host}/${context.repository.owner}/${context.repository.repo}.git`;
|
// instead of embedding the token in the remote URL. The helper script reads
|
||||||
await $`git remote set-url origin ${remoteUrl}`;
|
// from GH_TOKEN at auth time, so .git/config stays token-free. Written as a
|
||||||
console.log("✓ Updated remote URL with authentication token");
|
// file to avoid shell-escaping the helper body; placed under
|
||||||
|
// GITHUB_ACTION_PATH so it sits alongside the action source.
|
||||||
|
console.log("Configuring git credential helper...");
|
||||||
|
process.env.GH_TOKEN = githubToken;
|
||||||
|
const helperPath = join(
|
||||||
|
process.env.GITHUB_ACTION_PATH || homedir(),
|
||||||
|
".git-credential-gh-token",
|
||||||
|
);
|
||||||
|
await writeFile(
|
||||||
|
helperPath,
|
||||||
|
'#!/bin/sh\necho username=x-access-token\necho password="$GH_TOKEN"\n',
|
||||||
|
{ mode: 0o700 },
|
||||||
|
);
|
||||||
|
const cleanUrl = `https://${serverUrl.host}/${context.repository.owner}/${context.repository.repo}.git`;
|
||||||
|
await $`git remote set-url origin ${cleanUrl}`;
|
||||||
|
await $`git config credential.helper ${helperPath}`;
|
||||||
|
console.log("✓ Configured credential helper");
|
||||||
|
} else {
|
||||||
|
// Update the remote URL to include the token for authentication
|
||||||
|
console.log("Updating remote URL with authentication...");
|
||||||
|
const remoteUrl = `https://x-access-token:${githubToken}@${serverUrl.host}/${context.repository.owner}/${context.repository.repo}.git`;
|
||||||
|
await $`git remote set-url origin ${remoteUrl}`;
|
||||||
|
console.log("✓ Updated remote URL with authentication token");
|
||||||
|
}
|
||||||
|
|
||||||
console.log("Git authentication configured successfully");
|
console.log("Git authentication configured successfully");
|
||||||
}
|
}
|
||||||
|
|||||||
109
src/github/operations/restore-config.ts
Normal file
109
src/github/operations/restore-config.ts
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import { execFileSync } from "child_process";
|
||||||
|
import { cpSync, existsSync, rmSync } from "fs";
|
||||||
|
|
||||||
|
// Paths that are both PR-controllable and read from cwd at CLI startup.
|
||||||
|
//
|
||||||
|
// Deliberately excluded from the CLI's broader auto-edit blocklist:
|
||||||
|
// .git/ — not tracked by git; PR commits cannot place files there.
|
||||||
|
// Restoring it would also undo the PR checkout entirely.
|
||||||
|
// .gitconfig — git reads ~/.gitconfig and .git/config, never cwd/.gitconfig.
|
||||||
|
// .bashrc etc. — shells source these from $HOME; checkout cannot reach $HOME.
|
||||||
|
// .vscode/.idea— IDE config; nothing in the CLI's startup path reads them.
|
||||||
|
const SENSITIVE_PATHS = [
|
||||||
|
".claude",
|
||||||
|
".mcp.json",
|
||||||
|
".claude.json",
|
||||||
|
".gitmodules",
|
||||||
|
".ripgreprc",
|
||||||
|
"CLAUDE.md",
|
||||||
|
"CLAUDE.local.md",
|
||||||
|
".husky",
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores security-sensitive config paths from the PR base branch.
|
||||||
|
*
|
||||||
|
* The CLI's non-interactive mode trusts cwd: it reads `.mcp.json`,
|
||||||
|
* `.claude/settings.json`, and `.claude/settings.local.json` from the working
|
||||||
|
* directory and acts on them before any tool-permission gating — executing
|
||||||
|
* hooks (including SessionStart), setting env vars (NODE_OPTIONS, LD_PRELOAD,
|
||||||
|
* PATH), running apiKeyHelper/awsAuthRefresh shell commands, and auto-approving
|
||||||
|
* MCP servers. When this action checks out a PR head, all of these are
|
||||||
|
* attacker-controlled.
|
||||||
|
*
|
||||||
|
* Rather than enumerate every dangerous key, this replaces the entire `.claude/`
|
||||||
|
* tree and `.mcp.json` with the versions from the PR base branch, which a
|
||||||
|
* maintainer has reviewed and merged. Paths absent on base are deleted.
|
||||||
|
*
|
||||||
|
* Known limitation: if a PR legitimately modifies `.claude/` and the CLI later
|
||||||
|
* commits with `git add -A`, the revert will be included in that commit. This
|
||||||
|
* is a narrow UX tradeoff for closing the RCE surface.
|
||||||
|
*
|
||||||
|
* @param baseBranch - PR base branch name. Must be pre-validated (branch.ts
|
||||||
|
* calls validateBranchName on it before returning).
|
||||||
|
*/
|
||||||
|
export function restoreConfigFromBase(baseBranch: string): void {
|
||||||
|
console.log(
|
||||||
|
`Restoring ${SENSITIVE_PATHS.join(", ")} from origin/${baseBranch} (PR head is untrusted)`,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Snapshot every PR-authored sensitive path into .claude-pr/ before deletion
|
||||||
|
// so review agents can inspect what the PR changes without those files ever
|
||||||
|
// being executed. Captured before the security delete so it reflects the
|
||||||
|
// PR-authored version.
|
||||||
|
rmSync(".claude-pr", { recursive: true, force: true });
|
||||||
|
for (const p of SENSITIVE_PATHS) {
|
||||||
|
if (existsSync(p)) {
|
||||||
|
cpSync(p, `.claude-pr/${p}`, { recursive: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (existsSync(".claude-pr")) {
|
||||||
|
console.log(
|
||||||
|
"Preserved PR's sensitive paths → .claude-pr/ for review agents (not executed)",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete PR-controlled versions BEFORE fetching so the attacker-controlled
|
||||||
|
// .gitmodules is absent during the network operation. If git reads .gitmodules
|
||||||
|
// during fetch (fetch.recurseSubmodules=on-demand, the git default), it will
|
||||||
|
// attempt to fetch submodule objects and block on credential prompts in CI —
|
||||||
|
// causing an indefinite hang. Deleting first closes that window.
|
||||||
|
//
|
||||||
|
// If the restore below fails for a given path, that path stays deleted —
|
||||||
|
// the safe fallback (no attacker-controlled config). A bare `git checkout`
|
||||||
|
// alone wouldn't remove files the PR added, so nuke first.
|
||||||
|
for (const p of SENSITIVE_PATHS) {
|
||||||
|
rmSync(p, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
// --no-recurse-submodules: explicitly suppress submodule fetching regardless of
|
||||||
|
// fetch.recurseSubmodules config. Defense-in-depth alongside the delete above.
|
||||||
|
execFileSync(
|
||||||
|
"git",
|
||||||
|
["fetch", "origin", baseBranch, "--depth=1", "--no-recurse-submodules"],
|
||||||
|
{
|
||||||
|
stdio: "inherit",
|
||||||
|
env: process.env,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const p of SENSITIVE_PATHS) {
|
||||||
|
try {
|
||||||
|
execFileSync("git", ["checkout", `origin/${baseBranch}`, "--", p], {
|
||||||
|
stdio: "pipe",
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
// Path doesn't exist on base — it stays deleted.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// `git checkout <ref> -- <path>` stages the restored files. Unstage so the
|
||||||
|
// revert doesn't silently leak into commits the CLI makes later.
|
||||||
|
try {
|
||||||
|
execFileSync("git", ["reset", "--", ...SENSITIVE_PATHS], {
|
||||||
|
stdio: "pipe",
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
// Nothing was staged, or paths don't exist on HEAD — either is fine.
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -141,10 +141,14 @@ export async function setupGitHubToken(): Promise<string> {
|
|||||||
const permissions = parseAdditionalPermissions();
|
const permissions = parseAdditionalPermissions();
|
||||||
|
|
||||||
console.log("Exchanging OIDC token for app token...");
|
console.log("Exchanging OIDC token for app token...");
|
||||||
const appToken = await retryWithBackoff(() =>
|
const appToken = await retryWithBackoff(
|
||||||
exchangeForAppToken(oidcToken, permissions),
|
() => exchangeForAppToken(oidcToken, permissions),
|
||||||
|
{
|
||||||
|
shouldRetry: (error) => !(error instanceof WorkflowValidationSkipError),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
console.log("App token successfully obtained");
|
console.log("App token successfully obtained");
|
||||||
|
core.setSecret(appToken);
|
||||||
|
|
||||||
console.log("Using GITHUB_TOKEN from OIDC");
|
console.log("Using GITHUB_TOKEN from OIDC");
|
||||||
return appToken;
|
return appToken;
|
||||||
|
|||||||
@ -57,6 +57,13 @@ export type GitHubPullRequest = {
|
|||||||
baseRefName: string;
|
baseRefName: string;
|
||||||
headRefName: string;
|
headRefName: string;
|
||||||
headRefOid: string;
|
headRefOid: string;
|
||||||
|
isCrossRepository: boolean;
|
||||||
|
headRepository: {
|
||||||
|
owner: {
|
||||||
|
login: string;
|
||||||
|
};
|
||||||
|
name: string;
|
||||||
|
} | null;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
updatedAt?: string;
|
updatedAt?: string;
|
||||||
lastEditedAt?: string;
|
lastEditedAt?: string;
|
||||||
|
|||||||
@ -85,15 +85,15 @@ export async function prepareAgentMode({
|
|||||||
|
|
||||||
// Check for branch info from environment variables (useful for auto-fix workflows)
|
// Check for branch info from environment variables (useful for auto-fix workflows)
|
||||||
const claudeBranch = process.env.CLAUDE_BRANCH || undefined;
|
const claudeBranch = process.env.CLAUDE_BRANCH || undefined;
|
||||||
const baseBranch =
|
const defaultBranch = context.repository.default_branch || "main";
|
||||||
process.env.BASE_BRANCH || context.inputs.baseBranch || "main";
|
const baseBranch = context.inputs.baseBranch || defaultBranch;
|
||||||
|
|
||||||
// Detect current branch from GitHub environment
|
// Detect current branch from GitHub environment
|
||||||
const currentBranch =
|
const currentBranch =
|
||||||
claudeBranch ||
|
claudeBranch ||
|
||||||
process.env.GITHUB_HEAD_REF ||
|
process.env.GITHUB_HEAD_REF ||
|
||||||
process.env.GITHUB_REF_NAME ||
|
process.env.GITHUB_REF_NAME ||
|
||||||
"main";
|
defaultBranch;
|
||||||
|
|
||||||
// Get our GitHub MCP servers config
|
// Get our GitHub MCP servers config
|
||||||
const ourMcpConfig = await prepareMcpConfig({
|
const ourMcpConfig = await prepareMcpConfig({
|
||||||
|
|||||||
@ -114,16 +114,17 @@ export async function prepareTagMode({
|
|||||||
tool.startsWith("mcp__github_"),
|
tool.startsWith("mcp__github_"),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Build claude_args for tag mode with required tools
|
const gitPushWrapper = `${process.env.GITHUB_ACTION_PATH}/scripts/git-push.sh`;
|
||||||
// Tag mode REQUIRES these tools to function properly
|
|
||||||
|
// Build claude_args for tag mode with required tools.
|
||||||
|
// Edit/MultiEdit/Write are intentionally omitted: acceptEdits permission mode (set below)
|
||||||
|
// auto-allows file edits inside $GITHUB_WORKSPACE and denies writes outside (e.g. ~/.bashrc).
|
||||||
|
// Listing them here would grant blanket write access to the whole runner (Asana 1213310082312048).
|
||||||
const tagModeTools = [
|
const tagModeTools = [
|
||||||
"Edit",
|
|
||||||
"MultiEdit",
|
|
||||||
"Glob",
|
"Glob",
|
||||||
"Grep",
|
"Grep",
|
||||||
"LS",
|
"LS",
|
||||||
"Read",
|
"Read",
|
||||||
"Write",
|
|
||||||
"mcp__github_comment__update_claude_comment",
|
"mcp__github_comment__update_claude_comment",
|
||||||
"mcp__github_ci__get_ci_status",
|
"mcp__github_ci__get_ci_status",
|
||||||
"mcp__github_ci__get_workflow_run_details",
|
"mcp__github_ci__get_workflow_run_details",
|
||||||
@ -137,10 +138,7 @@ export async function prepareTagMode({
|
|||||||
tagModeTools.push(
|
tagModeTools.push(
|
||||||
"Bash(git add:*)",
|
"Bash(git add:*)",
|
||||||
"Bash(git commit:*)",
|
"Bash(git commit:*)",
|
||||||
"Bash(git push:*)",
|
`Bash(${gitPushWrapper}:*)`,
|
||||||
"Bash(git status:*)",
|
|
||||||
"Bash(git diff:*)",
|
|
||||||
"Bash(git log:*)",
|
|
||||||
"Bash(git rm:*)",
|
"Bash(git rm:*)",
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -171,8 +169,10 @@ export async function prepareTagMode({
|
|||||||
const escapedOurConfig = ourMcpConfig.replace(/'/g, "'\\''");
|
const escapedOurConfig = ourMcpConfig.replace(/'/g, "'\\''");
|
||||||
claudeArgs = `--mcp-config '${escapedOurConfig}'`;
|
claudeArgs = `--mcp-config '${escapedOurConfig}'`;
|
||||||
|
|
||||||
// Add required tools for tag mode
|
// Add required tools for tag mode.
|
||||||
claudeArgs += ` --allowedTools "${tagModeTools.join(",")}"`;
|
// acceptEdits: file edits auto-allowed inside cwd ($GITHUB_WORKSPACE), denied outside.
|
||||||
|
// Headless SDK has no prompt handler, so anything that falls through to "ask" is denied.
|
||||||
|
claudeArgs += ` --permission-mode acceptEdits --allowedTools "${tagModeTools.join(",")}"`;
|
||||||
|
|
||||||
// Append user's claude_args (which may have more --mcp-config flags)
|
// Append user's claude_args (which may have more --mcp-config flags)
|
||||||
if (userClaudeArgs) {
|
if (userClaudeArgs) {
|
||||||
|
|||||||
@ -3,6 +3,7 @@ export type RetryOptions = {
|
|||||||
initialDelayMs?: number;
|
initialDelayMs?: number;
|
||||||
maxDelayMs?: number;
|
maxDelayMs?: number;
|
||||||
backoffFactor?: number;
|
backoffFactor?: number;
|
||||||
|
shouldRetry?: (error: Error) => boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function retryWithBackoff<T>(
|
export async function retryWithBackoff<T>(
|
||||||
@ -14,6 +15,7 @@ export async function retryWithBackoff<T>(
|
|||||||
initialDelayMs = 5000,
|
initialDelayMs = 5000,
|
||||||
maxDelayMs = 20000,
|
maxDelayMs = 20000,
|
||||||
backoffFactor = 2,
|
backoffFactor = 2,
|
||||||
|
shouldRetry,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
let delayMs = initialDelayMs;
|
let delayMs = initialDelayMs;
|
||||||
@ -27,6 +29,11 @@ export async function retryWithBackoff<T>(
|
|||||||
lastError = error instanceof Error ? error : new Error(String(error));
|
lastError = error instanceof Error ? error : new Error(String(error));
|
||||||
console.error(`Attempt ${attempt} failed:`, lastError.message);
|
console.error(`Attempt ${attempt} failed:`, lastError.message);
|
||||||
|
|
||||||
|
if (shouldRetry && !shouldRetry(lastError)) {
|
||||||
|
console.error("Error is not retryable, giving up immediately");
|
||||||
|
throw lastError;
|
||||||
|
}
|
||||||
|
|
||||||
if (attempt < maxAttempts) {
|
if (attempt < maxAttempts) {
|
||||||
console.log(`Retrying in ${delayMs / 1000} seconds...`);
|
console.log(`Retrying in ${delayMs / 1000} seconds...`);
|
||||||
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env bun
|
#!/usr/bin/env bun
|
||||||
|
|
||||||
import { describe, test, expect } from "bun:test";
|
import { describe, test, expect, beforeAll } from "bun:test";
|
||||||
import {
|
import {
|
||||||
generatePrompt,
|
generatePrompt,
|
||||||
getEventTypeAndContext,
|
getEventTypeAndContext,
|
||||||
@ -9,6 +9,10 @@ import {
|
|||||||
} from "../src/create-prompt";
|
} from "../src/create-prompt";
|
||||||
import type { PreparedContext } from "../src/create-prompt";
|
import type { PreparedContext } from "../src/create-prompt";
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
process.env.GITHUB_ACTION_PATH = "/test/action/path";
|
||||||
|
});
|
||||||
|
|
||||||
describe("generatePrompt", () => {
|
describe("generatePrompt", () => {
|
||||||
const mockGitHubData = {
|
const mockGitHubData = {
|
||||||
contextData: {
|
contextData: {
|
||||||
@ -23,6 +27,8 @@ describe("generatePrompt", () => {
|
|||||||
baseRefName: "main",
|
baseRefName: "main",
|
||||||
headRefName: "feature-branch",
|
headRefName: "feature-branch",
|
||||||
headRefOid: "abc123",
|
headRefOid: "abc123",
|
||||||
|
isCrossRepository: false,
|
||||||
|
headRepository: { owner: { login: "testowner" }, name: "testrepo" },
|
||||||
commits: {
|
commits: {
|
||||||
totalCount: 2,
|
totalCount: 2,
|
||||||
nodes: [
|
nodes: [
|
||||||
@ -505,7 +511,7 @@ describe("generatePrompt", () => {
|
|||||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, "tag");
|
const prompt = await generatePrompt(envVars, mockGitHubData, false, "tag");
|
||||||
|
|
||||||
// Should contain PR-specific instructions (git commands when not using signing)
|
// Should contain PR-specific instructions (git commands when not using signing)
|
||||||
expect(prompt).toContain("git push");
|
expect(prompt).toContain("scripts/git-push.sh origin");
|
||||||
expect(prompt).toContain(
|
expect(prompt).toContain(
|
||||||
"Always push to the existing branch when triggered on a PR",
|
"Always push to the existing branch when triggered on a PR",
|
||||||
);
|
);
|
||||||
@ -643,7 +649,7 @@ describe("generatePrompt", () => {
|
|||||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, "tag");
|
const prompt = await generatePrompt(envVars, mockGitHubData, false, "tag");
|
||||||
|
|
||||||
// Should contain open PR instructions (git commands when not using signing)
|
// Should contain open PR instructions (git commands when not using signing)
|
||||||
expect(prompt).toContain("git push");
|
expect(prompt).toContain("scripts/git-push.sh origin");
|
||||||
expect(prompt).toContain(
|
expect(prompt).toContain(
|
||||||
"Always push to the existing branch when triggered on a PR",
|
"Always push to the existing branch when triggered on a PR",
|
||||||
);
|
);
|
||||||
@ -757,7 +763,7 @@ describe("generatePrompt", () => {
|
|||||||
expect(prompt).toContain("Use git commands via the Bash tool");
|
expect(prompt).toContain("Use git commands via the Bash tool");
|
||||||
expect(prompt).toContain("git add");
|
expect(prompt).toContain("git add");
|
||||||
expect(prompt).toContain("git commit");
|
expect(prompt).toContain("git commit");
|
||||||
expect(prompt).toContain("git push");
|
expect(prompt).toContain("scripts/git-push.sh origin");
|
||||||
|
|
||||||
// Should use the minimal comment tool
|
// Should use the minimal comment tool
|
||||||
expect(prompt).toContain("mcp__github_comment__update_claude_comment");
|
expect(prompt).toContain("mcp__github_comment__update_claude_comment");
|
||||||
@ -886,17 +892,18 @@ describe("buildAllowedToolsString", () => {
|
|||||||
const result = buildAllowedToolsString();
|
const result = buildAllowedToolsString();
|
||||||
|
|
||||||
// The base tools should be in the result
|
// The base tools should be in the result
|
||||||
expect(result).toContain("Edit");
|
// Edit/MultiEdit/Write are NOT in allowedTools — acceptEdits permission mode handles them
|
||||||
|
expect(result).not.toContain("Edit");
|
||||||
|
expect(result).not.toContain("Write");
|
||||||
expect(result).toContain("Glob");
|
expect(result).toContain("Glob");
|
||||||
expect(result).toContain("Grep");
|
expect(result).toContain("Grep");
|
||||||
expect(result).toContain("LS");
|
expect(result).toContain("LS");
|
||||||
expect(result).toContain("Read");
|
expect(result).toContain("Read");
|
||||||
expect(result).toContain("Write");
|
|
||||||
|
|
||||||
// Default is no commit signing, so should have specific Bash git commands
|
// Default is no commit signing, so should have specific Bash git commands
|
||||||
expect(result).toContain("Bash(git add:*)");
|
expect(result).toContain("Bash(git add:*)");
|
||||||
expect(result).toContain("Bash(git commit:*)");
|
expect(result).toContain("Bash(git commit:*)");
|
||||||
expect(result).toContain("Bash(git push:*)");
|
expect(result).toContain("scripts/git-push.sh:*)");
|
||||||
expect(result).toContain("mcp__github_comment__update_claude_comment");
|
expect(result).toContain("mcp__github_comment__update_claude_comment");
|
||||||
|
|
||||||
// Should not have commit signing tools
|
// Should not have commit signing tools
|
||||||
@ -908,12 +915,12 @@ describe("buildAllowedToolsString", () => {
|
|||||||
const result = buildAllowedToolsString([], false, false);
|
const result = buildAllowedToolsString([], false, false);
|
||||||
|
|
||||||
// The base tools should be in the result
|
// The base tools should be in the result
|
||||||
expect(result).toContain("Edit");
|
expect(result).not.toContain("Edit");
|
||||||
expect(result).toContain("Glob");
|
expect(result).toContain("Glob");
|
||||||
expect(result).toContain("Grep");
|
expect(result).toContain("Grep");
|
||||||
expect(result).toContain("LS");
|
expect(result).toContain("LS");
|
||||||
expect(result).toContain("Read");
|
expect(result).toContain("Read");
|
||||||
expect(result).toContain("Write");
|
expect(result).not.toContain("Write");
|
||||||
|
|
||||||
// Should have specific Bash git commands for non-signing mode
|
// Should have specific Bash git commands for non-signing mode
|
||||||
expect(result).toContain("Bash(git add:*)");
|
expect(result).toContain("Bash(git add:*)");
|
||||||
@ -930,7 +937,7 @@ describe("buildAllowedToolsString", () => {
|
|||||||
const result = buildAllowedToolsString(customTools);
|
const result = buildAllowedToolsString(customTools);
|
||||||
|
|
||||||
// Base tools should be present
|
// Base tools should be present
|
||||||
expect(result).toContain("Edit");
|
expect(result).toContain("Read");
|
||||||
expect(result).toContain("Glob");
|
expect(result).toContain("Glob");
|
||||||
|
|
||||||
// Custom tools should be appended
|
// Custom tools should be appended
|
||||||
@ -950,7 +957,7 @@ describe("buildAllowedToolsString", () => {
|
|||||||
const result = buildAllowedToolsString([], true);
|
const result = buildAllowedToolsString([], true);
|
||||||
|
|
||||||
// Base tools should be present
|
// Base tools should be present
|
||||||
expect(result).toContain("Edit");
|
expect(result).toContain("Read");
|
||||||
expect(result).toContain("Glob");
|
expect(result).toContain("Glob");
|
||||||
|
|
||||||
// GitHub Actions tools should be included
|
// GitHub Actions tools should be included
|
||||||
@ -964,7 +971,7 @@ describe("buildAllowedToolsString", () => {
|
|||||||
const result = buildAllowedToolsString(customTools, true);
|
const result = buildAllowedToolsString(customTools, true);
|
||||||
|
|
||||||
// Base tools should be present
|
// Base tools should be present
|
||||||
expect(result).toContain("Edit");
|
expect(result).toContain("Read");
|
||||||
|
|
||||||
// Custom tools should be included
|
// Custom tools should be included
|
||||||
expect(result).toContain("Tool1");
|
expect(result).toContain("Tool1");
|
||||||
@ -980,12 +987,12 @@ describe("buildAllowedToolsString", () => {
|
|||||||
const result = buildAllowedToolsString([], false, true);
|
const result = buildAllowedToolsString([], false, true);
|
||||||
|
|
||||||
// Base tools should be present
|
// Base tools should be present
|
||||||
expect(result).toContain("Edit");
|
expect(result).not.toContain("Edit");
|
||||||
expect(result).toContain("Glob");
|
expect(result).toContain("Glob");
|
||||||
expect(result).toContain("Grep");
|
expect(result).toContain("Grep");
|
||||||
expect(result).toContain("LS");
|
expect(result).toContain("LS");
|
||||||
expect(result).toContain("Read");
|
expect(result).toContain("Read");
|
||||||
expect(result).toContain("Write");
|
expect(result).not.toContain("Write");
|
||||||
|
|
||||||
// Commit signing tools should be included
|
// Commit signing tools should be included
|
||||||
expect(result).toContain("mcp__github_file_ops__commit_files");
|
expect(result).toContain("mcp__github_file_ops__commit_files");
|
||||||
@ -1001,20 +1008,17 @@ describe("buildAllowedToolsString", () => {
|
|||||||
const result = buildAllowedToolsString([], false, false);
|
const result = buildAllowedToolsString([], false, false);
|
||||||
|
|
||||||
// Base tools should be present
|
// Base tools should be present
|
||||||
expect(result).toContain("Edit");
|
expect(result).not.toContain("Edit");
|
||||||
expect(result).toContain("Glob");
|
expect(result).toContain("Glob");
|
||||||
expect(result).toContain("Grep");
|
expect(result).toContain("Grep");
|
||||||
expect(result).toContain("LS");
|
expect(result).toContain("LS");
|
||||||
expect(result).toContain("Read");
|
expect(result).toContain("Read");
|
||||||
expect(result).toContain("Write");
|
expect(result).not.toContain("Write");
|
||||||
|
|
||||||
// Specific Bash git commands should be included
|
// Specific Bash git commands should be included
|
||||||
expect(result).toContain("Bash(git add:*)");
|
expect(result).toContain("Bash(git add:*)");
|
||||||
expect(result).toContain("Bash(git commit:*)");
|
expect(result).toContain("Bash(git commit:*)");
|
||||||
expect(result).toContain("Bash(git push:*)");
|
expect(result).toContain("scripts/git-push.sh:*)");
|
||||||
expect(result).toContain("Bash(git status:*)");
|
|
||||||
expect(result).toContain("Bash(git diff:*)");
|
|
||||||
expect(result).toContain("Bash(git log:*)");
|
|
||||||
expect(result).toContain("Bash(git rm:*)");
|
expect(result).toContain("Bash(git rm:*)");
|
||||||
|
|
||||||
// Comment tool from minimal server should be included
|
// Comment tool from minimal server should be included
|
||||||
@ -1030,7 +1034,7 @@ describe("buildAllowedToolsString", () => {
|
|||||||
const result = buildAllowedToolsString(customTools, true, false);
|
const result = buildAllowedToolsString(customTools, true, false);
|
||||||
|
|
||||||
// Base tools should be present
|
// Base tools should be present
|
||||||
expect(result).toContain("Edit");
|
expect(result).toContain("Read");
|
||||||
expect(result).toContain("Bash(git add:*)");
|
expect(result).toContain("Bash(git add:*)");
|
||||||
|
|
||||||
// Custom tools should be included
|
// Custom tools should be included
|
||||||
|
|||||||
@ -1006,6 +1006,8 @@ describe("fetchGitHubData integration with time filtering", () => {
|
|||||||
baseRefName: "main",
|
baseRefName: "main",
|
||||||
headRefName: "feature",
|
headRefName: "feature",
|
||||||
headRefOid: "abc123",
|
headRefOid: "abc123",
|
||||||
|
isCrossRepository: false,
|
||||||
|
headRepository: { owner: { login: "testowner" }, name: "testrepo" },
|
||||||
createdAt: "2024-01-15T10:00:00Z",
|
createdAt: "2024-01-15T10:00:00Z",
|
||||||
updatedAt: "2024-01-15T12:30:00Z", // Edited after trigger
|
updatedAt: "2024-01-15T12:30:00Z", // Edited after trigger
|
||||||
lastEditedAt: "2024-01-15T12:30:00Z", // Edited after trigger
|
lastEditedAt: "2024-01-15T12:30:00Z", // Edited after trigger
|
||||||
|
|||||||
@ -24,6 +24,8 @@ describe("formatContext", () => {
|
|||||||
baseRefName: "main",
|
baseRefName: "main",
|
||||||
headRefName: "feature/test",
|
headRefName: "feature/test",
|
||||||
headRefOid: "abc123",
|
headRefOid: "abc123",
|
||||||
|
isCrossRepository: false,
|
||||||
|
headRepository: { owner: { login: "testowner" }, name: "testrepo" },
|
||||||
createdAt: "2023-01-01T00:00:00Z",
|
createdAt: "2023-01-01T00:00:00Z",
|
||||||
additions: 50,
|
additions: 50,
|
||||||
deletions: 30,
|
deletions: 30,
|
||||||
|
|||||||
@ -36,6 +36,7 @@ const defaultRepository = {
|
|||||||
owner: "test-owner",
|
owner: "test-owner",
|
||||||
repo: "test-repo",
|
repo: "test-repo",
|
||||||
full_name: "test-owner/test-repo",
|
full_name: "test-owner/test-repo",
|
||||||
|
default_branch: "main",
|
||||||
};
|
};
|
||||||
|
|
||||||
type MockContextOverrides = Omit<Partial<ParsedGitHubContext>, "inputs"> & {
|
type MockContextOverrides = Omit<Partial<ParsedGitHubContext>, "inputs"> & {
|
||||||
|
|||||||
@ -88,7 +88,7 @@ describe("Agent Mode", () => {
|
|||||||
expect(result.claudeArgs).toBe("--model claude-sonnet-4 --max-turns 10");
|
expect(result.claudeArgs).toBe("--model claude-sonnet-4 --max-turns 10");
|
||||||
expect(result.claudeArgs).not.toContain("--mcp-config");
|
expect(result.claudeArgs).not.toContain("--mcp-config");
|
||||||
|
|
||||||
// Verify return structure - should use "main" as fallback when no env vars set
|
// Verify return structure - should fall back to repository.default_branch when no env vars set
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
commentId: undefined,
|
commentId: undefined,
|
||||||
branchInfo: {
|
branchInfo: {
|
||||||
@ -108,6 +108,60 @@ describe("Agent Mode", () => {
|
|||||||
process.env.GITHUB_REF_NAME = originalRefName;
|
process.env.GITHUB_REF_NAME = originalRefName;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("prepare falls back to repository.default_branch when not 'main'", async () => {
|
||||||
|
const contextWithDevelop = createMockAutomationContext({
|
||||||
|
eventName: "workflow_dispatch",
|
||||||
|
repository: {
|
||||||
|
owner: "test-owner",
|
||||||
|
repo: "test-repo",
|
||||||
|
full_name: "test-owner/test-repo",
|
||||||
|
default_branch: "develop",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Save and clear env vars that would otherwise override the fallback
|
||||||
|
const originalClaudeBranch = process.env.CLAUDE_BRANCH;
|
||||||
|
const originalHeadRef = process.env.GITHUB_HEAD_REF;
|
||||||
|
const originalRefName = process.env.GITHUB_REF_NAME;
|
||||||
|
delete process.env.CLAUDE_BRANCH;
|
||||||
|
delete process.env.GITHUB_HEAD_REF;
|
||||||
|
delete process.env.GITHUB_REF_NAME;
|
||||||
|
|
||||||
|
const mockOctokit = {
|
||||||
|
rest: {
|
||||||
|
users: {
|
||||||
|
getAuthenticated: mock(() =>
|
||||||
|
Promise.resolve({
|
||||||
|
data: { login: "test-user", id: 12345, type: "User" },
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
getByUsername: mock(() =>
|
||||||
|
Promise.resolve({
|
||||||
|
data: { login: "test-user", id: 12345, type: "User" },
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
const result = await prepareAgentMode({
|
||||||
|
context: contextWithDevelop,
|
||||||
|
octokit: mockOctokit,
|
||||||
|
githubToken: "test-token",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.branchInfo.baseBranch).toBe("develop");
|
||||||
|
expect(result.branchInfo.currentBranch).toBe("develop");
|
||||||
|
|
||||||
|
// Restore env vars
|
||||||
|
if (originalClaudeBranch !== undefined)
|
||||||
|
process.env.CLAUDE_BRANCH = originalClaudeBranch;
|
||||||
|
if (originalHeadRef !== undefined)
|
||||||
|
process.env.GITHUB_HEAD_REF = originalHeadRef;
|
||||||
|
if (originalRefName !== undefined)
|
||||||
|
process.env.GITHUB_REF_NAME = originalRefName;
|
||||||
|
});
|
||||||
|
|
||||||
test("prepare rejects bot actors without allowed_bots", async () => {
|
test("prepare rejects bot actors without allowed_bots", async () => {
|
||||||
const contextWithPrompts = createMockAutomationContext({
|
const contextWithPrompts = createMockAutomationContext({
|
||||||
eventName: "workflow_dispatch",
|
eventName: "workflow_dispatch",
|
||||||
|
|||||||
@ -17,6 +17,8 @@ describe("pull_request_target event support", () => {
|
|||||||
baseRefName: "main",
|
baseRefName: "main",
|
||||||
headRefName: "feature-branch",
|
headRefName: "feature-branch",
|
||||||
headRefOid: "abc123",
|
headRefOid: "abc123",
|
||||||
|
isCrossRepository: false,
|
||||||
|
headRepository: { owner: { login: "testowner" }, name: "testrepo" },
|
||||||
commits: {
|
commits: {
|
||||||
totalCount: 2,
|
totalCount: 2,
|
||||||
nodes: [
|
nodes: [
|
||||||
@ -135,7 +137,7 @@ describe("pull_request_target event support", () => {
|
|||||||
const prompt = generatePrompt(envVars, mockGitHubData, false, "tag");
|
const prompt = generatePrompt(envVars, mockGitHubData, false, "tag");
|
||||||
|
|
||||||
// Should include git commands for non-commit-signing mode
|
// Should include git commands for non-commit-signing mode
|
||||||
expect(prompt).toContain("git push");
|
expect(prompt).toContain("scripts/git-push.sh origin");
|
||||||
expect(prompt).toContain(
|
expect(prompt).toContain(
|
||||||
"Always push to the existing branch when triggered on a PR",
|
"Always push to the existing branch when triggered on a PR",
|
||||||
);
|
);
|
||||||
|
|||||||
120
test/retry.test.ts
Normal file
120
test/retry.test.ts
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
import { describe, it, expect, beforeEach, afterEach, mock } from "bun:test";
|
||||||
|
import { retryWithBackoff } from "../src/utils/retry";
|
||||||
|
|
||||||
|
describe("retryWithBackoff", () => {
|
||||||
|
let originalConsoleLog: typeof console.log;
|
||||||
|
let originalConsoleError: typeof console.error;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
originalConsoleLog = console.log;
|
||||||
|
originalConsoleError = console.error;
|
||||||
|
console.log = mock(() => {});
|
||||||
|
console.error = mock(() => {});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
console.log = originalConsoleLog;
|
||||||
|
console.error = originalConsoleError;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns the result on first success", async () => {
|
||||||
|
const result = await retryWithBackoff(() => Promise.resolve("ok"), {
|
||||||
|
maxAttempts: 3,
|
||||||
|
initialDelayMs: 1,
|
||||||
|
});
|
||||||
|
expect(result).toBe("ok");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("retries on failure and succeeds", async () => {
|
||||||
|
let attempt = 0;
|
||||||
|
const result = await retryWithBackoff(
|
||||||
|
() => {
|
||||||
|
attempt++;
|
||||||
|
if (attempt < 3) throw new Error("transient");
|
||||||
|
return Promise.resolve("recovered");
|
||||||
|
},
|
||||||
|
{ maxAttempts: 3, initialDelayMs: 1 },
|
||||||
|
);
|
||||||
|
expect(result).toBe("recovered");
|
||||||
|
expect(attempt).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throws after exhausting all attempts", async () => {
|
||||||
|
await expect(
|
||||||
|
retryWithBackoff(() => Promise.reject(new Error("permanent")), {
|
||||||
|
maxAttempts: 2,
|
||||||
|
initialDelayMs: 1,
|
||||||
|
}),
|
||||||
|
).rejects.toThrow("permanent");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("stops retrying immediately when shouldRetry returns false", async () => {
|
||||||
|
class NonRetryableError extends Error {
|
||||||
|
constructor() {
|
||||||
|
super("non-retryable");
|
||||||
|
this.name = "NonRetryableError";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let attempts = 0;
|
||||||
|
await expect(
|
||||||
|
retryWithBackoff(
|
||||||
|
() => {
|
||||||
|
attempts++;
|
||||||
|
throw new NonRetryableError();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
maxAttempts: 3,
|
||||||
|
initialDelayMs: 1,
|
||||||
|
shouldRetry: (error) => !(error instanceof NonRetryableError),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
).rejects.toThrow("non-retryable");
|
||||||
|
expect(attempts).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("continues retrying when shouldRetry returns true", async () => {
|
||||||
|
let attempts = 0;
|
||||||
|
await expect(
|
||||||
|
retryWithBackoff(
|
||||||
|
() => {
|
||||||
|
attempts++;
|
||||||
|
throw new Error("retryable");
|
||||||
|
},
|
||||||
|
{
|
||||||
|
maxAttempts: 3,
|
||||||
|
initialDelayMs: 1,
|
||||||
|
shouldRetry: () => true,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
).rejects.toThrow("retryable");
|
||||||
|
expect(attempts).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("preserves the original error when shouldRetry aborts", async () => {
|
||||||
|
class SpecificError extends Error {
|
||||||
|
code = 401;
|
||||||
|
constructor() {
|
||||||
|
super("unauthorized");
|
||||||
|
this.name = "SpecificError";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await retryWithBackoff(
|
||||||
|
() => {
|
||||||
|
throw new SpecificError();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
maxAttempts: 3,
|
||||||
|
initialDelayMs: 1,
|
||||||
|
shouldRetry: (error) => !(error instanceof SpecificError),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
expect.unreachable("should have thrown");
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(SpecificError);
|
||||||
|
expect((error as SpecificError).code).toBe(401);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -36,6 +36,25 @@ describe("validateBranchName", () => {
|
|||||||
expect(() => validateBranchName("refs/heads/main")).not.toThrow();
|
expect(() => validateBranchName("refs/heads/main")).not.toThrow();
|
||||||
expect(() => validateBranchName("bugfix/JIRA-1234")).not.toThrow();
|
expect(() => validateBranchName("bugfix/JIRA-1234")).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should accept branch names containing # (git-valid, common in issue-linked branches)", () => {
|
||||||
|
// Reported in #1137: branches like "put-back-arm64-#2" were rejected
|
||||||
|
expect(() => validateBranchName("put-back-arm64-#2")).not.toThrow();
|
||||||
|
expect(() =>
|
||||||
|
validateBranchName("feature/#123-description"),
|
||||||
|
).not.toThrow();
|
||||||
|
expect(() => validateBranchName("fix/issue-#42")).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should accept branch names containing + (generated by Claude Code EnterWorktree)", () => {
|
||||||
|
// EnterWorktree converts "/" in worktree names to "+" when generating branch names.
|
||||||
|
// e.g. EnterWorktree("feat/skill-consolidation") → branch "worktree-feat+skill-consolidation"
|
||||||
|
expect(() =>
|
||||||
|
validateBranchName("worktree-feat+skill-consolidation"),
|
||||||
|
).not.toThrow();
|
||||||
|
expect(() => validateBranchName("fix+issue-123")).not.toThrow();
|
||||||
|
expect(() => validateBranchName("feature+new-thing")).not.toThrow();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("command injection attempts", () => {
|
describe("command injection attempts", () => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user