Skip to content

Commit 3817366

Browse files
fix(submit-proposals): pipe commit message and PR body via stdin (B10)
Bug surfaced in production on 2026-04-19 while opening a proposal batch PR via `submit-proposals.ts --pr`. Two symptoms: 1. commit message came out with empty slots where term IDs should be: - (zk-compression): Bubblegum Asset PDA - (zk-compression): cNFT Tree Pool instead of the expected `bubblegum-asset-pda (zk-compression): ...`. 2. `gh pr create` failed outright with errors like /bin/sh: 1: bubblegum-asset-pda: not found /bin/sh: 1: validate-term-proposal.ts: not found (one per backtick in the body) and returned exit code 1, so `pr_url` came back null even though the branch + commit had been made successfully. Root cause: both `commitProposals` and `submitPr` embedded the message/ body into the shell command string via template literal, only escaping double quotes. Any backtick in the text (plentiful: term IDs are formatted as `` `id` ``, and the PR body had an inline code block mentioning `validate-term-proposal.ts`) was interpreted as command substitution by /bin/sh, which then tried to execute each ID as a shell command. Fix: pipe the message via stdin using the native "read from stdin" options — `git commit -F -` and `gh pr create --body-file -`. execSync accepts an `input` option that pipes a string to stdin of the spawned process, so there is no shell quoting step at all. Validation: full submit-proposals --pr flow run end-to-end, produced a real PR (solanabr#47 against solanabr/solana-glossary) with correct commit message and correctly-rendered body. typecheck clean.
1 parent 215b080 commit 3817366

1 file changed

Lines changed: 19 additions & 6 deletions

File tree

apps/kuka-agent/skills/kuka/scripts/submit-proposals.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -555,9 +555,14 @@ function commitProposals(
555555
): void {
556556
const pluralSuffix = proposals.length > 1 ? "s" : "";
557557
const commitMsg = `feat(glossary): add ${proposals.length} community-proposed term${pluralSuffix}\n\nTerms proposed by Kuka agent during teaching conversations:\n${termList}`;
558-
const escapedCommitMsg = commitMsg.replaceAll('"', String.raw`\"`);
559-
execSync(`git commit -m "${escapedCommitMsg}"`, {
560-
stdio: "pipe",
558+
// Bug fix B10 (2026-04-19): pipe the commit message via stdin instead of
559+
// embedding it in the shell command. The termList format includes `id`
560+
// backticks, which /bin/sh interpreted as command substitution, producing
561+
// a commit message with empty slots where the term IDs should be. Using
562+
// `git commit -F -` bypasses shell quoting entirely.
563+
execSync("git commit -F -", {
564+
input: commitMsg,
565+
stdio: ["pipe", "pipe", "pipe"],
561566
});
562567
}
563568

@@ -587,11 +592,19 @@ Generated by Kuka 🎓 — Solana Glossary Teaching Companion`;
587592

588593
function submitPr(repo: string, proposals: Proposal[], termList: string): string {
589594
const prBody = buildPrBody(proposals, termList);
590-
const escapedPrBody = prBody.replaceAll('"', String.raw`\"`);
591595
const prTitle = `feat(glossary): add ${proposals.length} community-proposed terms`;
596+
// Bug fix B10 (2026-04-19): pipe the PR body via stdin using --body-file -.
597+
// The body contains `id` backticks and code-fenced blocks that /bin/sh
598+
// interpreted as command substitution, causing `gh pr create` to either
599+
// fail outright or render an empty body. --body-file - reads raw bytes
600+
// from stdin, sidestepping shell quoting.
592601
const result = execSync(
593-
`gh pr create --repo ${repo} --title "${prTitle}" --body "${escapedPrBody}"`,
594-
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] },
602+
`gh pr create --repo ${repo} --title "${prTitle.replaceAll('"', String.raw`\"`)}" --body-file -`,
603+
{
604+
input: prBody,
605+
encoding: "utf-8",
606+
stdio: ["pipe", "pipe", "pipe"],
607+
},
595608
);
596609
return result.trim();
597610
}

0 commit comments

Comments
 (0)