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

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);
@@ -35,11 +35,12 @@ on:
35
35
  workflow_dispatch:
36
36
  inputs:
37
37
  frequency:
38
- description: "How often the workflow should run"
38
+ description: "How often the workflow should run (maintenance = weekly + remove mission-complete + unlimited budget)"
39
39
  required: true
40
40
  type: choice
41
41
  options:
42
42
  - "off"
43
+ - "maintenance"
43
44
  - "weekly"
44
45
  - "daily"
45
46
  - "hourly"
@@ -95,6 +96,9 @@ jobs:
95
96
  const workflowPath = '.github/workflows/agentic-lib-workflow.yml';
96
97
  const tomlPath = 'agentic-lib.toml';
97
98
 
99
+ const isMaintenance = frequency === 'maintenance';
100
+ const effectiveFrequency = isMaintenance ? 'weekly' : frequency;
101
+
98
102
  const SCHEDULE_MAP = {
99
103
  off: null,
100
104
  weekly: '15 6 * * 1',
@@ -105,11 +109,11 @@ jobs:
105
109
 
106
110
  // Update agentic-lib-workflow.yml schedule
107
111
  let content = fs.readFileSync(workflowPath, 'utf8');
108
- const cron = SCHEDULE_MAP[frequency];
112
+ const cron = SCHEDULE_MAP[effectiveFrequency];
109
113
 
110
- // Check if the frequency is already set — skip if no-op
114
+ // Check if the frequency is already set — skip if no-op (but never skip maintenance)
111
115
  const supervisorRegex2 = /^\s*supervisor\s*=\s*"([^"]*)"/m;
112
- if (fs.existsSync(tomlPath)) {
116
+ if (!isMaintenance && fs.existsSync(tomlPath)) {
113
117
  const currentToml = fs.readFileSync(tomlPath, 'utf8');
114
118
  const currentMatch = currentToml.match(supervisorRegex2);
115
119
  const currentFreq = currentMatch ? currentMatch[1] : '';
@@ -144,7 +148,17 @@ jobs:
144
148
  }
145
149
 
146
150
  fs.writeFileSync(workflowPath, content);
147
- core.info(`Updated workflow schedule to: ${frequency} (cron: ${cron || 'none'})`);
151
+ core.info(`Updated workflow schedule to: ${effectiveFrequency} (cron: ${cron || 'none'})`);
152
+
153
+ // Maintenance mode: remove mission-complete/failed signals
154
+ if (isMaintenance) {
155
+ for (const f of ['MISSION_COMPLETE.md', 'MISSION_FAILED.md']) {
156
+ if (fs.existsSync(f)) {
157
+ fs.unlinkSync(f);
158
+ core.info(`Maintenance mode: removed ${f}`);
159
+ }
160
+ }
161
+ }
148
162
 
149
163
  // Update agentic-lib.toml with model and supervisor settings
150
164
  if (fs.existsSync(tomlPath)) {
@@ -174,6 +188,15 @@ jobs:
174
188
  }
175
189
  }
176
190
 
191
+ // Maintenance mode: set transformation-budget to 0 (unlimited)
192
+ if (isMaintenance) {
193
+ const budgetRegex = /^(\s*transformation-budget\s*=\s*)\d+/m;
194
+ if (budgetRegex.test(toml)) {
195
+ toml = toml.replace(budgetRegex, '$10');
196
+ core.info('Maintenance mode: set transformation-budget = 0 (unlimited)');
197
+ }
198
+ }
199
+
177
200
  fs.writeFileSync(tomlPath, toml);
178
201
  core.info(`Updated agentic-lib.toml: model=${model}, supervisor=${frequency}${profile ? ', profile=' + profile : ''}`);
179
202
  } else {
@@ -192,8 +215,14 @@ jobs:
192
215
  FREQUENCY="${{ inputs.frequency }}"
193
216
  MODEL="${{ inputs.model }}"
194
217
  git add .github/workflows/agentic-lib-workflow.yml agentic-lib.toml
218
+ # Stage removed mission files if maintenance mode deleted them
219
+ git rm --ignore-unmatch MISSION_COMPLETE.md MISSION_FAILED.md 2>/dev/null || true
195
220
  git diff --cached --quiet && echo "No changes to commit" && exit 0
196
- git commit -m "schedule: set to ${FREQUENCY}, model ${MODEL:-gpt-5-mini}"
221
+ if [ "$FREQUENCY" = "maintenance" ]; then
222
+ git commit -m "schedule: switch to maintenance mode (weekly, unlimited budget, mission reset)"
223
+ else
224
+ git commit -m "schedule: set to ${FREQUENCY}, model ${MODEL:-gpt-5-mini}"
225
+ fi
197
226
  for attempt in 1 2 3; do
198
227
  git push origin main && break
199
228
  echo "Push failed (attempt $attempt) — pulling and retrying"
@@ -35,11 +35,23 @@ on:
35
35
  #@dist - "**/*.yml"
36
36
  #@dist - "**/*.sh"
37
37
  workflow_call:
38
+ inputs:
39
+ push-screenshot:
40
+ type: string
41
+ required: false
42
+ default: "false"
38
43
  workflow_dispatch:
44
+ inputs:
45
+ push-screenshot:
46
+ description: "Push screenshot to main (default: only on schedule)"
47
+ type: boolean
48
+ required: false
49
+ default: false
39
50
 
40
51
  permissions:
41
52
  contents: write
42
53
  actions: write
54
+ issues: write
43
55
 
44
56
  jobs:
45
57
  test:
@@ -92,7 +104,9 @@ jobs:
92
104
  if-no-files-found: ignore
93
105
 
94
106
  - name: Push screenshot on main
95
- if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request'
107
+ if: |
108
+ github.ref == 'refs/heads/main' &&
109
+ (github.event_name == 'schedule' || inputs.push-screenshot == 'true' || inputs.push-screenshot == true)
96
110
  run: |
97
111
  git config --global --add safe.directory "$GITHUB_WORKSPACE"
98
112
  git config user.name "github-actions[bot]"
@@ -119,7 +133,7 @@ jobs:
119
133
  if: >-
120
134
  !cancelled()
121
135
  && github.ref == 'refs/heads/main'
122
- && (github.event_name == 'push' || github.event_name == 'schedule')
136
+ && (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_call')
123
137
  && github.repository != 'xn-intenton-z2a/agentic-lib'
124
138
  && (needs.test.result == 'failure' || needs.behaviour.result == 'failure')
125
139
  runs-on: ubuntu-latest
@@ -154,3 +168,92 @@ jobs:
154
168
  --repo "${{ github.repository }}" \
155
169
  -f mode=full \
156
170
  -f message="Build broken on main: agentic-lib-test run ${{ github.run_id }} failed. Please fix."
171
+
172
+ # ─── Report instability: create/update GitHub issue on test failure ──
173
+ report-instability:
174
+ needs: [test, behaviour]
175
+ if: >-
176
+ !cancelled()
177
+ && github.ref == 'refs/heads/main'
178
+ && github.repository != 'xn-intenton-z2a/agentic-lib'
179
+ && (needs.test.result == 'failure' || needs.behaviour.result == 'failure')
180
+ runs-on: ubuntu-latest
181
+ steps:
182
+ - name: Determine failure type
183
+ id: failure-type
184
+ run: |
185
+ UNIT="${{ needs.test.result }}"
186
+ BEHAVIOUR="${{ needs.behaviour.result }}"
187
+ if [ "$UNIT" = "failure" ] && [ "$BEHAVIOUR" = "failure" ]; then
188
+ echo "type=both" >> $GITHUB_OUTPUT
189
+ elif [ "$UNIT" = "failure" ]; then
190
+ echo "type=unit" >> $GITHUB_OUTPUT
191
+ else
192
+ echo "type=behaviour" >> $GITHUB_OUTPUT
193
+ fi
194
+
195
+ - name: Collect failure logs
196
+ id: logs
197
+ env:
198
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
199
+ run: |
200
+ RUN_ID="${{ github.run_id }}"
201
+ # Get failed job logs via gh CLI
202
+ gh run view "$RUN_ID" --repo "${{ github.repository }}" --log-failed > /tmp/failed-logs.txt 2>&1 || true
203
+ # Trim to reasonable size (keep last 400 lines — generous context)
204
+ tail -400 /tmp/failed-logs.txt > /tmp/trimmed-logs.txt
205
+
206
+ - name: Create or update instability issue
207
+ uses: actions/github-script@v8
208
+ with:
209
+ script: |
210
+ const fs = require('fs');
211
+ const failureType = '${{ steps.failure-type.outputs.type }}';
212
+ const runId = '${{ github.run_id }}';
213
+ const runUrl = `https://github.com/${{ github.repository }}/actions/runs/${runId}`;
214
+ const logs = fs.readFileSync('/tmp/trimmed-logs.txt', 'utf8').slice(0, 60000);
215
+
216
+ const title = `instability: ${failureType} test failure on main`;
217
+ const body = [
218
+ `## Test Failure Report`,
219
+ ``,
220
+ `**Type**: ${failureType}`,
221
+ `**Run**: [${runId}](${runUrl})`,
222
+ `**Trigger**: ${context.eventName}`,
223
+ `**Time**: ${new Date().toISOString()}`,
224
+ ``,
225
+ `## Failure Logs`,
226
+ ``,
227
+ '```',
228
+ logs,
229
+ '```',
230
+ ].join('\n');
231
+
232
+ // Check for existing open instability issue of the same failure type
233
+ const { data: existing } = await github.rest.issues.listForRepo({
234
+ ...context.repo, state: 'open', labels: 'instability', per_page: 10,
235
+ });
236
+
237
+ const match = existing.find(i => i.title.includes(failureType));
238
+ if (match) {
239
+ // Add a comment with the new failure logs instead of creating a duplicate
240
+ await github.rest.issues.createComment({
241
+ ...context.repo, issue_number: match.number,
242
+ body: `## Recurrence — run [${runId}](${runUrl})\n\n**Trigger**: ${context.eventName}\n**Time**: ${new Date().toISOString()}\n\n` + '```\n' + logs.slice(0, 30000) + '\n```',
243
+ });
244
+ core.info(`Updated existing instability issue #${match.number}`);
245
+ } else {
246
+ // Ensure instability label exists
247
+ try {
248
+ await github.rest.issues.createLabel({
249
+ ...context.repo, name: 'instability',
250
+ color: 'e11d48', description: 'Automated: test instability on main',
251
+ });
252
+ } catch (e) { /* label already exists */ }
253
+
254
+ const { data: issue } = await github.rest.issues.create({
255
+ ...context.repo, title, body,
256
+ labels: ['instability', 'ready', 'automated'],
257
+ });
258
+ core.info(`Created instability issue #${issue.number}`);
259
+ }
@@ -36,6 +36,10 @@ on:
36
36
  type: string
37
37
  required: false
38
38
  default: "true"
39
+ skipMaintain:
40
+ type: string
41
+ required: false
42
+ default: "false"
39
43
  config-path:
40
44
  type: string
41
45
  required: false
@@ -99,6 +103,11 @@ on:
99
103
  type: string
100
104
  required: false
101
105
  default: ""
106
+ skipMaintain:
107
+ description: "Skip maintain job (for testing fix-stuck in isolation)"
108
+ type: boolean
109
+ required: false
110
+ default: false
102
111
  dry-run:
103
112
  description: "Skip all push/PR/merge operations"
104
113
  type: boolean
@@ -319,6 +328,16 @@ jobs:
319
328
  labels: i.labels.map(l => l.name),
320
329
  }));
321
330
 
331
+ // W7: Check for open instability issues (mechanical priority override)
332
+ const { data: instabilityIssues } = await github.rest.issues.listForRepo({
333
+ owner, repo, state: 'open', labels: 'instability',
334
+ sort: 'created', direction: 'asc', per_page: 10,
335
+ });
336
+ const instabilityNumbers = instabilityIssues.map(i => i.number);
337
+ if (instabilityNumbers.length > 0) {
338
+ core.info(`Found ${instabilityNumbers.length} instability issue(s): ${instabilityNumbers.join(', ')}`);
339
+ }
340
+
322
341
  // Open PRs
323
342
  const { data: prs } = await github.rest.pulls.list({
324
343
  owner, repo, state: 'open', per_page: 10,
@@ -419,6 +438,7 @@ jobs:
419
438
 
420
439
  const telemetry = {
421
440
  issues: issuesSummary,
441
+ instabilityIssues: instabilityNumbers,
422
442
  prs: prsSummary,
423
443
  recentRuns: runsSummary,
424
444
  mission: mission.slice(0, 500),
@@ -470,7 +490,8 @@ jobs:
470
490
  if: |
471
491
  !cancelled() &&
472
492
  (needs.params.outputs.mode == 'full' || needs.params.outputs.mode == 'maintain-only') &&
473
- needs.params.result == 'success'
493
+ needs.params.result == 'success' &&
494
+ inputs.skipMaintain != 'true' && inputs.skipMaintain != true
474
495
  runs-on: ubuntu-latest
475
496
  steps:
476
497
  - uses: actions/checkout@v6
@@ -480,12 +501,16 @@ jobs:
480
501
  - name: Check mission-complete signal
481
502
  id: mission-check
482
503
  run: |
483
- if [ -f MISSION_COMPLETE.md ]; then
504
+ SUPERVISOR=$(grep '^\s*supervisor\s*=' agentic-lib.toml 2>/dev/null | head -1 | sed 's/.*=\s*"\([^"]*\)".*/\1/')
505
+ if [ -f MISSION_COMPLETE.md ] && [ "$SUPERVISOR" != "maintenance" ]; then
484
506
  echo "mission-complete=true" >> $GITHUB_OUTPUT
485
507
  echo "Mission is complete — skipping budget-consuming tasks"
486
508
  cat MISSION_COMPLETE.md
487
509
  else
488
510
  echo "mission-complete=false" >> $GITHUB_OUTPUT
511
+ if [ "$SUPERVISOR" = "maintenance" ] && [ -f MISSION_COMPLETE.md ]; then
512
+ echo "Maintenance mode — ignoring MISSION_COMPLETE.md"
513
+ fi
489
514
  fi
490
515
 
491
516
  - uses: actions/setup-node@v6
@@ -640,14 +665,15 @@ jobs:
640
665
  - name: Check mission-complete signal
641
666
  id: fix-mission-check
642
667
  run: |
643
- if [ -f MISSION_COMPLETE.md ]; then
668
+ SUPERVISOR=$(grep '^\s*supervisor\s*=' agentic-lib.toml 2>/dev/null | head -1 | sed 's/.*=\s*"\([^"]*\)".*/\1/')
669
+ if [ -f MISSION_COMPLETE.md ] && [ "$SUPERVISOR" != "maintenance" ]; then
644
670
  echo "mission-complete=true" >> $GITHUB_OUTPUT
645
671
  echo "Mission is complete — skipping fix-stuck"
646
672
  else
647
673
  echo "mission-complete=false" >> $GITHUB_OUTPUT
648
674
  fi
649
675
 
650
- - name: Find and fix stuck PRs or broken main build
676
+ - name: Find stuck PRs or broken main build
651
677
  if: steps.fix-mission-check.outputs.mission-complete != 'true'
652
678
  uses: actions/github-script@v8
653
679
  env:
@@ -663,10 +689,11 @@ jobs:
663
689
  if (prNumber) {
664
690
  core.info(`Specific PR requested: #${prNumber}`);
665
691
  core.exportVariable('FIX_PR_NUMBER', prNumber);
692
+ core.exportVariable('FIX_REASON', 'requested');
666
693
  return;
667
694
  }
668
695
 
669
- // Find PRs with failing checks or merge conflicts on agentic branches
696
+ // Find automerge PRs on agentic branches always attempt to sync with main
670
697
  const { data: openPRs } = await github.rest.pulls.list({
671
698
  owner, repo, state: 'open', per_page: 10,
672
699
  });
@@ -677,35 +704,20 @@ jobs:
677
704
  if (!hasAutomerge) continue;
678
705
  if (!pr.head.ref.startsWith('agentic-lib-') && !pr.head.ref.startsWith('copilot/')) continue;
679
706
 
680
- // Check for merge conflicts
681
- const { data: fullPr } = await github.rest.pulls.get({
682
- owner, repo, pull_number: pr.number,
683
- });
684
- const hasConflicts = fullPr.mergeable_state === 'dirty' || fullPr.mergeable === false;
685
-
686
- // Check if checks are failing
687
- const { data: checkRuns } = await github.rest.checks.listForRef({
688
- owner, repo, ref: pr.head.sha,
689
- });
690
- const hasFailing = checkRuns.check_runs.some(c => c.conclusion === 'failure');
691
-
692
- if (!hasFailing && !hasConflicts) continue;
693
-
694
- // Check fix attempt count
695
- const { data: fixRuns } = await github.rest.actions.listWorkflowRuns({
696
- owner, repo, workflow_id: 'agentic-lib-workflow.yml',
697
- branch: pr.head.ref, per_page: maxFixAttempts + 1,
707
+ // Check fix attempt count via PR comments with marker
708
+ const { data: comments } = await github.rest.issues.listComments({
709
+ owner, repo, issue_number: pr.number, per_page: 100,
698
710
  });
699
- if (fixRuns.total_count >= maxFixAttempts) {
700
- core.info(`PR #${pr.number} exceeded fix attempts. Removing automerge.`);
711
+ const fixAttempts = comments.filter(c => c.body && c.body.includes('<!-- fix-stuck-attempt -->')).length;
712
+ if (fixAttempts >= maxFixAttempts) {
713
+ core.info(`PR #${pr.number} exceeded ${maxFixAttempts} fix attempts (${fixAttempts} markers). Removing automerge.`);
701
714
  try { await github.rest.issues.removeLabel({ owner, repo, issue_number: pr.number, name: 'automerge' }); } catch (e) {}
702
715
  continue;
703
716
  }
704
717
 
705
- const reason = hasConflicts ? 'merge conflicts' : 'failing checks';
706
- core.info(`Will attempt to fix PR #${pr.number} (${reason})`);
718
+ core.info(`Will sync PR #${pr.number} with main (attempt ${fixAttempts + 1}/${maxFixAttempts})`);
707
719
  core.exportVariable('FIX_PR_NUMBER', String(pr.number));
708
- core.exportVariable('FIX_REASON', reason);
720
+ core.exportVariable('FIX_REASON', 'sync');
709
721
  foundPR = true;
710
722
  break;
711
723
  }
@@ -722,7 +734,6 @@ jobs:
722
734
  if (testRuns.workflow_runs.length > 0) {
723
735
  const latestTest = testRuns.workflow_runs[0];
724
736
  if (latestTest.conclusion === 'failure') {
725
- // Check we haven't already opened a fix branch for this
726
737
  const { data: existingPRs } = await github.rest.pulls.list({
727
738
  owner, repo, state: 'open', head: `${owner}:agentic-lib-fix-main-build`, per_page: 1,
728
739
  });
@@ -749,47 +760,128 @@ jobs:
749
760
  env:
750
761
  GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
751
762
 
763
+ - name: Record fix-stuck attempt on PR
764
+ if: env.FIX_PR_NUMBER != '' && steps.fix-mission-check.outputs.mission-complete != 'true'
765
+ env:
766
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
767
+ run: |
768
+ gh pr comment "${{ env.FIX_PR_NUMBER }}" --body "<!-- fix-stuck-attempt -->
769
+ **fix-stuck** attempting to resolve: ${{ env.FIX_REASON }} (run [${{ github.run_id }}](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}))"
770
+
752
771
  - name: Create fix branch for broken main build
753
772
  if: env.FIX_MAIN_BUILD == 'true' && steps.fix-mission-check.outputs.mission-complete != 'true'
754
773
  run: |
755
774
  git checkout -b agentic-lib-fix-main-build
756
775
 
757
- - name: "Tier 1: Auto-resolve trivial merge conflicts"
758
- if: env.FIX_PR_NUMBER != '' && env.FIX_REASON == 'merge conflicts' && steps.fix-mission-check.outputs.mission-complete != 'true'
776
+ - name: "Sync PR branch with main (incremental conflict resolution)"
777
+ if: env.FIX_PR_NUMBER != '' && steps.fix-mission-check.outputs.mission-complete != 'true'
759
778
  id: trivial-resolve
779
+ env:
780
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
760
781
  run: |
782
+ set -e
783
+ git config user.email 'action@github.com'
784
+ git config user.name 'GitHub Actions[bot]'
761
785
  git fetch origin main
762
- if git merge origin/main --no-edit 2>/dev/null; then
763
- echo "resolved=clean" >> $GITHUB_OUTPUT
786
+ BRANCH=$(git rev-parse --abbrev-ref HEAD)
787
+ RESOLVED=false
788
+
789
+ # --- Tier 1: Simple merge (no conflicts) ---
790
+ echo "=== Tier 1: Simple merge ==="
791
+ if git merge origin/main --no-edit 2>&1; then
792
+ echo "Tier 1: merge clean, pushing..."
793
+ git push origin HEAD:"$BRANCH" 2>&1 && RESOLVED=true || echo "Tier 1: push failed"
764
794
  else
765
- CONFLICTED=$(git diff --name-only --diff-filter=U)
766
- TRIVIAL_PATTERN='intentïon\.md|intention\.md|package-lock\.json'
767
- NON_TRIVIAL=$(echo "$CONFLICTED" | grep -vE "$TRIVIAL_PATTERN" || true)
768
- if [ -z "$NON_TRIVIAL" ]; then
769
- echo "All conflicts are trivial — auto-resolving"
770
- for f in $CONFLICTED; do
771
- git checkout --theirs "$f"
772
- git add "$f"
773
- done
795
+ echo "Tier 1: conflicts detected, aborting..."
796
+ git merge --abort 2>/dev/null || true
797
+ fi
798
+
799
+ # Check
800
+ if [ "$RESOLVED" = "true" ]; then
801
+ sleep 5
802
+ MERGEABLE=$(gh pr view "${{ env.FIX_PR_NUMBER }}" --json mergeable --jq '.mergeable')
803
+ echo "After Tier 1: mergeable=$MERGEABLE"
804
+ if [ "$MERGEABLE" = "CONFLICTING" ]; then
805
+ echo "Tier 1 pushed but PR still conflicting — continuing"
806
+ RESOLVED=false
807
+ fi
808
+ fi
809
+
810
+ # --- Tier 2: Merge preferring main for conflicts (-X theirs) ---
811
+ if [ "$RESOLVED" != "true" ]; then
812
+ echo "=== Tier 2: Merge with -X theirs ==="
813
+ git reset --hard HEAD 2>/dev/null || true
814
+ if git merge origin/main -X theirs --no-edit 2>&1; then
774
815
  npm install 2>/dev/null || true
775
816
  git add package-lock.json 2>/dev/null || true
776
- git commit --no-edit
777
- echo "resolved=trivial" >> $GITHUB_OUTPUT
817
+ git diff --cached --quiet || git commit --amend --no-edit
818
+ echo "Tier 2: merge succeeded, pushing..."
819
+ git push origin HEAD:"$BRANCH" 2>&1 || git push --force-with-lease origin HEAD:"$BRANCH" 2>&1
820
+ RESOLVED=true
778
821
  else
779
- git merge --abort
780
- echo "resolved=none" >> $GITHUB_OUTPUT
781
- echo "non_trivial<<EOF" >> $GITHUB_OUTPUT
782
- echo "$NON_TRIVIAL" >> $GITHUB_OUTPUT
783
- echo "EOF" >> $GITHUB_OUTPUT
822
+ echo "Tier 2: merge -X theirs failed, aborting..."
823
+ git merge --abort 2>/dev/null || true
784
824
  fi
785
825
  fi
786
826
 
787
- - name: "Tier 2: LLM fix (conflicts or failing checks)"
827
+ # Check
828
+ if [ "$RESOLVED" = "true" ]; then
829
+ sleep 5
830
+ MERGEABLE=$(gh pr view "${{ env.FIX_PR_NUMBER }}" --json mergeable --jq '.mergeable')
831
+ echo "After Tier 2: mergeable=$MERGEABLE"
832
+ if [ "$MERGEABLE" = "CONFLICTING" ]; then
833
+ echo "Tier 2 pushed but PR still conflicting — continuing"
834
+ RESOLVED=false
835
+ fi
836
+ fi
837
+
838
+ # --- Tier 3: Save source files, reset to main, copy back, force-push ---
839
+ if [ "$RESOLVED" != "true" ]; then
840
+ echo "=== Tier 3: Nuclear — save files, reset to main, copy back ==="
841
+ TMPDIR=$(mktemp -d)
842
+ for dir in src tests; do
843
+ [ -d "$dir" ] && cp -r "$dir" "$TMPDIR/" || true
844
+ done
845
+ cp package.json "$TMPDIR/" 2>/dev/null || true
846
+
847
+ git reset --hard origin/main
848
+ for dir in src tests; do
849
+ [ -d "$TMPDIR/$dir" ] && cp -r "$TMPDIR/$dir" ./ || true
850
+ done
851
+ cp "$TMPDIR/package.json" . 2>/dev/null || true
852
+ npm install 2>/dev/null || true
853
+
854
+ git add -A
855
+ if ! git diff --cached --quiet; then
856
+ git commit -m "fix-stuck: sync with main (resolve conflicts)"
857
+ git push --force-with-lease origin HEAD:"$BRANCH" 2>&1 && RESOLVED=true
858
+ else
859
+ echo "Tier 3: no differences after reset — branch identical to main"
860
+ RESOLVED=true
861
+ fi
862
+ rm -rf "$TMPDIR"
863
+ fi
864
+
865
+ # --- Final check: HARD FAIL if still not resolved ---
866
+ sleep 5
867
+ MERGEABLE=$(gh pr view "${{ env.FIX_PR_NUMBER }}" --json mergeable --jq '.mergeable')
868
+ echo "Final PR mergeable status: $MERGEABLE"
869
+ if [ "$MERGEABLE" = "CONFLICTING" ]; then
870
+ echo "::error::PR #${{ env.FIX_PR_NUMBER }} is STILL CONFLICTING after all 3 resolution tiers"
871
+ exit 1
872
+ fi
873
+ if [ "$RESOLVED" != "true" ]; then
874
+ echo "::error::All 3 tiers failed to resolve PR #${{ env.FIX_PR_NUMBER }}"
875
+ exit 1
876
+ fi
877
+ echo "PR #${{ env.FIX_PR_NUMBER }} successfully synced with main"
878
+ echo "resolved=true" >> $GITHUB_OUTPUT
879
+
880
+ - name: "Tier 2: LLM fix (only for explicitly requested PRs with failing checks)"
788
881
  if: |
789
882
  env.FIX_PR_NUMBER != '' &&
790
883
  steps.fix-mission-check.outputs.mission-complete != 'true' &&
791
- (env.FIX_REASON != 'merge conflicts' ||
792
- steps.trivial-resolve.outputs.resolved == 'none')
884
+ env.FIX_REASON == 'requested'
793
885
  uses: ./.github/agentic-lib/actions/agentic-step
794
886
  env:
795
887
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -828,9 +920,17 @@ jobs:
828
920
 
829
921
  - name: Commit and push fixes
830
922
  if: github.repository != 'xn-intenton-z2a/agentic-lib' && env.FIX_PR_NUMBER != '' && steps.fix-mission-check.outputs.mission-complete != 'true'
831
- uses: ./.github/agentic-lib/actions/commit-if-changed
832
- with:
833
- commit-message: "agentic-step: fix failing tests / resolve conflicts"
923
+ run: |
924
+ git config user.email 'action@github.com'
925
+ git config user.name 'GitHub Actions[bot]'
926
+ BRANCH=$(git rev-parse --abbrev-ref HEAD)
927
+ git add -A
928
+ if ! git diff --cached --quiet; then
929
+ git commit -m "agentic-step: fix failing tests / resolve conflicts"
930
+ git push origin HEAD:"$BRANCH" 2>&1 || git push --force-with-lease origin HEAD:"$BRANCH" 2>&1
931
+ else
932
+ echo "No additional changes to push"
933
+ fi
834
934
 
835
935
  - name: Commit, push, and open PR for main build fix
836
936
  if: github.repository != 'xn-intenton-z2a/agentic-lib' && env.FIX_MAIN_BUILD == 'true' && steps.fix-mission-check.outputs.mission-complete != 'true'
@@ -943,12 +1043,16 @@ jobs:
943
1043
  - name: Check mission-complete signal
944
1044
  id: dev-mission-check
945
1045
  run: |
946
- if [ -f MISSION_COMPLETE.md ]; then
1046
+ SUPERVISOR=$(grep '^\s*supervisor\s*=' agentic-lib.toml 2>/dev/null | head -1 | sed 's/.*=\s*"\([^"]*\)".*/\1/')
1047
+ if [ -f MISSION_COMPLETE.md ] && [ "$SUPERVISOR" != "maintenance" ]; then
947
1048
  echo "mission-complete=true" >> $GITHUB_OUTPUT
948
1049
  echo "Mission is complete — skipping dev transformation"
949
1050
  cat MISSION_COMPLETE.md
950
1051
  else
951
1052
  echo "mission-complete=false" >> $GITHUB_OUTPUT
1053
+ if [ "$SUPERVISOR" = "maintenance" ] && [ -f MISSION_COMPLETE.md ]; then
1054
+ echo "Maintenance mode — ignoring MISSION_COMPLETE.md"
1055
+ fi
952
1056
  fi
953
1057
 
954
1058
  - name: Find target issue
@@ -962,6 +1066,17 @@ jobs:
962
1066
  core.setOutput('issue-number', specificIssue);
963
1067
  return;
964
1068
  }
1069
+ // W7: Mechanical instability override — prioritise instability issues
1070
+ // before any other ready issues, regardless of supervisor decisions
1071
+ const { data: instabilityIssues } = await github.rest.issues.listForRepo({
1072
+ ...context.repo, state: 'open', labels: 'instability',
1073
+ sort: 'created', direction: 'asc', per_page: 1,
1074
+ });
1075
+ if (instabilityIssues.length > 0) {
1076
+ core.setOutput('issue-number', String(instabilityIssues[0].number));
1077
+ core.info(`Instability override: targeting issue #${instabilityIssues[0].number}: ${instabilityIssues[0].title}`);
1078
+ return;
1079
+ }
965
1080
  // Find oldest open issue with 'ready' label
966
1081
  const { data: issues } = await github.rest.issues.listForRepo({
967
1082
  ...context.repo, state: 'open', labels: 'ready',
@@ -1024,15 +1139,33 @@ jobs:
1024
1139
  echo "tests-passed=true" >> $GITHUB_OUTPUT
1025
1140
  echo "All tests passed"
1026
1141
 
1142
+ - name: Run behaviour tests before committing
1143
+ id: pre-commit-behaviour-test
1144
+ if: steps.issue.outputs.issue-number != '' && steps.pre-commit-test.outputs.tests-passed == 'true' && (hashFiles('playwright.config.js') != '' || hashFiles('playwright.config.ts') != '')
1145
+ run: |
1146
+ npx playwright install --with-deps chromium 2>/dev/null || true
1147
+ npm run build:web 2>/dev/null || true
1148
+ set +e
1149
+ npm run --if-present test:behaviour 2>&1 | tail -30
1150
+ EXIT_CODE=$?
1151
+ set -e
1152
+ if [ $EXIT_CODE -ne 0 ]; then
1153
+ echo "tests-passed=false" >> $GITHUB_OUTPUT
1154
+ echo "WARNING: Behaviour tests failed (exit $EXIT_CODE) — skipping commit and PR"
1155
+ exit 0
1156
+ fi
1157
+ echo "tests-passed=true" >> $GITHUB_OUTPUT
1158
+ echo "Behaviour tests passed"
1159
+
1027
1160
  - 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'
1161
+ 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
1162
  uses: ./.github/agentic-lib/actions/commit-if-changed
1030
1163
  with:
1031
1164
  commit-message: "agentic-step: transform issue #${{ steps.issue.outputs.issue-number }}"
1032
1165
  push-ref: ${{ steps.branch.outputs.branchName }}
1033
1166
 
1034
1167
  - 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'
1168
+ 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
1169
  uses: actions/github-script@v8
1037
1170
  with:
1038
1171
  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.103",
4
4
  "description": "Agentic-lib Agentic Coding Systems SDK powering automated GitHub workflows.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -50,7 +50,7 @@ function buildMissionMetrics(config, result, limitsStatus, cumulativeCost, featu
50
50
  const metrics = [
51
51
  { metric: "Open issues", value: String(openIssues), target: "0", status: openIssues === 0 ? "MET" : "NOT MET" },
52
52
  { metric: "Open PRs", value: String(openPrs), target: "0", status: openPrs === 0 ? "MET" : "NOT MET" },
53
- { metric: "Issues closed by review (RESOLVED)", value: String(resolvedCount), target: ">= 1", status: resolvedCount >= 1 ? "MET" : "NOT MET" },
53
+ { metric: "Issues resolved (review or PR merge)", value: String(resolvedCount), target: ">= 1", status: resolvedCount >= 1 ? "MET" : "NOT MET" },
54
54
  { metric: "Transformation budget used", value: `${cumulativeCost}/${budgetCap}`, target: budgetCap > 0 ? `< ${budgetCap}` : "unlimited", status: budgetCap > 0 && cumulativeCost >= budgetCap ? "EXHAUSTED" : "OK" },
55
55
  { metric: "Cumulative transforms", value: String(cumulativeCost), target: ">= 1", status: cumulativeCost >= 1 ? "MET" : "NOT MET" },
56
56
  { metric: "Mission complete declared", value: missionComplete ? "YES" : "NO", target: "—", status: "—" },
@@ -66,7 +66,7 @@ function buildMissionMetrics(config, result, limitsStatus, cumulativeCost, featu
66
66
  function buildMissionReadiness(metrics) {
67
67
  const openIssues = parseInt(metrics.find((m) => m.metric === "Open issues")?.value || "0", 10);
68
68
  const openPrs = parseInt(metrics.find((m) => m.metric === "Open PRs")?.value || "0", 10);
69
- const resolved = parseInt(metrics.find((m) => m.metric === "Issues closed by review (RESOLVED)")?.value || "0", 10);
69
+ const resolved = parseInt(metrics.find((m) => m.metric === "Issues resolved (review or PR merge)")?.value || "0", 10);
70
70
  const missionComplete = metrics.find((m) => m.metric === "Mission complete declared")?.value === "YES";
71
71
  const missionFailed = metrics.find((m) => m.metric === "Mission failed declared")?.value === "YES";
72
72
 
@@ -82,12 +82,12 @@ function buildMissionReadiness(metrics) {
82
82
 
83
83
  if (conditionsMet) {
84
84
  parts.push("Mission complete conditions ARE met.");
85
- parts.push(`0 open issues, 0 open PRs, ${resolved} issue(s) closed by review as RESOLVED.`);
85
+ parts.push(`0 open issues, 0 open PRs, ${resolved} issue(s) resolved.`);
86
86
  } else {
87
87
  parts.push("Mission complete conditions are NOT met.");
88
88
  if (openIssues > 0) parts.push(`${openIssues} open issue(s) remain.`);
89
89
  if (openPrs > 0) parts.push(`${openPrs} open PR(s) remain.`);
90
- if (resolved < 1) parts.push("No issues have been closed by review as RESOLVED yet.");
90
+ if (resolved < 1) parts.push("No issues have been resolved yet.");
91
91
  }
92
92
 
93
93
  return parts.join(" ");
@@ -19,8 +19,8 @@ export async function maintainFeatures(context) {
19
19
  const { config, instructions, writablePaths, model, octokit, repo } = context;
20
20
  const t = config.tuning || {};
21
21
 
22
- // Check mission-complete signal
23
- if (existsSync("MISSION_COMPLETE.md")) {
22
+ // Check mission-complete signal (skip in maintenance mode)
23
+ if (existsSync("MISSION_COMPLETE.md") && config.supervisor !== "maintenance") {
24
24
  return { outcome: "nop", details: "Mission already complete (MISSION_COMPLETE.md signal)" };
25
25
  }
26
26
 
@@ -19,8 +19,8 @@ export async function maintainLibrary(context) {
19
19
  const { config, instructions, writablePaths, model } = context;
20
20
  const t = config.tuning || {};
21
21
 
22
- // Check mission-complete signal
23
- if (existsSync("MISSION_COMPLETE.md")) {
22
+ // Check mission-complete signal (skip in maintenance mode)
23
+ if (existsSync("MISSION_COMPLETE.md") && config.supervisor !== "maintenance") {
24
24
  core.info("Mission is complete — skipping library maintenance");
25
25
  return { outcome: "nop", details: "Mission already complete (MISSION_COMPLETE.md signal)" };
26
26
  }
@@ -184,7 +184,8 @@ async function gatherContext(octokit, repo, config, t) {
184
184
  const { data: closedIssuesRaw } = await octokit.rest.issues.listForRepo({
185
185
  ...repo,
186
186
  state: "closed",
187
- per_page: 5,
187
+ labels: "automated",
188
+ per_page: 10,
188
189
  sort: "updated",
189
190
  direction: "desc",
190
191
  });
@@ -195,15 +196,27 @@ async function gatherContext(octokit, repo, config, t) {
195
196
  for (const ci of closedIssuesFiltered) {
196
197
  let closeReason = "closed";
197
198
  try {
199
+ // Check for review-closed (Automated Review Result comment)
198
200
  const { data: comments } = await octokit.rest.issues.listComments({
199
201
  ...repo,
200
202
  issue_number: ci.number,
201
- per_page: 1,
203
+ per_page: 5,
202
204
  sort: "created",
203
205
  direction: "desc",
204
206
  });
205
- if (comments.length > 0 && comments[0].body?.includes("Automated Review Result")) {
206
- closeReason = "closed by review as RESOLVED";
207
+ if (comments.some((c) => c.body?.includes("Automated Review Result"))) {
208
+ closeReason = "RESOLVED";
209
+ } else {
210
+ // Check for PR-linked closure (GitHub auto-closes via "Closes #N")
211
+ const { data: events } = await octokit.rest.issues.listEvents({
212
+ ...repo,
213
+ issue_number: ci.number,
214
+ per_page: 10,
215
+ });
216
+ const closedByPR = events.some((e) => e.event === "closed" && e.commit_id);
217
+ if (closedByPR) {
218
+ closeReason = "RESOLVED";
219
+ }
207
220
  }
208
221
  } catch (_) { /* ignore */ }
209
222
  recentlyClosedSummary.push(`#${ci.number}: ${ci.title} — ${closeReason}`);
@@ -631,15 +644,27 @@ async function executeMissionComplete(octokit, repo, params, ctx) {
631
644
  }
632
645
 
633
646
  if (process.env.GITHUB_REPOSITORY !== "xn-intenton-z2a/agentic-lib") {
647
+ // Only turn off schedule if it's not already off or in maintenance mode
648
+ let currentSupervisor = "";
634
649
  try {
635
- await octokit.rest.actions.createWorkflowDispatch({
636
- ...repo,
637
- workflow_id: "agentic-lib-schedule.yml",
638
- ref: "main",
639
- inputs: { frequency: "off" },
640
- });
641
- } catch (err) {
642
- core.warning(`Could not set schedule to off: ${err.message}`);
650
+ const tomlContent = readFileSync("agentic-lib.toml", "utf8");
651
+ const match = tomlContent.match(/^\s*supervisor\s*=\s*"([^"]*)"/m);
652
+ if (match) currentSupervisor = match[1];
653
+ } catch { /* ignore */ }
654
+
655
+ if (currentSupervisor === "off" || currentSupervisor === "maintenance") {
656
+ core.info(`Schedule already "${currentSupervisor}" not changing on mission-complete`);
657
+ } else {
658
+ try {
659
+ await octokit.rest.actions.createWorkflowDispatch({
660
+ ...repo,
661
+ workflow_id: "agentic-lib-schedule.yml",
662
+ ref: "main",
663
+ inputs: { frequency: "off" },
664
+ });
665
+ } catch (err) {
666
+ core.warning(`Could not set schedule to off: ${err.message}`);
667
+ }
643
668
  }
644
669
 
645
670
  // Announce mission complete via bot
@@ -688,15 +713,27 @@ async function executeMissionFailed(octokit, repo, params, ctx) {
688
713
  }
689
714
 
690
715
  if (process.env.GITHUB_REPOSITORY !== "xn-intenton-z2a/agentic-lib") {
716
+ // Only turn off schedule if it's not already off or in maintenance mode
717
+ let currentSupervisor = "";
691
718
  try {
692
- await octokit.rest.actions.createWorkflowDispatch({
693
- ...repo,
694
- workflow_id: "agentic-lib-schedule.yml",
695
- ref: "main",
696
- inputs: { frequency: "off" },
697
- });
698
- } catch (err) {
699
- core.warning(`Could not set schedule to off: ${err.message}`);
719
+ const tomlContent = readFileSync("agentic-lib.toml", "utf8");
720
+ const match = tomlContent.match(/^\s*supervisor\s*=\s*"([^"]*)"/m);
721
+ if (match) currentSupervisor = match[1];
722
+ } catch { /* ignore */ }
723
+
724
+ if (currentSupervisor === "off" || currentSupervisor === "maintenance") {
725
+ core.info(`Schedule already "${currentSupervisor}" not changing on mission-failed`);
726
+ } else {
727
+ try {
728
+ await octokit.rest.actions.createWorkflowDispatch({
729
+ ...repo,
730
+ workflow_id: "agentic-lib-schedule.yml",
731
+ ref: "main",
732
+ inputs: { frequency: "off" },
733
+ });
734
+ } catch (err) {
735
+ core.warning(`Could not set schedule to off: ${err.message}`);
736
+ }
700
737
  }
701
738
 
702
739
  // Announce mission failed via bot
@@ -810,17 +847,18 @@ export async function supervise(context) {
810
847
 
811
848
  // Strategy A: Deterministic mission-complete fallback
812
849
  // If the LLM didn't choose mission-complete but conditions are clearly met, auto-execute it.
813
- if (!ctx.missionComplete && !ctx.missionFailed) {
850
+ // Skip in maintenance mode — maintenance keeps running regardless of mission status.
851
+ if (!ctx.missionComplete && !ctx.missionFailed && config.supervisor !== "maintenance") {
814
852
  const llmChoseMissionComplete = results.some((r) => r.startsWith("mission-complete:"));
815
853
  if (!llmChoseMissionComplete) {
816
- const resolvedCount = ctx.recentlyClosedSummary.filter((s) => s.includes("closed by review as RESOLVED")).length;
854
+ const resolvedCount = ctx.recentlyClosedSummary.filter((s) => s.includes("RESOLVED")).length;
817
855
  const hasNoOpenIssues = ctx.issuesSummary.length === 0;
818
856
  const hasNoOpenPRs = ctx.prsSummary.length === 0;
819
- if (hasNoOpenIssues && hasNoOpenPRs && resolvedCount >= 2) {
857
+ if (hasNoOpenIssues && hasNoOpenPRs && resolvedCount >= 1) {
820
858
  core.info(`Deterministic mission-complete: 0 open issues, 0 open PRs, ${resolvedCount} recently resolved — LLM did not detect completion`);
821
859
  try {
822
860
  const autoResult = await executeMissionComplete(octokit, repo,
823
- { reason: `All acceptance criteria satisfied (${resolvedCount} issues closed by review as RESOLVED, 0 open issues, 0 open PRs)` },
861
+ { reason: `All acceptance criteria satisfied (${resolvedCount} issues resolved, 0 open issues, 0 open PRs)` },
824
862
  ctx);
825
863
  results.push(autoResult);
826
864
  } catch (err) {
@@ -26,8 +26,8 @@ export async function transform(context) {
26
26
  return { outcome: "nop", details: "No mission file found" };
27
27
  }
28
28
 
29
- // Check mission-complete signal
30
- if (existsSync("MISSION_COMPLETE.md")) {
29
+ // Check mission-complete signal (skip in maintenance mode)
30
+ if (existsSync("MISSION_COMPLETE.md") && config.supervisor !== "maintenance") {
31
31
  core.info("Mission is complete — skipping transformation (MISSION_COMPLETE.md exists)");
32
32
  return { outcome: "nop", details: "Mission already complete (MISSION_COMPLETE.md signal)" };
33
33
  }
@@ -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.103"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@playwright/test": "^1.58.0",