bros-harness 0.1.2 → 0.1.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.4 - 2026-06-03
4
+
5
+ - Fixed packaged command config to use OpenCode's `template` field.
6
+ - Fixed frontmatter parsing for quoted permission keys containing `:`.
7
+
8
+ ## 0.1.3 - 2026-06-03
9
+
10
+ - Fixed OpenCode 1.15 plugin loading by exporting the V1 plugin module shape with `id` and `server`.
11
+
3
12
  ## 0.1.2 - 2026-06-03
4
13
 
5
14
  - Added package plugin agent registration so raw OpenCode installs can load BROS agents from `plugin: ["bros-harness"]`.
package/README.md CHANGED
@@ -116,6 +116,7 @@ The package plugin is intentionally narrow.
116
116
  On load, it verifies packaged asset directories and uses OpenCode’s in-memory `config(cfg)` hook to add only:
117
117
 
118
118
  - the package-relative BROS skills directory to `skills.paths`, when the existing field has the expected safe shape; and
119
+ - packaged BROS agent entries to `agent`, without overwriting existing agent keys; and
119
120
  - packaged command prompt entries to `command`, without overwriting existing command keys.
120
121
 
121
122
  It does **not**:
@@ -125,11 +126,11 @@ It does **not**:
125
126
  - publish packages;
126
127
  - register providers;
127
128
  - add MCP servers;
128
- - change permissions;
129
+ - change top-level permissions;
129
130
  - configure telemetry;
130
131
  - read, validate, or write secrets.
131
132
 
132
- Packaged agent files are included as reviewed assets, but they are not auto-registered by the default plugin hook because permission-bearing agent registration should remain an explicit, reviewed configuration decision.
133
+ Packaged agent files are registered from reviewed assets so a package-only OpenCode install can expose BROS agents without copying local files.
133
134
 
134
135
  Three skipped raw skills remain excluded pending separate sanitized review. They are not imported by this package.
135
136
 
@@ -24,9 +24,9 @@ This is the preferred path for users and agents. Local path examples are contrib
24
24
 
25
25
  ## Runtime behavior
26
26
 
27
- The package plugin resolves assets relative to its own package root. It validates key asset directories, then uses OpenCode's in-memory `config(cfg)` hook only to add the package-relative skills directory to `skills.paths` when safe and add packaged command prompt entries without overwriting existing commands.
27
+ The package plugin resolves assets relative to its own package root. It validates key asset directories, then uses OpenCode's in-memory `config(cfg)` hook to add the package-relative skills directory to `skills.paths` when safe, register packaged agent entries without overwriting existing agents, and add packaged command prompt entries without overwriting existing commands.
28
28
 
29
- This runtime hook changes only the merged config object OpenCode passes to the plugin at startup. It is distinct from live user config file mutation: the plugin does not write `opencode.json`, `.opencode/`, global config files, or other filesystem config. The plugin does not register providers, MCP servers, permissions, telemetry, or secrets. Agent files are packaged as reviewed assets, but permission-bearing agent registration is intentionally not performed by the default plugin hook.
29
+ This runtime hook changes only the merged config object OpenCode passes to the plugin at startup. It is distinct from live user config file mutation: the plugin does not write `opencode.json`, `.opencode/`, global OpenCode config files, or other filesystem config. The plugin does not register providers, MCP servers, top-level permissions, telemetry, or secrets.
30
30
 
31
31
  ## Safe agent workflow
32
32
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bros-harness",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Package-first OpenCode plugin for disciplined BROS agent harness assets.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/plugin.mjs CHANGED
@@ -32,14 +32,14 @@ export async function verifyBrosHarnessAssets() {
32
32
  function parseCommandMarkdown(markdown) {
33
33
  const match = markdown.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
34
34
  if (!match) {
35
- return { description: "BROS Harness command.", prompt: markdown.trim() };
35
+ return { description: "BROS Harness command.", template: markdown.trim() };
36
36
  }
37
37
 
38
38
  const descriptionMatch = match[1].match(/^description:\s*(.+)$/m);
39
39
  const description = descriptionMatch?.[1]?.replace(/^['\"]|['\"]$/g, "").trim();
40
40
  return {
41
41
  description: description || "BROS Harness command.",
42
- prompt: match[2].trim()
42
+ template: match[2].trim()
43
43
  };
44
44
  }
45
45
 
@@ -54,6 +54,22 @@ function parseYamlScalar(value) {
54
54
  return trimmed;
55
55
  }
56
56
 
57
+ function parseYamlKeyValue(line) {
58
+ let quote = "";
59
+ for (let index = 0; index < line.length; index += 1) {
60
+ const char = line[index];
61
+ if ((char === '"' || char === "'") && line[index - 1] !== "\\") {
62
+ quote = quote === char ? "" : quote || char;
63
+ continue;
64
+ }
65
+
66
+ if (char === ":" && !quote) {
67
+ return [line.slice(0, index), line.slice(index + 1)];
68
+ }
69
+ }
70
+ return null;
71
+ }
72
+
57
73
  function parseSimpleYamlObject(yaml) {
58
74
  const root = {};
59
75
  const stack = [{ indent: -1, value: root }];
@@ -63,11 +79,11 @@ function parseSimpleYamlObject(yaml) {
63
79
 
64
80
  const indent = rawLine.match(/^ */)?.[0].length ?? 0;
65
81
  const line = rawLine.trim();
66
- const match = line.match(/^(.+?):(?:\s*(.*))?$/);
67
- if (!match) continue;
82
+ const parsedLine = parseYamlKeyValue(line);
83
+ if (!parsedLine) continue;
68
84
 
69
- const key = match[1].trim().replace(/^['"]|['"]$/g, "");
70
- const rawValue = match[2] ?? "";
85
+ const key = parsedLine[0].trim().replace(/^['"]|['"]$/g, "");
86
+ const rawValue = parsedLine[1]?.trimStart() ?? "";
71
87
 
72
88
  while (stack.length > 1 && indent <= stack[stack.length - 1].indent) {
73
89
  stack.pop();
@@ -170,7 +186,7 @@ function mergeAgents(cfg, agents) {
170
186
  }
171
187
  }
172
188
 
173
- export default async function brosHarnessPlugin(_input = {}, _options = {}) {
189
+ export async function brosHarnessServer(_input = {}, _options = {}) {
174
190
  await verifyBrosHarnessAssets();
175
191
  const agents = await loadPackagedAgents();
176
192
  const commands = await loadPackagedCommands();
@@ -183,3 +199,8 @@ export default async function brosHarnessPlugin(_input = {}, _options = {}) {
183
199
  }
184
200
  };
185
201
  }
202
+
203
+ export default {
204
+ id: "bros-harness",
205
+ server: brosHarnessServer
206
+ };