Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/quiet-recaps-label-gate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@agent-native/recap-cli": minor
"@agent-native/core": patch
"@agent-native/skills": patch
---

Add `VISUAL_RECAP_REQUIRED_LABELS` so PR Visual Recap can run only when a pull request has an opt-in label.
22 changes: 21 additions & 1 deletion .github/workflows/pr-visual-recap-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ name: PR Visual Recap (reusable)
#
# IMPORTANT: callers must trigger on the same pull_request event types as this
# file declares in its on.workflow_call section (opened, synchronize, reopened,
# ready_for_review, closed). The workflow_call trigger inherits the CALLER's event
# ready_for_review, labeled, closed). The workflow_call trigger inherits the CALLER's event
# context, so `github.event.pull_request.*` expressions here work correctly only
# when the caller fires on pull_request.

Expand Down Expand Up @@ -97,6 +97,11 @@ on:
required: false
type: string
default: "ubuntu-latest"
required-labels:
description: "Comma-separated PR labels; when set, recaps only run when the PR has at least one listed label"
required: false
type: string
default: ""
secrets:
# Required: bearer token minted by `agent-native connect`. Authorizes
# publishing the recap plan and the screenshot upload.
Expand Down Expand Up @@ -126,6 +131,7 @@ concurrency:
jobs:
gate:
name: Gate
if: github.event.action != 'labeled' || inputs.required-labels != ''
# A custom plain-label runner is allowed only for trusted same-repo authors.
# Fork and untrusted PRs are forced onto GitHub-hosted ubuntu-latest before
# any step starts. The only fromJSON input is this static association list.
Expand All @@ -152,6 +158,7 @@ jobs:
VISUAL_RECAP_MODEL: ${{ inputs.model }}
VISUAL_RECAP_RUNS_ON: ${{ inputs.runs-on }}
VISUAL_RECAP_BASE_URL: ${{ inputs.base-url }}
VISUAL_RECAP_REQUIRED_LABELS: ${{ inputs.required-labels }}
VISUAL_RECAP_SKILL_SOURCE: ${{ inputs.skill-source || 'auto' }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
with:
Expand All @@ -164,6 +171,19 @@ jobs:
if (pr && context.payload.action === 'closed' && !pr.merged) {
reasons.push('closed without merge');
}
const requiredLabels = (process.env.VISUAL_RECAP_REQUIRED_LABELS || '')
.split(',')
.map((label) => label.trim().toLowerCase())
.filter(Boolean);
if (pr && requiredLabels.length > 0) {
const prLabels = new Set((Array.isArray(pr.labels) ? pr.labels : [])
.map((label) => typeof label === 'string' ? label : label && label.name)
.filter(Boolean)
.map((label) => String(label).toLowerCase()));
if (!requiredLabels.some((label) => prLabels.has(label))) {
reasons.push(`missing required recap label (${requiredLabels.join(', ')})`);
}
}

// Fork PRs only receive repo secrets when the org/repo opts into
// GitHub's "Send secrets to workflows from pull requests" setting
Expand Down
18 changes: 17 additions & 1 deletion .github/workflows/pr-visual-recap.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ name: PR Visual Recap

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review, closed]
types: [opened, synchronize, reopened, ready_for_review, labeled, closed]

permissions:
contents: read
Expand All @@ -18,12 +18,14 @@ concurrency:
env:
VISUAL_RECAP_AGENT: ${{ vars.VISUAL_RECAP_AGENT || 'claude' }}
VISUAL_RECAP_BASE_URL: ${{ vars.VISUAL_RECAP_BASE_URL || '' }}
VISUAL_RECAP_REQUIRED_LABELS: ${{ vars.VISUAL_RECAP_REQUIRED_LABELS || '' }}
VISUAL_RECAP_SKILL_SOURCE: ${{ vars.VISUAL_RECAP_SKILL_SOURCE || 'auto' }}
VISUAL_RECAP_SECRET_SCAN: ${{ vars.VISUAL_RECAP_SECRET_SCAN || 'high-confidence' }}

jobs:
gate:
name: Gate
if: github.event.action != 'labeled' || vars.VISUAL_RECAP_REQUIRED_LABELS != ''
# A custom plain-label runner is allowed only for trusted same-repo authors.
# Fork and untrusted PRs are forced onto GitHub-hosted ubuntu-latest before
# any step starts. The only fromJSON input is this static association list.
Expand All @@ -50,6 +52,7 @@ jobs:
VISUAL_RECAP_BASE_URL: ${{ env.VISUAL_RECAP_BASE_URL }}
VISUAL_RECAP_MODEL: ${{ vars.VISUAL_RECAP_MODEL }}
VISUAL_RECAP_RUNS_ON: ${{ vars.VISUAL_RECAP_RUNS_ON || '"ubuntu-latest"' }}
VISUAL_RECAP_REQUIRED_LABELS: ${{ env.VISUAL_RECAP_REQUIRED_LABELS }}
VISUAL_RECAP_SKILL_SOURCE: ${{ env.VISUAL_RECAP_SKILL_SOURCE }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
with:
Expand All @@ -62,6 +65,19 @@ jobs:
if (pr && context.payload.action === 'closed' && !pr.merged) {
reasons.push('closed without merge');
}
const requiredLabels = (process.env.VISUAL_RECAP_REQUIRED_LABELS || '')
.split(',')
.map((label) => label.trim().toLowerCase())
.filter(Boolean);
if (pr && requiredLabels.length > 0) {
const prLabels = new Set((Array.isArray(pr.labels) ? pr.labels : [])
.map((label) => typeof label === 'string' ? label : label && label.name)
.filter(Boolean)
.map((label) => String(label).toLowerCase()));
if (!requiredLabels.some((label) => prLabels.has(label))) {
reasons.push(`missing required recap label (${requiredLabels.join(', ')})`);
}
}

// Fork PRs only receive repo secrets when the org/repo opts into
// GitHub's "Send secrets to workflows from pull requests" setting
Expand Down
6 changes: 4 additions & 2 deletions packages/core/docs/content/locales/ar-SA/pr-visual-recap.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ npx @agent-native/recap-cli@latest recap doctor
- **ثبّت نموذجًا أرخص.** بالنسبة لـ Claude، اضبط `VISUAL_RECAP_MODEL=claude-haiku-4-5` للمستودعات البسيطة أو الصغيرة — إنه أرخص فئة من Claude؛ `claude-sonnet-5` (الافتراضي) هو الفئة المتوازنة.
- **انتقل إلى Codex بنموذج أرخص.** اضبط `VISUAL_RECAP_AGENT=codex` مع `VISUAL_RECAP_MODEL=gpt-5.6-luna` (أرخص فئة من GPT-5.6) أو `gpt-5.6-terra` (فئة متوسطة)، واضبط `VISUAL_RECAP_REASONING=low` لخفض إنفاق رموز الاستدلال أكثر. يُطبَّق عمق الاستدلال على Codex فقط.
- **وجّهه إلى مزود متوافق مع OpenAI أرخص.** اضبط `VISUAL_RECAP_AGENT=openai-compatible` مع `VISUAL_RECAP_BASE_URL`/`VISUAL_RECAP_MODEL`/`VISUAL_RECAP_API_KEY` مستهدفًا DeepSeek أو Kimi أو أي نقطة نهاية أخرى متوافقة مع OpenAI.
- **قلّل من تكرار الملخصات.** عدّل `on.pull_request.types` في سير العمل المثبّت من `[opened, synchronize, reopened, ready_for_review, closed]` إلى `[opened, ready_for_review, closed]` بحيث يتم إنشاء الملخّص فقط عند فتح طلب السحب وعند دمجه، بدلاً من كل دفعة.
- **قلّل من تكرار الملخصات.** عدّل `on.pull_request.types` في سير العمل المثبّت من `[opened, synchronize, reopened, ready_for_review, labeled, closed]` إلى `[opened, ready_for_review, closed]` بحيث يتم إنشاء الملخّص فقط عند فتح طلب السحب وعند دمجه، بدلاً من كل دفعة.

يسجّل كل تشغيل ما أنفقه فعليًا: تُرفق خطوة `recap usage` في سير العمل استخدام الرموز والتكلفة بالخطة المنشورة، حتى تتمكن من الاطلاع على الإنفاق الفعلي لكل تشغيل بدلاً من التخمين.

Expand Down Expand Up @@ -479,10 +479,11 @@ name: PR Visual Recap

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review, closed]
types: [opened, synchronize, reopened, ready_for_review, labeled, closed]

jobs:
visual-recap:
if: github.event.action != 'labeled' || vars.VISUAL_RECAP_REQUIRED_LABELS != ''
permissions:
actions: write
contents: read
Expand All @@ -502,6 +503,7 @@ jobs:
skill-source: ${{ vars.VISUAL_RECAP_SKILL_SOURCE || 'auto' }}
runs-on: ${{ vars.VISUAL_RECAP_RUNS_ON || '"ubuntu-latest"' }}
gate-runs-on: ${{ vars.VISUAL_RECAP_GATE_RUNS_ON || 'ubuntu-latest' }}
required-labels: ${{ vars.VISUAL_RECAP_REQUIRED_LABELS || '' }}
# cli-version: "latest" # pin to a specific @agent-native/recap-cli version
```

Expand Down
6 changes: 4 additions & 2 deletions packages/core/docs/content/locales/de-DE/pr-visual-recap.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ So senken Sie die Kosten:
- **Pinnen Sie ein günstigeres Modell.** Setzen Sie für Claude `VISUAL_RECAP_MODEL=claude-haiku-4-5` bei einfachen oder kleinen Repositorys – das ist die günstigste Claude-Stufe; `claude-sonnet-5` (die Standardeinstellung) ist die ausgewogene Stufe.
- **Wechseln Sie zu Codex mit einem günstigeren Modell.** Setzen Sie `VISUAL_RECAP_AGENT=codex` zusammen mit `VISUAL_RECAP_MODEL=gpt-5.6-luna` (die günstigste GPT-5.6-Stufe) oder `gpt-5.6-terra` (mittlere Stufe), und setzen Sie `VISUAL_RECAP_REASONING=low`, um die Ausgaben für Argumentations-Token weiter zu senken. Die Argumentationstiefe gilt nur für Codex.
- **Nutzen Sie einen günstigeren OpenAI-kompatiblen Anbieter.** Setzen Sie `VISUAL_RECAP_AGENT=openai-compatible` zusammen mit `VISUAL_RECAP_BASE_URL`/`VISUAL_RECAP_MODEL`/`VISUAL_RECAP_API_KEY`, die auf DeepSeek, Kimi oder einen anderen OpenAI-kompatiblen Endpunkt verweisen.
- **Fassen Sie seltener zusammen.** Bearbeiten Sie `on.pull_request.types` des installierten Workflows von `[opened, synchronize, reopened, ready_for_review, closed]` zu `[opened, ready_for_review, closed]`, sodass nur beim Öffnen und beim Mergen eines PR zusammengefasst wird, statt bei jedem Push.
- **Fassen Sie seltener zusammen.** Bearbeiten Sie `on.pull_request.types` des installierten Workflows von `[opened, synchronize, reopened, ready_for_review, labeled, closed]` zu `[opened, ready_for_review, closed]`, sodass nur beim Öffnen und beim Mergen eines PR zusammengefasst wird, statt bei jedem Push.

Jeder Lauf zeichnet auf, was er tatsächlich gekostet hat: Der `recap usage`-Schritt des Workflows fügt dem veröffentlichten Plan Token- und Kostennutzung hinzu, sodass Sie die tatsächlichen Ausgaben pro Lauf einsehen können, statt zu raten.

Expand Down Expand Up @@ -479,10 +479,11 @@ name: PR Visual Recap

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review, closed]
types: [opened, synchronize, reopened, ready_for_review, labeled, closed]

jobs:
visual-recap:
if: github.event.action != 'labeled' || vars.VISUAL_RECAP_REQUIRED_LABELS != ''
permissions:
actions: write
contents: read
Expand All @@ -502,6 +503,7 @@ jobs:
skill-source: ${{ vars.VISUAL_RECAP_SKILL_SOURCE || 'auto' }}
runs-on: ${{ vars.VISUAL_RECAP_RUNS_ON || '"ubuntu-latest"' }}
gate-runs-on: ${{ vars.VISUAL_RECAP_GATE_RUNS_ON || 'ubuntu-latest' }}
required-labels: ${{ vars.VISUAL_RECAP_REQUIRED_LABELS || '' }}
# cli-version: "latest" # pin to a specific @agent-native/recap-cli version
```

Expand Down
6 changes: 4 additions & 2 deletions packages/core/docs/content/locales/es-ES/pr-visual-recap.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ Para reducir el costo:
- **Fije un modelo más económico.** Para Claude, configure `VISUAL_RECAP_MODEL=claude-haiku-4-5` para repositorios simples o pequeños — es el nivel más económico de Claude; `claude-sonnet-5` (el predeterminado) es el nivel equilibrado.
- **Cambie a Codex con un modelo más económico.** Configure `VISUAL_RECAP_AGENT=codex` con `VISUAL_RECAP_MODEL=gpt-5.6-luna` (el nivel más económico de GPT-5.6) o `gpt-5.6-terra` (nivel intermedio), y configure `VISUAL_RECAP_REASONING=low` para reducir aún más el gasto en tokens de razonamiento. La profundidad de razonamiento solo se aplica a Codex.
- **Apunte a un proveedor compatible con OpenAI más económico.** Configure `VISUAL_RECAP_AGENT=openai-compatible` con `VISUAL_RECAP_BASE_URL`/`VISUAL_RECAP_MODEL`/`VISUAL_RECAP_API_KEY` apuntando a DeepSeek, Kimi o cualquier otro endpoint compatible con OpenAI.
- **Resuma con menos frecuencia.** Edite el `on.pull_request.types` del flujo de trabajo instalado de `[opened, synchronize, reopened, ready_for_review, closed]` a `[opened, ready_for_review, closed]` para que solo genere resúmenes cuando un PR se abre y cuando se fusiona, en lugar de en cada push.
- **Resuma con menos frecuencia.** Edite el `on.pull_request.types` del flujo de trabajo instalado de `[opened, synchronize, reopened, ready_for_review, labeled, closed]` a `[opened, ready_for_review, closed]` para que solo genere resúmenes cuando un PR se abre y cuando se fusiona, en lugar de en cada push.

Cada ejecución registra lo que realmente gastó: el paso `recap usage` del flujo de trabajo adjunta el uso de tokens y costo al plan publicado, para que pueda ver el gasto real por ejecución en lugar de adivinar.

Expand Down Expand Up @@ -479,10 +479,11 @@ name: PR Visual Recap

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review, closed]
types: [opened, synchronize, reopened, ready_for_review, labeled, closed]

jobs:
visual-recap:
if: github.event.action != 'labeled' || vars.VISUAL_RECAP_REQUIRED_LABELS != ''
permissions:
actions: write
contents: read
Expand All @@ -502,6 +503,7 @@ jobs:
skill-source: ${{ vars.VISUAL_RECAP_SKILL_SOURCE || 'auto' }}
runs-on: ${{ vars.VISUAL_RECAP_RUNS_ON || '"ubuntu-latest"' }}
gate-runs-on: ${{ vars.VISUAL_RECAP_GATE_RUNS_ON || 'ubuntu-latest' }}
required-labels: ${{ vars.VISUAL_RECAP_REQUIRED_LABELS || '' }}
# cli-version: "latest" # pin to a specific @agent-native/recap-cli version
```

Expand Down
6 changes: 4 additions & 2 deletions packages/core/docs/content/locales/fr-FR/pr-visual-recap.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ Pour réduire le coût :
- **Épinglez un modèle moins cher.** Pour Claude, définissez `VISUAL_RECAP_MODEL=claude-haiku-4-5` pour les dépôts simples ou petits — c'est le niveau Claude le moins cher ; `claude-sonnet-5` (la valeur par défaut) est le niveau équilibré.
- **Passez à Codex avec un modèle moins cher.** Définissez `VISUAL_RECAP_AGENT=codex` avec `VISUAL_RECAP_MODEL=gpt-5.6-luna` (le niveau GPT-5.6 le moins cher) ou `gpt-5.6-terra` (niveau intermédiaire), et définissez `VISUAL_RECAP_REASONING=low` pour réduire encore la dépense en jetons de raisonnement. La profondeur de raisonnement ne s'applique qu'à Codex.
- **Pointez vers un fournisseur compatible OpenAI moins cher.** Définissez `VISUAL_RECAP_AGENT=openai-compatible` avec `VISUAL_RECAP_BASE_URL`/`VISUAL_RECAP_MODEL`/`VISUAL_RECAP_API_KEY` ciblant DeepSeek, Kimi ou tout autre point de terminaison compatible OpenAI.
- **Récapitulez moins souvent.** Modifiez le `on.pull_request.types` du flux de travail installé de `[opened, synchronize, reopened, ready_for_review, closed]` à `[opened, ready_for_review, closed]` afin qu'il ne récapitule que lorsqu'une PR s'ouvre et lorsqu'elle est fusionnée, au lieu de le faire à chaque poussée.
- **Récapitulez moins souvent.** Modifiez le `on.pull_request.types` du flux de travail installé de `[opened, synchronize, reopened, ready_for_review, labeled, closed]` à `[opened, ready_for_review, closed]` afin qu'il ne récapitule que lorsqu'une PR s'ouvre et lorsqu'elle est fusionnée, au lieu de le faire à chaque poussée.

Chaque exécution enregistre ce qu'elle a réellement dépensé : l'étape `recap usage` du flux de travail associe l'utilisation de jetons et de coût au plan publié, afin que vous puissiez consulter la dépense réelle par exécution plutôt que de deviner.

Expand Down Expand Up @@ -480,10 +480,11 @@ name: PR Visual Recap

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review, closed]
types: [opened, synchronize, reopened, ready_for_review, labeled, closed]

jobs:
visual-recap:
if: github.event.action != 'labeled' || vars.VISUAL_RECAP_REQUIRED_LABELS != ''
permissions:
actions: write
contents: read
Expand All @@ -503,6 +504,7 @@ jobs:
skill-source: ${{ vars.VISUAL_RECAP_SKILL_SOURCE || 'auto' }}
runs-on: ${{ vars.VISUAL_RECAP_RUNS_ON || '"ubuntu-latest"' }}
gate-runs-on: ${{ vars.VISUAL_RECAP_GATE_RUNS_ON || 'ubuntu-latest' }}
required-labels: ${{ vars.VISUAL_RECAP_REQUIRED_LABELS || '' }}
# cli-version: "latest" # pin to a specific @agent-native/recap-cli version
```

Expand Down
6 changes: 4 additions & 2 deletions packages/core/docs/content/locales/hi-IN/pr-visual-recap.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ npx @agent-native/recap-cli@latest recap doctor
- **एक सस्ता मॉडल पिन करें।** Claude के लिए, सरल या छोटे रिपॉज़िटरी के लिए `VISUAL_RECAP_MODEL=claude-haiku-4-5` सेट करें — यह सबसे सस्ता Claude स्तर है; `claude-sonnet-5` (डिफ़ॉल्ट) संतुलित स्तर है।
- **सस्ते मॉडल के साथ Codex पर स्विच करें।** `VISUAL_RECAP_AGENT=codex` को `VISUAL_RECAP_MODEL=gpt-5.6-luna` (सबसे सस्ता GPT-5.6 स्तर) या `gpt-5.6-terra` (मध्य-स्तर) के साथ सेट करें, और रीज़निंग-टोकन खर्च को और कम करने के लिए `VISUAL_RECAP_REASONING=low` सेट करें। रीज़निंग गहराई केवल Codex पर लागू होती है।
- **किसी सस्ते OpenAI-संगत प्रदाता की ओर इंगित करें।** DeepSeek, Kimi, या किसी अन्य OpenAI-संगत एंडपॉइंट को लक्षित करते हुए `VISUAL_RECAP_BASE_URL`/`VISUAL_RECAP_MODEL`/`VISUAL_RECAP_API_KEY` के साथ `VISUAL_RECAP_AGENT=openai-compatible` सेट करें।
- **रिकैप कम बार करें।** इंस्टॉल किए गए वर्कफ़्लो के `on.pull_request.types` को `[opened, synchronize, reopened, ready_for_review, closed]` से बदलकर `[opened, ready_for_review, closed]` करें ताकि यह हर पुश पर नहीं, बल्कि केवल तब रिकैप करे जब कोई PR खुले और जब वह मर्ज हो।
- **रिकैप कम बार करें।** इंस्टॉल किए गए वर्कफ़्लो के `on.pull_request.types` को `[opened, synchronize, reopened, ready_for_review, labeled, closed]` से बदलकर `[opened, ready_for_review, closed]` करें ताकि यह हर पुश पर नहीं, बल्कि केवल तब रिकैप करे जब कोई PR खुले और जब वह मर्ज हो।

हर रन यह रिकॉर्ड करता है कि वास्तव में कितना खर्च हुआ: वर्कफ़्लो का `recap usage` चरण टोकन और लागत उपयोग को प्रकाशित योजना से जोड़ देता है, ताकि आप अनुमान लगाने के बजाय प्रति रन वास्तविक खर्च देख सकें।

Expand Down Expand Up @@ -480,10 +480,11 @@ name: PR Visual Recap

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review, closed]
types: [opened, synchronize, reopened, ready_for_review, labeled, closed]

jobs:
visual-recap:
if: github.event.action != 'labeled' || vars.VISUAL_RECAP_REQUIRED_LABELS != ''
permissions:
actions: write
contents: read
Expand All @@ -503,6 +504,7 @@ jobs:
skill-source: ${{ vars.VISUAL_RECAP_SKILL_SOURCE || 'auto' }}
runs-on: ${{ vars.VISUAL_RECAP_RUNS_ON || '"ubuntu-latest"' }}
gate-runs-on: ${{ vars.VISUAL_RECAP_GATE_RUNS_ON || 'ubuntu-latest' }}
required-labels: ${{ vars.VISUAL_RECAP_REQUIRED_LABELS || '' }}
# cli-version: "latest" # pin to a specific @agent-native/recap-cli version
```

Expand Down
Loading
Loading