bobs-workshop 0.3.2 → 3.1.0

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.
Files changed (200) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +199 -210
  3. package/bin/bobs-workshop.js +109 -0
  4. package/config/agents.json +27 -0
  5. package/dist/plugins/bobs-workshop.js +34 -0
  6. package/dist/tools/background-agent/cancel.d.ts +3 -0
  7. package/dist/tools/background-agent/cancel.d.ts.map +1 -0
  8. package/dist/tools/background-agent/cancel.js +52 -0
  9. package/dist/tools/background-agent/concurrency.d.ts +15 -0
  10. package/dist/tools/background-agent/concurrency.d.ts.map +1 -0
  11. package/dist/tools/background-agent/concurrency.js +61 -0
  12. package/dist/tools/background-agent/index.d.ts +8 -0
  13. package/dist/tools/background-agent/index.d.ts.map +1 -0
  14. package/dist/tools/background-agent/index.js +7 -0
  15. package/dist/tools/background-agent/launch.d.ts +6 -0
  16. package/dist/tools/background-agent/launch.d.ts.map +1 -0
  17. package/dist/tools/background-agent/launch.js +33 -0
  18. package/dist/tools/background-agent/list.d.ts +7 -0
  19. package/dist/tools/background-agent/list.d.ts.map +1 -0
  20. package/dist/tools/background-agent/list.js +40 -0
  21. package/dist/tools/background-agent/manager.d.ts +29 -0
  22. package/dist/tools/background-agent/manager.d.ts.map +1 -0
  23. package/dist/tools/background-agent/manager.js +377 -0
  24. package/dist/tools/background-agent/output.d.ts +3 -0
  25. package/dist/tools/background-agent/output.d.ts.map +1 -0
  26. package/dist/tools/background-agent/output.js +41 -0
  27. package/dist/tools/background-agent/types.d.ts +46 -0
  28. package/dist/tools/background-agent/types.d.ts.map +1 -0
  29. package/dist/tools/background-agent/types.js +1 -0
  30. package/dist/tools/index.d.ts +9 -0
  31. package/dist/tools/index.d.ts.map +1 -0
  32. package/dist/tools/index.js +8 -0
  33. package/dist/tools/manual/index.d.ts +3 -0
  34. package/dist/tools/manual/index.d.ts.map +1 -0
  35. package/dist/tools/manual/index.js +2 -0
  36. package/dist/tools/manual/manual-update.d.ts +4 -0
  37. package/dist/tools/manual/manual-update.d.ts.map +1 -0
  38. package/dist/tools/manual/manual-update.js +190 -0
  39. package/dist/tools/manual/verify-manual.d.ts +4 -0
  40. package/dist/tools/manual/verify-manual.d.ts.map +1 -0
  41. package/dist/tools/manual/verify-manual.js +46 -0
  42. package/package.json +35 -67
  43. package/postinstall.js +190 -0
  44. package/src/agents/alice.md +466 -0
  45. package/src/agents/bob-rev.md +493 -0
  46. package/src/agents/bob-send.md +277 -0
  47. package/src/agents/bob.md +442 -0
  48. package/src/agents/trace.md +451 -0
  49. package/src/plugins/bobs-workshop.ts +45 -0
  50. package/src/skills/api-patterns/SKILL.md +376 -0
  51. package/src/skills/architecture/SKILL.md +271 -0
  52. package/src/skills/bobs-workshop/performance/icon.svg +3 -0
  53. package/src/skills/brainstorming/SKILL.md +210 -0
  54. package/src/skills/clean-code/SKILL.md +151 -0
  55. package/src/skills/code-review-checklist/SKILL.md +220 -0
  56. package/src/skills/database-design/SKILL.md +271 -0
  57. package/src/skills/exploration/SKILL.md +257 -0
  58. package/src/skills/frontend-ui-ux/SKILL.md +78 -0
  59. package/src/skills/git-master/SKILL.md +1105 -0
  60. package/src/skills/performance/SKILL.md +144 -0
  61. package/src/skills/performance/icon.svg +3 -0
  62. package/src/skills/plan-writing/SKILL.md +225 -0
  63. package/src/skills/security/SKILL.md +410 -0
  64. package/src/skills/simplification/SKILL.md +238 -0
  65. package/src/skills/systematic-debugging/SKILL.md +175 -0
  66. package/src/skills/testing-patterns/SKILL.md +305 -0
  67. package/src/skills/verification/SKILL.md +286 -0
  68. package/src/tools/background-agent/cancel.ts +67 -0
  69. package/src/tools/background-agent/concurrency.ts +71 -0
  70. package/src/tools/background-agent/index.ts +7 -0
  71. package/src/tools/background-agent/launch.ts +39 -0
  72. package/src/tools/background-agent/list.ts +50 -0
  73. package/src/tools/background-agent/manager.ts +455 -0
  74. package/src/tools/background-agent/output.ts +57 -0
  75. package/src/tools/background-agent/types.ts +55 -0
  76. package/src/tools/index.ts +8 -0
  77. package/src/tools/manual/index.ts +2 -0
  78. package/src/tools/manual/manual-update.ts +197 -0
  79. package/src/tools/manual/verify-manual.ts +55 -0
  80. package/uninstall.js +64 -0
  81. package/Claude.md +0 -162
  82. package/bin/bobs-mcp-server.js +0 -11
  83. package/bin/bobs-mcp.js +0 -130
  84. package/dist/api/taskLogger.js +0 -106
  85. package/dist/api/taskLogger.js.map +0 -1
  86. package/dist/cli/checker.js +0 -401
  87. package/dist/cli/checker.js.map +0 -1
  88. package/dist/cli/cleanup.js +0 -131
  89. package/dist/cli/cleanup.js.map +0 -1
  90. package/dist/cli/debug.js +0 -157
  91. package/dist/cli/debug.js.map +0 -1
  92. package/dist/cli/health.js +0 -97
  93. package/dist/cli/health.js.map +0 -1
  94. package/dist/cli/setup.js +0 -81
  95. package/dist/cli/setup.js.map +0 -1
  96. package/dist/cli/workshop.js +0 -42
  97. package/dist/cli/workshop.js.map +0 -1
  98. package/dist/dashboard/server.js +0 -1203
  99. package/dist/dashboard/server.js.map +0 -1
  100. package/dist/index.js +0 -960
  101. package/dist/index.js.map +0 -1
  102. package/dist/prompts/architect.js +0 -221
  103. package/dist/prompts/architect.js.map +0 -1
  104. package/dist/prompts/debugger.js +0 -257
  105. package/dist/prompts/debugger.js.map +0 -1
  106. package/dist/prompts/engineer.js +0 -249
  107. package/dist/prompts/engineer.js.map +0 -1
  108. package/dist/prompts/orchestrator.js +0 -304
  109. package/dist/prompts/orchestrator.js.map +0 -1
  110. package/dist/prompts/reviewer.js +0 -289
  111. package/dist/prompts/reviewer.js.map +0 -1
  112. package/dist/services/activitySummarizer.js +0 -388
  113. package/dist/services/activitySummarizer.js.map +0 -1
  114. package/dist/services/changeValidator.js +0 -396
  115. package/dist/services/changeValidator.js.map +0 -1
  116. package/dist/services/claudeOrchestrator.js +0 -343
  117. package/dist/services/claudeOrchestrator.js.map +0 -1
  118. package/dist/services/fileMonitor.js +0 -250
  119. package/dist/services/fileMonitor.js.map +0 -1
  120. package/dist/services/implementationSummarizer.js +0 -306
  121. package/dist/services/implementationSummarizer.js.map +0 -1
  122. package/dist/services/liveMonitor.js +0 -315
  123. package/dist/services/liveMonitor.js.map +0 -1
  124. package/dist/services/mcpAuditLogger.js +0 -104
  125. package/dist/services/mcpAuditLogger.js.map +0 -1
  126. package/dist/services/mcpLogger.js +0 -223
  127. package/dist/services/mcpLogger.js.map +0 -1
  128. package/dist/services/tmuxManager.js +0 -541
  129. package/dist/services/tmuxManager.js.map +0 -1
  130. package/dist/tools/approvalTools.js +0 -244
  131. package/dist/tools/approvalTools.js.map +0 -1
  132. package/dist/tools/autoDebugger.js +0 -147
  133. package/dist/tools/autoDebugger.js.map +0 -1
  134. package/dist/tools/cleanupService.js +0 -221
  135. package/dist/tools/cleanupService.js.map +0 -1
  136. package/dist/tools/dashboardTools.js +0 -342
  137. package/dist/tools/dashboardTools.js.map +0 -1
  138. package/dist/tools/developmentNudges.js +0 -336
  139. package/dist/tools/developmentNudges.js.map +0 -1
  140. package/dist/tools/gitTools.js +0 -741
  141. package/dist/tools/gitTools.js.map +0 -1
  142. package/dist/tools/orchestratorTools.js +0 -832
  143. package/dist/tools/orchestratorTools.js.map +0 -1
  144. package/dist/tools/searchCache.js +0 -64
  145. package/dist/tools/searchCache.js.map +0 -1
  146. package/dist/tools/searchTools.js +0 -1107
  147. package/dist/tools/searchTools.js.map +0 -1
  148. package/dist/tools/semgrep-patterns.js +0 -296
  149. package/dist/tools/semgrep-patterns.js.map +0 -1
  150. package/dist/tools/specTools.js +0 -332
  151. package/dist/tools/specTools.js.map +0 -1
  152. package/dist/tools/structural/__tests__/orchestrator.test.js +0 -61
  153. package/dist/tools/structural/__tests__/orchestrator.test.js.map +0 -1
  154. package/dist/tools/structural/cache.js +0 -226
  155. package/dist/tools/structural/cache.js.map +0 -1
  156. package/dist/tools/structural/engines/python/index.js +0 -118
  157. package/dist/tools/structural/engines/python/index.js.map +0 -1
  158. package/dist/tools/structural/engines/typescript/__tests__/typescript-engine.test.js +0 -97
  159. package/dist/tools/structural/engines/typescript/__tests__/typescript-engine.test.js.map +0 -1
  160. package/dist/tools/structural/engines/typescript/analyzer.js +0 -433
  161. package/dist/tools/structural/engines/typescript/analyzer.js.map +0 -1
  162. package/dist/tools/structural/engines/typescript/index.js +0 -381
  163. package/dist/tools/structural/engines/typescript/index.js.map +0 -1
  164. package/dist/tools/structural/engines/typescript/utils.js +0 -279
  165. package/dist/tools/structural/engines/typescript/utils.js.map +0 -1
  166. package/dist/tools/structural/index.js +0 -248
  167. package/dist/tools/structural/index.js.map +0 -1
  168. package/dist/tools/structural/types.js +0 -18
  169. package/dist/tools/structural/types.js.map +0 -1
  170. package/dist/tools/tmuxTools.js +0 -100
  171. package/dist/tools/tmuxTools.js.map +0 -1
  172. package/dist/tools/workRecorder.js +0 -215
  173. package/dist/tools/workRecorder.js.map +0 -1
  174. package/dist/tools/worktreeTools.js +0 -705
  175. package/dist/tools/worktreeTools.js.map +0 -1
  176. package/dist/utils/__tests__/integration.test.js +0 -57
  177. package/dist/utils/__tests__/integration.test.js.map +0 -1
  178. package/dist/utils/__tests__/serverDetection.test.js +0 -151
  179. package/dist/utils/__tests__/serverDetection.test.js.map +0 -1
  180. package/dist/utils/errorHandling.js +0 -336
  181. package/dist/utils/errorHandling.js.map +0 -1
  182. package/dist/utils/processManager.js +0 -172
  183. package/dist/utils/processManager.js.map +0 -1
  184. package/dist/utils/reliability.js +0 -263
  185. package/dist/utils/reliability.js.map +0 -1
  186. package/dist/utils/responseFormatter.js +0 -250
  187. package/dist/utils/responseFormatter.js.map +0 -1
  188. package/dist/utils/serverDetection.js +0 -133
  189. package/dist/utils/serverDetection.js.map +0 -1
  190. package/dist/utils/specMigration.js +0 -105
  191. package/dist/utils/specMigration.js.map +0 -1
  192. package/dist/validation/schemas.js +0 -299
  193. package/dist/validation/schemas.js.map +0 -1
  194. package/public/.well-known/mcp/manifest.json +0 -473
  195. package/public/index.html +0 -3157
  196. package/public/index.html.backup +0 -2805
  197. package/public/index.html.backup2 +0 -1292
  198. package/scripts/cleanup-system-logs.ts +0 -121
  199. package/scripts/init-workspace.js +0 -63
  200. package/scripts/install-search-tools.js +0 -116
@@ -0,0 +1,286 @@
1
+ ---
2
+ name: verification
3
+ description: Evidence-based verification methodology. SEE code working, do not just trust tests. Use when shipping code, final verification, output validation, evidence gathering. CRITICAL: Evidence before assertions.
4
+ metadata:
5
+ recommended_for: bob-send
6
+ category: verification
7
+ ---
8
+
9
+ # Evidence-Based Verification Skill
10
+
11
+ ## Core Philosophy
12
+
13
+ > "Evidence before assertions. Always."
14
+
15
+ Never claim code works without **seeing** it work. Tests passing is not enough. You must SEE the output.
16
+
17
+ ## When to Use
18
+
19
+ Use this skill during the SEND phase or any final verification:
20
+ - Before shipping code
21
+ - When validating implementation works
22
+ - When gathering evidence for review
23
+ - When tests pass but you need runtime proof
24
+
25
+ ## The Three Laws
26
+
27
+ 1. **See it working** - Screenshots, curl responses, CLI output. Actual evidence.
28
+ 2. **Human checkpoint** - No auto-shipping. Human reviews evidence and decides.
29
+ 3. **Fallback hierarchy** - If primary method fails, try the next method down.
30
+
31
+ ## Project Type Detection
32
+
33
+ First, detect what type of project you're verifying:
34
+
35
+ | Detection Pattern | Project Type | Primary Method |
36
+ |-------------------|--------------|----------------|
37
+ | package.json + src/app or pages/ | Web app | Screenshot + test flows |
38
+ | package.json + routes or controllers/ | API | Curl endpoints |
39
+ | Cargo.toml + src/main.rs with clap | CLI | Run commands |
40
+ | pyproject.toml + `__main__.py` | CLI | Run commands |
41
+ | `**/lib.rs` or `setup.py` | Library | Run examples |
42
+ | Dockerfile or docker-compose.yml | Service | Health check + logs |
43
+
44
+ ## Verification Methods
45
+
46
+ ### Web Applications
47
+
48
+ ```bash
49
+ # 1. Start dev server
50
+ npm run dev &
51
+ SERVER_PID=$!
52
+
53
+ # 2. Wait for server (max 30s)
54
+ sleep 5 # or: until curl -s http://localhost:3000 > /dev/null
55
+
56
+ # 3. Verify key pages load
57
+ curl -s http://localhost:3000 | head -20
58
+
59
+ # 4. Check for errors (if browser available, take screenshots)
60
+
61
+ # 5. Cleanup
62
+ kill $SERVER_PID
63
+ ```
64
+
65
+ **Evidence to capture:**
66
+ - Screenshots of key pages (if browser available)
67
+ - HTML response showing expected content
68
+ - Console errors (if any)
69
+
70
+ ### Browser Verification (Playwright)
71
+
72
+ For web applications, use Playwright for comprehensive browser verification:
73
+
74
+ **Capabilities:**
75
+ - **Verification**: Ensure web elements are present and functional
76
+ - **Browsing**: Navigate through web pages to gather information
77
+ - **Web Scraping**: Extract data from websites
78
+ - **Testing**: Run end-to-end tests
79
+ - **Screenshots**: Capture visual evidence of web states
80
+
81
+ **Usage:**
82
+ When a task involves browser interactions, use Playwright MCP tools:
83
+ ```bash
84
+ # Navigate to page
85
+ playwright_browser_navigate(url="http://localhost:3000")
86
+
87
+ # Take screenshot
88
+ playwright_browser_take_screenshot(filename="homepage.png", type="png")
89
+
90
+ # Interact with elements
91
+ playwright_browser_click(ref="submit-button")
92
+
93
+ # Verify element present
94
+ playwright_browser_snapshot()
95
+ ```
96
+
97
+ **Best practices:**
98
+ - Capture screenshots before and after interactions
99
+ - Verify console for errors
100
+ - Test across different viewport sizes
101
+ - Document all browser-based evidence
102
+
103
+ ### APIs
104
+
105
+ ```bash
106
+ # 1. Start server
107
+ npm start &
108
+ sleep 3
109
+
110
+ # 2. Test key endpoints
111
+ curl -s -w "%{http_code}" http://localhost:3000/api/health
112
+ curl -s -X POST http://localhost:3000/api/[endpoint] \
113
+ -H "Content-Type: application/json" \
114
+ -d '{"test": true}'
115
+
116
+ # 3. Verify response shapes match spec
117
+ ```
118
+
119
+ **Evidence to capture:**
120
+ - Status codes for each endpoint
121
+ - Response bodies (truncated if large)
122
+ - Error responses
123
+
124
+ ### CLI Tools
125
+
126
+ ```bash
127
+ # 1. Test help
128
+ ./cli --help
129
+ echo "Exit code: $?"
130
+
131
+ # 2. Test primary commands
132
+ ./cli [command] test-input.txt
133
+ echo "Exit code: $?"
134
+
135
+ # 3. Test error handling
136
+ ./cli [command] nonexistent.txt
137
+ echo "Exit code: $?" # Should be non-zero
138
+ ```
139
+
140
+ **Evidence to capture:**
141
+ - Command output (stdout)
142
+ - Error output (stderr)
143
+ - Exit codes
144
+
145
+ ### Libraries
146
+
147
+ ```bash
148
+ # 1. Run tests (confirm they pass)
149
+ npm test
150
+
151
+ # 2. Run examples from documentation
152
+ node examples/basic-usage.js
153
+
154
+ # 3. Check types compile
155
+ npm run typecheck
156
+ ```
157
+
158
+ **Evidence to capture:**
159
+ - Example output
160
+ - Test coverage summary
161
+
162
+ ## Fallback Hierarchy
163
+
164
+ If primary method fails, fall back in order:
165
+
166
+ ```
167
+ 1. Full runtime (screenshot/curl/run) ─ FAILED
168
+
169
+ └─► 2. Integration tests ─ FAILED
170
+
171
+ └─► 3. Unit tests + examples ─ FAILED
172
+
173
+ └─► 4. Type check + lint only ─ FAILED
174
+
175
+ └─► 5. Code review only (last resort)
176
+ └─► Report: "Unable to verify runtime behavior"
177
+ ```
178
+
179
+ **Always record:**
180
+ - Which method was attempted
181
+ - Why it failed
182
+ - Which fallback was used
183
+
184
+ ## Timeout Handling
185
+
186
+ **30-second timeout per verification method.**
187
+
188
+ If method times out:
189
+ 1. Kill the process
190
+ 2. Log the timeout
191
+ 3. Try fallback method
192
+
193
+ ## Evidence Storage
194
+
195
+ Document evidence in MANUAL Verification Logs:
196
+
197
+ ```markdown
198
+ ## ✅ Verification Evidence
199
+
200
+ ### Runtime Verification
201
+ **Project Type**: web
202
+ **Method Used**: curl + HTML inspection
203
+ **Fallback Level**: Primary (no fallback needed)
204
+
205
+ ### Evidence Captured
206
+ 1. **Homepage**: Returns 200, contains expected title
207
+ 2. **API Health**: /api/health returns {"status": "ok"}
208
+ 3. **Login Flow**: Form renders, submits correctly
209
+
210
+ ### Screenshots/Output
211
+ - [Describe what was observed]
212
+ - [Key behaviors verified]
213
+
214
+ ### Result: ✅ VERIFIED
215
+ ```
216
+
217
+ ## Red Flags — STOP and Reassess
218
+
219
+ If you're thinking any of these, you're about to violate the methodology:
220
+
221
+ - "Tests pass, that's good enough" → **NO. SEE it working.**
222
+ - "I'll verify after shipping" → **NO. Verify BEFORE ship.**
223
+ - "The type checker caught everything" → **NO. Types don't catch runtime issues.**
224
+ - "Screenshot failed but it probably works" → **NO. "Probably" isn't evidence.**
225
+ - "It should work because..." → **NO. SHOW it works.**
226
+ - "Evidence isn't necessary for this change" → **NO. Every change gets verified.**
227
+
228
+ ## Rationalizations to Resist
229
+
230
+ | Excuse | Reality |
231
+ |--------|---------|
232
+ | "Tests pass" | Tests aren't enough. SEE it working. |
233
+ | "Type checker caught everything" | Types don't catch runtime issues. |
234
+ | "It worked before" | Prove it works NOW. |
235
+ | "Human checkpoint is formality" | Human checkpoint is the gate. |
236
+ | "Code review is enough" | Code review is last resort fallback. |
237
+ | "Tests are flaky, ignore failure" | Flaky tests hide real failures. Fix or accept with caveat. |
238
+
239
+ ## Flaky Test Detection
240
+
241
+ ```
242
+ Test fails?
243
+ ├── Re-run failed tests
244
+ ├── Pass 2nd time?
245
+ │ └── Yes → Note flakiness, accept with caveat
246
+ └── Fail 2nd time?
247
+ ├── Run isolated
248
+ └── Still fail? → Real failure, must fix
249
+ ```
250
+
251
+ ## Output Format
252
+
253
+ When verification completes:
254
+
255
+ ```markdown
256
+ ### Verification Summary
257
+
258
+ | Check | Status | Method | Notes |
259
+ |-------|--------|--------|-------|
260
+ | Build | ✅ | npm run build | No errors |
261
+ | Lint | ✅ | npm run lint | 0 issues |
262
+ | Tests | ✅ | npm test | 47/47 passed |
263
+ | Runtime | ✅ | curl + inspect | Evidence captured |
264
+
265
+ ### Evidence
266
+ - Homepage renders correctly (verified via curl)
267
+ - API returns expected responses
268
+ - No console errors observed
269
+
270
+ ### Result: ✅ ALL CHECKS PASS + EVIDENCE GATHERED
271
+ ```
272
+
273
+ ## Anti-Patterns
274
+
275
+ **Don't do these:**
276
+
277
+ - Trusting test results without seeing code run
278
+ - Skipping output verification because "tests pass"
279
+ - Proceeding when verification method fails without fallback
280
+ - Modifying code after verification passes (invalidates verification)
281
+ - Ignoring flaky test warnings
282
+ - Auto-approving without human checkpoint
283
+
284
+ ---
285
+
286
+ **Remember**: You are gathering EVIDENCE. The human decides if it ships. Your job is to SEE the code work and document what you observed.
@@ -0,0 +1,67 @@
1
+ import { tool } from "@opencode-ai/plugin";
2
+ import type { PluginInput } from "@opencode-ai/plugin";
3
+ import { BackgroundManager } from "./manager.js";
4
+
5
+ const BackgroundCancelTool: any = tool({
6
+ description: "Cancel running background agent sessions (cleanup)",
7
+ args: {
8
+ task_id: tool.schema.string().optional()
9
+ .describe("Specific task ID to cancel (omit to cancel all)"),
10
+ all: tool.schema.boolean().optional()
11
+ .describe("Cancel all running tasks"),
12
+ },
13
+ async execute(args, context) {
14
+ const ctx = context as unknown as PluginInput & { sessionID: string };
15
+ const manager = BackgroundManager.getInstance(ctx);
16
+
17
+ if (!args.task_id && !args.all) {
18
+ return "❌ Must specify task_id OR all=true";
19
+ }
20
+
21
+ if (args.all) {
22
+ const runningTasks = manager.getRunningTasks();
23
+
24
+ if (runningTasks.length === 0) {
25
+ return "📭 No running tasks to cancel";
26
+ }
27
+
28
+ let cancelledCount = 0;
29
+ for (const task of runningTasks) {
30
+ if (task.sessionID) {
31
+ await ctx.client.session.delete({
32
+ path: { id: task.sessionID },
33
+ });
34
+ cancelledCount++;
35
+ }
36
+ }
37
+
38
+ return `🗑️ Cancelled ${cancelledCount} running tasks`;
39
+ }
40
+
41
+ if (args.task_id) {
42
+ const task = manager.getTask(args.task_id);
43
+
44
+ if (!task) {
45
+ return `❌ Task ${args.task_id} not found`;
46
+ }
47
+
48
+ if (task.status !== "running") {
49
+ return `⚠️ Task ${args.task_id} is ${task.status}, cannot cancel`;
50
+ }
51
+
52
+ if (!task.sessionID) {
53
+ return `❌ Task ${args.task_id} has no session`;
54
+ }
55
+
56
+ await ctx.client.session.delete({
57
+ path: { id: task.sessionID },
58
+ });
59
+
60
+ return `🗑️ Cancelled task ${args.task_id}`;
61
+ }
62
+
63
+ return "";
64
+ },
65
+ });
66
+
67
+ export default BackgroundCancelTool;
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Simple concurrency manager for background agents.
3
+ * Limits concurrent tasks per model/agent.
4
+ */
5
+ export class ConcurrencyManager {
6
+ private counts: Map<string, number> = new Map();
7
+ private queues: Map<string, Array<() => void>> = new Map();
8
+ private readonly defaultLimit = 5;
9
+
10
+ getConcurrencyLimit(key: string): number {
11
+ return this.defaultLimit;
12
+ }
13
+
14
+ async acquire(key: string): Promise<void> {
15
+ const limit = this.getConcurrencyLimit(key);
16
+ if (limit === Infinity) {
17
+ return;
18
+ }
19
+
20
+ const current = this.counts.get(key) ?? 0;
21
+ if (current < limit) {
22
+ this.counts.set(key, current + 1);
23
+ return;
24
+ }
25
+
26
+ return new Promise<void>((resolve) => {
27
+ const queue = this.queues.get(key) ?? [];
28
+ queue.push(resolve);
29
+ this.queues.set(key, queue);
30
+ });
31
+ }
32
+
33
+ release(key: string): void {
34
+ const limit = this.getConcurrencyLimit(key);
35
+ if (limit === Infinity) {
36
+ return;
37
+ }
38
+
39
+ const queue = this.queues.get(key);
40
+
41
+ // Try to hand off to a waiting entry
42
+ while (queue && queue.length > 0) {
43
+ const next = queue.shift()!;
44
+ if (next) {
45
+ next();
46
+ return;
47
+ }
48
+ }
49
+
50
+ // No handoff occurred - decrement count to free slot
51
+ const current = this.counts.get(key) ?? 0;
52
+ if (current > 0) {
53
+ this.counts.set(key, current - 1);
54
+ }
55
+ }
56
+
57
+ clear(): void {
58
+ for (const [key] of this.queues) {
59
+ this.cancelWaiters(key);
60
+ }
61
+ this.counts.clear();
62
+ this.queues.clear();
63
+ }
64
+
65
+ private cancelWaiters(key: string): void {
66
+ const queue = this.queues.get(key);
67
+ if (queue) {
68
+ this.queues.delete(key);
69
+ }
70
+ }
71
+ }
@@ -0,0 +1,7 @@
1
+ export * from "./types";
2
+ export { BackgroundManager } from "./manager";
3
+ export { ConcurrencyManager } from "./concurrency";
4
+ export { default as background_agent } from "./launch.js";
5
+ export { default as list_background_tasks } from "./list.js";
6
+ export { default as background_output } from "./output.js";
7
+ export { default as background_cancel } from "./cancel.js";
@@ -0,0 +1,39 @@
1
+ import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool";
2
+ import type { PluginInput } from "@opencode-ai/plugin";
3
+ import { BackgroundManager } from "./manager.js";
4
+ import type { LaunchInput } from "./types.js";
5
+
6
+ const BackgroundAgentTool: ToolDefinition = tool({
7
+ description: "Launch a background agent for LSP code exploration or verification",
8
+ args: {
9
+ agent: tool.schema.enum(["alice", "bob", "bob-eng", "bob-rev", "trace", "bob-send"])
10
+ .describe("Agent name to launch in background"),
11
+ prompt: tool.schema.string().describe("Prompt for the background agent"),
12
+ skills: tool.schema.array(tool.schema.string()).optional()
13
+ .describe("Skills to load from .opencode/skill/"),
14
+ model: tool.schema.string().optional()
15
+ .describe("Override model (defaults to agent's configured model)"),
16
+ manual_path: tool.schema.string().optional()
17
+ .describe("Path to MANUAL file (for bob/bob-rev agents)"),
18
+ },
19
+ async execute(args, context) {
20
+ const ctx = context as unknown as PluginInput & { sessionID: string };
21
+ const manager = BackgroundManager.getInstance(ctx);
22
+
23
+ const input: LaunchInput = {
24
+ description: `${args.agent} - ${args.prompt.slice(0, 50)}`,
25
+ prompt: args.prompt,
26
+ agent: args.agent,
27
+ parentSessionID: ctx.sessionID,
28
+ model: args.model,
29
+ skills: args.skills,
30
+ manual_path: args.manual_path,
31
+ };
32
+
33
+ const task = await manager.launch(input);
34
+ return `✅ Started background ${args.agent} session: ${task.id}`;
35
+ },
36
+ });
37
+
38
+ export default BackgroundAgentTool;
39
+ export { BackgroundManager };
@@ -0,0 +1,50 @@
1
+ import { tool } from "@opencode-ai/plugin";
2
+ import type { PluginInput } from "@opencode-ai/plugin";
3
+ import { BackgroundManager } from "./index.js";
4
+
5
+ const ListBackgroundTasksTool = tool({
6
+ description: "List all running background agent sessions",
7
+ args: {},
8
+ async execute(args, context) {
9
+ const ctx = context as unknown as PluginInput;
10
+ const manager = BackgroundManager.getInstance(ctx);
11
+
12
+ const tasks = manager.getAllTasks();
13
+
14
+ if (tasks.length === 0) {
15
+ return "📭 No background sessions running";
16
+ }
17
+
18
+ const output = tasks.map((t) => {
19
+ const statusEmoji: Record<string, string> = {
20
+ pending: "⏳",
21
+ running: "🔄",
22
+ completed: "✅",
23
+ error: "❌",
24
+ cancelled: "🚫",
25
+ };
26
+ const emoji = statusEmoji[t.status] || "❓";
27
+ const duration = t.startedAt && t.completedAt
28
+ ? `${Math.round((t.completedAt.getTime() - t.startedAt.getTime()) / 1000)}s`
29
+ : t.startedAt
30
+ ? `${Math.round((Date.now() - t.startedAt.getTime()) / 1000)}s (running)`
31
+ : "-";
32
+
33
+ const skillInfo = t.skills && t.skills.length > 0
34
+ ? ` [skills: ${t.skills.join(", ")}]`
35
+ : "";
36
+
37
+ return `${emoji} \`${t.id}\` - ${t.description} [${t.status}] ${duration}${skillInfo}`;
38
+ }).join('\n');
39
+
40
+ const runningCount = tasks.filter(t => t.status === "running").length;
41
+ const completedCount = tasks.filter(t => t.status === "completed").length;
42
+ const errorCount = tasks.filter(t => t.status === "error").length;
43
+
44
+ return `🗂️ Background Sessions (${tasks.length} total):\n` +
45
+ ` 🔄 Running: ${runningCount} | ✅ Completed: ${completedCount} | ❌ Error: ${errorCount}\n\n` +
46
+ `${output}`;
47
+ },
48
+ });
49
+
50
+ export default ListBackgroundTasksTool;