@xn-intenton-z2a/agentic-lib 7.1.14 → 7.1.16
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.
package/package.json
CHANGED
|
@@ -32,7 +32,20 @@ env:
|
|
|
32
32
|
configPath: ".github/agentic-lib/agents/agentic-lib.yml"
|
|
33
33
|
|
|
34
34
|
jobs:
|
|
35
|
+
params:
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
steps:
|
|
38
|
+
- name: Normalise params
|
|
39
|
+
id: normalise
|
|
40
|
+
shell: bash
|
|
41
|
+
run: |
|
|
42
|
+
STEP='${{ inputs.step }}'
|
|
43
|
+
echo "step=${STEP:-all}" >> $GITHUB_OUTPUT
|
|
44
|
+
outputs:
|
|
45
|
+
step: ${{ steps.normalise.outputs.step }}
|
|
46
|
+
|
|
35
47
|
maintain:
|
|
48
|
+
needs: params
|
|
36
49
|
runs-on: ubuntu-latest
|
|
37
50
|
steps:
|
|
38
51
|
- uses: actions/checkout@v4
|
|
@@ -58,7 +71,7 @@ jobs:
|
|
|
58
71
|
echo "libraryWritablePaths=${LIBRARY};${SOURCES}" >> $GITHUB_OUTPUT
|
|
59
72
|
|
|
60
73
|
- name: Maintain features
|
|
61
|
-
if:
|
|
74
|
+
if: needs.params.outputs.step == 'all' || needs.params.outputs.step == 'features'
|
|
62
75
|
uses: ./.github/agentic-lib/actions/agentic-step
|
|
63
76
|
env:
|
|
64
77
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -70,7 +83,7 @@ jobs:
|
|
|
70
83
|
writable-paths: ${{ steps.config.outputs.featuresWritablePaths }}
|
|
71
84
|
|
|
72
85
|
- name: Maintain library
|
|
73
|
-
if:
|
|
86
|
+
if: needs.params.outputs.step == 'all' || needs.params.outputs.step == 'library'
|
|
74
87
|
uses: ./.github/agentic-lib/actions/agentic-step
|
|
75
88
|
env:
|
|
76
89
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -31,8 +31,21 @@ env:
|
|
|
31
31
|
configPath: ".github/agentic-lib/agents/agentic-lib.yml"
|
|
32
32
|
|
|
33
33
|
jobs:
|
|
34
|
+
params:
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
steps:
|
|
37
|
+
- name: Normalise params
|
|
38
|
+
id: normalise
|
|
39
|
+
shell: bash
|
|
40
|
+
run: |
|
|
41
|
+
STEP='${{ inputs.step }}'
|
|
42
|
+
echo "step=${STEP:-all}" >> $GITHUB_OUTPUT
|
|
43
|
+
outputs:
|
|
44
|
+
step: ${{ steps.normalise.outputs.step }}
|
|
45
|
+
|
|
34
46
|
review-issues:
|
|
35
|
-
|
|
47
|
+
needs: params
|
|
48
|
+
if: needs.params.outputs.step == 'all' || needs.params.outputs.step == 'review'
|
|
36
49
|
runs-on: ubuntu-latest
|
|
37
50
|
steps:
|
|
38
51
|
- uses: actions/checkout@v4
|
|
@@ -56,7 +69,8 @@ jobs:
|
|
|
56
69
|
instructions: ".github/agentic-lib/agents/agent-review-issue.md"
|
|
57
70
|
|
|
58
71
|
enhance-issues:
|
|
59
|
-
|
|
72
|
+
needs: params
|
|
73
|
+
if: needs.params.outputs.step == 'all' || needs.params.outputs.step == 'enhance'
|
|
60
74
|
runs-on: ubuntu-latest
|
|
61
75
|
steps:
|
|
62
76
|
- uses: actions/checkout@v4
|
|
@@ -33,7 +33,20 @@ env:
|
|
|
33
33
|
configPath: ".github/agentic-lib/agents/agentic-lib.yml"
|
|
34
34
|
|
|
35
35
|
jobs:
|
|
36
|
+
params:
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
steps:
|
|
39
|
+
- name: Normalise params
|
|
40
|
+
id: normalise
|
|
41
|
+
shell: bash
|
|
42
|
+
run: |
|
|
43
|
+
MODEL='${{ inputs.model }}'
|
|
44
|
+
echo "model=${MODEL:-claude-sonnet-4}" >> $GITHUB_OUTPUT
|
|
45
|
+
outputs:
|
|
46
|
+
model: ${{ steps.normalise.outputs.model }}
|
|
47
|
+
|
|
36
48
|
transform:
|
|
49
|
+
needs: params
|
|
37
50
|
runs-on: ubuntu-latest
|
|
38
51
|
steps:
|
|
39
52
|
- uses: actions/checkout@v4
|
|
@@ -72,7 +85,7 @@ jobs:
|
|
|
72
85
|
config: ${{ env.configPath }}
|
|
73
86
|
instructions: ".github/agentic-lib/agents/agent-issue-resolution.md"
|
|
74
87
|
test-command: "npm test"
|
|
75
|
-
model: ${{
|
|
88
|
+
model: ${{ needs.params.outputs.model }}
|
|
76
89
|
writable-paths: ${{ steps.config.outputs.writablePaths }}
|
|
77
90
|
|
|
78
91
|
- name: Commit and push changes
|
|
@@ -3,7 +3,12 @@
|
|
|
3
3
|
# .github/workflows/agent-supervisor.yml
|
|
4
4
|
#
|
|
5
5
|
# Reactive orchestration — triggers workflows based on telemetry.
|
|
6
|
-
#
|
|
6
|
+
# Watches all agentic workflows and takes corrective or follow-up actions:
|
|
7
|
+
# - Failed builds on PR branches → dispatch fix-code (with loop protection)
|
|
8
|
+
# - Successful merges → dispatch transform to pick up next issue
|
|
9
|
+
# - Discussion bot actions → dispatch maintain or transform as follow-up
|
|
10
|
+
# - Stale issues → dispatch review
|
|
11
|
+
# - Stale conflicting PRs → remove automerge label
|
|
7
12
|
|
|
8
13
|
name: agent-supervisor
|
|
9
14
|
run-name: "agent-supervisor [${{ github.ref_name }}]"
|
|
@@ -14,6 +19,10 @@ on:
|
|
|
14
19
|
- test
|
|
15
20
|
- agent-flow-transform
|
|
16
21
|
- agent-flow-maintain
|
|
22
|
+
- agent-flow-fix-code
|
|
23
|
+
- agent-flow-review
|
|
24
|
+
- agent-discussions-bot
|
|
25
|
+
- ci-automerge
|
|
17
26
|
types:
|
|
18
27
|
- completed
|
|
19
28
|
workflow_dispatch:
|
|
@@ -22,8 +31,14 @@ permissions:
|
|
|
22
31
|
actions: write
|
|
23
32
|
contents: read
|
|
24
33
|
issues: read
|
|
34
|
+
pull-requests: write
|
|
25
35
|
checks: read
|
|
26
36
|
|
|
37
|
+
env:
|
|
38
|
+
maxFixAttempts: "3"
|
|
39
|
+
staleDays: "14"
|
|
40
|
+
stalePrDays: "3"
|
|
41
|
+
|
|
27
42
|
jobs:
|
|
28
43
|
evaluate:
|
|
29
44
|
runs-on: ubuntu-latest
|
|
@@ -32,54 +47,173 @@ jobs:
|
|
|
32
47
|
uses: actions/github-script@v7
|
|
33
48
|
with:
|
|
34
49
|
script: |
|
|
50
|
+
const owner = context.repo.owner;
|
|
51
|
+
const repo = context.repo.repo;
|
|
35
52
|
const workflowRun = context.payload.workflow_run;
|
|
53
|
+
const workflowName = workflowRun?.name || '';
|
|
54
|
+
const conclusion = workflowRun?.conclusion || '';
|
|
55
|
+
const branch = workflowRun?.head_branch || '';
|
|
56
|
+
const isAgenticBranch = branch && !['main', 'master'].includes(branch);
|
|
57
|
+
const maxFixAttempts = parseInt(process.env.maxFixAttempts) || 3;
|
|
58
|
+
const staleDays = parseInt(process.env.staleDays) || 14;
|
|
59
|
+
const stalePrDays = parseInt(process.env.stalePrDays) || 3;
|
|
36
60
|
|
|
37
|
-
|
|
38
|
-
if (workflowRun && workflowRun.conclusion === 'failure') {
|
|
39
|
-
const branch = workflowRun.head_branch;
|
|
40
|
-
const isAgenticBranch = !['main', 'master'].includes(branch);
|
|
61
|
+
core.info(`Supervisor: workflow="${workflowName}" conclusion="${conclusion}" branch="${branch}"`);
|
|
41
62
|
|
|
42
|
-
|
|
43
|
-
core.info(`Workflow "${workflowRun.name}" failed on branch ${branch}. Dispatching fix-code.`);
|
|
63
|
+
// ─── 1. Failure on PR branch → dispatch fix-code (with loop protection) ───
|
|
44
64
|
|
|
45
|
-
|
|
65
|
+
try {
|
|
66
|
+
if (workflowRun && conclusion === 'failure' && isAgenticBranch) {
|
|
46
67
|
const { data: prs } = await github.rest.pulls.list({
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
head: `${context.repo.owner}:${branch}`,
|
|
68
|
+
owner, repo, state: 'open',
|
|
69
|
+
head: `${owner}:${branch}`,
|
|
50
70
|
per_page: 1,
|
|
51
71
|
});
|
|
52
72
|
|
|
53
73
|
if (prs.length > 0) {
|
|
54
|
-
|
|
55
|
-
|
|
74
|
+
const pr = prs[0];
|
|
75
|
+
const prNumber = pr.number;
|
|
76
|
+
|
|
77
|
+
// Count prior fix-code runs for this branch to prevent infinite loops
|
|
78
|
+
const { data: fixRuns } = await github.rest.actions.listWorkflowRuns({
|
|
79
|
+
owner, repo,
|
|
56
80
|
workflow_id: 'agent-flow-fix-code.yml',
|
|
57
|
-
|
|
58
|
-
|
|
81
|
+
branch,
|
|
82
|
+
per_page: maxFixAttempts + 1,
|
|
59
83
|
});
|
|
60
|
-
|
|
84
|
+
const fixCount = fixRuns.total_count;
|
|
85
|
+
|
|
86
|
+
if (fixCount >= maxFixAttempts) {
|
|
87
|
+
core.info(`PR #${prNumber} has had ${fixCount} fix attempts (limit: ${maxFixAttempts}). Removing automerge label.`);
|
|
88
|
+
try {
|
|
89
|
+
await github.rest.issues.removeLabel({
|
|
90
|
+
owner, repo, issue_number: prNumber, name: 'automerge',
|
|
91
|
+
});
|
|
92
|
+
} catch (e) { /* label may not exist */ }
|
|
93
|
+
await github.rest.issues.createComment({
|
|
94
|
+
owner, repo, issue_number: prNumber,
|
|
95
|
+
body: `Supervisor: ${fixCount} fix-code attempts have failed. Removing automerge label — manual intervention needed.`,
|
|
96
|
+
});
|
|
97
|
+
} else {
|
|
98
|
+
core.info(`Dispatching fix-code for PR #${prNumber} (attempt ${fixCount + 1}/${maxFixAttempts}).`);
|
|
99
|
+
await github.rest.actions.createWorkflowDispatch({
|
|
100
|
+
owner, repo,
|
|
101
|
+
workflow_id: 'agent-flow-fix-code.yml',
|
|
102
|
+
ref: 'main',
|
|
103
|
+
inputs: { 'pr-number': String(prNumber) },
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
} catch (err) {
|
|
109
|
+
core.warning(`Fix-code dispatch failed: ${err.message}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ─── 2. Successful merge → dispatch transform for next issue ──────────
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
if (workflowName === 'ci-automerge' && conclusion === 'success') {
|
|
116
|
+
core.info('Automerge succeeded. Dispatching transform to pick up next issue.');
|
|
117
|
+
await github.rest.actions.createWorkflowDispatch({
|
|
118
|
+
owner, repo,
|
|
119
|
+
workflow_id: 'agent-flow-transform.yml',
|
|
120
|
+
ref: 'main',
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
} catch (err) {
|
|
124
|
+
core.warning(`Post-merge transform dispatch failed: ${err.message}`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ─── 3. Discussion bot follow-through ─────────────────────────────────
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
if (workflowName === 'agent-discussions-bot' && conclusion === 'success') {
|
|
131
|
+
// Check the most recent run's jobs for the outcome
|
|
132
|
+
const runId = workflowRun.id;
|
|
133
|
+
const { data: jobs } = await github.rest.actions.listJobsForWorkflowRun({
|
|
134
|
+
owner, repo, run_id: runId,
|
|
135
|
+
});
|
|
136
|
+
const respondJob = jobs.jobs.find(j => j.name === 'respond');
|
|
137
|
+
if (respondJob) {
|
|
138
|
+
// Look through step names/outputs for action indicators
|
|
139
|
+
const steps = respondJob.steps || [];
|
|
140
|
+
const agenticStep = steps.find(s => s.name === 'Respond to discussion');
|
|
141
|
+
if (agenticStep && agenticStep.conclusion === 'success') {
|
|
142
|
+
core.info('Discussion bot completed. Dispatching maintain to pick up any new features.');
|
|
143
|
+
await github.rest.actions.createWorkflowDispatch({
|
|
144
|
+
owner, repo,
|
|
145
|
+
workflow_id: 'agent-flow-maintain.yml',
|
|
146
|
+
ref: 'main',
|
|
147
|
+
});
|
|
148
|
+
}
|
|
61
149
|
}
|
|
62
150
|
}
|
|
151
|
+
} catch (err) {
|
|
152
|
+
core.warning(`Discussion bot follow-through failed: ${err.message}`);
|
|
63
153
|
}
|
|
64
154
|
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const fourteenDaysAgo = new Date(Date.now() - 14 * 24 * 60 * 60 * 1000);
|
|
76
|
-
const staleIssues = issues.filter(i => new Date(i.updated_at) < fourteenDaysAgo);
|
|
77
|
-
|
|
78
|
-
if (staleIssues.length > 0) {
|
|
79
|
-
core.info(`Found ${staleIssues.length} stale issue(s). Dispatching review.`);
|
|
80
|
-
await github.rest.actions.createWorkflowDispatch({
|
|
81
|
-
...context.repo,
|
|
82
|
-
workflow_id: 'agent-flow-review.yml',
|
|
83
|
-
ref: context.ref,
|
|
155
|
+
// ─── 4. Stale issues → dispatch review ────────────────────────────────
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
const { data: issues } = await github.rest.issues.listForRepo({
|
|
159
|
+
owner, repo, state: 'open',
|
|
160
|
+
labels: 'automated',
|
|
161
|
+
sort: 'updated',
|
|
162
|
+
direction: 'asc',
|
|
163
|
+
per_page: 5,
|
|
84
164
|
});
|
|
165
|
+
|
|
166
|
+
const cutoff = new Date(Date.now() - staleDays * 24 * 60 * 60 * 1000);
|
|
167
|
+
const staleIssues = issues.filter(i => new Date(i.updated_at) < cutoff);
|
|
168
|
+
|
|
169
|
+
if (staleIssues.length > 0) {
|
|
170
|
+
core.info(`Found ${staleIssues.length} stale issue(s). Dispatching review.`);
|
|
171
|
+
await github.rest.actions.createWorkflowDispatch({
|
|
172
|
+
owner, repo,
|
|
173
|
+
workflow_id: 'agent-flow-review.yml',
|
|
174
|
+
ref: 'main',
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
} catch (err) {
|
|
178
|
+
core.warning(`Stale issue check failed: ${err.message}`);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// ─── 5. Stale conflicting PRs → remove automerge label ────────────────
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
const { data: openPRs } = await github.rest.pulls.list({
|
|
185
|
+
owner, repo, state: 'open',
|
|
186
|
+
sort: 'updated',
|
|
187
|
+
direction: 'asc',
|
|
188
|
+
per_page: 10,
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
const prCutoff = new Date(Date.now() - stalePrDays * 24 * 60 * 60 * 1000);
|
|
192
|
+
for (const pr of openPRs) {
|
|
193
|
+
const hasAutomerge = pr.labels.some(l => l.name === 'automerge');
|
|
194
|
+
if (!hasAutomerge) continue;
|
|
195
|
+
|
|
196
|
+
const isStale = new Date(pr.updated_at) < prCutoff;
|
|
197
|
+
if (!isStale) continue;
|
|
198
|
+
|
|
199
|
+
// Fetch full PR to get mergeable_state
|
|
200
|
+
const { data: fullPr } = await github.rest.pulls.get({
|
|
201
|
+
owner, repo, pull_number: pr.number,
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
if (fullPr.mergeable_state === 'dirty' || fullPr.mergeable === false) {
|
|
205
|
+
core.info(`PR #${pr.number} has conflicts and is stale (${stalePrDays}+ days). Removing automerge label.`);
|
|
206
|
+
try {
|
|
207
|
+
await github.rest.issues.removeLabel({
|
|
208
|
+
owner, repo, issue_number: pr.number, name: 'automerge',
|
|
209
|
+
});
|
|
210
|
+
} catch (e) { /* label may not exist */ }
|
|
211
|
+
await github.rest.issues.createComment({
|
|
212
|
+
owner, repo, issue_number: pr.number,
|
|
213
|
+
body: `Supervisor: this PR has had conflicts for ${stalePrDays}+ days. Removing automerge label — resolve conflicts and re-add to retry.`,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
} catch (err) {
|
|
218
|
+
core.warning(`Stale PR check failed: ${err.message}`);
|
|
85
219
|
}
|
|
@@ -356,18 +356,18 @@ jobs:
|
|
|
356
356
|
message = `Branch '${pullRequest.head.ref}' deleted.`;
|
|
357
357
|
prMerged = 'true';
|
|
358
358
|
} else if (pullRequest.mergeable_state === 'dirty' || pullRequest.mergeable === false) {
|
|
359
|
-
message = `PR #${pullNumber} has conflicts.
|
|
359
|
+
message = `PR #${pullNumber} has conflicts. Removing automerge label.`;
|
|
360
|
+
try {
|
|
361
|
+
await github.rest.issues.removeLabel({
|
|
362
|
+
owner, repo, issue_number: pullNumber, name: 'automerge',
|
|
363
|
+
});
|
|
364
|
+
} catch (e) {
|
|
365
|
+
core.info(`Could not remove automerge label: ${e.message}`);
|
|
366
|
+
}
|
|
360
367
|
await github.rest.issues.createComment({
|
|
361
368
|
owner, repo, issue_number: pullNumber,
|
|
362
|
-
body: `
|
|
369
|
+
body: `Automerge label removed — this PR has conflicts (mergeable_state: ${pullRequest.mergeable_state}). Resolve conflicts and re-add the label to retry.`,
|
|
363
370
|
});
|
|
364
|
-
await github.rest.pulls.update({ owner, repo, pull_number: pullNumber, state: "closed" });
|
|
365
|
-
try {
|
|
366
|
-
await github.rest.git.deleteRef({ owner, repo, ref: `heads/${pullRequest.head.ref}` });
|
|
367
|
-
message += ` Branch '${pullRequest.head.ref}' deleted.`;
|
|
368
|
-
} catch (error) {
|
|
369
|
-
message += ` Failed to delete branch: ${error.message}`;
|
|
370
|
-
}
|
|
371
371
|
prMerged = 'false';
|
|
372
372
|
} else if (pullRequest.mergeable_state === 'unstable') {
|
|
373
373
|
message = `PR #${pullNumber} checks still running (mergeable_state: unstable). Will retry when test workflow completes.`;
|