Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
04310da
fix(android): record the instrumentation result when the snapshot hel…
thymikee Oct 28, 2026
68f55a9
fix(android): satisfy lint for the instrumentation result diagnostics
thymikee Oct 28, 2026
8f283da
fix(android): keep snapshot content out of the helper exit diagnostic…
thymikee Oct 28, 2026
86d1133
fix(android): filter snapshot content before cutting the tail, and re…
thymikee Oct 28, 2026
30f2f0d
fix(android): match only UiAutomator attributes as snapshot content a…
thymikee Oct 28, 2026
9eddef3
chore(android): drop an unused export and share the signal field helper
thymikee Oct 28, 2026
4057e42
refactor(android): keep only allowlisted instrumentation fields and a…
thymikee Oct 28, 2026
a61ecc1
test(android): cover stderr beyond the retained window
thymikee Oct 28, 2026
8bcc0ae
refactor(android): split protocol record reading out of the stdout li…
thymikee Oct 28, 2026
3db8275
fix(android): attach no raw helper stream on any failure path and fla…
thymikee Oct 28, 2026
28678f4
test(android): narrow the rejected startup error before reading its d…
thymikee Oct 28, 2026
c35d186
fix(android): read instrumentation results for every parse failure an…
thymikee Oct 28, 2026
77a7765
refactor(android): record parsed instrumentation fields only, drop th…
thymikee Oct 28, 2026
4861da3
fix(android): keep the helper failure message and stderr detail as be…
thymikee Oct 28, 2026
63ee8b5
fix(android): withhold message fields that hold snapshot markers and …
thymikee Oct 28, 2026
2e62e97
fix(android): withhold message fields with a generic fail-closed rule
thymikee Oct 28, 2026
c97885f
fix(android): match entities generically and keep the abort message t…
thymikee Oct 28, 2026
5e9942f
refactor(android): drop the dead numeric-entity branches from the mar…
thymikee Oct 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions packages/host-kit/src/internal/exec.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -483,3 +483,20 @@ test('commandHostEnvironment names the enclosing host and refuses outside one',
assert.equal(commandHostEnvironment(), host);
});
});

// Windows reports no signal for a terminated process.
test.skipIf(process.platform === 'win32')(
'every foreground executor reports the signal that ended the process',
async () => {
const kill = ['-e', "process.kill(process.pid, 'SIGKILL')"];
const options = { allowFailure: true };

assert.equal((await runCmd(process.execPath, kill, options)).signal, 'SIGKILL');
assert.equal((await runCmdStreaming(process.execPath, kill, options)).signal, 'SIGKILL');
assert.equal(runCmdSync(process.execPath, kill, options).signal, 'SIGKILL');

const exited = await runCmd(process.execPath, ['-e', 'process.exit(3)'], options);
assert.equal(exited.exitCode, 3);
assert.equal('signal' in exited, false);
},
);
28 changes: 19 additions & 9 deletions packages/host-kit/src/internal/exec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export type ExecResult = {
stderr: string;
exitCode: number;
stdoutBuffer?: Buffer;
/** The signal that ended the process, when one did. */
signal?: string;
Comment thread
thymikee marked this conversation as resolved.
Resolved
};

export type ExecOptions = {
Expand Down Expand Up @@ -46,7 +48,8 @@ export type ExecStreamOptions = ExecOptions & {

export type ExecBackgroundResult = {
child: ReturnType<typeof spawn>;
wait: Promise<ExecResult>;
/** A background run reports no `signal`: its caller owns the child and reads its exit directly. */
wait: Promise<Omit<ExecResult, 'signal'>>;
};

type ExecDetachedOptions = ExecOptions & {
Expand Down Expand Up @@ -268,12 +271,14 @@ function runSpawnedCommand(
reject(failure);
return;
}
resolve({
stdout,
stderr,
exitCode: finalExitCode,
stdoutBuffer: stdoutChunks ? Buffer.concat(stdoutChunks) : undefined,
});
resolve(
execResult(child, {
stdout,
stderr,
exitCode: finalExitCode,
stdoutBuffer: stdoutChunks ? Buffer.concat(stdoutChunks) : undefined,
}),
);
}
// A deadline that fires after the child exited on its own still has to settle: the
// group kill that would have ended the pipe holder can no longer run through a child
Expand Down Expand Up @@ -336,6 +341,11 @@ function runSpawnedCommand(
});
}

/** Returns the result with `signal` added when a signal terminated the process. */
function execResult(ended: { signalCode: string | null }, result: ExecResult): ExecResult {
return ended.signalCode ? { ...result, signal: ended.signalCode } : result;
}

export async function whichCmd(cmd: string, env: EnvMap): Promise<boolean> {
const candidate = normalizeExecutableLookup(cmd);
if (!candidate) return false;
Expand Down Expand Up @@ -449,7 +459,7 @@ export function runCmdSync(
throw createExitError(executable, cmd, args, exitCode, stdout, stderr);
}

return { stdout, stderr, exitCode, stdoutBuffer };
return execResult({ signalCode: result.signal }, { stdout, stderr, exitCode, stdoutBuffer });
}

export function runCmdDetached(
Expand Down Expand Up @@ -524,7 +534,7 @@ export function runCmdBackground(
});
}

const wait = new Promise<ExecResult>((resolve, reject) => {
const wait = new Promise<Omit<ExecResult, 'signal'>>((resolve, reject) => {
let settled = false;
function finish(event: 'error' | 'exit'): boolean {
if (settled) return false;
Expand Down
Loading
Loading