Files
openclaw/src/agents/bash-tools.process-send-keys.ts
bitloi ed6b030a43 feat(process): show input-wait hints in log and poll
Show input-wait hints in process log/poll for idle interactive background sessions, keep list markers and structured stdin metadata, and document the recovery flow through log plus existing input actions.

Docs: updated docs/gateway/background-process.md.

Verification:
- pnpm test src/agents/bash-tools.test.ts
- pnpm test src/agents/bash-tools.process.input-hints.test.ts
- pnpm test src/agents/bash-tools.process.input-hints.test.ts src/agents/bash-tools.process.poll-timeout.test.ts src/agents/bash-tools.process.supervisor.test.ts src/agents/bash-tools.process-send-keys.test.ts
- pnpm check:docs
- git diff --check
- CI on 4aea1f11fe: check, check-additional, check-docs, checks-node-core, process/security relevant shards, real behavior proof passed

Fixes #33957.
Thanks @bitloi and @vincentkoc.

Co-authored-by: bitloi <89318445+bitloi@users.noreply.github.com>
Co-authored-by: bitloi <raphaelaloi.eth@gmail.com>
2026-05-10 04:13:07 -04:00

80 lines
2.1 KiB
TypeScript

import type { AgentToolResult } from "@mariozechner/pi-agent-core";
import type { ProcessSession } from "./bash-process-registry.js";
import { deriveSessionName } from "./bash-tools.shared.js";
import { encodeKeySequence, hasCursorModeSensitiveKeys } from "./pty-keys.js";
export type WritableStdin = {
write: (data: string, cb?: (err?: Error | null) => void) => void;
end: () => void;
destroyed?: boolean;
writable?: boolean;
writableEnded?: boolean;
writableFinished?: boolean;
};
function failText(text: string): AgentToolResult<unknown> {
return {
content: [
{
type: "text",
text,
},
],
details: { status: "failed" },
};
}
async function writeToStdin(stdin: WritableStdin, data: string) {
await new Promise<void>((resolve, reject) => {
stdin.write(data, (err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
}
export async function handleProcessSendKeys(params: {
sessionId: string;
session: ProcessSession;
stdin: WritableStdin;
keys?: string[];
hex?: string[];
literal?: string;
}): Promise<AgentToolResult<unknown>> {
const request = {
keys: params.keys,
hex: params.hex,
literal: params.literal,
};
if (params.session.cursorKeyMode === "unknown" && hasCursorModeSensitiveKeys(request)) {
return failText(
`Session ${params.sessionId} cursor key mode is not known yet. Poll or log until startup output appears, then retry send-keys.`,
);
}
const cursorKeyMode =
params.session.cursorKeyMode === "unknown" ? undefined : params.session.cursorKeyMode;
const { data, warnings } = encodeKeySequence(request, cursorKeyMode);
if (!data) {
return failText("No key data provided.");
}
await writeToStdin(params.stdin, data);
return {
content: [
{
type: "text",
text:
`Sent ${data.length} bytes to session ${params.sessionId}.` +
(warnings.length ? `\nWarnings:\n- ${warnings.join("\n- ")}` : ""),
},
],
details: {
status: "running",
sessionId: params.sessionId,
name: deriveSessionName(params.session.command),
},
};
}