Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion README.ko.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

<p align="center">
<a href="https://github.com/lidge-jun/codexclaw/actions/workflows/ci.yml"><img src="https://github.com/lidge-jun/codexclaw/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
<img src="https://img.shields.io/badge/tests-2%2C579_passing-brightgreen" alt="2,579 tests passing">
<img src="https://img.shields.io/badge/tests-2%2C580_passing-brightgreen" alt="2,580 tests passing">
<img src="https://img.shields.io/badge/skills-28-blue" alt="28 skills">
<img src="https://img.shields.io/badge/hooks-23-blue" alt="23 hooks">
<a href="https://lidge-jun.github.io/codexclaw/"><img src="https://img.shields.io/badge/docs-codexclaw-black" alt="Documentation"></a>
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

<p align="center">
<a href="https://github.com/lidge-jun/codexclaw/actions/workflows/ci.yml"><img src="https://github.com/lidge-jun/codexclaw/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
<img src="https://img.shields.io/badge/tests-2%2C579_passing-brightgreen" alt="2,579 tests passing">
<img src="https://img.shields.io/badge/tests-2%2C580_passing-brightgreen" alt="2,580 tests passing">
<img src="https://img.shields.io/badge/skills-28-blue" alt="28 skills">
<img src="https://img.shields.io/badge/hooks-23-blue" alt="23 hooks">
<a href="https://lidge-jun.github.io/codexclaw/"><img src="https://img.shields.io/badge/docs-codexclaw-black" alt="Documentation"></a>
Expand Down
2 changes: 1 addition & 1 deletion README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

<p align="center">
<a href="https://github.com/lidge-jun/codexclaw/actions/workflows/ci.yml"><img src="https://github.com/lidge-jun/codexclaw/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
<img src="https://img.shields.io/badge/tests-2%2C579_passing-brightgreen" alt="2,579 tests passing">
<img src="https://img.shields.io/badge/tests-2%2C580_passing-brightgreen" alt="2,580 tests passing">
<img src="https://img.shields.io/badge/skills-28-blue" alt="28 skills">
<img src="https://img.shields.io/badge/hooks-23-blue" alt="23 hooks">
<a href="https://lidge-jun.github.io/codexclaw/"><img src="https://img.shields.io/badge/docs-codexclaw-black" alt="Documentation"></a>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -968,7 +968,8 @@ function main() {
? denyEnvelope("codexclaw spawn policy input exceeded 4 MiB; refusing to bypass the recursion and trust boundary")
: runSpawnAttachHook(stdin.raw);
if (out) process.stdout.write(out);
process.exit(0);
// Piped stdout is asynchronous on POSIX; let pending writes finish before exiting.
process.exitCode = 0;
}

// Only run as a CLI entrypoint, not when imported by tests. Compare via realpath:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -968,7 +968,8 @@ function main(): void {
? denyEnvelope("codexclaw spawn policy input exceeded 4 MiB; refusing to bypass the recursion and trust boundary")
: runSpawnAttachHook(stdin.raw);
if (out) process.stdout.write(out);
process.exit(0);
// Piped stdout is asynchronous on POSIX; let pending writes finish before exiting.
process.exitCode = 0;
}

// Only run as a CLI entrypoint, not when imported by tests. Compare via realpath:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1049,3 +1049,34 @@ test("concise entrypoint is delivered once without recursively inlining its refs
const detail = readFileSync(join(SKILLS_DIR, "dev", "references", "development-practice.md"), "utf8").trim();
assert.ok(!first.includes(detail));
});

test("BUG-R1: CLI source and dist drain large rewritten spawn JSON over a pipe", () => {
const SENTINEL = "CXC-STDOUT-DRAIN-SENTINEL-END";
const originalMessage = `${"A".repeat(200 * 1024)}${SENTINEL}`;
assert.ok(originalMessage.length < 256 * 1024, "spawn message must stay under the normalization cap");
const cwd = workspaceWithConfig({
executor: { mode: "model", model: "gpt-5.6-luna", effort: "high", promptOverride: null },
});
const payload = spawnPayloadAt(cwd, { agent_type: "worker", message: originalMessage });
try {
for (const [label, cli] of [
["source", resolve(here, "../src/spawn-attach-hook.ts")],
["dist", resolve(here, "../dist/spawn-attach-hook.js")],
] as const) {
const result = spawnSync(process.execPath, [cli, "hook", "pre-tool-use"], {
input: payload,
encoding: "utf8",
maxBuffer: 2 * 1024 * 1024,
});
assert.equal(result.status, 0, `${label} exit status`);
const parsed = JSON.parse(result.stdout);
const ui = parsed.hookSpecificOutput.updatedInput as Record<string, unknown>;
assert.equal(ui.model, "gpt-5.6-luna", `${label} model`);
assert.equal(ui.reasoning_effort, "high", `${label} effort`);
assert.equal(typeof ui.message, "string", `${label} message type`);
assert.ok(String(ui.message).endsWith(originalMessage), `${label} original message retained`);
}
} finally {
rmSync(cwd, { recursive: true, force: true });
}
});