Skip to content

ctx_batch_execute corrupts heredoc commands by appending stderr redirection #656

@Noctivoro

Description

@Noctivoro

Summary

ctx_batch_execute corrupts shell commands that use heredocs because runBatchCommands() appends 2>&1 directly to each command string before passing it to the shell executor.

For a command like:

node - <<'NODE'
console.log('heredoc works')
NODE

ctx_batch_execute effectively executes:

node - <<'NODE'
console.log('heredoc works')
NODE 2>&1

That changes the heredoc terminator from NODE to NODE 2>&1, so the shell does not terminate the heredoc where intended. The batch result can then show (no output) or otherwise misleading indexed/search output even though the command itself is valid.

Reproduction

Call ctx_batch_execute with a heredoc command:

{
  "commands": [
    {
      "label": "heredoc node simple",
      "command": "node - <<'NODE'\nconsole.log('heredoc works');\nconsole.log(process.version);\nNODE"
    }
  ],
  "queries": ["heredoc works node version"],
  "timeout": 5000
}

Observed output includes an indexed section for the command, but the section body is empty / (no output).

For comparison, the same command works through ctx_execute(language: "shell", code: ...).

Expected behavior

ctx_batch_execute should execute the user's command string as provided. It should not append shell syntax after the command body because that can alter multiline shell constructs such as heredocs.

Stderr should still be captured and indexed alongside stdout.

Likely cause

Current upstream main still appears to append redirection in src/server.ts:

code: `${nodeOptsPrefix}${cmd.command} 2>&1`,

This appears in both the serial and parallel runBatchCommands() paths.

Suggested fix

Do not mutate the command with 2>&1. Instead:

  1. Execute the command string as-is:
code: `${nodeOptsPrefix}${cmd.command}`,
  1. Combine the executor's captured streams before formatting/indexing:
const combinedOutput = result.stderr
  ? `${result.stdout}${result.stdout && !result.stdout.endsWith("\n") ? "\n" : ""}${result.stderr}`
  : result.stdout;

formatCommandOutput(cmd.label, combinedOutput, onFsBytes)

Apply the same pattern in both serial and parallel paths.

Environment

  • context-mode: 1.0.146
  • npm latest checked: 1.0.146
  • Platform observed: macOS / Pi coding agent

Impact

This is easy for agents to hit because ctx_batch_execute is recommended as the primary data-gathering tool, and heredoc-based Node/Python snippets are a common way to keep complex analysis code readable inside shell commands.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions