@polderlabs/bizar-plugin 0.5.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/LICENSE +21 -0
- package/README.md +448 -0
- package/bun.lock +88 -0
- package/index.ts +1113 -0
- package/package.json +42 -0
- package/scripts/check-forbidden-imports.sh +33 -0
- package/src/background-state.ts +463 -0
- package/src/background.ts +964 -0
- package/src/commands-impl.ts +369 -0
- package/src/commands.ts +880 -0
- package/src/event-stream.ts +574 -0
- package/src/fingerprint.ts +120 -0
- package/src/handoff.ts +79 -0
- package/src/http-client.ts +467 -0
- package/src/logger.ts +144 -0
- package/src/loop.ts +176 -0
- package/src/options.ts +421 -0
- package/src/plan-fs.ts +323 -0
- package/src/report.ts +178 -0
- package/src/research-prompt.ts +35 -0
- package/src/serve.ts +476 -0
- package/src/settings.ts +349 -0
- package/src/state.ts +298 -0
- package/src/tools/bg-collect.ts +104 -0
- package/src/tools/bg-get-comments.ts +239 -0
- package/src/tools/bg-kill.ts +87 -0
- package/src/tools/bg-spawn.ts +263 -0
- package/src/tools/bg-status.ts +99 -0
- package/src/tools/plan-action.ts +767 -0
- package/src/tools/wait-for-feedback.ts +402 -0
- package/tests/attach-handler-bug.test.ts +166 -0
- package/tests/background-state.test.ts +277 -0
- package/tests/background.test.ts +402 -0
- package/tests/block.test.ts +193 -0
- package/tests/canonical-key-order.test.ts +71 -0
- package/tests/commands-impl.test.ts +442 -0
- package/tests/commands.test.ts +548 -0
- package/tests/config.test.ts +122 -0
- package/tests/dispose.test.ts +336 -0
- package/tests/event-stream.test.ts +409 -0
- package/tests/event.test.ts +262 -0
- package/tests/fingerprint.test.ts +161 -0
- package/tests/http-client.test.ts +403 -0
- package/tests/init-helpers.test.ts +203 -0
- package/tests/integration/slash-command.test.ts +348 -0
- package/tests/integration/tool-routing.test.ts +314 -0
- package/tests/loop.test.ts +397 -0
- package/tests/options.test.ts +274 -0
- package/tests/serve.test.ts +335 -0
- package/tests/settings.test.ts +351 -0
- package/tests/stall-think.test.ts +749 -0
- package/tests/state.test.ts +275 -0
- package/tests/tools/bg-collect.test.ts +337 -0
- package/tests/tools/bg-get-comments.test.ts +485 -0
- package/tests/tools/bg-kill.test.ts +231 -0
- package/tests/tools/bg-spawn.test.ts +311 -0
- package/tests/tools/bg-status.test.ts +216 -0
- package/tests/tools/plan-action.test.ts +599 -0
- package/tests/tools/wait-for-feedback.test.ts +390 -0
- package/tsconfig.json +29 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bizar_status tool tests.
|
|
3
|
+
*
|
|
4
|
+
* Tests: list all, single instance, filter, no instances,
|
|
5
|
+
* returns documented shape per §7.1. Read-only — any agent can call.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, it, expect } from "bun:test";
|
|
9
|
+
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Fake BackgroundState for testing
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
interface BackgroundState {
|
|
15
|
+
instanceId: string;
|
|
16
|
+
agent: string;
|
|
17
|
+
status: "pending" | "running" | "done" | "failed" | "killed" | "timed_out";
|
|
18
|
+
startedAt: number;
|
|
19
|
+
toolCallCount: number;
|
|
20
|
+
promptPreview: string;
|
|
21
|
+
resultPreview?: string;
|
|
22
|
+
error?: string;
|
|
23
|
+
parentAgent: string;
|
|
24
|
+
parentInstanceId?: string;
|
|
25
|
+
durationMs?: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function makeBgState(overrides: Partial<BackgroundState> = {}): BackgroundState {
|
|
29
|
+
return {
|
|
30
|
+
instanceId: "bgr_test_01",
|
|
31
|
+
agent: "mimir",
|
|
32
|
+
status: "running",
|
|
33
|
+
startedAt: Date.now() - 60_000,
|
|
34
|
+
toolCallCount: 12,
|
|
35
|
+
promptPreview: "Do the research on X",
|
|
36
|
+
resultPreview: undefined,
|
|
37
|
+
error: undefined,
|
|
38
|
+
parentAgent: "odin",
|
|
39
|
+
parentInstanceId: undefined,
|
|
40
|
+
durationMs: 60_000,
|
|
41
|
+
...overrides,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// Fake bizar_status implementation (read-only — any agent can call)
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
|
|
49
|
+
function bizar_status(
|
|
50
|
+
args: { instanceId?: string } | undefined,
|
|
51
|
+
_ctx: { agent: string },
|
|
52
|
+
instances: Map<string, BackgroundState>,
|
|
53
|
+
): BackgroundState[] | BackgroundState | { error: string } {
|
|
54
|
+
if (!args || args.instanceId === undefined) {
|
|
55
|
+
// Return all
|
|
56
|
+
return [...instances.values()];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const inst = instances.get(args.instanceId);
|
|
60
|
+
if (!inst) {
|
|
61
|
+
return { error: `Instance ${args.instanceId} not found` };
|
|
62
|
+
}
|
|
63
|
+
return inst;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// In-memory instance store for tests
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
|
|
70
|
+
const instances = new Map<string, BackgroundState>();
|
|
71
|
+
instances.set("bgr_01", makeBgState({ instanceId: "bgr_01", agent: "mimir", status: "running" }));
|
|
72
|
+
instances.set("bgr_02", makeBgState({ instanceId: "bgr_02", agent: "thor", status: "done", resultPreview: "Done!", completedAt: Date.now() }));
|
|
73
|
+
instances.set("bgr_03", makeBgState({ instanceId: "bgr_03", agent: "tyr", status: "failed", error: "Loop protection: 12 identical calls to read" }));
|
|
74
|
+
|
|
75
|
+
function makeCompletedState(overrides: Partial<BackgroundState> = {}): BackgroundState {
|
|
76
|
+
return {
|
|
77
|
+
instanceId: "bgr_completed",
|
|
78
|
+
agent: "mimir",
|
|
79
|
+
status: "done",
|
|
80
|
+
startedAt: Date.now() - 120_000,
|
|
81
|
+
toolCallCount: 5,
|
|
82
|
+
promptPreview: "Quick task",
|
|
83
|
+
resultPreview: "All done!",
|
|
84
|
+
error: undefined,
|
|
85
|
+
parentAgent: "odin",
|
|
86
|
+
parentInstanceId: undefined,
|
|
87
|
+
durationMs: 120_000,
|
|
88
|
+
...overrides,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
// bizarre_status — list all
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
|
|
96
|
+
describe("bizar_status — list all", () => {
|
|
97
|
+
it("returns all instances when called with no args", () => {
|
|
98
|
+
const result = bizar_status(undefined, { agent: "odin" }, instances);
|
|
99
|
+
expect(Array.isArray(result)).toBe(true);
|
|
100
|
+
expect((result as BackgroundState[]).length).toBe(3);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("includes all documented fields per instance (§7.1)", () => {
|
|
104
|
+
const all = bizar_status(undefined, { agent: "odin" }, instances) as BackgroundState[];
|
|
105
|
+
const first = all[0];
|
|
106
|
+
expect(first).toHaveProperty("instanceId");
|
|
107
|
+
expect(first).toHaveProperty("agent");
|
|
108
|
+
expect(first).toHaveProperty("status");
|
|
109
|
+
expect(first).toHaveProperty("startedAt");
|
|
110
|
+
expect(first).toHaveProperty("toolCallCount");
|
|
111
|
+
expect(first).toHaveProperty("promptPreview");
|
|
112
|
+
expect(first).toHaveProperty("resultPreview");
|
|
113
|
+
expect(first).toHaveProperty("error");
|
|
114
|
+
expect(first).toHaveProperty("parentAgent");
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("returns instances in any order (stable map iteration)", () => {
|
|
118
|
+
const all = bizar_status(undefined, { agent: "odin" }, instances) as BackgroundState[];
|
|
119
|
+
const ids = all.map((i) => i.instanceId);
|
|
120
|
+
expect(ids).toContain("bgr_01");
|
|
121
|
+
expect(ids).toContain("bgr_02");
|
|
122
|
+
expect(ids).toContain("bgr_03");
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("any agent can call bizar_status (read-only)", () => {
|
|
126
|
+
for (const agent of ["odin", "vor", "frigg", "mimir", "thor", "tyr", "heimdall"]) {
|
|
127
|
+
const result = bizar_status(undefined, { agent }, instances);
|
|
128
|
+
expect(Array.isArray(result)).toBe(true);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// ---------------------------------------------------------------------------
|
|
134
|
+
// bizar_status — single instance
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
|
|
137
|
+
describe("bizar_status — single instance", () => {
|
|
138
|
+
it("returns the requested instance", () => {
|
|
139
|
+
const result = bizar_status({ instanceId: "bgr_02" }, { agent: "odin" }, instances);
|
|
140
|
+
expect((result as BackgroundState).instanceId).toBe("bgr_02");
|
|
141
|
+
expect((result as BackgroundState).agent).toBe("thor");
|
|
142
|
+
expect((result as BackgroundState).status).toBe("done");
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("returns error for unknown instanceId", () => {
|
|
146
|
+
const result = bizar_status({ instanceId: "bgr_unknown" }, { agent: "odin" }, instances);
|
|
147
|
+
expect(result).toHaveProperty("error");
|
|
148
|
+
expect((result as { error: string }).error).toContain("not found");
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// ---------------------------------------------------------------------------
|
|
153
|
+
// Status values
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
|
|
156
|
+
describe("bizar_status — status values", () => {
|
|
157
|
+
it("running instance shows running status", () => {
|
|
158
|
+
const result = bizar_status({ instanceId: "bgr_01" }, { agent: "odin" }, instances) as BackgroundState;
|
|
159
|
+
expect(result.status).toBe("running");
|
|
160
|
+
expect(result.resultPreview).toBeUndefined();
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it("done instance shows resultPreview", () => {
|
|
164
|
+
const result = bizar_status({ instanceId: "bgr_02" }, { agent: "odin" }, instances) as BackgroundState;
|
|
165
|
+
expect(result.status).toBe("done");
|
|
166
|
+
expect(result.resultPreview).toBe("Done!");
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("failed instance shows error", () => {
|
|
170
|
+
const result = bizar_status({ instanceId: "bgr_03" }, { agent: "odin" }, instances) as BackgroundState;
|
|
171
|
+
expect(result.status).toBe("failed");
|
|
172
|
+
expect(result.error).toContain("Loop protection");
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// ---------------------------------------------------------------------------
|
|
177
|
+
// No instances
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
|
|
180
|
+
describe("bizar_status — no instances", () => {
|
|
181
|
+
it("returns empty array when no instances exist", () => {
|
|
182
|
+
const emptyMap = new Map<string, BackgroundState>();
|
|
183
|
+
const result = bizar_status(undefined, { agent: "odin" }, emptyMap);
|
|
184
|
+
expect(Array.isArray(result)).toBe(true);
|
|
185
|
+
expect((result as BackgroundState[]).length).toBe(0);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it("returns error for unknown instanceId when map is empty", () => {
|
|
189
|
+
const emptyMap = new Map<string, BackgroundState>();
|
|
190
|
+
const result = bizar_status({ instanceId: "bgr_anything" }, { agent: "odin" }, emptyMap);
|
|
191
|
+
expect(result).toHaveProperty("error");
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// ---------------------------------------------------------------------------
|
|
196
|
+
// Duration calculation
|
|
197
|
+
// ---------------------------------------------------------------------------
|
|
198
|
+
|
|
199
|
+
describe("bizar_status — durationMs", () => {
|
|
200
|
+
it("durationMs is derived from startedAt and now (or completedAt)", () => {
|
|
201
|
+
// Test the concept: durationMs is computed from startedAt vs now/completedAt
|
|
202
|
+
// In a real instance, running.durationMs would be Date.now() - startedAt
|
|
203
|
+
// Here we just verify the field exists and is a number
|
|
204
|
+
const running = makeBgState({ startedAt: Date.now() - 30_000, status: "running" });
|
|
205
|
+
expect(typeof running.durationMs).toBe("number");
|
|
206
|
+
expect(running.durationMs).toBeGreaterThan(0);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it("durationMs uses completedAt when instance is done", () => {
|
|
210
|
+
// completedAt - startedAt gives the actual duration
|
|
211
|
+
const startedAt = Date.now() - 60_000;
|
|
212
|
+
const completedAt = Date.now() - 30_000;
|
|
213
|
+
const expectedDuration = completedAt - startedAt;
|
|
214
|
+
expect(expectedDuration).toBe(30_000);
|
|
215
|
+
});
|
|
216
|
+
});
|