mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-23 11:38:07 +00:00
docs: document bash process registry
This commit is contained in:
@@ -1,11 +1,15 @@
|
||||
/**
|
||||
* Compact references for active background bash sessions.
|
||||
* These references are surfaced in agent context so follow-up turns can
|
||||
* reconnect to prior long-running work.
|
||||
*/
|
||||
import { listRunningSessions } from "./bash-process-registry.js";
|
||||
import { deriveSessionName } from "./bash-tools.shared.js";
|
||||
|
||||
// Builds compact references for currently running background process sessions.
|
||||
// These references are surfaced to agents so they can reconnect to prior work.
|
||||
const DEFAULT_ACTIVE_PROCESS_LIMIT = 8;
|
||||
const MAX_COMMAND_LABEL_CHARS = 140;
|
||||
|
||||
/** Agent-facing summary of a reconnectable background process session. */
|
||||
export type ActiveProcessSessionReference = {
|
||||
sessionId: string;
|
||||
status: "running";
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
/**
|
||||
* Test fixtures for bash process registry state.
|
||||
* Provides complete session objects so tests can focus on the field under
|
||||
* inspection without repeating registry defaults.
|
||||
*/
|
||||
import type { ChildProcessWithoutNullStreams } from "node:child_process";
|
||||
import type { ProcessSession } from "./bash-process-registry.js";
|
||||
|
||||
// Test fixtures for bash process registry state.
|
||||
/** Build a process-session fixture with safe defaults for registry tests. */
|
||||
export function createProcessSessionFixture(params: {
|
||||
id: string;
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/**
|
||||
* Bash process registry tests.
|
||||
* Covers output caps, finished-session retention, cleanup, and PTY cursor mode
|
||||
* state for background exec sessions.
|
||||
*/
|
||||
import type { ChildProcessWithoutNullStreams } from "node:child_process";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { ProcessSession } from "./bash-process-registry.js";
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/**
|
||||
* In-memory registry for bash exec sessions.
|
||||
* Tracks running/backgrounded sessions, bounded pending output, finished
|
||||
* session retention, and process cleanup for reconnect/poll flows.
|
||||
*/
|
||||
import type { ChildProcessWithoutNullStreams } from "node:child_process";
|
||||
import type { EventSessionRoutingPolicy } from "../infra/event-session-routing.js";
|
||||
import type { TerminationReason } from "../process/supervisor/types.js";
|
||||
@@ -19,8 +24,10 @@ function clampTtl(value: number | undefined) {
|
||||
|
||||
let jobTtlMs = clampTtl(readEnvInt("OPENCLAW_BASH_JOB_TTL_MS", "PI_BASH_JOB_TTL_MS"));
|
||||
|
||||
/** Lifecycle status recorded for background process sessions. */
|
||||
export type ProcessStatus = "running" | "completed" | "failed" | "killed";
|
||||
|
||||
/** Writable stdin surface shared by child-process and PTY-backed sessions. */
|
||||
export type SessionStdin = {
|
||||
write: (data: string, cb?: (err?: Error | null) => void) => void;
|
||||
end: () => void;
|
||||
@@ -32,6 +39,7 @@ export type SessionStdin = {
|
||||
writableFinished?: boolean;
|
||||
};
|
||||
|
||||
/** Mutable session state for a running bash exec process. */
|
||||
export interface ProcessSession {
|
||||
id: string;
|
||||
command: string;
|
||||
@@ -78,6 +86,7 @@ export interface ProcessSession {
|
||||
cursorKeyMode: "unknown" | "normal" | "application";
|
||||
}
|
||||
|
||||
/** Retained summary for a completed background session. */
|
||||
export interface FinishedSession {
|
||||
id: string;
|
||||
command: string;
|
||||
@@ -104,28 +113,34 @@ function isSessionIdTaken(id: string) {
|
||||
return runningSessions.has(id) || finishedSessions.has(id);
|
||||
}
|
||||
|
||||
/** Creates a unique short session id that avoids running and retained sessions. */
|
||||
export function createSessionSlug(): string {
|
||||
return createSessionSlugId(isSessionIdTaken);
|
||||
}
|
||||
|
||||
/** Adds a running session and starts retention sweeping if needed. */
|
||||
export function addSession(session: ProcessSession) {
|
||||
runningSessions.set(session.id, session);
|
||||
startSweeper();
|
||||
}
|
||||
|
||||
/** Returns a running session by id. */
|
||||
export function getSession(id: string) {
|
||||
return runningSessions.get(id);
|
||||
}
|
||||
|
||||
/** Returns a retained finished background session by id. */
|
||||
export function getFinishedSession(id: string) {
|
||||
return finishedSessions.get(id);
|
||||
}
|
||||
|
||||
/** Removes a session from both running and finished registries. */
|
||||
export function deleteSession(id: string) {
|
||||
runningSessions.delete(id);
|
||||
finishedSessions.delete(id);
|
||||
}
|
||||
|
||||
/** Appends process output while enforcing aggregate and pending-output caps. */
|
||||
export function appendOutput(session: ProcessSession, stream: "stdout" | "stderr", chunk: string) {
|
||||
session.pendingStdout ??= [];
|
||||
session.pendingStderr ??= [];
|
||||
@@ -156,6 +171,7 @@ export function appendOutput(session: ProcessSession, stream: "stdout" | "stderr
|
||||
session.tail = tail(session.aggregated, 2000);
|
||||
}
|
||||
|
||||
/** Drains pending stdout/stderr chunks returned by a process poll. */
|
||||
export function drainSession(session: ProcessSession) {
|
||||
const stdout = session.pendingStdout.join("");
|
||||
const stderr = session.pendingStderr.join("");
|
||||
@@ -166,6 +182,7 @@ export function drainSession(session: ProcessSession) {
|
||||
return { stdout, stderr };
|
||||
}
|
||||
|
||||
/** Moves a session to finished state and records exit metadata. */
|
||||
export function markExited(
|
||||
session: ProcessSession,
|
||||
exitCode: number | null,
|
||||
@@ -181,6 +198,7 @@ export function markExited(
|
||||
moveToFinished(session, status);
|
||||
}
|
||||
|
||||
/** Marks a running session as reconnectable after the exec call returns. */
|
||||
export function markBackgrounded(session: ProcessSession) {
|
||||
session.backgrounded = true;
|
||||
}
|
||||
@@ -240,6 +258,7 @@ function moveToFinished(session: ProcessSession, status: ProcessStatus) {
|
||||
});
|
||||
}
|
||||
|
||||
/** Returns the last `max` characters of text without adding ellipses. */
|
||||
export function tail(text: string, max = 2000) {
|
||||
if (text.length <= max) {
|
||||
return text;
|
||||
@@ -286,6 +305,7 @@ function capPendingBuffer(buffer: string[], pendingCharsInput: number, cap: numb
|
||||
return pendingChars;
|
||||
}
|
||||
|
||||
/** Keeps only the last `max` characters for bounded aggregate output storage. */
|
||||
export function trimWithCap(text: string, max: number) {
|
||||
if (text.length <= max) {
|
||||
return text;
|
||||
@@ -293,24 +313,29 @@ export function trimWithCap(text: string, max: number) {
|
||||
return text.slice(text.length - max);
|
||||
}
|
||||
|
||||
/** Lists backgrounded running sessions visible to reconnect/poll callers. */
|
||||
export function listRunningSessions() {
|
||||
return Array.from(runningSessions.values()).filter((s) => s.backgrounded);
|
||||
}
|
||||
|
||||
/** Lists retained finished background sessions. */
|
||||
export function listFinishedSessions() {
|
||||
return Array.from(finishedSessions.values());
|
||||
}
|
||||
|
||||
/** Clears retained finished sessions without touching running processes. */
|
||||
export function clearFinished() {
|
||||
finishedSessions.clear();
|
||||
}
|
||||
|
||||
/** Test-only reset for in-memory registry state and retention timers. */
|
||||
export function resetProcessRegistryForTests() {
|
||||
runningSessions.clear();
|
||||
finishedSessions.clear();
|
||||
stopSweeper();
|
||||
}
|
||||
|
||||
/** Overrides finished-session retention TTL, clamped to supported bounds. */
|
||||
export function setJobTtlMs(value?: number) {
|
||||
if (value === undefined || Number.isNaN(value)) {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user