@plainconceptsplatform/workflows 0.19.2 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/catalog-installation.js +12 -1
  2. package/dist/stack-defaults.js +16 -16
  3. package/dist/worker-env.js +14 -0
  4. package/loops/actions/add-issue-labels/action.yml +50 -50
  5. package/loops/actions/agent-output.cjs +17 -17
  6. package/loops/actions/apply-agent-bundle/action.yml +24 -24
  7. package/loops/actions/apply-agent-comments/action.yml +42 -42
  8. package/loops/actions/apply-agent-labels/action.yml +55 -55
  9. package/loops/actions/apply-agent-output/action.yml +108 -108
  10. package/loops/actions/assess-blast-radius/action.yml +148 -0
  11. package/loops/actions/assess-blast-radius/assess-blast-radius.sh +138 -0
  12. package/loops/actions/classify-route/action.yml +100 -100
  13. package/loops/actions/cleanup-artifacts/action.yml +91 -91
  14. package/loops/actions/close-agent-issues/action.yml +43 -43
  15. package/loops/actions/create-agent-issues/action.yml +52 -52
  16. package/loops/actions/create-issue-comment/action.yml +29 -29
  17. package/loops/actions/download-agent-output/action.yml +53 -53
  18. package/loops/actions/housekeeping/action.yml +55 -2
  19. package/loops/actions/link-pr-to-issue/action.yml +40 -40
  20. package/loops/actions/list-open-issues/action.yml +33 -33
  21. package/loops/actions/load-issue-context/action.yml +45 -45
  22. package/loops/actions/merge-agent-pr/action.yml +49 -49
  23. package/loops/actions/push-agent-branch/action.yml +45 -45
  24. package/loops/actions/remove-issue-labels/action.yml +37 -37
  25. package/loops/actions/update-agent-issues/action.yml +58 -58
  26. package/loops/actions/validate-merge-gate-output/action.yml +62 -40
  27. package/loops/actions/validate-merge-gate-output/validate-merge-gate-output.sh +147 -31
  28. package/loops/actions/validate-refine-output/action.yml +48 -44
  29. package/loops/actions/validate-refine-output/validate-refine-output.sh +15 -4
  30. package/loops/actions/validate-review-output/action.yml +35 -35
  31. package/loops/actions/validate-triage-output/action.yml +36 -36
  32. package/loops/actions/verify-composite-actions/action.yml +9 -9
  33. package/loops/actions/verify-refine-output/action.yml +9 -9
  34. package/loops/actions/verify-refine-output/verify-refine-output.sh +6 -1
  35. package/loops/actions/verify-route-matrix/action.yml +9 -9
  36. package/loops/actions/verify-route-matrix/verify-gate-metrics.mjs +51 -0
  37. package/loops/actions/verify-route-matrix/verify-route-matrix.sh +329 -29
  38. package/loops/scripts/compile-agent-workflows.mjs +331 -331
  39. package/loops/templates/agentics/agentics-maintenance.yml +121 -121
  40. package/loops/templates/ci/app-ci-dotnet-next.yml +330 -330
  41. package/loops/templates/ci/app-ci-node-monorepo.yml +260 -260
  42. package/loops/templates/issues/bug_report.yml +109 -109
  43. package/loops/templates/issues/feature_request.yml +75 -75
  44. package/loops/templates/opencode/opencode.ci.json +55 -49
  45. package/loops/templates/opencode/opencode.ci.json.md +59 -49
  46. package/loops/templates/release/github-release.yml +30 -30
  47. package/loops/workflows/agent-merge-gate.md +367 -148
  48. package/loops/workflows/agent-refine.md +60 -16
  49. package/loops/workflows/authorize-bot-work.yml +105 -105
  50. package/loops/workflows/shared/opencode-ci.md +206 -206
  51. package/loops/workflows/shared/platform-defaults.md +19 -19
  52. package/package.json +1 -1
@@ -1,100 +1,100 @@
1
- # Managed by @plainconceptsplatform/workflows. Source: loops/actions/classify-route/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
- name: Classify route
3
- description: Classify the triggering event into exactly one route, and resolve the issue a gated pull request closes.
4
- inputs:
5
- token:
6
- description: GitHub token with pull-requests read access.
7
- required: true
8
- outputs:
9
- route:
10
- description: The single route this event selects, or `none`.
11
- value: ${{ steps.classify.outputs.route }}
12
- issue-number:
13
- description: Issue number the route operates on.
14
- value: ${{ steps.classify.outputs.issue-number }}
15
- pr-number:
16
- description: Pull request number the route operates on.
17
- value: ${{ steps.classify.outputs.pr-number }}
18
- linked-issue:
19
- description: Issue the pull request closes. Empty for routes that do not target one.
20
- value: ${{ steps.linked-issue.outputs.issue }}
21
- ci-conclusion:
22
- description: Conclusion reported by the CI run that triggered a merge-gate route.
23
- value: ${{ steps.classify.outputs.ci-conclusion }}
24
- ci-run-id:
25
- description: Workflow run ID of that CI run.
26
- value: ${{ steps.classify.outputs.ci-run-id }}
27
- merge-gate-attempts:
28
- description: Failed merge-gate attempts already made against this CI verdict.
29
- value: ${{ steps.classify.outputs.merge-gate-attempts }}
30
- implement-attempts:
31
- description: Implement runs already made for this issue that died before producing an answer.
32
- value: ${{ steps.classify.outputs.implement-attempts }}
33
- refine-mode:
34
- description: first or rerefine.
35
- value: ${{ steps.classify.outputs.refine-mode }}
36
- triage-mode:
37
- description: first or retriage.
38
- value: ${{ steps.classify.outputs.triage-mode }}
39
- trigger-kind:
40
- description: scheduled or manual.
41
- value: ${{ steps.classify.outputs.trigger-kind }}
42
- runs:
43
- using: composite
44
- steps:
45
- - name: Classify the event
46
- id: classify
47
- shell: bash
48
- env:
49
- EVENT: ${{ github.event_name }}
50
- ACTION: ${{ github.event.action }}
51
- LABEL: ${{ github.event.label.name }}
52
- ISSUE_LABELS: ${{ toJSON(github.event.issue.labels.*.name) }}
53
- ISSUE_STATE: ${{ github.event.issue.state }}
54
- EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}
55
- EVENT_PR_NUMBER: ${{ github.event.pull_request.number }}
56
- COMMENT_ON_PR: ${{ github.event.issue.pull_request != '' }}
57
- COMMENT_SENDER_TYPE: ${{ github.event.comment.user.type }}
58
- ACTOR: ${{ github.actor }}
59
- RUN_PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number }}
60
- RUN_CONCLUSION: ${{ github.event.workflow_run.conclusion }}
61
- RUN_ID: ${{ github.event.workflow_run.id }}
62
- SCHEDULE: ${{ github.event.schedule }}
63
- OPERATION: ${{ github.event.inputs.operation }}
64
- INPUT_ISSUE_NUMBER: ${{ github.event.inputs.issue-number }}
65
- INPUT_PR_NUMBER: ${{ github.event.inputs.pr-number }}
66
- INPUT_MODE: ${{ github.event.inputs.mode }}
67
- INPUT_CI_CONCLUSION: ${{ github.event.inputs.ci-conclusion }}
68
- INPUT_CI_RUN_ID: ${{ github.event.inputs.ci-run-id }}
69
- INPUT_ATTEMPTS_SO_FAR: ${{ github.event.inputs.attempts_so_far }}
70
- INPUT_TRIGGER_KIND: ${{ github.event.inputs.trigger-kind }}
71
- run: |
72
- set -euo pipefail
73
-
74
- bash "${GITHUB_ACTION_PATH}/classify-route.sh" | tee "$RUNNER_TEMP/route.env"
75
- cat "$RUNNER_TEMP/route.env" >> "$GITHUB_OUTPUT"
76
-
77
- route="$(sed -n 's/^route=//p' "$RUNNER_TEMP/route.env")"
78
- reason="$(sed -n 's/^error=//p' "$RUNNER_TEMP/route.env")"
79
-
80
- if [ "$route" = "none" ] && [ -n "$reason" ]; then
81
- echo "::notice::No route for this event: $reason"
82
- fi
83
-
84
- - name: Resolve the issue the pull request closes
85
- id: linked-issue
86
- if: steps.classify.outputs.route == 'merge-gate' || steps.classify.outputs.route == 'apply-review'
87
- shell: bash
88
- env:
89
- GH_TOKEN: ${{ inputs.token }}
90
- REPO: ${{ github.repository }}
91
- PR_NUMBER: ${{ steps.classify.outputs.pr-number }}
92
- run: |
93
- set -euo pipefail
94
-
95
- issue="$(gh pr view "$PR_NUMBER" --repo "$REPO" \
96
- --json closingIssuesReferences \
97
- --jq '.closingIssuesReferences[0].number // empty')"
98
-
99
- echo "issue=${issue}" >> "$GITHUB_OUTPUT"
100
- echo "Pull request #${PR_NUMBER} closes issue #${issue:-<none>}"
1
+ # Managed by @plainconceptsplatform/workflows. Source: loops/actions/classify-route/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
+ name: Classify route
3
+ description: Classify the triggering event into exactly one route, and resolve the issue a gated pull request closes.
4
+ inputs:
5
+ token:
6
+ description: GitHub token with pull-requests read access.
7
+ required: true
8
+ outputs:
9
+ route:
10
+ description: The single route this event selects, or `none`.
11
+ value: ${{ steps.classify.outputs.route }}
12
+ issue-number:
13
+ description: Issue number the route operates on.
14
+ value: ${{ steps.classify.outputs.issue-number }}
15
+ pr-number:
16
+ description: Pull request number the route operates on.
17
+ value: ${{ steps.classify.outputs.pr-number }}
18
+ linked-issue:
19
+ description: Issue the pull request closes. Empty for routes that do not target one.
20
+ value: ${{ steps.linked-issue.outputs.issue }}
21
+ ci-conclusion:
22
+ description: Conclusion reported by the CI run that triggered a merge-gate route.
23
+ value: ${{ steps.classify.outputs.ci-conclusion }}
24
+ ci-run-id:
25
+ description: Workflow run ID of that CI run.
26
+ value: ${{ steps.classify.outputs.ci-run-id }}
27
+ merge-gate-attempts:
28
+ description: Failed merge-gate attempts already made against this CI verdict.
29
+ value: ${{ steps.classify.outputs.merge-gate-attempts }}
30
+ implement-attempts:
31
+ description: Implement runs already made for this issue that died before producing an answer.
32
+ value: ${{ steps.classify.outputs.implement-attempts }}
33
+ refine-mode:
34
+ description: first or rerefine.
35
+ value: ${{ steps.classify.outputs.refine-mode }}
36
+ triage-mode:
37
+ description: first or retriage.
38
+ value: ${{ steps.classify.outputs.triage-mode }}
39
+ trigger-kind:
40
+ description: scheduled or manual.
41
+ value: ${{ steps.classify.outputs.trigger-kind }}
42
+ runs:
43
+ using: composite
44
+ steps:
45
+ - name: Classify the event
46
+ id: classify
47
+ shell: bash
48
+ env:
49
+ EVENT: ${{ github.event_name }}
50
+ ACTION: ${{ github.event.action }}
51
+ LABEL: ${{ github.event.label.name }}
52
+ ISSUE_LABELS: ${{ toJSON(github.event.issue.labels.*.name) }}
53
+ ISSUE_STATE: ${{ github.event.issue.state }}
54
+ EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}
55
+ EVENT_PR_NUMBER: ${{ github.event.pull_request.number }}
56
+ COMMENT_ON_PR: ${{ github.event.issue.pull_request != '' }}
57
+ COMMENT_SENDER_TYPE: ${{ github.event.comment.user.type }}
58
+ ACTOR: ${{ github.actor }}
59
+ RUN_PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number }}
60
+ RUN_CONCLUSION: ${{ github.event.workflow_run.conclusion }}
61
+ RUN_ID: ${{ github.event.workflow_run.id }}
62
+ SCHEDULE: ${{ github.event.schedule }}
63
+ OPERATION: ${{ github.event.inputs.operation }}
64
+ INPUT_ISSUE_NUMBER: ${{ github.event.inputs.issue-number }}
65
+ INPUT_PR_NUMBER: ${{ github.event.inputs.pr-number }}
66
+ INPUT_MODE: ${{ github.event.inputs.mode }}
67
+ INPUT_CI_CONCLUSION: ${{ github.event.inputs.ci-conclusion }}
68
+ INPUT_CI_RUN_ID: ${{ github.event.inputs.ci-run-id }}
69
+ INPUT_ATTEMPTS_SO_FAR: ${{ github.event.inputs.attempts_so_far }}
70
+ INPUT_TRIGGER_KIND: ${{ github.event.inputs.trigger-kind }}
71
+ run: |
72
+ set -euo pipefail
73
+
74
+ bash "${GITHUB_ACTION_PATH}/classify-route.sh" | tee "$RUNNER_TEMP/route.env"
75
+ cat "$RUNNER_TEMP/route.env" >> "$GITHUB_OUTPUT"
76
+
77
+ route="$(sed -n 's/^route=//p' "$RUNNER_TEMP/route.env")"
78
+ reason="$(sed -n 's/^error=//p' "$RUNNER_TEMP/route.env")"
79
+
80
+ if [ "$route" = "none" ] && [ -n "$reason" ]; then
81
+ echo "::notice::No route for this event: $reason"
82
+ fi
83
+
84
+ - name: Resolve the issue the pull request closes
85
+ id: linked-issue
86
+ if: steps.classify.outputs.route == 'merge-gate' || steps.classify.outputs.route == 'apply-review'
87
+ shell: bash
88
+ env:
89
+ GH_TOKEN: ${{ inputs.token }}
90
+ REPO: ${{ github.repository }}
91
+ PR_NUMBER: ${{ steps.classify.outputs.pr-number }}
92
+ run: |
93
+ set -euo pipefail
94
+
95
+ issue="$(gh pr view "$PR_NUMBER" --repo "$REPO" \
96
+ --json closingIssuesReferences \
97
+ --jq '.closingIssuesReferences[0].number // empty')"
98
+
99
+ echo "issue=${issue}" >> "$GITHUB_OUTPUT"
100
+ echo "Pull request #${PR_NUMBER} closes issue #${issue:-<none>}"
@@ -1,91 +1,91 @@
1
- # Managed by @plainconceptsplatform/workflows. Source: loops/actions/cleanup-artifacts/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
- name: Clean up artifacts
3
- description: Delete workflow artifacts older than the configured retention period.
4
- inputs:
5
- token:
6
- description: GitHub token with actions write access.
7
- required: true
8
- artifact-retention-days:
9
- description: Retention period in days. Invalid or empty values use 3.
10
- required: false
11
- default: ''
12
- runs:
13
- using: composite
14
- steps:
15
- - name: Delete expired artifacts
16
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
17
- env:
18
- ARTIFACT_RETENTION_DAYS: ${{ inputs.artifact-retention-days }}
19
- with:
20
- github-token: ${{ inputs.token }}
21
- script: |
22
- const parsedDays = Number.parseInt(process.env.ARTIFACT_RETENTION_DAYS, 10);
23
- const days = Number.isInteger(parsedDays) && parsedDays > 0 ? parsedDays : 3;
24
- const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000);
25
-
26
- core.info(`Retention: ${days} days (cutoff ${cutoff.toISOString()})`);
27
-
28
- const artifacts = await github.paginate(github.rest.actions.listArtifactsForRepo, {
29
- ...context.repo,
30
- per_page: 100,
31
- });
32
-
33
- const expired = artifacts.filter((artifact) => new Date(artifact.created_at) < cutoff);
34
-
35
- let deleted = 0;
36
- const failed = [];
37
-
38
- for (const artifact of expired) {
39
- // GitHub answers a delete with a 5xx now and then. Three tries, because the
40
- // alternative is a red daily run over one artifact that tomorrow's run would
41
- // have removed anyway.
42
- let lastError;
43
- for (let attempt = 1; attempt <= 3; attempt += 1) {
44
- try {
45
- await github.rest.actions.deleteArtifact({
46
- ...context.repo,
47
- artifact_id: artifact.id,
48
- });
49
-
50
- core.info(`Deleted ${artifact.name} (created ${artifact.created_at})`);
51
- deleted += 1;
52
- lastError = undefined;
53
- break;
54
- } catch (error) {
55
- lastError = error;
56
- if (attempt < 3) await new Promise((wait) => setTimeout(wait, attempt * 2000));
57
- }
58
- }
59
-
60
- if (lastError) {
61
- core.warning(
62
- `Could not delete ${artifact.name} (${artifact.id}) after 3 tries: ${lastError.message}`,
63
- );
64
- failed.push({ name: artifact.name, status: lastError.status });
65
- }
66
- }
67
-
68
- await core.summary
69
- .addHeading('Artifact cleanup', 2)
70
- .addList([
71
- `Retention: ${days} days (cutoff ${cutoff.toISOString()})`,
72
- `Deleted: ${deleted}`,
73
- `Failed to delete: ${failed.length}`,
74
- `Within retention: ${artifacts.length - expired.length}`,
75
- ])
76
- .write();
77
-
78
- // Deleting nothing at all while expired artifacts exist is a permission or
79
- // configuration problem, and has to be loud. One stubborn artifact among many is
80
- // the API having a bad minute: tomorrow's run picks it up, and failing here only
81
- // teaches people to ignore a red cleanup. A 4xx is never transient, so it fails
82
- // whatever else succeeded.
83
- const names = failed.map((entry) => entry.name).join(', ');
84
- const structural = failed.some((entry) => entry.status && entry.status < 500);
85
- if (failed.length > 0 && (deleted === 0 || structural)) {
86
- core.setFailed(`${failed.length} artifact(s) could not be deleted: ${names}`);
87
- } else if (failed.length > 0) {
88
- core.warning(
89
- `${failed.length} artifact(s) survived this run and will be retried tomorrow: ${names}`,
90
- );
91
- }
1
+ # Managed by @plainconceptsplatform/workflows. Source: loops/actions/cleanup-artifacts/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
+ name: Clean up artifacts
3
+ description: Delete workflow artifacts older than the configured retention period.
4
+ inputs:
5
+ token:
6
+ description: GitHub token with actions write access.
7
+ required: true
8
+ artifact-retention-days:
9
+ description: Retention period in days. Invalid or empty values use 3.
10
+ required: false
11
+ default: ''
12
+ runs:
13
+ using: composite
14
+ steps:
15
+ - name: Delete expired artifacts
16
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
17
+ env:
18
+ ARTIFACT_RETENTION_DAYS: ${{ inputs.artifact-retention-days }}
19
+ with:
20
+ github-token: ${{ inputs.token }}
21
+ script: |
22
+ const parsedDays = Number.parseInt(process.env.ARTIFACT_RETENTION_DAYS, 10);
23
+ const days = Number.isInteger(parsedDays) && parsedDays > 0 ? parsedDays : 3;
24
+ const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000);
25
+
26
+ core.info(`Retention: ${days} days (cutoff ${cutoff.toISOString()})`);
27
+
28
+ const artifacts = await github.paginate(github.rest.actions.listArtifactsForRepo, {
29
+ ...context.repo,
30
+ per_page: 100,
31
+ });
32
+
33
+ const expired = artifacts.filter((artifact) => new Date(artifact.created_at) < cutoff);
34
+
35
+ let deleted = 0;
36
+ const failed = [];
37
+
38
+ for (const artifact of expired) {
39
+ // GitHub answers a delete with a 5xx now and then. Three tries, because the
40
+ // alternative is a red daily run over one artifact that tomorrow's run would
41
+ // have removed anyway.
42
+ let lastError;
43
+ for (let attempt = 1; attempt <= 3; attempt += 1) {
44
+ try {
45
+ await github.rest.actions.deleteArtifact({
46
+ ...context.repo,
47
+ artifact_id: artifact.id,
48
+ });
49
+
50
+ core.info(`Deleted ${artifact.name} (created ${artifact.created_at})`);
51
+ deleted += 1;
52
+ lastError = undefined;
53
+ break;
54
+ } catch (error) {
55
+ lastError = error;
56
+ if (attempt < 3) await new Promise((wait) => setTimeout(wait, attempt * 2000));
57
+ }
58
+ }
59
+
60
+ if (lastError) {
61
+ core.warning(
62
+ `Could not delete ${artifact.name} (${artifact.id}) after 3 tries: ${lastError.message}`,
63
+ );
64
+ failed.push({ name: artifact.name, status: lastError.status });
65
+ }
66
+ }
67
+
68
+ await core.summary
69
+ .addHeading('Artifact cleanup', 2)
70
+ .addList([
71
+ `Retention: ${days} days (cutoff ${cutoff.toISOString()})`,
72
+ `Deleted: ${deleted}`,
73
+ `Failed to delete: ${failed.length}`,
74
+ `Within retention: ${artifacts.length - expired.length}`,
75
+ ])
76
+ .write();
77
+
78
+ // Deleting nothing at all while expired artifacts exist is a permission or
79
+ // configuration problem, and has to be loud. One stubborn artifact among many is
80
+ // the API having a bad minute: tomorrow's run picks it up, and failing here only
81
+ // teaches people to ignore a red cleanup. A 4xx is never transient, so it fails
82
+ // whatever else succeeded.
83
+ const names = failed.map((entry) => entry.name).join(', ');
84
+ const structural = failed.some((entry) => entry.status && entry.status < 500);
85
+ if (failed.length > 0 && (deleted === 0 || structural)) {
86
+ core.setFailed(`${failed.length} artifact(s) could not be deleted: ${names}`);
87
+ } else if (failed.length > 0) {
88
+ core.warning(
89
+ `${failed.length} artifact(s) survived this run and will be retried tomorrow: ${names}`,
90
+ );
91
+ }
@@ -1,43 +1,43 @@
1
- # Managed by @plainconceptsplatform/workflows. Source: loops/actions/close-agent-issues/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
- name: Close agent issues
3
- description: Close every close_issue item from agent_output.json.
4
- inputs:
5
- output-file:
6
- description: Path to agent_output.json.
7
- required: true
8
- token:
9
- description: GitHub token with issues:write.
10
- required: true
11
- runs:
12
- using: composite
13
- steps:
14
- - name: Close issues
15
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
16
- env:
17
- AGENT_OUTPUT_LIB: ${{ github.action_path }}/../agent-output.cjs
18
- OUTPUT_FILE: ${{ inputs.output-file }}
19
- with:
20
- github-token: ${{ inputs.token }}
21
- script: |
22
- const { readAgentItems } = require(process.env.AGENT_OUTPUT_LIB);
23
- const items = readAgentItems(process.env.OUTPUT_FILE, 'close_issue');
24
-
25
- let closed = 0;
26
-
27
- for (const item of items) {
28
- if (!item.item_number) {
29
- core.warning(`close_issue item has no item_number, skipping: ${JSON.stringify(item)}`);
30
- continue;
31
- }
32
-
33
- await github.rest.issues.update({
34
- ...context.repo,
35
- issue_number: Number(item.item_number),
36
- state: 'closed',
37
- state_reason: item.state_reason === 'not_planned' ? 'not_planned' : 'completed',
38
- });
39
-
40
- closed += 1;
41
- }
42
-
43
- core.info(`Closed ${closed} issue(s).`);
1
+ # Managed by @plainconceptsplatform/workflows. Source: loops/actions/close-agent-issues/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
+ name: Close agent issues
3
+ description: Close every close_issue item from agent_output.json.
4
+ inputs:
5
+ output-file:
6
+ description: Path to agent_output.json.
7
+ required: true
8
+ token:
9
+ description: GitHub token with issues:write.
10
+ required: true
11
+ runs:
12
+ using: composite
13
+ steps:
14
+ - name: Close issues
15
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
16
+ env:
17
+ AGENT_OUTPUT_LIB: ${{ github.action_path }}/../agent-output.cjs
18
+ OUTPUT_FILE: ${{ inputs.output-file }}
19
+ with:
20
+ github-token: ${{ inputs.token }}
21
+ script: |
22
+ const { readAgentItems } = require(process.env.AGENT_OUTPUT_LIB);
23
+ const items = readAgentItems(process.env.OUTPUT_FILE, 'close_issue');
24
+
25
+ let closed = 0;
26
+
27
+ for (const item of items) {
28
+ if (!item.item_number) {
29
+ core.warning(`close_issue item has no item_number, skipping: ${JSON.stringify(item)}`);
30
+ continue;
31
+ }
32
+
33
+ await github.rest.issues.update({
34
+ ...context.repo,
35
+ issue_number: Number(item.item_number),
36
+ state: 'closed',
37
+ state_reason: item.state_reason === 'not_planned' ? 'not_planned' : 'completed',
38
+ });
39
+
40
+ closed += 1;
41
+ }
42
+
43
+ core.info(`Closed ${closed} issue(s).`);
@@ -1,52 +1,52 @@
1
- # Managed by @plainconceptsplatform/workflows. Source: loops/actions/create-agent-issues/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
- name: Create agent issues
3
- description: Create every create_issue item from agent_output.json.
4
- inputs:
5
- output-file:
6
- description: Path to agent_output.json.
7
- required: true
8
- token:
9
- description: GitHub token with issues:write.
10
- required: true
11
- outputs:
12
- created-count:
13
- description: Number of issues created.
14
- value: ${{ steps.create.outputs.created-count }}
15
- first-issue-number:
16
- description: Issue number of the first issue created, or empty.
17
- value: ${{ steps.create.outputs.first-issue-number }}
18
- runs:
19
- using: composite
20
- steps:
21
- - name: Create issues
22
- id: create
23
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
24
- env:
25
- AGENT_OUTPUT_LIB: ${{ github.action_path }}/../agent-output.cjs
26
- OUTPUT_FILE: ${{ inputs.output-file }}
27
- with:
28
- github-token: ${{ inputs.token }}
29
- script: |
30
- const { readAgentItems } = require(process.env.AGENT_OUTPUT_LIB);
31
- const items = readAgentItems(process.env.OUTPUT_FILE, 'create_issue');
32
-
33
- const created = [];
34
-
35
- for (const item of items) {
36
- if (!item.title) {
37
- core.warning(`create_issue item has no title, skipping: ${JSON.stringify(item)}`);
38
- continue;
39
- }
40
-
41
- const { data } = await github.rest.issues.create({
42
- ...context.repo,
43
- title: item.title,
44
- body: item.body ?? '',
45
- });
46
-
47
- created.push(data.number);
48
- core.info(`Created #${data.number}: ${item.title}`);
49
- }
50
-
51
- core.setOutput('created-count', String(created.length));
52
- core.setOutput('first-issue-number', created.length > 0 ? String(created[0]) : '');
1
+ # Managed by @plainconceptsplatform/workflows. Source: loops/actions/create-agent-issues/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
+ name: Create agent issues
3
+ description: Create every create_issue item from agent_output.json.
4
+ inputs:
5
+ output-file:
6
+ description: Path to agent_output.json.
7
+ required: true
8
+ token:
9
+ description: GitHub token with issues:write.
10
+ required: true
11
+ outputs:
12
+ created-count:
13
+ description: Number of issues created.
14
+ value: ${{ steps.create.outputs.created-count }}
15
+ first-issue-number:
16
+ description: Issue number of the first issue created, or empty.
17
+ value: ${{ steps.create.outputs.first-issue-number }}
18
+ runs:
19
+ using: composite
20
+ steps:
21
+ - name: Create issues
22
+ id: create
23
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
24
+ env:
25
+ AGENT_OUTPUT_LIB: ${{ github.action_path }}/../agent-output.cjs
26
+ OUTPUT_FILE: ${{ inputs.output-file }}
27
+ with:
28
+ github-token: ${{ inputs.token }}
29
+ script: |
30
+ const { readAgentItems } = require(process.env.AGENT_OUTPUT_LIB);
31
+ const items = readAgentItems(process.env.OUTPUT_FILE, 'create_issue');
32
+
33
+ const created = [];
34
+
35
+ for (const item of items) {
36
+ if (!item.title) {
37
+ core.warning(`create_issue item has no title, skipping: ${JSON.stringify(item)}`);
38
+ continue;
39
+ }
40
+
41
+ const { data } = await github.rest.issues.create({
42
+ ...context.repo,
43
+ title: item.title,
44
+ body: item.body ?? '',
45
+ });
46
+
47
+ created.push(data.number);
48
+ core.info(`Created #${data.number}: ${item.title}`);
49
+ }
50
+
51
+ core.setOutput('created-count', String(created.length));
52
+ core.setOutput('first-issue-number', created.length > 0 ? String(created[0]) : '');
@@ -1,29 +1,29 @@
1
- # Managed by @plainconceptsplatform/workflows. Source: loops/actions/create-issue-comment/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
- name: Create issue comment
3
- description: Create a comment on an issue or pull request.
4
- inputs:
5
- token:
6
- description: GitHub token used by github-script.
7
- required: true
8
- issue-number:
9
- description: Issue or pull request number.
10
- required: true
11
- body:
12
- description: Complete Markdown comment body.
13
- required: true
14
- runs:
15
- using: composite
16
- steps:
17
- - name: Create comment
18
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
19
- env:
20
- ISSUE_NUMBER: ${{ inputs.issue-number }}
21
- BODY: ${{ inputs.body }}
22
- with:
23
- github-token: ${{ inputs.token }}
24
- script: |
25
- await github.rest.issues.createComment({
26
- ...context.repo,
27
- issue_number: Number(process.env.ISSUE_NUMBER),
28
- body: process.env.BODY,
29
- });
1
+ # Managed by @plainconceptsplatform/workflows. Source: loops/actions/create-issue-comment/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
+ name: Create issue comment
3
+ description: Create a comment on an issue or pull request.
4
+ inputs:
5
+ token:
6
+ description: GitHub token used by github-script.
7
+ required: true
8
+ issue-number:
9
+ description: Issue or pull request number.
10
+ required: true
11
+ body:
12
+ description: Complete Markdown comment body.
13
+ required: true
14
+ runs:
15
+ using: composite
16
+ steps:
17
+ - name: Create comment
18
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
19
+ env:
20
+ ISSUE_NUMBER: ${{ inputs.issue-number }}
21
+ BODY: ${{ inputs.body }}
22
+ with:
23
+ github-token: ${{ inputs.token }}
24
+ script: |
25
+ await github.rest.issues.createComment({
26
+ ...context.repo,
27
+ issue_number: Number(process.env.ISSUE_NUMBER),
28
+ body: process.env.BODY,
29
+ });