@veedubin/boomerang-v3 0.3.3 → 0.4.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.
@@ -18,7 +18,6 @@ permission:
18
18
  tool:
19
19
  "memini-ai-dev_*": allow
20
20
  "searxng_*": allow
21
- "sequential-thinking_*": allow
22
21
  "markitdown_*": allow
23
22
  "github-mcp_*": allow
24
23
  "playwright_*": allow
@@ -18,7 +18,6 @@ permission:
18
18
  tool:
19
19
  "memini-ai-dev_*": allow
20
20
  "searxng_*": allow
21
- "sequential-thinking_*": allow
22
21
  "markitdown_*": allow
23
22
  "github-mcp_*": allow
24
23
  "playwright_*": allow
@@ -49,7 +48,7 @@ You are the **Boomerang Architect** - the authority on design decisions, archite
49
48
  ## MANDATORY MEMORY PROTOCOL
50
49
 
51
50
  1. **Query memini-ai FIRST** - `memini-ai-dev_query_memories` for previous decisions
52
- 2. **Use sequential-thinking** - `sequential-thinking_sequentialthinking` for complex analysis
51
+ 2. **Use thought chains** - `memini-ai-dev_add_thought` for complex analysis
53
52
  3. **Query knowledge graph** - `memini-ai-dev_query_kg` for entity relationships
54
53
  4. **Save when complete** - `memini-ai-dev_add_memory` with key decisions
55
54
 
@@ -18,7 +18,6 @@ permission:
18
18
  tool:
19
19
  "memini-ai-dev_*": allow
20
20
  "searxng_*": allow
21
- "sequential-thinking_*": allow
22
21
  "markitdown_*": allow
23
22
  "github-mcp_*": allow
24
23
  "playwright_*": allow
@@ -49,7 +48,7 @@ Implement features, fix bugs, and write tests efficiently using the Context Pack
49
48
  ## MANDATORY MEMORY PROTOCOL
50
49
 
51
50
  1. **Query memini-ai FIRST** - Call `memini-ai-dev_query_memories` before doing ANY work
52
- 2. **Use sequential-thinking** - Call `sequential-thinking_sequentialthinking` for complex tasks
51
+ 2. **Use thought chains** - Call `memini-ai-dev_add_thought` for complex tasks
53
52
  3. **Save when complete** - Call `memini-ai-dev_add_memory` with a summary of your work
54
53
 
55
54
  ## Context Requirements
@@ -1,7 +1,7 @@
1
1
  ---
2
- description: Boomerang Explorer v3 - Fast file finding using devstral-2:cloud (Ollama Cloud) with memini-ai semantic search.
2
+ description: Boomerang Explorer v3 - Fast file finding using devstral-2:123b-cloud (Ollama Cloud) with memini-ai semantic search.
3
3
  mode: subagent
4
- model: ollama-cloud/devstral-2:cloud
4
+ model: ollama-cloud/devstral-2:123b-cloud
5
5
  steps: 30
6
6
  permission:
7
7
  read:
@@ -18,7 +18,6 @@ permission:
18
18
  tool:
19
19
  "memini-ai-dev_*": allow
20
20
  "searxng_*": allow
21
- "sequential-thinking_*": allow
22
21
  "markitdown_*": allow
23
22
  "github-mcp_*": allow
24
23
  "playwright_*": allow
@@ -18,7 +18,6 @@ permission:
18
18
  tool:
19
19
  "memini-ai-dev_*": allow
20
20
  "searxng_*": allow
21
- "sequential-thinking_*": allow
22
21
  "markitdown_*": allow
23
22
  "github-mcp_*": allow
24
23
  "playwright_*": allow
@@ -18,7 +18,6 @@ permission:
18
18
  tool:
19
19
  "memini-ai-dev_*": allow
20
20
  "searxng_*": allow
21
- "sequential-thinking_*": allow
22
21
  "markitdown_*": allow
23
22
  "github-mcp_*": allow
24
23
  "playwright_*": allow
@@ -18,7 +18,6 @@ permission:
18
18
  tool:
19
19
  "memini-ai-dev_*": allow
20
20
  "searxng_*": allow
21
- "sequential-thinking_*": allow
22
21
  "markitdown_*": allow
23
22
  "github-mcp_*": allow
24
23
  "playwright_*": allow
@@ -18,7 +18,6 @@ permission:
18
18
  tool:
19
19
  "memini-ai-dev_*": allow
20
20
  "searxng_*": allow
21
- "sequential-thinking_*": allow
22
21
  "markitdown_*": allow
23
22
  "github-mcp_*": allow
24
23
  "playwright_*": allow
@@ -18,7 +18,6 @@ permission:
18
18
  tool:
19
19
  "memini-ai-dev_*": allow
20
20
  "searxng_*": allow
21
- "sequential-thinking_*": allow
22
21
  "markitdown_*": allow
23
22
  "github-mcp_*": allow
24
23
  "playwright_*": allow
@@ -18,7 +18,6 @@ permission:
18
18
  tool:
19
19
  "memini-ai-dev_*": allow
20
20
  "searxng_*": allow
21
- "sequential-thinking_*": allow
22
21
  "markitdown_*": allow
23
22
  "github-mcp_*": allow
24
23
  "playwright_*": allow
@@ -18,7 +18,6 @@ permission:
18
18
  tool:
19
19
  "memini-ai-dev_*": allow
20
20
  "searxng_*": allow
21
- "sequential-thinking_*": allow
22
21
  "markitdown_*": allow
23
22
  "github-mcp_*": allow
24
23
  "playwright_*": allow
@@ -1,7 +1,7 @@
1
1
  ---
2
- description: Boomerang Writer v3 - Documentation specialist using gemma4:cloud (Ollama Cloud) with memini-ai for context.
2
+ description: Boomerang Writer v3 - Documentation specialist using gemma4:31b-cloud (Ollama Cloud) with memini-ai for context.
3
3
  mode: subagent
4
- model: ollama-cloud/gemma4:cloud
4
+ model: ollama-cloud/gemma4:31b-cloud
5
5
  steps: 40
6
6
  permission:
7
7
  read:
@@ -18,7 +18,6 @@ permission:
18
18
  tool:
19
19
  "memini-ai-dev_*": allow
20
20
  "searxng_*": allow
21
- "sequential-thinking_*": allow
22
21
  "markitdown_*": allow
23
22
  "github-mcp_*": allow
24
23
  "playwright_*": allow
@@ -18,7 +18,6 @@ permission:
18
18
  tool:
19
19
  "memini-ai-dev_*": allow
20
20
  "searxng_*": allow
21
- "sequential-thinking_*": allow
22
21
  "markitdown_*": allow
23
22
  "github-mcp_*": allow
24
23
  "playwright_*": allow
@@ -72,8 +71,8 @@ You are the **Boomerang v3 Orchestrator** - the central coordinator using memini
72
71
  Immediately call `memini-ai-dev_query_memories` with the user's request.
73
72
  Do not write any text before calling this tool.
74
73
 
75
- ### STEP 2: Use sequential thinking (MANDATORY SECOND ACTION)
76
- Immediately call `sequential-thinking_sequentialthinking` with your analysis.
74
+ ### STEP 2: Use thought chains (MANDATORY SECOND ACTION)
75
+ Immediately call `memini-ai-dev_add_thought` with your analysis. Note: This creates a `thinkingChainId` that must be passed to sub-agents in their Context Package.
77
76
 
78
77
  ### STEP 3: Plan (MANDATORY unless explicitly waived)
79
78
  Create an implementation plan UNLESS user says "skip planning", "just do it", "/boomerang-handoff", "do a handoff", or "no plan needed".
@@ -18,7 +18,6 @@ permission:
18
18
  tool:
19
19
  "memini-ai-dev_*": allow
20
20
  "searxng_*": allow
21
- "sequential-thinking_*": allow
22
21
  "markitdown_*": allow
23
22
  "github-mcp_*": allow
24
23
  "playwright_*": allow
@@ -18,7 +18,6 @@ permission:
18
18
  tool:
19
19
  "memini-ai-dev_*": allow
20
20
  "searxng_*": allow
21
- "sequential-thinking_*": allow
22
21
  "markitdown_*": allow
23
22
  "github-mcp_*": allow
24
23
  "playwright_*": allow
package/AGENTS.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Boomerang Agent Roster
2
2
 
3
+ ## ⚡ CRITICAL: memini-ai Memory Protocol (MUST FOLLOW)
4
+
5
+ All agents **MUST** interact with memini-ai at every step:
6
+ 1. **Query FIRST** — Call `memini-ai-dev_query_memories` before starting work
7
+ 2. **Save DURING** — Call `memini-ai-dev_add_memory` after every meaningful decision
8
+ 3. **Preserve CONTEXT** — Save important context; query it back when continuing work
9
+
10
+ Failure to use memini-ai causes context loss, duplicate work, and wasted tokens.
11
+
12
+
3
13
  ## Core Agents
4
14
 
5
15
  > **Note**: Models are configurable. Use `install-agents.js --primary=<model> --secondary=<model>` to customize.
@@ -9,11 +19,11 @@
9
19
  | **boomerang** | boomerang-orchestrator | kimi-k2.6:cloud | Specifically built for swarm-based task orchestration and proactive autonomous delegation. |
10
20
  | **boomerang-coder** | boomerang-coder | glm-5.1:cloud | Flagship for agentic engineering; achieves SOTA on SWE-Bench Pro for complex, multi-file generation. |
11
21
  | **boomerang-architect** | boomerang-architect | deepseek-v4-pro:cloud | Offers frontier reasoning with dedicated "thinking modes" for analyzing complex architectural trade-offs. |
12
- | **boomerang-explorer** | boomerang-explorer | devstral-2:cloud | Explicitly designed to navigate codebases, trace dependencies, and map repository structures. |
22
+ | **boomerang-explorer** | boomerang-explorer | devstral-2:123b-cloud | Explicitly designed to navigate codebases, trace dependencies, and map repository structures. |
13
23
  | **boomerang-tester** | boomerang-tester | deepseek-v4-flash:cloud | Massive 1M context window for ingesting deep error logs and codebase context quickly and efficiently. |
14
24
  | **boomerang-linter** | boomerang-linter | qwen3-coder-next:cloud | Highly optimized for agentic coding workflows; blazing fast for syntax formatting and style checks. |
15
25
  | **boomerang-git** | boomerang-git | minimax-m2.7:cloud | Fast and highly reliable for standard professional productivity and executing structured terminal commands. |
16
- | **boomerang-writer** | boomerang-writer | gemma4:cloud | Frontier-level instruction following; excels at translating technical logic into clean, readable Markdown. |
26
+ | **boomerang-writer** | boomerang-writer | gemma4:31b-cloud | Frontier-level instruction following; excels at translating technical logic into clean, readable Markdown. |
17
27
  | **boomerang-scraper** | boomerang-scraper | qwen3.5:cloud | Strong, lightweight generalist with excellent tool-use capabilities for reliable data extraction. |
18
28
  | **boomerang-release** | boomerang-release | devstral-small-2:cloud | Fast 24B model perfect for targeted automation tasks like bumping versions and summarizing changelogs. |
19
29
  | **boomerang-agent-builder** | boomerang-agent-builder | glm-5.1:cloud | Excels at long-horizon tasks and ambiguous problems; ideal for writing and optimizing new agent logic. |
@@ -67,12 +77,12 @@ The orchestrator MUST delegate based on these rules. No exceptions.
67
77
  |-----------|------------------|-------|-------------------|
68
78
  | Complex planning / orchestration | `boomerang` | kimi-k2.6:cloud | `general` |
69
79
  | Architecture / design decisions | `boomerang-architect` | deepseek-v4-pro:cloud | `general`, `boomerang-coder` |
70
- | Documentation writing | `boomerang-writer` | gemma4:cloud | `general` |
80
+ | Documentation writing | `boomerang-writer` | gemma4:31b-cloud | `general` |
71
81
  | Session initialization | `boomerang-init` | kimi-k2.6:cloud | Everything else |
72
82
  | Session wrap-up / handoff | `boomerang-handoff` | kimi-k2.6:cloud | Everything else |
73
83
  | Skill/agent creation | `boomerang-agent-builder` | glm-5.1:cloud | `general` |
74
84
  | Fast code generation / bug fixes | `boomerang-coder` | glm-5.1:cloud | `general`, `boomerang-explorer` |
75
- | Code exploration / finding files | `boomerang-explorer` | devstral-2:cloud | Everything else |
85
+ | Code exploration / finding files | `boomerang-explorer` | devstral-2:123b-cloud | Everything else |
76
86
  | Writing / running tests | `boomerang-tester` | deepseek-v4-flash:cloud | `general`, `boomerang-coder` |
77
87
  | Linting / formatting | `boomerang-linter` | qwen3-coder-next:cloud | Everything else |
78
88
  | Git operations | `boomerang-git` | minimax-m2.7:cloud | Everything else |
@@ -129,7 +139,7 @@ All agents **MUST** follow the **8-Step Boomerang Protocol** — enforcement is
129
139
  ### 8-Step Protocol (MANDATORY)
130
140
 
131
141
  1. **Query Memory** — `memini-ai-dev_query_memories` FIRST
132
- 2. **Think** — `sequential-thinking_sequentialthinking` for complex tasks
142
+ 2. **Think** — `memini-ai-dev_add_thought` for complex tasks
133
143
  3. **Plan** — Create/refine implementation plan (MANDATORY unless user explicitly waives)
134
144
  4. **Delegate** — OpenCode executes selected agent with Context Package
135
145
  5. **Git Check** — Verify working tree state before code changes
@@ -199,7 +209,7 @@ Boomerang v3 uses **memini-ai** for memory — a Python-based semantic memory se
199
209
 
200
210
  All agents SHOULD:
201
211
  1. **Query memory FIRST** — `memini-ai-dev_query_memories` before work
202
- 2. **Use sequential-thinking** — For complex tasks
212
+ 2. **Use thought chains** — For complex tasks
203
213
  3. **Save results** — `memini-ai-dev_add_memory` when complete
204
214
 
205
215
  ### Trust-Weighted Memory
@@ -320,7 +330,7 @@ IDLE → MEMORY_QUERY → SEQUENTIAL_THINK → PLAN → DELEGATE → GIT_CHECK
320
330
  ### 8-Step Mandatory Protocol
321
331
 
322
332
  1. **MEMORY_QUERY** — MUST call `memini-ai-dev_query_memories` first
323
- 2. **SEQUENTIAL_THINK** — MUST call `sequential-thinking_sequentialthinking` for complex tasks
333
+ 2. **SEQUENTIAL_THINK** — MUST call `memini-ai-dev_add_thought` for complex tasks
324
334
  3. **PLAN** — MUST create plan or delegate to architect for build tasks
325
335
  4. **DELEGATE** — OpenCode handles agent execution
326
336
  5. **GIT_CHECK** — MUST verify working tree state before code changes
@@ -0,0 +1,290 @@
1
+ /**
2
+ * Context Buffer Middleware — Transparent orchestrator integration
3
+ * for capturing and restoring agent invocation context via memini-ai.
4
+ *
5
+ * This middleware wraps around agent dispatch in the orchestrator,
6
+ * saving invocation context (output, tool calls, decisions, errors)
7
+ * as segmented memories in memini-ai. It also provides before/after
8
+ * hooks for telemetry and context injection.
9
+ *
10
+ * Design:
11
+ * - Segmenting: ~4 chars per token. Split at ~50K tokens = ~200K chars.
12
+ * - Memory metadata includes session_id, agent_name, segment_index.
13
+ * - All segments of an invocation are linked via DERIVED_FROM relationships.
14
+ * - The middleware is OPTIONAL — if not configured, the orchestrator
15
+ * operates identically to before this integration.
16
+ */
17
+ import { TelemetryClient } from './telemetry-client.js';
18
+ /** Estimated ratio: 1 token ≈ 4 characters. */
19
+ const CHARS_PER_TOKEN = 4;
20
+ /**
21
+ * Context buffer middleware that works transparently with the existing
22
+ * orchestrator to capture, segment, and restore agent invocation context.
23
+ */
24
+ export class ContextBufferMiddleware {
25
+ sessionId;
26
+ config;
27
+ memini;
28
+ telemetry;
29
+ segmentIds = [];
30
+ constructor(sessionId, config) {
31
+ this.sessionId = sessionId;
32
+ this.config = config;
33
+ this.memini = config.meminiClient;
34
+ this.telemetry = new TelemetryClient(config.telemetryEndpoint);
35
+ }
36
+ /**
37
+ * Called BEFORE an agent runs.
38
+ *
39
+ * Queries memini-ai for relevant context based on the task description,
40
+ * injects it into the agent's context package, and emits a start event
41
+ * to telemetry.
42
+ *
43
+ * @returns A context string to inject into the agent invocation, or
44
+ * an empty string if no relevant context is found.
45
+ */
46
+ async beforeInvocation(agentName, task, context) {
47
+ const _startTime = Date.now();
48
+ await this.ensureSessionRow(task);
49
+ await this.emitTelemetry({
50
+ event_type: 'invocation_start',
51
+ session_id: this.sessionId,
52
+ agent_name: agentName,
53
+ metadata: { task, contextProvided: context !== undefined },
54
+ });
55
+ let injectedContext = '';
56
+ try {
57
+ const results = await this.memini.search(task, {
58
+ topK: 5,
59
+ strategy: 'TIERED',
60
+ });
61
+ if (results.length > 0) {
62
+ const contextParts = results
63
+ .slice(0, 5)
64
+ .map((r) => `[trust=${r.entry.trustScore?.toFixed(2) ?? '0.50'}] ${r.entry.text}`)
65
+ .join('\n\n---\n\n');
66
+ injectedContext = `\n## Relevant Context from Previous Sessions\n\n${contextParts}\n`;
67
+ }
68
+ }
69
+ catch (err) {
70
+ console.warn('[ContextBuffer] beforeInvocation search failed:', err);
71
+ }
72
+ return injectedContext;
73
+ }
74
+ /**
75
+ * Called AFTER an agent completes (or fails).
76
+ *
77
+ * Captures the full invocation payload, segments if needed, saves
78
+ * each segment to memini-ai, links them via relationships, and emits
79
+ * an end event to telemetry.
80
+ *
81
+ * @returns Array of memory IDs for the saved segments.
82
+ */
83
+ async afterInvocation(agentName, result, durationMs) {
84
+ const success = 'success' in result ? result.success : true;
85
+ const error = 'success' in result && !result.success ? result.error : undefined;
86
+ await this.emitTelemetry({
87
+ event_type: success ? 'invocation_end' : 'invocation_error',
88
+ session_id: this.sessionId,
89
+ agent_name: agentName,
90
+ duration_ms: durationMs,
91
+ success,
92
+ error_message: error,
93
+ });
94
+ const payload = this.buildPayload(agentName, result, durationMs);
95
+ const memoryIds = await this.saveContextSegments(agentName, payload);
96
+ this.segmentIds = memoryIds;
97
+ // Link segments to each other via DERIVED_FROM relationships
98
+ await this.linkSegments(memoryIds);
99
+ return memoryIds;
100
+ }
101
+ /**
102
+ * Get the memory IDs saved during the current session.
103
+ */
104
+ getSegmentIds() {
105
+ return [...this.segmentIds];
106
+ }
107
+ // ---------------------------------------------------------------------------
108
+ // Private helpers
109
+ // ---------------------------------------------------------------------------
110
+ /**
111
+ * Build an AgentContextPayload from a task result.
112
+ */
113
+ buildPayload(agentName, result, durationMs) {
114
+ const now = Date.now();
115
+ if ('success' in result && !result.success) {
116
+ return {
117
+ output: '',
118
+ toolCalls: [],
119
+ filesModified: [],
120
+ decisions: [],
121
+ errors: [result.error],
122
+ startTime: now - durationMs,
123
+ endTime: now,
124
+ durationMs,
125
+ };
126
+ }
127
+ const taskResult = result;
128
+ return {
129
+ output: taskResult.output ?? '',
130
+ toolCalls: taskResult.toolCalls ?? [],
131
+ filesModified: taskResult.filesModified ?? [],
132
+ decisions: taskResult.decisions ?? [],
133
+ errors: taskResult.errors ?? [],
134
+ startTime: now - durationMs,
135
+ endTime: now,
136
+ durationMs,
137
+ };
138
+ }
139
+ /**
140
+ * Save context segments to memini-ai.
141
+ * If the summary exceeds the segment threshold, it is split into
142
+ * multiple segments, each saved separately.
143
+ */
144
+ async saveContextSegments(agentName, payload) {
145
+ const summary = this.generateContextSummary(agentName, payload);
146
+ const thresholdChars = this.config.segmentThreshold * CHARS_PER_TOKEN;
147
+ const segments = this.splitIfNeeded(summary, thresholdChars);
148
+ const memoryIds = [];
149
+ for (let i = 0; i < segments.length; i++) {
150
+ const segment = segments[i];
151
+ try {
152
+ const entry = await this.memini.addMemory({
153
+ text: segment,
154
+ sourceType: 'boomerang',
155
+ sourcePath: `context-buffer://${this.sessionId}/${agentName}`,
156
+ metadataJson: JSON.stringify({
157
+ type: 'context_segment',
158
+ session_id: this.sessionId,
159
+ agent_name: agentName,
160
+ segment_index: i,
161
+ total_segments: segments.length,
162
+ files_modified: payload.filesModified,
163
+ decisions: payload.decisions,
164
+ errors: payload.errors,
165
+ duration_ms: payload.durationMs,
166
+ success: payload.errors.length === 0,
167
+ }),
168
+ sessionId: this.sessionId,
169
+ });
170
+ memoryIds.push(entry.id);
171
+ }
172
+ catch (err) {
173
+ console.warn(`[ContextBuffer] Failed to save segment ${i}/${segments.length}:`, err);
174
+ }
175
+ }
176
+ return memoryIds;
177
+ }
178
+ /**
179
+ * Link segments via DERIVED_FROM relationships in memini-ai.
180
+ * Each segment (except the first) derives from the previous one.
181
+ */
182
+ async linkSegments(memoryIds) {
183
+ if (memoryIds.length < 2) {
184
+ return;
185
+ }
186
+ for (let i = 1; i < memoryIds.length; i++) {
187
+ try {
188
+ await this.memini.createRelationship(memoryIds[i], memoryIds[i - 1], 'DERIVED_FROM', 0.9);
189
+ }
190
+ catch (err) {
191
+ console.warn(`[ContextBuffer] Failed to link segments ${i - 1} → ${i}:`, err);
192
+ }
193
+ }
194
+ }
195
+ /**
196
+ * Split content into segments if it exceeds the threshold.
197
+ * Tries to split on paragraph boundaries (double newlines).
198
+ */
199
+ splitIfNeeded(content, thresholdChars) {
200
+ if (content.length <= thresholdChars) {
201
+ return [content];
202
+ }
203
+ const segments = [];
204
+ let remaining = content;
205
+ while (remaining.length > 0) {
206
+ if (remaining.length <= thresholdChars) {
207
+ segments.push(remaining);
208
+ break;
209
+ }
210
+ // Find a paragraph boundary near the threshold
211
+ const searchStart = Math.max(0, thresholdChars - 1000);
212
+ const searchEnd = Math.min(remaining.length, thresholdChars + 1000);
213
+ const searchRegion = remaining.slice(searchStart, searchEnd);
214
+ const newlinePos = searchRegion.indexOf('\n\n');
215
+ if (newlinePos !== -1) {
216
+ const splitPos = searchStart + newlinePos + 2;
217
+ segments.push(remaining.slice(0, splitPos));
218
+ remaining = remaining.slice(splitPos);
219
+ }
220
+ else {
221
+ // No good boundary; hard split at threshold
222
+ segments.push(remaining.slice(0, thresholdChars));
223
+ remaining = remaining.slice(thresholdChars);
224
+ }
225
+ }
226
+ return segments;
227
+ }
228
+ /**
229
+ * Generate a human-readable context summary from the agent payload.
230
+ */
231
+ generateContextSummary(agentName, payload) {
232
+ const lines = [
233
+ `# Agent Invocation: ${agentName}`,
234
+ `Duration: ${payload.durationMs}ms`,
235
+ `Status: ${payload.errors.length === 0 ? 'SUCCESS' : 'FAILED'}`,
236
+ '',
237
+ ];
238
+ if (payload.output) {
239
+ lines.push('## Output');
240
+ lines.push(payload.output);
241
+ lines.push('');
242
+ }
243
+ if (payload.filesModified.length > 0) {
244
+ lines.push('## Files Modified');
245
+ for (const f of payload.filesModified) {
246
+ lines.push(`- ${f}`);
247
+ }
248
+ lines.push('');
249
+ }
250
+ if (payload.decisions.length > 0) {
251
+ lines.push('## Decisions');
252
+ for (const d of payload.decisions) {
253
+ lines.push(`- ${d}`);
254
+ }
255
+ lines.push('');
256
+ }
257
+ if (payload.toolCalls.length > 0) {
258
+ lines.push('## Tool Calls');
259
+ for (const tc of payload.toolCalls) {
260
+ lines.push(`- ${tc.name}(${JSON.stringify(tc.arguments).slice(0, 200)})`);
261
+ }
262
+ lines.push('');
263
+ }
264
+ if (payload.errors.length > 0) {
265
+ lines.push('## Errors');
266
+ for (const e of payload.errors) {
267
+ lines.push(`- ${e}`);
268
+ }
269
+ lines.push('');
270
+ }
271
+ return lines.join('\n');
272
+ }
273
+ /**
274
+ * Ensure a session row exists in telemetry.
275
+ */
276
+ async ensureSessionRow(task) {
277
+ try {
278
+ await this.telemetry.createSession(this.sessionId, 'default', task);
279
+ }
280
+ catch {
281
+ // Session may already exist; ignore errors
282
+ }
283
+ }
284
+ /**
285
+ * Emit a telemetry event. Fire-and-forget — errors are logged only.
286
+ */
287
+ async emitTelemetry(event) {
288
+ await this.telemetry.emit(event);
289
+ }
290
+ }
package/dist/index.js CHANGED
@@ -2,13 +2,17 @@
2
2
  * Boomerang v3 — Multi-agent orchestration plugin for OpenCode
3
3
  *
4
4
  * Exports:
5
- * - orchestrator: Concurrency-aware orchestrator
5
+ * - orchestrator: Concurrency-aware orchestrator with context buffer
6
6
  * - plugin: Plugin metadata
7
7
  * - concurrency: TaskLimiter, RetryExecutor, TimeoutEnforcer
8
+ * - context-buffer: ContextBufferMiddleware
9
+ * - telemetry: TelemetryClient
8
10
  * - types: Core type definitions
9
11
  */
10
12
  export { BoomerangOrchestrator, createOrchestrator } from './orchestrator.js';
11
13
  export { TaskLimiter, executeWithRetry, executeWithTimeout, } from './concurrency/index.js';
14
+ export { ContextBufferMiddleware } from './context-buffer.js';
15
+ export { TelemetryClient } from './telemetry-client.js';
12
16
  export { TimeoutError, } from './types.js';
13
17
  export const orchestrator = {
14
18
  name: 'boomerang-v3',
@@ -552,7 +552,7 @@ export function getClient() {
552
552
  }
553
553
  return clientInstance;
554
554
  }
555
- export async function initializeClient(pythonPath, serverModule) {
555
+ export async function initializeClient(_pythonPath, _serverModule) {
556
556
  const client = getClient();
557
557
  await client.initialize();
558
558
  return client;
@@ -89,7 +89,7 @@ export async function challengeMemory(memoryId, challengeText, client) {
89
89
  /**
90
90
  * Adapt a raw memory from memini-ai to our MemoryEntry type
91
91
  */
92
- function adaptMemoryEntry(raw) {
92
+ function _adaptMemoryEntry(raw) {
93
93
  let timestamp;
94
94
  if (typeof raw.timestamp === 'number') {
95
95
  timestamp = raw.timestamp;
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import { initializeClient, } from '../memini-client/index.js';
7
7
  import { DEFAULT_SEARCH_OPTIONS } from './schema.js';
8
- const PROJECT_ID = process.env.BOOMERANG_PROJECT_ID || 'boomerang-default';
8
+ const _PROJECT_ID = process.env.BOOMERANG_PROJECT_ID || 'boomerang-default';
9
9
  class MemorySystem {
10
10
  static instance = null;
11
11
  _initialized = false;
@@ -130,7 +130,7 @@ export async function triggerConsolidation(force = false, client) {
130
130
  /**
131
131
  * Adapt a raw memory from memini-ai to our MemoryEntry type
132
132
  */
133
- function adaptMemoryEntry(meminiEntry) {
133
+ function _adaptMemoryEntry(meminiEntry) {
134
134
  return {
135
135
  id: meminiEntry.id,
136
136
  text: meminiEntry.text,