opencode-mad 0.3.10 → 0.3.11

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.
@@ -579,6 +579,42 @@ Celebrate! The project is clean.
579
579
 
580
580
  ---
581
581
 
582
+ ## Phase 6: Push & CI Watch
583
+
584
+ After all checks pass, push and watch CI:
585
+
586
+ ```
587
+ mad_push_and_watch()
588
+ ```
589
+
590
+ This will:
591
+ 1. Push changes to the remote
592
+ 2. Detect if GitHub Actions CI exists
593
+ 3. Watch CI progress with `gh run watch`
594
+ 4. Report success or failure
595
+
596
+ ### If CI fails:
597
+ Create a fix worktree:
598
+ ```
599
+ mad_worktree_create(
600
+ branch: "fix-ci",
601
+ task: "Fix CI failures:
602
+ [error details from mad_push_and_watch]
603
+
604
+ YOU OWN ALL FILES."
605
+ )
606
+
607
+ Task(
608
+ subagent_type: "mad-fixer",
609
+ description: "Fix CI",
610
+ prompt: "Fix the CI errors, commit, and call mad_done."
611
+ )
612
+ ```
613
+
614
+ Then merge, push again, and watch until CI passes.
615
+
616
+ ---
617
+
582
618
  ## Available Tools
583
619
 
584
620
  | Tool | Description |
@@ -594,6 +630,7 @@ Celebrate! The project is clean.
594
630
  | `mad_read_task` | Read task description |
595
631
  | `mad_log` | Log events for debugging |
596
632
  | `mad_final_check` | Run global build/lint and categorize errors |
633
+ | `mad_push_and_watch` | Push to remote and watch CI |
597
634
 
598
635
  ## Subagents
599
636
 
@@ -731,6 +768,11 @@ Task(
731
768
  ║ → Run mad_cleanup() for ALL worktrees ║
732
769
  ║ → Verify with mad_status() that worktree list is empty ║
733
770
  ║ ║
771
+ ║ □ 5. PUSHED AND CI PASSED? ║
772
+ ║ → Run mad_push_and_watch() after cleanup ║
773
+ ║ → If CI fails, create fix-ci worktree and fix ║
774
+ ║ → Re-push until CI passes ║
775
+ ║ ║
734
776
  ╚══════════════════════════════════════════════════════════════════════════════╝
735
777
  ```
736
778
 
@@ -759,7 +801,9 @@ Task(
759
801
  5. mad_final_check() → Re-verify (repeat until clean)
760
802
  6. mad_cleanup() x N → Remove all worktrees
761
803
  7. mad_status() → Confirm worktree list is empty
762
- 8. Report to user NOW you can say "DONE" 🎉
804
+ 8. mad_push_and_watch() Push to remote and watch CI
805
+ 9. [If CI fails] Fix it → Create fix-ci worktree, fix, merge, re-push
806
+ 10. Report to user → NOW you can say "DONE" 🎉
763
807
  ```
764
808
 
765
809
  > **🚨 IF YOU DECLARE "DONE" WITHOUT COMPLETING THIS CHECKLIST, YOU HAVE FAILED! 🚨**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-mad",
3
- "version": "0.3.10",
3
+ "version": "0.3.11",
4
4
  "description": "Multi-Agent Dev - Parallel development orchestration plugin for OpenCode",
5
5
  "type": "module",
6
6
  "main": "plugins/mad-plugin.ts",
@@ -13,7 +13,7 @@ import { execSync } from "child_process"
13
13
  */
14
14
 
15
15
  // Current version of opencode-mad
16
- const CURRENT_VERSION = "0.3.8"
16
+ const CURRENT_VERSION = "0.3.11"
17
17
 
18
18
  // Update notification state (shown only once per session)
19
19
  let updateNotificationShown = false
@@ -729,6 +729,126 @@ Latest version: ${updateInfo.latest}`
729
729
  },
730
730
  }),
731
731
 
732
+ /**
733
+ * Push and watch CI
734
+ */
735
+ mad_push_and_watch: tool({
736
+ description: `Push changes to remote and watch CI if it exists.
737
+ After all merges and final checks, this pushes to the remote and monitors GitHub Actions.
738
+ Uses 'gh run watch' to follow CI progress in real-time.
739
+ If CI fails, returns error details for the orchestrator to spawn a fixer.`,
740
+ args: {
741
+ createFixWorktree: tool.schema.boolean().optional().describe("If true and CI fails, automatically suggest creating a fix-ci worktree"),
742
+ },
743
+ async execute(args, context) {
744
+ try {
745
+ const gitRoot = getGitRoot()
746
+ let report = getUpdateNotification() + "# Push & CI Watch\n\n"
747
+
748
+ // 1. Check if we have a remote
749
+ const remoteResult = runCommand("git remote get-url origin", gitRoot)
750
+ if (!remoteResult.success) {
751
+ return report + "⚠️ No remote 'origin' configured. Skipping push."
752
+ }
753
+
754
+ // 2. Get current branch
755
+ const branch = getCurrentBranch()
756
+ report += `📍 Branch: \`${branch}\`\n\n`
757
+
758
+ // 3. Check if upstream exists, if not set it
759
+ const upstreamResult = runCommand(`git rev-parse --abbrev-ref ${branch}@{upstream}`, gitRoot)
760
+
761
+ // 4. Push
762
+ report += "## 🚀 Pushing to remote...\n"
763
+ const pushCmd = upstreamResult.success
764
+ ? "git push"
765
+ : `git push -u origin ${branch}`
766
+
767
+ const pushResult = runCommand(pushCmd, gitRoot)
768
+ if (!pushResult.success) {
769
+ return report + `❌ Push failed:\n\`\`\`\n${pushResult.error}\n\`\`\`\n\nFix the issue and try again.`
770
+ }
771
+ report += "✅ Push successful!\n\n"
772
+
773
+ // 5. Check if gh CLI is available
774
+ const ghCheck = runCommand("gh --version", gitRoot)
775
+ if (!ghCheck.success) {
776
+ return report + "⚠️ GitHub CLI (gh) not installed. Cannot watch CI.\n\nInstall with: https://cli.github.com/"
777
+ }
778
+
779
+ // 6. Check for running/pending workflow runs
780
+ report += "## 🔍 Checking for CI workflows...\n"
781
+ const runsResult = runCommand(
782
+ `gh run list --branch ${branch} --limit 1 --json databaseId,status,conclusion,name,event`,
783
+ gitRoot
784
+ )
785
+
786
+ if (!runsResult.success) {
787
+ return report + "⚠️ Could not check CI status. You may not be authenticated with `gh auth login`."
788
+ }
789
+
790
+ let runs: any[] = []
791
+ try {
792
+ runs = JSON.parse(runsResult.output)
793
+ } catch {
794
+ return report + "⚠️ No CI workflows found for this repository.\n\n✅ Push complete (no CI to watch)."
795
+ }
796
+
797
+ if (runs.length === 0) {
798
+ return report + "ℹ️ No CI workflows found for this branch.\n\n✅ Push complete!"
799
+ }
800
+
801
+ const latestRun = runs[0]
802
+ report += `Found workflow: **${latestRun.name}** (${latestRun.event})\n\n`
803
+
804
+ // 7. If already completed, just report status
805
+ if (latestRun.status === "completed") {
806
+ if (latestRun.conclusion === "success") {
807
+ return report + `✅ CI already passed! (${latestRun.name})\n\n🎉 All done!`
808
+ } else {
809
+ report += `❌ CI failed with conclusion: ${latestRun.conclusion}\n\n`
810
+ report += "Use `gh run view --log-failed` to see error details.\n"
811
+ if (args.createFixWorktree) {
812
+ report += "\n💡 **Suggestion:** Create a `fix-ci` worktree to fix the CI errors."
813
+ }
814
+ return report
815
+ }
816
+ }
817
+
818
+ // 8. Watch the CI run in real-time
819
+ report += "## ⏳ Watching CI...\n"
820
+ report += `Running: \`gh run watch ${latestRun.databaseId}\`\n\n`
821
+
822
+ // Use gh run watch (this blocks until complete)
823
+ const watchResult = runCommand(
824
+ `gh run watch ${latestRun.databaseId} --exit-status`,
825
+ gitRoot
826
+ )
827
+
828
+ if (watchResult.success) {
829
+ return report + `✅ CI passed!\n\n\`\`\`\n${watchResult.output.slice(-500)}\n\`\`\`\n\n🎉 All done!`
830
+ } else {
831
+ report += `❌ CI failed!\n\n\`\`\`\n${(watchResult.error || watchResult.output).slice(-1000)}\n\`\`\`\n\n`
832
+
833
+ // Get failed logs
834
+ const logsResult = runCommand(`gh run view ${latestRun.databaseId} --log-failed`, gitRoot)
835
+ if (logsResult.success && logsResult.output) {
836
+ report += `### Failed logs:\n\`\`\`\n${logsResult.output.slice(-2000)}\n\`\`\`\n\n`
837
+ }
838
+
839
+ if (args.createFixWorktree) {
840
+ report += "💡 **Recommendation:** Create a `fix-ci` worktree to fix these errors."
841
+ }
842
+
843
+ return report
844
+ }
845
+ } catch (e: any) {
846
+ logEvent("error", "mad_push_and_watch exception", { error: e.message })
847
+ return getUpdateNotification() + `❌ Error: ${e.message}`
848
+ }
849
+ }
850
+ }),
851
+
732
852
  /**
733
853
  * Final check - run global build/lint and categorize errors
734
854
  */
@@ -112,6 +112,19 @@ mad_final_check()
112
112
  ```
113
113
  This distinguishes session errors from pre-existing issues.
114
114
 
115
+ ### 9. Push & CI Watch
116
+ Push to remote and monitor CI:
117
+ ```
118
+ mad_push_and_watch()
119
+ ```
120
+ This will:
121
+ - Push changes to the remote
122
+ - Detect if GitHub Actions CI exists
123
+ - Watch CI progress in real-time with `gh run watch`
124
+ - Report success or failure with logs
125
+
126
+ If CI fails, create a `fix-ci` worktree to fix the errors.
127
+
115
128
  ## Best Practices
116
129
 
117
130
  1. **Keep subtasks focused** - Each should be completable in one session
@@ -134,6 +147,7 @@ This distinguishes session errors from pre-existing issues.
134
147
  | `mad_blocked` | Mark task blocked |
135
148
  | `mad_read_task` | Read task description |
136
149
  | `mad_final_check` | Run global build/lint and categorize errors |
150
+ | `mad_push_and_watch` | Push to remote and watch CI |
137
151
 
138
152
  ## Example
139
153