@polderlabs/bizar 5.4.1 → 5.5.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.
Files changed (119) hide show
  1. package/bizar-dash/dist/assets/{EnvVarsSection-DhLHZ5ua.js → EnvVarsSection-BUQnyVQD.js} +3 -3
  2. package/bizar-dash/dist/assets/{EnvVarsSection-DhLHZ5ua.js.map → EnvVarsSection-BUQnyVQD.js.map} +1 -1
  3. package/bizar-dash/dist/assets/{MobileChat-9UpvDP6-.js → MobileChat-8FupFgTv.js} +1 -1
  4. package/bizar-dash/dist/assets/{MobileChat-9UpvDP6-.js.map → MobileChat-8FupFgTv.js.map} +1 -1
  5. package/bizar-dash/dist/assets/MobileSettings-BkXtglA6.js +1 -0
  6. package/bizar-dash/dist/assets/MobileSettings-BkXtglA6.js.map +1 -0
  7. package/bizar-dash/dist/assets/{Toast-BlcKl_dN.js → Toast-CUwkLRms.js} +1 -1
  8. package/bizar-dash/dist/assets/{Toast-BlcKl_dN.js.map → Toast-CUwkLRms.js.map} +1 -1
  9. package/bizar-dash/dist/assets/{icons-CMPxNV8t.js → icons-COpQr35l.js} +125 -110
  10. package/bizar-dash/dist/assets/icons-COpQr35l.js.map +1 -0
  11. package/bizar-dash/dist/assets/main-Bz_zWFCw.css +1 -0
  12. package/bizar-dash/dist/assets/main-gqVwliHz.js +18 -0
  13. package/bizar-dash/dist/assets/main-gqVwliHz.js.map +1 -0
  14. package/bizar-dash/dist/assets/mobile-B7dAkmYd.js +1 -0
  15. package/bizar-dash/dist/assets/{mobile-DDY1lquG.js.map → mobile-B7dAkmYd.js.map} +1 -1
  16. package/bizar-dash/dist/assets/mobile-layout-ClC6Qa42.js +2 -0
  17. package/bizar-dash/dist/assets/mobile-layout-ClC6Qa42.js.map +1 -0
  18. package/bizar-dash/dist/assets/{useSlashCommands-eFCiWHVt.js → useSlashCommands-B3MZ1JXa.js} +2 -2
  19. package/bizar-dash/dist/assets/{useSlashCommands-eFCiWHVt.js.map → useSlashCommands-B3MZ1JXa.js.map} +1 -1
  20. package/bizar-dash/dist/index.html +7 -7
  21. package/bizar-dash/dist/mobile.html +3 -3
  22. package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  23. package/bizar-dash/src/server/backup-store.mjs +6 -1
  24. package/bizar-dash/src/server/bg-spawner.mjs +791 -0
  25. package/bizar-dash/src/server/headroom.mjs +3 -1
  26. package/bizar-dash/src/server/memory-lightrag.mjs +268 -2
  27. package/bizar-dash/src/server/memory-store.mjs +43 -3
  28. package/bizar-dash/src/server/opencode-sdk.mjs +63 -3
  29. package/bizar-dash/src/server/plugins/registry.mjs +1 -1
  30. package/bizar-dash/src/server/routes/activity.mjs +85 -0
  31. package/bizar-dash/src/server/routes/background.mjs +161 -0
  32. package/bizar-dash/src/server/routes/lightrag.mjs +10 -0
  33. package/bizar-dash/src/server/routes/memory.mjs +8 -0
  34. package/bizar-dash/src/server/routes/opencode-session-detail.mjs +1 -1
  35. package/bizar-dash/src/server/server.mjs +26 -1
  36. package/bizar-dash/src/web/App.tsx +46 -36
  37. package/bizar-dash/src/web/components/InstallConfirmDialog.tsx +1 -1
  38. package/bizar-dash/src/web/components/Sidebar.tsx +7 -27
  39. package/bizar-dash/src/web/components/Topbar.tsx +48 -11
  40. package/bizar-dash/src/web/lib/types.ts +39 -1
  41. package/bizar-dash/src/web/styles/main.css +93 -26
  42. package/bizar-dash/src/web/styles/memory.css +17 -0
  43. package/bizar-dash/src/web/styles/settings.css +9 -171
  44. package/bizar-dash/src/web/views/BackgroundAgents.tsx +399 -30
  45. package/bizar-dash/src/web/views/Marketplace.tsx +192 -31
  46. package/bizar-dash/src/web/views/Settings.tsx +205 -184
  47. package/bizar-dash/src/web/views/SpawnAgentModal.tsx +221 -0
  48. package/bizar-dash/src/web/views/memory/ConfigPanel.tsx +157 -7
  49. package/bizar-dash/src/web/views/memory/MemoryOverview.tsx +11 -0
  50. package/bizar-dash/src/web/views/settings/MemorySection.tsx +65 -11
  51. package/bizar-dash/tests/BackgroundAgents.test.tsx +160 -0
  52. package/bizar-dash/tests/background-pause-resume.test.mjs +46 -0
  53. package/bizar-dash/tests/background-sdk-session.test.mjs +94 -0
  54. package/bizar-dash/tests/background-session-events.test.mjs +74 -0
  55. package/bizar-dash/tests/background-spawn-from-ui.test.mjs +36 -0
  56. package/bizar-dash/tests/background-steer-sdk.test.mjs +71 -0
  57. package/bizar-dash/tests/background-steer.test.mjs +60 -0
  58. package/bizar-dash/tests/lightrag-startup-hook.test.mjs +206 -0
  59. package/bizar-dash/tests/memory-auto-reindex.test.mjs +196 -0
  60. package/bizar-dash/tests/memory-cli.test.mjs +1 -1
  61. package/bizar-dash/tests/memory-default-vault.test.mjs +90 -3
  62. package/bizar-dash/tests/memory-lightrag-extended.test.mjs +131 -0
  63. package/bizar-dash/tests/views/Marketplace.test.tsx +200 -0
  64. package/bizar-dash/tests/views/Memory.test.tsx +235 -0
  65. package/bizar-dash/tests/views/Settings.test.tsx +160 -0
  66. package/bizar-dash/tests/views/sidebar.test.tsx +116 -0
  67. package/bizar-dash/tests/views/topbar.test.tsx +102 -0
  68. package/cli/bin.mjs +16 -0
  69. package/cli/commands/deploy/docker.mjs +2 -1
  70. package/cli/commands/lightrag.mjs +171 -0
  71. package/cli/commands/marketplace.mjs +1 -1
  72. package/cli/commands/service.mjs +7 -0
  73. package/cli/commands/util.mjs +8 -1
  74. package/cli/init.mjs +1 -1
  75. package/cli/post-install-smoke.mjs +230 -0
  76. package/cli/provision.mjs +177 -0
  77. package/cli/provision.test.mjs +180 -0
  78. package/cli/service-controller.mjs +378 -28
  79. package/cli/service-controller.test.mjs +100 -0
  80. package/cli/service-env.mjs +139 -0
  81. package/cli/service.mjs +23 -0
  82. package/config/agents/_shared/AGENT_BASELINE.md +6 -6
  83. package/install.sh +87 -6
  84. package/package.json +1 -1
  85. package/plugins/bizar/index.ts +147 -0
  86. package/plugins/bizar/src/background-state.ts +95 -5
  87. package/plugins/bizar/src/background.ts +571 -15
  88. package/plugins/bizar/src/hooks/memory-inject.ts +247 -0
  89. package/plugins/bizar/src/hooks/memory-write-on-end.ts +188 -0
  90. package/plugins/bizar/src/opencode-runner.ts +100 -287
  91. package/plugins/bizar/src/tools/bg-pause.ts +77 -0
  92. package/plugins/bizar/src/tools/bg-report-progress.ts +101 -0
  93. package/plugins/bizar/src/tools/bg-resume.ts +72 -0
  94. package/plugins/bizar/src/tools/bg-send-message.ts +204 -0
  95. package/plugins/bizar/src/tools/bg-spawn.ts +237 -151
  96. package/plugins/bizar/src/tools/bg-status.ts +10 -0
  97. package/plugins/bizar/src/tools/memory-list.ts +135 -0
  98. package/plugins/bizar/src/tools/memory-read.ts +142 -0
  99. package/plugins/bizar/src/tools/memory-search.ts +228 -0
  100. package/plugins/bizar/src/tools/memory-write.ts +183 -0
  101. package/plugins/bizar/tests/memory-write-on-end.test.ts +92 -0
  102. package/plugins/bizar/tests/tools/bg-pause.test.ts +64 -0
  103. package/plugins/bizar/tests/tools/bg-report-progress.test.ts +82 -0
  104. package/plugins/bizar/tests/tools/bg-resume.test.ts +43 -0
  105. package/plugins/bizar/tests/tools/bg-send-message.test.ts +119 -0
  106. package/plugins/bizar/tests/tools/bg-spawn-http.test.ts +223 -0
  107. package/bizar-dash/dist/assets/MobileSettings-BFmN9ZWR.js +0 -1
  108. package/bizar-dash/dist/assets/MobileSettings-BFmN9ZWR.js.map +0 -1
  109. package/bizar-dash/dist/assets/icons-CMPxNV8t.js.map +0 -1
  110. package/bizar-dash/dist/assets/main-Dhrvp9Gt.js +0 -16
  111. package/bizar-dash/dist/assets/main-Dhrvp9Gt.js.map +0 -1
  112. package/bizar-dash/dist/assets/main-O2tZVdHm.css +0 -1
  113. package/bizar-dash/dist/assets/mobile-DDY1lquG.js +0 -1
  114. package/bizar-dash/dist/assets/mobile-layout-BjkoHh1W.js +0 -2
  115. package/bizar-dash/dist/assets/mobile-layout-BjkoHh1W.js.map +0 -1
  116. package/bizar-dash/src/web/components/SettingsNav.tsx +0 -101
  117. package/bizar-dash/tests/settings-layout.test.tsx +0 -129
  118. package/bizar-dash/tests/settings-mode-wiring.test.tsx +0 -151
  119. package/bizar-dash/tests/settings-nav.test.tsx +0 -126
@@ -0,0 +1,72 @@
1
+ /**
2
+ * plugins/bizar/src/tools/bg-resume.ts
3
+ *
4
+ * v5.x — `bizar_resume` tool. Sends SIGCONT to a paused background
5
+ * agent's subprocess. Companion to {@link ./bg-pause.ts}.
6
+ *
7
+ * Odin-only.
8
+ */
9
+ import { tool } from "@opencode-ai/plugin";
10
+ import { z } from "zod";
11
+
12
+ import type { InstanceManager } from "../background.js";
13
+ import type { Logger } from "../logger.js";
14
+
15
+ export interface BgResumeDeps {
16
+ instanceManager: InstanceManager;
17
+ logger: Logger;
18
+ }
19
+
20
+ export function createBgResumeTool(deps: BgResumeDeps) {
21
+ return tool({
22
+ description:
23
+ "Resume a paused background agent by sending SIGCONT to its subprocess. " +
24
+ "Only Odin may resume. No-op on already-running instances. POSIX only.",
25
+ args: {
26
+ instanceId: z
27
+ .string()
28
+ .min(1)
29
+ .describe("Instance id returned by bizar_spawn_background."),
30
+ },
31
+ execute: async (rawArgs, ctx) => {
32
+ if (ctx.agent !== "odin") {
33
+ return {
34
+ output: JSON.stringify({
35
+ error:
36
+ "Only Odin can resume background agents. Use bizar_status to inspect or ask Odin to resume.",
37
+ }),
38
+ };
39
+ }
40
+ const args = rawArgs as { instanceId: string };
41
+ try {
42
+ const result = await deps.instanceManager.resume(args.instanceId);
43
+ if (!result.ok) {
44
+ return {
45
+ output: JSON.stringify({
46
+ error: result.error || "resume failed",
47
+ instanceId: args.instanceId,
48
+ }),
49
+ };
50
+ }
51
+ return {
52
+ output: JSON.stringify({
53
+ instanceId: args.instanceId,
54
+ status: "running",
55
+ }),
56
+ };
57
+ } catch (err: unknown) {
58
+ deps.logger.warn(
59
+ `bizar: resume(${args.instanceId}) threw: ${
60
+ err instanceof Error ? err.message : String(err)
61
+ }`,
62
+ );
63
+ return {
64
+ output: JSON.stringify({
65
+ error: `resume threw: ${err instanceof Error ? err.message : String(err)}`,
66
+ instanceId: args.instanceId,
67
+ }),
68
+ };
69
+ }
70
+ },
71
+ });
72
+ }
@@ -0,0 +1,204 @@
1
+ /**
2
+ * plugins/bizar/src/tools/bg-send-message.ts
3
+ *
4
+ * v5.5.1 — `bizar_send_message` tool. TRUE mid-flight steer.
5
+ *
6
+ * In v5.5.0 this tool returned `unavailable_in_subprocess_mode` because
7
+ * `opencode run` is a one-shot CLI. v5.5.1 switched bg agents to
8
+ * long-lived opencode serve SDK sessions, so this tool now delegates
9
+ * to `POST /api/background/<id>/steer` on the dashboard. The dashboard
10
+ * calls `sdk.sessions.prompt()` on the live session, which the
11
+ * opencode serve child picks up mid-loop as the next user turn.
12
+ *
13
+ * Wire contract (mirrors `bizar-dash/src/server/routes/background.mjs`):
14
+ * - Request: `POST /api/background/:id/steer` with body `{ message }`.
15
+ * - Response: `{ ok, mode: 'true_midflight', newInstanceId: null, instanceId, steerCount }`.
16
+ *
17
+ * Errors surface as `{ ok: false, error }` so callers can react.
18
+ */
19
+ import { tool } from "@opencode-ai/plugin";
20
+ import { z } from "zod";
21
+
22
+ import type { InstanceManager } from "../background.js";
23
+ import type { Logger } from "../logger.js";
24
+ import { readFileSync, existsSync } from "node:fs";
25
+ import { join } from "node:path";
26
+ import { homedir } from "node:os";
27
+
28
+ export interface BgSendMessageDeps {
29
+ instanceManager: InstanceManager;
30
+ logger: Logger;
31
+ /**
32
+ * Optional injection point for tests. When provided, the dashboard
33
+ * HTTP call is short-circuited and the test function is called with
34
+ * the resolved request shape.
35
+ */
36
+ _dashboardPost?: (url: string, init: { headers: Record<string, string>; body: string }) => Promise<{ ok: boolean; status: number; json: () => Promise<unknown> }>;
37
+ }
38
+
39
+ // --- Dashboard URL + token (mirrors bg-spawn.ts) ------------------------
40
+
41
+ function resolveDashboardUrl(): string {
42
+ const fromEnv = process.env.BIZAR_DASHBOARD_URL;
43
+ if (fromEnv && fromEnv.trim()) return fromEnv.trim().replace(/\/+$/, "");
44
+ const port = process.env.BIZAR_DASHBOARD_PORT;
45
+ if (port && /^\d+$/.test(port)) return `http://127.0.0.1:${port}`;
46
+ return "http://127.0.0.1:4098";
47
+ }
48
+
49
+ const DEFAULT_DASHBOARD_AUTH_PATHS = [
50
+ join(homedir(), ".config", "bizar", "dashboard-secret"),
51
+ join(homedir(), ".cache", "bizarharness", "dash-auth.json"),
52
+ join(homedir(), ".cache", "bizar", "dash-auth.json"),
53
+ ];
54
+
55
+ function readDashboardToken(): string {
56
+ for (const candidate of DEFAULT_DASHBOARD_AUTH_PATHS) {
57
+ try {
58
+ if (!existsSync(candidate)) continue;
59
+ const text = readFileSync(candidate, "utf-8").trim();
60
+ if (text && text.length >= 16) return text;
61
+ } catch {
62
+ /* ignore */
63
+ }
64
+ }
65
+ for (const candidate of DEFAULT_DASHBOARD_AUTH_PATHS) {
66
+ try {
67
+ if (!existsSync(candidate)) continue;
68
+ const parsed = JSON.parse(readFileSync(candidate, "utf-8")) as { password?: unknown };
69
+ if (typeof parsed.password === "string" && parsed.password.length >= 16) {
70
+ return parsed.password;
71
+ }
72
+ } catch {
73
+ /* ignore */
74
+ }
75
+ }
76
+ return "";
77
+ }
78
+
79
+ async function postJsonToDashboard(
80
+ url: string,
81
+ body: unknown,
82
+ override?: BgSendMessageDeps["_dashboardPost"],
83
+ ): Promise<unknown> {
84
+ if (override) {
85
+ const res = await override(url, {
86
+ headers: { "content-type": "application/json" },
87
+ body: JSON.stringify(body),
88
+ });
89
+ if (!res.ok) {
90
+ const text = await res.json().catch(() => ({}));
91
+ const err = new Error(
92
+ `dashboard HTTP ${res.status}: ${JSON.stringify(text).slice(0, 200)}`,
93
+ );
94
+ (err as Error & { httpStatus?: number }).httpStatus = res.status;
95
+ throw err;
96
+ }
97
+ return res.json();
98
+ }
99
+ const token = readDashboardToken();
100
+ const headers: Record<string, string> = {
101
+ "content-type": "application/json",
102
+ accept: "application/json",
103
+ };
104
+ if (token) headers.authorization = `Bearer ${token}`;
105
+
106
+ const ac = new AbortController();
107
+ const timer = setTimeout(() => ac.abort(), 8_000);
108
+ try {
109
+ const res = await fetch(url, {
110
+ method: "POST",
111
+ headers,
112
+ body: JSON.stringify(body),
113
+ signal: ac.signal,
114
+ });
115
+ if (!res.ok) {
116
+ const text = await res.text().catch(() => "");
117
+ const err = new Error(
118
+ `dashboard HTTP ${res.status}: ${text.slice(0, 200)}`,
119
+ );
120
+ (err as Error & { httpStatus?: number }).httpStatus = res.status;
121
+ throw err;
122
+ }
123
+ return res.json();
124
+ } finally {
125
+ clearTimeout(timer);
126
+ }
127
+ }
128
+
129
+ export function createBgSendMessageTool(deps: BgSendMessageDeps) {
130
+ return tool({
131
+ description:
132
+ "Send a follow-up message to a running background agent. " +
133
+ "v5.5.1: TRUE mid-flight steer via the opencode serve SDK. " +
134
+ "The same instance keeps running; the new message becomes the next user turn " +
135
+ "of the running opencode session. No kill+respawn, no [STEERED <ts>] marker, " +
136
+ "no loss of agent context.",
137
+ args: {
138
+ instanceId: z
139
+ .string()
140
+ .min(1)
141
+ .describe("Instance id returned by bizar_spawn_background."),
142
+ message: z
143
+ .string()
144
+ .min(1)
145
+ .describe("The follow-up instruction to send."),
146
+ },
147
+ execute: async (rawArgs, _ctx) => {
148
+ const args = rawArgs as { instanceId: string; message: string };
149
+ // 1. Verify the instance exists so we don't silently accept bogus ids.
150
+ const inst = await deps.instanceManager.get(args.instanceId);
151
+ if (!inst) {
152
+ return {
153
+ output: JSON.stringify({
154
+ error: "instance_not_found",
155
+ instanceId: args.instanceId,
156
+ }),
157
+ };
158
+ }
159
+
160
+ // 2. v5.5.1 — delegate to the dashboard. The dashboard owns the
161
+ // opencode SDK and calls `sdk.sessions.prompt({...})` on the
162
+ // live session, which the opencode serve child picks up
163
+ // mid-loop as the next user turn.
164
+ const dashboardUrl = `${resolveDashboardUrl()}/api/background/${encodeURIComponent(args.instanceId)}/steer`;
165
+ try {
166
+ const data = (await postJsonToDashboard(
167
+ dashboardUrl,
168
+ { message: args.message },
169
+ deps._dashboardPost,
170
+ )) as { ok: boolean; mode?: string; steerCount?: number; error?: string };
171
+ if (!data || data.ok !== true) {
172
+ return {
173
+ output: JSON.stringify({
174
+ error: data?.error || "steer_failed",
175
+ instanceId: args.instanceId,
176
+ }),
177
+ };
178
+ }
179
+ deps.logger.info(
180
+ `bizar: sendMessage(${args.instanceId}) — TRUE mid-flight steer #${data.steerCount ?? "?"} accepted`,
181
+ );
182
+ return {
183
+ output: JSON.stringify({
184
+ ok: true,
185
+ mode: data.mode || "true_midflight",
186
+ instanceId: args.instanceId,
187
+ steerCount: data.steerCount ?? 0,
188
+ message:
189
+ "Steer delivered to the running opencode session. The agent will pick up your message as the next user turn — no kill+respawn was performed, no context was lost.",
190
+ }),
191
+ };
192
+ } catch (err: unknown) {
193
+ const msg = err instanceof Error ? err.message : String(err);
194
+ deps.logger.warn(`bizar: sendMessage(${args.instanceId}) failed: ${msg}`);
195
+ return {
196
+ output: JSON.stringify({
197
+ error: `steer_failed: ${msg}`,
198
+ instanceId: args.instanceId,
199
+ }),
200
+ };
201
+ }
202
+ },
203
+ });
204
+ }