yams-blackboard 0.1.1 → 1.0.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 +5 -4
- package/index.js +22 -27
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# YAMS Blackboard Plugin for OpenCode
|
|
2
2
|
|
|
3
|
-
A **blackboard architecture** plugin enabling agent-to-agent communication through [YAMS](https://github.com/
|
|
3
|
+
A **blackboard architecture** plugin enabling agent-to-agent communication through [YAMS](https://github.com/trvon/yams) as shared memory.
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
@@ -24,7 +24,7 @@ This plugin implements the classic [blackboard pattern](https://en.wikipedia.org
|
|
|
24
24
|
|
|
25
25
|
## Prerequisites
|
|
26
26
|
|
|
27
|
-
- **YAMS
|
|
27
|
+
- **[YAMS](https://github.com/trvon/yams)** - must be installed and daemon running
|
|
28
28
|
- **bun** (for local development/building)
|
|
29
29
|
- **OpenCode** v1.1.0+ (for plugin support)
|
|
30
30
|
|
|
@@ -36,7 +36,8 @@ Add to your `opencode.json`:
|
|
|
36
36
|
|
|
37
37
|
```json
|
|
38
38
|
{
|
|
39
|
-
"
|
|
39
|
+
"$schema": "https://opencode.ai/config.json",
|
|
40
|
+
"plugin": ["yams-blackboard"]
|
|
40
41
|
}
|
|
41
42
|
```
|
|
42
43
|
|
|
@@ -255,7 +256,7 @@ YAMS must be installed and in your PATH. Check your installation.
|
|
|
255
256
|
|
|
256
257
|
### Plugin not loading
|
|
257
258
|
|
|
258
|
-
1. Verify `opencode.json` has `"
|
|
259
|
+
1. Verify `opencode.json` has `"plugin": ["yams-blackboard"]`
|
|
259
260
|
2. Check OpenCode logs for plugin load errors
|
|
260
261
|
3. Try clearing npm cache: `npm cache clean --force`
|
|
261
262
|
|
package/index.js
CHANGED
|
@@ -30,23 +30,21 @@ class YamsBlackboard {
|
|
|
30
30
|
}
|
|
31
31
|
async shell(cmd) {
|
|
32
32
|
try {
|
|
33
|
-
const result = await this.$`sh -c ${cmd}`;
|
|
33
|
+
const result = await this.$`sh -c ${cmd + " 2>&1"}`;
|
|
34
34
|
if (typeof result === "string") {
|
|
35
35
|
return result.trim();
|
|
36
36
|
}
|
|
37
|
-
if (this.isBufferLike(result)) {
|
|
38
|
-
return result.toString("utf-8").trim();
|
|
39
|
-
}
|
|
40
37
|
if (result && typeof result === "object") {
|
|
41
|
-
|
|
42
|
-
if (
|
|
43
|
-
return
|
|
38
|
+
let raw = result.stdout ?? result.output ?? result.text;
|
|
39
|
+
if (raw instanceof Uint8Array || Buffer.isBuffer(raw)) {
|
|
40
|
+
return new TextDecoder().decode(raw).trim();
|
|
44
41
|
}
|
|
45
|
-
if (
|
|
46
|
-
return
|
|
42
|
+
if (typeof raw === "string") {
|
|
43
|
+
return raw.trim();
|
|
47
44
|
}
|
|
48
|
-
if (typeof
|
|
49
|
-
|
|
45
|
+
if (typeof raw === "function") {
|
|
46
|
+
const text = await raw();
|
|
47
|
+
return typeof text === "string" ? text.trim() : String(text).trim();
|
|
50
48
|
}
|
|
51
49
|
}
|
|
52
50
|
return String(result ?? "").trim();
|
|
@@ -337,7 +335,7 @@ ${finding.content}
|
|
|
337
335
|
}
|
|
338
336
|
}
|
|
339
337
|
async getReadyTasks(agentCapabilities) {
|
|
340
|
-
const pending = await this.queryTasks({ status: "pending", limit: 100 });
|
|
338
|
+
const pending = await this.queryTasks({ status: "pending", limit: 100, offset: 0 });
|
|
341
339
|
const ready = [];
|
|
342
340
|
for (const task of pending) {
|
|
343
341
|
if (task.depends_on?.length) {
|
|
@@ -405,8 +403,8 @@ ${finding.content}
|
|
|
405
403
|
}
|
|
406
404
|
}
|
|
407
405
|
async getContextSummary(contextId) {
|
|
408
|
-
const findings = await this.queryFindings({ context_id: contextId, limit: 100 });
|
|
409
|
-
const tasks = await this.queryTasks({ context_id: contextId, limit: 100 });
|
|
406
|
+
const findings = await this.queryFindings({ context_id: contextId, limit: 100, offset: 0 });
|
|
407
|
+
const tasks = await this.queryTasks({ context_id: contextId, limit: 100, offset: 0 });
|
|
410
408
|
const agents = await this.listAgents();
|
|
411
409
|
const activeAgents = agents.filter((a) => a.status === "active");
|
|
412
410
|
const highSeverity = findings.filter((f) => f.severity === "high" || f.severity === "critical");
|
|
@@ -450,8 +448,8 @@ ${blockedTasks.length ? `- ${blockedTasks.length} tasks blocked` : ""}
|
|
|
450
448
|
}
|
|
451
449
|
async getStats() {
|
|
452
450
|
const agents = await this.listAgents();
|
|
453
|
-
const findings = await this.queryFindings({ limit: 1000 });
|
|
454
|
-
const tasks = await this.queryTasks({ limit: 1000 });
|
|
451
|
+
const findings = await this.queryFindings({ limit: 1000, offset: 0 });
|
|
452
|
+
const tasks = await this.queryTasks({ limit: 1000, offset: 0 });
|
|
455
453
|
const findingsByTopic = {};
|
|
456
454
|
const findingsByStatus = {};
|
|
457
455
|
const findingsBySeverity = {};
|
|
@@ -533,7 +531,7 @@ var FindingSchema = z.object({
|
|
|
533
531
|
resolution: z.string().optional().describe("How it was resolved"),
|
|
534
532
|
scope: FindingScope.default("persistent"),
|
|
535
533
|
ttl: z.number().int().positive().optional().describe("TTL in seconds for session-scoped"),
|
|
536
|
-
metadata: z.record(z.string()).optional()
|
|
534
|
+
metadata: z.record(z.string(), z.string()).optional()
|
|
537
535
|
});
|
|
538
536
|
var CreateFindingSchema = FindingSchema.omit({
|
|
539
537
|
id: true,
|
|
@@ -587,7 +585,7 @@ var TaskSchema = z.object({
|
|
|
587
585
|
error: z.string().optional().describe("Error message if failed"),
|
|
588
586
|
retry_count: z.number().int().nonnegative().optional(),
|
|
589
587
|
max_retries: z.number().int().nonnegative().optional(),
|
|
590
|
-
metadata: z.record(z.string()).optional()
|
|
588
|
+
metadata: z.record(z.string(), z.string()).optional()
|
|
591
589
|
});
|
|
592
590
|
var CreateTaskSchema = TaskSchema.omit({
|
|
593
591
|
id: true,
|
|
@@ -635,21 +633,18 @@ var TaskQuerySchema = z.object({
|
|
|
635
633
|
|
|
636
634
|
// index.ts
|
|
637
635
|
var YamsBlackboardPlugin = async ({ $, project, directory }) => {
|
|
638
|
-
|
|
636
|
+
const blackboard = new YamsBlackboard($, { defaultScope: "persistent" });
|
|
639
637
|
let currentContextId;
|
|
640
638
|
return {
|
|
641
639
|
"session.created": async () => {
|
|
642
|
-
|
|
643
|
-
console.log(`[yams-blackboard] Session started: ${sessionName}`);
|
|
640
|
+
await blackboard.startSession();
|
|
644
641
|
},
|
|
645
642
|
"session.compacted": async (input, output) => {
|
|
646
643
|
try {
|
|
647
644
|
const contextId = currentContextId || "default";
|
|
648
645
|
const summary = await blackboard.getContextSummary(contextId);
|
|
649
646
|
output.context.push(summary);
|
|
650
|
-
} catch
|
|
651
|
-
console.error("[yams-blackboard] Failed to generate compaction summary:", e);
|
|
652
|
-
}
|
|
647
|
+
} catch {}
|
|
653
648
|
},
|
|
654
649
|
tool: {
|
|
655
650
|
bb_register_agent: tool({
|
|
@@ -705,7 +700,7 @@ Registered at: ${agent.registered_at}`;
|
|
|
705
700
|
context_id: z2.string().optional().describe("Group with related findings"),
|
|
706
701
|
parent_id: z2.string().optional().describe("Reply to another finding"),
|
|
707
702
|
scope: FindingScope.optional().describe("Persistence: 'persistent' (default) or 'session'"),
|
|
708
|
-
metadata: z2.record(z2.string()).optional().describe("Additional key-value metadata")
|
|
703
|
+
metadata: z2.record(z2.string(), z2.string()).optional().describe("Additional key-value metadata")
|
|
709
704
|
},
|
|
710
705
|
async execute(args) {
|
|
711
706
|
const finding = await blackboard.postFinding({
|
|
@@ -1016,8 +1011,8 @@ ${args.set_current !== false ? "(Set as current context)" : ""}`;
|
|
|
1016
1011
|
},
|
|
1017
1012
|
async execute(args) {
|
|
1018
1013
|
const limit = args.limit || 10;
|
|
1019
|
-
const findings = await blackboard.queryFindings({ limit });
|
|
1020
|
-
const tasks = await blackboard.queryTasks({ limit });
|
|
1014
|
+
const findings = await blackboard.queryFindings({ limit, offset: 0 });
|
|
1015
|
+
const tasks = await blackboard.queryTasks({ limit, offset: 0 });
|
|
1021
1016
|
const output = [`## Recent Activity
|
|
1022
1017
|
`];
|
|
1023
1018
|
if (findings.length > 0) {
|
package/package.json
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yams-blackboard",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "YAMS Blackboard plugin for OpenCode - agent-to-agent communication via shared memory",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"scripts": {
|
|
9
9
|
"build": "bun build index.ts --outdir . --target node --external zod --external @opencode-ai/plugin",
|
|
10
|
-
"typecheck": "tsc --noEmit"
|
|
10
|
+
"typecheck": "tsc --noEmit",
|
|
11
|
+
"test": "bun test __tests__/plugin.test.ts __tests__/blackboard.test.ts",
|
|
12
|
+
"test:integration": "YAMS_INTEGRATION=1 bun test __tests__/integration.test.ts",
|
|
13
|
+
"test:all": "bun test"
|
|
11
14
|
},
|
|
12
15
|
"files": [
|
|
13
16
|
"index.js",
|
|
@@ -16,9 +19,10 @@
|
|
|
16
19
|
],
|
|
17
20
|
"dependencies": {
|
|
18
21
|
"@opencode-ai/plugin": "^1.1.0",
|
|
19
|
-
"zod": "^
|
|
22
|
+
"zod": "^4.1.8"
|
|
20
23
|
},
|
|
21
24
|
"devDependencies": {
|
|
25
|
+
"bun-types": "^1.1.0",
|
|
22
26
|
"typescript": "^5.0.0"
|
|
23
27
|
},
|
|
24
28
|
"keywords": [
|