Attempts to normalized Agent output when using OpenSSH Server

This commit is contained in:
Raven Scott
2026-04-22 17:11:42 -04:00
parent 50f90320f7
commit bc22a0d63e
11 changed files with 105 additions and 30 deletions
@@ -275,6 +275,11 @@ function createSshChildCtx(ctx, stream) {
return Object.assign({}, ctx, {
console: { log, info: log, warn: err, error: err, debug: log },
writeScreen: (s) => w(String(s)),
/**
* Raw stream writes from utilities (e.g. `/bin/agent` SSE chunks) must newline-normalize like
* `bareOpensshWritePtyConsoleLine` so streaming text renders over SSH PTYs.
*/
bareOsPtyStdoutCrlf: true,
/** `/bin/edit`, baretop, etc. use replStdin/replStdout — not Pear CLI. */
replStdin: stream,
replStdout: stream,
+4
View File
@@ -125,6 +125,10 @@ export interface BareOsKernelContext {
* Utilities may emit **one record per line** instead of multi-column text (e.g. **`ls`**).
*/
bareOsStdoutCaptured?: boolean
/**
* When true (SSH PTY child contexts), utilities that raw-write **`replStdout`** should emit CRLF newlines like **`bareOpensshWritePtyConsoleLine`** so streaming output (e.g. **`agent`**) displays line-by-line.
*/
bareOsPtyStdoutCrlf?: boolean
/** Optional raw output hook for NUL/binary (e.g. **`printenv -0`**, **`find -print0`**) when **`process.stdout.write`** is unavailable. */
bareOsBinWrite?(chunk: Uint8Array | string): void
bareOsIpc?: BareOsIpc
+30 -8
View File
@@ -25,19 +25,36 @@ function bareAgentErr(ctx, s) {
}
/**
* SSH PTYs expect CRLF for line breaks (same as `bare-openssh-pty-console.js` / `man` via console).
* @param {Record<string, unknown> | undefined} ctx
* @param {string} s
*/
function bareAgentNormalizeStreamNewlines(ctx, s) {
if (ctx && ctx.bareOsPtyStdoutCrlf)
return String(s).replace(/\r?\n/g, '\r\n')
return String(s)
}
/**
* @param {Record<string, unknown> | undefined} ctx
* @param {import('stream').Writable | undefined} out
* @param {string} s
*/
function bareAgentWriteOut(out, s) {
function bareAgentWriteOut(ctx, out, s) {
const text = bareAgentNormalizeStreamNewlines(ctx, s)
if (out && typeof out.write === 'function') {
try {
out.write(s)
out.write(text)
} catch {
/* ignore */
}
} else {
try {
process.stdout.write(s)
if (typeof bareOsEmitRaw === 'function') {
bareOsEmitRaw(ctx, text)
} else if (typeof process !== 'undefined' && process.stdout?.write) {
process.stdout.write(text)
}
} catch {
/* ignore */
}
@@ -125,7 +142,7 @@ async function bareAgentPromptSetupLine(ctx, prompt) {
if (!stdin || typeof stdin.on !== 'function') {
throw new Error('setup: stdin stream unavailable')
}
bareAgentWriteOut(stdout, '\x1b[?25h\x1b[0m' + prompt)
bareAgentWriteOut(ctx, stdout, '\x1b[?25h\x1b[0m' + prompt)
return bareAgentReadStreamLineOnce(stdin)
}
@@ -263,6 +280,7 @@ async function bareAgentInteractiveSetup(ctx, argv0, paths, config, opts) {
}
const stdout = ctx.replStdout || ctx.stdout
bareAgentWriteOut(
ctx,
stdout,
'\n=== ' +
argv0 +
@@ -540,6 +558,7 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
const fn = () => {
masterAbort.abort()
bareAgentWriteOut(
ctx,
stdout,
bareEditSgr('dim', useColor) + '^C' + EDIT_ANSI_RESET + '\n'
)
@@ -609,7 +628,7 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
if (e.type === 'delta_content') {
const chunk = typeof e.content === 'string' ? e.content : ''
assistantContent += chunk
bareAgentWriteOut(stdout, chunk)
bareAgentWriteOut(ctx, stdout, chunk)
} else if (e.type === 'delta_tool_calls') {
const arr = e.tool_calls
if (Array.isArray(arr)) {
@@ -650,6 +669,7 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
const pt = u.prompt_tokens
const ct = u.completion_tokens
bareAgentWriteOut(
ctx,
stdout,
'\n' +
bareEditSgr('dim', useColor) +
@@ -664,7 +684,7 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
if (!hasTools) {
await bareAgentSaveHistory(ctx, paths.history, messages)
bareAgentWriteOut(stdout, '\n')
bareAgentWriteOut(ctx, stdout, '\n')
break
}
@@ -685,6 +705,7 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
const name = fn?.name || ''
const argsStr = fn?.arguments || '{}'
bareAgentWriteOut(
ctx,
stdout,
'\n' +
bareEditSgr('keyword', useColor) +
@@ -695,7 +716,7 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
)
const spinner = bareEditSgr('dim', useColor) + '… running ' + name + EDIT_ANSI_RESET
bareAgentWriteOut(stdout, spinner + '\r')
bareAgentWriteOut(ctx, stdout, spinner + '\r')
const resultStr = await bareAgentDispatchTool({
ctx,
@@ -710,7 +731,7 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
onTaskComplete
})
bareAgentWriteOut(stdout, '\x1b[K')
bareAgentWriteOut(ctx, stdout, '\x1b[K')
messages.push({
role: 'tool',
@@ -724,6 +745,7 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
await bareAgentSaveHistory(ctx, paths.history, messages)
if (completed) {
bareAgentWriteOut(
ctx,
stdout,
bareEditSgr('dim', useColor) +
'\nDone: ' +
+30 -8
View File
@@ -4225,19 +4225,36 @@ function bareAgentErr(ctx, s) {
}
/**
* SSH PTYs expect CRLF for line breaks (same as `bare-openssh-pty-console.js` / `man` via console).
* @param {Record<string, unknown> | undefined} ctx
* @param {string} s
*/
function bareAgentNormalizeStreamNewlines(ctx, s) {
if (ctx && ctx.bareOsPtyStdoutCrlf)
return String(s).replace(/\r?\n/g, '\r\n')
return String(s)
}
/**
* @param {Record<string, unknown> | undefined} ctx
* @param {import('stream').Writable | undefined} out
* @param {string} s
*/
function bareAgentWriteOut(out, s) {
function bareAgentWriteOut(ctx, out, s) {
const text = bareAgentNormalizeStreamNewlines(ctx, s)
if (out && typeof out.write === 'function') {
try {
out.write(s)
out.write(text)
} catch {
/* ignore */
}
} else {
try {
process.stdout.write(s)
if (typeof bareOsEmitRaw === 'function') {
bareOsEmitRaw(ctx, text)
} else if (typeof process !== 'undefined' && process.stdout?.write) {
process.stdout.write(text)
}
} catch {
/* ignore */
}
@@ -4325,7 +4342,7 @@ async function bareAgentPromptSetupLine(ctx, prompt) {
if (!stdin || typeof stdin.on !== 'function') {
throw new Error('setup: stdin stream unavailable')
}
bareAgentWriteOut(stdout, '\x1b[?25h\x1b[0m' + prompt)
bareAgentWriteOut(ctx, stdout, '\x1b[?25h\x1b[0m' + prompt)
return bareAgentReadStreamLineOnce(stdin)
}
@@ -4463,6 +4480,7 @@ async function bareAgentInteractiveSetup(ctx, argv0, paths, config, opts) {
}
const stdout = ctx.replStdout || ctx.stdout
bareAgentWriteOut(
ctx,
stdout,
'\n=== ' +
argv0 +
@@ -4740,6 +4758,7 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
const fn = () => {
masterAbort.abort()
bareAgentWriteOut(
ctx,
stdout,
bareEditSgr('dim', useColor) + '^C' + EDIT_ANSI_RESET + '\n'
)
@@ -4809,7 +4828,7 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
if (e.type === 'delta_content') {
const chunk = typeof e.content === 'string' ? e.content : ''
assistantContent += chunk
bareAgentWriteOut(stdout, chunk)
bareAgentWriteOut(ctx, stdout, chunk)
} else if (e.type === 'delta_tool_calls') {
const arr = e.tool_calls
if (Array.isArray(arr)) {
@@ -4850,6 +4869,7 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
const pt = u.prompt_tokens
const ct = u.completion_tokens
bareAgentWriteOut(
ctx,
stdout,
'\n' +
bareEditSgr('dim', useColor) +
@@ -4864,7 +4884,7 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
if (!hasTools) {
await bareAgentSaveHistory(ctx, paths.history, messages)
bareAgentWriteOut(stdout, '\n')
bareAgentWriteOut(ctx, stdout, '\n')
break
}
@@ -4885,6 +4905,7 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
const name = fn?.name || ''
const argsStr = fn?.arguments || '{}'
bareAgentWriteOut(
ctx,
stdout,
'\n' +
bareEditSgr('keyword', useColor) +
@@ -4895,7 +4916,7 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
)
const spinner = bareEditSgr('dim', useColor) + '… running ' + name + EDIT_ANSI_RESET
bareAgentWriteOut(stdout, spinner + '\r')
bareAgentWriteOut(ctx, stdout, spinner + '\r')
const resultStr = await bareAgentDispatchTool({
ctx,
@@ -4910,7 +4931,7 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
onTaskComplete
})
bareAgentWriteOut(stdout, '\x1b[K')
bareAgentWriteOut(ctx, stdout, '\x1b[K')
messages.push({
role: 'tool',
@@ -4924,6 +4945,7 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
await bareAgentSaveHistory(ctx, paths.history, messages)
if (completed) {
bareAgentWriteOut(
ctx,
stdout,
bareEditSgr('dim', useColor) +
'\nDone: ' +
@@ -1,7 +1,7 @@
{
"schema": 2,
"profileId": "bare-os-posix-like",
"generatedAt": "2026-04-22T07:30:25.994Z",
"generatedAt": "2026-04-22T21:10:53.539Z",
"note": "Sparse POSIX Issue 7 coverage hints for /bin utilities. Omitted command names are not yet profiled here.",
"commandIndex": [
{
@@ -1,6 +1,6 @@
{
"schema": 1,
"atMs": 1776843025994,
"atMs": 1776892253538,
"commands": [
"agent",
"arch",
File diff suppressed because one or more lines are too long