wavebrain 0.2.0 → 0.2.1

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.
@@ -1,5 +1,5 @@
1
1
  name: wavebrain
2
- version: 0.2.0
2
+ version: 0.2.1
3
3
  description: "WaveBrain: records your agent's deploys, pushes, releases, emails, payments and other real-world actions to its audit log, even when the model forgets to call log_action."
4
4
  author: Tambo Labs
5
5
  homepage: https://getwavebrain.com
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wavebrain",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Connect Claude Code, Codex, Cursor, Windsurf, Claude Desktop, VS Code and Hermes to WaveBrain, the audit log of what your AI agents do.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/capture.mjs CHANGED
@@ -186,3 +186,46 @@ export function hermesPluginToggle(ctx, hermesDir, on) {
186
186
  });
187
187
  return r.status === 0;
188
188
  }
189
+
190
+ /**
191
+ * Removes "wavebrain" from plugins.enabled / plugins.disabled in a Hermes config.yaml, and drops a
192
+ * plugins block that is left empty. Used by `remove` (the plugin files are deleted too), so the
193
+ * file ends up as it was rather than with wavebrain on the disabled list.
194
+ */
195
+ export function hermesUnlistPlugin(text) {
196
+ if (text === null) return null;
197
+ const lines = text.split("\n");
198
+ const start = lines.findIndex((l) => /^plugins:\s*(#.*)?$/.test(l));
199
+ if (start < 0) return text;
200
+ let end = start + 1;
201
+ while (end < lines.length && (lines[end] === "" || /^\s/.test(lines[end]))) end++;
202
+ let block = lines.slice(start + 1, end);
203
+ block = block.filter((l) => !/^\s+-\s*["']?wavebrain["']?\s*$/.test(l));
204
+ block = block.map((l) =>
205
+ l.replace(/^(\s+(?:enabled|disabled):\s*)\[(.*)\]\s*$/, (_, k, items) => {
206
+ const left = items.split(",").map((x) => x.trim()).filter((x) => x && !/^["']?wavebrain["']?$/.test(x));
207
+ return `${k}[${left.join(", ")}]`;
208
+ }),
209
+ );
210
+ // A key with no list items left: " enabled:" followed by nothing indented deeper.
211
+ block = block.filter((l, i) => {
212
+ const m = /^(\s+)(enabled|disabled):\s*(\[\])?\s*$/.exec(l);
213
+ if (!m) return true;
214
+ const next = block.slice(i + 1).find((x) => x.trim() !== "");
215
+ return next !== undefined && next.match(/^\s*/)[0].length > m[1].length && /^\s+-/.test(next);
216
+ });
217
+ const meaningful = block.some((l) => l.trim() && !l.trim().startsWith("#"));
218
+ // Drop trailing blank lines inside the block range.
219
+ while (block.length && block[block.length - 1] === "") block.pop();
220
+ let out;
221
+ if (meaningful) out = [...lines.slice(0, start + 1), ...block, ...(end < lines.length ? [""] : []), ...lines.slice(end)];
222
+ else {
223
+ let head = lines.slice(0, start);
224
+ while (head.length && head[head.length - 1] === "") head.pop();
225
+ const tail = lines.slice(end);
226
+ out = [...head, ...(tail.length && head.length ? [""] : []), ...tail];
227
+ }
228
+ let res = out.join("\n");
229
+ if (text.endsWith("\n") && !res.endsWith("\n")) res += "\n";
230
+ return res;
231
+ }
package/src/cli.mjs CHANGED
@@ -6,7 +6,7 @@ import { loadState, ownedBy, saveState, statePath } from "./state.mjs";
6
6
  import { stageCapture, unstageCapture } from "./capture.mjs";
7
7
  import { KEY_ENV, allTargets, targetById, tilde } from "./targets.mjs";
8
8
 
9
- export const VERSION = "0.2.0";
9
+ export const VERSION = "0.2.1";
10
10
  const DEFAULT_URL = "https://getwavebrain.com/api/mcp";
11
11
  const SETUP_URL = "https://getwavebrain.com/dashboard/setup";
12
12
 
package/src/targets.mjs CHANGED
@@ -27,6 +27,7 @@ import {
27
27
  hasOurHooks,
28
28
  hermesPluginFiles,
29
29
  hermesPluginToggle,
30
+ hermesUnlistPlugin,
30
31
  hookCommand,
31
32
  removeHooks,
32
33
  skillText,
@@ -408,6 +409,12 @@ const hermesParts = (profile) => (ctx) =>
408
409
  const hermesToggle = (profile) => (ctx, s, on) => {
409
410
  const id = profile ? `hermes:${profile}` : "hermes";
410
411
  if (s.dryRun) return [{ ref: `${id}:plugin-enabled`, file: path.join(hermesDir(ctx, profile), "config.yaml"), kind: on ? "enable plugin" : "disable plugin" }];
412
+ const file = path.join(hermesDir(ctx, profile), "config.yaml");
413
+ if (!on) {
414
+ // The plugin files are being deleted; take wavebrain off the plugin lists rather than marking it disabled.
415
+ const kind = s.edit(file, hermesUnlistPlugin);
416
+ return kind === "unchanged" ? [] : [{ ref: `${id}:plugin-enabled`, file, kind: "disabled plugin" }];
417
+ }
411
418
  if (!onPath(ctx, "hermes")) return [];
412
419
  const ok = hermesPluginToggle(ctx, hermesDir(ctx, profile), on);
413
420
  return ok ? [{ ref: `${id}:plugin-enabled`, file: path.join(hermesDir(ctx, profile), "config.yaml"), kind: on ? "enabled plugin" : "disabled plugin" }] : [];