opencode-mad 0.3.0 → 0.3.2

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/README.md CHANGED
@@ -1,235 +1,238 @@
1
- # opencode-mad
2
-
3
- **Multi-Agent Dev (MAD)** - Parallel development orchestration plugin for [OpenCode](https://opencode.ai).
4
-
5
- Decompose complex tasks into parallelizable subtasks, each running in isolated git worktrees with dedicated AI subagents.
6
-
7
- ## Features
8
-
9
- - **Smart Planning** - Orchestrator asks clarifying questions before coding
10
- - **File Ownership** - Each agent has exclusive files, preventing merge conflicts
11
- - **Parallel Execution** - Multiple developers work simultaneously in git worktrees
12
- - **Automated Testing** - Tester agent validates code before merge
13
- - **Conflict Resolution** - Dedicated merger agent handles git conflicts
14
- - **Integration Fixes** - Fixer agent ensures everything works together
15
-
16
- ## Installation
17
-
18
- ### Option 1: npx (Recommended)
19
-
20
- ```bash
21
- # Install to current project
22
- npx opencode-mad install
23
-
24
- # Or install globally (all projects)
25
- npx opencode-mad install -g
26
- ```
27
-
28
- ### Option 2: Manual copy
29
-
30
- ```bash
31
- # Clone the repo
32
- git clone https://github.com/Nistro-dev/opencode-mad.git
33
-
34
- # Copy to your project
35
- cp -r opencode-mad/agents your-project/.opencode/
36
- cp -r opencode-mad/commands your-project/.opencode/
37
- cp -r opencode-mad/plugins your-project/.opencode/
38
- cp -r opencode-mad/skills your-project/.opencode/
39
-
40
- # Or copy globally
41
- cp -r opencode-mad/agents ~/.config/opencode/agents/
42
- cp -r opencode-mad/commands ~/.config/opencode/commands/
43
- cp -r opencode-mad/plugins ~/.config/opencode/plugins/
44
- cp -r opencode-mad/skills ~/.config/opencode/skills/
45
- ```
46
-
47
- ### Project structure after installation
48
-
49
- ```
50
- your-project/
51
- ├── .opencode/
52
- │ ├── agents/
53
- │ │ ├── orchestrator.md # Main coordinator
54
- │ │ ├── mad-developer.md # Implements features
55
- │ │ ├── mad-tester.md # Tests before merge
56
- │ │ ├── mad-merger.md # Resolves conflicts
57
- │ │ └── mad-fixer.md # Fixes integration
58
- │ ├── commands/
59
- │ ├── plugins/
60
- │ │ └── mad-plugin.ts
61
- └── skills/
62
- └── ... your code
63
- ```
64
-
65
- ## Usage
66
-
67
- Once installed, just talk to the orchestrator naturally:
68
-
69
- ```
70
- You: Create a Task Timer app with Express backend and React frontend
71
-
72
- Orchestrator: Before I create the development plan, I need to clarify:
73
- 1. Database: SQLite, PostgreSQL, or in-memory?
74
- 2. Authentication needed?
75
- 3. Dark mode or light mode?
76
- ...
77
-
78
- You: SQLite, no auth, dark mode
79
-
80
- Orchestrator: Here's the development plan:
81
- [Shows plan with file ownership]
82
-
83
- Ready to proceed? Reply "GO"
84
-
85
- You: GO
86
-
87
- Orchestrator: [Creates worktrees, spawns developers in parallel...]
88
- ```
89
-
90
- ### Commands (Optional)
91
-
92
- | Command | Description |
93
- |---------|-------------|
94
- | `/mad <task>` | Start parallel orchestration |
95
- | `/mad-status` | Show worktree status |
96
- | `/mad-visualize` | ASCII dashboard |
97
- | `/mad-fix <worktree>` | Fix errors in a worktree |
98
- | `/mad-merge-all` | Merge all completed worktrees |
99
-
100
- ### Reporting Bugs
101
-
102
- Just tell the orchestrator about the bug - it will delegate to a fixer:
103
-
104
- ```
105
- You: There's a CORS error, the frontend can't reach the backend
106
-
107
- Orchestrator: I'll spawn a fixer to resolve this.
108
- [Delegates to mad-fixer]
109
- ```
110
-
111
- ## How It Works
112
-
113
- ```
114
- ┌─────────────────────────────────────────────────────────────┐
115
- │ You: "Create a full-stack app..." │
116
- └─────────────────────────────────────────────────────────────┘
117
-
118
-
119
- ┌─────────────────────────────────────────────────────────────┐
120
- │ ORCHESTRATOR (primary agent) │
121
- - Asks clarifying questions
122
- │ - Creates plan with file ownership │
123
- - Waits for "GO" │
124
- └─────────────────────────────────────────────────────────────┘
125
- │ "GO"
126
-
127
- ┌─────────────────────────────────────────────────────────────┐
128
- DEVELOPERS (parallel in git worktrees)
129
- ┌──────────┐ ┌──────────┐ ┌──────────┐
130
- │ │ Backend │ │ Frontend │ │ Config │ │
131
- /backend │ │ /frontend│ │ /root │ │
132
- │ └──────────┘ └──────────┘ └──────────┘ │
133
- │ Each owns exclusive files - no conflicts! │
134
- └─────────────────────────────────────────────────────────────┘
135
-
136
-
137
- ┌─────────────────────────────────────────────────────────────┐
138
- TESTERS (parallel)
139
- - Test APIs with curl
140
- │ - Check frontend for errors │
141
- - Verify integration │
142
- │ - Fix simple bugs or block if major issues │
143
- └─────────────────────────────────────────────────────────────┘
144
-
145
-
146
- ┌─────────────────────────────────────────────────────────────┐
147
- MERGER (if conflicts)
148
- │ - Understands both branches' intent
149
- │ - Combines functionality intelligently │
150
- └─────────────────────────────────────────────────────────────┘
151
-
152
-
153
- ┌─────────────────────────────────────────────────────────────┐
154
- FIXER (if integration issues)
155
- │ - Fixes cross-component bugs
156
- │ - Ensures frontend + backend work together │
157
- └─────────────────────────────────────────────────────────────┘
158
-
159
-
160
- DONE!
161
- ```
162
-
163
- ## Agents
164
-
165
- | Agent | Mode | Description |
166
- |-------|------|-------------|
167
- | `orchestrator` | primary | Coordinates workflow, asks questions, creates plans. **Never codes directly.** |
168
- | `mad-developer` | subagent | Implements tasks in isolated worktrees |
169
- | `mad-tester` | subagent | Tests code before merge |
170
- | `mad-merger` | subagent | Resolves git merge conflicts |
171
- | `mad-fixer` | subagent | Fixes integration issues |
172
-
173
- ## Custom Tools
174
-
175
- The plugin provides these tools:
176
-
177
- | Tool | Description |
178
- |------|-------------|
179
- | `mad_worktree_create` | Create isolated git worktree |
180
- | `mad_status` | Get status of all worktrees |
181
- | `mad_visualize` | ASCII art dashboard |
182
- | `mad_test` | Run tests on a worktree |
183
- | `mad_merge` | Merge completed worktree |
184
- | `mad_cleanup` | Remove finished worktree |
185
- | `mad_done` | Mark task as completed |
186
- | `mad_blocked` | Mark task as blocked |
187
- | `mad_read_task` | Read task description |
188
- | `mad_log` | Log orchestration events |
189
-
190
- ## File Ownership System
191
-
192
- The key to avoiding merge conflicts is **explicit file ownership**:
193
-
194
- ```
195
- Task 1 (backend):
196
- OWNS: /backend/**
197
- CANNOT TOUCH: /frontend/**, /package.json
198
-
199
- Task 2 (frontend):
200
- OWNS: /frontend/**
201
- CANNOT TOUCH: /backend/**, /package.json
202
-
203
- Task 3 (config):
204
- OWNS: /package.json, /README.md, /.gitignore
205
- CANNOT TOUCH: /backend/**, /frontend/**
206
- ```
207
-
208
- ## Requirements
209
-
210
- - [OpenCode](https://opencode.ai) 1.0+
211
- - Git (for worktrees)
212
- - Node.js 18+
213
-
214
- ## Configuration
215
-
216
- The orchestrator uses these defaults:
217
- - Model: `anthropic/claude-opus-4-5`
218
- - Never pushes automatically (only commits)
219
- - Always asks questions before planning
220
-
221
- To change the model, edit `.opencode/agents/orchestrator.md`:
222
-
223
- ```yaml
224
- ---
225
- model: anthropic/claude-sonnet-4-20250514
226
- ---
227
- ```
228
-
229
- ## License
230
-
231
- MIT
232
-
233
- ## Contributing
234
-
235
- Issues and PRs welcome at [github.com/Nistro-dev/opencode-mad](https://github.com/Nistro-dev/opencode-mad)
1
+ # opencode-mad
2
+
3
+ **Multi-Agent Dev (MAD)** - Parallel development orchestration plugin for [OpenCode](https://opencode.ai).
4
+
5
+ Decompose complex tasks into parallelizable subtasks, each running in isolated git worktrees with dedicated AI subagents.
6
+
7
+ ## Features
8
+
9
+ - **Smart Planning** - Orchestrator asks clarifying questions before coding
10
+ - **File Ownership** - Each agent has exclusive files, preventing merge conflicts
11
+ - **Parallel Execution** - Multiple developers work simultaneously in git worktrees
12
+ - **Automated Testing** - Tester agent validates code before merge
13
+ - **Conflict Resolution** - Dedicated merger agent handles git conflicts
14
+ - **Integration Fixes** - Fixer agent ensures everything works together
15
+
16
+ ## Installation
17
+
18
+ ### Option 1: npx (Recommended)
19
+
20
+ ```bash
21
+ # Install to current project
22
+ npx opencode-mad install
23
+
24
+ # Or install globally (all projects)
25
+ npx opencode-mad install -g
26
+
27
+ # Update existing installation
28
+ npx opencode-mad update -g
29
+
30
+ # Check version
31
+ npx opencode-mad version
32
+ ```
33
+
34
+ ### Option 2: Manual copy
35
+
36
+ ```bash
37
+ # Clone the repo
38
+ git clone https://github.com/Nistro-dev/opencode-mad.git
39
+
40
+ # Copy to your project
41
+ cp -r opencode-mad/agents your-project/.opencode/
42
+ cp -r opencode-mad/commands your-project/.opencode/
43
+ cp -r opencode-mad/plugins your-project/.opencode/
44
+ cp -r opencode-mad/skills your-project/.opencode/
45
+
46
+ # Or copy globally
47
+ cp -r opencode-mad/agents ~/.config/opencode/agents/
48
+ cp -r opencode-mad/commands ~/.config/opencode/commands/
49
+ cp -r opencode-mad/plugins ~/.config/opencode/plugins/
50
+ cp -r opencode-mad/skills ~/.config/opencode/skills/
51
+ ```
52
+
53
+ ### Project structure after installation
54
+
55
+ ```
56
+ your-project/
57
+ ├── .opencode/
58
+ │ ├── agents/
59
+ ├── orchestrator.md # Main coordinator
60
+ │ │ ├── mad-developer.md # Implements features
61
+ │ ├── mad-tester.md # Tests before merge
62
+ │ │ ├── mad-merger.md # Resolves conflicts
63
+ │ │ └── mad-fixer.md # Fixes integration
64
+ │ ├── commands/
65
+ │ ├── plugins/
66
+ │ │ └── mad-plugin.ts
67
+ │ └── skills/
68
+ └── ... your code
69
+ ```
70
+
71
+ ## Usage
72
+
73
+ Once installed, just talk to the orchestrator naturally:
74
+
75
+ ```
76
+ You: Create a Task Timer app with Express backend and React frontend
77
+
78
+ Orchestrator: Before I create the development plan, I need to clarify:
79
+ 1. Database: SQLite, PostgreSQL, or in-memory?
80
+ 2. Authentication needed?
81
+ 3. Dark mode or light mode?
82
+ ...
83
+
84
+ You: SQLite, no auth, dark mode
85
+
86
+ Orchestrator: Here's the development plan:
87
+ [Shows plan with file ownership]
88
+
89
+ Ready to proceed? Reply "GO"
90
+
91
+ You: GO
92
+
93
+ Orchestrator: [Creates worktrees, spawns developers in parallel...]
94
+ ```
95
+
96
+ ### Commands (Optional)
97
+
98
+ | Command | Description |
99
+ |---------|-------------|
100
+ | `/mad <task>` | Start parallel orchestration |
101
+ | `/mad-status` | Show worktree status |
102
+ | `/mad-visualize` | ASCII dashboard |
103
+ | `/mad-fix <worktree>` | Fix errors in a worktree |
104
+ | `/mad-merge-all` | Merge all completed worktrees |
105
+
106
+ ### Reporting Bugs
107
+
108
+ Just tell the orchestrator about the bug - it will delegate to a fixer:
109
+
110
+ ```
111
+ You: There's a CORS error, the frontend can't reach the backend
112
+
113
+ Orchestrator: I'll spawn a fixer to resolve this.
114
+ [Delegates to mad-fixer]
115
+ ```
116
+
117
+ ## How It Works
118
+
119
+ ```
120
+ ┌─────────────────────────────────────────────────────────────┐
121
+ You: "Create a full-stack app..."
122
+ └─────────────────────────────────────────────────────────────┘
123
+
124
+
125
+ ┌─────────────────────────────────────────────────────────────┐
126
+ │ ORCHESTRATOR (primary agent) │
127
+ │ - Asks clarifying questions │
128
+ - Creates plan with file ownership
129
+ - Waits for "GO"
130
+ └─────────────────────────────────────────────────────────────┘
131
+ "GO"
132
+
133
+ ┌─────────────────────────────────────────────────────────────┐
134
+ │ DEVELOPERS (parallel in git worktrees) │
135
+ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
136
+ │ │ Backend │ │ Frontend │ │ Config │ │
137
+ │ │ /backend │ │ /frontend│ │ /root │ │
138
+ └──────────┘ └──────────┘ └──────────┘
139
+ Each owns exclusive files - no conflicts!
140
+ └─────────────────────────────────────────────────────────────┘
141
+
142
+
143
+ ┌─────────────────────────────────────────────────────────────┐
144
+ TESTERS (parallel) │
145
+ │ - Test APIs with curl │
146
+ │ - Check frontend for errors │
147
+ - Verify integration
148
+ │ - Fix simple bugs or block if major issues
149
+ └─────────────────────────────────────────────────────────────┘
150
+
151
+
152
+ ┌─────────────────────────────────────────────────────────────┐
153
+ │ MERGER (if conflicts) │
154
+ - Understands both branches' intent
155
+ │ - Combines functionality intelligently
156
+ └─────────────────────────────────────────────────────────────┘
157
+
158
+
159
+ ┌─────────────────────────────────────────────────────────────┐
160
+ │ FIXER (if integration issues) │
161
+ │ - Fixes cross-component bugs │
162
+ │ - Ensures frontend + backend work together │
163
+ └─────────────────────────────────────────────────────────────┘
164
+
165
+
166
+ DONE!
167
+ ```
168
+
169
+ ## Agents
170
+
171
+ | Agent | Mode | Description |
172
+ |-------|------|-------------|
173
+ | `orchestrator` | primary | Coordinates workflow, asks questions, creates plans. **Never codes directly.** |
174
+ | `mad-developer` | subagent | Implements tasks in isolated worktrees |
175
+ | `mad-tester` | subagent | Tests code before merge |
176
+ | `mad-merger` | subagent | Resolves git merge conflicts |
177
+ | `mad-fixer` | subagent | Fixes integration issues |
178
+
179
+ ## Custom Tools
180
+
181
+ The plugin provides these tools:
182
+
183
+ | Tool | Description |
184
+ |------|-------------|
185
+ | `mad_worktree_create` | Create isolated git worktree |
186
+ | `mad_status` | Get status of all worktrees |
187
+ | `mad_visualize` | ASCII art dashboard |
188
+ | `mad_test` | Run tests on a worktree |
189
+ | `mad_merge` | Merge completed worktree |
190
+ | `mad_cleanup` | Remove finished worktree |
191
+ | `mad_done` | Mark task as completed |
192
+ | `mad_blocked` | Mark task as blocked |
193
+ | `mad_read_task` | Read task description |
194
+ | `mad_log` | Log orchestration events |
195
+ | `mad_check_update` | Check for plugin updates |
196
+
197
+ ## Updates
198
+
199
+ opencode-mad checks for updates automatically and notifies you when a new version is available.
200
+
201
+ To update manually:
202
+ ```bash
203
+ npx opencode-mad update -g
204
+ ```
205
+
206
+ To check for updates:
207
+ ```bash
208
+ npx opencode-mad version
209
+ ```
210
+
211
+ ## Requirements
212
+
213
+ - [OpenCode](https://opencode.ai) 1.0+
214
+ - Git (for worktrees)
215
+ - Node.js 18+
216
+
217
+ ## Configuration
218
+
219
+ The orchestrator uses these defaults:
220
+ - Model: `anthropic/claude-opus-4-5`
221
+ - Never pushes automatically (only commits)
222
+ - Always asks questions before planning
223
+
224
+ To change the model, edit `.opencode/agents/orchestrator.md`:
225
+
226
+ ```yaml
227
+ ---
228
+ model: anthropic/claude-sonnet-4-20250514
229
+ ---
230
+ ```
231
+
232
+ ## License
233
+
234
+ MIT
235
+
236
+ ## Contributing
237
+
238
+ Issues and PRs welcome at [github.com/Nistro-dev/opencode-mad](https://github.com/Nistro-dev/opencode-mad)
package/install.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  /**
4
4
  * opencode-mad installer
package/package.json CHANGED
@@ -1,36 +1,36 @@
1
- {
2
- "name": "opencode-mad",
3
- "version": "0.3.0",
4
- "description": "Multi-Agent Dev - Parallel development orchestration plugin for OpenCode",
5
- "type": "module",
6
- "main": "plugins/mad-plugin.ts",
7
- "bin": {
8
- "opencode-mad": "./install.js"
9
- },
10
- "files": [
11
- "agents",
12
- "commands",
13
- "plugins",
14
- "skills",
15
- "install.js"
16
- ],
17
- "dependencies": {
18
- "@opencode-ai/plugin": "^1.1.34"
19
- },
20
- "keywords": [
21
- "opencode",
22
- "plugin",
23
- "multi-agent",
24
- "parallel-development",
25
- "git-worktree",
26
- "ai",
27
- "orchestration"
28
- ],
29
- "author": "Nistro-dev",
30
- "license": "MIT",
31
- "repository": {
32
- "type": "git",
33
- "url": "https://github.com/Nistro-dev/opencode-mad"
34
- },
35
- "homepage": "https://github.com/Nistro-dev/opencode-mad#readme"
36
- }
1
+ {
2
+ "name": "opencode-mad",
3
+ "version": "0.3.2",
4
+ "description": "Multi-Agent Dev - Parallel development orchestration plugin for OpenCode",
5
+ "type": "module",
6
+ "main": "plugins/mad-plugin.ts",
7
+ "bin": {
8
+ "opencode-mad": "./install.js"
9
+ },
10
+ "files": [
11
+ "agents",
12
+ "commands",
13
+ "plugins",
14
+ "skills",
15
+ "install.js"
16
+ ],
17
+ "dependencies": {
18
+ "@opencode-ai/plugin": "^1.1.34"
19
+ },
20
+ "keywords": [
21
+ "opencode",
22
+ "plugin",
23
+ "multi-agent",
24
+ "parallel-development",
25
+ "git-worktree",
26
+ "ai",
27
+ "orchestration"
28
+ ],
29
+ "author": "Nistro-dev",
30
+ "license": "MIT",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/Nistro-dev/opencode-mad"
34
+ },
35
+ "homepage": "https://github.com/Nistro-dev/opencode-mad#readme"
36
+ }
@@ -13,7 +13,11 @@ import { execSync } from "child_process"
13
13
  */
14
14
 
15
15
  // Current version of opencode-mad
16
- const CURRENT_VERSION = "0.3.0"
16
+ const CURRENT_VERSION = "0.3.2"
17
+
18
+ // Update notification state (shown only once per session)
19
+ let updateNotificationShown = false
20
+ let pendingUpdateMessage: string | null = null
17
21
 
18
22
  export const MADPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
19
23
 
@@ -97,18 +101,28 @@ export const MADPlugin: Plugin = async ({ project, client, $, directory, worktre
97
101
  return { hasUpdate: false, current: CURRENT_VERSION, latest: CURRENT_VERSION }
98
102
  }
99
103
 
100
- // Check for updates at plugin initialization
104
+ // Check for updates at plugin initialization and store message for first tool response
101
105
  try {
102
106
  const updateInfo = await checkForUpdates()
103
107
  if (updateInfo.hasUpdate) {
104
- console.log(`\n🔄 opencode-mad update available: ${updateInfo.current} → ${updateInfo.latest}`)
105
- console.log(` Run: npx opencode-mad install -g\n`)
108
+ pendingUpdateMessage = `🔄 **Update available!** opencode-mad ${updateInfo.current} → ${updateInfo.latest}\n Run: \`npx opencode-mad install -g\`\n\n`
106
109
  logEvent("info", "Update available", { current: updateInfo.current, latest: updateInfo.latest })
107
110
  }
108
111
  } catch (e) {
109
112
  // Silent fail - don't break plugin initialization
110
113
  }
111
114
 
115
+ /**
116
+ * Helper to get update notification (returns message only once)
117
+ */
118
+ const getUpdateNotification = (): string => {
119
+ if (pendingUpdateMessage && !updateNotificationShown) {
120
+ updateNotificationShown = true
121
+ return pendingUpdateMessage
122
+ }
123
+ return ""
124
+ }
125
+
112
126
  return {
113
127
  // Custom tools for MAD workflow
114
128
  tool: {
@@ -131,12 +145,12 @@ Each worktree has its own branch and working directory.`,
131
145
  // Validate inputs
132
146
  if (!branch || branch.trim() === "") {
133
147
  logEvent("error", "mad_worktree_create failed: empty branch name")
134
- return "❌ Error: Branch name cannot be empty"
148
+ return getUpdateNotification() + "❌ Error: Branch name cannot be empty"
135
149
  }
136
150
 
137
151
  if (!task || task.trim() === "") {
138
152
  logEvent("error", "mad_worktree_create failed: empty task description")
139
- return "❌ Error: Task description cannot be empty"
153
+ return getUpdateNotification() + "❌ Error: Task description cannot be empty"
140
154
  }
141
155
 
142
156
  const gitRoot = getGitRoot()
@@ -148,7 +162,7 @@ Each worktree has its own branch and working directory.`,
148
162
  // Check if worktree already exists
149
163
  if (existsSync(worktreePath)) {
150
164
  logEvent("warn", "Worktree already exists", { branch, path: worktreePath })
151
- return `⚠️ Worktree already exists at ${worktreePath}\nUse a different branch name or clean up with mad_cleanup.`
165
+ return getUpdateNotification() + `⚠️ Worktree already exists at ${worktreePath}\nUse a different branch name or clean up with mad_cleanup.`
152
166
  }
153
167
 
154
168
  logEvent("info", "Creating worktree", { branch, baseBranch })
@@ -177,7 +191,7 @@ worktrees/
177
191
  mkdirSync(worktreeDir, { recursive: true })
178
192
  } catch (e: any) {
179
193
  logEvent("error", "Failed to create worktree directory", { error: e.message })
180
- return `❌ Error creating worktree directory: ${e.message}`
194
+ return getUpdateNotification() + `❌ Error creating worktree directory: ${e.message}`
181
195
  }
182
196
 
183
197
  // Check if branch exists
@@ -196,7 +210,7 @@ worktrees/
196
210
  command: worktreeCmd,
197
211
  error: worktreeResult.error
198
212
  })
199
- return `❌ Error creating git worktree: ${worktreeResult.error}`
213
+ return getUpdateNotification() + `❌ Error creating git worktree: ${worktreeResult.error}`
200
214
  }
201
215
 
202
216
  // Write task file using Node.js
@@ -215,7 +229,7 @@ ${task}
215
229
 
216
230
  logEvent("info", "Worktree created successfully", { branch, path: worktreePath })
217
231
 
218
- return `✅ Worktree created successfully!
232
+ return getUpdateNotification() + `✅ Worktree created successfully!
219
233
  - Path: ${worktreePath}
220
234
  - Branch: ${branch}
221
235
  - Base: ${baseBranch}
@@ -224,7 +238,7 @@ ${task}
224
238
  The developer subagent can now work in this worktree using the Task tool.`
225
239
  } catch (e: any) {
226
240
  logEvent("error", "mad_worktree_create exception", { error: e.message, stack: e.stack })
227
- return `❌ Unexpected error creating worktree: ${e.message}`
241
+ return getUpdateNotification() + `❌ Unexpected error creating worktree: ${e.message}`
228
242
  }
229
243
  },
230
244
  }),
@@ -241,15 +255,15 @@ Shows which tasks are done, in progress, blocked, or have errors.`,
241
255
  const worktreeDir = join(gitRoot, "worktrees")
242
256
 
243
257
  if (!existsSync(worktreeDir)) {
244
- return "No active MAD worktrees. Use mad_worktree_create to create one."
258
+ return getUpdateNotification() + "No active MAD worktrees. Use mad_worktree_create to create one."
245
259
  }
246
260
 
247
261
  const entries = readdirSync(worktreeDir)
248
262
  if (entries.length === 0) {
249
- return "No active MAD worktrees. Use mad_worktree_create to create one."
263
+ return getUpdateNotification() + "No active MAD worktrees. Use mad_worktree_create to create one."
250
264
  }
251
265
 
252
- let status = "# MAD Status Dashboard\n\n"
266
+ let status = getUpdateNotification() + "# MAD Status Dashboard\n\n"
253
267
  let total = 0, done = 0, blocked = 0, errors = 0, wip = 0
254
268
 
255
269
  for (const entry of entries) {
@@ -330,10 +344,10 @@ Returns the results and creates an error file if tests fail.`,
330
344
  const worktreePath = join(gitRoot, "worktrees", args.worktree)
331
345
 
332
346
  if (!existsSync(worktreePath)) {
333
- return `Worktree not found: ${worktreePath}`
347
+ return getUpdateNotification() + `Worktree not found: ${worktreePath}`
334
348
  }
335
349
 
336
- let results = `# Test Results for ${args.worktree}\n\n`
350
+ let results = getUpdateNotification() + `# Test Results for ${args.worktree}\n\n`
337
351
  let hasError = false
338
352
  let errorMessages = ""
339
353
 
@@ -413,22 +427,22 @@ Handles merge conflicts by reporting them.`,
413
427
  const branch = args.worktree.replace(/-/g, "/")
414
428
 
415
429
  if (!existsSync(worktreePath)) {
416
- return `Worktree not found: ${worktreePath}`
430
+ return getUpdateNotification() + `Worktree not found: ${worktreePath}`
417
431
  }
418
432
 
419
433
  if (!existsSync(doneFile)) {
420
- return `Cannot merge: worktree ${args.worktree} is not marked as done. Complete the task first.`
434
+ return getUpdateNotification() + `Cannot merge: worktree ${args.worktree} is not marked as done. Complete the task first.`
421
435
  }
422
436
 
423
- const result = runCommand(`git merge ${branch} --no-edit`, gitRoot)
437
+ const result = runCommand(`git merge --no-ff ${branch} --no-edit`, gitRoot)
424
438
  if (result.success) {
425
- return `✅ Successfully merged ${branch}!\n\n${result.output}`
439
+ return getUpdateNotification() + `✅ Successfully merged ${branch}!\n\n${result.output}`
426
440
  } else {
427
441
  const output = result.error || "Unknown error"
428
442
  if (output.includes("CONFLICT")) {
429
- return `⚠️ Merge conflict detected!\n\n${output}\n\nResolve conflicts manually or use the fixer agent.`
443
+ return getUpdateNotification() + `⚠️ Merge conflict detected!\n\n${output}\n\nResolve conflicts manually or use the fixer agent.`
430
444
  }
431
- return `❌ Merge failed:\n${output}`
445
+ return getUpdateNotification() + `❌ Merge failed:\n${output}`
432
446
  }
433
447
  },
434
448
  }),
@@ -449,19 +463,19 @@ Removes the worktree directory and prunes git worktree references.`,
449
463
  const doneFile = join(worktreePath, ".agent-done")
450
464
 
451
465
  if (!existsSync(worktreePath)) {
452
- return `Worktree not found: ${worktreePath}`
466
+ return getUpdateNotification() + `Worktree not found: ${worktreePath}`
453
467
  }
454
468
 
455
469
  if (!args.force && !existsSync(doneFile)) {
456
- return `Worktree ${args.worktree} is not marked as done. Use force=true to cleanup anyway.`
470
+ return getUpdateNotification() + `Worktree ${args.worktree} is not marked as done. Use force=true to cleanup anyway.`
457
471
  }
458
472
 
459
473
  try {
460
474
  await $`git worktree remove ${worktreePath} --force`
461
475
  await $`git worktree prune`
462
- return `✅ Cleaned up worktree: ${args.worktree}`
476
+ return getUpdateNotification() + `✅ Cleaned up worktree: ${args.worktree}`
463
477
  } catch (e: any) {
464
- return `❌ Cleanup failed: ${e.message}`
478
+ return getUpdateNotification() + `❌ Cleanup failed: ${e.message}`
465
479
  }
466
480
  },
467
481
  }),
@@ -481,14 +495,14 @@ Use this when you've finished implementing the task in a worktree.`,
481
495
  const worktreePath = join(gitRoot, "worktrees", args.worktree)
482
496
 
483
497
  if (!existsSync(worktreePath)) {
484
- return `Worktree not found: ${worktreePath}`
498
+ return getUpdateNotification() + `Worktree not found: ${worktreePath}`
485
499
  }
486
500
 
487
501
  await $`echo ${args.summary} > ${join(worktreePath, ".agent-done")}`
488
502
  // Remove error/blocked files
489
503
  await $`rm -f ${join(worktreePath, ".agent-error")} ${join(worktreePath, ".agent-blocked")}`
490
504
 
491
- return `✅ Marked ${args.worktree} as done: ${args.summary}`
505
+ return getUpdateNotification() + `✅ Marked ${args.worktree} as done: ${args.summary}`
492
506
  },
493
507
  }),
494
508
 
@@ -507,12 +521,12 @@ Use this when you cannot proceed due to missing information or dependencies.`,
507
521
  const worktreePath = join(gitRoot, "worktrees", args.worktree)
508
522
 
509
523
  if (!existsSync(worktreePath)) {
510
- return `Worktree not found: ${worktreePath}`
524
+ return getUpdateNotification() + `Worktree not found: ${worktreePath}`
511
525
  }
512
526
 
513
527
  await $`echo ${args.reason} > ${join(worktreePath, ".agent-blocked")}`
514
528
 
515
- return `🚫 Marked ${args.worktree} as blocked: ${args.reason}`
529
+ return getUpdateNotification() + `🚫 Marked ${args.worktree} as blocked: ${args.reason}`
516
530
  },
517
531
  }),
518
532
 
@@ -530,10 +544,10 @@ Use this to understand what needs to be done in a specific worktree.`,
530
544
  const taskFile = join(gitRoot, "worktrees", args.worktree, ".agent-task")
531
545
 
532
546
  if (!existsSync(taskFile)) {
533
- return `Task file not found: ${taskFile}`
547
+ return getUpdateNotification() + `Task file not found: ${taskFile}`
534
548
  }
535
549
 
536
- return readFileSync(taskFile, "utf-8")
550
+ return getUpdateNotification() + readFileSync(taskFile, "utf-8")
537
551
  },
538
552
  }),
539
553
 
@@ -551,9 +565,9 @@ Creates structured logs in .mad-logs.jsonl for tracking the workflow.`,
551
565
  async execute(args, context) {
552
566
  try {
553
567
  await logEvent(args.level as "info" | "warn" | "error" | "debug", args.message, args.context)
554
- return `📝 Logged [${args.level.toUpperCase()}]: ${args.message}`
568
+ return getUpdateNotification() + `📝 Logged [${args.level.toUpperCase()}]: ${args.message}`
555
569
  } catch (e: any) {
556
- return `⚠️ Failed to write log: ${e.message}`
570
+ return getUpdateNotification() + `⚠️ Failed to write log: ${e.message}`
557
571
  }
558
572
  },
559
573
  }),
@@ -571,12 +585,12 @@ Shows progress, worktree statuses, timeline, and statistics in a beautiful dashb
571
585
  const worktreeDir = join(gitRoot, "worktrees")
572
586
 
573
587
  if (!existsSync(worktreeDir)) {
574
- return "No active MAD worktrees. Use mad_worktree_create to create one."
588
+ return getUpdateNotification() + "No active MAD worktrees. Use mad_worktree_create to create one."
575
589
  }
576
590
 
577
591
  const entries = readdirSync(worktreeDir)
578
592
  if (entries.length === 0) {
579
- return "No active MAD worktrees. Use mad_worktree_create to create one."
593
+ return getUpdateNotification() + "No active MAD worktrees. Use mad_worktree_create to create one."
580
594
  }
581
595
 
582
596
  let total = 0, done = 0, blocked = 0, errors = 0, wip = 0
@@ -636,7 +650,7 @@ Shows progress, worktree statuses, timeline, and statistics in a beautiful dashb
636
650
  const progressBar = "█".repeat(Math.floor(progress / 5)) + "░".repeat(20 - Math.floor(progress / 5))
637
651
 
638
652
  // Build visualization
639
- let output = `
653
+ let output = getUpdateNotification() + `
640
654
  ┌────────────────────────────────────────────────────────────────┐
641
655
  │ MAD ORCHESTRATION DASHBOARD │
642
656
  └────────────────────────────────────────────────────────────────┘
@@ -679,7 +693,7 @@ Shows progress, worktree statuses, timeline, and statistics in a beautiful dashb
679
693
 
680
694
  return output
681
695
  } catch (e: any) {
682
- return `❌ Error generating visualization: ${e.message}`
696
+ return getUpdateNotification() + `❌ Error generating visualization: ${e.message}`
683
697
  }
684
698
  },
685
699
  }),
@@ -696,7 +710,7 @@ Returns the current version, latest version, and whether an update is available.
696
710
  const updateInfo = await checkForUpdates()
697
711
 
698
712
  if (updateInfo.hasUpdate) {
699
- return `🔄 Update available!
713
+ return getUpdateNotification() + `🔄 Update available!
700
714
 
701
715
  Current version: ${updateInfo.current}
702
716
  Latest version: ${updateInfo.latest}
@@ -704,13 +718,13 @@ Latest version: ${updateInfo.latest}
704
718
  To update, run:
705
719
  npx opencode-mad install -g`
706
720
  } else {
707
- return `✅ You're up to date!
721
+ return getUpdateNotification() + `✅ You're up to date!
708
722
 
709
723
  Current version: ${updateInfo.current}
710
724
  Latest version: ${updateInfo.latest}`
711
725
  }
712
726
  } catch (e: any) {
713
- return `❌ Failed to check for updates: ${e.message}`
727
+ return getUpdateNotification() + `❌ Failed to check for updates: ${e.message}`
714
728
  }
715
729
  },
716
730
  }),