From 8cce897c64e5e44b2cafa5476639afa308924f03 Mon Sep 17 00:00:00 2001 From: "Fred K. Schott" <622227+FredKSchott@users.noreply.github.com> Date: Mon, 23 Feb 2026 10:48:37 -0800 Subject: [PATCH 1/2] auto-triage improvements: security improvements, sandbox updates, skill refinements (#15545) * update @flue/cli and @flue/client to latest versions * update @flue/cli and @flue/client to latest versions * replace curl GitHub API calls with gh CLI in triage verify skill * refine comment template formatting in triage comment skill * add scope reference to skills * test the github proxy * update @flue/cli and @flue/client to latest * add scope to comment skill * remove hardcoded -R withastro/astro from verify skill gh commands * add back github explicit trigger * fetch full git history in triage workflow for git blame/log * promote git blame to its own subsection in verify skill * add analyze-github-action-logs skill * update @flue packages and refactor triage workflow for new client API * update @flue/cli and @flue/client packages, post comments via direct API call * fix indentation in proxy config and markdown formatting in comment skill * refactor label operations to use direct API calls instead of gh CLI * add environment guide to AGENTS.md: prefer node over python for scripting * improve AGENTS.md structure and add bgproc dependency Reorganize AGENTS.md with clearer sections for monorepo guide, bgproc, and agent-browser workflows. Add bgproc as a dev dependency for managing long-running dev/preview servers. * add note on list * update @flue/cli to 0.0.40 * merge issue-opened.yml into issue-triage.yml workflow * fix(astro-workflow): guard shell results with exitCode checks before JSON.parse * update @flue/cli to 0.0.41 * update @flue/cli to 0.0.42 and @flue/client to 0.0.26 * update @flue/cli to 0.0.43 and @flue/client to 0.0.27 * split issue-labeled.yml into issue-needsrepro.yml and issue-wontfix.yml * fix: add missing lsof/procps to Docker sandbox and fix bgproc instructions in AGENTS.md * refactor: combine needs-repro workflows into a single file * fix: use FREDKBOT_GITHUB_TOKEN with GITHUB_TOKEN fallback in issue-triage * add knip note about bgproc * cleanup * refactor: extract GitHub API helpers into github.ts, replace flue.shell with direct fetch calls * fix: correct authorAssociation field name in reproduce.md to match camelCase schema * docs: clarify bgproc logs description in AGENTS.md * ci: set PNPM_STORE_DIR to keep pnpm store inside workspace for sandbox access * fix: fall back to GITHUB_TOKEN when FREDKBOT_GITHUB_TOKEN is not set * update AGENTS * ci: inject global OpenCode rules into sandbox container via AGENTS.sandbox.md * refactor: derive branch name from issueNumber and use valibot schema for triage args * ci: add jq to sandbox container system packages * update AGENTS.sandbox.md * refactor: restructure workflows to directory-per-workflow convention * refactor: move sandbox files into .flue/sandbox/ directory * update deps * format, link --------- Co-authored-by: Fred K. Schott --- .../analyze-github-action-logs/SKILL.md | 115 ++++++++++++++ .agents/skills/triage/comment.md | 8 +- .agents/skills/triage/diagnose.md | 2 + .agents/skills/triage/reproduce.md | 4 +- .agents/skills/triage/verify.md | 21 +-- .flue/sandbox/AGENTS.md | 4 + .../Dockerfile} | 19 ++- .../WORKFLOW.ts} | 136 +++++++---------- .flue/workflows/issue-triage/github.ts | 144 ++++++++++++++++++ .github/workflows/build-sandbox-image.yml | 6 +- .github/workflows/issue-labeled.yml | 47 ------ .github/workflows/issue-needs-repro.yml | 26 +++- .github/workflows/issue-opened.yml | 23 --- .github/workflows/issue-triage.yml | 31 +++- .github/workflows/issue-wontfix.yml | 28 ++++ AGENTS.md | 56 +++++-- knip.js | 3 +- package.json | 1 + pnpm-lock.yaml | 11 ++ 19 files changed, 487 insertions(+), 198 deletions(-) create mode 100644 .agents/skills/analyze-github-action-logs/SKILL.md create mode 100644 .flue/sandbox/AGENTS.md rename .flue/{Dockerfile.sandbox => sandbox/Dockerfile} (69%) rename .flue/workflows/{issue-triage.ts => issue-triage/WORKFLOW.ts} (74%) create mode 100644 .flue/workflows/issue-triage/github.ts delete mode 100644 .github/workflows/issue-labeled.yml delete mode 100644 .github/workflows/issue-opened.yml create mode 100644 .github/workflows/issue-wontfix.yml diff --git a/.agents/skills/analyze-github-action-logs/SKILL.md b/.agents/skills/analyze-github-action-logs/SKILL.md new file mode 100644 index 000000000000..96926c7b3044 --- /dev/null +++ b/.agents/skills/analyze-github-action-logs/SKILL.md @@ -0,0 +1,115 @@ +--- +name: analyze-github-action-logs +description: Analyze recent GitHub Actions workflow runs to identify patterns, mistakes, and improvements. Use when asked to "analyze workflow logs", "review action runs", or "analyze GitHub Actions". +compatibility: Requires gh CLI and access to the GitHub repository. +--- + +# Analyze GitHub Action Logs + +Fetch and analyze recent GitHub Actions runs for a given workflow. Review agent/step performance, identify wasted effort and mistakes, and produce a report with actionable improvements. + +## Input + +You need: + +- **`workflow`** (required) — The workflow file name or ID (e.g., `issue-triage.yml`, `deploy.yml`). +- **`repo`** (optional) — The GitHub repository in `OWNER/REPO` format. Defaults to `withastro/astro`. +- **`count`** (optional) — Number of recent completed runs to analyze. Defaults to `5`. + +## Step 1: List Recent Runs + +Fetch the most recent completed runs for the workflow. Filter by `--status=completed`: + +```bash +gh run list --workflow= -R --status=completed -L +``` + +Present the list to orient yourself: run IDs, titles, status (success/failure), and duration. Pick the runs to analyze — prefer a mix of successes and failures if available, and prefer runs that exercised more steps (longer runs tend to go through more stages, while shorter runs may exit early). + +## Step 2: Fetch Logs + +For each run you want to analyze, save the full log to a temp file: + +```bash +gh run view -R --log > /tmp/actions-run-.log +``` + +## Step 3: Identify Step/Skill Boundaries + +Search each log file for markers that indicate where each step or skill starts and ends. The markers depend on the workflow — look for patterns like: + +- **Flue skill markers**: `[flue] skill("..."): starting` / `completed` +- **GitHub Actions step markers**: Step name headers in the log output +- **Custom markers**: Any `START`/`END` or similar delimiters the workflow uses + +```bash +grep -n "skill(\|step\|START\|END\|starting\|completed" /tmp/actions-run-.log | head -50 +``` + +From this, determine which line ranges correspond to each step/skill. Also find any result markers: + +```bash +grep -n "RESULT_START\|RESULT_END\|extractResult" /tmp/actions-run-.log +``` + +Note: Some log files may contain binary/null bytes. Use `grep -a` if needed. + +## Step 4: Analyze Each Step (Use Subagents) + +For each step/skill that ran, **launch a subagent** to analyze that section's log. This is critical to avoid polluting your context with thousands of log lines. + +For each subagent, provide: + +1. The log file path and the line range for that step +2. If skill instruction files exist for the workflow, tell the subagent to read them first for context +3. The run title/context so the subagent understands what was being done +4. The analysis criteria below + +### Analysis Criteria + +Tell each subagent to evaluate: + +1. **Correctness** — Was the step's final result/verdict correct? +2. **Efficiency** — How long did it take? What's a reasonable baseline? Where was time wasted? +3. **Mistakes** — Wrong tool calls, failed commands retried without changes, unnecessary rebuilds, etc. +4. **Instruction compliance** — If skill instructions exist, did the agent follow them? Where did it deviate? +5. **Scope creep** — Did the agent do work that belongs in a different step? +6. **Suggestions** — Specific, actionable changes that would prevent the issues found. + +Tell each subagent to return a structured response with: Summary, Time Analysis, Issues Found (with estimated time wasted for each), and Suggestions for Improvement. + +## Step 5: Consolidate Report + +After all subagents return, synthesize their findings into a single report. Structure it as: + +### Per-Run Summary Table + +For each run analyzed, include a table: + +| Step/Skill | Time | Result | Time Wasted | Top Issue | +| ---------- | ---- | ------ | ----------- | --------- | + +### Cross-Cutting Patterns + +Identify issues that appeared across multiple runs or multiple steps. These are the highest-value improvements. Common patterns to look for: + +- **TodoWrite abuse** — Agent wasting time on task list management during automated runs +- **Server management failures** — Port conflicts, failed process kills, stale log files +- **Tool misuse** — Using `curl` instead of `gh`, `jq` not found, etc. +- **Scope creep** — One step doing work that belongs in another +- **Unnecessary rebuilds** — Building packages multiple times without changes +- **Test timeouts** — Running slow E2E/Playwright tests that time out +- **Instruction violations** — Agent doing something the instructions explicitly forbid +- **Redundant work** — Re-reading files, re-running searches, re-installing dependencies + +### Prioritized Recommendations + +Rank your improvement suggestions by estimated time savings across all runs. For each recommendation: + +1. **What to change** — Which file(s) to edit and what to add/modify +2. **Why** — What pattern it addresses, with evidence from the runs +3. **Estimated impact** — How much time it would save per run + +## Output + +Present the full consolidated report. Do NOT edit any workflow or skill files — only report findings and recommendations. The user will decide which changes to apply. diff --git a/.agents/skills/triage/comment.md b/.agents/skills/triage/comment.md index 1ffbbefe37e2..f446dc6eecf1 100644 --- a/.agents/skills/triage/comment.md +++ b/.agents/skills/triage/comment.md @@ -4,6 +4,8 @@ Generate a GitHub issue comment from triage findings. **CRITICAL: You MUST always read `report.md` and produce a GitHub comment as your final output, regardless of what input files are available. Even if `report.md` is missing or empty, you must still produce a comment. In that case, produce a minimal comment stating that automated triage could not be completed.** +**SCOPE: Your job is comment generation only. Finish your work once you've completed this workflow. Do NOT go further than this. It is no longer time to attempt reproduction, diagnosis, or fixing of the issue.** + ## Prerequisites These variables are referenced throughout this skill. They may be passed as args by an orchestrator, or inferred from the conversation when run standalone. @@ -41,16 +43,16 @@ The **Fix** line in the template has three possible forms. Choose the one that m The **Priority** line communicates the severity of this issue to maintainers. Its goal is to answer the question: **"How bad is it?"** -Select exactly ONE priority label from the `priorityLabels` arg. Use the label descriptions to guide your decision, combined with the triage report's root cause and impact analysis. Render the chosen label name in square brackets, in bold, formatted with the `- ` prefix removed (Example: `**[P2: Has Workaround].**). Then, follow it with 1-2 sentences explaining **why** you chose that priority. Answer: "who is likely to be affected and under what conditions?". If you are unsure, use your best judgment based on the label descriptions and the triage findings. +Select exactly ONE priority label from the `priorityLabels` arg. Use the label descriptions to guide your decision, combined with the triage report's root cause and impact analysis. Render it in bold, with the `- ` prefix removed, like this: `**Priorty P2: Has Workaround.** Then, follow it with 1-2 sentences explaining _why_ you chose that priority. Answer: "who is likely to be affected and under what conditions?". If you are unsure, use your best judgment based on the label descriptions and the triage findings. ### Template ```markdown **[I was able to reproduce this issue. / I was unable to reproduce this issue.]** [2-3 sentences describing the root cause, result, and key observations.] -**Fix:** **[See "Fix" Instructions above.]** [1-2 sentences describing the solution, where/when it was already fixed, or guidance on where a fix might be.] [If `branchName` is non-null: [View Suggested Fix](https://github.com/withastro/astro/compare/{branchName}?expand=1)] +**[See "Fix" Instructions above.]** [1-2 sentences describing the solution, where/when it was already fixed, or guidance on where a fix might be.] [If `branchName` is non-null: [View Suggested Fix](https://github.com/withastro/astro/compare/{branchName}?expand=1)] -**Priority:** **[See "Priority" Instructions above.]** [1-2 sentences explaining why this priority was chosen, who is likely to be affected, and under what conditions (this section should answer the question: "how bad is it?")] +**[See "Priority" Instructions above.]** [1-2 sentences explaining why this priority was chosen, who is likely to be affected, and under what conditions (this section should answer the question: "how bad is it?")]
Full Triage Report diff --git a/.agents/skills/triage/diagnose.md b/.agents/skills/triage/diagnose.md index 0e6cfaef393d..b27d3939577f 100644 --- a/.agents/skills/triage/diagnose.md +++ b/.agents/skills/triage/diagnose.md @@ -4,6 +4,8 @@ Find the root cause of a reproduced bug in the Astro source code. **CRITICAL: You MUST always read `report.md` and append to `report.md` before finishing, regardless of outcome. Even if you cannot identify the root cause, hit errors, or the investigation is inconclusive — always update `report.md` with your findings. The orchestrator and downstream skills depend on this file to determine what happened.** +**SCOPE: Your job is diagnosis only. Finish your work once you've completed this workflow. Do NOT go further than this (no larger verification of the issue, no fixing of the issue, etc.).** + ## Prerequisites These variables are referenced throughout this skill. They may be passed as args by an orchestrator, or inferred from the conversation when run standalone. diff --git a/.agents/skills/triage/reproduce.md b/.agents/skills/triage/reproduce.md index 87442b7ef767..4b307c897ed7 100644 --- a/.agents/skills/triage/reproduce.md +++ b/.agents/skills/triage/reproduce.md @@ -4,6 +4,8 @@ Reproduce a GitHub issue to determine if a bug is valid and reproducible. **CRITICAL: You MUST always read `report.md` and write `report.md` to the triage directory before finishing, regardless of outcome. Even if you encounter errors, cannot reproduce the bug, hit unexpected problems, or need to skip — always write `report.md`. The orchestrator and downstream skills depend on this file to determine what happened. If you finish without writing it, the entire pipeline fails silently.** +**SCOPE: Your job is reproduction only. Finish your work once you've completed this workflow. Do NOT go further than this (no larger diagnosis of the issue, no fixing of the issue, etc.).** + ## Prerequisites These variables are referenced throughout this skill. They may be passed as args by an orchestrator, or inferred from the conversation when run standalone. @@ -67,7 +69,7 @@ Skip if the bug is specific to Bun or Deno. Our sandbox only supports Node.js. ### Maintainer Override (`maintainer-override`) -Skip if a repository maintainer has commented that this issue should not be reproduced here. To determine if a commenter is a maintainer, check the `author_association` field on their comment in `issueDetails` — values of `MEMBER`, `COLLABORATOR`, or `OWNER` indicate a maintainer. +Skip if a repository maintainer has commented that this issue should not be reproduced here. To determine if a commenter is a maintainer, check the `authorAssociation` field on their comment in `issueDetails` — values of `MEMBER`, `COLLABORATOR`, or `OWNER` indicate a maintainer. ## Step 3: Set Up Reproduction Project diff --git a/.agents/skills/triage/verify.md b/.agents/skills/triage/verify.md index e0bdebb5c24d..3e627da0de94 100644 --- a/.agents/skills/triage/verify.md +++ b/.agents/skills/triage/verify.md @@ -4,6 +4,8 @@ Verify whether a GitHub issue describes an actual bug or a misunderstanding of i **CRITICAL: You MUST always read `report.md` and append to `report.md` before finishing, regardless of outcome. Even if you cannot reach a conclusion — always update `report.md` with your findings. The orchestrator and downstream skills depend on this file to determine what happened.** +**SCOPE: Your job is verification only. Finish your work once you've completed this workflow. Do NOT go further than this (no fixing of the issue, etc.).** + ## Prerequisites These variables are referenced throughout this skill. They may be passed as args by an orchestrator, or inferred from the conversation when run standalone. @@ -46,28 +48,29 @@ Look at the relevant source code in `packages/`. Pay close attention to: - **Comments explaining "why"** — If a developer left a comment explaining why the code works a certain way, that is strong evidence of intentional design. Treat these comments as authoritative unless they are clearly outdated. - **Explicit conditionals and early returns** — Code that explicitly checks for the reported scenario and handles it differently than the reporter expects is likely intentional. - **Named constants and configuration** — Behavior controlled by a named config option or constant was probably a deliberate choice. -- **Git blame on key lines** — If `report.md` identifies specific files and line numbers, run `git blame` on the relevant lines to find the commit that introduced the behavior. Then read the full commit message with `git show --no-patch ` and review the associated PR if referenced. You can fetch PR details with `curl -s "https://api.github.com/repos/withastro/astro/pulls/"`. A commit message or PR description that explains the rationale is strong evidence of intentional design. -### 2c: Search prior GitHub issues and PRs +### 2c: Git blame on key lines + +If `report.md` identifies specific files and line numbers, run `git blame` on the relevant lines to find the commit that introduced the behavior. Then read the full commit message with `git show --no-patch ` and review the associated PR if referenced. You can fetch PR details with `gh pr view `. A commit message, PR description, or PR comment from the author explaining the rationale is strong evidence of intentional design. + +### 2d: Search prior GitHub issues and PRs Search for prior issues and PRs that discuss the same behavior using the GitHub API. This can reveal whether the behavior was previously discussed, intentionally introduced, or already reported and closed as "not a bug." ```bash # Search issues for keywords related to the reported behavior -curl -s "https://api.github.com/search/issues?q=+repo:withastro/astro+is:issue&per_page=10" +gh search issues "" # Search PRs that may have introduced or discussed the behavior -curl -s "https://api.github.com/search/issues?q=+repo:withastro/astro+is:pr&per_page=10" +gh search prs "" # Read a specific issue for context -curl -s "https://api.github.com/repos/withastro/astro/issues/" -# Read issue comments -curl -s "https://api.github.com/repos/withastro/astro/issues//comments" +gh issue view --comments # Read a specific PR for context -curl -s "https://api.github.com/repos/withastro/astro/pulls/" +gh pr view --comments ``` If you find a closed issue where a maintainer explained why the behavior is intentional, or a PR that deliberately introduced it, that is strong evidence of intended behavior. -### 2d: Distinguish bugs from non-bugs +### 2e: Distinguish bugs from non-bugs This is the most important and most error-prone step. For triage purposes, the definitions are: diff --git a/.flue/sandbox/AGENTS.md b/.flue/sandbox/AGENTS.md new file mode 100644 index 000000000000..e80afb75db83 --- /dev/null +++ b/.flue/sandbox/AGENTS.md @@ -0,0 +1,4 @@ +# Sandbox Environment (CI) + +- You are running inside a Docker container in CI. +- Always use `CI=true` with `pnpm install` (no TTY available) diff --git a/.flue/Dockerfile.sandbox b/.flue/sandbox/Dockerfile similarity index 69% rename from .flue/Dockerfile.sandbox rename to .flue/sandbox/Dockerfile index 711370782f0d..ab6b9793d65e 100644 --- a/.flue/Dockerfile.sandbox +++ b/.flue/sandbox/Dockerfile @@ -7,7 +7,7 @@ ENV DEBIAN_FRONTEND=noninteractive # The slim image includes Node.js and npm but not git, curl, or wget. RUN apt-get update \ && apt-get install -y --no-install-recommends \ - ca-certificates curl wget git \ + ca-certificates curl wget git jq lsof procps \ && rm -rf /var/lib/apt/lists/* # --- pnpm --- @@ -44,7 +44,17 @@ RUN apt-get update \ && chmod -R o+rx /opt/pw-browsers \ && npm uninstall -g playwright -# NOTE: gh CLI is intentionally NOT installed in the sandbox due to lack of tokens. +# --- GitHub CLI (for read-only public repo operations without auth) --- +RUN (type -p wget >/dev/null || (apt-get update && apt-get install wget -y)) \ + && mkdir -p -m 755 /etc/apt/keyrings \ + && out=$(mktemp) && wget -nv -O$out https://cli.github.com/packages/githubcli-archive-keyring.gpg \ + && cat $out | tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null \ + && chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \ + && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \ + | tee /etc/apt/sources.list.d/github-cli.list > /dev/null \ + && apt-get update \ + && apt-get install gh -y \ + && rm -rf /var/lib/apt/lists/* # --- Compatibility fixes --- # Allow any directory as a git safe.directory. The host workspace is bind-mounted @@ -52,6 +62,11 @@ RUN apt-get update \ # runs as a non-root UID via --user, so git would otherwise refuse to operate. RUN git config --system --add safe.directory '*' +# --- Global OpenCode rules for CI sessions --- +# The flue CLI sets HOME=/tmp at runtime, so OpenCode reads global rules from +# /tmp/.config/opencode/AGENTS.md. This injects CI-specific instructions. +COPY .flue/sandbox/AGENTS.md /tmp/.config/opencode/AGENTS.md + EXPOSE 48765 # Default: start OpenCode server listening on all interfaces diff --git a/.flue/workflows/issue-triage.ts b/.flue/workflows/issue-triage/WORKFLOW.ts similarity index 74% rename from .flue/workflows/issue-triage.ts rename to .flue/workflows/issue-triage/WORKFLOW.ts index 5e76aef836ce..373776d45cbc 100644 --- a/.flue/workflows/issue-triage.ts +++ b/.flue/workflows/issue-triage/WORKFLOW.ts @@ -1,31 +1,38 @@ -import type { Flue } from '@flue/client'; +import type { FlueClient } from '@flue/client'; +import { anthropic, github, githubBody } from '@flue/client/proxies'; import * as v from 'valibot'; +import { + type IssueDetails, + type RepoLabel, + addGitHubLabels, + fetchIssueDetails, + fetchRepoLabels, + postGitHubComment, + removeGitHubLabel, +} from './github.ts'; + +export const proxies = { + anthropic: anthropic(), + github: github({ + policy: { + base: 'allow-read', + allow: [ + // Allow read-only access to the GraphQL endpoint + { method: 'POST', path: '/graphql', body: githubBody.graphql() }, + // Allow git clone, fetch, and push over smart HTTP transport + { method: 'GET', path: '/*/info/refs' }, + { method: 'POST', path: '/*/git-upload-pack' }, + { method: 'POST', path: '/*/git-receive-pack' }, + ], + }, + }), +}; function assert(condition: unknown, message: string): asserts condition { if (!condition) throw new Error(message); } -const issueDetailsSchema = v.object({ - title: v.string(), - body: v.string(), - author: v.object({ login: v.string() }), - labels: v.array(v.looseObject({ name: v.string() })), - createdAt: v.string(), - state: v.string(), - number: v.number(), - url: v.string(), - comments: v.array( - v.looseObject({ - author: v.object({ login: v.string() }), - authorAssociation: v.string(), - body: v.string(), - createdAt: v.string(), - }), - ), -}); -type IssueDetails = v.InferOutput; - -async function shouldRetriage(flue: Flue, issue: IssueDetails): Promise<'yes' | 'no'> { +async function shouldRetriage(flue: FlueClient, issue: IssueDetails): Promise<'yes' | 'no'> { return flue.prompt( `You are reviewing a GitHub issue conversation to decide whether a triage re-run is warranted. @@ -57,43 +64,14 @@ Return only "yes" or "no" inside the ---RESULT_START--- / ---RESULT_END--- block ); } -const repoLabelSchema = v.object({ - name: v.string(), - description: v.nullable(v.string()), -}); -type RepoLabel = v.InferOutput; - -async function fetchRepoLabels(flue: Flue): Promise<{ - priorityLabels: RepoLabel[]; - packageLabels: RepoLabel[]; -}> { - const labelsJson = await flue.shell( - "gh api repos/withastro/astro/labels --paginate --jq '.[] | {name, description}'", - { env: { GH_TOKEN: flue.secrets.GITHUB_TOKEN } }, - ); - const allLabels = v.parse( - v.array(repoLabelSchema), - labelsJson.stdout - .trim() - .split('\n') - .filter(Boolean) - .map((line) => JSON.parse(line)), - ); - - return { - priorityLabels: allLabels.filter((l) => /^- P\d/.test(l.name)), - packageLabels: allLabels.filter((l) => l.name.startsWith('pkg:')), - }; -} - async function selectTriageLabels( - flue: Flue, + flue: FlueClient, { comment, priorityLabels, packageLabels, }: { comment: string; priorityLabels: RepoLabel[]; packageLabels: RepoLabel[] }, -): Promise { +): Promise { const priorityLabelNames = priorityLabels.map((l) => l.name); const packageLabelNames = packageLabels.map((l) => l.name); @@ -132,12 +110,11 @@ ${comment} }, ); - const allLabels = [labelResult.priority, ...labelResult.packages]; - return allLabels.map((l) => `--add-label ${JSON.stringify(l)}`).join(' '); + return [labelResult.priority, ...labelResult.packages]; } async function runTriagePipeline( - flue: Flue, + flue: FlueClient, issueNumber: number, issueDetails: IssueDetails, ): Promise<{ @@ -239,20 +216,22 @@ async function runTriagePipeline( }; } -export default async function triage(flue: Flue) { - const { issueNumber } = v.parse(v.object({ issueNumber: v.number() }), flue.args); - const issueResult = await flue.shell( - `gh issue view ${issueNumber} --json title,body,author,labels,createdAt,state,number,url,comments`, - { env: { GH_TOKEN: flue.secrets.GITHUB_TOKEN } }, - ); - const issueDetails = v.parse(issueDetailsSchema, JSON.parse(issueResult.stdout)); +export const args = v.object({ + issueNumber: v.number(), +}); + +export default async function triage( + flue: FlueClient, + { issueNumber }: v.InferOutput, +) { + const branch = `flue/fix-${issueNumber}`; + const issueDetails = await fetchIssueDetails(issueNumber); // If there are prior comments, this is a re-triage. Check whether new // actionable information has been provided before running the full pipeline. const hasExistingConversation = issueDetails.comments.length > 0; if (hasExistingConversation) { const shouldRetriageResult = await shouldRetriage(flue, issueDetails); - if (shouldRetriageResult === 'no') { return { skipped: true, reason: 'No new actionable information' }; } @@ -270,7 +249,6 @@ export default async function triage(flue: Flue) { if (triageResult.fixed) { const diff = await flue.shell('git diff main --stat'); if (diff.stdout.trim()) { - await flue.shell(`git checkout -B ${flue.branch}`); const status = await flue.shell('git status --porcelain'); if (status.stdout.trim()) { await flue.shell('git add -A'); @@ -278,7 +256,7 @@ export default async function triage(flue: Flue) { `git commit -m ${JSON.stringify(triageResult.commitMessage ?? 'fix(auto-triage): automated fix')}`, ); } - const pushResult = await flue.shell(`git push -f origin ${flue.branch}`); + const pushResult = await flue.shell(`git push -f origin ${branch}`); console.info('push result:', pushResult); isPushed = pushResult.exitCode === 0; } @@ -286,11 +264,11 @@ export default async function triage(flue: Flue) { // Fetch repo labels upfront so we can pass priority labels to the comment // skill (which selects the priority) and package labels to the label selector. - const { priorityLabels, packageLabels } = await fetchRepoLabels(flue); + const { priorityLabels, packageLabels } = await fetchRepoLabels(); assert(priorityLabels.length > 0, 'no priority labels found'); assert(packageLabels.length > 0, 'no package labels found'); - const branchName = isPushed ? flue.branch : null; + const branchName = isPushed ? branch : null; const comment = await flue.skill('triage/comment.md', { args: { branchName, priorityLabels, issueDetails }, result: v.pipe( @@ -301,33 +279,23 @@ export default async function triage(flue: Flue) { ), }); - await flue.shell(`gh issue comment ${issueNumber} --body-file -`, { - stdin: comment, - env: { GH_TOKEN: flue.secrets.FREDKBOT_GITHUB_TOKEN }, - }); + await postGitHubComment(issueNumber, comment); if (triageResult.reproducible) { - await flue.shell(`gh issue edit ${issueNumber} --remove-label "needs triage"`, { - env: { GH_TOKEN: flue.secrets.GITHUB_TOKEN }, - }); - - const labelFlags = await selectTriageLabels(flue, { + await removeGitHubLabel(issueNumber, 'needs triage'); + const selectedLabels = await selectTriageLabels(flue, { comment, priorityLabels, packageLabels, }); - if (labelFlags) { - await flue.shell(`gh issue edit ${issueNumber} ${labelFlags}`, { - env: { GH_TOKEN: flue.secrets.GITHUB_TOKEN }, - }); + if (selectedLabels.length > 0) { + await addGitHubLabels(issueNumber, selectedLabels); } } else if (triageResult.skipped) { // Triage was skipped due to a runner limitation. Keep "needs triage" so a // maintainer can still pick it up, and add "auto triage skipped" to prevent // the workflow from re-running on every new comment. - await flue.shell(`gh issue edit ${issueNumber} --add-label "auto triage skipped"`, { - env: { GH_TOKEN: flue.secrets.GITHUB_TOKEN }, - }); + await addGitHubLabels(issueNumber, ['auto triage skipped']); } else { // Not reproducible: do nothing. The "needs triage" label stays on the issue // so that it can continue to be worked on and triaged by the humans. diff --git a/.flue/workflows/issue-triage/github.ts b/.flue/workflows/issue-triage/github.ts new file mode 100644 index 000000000000..5cc00952a7dc --- /dev/null +++ b/.flue/workflows/issue-triage/github.ts @@ -0,0 +1,144 @@ +import * as v from 'valibot'; + +const REPO = 'withastro/astro'; + +function headers(): Record { + const token = process.env.FREDKBOT_GITHUB_TOKEN || process.env.GITHUB_TOKEN; + if (!token) throw new Error('token is not set'); + return { + Authorization: `token ${token}`, + 'Content-Type': 'application/json', + Accept: 'application/vnd.github+json', + }; +} + +export const issueDetailsSchema = v.object({ + title: v.string(), + body: v.string(), + author: v.object({ login: v.string() }), + labels: v.array(v.looseObject({ name: v.string() })), + createdAt: v.string(), + state: v.string(), + number: v.number(), + url: v.string(), + comments: v.array( + v.looseObject({ + author: v.object({ login: v.string() }), + authorAssociation: v.string(), + body: v.string(), + createdAt: v.string(), + }), + ), +}); +export type IssueDetails = v.InferOutput; + +export const repoLabelSchema = v.object({ + name: v.string(), + description: v.nullable(v.string()), +}); + +export type RepoLabel = v.InferOutput; + +export async function fetchIssueDetails(issueNumber: number): Promise { + const [issueRes, commentsRes] = await Promise.all([ + fetch(`https://api.github.com/repos/${REPO}/issues/${issueNumber}`, { headers: headers() }), + fetch(`https://api.github.com/repos/${REPO}/issues/${issueNumber}/comments?per_page=100`, { + headers: headers(), + }), + ]); + + if (!issueRes.ok) { + throw new Error( + `Failed to fetch issue ${issueNumber} (HTTP ${issueRes.status}): ${await issueRes.text()}`, + ); + } + if (!commentsRes.ok) { + throw new Error( + `Failed to fetch comments for issue ${issueNumber} (HTTP ${commentsRes.status}): ${await commentsRes.text()}`, + ); + } + + const issue = (await issueRes.json()) as Record; + const rawComments = (await commentsRes.json()) as Record[]; + + // Map from REST API snake_case to the camelCase shape the workflow expects + return v.parse(issueDetailsSchema, { + title: issue.title, + body: issue.body ?? '', + author: { login: (issue.user as Record)?.login }, + labels: issue.labels, + createdAt: issue.created_at, + state: issue.state, + number: issue.number, + url: issue.html_url, + comments: rawComments.map((c) => ({ + author: { login: (c.user as Record)?.login }, + authorAssociation: c.author_association, + body: c.body, + createdAt: c.created_at, + })), + }); +} + +export async function fetchRepoLabels(): Promise<{ + priorityLabels: RepoLabel[]; + packageLabels: RepoLabel[]; +}> { + const allLabels: RepoLabel[] = []; + let page = 1; + + // Paginate through all labels (100 per page) + while (true) { + const res = await fetch( + `https://api.github.com/repos/${REPO}/labels?per_page=100&page=${page}`, + { headers: headers() }, + ); + if (!res.ok) { + throw new Error(`Failed to fetch labels (HTTP ${res.status}): ${await res.text()}`); + } + const batch = v.parse(v.array(repoLabelSchema), await res.json()); + allLabels.push(...batch); + if (batch.length < 100) break; + page++; + } + + return { + priorityLabels: allLabels.filter((l) => /^- P\d/.test(l.name)), + packageLabels: allLabels.filter((l) => l.name.startsWith('pkg:')), + }; +} + +export async function postGitHubComment(issueNumber: number, body: string): Promise { + const res = await fetch(`https://api.github.com/repos/${REPO}/issues/${issueNumber}/comments`, { + method: 'POST', + headers: headers(), + body: JSON.stringify({ body }), + }); + if (!res.ok) { + throw new Error(`Failed to post comment (HTTP ${res.status}): ${await res.text()}`); + } +} + +export async function addGitHubLabels(issueNumber: number, labels: string[]): Promise { + const res = await fetch(`https://api.github.com/repos/${REPO}/issues/${issueNumber}/labels`, { + method: 'POST', + headers: headers(), + body: JSON.stringify({ labels }), + }); + if (!res.ok) { + throw new Error(`Failed to add labels (HTTP ${res.status}): ${await res.text()}`); + } +} + +export async function removeGitHubLabel(issueNumber: number, label: string): Promise { + const res = await fetch( + `https://api.github.com/repos/${REPO}/issues/${issueNumber}/labels/${encodeURIComponent(label)}`, + { + method: 'DELETE', + headers: headers(), + }, + ); + if (!res.ok && res.status !== 404) { + throw new Error(`Failed to remove label (HTTP ${res.status}): ${await res.text()}`); + } +} diff --git a/.github/workflows/build-sandbox-image.yml b/.github/workflows/build-sandbox-image.yml index 38d06cce8afe..704771e41dfa 100644 --- a/.github/workflows/build-sandbox-image.yml +++ b/.github/workflows/build-sandbox-image.yml @@ -2,7 +2,7 @@ name: Build Sandbox Image on: push: - paths: ['.flue/Dockerfile.sandbox', '.github/workflows/build-sandbox-image.yml'] + paths: ['.flue/sandbox/Dockerfile', '.flue/sandbox/AGENTS.md', '.github/workflows/build-sandbox-image.yml'] workflow_dispatch: env: @@ -31,10 +31,10 @@ jobs: - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 with: context: . - file: .flue/Dockerfile.sandbox + file: .flue/sandbox/Dockerfile push: true tags: | ${{ env.IMAGE }}:latest - ${{ env.IMAGE }}:${{ hashFiles('.flue/Dockerfile.sandbox') }} + ${{ env.IMAGE }}:${{ hashFiles('.flue/sandbox/Dockerfile', '.flue/sandbox/AGENTS.md') }} cache-from: type=gha cache-to: type=gha,mode=max diff --git a/.github/workflows/issue-labeled.yml b/.github/workflows/issue-labeled.yml deleted file mode 100644 index 279ed4327008..000000000000 --- a/.github/workflows/issue-labeled.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Issue Labeled - -on: - issues: - types: [labeled] - -jobs: - reply-labeled: - if: github.repository == 'withastro/astro' - runs-on: ubuntu-latest - steps: - - name: remove triage - if: contains(github.event.label.description, '(priority)') && contains(github.event.issue.labels.*.name, 'needs triage') - uses: actions-cool/issues-helper@71b62d7da76e59ff7b193904feb6e77d4dbb2777 # v3.7.6 - with: - actions: "remove-labels" - token: ${{ secrets.GITHUB_TOKEN }} - issue-number: ${{ github.event.issue.number }} - labels: "needs triage" - - - name: needs repro - if: github.event.label.name == 'needs repro' - uses: actions-cool/issues-helper@71b62d7da76e59ff7b193904feb6e77d4dbb2777 # v3.7.6 - with: - actions: "create-comment, remove-labels" - token: ${{ secrets.GITHUB_TOKEN }} - issue-number: ${{ github.event.issue.number }} - body: | - Hello @${{ github.event.issue.user.login }}. Please provide a [minimal reproduction](https://stackoverflow.com/help/minimal-reproducible-example) using a GitHub repository or [StackBlitz](https://astro.new/repro). Issues marked with `needs repro` will be closed if they have no activity within 3 days. - labels: "needs triage" - - name: wontfix - if: github.event.label.name == 'wontfix' - uses: actions-cool/issues-helper@71b62d7da76e59ff7b193904feb6e77d4dbb2777 # v3.7.6 - with: - actions: "create-comment, close-issue" - token: ${{ secrets.GITHUB_TOKEN }} - issue-number: ${{ github.event.issue.number }} - body: | - Hello! - - This is an automated message to let you know that we've triaged this issue and unfortunately, we will be closing it as "not planned". - - We sometimes have to close good ideas (even great ones!) because our limited resources simply do not allow us to pursue all possible features and improvements, and when fixing bugs we have to balance the impact of the bug against the effort required for the fix. Before closing this we considered several factors such as the amount of work involved, the severity of the problem, the number of people affected, whether a workaround is available, and the ongoing cost of maintenance. - - If you're seeing this message and believe you can contribute to this issue, please consider submitting a PR yourself. Astro encourages [community contributions](https://docs.astro.build/en/contribute/)! - - If you have more questions, come and say hi in the [Astro Discord](https://astro.build/chat). diff --git a/.github/workflows/issue-needs-repro.yml b/.github/workflows/issue-needs-repro.yml index a7647bb12ae5..703a590cae84 100644 --- a/.github/workflows/issue-needs-repro.yml +++ b/.github/workflows/issue-needs-repro.yml @@ -1,16 +1,32 @@ -name: Close Issues (needs repro) +name: "Issue: Needs Repro" on: + issues: + types: [labeled] schedule: - cron: "0 0 * * *" jobs: - close-issues: - if: github.repository == 'withastro/astro' + on-labeled: + if: github.event_name == 'issues' && github.event.label.name == 'needs repro' runs-on: ubuntu-latest + permissions: + issues: write steps: - - name: needs repro - uses: actions-cool/issues-helper@71b62d7da76e59ff7b193904feb6e77d4dbb2777 # v3.7.6 + - uses: actions-cool/issues-helper@71b62d7da76e59ff7b193904feb6e77d4dbb2777 # v3.7.6 + with: + actions: "create-comment, remove-labels" + token: ${{ secrets.GITHUB_TOKEN }} + issue-number: ${{ github.event.issue.number }} + body: | + Hello @${{ github.event.issue.user.login }}. Please provide a [minimal reproduction](https://stackoverflow.com/help/minimal-reproducible-example) using a GitHub repository or [StackBlitz](https://astro.new/repro). Issues marked with `needs repro` will be closed if they have no activity within 3 days. + labels: "needs triage" + + close-stale: + if: github.event_name == 'schedule' && github.repository == 'withastro/astro' + runs-on: ubuntu-latest + steps: + - uses: actions-cool/issues-helper@71b62d7da76e59ff7b193904feb6e77d4dbb2777 # v3.7.6 with: actions: "close-issues" token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/issue-opened.yml b/.github/workflows/issue-opened.yml deleted file mode 100644 index 8b3aa6d6c230..000000000000 --- a/.github/workflows/issue-opened.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Label issues -on: - issues: - types: - - reopened - - opened - -jobs: - label_issues: - runs-on: ubuntu-latest - if: github.repository == 'withastro/astro' - permissions: - issues: write - steps: - - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 - with: - script: | - github.rest.issues.addLabels({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - labels: ["needs triage"] - }) diff --git a/.github/workflows/issue-triage.yml b/.github/workflows/issue-triage.yml index b51afff30604..40151d5c9968 100644 --- a/.github/workflows/issue-triage.yml +++ b/.github/workflows/issue-triage.yml @@ -2,12 +2,13 @@ name: Issue Triage on: issues: - types: [opened] + types: [opened, reopened] issue_comment: types: [created] env: IMAGE: ghcr.io/${{ github.repository }}/flue-sandbox + PNPM_STORE_DIR: .pnpm-store concurrency: # Only one triage run per issue at a time. New runs queue (not cancel) @@ -16,6 +17,24 @@ concurrency: cancel-in-progress: false jobs: + label: + if: >- + !github.event.issue.pull_request && + (github.event.action == 'opened' || github.event.action == 'reopened') + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + with: + script: | + github.rest.issues.addLabels({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: ["needs triage"] + }) + triage: # 1. Skip issues with "auto triage skipped" label # 2. Skip pull requests (issues only) @@ -39,6 +58,8 @@ jobs: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 - name: Configure Git identity run: | @@ -97,6 +118,9 @@ jobs: echo "To attach from your machine:" echo " OPENCODE_API_URL=\$(grep -o 'https://[^ ]*\\.trycloudflare\\.com' /tmp/cloudflared.log) opencode attach" + - name: Checkout fix branch + run: git checkout -B "flue/fix-${{ github.event.issue.number }}" + - name: Run workflow env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -104,8 +128,7 @@ jobs: ANTHROPIC_API_KEY: ${{ secrets.CI_ANTHROPIC_API_KEY }} ISSUE_NUMBER: ${{ github.event.issue.number }} run: | - pnpm flue run .flue/workflows/issue-triage.ts \ + pnpm flue run .flue/workflows/issue-triage/WORKFLOW.ts \ --sandbox $IMAGE:latest \ - --args "{\"issueNumber\": $ISSUE_NUMBER, \"triageDir\": \"triage/issue-$ISSUE_NUMBER\"}" \ - --branch "flue/fix-$ISSUE_NUMBER" \ + --args "{\"issueNumber\": $ISSUE_NUMBER}" \ --model anthropic/claude-opus-4-6 diff --git a/.github/workflows/issue-wontfix.yml b/.github/workflows/issue-wontfix.yml new file mode 100644 index 000000000000..cbc5d3daa0ea --- /dev/null +++ b/.github/workflows/issue-wontfix.yml @@ -0,0 +1,28 @@ +name: "Issue: Wontfix" + +on: + issues: + types: [labeled] + +jobs: + wontfix: + if: github.event.label.name == 'wontfix' + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - uses: actions-cool/issues-helper@71b62d7da76e59ff7b193904feb6e77d4dbb2777 # v3.7.6 + with: + actions: "create-comment, close-issue" + token: ${{ secrets.GITHUB_TOKEN }} + issue-number: ${{ github.event.issue.number }} + body: | + Hello! + + This is an automated message to let you know that we've triaged this issue and unfortunately, we will be closing it as "not planned". + + We sometimes have to close good ideas (even great ones!) because our limited resources simply do not allow us to pursue all possible features and improvements, and when fixing bugs we have to balance the impact of the bug against the effort required for the fix. Before closing this we considered several factors such as the amount of work involved, the severity of the problem, the number of people affected, whether a workaround is available, and the ongoing cost of maintenance. + + If you're seeing this message and believe you can contribute to this issue, please consider submitting a PR yourself. Astro encourages [community contributions](https://docs.astro.build/en/contribute/)! + + If you have more questions, come and say hi in the [Astro Discord](https://astro.build/chat). diff --git a/AGENTS.md b/AGENTS.md index 0e8a706fc96b..ef07345383be 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,9 +5,15 @@ - Run `pnpm format` to auto-format the entire repo. - Run `pnpm lint` to lint the entire repo. +# Environment Guide + +- Use `node -e` for scripting tasks, not `python` or `python3`. + # Monorepo Structure -- This directory is a Git monorepo containing a `pnpm` workspace. The codebase is primarily TypeScript. +This directory is a Git monorepo containing a `pnpm` workspace: + +- The codebase is primarily TypeScript. - All packages live in `packages/`. - Integration packages live in `packages/integrations/`. - The core Astro package is `packages/astro`. @@ -17,7 +23,9 @@ In error stack traces, built files from workspace packages in `node_modules/` ma - `node_modules/astro/dist/...` → `packages/astro/src/...` - `node_modules/@astrojs/react/...` → `packages/integrations/react/src/...` -Note: Edits to source files take effect after rebuilding the package via `pnpm build`. +Edits to source files take effect after rebuilding the package via `pnpm build`. + +Use `pnpm -C ` for project-local script commands when working in packages/examples/triage directories (Example: `pnpm -C packages/astro build`, `pnpm -C examples/blog dev`). Only omit `-C` flag when intentionally working in the monorepo root (Example: `pnpm format`, `pnpm lint`, `pnpm test:types`). # Running Tests @@ -36,23 +44,39 @@ Note: Edits to source files take effect after rebuilding the package via `pnpm b # Astro Quick Reference -- Use `astro dev` to start the local dev server with HMR. -- Use `astro build` to create a production build in `dist/` (static or Node server). -- Use `astro preview` to serve the production build locally (static or Node server). +- Use `astro dev` to start the local dev server with HMR. Do not use other web servers (`python -m http.server`, etc.). +- Use `astro build` to create a production build in `dist/`, by default. +- Use `astro preview` to serve the production build locally. Do not use other web servers (`python -m http.server`, etc.). - Use `astro check` to run type checking and diagnostics. - Use `astro sync` to generate and update TypeScript types. - Use `astro add` to install and configure an official integration. - Fetch **LLM-optimized** docs at https://docs.astro.build/llms.txt. - Fetch **Full docs** at https://docs.astro.build/ (primary source, use when llms.txt lacks info). -# Working with Astro - -- Use `astro dev` and `astro preview` in the background to prevent hanging your entire session, and use `&` to run them in the background. Use `--port RANDOM_NUMBER --strictPort` to avoid port conflicts. Cleanup old servers when you're done. -- Use `astro dev` and `astro preview` as web servers for Astro project. They are reliable. Don't use other web servers for testing. -- Use `pnpm -C ` for project-local script commands when working in packages/examples/triage directories. Only omit `-C` flag when intentionally working in the monorepo root. (Example: `pnpm -C packages/astro build`, `pnpm -C examples/blog dev`) -- Use `agent-browser` for web automation or when UI interaction, long-running browsers, or HMR testing is required. Use `agent-browser --help` for all commands. Use this core workflow: - - Example: `agent-browser open ` - Navigate to page - - Example: `agent-browser snapshot -i` - Get interactive elements with refs (@e1, @e2) - - Example: `agent-browser click @e1` / `fill @e2 "text"` - Interact using refs - - Re-snapshot after page changes. - - Note: If you can't find `agent-browser`, your machine may not have it installed. If this happens, ask the user to run `npm install -g agent-browser && agent-browser install`. If you are running in headless mode with no human operator and need this tool to complete your job, it is best to fail the job vs. trying to work around not having the tool. +# `bgproc` + +Use `pnpm exec bgproc` to start, stop, and manage long-running `astro dev` & `astro preview` servers in the background. Do not manually start detatched servers with `&` if you can use `bgproc` instead. + +Use `pnpm exec bgproc --help` to see all available commands. + +Workflow: + +1. `pnpm exec bgproc start -n devserver --wait-for-port 10 --force -- pnpm -C examples/minimal dev` - Start the dev server +2. `pnpm exec bgproc logs -n devserver` - View logs from the dev server. Useful for debugging server logs. +3. `pnpm exec bgproc stop -n devserver` - Stop when dev server when your work is complete +4. `pnpm exec bgproc list` - List all running servers, background processes. Useful for cleanup. + +# `agent-browser` + +Use `agent-browser` for web automation or when UI interaction, long-running browsers, or HMR testing is required. Do not use `curl` to test HMR issues. + +Use `agent-browser --help` to see all available commands. + +Workflow: + +1. `agent-browser open ` - Navigate to page +2. `agent-browser snapshot -i` - Get interactive elements with refs (@e1, @e2) +3. `agent-browser click @e1` / `fill @e2 "text"` - Interact using refs +4. Re-snapshot after all page changes, navigations, interactions. + +Note: `agent-browser` should be installed globally, and is not a dependency of this monorepo. If `agent-browser` isn't available on this machine, ask the user to run `npm install -g agent-browser && agent-browser install`. If you are running in headless mode with no human operator and need this tool to complete your job, it is best to fail the job vs. trying to work around not having the tool. diff --git a/knip.js b/knip.js index 166660a63dc0..70702de01bc7 100644 --- a/knip.js +++ b/knip.js @@ -15,12 +15,13 @@ export default { '.': { ignoreDependencies: [ '@astrojs/check', // Used by the build script but not as a standard module import + 'bgproc', // Used by agents, documented in the AGENTS.md file ], // In smoke tests, we checkout to the docs repo so those binaries are not present in this project // vsce and ovsx are only used in CI for publishing, and due to how we have to publish the VS Code extension have // to be installed in the vscode package, but knip is expecting them to be in the root node_modules ignoreBinaries: ['docgen', 'docgen:errors', 'playwright', 'vsce', 'ovsx'], - entry: ['.flue/workflows/*'], + entry: ['.flue/workflows/*/WORKFLOW.ts'], }, 'packages/*': { entry: [testEntry], diff --git a/package.json b/package.json index af011e8f420f..07af218309b9 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "@flue/cli": "^0.0.44", "@flue/client": "^0.0.27", "@types/node": "^18.19.115", + "bgproc": "^0.2.0", "esbuild": "0.25.5", "eslint": "^9.39.2", "eslint-plugin-regexp": "^3.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 12ad52208a51..a886bf0e65a9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,6 +33,9 @@ importers: '@types/node': specifier: ^18.19.115 version: 18.19.130 + bgproc: + specifier: ^0.2.0 + version: 0.2.0 esbuild: specifier: 0.25.5 version: 0.25.5 @@ -10975,6 +10978,10 @@ packages: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} + bgproc@0.2.0: + resolution: {integrity: sha512-kBlr0b7PXwde2PmF21g2+i7NJW+pnF2iq5REaJK0uNMNE4iRp0188dG7MaP2Q4qYxJh2VgyB6MGnshGwZ7Aw2A==} + hasBin: true + binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -20387,6 +20394,10 @@ snapshots: dependencies: is-windows: 1.0.2 + bgproc@0.2.0: + dependencies: + citty: 0.1.6 + binary-extensions@2.3.0: {} binaryextensions@6.11.0: From 3252a25b7eb180299e00eb96ac1ebf170143dede Mon Sep 17 00:00:00 2001 From: "Fred K. Schott" <622227+FredKSchott@users.noreply.github.com> Date: Mon, 23 Feb 2026 11:02:25 -0800 Subject: [PATCH 2/2] fix broken proxy policy (#15626) Co-authored-by: Fred K. Schott --- .flue/workflows/issue-triage/WORKFLOW.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.flue/workflows/issue-triage/WORKFLOW.ts b/.flue/workflows/issue-triage/WORKFLOW.ts index 373776d45cbc..8502c78626a5 100644 --- a/.flue/workflows/issue-triage/WORKFLOW.ts +++ b/.flue/workflows/issue-triage/WORKFLOW.ts @@ -20,9 +20,9 @@ export const proxies = { // Allow read-only access to the GraphQL endpoint { method: 'POST', path: '/graphql', body: githubBody.graphql() }, // Allow git clone, fetch, and push over smart HTTP transport - { method: 'GET', path: '/*/info/refs' }, - { method: 'POST', path: '/*/git-upload-pack' }, - { method: 'POST', path: '/*/git-receive-pack' }, + { method: 'GET', path: '/*/*/info/refs' }, + { method: 'POST', path: '/*/*/git-upload-pack' }, + { method: 'POST', path: '/*/*/git-receive-pack' }, ], }, }),