Add close-inactive workflow; enable plugin configs
Add a GitHub Actions workflow (.github/workflows/close-inactive.yml) that searches for open issues and PRs with no activity past a configurable cutoff and optionally posts a closing comment and closes them. The workflow runs on a daily cron and supports manual dispatch with inputs for inactive_days and dry_run; it uses actions/github-script to paginate search results and handle closing. Also update plugins/text_editor/plugin.yaml to enable per_project_config and per_agent_config (changed from false to true) so the text_editor plugin can be configured per project and per agent.
frdel committed
Mar 3, 2026 at 18:50 UTC
e2a7df7d33528e38be35f75eb9c953a6e2671f66
2 files changed
+110
-2
.github/workflows/close-inactive.yml
new
+108
@@ -0,0 +1,108 @@
1
+name: Close inactive issues and PRs
2
+
3
+on:
4
+ schedule:
5
+ - cron: "17 3 * * *"
6
+ workflow_dispatch:
7
+ inputs:
8
+ inactive_days:
9
+ description: "Close items with no activity for more than N days"
10
+ required: false
11
+ default: "90"
12
+ dry_run:
13
+ description: "If true, only print URLs (no comment/close)"
14
+ required: false
15
+ default: "true"
16
+
17
+permissions:
18
+ issues: write
19
+ pull-requests: write
20
+
21
+env:
22
+ DEFAULT_INACTIVE_DAYS: "90"
23
+ DEFAULT_DRY_RUN: "true"
24
+
25
+jobs:
26
+ close_inactive:
27
+ if: github.repository == 'agent0ai/agent-zero' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
28
+ runs-on: ubuntu-latest
29
+ steps:
30
+ - name: Find and optionally close inactive issues/PRs
31
+ uses: actions/github-script@v7
32
+ env:
33
+ INACTIVE_DAYS: ${{ github.event_name == 'workflow_dispatch' && inputs.inactive_days || env.DEFAULT_INACTIVE_DAYS }}
34
+ DRY_RUN: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run || env.DEFAULT_DRY_RUN }}
35
+ with:
36
+ script: |
37
+ const inactiveDaysRaw = process.env.INACTIVE_DAYS ?? "90";
38
+ const inactiveDays = Number.parseInt(inactiveDaysRaw, 10);
39
+ if (!Number.isFinite(inactiveDays) || inactiveDays <= 0) {
40
+ core.setFailed(`Invalid INACTIVE_DAYS: ${inactiveDaysRaw}`);
41
+ return;
42
+ }
43
+
44
+ const dryRunRaw = (process.env.DRY_RUN ?? "true").toLowerCase();
45
+ const dryRun = ["1", "true", "yes", "y"].includes(dryRunRaw);
46
+
47
+ const now = new Date();
48
+ const cutoff = new Date(now.getTime() - inactiveDays * 24 * 60 * 60 * 1000);
49
+ const cutoffDate = cutoff.toISOString().slice(0, 10);
50
+
51
+ core.info(`inactiveDays=${inactiveDays}`);
52
+ core.info(`dryRun=${dryRun}`);
53
+ core.info(`cutoffDate=${cutoffDate}`);
54
+
55
+ const owner = context.repo.owner;
56
+ const repo = context.repo.repo;
57
+
58
+ async function processQuery(kind, searchQuery) {
59
+ core.info(`Searching ${kind}: ${searchQuery}`);
60
+
61
+ const items = await github.paginate(github.rest.search.issuesAndPullRequests, {
62
+ q: searchQuery,
63
+ per_page: 100,
64
+ });
65
+
66
+ if (items.length === 0) {
67
+ core.info(`No inactive ${kind} found.`);
68
+ return;
69
+ }
70
+
71
+ core.info(`Found ${items.length} inactive ${kind}. URLs:`);
72
+ for (const item of items) {
73
+ core.info(item.html_url);
74
+ }
75
+
76
+ if (dryRun) {
77
+ return;
78
+ }
79
+
80
+ for (const item of items) {
81
+ const issueNumber = item.number;
82
+ const url = item.html_url;
83
+
84
+ try {
85
+ await github.rest.issues.createComment({
86
+ owner,
87
+ repo,
88
+ issue_number: issueNumber,
89
+ body: `Closing due to inactivity of ${inactiveDays} days.`,
90
+ });
91
+
92
+ await github.rest.issues.update({
93
+ owner,
94
+ repo,
95
+ issue_number: issueNumber,
96
+ state: "closed",
97
+ });
98
+
99
+ core.info(`Closed: ${url}`);
100
+ } catch (err) {
101
+ core.warning(`Failed to close ${url}: ${err?.message ?? String(err)}`);
102
+ }
103
+ }
104
+ }
105
+
106
+ const base = `repo:${owner}/${repo} is:open updated:<${cutoffDate}`;
107
+ await processQuery("issues", `${base} is:issue`);
108
+ await processQuery("pull requests", `${base} is:pr`);
plugins/text_editor/plugin.yaml
+2
-2
@@ -3,5 +3,5 @@ description: Native tool to read, write, and patch text files in an LLM-friendly
3
version: 1.0.0
4
settings_sections:
5
- agent
6
-per_project_config: false
7
-per_agent_config: false
6
+per_project_config: true
7
+per_agent_config: true