@xn-intenton-z2a/agentic-lib 7.1.101 → 7.1.102

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.
@@ -231,18 +231,26 @@ jobs:
231
231
  const tomlPath = 'agentic-lib.toml';
232
232
  if (!fs.existsSync(tomlPath)) return;
233
233
  let toml = fs.readFileSync(tomlPath, 'utf8');
234
- if (model) {
235
- const modelRegex = /(\[tuning\][^\[]*?)(^\s*model\s*=\s*"[^"]*")/m;
236
- if (modelRegex.test(toml)) {
237
- toml = toml.replace(modelRegex, `$1model = "${model}"`);
238
- core.info(`Updated [tuning].model to: ${model}`);
234
+ // Extract the [tuning] section, then replace within it.
235
+ // Previous regex [^\[]*? failed when comments contained '[' characters.
236
+ const tuningSectionRegex = /(\[tuning\])([\s\S]*?)(?=\n\[|$)/;
237
+ const tuningMatch = toml.match(tuningSectionRegex);
238
+ if (tuningMatch) {
239
+ let section = tuningMatch[0];
240
+ if (model) {
241
+ const updated = section.replace(/^(\s*model\s*=\s*)"[^"]*"/m, `$1"${model}"`);
242
+ if (updated !== section) {
243
+ toml = toml.replace(section, updated);
244
+ section = updated;
245
+ core.info(`Updated [tuning].model to: ${model}`);
246
+ }
239
247
  }
240
- }
241
- if (profile) {
242
- const profileRegex = /(\[tuning\][^\[]*?)(^\s*profile\s*=\s*"[^"]*")/m;
243
- if (profileRegex.test(toml)) {
244
- toml = toml.replace(profileRegex, `$1profile = "${profile}"`);
245
- core.info(`Updated [tuning].profile to: ${profile}`);
248
+ if (profile) {
249
+ const updated = section.replace(/^(\s*profile\s*=\s*)"[^"]*"/m, `$1"${profile}"`);
250
+ if (updated !== section) {
251
+ toml = toml.replace(section, updated);
252
+ core.info(`Updated [tuning].profile to: ${profile}`);
253
+ }
246
254
  }
247
255
  }
248
256
  fs.writeFileSync(tomlPath, toml);
@@ -40,6 +40,7 @@ on:
40
40
  permissions:
41
41
  contents: write
42
42
  actions: write
43
+ issues: write
43
44
 
44
45
  jobs:
45
46
  test:
@@ -119,7 +120,7 @@ jobs:
119
120
  if: >-
120
121
  !cancelled()
121
122
  && github.ref == 'refs/heads/main'
122
- && (github.event_name == 'push' || github.event_name == 'schedule')
123
+ && (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_call')
123
124
  && github.repository != 'xn-intenton-z2a/agentic-lib'
124
125
  && (needs.test.result == 'failure' || needs.behaviour.result == 'failure')
125
126
  runs-on: ubuntu-latest
@@ -154,3 +155,92 @@ jobs:
154
155
  --repo "${{ github.repository }}" \
155
156
  -f mode=full \
156
157
  -f message="Build broken on main: agentic-lib-test run ${{ github.run_id }} failed. Please fix."
158
+
159
+ # ─── Report instability: create/update GitHub issue on test failure ──
160
+ report-instability:
161
+ needs: [test, behaviour]
162
+ if: >-
163
+ !cancelled()
164
+ && github.ref == 'refs/heads/main'
165
+ && github.repository != 'xn-intenton-z2a/agentic-lib'
166
+ && (needs.test.result == 'failure' || needs.behaviour.result == 'failure')
167
+ runs-on: ubuntu-latest
168
+ steps:
169
+ - name: Determine failure type
170
+ id: failure-type
171
+ run: |
172
+ UNIT="${{ needs.test.result }}"
173
+ BEHAVIOUR="${{ needs.behaviour.result }}"
174
+ if [ "$UNIT" = "failure" ] && [ "$BEHAVIOUR" = "failure" ]; then
175
+ echo "type=both" >> $GITHUB_OUTPUT
176
+ elif [ "$UNIT" = "failure" ]; then
177
+ echo "type=unit" >> $GITHUB_OUTPUT
178
+ else
179
+ echo "type=behaviour" >> $GITHUB_OUTPUT
180
+ fi
181
+
182
+ - name: Collect failure logs
183
+ id: logs
184
+ env:
185
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
186
+ run: |
187
+ RUN_ID="${{ github.run_id }}"
188
+ # Get failed job logs via gh CLI
189
+ gh run view "$RUN_ID" --repo "${{ github.repository }}" --log-failed > /tmp/failed-logs.txt 2>&1 || true
190
+ # Trim to reasonable size (keep last 400 lines — generous context)
191
+ tail -400 /tmp/failed-logs.txt > /tmp/trimmed-logs.txt
192
+
193
+ - name: Create or update instability issue
194
+ uses: actions/github-script@v8
195
+ with:
196
+ script: |
197
+ const fs = require('fs');
198
+ const failureType = '${{ steps.failure-type.outputs.type }}';
199
+ const runId = '${{ github.run_id }}';
200
+ const runUrl = `https://github.com/${{ github.repository }}/actions/runs/${runId}`;
201
+ const logs = fs.readFileSync('/tmp/trimmed-logs.txt', 'utf8').slice(0, 60000);
202
+
203
+ const title = `instability: ${failureType} test failure on main`;
204
+ const body = [
205
+ `## Test Failure Report`,
206
+ ``,
207
+ `**Type**: ${failureType}`,
208
+ `**Run**: [${runId}](${runUrl})`,
209
+ `**Trigger**: ${context.eventName}`,
210
+ `**Time**: ${new Date().toISOString()}`,
211
+ ``,
212
+ `## Failure Logs`,
213
+ ``,
214
+ '```',
215
+ logs,
216
+ '```',
217
+ ].join('\n');
218
+
219
+ // Check for existing open instability issue of the same failure type
220
+ const { data: existing } = await github.rest.issues.listForRepo({
221
+ ...context.repo, state: 'open', labels: 'instability', per_page: 10,
222
+ });
223
+
224
+ const match = existing.find(i => i.title.includes(failureType));
225
+ if (match) {
226
+ // Add a comment with the new failure logs instead of creating a duplicate
227
+ await github.rest.issues.createComment({
228
+ ...context.repo, issue_number: match.number,
229
+ body: `## Recurrence — run [${runId}](${runUrl})\n\n**Trigger**: ${context.eventName}\n**Time**: ${new Date().toISOString()}\n\n` + '```\n' + logs.slice(0, 30000) + '\n```',
230
+ });
231
+ core.info(`Updated existing instability issue #${match.number}`);
232
+ } else {
233
+ // Ensure instability label exists
234
+ try {
235
+ await github.rest.issues.createLabel({
236
+ ...context.repo, name: 'instability',
237
+ color: 'e11d48', description: 'Automated: test instability on main',
238
+ });
239
+ } catch (e) { /* label already exists */ }
240
+
241
+ const { data: issue } = await github.rest.issues.create({
242
+ ...context.repo, title, body,
243
+ labels: ['instability', 'ready', 'automated'],
244
+ });
245
+ core.info(`Created instability issue #${issue.number}`);
246
+ }
@@ -319,6 +319,16 @@ jobs:
319
319
  labels: i.labels.map(l => l.name),
320
320
  }));
321
321
 
322
+ // W7: Check for open instability issues (mechanical priority override)
323
+ const { data: instabilityIssues } = await github.rest.issues.listForRepo({
324
+ owner, repo, state: 'open', labels: 'instability',
325
+ sort: 'created', direction: 'asc', per_page: 10,
326
+ });
327
+ const instabilityNumbers = instabilityIssues.map(i => i.number);
328
+ if (instabilityNumbers.length > 0) {
329
+ core.info(`Found ${instabilityNumbers.length} instability issue(s): ${instabilityNumbers.join(', ')}`);
330
+ }
331
+
322
332
  // Open PRs
323
333
  const { data: prs } = await github.rest.pulls.list({
324
334
  owner, repo, state: 'open', per_page: 10,
@@ -419,6 +429,7 @@ jobs:
419
429
 
420
430
  const telemetry = {
421
431
  issues: issuesSummary,
432
+ instabilityIssues: instabilityNumbers,
422
433
  prs: prsSummary,
423
434
  recentRuns: runsSummary,
424
435
  mission: mission.slice(0, 500),
@@ -962,6 +973,17 @@ jobs:
962
973
  core.setOutput('issue-number', specificIssue);
963
974
  return;
964
975
  }
976
+ // W7: Mechanical instability override — prioritise instability issues
977
+ // before any other ready issues, regardless of supervisor decisions
978
+ const { data: instabilityIssues } = await github.rest.issues.listForRepo({
979
+ ...context.repo, state: 'open', labels: 'instability',
980
+ sort: 'created', direction: 'asc', per_page: 1,
981
+ });
982
+ if (instabilityIssues.length > 0) {
983
+ core.setOutput('issue-number', String(instabilityIssues[0].number));
984
+ core.info(`Instability override: targeting issue #${instabilityIssues[0].number}: ${instabilityIssues[0].title}`);
985
+ return;
986
+ }
965
987
  // Find oldest open issue with 'ready' label
966
988
  const { data: issues } = await github.rest.issues.listForRepo({
967
989
  ...context.repo, state: 'open', labels: 'ready',
@@ -1024,15 +1046,33 @@ jobs:
1024
1046
  echo "tests-passed=true" >> $GITHUB_OUTPUT
1025
1047
  echo "All tests passed"
1026
1048
 
1049
+ - name: Run behaviour tests before committing
1050
+ id: pre-commit-behaviour-test
1051
+ if: steps.issue.outputs.issue-number != '' && steps.pre-commit-test.outputs.tests-passed == 'true' && (hashFiles('playwright.config.js') != '' || hashFiles('playwright.config.ts') != '')
1052
+ run: |
1053
+ npx playwright install --with-deps chromium 2>/dev/null || true
1054
+ npm run build:web 2>/dev/null || true
1055
+ set +e
1056
+ npm run --if-present test:behaviour 2>&1 | tail -30
1057
+ EXIT_CODE=$?
1058
+ set -e
1059
+ if [ $EXIT_CODE -ne 0 ]; then
1060
+ echo "tests-passed=false" >> $GITHUB_OUTPUT
1061
+ echo "WARNING: Behaviour tests failed (exit $EXIT_CODE) — skipping commit and PR"
1062
+ exit 0
1063
+ fi
1064
+ echo "tests-passed=true" >> $GITHUB_OUTPUT
1065
+ echo "Behaviour tests passed"
1066
+
1027
1067
  - name: Commit and push
1028
- if: github.repository != 'xn-intenton-z2a/agentic-lib' && steps.issue.outputs.issue-number != '' && needs.params.outputs.dry-run != 'true' && steps.pre-commit-test.outputs.tests-passed == 'true'
1068
+ if: github.repository != 'xn-intenton-z2a/agentic-lib' && steps.issue.outputs.issue-number != '' && needs.params.outputs.dry-run != 'true' && steps.pre-commit-test.outputs.tests-passed == 'true' && steps.pre-commit-behaviour-test.outputs.tests-passed != 'false'
1029
1069
  uses: ./.github/agentic-lib/actions/commit-if-changed
1030
1070
  with:
1031
1071
  commit-message: "agentic-step: transform issue #${{ steps.issue.outputs.issue-number }}"
1032
1072
  push-ref: ${{ steps.branch.outputs.branchName }}
1033
1073
 
1034
1074
  - name: Create PR and attempt merge
1035
- if: github.repository != 'xn-intenton-z2a/agentic-lib' && steps.issue.outputs.issue-number != '' && needs.params.outputs.dry-run != 'true' && steps.pre-commit-test.outputs.tests-passed == 'true'
1075
+ if: github.repository != 'xn-intenton-z2a/agentic-lib' && steps.issue.outputs.issue-number != '' && needs.params.outputs.dry-run != 'true' && steps.pre-commit-test.outputs.tests-passed == 'true' && steps.pre-commit-behaviour-test.outputs.tests-passed != 'false'
1036
1076
  uses: actions/github-script@v8
1037
1077
  with:
1038
1078
  script: |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xn-intenton-z2a/agentic-lib",
3
- "version": "7.1.101",
3
+ "version": "7.1.102",
4
4
  "description": "Agentic-lib Agentic Coding Systems SDK powering automated GitHub workflows.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -106,6 +106,9 @@ Check the Recent Activity log and Recently Closed Issues for patterns:
106
106
  - If the last 3+ cycles show the pattern: create issue → review closes as resolved → no transform → create identical issue, the pipeline is stuck. Check if acceptance criteria are truly met (use `mission-complete`) or if review is wrong (create a more specific issue). If neither works, use `mission-failed`.
107
107
  - Look for `transform: nop` or `transform: transformed` patterns in the activity log to distinguish productive iterations from idle ones.
108
108
 
109
+ **Dedup deadlock recovery:**
110
+ - If your issue creation is blocked by the dedup guard (similar to a recently closed issue), do NOT retry the same issue title. Instead, create an issue with a different scope — e.g. "fix: resolve failing tests on main" or "fix: align code and test expectations" — with both the `instability` and `ready` labels. This sidesteps the dedup guard and directs the dev job to the actual problem. The `instability` label gives the issue mechanical priority over other `ready` issues.
111
+
109
112
  ## Discussions Awareness
110
113
 
111
114
  Check the Recent Activity log for discussion bot referrals (lines containing `discussion-request-supervisor`). These indicate a user asked the bot something that requires supervisor action. **Prioritise responding to these referrals.**
@@ -17,7 +17,7 @@
17
17
  "author": "",
18
18
  "license": "MIT",
19
19
  "dependencies": {
20
- "@xn-intenton-z2a/agentic-lib": "^7.1.101"
20
+ "@xn-intenton-z2a/agentic-lib": "^7.1.102"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@playwright/test": "^1.58.0",