@xn-intenton-z2a/agentic-lib 7.4.27 → 7.4.29

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.
@@ -87,7 +87,7 @@ jobs:
87
87
  steps:
88
88
  - uses: actions/checkout@v6
89
89
  with:
90
- ref: ${{ inputs.ref || github.sha }}
90
+ ref: ${{ inputs.ref || github.ref }}
91
91
  sparse-checkout: ${{ env.configPath }}
92
92
  sparse-checkout-cone-mode: false
93
93
  - name: Normalise params
@@ -116,7 +116,7 @@ jobs:
116
116
  - uses: actions/checkout@v6
117
117
  with:
118
118
  fetch-depth: 0
119
- ref: ${{ inputs.ref || github.sha }}
119
+ ref: ${{ inputs.ref || github.ref }}
120
120
 
121
121
  - uses: actions/setup-node@v6
122
122
  with:
@@ -96,6 +96,8 @@ jobs:
96
96
  update:
97
97
  if: inputs.mode != 'skip'
98
98
  uses: ./.github/workflows/agentic-lib-update.yml
99
+ with:
100
+ skip-tests: 'true'
99
101
  secrets: inherit
100
102
 
101
103
  # ── Phase 0b: Init (purge/reseed/update) ───────────────────────────
@@ -693,7 +695,42 @@ jobs:
693
695
  git add BENCHMARK_REPORT_FLOW_*.md
694
696
  git diff --staged --quiet && echo "No report to commit" && exit 0
695
697
  git commit -m "flow: benchmark report for ${{ inputs.mission-seed }} (${{ inputs.workflow-runs }} runs) [skip ci]"
696
- git push origin main || echo "Push failed — report saved as artifact"
698
+ MAX_RETRIES=3
699
+ PUSH_SUCCESS=""
700
+ for attempt in $(seq 1 $MAX_RETRIES); do
701
+ case $attempt in
702
+ 1)
703
+ echo "=== Attempt 1: rebase (cleanest) ==="
704
+ git pull --rebase origin main || {
705
+ git rebase --abort 2>/dev/null || true
706
+ sleep $((10 + RANDOM % 10))
707
+ continue
708
+ }
709
+ ;;
710
+ 2)
711
+ echo "=== Attempt 2: merge (handles non-overlapping changes) ==="
712
+ git pull --no-rebase origin main || {
713
+ git merge --abort 2>/dev/null || true
714
+ sleep $((20 + RANDOM % 10))
715
+ continue
716
+ }
717
+ ;;
718
+ 3)
719
+ echo "=== Attempt 3: merge -X theirs (accept remote on conflict) ==="
720
+ git pull -X theirs --no-rebase origin main || {
721
+ git merge --abort 2>/dev/null || true
722
+ sleep $((30 + RANDOM % 10))
723
+ continue
724
+ }
725
+ ;;
726
+ esac
727
+ git push origin main && { PUSH_SUCCESS="true"; break; }
728
+ echo "Push failed on attempt $attempt"
729
+ sleep $((attempt * 10 + RANDOM % 10))
730
+ done
731
+ if [ "$PUSH_SUCCESS" != "true" ]; then
732
+ echo "::warning::Failed to push report after $MAX_RETRIES attempts — saved as artifact"
733
+ fi
697
734
 
698
735
  - name: Upload report artifact
699
736
  uses: actions/upload-artifact@v4
@@ -48,6 +48,10 @@ on:
48
48
  type: string
49
49
  required: false
50
50
  default: "false"
51
+ run-workflow:
52
+ type: string
53
+ required: false
54
+ default: "true"
51
55
  workflow_dispatch:
52
56
  inputs:
53
57
  mode:
@@ -131,6 +135,11 @@ on:
131
135
  type: boolean
132
136
  required: false
133
137
  default: false
138
+ run-workflow:
139
+ description: "Dispatch agentic-lib-workflow after init completes"
140
+ type: boolean
141
+ required: false
142
+ default: true
134
143
 
135
144
  permissions: write-all
136
145
 
@@ -179,7 +188,7 @@ jobs:
179
188
  - uses: actions/checkout@v6
180
189
  if: inputs.dry-run == 'true' || inputs.dry-run == true
181
190
  with:
182
- ref: ${{ inputs.ref || github.sha }}
191
+ ref: ${{ inputs.ref || github.ref }}
183
192
  - uses: actions/checkout@v6
184
193
  if: inputs.dry-run != 'true' && inputs.dry-run != true
185
194
  with:
@@ -350,20 +359,47 @@ jobs:
350
359
  else
351
360
  git commit -m "init ${INIT_MODE} (agentic-lib@${VERSION}) [skip ci]"
352
361
  fi
353
- for attempt in 1 2 3; do
354
- # Use HEAD:refs/heads/main to handle detached HEAD state
355
- git push origin HEAD:refs/heads/main && break
356
- echo "Push failed (attempt $attempt) — pulling and retrying"
357
- git pull --rebase origin main || {
358
- echo "Rebase conflict — aborting rebase and retrying"
359
- git rebase --abort 2>/dev/null || true
360
- }
361
- sleep $((attempt * 2))
362
- if [ "$attempt" -eq 3 ]; then
363
- echo "::error::Failed to push after 3 attempts"
364
- exit 1
365
- fi
362
+ MAX_RETRIES=3
363
+ PUSH_SUCCESS=""
364
+ for attempt in $(seq 1 $MAX_RETRIES); do
365
+ # Tiered conflict resolution (mirrors fix-stuck strategy)
366
+ case $attempt in
367
+ 1)
368
+ echo "=== Attempt 1: rebase (cleanest) ==="
369
+ git pull --rebase origin main || {
370
+ echo "Rebase conflict on attempt 1 — aborting rebase"
371
+ git rebase --abort 2>/dev/null || true
372
+ sleep $((10 + RANDOM % 10))
373
+ continue
374
+ }
375
+ ;;
376
+ 2)
377
+ echo "=== Attempt 2: merge (handles non-overlapping changes) ==="
378
+ git pull --no-rebase origin main || {
379
+ echo "Merge conflict on attempt 2 — aborting merge"
380
+ git merge --abort 2>/dev/null || true
381
+ sleep $((20 + RANDOM % 10))
382
+ continue
383
+ }
384
+ ;;
385
+ 3)
386
+ echo "=== Attempt 3: merge -X theirs (accept remote on conflict) ==="
387
+ git pull -X theirs --no-rebase origin main || {
388
+ echo "Merge -X theirs failed on attempt 3"
389
+ git merge --abort 2>/dev/null || true
390
+ sleep $((30 + RANDOM % 10))
391
+ continue
392
+ }
393
+ ;;
394
+ esac
395
+ git push origin HEAD:refs/heads/main && { PUSH_SUCCESS="true"; break; }
396
+ echo "Push failed on attempt $attempt"
397
+ sleep $((attempt * 10 + RANDOM % 10))
366
398
  done
399
+ if [ "$PUSH_SUCCESS" != "true" ]; then
400
+ echo "::error::Failed to push after $MAX_RETRIES attempts"
401
+ exit 1
402
+ fi
367
403
 
368
404
  - name: "Verify schedule registered with GitHub"
369
405
  if: github.repository != 'xn-intenton-z2a/agentic-lib' && inputs.schedule != '' && inputs.dry-run != 'true' && inputs.dry-run != true
@@ -440,3 +476,26 @@ jobs:
440
476
  script: |
441
477
  const summary = `## Job: init\n| Key | Value |\n|-----|-------|\n| Status | ${context.job.status || 'completed'} |\n| Mode | ${{ inputs.mode }} |\n| Dry Run | ${{ inputs.dry-run }} |\n| Create Seed Issues | ${{ inputs.create-seed-issues }} |`;
442
478
  core.summary.addRaw(summary).write();
479
+
480
+ # Step 3: Dispatch agentic-lib-workflow to start the first cycle
481
+ dispatch-workflow:
482
+ needs: [params, init]
483
+ if: >-
484
+ !cancelled()
485
+ && needs.init.result == 'success'
486
+ && inputs.dry-run != 'true' && inputs.dry-run != true
487
+ && inputs.run-workflow != 'false' && inputs.run-workflow != false
488
+ && github.repository != 'xn-intenton-z2a/agentic-lib'
489
+ runs-on: ubuntu-latest
490
+ steps:
491
+ - name: Dispatch agentic-lib-workflow
492
+ env:
493
+ GH_TOKEN: ${{ secrets.WORKFLOW_TOKEN }}
494
+ run: |
495
+ echo "Dispatching agentic-lib-workflow to start first cycle..."
496
+ gh workflow run agentic-lib-workflow.yml \
497
+ --repo "${{ github.repository }}" \
498
+ --ref main \
499
+ -f mode=full \
500
+ -f dry-run=false
501
+ echo "Dispatched agentic-lib-workflow"
@@ -104,7 +104,7 @@ jobs:
104
104
  - uses: actions/checkout@v6
105
105
  if: inputs.dry-run == 'true' || inputs.dry-run == true
106
106
  with:
107
- ref: ${{ inputs.ref || github.sha }}
107
+ ref: ${{ inputs.ref || github.ref }}
108
108
  - uses: actions/checkout@v6
109
109
  if: inputs.dry-run != 'true' && inputs.dry-run != true
110
110
  with:
@@ -261,28 +261,57 @@ jobs:
261
261
  FREQUENCY="${{ inputs.frequency }}"
262
262
  MODEL="${{ inputs.model }}"
263
263
  git add .github/workflows/agentic-lib-workflow.yml agentic-lib.toml
264
- # Stage removed mission files if maintenance mode deleted them
265
- git rm --ignore-unmatch MISSION_COMPLETE.md MISSION_FAILED.md 2>/dev/null || true
264
+ # Stage removed mission files ONLY if maintenance mode deleted them
265
+ if [ "$FREQUENCY" = "maintenance" ]; then
266
+ git rm --ignore-unmatch MISSION_COMPLETE.md MISSION_FAILED.md 2>/dev/null || true
267
+ fi
266
268
  git diff --cached --quiet && echo "No changes to commit" && exit 0
267
269
  if [ "$FREQUENCY" = "maintenance" ]; then
268
270
  git commit -m "schedule: switch to maintenance mode (weekly, unlimited budget, mission reset)"
269
271
  else
270
272
  git commit -m "schedule: set to ${FREQUENCY}, model ${MODEL:-gpt-5-mini}"
271
273
  fi
272
- for attempt in 1 2 3; do
273
- # Use HEAD:refs/heads/main to handle detached HEAD state
274
- git push origin HEAD:refs/heads/main && break
275
- echo "Push failed (attempt $attempt) — pulling and retrying"
276
- git pull --rebase origin main || {
277
- echo "Rebase conflict — aborting rebase and retrying"
278
- git rebase --abort 2>/dev/null || true
279
- }
280
- sleep $((attempt * 2))
281
- if [ "$attempt" -eq 3 ]; then
282
- echo "::error::Failed to push after 3 attempts"
283
- exit 1
284
- fi
274
+ MAX_RETRIES=3
275
+ PUSH_SUCCESS=""
276
+ for attempt in $(seq 1 $MAX_RETRIES); do
277
+ # Tiered conflict resolution (mirrors fix-stuck strategy)
278
+ case $attempt in
279
+ 1)
280
+ echo "=== Attempt 1: rebase (cleanest) ==="
281
+ git pull --rebase origin main || {
282
+ echo "Rebase conflict on attempt 1 — aborting rebase"
283
+ git rebase --abort 2>/dev/null || true
284
+ sleep $((10 + RANDOM % 10))
285
+ continue
286
+ }
287
+ ;;
288
+ 2)
289
+ echo "=== Attempt 2: merge (handles non-overlapping changes) ==="
290
+ git pull --no-rebase origin main || {
291
+ echo "Merge conflict on attempt 2 — aborting merge"
292
+ git merge --abort 2>/dev/null || true
293
+ sleep $((20 + RANDOM % 10))
294
+ continue
295
+ }
296
+ ;;
297
+ 3)
298
+ echo "=== Attempt 3: merge -X theirs (accept remote on conflict) ==="
299
+ git pull -X theirs --no-rebase origin main || {
300
+ echo "Merge -X theirs failed on attempt 3"
301
+ git merge --abort 2>/dev/null || true
302
+ sleep $((30 + RANDOM % 10))
303
+ continue
304
+ }
305
+ ;;
306
+ esac
307
+ git push origin HEAD:refs/heads/main && { PUSH_SUCCESS="true"; break; }
308
+ echo "Push failed on attempt $attempt"
309
+ sleep $((attempt * 10 + RANDOM % 10))
285
310
  done
311
+ if [ "$PUSH_SUCCESS" != "true" ]; then
312
+ echo "::error::Failed to push after $MAX_RETRIES attempts"
313
+ exit 1
314
+ fi
286
315
 
287
316
  - name: "Problem 2 fix: Verify schedule registered with GitHub"
288
317
  if: github.repository != 'xn-intenton-z2a/agentic-lib' && inputs.dry-run != 'true' && inputs.dry-run != true
@@ -107,20 +107,47 @@ jobs:
107
107
  git diff --cached --quiet && echo "No changes" && exit 0
108
108
  VERSION=$(npx @xn-intenton-z2a/agentic-lib version 2>/dev/null || echo "latest")
109
109
  git commit -m "update agentic-lib@${VERSION} [skip ci]"
110
- for attempt in 1 2 3; do
111
- # Use HEAD:refs/heads/main to handle detached HEAD state
112
- git push origin HEAD:refs/heads/main && break
113
- echo "Push failed (attempt $attempt) — pulling and retrying"
114
- git pull --rebase origin main || {
115
- echo "Rebase conflict — aborting rebase and retrying"
116
- git rebase --abort 2>/dev/null || true
117
- }
118
- sleep $((attempt * 2))
119
- if [ "$attempt" -eq 3 ]; then
120
- echo "::error::Failed to push after 3 attempts"
121
- exit 1
122
- fi
110
+ MAX_RETRIES=3
111
+ PUSH_SUCCESS=""
112
+ for attempt in $(seq 1 $MAX_RETRIES); do
113
+ # Tiered conflict resolution (mirrors fix-stuck strategy)
114
+ case $attempt in
115
+ 1)
116
+ echo "=== Attempt 1: rebase (cleanest) ==="
117
+ git pull --rebase origin main || {
118
+ echo "Rebase conflict on attempt 1 — aborting rebase"
119
+ git rebase --abort 2>/dev/null || true
120
+ sleep $((10 + RANDOM % 10))
121
+ continue
122
+ }
123
+ ;;
124
+ 2)
125
+ echo "=== Attempt 2: merge (handles non-overlapping changes) ==="
126
+ git pull --no-rebase origin main || {
127
+ echo "Merge conflict on attempt 2 — aborting merge"
128
+ git merge --abort 2>/dev/null || true
129
+ sleep $((20 + RANDOM % 10))
130
+ continue
131
+ }
132
+ ;;
133
+ 3)
134
+ echo "=== Attempt 3: merge -X theirs (accept remote on conflict) ==="
135
+ git pull -X theirs --no-rebase origin main || {
136
+ echo "Merge -X theirs failed on attempt 3"
137
+ git merge --abort 2>/dev/null || true
138
+ sleep $((30 + RANDOM % 10))
139
+ continue
140
+ }
141
+ ;;
142
+ esac
143
+ git push origin HEAD:refs/heads/main && { PUSH_SUCCESS="true"; break; }
144
+ echo "Push failed on attempt $attempt"
145
+ sleep $((attempt * 10 + RANDOM % 10))
123
146
  done
147
+ if [ "$PUSH_SUCCESS" != "true" ]; then
148
+ echo "::error::Failed to push after $MAX_RETRIES attempts"
149
+ exit 1
150
+ fi
124
151
 
125
152
  - name: Job Summary
126
153
  if: always()
@@ -139,7 +139,7 @@ jobs:
139
139
  steps:
140
140
  - uses: actions/checkout@v6
141
141
  with:
142
- ref: ${{ inputs.ref || github.sha }}
142
+ ref: ${{ inputs.ref || github.ref }}
143
143
  sparse-checkout: |
144
144
  ${{ env.configPath }}
145
145
  MISSION_COMPLETE.md
@@ -308,7 +308,7 @@ jobs:
308
308
  steps:
309
309
  - uses: actions/checkout@v6
310
310
  with:
311
- ref: ${{ inputs.ref || github.sha }}
311
+ ref: ${{ inputs.ref || github.ref }}
312
312
 
313
313
  - uses: actions/setup-node@v6
314
314
  with:
@@ -351,7 +351,7 @@ jobs:
351
351
  steps:
352
352
  - uses: actions/checkout@v6
353
353
  with:
354
- ref: ${{ inputs.ref || github.sha }}
354
+ ref: ${{ inputs.ref || github.ref }}
355
355
 
356
356
  - uses: actions/setup-node@v6
357
357
  with:
@@ -623,7 +623,7 @@ jobs:
623
623
  - uses: actions/checkout@v6
624
624
  with:
625
625
  fetch-depth: 0
626
- ref: ${{ inputs.ref || github.sha }}
626
+ ref: ${{ inputs.ref || github.ref }}
627
627
 
628
628
  - name: Fetch log and screenshot from log branch
629
629
  env:
@@ -735,6 +735,7 @@ jobs:
735
735
  with:
736
736
  commit-message: "agentic-step: maintain features and library"
737
737
  push-ref: ${{ github.ref_name }}
738
+ fail-on-conflict: "false"
738
739
 
739
740
  - name: Capture commit SHA
740
741
  id: get-sha
@@ -762,7 +763,7 @@ jobs:
762
763
  - uses: actions/checkout@v6
763
764
  with:
764
765
  fetch-depth: 0
765
- ref: ${{ inputs.ref || github.sha }}
766
+ ref: ${{ inputs.ref || github.ref }}
766
767
 
767
768
  - name: Fetch log and agent logs from log branch
768
769
  env:
@@ -830,7 +831,7 @@ jobs:
830
831
  - uses: actions/checkout@v6
831
832
  with:
832
833
  fetch-depth: 0
833
- ref: ${{ needs.maintain.outputs.commit-sha || github.sha }}
834
+ ref: ${{ needs.maintain.outputs.commit-sha || github.ref }}
834
835
 
835
836
  - name: Fetch log and screenshot from log branch
836
837
  env:
@@ -895,7 +896,7 @@ jobs:
895
896
  - uses: actions/checkout@v6
896
897
  with:
897
898
  fetch-depth: 0
898
- ref: ${{ needs.maintain.outputs.commit-sha || github.sha }}
899
+ ref: ${{ needs.maintain.outputs.commit-sha || github.ref }}
899
900
 
900
901
  - name: Fetch log, screenshot and state from log branch
901
902
  env:
@@ -980,7 +981,7 @@ jobs:
980
981
  - uses: actions/checkout@v6
981
982
  with:
982
983
  fetch-depth: 0
983
- ref: ${{ needs.maintain.outputs.commit-sha || github.sha }}
984
+ ref: ${{ needs.maintain.outputs.commit-sha || github.ref }}
984
985
 
985
986
  - uses: actions/setup-node@v6
986
987
  with:
@@ -1366,7 +1367,7 @@ jobs:
1366
1367
  steps:
1367
1368
  - uses: actions/checkout@v6
1368
1369
  with:
1369
- ref: ${{ needs.maintain.outputs.commit-sha || github.sha }}
1370
+ ref: ${{ needs.maintain.outputs.commit-sha || github.ref }}
1370
1371
 
1371
1372
  - uses: actions/setup-node@v6
1372
1373
  with:
@@ -1421,7 +1422,7 @@ jobs:
1421
1422
  with:
1422
1423
  fetch-depth: 0
1423
1424
  token: ${{ secrets.GITHUB_TOKEN }}
1424
- ref: ${{ needs.maintain.outputs.commit-sha || github.sha }}
1425
+ ref: ${{ needs.maintain.outputs.commit-sha || github.ref }}
1425
1426
 
1426
1427
  - name: Fetch log and screenshot from log branch
1427
1428
  env:
@@ -1722,7 +1723,7 @@ jobs:
1722
1723
  - uses: actions/checkout@v6
1723
1724
  with:
1724
1725
  fetch-depth: 0
1725
- ref: ${{ needs.maintain.outputs.commit-sha || github.sha }}
1726
+ ref: ${{ needs.maintain.outputs.commit-sha || github.ref }}
1726
1727
 
1727
1728
  - name: Summary
1728
1729
  run: |
@@ -1815,7 +1816,7 @@ jobs:
1815
1816
  && needs.params.result == 'success'
1816
1817
  uses: ./.github/workflows/agentic-lib-test.yml
1817
1818
  with:
1818
- ref: ${{ needs.maintain.outputs.commit-sha || github.sha }}
1819
+ ref: ${{ needs.maintain.outputs.commit-sha || github.ref }}
1819
1820
  secrets: inherit
1820
1821
 
1821
1822
  # ─── Schedule change (if requested) ────────────────────────────────
@@ -1824,7 +1825,7 @@ jobs:
1824
1825
  if: ${{ !cancelled() && needs.params.outputs.dry-run != 'true' && needs.params.outputs.schedule != '' && needs.params.result == 'success' }}
1825
1826
  uses: ./.github/workflows/agentic-lib-schedule.yml
1826
1827
  with:
1827
- ref: ${{ needs.maintain.outputs.commit-sha || github.sha }}
1828
+ ref: ${{ needs.maintain.outputs.commit-sha || github.ref }}
1828
1829
  frequency: ${{ needs.params.outputs.schedule }}
1829
1830
  model: ${{ needs.params.outputs.model }}
1830
1831
  profile: ${{ needs.params.outputs.profile }}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xn-intenton-z2a/agentic-lib",
3
- "version": "7.4.27",
3
+ "version": "7.4.29",
4
4
  "description": "Agentic-lib Agentic Coding Systems SDK powering automated GitHub workflows.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -228,14 +228,26 @@ async function executeMissionComplete(octokit, repo, reason) {
228
228
  }
229
229
 
230
230
  // W3: Disable schedule on mission-complete (Benchmark 011 FINDING-4)
231
+ // W6: Skip dispatch if schedule is already at target frequency
231
232
  try {
232
- await octokit.rest.actions.createWorkflowDispatch({
233
- ...repo,
234
- workflow_id: "agentic-lib-schedule.yml",
235
- ref: "main",
236
- inputs: { frequency: "off" },
237
- });
238
- core.info("Dispatched schedule change to off after mission-complete");
233
+ let skipDispatch = false;
234
+ try {
235
+ const tomlContent = readFileSync("agentic-lib.toml", "utf8");
236
+ const supervisorMatch = tomlContent.match(/^\s*supervisor\s*=\s*"([^"]*)"/m);
237
+ if (supervisorMatch && supervisorMatch[1] === "off") {
238
+ core.info("Schedule already off — skipping dispatch");
239
+ skipDispatch = true;
240
+ }
241
+ } catch { /* toml read failed — dispatch anyway */ }
242
+ if (!skipDispatch) {
243
+ await octokit.rest.actions.createWorkflowDispatch({
244
+ ...repo,
245
+ workflow_id: "agentic-lib-schedule.yml",
246
+ ref: "main",
247
+ inputs: { frequency: "off" },
248
+ });
249
+ core.info("Dispatched schedule change to off after mission-complete");
250
+ }
239
251
  } catch (err) {
240
252
  core.warning(`Could not dispatch schedule change: ${err.message}`);
241
253
  }
@@ -315,14 +327,26 @@ async function executeMissionFailed(octokit, repo, reason, metricAssessment) {
315
327
  }
316
328
 
317
329
  // C3: Dispatch schedule change to weekly
330
+ // W6: Skip dispatch if schedule is already at target frequency
318
331
  try {
319
- await octokit.rest.actions.createWorkflowDispatch({
320
- ...repo,
321
- workflow_id: "agentic-lib-schedule.yml",
322
- ref: "main",
323
- inputs: { frequency: "weekly" },
324
- });
325
- core.info("Dispatched schedule change to weekly after mission-failed");
332
+ let skipDispatch = false;
333
+ try {
334
+ const tomlContent = readFileSync("agentic-lib.toml", "utf8");
335
+ const supervisorMatch = tomlContent.match(/^\s*supervisor\s*=\s*"([^"]*)"/m);
336
+ if (supervisorMatch && supervisorMatch[1] === "weekly") {
337
+ core.info("Schedule already weekly — skipping dispatch");
338
+ skipDispatch = true;
339
+ }
340
+ } catch { /* toml read failed — dispatch anyway */ }
341
+ if (!skipDispatch) {
342
+ await octokit.rest.actions.createWorkflowDispatch({
343
+ ...repo,
344
+ workflow_id: "agentic-lib-schedule.yml",
345
+ ref: "main",
346
+ inputs: { frequency: "weekly" },
347
+ });
348
+ core.info("Dispatched schedule change to weekly after mission-failed");
349
+ }
326
350
  } catch (err) {
327
351
  core.warning(`Could not dispatch schedule change: ${err.message}`);
328
352
  }
@@ -16,6 +16,10 @@ inputs:
16
16
  description: "Branch ref to push to (default: current ref_name)"
17
17
  required: false
18
18
  default: ""
19
+ fail-on-conflict:
20
+ description: "Fail the step if push conflicts cannot be resolved (default: true)"
21
+ required: false
22
+ default: "true"
19
23
 
20
24
  runs:
21
25
  using: "composite"
@@ -32,6 +36,13 @@ runs:
32
36
  git reset HEAD -- 'intentïon.md' 'SCREENSHOT_INDEX.png' 2>/dev/null || true
33
37
  git reset HEAD -- agent-log-*.md 2>/dev/null || true
34
38
  git reset HEAD -- agentic-lib-state.toml 2>/dev/null || true
39
+ # W1: Validate test files — reject empty test suites that break vitest
40
+ for f in $(git diff --cached --name-only --diff-filter=ACM -- '*.test.js' '*.test.ts' '*.test.mjs'); do
41
+ if [ -f "$f" ] && ! grep -qE '(describe|test|it)\s*\(' "$f"; then
42
+ echo "::warning::${f} has no test suite (no describe/test/it blocks) — removing from commit"
43
+ git reset HEAD -- "$f"
44
+ fi
45
+ done
35
46
  if git diff --cached --quiet; then
36
47
  echo "No changes to commit"
37
48
  fi
@@ -49,44 +60,75 @@ runs:
49
60
  else
50
61
  REMOTE_REF_EXISTS="true"
51
62
  fi
63
+ # Determine push command based on ref
64
+ if [ -n "$REF" ]; then
65
+ PUSH_CMD="git push origin HEAD:refs/heads/$REF"
66
+ else
67
+ PUSH_CMD="git push"
68
+ fi
69
+ PULL_TARGET="${REF:+origin $REF}"
52
70
  for attempt in $(seq 1 $MAX_RETRIES); do
53
- if [ -n "$REF" ]; then
54
- if [ "$REMOTE_REF_EXISTS" = "true" ]; then
55
- git pull --rebase origin "$REF" || {
56
- echo "Rebase conflict on attempt $attempt aborting rebase and retrying"
71
+ # New branch no pull needed, just push
72
+ if [ -n "$REF" ] && [ "$REMOTE_REF_EXISTS" != "true" ]; then
73
+ $PUSH_CMD && { REMOTE_REF_EXISTS="true"; PUSH_SUCCESS="true"; break; } || true
74
+ sleep $((attempt * 10 + RANDOM % 10))
75
+ continue
76
+ fi
77
+ # Tiered conflict resolution (mirrors fix-stuck strategy)
78
+ case $attempt in
79
+ 1)
80
+ echo "=== Attempt 1: rebase (cleanest) ==="
81
+ git pull --rebase $PULL_TARGET || {
82
+ echo "Rebase conflict on attempt 1 — aborting rebase"
57
83
  git rebase --abort 2>/dev/null || true
58
- sleep $((attempt * 2))
84
+ sleep $((10 + RANDOM % 10))
59
85
  continue
60
86
  }
61
- # After rebase, check if our changes survived (rebase may drop empty commits)
62
- LOCAL_SHA=$(git rev-parse HEAD)
63
- REMOTE_SHA=$(git rev-parse "origin/$REF" 2>/dev/null || echo "")
64
- if [ "$LOCAL_SHA" = "$REMOTE_SHA" ]; then
65
- echo "Rebase dropped local commit (already on remote) nothing to push"
66
- PUSH_SUCCESS="true"
67
- break
68
- fi
87
+ ;;
88
+ 2)
89
+ echo "=== Attempt 2: merge (handles non-overlapping changes) ==="
90
+ git pull --no-rebase $PULL_TARGET || {
91
+ echo "Merge conflict on attempt 2aborting merge"
92
+ git merge --abort 2>/dev/null || true
93
+ sleep $((20 + RANDOM % 10))
94
+ continue
95
+ }
96
+ ;;
97
+ 3)
98
+ echo "=== Attempt 3: merge -X theirs (accept remote on conflict) ==="
99
+ git pull -X theirs --no-rebase $PULL_TARGET || {
100
+ echo "Merge -X theirs failed on attempt 3"
101
+ git merge --abort 2>/dev/null || true
102
+ sleep $((30 + RANDOM % 10))
103
+ continue
104
+ }
105
+ ;;
106
+ esac
107
+ # Check if rebase/merge dropped our commit (already on remote)
108
+ if [ -n "$REF" ]; then
109
+ LOCAL_SHA=$(git rev-parse HEAD)
110
+ REMOTE_SHA=$(git rev-parse "origin/$REF" 2>/dev/null || echo "")
111
+ if [ "$LOCAL_SHA" = "$REMOTE_SHA" ]; then
112
+ echo "Rebase/merge dropped local commit (already on remote) — nothing to push"
113
+ PUSH_SUCCESS="true"
114
+ break
69
115
  fi
70
- # Use HEAD:refs/heads/$REF to handle detached HEAD state
71
- # (actions/checkout with a SHA puts us in detached HEAD, so
72
- # "git push origin main" fails with "src refspec main does not match any")
73
- git push origin "HEAD:refs/heads/$REF" && { REMOTE_REF_EXISTS="true"; PUSH_SUCCESS="true"; break; }
74
- else
75
- git pull --rebase || {
76
- echo "Rebase conflict on attempt $attempt — aborting rebase and retrying"
77
- git rebase --abort 2>/dev/null || true
78
- sleep $((attempt * 2))
79
- continue
80
- }
81
- git push && { PUSH_SUCCESS="true"; break; }
82
116
  fi
83
- echo "Push failed on attempt $attempt, retrying..."
84
- sleep $((attempt * 2))
117
+ $PUSH_CMD && { REMOTE_REF_EXISTS="true"; PUSH_SUCCESS="true"; break; }
118
+ echo "Push failed on attempt $attempt"
119
+ sleep $((attempt * 10 + RANDOM % 10))
85
120
  done
86
121
  # Restore stashed unstaged changes
87
122
  git stash pop 2>/dev/null || true
88
123
  if [ "$PUSH_SUCCESS" != "true" ]; then
89
- echo "::error::Failed to push after $MAX_RETRIES attempts"
90
- exit 1
124
+ FAIL_ON_CONFLICT="${{ inputs.fail-on-conflict }}"
125
+ if [ "$FAIL_ON_CONFLICT" = "false" ]; then
126
+ echo "::warning::Failed to push after $MAX_RETRIES attempts — skipping (fail-on-conflict=false)"
127
+ git rebase --abort 2>/dev/null || true
128
+ git merge --abort 2>/dev/null || true
129
+ else
130
+ echo "::error::Failed to push after $MAX_RETRIES attempts"
131
+ exit 1
132
+ fi
91
133
  fi
92
134
  fi
@@ -17,7 +17,7 @@
17
17
  "author": "",
18
18
  "license": "MIT",
19
19
  "dependencies": {
20
- "@xn-intenton-z2a/agentic-lib": "^7.4.27"
20
+ "@xn-intenton-z2a/agentic-lib": "^7.4.29"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@playwright/test": "^1.58.0",