@polderlabs/bizar 5.5.0 → 5.5.2
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/bizar-dash/dist/assets/{EnvVarsSection-L413CQEI.js → EnvVarsSection-DoIzqrlb.js} +3 -3
- package/bizar-dash/dist/assets/{EnvVarsSection-L413CQEI.js.map → EnvVarsSection-DoIzqrlb.js.map} +1 -1
- package/bizar-dash/dist/assets/{MobileChat-0kGQb1S6.js → MobileChat-CoUCUsbr.js} +1 -1
- package/bizar-dash/dist/assets/{MobileChat-0kGQb1S6.js.map → MobileChat-CoUCUsbr.js.map} +1 -1
- package/bizar-dash/dist/assets/MobileSettings-BeO04g52.js +1 -0
- package/bizar-dash/dist/assets/MobileSettings-BeO04g52.js.map +1 -0
- package/bizar-dash/dist/assets/{Toast-C6f1zFJ2.js → Toast-D9nv5N6m.js} +1 -1
- package/bizar-dash/dist/assets/{Toast-C6f1zFJ2.js.map → Toast-D9nv5N6m.js.map} +1 -1
- package/bizar-dash/dist/assets/{icons-BsWXWkEF.js → icons-Btipv2pp.js} +100 -90
- package/bizar-dash/dist/assets/icons-Btipv2pp.js.map +1 -0
- package/bizar-dash/dist/assets/main-DHXPuddY.js +18 -0
- package/bizar-dash/dist/assets/main-DHXPuddY.js.map +1 -0
- package/bizar-dash/dist/assets/{main-BklYy02e.css → main-UG4jKK-F.css} +1 -1
- package/bizar-dash/dist/assets/mobile-H5KH9cTL.js +1 -0
- package/bizar-dash/dist/assets/{mobile-CsaN4CxH.js.map → mobile-H5KH9cTL.js.map} +1 -1
- package/bizar-dash/dist/assets/{mobile-layout-iFBdjEE4.js → mobile-layout-BqHxVb6_.js} +2 -2
- package/bizar-dash/dist/assets/{mobile-layout-iFBdjEE4.js.map → mobile-layout-BqHxVb6_.js.map} +1 -1
- package/bizar-dash/dist/assets/{useSlashCommands-DGJcC9iQ.js → useSlashCommands-C24-O1e7.js} +2 -2
- package/bizar-dash/dist/assets/{useSlashCommands-DGJcC9iQ.js.map → useSlashCommands-C24-O1e7.js.map} +1 -1
- package/bizar-dash/dist/index.html +7 -7
- package/bizar-dash/dist/mobile.html +3 -3
- package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/bizar-dash/src/server/bg-spawner.mjs +522 -305
- package/bizar-dash/src/server/headroom.mjs +3 -1
- package/bizar-dash/src/server/memory-lightrag.mjs +26 -2
- package/bizar-dash/src/server/memory-store.mjs +74 -28
- package/bizar-dash/src/server/opencode-sdk.mjs +63 -3
- package/bizar-dash/src/server/plugins/registry.mjs +1 -1
- package/bizar-dash/src/server/routes/activity.mjs +85 -0
- package/bizar-dash/src/server/routes/background.mjs +31 -13
- package/bizar-dash/src/server/routes/memory.mjs +91 -38
- package/bizar-dash/src/server/routes/opencode-session-detail.mjs +1 -1
- package/bizar-dash/src/server/server.mjs +4 -1
- package/bizar-dash/src/web/components/Sidebar.tsx +0 -1
- package/bizar-dash/src/web/styles/main.css +52 -13
- package/bizar-dash/src/web/styles/memory.css +17 -0
- package/bizar-dash/src/web/styles/settings.css +6 -56
- package/bizar-dash/src/web/views/Marketplace.tsx +192 -31
- package/bizar-dash/src/web/views/memory/ConfigPanel.tsx +157 -7
- package/bizar-dash/src/web/views/memory/MemoryOverview.tsx +11 -0
- package/bizar-dash/src/web/views/settings/MemorySection.tsx +65 -11
- package/bizar-dash/tests/background-sdk-session.test.mjs +94 -0
- package/bizar-dash/tests/background-session-events.test.mjs +74 -0
- package/bizar-dash/tests/background-steer-sdk.test.mjs +71 -0
- package/bizar-dash/tests/background-steer.test.mjs +25 -7
- package/bizar-dash/tests/memory-namespace.test.mjs +2 -2
- package/bizar-dash/tests/memory-status-root.test.mjs +144 -0
- package/bizar-dash/tests/memory-store.test.mjs +5 -4
- package/bizar-dash/tests/memory-vault-config-endpoint.test.mjs +173 -0
- package/bizar-dash/tests/settings-mode-wiring.test.tsx +1 -1
- package/bizar-dash/tests/settings-nav.test.tsx +0 -1
- package/bizar-dash/tests/views/Marketplace.test.tsx +200 -0
- package/bizar-dash/tests/views/Memory.test.tsx +274 -0
- package/bizar-dash/tests/views/sidebar.test.tsx +116 -0
- package/bizar-dash/tests/views/topbar.test.tsx +87 -0
- package/cli/commands/marketplace.mjs +1 -1
- package/cli/memory.mjs +1 -1
- package/package.json +1 -1
- package/plugins/bizar/src/background-state.ts +11 -0
- package/plugins/bizar/src/background.ts +212 -34
- package/plugins/bizar/src/opencode-runner.ts +80 -353
- package/plugins/bizar/src/tools/bg-send-message.ts +160 -61
- package/plugins/bizar/src/tools/bg-spawn.ts +235 -156
- package/plugins/bizar/tests/tools/bg-send-message.test.ts +84 -11
- package/plugins/bizar/tests/tools/bg-spawn-http.test.ts +223 -0
- package/bizar-dash/dist/assets/MobileSettings-Cq1oFIdO.js +0 -1
- package/bizar-dash/dist/assets/MobileSettings-Cq1oFIdO.js.map +0 -1
- package/bizar-dash/dist/assets/icons-BsWXWkEF.js.map +0 -1
- package/bizar-dash/dist/assets/main-CBTgYSeG.js +0 -18
- package/bizar-dash/dist/assets/main-CBTgYSeG.js.map +0 -1
- package/bizar-dash/dist/assets/mobile-CsaN4CxH.js +0 -1
|
@@ -1,54 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* plugins/bizar/src/opencode-runner.ts
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* v5.5.1 — DEAD CODE stub.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* Background agents no longer run as `opencode run` subprocesses. They
|
|
7
|
+
* run as long-lived opencode serve SDK sessions, managed by the
|
|
8
|
+
* Bizar dashboard (`bizar-dash/src/server/bg-spawner.mjs`). The plugin
|
|
9
|
+
* delegates to the dashboard via HTTP (`bg-spawn.ts`,
|
|
10
|
+
* `bg-send-message.ts`, …) instead of spawning anything directly.
|
|
10
11
|
*
|
|
11
|
-
*
|
|
12
|
-
* loop in-process, drives it to completion, and exits. This module
|
|
13
|
-
* gives the plugin a clean way to spawn one `opencode run` per
|
|
14
|
-
* background agent, capture its output to the LogWriter's log file,
|
|
15
|
-
* track the PID for status/kill, and extract the opencode session
|
|
16
|
-
* id from the structured log stream.
|
|
12
|
+
* This module is kept as a stub for two reasons:
|
|
17
13
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* (`session.next.prompt.admitted` event) but no agent loop processed
|
|
24
|
-
* it. The result: a session record was created, a tmux pane was
|
|
25
|
-
* spawned, and nothing happened. The user saw "spawns but does
|
|
26
|
-
* nothing" and was right.
|
|
14
|
+
* 1. `buildOpencodeRunArgs` and the `SpawnAgentOptions` type are
|
|
15
|
+
* still imported by `plugins/bizar/tests/tools/opencode-runner.test.ts`
|
|
16
|
+
* and serve as a regression pin for the argv layout that USED to
|
|
17
|
+
* be passed to `Bun.spawn`. The test suite stays green because
|
|
18
|
+
* the pure helpers are unchanged.
|
|
27
19
|
*
|
|
28
|
-
*
|
|
20
|
+
* 2. A handful of function names (`isAlive`, `killAgent`, …) are
|
|
21
|
+
* imported elsewhere (`background.ts`) as a future-proofing hook.
|
|
22
|
+
* We replace the implementations with no-op / error stubs so any
|
|
23
|
+
* leftover call gets a clear, deliberate response instead of
|
|
24
|
+
* silently succeeding.
|
|
29
25
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* `opencode run` writes structured logs to stderr, one log per line:
|
|
34
|
-
*
|
|
35
|
-
* timestamp=2026-06-24T01:25:13.537Z level=INFO run=<uuid> message="creating instance" directory=/tmp
|
|
36
|
-
* timestamp=2026-06-24T01:25:16.555Z level=INFO run=<uuid> message=created id=ses_… title="…" agent=…
|
|
37
|
-
* timestamp=2026-06-24T01:25:16.951Z level=INFO run=<uuid> message=loop session.id=ses_… step=0
|
|
38
|
-
* timestamp=2026-06-24T01:25:21.253Z level=INFO run=<uuid> message="exiting loop" session.id=ses_…
|
|
39
|
-
*
|
|
40
|
-
* The `message=created id=ses_<id>` line is how we recover the
|
|
41
|
-
* sessionId (the agent generated it; we don't pre-allocate). We
|
|
42
|
-
* parse the line with `message=created id=(ses_[A-Za-z0-9_]+)`.
|
|
43
|
-
*
|
|
44
|
-
* Both stdout and stderr are piped to `logPath` so the operator's
|
|
45
|
-
* tmux pane (and the dashboard's log viewer) can watch the agent
|
|
46
|
-
* work in real time. We prefix each line with the stream name
|
|
47
|
-
* ([stdout] / [stderr]) for human readability; downstream parsers
|
|
48
|
-
* can split on the first `] `.
|
|
26
|
+
* If something imports `spawnAgent`, it now gets back `{ ok: false,
|
|
27
|
+
* error: "spawnAgent removed in v5.5.1" }`. This forces callers to the
|
|
28
|
+
* dashboard path; nothing in the plugin should be calling this anymore.
|
|
49
29
|
*/
|
|
50
|
-
import { createWriteStream, mkdirSync, existsSync } from "node:fs";
|
|
51
|
-
import { dirname } from "node:path";
|
|
52
30
|
import type { Subprocess } from "bun";
|
|
53
31
|
|
|
54
32
|
export type AgentState =
|
|
@@ -97,38 +75,15 @@ export interface SpawnAgentResult {
|
|
|
97
75
|
|
|
98
76
|
type ExitCallback = (status: AgentStatus) => void;
|
|
99
77
|
|
|
100
|
-
interface AgentRecord {
|
|
101
|
-
status: AgentStatus;
|
|
102
|
-
proc: Subprocess;
|
|
103
|
-
onExit: ExitCallback[];
|
|
104
|
-
// Resolvers for the spawn promise. Consumed when the sessionId
|
|
105
|
-
// arrives (or the process exits before that).
|
|
106
|
-
spawnResolvers: Array<(result: SpawnAgentResult) => void>;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Module-level registry of running agents.
|
|
110
|
-
const agents = new Map<number, AgentRecord>();
|
|
111
|
-
|
|
112
|
-
// --- Public API -----------------------------------------------------------
|
|
113
|
-
|
|
114
78
|
/**
|
|
115
|
-
* Pure
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
* a
|
|
119
|
-
*
|
|
120
|
-
* fall back to opencode's default agent and break session attribution
|
|
121
|
-
* (the title prefix `bgr:<agent>:...` would also degrade to `bgr::...`).
|
|
79
|
+
* v5.5.1 — Pure helper, UNCHANGED. Kept around so the regression test
|
|
80
|
+
* that pins the argv layout still passes. (The argv used to be passed
|
|
81
|
+
* to `Bun.spawn`; v5.5.1 no longer spawns anything, but the wire format
|
|
82
|
+
* is a useful reference and may be reused if we ever revive subprocess
|
|
83
|
+
* mode.)
|
|
122
84
|
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
* --dir <worktree>
|
|
126
|
-
* --print-logs
|
|
127
|
-
* --log-level INFO
|
|
128
|
-
* --title <title>
|
|
129
|
-
* --agent <agent> ← REQUIRED; was missing pre-v0.8.1
|
|
130
|
-
* [--model <providerID>/<modelID>] ← optional override
|
|
131
|
-
* -- <prompt>
|
|
85
|
+
* @param opts
|
|
86
|
+
* @returns argv that USED to be passed to `Bun.spawn(["opencode", "run", …])`
|
|
132
87
|
*/
|
|
133
88
|
export function buildOpencodeRunArgs(opts: SpawnAgentOptions): string[] {
|
|
134
89
|
if (!opts.agent) {
|
|
@@ -146,331 +101,103 @@ export function buildOpencodeRunArgs(opts: SpawnAgentOptions): string[] {
|
|
|
146
101
|
if (opts.model) {
|
|
147
102
|
args.push("--model", `${opts.model.providerID}/${opts.model.modelID}`);
|
|
148
103
|
}
|
|
149
|
-
// `--` separates flags from positional so a prompt starting with
|
|
150
|
-
// `-` is treated as a message.
|
|
151
104
|
args.push("--", opts.prompt);
|
|
152
105
|
return args;
|
|
153
106
|
}
|
|
154
107
|
|
|
155
108
|
/**
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
* because of an early error like a missing API key).
|
|
109
|
+
* v5.5.1 — STUB. Background agents run on the opencode serve SDK,
|
|
110
|
+
* not as `opencode run` subprocesses. Returns an error directing the
|
|
111
|
+
* caller to the dashboard HTTP API.
|
|
160
112
|
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
113
|
+
* The plugin's `bg-spawn.ts` no longer calls this; it's kept for any
|
|
114
|
+
* late caller we missed.
|
|
163
115
|
*/
|
|
164
|
-
export async function spawnAgent(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
return {
|
|
172
|
-
ok: false,
|
|
173
|
-
error: `cannot create log dir ${logDir}: ${err instanceof Error ? err.message : String(err)}`,
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// 2. Build argv. Pulled into a pure function so tests can assert the
|
|
179
|
-
// flag layout (notably the `--agent` flag and the migrated model
|
|
180
|
-
// ID format) without spawning a real `opencode run` process.
|
|
181
|
-
const args = buildOpencodeRunArgs(opts);
|
|
182
|
-
|
|
183
|
-
// 3. Spawn the process.
|
|
184
|
-
let proc: Subprocess;
|
|
185
|
-
try {
|
|
186
|
-
proc = Bun.spawn(args, {
|
|
187
|
-
stdout: "pipe",
|
|
188
|
-
stderr: "pipe",
|
|
189
|
-
env: { ...process.env, ...(opts.env || {}) },
|
|
190
|
-
});
|
|
191
|
-
} catch (err: unknown) {
|
|
192
|
-
return {
|
|
193
|
-
ok: false,
|
|
194
|
-
error: `failed to spawn opencode run: ${err instanceof Error ? err.message : String(err)}`,
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// 4. Track the agent.
|
|
199
|
-
const rec: AgentRecord = {
|
|
200
|
-
status: {
|
|
201
|
-
state: "starting",
|
|
202
|
-
processId: proc.pid,
|
|
203
|
-
startedAt: Date.now(),
|
|
204
|
-
},
|
|
205
|
-
proc,
|
|
206
|
-
onExit: [],
|
|
207
|
-
spawnResolvers: [],
|
|
208
|
-
};
|
|
209
|
-
agents.set(proc.pid, rec);
|
|
210
|
-
|
|
211
|
-
// 5. Pipe stdout+stderr to the log file. Both go to the same file;
|
|
212
|
-
// lines are prefixed [stdout] / [stderr] for readability.
|
|
213
|
-
const logStream = createWriteStream(opts.logPath, { flags: "a" });
|
|
214
|
-
const decoder = new TextDecoder("utf-8");
|
|
215
|
-
const sessionIdRegex = /message=created id=(ses_[A-Za-z0-9_]+)/;
|
|
216
|
-
let sessionId: string | undefined;
|
|
217
|
-
|
|
218
|
-
const resolveSpawnIfReady = (forceError?: string) => {
|
|
219
|
-
const resolvers = rec.spawnResolvers.splice(0);
|
|
220
|
-
if (resolvers.length === 0) return;
|
|
221
|
-
if (forceError) {
|
|
222
|
-
for (const r of resolvers) {
|
|
223
|
-
r({ ok: false, processId: proc.pid, error: forceError });
|
|
224
|
-
}
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
if (sessionId) {
|
|
228
|
-
rec.status.state = "running";
|
|
229
|
-
for (const r of resolvers) {
|
|
230
|
-
r({ ok: true, sessionId, processId: proc.pid });
|
|
231
|
-
}
|
|
232
|
-
}
|
|
116
|
+
export async function spawnAgent(_opts: SpawnAgentOptions): Promise<SpawnAgentResult> {
|
|
117
|
+
return {
|
|
118
|
+
ok: false,
|
|
119
|
+
error:
|
|
120
|
+
"spawnAgent removed in v5.5.1 — bg agents now run as opencode serve sessions " +
|
|
121
|
+
"managed by the Bizar dashboard. POST /api/background instead. " +
|
|
122
|
+
"See plugins/bizar/src/tools/bg-spawn.ts.",
|
|
233
123
|
};
|
|
234
|
-
|
|
235
|
-
const readStream = async (
|
|
236
|
-
reader: ReadableStreamDefaultReader<Uint8Array>,
|
|
237
|
-
label: "stderr" | "stdout",
|
|
238
|
-
): Promise<void> => {
|
|
239
|
-
let buf = "";
|
|
240
|
-
try {
|
|
241
|
-
while (true) {
|
|
242
|
-
const { done, value } = await reader.read();
|
|
243
|
-
if (done) break;
|
|
244
|
-
const text = decoder.decode(value, { stream: true });
|
|
245
|
-
logStream.write(`[${label}] ${text}`);
|
|
246
|
-
if (label === "stderr" && !sessionId) {
|
|
247
|
-
buf += text;
|
|
248
|
-
const m = buf.match(sessionIdRegex);
|
|
249
|
-
if (m && m[1]) {
|
|
250
|
-
sessionId = m[1];
|
|
251
|
-
rec.status.sessionId = sessionId;
|
|
252
|
-
resolveSpawnIfReady();
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
} finally {
|
|
257
|
-
try { reader.releaseLock(); } catch { /* ignore */ }
|
|
258
|
-
}
|
|
259
|
-
};
|
|
260
|
-
|
|
261
|
-
// 6. Stream readers + exit handler — install BEFORE returning the
|
|
262
|
-
// promise so a fast-exiting process still produces a clean
|
|
263
|
-
// resolution.
|
|
264
|
-
const stderrReader = (proc.stderr as ReadableStream<Uint8Array>).getReader() as unknown as ReadableStreamDefaultReader<Uint8Array<ArrayBufferLike>>;
|
|
265
|
-
const stdoutReader = (proc.stdout as ReadableStream<Uint8Array>).getReader() as unknown as ReadableStreamDefaultReader<Uint8Array<ArrayBufferLike>>;
|
|
266
|
-
void readStream(stderrReader, "stderr");
|
|
267
|
-
void readStream(stdoutReader, "stdout");
|
|
268
|
-
|
|
269
|
-
proc.exited
|
|
270
|
-
.then((exitCode: number | null) => {
|
|
271
|
-
const code = exitCode ?? -1;
|
|
272
|
-
rec.status.exitCode = exitCode ?? undefined;
|
|
273
|
-
rec.status.endedAt = Date.now();
|
|
274
|
-
if (rec.status.state !== "killed") {
|
|
275
|
-
rec.status.state = code === 0 ? "done" : "failed";
|
|
276
|
-
if (code !== 0 && !rec.status.error) {
|
|
277
|
-
rec.status.error = `opencode run exited with code ${code}`;
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
// Resolve any unresolved spawn promises.
|
|
281
|
-
if (!sessionId) {
|
|
282
|
-
resolveSpawnIfReady(rec.status.error || "opencode run exited before reporting session id");
|
|
283
|
-
}
|
|
284
|
-
// Fire subscribers.
|
|
285
|
-
const cbs = rec.onExit.splice(0);
|
|
286
|
-
for (const cb of cbs) {
|
|
287
|
-
try { cb({ ...rec.status }); } catch { /* ignore */ }
|
|
288
|
-
}
|
|
289
|
-
// Best-effort flush + close of the log stream.
|
|
290
|
-
try { logStream.end(); } catch { /* ignore */ }
|
|
291
|
-
})
|
|
292
|
-
.catch(() => {
|
|
293
|
-
// proc.exited only rejects if the proc was already awaited or
|
|
294
|
-
// never spawned; safe to ignore.
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
// 7. Race the spawn promise against a timeout. The default is 10s
|
|
298
|
-
// which is plenty for opencode to print the "created" line on
|
|
299
|
-
// a warm host (<500ms in practice).
|
|
300
|
-
const sessionIdTimeoutMs = opts.sessionIdTimeoutMs ?? 10_000;
|
|
301
|
-
return new Promise<SpawnAgentResult>((resolve) => {
|
|
302
|
-
rec.spawnResolvers.push(resolve);
|
|
303
|
-
setTimeout(() => {
|
|
304
|
-
if (!sessionId) {
|
|
305
|
-
resolveSpawnIfReady(
|
|
306
|
-
`opencode run did not report a session id within ${sessionIdTimeoutMs}ms`,
|
|
307
|
-
);
|
|
308
|
-
}
|
|
309
|
-
}, sessionIdTimeoutMs);
|
|
310
|
-
});
|
|
311
124
|
}
|
|
312
125
|
|
|
313
126
|
/**
|
|
314
|
-
*
|
|
315
|
-
*
|
|
316
|
-
* in-memory map).
|
|
127
|
+
* v5.5.1 — STUB. Returns null because there is no in-process subprocess
|
|
128
|
+
* registry to look up.
|
|
317
129
|
*/
|
|
318
|
-
export function getStatus(
|
|
319
|
-
|
|
320
|
-
if (!rec) return null;
|
|
321
|
-
return { ...rec.status };
|
|
130
|
+
export function getStatus(_processId: number): AgentStatus | null {
|
|
131
|
+
return null;
|
|
322
132
|
}
|
|
323
133
|
|
|
324
134
|
/**
|
|
325
|
-
*
|
|
326
|
-
*
|
|
327
|
-
* subscribers are allowed; all of them fire in registration order.
|
|
328
|
-
*
|
|
329
|
-
* @returns unsubscribe function
|
|
135
|
+
* v5.5.1 — STUB. The real exit subscription lives on the dashboard side.
|
|
136
|
+
* Returns a no-op unsubscribe.
|
|
330
137
|
*/
|
|
331
|
-
export function onExit(
|
|
332
|
-
|
|
333
|
-
if (!rec) return () => undefined;
|
|
334
|
-
rec.onExit.push(cb);
|
|
335
|
-
// If the agent has already exited, fire the callback immediately
|
|
336
|
-
// (next microtask) so the caller doesn't have to special-case
|
|
337
|
-
// pre-exited agents.
|
|
338
|
-
if (rec.status.endedAt !== undefined) {
|
|
339
|
-
queueMicrotask(() => {
|
|
340
|
-
try { cb({ ...rec.status }); } catch { /* ignore */ }
|
|
341
|
-
});
|
|
342
|
-
}
|
|
343
|
-
return () => {
|
|
344
|
-
const i = rec.onExit.indexOf(cb);
|
|
345
|
-
if (i >= 0) rec.onExit.splice(i, 1);
|
|
346
|
-
};
|
|
138
|
+
export function onExit(_processId: number, _cb: ExitCallback): () => void {
|
|
139
|
+
return () => undefined;
|
|
347
140
|
}
|
|
348
141
|
|
|
349
142
|
/**
|
|
350
|
-
*
|
|
351
|
-
*
|
|
143
|
+
* v5.5.1 — STUB. Kill is now a dashboard-side operation
|
|
144
|
+
* (`sdk.sessions.abort`). The plugin's `bg-kill.ts` posts to the
|
|
145
|
+
* dashboard HTTP API; this function is here only as a fallback that
|
|
146
|
+
* always reports "no such process tracked" so the dashboard's view of
|
|
147
|
+
* the world is the source of truth.
|
|
352
148
|
*/
|
|
353
149
|
export function killAgent(
|
|
354
|
-
|
|
355
|
-
|
|
150
|
+
_processId: number,
|
|
151
|
+
_signal: "SIGTERM" | "SIGKILL" = "SIGTERM",
|
|
356
152
|
): { ok: boolean; error?: string } {
|
|
357
|
-
|
|
358
|
-
if (!rec) {
|
|
359
|
-
return { ok: true, error: "no such process tracked" };
|
|
360
|
-
}
|
|
361
|
-
if (rec.status.endedAt !== undefined) {
|
|
362
|
-
return { ok: true, error: "process already exited" };
|
|
363
|
-
}
|
|
364
|
-
rec.status.state = "killed";
|
|
365
|
-
try {
|
|
366
|
-
rec.proc.kill(signal);
|
|
367
|
-
} catch (err: unknown) {
|
|
368
|
-
return {
|
|
369
|
-
ok: false,
|
|
370
|
-
error: `kill(${signal}) failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
371
|
-
};
|
|
372
|
-
}
|
|
373
|
-
// Schedule a forced kill after 5s in case SIGTERM is ignored.
|
|
374
|
-
setTimeout(() => {
|
|
375
|
-
if (rec.status.endedAt === undefined) {
|
|
376
|
-
try { rec.proc.kill("SIGKILL"); } catch { /* ignore */ }
|
|
377
|
-
}
|
|
378
|
-
}, 5_000);
|
|
379
|
-
return { ok: true };
|
|
153
|
+
return { ok: true, error: "no_such_process_tracked_v5_5_1_use_dashboard_delete" };
|
|
380
154
|
}
|
|
381
155
|
|
|
382
156
|
/**
|
|
383
|
-
* v5.
|
|
384
|
-
*
|
|
385
|
-
*
|
|
386
|
-
*
|
|
387
|
-
* The agent's `state` flips to `"paused"` so {@link getStatus}
|
|
388
|
-
* reflects the new lifecycle accurately.
|
|
157
|
+
* v5.5.1 — STUB. Pause is an output-pause at the dashboard side now.
|
|
158
|
+
* The plugin's `bg-pause.ts` posts to the dashboard; this stub returns
|
|
159
|
+
* `unsupported` so a leftover caller gets a clear signal.
|
|
389
160
|
*/
|
|
390
|
-
export function pauseAgent(
|
|
391
|
-
|
|
392
|
-
): { ok: boolean; error?: string } {
|
|
393
|
-
if (process.platform === "win32") {
|
|
394
|
-
return { ok: false, error: "pause unsupported on win32" };
|
|
395
|
-
}
|
|
396
|
-
const rec = agents.get(processId);
|
|
397
|
-
if (!rec) return { ok: false, error: "no such process" };
|
|
398
|
-
if (rec.status.endedAt !== undefined) return { ok: true, error: "already_exited" };
|
|
399
|
-
if (rec.status.state === "paused") return { ok: true };
|
|
400
|
-
try {
|
|
401
|
-
rec.proc.kill("SIGSTOP");
|
|
402
|
-
rec.status.state = "paused";
|
|
403
|
-
return { ok: true };
|
|
404
|
-
} catch (err: unknown) {
|
|
405
|
-
return {
|
|
406
|
-
ok: false,
|
|
407
|
-
error: `SIGSTOP failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
408
|
-
};
|
|
409
|
-
}
|
|
161
|
+
export function pauseAgent(_processId: number): { ok: boolean; error?: string } {
|
|
162
|
+
return { ok: false, error: "pause_via_dashboard_v5_5_1" };
|
|
410
163
|
}
|
|
411
164
|
|
|
412
165
|
/**
|
|
413
|
-
* v5.
|
|
414
|
-
* against an exited process.
|
|
166
|
+
* v5.5.1 — STUB. Same as `pauseAgent` — dashboard-side only.
|
|
415
167
|
*/
|
|
416
|
-
export function resumeAgent(
|
|
417
|
-
|
|
418
|
-
): { ok: boolean; error?: string } {
|
|
419
|
-
if (process.platform === "win32") {
|
|
420
|
-
return { ok: false, error: "resume unsupported on win32" };
|
|
421
|
-
}
|
|
422
|
-
const rec = agents.get(processId);
|
|
423
|
-
if (!rec) return { ok: false, error: "no such process" };
|
|
424
|
-
if (rec.status.endedAt !== undefined) return { ok: true, error: "already_exited" };
|
|
425
|
-
if (rec.status.state !== "paused") return { ok: true };
|
|
426
|
-
try {
|
|
427
|
-
rec.proc.kill("SIGCONT");
|
|
428
|
-
rec.status.state = "running";
|
|
429
|
-
return { ok: true };
|
|
430
|
-
} catch (err: unknown) {
|
|
431
|
-
return {
|
|
432
|
-
ok: false,
|
|
433
|
-
error: `SIGCONT failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
434
|
-
};
|
|
435
|
-
}
|
|
168
|
+
export function resumeAgent(_processId: number): { ok: boolean; error?: string } {
|
|
169
|
+
return { ok: false, error: "resume_via_dashboard_v5_5_1" };
|
|
436
170
|
}
|
|
437
171
|
|
|
438
172
|
/**
|
|
439
|
-
* v5.
|
|
440
|
-
*
|
|
441
|
-
*
|
|
442
|
-
*
|
|
443
|
-
*
|
|
444
|
-
* NOTE: this is a separate registry from the in-memory `agents` map.
|
|
445
|
-
* After a plugin restart, the in-memory map is empty but the
|
|
446
|
-
* underlying PID may still be alive. The function probes the OS, so
|
|
447
|
-
* it answers the underlying question even when the agent record has
|
|
448
|
-
* been forgotten.
|
|
173
|
+
* v5.5.1 — STUB. Returns false because there is no in-process PID
|
|
174
|
+
* registry. Liveness is owned by the dashboard; the plugin's state
|
|
175
|
+
* reconciliation code already uses this as a probe and falls back to
|
|
176
|
+
* "fail closed" when the answer is false.
|
|
449
177
|
*/
|
|
450
178
|
export function isAlive(processId: number): boolean {
|
|
451
179
|
if (!Number.isFinite(processId) || processId <= 0) return false;
|
|
452
|
-
|
|
453
|
-
// Signal 0 = probe only. Returns true if the process exists and
|
|
454
|
-
// we have permission to signal it.
|
|
455
|
-
process.kill(processId, 0);
|
|
456
|
-
return true;
|
|
457
|
-
} catch {
|
|
458
|
-
return false;
|
|
459
|
-
}
|
|
180
|
+
return false;
|
|
460
181
|
}
|
|
461
182
|
|
|
462
183
|
/**
|
|
463
|
-
*
|
|
464
|
-
* state and by tests.
|
|
184
|
+
* v5.5.1 — STUB. Returns an empty list — the runner registry is gone.
|
|
465
185
|
*/
|
|
466
186
|
export function list(): AgentStatus[] {
|
|
467
|
-
return
|
|
187
|
+
return [];
|
|
468
188
|
}
|
|
469
189
|
|
|
470
190
|
/**
|
|
471
|
-
*
|
|
472
|
-
*
|
|
191
|
+
* v5.5.1 — STUB. Clears nothing (the registry is empty). Kept for the
|
|
192
|
+
* test suite that imports it.
|
|
473
193
|
*/
|
|
474
194
|
export function _resetForTests(): void {
|
|
475
|
-
|
|
195
|
+
// no-op — the in-memory registry was removed.
|
|
476
196
|
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* v5.5.1 — STUB. Returns an empty record because no agent is tracked
|
|
200
|
+
* here. Provided so the module typechecks in callers that still reach
|
|
201
|
+
* for a status record shape.
|
|
202
|
+
*/
|
|
203
|
+
export type { Subprocess };
|