@xn-intenton-z2a/agentic-lib 7.1.13 → 7.1.15

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xn-intenton-z2a/agentic-lib",
3
- "version": "7.1.13",
3
+ "version": "7.1.15",
4
4
  "description": "Agentic-lib Agentic Coding Systems SDK powering automated GitHub workflows.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -32,8 +32,7 @@ env:
32
32
  configPath: ".github/agentic-lib/agents/agentic-lib.yml"
33
33
 
34
34
  jobs:
35
- maintain-features:
36
- if: inputs.step == 'all' || inputs.step == 'features' || github.event_name == 'schedule'
35
+ maintain:
37
36
  runs-on: ubuntu-latest
38
37
  steps:
39
38
  - uses: actions/checkout@v4
@@ -48,14 +47,18 @@ jobs:
48
47
  working-directory: .github/agentic-lib/actions/agentic-step
49
48
  run: npm ci
50
49
 
51
- - name: Load config for features
52
- id: features-config
50
+ - name: Load config
51
+ id: config
53
52
  run: |
54
53
  CONFIG="${{ env.configPath }}"
55
54
  FEATURES=$(yq -r '.paths.featuresPath.path // ".github/agentic-lib/features/"' "$CONFIG")
56
- echo "writablePaths=${FEATURES}" >> $GITHUB_OUTPUT
55
+ LIBRARY=$(yq -r '.paths.libraryDocumentsPath.path // "library/"' "$CONFIG")
56
+ SOURCES=$(yq -r '.paths.librarySourcesFilepath.path // "SOURCES.md"' "$CONFIG")
57
+ echo "featuresWritablePaths=${FEATURES}" >> $GITHUB_OUTPUT
58
+ echo "libraryWritablePaths=${LIBRARY};${SOURCES}" >> $GITHUB_OUTPUT
57
59
 
58
60
  - name: Maintain features
61
+ if: inputs.step == 'all' || inputs.step == 'features' || github.event_name == 'schedule'
59
62
  uses: ./.github/agentic-lib/actions/agentic-step
60
63
  env:
61
64
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -64,40 +67,10 @@ jobs:
64
67
  task: "maintain-features"
65
68
  config: ${{ env.configPath }}
66
69
  instructions: ".github/agentic-lib/agents/agent-maintain-features.md"
67
- writable-paths: ${{ steps.features-config.outputs.writablePaths }}
68
-
69
- - name: Commit and push changes
70
- uses: ./.github/agentic-lib/actions/commit-if-changed
71
- with:
72
- commit-message: "agentic-step: maintain-features"
73
- push-ref: ${{ github.ref_name }}
74
-
75
- maintain-library:
76
- needs: maintain-features
77
- if: always() && (inputs.step == 'all' || inputs.step == 'library' || github.event_name == 'schedule')
78
- runs-on: ubuntu-latest
79
- steps:
80
- - uses: actions/checkout@v4
81
- with:
82
- fetch-depth: 0
83
-
84
- - uses: actions/setup-node@v4
85
- with:
86
- node-version: "24"
87
-
88
- - name: Install agentic-step dependencies
89
- working-directory: .github/agentic-lib/actions/agentic-step
90
- run: npm ci
91
-
92
- - name: Load config for library
93
- id: library-config
94
- run: |
95
- CONFIG="${{ env.configPath }}"
96
- LIBRARY=$(yq -r '.paths.libraryDocumentsPath.path // "library/"' "$CONFIG")
97
- SOURCES=$(yq -r '.paths.librarySourcesFilepath.path // "SOURCES.md"' "$CONFIG")
98
- echo "writablePaths=${LIBRARY};${SOURCES}" >> $GITHUB_OUTPUT
70
+ writable-paths: ${{ steps.config.outputs.featuresWritablePaths }}
99
71
 
100
72
  - name: Maintain library
73
+ if: inputs.step == 'all' || inputs.step == 'library' || github.event_name == 'schedule'
101
74
  uses: ./.github/agentic-lib/actions/agentic-step
102
75
  env:
103
76
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -106,10 +79,10 @@ jobs:
106
79
  task: "maintain-library"
107
80
  config: ${{ env.configPath }}
108
81
  instructions: ".github/agentic-lib/agents/agent-maintain-library.md"
109
- writable-paths: ${{ steps.library-config.outputs.writablePaths }}
82
+ writable-paths: ${{ steps.config.outputs.libraryWritablePaths }}
110
83
 
111
84
  - name: Commit and push changes
112
85
  uses: ./.github/agentic-lib/actions/commit-if-changed
113
86
  with:
114
- commit-message: "agentic-step: maintain-library"
87
+ commit-message: "agentic-step: maintain features and library"
115
88
  push-ref: ${{ github.ref_name }}
@@ -3,7 +3,12 @@
3
3
  # .github/workflows/agent-supervisor.yml
4
4
  #
5
5
  # Reactive orchestration — triggers workflows based on telemetry.
6
- # When a build fails, dispatches fix-code. When issues pile up, dispatches review.
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
- // If a workflow failed, trigger fix-code
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
- if (isAgenticBranch) {
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
- // Find the PR for this branch
65
+ try {
66
+ if (workflowRun && conclusion === 'failure' && isAgenticBranch) {
46
67
  const { data: prs } = await github.rest.pulls.list({
47
- ...context.repo,
48
- state: 'open',
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
- await github.rest.actions.createWorkflowDispatch({
55
- ...context.repo,
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
- ref: context.ref,
58
- inputs: { 'pr-number': String(prs[0].number) },
81
+ branch,
82
+ per_page: maxFixAttempts + 1,
59
83
  });
60
- core.info(`Dispatched fix-code for PR #${prs[0].number}`);
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
- // Check for stale issues (open > 14 days with no activity)
66
- const { data: issues } = await github.rest.issues.listForRepo({
67
- ...context.repo,
68
- state: 'open',
69
- labels: 'automated',
70
- sort: 'updated',
71
- direction: 'asc',
72
- per_page: 5,
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
  }
@@ -12,6 +12,11 @@ run-name: "ci-automerge [${{ github.ref_name }}]"
12
12
  on:
13
13
  pull_request:
14
14
  check_suite:
15
+ workflow_run:
16
+ workflows:
17
+ - test
18
+ types:
19
+ - completed
15
20
  workflow_dispatch:
16
21
  workflow_call:
17
22
  inputs:
@@ -148,7 +153,12 @@ jobs:
148
153
 
149
154
  ls:
150
155
  needs: label
151
- if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || inputs.workflow == 'true' || github.event_name == 'workflow_call' || github.event_name == 'workflow_run'
156
+ if: >-
157
+ github.event_name == 'schedule' ||
158
+ github.event_name == 'workflow_dispatch' ||
159
+ github.event_name == 'workflow_run' ||
160
+ inputs.workflow == 'true' ||
161
+ github.event_name == 'workflow_call'
152
162
  runs-on: ubuntu-latest
153
163
  steps:
154
164
  - name: Determine pull request number
@@ -346,18 +356,21 @@ jobs:
346
356
  message = `Branch '${pullRequest.head.ref}' deleted.`;
347
357
  prMerged = 'true';
348
358
  } else if (pullRequest.mergeable_state === 'dirty' || pullRequest.mergeable === false) {
349
- message = `PR #${pullNumber} has conflicts. Closing.`;
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
+ }
350
367
  await github.rest.issues.createComment({
351
368
  owner, repo, issue_number: pullNumber,
352
- body: `This pull request is being closed due to conflicts (mergeable_state: ${pullRequest.mergeable_state}, mergeable: ${pullRequest.mergeable}).`,
369
+ body: `Automerge label removed this PR has conflicts (mergeable_state: ${pullRequest.mergeable_state}). Resolve conflicts and re-add the label to retry.`,
353
370
  });
354
- await github.rest.pulls.update({ owner, repo, pull_number: pullNumber, state: "closed" });
355
- try {
356
- await github.rest.git.deleteRef({ owner, repo, ref: `heads/${pullRequest.head.ref}` });
357
- message += ` Branch '${pullRequest.head.ref}' deleted.`;
358
- } catch (error) {
359
- message += ` Failed to delete branch: ${error.message}`;
360
- }
371
+ prMerged = 'false';
372
+ } else if (pullRequest.mergeable_state === 'unstable') {
373
+ message = `PR #${pullNumber} checks still running (mergeable_state: unstable). Will retry when test workflow completes.`;
361
374
  prMerged = 'false';
362
375
  } else if (pullRequest.mergeable === null) {
363
376
  message = `PR #${pullNumber} does not yet have a value for mergeability.`;