diff --git a/.github/workflows/archie.lock.yml b/.github/workflows/archie.lock.yml index 766d7c2af4..dc8d9e743f 100644 --- a/.github/workflows/archie.lock.yml +++ b/.github/workflows/archie.lock.yml @@ -97,7 +97,8 @@ jobs: global.context = context; global.exec = exec; global.io = io; - require('/tmp/gh-aw/actions/compute_text.cjs'); + const { main } = require('/tmp/gh-aw/actions/compute_text.cjs'); + await main(); - name: Add eyes reaction to the triggering item id: react if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.id == github.repository_id) diff --git a/.github/workflows/brave.lock.yml b/.github/workflows/brave.lock.yml index 9c4c569542..4f224fe5ac 100644 --- a/.github/workflows/brave.lock.yml +++ b/.github/workflows/brave.lock.yml @@ -89,7 +89,8 @@ jobs: global.context = context; global.exec = exec; global.io = io; - require('/tmp/gh-aw/actions/compute_text.cjs'); + const { main } = require('/tmp/gh-aw/actions/compute_text.cjs'); + await main(); - name: Add eyes reaction to the triggering item id: react if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.id == github.repository_id) diff --git a/.github/workflows/changeset.lock.yml b/.github/workflows/changeset.lock.yml index a262369daa..b3b43c92d9 100644 --- a/.github/workflows/changeset.lock.yml +++ b/.github/workflows/changeset.lock.yml @@ -97,7 +97,8 @@ jobs: global.context = context; global.exec = exec; global.io = io; - require('/tmp/gh-aw/actions/compute_text.cjs'); + const { main } = require('/tmp/gh-aw/actions/compute_text.cjs'); + await main(); - name: Add rocket reaction to the triggering item id: react if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.id == github.repository_id) diff --git a/.github/workflows/cloclo.lock.yml b/.github/workflows/cloclo.lock.yml index 116cbcf71c..50786c7133 100644 --- a/.github/workflows/cloclo.lock.yml +++ b/.github/workflows/cloclo.lock.yml @@ -123,7 +123,8 @@ jobs: global.context = context; global.exec = exec; global.io = io; - require('/tmp/gh-aw/actions/compute_text.cjs'); + const { main } = require('/tmp/gh-aw/actions/compute_text.cjs'); + await main(); - name: Add eyes reaction to the triggering item id: react if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.id == github.repository_id) diff --git a/.github/workflows/craft.lock.yml b/.github/workflows/craft.lock.yml index 5e48986bcd..ee392fd656 100644 --- a/.github/workflows/craft.lock.yml +++ b/.github/workflows/craft.lock.yml @@ -85,7 +85,8 @@ jobs: global.context = context; global.exec = exec; global.io = io; - require('/tmp/gh-aw/actions/compute_text.cjs'); + const { main } = require('/tmp/gh-aw/actions/compute_text.cjs'); + await main(); - name: Add eyes reaction to the triggering item id: react if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.id == github.repository_id) diff --git a/.github/workflows/grumpy-reviewer.lock.yml b/.github/workflows/grumpy-reviewer.lock.yml index a93d23dd3d..3f668c9bca 100644 --- a/.github/workflows/grumpy-reviewer.lock.yml +++ b/.github/workflows/grumpy-reviewer.lock.yml @@ -90,7 +90,8 @@ jobs: global.context = context; global.exec = exec; global.io = io; - require('/tmp/gh-aw/actions/compute_text.cjs'); + const { main } = require('/tmp/gh-aw/actions/compute_text.cjs'); + await main(); - name: Add eyes reaction to the triggering item id: react if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.id == github.repository_id) diff --git a/.github/workflows/issue-classifier.lock.yml b/.github/workflows/issue-classifier.lock.yml index 4f4a69a3e5..254bbbc702 100644 --- a/.github/workflows/issue-classifier.lock.yml +++ b/.github/workflows/issue-classifier.lock.yml @@ -86,7 +86,8 @@ jobs: global.context = context; global.exec = exec; global.io = io; - require('/tmp/gh-aw/actions/compute_text.cjs'); + const { main } = require('/tmp/gh-aw/actions/compute_text.cjs'); + await main(); - name: Add eyes reaction to the triggering item id: react if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.id == github.repository_id) diff --git a/.github/workflows/pdf-summary.lock.yml b/.github/workflows/pdf-summary.lock.yml index d53d61567c..cf47aae517 100644 --- a/.github/workflows/pdf-summary.lock.yml +++ b/.github/workflows/pdf-summary.lock.yml @@ -107,7 +107,8 @@ jobs: global.context = context; global.exec = exec; global.io = io; - require('/tmp/gh-aw/actions/compute_text.cjs'); + const { main } = require('/tmp/gh-aw/actions/compute_text.cjs'); + await main(); - name: Add eyes reaction to the triggering item id: react if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.id == github.repository_id) diff --git a/.github/workflows/plan.lock.yml b/.github/workflows/plan.lock.yml index 2d3540b98c..01072ed4e6 100644 --- a/.github/workflows/plan.lock.yml +++ b/.github/workflows/plan.lock.yml @@ -89,7 +89,8 @@ jobs: global.context = context; global.exec = exec; global.io = io; - require('/tmp/gh-aw/actions/compute_text.cjs'); + const { main } = require('/tmp/gh-aw/actions/compute_text.cjs'); + await main(); - name: Add eyes reaction to the triggering item id: react if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.id == github.repository_id) diff --git a/.github/workflows/poem-bot.lock.yml b/.github/workflows/poem-bot.lock.yml index f710fb1a20..08fc0a96ce 100644 --- a/.github/workflows/poem-bot.lock.yml +++ b/.github/workflows/poem-bot.lock.yml @@ -92,7 +92,8 @@ jobs: global.context = context; global.exec = exec; global.io = io; - require('/tmp/gh-aw/actions/compute_text.cjs'); + const { main } = require('/tmp/gh-aw/actions/compute_text.cjs'); + await main(); - name: Add eyes reaction to the triggering item id: react if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.id == github.repository_id) diff --git a/.github/workflows/q.lock.yml b/.github/workflows/q.lock.yml index 5d8bf3127c..166ecb88f1 100644 --- a/.github/workflows/q.lock.yml +++ b/.github/workflows/q.lock.yml @@ -118,7 +118,8 @@ jobs: global.context = context; global.exec = exec; global.io = io; - require('/tmp/gh-aw/actions/compute_text.cjs'); + const { main } = require('/tmp/gh-aw/actions/compute_text.cjs'); + await main(); - name: Add rocket reaction to the triggering item id: react if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.id == github.repository_id) diff --git a/.github/workflows/scout.lock.yml b/.github/workflows/scout.lock.yml index 16a820596d..484fa5141c 100644 --- a/.github/workflows/scout.lock.yml +++ b/.github/workflows/scout.lock.yml @@ -133,7 +133,8 @@ jobs: global.context = context; global.exec = exec; global.io = io; - require('/tmp/gh-aw/actions/compute_text.cjs'); + const { main } = require('/tmp/gh-aw/actions/compute_text.cjs'); + await main(); - name: Add eyes reaction to the triggering item id: react if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.id == github.repository_id) diff --git a/.github/workflows/speckit-dispatcher.lock.yml b/.github/workflows/speckit-dispatcher.lock.yml index 978034cf2f..eba2c26a1a 100644 --- a/.github/workflows/speckit-dispatcher.lock.yml +++ b/.github/workflows/speckit-dispatcher.lock.yml @@ -112,7 +112,8 @@ jobs: global.context = context; global.exec = exec; global.io = io; - require('/tmp/gh-aw/actions/compute_text.cjs'); + const { main } = require('/tmp/gh-aw/actions/compute_text.cjs'); + await main(); - name: Add eyes reaction to the triggering item id: react if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.id == github.repository_id) diff --git a/pkg/cli/templates/github-agentic-workflows.md b/pkg/cli/templates/github-agentic-workflows.md index f04794f4a9..30ddce78ae 100644 --- a/pkg/cli/templates/github-agentic-workflows.md +++ b/pkg/cli/templates/github-agentic-workflows.md @@ -454,6 +454,19 @@ The YAML frontmatter supports these fields: if-no-changes: "warn" # Optional: "warn" (default), "error", or "ignore" ``` Not supported for cross-repository operations. + - `update-discussion:` - Update discussion title, body, or labels + ```yaml + safe-outputs: + update-discussion: + title: true # Optional: enable title updates + body: true # Optional: enable body updates + labels: true # Optional: enable label updates + allowed-labels: [status, type] # Optional: restrict to specific labels + max: 1 # Optional: max updates (default: 1) + target: "*" # Optional: "triggering" (default), "*", or number + target-repo: "owner/repo" # Optional: cross-repository + ``` + When using `safe-outputs.update-discussion`, the main job does **not** need `discussions: write` permission since updates are handled by a separate job with appropriate permissions. - `update-release:` - Update GitHub release descriptions ```yaml safe-outputs: @@ -463,6 +476,17 @@ The YAML frontmatter supports these fields: github-token: ${{ secrets.CUSTOM_TOKEN }} # Optional: custom token ``` Operation types: `replace`, `append`, `prepend`. + - `upload-asset:` - Publish files to orphaned git branch + ```yaml + safe-outputs: + upload-asset: + branch: "assets/${{ github.workflow }}" # Optional: branch name + max-size: 10240 # Optional: max file size in KB (default: 10MB) + allowed-exts: [.png, .jpg, .pdf] # Optional: allowed file extensions + max: 10 # Optional: max assets (default: 10) + target-repo: "owner/repo" # Optional: cross-repository + ``` + Publishes workflow artifacts to an orphaned git branch for persistent storage. Default allowed extensions include common non-executable types. Maximum file size is 50MB (51200 KB). - `create-code-scanning-alert:` - Generate SARIF security advisories ```yaml safe-outputs: @@ -486,6 +510,28 @@ The YAML frontmatter supports these fields: target-repo: "owner/repo" # Optional: cross-repository ``` Requires PAT with elevated permissions as `GH_AW_AGENT_TOKEN`. + - `assign-to-user:` - Assign users to issues or pull requests + ```yaml + safe-outputs: + assign-to-user: + assignees: [user1, user2] # Optional: restrict to specific users + max: 3 # Optional: max assignments (default: 3) + target: "*" # Optional: "triggering" (default), "*", or number + target-repo: "owner/repo" # Optional: cross-repository + ``` + When using `safe-outputs.assign-to-user`, the main job does **not** need `issues: write` or `pull-requests: write` permission since user assignment is handled by a separate job with appropriate permissions. + - `hide-comment:` - Hide comments on issues, PRs, or discussions + ```yaml + safe-outputs: + hide-comment: + max: 5 # Optional: max comments to hide (default: 5) + allowed-reasons: # Optional: restrict hide reasons + - spam + - outdated + - resolved + target-repo: "owner/repo" # Optional: cross-repository + ``` + Allowed reasons: `spam`, `abuse`, `off_topic`, `outdated`, `resolved`. When using `safe-outputs.hide-comment`, the main job does **not** need write permissions since comment hiding is handled by a separate job. - `noop:` - Log completion message for transparency (auto-enabled) ```yaml safe-outputs: diff --git a/pkg/workflow/compiler_activation_jobs.go b/pkg/workflow/compiler_activation_jobs.go index e25db2cdba..00e0fc505d 100644 --- a/pkg/workflow/compiler_activation_jobs.go +++ b/pkg/workflow/compiler_activation_jobs.go @@ -397,7 +397,8 @@ func (c *Compiler) buildActivationJob(data *WorkflowData, preActivationJobCreate steps = append(steps, " global.context = context;\n") steps = append(steps, " global.exec = exec;\n") steps = append(steps, " global.io = io;\n") - steps = append(steps, " require('"+SetupActionDestination+"/compute_text.cjs');\n") + steps = append(steps, " const { main } = require('"+SetupActionDestination+"/compute_text.cjs');\n") + steps = append(steps, " await main();\n") } else { // Inline the JavaScript directly instead of using shared action steps = append(steps, FormatJavaScriptForYAML(getComputeTextScript())...) diff --git a/pkg/workflow/js/compute_text.cjs b/pkg/workflow/js/compute_text.cjs index 84ae22f413..d4f77620d6 100644 --- a/pkg/workflow/js/compute_text.cjs +++ b/pkg/workflow/js/compute_text.cjs @@ -170,4 +170,4 @@ async function main() { } } -await main(); +module.exports = { main }; diff --git a/pkg/workflow/js/compute_text.test.cjs b/pkg/workflow/js/compute_text.test.cjs index 30e4b90753..22dca4f36a 100644 --- a/pkg/workflow/js/compute_text.test.cjs +++ b/pkg/workflow/js/compute_text.test.cjs @@ -39,7 +39,7 @@ const mockCore = { (vi.clearAllMocks(), (mockContext.eventName = "issues"), (mockContext.payload = {}), delete process.env.GH_AW_ALLOWED_DOMAINS); const scriptPath = path.join(process.cwd(), "compute_text.cjs"); computeTextScript = fs.readFileSync(scriptPath, "utf8"); - const scriptWithExport = computeTextScript.replace("await main();", "global.testSanitizeIncomingText = sanitizeIncomingText; global.testMain = main;"); + const scriptWithExport = computeTextScript.replace("module.exports = { main };", "global.testSanitizeIncomingText = sanitizeIncomingText; global.testMain = main;"); (eval(scriptWithExport), (sanitizeIncomingTextFunction = global.testSanitizeIncomingText)); }), describe("sanitizeIncomingText function", () => {