Skip to content

Diagnose & document Go-template args split by unquoted spaces (#172)#173

Merged
konard merged 5 commits into
mainfrom
issue-172-92a29c0e040c
Jun 21, 2026
Merged

Diagnose & document Go-template args split by unquoted spaces (#172)#173
konard merged 5 commits into
mainfrom
issue-172-92a29c0e040c

Conversation

@konard

@konard konard commented Jun 21, 2026

Copy link
Copy Markdown
Member

Summary

Fixes #172.

A literal Go/Docker template token typed in a $ template — e.g. --format {{json .Config.Env}} — contains an unquoted space, so command-stream splits it into separate argv words. That is exactly what a POSIX shell (bash) does, but it surprised users because a space-free {{.Id}} survives while the spaced token reaches Docker broken (template parsing error: ... unclosed action).

Root-cause finding

This is shell-faithful behavior, not corruption. I verified command-stream matches bash argv-for-argv:

Pattern argv Notes
--format {{json .Config.Env}} (unquoted) --format, {{json, .Config.Env}} splits on the unquoted space — same as bash
--format {{.Id}} (no space) --format, {{.Id}} single word
--format '{{json .Config.Env}}' --format, {{json .Config.Env}} quoted → single arg
--format "{{json .Config.Env}}" --format, {{json .Config.Env}} quoted → single arg
--format ${format} (interpolated) --format, {{json .Config.Env}} auto-quoted → single arg

So the fix is to make the failing case diagnosable and documented, while keeping shell parity (full verbatim passthrough would deviate from shell semantics).

Changes

  1. Diagnostics — when a built command contains an unquoted {{ … }} token with an internal space, command-stream prints a one-line warning to stderr pointing at the gotcha. Fires once per unique token; silence with COMMAND_STREAM_NO_TEMPLATE_WARNING=1. (src/$.quote.mjs, new findSplitTemplateToken.)
  2. Docs — new README section "Go templates & {{ }} arguments" showing the works/breaks/workaround patterns.
  3. Exampleexamples/go-template-arguments.mjs demonstrating each pattern.
  4. Teststests/go-template-quoting.test.mjs (13 tests) asserting splitting/quoting behavior and the warning (emit, dedup, env silence, quoted/space-free no-warn).
  5. Changeset — patch release note.

Reproduction / verification

import { $ } from 'command-stream';
// ❌ unquoted space → split like bash (now also prints a one-line warning)
await $`docker image inspect alpine --format {{json .Config.Env}}`;
// ✅ quote it, like a shell script
await $`docker image inspect alpine --format '{{json .Config.Env}}'`;
// ✅ or interpolate the whole token
const format = '{{json .Config.Env}}';
await $`docker image inspect alpine --format ${format}`;
$ node examples/go-template-arguments.mjs
[command-stream] Warning: template token `{{json .Config.Env}}` contains an unquoted space, so the shell splits it into multiple arguments (just like bash would). Quote it ('{{json .Config.Env}}') or interpolate it as a single ${value} ...
1. UNQUOTED  ...   -> ["--format","{{json",".Config.Env}}"]
2. NO SPACE  ...   -> ["--format","{{.Id}}"]
3. SINGLE-QUOTED   -> ["--format","{{json .Config.Env}}"]
4. INTERPOLATED    -> ["--format","{{json .Config.Env}}"]

All new tests pass; the full suite has no new failures (pre-existing jq-not-installed failures are environmental).

Rust parity

The diagnostic is mirrored in the Rust implementation to satisfy the JS/Rust source-parity CI check: find_split_template_token / warn_on_split_template in rust/src/quote.rs, wired into build_shell_command and the cmd! macro in rust/src/macros.rs, with unit tests + a doctest and a rust/changelog.d/ fragment.

Adding .gitkeep for PR creation (default mode).
This file will be removed when the task is complete.

Issue: #172
@konard konard self-assigned this Jun 21, 2026
A literal template token like `--format {{json .Config.Env}}` contains an
unquoted space, so command-stream splits it into separate argv words exactly
as a POSIX shell does. Quoting or interpolating the token passes it through
untouched. To make the failing case easy to spot:

- Emit a one-line stderr warning when a built command contains an unquoted
  {{ }} token with an internal space (once per token; silence via
  COMMAND_STREAM_NO_TEMPLATE_WARNING=1).
- Add a README "Go templates & {{ }} arguments" section with the
  works/breaks/workaround patterns.
- Add examples/go-template-arguments.mjs and a test suite covering the
  splitting behavior and the diagnostic.
@konard konard changed the title [WIP] $ mangles Go-template args with internal spaces (e.g. --format {{json .Config.Env}}); shell-script look-and-feel breaks in .mjs Diagnose & document Go-template args split by unquoted spaces (#172) Jun 21, 2026
@konard konard marked this pull request as ready for review June 21, 2026 15:06
konard added 2 commits June 21, 2026 15:09
Add find_split_template_token + warn_on_split_template to rust/src/quote.rs
and emit the one-line warning from build_shell_command and the cmd! macro,
matching the JavaScript implementation. Silenced via the same
COMMAND_STREAM_NO_TEMPLATE_WARNING env var; once per unique token.
@konard

konard commented Jun 21, 2026

Copy link
Copy Markdown
Member Author

Working session summary

Everything is complete and green. Here's the final state of PR #173:

Summary

The failing Rust changelog fragment check is now resolved — that was the last blocker. I added rust/changelog.d/20260621_151257_go_template_split_diagnostic.md (a patch fragment following the repo's YYYYMMDD_HHMMSS_description.md convention), committed it, and pushed.

All three CI checks now pass on the latest commit (d9cffde):

  • ✅ Language parity check
  • ✅ JavaScript checks and release
  • ✅ Rust checks and release

The working tree is clean and the PR is mergeable (not draft).

What the PR delivers (all three issue asks)

  1. Docs — new README section "Go templates & {{ }} arguments" with works/breaks/workaround patterns.
  2. Code/diagnostics — a one-line stderr warning fires when a built command contains an unquoted {{ … }} token with an internal space (the root cause: command-stream is shell-faithful and splits on the unquoted space exactly like bash). Dedup'd per unique token, silenced via COMMAND_STREAM_NO_TEMPLATE_WARNING=1. Implemented in js/src/$.quote.mjs (findSplitTemplateToken / warnOnSplitTemplate) and mirrored in rust/src/quote.rs + rust/src/macros.rs for parity.
  3. Tests + examplejs/tests/go-template-quoting.test.mjs (13 tests), Rust unit tests + doctest, and a runnable js/examples/go-template-arguments.mjs.

PR: #173

The root-cause finding stands: this is shell-faithful behavior, not corruption — making full template passthrough would deviate from POSIX shell semantics, so the right fix is diagnosis + documentation, which is what's shipped.


This summary was automatically extracted from the AI working session output.

@konard

konard commented Jun 21, 2026

Copy link
Copy Markdown
Member Author

🤖 Solution Draft Log

This log file contains the complete execution trace of the AI solution draft process.

💰 Cost estimation:

  • Public pricing estimate: $6.393531
  • Calculated by Anthropic: $6.393860
  • Difference: $0.000330 (+0.01%)

📊 Context and tokens usage:

Claude Opus 4.8: (2 sub-sessions)

  1. 116.9K / 1M (12%) input tokens, 42.7K / 128K (33%) output tokens
  2. 41.1K / 1M (4%) input tokens, 4.1K / 128K (3%) output tokens

Total: (22.8K new + 132.7K cache writes + 7.3M cache reads) input tokens, 52.4K output tokens, $6.393531 cost

🤖 Models used:

  • Tool: Anthropic Claude Code
  • Requested: opus (claude-opus-4-8)
  • Model: Claude Opus 4.8 (claude-opus-4-8)

📎 Log file uploaded as Gist (2825KB)


Now working session is ended, feel free to review and add any feedback on the solution draft.

@konard

konard commented Jun 21, 2026

Copy link
Copy Markdown
Member Author

✅ Ready to merge

This pull request is now ready to be merged:

  • All CI checks have passed
  • No merge conflicts
  • No pending changes

Monitored by hive-mind with --auto-restart-until-mergeable flag

@konard konard merged commit f042c68 into main Jun 21, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

$ mangles Go-template args with internal spaces (e.g. --format {{json .Config.Env}}); shell-script look-and-feel breaks in .mjs

1 participant