@polderlabs/bizar-plugin 0.6.2 → 0.8.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.
@@ -27,13 +27,13 @@ function parseModel(model: string | undefined): { providerID: string; modelID: s
27
27
  const parts = model.split("/");
28
28
  if (parts.length !== 2) {
29
29
  throw new Error(
30
- `model must be in "providerID/modelID" format (e.g. "openrouter/minimax-m3"). Omit to use the agent's default.`,
30
+ `model must be in "providerID/modelID" format (e.g. "minimax/minimax-m3"). Omit to use the agent's default.`,
31
31
  );
32
32
  }
33
33
  const [providerID, modelID] = parts;
34
34
  if (!providerID || !modelID) {
35
35
  throw new Error(
36
- `model must be in "providerID/modelID" format (e.g. "openrouter/minimax-m3"). Omit to use the agent's default.`,
36
+ `model must be in "providerID/modelID" format (e.g. "minimax/minimax-m3"). Omit to use the agent's default.`,
37
37
  );
38
38
  }
39
39
  return { providerID, modelID };
@@ -132,9 +132,9 @@ describe("bizar_spawn_background — Odin-only", () => {
132
132
  // ---------------------------------------------------------------------------
133
133
 
134
134
  describe("bizar_spawn_background — model parsing (HIGH-3, LOW-34)", () => {
135
- it('"openrouter/minimax-m3" parses to { providerID: "openrouter", modelID: "minimax-m3" }', () => {
136
- const result = parseModel("openrouter/minimax-m3");
137
- expect(result).toEqual({ providerID: "openrouter", modelID: "minimax-m3" });
135
+ it('"minimax/minimax-m3" parses to { providerID: "minimax", modelID: "minimax-m3" }', () => {
136
+ const result = parseModel("minimax/minimax-m3");
137
+ expect(result).toEqual({ providerID: "minimax", modelID: "minimax-m3" });
138
138
  });
139
139
 
140
140
  it('"opencode/deepseek-v4-flash-free" parses correctly', () => {
@@ -168,7 +168,7 @@ describe("bizar_spawn_background — model parsing (HIGH-3, LOW-34)", () => {
168
168
 
169
169
  it("spawn tool includes parsed model in POST /session body", () => {
170
170
  const result = bizarre_spawn_background(
171
- { agent: "mimir", prompt: "Do X", model: "openrouter/minimax-m3" },
171
+ { agent: "mimir", prompt: "Do X", model: "minimax/minimax-m3" },
172
172
  { agent: "odin", sessionID: "sess_parent", worktree: "/tmp" },
173
173
  );
174
174
  expect(result).not.toHaveProperty("error");
@@ -0,0 +1,115 @@
1
+ /**
2
+ * plugins/bizar/tests/tools/opencode-runner.test.ts
3
+ *
4
+ * Unit tests for `buildOpencodeRunArgs` — the pure helper extracted
5
+ * from `plugins/bizar/src/opencode-runner.ts` so the argv passed to
6
+ * `Bun.spawn(["opencode", "run", ...])` can be asserted without
7
+ * spawning a real process.
8
+ *
9
+ * These tests pin the two regressions that motivated the extraction:
10
+ *
11
+ * 1. Bug 1 (HIGH): the `--agent` flag was missing from the args list,
12
+ * so `opencode run` silently fell back to the opencode default
13
+ * agent and broke session attribution.
14
+ *
15
+ * 2. Bug 2 (HIGH): the OpenRouter model IDs were renamed. Tests assert
16
+ * the new `minimax/minimax-m3` / `minimax/minimax-m2.7` format so
17
+ * a stale `openrouter/minimax-m3` reference is caught immediately.
18
+ */
19
+
20
+ import { describe, it, expect } from "bun:test";
21
+ import {
22
+ buildOpencodeRunArgs,
23
+ type SpawnAgentOptions,
24
+ } from "../../src/opencode-runner";
25
+
26
+ function baseOpts(overrides: Partial<SpawnAgentOptions> = {}): SpawnAgentOptions {
27
+ return {
28
+ agent: "thor",
29
+ prompt: "Investigate the auth module",
30
+ worktree: "/tmp/worktree",
31
+ logPath: "/tmp/worktree/.bgr/log.log",
32
+ ...overrides,
33
+ };
34
+ }
35
+
36
+ describe("buildOpencodeRunArgs — Bug 1 regression: --agent flag", () => {
37
+ it("argv contains the --agent flag followed by the agent name", () => {
38
+ const args = buildOpencodeRunArgs(baseOpts({ agent: "thor" }));
39
+ const i = args.indexOf("--agent");
40
+ expect(i).toBeGreaterThanOrEqual(0);
41
+ expect(args[i + 1]).toBe("thor");
42
+ });
43
+
44
+ it("--agent value matches opts.agent exactly (no default fallback)", () => {
45
+ for (const agent of ["mimir", "thor", "tyr", "heimdall", "hermod"]) {
46
+ const args = buildOpencodeRunArgs(baseOpts({ agent }));
47
+ expect(args[args.indexOf("--agent") + 1]).toBe(agent);
48
+ }
49
+ });
50
+
51
+ it("throws a clear error when opts.agent is empty", () => {
52
+ expect(() => buildOpencodeRunArgs(baseOpts({ agent: "" }))).toThrow(
53
+ /agent is required/,
54
+ );
55
+ });
56
+ });
57
+
58
+ describe("buildOpencodeRunArgs — Bug 2 regression: migrated model ID", () => {
59
+ it("emits --model with the migrated 'minimax/minimax-m3' ID", () => {
60
+ const args = buildOpencodeRunArgs(
61
+ baseOpts({
62
+ model: { providerID: "minimax", modelID: "minimax-m3" },
63
+ }),
64
+ );
65
+ const i = args.indexOf("--model");
66
+ expect(i).toBeGreaterThanOrEqual(0);
67
+ expect(args[i + 1]).toBe("minimax/minimax-m3");
68
+ // The full flag pair proves the migration target — the OLD ID would
69
+ // be 'openrouter/minimax-m3'; the NEW ID is 'minimax/minimax-m3'.
70
+ expect(args[i + 1]).not.toBe("openrouter/minimax-m3");
71
+ });
72
+
73
+ it("emits --model with the migrated 'minimax/minimax-m2.7' ID", () => {
74
+ const args = buildOpencodeRunArgs(
75
+ baseOpts({
76
+ model: { providerID: "minimax", modelID: "minimax-m2.7" },
77
+ }),
78
+ );
79
+ expect(args[args.indexOf("--model") + 1]).toBe("minimax/minimax-m2.7");
80
+ });
81
+
82
+ it("omits --model entirely when opts.model is not provided", () => {
83
+ const args = buildOpencodeRunArgs(baseOpts({ model: undefined }));
84
+ expect(args).not.toContain("--model");
85
+ });
86
+ });
87
+
88
+ describe("buildOpencodeRunArgs — arg layout", () => {
89
+ it("starts with 'opencode' 'run'", () => {
90
+ const args = buildOpencodeRunArgs(baseOpts());
91
+ expect(args[0]).toBe("opencode");
92
+ expect(args[1]).toBe("run");
93
+ });
94
+
95
+ it("appends prompt after the -- separator", () => {
96
+ const args = buildOpencodeRunArgs(baseOpts({ prompt: "do the thing" }));
97
+ const sep = args.indexOf("--");
98
+ expect(sep).toBeGreaterThanOrEqual(0);
99
+ expect(args[sep + 1]).toBe("do the thing");
100
+ });
101
+
102
+ it("uses opts.title when provided, else defaults to bgr:<agent>:<ts>", () => {
103
+ const a = buildOpencodeRunArgs(baseOpts({ title: "custom title" }));
104
+ expect(a[a.indexOf("--title") + 1]).toBe("custom title");
105
+
106
+ const b = buildOpencodeRunArgs(baseOpts({ agent: "mimir" }));
107
+ expect(b[b.indexOf("--title") + 1]).toMatch(/^bgr:mimir:\d+$/);
108
+ });
109
+
110
+ it("wires --dir to opts.worktree and --log-level to INFO", () => {
111
+ const args = buildOpencodeRunArgs(baseOpts({ worktree: "/srv/repo" }));
112
+ expect(args[args.indexOf("--dir") + 1]).toBe("/srv/repo");
113
+ expect(args[args.indexOf("--log-level") + 1]).toBe("INFO");
114
+ });
115
+ });
@@ -75,6 +75,7 @@ function createManager(stateDir: string): {
75
75
  maxConcurrent: 8,
76
76
  toolCallCap: 250,
77
77
  logger,
78
+ worktree: "/tmp",
78
79
  serve: { worktree: "/tmp" } as never,
79
80
  http: {} as never,
80
81
  stream: new FakeEventStream() as never,