mirror of
https://github.com/vercel-labs/fx.git
synced 2026-10-28 10:15:17 +08:00
Reuse the UTF-8 boundary helper for the stderr tail
- Skip a partial character at the start of the retained stderr tail with the shared boundary helper, and test tails that begin inside a character. - Fail the stdio diagnostics tests instead of crashing when a child has not been reaped. - Rewrap the startup failure paragraph in CONTRIBUTING.md.
This commit is contained in:
3 files changed
+21
-11
No files matched your search
+7
-6
@@ -310,12 +310,13 @@ after shutdown or startup failure. An explicit cidfile remains user-owned.
|
||||
When a stdio server closes its connection before answering `initialize`, for
|
||||
example because its process exited, the reported failure names the exit code
|
||||
or signal and includes a bounded, terminal-safe excerpt of the server's stderr
|
||||
with secrets masked. A startup timeout names the budget the
|
||||
connection had, plus an earlier launch's exit when there was one, and names the
|
||||
`startup_timeout_ms` key when that setting set the budget. A startup restart runs only when it could change the
|
||||
outcome: a server that closed its connection at every offered protocol version
|
||||
is not restarted, and neither is one whose startup deadline has already passed.
|
||||
A server that fx stopped because of invalid output still gets its restart.
|
||||
with secrets masked. A startup timeout names the budget the connection had,
|
||||
plus an earlier launch's exit when there was one, and names the
|
||||
`startup_timeout_ms` key when that setting set the budget. A startup restart
|
||||
runs only when it could change the outcome: a server that closed its
|
||||
connection at every offered protocol version is not restarted, and neither is
|
||||
one whose startup deadline has already passed. A server that fx stopped
|
||||
because of invalid output still gets its restart.
|
||||
|
||||
MongoDB Atlas Managed MCP configuration service accounts use the OAuth
|
||||
client-credentials grant. fx does not implement that grant directly. Use
|
||||
|
||||
@@ -1263,9 +1263,7 @@ fn displayStderr(arena: Allocator, capture: *const stdio_dispatcher.StderrCaptur
|
||||
try plain.appendSlice(arena, " ... ");
|
||||
// The retained tail can begin inside a UTF-8 sequence.
|
||||
const tail = capture.tailSlice();
|
||||
var tail_start: usize = 0;
|
||||
while (tail_start < tail.len and (tail[tail_start] & 0xc0) == 0x80) tail_start += 1;
|
||||
try appendWithoutAnsi(arena, &plain, tail[tail_start..]);
|
||||
try appendWithoutAnsi(arena, &plain, tail[text_utils.utf8ForwardBoundary(tail, 0)..]);
|
||||
} else {
|
||||
const contiguous = try std.mem.concat(arena, u8, &.{ capture.headSlice(), capture.tailSlice() });
|
||||
try appendWithoutAnsi(arena, &plain, contiguous);
|
||||
@@ -1394,6 +1392,17 @@ test "server stderr display keeps the first line and the end, bounded and masked
|
||||
hostile.append("\x98\xa9ok \xff caf\xc3\xa9\x1b]0;title\x07\n\n\t done\x07");
|
||||
try std.testing.expectEqualStrings("\\x98\\xa9ok \\xff caf\xc3\xa9 done\\x07", try displayStderr(arena, &hostile));
|
||||
|
||||
// One of these makes the retained tail start inside a two-byte character.
|
||||
for ([_][]const u8{ "z", "zz" }) |suffix| {
|
||||
var split: stdio_dispatcher.StderrCapture = .{};
|
||||
for (0..3_000) |_| split.append("\xc3\xa9");
|
||||
split.append(suffix);
|
||||
try std.testing.expect(split.omitted);
|
||||
const shown = try displayStderr(arena, &split);
|
||||
try std.testing.expect(std.mem.find(u8, shown, "\\x") == null);
|
||||
try std.testing.expect(std.mem.endsWith(u8, shown, suffix));
|
||||
}
|
||||
|
||||
var invisible: stdio_dispatcher.StderrCapture = .{};
|
||||
invisible.append("rtl \u{202e}txt\u{200b} nel\u{85}");
|
||||
try std.testing.expectEqualStrings("rtl \\u{202e}txt\\u{200b} nel\\u{0085}", try displayStderr(arena, &invisible));
|
||||
|
||||
@@ -2665,7 +2665,7 @@ test "MCP stdio records how a child that exits before replying ended and what it
|
||||
),
|
||||
);
|
||||
const diagnostics = dispatcher.childDiagnostics();
|
||||
try std.testing.expectEqual(std.process.Child.Term{ .exited = 3 }, diagnostics.term.?);
|
||||
try std.testing.expectEqual(std.process.Child.Term{ .exited = 3 }, diagnostics.term orelse return error.TestExpectedExit);
|
||||
try std.testing.expectEqualStrings(
|
||||
"npm error code E401\nnpm error Incorrect or missing password.\n",
|
||||
diagnostics.stderr.headSlice(),
|
||||
@@ -2703,7 +2703,7 @@ test "MCP stdio reports a write to a child that closed stdin as a closed connect
|
||||
);
|
||||
// fx ends a child it can no longer write to; the details still arrive.
|
||||
const diagnostics = dispatcher.childDiagnostics();
|
||||
try std.testing.expectEqual(std.process.Child.Term{ .signal = .KILL }, diagnostics.term.?);
|
||||
try std.testing.expectEqual(std.process.Child.Term{ .signal = .KILL }, diagnostics.term orelse return error.TestExpectedExit);
|
||||
try std.testing.expectEqualStrings("stdin closed\n", diagnostics.stderr.headSlice());
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user